Lowlevel

OffZone => Offtopic => Thema gestartet von: Tufelix am 31. October 2012, 09:46

Titel: Logisim CPU
Beitrag von: Tufelix am 31. October 2012, 09:46
Huhu, hab mir eine CPU in logisim gebaut und möchte jetzt für die CPU ein OS programmieren. Nun hab mir schon einige Gedanken für das dateisystem gemacht:

die ganzen dateien werden im Ram gespeichert.

es gibt 2 große listen, die Dateiliste und die Verzeichniss liste.In denen werden die ganzen ID's gespeichert

/a/programm/Hirn.OS
 0        1      1024,1

nun jedes verzeichniss hat einen bestimmten pfad ID.Wird nach ner datei gesucht wird zunächst die Pfad's in ihre ID'n übersetzt und dann die ID'S zusammen addiert.

0+1 = 1 PfadID

dannach wird die datei Übersetzt:

DateiID = 1024
DateiPfadID = 1

Nun jetzt wird überprüft ob die PfadID mit der DateiPfadID übereinstimmt wenn das nicht der fall ist wird ne fehlermeldung angezeigt.Die DateiID für zur adresse im ram.

So, gibt ne Effektivere Möglichkeit für das Dateiensystem? Auserdem will ich für das projekt einen Compiler programmieren, hat wer ne Idee wie man das am besten macht ? :D

MfG Tufelix
Titel: Re: Logisim CPU
Beitrag von: Jidder am 31. October 2012, 12:29
Hi und Willkommen an Board ;)

Was mit bei deiner Idee nicht ganz klar ist, was das mit der Addition werden soll. Soll die Summe die Datei identifizieren? Wenn ja, könntest du Probleme bekommen, weil die Summen nicht eindeutig sind. Zum Beispiel 2+3=5 und 1+4=5. Meine Idee ist vielleicht nicht unbedingt effektiver, aber ich glaube die funktioniert wenigstens ;)

Ein Dateisystem ist häufig als Baumstruktur aufgebaut. Ein Verzeichnis ist ein Knoten in diesem Baum (= Liste der Dateien und Unterverzeichnisse), und eine Datei ist ein Blatt in diesem Baum. Ein Verzeichnis könnte als Liste von Dateieinträgen aufgebaut sein. Ein Dateieintrag könnte auch ein Verzeichniseintrag sein. Der Dateieintrag enthält Sachen wie Dateiname, Größe, Offset im RAM und Typ (Datei oder Verzeichnis). Wenn du zum Beispiel die Datei /users/steve/minecraft.exe suchst, dann suchst du im Wurzelverzeichnis nach dem Eintrag für "users". Dann prüfst du, ob es ein Verzeichnis ist, und wenn ja, suchst du bei dem im Eintrag angegebenen Offset nach dem Eintrag für steve. (Zum Beispiel rekursiv.) Im Verzeichnis "steve" suchst du dann nach dem Eintrag für minecraft.exe und kriegst so das Offset der Datei raus.

Dieses Prinzip ist zwar im Vergleich zu "echten" Dateisystemen relativ einfach, allerdings auch ineffizient. Zum Beispiel bekommst du ein Problem, wenn du eine Datei vergrößern willst, aber direkt hinter dieser Datei eine andere Datei liegt. Dann musst du die Datei fragmentieren oder verschieben. Genau dasselbe Problem bekommst du mit Verzeichnissen, wenn du eine feste Anzahl an möglicher Einträge reservierst. Das Problem ist dann, was wenn du mehr Dateien als vorgesehen reinschreiben willst. Du könntest das Konzept um Sektoren oder Cluster erweitern, und die Dateien nicht einfach als durchgehendes Array speichern, sondern als eine Art verkettete Liste, wobei die Sektor-/Clusternummern praktisch die next-Zeiger sind.

Zitat
Auserdem will ich für das projekt einen Compiler programmieren, hat wer ne Idee wie man das am besten macht ?
Hast du denn schon einen Assembler dafür geschrieben?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 31. October 2012, 13:13
Danke für die coole Idee  :-) .

joar hab ich mal, ist aber eher ein übersetzer der ne Sprache einließt und dann die einzelne Befehle in der CodeDatei nacheinnander in den Opcode übersetzt.
Titel: Re: Logisim CPU
Beitrag von: chris12 am 31. October 2012, 16:13
du kannst auch alles in ein physikalisches verzeichnis werfen und den pfad sowie dateinamen als einheit betrachten ... aber, dann musst du dir überlegen, wie lang du die namen erlaubst

hätte den vorteil, dass nur ein verzeichnis durchsucht werden müsste, man bräuchte aber einen guten sortieralgo um einen verzeichnisbaum zu erstellen ...

Titel: Re: Logisim CPU
Beitrag von: Tufelix am 31. October 2012, 17:32
mmh ich glaub so mache ich's :-D
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 27. November 2012, 19:28
Nun, mein jetziger CPU hat kein richtige Jump-funktion. Man kann kein sprungziel angeben, es wird nur entweder eine 1 oder ne 0 im flagregister geschrieben...Daher hab ich mir überlegt einen einen Cpu zubauen, damit er wieder verwendbar wird soll der I/O ports bekommen, hab mir schon im mathe-unterricht was ausgetüftelt  :-D :


1 ich geh mal davon aus das wir 16 register haben werden, also ein instuktion-set mit 8 argument-bits, und 2x 4 bit registerbits

00000000|0000|0000|0000000000000000
Argument   RX   RX             NUM

2 Nun jetzt zum I/O port:

2.1 Es gibt 4 I/O gruppen die jeweils 8 I/O ports zusammenfassen.

Ein I/O port kann endweder ein ausgang oder ein eingang sein aber niemals beides.

Man kann die Ports über einen Opcode zu einem aus- oder einem Eingang machen, dazu später mehr :D.

2.2 Nun mal zu den befehlen:

Man steuert nicht jeden I/O port an sondern seine Gruppe.

Jeder Befehl für die I/O ports sind in etwa gleich auf gebaut:

00000000|0000|0000|00000000|00000000|
Argument RX/Gruppe   Num         Die Ports die aktiviert werden
              /\
              |
   Die Gruppenbits und die RX bits, wechseln je nach Befehl.

2.3 Nun jetzt mal ein Beispiel:

2.3.1 Eingang-Ports
   
Wir haben in der portgruppe "A"  die ersten 7 bits als eingang gesetzt(für ne tastatur) und der letzte als Ausgang(löschbit für die Tastatur).

Nun wenn wir jetzt Alle 7 bits einlesen möchten wählen wir zunächst die Gruppe aus (also 0001 ) , dann die bits die wir einlesen möchten (11111110) zudem braucht man ein register wohin die daten kommen(wir nehmen mal gx).

der dazugehörige Opcode sieht dan so aus:
00000000|0011|0001|00000000|11111110
Argument  RX    Grup.       Num    Aktivierte Bit's

Eventuell kann man das ganze so bauen das man mehrende gruppen auswählen kann, das ganze wird aber dann viel komplizierter.

2.3.2 Ausgänge:

So wir haben jetzt in Gruppe B 8 bits als Ausgänge markiert(7 für ne Console und der letzte ist der löschbit).

Wir wollen Jetzt mal nen Coolen Buchstaben Ausgeben dazu wählen wir mal unsere Gruppe aus(0010) dann setzen wir der Buchstabe im Num-Feld "10110100" und dann noch die bit's die aktiviert werden sollen (11111110)

Im Opcode sieht das ganze jetzt so aus:

00000000|0010|0000|10110100|11111110
Argument  Grup.  RX      Num        Ausgewählte Bit's

Wir können aber auch ein register Wählen aus dem dann die bits kommen.
Auch ist es möglich beides zu verwenden, also RX und Num-feld, in diesem Fall haben die Num-Bit's vorrang.
Muss aber noch ne lösung für ein paar probleme finden.

2.4 I/O Ports als Ein- bzw. als ausgänge zu markieren.

Nun wir nehmen wieder das Beispiel mit der Konsole, wenn wir die ersten 7 bits als ausgänge setzen wollen müssen wir zunächnächt die Bits auswählen(11111110) und dann die Gruppe(0010)

00000000|0010|0000|00000000|11111110|

so jeder der genannten Opcodes haben ein eigenes argument, die müssen wir aber noch bestimmen.

Nun was hält ihr von der Idee bzw. gibt es bessere ?
Titel: Re: Logisim CPU
Beitrag von: chris12 am 27. November 2012, 19:46
also die idee scheint mir etwas unverständlich, aber ich hab mich auch nicht tiefgründig eingelesen, aber egal ... wie auch immer, wenn du noch keinen sprungbefehl hast, solltest du unbedingt einen einbauen, da sonst deine cpu nicht turing vollständig ist, aber wie auch immer.
Hmm in und out kannst du auch als memory mapped i/o organisieren, so hab ich das bei meinen entwürfen gemacht, das ist wesentlich einfacher ... ich glaube aber bei meinem neusten projekt hab ich auf eine mischung von beidem zurück gegriffen. Der Bildschirm ist aus geschwindigkeitsgründen in den speicher eingeblendet, genauso wie die fontmap. Rest hängt alles an einem seperaten bus, der aber eigentlich genauso aufgebaut ist, wie der RAM/CPU bus mit adress- und datenleitung.
also so hab ich das gelöst ... es gibt bestimmt noch bessere wege, oder zumindest andere wege.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 27. November 2012, 19:59
wie schnell ist dieses memorie-mapping ? :D
Titel: Re: Logisim CPU
Beitrag von: chris12 am 27. November 2012, 20:32
naja ... so schnell wie der ram halt ist, es kommt auf die implementierung an .... bei mir ist es z.B. so, dass du den Port nur implizit angeben kannst und auch nur in und von registern auf ports schreiben kannst, das heißt es ist schon insofern langsamer, als das du erst zwei register mit den werten laden musst, bevor du schreiben kannst ... beim ram hingegen ist es so gelöst, als das du sowas machen kannst wie const -> [adresse + offset], das kann durch die verwendung des zero registers in const -> [adresse] umgewandelt werden ... aber jetzt wo ich das hier schreibe, weiß ich garnicht mehr so recht, warum ich das mit mmio gemacht hab ... wenn ich ein paar mehr opcodes für die port zugriffe definieren würde, würde es wesentlich eleganter sein. Ich habs halt so gemacht. ... :D
Titel: Re: Logisim CPU
Beitrag von: Svenska am 27. November 2012, 23:48
Hallo,

Nun, mein jetziger CPU hat kein richtige Jump-funktion.
Die macht vieles einfacher. Stattdessen kannst du aber auch den Program Counter als normales Register definieren oder CALL/RETURN (notwendig für Funktionen) einbauen.

1 ich geh mal davon aus das wir 16 register haben werden, also ein instuktion-set mit 8 argument-bits, und 2x 4 bit registerbits
Die Argument-Bits nennt man klassisch Opcodes oder Instructions.

Ein I/O port kann endweder ein ausgang oder ein eingang sein aber niemals beides. Man kann die Ports über einen Opcode zu einem aus- oder einem Eingang machen, dazu später mehr.
Hmm, das kostet wertvolle Opcodes. Außerdem ist deine Zugriffsweise etwas ... gewöhnungsbedürftig, weil deine Ports nicht unabhängig voneinander sind.

Schaue dir mal Ports bei modernen Microcontrollern an (z.B. Atmel AVR). Da hast du pro Port x drei Register:
- DDRx gibt (pro Bit) an, ob der Port ein Eingang oder ein Ausgang ist.
- PORTx gibt (pro Bit) den Wert der Ausgangsbits an bzw. aktiviert bei Eingängen einen Pullup-Widerstand.
- PINx enthält den aktuellen Zustand der einzelnen Bits.

In einer simulierten CPU reichen eigentlich zwei Register (DIRx für die Richtung, PORTx für den Wert), die so breit sind, wie der Port selbst. Wenn du die I/O-Ports nicht mit Opcodes, sondern mit Registern (Speicheradressen, nicht CPU-Register!) steuerst, kannst du theoretisch beliebig viele davon haben.

Dein Tastaturbeispiel an Port A sähe in C dann ungefähr so aus:
DIRA = 0xFE;           /* Bits 7..1 als Ausgang, Bit 0 als Eingang */
wert = PORTA & 0xFE;   /* Lesen der oberen 7 Bits in eine Variable */
PORTA = PORTA | 0x01;  /* Setzen des Ausgangsbits auf 1 */
PORTA = PORTA & ~0x01; /* Löschen des Ausgangsbits */

Das finde ich persönlich weniger kompliziert und ist ähnlich flexibel. Die "Gruppen" sind hier die Port-Bezeichner.

Nun was hält ihr von der Idee bzw. gibt es bessere ?
Neben dem, was ich oben vorgestellt habe, gibt es noch MMIO. Da tut angeschlossene Hardware so, als wäre sie RAM. Die notwendigen Leitungen (Adressbits, Datenbits, Read-/Write-Bit) werden oft mit dem RAM gemeinsam genutzt; für die CPU besteht somit kein Unterschied zwischen RAM- und Hardwarezugriffen. Damit brauchst du die Registerwerte nicht immer lesen/ändern/schreiben, sondern kannst direkt drauf rumrechnen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 29. November 2012, 16:25
Nun, ein Port ist also eine Gruppe von Pins oder ? :-D Ich hab immer angenommen das ein port nur ein Pin am CPU/Mircocontroller ist. 
Titel: Re: Logisim CPU
Beitrag von: Svenska am 29. November 2012, 17:13
Genau. Ist auch eher logisch, weil CPUs ungern mit einzelnen Bits arbeiten und Bitgruppen (8, 16, 32 Bit) bevorzugen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 29. November 2012, 18:13
nun dann kann ich wohl mein selbstentworfendes konzept vergessen :D.  Nun Ich hab mal ein Flussdiagramm erstellt wie der CPU vielleicht nacher Ausehen wird, hab jetzt mal bei den I/O-Ports ein hybrid aus mmio und Svenska's Idee gewählt. (http://img4.fotos-hochladen.net/uploads/1zy0g8xjn6.png) (http://www.fotos-hochladen.net)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 30. November 2012, 01:28
Hallo,

das sieht mal ... komplett anders aus, als man es normalerweise tut. :roll:

Zwei Dinge habe ich in realen Systemen gesehen, sind aber unpraktisch:
- Liegt der Stack nicht im RAM, hast du nur eine äußerst begrenzte Zahl von nested function calls. Praktisch verhinderst du damit jede Form von Rekursion. Gibt es in der Realität z.B. in Tastaturprozessoren oder Embedded Controllern in Notebooks.
- Ist der Stack nicht im RAM verschiebbar, verhinderst du jede Form von Multitasking. Darum kann es Projekte wie SymbOS (http://www.symbos.de) nicht auf dem C64 geben, weil der 6502/6510 nur einen fixen Stack hat.

Ein paar weitere Dinge sind einfach nur unpraktisch bis kaputt:
- Der Adressbus fehlt. Adressen kann man zwar auch über den Datenbus laufen lassen, aber das kostet zusätzliche Logik, spart Leitungen und kostet Performance. ((Außerdem sind reale Bussysteme normalerweise deutlich langsamer als CPUs.))
- Dein RAM-Subsystem muss wissen, wie Hardwaregeräte angesprochen werden. Normalerweise reicht es, wenn die Hardware das selbst weiß. ((Außerdem werden optimierte Zugriffsmuster, z.B. Bursts, schwieriger umsetzbar.))
- Der Datenbus wird mit Dingen belastet, die niemanden interessieren sollten, z.B. Registerwerte.
- Du kannst zwar diverse Hardware mit MMIO ansprechen, allerdings nicht den ROM selbst. Normalerweise steht da nicht nur Code drin, sondern auch Wertetabellen, Strings und andere Dinge, die man lesen können möchte, nicht nur ausführen.
- Du hast eine (seltsame) Harvard-Architektur, d.h. dein RAM ist nicht ausführbar. Programme von Festplatte laden und starten geht nicht.
- Wie das "Jump" funktionieren soll, ist mir schleierhaft.

Aber viel Spaß beim Implementieren. :-) Wenn das funktioniert, möchte ich den Beweis sehen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 30. November 2012, 14:17
nun, ist nur ein konezpt :D.
Zitat
Der Adressbus fehlt. Adressen kann man zwar auch über den Datenbus laufen lassen, aber das kostet zusätzliche Logik, spart Leitungen und kostet Performance. ((Außerdem sind reale Bussysteme normalerweise deutlich langsamer als CPUs.))
Mhh ich wusste ich hab was vergessen. :-D

Zitat
- Der Datenbus wird mit Dingen belastet, die niemanden interessieren sollten, z.B. Registerwerte
Oje, dachte wenn man registerwerte in den ram laden möchte wäre das die einfachste möglichkeit.  :roll:

Zitat
- Du hast eine (seltsame) Harvard-Architektur, d.h. dein RAM ist nicht ausführbar. Programme von Festplatte laden und starten geht nicht.
In den ram werden die Programme geladen ?  :-o, jaja man lernt nie aus  :-D.

Zitat
- Liegt der Stack nicht im RAM, hast du nur eine äußerst begrenzte Zahl von nested function calls. Praktisch verhinderst du damit jede Form von Rekursion. Gibt es in der Realität z.B. in Tastaturprozessoren oder Embedded Controllern in Notebooks.
- Ist der Stack nicht im RAM verschiebbar, verhinderst du jede Form von Multitasking. Darum kann es Projekte wie SymbOS nicht auf dem C64 geben, weil der 6502/6510 nur einen fixen Stack hat.
Nun das heißt das ich den stack beerdige und stattdessen so Art Stackpointer einbaue der auf den Ram zugreift.

Hab mich ein wenig informiert und das hier gefunden http://www.rn-wissen.de/index.php/ATmega16_ATmega32_ATmega644 (http://www.rn-wissen.de/index.php/ATmega16_ATmega32_ATmega644), im Instuction-Set gibt es aber nicht sowas wie "register-Bits". Sind registerbits etwa unpraktisch ?  :?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 01. December 2012, 18:04
wie viel Leistung mehr, würde ein MultKern-CPU bringen?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 01. December 2012, 23:21
Hallo,

Oje, dachte wenn man registerwerte in den ram laden möchte wäre das die einfachste möglichkeit.  :roll:
Normalerweise nimmt man dafür Instruktionen, also "Kopiere Register X nach RAM-Adresse Y" oder "Nimm das Register Z als Adresse in den RAM und kopiere das, was da steht in das Register X".

In den ram werden die Programme geladen ?
Ist nicht zwingend, aber hilfreich. Lese dich mal zu Harvard-Architektur und von-Neumann-Architektur ein.

Nun das heißt das ich den stack beerdige und stattdessen so Art Stackpointer einbaue der auf den Ram zugreift.
Moderne CPUs benutzen zwei Register für den Stack. Eines, welches angibt, wo der Stack überhaupt liegt (damit es mehrere Stacks geben kann) und eins, welches angibt, wo man sich gerade im Stack befindet.

im Instuction-Set gibt es aber nicht sowas wie "register-Bits". Sind registerbits etwa unpraktisch ?
Was meinst du?

wie viel Leistung mehr, würde ein MultKern-CPU bringen?
Für n Kerne ist der Leistungszuwachs kleiner als n.
Andererseits ist es deutlich mehr Aufwand.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: chris12 am 02. December 2012, 01:09
Zitat
Zitat
Oje, dachte wenn man registerwerte in den ram laden möchte wäre das die einfachste möglichkeit. 
Normalerweise nimmt man dafür Instruktionen, also "Kopiere Register X nach RAM-Adresse Y" oder "Nimm das Register Z als Adresse in den RAM und kopiere das, was da steht in das Register X".

wobei das schon ein guter ansatz ist, da er ja die werte irgendwie in den ram bekommen muss ...
allerdings würde dich empfehlen zwei busse zu nehmen, einen internen und einen externen. intern für den datenlauf innerhalb der cpu, also zwischen registern und der alu und einen externen als bussystem zwischen ram, geräten (bei mmio) und cpu

du kannst natürlich auch dein eigenes design wählen.


was du allerdings mit registerbits meinst, ist mir auch noch nicht so ersichtlich. meinst du damit tatsächlich, die codierung der register im opcode? wenn ja, dann brauchst du sowas unbedingt, denn irgendwie muss dein steuerwerk ja wissen, welches der register es wählen soll. es sei denn, du hast nur zwei register, der extrem spezialisiert sind. ....
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 02. December 2012, 14:32
Hallo Tufelix,


Wenn Du eine CPU bauen möchtest solltest Du vorher ein paar grundsätzliche Design-Entscheidungen treffen.

z.B.: RISC vs. CISC  oder anders:  simple Load/Modify/Store-Architektur oder was komplexeres.
CISC ermöglicht oft Befehle wie "add [ax],bx" was bedeutet das der Wert von Adresse aus AX geladen wird (in ein internes temporäres Zwischenregister das nicht explizit ansprechbar ist), dann der Wert von BX dazuaddiert wird und das Ergebnis wieder an die selbe Adresse (AX) in den Speicher zurückgeschrieben wird. Bei RISC benötigt man dazu oft 3 Befehle: "ld r3,[r1]  ;  add r3,r3,r2  ;  st [r1],r3" was bedeutet das der erste Befehl den Wert von Adresse R1 in das normale Register R3 lädt (R3 dient hier als Zwischenregister), der zweite Befehl dann R3 = R3 + R1 berechnet und der letzte Befehl das Ergebnis wieder in den Speicher schreibt. Der Hintergrund dieser Design-Entscheidung ist ob Du die Komplexität in Deine CPU packst, für die erste Variante benötigst Du eine recht komplexe State-Maschine (oft basierend auf Micro-Code), oder ob das der Compiler erledigen soll und Du dafür eine Menge Arbeit beim CPU-Design sparst. Für die zweite Variante spricht das es nur 2 Befehle geben muss die auf Speicher zugreifen können und Du gezielt dort die Komplexität von höherwertigen Speicheradressierungsmodi unterbringen kannst ohne die restlichen Befehle unnötig aufzublähen. Von der Performance sind beide Varianten etwa gleichwertig wenn man die CPU wirklich gut baut (heutige x86-CPUs setzten Befehle wie den oben genannten intern auch in mehrere Befehle um aber benötigen dafür vielfach mehr Transistoren im Decoder als z.B. eine ARM-CPU die pro Takt letztlich eine ähnliche Performance erreicht). Für den Einstieg würde ich trotzdem ganz klar RISC bevorzugen und alles was auch nur minimal komplex ist dem Compiler überlassen (der LLVM kann sowas bereits ziemlich gut).

Für den Stack benötigt man nicht unbedingt mehr als ein Register, alle modernen CPUs die das Flat-Memory-Model unterstützen kommen mit einem Register für den Stack aus. Für Hochsprachen lohnt es sich aber wenn es zusätzlich zum Stack-Pointer noch einen Frame-Pointer gibt, spätestens wenn VLA oder ähnliches unterstützt werden soll ist das sogar zwingend erforderlich. Multithreading lässt sich auch mit einem einzelnen Stack-Pointer-Register erledigen indem für jeden Thread der Stack in einem anderen Speicherbereich liegt, klar bedeutet dass das die einzelnen Stacks (von einem Prozess) nicht wirklich gegeneinander geschützt sind aber das sind sie bei allen anderen heutigen CPUs auch nicht. Interessanter ist schon eher die Design-Entscheidung ob Dein Stack nach oben oder nach unten wachsen soll (letzteres ist eher ein Relikt aus der Zeit als Programme noch grundsätzlich singlethreaded waren und es nur einen kleinen Speicherbereich gab der von unten kommend mit dem Heap und von oben kommend mit dem Stack belegt wurde wird aber trotzdem von vielen CPUs so genutzt bzw. von den Compilern so festgelegt (ARM/PowerPC/... können beides)).
Auch musst Du entscheiden ob es außer LD und ST noch Befehle wie PUSH und POP geben soll die implizit den Stack benutzen oder ob CALL/RET für die Rücksprungadresse den Stack implizit nutzen können oder ob ein extra Link-Register existieren soll. Beides hat Vorteile und Nachteile, und kann z.B. darüber entscheiden wie Aufwendig das Verschachteln von Interrupts/Exceptions wird.

Es gibt noch jede Menge anderer Design-Entscheidungen die Du treffen musst bevor Du anfangen kannst, z.B. wie Du bedingte Befehlsausführung realisieren willst (mit einem der möglichen Flag-Konzepte oder anders (siehe ALPHA)).


Auserdem will ich für das projekt einen Compiler programmieren, hat wer ne Idee wie man das am besten macht?
Da solltest Du vielleicht mal einen Blick auf den LLVM werfen. Dort gibt es auch Vorlagen für einen Assembler der dann auch Labels usw. beherrscht.


Um mal einen Überblick über die möglichen CPU-Architekturen zu bekommen empfehle ich zuerst den 8Bit-AVR und dann mal den AVR32 (für beides gibt es bei Atmel sehr gute Beschreibungen der Befehlssätze und der OpCode-Architektur). Auch die NIOS-Soft-CPU von Altera ist einen Blick wert vor allem da die Tools mit denen man daraus zusammen mit der Peripherie vollständige Systeme baut recht gut sind (und ebenfalls eine gute Doku für die Befehlsarchitektur vorhanden ist) aber das setzt Kenntnisse in der FPGA-Programmierung voraus.

Falls Du Programme von einem externen Speichermedium laden können möchtest dann ist die Harvard-Architektur IMHO nicht sehr empfehlenswert aber für die ersten Gehversuche ist das sicher keine so schlechte Wahl.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. December 2012, 18:26
Nun ich hab mir jetzt ein paar Gedanken gemacht, und hab mein derzeitiges Konzept überarbeitet.

Ich hab mich für ein Risc-Prozessor mit einer einfachen Harvard-Architektur entschieden.

(http://img5.fotos-hochladen.net/uploads/tmc152x8el.png) (http://www.fotos-hochladen.net)

Es gibt insgesamt 13 allgemeine Register für Rechnungen, zudem noch das AdressPointer-Register (AdressP) , das StackPointer-Register (StackP) und das ProgrammPointer-Register (ProgramP) .
Bei einem JMP Befehl wird im Status-Register die Adresse für die Rom hinein geschrieben und falls die ALU eine 1 zurück gibt wird zu dieser Adresse gesprungen.
Im Instuktion-decoder werden die Befehle der Rom decodiert und an die jeweiligen Module weitergeleitet.

Ich hoffe der Entwurf ist besser wie der alte :-D.

Mfg Tufelix
Titel: Re: Logisim CPU
Beitrag von: Svenska am 02. December 2012, 19:00
Ich sehe da nicht so recht durch und lese da ungefähr folgendes raus:

- Ein Befehl aus dem ROM geht durch ein Befehls-Register zum Instruction Decoder und verschwindet.
- Program-Pointer und Status-Register bilden zusammen den Program-Counter, also eine ROM-Adresse, die vom Ergebnis des letzten Befehls abhängt.
- Die ALU kommuniziert mit dem Program-Pointer, der aber Adresse enthält - keine (ALU-)Befehle.
- Die eigentliche CPU kann den RAM nicht lesen.
- Der RAM kommuniziert mit externer Hardware. Daten werden also immer von der Hardware in den RAM kopiert und umgekehrt. Das ist nicht MMIO, sondern DMA.
- Der Datenbus enthält nur I/O-Daten, ein eigener Adressbus fehlt.
- Die allgemeinen Register sind mit nichts verbunden.

Warum ein JUMP für seine Erlaubnis die ALU fragen soll, ist nachvollziehbar (wenn auch unpraktisch). Wie die ALU aber ihre Entscheidung treffen soll, ist unklar.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. December 2012, 20:33
Zitat
- Ein Befehl aus dem ROM geht durch ein Befehls-Register zum Instruction Decoder und verschwindet.
Nun die Befehle werden Decodiert und an die jeweiligen Module weitergeleitet, also An Ram,Registerblock,Alu...

Zitat
Warum ein JUMP für seine Erlaubnis die ALU fragen soll, ist nachvollziehbar (wenn auch unpraktisch). Wie die ALU aber ihre Entscheidung treffen soll, ist unklar.
Die ALU hätte eigentlich bei einem Sprung die 2 werte subtrahiert und dann über einen Komparator geschaut ob das ergebnis größer, kleiner oder gleich wie 0 ist.Am schluss währe entweder ein true(1) oder ein false(0) an das Statusregister geschickt worden.Naja das ganze ist eigentlich überflüssig...daher werd ich das "vergleichen" direkt in dem Statusregister einbauen(heißt jetzt Jump)

Zitat
Program-Pointer und Status-Register bilden zusammen den Program-Counter, also eine ROM-Adresse, die vom Ergebnis des letzten Befehls abhängt.
Naja der Programm-Counter ist ein Zähler und bei einem Befehl wo was in das ProgrammPointer-Register geschrieben wird(bzw. wenn das Status-Register springt), werden die jeweiligen Daten in den Zähler geschrieben.

Zitat
Die eigentliche CPU kann den RAM nicht lesen.
Joar da hab ich nen Pfeil vergessen :-D.

Zitat
- Der Datenbus enthält nur I/O-Daten, ein eigener Adressbus fehlt.
ein Adressbus wofür?

Zitat
- Die allgemeinen Register sind mit nichts verbunden.
Doch mit der ALU und mit dem RAM da hab ich aber den Pfeil vergessen.

So jetzt nochmal mein verbesserter Entwurf:
(http://img5.fotos-hochladen.net/uploads/jxif7da8l3.png) (http://www.fotos-hochladen.net)

Nochmal zur "Jump"(status-register) funktion, dort werden 2 werte miteinander verglichen und falls die Bedingung für den Sprung stimmt wird die Adresse in den Programm-Counter geschrieben.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 02. December 2012, 22:09
Hallo,

Zitat
- Ein Befehl aus dem ROM geht durch ein Befehls-Register zum Instruction Decoder und verschwindet.
Nun die Befehle werden Decodiert und an die jeweiligen Module weitergeleitet, also An Ram,Registerblock,Alu...
Das fehlt in deinem Bild immernoch. Da ist hinter dem Decoder Schluss.

Die ALU hätte eigentlich bei einem Sprung die 2 werte subtrahiert und dann über einen Komparator geschaut ob das ergebnis größer, kleiner oder gleich wie 0 ist.
Alle drei Fälle sind sinnvoll (Funktionen: Sprung nach vorne, Schleifen: Sprung nach hinten, Endlosschleife: Sprung zu sich selbst), insofern bringt der Vergleich nichts.

Naja der Programm-Counter ist ein Zähler und bei einem Befehl wo was in das ProgrammPointer-Register geschrieben wird(bzw. wenn das Status-Register springt), werden die jeweiligen Daten in den Zähler geschrieben.
Hat das nen Sinn oder möchtest du nur wissen, wieviele Befehle die CPU jetzt ausgeführt hat?

Zitat
- Der Datenbus enthält nur I/O-Daten, ein eigener Adressbus fehlt.
ein Adressbus wofür?
Du hast da vier Ports eingezeichnet... wenn ich jetzt ein "OUT" machen will - welche Hardware soll sich angesprochen fühlen? Alle gleichzeitig?

Schau dir mal den Pinout von (antiken, weil weniger komplex) realen CPUs an. Ein Großteil dessen kann dir in einer Simulation natürlich ziemlich egal sein, aber du siehst dabei ganz gut, welche Verbindungen es von "drinnen" nach "draußen" und umgekehrt gibt. Die unterscheiden sich zwischen Mikroprozessoren (µP) und Mikrocontrollern (µC), sind aber innerhalb einer Klasse ziemlich gleich.

µPs und µCs:
- Taktversorung
- Reset (sinnvoll für definierten Start)

µCs:
- Ports für Hardwarezugriffe

µPs:
- Adress-/Datenbus für RAM und MMIO(*)
- (Harvard-Architektur) Adress-/Datenbus für ROM und Flash(*)
- (optional) I/O-Bus für Hardwarezugriffe(*)
- IRQ- und NMI-Eingang

(*) Die Bussysteme können sich die Pins teilen, d.h. es gibt dann zusätzliche Pins, die angeben, welcher Bus jetzt gemeint ist und ob die Pins als Inputs, Outputs oder High-Impedance geschaltet sind (letzteres trennt die Pins vom Bus ab und ist wichtig, wenn sich zwei andere Geräte über den Bus unterhalten möchten)

Das Konzept von Mikroprozessoren ist flexibler, erfordert aber eine komplexere Bus-Logik. Bei Mikrocontrollern nutzt man meist nur eine Hardware an einem Port oder muss die Bus-Arbitrierung mit mehreren Ports in Software realisieren, wenn man mehr Geräte anschließen möchte. Das Interrupt-Management solltest du dir auch noch überlegen; µPs haben fixe Pins (und oft einen Interruptcontroller), bei µCs sind die Ports selbst in Grenzen in der Lage, Interrupts auszulösen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 03. December 2012, 12:03
Hallo Tufelix,


schau doch mal auf http://en.wikibooks.org/wiki/Microprocessor_Design/Pipelined_Processors (http://en.wikibooks.org/wiki/Microprocessor_Design/Pipelined_Processors) das vierte Bild zeigt eine relativ simple RISC-Pipeline in der recht gut zu erkennen ist wie u.a. das Registerfile eingebunden ist.
(und auch ins eigentliche Buch http://en.wikibooks.org/wiki/Microprocessor_Design (http://en.wikibooks.org/wiki/Microprocessor_Design))

Was Du in deinem Bild mit "RAM" beschreibst sollte eine Art Bus-Master sein der einen externen Bus ansteuert an welchem dann RAM aber auch MMIO-Ports hängen können, so ein Bus benötigt nicht nur die eigentlichen Datenleitungen sondern auch Adressleitungen (die Anzahl dieser Leitungen bestimmt die Größe des Adressraums der CPU) und Steuerleitungen (um z.B. zwischen Lesen und Schreiben unterscheiden zu können). Wenn das was bei Dir mit "ROM" bezeichnet wird ein vergleichbarer Busmaster ist dann kannst Du einfach zwischen Harvard (jeder dieser Busmaster verfügt über ein eigenes System) oder von-Neuman (beide Busmaster greifen auf den selben Bus zu, was natürlich eine Arbitrierung erfordert) umbauen.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 04. December 2012, 16:56
mmh pipelines ist was ganz neues für mich...bisher haben meine cpu's die Befehle mit 1 taktzyklus abgearbeitet. War immer der Meinung das es in Logisim nix bringt.
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 04. December 2012, 19:54
Hallo Tufelix,


die Pipeline entsteht durch die Zwischenregister (die grünen vertikalen Blöcke), einige davon (aber nicht alle!) kannst Du problemlos weglassen und schon hat diese Pipeline weniger Stufen. Solange Du nur innerhalb eines Simulators bleibst der keine Durchlaufzeit durch die Logik hat ist das völlig in Ordnung.

In dem Wikibook gibt es doch auch Single-Clock-CPUs, schau dort mal vorbei.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. December 2012, 17:54

Nun ich hab jetzt mein konzept wieder einmal verbessert. :-D

(http://img5.fotos-hochladen.net/uploads/gnr0c9plky.png) (http://www.fotos-hochladen.net)
Legende:
Weiße Bauteile= I/O Ports.
Hellblau = Ram-Speicher( hab mal 2 Ram-Speicher eingebaut, den eigentliche Ram und der Speicher der Portx und DIRx werte der I/O-Ports.).
Blau = Registerblöcke.
Orange = Rechen- und Jump-einheiten.
Grün = Alles Was mit den Befehlen zu tun hat.

Schwarzer Pfeil = Daten.
Roter Pfeil = Decodierte Befehle.
Blauer Pfeil = Adressen.

Erklärung:


Programm-Counter:
Der zeigt auf die nächste Adresse in der Rom, kann aber auch mit werten gefüttert werden( Das passiert z.b. bei einem Sprung).

Die ROM:
Eine Einfache Rom die , die Befehle für den CPU enthält, die Adresse für die Rom kommt vom Programm-Counter.

Befehls-Register
Enthält den Befehl der gerade ausgeführt wird.

Instruktion Decoder
Decodiert den Befehl und schickt ihn an den
einzelne Komponenten.
In meine Decoder gab es bisher immer für jede Instruktion (also die Argumentbits wie Mov,ALU,JMP...) eine sogenannte Programmierbare Instruktion-Unit. Über spezielle eingänge konnte man bestimmen wann sie sich aktivieren sollte, was sie an die Ausgänge des Decoders schicken Sollte außerdem konnte sie man so programmieren das sie bei einem bestimmten Registern ein ausgang-bit aktiviert(z.b. wenn im Programm-Pointer was reingeschrieben wird hätte sie dann den Programm-Counter zum schreiben freigegeben). Gibt es bessere Möglichkeiten die so übersichtlich sind aber mehr freiheit bietet?
 
ALU
verrechnet 2 Register und Speichert dann das Ergebnis im Drain-Register.

JUMP
Vergleicht 2 Register und wenn die Bedingungen erfüllt sind schreibt er die Adresse die im Befehl angegeben ist in den Programm-Counter.

I/O( das hellblaue)
Enthält alle Dirx und PORTx werte der I/O Ports.
Wird genauso angesprochen wie der Ram.

So noch ihrgentwelche Fragen bzw Kritik ?

MfG Tufelix

Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 05. December 2012, 18:40
Hallo Tufelix,


Nun ich hab jetzt mein konzept wieder einmal verbessert.
Ja, also die Richtung stimmt schon mal, nur weiter so.

Das "JUMP" zwei Register vergleichen kann ist recht gut, auf diese Weise kannst Du Dinge wie "if (a > b) then ..." ziemlich effizient umsetzen und kannst Dir die Flags komplett sparen. Wimre waren in der offiziellen Spec der ALPHA-CPU sogar einige Beispiele drin wie man sowas geschickt einsetzen kann, das ist zwar eher für Compiler-Programmierer interessant aber dürfte einen angehenden CPU-Entwickler sicher auch nicht schaden.

Wozu der Programm-Counter zweimal vorhanden ist (einmal einzeln oben rechts und einmal im Registerfile unten) verstehe ich nicht. Du kannst den aktuellen Programm-Counter durchaus als "normales" Register anbieten aber er sollte trotzdem nur an einem Ort gespeichert sein. Wenn der Programm-Counter als normales Register ansprechbar ist musst Du erstmal definieren was für einen Wert ein Befehl daraus lesen kann, z.B. seine eigene Adresse (das ist super toll für positionsunabhängigen Code und ein paar andere Nettigkeiten). Auch musst Du definieren was passieren soll wenn auf dieses Register geschrieben wird, z.B. das die Pipe-Line geleert werden soll und an der neuen Adresse im ROM weiter gearbeitet wird womit Du nahezu jeden Rechenbefehl als JUMP benutzen kannst und z.B. ein simpler "MOV ProgCount,LinkReg" als RET-Befehl funktioniert (spart Dir wertvolle OpCode-Bits ein da es so keinen eigenständigen RET-Befehl gibt). Außerdem ist dann ein unbedingter JUMP nur ein "LI ProgCount,&Label" (also ein normaler Load-Imediate den Du eh brauchst um Konstanten in ein beliebiges Register zu laden).

Das Du I/O als RAM bauen möchtest verstehe ich nicht, bei mancher Hardware ist so ein I/O-Register gar kein echtes Speicherelement sondern der Schreibzugriff startet einfach nur eine Aktion in der Hardware welche durch den übermittelten Wert selektiert wird (also eine Art Commando-Port, Lesezugriffe auf diesen Port liefern oft nichts oder einen reinen Status-Wert). Ich würde Dir doch noch mal empfehlen an die Stelle von RAM und I/O einen richtigen Bus-Master zu setzen der dann mit seinem Bus eben RAM aber auch beliebige Memory-Mapped-Hardware ansprechen kann.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. December 2012, 19:42
Nun wie funktioniert eigentlich so ein Busmaster ? :D
Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. December 2012, 23:06
Hallo,

stellt sich die Gegenfrage: Was ist ein Bus? :-)

Einfache, parallele Bussysteme bestehen aus drei Komponenten:

Hast du diese Bestandteile, kann die CPU auf den angeschlossenen Adressraum (RAM, MMIO) zugreifen. Allerdings geht dann jeder Buszugriff von der CPU aus (die CPU ist der Busmaster). Es gibt übrigens drei Zustände, die jede Leitung haben kann: "High" (logisch 1), "Low" (logisch 0) und "High-Impedance"/"Tri-State" (nicht angeschlossen). Wenn ein Gerät ein High schreibt und ein zweites Gerät ein Low, ist das Ergebnis Müll, im schlimmsten Fall ein Kurzschluss (es gibt allerdings auch Bussysteme, die anders funktionieren - z.B. I²C). Geräte am Bus haben also die Adressleitungen und R/W als Input und die Datenleitungen als Tri-State, bis sie angesprochen werden - dann schalten sie die Datenleitungen entsprechend um.

Sollen sich zwei Geräte direkt miteinander unterhalten können (z.B. ein DMA-Controller und der RAM), musst du eine Busarbitrierung haben. Das kannst du mit zwei Leitungen machen: BUSREQ/BUSACK. Wann immer ein Gerät, welches nicht die CPU ist, auf den Bus schreiben möchte, muss es die Leitung BUSREQ (Bus Request) aktivieren und warten. Die CPU aktiviert dann die Leitung BUSACK (Bus Acknowledge) und trennt ihre eigenen Adress- und Datenleitungen vom Bus ab (Tri-State), bis BUSREQ wieder Low ist. Solange ein Gerät also BUSREQ aktiviert hält und BUSACK von der CPU auf High gehalten wird, darf es auf dem Bus tun und lassen, was es will. Die CPU ist also nach wie vor der Chef auf dem Bus, aber andere Geräte dürfen ihn auch benutzen, also temporär den Status des "Busmasters" übernehmen.

In dieser Darstellung ist es hilfreich, die CPU als Ganzes mit den Verbindungen zu ihrer Außenwelt zu sehen. Wie die CPU intern aufgebaut ist, ist schließlich der Umgebung egal - eine CPU liest und schreibt Adressen, mehr nicht (d.h.: liest/schreibt RAM, liest ROM, liest/schreibt MMIO-Geräte).

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 06. December 2012, 00:08
Hallo,


Nun wie funktioniert eigentlich so ein Busmaster?
Das ist im wesentlichen eine Bridge die zwischen der internen Art wie die CPU auf Speicher zugreift in das Protokoll übersetzt welches auf dem externen Bus benutzt wird.
Schau Dir doch mal an wie die Klassiker wie ISA o.ä. funktionieren.
Zu den CPUs aus der Altersgruppe 386 und 486 gibt es im iNetz bestimmt eine ansprechende Beschreibung wie ein ordentlicher 32Bit-Bus funktioniert.
Und wenn Du dann das Niveau "fortgeschritten" erreicht hast ist PCI oder besser PCI-Express auch eine interessante Lektüre ;) (mal davon abgesehen das diese Spezifikationen nicht frei erhältlich sind, aber die iNetz-Suchmaschine Deines persönlich geringsten Misstrauens kann Dir bestimmt weiterhelfen, ansonsten ist Hypertransport guter Lesestoff, aber Vorsicht: alle diese Specs haben etliche hundert Seiten).

edit:
Für den Anfang ist aber z.B. der 8Bit-AVR eine gute Vorlage, wimre gab es auch dort Versionen die externen SRAM (und auch passende MMIO-Hardware) anbinden können. Üblicherweise liefert Atmel sehr gute (und frei verfügbare) Datenblätter in denen bestimmt sehr anschaulich beschrieben ist wie dieser externe Bus arbeitet also wie ein Zugriff auf externen Speicher abläuft und wie das vom CPU-Kern benutzt wird.


... musst du eine Busarbitrierung haben. Das kannst du mit zwei Leitungen machen: BUSREQ/BUSACK.
Fast richtig, jedes busmasterfähige Gerät benötigt natürlich ein eigenes BUSREQ/BUSACK-Pärchen. SCNR
Theoretisch kann man sogar diese Arbitrierungslogik als eigenständige Komponente bauen und die CPU benötigt dann ebenfalls BUSREQ/BUSACK um den Bus bekommen zu können (aber üblicherweise wird die Arbitrierungslogik einfach in die CPU integriert und deren BUSREQ/BUSACK-Leitungen gehen nur im Chip vom CPU-Kern zum Arbiter). Bei besseren Systemen berücksichtigt der Arbiter auch Prioritäten damit z.B. die CPU nicht so lange warten muss bis sie mal wieder ran darf aber fürs erste geht es auch ohne solche Extras.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: OS_3000 am 06. December 2012, 14:50
Ich selber beschäftige mich schon seit einiger Zeit mit dem "virtuellen Prozessorbau".
Allerdings nicht in einer Logiksimulation sondern in Form von zellulären Automaten.

Derzeit baue ich einen sehr einfachen Neumann 32Bit RISC Prozessor.
Grob inspiriert wurde ich ursprünglich von den Pic-Mikrocontrollern von Microchip. (So änlich wie die Avrs. Ich persönlich verwende ausschießlich solche, was aber hauptsächlich Geschmackssache ist.)

Das Design habe ich als Pdf angehängt. Vielleicht enthält es wiederrum für dich die eine oder andere Inspiration.  :wink:
Spezielle Befehle wie Goto\If\In\Out gibt es darin nicht. Die Peripherie wird auf die selbe Weise angesprochen wie der Speicher. ("Memory-Mapped-Hardware" wie es erik.vikinger genannt hat)

Der Programmcounter ist (fast) ein ganz normales Register. Beim Sprung wird einfach der Registerwert neu gesetzt, genauso wie beim Setzten eines X-beliebigen anderen Registers.
Stackpointer und co sind wegrationalisiert. Entweder wird der Stack softwaremäßig emuliert oder der Rücksprung wird einfach durch "goto"-Konstrukte ersetzt. Das sollte dann der Compiler erledigen können. Das es später einmal einen hardwaremäßigen Stack gibt, schließe ich jetzt auch nicht hundertprozentig aus.

Der Bus sieht bei mir so aus:
Eine Anfrage besteht aus Befehl, Adresse und Daten\Feedback. (Daten beim Schreiben\Feedback beim Lesen)
Nun werden die Anfragen im Scheduler zwischengespeichert(Queue) und weitergegeben sobald das "Gerät", das in dem Adressbereich liegt, bereit ist.
Das "Gerät" speichert entweder die Daten an der Adresse oder es liest an der Adresse und schickt die gelesenen Daten wieder zurück mit dem angehängten Feedback. Was es tut, hängt vom Befehl ab.
Die Komponente die die Anfrage gestellt hat erkennt an dem Binärcode im Feedback, dass jetzt die Daten kommen, die es angefordert hat.

Da es in Logiksim aber scheinbar keine Durchlaufzeit gibt, kann man das wahrscheinlich deutlich einfacher gestallten.
Eine umfangreiche Komponente die die ganzen Anfragen "managt" kann man sich dann auch sparen.
Das alles passiert in meinem Fall seriell. In der Realität und auch Logiksim ist es parallel eher geschickter.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 07. December 2012, 21:03
nun ich hab jetzt ein Paralleles Bussystem mit passive Komponenten entworfen
(http://img3.fotos-hochladen.net/uploads/bus4tapof5h60.png) (http://www.fotos-hochladen.net)
Legende :
Schwarzer Pfeil = Daten.
Blauer Pfeil = Adresse.
Roter Pfeil = Befehle.
grüner Pfeil = Aktivierungsadresse

Verteilung der Adresse:
0-16 Register.
16-2064 Stack und Framepointer.
2064-2096 I/O ports,
Der Rest ist ist Ram.


Nun um etwas in ein Register der CPU bzw. etwas herraus zu laden gibt es 2 Spezial Befehle.
Um etwas von einer Komponente zu einer anderen Komponenten zu laden setzt man einfach den aktivierungs-Adresse vom DME-Modul auf die Quelladresse bzw auf eine Zieladresse und dann ladet man die werte( für das Werte laden gibts 2 Befehle, der eine nimmt den aktivierungsadresse als ziel und der Andere Als quelle).

MfG tufelix
Titel: Re: Logisim CPU
Beitrag von: Svenska am 08. December 2012, 00:00
Hallo,

das sieht auf jeden Fall so aus, als ob es funktionieren könnte. Ein paar Anmerkungen:
- Wofür steht DME? :-)
- Warum hast du einen eigenen Instruktionsbus? Instruktionen sind doch auch nur Daten.
- Framepointer und Stackpointer sind genau zwei Pointer, die brauchen also auch zwei Register, um gespeichert zu werden. Außerdem kann man die auch in die CPU einbauen und muss sie dann nicht an den Bus anschließen.
- Register sind Teil der CPU, brauchen also keine (Bus-)Adressen besitzen. Innerhalb der CPU natürlich schon, aber da hast du natürlich andere Adressen.

Die Systemstruktur kannst du auch deutlich einfacher gestalten, ich häng unten mal ein schnell gekliertes Bild ran. Erklärung: A=Adressleitungen, D=Datenleitungen, Clk=Taktleitung, R/W=Read/Write (0=Read, 1=Write) und I/O ist mit MMIO angebundene Hardware. Die Busbreiten (24-Bit-Adressbus, 8-Bit-Datenbus) sind nur ein (unpraktisches) Beispiel.

Ein 24-Bit Adressbus erlaubt 16M verschiedene Adressen, bei 8-Bit-Daten ist das dann ein Adressraum von 16 MB. Wie du den aufteilst, ist deine Sache, eine Möglichkeit ist:
- 00xxxxxx xxxxxxxx xxxxxxxx (unteres Viertel, 0 bis 4M): ROM (max. 4 MB)
- 01xxxxxx xxxxxxxx xxxxxxxx (4M bis 8M): Hardware-Register für MMIO (max. 4 MB)
- 1xxxxxxx xxxxxxxx xxxxxxxx (obere Hälfte, 8M bis 16M): RAM

Die CPU ist in diesem Beispiel der einzige Busmaster (ansonsten bräuchtest du noch BUSREQ/BUSACK, wie oben beschrieben). Um Code oder Daten zu lesen, macht die CPU nun beispielsweise folgendes:
- CPU legt Adresse auf die Adressleitungen
- CPU legt R/W-Leitung auf Low (CPU will lesen)
- CPU legt Taktleitung auf High (Adressen sind jetzt gültig)
- alle Geräte am Bus dekodieren die Adresse (prüfen, ob sie die Adresse besitzen)
- das angesprochene Gerät legt die gewünschten Daten auf den Datenbus
- CPU legt Taktleitung auf Low und liest die Daten ein
Der Takt muss natürlich langsam genug sein, dass die Geräte schnell genug reagieren können.

(http://img5.fotos-hochladen.net/uploads/bus07bcguyez4.png)

Nachtrag: Kann man eigentlich Bilder ins Forum hochladen? :-)

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 09. December 2012, 19:59
Nun braucht man den eigentlich diese BUSACK-leitung überhaupt? Die Befehle aus der Rom werden ja Zeile für Zeile abgearbeitet. Wenn in der Zeile jetzt steht das ein I/O port- seinen wert in den Ram laden soll, muss das doch nicht von dem CPU abgesichert werden. Weil die CPU ja in diesem Moment nix ausführt.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 09. December 2012, 20:16
Hallo,

du brauchst kein BUSREQ/BUSACK, wenn alle Aktivitäten auf dem Bus von einem Gerät ausgehen. Für solche netten Features wie DMA (allgemeiner: mehrere möglichen Busmaster) brauchst du aber eine Form von Busarbitrierung. Sind aber nicht unbedingt notwendig.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 11. December 2012, 16:25
nun wie würde der bus bei einem cics-CPU ausehen ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 11. December 2012, 23:21
nun wie würde der bus bei einem cics-CPU ausehen ?
Vier Räder, große Fenster, viele Sitze, ... wie ein Bus halt. :roll:
Titel: Re: Logisim CPU
Beitrag von: LittleFox am 11. December 2012, 23:47
Svenska, du kannst nicht sinnvolle Beiträge schreiben? Da hätte ich dir irgendwie nicht zugetraut^^

@Tufelix AFAIK nicht anders als bei einem RISC, der Unterschied ist ja wimre dass die CPU mehr Befehle unterstützt die auch alle mächtiger sind, aber auch mal länger als einen Takt brauchen (können)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 11. December 2012, 23:54
Das sollte subtil darauf hinweisen, dass die Frage ... nicht so toll war.
Ein Bus transportiert Menschen. Dem ist es relativ egal, wie die aussehen.
Ein Bus transportiert Daten. Dem ist es relativ egal, was da angeschlossen ist (schließt die CPU ein).
Hauptsache, man hält sich an die für den Bus gültigen Protokolle (Fahrschein bezahlt, Adressen vollständig dekodiert, ...)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. December 2012, 12:23
Die Datenleitung des Bus (der im Computer und nicht der auf der Straße ) wird auch für den "Transport" von Befehlen für CPU genutzt, oder? 
Titel: Re: Logisim CPU
Beitrag von: LittleFox am 13. December 2012, 13:23
ja
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. December 2012, 17:10
Mhh wie funktioniert das ohne die Datenleitung dauerhaft zu blockieren? Werden die Befehle da zunächst in eine art Speicher in der CPU geladen und dann ausgeführt?
Titel: Re: Logisim CPU
Beitrag von: LittleFox am 13. December 2012, 17:12
ja^^
Titel: Re: Logisim CPU
Beitrag von: Svenska am 13. December 2012, 23:46
Die Datenleitung des Bus (der im Computer und nicht der auf der Straße ) wird auch für den "Transport" von Befehlen für CPU genutzt, oder?
Bei einer von-Neumann-Architektur: Ja. Bei einer Harvard-Architektur: Nein, dort werden verschiedene Busse für Befehle und Daten genutzt.

Mhh wie funktioniert das ohne die Datenleitung dauerhaft zu blockieren? Werden die Befehle da zunächst in eine art Speicher in der CPU geladen und dann ausgeführt?
Ja, diese "Art Speicher" nennt man üblicherweise Register.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 14. December 2012, 14:05
Also ich wollte eigentlich einen Parallelen externen Bus verwenden (der zwischen CPU, RAM und I/O-Ports) der nur eine Daten- und 1 Adressleitung hat. Wenn man jetzt eine Festplatte an einem I/O Ports anschließt wie kommen dann die Befehle zur CPU ohne das die ganze Zeit die Datenleitung von der Festplatte belegt wird. Ein Register kann doch nur 1 Befehl aufnehmen oder ? Ich wollte da jetzt eigentlich so was wie eine Befehls-Cache einbauen.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 15. December 2012, 00:51
Hallo,

was du da geschrieben hast, ist Müll.

Du hast nicht verstanden, wie Bussysteme funktionieren. Bitte arbeite dich in die Thematik ein und schaue dir reale Bussysteme an, ehe du versuchst, ein eigenes zu entwickeln.
Du hast nicht verstanden, wie Hardware funktioniert. Arbeite dich mal in die Materie ein, damit du ein Gefühl dafür kriegst, wie Hardware funktioniert. Am besten, du schreibst einen Treiber für eine etwas kompliziertere Hardware (z.B. IDE), ohne int 21h (DOS) und int 13h (BIOS) zu benutzen. Muss ja kein ganzes Betriebssystem werden.

Übrigens: Seriell = eine Leitung, parallel = mehrere Leitungen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 16. December 2012, 12:28
Oje  :-(, was ist den genau an meinem konzept falsch?

Hab mich hier informiert über Busse informiert und mein Konzept auch so gestaltet : http://de.wikipedia.org/wiki/Bus_%28Datenverarbeitung%29

Mhh ein Treiber für den IDE Controller... naja ich versuchs mal.  :-D
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 17. December 2012, 18:15
Hallo Tufelix,


Oje  :-(, was ist den genau an meinem konzept falsch?
Ich glaube ebenfalls das Deine Vorstellung davon wie Hardware funktioniert noch nicht so ganz richtig ist, ebenso von dem Zusammenspiel zwischen Software und Hardware.

Keine Hardware-Komponente hat eine exklusive Verbindung zur CPU, ist spätestens bei mehreren CPUs auch Unsinn. Ein Bussystem in einem Computer stellt die Verbindung zwischen 2 Komponenten immer nur für eine kurze Zeit her damit diese 2 Komponenten eine kleine Hand voll Daten in eine der beiden Richtungen austauschen können. Ein solcher Austausch wird üblicherweise Transfer genannt und stellt einen in sich abgeschlossenen Lesezugriff oder Schreibzugriff dar (pro Zugriff kann aber mehr als ein Byte oder ein Word übertragen werden, das nennt sich dann Burst oder Block-Transfer). Für alles was komplexer ist werden mehrere unabhängige Transfers benutzt (wo dazwischen sogar der Bus von anderen Komponenten benutzt werden kann). In dem von Dir verlinkten Wikipedia-Artikel gibt es gar keine Beschreibung wie ein Datenbus in einem Computer im Detail funktioniert, dafür ist dort der NuBus verlinkt und in dessen Wikipedia-Artikel ist die zugehörige Spezifikation verlinkt. Das sind relativ wenige Seiten Text und der NuBus ist vom Feature-Umfang noch recht überschaubar und würde ungefähr das bieten was Du aktuell brauchst (was jetzt keine Aufforderung sein soll diesen Bus umzusetzen sondern das ist nur ein Hinweis auf eine Technologie in ungefähr der benötigten Gewichtsklasse). Ich hab mir die Spezifikation gerade mal durchgelesen und empfinde die als einigermaßen verständlich geschrieben und es sind auch keine zu komplexen Sachen drin (der NuBus kennt z.B. keine Bridges u.ä. so das es immer nur einen einzigen NuBus in einem System gibt was die Sache fürs erste unheimlich vereinfacht).

Ein Bussystem in einem Computer ist im Ideal absolut agnostisch gegenüber allen angeschlossenen Komponenten und auch diese Komponenten sollten möglichst agnostisch gegenüber dem Rest der Komponenten sein (außer das alle Komponenten natürlich das Protokoll auf diesem Bus beherrschen müssen wissen die üblicherweise nichts über alles was sonst noch so an diesem Bus hängt) auch die CPU interessiert sich nicht dafür was wo ist und wie diese Komponenten funktionieren (das ist Aufgabe der Software also der Gerätetreiber die ihr jeweiliges Gerät gegenüber einer generischen Schnittstelle im Betriebssystem passend darstellen), die CPU muss dazu nur Befehle wie Speicherlesen und Speicherschreiben beherrschen (und das dann natürlich mit dem richtigen Protokoll auf den Bus bringen) damit die Software das kann.


Mit einem IDE-Treiber würde ich nicht als erstes anfangen, ich würde eher die Serielle Schnittstelle als Anfang empfehlen obwohl da leider die Gefahr besteht das Du sowas gar nicht mehr in Deinem PC hast (was aber auf IDE ebenfalls zutrifft, falls Du im BIOS bereits auf AHCI-Modus umgestellt hast). Es geht natürlich auch irgendein Emulator (Qemu/VirtualBox/...) die können alle noch eine echte Serielle Schnittstelle anbieten und diese auch im Host-OS als virtuellen Port zur Verfügung stellen so das auf dem Host-System wieder ein Programm (das natürlich die API des Host-OS benutzen muss) der passende Kommunikationspartner ist.
Für den zweiten Schritt ist IDE aber eine gute Wahl wobei ich hier auch auf einen Emulator setzen würde (schon damit Du nicht aus Versehen Deine echte HDD killst).


Grüße
Erik


Vier Räder, große Fenster, viele Sitze, ... wie ein Bus halt. :roll:
Also hier in Nürnberg haben die meisten Busse mehr als 4 Räder (also auf der Straße, zusätzlich zu Lenkrad und Reserverad). Dafür sind die Fenster nur noch eingeschränkt nutzbar da die von Außen mit Spam zugekleistert sind.
SCNR
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 21. December 2012, 17:27
So hab jetzt mal ein komplettes Konzept gemacht: (hab einen roten Pfeil zum Adress-rechenwerk vergessen )
(http://img3.fotos-hochladen.net/uploads/aufbauohx46z2b9l.png)
roter Pfeil = Steuer-Daten.
Blauer Pfeil = Adressen
Schwarzer Pfeil = Daten

Habe mich für eine einfache Harvard-Architektur für den Bus entschieden.
Ich hab jetzt mal den Ram in die CPU integriert. Dadurch kann ohne einen System-bus (also BREQ und BGRT ) zum Beispiel Daten vom Ram in ein I/O-Port laden.
Zudem habe ich meine alte CPU-architektur verwendet und ein paar verbesserungen durchgeführt. Zum Beispiel gehört jetzt der ProgrammCounter (ProgrammP) zu den Registern. Es gibt immernoch die alten Pointer-Register ( Stack-, Frame und Adresspointer) nur wird jetzt die adresse im Adress-Rechenwerk zusammengesetz.(hab mir das so gedacht das man wählen kann ob frame und Stackpointer die adresse angeben oder das der adresspointer allein die adresse angibt.
Und wie findet ihr fiesmal mein Konzept :D
Titel: Re: Logisim CPU
Beitrag von: Svenska am 21. December 2012, 21:25
Hallo,

Habe mich für eine einfache Harvard-Architektur für den Bus entschieden.
Für die CPU, nicht für den Bus. :-)

Ich hab jetzt mal den Ram in die CPU integriert. Dadurch kann ohne einen System-bus (also BREQ und BGRT ) zum Beispiel Daten vom Ram in ein I/O-Port laden.
Hmm, also BREQ/BGRT brauchst du nur, wenn dein Bussystem multimasterfähig sein soll. Lässt du die Signale weg und definierst einen fixen Master (die CPU), ist es trotzdem ein Bus. Es ist sogar ein System-Bus, weil du nur einen Typ von Adressen kennst und daran alles, inklusive der Register, angeschlossen ist. Praktisch heißt das, dass für das Betriebssystem kein Unterschied zwischen CPU-Registern und RAM mehr besteht.

Für gewöhnlich baut man CPUs mit einem externen Bussystem nach außen (zu RAM und Hardware, oft multimasterfähig) und einem internen Bussystem, welches die Register, ALU, Befehlsdecoder usw. miteinander und mit dem externen Bussystem verbindet. Das macht man, damit die Hardware - einen Treiber vorausgesetzt - unabhängig von der CPU funktionieren kann (z.B. gibt es den EISA-Bus auf x86- und MIPS-Maschinen und den PCI-Bus auf x86, x86_64, ARM, PowerPC u.v.m.). Die Hardware hat es nicht zu interessieren, welche Register die CPU nun hat.

Dein Konzept sieht jedenfalls nach außen funktionsfähig aus. Den internen Aufbau hätte ich anders gelöst, aber es sollte funktionieren. Durch die fixe Verdrahtung von ProgramP an das ROM und ROM an den Befehlsdekoder sind Disketten/Festplatten für Programme aber nutzlos.

fiesmal
Ne, ich denke, diesmal brauch ich nicht fies sein. Ist ja Weihnachten und so. :-)

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 22. December 2012, 12:00
Nun, sollte eigentlich das Konzept für ein Micro-Controller sein (hab in "Hirn X73" getauft ), da ist es glaub nicht so wichtig ob das externe Bus-system unabhängig vom CPU läuft oder ?  :-D
Titel: Re: Logisim CPU
Beitrag von: Svenska am 22. December 2012, 23:25
Hallo,

Microcontroller haben üblicherweise keinen externen (d.h. nach außen geführten) Bus, sondern Ports. Trotzdem müssen sie einen (oder mehrere) internen Bus, über den die Komponenten miteinander kommunizieren. Stell dir einfach einen Mikrocontroller als einen Mikroprozessor (CPU) mit eingebauter Zusatzhardware vor...

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 25. December 2012, 11:28
Mhh, ich glaub ich bau doch ein Micrp-Computer... gibt es eigentlich neben Logisim und als Zellulärer Automat noch andere Möglichkeiten wo man mein Projekt umsetzen könnte ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 25. December 2012, 20:22
Hallo,

das hängt davon ab, was du genau möchtest... für eine Simulation von Logik mit Gattern habe ich mal KLogic benutzt (taugte aber nicht viel), KSimus wirkte stabiler, aber komplizierter. Kannst dich ja hier (http://www.mikrocontroller.net/articles/Schaltungssimulation) mal umschauen. Die professionellere Variante - mit grausamer Lernkurve - geht dann in Richtung CPLD-/FPGA-Programmierung mit VHDL oder Verilog. Auch dafür gibt es Simulatoren, aber da hält sich meine Erfahrung in Grenzen. Damit läufst du in Richtung "CPU" mit ein bisschen angebastelter Hardware (RAM, LEDs o.ä.).

Wenn du eher in Richtung "Computer" laufen möchtest (also Hardware wie Display/Tastatur/... mit einer programmierbaren CPU drin), dann gibt es dort die teure und sehr aufwändige Möglichkeit, alles diskret mit z.B. 74xx-Bausteinen aufzubauen (Beispiele hier (http://mycpu.eu/) oder hier (http://www.homebrewcpu.com/)). Das läuft aber eher auf Jahre statt Monate hinaus. Dann kannst du auch fertige Mikrocontroller (z.B. einen oder mehrere AVR) nehmen, die CPU in Software simulieren und eine Hardwareplattform außenrum zimmern (siehe z.B. hier (http://www.mmk64.de/), aber das ist schon recht extrem). Zu guter Letzt kannst du auch eine alte, vorhandene CPU-Architektur (z.B. Z80, 68000, 6502) nehmen und eine Hardwareplattform darum aufbauen. Fakt ist aber, dass du nicht weit über die Leistungsklasse der 80er Jahre hinauskommst (d.h. irgendwo bei 4 MB RAM und 16 MHz ist dann die Schmerzgrenze erreicht).

Musst mal schreiben, was du überhaupt bauen möchtest.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 26. December 2012, 00:10
Nun will eigentlich schon was richtung Computer bauen, soll aber nur maximal so komplex sein wie ein apple 1.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 26. December 2012, 02:36
Ersetze mal "Apple 1" durch "C64" oder "CP/M-basierender Heimcomputer der 80er", dann ist das vermutlich einfacher.

Schreib mal auf, was du konkret willst:
- Was soll es können? Das solltest du am Anfang relativ genau wissen (kannst es ja später noch ändern), aber das ist dein Ziel - und gibt an, wann das Projekt "fertig" ist.
- Was kannst du? Wenn du dich in jedes Thema einarbeiten musst, kannst du für komplexere Themen gern mal 1-2 Monate zusätzlich veranschlagen, bis du weißt, was du wie tun kannst, damit es funktioniert.
- Soll es eine Hardware werden oder eine Simulation? Ersteres kann ziemlich ins Geld gehen und ist viel mehr Aufwand, dafür ist die Freude am Ende größer. Setzt natürlich auch Messgeräte voraus (2 gute Multimeter sind Minimum) und ein Grundverständnis von Elektro-/Digitaltechnik (also U, I, R, C, L, Tri-State, PullUp-/PullDown-Widerstände und sowas).

Erst wenn du das Ziel kennst, solltest du loslaufen - den Weg findest du notfalls unterwegs.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 26. December 2012, 13:07
Zitat
- Was soll es können? Das solltest du am Anfang relativ genau wissen (kannst es ja später noch ändern), aber das ist dein Ziel - und gibt an, wann das Projekt "fertig" ist.
Nun ne einfache Textausgabe mit ner Tastatureingabe würde mir reichen.

Zitat
- Was kannst du? Wenn du dich in jedes Thema einarbeiten musst, kannst du für komplexere Themen gern mal 1-2 Monate zusätzlich veranschlagen, bis du weißt, was du wie tun kannst, damit es funktioniert.
Einiges, z.b das Ohmsche Gesetz, die Logik-Gatter , einigermaßen C++, grundkenntnisse im Löten zudem hab ich hier http://www.netzmafia.de/skripten/index.html fast alle Skripte im Thema Hardware und Betriebsysteme gelesen.

Zitat
- Soll es eine Hardware werden oder eine Simulation? Ersteres kann ziemlich ins Geld gehen und ist viel mehr Aufwand, dafür ist die Freude am Ende größer. Setzt natürlich auch Messgeräte voraus (2 gute Multimeter sind Minimum) und ein Grundverständnis von Elektro-/Digitaltechnik (also U, I, R, C, L, Tri-State, PullUp-/PullDown-Widerstände und sowas).
Mhh Hardware wäre natürlich am schönsten, leider habe ich weder einen Lötkolben noch ein Netzteil oder ein Multimeter (wird aber ihrgentwann so sein das ich mir wegen der Schule die sachen zulegen werde.). Daher wird es wohl zunächst auf den simulator hinaus laufen.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 27. December 2012, 02:11
Hallo,

für ne Hardware würde ich dir dann nen AVR mit HD44780 (Textdisplay) und ein paar I/O-Pins für eine PS/2-Tastatur empfehlen. Damit eine Textausgabe zu programmieren ist relativ einfach. Ob das dann allerdings als "Computer" zählt...

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 27. December 2012, 13:49
Nun wie schwer wird es nen Einplatinen-Computer aufzubauen ?
Und wieso ist das eigentlich komplexer wie ein C64 ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 27. December 2012, 16:40
Hallo,

Nun wie schwer wird es nen Einplatinen-Computer aufzubauen ?
Welche Randbedingungen? :-) "moderner Mikrocontroller + Spannungsregler + Peripherie" reicht aus. Wenn du einen richtigen Mikroprozessor benutzen möchtest, kommen da noch mindestens Chips für Taktversorgung, I/O, Timer, RAM und ROM dazu, ehe das System funktioniert. Das ist dann schon ziemlich viel Aufwand.

Und wieso ist das eigentlich komplexer wie ein C64 ?
Ist es nicht, wenn du heutige Technologien verwendest. Ein STM32 braucht fast keine externe Beschaltung und bildet den Kern - Displayansteuerung und Tastatur sind dann nur noch Software.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 29. December 2012, 15:21
Nun ich kann ja mal versuchen sowas zu bauen...
Für den Controller nehme ich einen Propeller-Chip von Parallax. An seinen Ports schließe ich einfach den VGA und den PS/2 anschluss an und regle den rest mit der software.
Mein einzigste Problem ist neben der Fehlenden Ausrüstung das ich noch nicht ganz die Vertikale und Horizontale Synchronisation-Pins im VGA Anschluss verstehe, werden da die bits über mehrende Takt-Zyklen transportiert ?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 30. December 2012, 21:49
Hallo Tufelix,


Für den Controller nehme ich einen Propeller-Chip von Parallax.
dann schau Dir mal das an: http://www.linusakesson.net/scene/turbulence/ (http://www.linusakesson.net/scene/turbulence/), damit Du weist wo die Messlatte hängt. ;)
Der Typ hat auch was ähnliches mit nem AVR gemacht (findest Du bestimmt auf seiner Seite).

das ich noch nicht ganz die Vertikale und Horizontale Synchronisation-Pins im VGA Anschluss verstehe, werden da die bits über mehrende Takt-Zyklen transportiert?
VGA arbeitet analog, das bedeutet das die (Farb-)Information im Spannungspegel (üblicherweise zwischen 0,0V und 0,7V) enthalten ist.


Zu Deiner CPU kann ich nur empfehlen das Du erst mal versuchen solltest ein System mit maximal 8 Tastern und maximal 8 LEDs und ein ganz klein wenig Software (kein RAM oder sonstige Peripherie) zum Laufen zu bekommen, damit Du eine bessere/konkretere Vorstellung davon bekommst was Du eigentlich tun willst.


Erst wenn du das Ziel kennst, solltest du loslaufen - den Weg findest du notfalls unterwegs.
Full ACK, vor allem zum zweiten Teil. ;)


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 31. December 2012, 00:23
Erst wenn du das Ziel kennst, solltest du loslaufen
Dann hätte ich bis heute noch keinen Kernel gebastelt...
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 31. December 2012, 15:30
Erst wenn du das Ziel kennst, solltest du loslaufen
Dann hätte ich bis heute noch keinen Kernel gebastelt...
Es fällt mir tatsächlich etwas schwer das komplett zu glauben.
Oder wolltest Du anfangs einfach nur ein besseres Terminal-Programm entwickeln? ;)
Titel: Re: Logisim CPU
Beitrag von: kevin am 31. December 2012, 16:26
Ich? Ich wollte einfach einen Kernel schreiben. Mit nicht näher definiertem Umfang und zu keinem Zweck. Because I can. (Oder eigentlich konnte ich es nicht... ;))
Titel: Re: Logisim CPU
Beitrag von: Svenska am 31. December 2012, 16:45
Ich? Ich wollte einfach einen Kernel schreiben.
Ist das kein Ziel? :-)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. January 2013, 00:11
Nun...
Zitat
VGA arbeitet analog, das bedeutet das die (Farb-)Information im Spannungspegel (üblicherweise zwischen 0,0V und 0,7V) enthalten ist.
Aja, ich glaub ich habs kappiert: Die einzellen Bildzeilen werden von links nach rechts erstellt, die zeilen werden von oben nach unten erstellt. Nun die Horizontale Synchronisation markiert das ende einer alten bzw den anfang einer neuen Zeile, die Vertikale Synchronisation markiert das Ende der letzten Zeile und somit auch den Anfang eines neuen Bildes. Ist das jetzt so richtig ?

Zitat
dann schau Dir mal das an: http://www.linusakesson.net/scene/turbulence/, damit Du weist wo die Messlatte hängt. ;)
Der Typ hat auch was ähnliches mit nem AVR gemacht (findest Du bestimmt auf seiner Seite).
Sowas ähnliches hab ich auch geplant, auch mit 2-Bit DAC's für den VGA anschluss eben ohne audioausgang(obwohl, nen audioausgang währe eigentlich ziemlich cool) dafür mit nem Ps/2 anschluss für ein Keyboard .
Titel: Re: Logisim CPU
Beitrag von: kevin am 02. January 2013, 00:33
Ich? Ich wollte einfach einen Kernel schreiben.
Ist das kein Ziel? :-)
Ja, aber ein reichlich unkonkretes. Wenn du das gelten lässt, dann kennt Tufelix sein Ziel auch... ;)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 02. January 2013, 15:39
Ich? Ich wollte einfach einen Kernel schreiben.
Ist das kein Ziel? :-)
Ja, aber ein reichlich unkonkretes. Wenn du das gelten lässt, dann kennt Tufelix sein Ziel auch... ;)
Ich meinte nicht, dass du das Ziel in allen Details schon vorher kennen sollst. Eine grobe Idee, in welche Richtung du entwickeln willst, solltest du aber schon vorher haben (dein Kernel wird auch so Dinge wie "Protected Mode" und "Multitasking" vorgesehen haben, ehe du angefangen hast - oder?).
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 02. January 2013, 19:29
Hallo Tufelix,


Sowas ähnliches hab ich auch geplant ...
Aha, sorry wenn ich da jetzt ein ganz klein wenig arrogant klinge, aber hast Du wirklich eine konkrete Vorstellung davon wie der Weg zu diesem Ziel aussieht? Damit meine ich noch nicht mal die Probleme bei seiner konkreten Umsetzung seines Demos (z.B. Frame-Buffer mit nur ner Hand voll Bytes an RAM, also gar keinen Frame-Buffer sondern alles in Real-Time-Calculation u.a.m.) sondern die Techniken die man zur Lösung solcher Probleme beherrschen muss. Als Kevin mit dem Tyndur-Kernel angefangen hat wusste er mit Sicherheit noch nicht wie man jedes einzelne Teilproblem lösen kann (viele dieser kleinen Stolpersteine hat er wohl nicht mal gesehen als er angefangen hat, einiges davon sieht man eben erst wenn man es tatsächlich versucht umzusetzen) aber ich unterstelle mal das Kevin ungefähr wusste wie eine Flat-Memory-Speicherverwaltung aussieht und was diese zu leisten hat und er auch ausreichend Erfahrung mit den ganzen Techniken wie der Programmiersprache oder der Tool-Chain hatte.

Dieser Linus Akesson hat das Demo auf dem Propeller (turbulence) 2009 gemacht und das Demo auf dem ATmega88 (craft) 2008, seiner Homepage ist zu entnehmen das er auch vorher schon einige andere sehr Hardware-nahe Projekte (C64-Programmierung fällt IMHO immer in diese Kategorie ;) ) erfolgreich abgeschlossen hat, an dieser Historie kann man die erforderliche Lernkurve für so ein Demo ablesen und das waren sicher 10 oder mehr Jahre (von der ersten Programmiererfahrung angefangen). Ich selber habe auch schon etliche Projekte mit Micro-Controllern u.ä. erfolgreich abgeschlossen (beruflich aber auch privat, dazu kommen jetzt 20 Jahre Programmiererfahrung allgemein) aber so ein Demo würde ich mir trotzdem nicht einfach so zutrauen, ich schätze mal das ich etwa 3 bis 5 Jahre bräuchte (bei der Menge Freizeit die ein berufstätiger und alleinerziehender Vater so hat) um mir die dafür nötigen Fähigkeiten (also alles das was mir zu so einem Demo heute fehlt) anzueignen und das obwohl ich 1997-1998 selber an Demos, allerdings auf dem PC, mitgearbeitet hab.

Mir ist klar das Du nicht vor hast so ein anspruchsvolles Demo zu entwickeln aber eine richtige General-Purpose-CPU ist auch keine Kleinigkeit, an meinem Projekt hänge ich jetzt bald 5 Jahre dran und hab erst einige kleine Teile meiner CPU fertig und für vieles andere nur recht detaillierte Konzepte (wenn mein Privatleben die letzten Jahre etwas leichter gewesen wäre wäre ich aber schon etwas weiter). Gut mein Ziel ist auch etwas ambitionierter: ich möchte bei gleichen Takt etwa die Performance eines Pentium Pro (686) erreichen (zumindest wenn ich richtige Out-of-Order-Execution hinbekomme, ansonsten wird es wohl höchstens für nen normalen Pentium (586) reichen). Auch einem Cortex M mit gleichem Takt möchte ich überholen können, was sich von alleine ergibt wenn ich den Pentium Pro erreiche. Bei Performance pro Watt dürfte ich dank heutiger FPGAs wohl mit dem Pentium Pro gerade so mithalten können aber für den normalen Pentium sind FPGAs einfach zu durstig und einem Micro-Kontroller der dank heutiger Fertigungstechnologie mit ein paar mW auskommt komm ich mit nem FPGA natürlich erst recht nicht bei.

Daher kann ich nur wiederholen:
Zu Deiner CPU kann ich nur empfehlen das Du erst mal versuchen solltest ein System mit maximal 8 Tastern und maximal 8 LEDs und ein ganz klein wenig Software (kein RAM oder sonstige Peripherie) zum Laufen zu bekommen, damit Du eine bessere/konkretere Vorstellung davon bekommst was Du eigentlich tun willst.
Ich denke das Du noch auf dem richtigen Weg bist aber Du solltest Dir erst mal ein Etappenziel in realistischer Entfernung vornehmen und dann weitersehen. Ich würde an Deiner Stelle erst mal versuchen eine reine 8Bit-CPU (wie nen kleinen AVR) aber einem nur 8-bittigem Speicher-Adressraum (der Code-Adressraum darf aber größer sein, schau Dir mal die kleinen PICs 14F...18F von Microchip an) umzusetzen. An Tastatur oder gar Monitor solltest Du auch noch nicht denken, fürs erste reichen ein paar Taster und ein paar LEDs völlig aus.

Hast Du schon daran gedacht das Du für Deine eigene CPU auch eigene Linker/Assembler/Compiler benötigst?
Auch da gilt es einige Herausforderungen zu meisten.


Grüße
Erik


PS.: Bitte glaube mir das es wirklich nicht meine Absicht ist zu Desillusionieren.
Titel: Re: Logisim CPU
Beitrag von: XanClic am 02. January 2013, 22:01
Als ich mit Kernelentwicklung angefangen hab, wollte ich nur Assembler lernen. Dass es sowas wie Protected Mode oder Speicherverwaltung überhaupt gibt, wusste ich gar nicht. :wink:

Gut, Assembler kann ich heute akzeptabel, insofern kann man behaupten, dass ich mein Ziel erreicht habe, aber na ja…
Titel: Re: Logisim CPU
Beitrag von: kevin am 03. January 2013, 12:25
Ich meinte nicht, dass du das Ziel in allen Details schon vorher kennen sollst. Eine grobe Idee, in welche Richtung du entwickeln willst, solltest du aber schon vorher haben (dein Kernel wird auch so Dinge wie "Protected Mode" und "Multitasking" vorgesehen haben, ehe du angefangen hast - oder?).
Okay, klar, Multitasking schon. Die noch lange nicht verwirklichte Vision eines Desktop-OS gibt das ja quasi vor. Ich bin mir nicht sicher, ob die allerdings in den Anfängen als konkretes Ziel taugt, und mit der Zeit gibt man sie ja sowieso auf. ;) Protected Mode war eigentlich kein Ziel, sondern eher so eine Sache, wo überall stand "das macht man so" und dann hab ich es halt so gemacht. Damit es ein Ziel hätte sein können, hätte ich ja genau wissen müssen, was das überhaupt ist.

Ansonsten war das einfach ein Vorwärtstasten. Was hätte ich noch gern, ist mit überschaubarem Aufwand machbar und habe ich grad Lust, zu basteln? Dann schaue ich da mal rein. So funktioniert das bei mir mit der tyndur-Entwicklung nach wie vor. Wobei sich in letzter Zeit bedauerlicherweise eine gewisse Diskrepanz zwischen was nötig ist und worauf ich Lust habe eingestellt hat - dann funktioniert dieses Modell nicht mehr so richtig gut...

Als Kevin mit dem Tyndur-Kernel angefangen hat wusste er mit Sicherheit noch nicht wie man jedes einzelne Teilproblem lösen kann (viele dieser kleinen Stolpersteine hat er wohl nicht mal gesehen als er angefangen hat, einiges davon sieht man eben erst wenn man es tatsächlich versucht umzusetzen) aber ich unterstelle mal das Kevin ungefähr wusste wie eine Flat-Memory-Speicherverwaltung aussieht und was diese zu leisten hat und er auch ausreichend Erfahrung mit den ganzen Techniken wie der Programmiersprache oder der Tool-Chain hatte.
*hust* Willst du raten, was mein erstes richtiges Projekt in C war, mit dem ich die Sprache eigentlich gelernt habe? :-D

Und natürlich wusste ich nicht, wie man jedes einzelnes Teilproblem lösen kann, ich wusste ja nicht mal welche Teilprobleme es gibt. Und wie man sie richtig löst, weiß ich bis heute nicht, ich kenne nur teilweise mehr unbefriedigende Möglichkeiten... Und wie ein malloc funktioniert, hatte ich in der Tat schonmal an der Uni gehört; dass es sowas wie Paging gibt und wie man das unfallfrei verwendet, war trotzdem Neuland für mich.

tl;dr: Ich hatte keine Ahnung, was ich tat, und ich habe das Gefühl, dass sich seither nur das Niveau der Ahnungslosigkeit verschoben hat.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 03. January 2013, 14:43
Der PM gibt einen Rahmen vor, was theoretisch möglich ist - auch dann, wenn man ihn nicht nutzt oder kennt. Darum heißt es hier im Forum ja auch immer "GRUB", "PM" und "VESA", wenn jemand nicht weiß, womit er anfangen soll. Bei Hardware ist die Entscheidung nicht so einfach, finde ich. Da sollte man diesen Rahmen stecken, bevor man anfängt; eine 8-Bit-CPU ohne Adress-/Datenbusse geht halt nicht.

So, mit diesem Link (http://www.youtube.com/watch?v=DIwC9vdqfqw (http://www.youtube.com/watch?v=DIwC9vdqfqw)) zu einem Vortrag vom 29C3 kehre ich wieder zum Thema zurück. :-)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 03. January 2013, 16:45
Mhh, ich glaub es ist zunächst besser wieder zu logisim zurück zu kehren und wenn ich dann ein besseres Verständniss für Hardware hab zu versuchen so ein Demo-board zu bauen.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 03. January 2013, 18:35
Die grundsätzlichen Ideen bleiben aber die gleichen (also Daten-/Adressbus usw.).
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 04. January 2013, 15:16
Jop bleiben gleich...
Nun ich hab mir jetzt überlegt das ich nen Cisc-CPU mit 5 Pipline stufen baue. Zunächst, wie kann ich löst man am besten solche Pipeline-Hazard ohne das Lücken entstehen?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 04. January 2013, 17:16
Hallo,


Protected Mode war eigentlich kein Ziel [....]. Damit es ein Ziel hätte sein können, hätte ich ja genau wissen müssen, was das überhaupt ist.
Vor allem hättest Du auch die Alternativen kennen müssen um Dich überhaupt bewusst für oder gegen Konzepte wie PM oder Flat-Memory entscheiden zu können. ;)

*hust* Willst du raten, was mein erstes richtiges Projekt in C war, mit dem ich die Sprache eigentlich gelernt habe? :-D
Bin ich hier eigentlich der einzigste der auch nur halbwegs strukturiert vorgeht? :roll:

und ich habe das Gefühl, dass sich seither nur das Niveau der Ahnungslosigkeit verschoben hat.
Mir fehlen die Worte!


Mhh, ich glaub es ist zunächst besser wieder zu logisim zurück zu kehren und wenn ich dann ein besseres Verständniss für Hardware hab zu versuchen
Ja, das klingt nach einem guten Plan.

so ein Demo-board zu bauen.
Und was soll dann da drauf?
Wenn Du wirklich eine CPU entwickeln möchtest dann empfehle ich Dir so ein FPGA-Board mit gut DRAM und einigen Schnittstellen. Ich weiß das man da durchaus mit 250 Euronen (eventuell auch etwas mehr) dabei ist aber dafür bekommt man auch ein echt tolles Spielzeug auf dem das Basteln an einer eigenen CPU richtig viel Spaß machen kann.


Nun ich hab mir jetzt überlegt das ich nen Cisc-CPU mit 5 Pipline stufen baue.
Also von CISC würde ich eher abraten da es heute günstiger ist wenige schnelle Befehle zu haben als viele langsame und komplexe Befehle. Vor allem würde ich davon abraten das prinzipiell jeder Befehl in der Lage ist auf den Speicher zuzugreifen. Ist aber nur meine persönliche subjektive Meinung.

wie kann ich löst man am besten solche Pipeline-Hazard ohne das Lücken entstehen?
Gar nicht. Wenn Du diese Lücken nicht willst dann musst du echte Out-of-Order-Execution schaffen damit Du die Pipeline mit voneinander unabhängigen Befehlen befüllen kannst.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 04. January 2013, 19:32
*hust* Willst du raten, was mein erstes richtiges Projekt in C war, mit dem ich die Sprache eigentlich gelernt habe? :-D
Bin ich hier eigentlich der einzigste der auch nur halbwegs strukturiert vorgeht? :roll:
Vermutlich. Und der einzige, der noch keine Ergebnisse hat. *duck* :-D

Aber mal ganz ehrlich: Womit hätte ich denn sonst C lernen sollen, wenn nicht mit einem Projekt, das mich interessiert?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 04. January 2013, 23:52
Cisc-CPU
Rate ich von ab, baue lieber wenige Befehle - spart Komplexität.
5 Pipline stufen
Rate ich von ab, baue lieber eine Maschine mit entweder 1 Takt/Befehl (komplizierter) oder x Takte/Befehl (einfacher) ohne Pipeline.

Bei deinem Wissen, zumindest so wie ich das einschätze, würde ich erstmal ganz klein anfangen. Du wirst schon dabei genug Wissen anhäufen, um eine Menge Fehler im zweiten Anlauf zu vermeiden. :-)

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. January 2013, 13:06
Nun gut, werde dann wohl jetzt ein Risc-CPU mit Harvard-architektur bauen. Meine bisherigen CPU's haben die Befehle immer mit einem Takt abgearbeitet, daher wird es kein problem sein dies auch in meinem neuem CPU umzusetzen. Auserdem hab ich mir gedacht das man doch so nen Dualkern-CPU bauen könnte, jeder der 2 Kerne bekommt dann seinen eigenen Ram und Programmspeicher und über das Round-Robin-Verfahren könnten dann jeder der 2 Kerne auf das externe Bussystem zugreifen. Was haltet ihr von der idee ?  :-D
Titel: Re: Logisim CPU
Beitrag von: chris12 am 05. January 2013, 15:53
warum baust du nicht erstmal was funktionierendes simples?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. January 2013, 16:26
Getrennte CPUs mit getrennten Speichern sind getrennte Systeme, also kein Dual-Core. Und zwei Geräte (CPUs) an einem Bussystem ist ein normales Multi-Master-Bussystem, wie oben beschrieben. Außerdem mag es Hardware garnicht, gleichzeitig von verschiedenen Treibern angesprochen zu werden.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. January 2013, 18:02
Naja war nur so ne Idee...nun ich hab jetzt mal eine CPU gezeichnet:
(http://img4.fotos-hochladen.net/uploads/aufbaujdhqps5k8y.png)
(Die buffer kann man eigentlich weg lassen, weil der Bus mit der gleichen Schaltfrequenz arbeitet wie die CPU)

So Jetzt zum Bus:
(http://img4.fotos-hochladen.net/uploads/buskudhvqnwp3.png)
Der Control bus besteht aus 2 Leitungen : R/W und Takt.
Titel: Re: Logisim CPU
Beitrag von: Martin Erhardt am 05. January 2013, 18:21
Endlich mal'n klar struktierirtes Schaubild das ich verstehe :-D
Also die Allzweckregister liegen in nem Datenbuffer.
Stackpointer entspricht esp.
framepointer -> ebp
Addresspointer -> ?
P.counter -> eip zeigt aber nicht auf eine SpeicherAdresse in der RAM sondern in der ROM, weil die Firmware dort fest eingedrahtet ist.
Der Instruction Decoder sucht sich jetzt den Befehl auf der addresse vom P.Counter decoded et und leitet den Strom weiter zu den ALU die Instruktion ausführen.

Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 05. January 2013, 18:41
Hallo,


Vermutlich. Und der einzige, der noch keine Ergebnisse hat. *duck* :-D
Hm, vielleicht bin ich aber auch der einzige der ein Projekt hat bei dem man auf keinen Fall am Ende feststellen möchte das man am Anfang etwas falsch gemacht hat (egal wie klein dieses etwas auch sein mag).
Deswegen beschäftige ich mich zur Zeit mit der Funktionsweise von Floating-Point-Befehlen obwohl ich erstmal gar keine implementieren möchte, nur um Heute schon Flag-Register/Exception-Handling/.... anständig designen zu können (Floating-Point soll bei mir integraler (aber optionaler) Bestandteil der CPU sein und nicht als zusätzliches Rechenwerk oder gar zusätzlicher Coprozessor realisiert werden) und hoffentlich später nicht feststellen muss das ich etwas übersehen habe und dann entscheiden darf ob ich eine Krücke dranbastle oder noch mal von vorne anfange.

Womit hätte ich denn sonst C lernen sollen, wenn nicht mit einem Projekt, das mich interessiert?
Soll das heißen das es im User-Mode nichts gibt was Dich mal interessieren würde? ;)


jeder der 2 Kerne bekommt dann seinen eigenen Ram und Programmspeicher und über das Round-Robin-Verfahren könnten dann jeder der 2 Kerne auf das externe Bussystem zugreifen.
Wenn Du da "Ram" und "Programmspeicher" gegen L1-Data/Code-Cache austauscht und dann noch anständige Cache-Kohärenz schaffst hast Du echtes SMP (was Du beschreibst ist AMP).
Ich will jetzt wirklich nicht überheblich klingen aber ich schätze mal dass das Heute die Grenzen Deiner Möglichkeiten ein ganz klein wenig überschreitet.
Du solltest wirklich erst mal mit was ganz einfachem Anfangen: erst mal eine kleine CPU nach Harvard und als einzigste Peripherie ein paar Taster und LEDs (noch nicht mal Data-RAM, für die ersten kleinen Programmchen reichen die Register). Erst nachdem Du das erfolgreich geschafft hast würde ich mal einen UART als Schnittstelle zur Außenwelt und RAM dazu packen und erst dann wenn Deine Programme deutlich komplexer werden und wirklich mehr Möglichkeiten brauchen solltest Du weiter denken. Vor allem sammelst Du so Erfahrungen noch bevor die Größe Deines Projekts in Mann-Jahre gemessen werden muss und ein Fehlschuss in zu vielen Tränen endet.

Dein CPU-Diagramm sieht nach einem realistischem Plan aus, beim BUS fehlen noch 2 Byte-Enable-Leitungen falls Du nicht nur 16Bit-Weise zugreifen willst und die Adressleitung A0 kann eventuell eingespart werden (wird durch die 2 Byte-Enables erledigt) falls Du Byteweise adressieren möchtest (falls Dein BUS als kleines Datum 16Bit-Werte verarbeitet/adressiert ist er so aber Okay).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Martin Erhardt am 05. January 2013, 18:43
Ich weiß aber garnicht ob RISC CPUs überhaupt explizite Stackpointerregister haben. Bei 28 Registern ist das im Normalfall wohl gar nicht notwendig. Und wenn doch kann man dafür wohl einfach ein Allzweckregister benutzen.
Instruktionen wie push und pop,welche explizite Stackpointerregister vorraussetzen, sind ja Memory/register mixed Instruktionen,die komplex sind und in einem RISC garnicht vorkommen dürfen. <- keine Garantie,dass meine These stimmt.
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 05. January 2013, 19:21
Hallo,


Ich weiß aber garnicht ob RISC CPUs überhaupt ein explizite Stackpointerregister haben....
Eigentlich nicht, echte RISC-CPUs geben nicht mal vor ob der Stack nach unten oder nach oben wächst (das ist dann eine Vorgabe des OS oder Compilers). Bei ARM sind im Assembler z.B. PUSH und POP nur Aliase für Speicherzugriffe mit R13 (ist bei ARM der "offizielle" Stackpointer) und Pre-Decrement bzw. Post-Inkrement aber das könnte man auch ganz anders lösen da diese Befehle mit jedem Register als Adressregister umgehen können.
Das Problem ist eher der erforderliche Schaltungsaufwand in der CPU (jedes beliebige Register als Adressregister benutzen zu können erfordert mehr Logik als immer nur bestimmte Register zu benutzen) und der verfügbare Platz in den OpCodes (PUSH und POP für die normalen Register sind bei 8086 nur 1 Byte groß aber bei ARM immer 32Bit, früher war das durchaus relevant aber bei heutigen Speicherpreisen ist das nicht mehr so schlimm). Ein anderes Problem sind die verfügbaren Adressierungsmodi, bei x86 gibt es kein Pre/Post-Inkrement/Dekrement so das sich PUSH und POP gar nicht ohne zusätzliche Rechenbefehle (die dann auch noch die Flags modifizieren) mit normalen Speicherzugriffen ersetzen ließen.
Ein anderes Problem ist die Performance. So ist z.B.
pop  ecx
pop  ebx
pop  eax
langsamer als
mov  ecx,[esp]
mov  ebx,[esp+4]
mov  eax,[esp+8]
add  esp,12
da im ersten Code jeder der POP-Befehle warten muss bis der vorangegangene POP-Befehl ESP fertig modifiziert hat bevor er weiß von wo er Daten lesen soll wohingegen im zweiten Code alle 4 Befehle parallel ausgeführt werden können (zumindest theoretisch) solange sichergestellt ist das die Modifikation an ESP durch den ADD-Befehl erst dann sichtbar wird wenn alle vorangegangenen Befehle ESP gelesen haben (der eigentliche Speicherzugriff muss deswegen noch nicht fertig sein).


@Tufelix:
mach Deine CPU erst mal so einfach wie irgend möglich, die komplexeren Dinge kommen später (und Performance noch viel später).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 05. January 2013, 19:26
Soll das heißen das es im User-Mode nichts gibt was Dich mal interessieren würde? ;)
Im Moment würde mir das tatsächlich schwerfallen, was zu benennen. Vielleicht muss ich doch mal einen funktionierenden Compiler schreiben, einfach um das auch mal getan zu haben, aber auch dazu hält sich die Motivation in Grenzen. Aber damals wie heute gibt es keinen Grund, warum ich das dann in C machen sollte. ;)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. January 2013, 20:26
Naja war nur so ne Idee...nun ich hab jetzt mal eine CPU gezeichnet
Sieht gut aus.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 06. January 2013, 00:13
Na dann werd ich wohl den Stackpointer(hab in jetzt "ebp" genannt)  streichen und nur dem Framepointer behalten. Nun dann wird man aber 2 Befehle fürs Popen oder Pushen brauchen...(zunächst muss die adresse modifiziert und dann der wert aus bzw in den Ram geladen werden.) Hab mir deswegen überlegt das man ja über Befehle kurzzeitig 1 bestimmten wert im Adressrechenwerk dazu zählen bzw. abziehen könnte.
Titel: Re: Logisim CPU
Beitrag von: Martin Erhardt am 06. January 2013, 15:24
FLOATing-Point soll bei mir INTegraler (...) Bestandteil der CPU sein
Klingt ja interessant. :-D
http://forum.lowlevel.eu/index.php?topic=3137.0 nicht das die neuen Posts da jetzt in den Hintergrund gedrängt werden
Titel: Re: Logisim CPU
Beitrag von: LittleFox am 06. January 2013, 16:04
FLOATing-Point soll bei mir INTegraler (...) Bestandteil der CPU sein

Zitate! :D

Sorry für OT ...
Titel: Re: Logisim CPU
Beitrag von: Svenska am 06. January 2013, 17:03
Na dann werd ich wohl den Stackpointer(hab in jetzt "ebp" genannt)  streichen und nur dem Framepointer behalten.
Ob du nun sagst, dass dein Stackpointer "ebp" oder "R15" heißt, ist egal. Der wichtige Unterschied ist, ob es nur einen einzigen Stackpointer gibt (macht die Verdrahtung einfacher) oder ob jedes Register ein Stackpointer sein kann (flexibler, aber mehr Aufwand). Für den Framepointer gilt das gleiche.

Bedenke, dass du - wenn du Interrupts unterstützen möchtest - im Interrupthandler alle Register sichern können musst, d.h. da stehen dann viele PUSHs und POPs hintereinander.
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 07. January 2013, 13:44
Hallo,


Der Frame-Pointer ist eher eine reine Software-Angelegenheit für Hochsprachen-Compiler aber er sollte trotzdem vorhanden sein und flexibles Adressieren mit positiven und negativen Displacements ermöglichen.

... im Interrupthandler alle Register sichern können musst ...
Dazu gehören auch die Flags (deswegen hab ich die einfach in ein normales Register gelegt) und alles andere was zum Zustand eines Threads/Task gehört. Dieses Sichern und Wiederherstellen muss übrigens Zerstörungsfrei sein (darf den zu sichernden/wiederherzustellenden Zustand nicht beeinflussen).


Floating-Point soll bei mir integraler (aber optionaler) Bestandteil der CPU sein
Damit ist gemeint das bei meiner CPU die Floating-Point-Befehle u.a. die selben Flags benutzen so das man z.B. nach einem FSUB die selben bedingten Sprünge nutzen kann um das Ergebnis auszuwerten wie nach einem SUB (reine CMP/FCMP wird es auf meiner CPU nicht geben so das man für Vergleiche immer SUB/FSUB nutzen und ein Register verschwenden muss). Auch bedeutet dass das z.B. IDIV das selbe "Divide-by-Zero"-Flag setzt (und damit auch die selbe Exception auslösen kann) wie FDIV um diese Art von Fehler zu signalisieren. Dazu kommt der Vorteil das der Scheduler im OS-Kernel nur einen Register-Satz sichern/wiederherstellen muss um den Zustand eines Threads immer komplett verwalten zu können.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 07. January 2013, 19:09
Mhh die Interrupts hab ich ganz vergessen...naja dann werd ich ein paar mehr Controlleitungen im Bussystem für die I/O Ports-Interrupts und ein Interrupt-Enable-Flag im CPU einbauen. Was ich nicht ganz verstehe, ist wie die Registerinhalte gesichert werden. Dazu muss ja ne Subroutine aufgerufen werden und das verändert dann den wert im Programm-counter. Auserdem werd ich dabei bleiben das es nur einen einzigen Stackpointer, Framepointer und Adresspointer gibt.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 07. January 2013, 19:17
Was ich nicht ganz verstehe, ist wie die Registerinhalte gesichert werden. Dazu muss ja ne Subroutine aufgerufen werden und das verändert dann den wert im Programm-counter.
Du musst in der Lage sein, bei einem Interrupt ein "PUSH Program Counter; JUMP Interrupt Handler" auszuführen. Den Rest kannst du dann mit Software erschlagen. Praktisch reicht auch ein einziger Interrupt, wenn du einen Interrupt-Controller benutzen möchtest.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 07. January 2013, 19:58
und ein CALL ist ein "PUSH Programcounter; JUMP Zieladresse". Den Programmcounter musst Du niemals mit einem explizitem PUSH-Befehl sichern können aber wiederherstellen ist erforderlich, also ein "POP Programmcounter" (um dann an der neuen Adresse den nächsten Befehl zu holen), das nennt sich dann RET.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 07. January 2013, 21:44
Hm, nett ja, aber notwendig? Warum nicht statt "pop $pc" nicht ein "ld $sp, $r1; jmp $r1"? (Pseudo-Assembler fdS! :-D)

Und bei einem Interrupt kann man den Program Counter auch in ein Kernel-Mode-Register speichern statt auf den möglicherweise kaputten Stack zu pushen. Oder willst du einen automagischen Stackwechsel machen wie bei x86?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 07. January 2013, 22:10
Hallo,


Warum nicht statt "pop $pc" nicht ein "ld $sp, $r1; jmp $r1"?
Weil damit r1 kaputt gemacht wird. Diese Art von RET ist nicht zerstörungsfrei. Das ist sowohl bei Funktionen als auch bei Interrupt-Handlern ein Problem es sei denn Du definierst r1 zur alleinigen Verwendung für diesen Zweck (dann darf r1 auch nie manuell gesichert/wiederhergestellt werden).

Und bei einem Interrupt kann man den Program Counter auch in ein Kernel-Mode-Register speichern statt auf den möglicherweise kaputten Stack zu pushen.
Das ist zwar ein gutes Argument das für eine richtige CPU in jeden Fall beachtet werden muss aber für ein Test-Design zum üben ist sowas IMHO noch nicht erforderlich. Solange die CPU von Tufelix nicht zwischen User-Mode und System-Mode unterscheidet reicht es wenn Interrupt-Handler genau so behandelt werden wie Funktionen (nur mit dem Unterschied das beim Interrupt-Handler alle Register callee-save / nonvolatile sind, dafür gibt es nur ein RET und nicht RET und IRET) auch wenn das ein paar grundlegende Sicherheitsrisiken hat die man bei einer richtigen General-Purpose-CPU nicht tolerieren kann.

Wenn ein Interrupt oder eine Exception nicht auf den Speicher zugreifen soll (was grundsätzlich eine gute Idee ist) benötigt man dafür in jedem Fall für jeden System-Mode einen eigenen Programm-Counter (siehe ARM), wenn es für den System-Mode nur einen einzigen Programm-Counter gibt bedeutet dass das Syscall/Exceptions/Interrupts nicht kaskadierbar sind (auf meine CPU trifft das zu) wohingegen es ja gerade der große Vorteil von x86 ist das dort quasi beliebig kaskadiert werden kann (im RM und im PM, solange auf dem Stack noch Platz ist).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Svenska am 07. January 2013, 22:16
Hallo,

den PC in ein Schattenregister zu stopfen verhindert nested interrupts. :-D Was ich skizziert habe, hat mit einem Stackwechsel aber auch nichts zu tun... halte ich auch nicht für notwendig, da eh kein Speicherschutz vorhanden ist. Dein Ansatz macht nach einem Interrupt aber $r1 kaputt (und du musst $sp noch inkrementieren), was irgendwie nicht hilfreich ist. Ansonsten ist es ziemlich egal, ob es ein RET nun in Hardware gibt oder nicht, aber eine seiteneffektfreie Variante ist notwendig.

edit: Mist, Erik war schneller. Dafür ist das hier die hundertste Antwort zum Thema.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 07. January 2013, 22:28
Nun, das heist bei meinem CPU das die CPU sofort nach einem Interrupt-signal den inhalt im Programm-Counter in die adresse vom Framepointer ladet und danach das Unterprogramm für das Registersichern aufruft.
Titel: Re: Logisim CPU
Beitrag von: kevin am 07. January 2013, 22:30
Weil damit r1 kaputt gemacht wird. Diese Art von RET ist nicht zerstörungsfrei. Das ist sowohl bei Funktionen als auch bei Interrupt-Handlern ein Problem es sei denn Du definierst r1 zur alleinigen Verwendung für diesen Zweck (dann darf r1 auch nie manuell gesichert/wiederhergestellt werden).
Für Funktionen macht das nichts, ich gehe davon aus, dass per Konvention sowieso ein paar Register als caller saved definiert werden. Interrupts sind allerdings ein gutes Argument, erst recht wenn es kein separates iret gibt...

Solange die CPU von Tufelix nicht zwischen User-Mode und System-Mode unterscheidet reicht es wenn Interrupt-Handler genau so behandelt werden wie Funktionen (nur mit dem Unterschied das beim Interrupt-Handler alle Register callee-save / nonvolatile sind, dafür gibt es nur ein RET und nicht RET und IRET) auch wenn das ein paar grundlegende Sicherheitsrisiken hat die man bei einer richtigen General-Purpose-CPU nicht tolerieren kann.
Einverstanden, ohne getrennten Kernelmode ist das nicht nötig.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 08. January 2013, 22:22
Bei Microcontrollern ist das ja so das eine Programmunterbrechung entsteht wenn ein Neuen Wert in die Eingänge Geladen wird, oder  ?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 08. January 2013, 22:46
Hallo,


ich weiß jetzt nicht genau ob es das ist was Du meinst aber die I/O-Pins an typischen µC können bei einem Pegelwechsel einen Interrupt auslösen (bei den besseren µC ist das sehr fein konfigurierbar, z.B. nur bestimmte Flanken und/oder Pegel) aber diese Funktionalität kommt vom GPIO-Controller (ist eine Peripherie-Komponente zur Steuerung der I/O-Pins) in dem µC und hat nichts mit dem CPU-Kern ansich zu tun.

Falls Deine Frage auf was anderes abzielt dann Bitte konkreter formulieren.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Svenska am 08. January 2013, 23:16
Hallo,

Bei Microcontrollern ist das ja so das eine Programmunterbrechung entsteht wenn ein Neuen Wert in die Eingänge Geladen wird, oder?
Eine Programmunterbrechung entsteht, wenn ein Interrupt ausgelöst wird. Normalerweise führt die CPU den aktuellen Befehl dann noch zum Schluss und springt dann in den Handler, sofern Interrupts aktiviert sind.

Wird dein Projekt jetzt eher ein µC (also mit Ports) oder ein µP (also mit Bus)? Die letzte Zeichnung hatte zumindest eine Harvard-Architektur mit zwei Bussen (I/O+RAM und ROM) - da gibt es keine einzelnen "Eingänge" in dem Sinn; alles nach außen führende läuft über den Bus mit der entsprechenden Logik. Da zählt als Steuerleitung auch die Interruptleitung dazu.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 08. January 2013, 23:28
Hallo,


Wird dein Projekt jetzt eher ein µC (also mit Ports) oder ein µP (also mit Bus)?
Und wo ist da für die eigentliche CPU der Unterschied?
Der CPU ansich ist es doch egal ob sie mit der Peripherie auf einem Stück Silizium untergebracht ist (und der Bus nicht nach außen geführt wird) oder ob der Bus nach außen geführt wird so das man beliebige externe Peripherie anschließen kann. Auch Mischformen sind möglich.


@Tufelix:
Konzentriere Dich erst mal auf Deine CPU, die Peripherie kommt später dran. Immer schön Schritt für Schritt und bloß keinen Vielfrontenkrieg anzetteln.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Svenska am 08. January 2013, 23:51
Hallo,

Wird dein Projekt jetzt eher ein µC (also mit Ports) oder ein µP (also mit Bus)?
Und wo ist da für die eigentliche CPU der Unterschied?
Ich vermute, dass Tufelix am Anfang nicht so ganz klar war, dass man auch für Ports einen Bus haben sollte... ansonsten landen die mitten in der CPU-Logik, wie in den ersten Designs. Wenn du einen Bus für die Kommunikation nutzt, gibt es keine unabhängigen "Eingänge" an der CPU mehr - wann die Datenleitungen als Eingang betrieben werden, hängt von den Steuerleitungen ab.

Darauf wollte ich hinaus. Mehr nicht.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 09. January 2013, 18:12
Nun ich wollte eigentlich so nen Microcontroller mit programmierbaren Pin's bauen... naja aber zunächst zur CPU... da wollte ich jetzt ein Interruptsystem mit Reset-, IRQ- und XIRQ-Signal dazu noch ein software-interrupt Befehl bauen...Nun ich möchte jetzt mal den Befehlssatz gestalten, muss ich da auf etwas bestimmtes achten oder kann ich da sofort los legen  :-D
Titel: Re: Logisim CPU
Beitrag von: Dimension am 09. January 2013, 19:25
Es ist sinnvoll klein anzufangen und die Probleme der Reihe nach zu lösen, doch es ist auch hilfreich eine Vision zu haben und zu wissen, was man mit seinem Projekt erreichen will. Hast du dir schon überlegt, wozu deine CPU gut sein soll, bzw. was du damit erreichen willst?

Falls du deine CPU mal auf echte Hardware bringen willst, würde ich dir ein FPGA-Entwicklerboard empfehlen, die gibts so ab 200 Euro. Ein FPGA ist eine Art programmierbarer Chip, in den Schaltungen einprogrammiert werden können. Die Schaltungen werden meist aus einer Hardwarebeschreibungssprache synthetisiert. Als Beschreibungssprachen wären da VHDL und Verilog zu nennen, wobei ich letzteres nicht kenne. Ich arbeite mit VHDL und komme damit gut zurecht. Auf Linux kannst du zwar mit ghdl und gtkwave deine Schaltung simulieren, für die Synthese brauchst du aber eine extra Software. Erik kann dir hier bestimmt weiterhelfen.

Falls du dir nicht sicher bist würde ich mir einfach ein günstiges Board aussuchen. Ich denke eine serielle Schnittstelle auf dem Board wäre vorerst wichtiger, da du vermutlich keine Lust hast erst einen VGA- oder Ethernet-Treiber zu schreiben. Danach würde ich damit anfangen eine sinnvolle Umgebung für die Ausführung von Programmen zu schreiben, etwa einen Assembler oder ein GCC-Backend.

Gruß
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 09. January 2013, 20:02
Zitat
Es ist sinnvoll klein anzufangen und die Probleme der Reihe nach zu lösen, doch es ist auch hilfreich eine Vision zu haben und zu wissen, was man mit seinem Projekt erreichen will. Hast du dir schon überlegt, wozu deine CPU gut sein soll, bzw. was du damit erreichen willst?
Nun die CPU soll eben das können was ein sehr einfacher Risc-CPU auch kann :
Werte zwischen 2 Register transportieren können.
Werte zwischen Bus und Register transportieren.
Sie Sollte Konstante- und absolute Adressierung beherschen können.
Zudem soll er Addieren, subtrahieren, multiplizieren, dividieren, incrementieren und decrementieren und dann noch alle 3 logische Befehle können(vielleicht noch Schiebe-Befehle ....)
Dann sollte er Sprungbefehle können und Interrupts behandel können.
Vielleicht dann noch auch Pop und Push.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 10. January 2013, 01:09
Hallo,

Werte zwischen 2 Register transportieren können.
Check.
Werte zwischen Bus und Register transportieren.
Also Speicherzugriff, im weitesten Sinne. Normalerweise hat eine einfache RISC-CPU genau zwei Befehle, die auf den Bus zugreifen: LOAD und STORE. Alle anderen Befehle arbeiten ausschließlich auf Registern.
Sie Sollte Konstante- und absolute Adressierung beherschen können.
Hä? Meinst du sowas wie MOV R4, [R6]? Das wäre dann ein LOAD.
Zudem soll er Addieren, subtrahieren, multiplizieren, dividieren, incrementieren und decrementieren und dann noch alle 3 logische Befehle können(vielleicht noch Schiebe-Befehle ....)
Ein AVR kann in Hardware nicht multiplizieren und nicht dividieren, außerdem kann er Shift-Befehle nur um eins (d.h. (i<<1) ja, (i<<2) nein). Das muss in Software erledigt werden. Zu Addition/Substraktion: Wie stellst du negative Zahlen dar? Im Einer- oder Zweierkomplement? (Das Einerkomplement ist inzwischen ausgestorben.) Fließkommazahlen solltest du vollständig ignorieren.
Dann sollte er Sprungbefehle können und Interrupts behandel können.
Welche bedingten Sprungbefehle möchtest du unterstützen? Sollen sie als CMP/Jxx mit Flags arbeiten oder z.B. mit Registervergleichen? Zu Interrupts siehe unten.
Vielleicht dann noch auch Pop und Push.
Sind sinnvoll, aber zwei weitere Befehle, die auf Speicher zugreifen.
da wollte ich jetzt ein Interruptsystem mit Reset-, IRQ- und XIRQ-Signal dazu noch ein software-interrupt Befehl bauen...
Warum so kompliziert? Reset ist nachvollziehbar, IRQ ebenfalls. Was ist das besondere am XIRQ? Wozu brauchst du Software-Interrupts? Wenn du keinen Speicherschutz hast, kannst du Syscalls auch über "JUMP SyscallHandler" erledigen. Hat AmigaOS so gemacht, ist extrem schnell.

Nun ich möchte jetzt mal den Befehlssatz gestalten, muss ich da auf etwas bestimmtes achten oder kann ich da sofort los legen  :-D
Du solltest auf folgendes achten:
- Brauchst du den Befehl wirklich? Du musst jeden einzelnen Befehl in Hardware verdrahten.
- Wie schwierig ist es, den Befehl in Hardware zu gießen? (Damit fallen z.B. Multiplikation/Division raus, weil die nicht so einfach in einem Takt ausgeführt werden können.)
- Wie schwierig ist es, den Befehl zu dekodieren? (Also das Bitmuster zu zerstückeln und an die richtigen Teile der CPU weiterzuleiten.)

Wir hatten das Thema hier im Forum schon öfter mal, z.B. hier von 2004 (https://forum.lowlevel.eu/index.php?topic=69.msg490) oder hier von 2010 (https://forum.lowlevel.eu/index.php?topic=2470.msg27682). Da kannst du dir noch ein paar Anregungen raussuchen. Meine CPU ist allerdings im Sande verlaufen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 10. January 2013, 19:08
Hallo Tufelix,


beim Gestalten eines Befehlssatz gibt es eine Menge zu beachten.

Ein MOV-Befehl zum Kopieren zwischen 2 beliebigen Register ist logisch, die grundlegenden Rechenarten (ADD/SUB/AND/OR/XOR) auch. ADDC/SUBC sind eine Überlegung wert (man bräuchte dafür in der eigentlichen Ausführungseinheit auch keine extra Logik sondern am Addierer/Subtrahierer eben nur noch einen Carry-Eingang der beim normalen ADD/SUB mit 0 beschickt wird) um einigermaßen Effizient mit Integer-Zahlen umgehen zu können die größer als die native Wortbreite sind. Auf Schiebe-Befehle würde ich auf gar keinen Fall verzichten da sich diese nur ganz schlecht nachbauen lassen, Du solltest auch alle 4 wichtigen Schiebeoperatoren berücksichtigen: SHL/SHR/SAR/ROL. Falls Du mehr als 8Bit breite Register hast solltest Du auch darüber nachdenken wie all die Rechenbefehle mit verschiedenen Bitbreiten umgehen können sollen (auf meiner CPU haben all diese Befehle ein Size-Attribut das angibt ob der Befehl mit 8, 16, 32 oder 64 Bit arbeiten soll, in Wirklichkeit arbeiten die Rechenbefehle aber immer mit der vollen Registerbreite (und speichern das auch immer vollständig im Zielregister ab) und nur bei der Generierung der Flags wird das dann korrekt beachtet, die Schiebe-Befehle arbeiten natürlich immer mit der gewünschten Anzahl an Datenbits). Falls Deine CPU nur ein einziges Flagset hat wäre es eine Überlegung wert ob Du all den Rechen/Schiebe-Befehlen ein Bit im OpCode spendierst mit dem bestimmt werden kann ob die Flags von dem Befehl überhaupt manipuliert werden sollen so das ein Rechenbefehl bei dem die Flags nicht weiter benötigt werden diese auch nicht zwangsweise überschreiben muss, bei ARM und MIPS (und wimre auch PowerPC) wird das so gemacht.
Auf Multiplikation und Division würde ich bei der OpCode-Gestalltung erst mal nicht verzichten, ob Du diese Befehle dann später auch realisierst ist aber noch eine andere Frage. Falls Du Deine CPU mal in einem FPGA realisieren möchtest dann geht das in VHDL ganz einfach mit dem Operator * (so wie in C auch) ohne das Du da was selber bauen musst (und da die meisten aktuellen FPGAs über Hardware-Multiplizierer verfügen sollte auch dieser Befehl in einem Takt gehen) aber für die Division wird das schon etwas komplexer. Bei diesen beiden Befehlen ist es auch von Vorteil wenn es jeweils zwei Varianten gibt die mit einem doppelt breitem Produkt/Dividend umgehen können (jeweils einmal als signed und einmal als unsigned). Bei der kleinen Multiplikation, deren Produkt genau so viele Bits hat wie die beiden Faktoren, brauchst Du nicht zwischen signed und unsigned unterscheiden da die untere Hälfte beim Produkt immer gleich ist.

Speicherzugriffe sind auf jeden Fall auch sehr wichtig aber hier würde ich mich auf ein LOAD und ein STORE beschränken diese aber dafür mit leistungsfähigen Adressierungsarten ausstatten (der Compiler Deiner Wahl wird dafür mal sehr dankbar sein). Hier sind vor allen Pre/Post-Inkrement/Dekrement (also wirklich alle 4 Kombinationen) wichtig aber auch [Adress-Register +/- beliebiges-Register] und [Adressregister +/- feste-Zahl] (diese feste Zahl muss nicht die volle Größe haben da die meisten Strukturen und Klassen nur relativ klein sind, falls diese feste Zahl vorzeichenbehaftet im OpCode gespeichert ist benötigst Du nur + oder - zur Adressberechnung). Wichtig ist bei den Speicherzugriffen aber auch wieder das die Befehle ein Parameter für die benötigte Datenbreite haben und bei den Lese-Befehle wäre noch ein Bit im OpCode wichtig das angibt ob der obere Rest im Register mit 0-Bits oder vorzeichenkorrekt aufgefüllt werden soll. Ich würde generell nicht empfehlen das man auf Register nur teilweise schreiben kann sondern eher das alle Befehle die Zielregister immer komplett beschreiben dazu musst Du nur klar definieren mit was. Wenn Du das alles ordentlich hinbekommst kannst Du auf PUSH und POP als zusätzliche Befehle verzichten, das sind dann einfach nur STORE und LOAD mit jeweils der passenden Adressierungsart.

Ein anderer Punkt sind Befehle die beliebige Konstanten in die Register laden und ob bei Deinen Rechenbefehlen einer der Parameter gegen ein Konstante austauschbar sein soll (in der Art von R4 := R8 + 479). Hier muss vor allem überlegt werden wie (mit wie vielen Bits) diese Konstanten im Befehl kodiert sein sollen.


Alle anderen wichtigen Punkte bezüglich des Befehlssatz hat Svenska ja schon genannt.

Du wärst damit bei etwa 30 Befehlen als minimale Ausbaustufe. Das ist noch nicht allzu komplex und sollte den Aufwand für den Decoder in Grenzen halten.
Auf einen Software-Interrupt (aka SYSCALL) würde ich nicht gerne verzichten da somit zumindest die Programme nicht wissen müssen wo das OS im Speicher liegt aber zu Not geht es auch mit einem CALL auf eine feste Adresse.


Es gibt aber noch ein paar Aspekte drum herum, wie z.B. :
- Wie breit soll Deine Architektur überhaupt sein?
- Wie breit sollen Deine Befehle sein? Immer mit fester Breite oder flexibel?
- Wo sind die Flags untergebracht (falls es welche gibt)?


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 10. January 2013, 19:12
Zitat
Hä? Meinst du sowas wie MOV R4, [R6]? Das wäre dann ein LOAD.
Mhh mit Konstante Adressierung meinte ich das die Daten, die in den jeweiligen Speicher geladen werden soll im Befehl stehen. Also im assembler müsste das z.b. so aussehen: mov ax,#24
Nun mit absolute Adressierung meine ich das immer für LOAD oder STORE eine 16 Bit adresse aus einer der 3 Adressregister verwendet wird, man kann dann nicht die adresse direkt im Befehl angeben, dazu muss man sie erst ins Adressregister laden.(also in etwa so wie dein MOV R4, [R6] )

Zitat
Ein AVR kann in Hardware nicht multiplizieren und nicht dividieren, außerdem kann er Shift-Befehle nur um eins (d.h. (i<<1) ja, (i<<2) nein). Das muss in Software erledigt werden. Zu Addition/Substraktion: Wie stellst du negative Zahlen dar? Im Einer- oder Zweierkomplement? (Das Einerkomplement ist inzwischen ausgestorben.) Fließkommazahlen solltest du vollständig ignorieren.
Nun in Logisim gibts ja das Multiplizierer- und Dividierer-Bauteil (bei denen legt man einfach 2 werte an die eingäge und ohne takt bzw verzögerung wird das ergebniss an den ausgang angelegt und bleibt solange bestehen bis die werte am eingang sich verändern), die wollte ich in die ALU mit einbauen . Und ich stell negative Zahlen meistens im Zweierkomplement dar.

Zitat
Welche bedingten Sprungbefehle möchtest du unterstützen? Sollen sie als CMP/Jxx mit Flags arbeiten oder z.B. mit Registervergleichen? Zu Interrupts siehe unten.
Nun ich eigentlich nur fünf, JE, JG, JGE, JL und JLE. Und sie sollten mit Registervergleichen arbeiten, will daher diese Jump-Einheit einbauen.

Zitat
Vielleicht dann noch auch Pop und Push.
Mhh ich glaub ich bau diese Pop und Push befehl ein.

Zitat
Warum so kompliziert? Reset ist nachvollziehbar, IRQ ebenfalls. Was ist das besondere am XIRQ? Wozu brauchst du Software-Interrupts? Wenn du keinen Speicherschutz hast, kannst du Syscalls auch über "JUMP SyscallHandler" erledigen. Hat AmigaOS so gemacht, ist extrem schnell.
Naja dachte mir wenn schon den schon :-D... Aber ich glaub du hast recht, Reset und IRQ reichen eigentlich für den anfang.

Titel: Re: Logisim CPU
Beitrag von: Svenska am 10. January 2013, 19:47
Hallo,

Mhh mit Konstante Adressierung meinte ich das die Daten, die in den jeweiligen Speicher geladen werden soll im Befehl stehen.
Achso, also einfach eine Konstante in ein Register laden. Ja, das ist natürlich sinnvoll. :-) Du musst dir aber überlegen, ob Konstanten die volle Registerbreite ausnutzen dürfen oder nicht. Wenn du bei 16-Bit-Befehlen 5 Bit für den Opcode, 5 Bit für das Zielregister und 6 Bit für die Konstante definierst, brauchst du zum Einlesen nur einen ROM-Lesezyklus, sonst zwei. Dafür musst du größere Konstanten immer mit Arithmetik ausrechnen... keine Ahnung, ob das sehr schmerzt.

Nun mit absolute Adressierung meine ich das immer für LOAD oder STORE eine 16 Bit adresse aus einer der 3 Adressregister verwendet wird, man kann dann nicht die adresse direkt im Befehl angeben, dazu muss man sie erst ins Adressregister laden.
Du solltest vielleicht (konstante) Offsets erlauben, damit du einen Pointer auf eine Struct/ein Array im Adressregister halten kannst und kein weiteres Register für den Zugriff auf einzelne Elemente brauchst. Auch diese Konstanten brauchen nicht riesig sein.

Und ich stell negative Zahlen meistens im Zweierkomplement dar.
Also das Wort "meistens" gefällt mir an dem Satz am besten. :-P

Zitat
Welche bedingten Sprungbefehle möchtest du unterstützen? Sollen sie als CMP/Jxx mit Flags arbeiten oder z.B. mit Registervergleichen? Zu Interrupts siehe unten.
Nun ich eigentlich nur fünf, JE, JG, JGE, JL und JLE. Und sie sollten mit Registervergleichen arbeiten, will daher diese Jump-Einheit einbauen.
Du brauchst für einen Vergleich also zwei Register. Eventuell ist es sinnvoll, auch kleine Konstanten zuzulassen (mit 0, 1 und -1 vergleicht man relativ oft).

Auf welche Registerbreite willst du denn gehen? Wenn du mit einer 16-Bit-Architektur hantierst, solltest du vielleicht einige Befehle mit 8 Bit anbieten, um Datentypen wie "char" sinnvoll unterstützen zu können.
Wieviele Register willst du denn haben?

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 10. January 2013, 20:50
Zitat
- Wie breit soll Deine Architektur überhaupt sein?
- Wie breit sollen Deine Befehle sein? Immer mit fester Breite oder flexibel?
- Wo sind die Flags untergebracht (falls es welche gibt)?
Nun hab an 16 bit gedacht und die Befehle feste 32 bit breite. Flags hab ich ganz vergessen :-D... naja welche Flags brauch ich den ?

Welche Vor und nach Teile hat eigentlich so ne 16 bit architektur im gegensatz zu 8 bit ?  :roll:

Zitat
Wieviele Register willst du denn haben?
Nun entwerder 16 oder 32
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 10. January 2013, 22:05
Hallo Tufelix,


Nun in Logisim gibts ja das Multiplizierer- und Dividierer-Bauteil (bei denen legt man einfach 2 werte an die eingäge und ohne takt bzw verzögerung wird das ergebniss an den ausgang angelegt und bleibt solange bestehen bis die werte am eingang sich verändern), die wollte ich in die ALU mit einbauen.
Dann bau die beiden Befehle mit ein. Falls Du diese CPU später mal in einem echten FPGA haben möchtest dann ist die Multiplikation (wie schon geschrieben) kein Problem und für die Division kann ich Dir gerne ein wenig voll parametrierbaren VHDL-Code geben.

Und ich stell negative Zahlen meistens im Zweierkomplement dar.
Ja, der ist wirklich gut, ich hab fast unterm Tisch gelegen!
Im Ernst, nimm Zweierkomplement so wie alle anderen auch. Die mathematischen Bibliotheken für VHDL können wimre mit Einerkomplement gar nicht umgehen und nen vernünftigen Addierer/Subtrahierer für Einerkomplement dürfte man in normalen FPGAs auch nur schwer schaffen. Außerdem verlassen sich viele C-Programmierer unbewusst auf das Zweierkomplement wenn diese mit -1 anstatt ~0 (oder noch korrekter 0xFFFFF...) vergleichen um zu prüfen ob alle Bits gesetzt sind.
Wichtigstes Argument: die Rechtschreibprüfung im Firefox kennt das Wort "Einerkomplement" gar nicht, im Gegensatz zu Zweierkomplement. ;) SCNR

Nun ich eigentlich nur fünf, JE, JG, JGE, JL und JLE.
Ich fürchte das wird nicht reichen. Da fehlt zumindest ein JNE (falls mal etwas nicht gleich sein soll) und für die anderen 4 fehlen noch 4 weitere Varianten für unsigned (JA/JAE/JB/JBE) und eventuell noch die Varianten zum direkten testen der anderen Flagbits (mit JE/JNE prüft man nur das Z-Flag). Du solltest Dir generell mal das Zusammenspiel der klassischen 4 Flagbits und der zugehörigen 14 Bedingungen ansehen (bei x86 gibt es noch zusätzlich das exotische Parity-Bit und eben 16 Bedingungen aber das muss kein Vorbild sein). Auch solltest Du Dich mal damit beschäftigen wie die verschiedenen Rechenbefehle die Flags setzen und wie man daraus Rückschlüsse auf signed und unsigned ziehen kann.

Und sie sollten mit Registervergleichen arbeiten, will daher diese Jump-Einheit einbauen.
Falls Du damit meinst das Du direkt den Inhalt von zwei beliebigen Registern vergleichen willst (oder einem beliebigen Register und ner kleinen Auswahl an Konstanten wie +1/0/-1) dann finde ich das ne ganz tolle Idee, damit könntest Du die Flags gleich komplett sparen und würdest eine Engstelle bei den Abhängigkeiten zwischen den Befehlen beseitigen.

Mhh ich glaub ich bau diese Pop und Push befehl ein.
Also ich persönlich rate davon ab aber das hatte ich ja schon erklärt.

Nun hab an 16 bit gedacht und die Befehle feste 32 bit breite.
Cooool, da kannst Du ja bei den Befehlen aus dem Vollen schöpfen. Dann solltest Du bei der Anzahl der Register lieber ein klein wenig großzügiger sein. Da Du so in 16 OpCode-Bits immer den Befehl ansich und noch 2 Register unterbringen kannst sollten alle Befehle die mit Konstanten arbeiten diese auch immer mit voller 16Bit-Größe enthalten können.
Sei froh das Du mit dieser CPU kein Geld verdienen musst, ökonomisch dürfte das nicht werden. ;)

naja welche Flags brauch ich den?
Wenn Du wirklich bedingte Sprünge baust die den Vergleich mit enthalten dann gar keine, ansonsten die üblichen 4.

Welche Vor und nach Teile hat eigentlich so ne 16 bit architektur im gegensatz zu 8 bit?
Kostet mehr Geld (also Transistoren auf echtem Silizium) und kann mehr leisten. Auf ner winzigen 8Bit-CPU würde ich erst gar nicht anfangen etwas zu programmieren das man hinterher als OS bezeichnen möchte, ja ich weiß das es sowas gibt aber mit einem richtigen OS hat das meiner persönlichen Meinung nach noch nicht viel zu tun sondern ist eher ne Art Runtime-Library.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Svenska am 10. January 2013, 23:24
Hallo,

Welche Vor und nach Teile hat eigentlich so ne 16 bit architektur im gegensatz zu 8 bit ? :roll:
Sie kostet mehr Silizium/Schaltungsaufwand und verbraucht dementsprechend bei gleicher Taktfrequenz (und Mikroarchitektur) mehr Strom. Auf der anderen Seite kann sie kompliziertere Berechnungen schneller ausführen und daher länger im Stromsparmodus verweilen. Außerdem haben die meisten 8-Bit-CPUs einen 16-Bit-Adressbus (um wenigstens 64K ansprechen zu können), d.h. Pointerrechnungen sind mit breiteren Registern einfacher.

Auf ner winzigen 8Bit-CPU würde ich erst gar nicht anfangen etwas zu programmieren das man hinterher als OS bezeichnen möchte, ja ich weiß das es sowas gibt aber mit einem richtigen OS hat das meiner persönlichen Meinung nach noch nicht viel zu tun sondern ist eher ne Art Runtime-Library.
Schau dir mal http://www.symbos.de (http://www.symbos.de) an und z.B. dieses Video (https://www.youtube.com/watch?v=Ish4ReOjdIw) an. Ein AVR mit 20 MHz ist noch deutlich schneller als der gezeigte Z80 mit 4 MHz (und zusätzlich gestreckten Zyklen). Als 8-Bit-CPUs noch Stand der Dinge waren, gab es viele moderne Programmiertechniken noch garnicht.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 11. January 2013, 17:59
Zitat
Du solltest vielleicht (konstante) Offsets erlauben, damit du einen Pointer auf eine Struct/ein Array im Adressregister halten kannst und kein weiteres Register für den Zugriff auf einzelne Elemente brauchst. Auch diese Konstanten brauchen nicht riesig sein.
Nun wenn ich jetzt in einem Befehl einen 16 bit wert in den ram laden möchte, und dazu ein 8 bit offset benutzen will, sind ja 32 bit für den Befehl zu kurz oder? Es gehen ja schon für die opcodebits 16 bits drauf und dazu noch den 16 bitwert... oder gibts da ne andere methode ?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 11. January 2013, 20:13
Hallo,


Nun wenn ich jetzt in einem Befehl einen 16 bit wert in den ram laden möchte
Du meinst eine Konstante direkt in den Speicher schreiben? Welchem Zweck sollte so ein Befehl dienen? Ich kenne außer x86 keine CPU die sowas kann (obwohl, wimre kann die PDP-11 sowas auch), zumindest kenne ich keine RISC-CPU die sowas kann.

Es reicht wenn Du den Inhalt eines beliebigen Registers möglichst flexibel in den Speicher schreiben oder aus diesem laden kannst, also u.a. mit einer Adresse in der Form [r8 +/- Konstante]. Dazu musst Du auch nur 2 Register und den Befehl ansich in 16 Bit unterbringen und das sollte wirklich kein Problem sein.


@Svenska:
Ich weiß das es sowas gibt, aber ich muss auch ehrlich sagen das ein System das bis zu 1 MB RAM verwalten kann IMHO bei weitem kein reines 8Bit-System mehr ist. Selbst wenn eine CPU nur mit maximal 8 Bit Werten rechnen kann bin ich der Meinung das wenn diese in der Lage ist nativ mit 16 Bit-Adressen umzugehen ist sie zumindest ein 8Bit/16Bit-Hybrid. Das trifft IMHO auch auf die kleinen AVRs zu, die einzigsten µC die mir spontan einfallen die echte 8 Bit-CPUs enthalten sind die kleinen PICs von Microchip (und sebst für diese gibt es Librarys die z.B. preemptives Multitasking anbieten aber die kann man meiner persönlichen Meinung nach noch nicht als OS bezeichnen).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Svenska am 11. January 2013, 20:42
Wenn du "8-Bit-CPU" auf CPUs mit maximal 256 Words adressierbarem(!) Speicher beschränkst, dann fallen da sämtliche Heimcomputer und alle CPUs raus, die man üblicherweise als 8-Bit-CPUs bezeichnet, wie etwa 6502, Z80, 8051, ... und ja, ich gebe zu, dass ein OS unter diesen Bedingungen ziemlich unmöglich ist.
Titel: Re: Logisim CPU
Beitrag von: kevin am 11. January 2013, 21:55
Hm, auf einer 8-Bit-CPU noch von Words statt einfach Bytes zu reden fühlt sich irgendwie auch ein bisschen schräg an. ;)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 11. January 2013, 22:29
Hängt damit zusammen, dass die ganz kleinen 8-Bit-CPUs meist mit 10-, 12- oder 14-Bit-Befehle haben und der ROM entsprechend breit angebunden ist. :-) Die sind also auch hybrid.

Ich kenne keine 8-Bit-CPU, die ausschließlich 8-Bit hat, also mit 8-Bit-Opcodes und 8-Bit-Registern und 8-Bit-Daten.
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 12. January 2013, 13:06
Hallo,


... dann fallen da sämtliche Heimcomputer und alle CPUs raus, die man üblicherweise als 8-Bit-CPUs bezeichnet ...
Ja, aber das liegt daran das man zur Klassifizierung üblicherweise die Datenpfadbreite in der ALU heranzieht. Ich persönlich bin aber der Meinung dass das nicht so ganz korrekt ist, zumindest die vom CPU-Kern nativ unterstützte Adressbreite sollte ebenfalls etwas berücksichtigt werden. Stell Dir mal vor es würde jemand eine CPU bauen die zwar nur über 8Bit breite Register und eine entsprechende ALU verfügt aber dafür in der Lage ist immer 4 dieser Register zu einem Pointer zusammenzufassen um damit 4GB Speicher flach zu adressieren und dazu vielleicht sogar noch vollwertiges Paging beherrscht (so das sogar ein normales unbeschränktes Linux drauf laufen könnte), würdest Du das immernoch als 8Bit-CPU bezeichnen?

Von der Adressgröße beim Programmcode wollen wir erst gar nicht reden, es gibt z.B. AVRs die mehr als 64k-Befehle adressieren können (wobei jeder Befehl auch 16Bit groß ist) und die trotzdem noch offiziell als 8Bit-CPU klassifiziert werden.

Aber letztendlich ist das eine rein akademische Diskussion da in der Realität zur Zeit sogar die aller kleinsten CPUs (in Taschenrechnern und Waschmaschinen) langsam gegen 32Bitter ausgetauscht werden. Kleine Cortex-M0-µC sind teilweise bereits für unter 1 Dollar (bei großen Stückzahlen) zu bekommen und auch für die Entwickler ist es einfacher keinen exotischen Compiler zu benötigen der in der Lage ist mit dem zusammengestückelten Adressraum der 8Bit-Generation umzugehen.

... dass ein OS unter diesen Bedingungen ziemlich unmöglich ist.
Vor allem auch ziemlich nutzlos. Mehr als eine einfache Library (die ins eigentliche Programm fest mit einkopiliert werden muss) die ein paar der Funktionen eines OS anbietet (wie z.B. preemptives Multitasking oder einfache Kommunikationsmechanismen) macht auf CPUs wie dem AVR einfach keinen Sinn.

Ich kenne keine 8-Bit-CPU, die ausschließlich 8-Bit hat, also mit 8-Bit-Opcodes und 8-Bit-Registern und 8-Bit-Daten.
Ich auch nicht, also lassen wir das einfach so wie es ist. ;)


Hm, auf einer 8-Bit-CPU noch von Words statt einfach Bytes zu reden fühlt sich irgendwie auch ein bisschen schräg an.
Wenn "Word" im Sinne von "kleinste adressierbare Einheit" gemeint ist ergibt das durchaus Sinn. Für Audio gab es mal spezielle DSPs die 64kWords adressieren konnten aber diese Words immer 24Bit groß waren oder denke an die 4Bit-CPUs für Taschenrechner u.ä.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 14. January 2013, 20:15
So ich hab jetzt mal ein Konzept für das instruktion-set kreiert:

Numer   Name   |Operanden   |Beschreibung      |Operation
---------------------------------------------------------------------
1   |ADD   |Rd,Rs      |Addiert      |Rd+Rs -> Rd   
---------------------------------------------------------------------
2   |ADCI   |Rd,Wert   |Addiere Wert dazu   |Rd+Wert -> Rd
---------------------------------------------------------------------
3   |Sub   |Rd,Rs      |Subtrahiert      |Rd-Rs -> Rd
---------------------------------------------------------------------
4   |SBCI   |Rd,Wert   |Subtrahiere wert ab   |Rd-wert -> Rd
----------------------------------------------------------------------
5   |MUL   |Rd,Rs      |Multipliziere       |Rd*Rs -> Rd
---------------------------------------------------------------------
6   |MLCI   |Rd,Wert   |Multipliziere mit Wert   |Rd*Wert -> Rd
---------------------------------------------------------------------
7   |DIV   |Rd,Rs      |Divison      |Rd/Rs -> Rd
---------------------------------------------------------------------
8   |DVCI   |Rd,Wert   |Dividiere mit Wert   |Rd/wert - Rd
---------------------------------------------------------------------
9   |AND   |Rd,Rs      |AND         |Rd•Rs -> Rd
---------------------------------------------------------------------
10   |ANDI   |Rd,Wert   |AND mit wert      |Rd•Wert -> Rd
---------------------------------------------------------------------
11   |OR   |Rd,Rs      |OR         |Rd v Rs -> Rd
---------------------------------------------------------------------
12   |ORI   |Rd,Wert   |OR mit wert      |Rd v Wert -> Rd
---------------------------------------------------------------------
13   |XOR   |Rd,Rs      |XOR         |Rd "XOR" Rs -> Rd
--------------------------------------------------------------------------
14   |XORI   |Rd,Wert   |XOR mit Wert      |Rd "Xor" Wert -> Rd
----------------------------------------------------------------------------
15   |NEG   |Rd      |Zweierkompliment   |$00-Rd -> Rd
----------------------------------------------------------------------------
16   |INC   |Rd      |Incrementieren      |Rd+1 -> Rd
-----------------------------------------------------------------------
17   |DEC   |Rd      |Decrementieren      |Rd-1 -> Rd
-----------------------------------------------------------------------

      Sprung- und Rücksprung Befehle
-----------------------------------------------------------------------
18   |JmP   |adr      |Springe zur adresse   |Adr -> PC
-----------------------------------------------------------------------
19   |JE   |Rd,RS,adr   |Springe wenn gleich   |Rd==Rs Adr->PC
-----------------------------------------------------------------------
20   |JG   |Rd,Rs,adr   |Springe wenn größer   |Rd>Rs Adr->PC
-----------------------------------------------------------------------
21   |JGE   |Rd,Rs,adr   |Springe wenn gr od. gl   |Rd=>Rs Adr->PC
-----------------------------------------------------------------------
22   |JL   |Rd,Rs,adr   |Springe wenn kleiner   |Rd<Rs Adr->PC
-----------------------------------------------------------------------
23   |JLE   |Rd,Rs,adr   |Springe wenn gl od. kl |Rd=<Rs Adr->PC
-----------------------------------------------------------------------
24   |JNE   |Rd,Rs,adr   |Spinge wenn nicht gl.   |Rd!=Rs   Adr->PC
-----------------------------------------------------------------------
25   |JNG   |Rd,Rs,adr   |Springe wenn nicht gr.   |Rd!>RS   Adr->PC
-----------------------------------------------------------------------
26   |JNGE   |Rd,Rs,adr   |Spr wenn nicht gl od gr|Rd!=>RS Adr->PC
-----------------------------------------------------------------------
27   |JNL   |Rd,Rs,adr   |Spr wenn nicht kleiner   |Rd!<Rs Adr->PC
-----------------------------------------------------------------------
28   |JNLE   |Rd,Rs,adr   |Spr Wenn nicht kl od gr|Rd!=<Rs Adr->PC
-------------------------------------------------------------------------
29   |JSR   |adr      |Sprung, ablage des PC    |adr->PC
-----------------------------------------------------------------------
30   |RETS   |      |Rücksprung aus UP   |(FP-1)->PC
-----------------------------------------------------------------------
31   |RETI   |      |Rücksprung aus ISR   |(FP-1 bis FP-32) -> Registerblock   
-------------------------------------------------------------------------
   
      Register-Transfer-Befehle
-------------------------------------------------------------------------
32   |MOV   |Rd,Rs      |Kopiere  Register   |Rs -> Rd   
-------------------------------------------------------------------------
33   |LDK   |Rd,Wert   |Lade Konstante      |Wert->Rd
-------------------------------------------------------------------------

         LOAD-Befehle
-------------------------------------------------------------------------
34   |LD   |Rd      |Lade aus Bussystem    |(AP)->Rd   
-------------------------------------------------------------------------
35   |LDPOI   |Rd      |Lade, Post-Increment   |(AP)->Rd, AP+1->AP
-------------------------------------------------------------------------
36   |LDPOD   |Rd      |Lade, Post-Decrement   |(AP)->Rd, AP-1->AP
-------------------------------------------------------------------------
37   |LDPRI   |Rd      |Lade,Pre-Increment   |(AP+1->AP)->Rd
-----------------------------------------------------------------------
38   |LDPRD   |Rd      |Lade,Pre-Decrement   |(AP-1->AP)->Rd
-----------------------------------------------------------------------
39   |LDAR   |Rd,Rx      |Lade,Add Register   |(AP+Rx)->Rd
-----------------------------------------------------------------------
40   |LDSR   |Rd,Rx      |Lade,Sub Register   |(AP-Rx)->Rd
-----------------------------------------------------------------------
41   |LDAW   |Rd,wert(8 bit)   |Lade, Add Wert      |(AP+wert)->Rd
-----------------------------------------------------------------------
42   |LDSW   |Rd,wert(8 bit)   |Lade, sub wert      |(AP-wert)->Rd
-----------------------------------------------------------------------

      Store-Befehle
-------------------------------------------------------------------------
43   |ST   |Rs      |Speicher,aus Bussystem   |(AP)<-Rs   
-------------------------------------------------------------------------
44   |STPOI   |Rs      |Speicher,Post-Increment|(AP)<-Rs, AP+1->AP
-------------------------------------------------------------------------
45   |STPOD   |Rs      |Speicher,Post-Decrement|(AP)<-Rs, AP-1->AP
-------------------------------------------------------------------------
46   |STPRI   |Rs      |Speicher,Pre-Increment   |(AP+1->AP)<-Rs
-----------------------------------------------------------------------
47   |STPRD   |Rs      |Speicher,Pre-Decrement   |(AP-1->AP)<-Rs
-----------------------------------------------------------------------
48   |STAR   |Rs,Rx      |Speicher,Add Register   |(AP+Rx)<-Rs
-----------------------------------------------------------------------
49   |STSR   |Rs,Rx      |Speicher,Sub Register   |(AP-Rx)<-Rs
-----------------------------------------------------------------------
50   |STAW   |Rs,wert(8 bit)   |Speicher, Add Wert   |(AP+wert)<-Rs
-----------------------------------------------------------------------
51   |STSW   |Rs,wert(8 bit)   |Speicher, sub wert   |(AP-wert)<-Rs
-----------------------------------------------------------------------

   Push/POP Befehle
-----------------------------------------------------------------------
52   |push   |Rs      |Push auf Stack      |(SP)<-Rs, SP-1->SP
-----------------------------------------------------------------------
53   |pop   |Rd      |pop von Stack      |(SP)->Rs, SP+1->SP
-----------------------------------------------------------------------

   Schiebe Befehle
-----------------------------------------------------------------------
54   |SHR   |Rd      |Shift logisch nach rechts
-----------------------------------------------------------------------
55   |SHL   |Rd      |Shift logisch nach Links
-----------------------------------------------------------------------
56   |SAR   |Rd      |Shift Arithmetisch nach Rechts
-----------------------------------------------------------------------
57   |ROR   |Rd      |Rotieren logisch nach rechts
-----------------------------------------------------------------------
58   |ROL   |Rd      |Rotieren logisch nach Links
-----------------------------------------------------------------------
59   |NOP   |   


(man ist das lang  :roll:. )
Nun hat jemand vielleicht Kritik, bzw ne idee was man besser machen könne  :-D
Titel: Re: Logisim CPU
Beitrag von: chris12 am 14. January 2013, 20:42
also wie ich das sehe, hast du ein paar redundante befehle drin, vorallem bei den sprungbefehlen. mit redundante befehle mein ich nicht, dass man ein ldk rd, wert auch durch ein xor rd, rd; addci rd, wert darstellen kann, wogegen aber nichts spricht ;)

jge = jnl
jl = jnge
jle = jng

... liegt an dir die drinzuhalten, ich persönlich würde die durch andere mnemonics im assembler ersetzen, die dann in den selber befehl umgesetzt werden, spart opcodespeicher :D
ansonsten seh ich keine probleme, oh vllt solltest du nop auf opcode 00 legen, es spricht zwar nichts dagegen es auf 59 zu legen, aber ... nungut, ist nur persönlicher geschmack und zudem hat der logiksimulator (logisim) die ramzellen auf 0 initialisiert, desswegen bin ich der überzeugung ... wenn du allerdings microcode steuerung hast und bei opcode 0 deine steuerung zum laden des nächsten befehls liegt, dann solltest du es lassen ... obwohl ist das laden des nächsten befehls, sehen dass der nächste befehl das laden des nächsten befehls ist, nicht nop?

wie dem auch sei, viel spass und mfg :D

PS: ich sollte nach 20:00 keinen kaffee mehr trinken .... obwohl .... eig erst die richtige arbeitszeit :P
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 14. January 2013, 22:43
Mhh zunächst hab ich glaub vergessen zu erwähnen das Rd das Quellenregister und Rs das Zielregister ist...das nop an letze stelle steht hat sich so ergeben :-D, werd das aber das noch auf jeden fall ändern....
Titel: Re: Logisim CPU
Beitrag von: chris12 am 15. January 2013, 00:18
Rd und Rs ist natürlich jedem überlassen, wie man es nennt, aber ist es nicht sinnvoller Rd als Destination Register und Rs als Source Register zu sehen?
Titel: Re: Logisim CPU
Beitrag von: kevin am 15. January 2013, 00:21
Weiß nicht, ob das bei so einer einfachen CPU sinnvoll ist, aber bei was richtigem würde ich auf die 0 kein nop legen, sondern etwas, was immer eine Exception wirft (wie ud2 auf x86).
Titel: Re: Logisim CPU
Beitrag von: Svenska am 15. January 2013, 01:00
Hallo,

ASCII-Tabellen
| Kannst  | du          |
| auch    | auch        |
| so      | darstellen. |
(mit \[tt\])

Alternativ gehen natürlich auch \[code\]-Tags.

Die Opcodes der Reihe nach auflisten funktioniert zwar, ist aber nicht besonders schön.

Wenn du die ersten acht Bit für den Opcode reservierst, dann darfst du zwischen logisch getrennten Blöcken auch Lücken lassen. Schau dir diese Bitmuster an:
Arithmetik = 0x01..0x0F = 1..31  = 0000 xxxx (16 Opcodes)
Jumps      = 0x20..0x2f = 32..47 = 0010 xxxx (16 Opcodes)
Logik      = 0x30..0x37 = 48..55 = 0011 0xxx (8  Opcodes)
Shifts     = 0x38..0x3f = 56..63 = 0011 1xxx (8  Opcodes)


Wenn du das so ähnlich strukturierst, vereinfachst du deine Befehlsdekodierung ziemlich, weil du in jedem Befehl nur die hinteren n Bits beachten musst. Beispielsweise sagen die ersten 5 Bits "Arithmetik", die nächsten 2 Bits "Addieren", das folgende Bit sagt "Immediate-Wert oder Register". Dann folgen 4 Bit "Destination-Register", dann 4 Bit "Source-Register" und dann 16 Bit "Immediate-Wert". Für Jumps wären es 5 Bit "Jump", 2 Bit "Bedingung" (immer/gleich/größer/größergleich), 1 Bit "absolut/relativ", dann wieder 4 Bit "Destination-Register", 4 Bit "Source-Register", 16 Bit "absolute oder relative Adresse".

Damit zerteilt dein Befehlsdekoder den Befehl an festen Bitgrenzen in immer kleinere Bestandteile, die du in die Subsysteme nicht mehr weitergeben musst. Das macht die Logik einfacher zu verstehen und übersichtlicher. Bei 32-Bit-Befehlen auf einer 16-Bit-CPU darfst du sogar richtig Bits verschwenden (im Fall oben: Entweder die 4 Bit "Source-Register" oder die 16 Bit "Immediate-Wert" sind egal). Ein NOP kannst du dir übrigens sparen und im Assembler durch ein "MOV R0, R0" ersetzen (macht ARM z.B. so).

Es wird natürlich Befehle geben, auf die so eine Struktur nicht passt. Die kannst du aber alle so legen, dass die ersten 5 Bits "11111" sein müssen, dann hast du 27 Bits für diese Sonderfälle frei.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 15. January 2013, 14:45
 
Zitat
Rd und Rs ist natürlich jedem überlassen, wie man es nennt, aber ist es nicht sinnvoller Rd als Destination Register und Rs als Source Register zu sehen?
Mhh ich glaub ich hab bei meiner Antwort Rd(drain) mit Rs(source) verwechselt  :roll:

Zitat
ASCII-Tabellen
| Kannst  | du          |
| auch    | auch        |
| so      | darstellen. | (mit \[tt\])

Alternativ gehen natürlich auch \[code\]-Tags.
Mh was sind ASCII Tabellen...und wie stelle ich die Normal dar ?  und Wofür brauch ich die ?  :-D

Zitat
Wenn du die ersten acht Bit für den Opcode reservierst, dann darfst du zwischen logisch getrennten Blöcken auch Lücken lassen. Schau dir diese Bitmuster an:
Arithmetik = 0x01..0x0F = 1..31  = 0000 xxxx (16 Opcodes)
Jumps      = 0x20..0x2f = 32..47 = 0010 xxxx (16 Opcodes)
Logik      = 0x30..0x37 = 48..55 = 0011 0xxx (8  Opcodes)
Shifts     = 0x38..0x3f = 56..63 = 0011 1xxx (8  Opcodes)
So hab ichs bei meinem alten CPU gemacht...wollte aber jetzt eigentlich 32 register haben...aber naja ich kanns ja mal mit 16 versuchen ....
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 15. January 2013, 15:38
Hallo Tufelix,


Wo das NOP liegt ist mMn eher egal aber ich möchte Kevin zustimmen und würde dafür sorgen das wenn der Befehl komplett aus 0-Bits besteht das dann eine Undefined-OpCode-Exception kommt. Das selbe auch wenn der Befehl komplett aus 1-Bits besteht da viele FLASHs und EEPROMs im unprogrammierten Zustand immer 0xFF liefern. Aber in der Realität wird das nur bei sehr wenigen CPUs so gehandhabt und die funktionieren auch alle also ist es wahrscheinlich relativ egal. Auf NOP ganz verzichten würde ich aber trotzdem nicht, ein NOP zeichnet sich meiner Meinung nach dadurch aus das dieser von keinem anderen Befehl abhängig ist und auch kein anderer Befehl vom NOP abhängt, bei einem MOV R0,R0 ist das nicht so einfach gegeben da es auch andere Befehle geben kann die R0 benutzen. Eine Option wäre natürlich diesen MOV R0,R0 im Decoder als Sonderfall zu behandeln der dann innerhalb der eigentlichen Pipeline als echter NOP dargestellt wird (und auch der Disassembler zeigt für die Bitkombination die MOV R0,R0 entspricht immer NOP an) aber dieser NOP eben keinen eigenen OpCode hat.


Da Du ja 32 Bit pro Befehl hast würde ich den Aufbau minimal ändern:
6 Bit  | 5 Bit | 5 Bit |  16 Bit
OpCode |  RD   | RS(1) | Konstante oder RS2

64 maximal mögliche Befehle dürften für Dein Konzept komplett ausreichen (Du hast wirklich einige Redundanz drin) und 32 anstatt 16 Register sind auf jeden Fall nicht zu verachten. Ein drittes Register (aus dem aber nur gelesen werden kann) ist ebenfalls eine gute Idee da damit zerstörungsfreie 3-Operanden-Befehle möglich werden (alle anständigen RISC-CPUs die was auf sich halten können sowas und die Compiler lieben das abgöttisch).


Bei den bedingten Sprüngen reichen 6 Varianten völlig aus. Im Assembler Mnemonik solltest Du folgende 18 Varianten haben: JE, JNE, JA, JAE, JB, JBE, JNA, JNAE, JNB, JNBE, JG, JGE, JL, JLE, JNG, JNGE, JNL, JNLE (die ersten 2 sind für signed und unsigned, die nächsten 8 für unsigned und die letzten 8 für signed). Damit sind alle Vergleichsmöglichkeiten zwischen 2 Integer-Werten abgedeckt. Die beiden ersten Varianten JE und JNE müssen so auch als OpCode verfügbar sein, die anderen 16 Mnemoniks lassen sich mit 4 OpCodes darstellen : JA ist das selbe wie JNBE und JAE ist das selbe wie JNB usw. und schon sind es nur noch diese 8 Möglichkeiten : JA, JAE, JB, JBE, JG, JGE, JL, JLE (ich hab mal alle die Varianten mit N gestrichen). Zur weiteren Halbierung muss Dein Assembler in der Lage sein die Register zu vertauschen : JB R1,R2,Destination ist das selbe wie JA R2,R1,Destination usw. und schon sind es nur noch 4 richtige Vergleiche (2 für unsigned und 2 für signed), zusätzlich zu JE und JNE.
Der Aufbau für Deine bedingten Sprünge wäre also:
OpCode (6 aus 64) | RA (5Bit) | RB (5Bit) | Destination (16Bit)
wobei RA und RB immer nur gelesen werden (diese Befehle also nie irgendwelche Register ändern), ob Destination absolut oder relativ ist bleibt erst mal Dir überlassen aber ich würde für eine einfache CPU bei der es keine Möglichkeit gibt Code von einem externen Datenträger zu Laden bei absolut bleiben, spätestens der Linker weiß ja an welche Adresse er jeden Befehl packt und kann deswegen immer absolute Sprünge bauen (und der Decoder in der CPU wird einfacher wenn er nicht das absolute Sprungziel erst berechnen muss).

Bei Deinen mathematischen Befehlen (da schließe ich AND/OR/XOR mit ein) würde ich einen vergleichbaren Aufbau nutzen:
OpCode (12 aus 64) | RD (5Bit) | RS1 (5Bit) | Konstante (16Bit) oder RS2 (5Bit)
Die OpCodes sind mMn : ADD, ADDI, SUB, SUBI, SUBR, SUBRI, AND, ANDI, OR, ORI, XOR, XORI (wobei SUBR durch SUB mit vertauschten RS1 und RS2 ersetzt werden kann aber ich lass den mal der Konsistens wegen drin).
Befehle mit I am Ende funktionieren so : RD <= RS1 [Operator] Konstante
Befehle ohne I am Ende entsprechend : RD <= RS1 [Operator] RS2
Bei allen diesen Befehlen ist es egal in welcher Reihenfolge die beiden Quell-Operanden stehen nur bei SUB nicht und deswegen gibt es den SUBRI damit eben auch RD <= Konstante - RS1 möglich ist (ARM hat sowas auch aber dort vor allem deswegen weil nur einer der beiden Operanden ein Shifter-Operand sein kann und diese Fähigkeit eben nicht nur dem Subtrahend sondern auch dem Minuend zur Verfügung stehen soll).

INC und DEC wird als eigenständiger OpCode nicht benötigt da sich das mit ADD und SUB darstellen lässt. NEG ist gut aber läst sich mit SUBRI RD,RS1,0 darstellen, dafür hast Du NOT (alle Bits invertieren) vergessen aber der lässt sich mit XOR RD,RS1,0xFFFF darstellen.

MOV und LDK sollten auf jeden Fall beide so bleiben und hätten diesen Aufbau :
MOV | RD (5Bit) | RS (5Bit) | ungenutzt
LDK | RD (5Bit) | ungenutzt | Konstante (16Bit)
Wenn bei MOV RD und RS identisch sind lassen sich damit Spezial-Fälle umsetzen: z.B. wenn RD == RS == 0 zutrifft könnte damit ein NOP gemeint sein. Mit den Werten 1..31 in RD/RS lassen sich noch andere Spezial-Fälle abdecken. Solche Spezial-Fälle in einen vorhanden Befehl mit hinein zu kodieren spart Dir zwar OpCodes aber macht dafür den Decoder komplizierter, in der Pipeline hat das aber keine Konsequenzen da die Spezial-Fälle dort eh als eigenständige Befehle benötigt werden.

Zu Shiften und Rotieren reichen 4 Befehle da ROR sich durch ROL abbilden lässt und diese müssten folgenden Aufbau haben:
OpCode (4 aus 64) | RD (5Bit) | RS (5Bit) | ein Bit das unterschiedet ob der Anzahl der Shifts bzw. Rotationen als Konstante oder aus einem Register kommt | unbenutzt (10 Bit) | Konstante (4Bit) oder RS2 (5Bit)
woraus dann diese Mnemoniks entstehen : SHR, SHRI, SHL, SHLI, SAR, SARI, ROL, ROLI was in C so aussieht RD = RS [Operator] Konstante oder Variable (in RS2).

Bis jetzt sind es gerade mal 24 Befehle und wir haben schon fast alles was wichtig ist, es fehlen nur noch Multiplikation/Division, unbedingte Sprünge bzw. Funktionsaufrufe und die Speicherzugriffe.
Aber dazu schreibe ich später noch was wenn Du das wirklich möchtest (meine Beiträge ziehen sonst wieder so arge Kritik wegen ihrer übergebührlichen Länge auf sich ;) ).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 15. January 2013, 17:02
Braucht man mov denn jetzt noch in Hardware? Mit drei Operanden ist ein mov r1,r2 doch das gleiche wie ein add r1,r2,0.

Und fürs Shiften und Rotieren gab es doch diese coolen riscigen Bitschnippelbefehle, die erst rotieren und das Ergebnis dann maskieren. Wobei ich keine Ahnung habe, wie doof sowas umzusetzen ist. ;)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 15. January 2013, 17:34
Hallo,

Mh was sind ASCII Tabellen...und wie stelle ich die Normal dar ?  und Wofür brauch ich die ?  :-D
Damit kannst du Tabellen darstellen, ohne Tabellen benutzen zu müssen. Schau dir mal deinen Beitrag und meinen Beitrag an - bei mir sind in der Liste alle Zeichen gleich breit und alle Gleichheitszeichen stehen direkt übereinander. Das erhöht die Lesbarkeit. :-)

Im Zweifelsfall ist es ein Spezialfall von ASCII-Art, nur halt für Tabellen benutzt.

wollte aber jetzt eigentlich 32 register haben...aber naja ich kanns ja mal mit 16 versuchen ....
Dann nimmst du halt 5 Bit für "Source-Register" und 5 Bit für "Destination-Register"... ich wollte dir nur zeigen, wie du es einfacher machen kannst. Niemand hindert dich, die Bitaufteilung so zu machen, wie du sie für richtig hältst; aber fixe Bitgrenzen machen es viel einfacher zu implementieren.

Wo das NOP liegt ist mMn eher egal aber ich möchte Kevin zustimmen und würde dafür sorgen das wenn der Befehl komplett aus 0-Bits besteht das dann eine Undefined-OpCode-Exception kommt. Das selbe auch wenn der Befehl komplett aus 1-Bits besteht da viele FLASHs und EEPROMs im unprogrammierten Zustand immer 0xFF liefern.
Einverstanden, bedenke allerdings, dass es hier um eine simulierte CPU geht. :-)

Auf NOP ganz verzichten würde ich aber trotzdem nicht, ein NOP zeichnet sich meiner Meinung nach dadurch aus das dieser von keinem anderen Befehl abhängig ist und auch kein anderer Befehl vom NOP abhängt, bei einem MOV R0,R0 ist das nicht so einfach gegeben da es auch andere Befehle geben kann die R0 benutzen.
Ein guter Compiler darf, wenn R0 in Benutzung ist, auch ein MOV R1, R1 für NOP benutzen. Ansonsten gehe ich mal davon aus, dass Tufelix keine CPU mit superskalarem Pipelining baut, sondern eher eine von den Fähigkeiten aufgebohrte 8-Bit-Technologie mit breiteren Registern. Da ist es dann ziemlich egal, wie ein NOP nun dargestellt wird. Ich bezweifle, dass Tufelix die 16-Bit-Über-RISC-CPU mit Hardware-Realisierung im ASIC entwickeln will...

Braucht man mov denn jetzt noch in Hardware? Mit drei Operanden ist ein mov r1,r2 doch das gleiche wie ein add r1,r2,0.
MIPS hat ein Nullregister, mit dem das geht. Konstanten finde ich aber flexibler (außerdem kriegst du ein zusätzliches Allzweckregister geschenkt). Tufelix hat bisher dazu nichts geschrieben. :-P

Und fürs Shiften und Rotieren gab es doch diese coolen riscigen Bitschnippelbefehle, die erst rotieren und das Ergebnis dann maskieren. Wobei ich keine Ahnung habe, wie doof sowas umzusetzen ist. ;)
Dazu brauchst du einen Barrel-Shifter und zusätzliche Bits im Opcode, daher wurden die bei Thumb/Thumb-2 m.W. abgeschafft. Der originale 32-Bit-ARM-Befehlssatz hat sowas aber im Befehl codiert, ja.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: kevin am 15. January 2013, 20:45
Braucht man mov denn jetzt noch in Hardware? Mit drei Operanden ist ein mov r1,r2 doch das gleiche wie ein add r1,r2,0.
MIPS hat ein Nullregister, mit dem das geht. Konstanten finde ich aber flexibler (außerdem kriegst du ein zusätzliches Allzweckregister geschenkt). Tufelix hat bisher dazu nichts geschrieben. :-P
Ich rede vom mov, das braucht kein Nullregister, wenn man ein addi hat. Das ldk zu emulieren bräuchte ohne Nullregister zwei Befehle, das stimmt (xor r1, r1, r1; addi r1, r1, $1234)

Zitat
Dazu brauchst du einen Barrel-Shifter und zusätzliche Bits im Opcode, daher wurden die bei Thumb/Thumb-2 m.W. abgeschafft. Der originale 32-Bit-ARM-Befehlssatz hat sowas aber im Befehl codiert, ja.
Bits im Opcode haben wir ja massig übrig.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 15. January 2013, 22:16
Zitat
MIPS hat ein Nullregister, mit dem das geht. Konstanten finde ich aber flexibler (außerdem kriegst du ein zusätzliches Allzweckregister geschenkt). Tufelix hat bisher dazu nichts geschrieben. :-P
Nun ich behalte glaub den Mov- und den ldk-Befehl. Für den NOP-Befehl benutze ich ein MOV R1,R1 mein CPU wird erstmal ohne Pipeline arbeiten, da wird es sicherlich keine Probleme wegen der abhängigkeit geben...

Werde dann wohl auch die 3-Operanten Befehle einbauen...

Bei den Jumps mach ich das so wie Wikinger Beschrieben hat.(also das mit den 6 Varianten).

Zitat
Dazu brauchst du einen Barrel-Shifter und zusätzliche Bits im Opcode, daher wurden die bei Thumb/Thumb-2 m.W. abgeschafft. Der originale 32-Bit-ARM-Befehlssatz hat sowas aber im Befehl codiert, ja.
Barrel-shifter könnte ich eigentlich auch einbauen... dann werd ich auf die ersten 4 bits der Konstanten-bits die distanz-bits legen.

Nun kann man eigentlich etwas an den Load und Store-Bits verbessern ?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 18. January 2013, 14:33
Hallo,


Wobei ich keine Ahnung habe, wie doof sowas umzusetzen ist.
Ziemlich doof, glaub mir.
Außerdem ist ARM32 meines Wissens nach die einzigste real existierende CPU die sowas überhaupt hat (auch in ARM64 ist das wohl nicht mehr drin), was sicher auch etwas über die Nützlichkeit dieses Features aussagt.


mein CPU wird erstmal ohne Pipeline arbeiten, da wird es sicherlich keine Probleme wegen der abhängigkeit geben...
Ja, bei mit ohne Pipeline sollte das keine Probleme mit der Performance o.ä. machen.

Werde dann wohl auch die 3-Operanten Befehle einbauen...
Das alleine bringt schon einiges an Performance weil weniger Befehle für die selbe Sache benötigt werden.

Barrel-shifter könnte ich eigentlich auch einbauen
Ich denke das solltest Du fürs erste lassen, damit wird Deine CPU um einiges komplexer und vor allem wird die Codierung der Befehle deutlich komplexer. Versuch doch erst mal eine möglichst einfache CPU zuverlässig ans laufen zu bekommen bevor Du Dir die nächste Schwierigkeitsstufe vornimmst. ARM hat diese Shifter-Operanden auch nur bei manchen Befehlen und für Konstanten, letzteres Problem hast Du nicht weil Du in Deine 32Bit Befehle eine 16Bit-Konstante immer ohne Verrenkungen komplett rein bekommst.

dann werd ich auf die ersten 4 bits der Konstanten-bits die distanz-bits legen.
Hä, wie meinen?

Nun kann man eigentlich etwas an den Load und Store-Bits verbessern?
Versuch doch erst mal Dein Konzept als ganzes mit den jüngsten Vorschlägen dieses Thread neu aufzubauen und dann sehen wir wie weiter verbessert werden kann.

Zu MUL/DIV möchte ich aber dennoch was schreiben: Du solltest Dir überlegen ob Du das Produkt der Multiplikation in voller Bitgröße haben willst was eben immer 2 Ziel-Register erfordert, solange Du nur die untere Hälfte des Produkts hast brauchst Du auch nicht zwischen signed und unsigned unterscheiden aber wenn Du mehr willst musst Du das beachten. Auch für die Division könnte es sich lohnen wenn Du zwei Ziel-Register ansprechen kannst da es ja dort noch den Rest gibt (wird u.a. für den %-Operator von C benötigt). Bei der Division muss wimre immer zwischen signed und unsigned unterschieden werden. Ein Speicher-Lesebefehl mit Pre/Post-Inkrement/Dekrement hat auch immer 2 Ziel-Register (das wo die gelesenen Daten rein gelegt werden und das Adressregister das modifiziert wird).


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 18. January 2013, 17:01
Ich glaube, wir reden aneinander vorbei, Erik. Ich hab mal das Internet befragt und vermute, dass du das Feature meinst, das den zweiten Operanden shiften kann, bevor er verarbeitet wird. Auch eine lustige Idee, aber das habe ich nicht gemeint. ;)

Ich rede von Instruktionen wie rlwimi oder rlwinm auf PPC.
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 18. January 2013, 19:33
Hallo,


Ich glaube, wir reden aneinander vorbei, Erik.
Ja, das glaube ich jetzt auch. Fragt sich nur was Tufelix dachte.

Ich rede von Instruktionen wie rlwimi oder rlwinm auf PPC.
Ja, diese beiden Befehle sind cool. rlwimi hab ich auf meiner CPU auch aber etwas anders, es geht dabei ja im Prinzip darum aus einem Register von einem beliebigen Bitoffset eine bestimmte Anzahl an Bits (zusammenhängend aber ggf. mit Umlauf) aus einem Register raus zu holen und in ein anderes Register an einem anderen beliebigen Bitoffset rein zu packen (auch wieder zusammenhängend mit optionalem Umlauf) und die übrigen Bits des Zielregisters unverändert zu lassen. lrwinm hab ich aber nicht als Einzelbefehl da sich sowas auch einfach mit einer Rotation und einem anschliessendem AND darstellen lässt (wobei ich das dank des Shifter-Operanden, den ich doch vorgesehen habe, auch als Einzelbefehl haben kann aber dafür die Maske bereits in einem anderen Register vorhanden sein muss) und ich auch nicht so ganz sicher bin ob man sowas oft braucht.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 19. January 2013, 11:10
Zitat
Hä, wie meinen?
Mhh ich glaub ich hab da was verwechselt. :roll:

Zitat
Ja, das glaube ich jetzt auch. Fragt sich nur was Tufelix dachte.
Dachte an Shift-Befehle so wie wikinger beschrieben hatte...
Zitat
Zu Shiften und Rotieren reichen 4 Befehle da ROR sich durch ROL abbilden lässt und diese müssten folgenden Aufbau haben:
OpCode (4 aus 64) | RD (5Bit) | RS (5Bit) | ein Bit das unterschiedet ob der Anzahl der Shifts bzw. Rotationen als Konstante oder aus einem Register kommt | unbenutzt (10 Bit) | Konstante (4Bit) oder RS2 (5Bit)
woraus dann diese Mnemoniks entstehen : SHR, SHRI, SHL, SHLI, SAR, SARI, ROL, ROLI was in C so aussieht RD = RS [Operator] Konstante oder Variable (in RS2).

Wofür braucht man eigentlich die Sprungbefehle JA,JAE,JB,JBE. Kann man da nicht für JA auch ein JE Befehl nehmen und für JB ein JL ?

Zitat
Zu MUL/DIV möchte ich aber dennoch was schreiben: Du solltest Dir überlegen ob Du das Produkt der Multiplikation in voller Bitgröße haben willst was eben immer 2 Ziel-Register erfordert, solange Du nur die untere Hälfte des Produkts hast brauchst Du auch nicht zwischen signed und unsigned unterscheiden aber wenn Du mehr willst musst Du das beachten. Auch für die Division könnte es sich lohnen wenn Du zwei Ziel-Register ansprechen kannst da es ja dort noch den Rest gibt (wird u.a. für den %-Operator von C benötigt). Bei der Division muss wimre immer zwischen signed und unsigned unterschieden werden. Ein Speicher-Lesebefehl mit Pre/Post-Inkrement/Dekrement hat auch immer 2 Ziel-Register (das wo die gelesenen Daten rein gelegt werden und das Adressregister das modifiziert wird).
Mhh wenn ich jetzt schon 2 Quellregister hab könnte ich eigentlich ja auch 2 Zielregister einbauen...was passiert eigentlich wenn man bei den 2. Zielregister das selbe Register angibt wie beim ersten Zielregister ?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 19. January 2013, 11:54
Hallo,


Dachte an Shift-Befehle so wie wikinger beschrieben hatte...
Okay, ich denke das Svenska auch an diesen Shifter-Operanden von ARM dachte den die speziellen PPC-Befehle haben 5 Operanden und sowas gibt es wimre beim klassischen ARM32 nicht (diese 5 Operanden würden bei ARM32 zusammen 23 Bit belegen).

Wofür braucht man eigentlich die Sprungbefehle JA,JAE,JB,JBE. Kann man da nicht für JA auch ein JE Befehl nehmen und für JB ein JL?
JA (>) und JE (==) sind zwei unterschiedliche Dinge und deswegen wirst Du auch beide brauchen. JL und JB sind auch unterschiedlich da ersteres für signed und letzteres für unsigned ist. Bitte beschäftige Dich mal mit der Zahlendarstellung im Zweierkomplement für signed und unsigned.
Das Zitat mit den Shift-Befehlen passt zu Deiner Frage nicht.

Mhh wenn ich jetzt schon 2 Quellregister hab könnte ich eigentlich ja auch 2 Zielregister einbauen
Solange Du nur bei Registern bleibst sollten in Deine 32Bit-Befehle locker 4 Operanden rein passen aber es gibt nur wenige Befehle die so viele Operanden wirklich benötigen und in Deiner Pipeline (also in der internen dekodierten Befehlsdarstellung) musst Du trotzdem immer 4 Operanden vorsehen (auch bei Befehlen die das nicht nutzen). Damit wäre ein R1 * R2 := R3:R4 möglich (R3 ist der High-Part des Produkts und R4 der Low-Part).
Bei der Division wird es aber noch schwieriger, eine vollwertige Division ist eigentlich ein 5 Operanden-Befehl: R1:R2 / R3 = R4,R5 (R1 ist der High-Part des Dividend und R2 der zugehörige Low-Part, R3 der Divisor, R4 der Quotient und R5 der Rest). Bei Deinen 32Bit-Befehlen sollten auch 5 Register problemlos kodierbar sein aber das macht Deine interne Darstellung sehr umfangreich. Hier kommst Du eben in das Problem das Du dafür eine fette interne Befehlsdarstellung brauchst die aber nur von sehr wenigen Befehlen wirklich ausgereizt wird.

was passiert eigentlich wenn man bei den 2. Zielregister das selbe Register angibt wie beim ersten Zielregister?
Das musst Du als CPU-Designer festlegen. Deswegen wolltest Du doch diesen Job, oder? ;)
Auf meiner CPU ist das verboten, der Decoder wird solche Befehle als Undefined-OpCode verwerfen und es kommt eine Exception. Aber es macht auch den Decoder komplexer wenn er für jeden Befehl individuell prüfen muss ob die aktuelle Kombination aus Operanden gültig ist, hier ist es wichtig ein gutes Mittelmaß zu treffen damit der Decoder mindestens den kritischen Unfug abfängt aber auch nicht zu komplex wird. Dieses Problem existiert auch bei den Speicher-Lesebefehlen wenn das Zielregister mit dem Adressregister übereinstimmt, theoretisch sollte das funktionieren aber wenn Du das Adressregister Inkrementierst/Dekrementierst darf es nicht noch zusätzlich mit den gelesenen Daten überschrieben werden.


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 19. January 2013, 19:23
Zitat
JA (>) und JE (==) sind zwei unterschiedliche Dinge und deswegen wirst Du auch beide brauchen. JL und JB sind auch unterschiedlich da ersteres für signed und letzteres für unsigned ist. Bitte beschäftige Dich mal mit der Zahlendarstellung im Zweierkomplement für signed und unsigned.
Das Zitat mit den Shift-Befehlen passt zu Deiner Frage nicht.
Ah, ich glaub jetzt hab ichs verstanden  :-D

Zitat
Das musst Du als CPU-Designer festlegen. Deswegen wolltest Du doch diesen Job, oder? ;)
Auf meiner CPU ist das verboten, der Decoder wird solche Befehle als Undefined-OpCode verwerfen und es kommt eine Exception. Aber es macht auch den Decoder komplexer wenn er für jeden Befehl individuell prüfen muss ob die aktuelle Kombination aus Operanden gültig ist, hier ist es wichtig ein gutes Mittelmaß zu treffen damit der Decoder mindestens den kritischen Unfug abfängt aber auch nicht zu komplex wird. Dieses Problem existiert auch bei den Speicher-Lesebefehlen wenn das Zielregister mit dem Adressregister übereinstimmt, theoretisch sollte das funktionieren aber wenn Du das Adressregister Inkrementierst/Dekrementierst darf es nicht noch zusätzlich mit den gelesenen Daten überschrieben werden.
Mhh man kann auch doch nur bei ein paar bestimmten Befehlen prüfen ob die Operanden gültig sind(also bei Befehlen wo das wirklich nötig ist)

Nun ich hab jetzt mal mein Instuktions set verbessert:



arithmetische Befehle:
Opcode:(11 aus 64)|Rd(5 bits) |Rs1(5bits) |Konstante(16 bit) oder Rs2(5 bit)
---------------------------------------------------------------------
1 |ADD |Rd,Rs |Addiert |Rd+Rs -> Rd
---------------------------------------------------------------------
2 |ANDI |Rd,Wert |Addiere Wert dazu |Rd+Wert -> Rd
---------------------------------------------------------------------
3 |Sub |Rd,Rs1,Rs2 |Subtrahiert |Rs1-Rs2 -> Rd
---------------------------------------------------------------------
4 |SUBI |Rd,Rs1,Wert |Subtrahiere wert ab |Rs1-wert -> Rd
----------------------------------------------------------------------
5 |SUBI |Rd,Rs1,Wert |Subtrahiere Rs1 ab |Wert-Rs1 -> Rd
-----------------------------------------------------------------------
6 |AND |Rd,Rs1,Rs2 |AND |Rs1•Rs2 -> Rd
-----------------------------------------------------------------------
7 |ANDI |Rd,Rs1,wert |AND mit Wert |Rs1•wert -> Rd
-----------------------------------------------------------------------
8 |OR |Rd,Rs1,Rs2 |OR |Rs1 v Rs2 -> Rd
------------------------------------------------------------------------
9 |ORI |Rd,Rs1,wert |OR mit wert |Rs1 v Wert -> Rd
-------------------------------------------------------------------------
10 |XOR |Rd,Rs1,Rs2 |XOR |Rs1 "Xor" Rs2 -> Rd
---------------------------------------------------------------------------
11 |XORI |Rd,Rs1,Wert |XOR mit wert |Rs1 "Xor" wert -> Rd
-----------------------------------------------------------------------------

Spring-Befehle:
Opcode:(9 aus 64) |Rd(5 bits)| Rs(5 Bits)| Adresse(16 bits)
-------------------------------------------------------------------
12 |JA |Rd,Rs,Adresse |Spr. wenn darüber |Rd<Rs
-------------------------------------------------------------------
13 |JAE |Rd,Rs,Adresse |Spr. wenn Gl. oder dar.|Rd<=Rs
-------------------------------------------------------------------
14 |JG |Rd,Rs,Adresse |Spr. wenn größer |Rd<Rs
-------------------------------------------------------------------
15 |JGE |Rd,Rs,Adresse |Spr. wenn Gl oder gr. |Rd<=Rs
-------------------------------------------------------------------
16 |JE |Rd,Rs,Adresse |Spr. wenn gleich |Rd==Rs
-------------------------------------------------------------------
17 |JNE |Rd,Rs,Adresse |Spr. wenn nicht gleich |Rd!=Rs
-------------------------------------------------------------------
18 |JSR |Adresse |Springe, ablage des CP |[FP-1]<-CP, Adresse->CP
--------------------------------------------------------------------
19 |RTS | |Rücksprung aus UP |[FP-1]->CP
--------------------------------------------------------------------
20 |RTI | |Rücksprung aus ISR |[FP-1 bis FP-32] -> Registerblock
--------------------------------------------------------------------

Shift-Befehle
Opcode:(4 von 64) |Rd(5 bits) | Rs1(5 bits)|"Kon-or-Rx-Bit"(1 bit)|10 bit unbenutzt|Konstante(4 bit) oder Rs2(5 bit)
--------------------------------------------------------------------
21 |SHR |Rd,Rs1 or wert |shift logi. nach rechts
--------------------------------------------------------------------
22 |SHL |Rd,Rs1 or wert |shift logi. nach links
--------------------------------------------------------------------
23 |SAR |Rd,Rs1 or wert |shift arith. nach rechts
--------------------------------------------------------------------
24 |ROR |Rd,Rs1 or wert |rotieren logisch nach rechts
--------------------------------------------------------------------

Register-Transfer-Befehle
Opcode:(2 von 64)|Rd(5 bits) |Rs(5bits) |Konstante(16 bits)
--------------------------------------------------------------------
25 |MOV |Rd,Rs |Kopiere Register |Rs->Rd
--------------------------------------------------------------------
26 |LDK |Rd,wert |Lade Konstante |wert->Rd
--------------------------------------------------------------------

Multipliezieren/Dividierern
Opcode:(2 aus 64)|Rd(5) oder Rs(5)|Rs1(5 bits)|Rs2(5Bits)|Rs3(5 bits)|Rd1(5 bits)|
---------------------------------------------------------------------
27 |MUL |Rd,Rd1,Rs1,Rs2 |MUL |Rs1*Rs2->Rd:Rd1
---------------------------------------------------------------------
28 |DIV |Rd,Rd1,Rs1,Rs2,Rs3|Div |Rs1:Rs2/Rs3->Rd,Rd1
------------------------------------------------------------------------

Store und LOAD
OPCODE(2 aus 64)|Rd(5 bits)|Rs1(5 bits)|Controll-Bits(4 bits)|4 bit unbenutzt|Offset(8 bit) oder Rs2(5 bits)
-----------------------------------------------------------------------
29 |Load |Rd,Rs1,wert,Rs2|Load²
-----------------------------------------------------------------------
30 |Store |Rd,Rs1,wert,Rs2|Store³
-----------------------------------------------------------------------

²Es gibt 9 adressierungsarten, diese werden über die Controllbits festgelegt.
------------------------------------------------------------------------
LOAD |Rd,Rs1 |Lade |[Rs1]->Rd
------------------------------------------------------------------------
LDPOI |Rd,Rs1 |Lade, Post-Increment |[Rs1]->Rd, Rs+1->Rs1
-------------------------------------------------------------------------
LDPOD |Rd,Rs1 |Lade, Post-Decrement |[Rs1]->Rd, Rs1-1->Rs1
-------------------------------------------------------------------------
LDPRI |Rd,Rs1 |Lade,Pre-Increment |[Rs1+1->Rs1]->Rd
-----------------------------------------------------------------------
LDPRD |Rd,Rs1 |Lade,Pre-Decrement |[Rs1-1->Rs1]->Rd
-----------------------------------------------------------------------
LDAR |Rd,Rs1,Rs2 |Lade,Add Register |[Rs1+Rs2]->Rd
-----------------------------------------------------------------------
LDSR |Rd,Rs1,Rs2 |Lade,Sub Register |[Rs1-Rs2]->Rd
-----------------------------------------------------------------------
LDAW |Rd,wert(8 bit) |Lade, Add Wert |[Rs1+wert]->Rd
-----------------------------------------------------------------------
LDSW |Rd,wert(8 bit) |Lade, sub wert |[Rs1-wert]->Rd
-----------------------------------------------------------------------

³Auch hier gibts 9 adressierungsarten:

-------------------------------------------------------------------------
ST |Rs,Rs1 |Speicher,aus Bussystem |[Rs1]<-Rs
-------------------------------------------------------------------------
STPOI |Rs,Rs1 |Speicher,Post-Increment|[Rs1]<-Rs, AP+1->AP
-------------------------------------------------------------------------
STPOD |Rs,Rs1 |Speicher,Post-Decrement|[Rs1]<-Rs, AP-1->AP
-------------------------------------------------------------------------
STPRI |Rs,Rs1 |Speicher,Pre-Increment |[Rs1+1->AP]<-Rs
-----------------------------------------------------------------------
STPRD |Rs,Rs1 |Speicher,Pre-Decrement |[Rs1-1->AP]<-Rs
-----------------------------------------------------------------------
STAR |Rs,Rs1,Rs2 |Speicher,Add Register |[Rs1+Rs2]<-Rs
-----------------------------------------------------------------------
STSR |Rs,Rs1,Rs2 |Speicher,Sub Register |[Rs1-Rs2]<-Rs
-----------------------------------------------------------------------
STAW |Rs,wert(8 bit) |Speicher, Add Wert |[Rs1+wert]<-Rs
-----------------------------------------------------------------------
STSW |Rs,wert(8 bit) |Speicher, sub wert |[Rs1-wert]<-Rs
-----------------------------------------------------------------------

jetzt kann man auch alle register als adressregister benutzen.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 19. January 2013, 20:51
LDK ist nur sinnvoll, wenn man deutsch versteht. :-)
Sonst benutzt du Pärchen wie AND/ANDI, für Konsistenz könntest du z.B. LD/LDI benutzen. Ist aber nur eine Bezeichnung im Assembler. Ansonsten würden mich noch die Opcodes in Binär-/Hexschreibweise interessieren, weil ich einfaches Durchnummerieren immernoch als unschön empfinde. :-)

Ansonsten sieht es für mich stimmig aus.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 20. January 2013, 20:17
Hallo Tufelix,


dem was Svenska geschrieben hat kann ich nur zustimmen, aber ich hab noch ein paar weitere kleinere Problemchen gefunden (ja ich weiß das ihr alle meinen Perfektionismus ganz arg liebt):

Mhh man kann auch doch nur bei ein paar bestimmten Befehlen prüfen ob die Operanden gültig sind(also bei Befehlen wo das wirklich nötig ist)
Ja, konzentriere Dich ruhig erst mal darauf das der Decoder die echt kritischen Dinge abfängt und den Rest kannst Du erst mal dem Assembler überlassen (also das dieser bestimmte Operanden-Kombinationen bei bestimmten Befehlen einfach nicht umsetzt, grundsätzlich sollte der Assembler keine Befehle umsetzen die die CPU bekanntermaßen nicht ausführen möchte oder die sonstwie problematisch sind). Mach Dir doch einfach dazu noch ein paar Gedanken und schreibe bei den Befehlen wo es Einschränkungen (von der CPU) geben soll diese mit dazu.

jetzt kann man auch alle register als adressregister benutzen.
Sehr gut, Du musst ja nicht gleich alles in Deiner CPU unterstützen was der OpCode theoretisch her gibt.


Man sieht auf jeden Fall das es vorwärts geht, weiter so! :-D
Und lass Dich nicht von so Miesepetern wie Kevin verunsichern, der Weg zu einer echten vollwertigen CPU ist nunmal nicht ganz so leicht wie bei einem OS das nur gut ausgetrampelten Pfaden folgt. (ich glaub jetzt mag er mich endgültig nicht mehr)


Grüße
Erik
Titel: Re: Logisim CPU
Beitrag von: kevin am 20. January 2013, 20:47
Und lass Dich nicht von so Miesepetern wie Kevin verunsichern
:?
Titel: Re: Logisim CPU
Beitrag von: erik.vikinger am 20. January 2013, 21:25
:?
Entschuldige Bitte, aber Du weißt was ich meine.
Titel: Re: Logisim CPU
Beitrag von: kevin am 20. January 2013, 23:00
Nein. Ich wüsste nicht, dass ich an Tufelix' Ideen rumkritisiert hätte, das haben andere getan.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 22. January 2013, 16:23
Zitat
Nr. 27,28 (MUL/DIV) diese beiden Befehle benötigst Du in jedem Fall jeweils für signed und unsigned, für schnelle Adressberechnung wäre auch eine simple Form der Multiplikation (nur Rs1 * Rs2 -> Rd, keine Unterscheidung zwischen signed und unsigned) nützlich
Nun was ist bei einer Unsigned-multiplikation anders wie bei ner signed?

Zitat
Nr. 29,30 (Load/Store) hier müsstest Du Bitte mal die Kodierung der einzelnen Adressierungsarten näher beschreiben (da reichen die hinteren 16 Bit des Befehls) und die Konstante könnte ruhig auch 12 Bit groß sein (ich denke das passt rein)

Naja ,je nachdem wie man die controllbits setzt wird ein andere adressierungsart ausgewählt(wird Pre/post -inkrementieren/decrementieren als adressierungsart ausgewählt wird zusätzlich geprüft ob die Operanten stimmen.). Dann wird je nach adressierungsart die ersten 5 bits als adresse für ein register bzw die ersten 12 bits als offset benutzt. Auserdem wird bei Store-Befehle, die Rd adresse für Rs benutzt(hab das vergessen im Instruktionsset anzugeben  :-D).
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 24. January 2013, 19:54
Zitat
Zitat
Zitat
    Nr. 27,28 (MUL/DIV) diese beiden Befehle benötigst Du in jedem Fall jeweils für signed und unsigned, für schnelle Adressberechnung wäre auch eine simple Form der Multiplikation (nur Rs1 * Rs2 -> Rd, keine Unterscheidung zwischen signed und unsigned) nützlich
Nun was ist bei einer Unsigned-multiplikation anders wie bei ner signed?
Aja ich glaub ich blick langsam durch... diese Multiplizier/Dividiere-Einheit in logisim kann wohl nur unsigned... daher werd ich glaub zunächst Div/Mul-Signed Befehle drausen lassen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 26. January 2013, 23:17
Nun ich hab mal angefangen einen Prototyp zu bauen...Was mir noch Probleme macht ist die CU einheit (bzw. Befehls-decoder), hat da jemand nen tipp wie man die am besten baut ?
Titel: Re: Logisim CPU
Beitrag von: chris12 am 26. January 2013, 23:19
CU, ka, was soll das heißen?

Befehlsdecoder hast du zwei möglichkeiten:
a) alle befehle mittels decodern aufdröseln und hart verdraten, oder
b) mittels microprogrammsteuerwerk die einzelnen leitungen einzeln schalten und alle befehle einprogrammieren
Titel: Re: Logisim CPU
Beitrag von: Svenska am 27. January 2013, 01:43
Hallo,

Was mir noch Probleme macht ist die CU einheit (bzw. Befehls-decoder), hat da jemand nen tipp wie man die am besten baut ?
Du könntest mit einem Demultiplexer dekodieren. N Eingänge, 2^N Ausgänge (N=Anzahl der Opcode-Bits). Jeder Ausgang ist eine ENABLE-Leitung und schaltet einen ganz bestimmten Befehl aktiv. Alle Bits nach dem Opcode gehen in alle Befehle.

Darum hatte ich dir übrigens empfohlen, die Befehle an Bitgrenzen in Gruppen zu teilen, so dass du erst die vorderen Bits in die Gruppen dekodierst (und dann wegwirfst), dann innerhalb jeder Gruppe die vorderen Bits in die Befehle dekodierst (und dann wegwirfst) und zum Schluss die restlichen Bits in die Befehlsvariante plus Operanden aufspaltest. Dann hast du zwar mehrere Multiplexer hintereinander, aber die sind alle kleiner (z.B. 2^3 Gruppen und 2^5 Befehle/Gruppe statt 2^8 Befehle).

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. February 2013, 23:02
Nun, hab mir überlegt das ich sowas ähnliches wie Svenska beschrieben hat bauen werde...die Opcode-Bits dienen als adresse für zwei ROMs. In der einen steht wohin die 26 restlichen bits gehen soll, und in der anderer wie die Steuerleitungen geschaltet werden. Die max. Wortbreite(32 bit) einer einzelen Rom hatte nicht gereicht um alles unterzukriegen daher hab ich mal 2 eingeplant. Auserdem hab ich den Befehlsatz etwas vereinfacht: Hauptproblem waren de LOAD und STORE Befehle sowie die Shift-Befehle, die verschiedene Adressierungsarten hab ich jetzt direkt als Befehle eingebaut, bei den Shift-Befehle hab ich den Wahlbit für Konstante oder Register rausgenommen und stattessen jeweils die 4 shift-Befehle mit einer Konstante als Distanz-Bit² und die 4-shift-befehle mit einem Register als Distanz-Bit².

² Distanz-Bit stet für wie weit die eingangs-bit zu schieben sind.

Auserdem wollte ich für das interrupt-signal ein Flip-Flop in der instruktions-decoder einbauen, bei einem interrupt sollte der stand des CP-registers auf den Stack gepusht werden, und dann zu dem Programm gesprungen werden was die restlichen Register pusht(die adresse des Programms ist von dem instruktions-decoder vorgegeben) Das ende des Programms wird mit einem Noop-befehl gekennzeichnet, der instruktions-decoder wird dann die Programm-adresse vom interrupt aus dem Ram in den CP geladen(also aus dem Interrupt-vektor)...
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 11. February 2013, 15:32
kennt eigentlich einer ne website wo genau beschrieben ist wie so ein instruktions-decoder aufgebaut ist ?
Titel: Re: Logisim CPU
Beitrag von: MNemo am 11. February 2013, 16:05
Hier gibt es einen Folien Satz zu einer Vorlesung die den Aufbau schritt für schritt erklärt: MIPS-PDF (http://www.iss.tu-darmstadt.de/student_area/tgdi/folien/Kapitel07v5.pdf) (Webseite (http://www.iss.tu-darmstadt.de/student_area/tgdi))

PC steht für Program-Counter und entspricht dem i386 Instruction-Pointer (E)IP
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 23. February 2013, 16:44
Nun bei mir ist es ja so das man bei Mul 4 und bei Div 5 register angeben muss, gibt es sowas auch bei anderen architekturen ?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 01. March 2013, 19:24
Nun, ich hab jetzt ein wenig meine architektur umgebaut... ansich bleibt alles beim alten nur das es jetzt eine Von-Neuman architektur ist... Fals die CPU dann etwas in bzw. aus dem Bus laden möchte wird der CP und das Laden eines Neuem Befehls für einen taktzyklus angehalten. Auserdem hab ich die Architektur auf 32 bit erweitert, wenn man z.b einen Wert mit einem register addieren möchte, wird der 16 bit Wert mit einem Vorzeichenerweiterer auf 32 bit erweitert.Zudem, ist es dann sinvoll 2 LDK befehle einzubauen ? Also das der eine Befehl seinen 16 bit wert in die untere Hälfte des Registers ladet und der andere Befehl seinen wert in obrige Hälfte ladet.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. March 2013, 11:58
soll ich die Jump-adresse eines Jump-Befehles auch Vorzeichenerweitern ?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 24. March 2013, 15:52
Nun ich hab jetzt 3 ldk befehle eingebaut, einmal "ldk16": ladet ein 16 bit unsigned-wert in ein register. Dann "ldsk16" ladet ein 16 bit signed wert in ein register und dann noch "ldk32" der ladet ein 32 bit wert in ein Register, dabei steht der 32 bit wert in der nächsten adresse des PC. Ist das so ok oder soll ich bei den Befehlen was ändern?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 24. March 2013, 16:31
Das musst du wissen, darum entwickelst du ja die CPU. :-)
Mach dich nicht zu sehr verrückt, du wirst beim Programieren schon feststellen, was fehlt oder unhandlich gelöst ist - und beim Aufbau, was zu komplex ist. Auf Anhieb schaffts eh keiner richtig.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 24. March 2013, 16:38
mmh ok, dann bau ich mal meine CPU zuende :D
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. April 2013, 14:30
Gibt es eigntlich eine art schaltung die bei einem stacküberlauf eine Exception auslöst ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 02. April 2013, 17:05
Hallo,

Exceptions funktionieren alle gleich, egal ob Stack-Overflow, Undefined Opcode oder Division By Zero, d.h. von verschiedenen Teilen der CPU kommen Leitungen zur Interruptverarbeitung.

Um Stack-Overflows erkennen zu können, gibt es zwei Bedingungen:
- Die CPU muss Stackzugriffe von normalen Speicherzugriffen unterscheiden können. (Im einfachsten Fall prüfst du nur bei PUSH und POP.)
- Die CPU muss die Größe (Anfang und Ende) des aktiven Stacks kennen und bei Stackzugriffen mit dem Stackpointer vergleichen.

Bedenke, dass du wahrscheinlich mehrere Stacks in deinem System haben wirst (pro Thread einen, plus Kernelstack) und zwischen diesen auch umschalten können musst. Während du umschaltest, ist der Stack ungültig - da sollte diese Exception nicht auftreten dürfen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 04. April 2013, 12:52
Mhh wie wurde sowas in anderen Systemen umgesetzt ?
Titel: Re: Logisim CPU
Beitrag von: Jidder am 04. April 2013, 18:34
Auf x86 können Stack Overflows eigentlich nur durch das Segment Limit erkannt werden. Aber da man heutzutage in der Regel das Limit so setzt, dass die Segmente den gesamten Adressraum überspannen, werden mit diesem Mechanismus keine Stack Overflows erkannt. Wenn das Betriebssystem Paging nutzt, können Stack Overflows unter bestimmten Bedingungen abgefangen werden, indem Seiten direkt unter dem Stack nicht gemappt werden und so beim Zugriff einen Page Fault auslösen. Dann hast du allerdings immer noch das Risiko, dass der Stack Overflow in einem einzigen Schritt so groß ausfallen könnte, dass er diesen geschützen Bereich einfach überspringt, und dann weiter entfernt vom Stack Schaden anrichtet.

Das Problem ist also immer, dass die CPU wissen muss, wo eigentlich der Stack beginnt und endet. Wenn du das mit Segmenten machst, hast du das Problem, dass das von Hochsprachen wie C eher nicht unterstützt wird oder unperformant ist, und wenn du es mittels Paging machst, hast du immer eine Unsicherheit drin.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 07. April 2013, 13:01
Nun mal ne blöde frage, was darf überhapt alles ein thead ? Darf der nur auf seinen Stack-bereich und der Bereich wo die Befehle liegen zugreifen oder darf er auch daten laden die sich nicht in seinem Stack befinden?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 07. April 2013, 13:50
Gegenfrage: Was unterscheidet Threads von Prozessen?
Titel: Re: Logisim CPU
Beitrag von: Roadrunner am 07. April 2013, 21:14
Ein Prozess kann aus einem oder mehreren Threads bestehen, aber einem Thread ist genau ein Prozess zugeordnet. Jeder Prozess erhält eigenen Speicher etc., während die Threads sich den Speicher und die restlichen Ressourcen, die dem Prozess zustehen, teilen müssen.

Also ist die Frage, was ein Thread darf, wohl eher die Frage, was der Prozess darf. Als Userspace-Prozess vermutlich eher wenig.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 08. April 2013, 01:31
Und wieder habe ich einen Ironiedetektor überlistet...
Das richtete sich an Tufelix, denn die Antwort auf seine Fragen ergeben sich von selbst, wenn er meine Frage beantwortet. Nun ist es zu spät, daher hier die Auflösung:

Nun mal ne blöde frage, was darf überhapt alles ein thead ?
Ein Thread darf das, was ein Prozess darf. Was genau das ist, entscheidest du als Entwickler von CPU und Betriebssystem. :-)

Darf der nur auf seinen Stack-bereich und der Bereich wo die Befehle liegen zugreifen oder darf er auch daten laden die sich nicht in seinem Stack befinden?
Alle Threads eines Prozesses teilen sich einen Adressraum (das ist der Sinn von Threads). Das heißt, dass jeder Thread grundsätzlich auf alles zugreifen darf, was diesem Prozess zugeordnet ist - konkret also Code, (globale) Daten und alle(!) Stacks des Prozesses. Dazu kommt eventuell noch Thread-Local Storage.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Roadrunner am 15. April 2013, 15:04
Zitat
Und wieder habe ich einen Ironiedetektor überlistet...
Das hatte ich befürchtet. Allerdings war ihm damit wohl wenig geholfen, weshalb ich die Auflösung gleich mal angehängt habe.

Aber eine andere Frage: Was meinst du mit Thread-Local Storage? Schließlich teilen sich alle Threads meines Wissens nach den gleichen Speicher, oder etwa nicht?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 15. April 2013, 16:50
Zitat
Und wieder habe ich einen Ironiedetektor überlistet...
Das hatte ich befürchtet. Allerdings war ihm damit wohl wenig geholfen, weshalb ich die Auflösung gleich mal angehängt habe.
Selber denken macht schlau. :P

Was meinst du mit Thread-Local Storage? Schließlich teilen sich alle Threads meines Wissens nach den gleichen Speicher, oder etwa nicht?
Die Suchmaschine des geringsten Misstrauens wirft folgenden Link (http://en.wikipedia.org/wiki/Thread-local_storage) als erstes Ergebnis zu der Frage aus. TLS ist eigentlich ein Workaround für historisch gewachsene Dinge, die Multithreading behindern, wie z.B. errno.

Oder als Frage an die Spezialisten: Gibt es da noch andere sinnvolle Einsatzzwecke für?

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: XanClic am 15. April 2013, 19:30
Ich persönlich hab da noch die PID, die PPID und die PGID drin, aber na ja…
Titel: Re: Logisim CPU
Beitrag von: Svenska am 15. April 2013, 23:20
Die passen auch in die normale Thread-Struktur (neben der TID), müssen nicht über TLS laufen. Ist aber auch eine Möglichkeit. :-)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 21. April 2013, 18:11
Nun was wird genau in so nem Thread-Local Storage gespeichert, und wie funktioniert er ? Und was sind Thread-strukturen? Auserdem, wie werden in risc-CPU´s stack-überläufer verhindert ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 21. April 2013, 22:25
Die Thread-Struktur speichert all das, was man zu einem Thread wissen muss. Also z.B. ID, zugeordneter Prozess, Adresse für Thread Local Storage und so weiter.

Im Thread-Local Storage wird die Variable "errno" gespeichert und vielleicht auch noch andere Dinge, die mir nicht einfallen.

Einen Stack-Überlauf kannst du nicht verhindern. Guard Pages versuchen nur, einen Stack-Overflow zu erkennen, nachdem er aufgetreten ist und bevor er Schaden verursacht. Das gelingt naturgemäß nur unzureichend.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 21. April 2013, 22:31
Was sind guard Pages ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 21. April 2013, 23:05
bitte schaue hier (http://www.lmgtfy.com/?q=guard+page)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 23. April 2013, 19:24
ops, hatte ganz vergessen das man es auch googlen kann :-D. Aber naja gibts keine andere möglichkeit ohne große segment-tabellen effektiv overflows zu erkennen? Bzw hat einer ne idee wie sowas ausehen müsste ?
Titel: Re: Logisim CPU
Beitrag von: Jidder am 23. April 2013, 19:55
Du musst doch im Prinzip nur sicherstellen, dass der Stackpointer SP innerhalb eines bestimmten Intervalls liegt. Dazu baust du zwei Register in deine CPU ein: SP_min und SP_max, und bei jeder Stackoperation bzw. Zugriff über den Stackzeiger prüfst du, ob SP_min <= SP <= SP_max (+- Wortgröße je nach Design). Wenn diese Bedingung falsch ist, dann löst du eine Exception aus und das Programm wird aufgrund eines ungültigen Zugriffs terminiert.

Wenn du zusätzlich einen Framepointer hast (wie z. B. BP bei x86) dann behandelst du den genauso wie SP. Außerdem solltest du dir überlegen, ob du verhindern willst, dass der Wert des Stackpointer/Framepointers in ein anderes Register kopiert wird oder in den Speicher geschrieben wird. Sonst lässt sich der Mechanismus nämlich aushebeln, weil normale indirekte Speicherzugriffe ja nicht der oben genannten Prüfung unterlegen. Das ist natürlich eine massive Einschränkung und macht es z. B. unmöglich C vollständig auf die CPU zu portieren.

Beispiel: Wenn du es wie die meisten anderen CPUs machst, und SP wie ein normales Register behandelst, kann man einfach folgenden C-Code schreiben (trifft natürlich auf äquivalenten Code in beliebigen anderen Sprachen inkl. Assembler zu):

int *px;

void foo() {
    int x;
    px = &x; // Zeiger auf x
    *px = 12; // Setze x auf 12. Gültig, weil x existiert.
}

void bar() {
    foo();
    // Zwei fehlerhafte Stackzugriffe:
    *px = 123; // Fehler: x existiert nicht mehr
    px[456] = 789; // Möglicherweise Stackoverflow
}

Wie kann man also dafür sorgen, dass das korrekt erkannt wird? Eine Möglichkeit wäre jedes Wort im Speicher mit einem speziellen Bit auszustatten, auf das von Programmen normalerweise nicht  zugegriffen werden werden kann. Das heißt wenn du zum Beispiel eine Architektur mit 16-Bit-Worten hast, musst du RAM verwenden, der 17-Bit-Worte unterstützt. 16-Bit von diesem 17-Bit-Wort werden ganz normal vom Programm gelesen/beschrieben. Das eine zusätzliche Bit wird hingegen verwendet, um den Ursprung des Wertes zu kennzeichnen.

Bei jedem schreibenden Speicherzugriff wird dieses Bit gesetzt, wenn der Wert eine gültige Stackadresse ist. Das Bit wird gelöscht, wenn es "normale Daten" (Zahlenwerte oder Zeiger auf was anderes als den Stack) sind. Die CPU-Architektur muss intern auch zu jedem Register ein zusätzliches Bit speichern, das genau besagt, ob es eine Stackadresse ist oder nicht. Wenn du also aus dem Speicher etwas liest, wird das 17. Bit aus dem RAM in das zu dem Register gehörende Bit kopiert. Jede Operation (Indirekter Speicherzugriff, Arithmetik, ...) verhält sich nun unterschiedlich jenachdem, ob in einem Register oder in einem Wort im RAM eine Stackadresse steht. Zum Beispiel muss das Ergebnis einer Addition einer Konstante und einem Register, das als Stackadresse markiert ist, weiterhin eine gültige Stackadresse sein. Oder wenn zum Beispiel zufällig in einem Register ein Wert steht, der einer Stackadresse entspricht, aber das Register nicht als Stackadresse gekennzeichnet ist, musst du eine bei einem indirekten Speicherzugriff über dieses Register eine Exception auslösen.

Wenn man das etwas ausweitet, lässt sich vermutlich der fehlerhafte Zugriff auf die nicht mehr existierende Variable x durch *px = 123; auch erkennen. Man könnte z. B. bei Speicherzugriffen überprüfen, ob die Adresse zwischen SP und SP_max liegt (wenn der Stack nach unten wächst). Aber wenn der alte Speicherplatz von x inzwischen von einer andere Variablen verwendet wird, lässt sich das nicht mehr erkennen (aber das ist ja dann kein Stack Overflow mehr, sondern ein anderer Fehler).

Diesen Mechanismus mit dem speziellen Bit kannst du weiter ausbauen, um z. B. ein Sicherheitskonzept basierend auf Capabilities (http://en.wikipedia.org/wiki/Capability-based_addressing) umzusetzen.

Ich halte das hier beschriebene allerdings nicht für sinnvoll. Stack Overflows muss man nicht so präzise erkennen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 23. April 2013, 22:26
mmh ok, wieso muss man die stack-überläufe nicht so genau erkennen ?
Titel: Re: Logisim CPU
Beitrag von: Jidder am 24. April 2013, 00:38
Meine Posts hier sind alles nur meine persönliche Ansicht. Beim Design von CPUs/Betriebssystemen geht man immer Kompromisse ein, mit denen nicht jeder einverstanden ist. Meine einzige absolute Aussage ist, dass alle absoluten Aussagen falsch sind.
:mrgreen:

Meine Grundannahme ist, dass jedes System, bei dem Stackschutz relevant ist, Virtual Memory beherrscht. Ansonsten ist kann man da nicht viel mit Sicherheit argumentieren und die Erkennung von Fehlern in ausgelieferten Programmen rechtfertigt keine aufwändigen CPU-Features. Guard Pages fangen Stack Overflows ab, wenn der Stack Pointer höchstens ein paar Kilobytes1) über das Ende hinausgeht. Die Frage ist also, wieviel Aufwand man treiben will, um Stack Overflows zu erkennen, bei denen der Stack Pointer größere Sprünge macht.

Mir fallen nur zwei Ursachen ein: Wenn ein Programmierer versucht sehr große, dünnbesetzte Objekte auf dem Stack anzulegen, oder ein Angriff durch Schadsoftware. Den ersten Fall argumentiere wie eben auch weg: Der Programmierer braucht kein aufwändiges CPU-Feature, um seinen Fehler zu erkennen. Den zweiten Fall kann man nur wegargumentieren, wenn man entweder andere Sicherheitslücken vorschiebt (also den Overflow als Folgefehler deklariert) oder aber wie ich behauptet, dass man das erstmal einen erfolgreichen Angriff durch einen Stack Overflow, der nicht von Guard Pages abgefangen wird, hinkriegen muss. Das Ziel eines solchen Angriffs ist ja etwas außerhalb des Stacks zu überschreiben (andere Angriffe erkennt ein Overflowschutz nicht). Sowas kann man auch versuchen zu verhindern, indem man Stack, Heap, Programm, Shared Librarys an zufälligen Adressen im Speicher platziert (ALSR (http://en.wikipedia.org/wiki/Address_space_layout_randomization).) Damit kann man meistens die Erfolgswahrscheinlichkeit von Angriffen reduzieren. Das ist genauso wie Guard Pages kein 100%iger Schutz, aber (vermutlich) einfacher umzusetzen als die Alternativen (Extra-Bit für Adressen, Segmentierung).

1) Wenn man einen 64-Bit-Adressraum hat, dann ist gegen Guard Pages, die ein paar Mega- oder Gigabyte überspannen, auch nichts einzuwenden.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 27. April 2013, 19:25
Mhh stimmt software würde für den stackschutz völlig ausreichen und wäre mir zudem lieber wie hardware. Aber naja die software braucht rechenleistung und da dachte ich mir das vielleicht durch so ne hardware stack-überlaufschutz meine CPU ein wenig schneller wird  :roll:. Naja ich hab ein wenig nachgedacht und weiß jetzt das des ne blöde idee war :-D. Ich glaub ich sollte erstmal schauen das meine CPU überhaupt funkioniert bevor ich an rechenleistung denke und die rechenleichtung mit ner hardware stacksicherung zu erhöhen ist glaub auch nicht so ne tolle idee.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 28. April 2013, 10:00
stimmt software würde für den stackschutz völlig ausreichen
Kann sie nicht. Auch der Einsatz von Guard Pages basiert auf Hardwarefähigkeiten (nämlich Page Faults und "schreiben in nur lesbare Pages").
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 04. May 2013, 20:41
Mhh dann hab ich wohl was falsch verstanden... ich werd dann in meiner cpu zusätzlich eine mmu einbauen die dann paging unterstützt
Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. May 2013, 00:12
Hallo,

du kannst die MMU auch weglassen und einfach mit physischen Adressen arbeiten. Sie ist für Betriebssysteme nicht unbedingt erforderlich (siehe uClinux, MINIX/68k und allgemein ältere Unixe).

Bis 12/16 MHz Taktfrequenz kannst du gewöhnliche SIMM-Module (8 Bit, 30 Pin, 80/60 ns) einsetzen, die du billig bei eBay oder auf dem Flohmarkt schießen kannst. (Für SD- und DDR-Speicher solltest du Hochfrequenzerfahrung haben, die sind vom Timing her deutlich kritischer.) Bei den Geschwindigkeiten brauchst du auch keinen Cache, der die Sache nur unnötig verkompliziert.

Ohne Cache kannst du eine MMU später problemlos nachrüsten, die sitzt dann einfach zwischen CPU und RAM, hat ein bisschen eigenen Speicher (SRAM) für die Tabellen und wird von der CPU wie jede andere Hardware auch angesprochen. Wichtig ist aber, dass deine CPU einen Speicherbusfehler akzeptieren kann.

Die Motorola 68010/68020 konnten mit externen MMUs (68451 und 68851) betrieben werden.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. May 2013, 11:03
Zitat
du kannst die MMU auch weglassen und einfach mit physischen Adressen arbeiten. Sie ist für Betriebssysteme nicht unbedingt erforderlich (siehe uClinux, MINIX/68k und allgemein ältere Unixe).
Mhh ok, wie mache ich das dann aber mit den guard pages ?

Zitat
Bis 12/16 MHz Taktfrequenz kannst du gewöhnliche SIMM-Module (8 Bit, 30 Pin, 80/60 ns) einsetzen, die du billig bei eBay oder auf dem Flohmarkt schießen kannst. (Für SD- und DDR-Speicher solltest du Hochfrequenzerfahrung haben, die sind vom Timing her deutlich kritischer.) Bei den Geschwindigkeiten brauchst du auch keinen Cache, der die Sache nur unnötig verkompliziert.
Naja ich will eigentlich zunächst die CPU in logisim zuende bauen bevor ich sie dann in hardware verwirkliche.
 
Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. May 2013, 12:03
Garnicht. :-D Ohne MMU/MPU gibt es keinen Speicherschutz.

Wobei du die Guard Pages trotzdem einbauen kannst und dann z.B. nur beim Taskwechsel vom Scheduler prüfen lässt, ob die überschrieben wurden oder nicht. Kostet halt etwas mehr RAM in der Implementation, ist langsamer und schützt nicht so gut - ist aber trotzdem besser als nichts.

Naja ich will eigentlich zunächst die CPU in logisim zuende bauen bevor ich sie dann in hardware verwirkliche.
Ist ein Argument. :-) Allerdings solltest du dir trotzdem überlegen, was du überhaupt verwirklichen kannst und was eher nicht.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 05. May 2013, 19:36
Zitat
Garnicht. :-D Ohne MMU/MPU gibt es keinen Speicherschutz.
Naja wollt schon immer ne MMU in logisim bauen. Wie werden eigentlich die tabellen von der mmu beschrieben?


Titel: Re: Logisim CPU
Beitrag von: Svenska am 05. May 2013, 22:08
Denk dir was aus, du bist CPU-Designer. :evil:
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 11. May 2013, 17:44
Nun ich hab mir folgenes ausgedacht, die tabellen sind direkt am bus angeschlossen. Auserdem gibts noch zusätzlich 9 "spezial-adressen" die auch am Bus angeschlossen sind. 8 "permission-adressen" und 1. "controll-adresse". Sowohl auf die tabellen als auch auf die spezial-adressen kann man nur zugreifen wenn das erste bit der "controll-adresse" 0 ist. Der bit wir immer nur  Beim einschalten oder wenn sich im programm-counter der CPU ,sich die selbe adresse befindet wie in einem der 8 "permission-adressen" auf 0 gesetzt.Nun was hält ihr von der Idee, bzw hat jemand fragen ? :)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 12. May 2013, 21:07
Ich verstehe deinen Post nicht wirklich.

Du willst also acht Adressen im Speicher haben, die die MMU verändern dürfen und sonst nichts? Dürfte funktionieren, aber verkompliziert unter Umständen das Betriebssystem (eine Schleife, um z.B. die Tabellen zu leeren, dürfte schon mehr als acht Byte brauchen - und du wirst vermutlich auch an mehreren Stellen im VMM die MMU verändern wollen).
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 12. May 2013, 21:29
Naja eigentlich hab ich mir das anders gedacht...Das Betriebssystem oder eine anwendung darf auf alle adressen der tabelle und den "spezial-adressen zugreifen, Wenn die Tabellen und die Spezial-adressen nicht durch den ersten bit der "controll-adresse" gesperrt sind.... Die Spezial-adressen sind eigentlich nur da um die Tabellen vor unbefugte zugriffe zu schützen... In den 8 "permissions-adressen" stehen dann z.b die Start-adressen der Funktionen die auf die Tabellen zugreifen dürfen...
Titel: Re: Logisim CPU
Beitrag von: Svenska am 12. May 2013, 22:57
Adressen haben normalerweise, im Gegensatz zu Daten, die sehr angenehme Eigenschaft, konstant zu bleiben. Das heißt, deine "controll-adresse" (da ist ein L zuviel, und Bit ist sächlich, wenn es nix mit Bohrmaschinen zu tun hat :evil:) sollte eine Konstante sein. Sonst greift ein Programm einfach auf die Adresse mit invertiertem Erlaubnisbit zu und freut sich.

Deine Permissions-Adressen zeigen auf ein einzelnes CPU-Wort. Wenn du den Zugriff auf einzelne Funktionen beschränken willst, muss da mindestens noch eine Größenangabe dazu, sonst wird das nix.

Vermutlich solltest du einfach eine Unterscheidung zwischen "privilegierten Befehlen" (Kernel-Mode) und normalen Befehlen (User-Mode) einbauen und die MMU-Zugriffe nur im Kernel-Mode zulassen. Es gibt ja noch andere Befehle, die man Anwendungen verbieten will. Wenn du einen speziellen I/O-Bus hast (der dann privilegiert ist), kannst du die MMU auch über diesen steuern.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. May 2013, 15:53
Zitat
Adressen haben normalerweise, im Gegensatz zu Daten, die sehr angenehme Eigenschaft, konstant zu bleiben. Das heißt, deine "controll-adresse" (da ist ein L zuviel, und Bit ist sächlich, wenn es nix mit Bohrmaschinen zu tun hat :evil:) sollte eine Konstante sein. Sonst greift ein Programm einfach auf die Adresse mit invertiertem Erlaubnisbit zu und freut sich.

Naja mit adresse hab ich eigentlich eine adresse im Bus-system gemeint :-D konstant sollen die eigentlich nicht sein.

Zitat
Deine Permissions-Adressen zeigen auf ein einzelnes CPU-Wort. Wenn du den Zugriff auf einzelne Funktionen beschränken willst, muss da mindestens noch eine Größenangabe dazu, sonst wird das nix.
Mhh naja auf einzelne Funktionen will ich mich eigentlich nicht beschränken... Die jeweiligen funktionen deren Start-adresse in den "Permission-adressen" stehen öffnen eher Die Tabellen und den "spezial-adressen" für weiter zugriffe.(sozusagen den Kernel-Mode) Wenn dann alle zugriffe auf die mmu und den "spezial-adressen gemacht wurde, setzt man als letztes den ersten bit der "controll-adresse" manuell wieder auf 0.(und wechselt somit wieder dann in den user-mode) So hatte ich mir das eigentlich vorgestellt...


Titel: Re: Logisim CPU
Beitrag von: Svenska am 13. May 2013, 22:25
Ich verstehe nicht, was du da eigentlich vor hast. Benutze bitte Worte, die ich kenne und/oder einordnen kann.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. May 2013, 22:56
Mhh nun gut... ich versuchs mal so zu fromulieren: Nun neben den Tabellen der MMU gibts noch 9 weitere speicher-plätze ("Spezial-adressen,8 -Permissions-adressen & 1 Control adresse") . Sowohl die Tabellen als auch die Speicher-pläzte kann man nur zugreifen wenn der erste bit der Control adresse auf 1 gesetzt ist ansonsten wird beim versuch auf die tabellen und den spezial-speicher-plätze zuzugeifen ein interrupt ausgelöst. Wenn der erste bit der "control-adresse" 0 ist, lässt sich logischerweiße nicht mehr mit Befehlen auf die Tabellen und den Speicher-plätze zugreifen bzw die "controll-adresse" wieder auf 1 setzen um die tabellen und den spezial-speicher-plätze zu entsperren. Nun dammit man das trotzdem entsperren kann , gibts jetzt die 8 "permissions-adressen" . In denen stehen ihrgentwelche adressen(z.b die startadresse einer funktion), diese werden die ganze zeit mit der adresse in dem programm-counter verglichen. Und wenn dann ein inhalt einer "permissions-adresse" mit dem inhalt der Programm-counter übereinstimmt wird automatisch der erste bit der "controll-adresse" auf 1 gestetzt, ohne das das programm davon ihrgentwas mitbekommt  :roll: .
Allle weiteren speicher-zugriffe und befehle können dann auf die Tabellen der MMU zugreifen ohne das ihrgent ein interrrupt ausgelößt wird. Fals dann Die Tabellen und die "spezial-speicher-plätze" wieder gesperrt werden soll muss man manuel das erste bit der "controll-adresse" wieder auf 0 setzten. Un normalerwieße ist das erste bit beim einschalten immer auf 1
Titel: Re: Logisim CPU
Beitrag von: Svenska am 14. May 2013, 00:12
Hallo,

die sehr schlechte Rechtschreibung und Fließtext machen das nicht unbedingt lesbarer... achte demnächst darauf. Laut Duden ist es übrigens immernoch "das" Bit, aber egal.

So, wie ich das verstehe, ist deine "Control Adresse" keine Adresse, sondern nur eine einzelne (zusätzliche) Steuerleitung auf dem Bus, wo die anderen Bits keine Bedeutung haben. Die "Permissions Adressen" sind dann einfach Register innerhalb der MMU.

Die Idee, die MMU "im Vorbeigehen" zu entsperren, finde ich nicht gut. Aktionen sollten nicht "einfach so" ausgelöst werden, sondern immer eine konkrete, beeinflussbare Ursache haben.

Der Übergang von User- in Kernel-Mode sollte nur durch bestimmte Befehle (Interrupts, Syscall) möglich sein, sonst kannst du dir die Unterscheidung gleich sparen. Außerdem sollten bestimmte Befehle im User-Mode verboten sein.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 14. May 2013, 10:23
Ich mache mir auch Sorgen, dass ein Programmierer nach dem Zugriff vergessen könnte das erste Bit deiner 'Control-Adresse' auf 0 zu setzten. Dann würde nämlich jedem Task deine MMU offen stehen.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 14. May 2013, 18:56
Zitat
Hallo,

die sehr schlechte Rechtschreibung und Fließtext machen das nicht unbedingt lesbarer...
Naja ist relativ :P

Zitat
So, wie ich das verstehe, ist deine "Control Adresse" keine Adresse, sondern nur eine einzelne (zusätzliche) Steuerleitung auf dem Bus, wo die anderen Bits keine Bedeutung haben. Die "Permissions Adressen" sind dann einfach Register innerhalb der MMU.
Das ist eigentlich auch ein register bei dem bis jetzt nur DAS erste Bit genutzt wird.( Für die restlichen Bits hab ich noch keine Verwendung  :-D ).

Zitat
Die Idee, die MMU "im Vorbeigehen" zu entsperren, finde ich nicht gut. Aktionen sollten nicht "einfach so" ausgelöst werden, sondern immer eine konkrete, beeinflussbare Ursache haben.
Na dann bau ich ein bestätigungs-Befehl ein. DAS erste Bit des "Control-Registers" setzt sich dann nur auf 1 wenn sich ein "Permissions-Register" mit dem CP übereinstimmt und zusätzlich an der Adresse auf die der CP zeigt ein solcher Befehl ist.

Zitat
Der Übergang von User- in Kernel-Mode sollte nur durch bestimmte Befehle (Interrupts, Syscall) möglich sein, sonst kannst du dir die Unterscheidung gleich sparen. Außerdem sollten bestimmte Befehle im User-Mode verboten sein.

Naja ich hab bei mir kein software-interrupts eingebaut, mit interrupts in den kernel-Mode zu kommen wird daher eher schwierig :D . Und wieso sollten Befehle verboten sein ?

Zitat
ch mache mir auch Sorgen, dass ein Programmierer nach dem Zugriff vergessen könnte das erste Bit deiner 'Control-Adresse' auf 0 zu setzten. Dann würde nämlich jedem Task deine MMU offen stehen.
Mhh stimmt, ich überleg mir da noch was...
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 14. May 2013, 19:55
Zitat
Na dann bau ich ein bestätigungs-Befehl ein. DAS erste Bit des "Control-Registers" setzt sich dann nur auf 1 wenn sich ein "Permissions-Register" mit dem CP übereinstimmt und zusätzlich an der Adresse auf die der CP zeigt ein solcher Befehl ist.
Das verkompliziert die Sache nur noch, da man damit auf bestimmten Adressen auch noch bestimmte Befehle haben muss.

Zitat
Und wieso sollten Befehle verboten sein ?
Darum. Und weil sonst jeden beliebige Programm z.B. an den I/O-Ports (sofern vorhanden) rumspielen kann. Je nach dem was da dran hängt (bei x86 z.B. der PIT) könnte das Programm dann das komplette System einfrieren bzw. sich unendlich viel Rechenzeit verschaffen.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Jidder am 14. May 2013, 20:06
Ich interpretiere deinen Mechanismus mit den "Permission-Registern" als Versuch bestimmte Funktionen als privilegiert zu markieren. Und du willst, dass nur diese privilegierten Funktionen Operationen an dem Mapping zwischen virtuellen und physischen Adressen ausführen dürfen. Dadurch soll gewährleistet werden, dass kein Programm Änderungen an dem Mapping vornehmen kann, um den Kernel bzw. andere Programme unzulässig zu beeinflussen. Ist das richtig?

Das reicht nämlich nicht. Du brauchst definitiv eine konkrete Trennung zwischen User-Mode und Kernel-Mode mit einem definierten Übergang. Ein Problem ist folgendes: Einzelne Funktionen als privilegiert zu markieren reicht nicht, weil es funktionale Abhängigkeiten zwischen den Kernelbestandteilen gibt. Eine privilegierte Funktion, die die Page Tables ändert, ist ja kein Selbstzweck, sondern wird von vielen anderen Funktionen, z.B. aus der Speicherverwaltung (sowas wie malloc und free, ganze Seiten anfordern/freigeben für Treiber, ...), Prozessverwaltung (z.B. Erstellung eines neuen Adressraums), oder Interprozesskommunikation (Shared Memory) aufgerufen. Und natürlich ruft vermutlich jeder Bestandteil im Kernel malloc/free auf, also irgendwann landet jeder mal in einer privilegierten Funktion. Das Problem ist, dass eine privilegierte Funktion nicht feststellen kann, zu welchem dieser Zwecke sie verwendet wird. Sie kann ohne definierten Übergang zwischen User-Space und Kernel-Space auch nicht feststellen, ob sie gerade von einem Programm aufgerufen wird. Ein Programm könnte den System-Zustand (Registerinhalte und Stack) so hindrehen, dass es aussieht, als ob die Funktion aus dem Kernel aufgerufen wird, obwohl das nicht der Fall ist. Das kannst du nur verhindern, indem du dafür sorgst, dass jeder Aufruf vom User-Space in den Kernel durch eine "Schleuse" (Interrupt/Syscall) geht.

Ein weiteres Problem ist, dass du mit dem Mechanismus nur Code schützt. Daten sind entweder ungeschützt, unzugänglich für nicht privilegierte Funktionen oder nicht gemappt. Wenn sie nicht gemappt sind, müssen sie erst von einer privilegierten Funktion gemappt werden, was ebenfalls die eben beschriebenen mit sich bringt, und darüberhinaus langsam ist. Das verkompliziert die Kernel-Entwicklung erheblich.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 14. May 2013, 23:52
Hallo,

Zitat
Der Übergang von User- in Kernel-Mode sollte nur durch bestimmte Befehle (Interrupts, Syscall) möglich sein, sonst kannst du dir die Unterscheidung gleich sparen. Außerdem sollten bestimmte Befehle im User-Mode verboten sein.
Naja ich hab bei mir kein software-interrupts eingebaut, mit interrupts in den kernel-Mode zu kommen wird daher eher schwierig :D Und wieso sollten Befehle verboten sein ?
Ob du Syscalls nun über Interrupts, Call Gates, spezielle Syscall-Befehle oder Longjmp machst, ist an sich total egal. Wichtig ist, wie Jidder schrieb, dass dieser Durchgang die einzige Möglichkeit ist, um in den Kernel-Mode zu kommen - dann kannst du alle Berechtigungen nämlich an dieser Stelle prüfen.

Warum du bestimmte Befehle im User-Mode sperren solltest? Weil sie dein Betriebssystem gefährden können. So Dinge wie HLT (hält die CPU bis zum nächsten Interrupt an) oder CLI/STI (spiele am Interrupt-Flag rum) sind da ganz wunderbare Kandidaten.

Dein Ansatz ist nicht tauglich, um das Problem zu lösen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Dimension am 15. May 2013, 10:53
Ich glaube er will bestimmte Prozedureinsprungspunkte markieren, so dass diese bei Aufruf in einen privilegierten Modus wechseln und mit privilegierten Rechten ausgeführt werden. Vor dem RET muss die privilegierte Funktion den privilegierten Modus beenden, da die Markierungen nur in eine Richtung funktionieren.

Diese Markierungen und das "privileged mode Flag" sind wiederum nur schreibbar, wenn der privilegierte Modus aktiv ist, so auch beim Systemstart.

Aber so richtig verstanden habe ich es wohl auch nicht.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 25. May 2013, 18:20
Naja meine idee ist glaub wirklich nicht so gut wie ich anfangs dachte...Meine CPU wechselt jetzt einfach bei einem interrupt in den Kernel-Mode , auserdem bau ich dazu noch ein software-interrupt ein. Nun spezielle Befehle die nur im Kernelmode benutzt werden dürfen werd ich glaub nicht einbauen. Die größten Probleme macht mir noch der Systemstart..das Panging muss ja da deaktiviert sein da die Tabellen noch nicht beschrieben sind oder ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 26. May 2013, 00:48
Die größten Probleme macht mir noch der Systemstart..das Panging muss ja da deaktiviert sein da die Tabellen noch nicht beschrieben sind oder ?
Das Stichwort dabei nennt sich "Reset-Logik". Deine MMU kann nach einem Reset durchaus aktiv sein, wenn sie nach einem Reset automatisch ein 1:1-Mapping herstellt. Streng genommen muss das auch nicht für den ganzen Speicher gelten, sondern z.B. nur für die erste Page.

Was genau unterscheidet deinen Kernel-Mode vom User-Mode?

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 26. May 2013, 16:49
Zitat
Was genau unterscheidet deinen Kernel-Mode vom User-Mode?
Nun im Kernel-Mode darf man auf die MMU tabellen und den interrupt-controler zugreifen.

Zitat
Das Stichwort dabei nennt sich "Reset-Logik". Deine MMU kann nach einem Reset durchaus aktiv sein, wenn sie nach einem Reset automatisch ein 1:1-Mapping herstellt. Streng genommen muss das auch nicht für den ganzen Speicher gelten, sondern z.B. nur für die erste Page.
Mhh cool, hab schon ne idee wie ich das umsetzten könnte XD.

Auserdem ist mir noch was beim Paging aufgefallen was ich nicht ganz verstehe...
Nun normalerweiße ist das ja so:
Der jeweilige Eintrag im Page Direcory dient als Basis-adresse für die Page-table. Und aus dem jeweiligen Eintrag der Page table und dem Offset wird dann die Physikalische Adresse.
(http://img4.fotos-hochladen.net/uploads/pagingarload3tvm7.png) (http://www.fotos-hochladen.net)

Wiso macht man das dann nicht so:
Das aus dem Jeweiligen eintrag Der Page-Directory und der Page-Table zusammen mit dem Offset die physikalische adresse wird.
(http://img4.fotos-hochladen.net/uploads/pangingbdu6ozmxa0j.png) (http://www.fotos-hochladen.net)

Titel: Re: Logisim CPU
Beitrag von: streetrunner am 26. May 2013, 20:44
Ziel einer MMU ist es aus einer virtuellen eine reale Speicheradresse zu machen. Das heißt u.U. das zwei unterschiedliche Adressen auf die selbe reale Adresse gemappt werden. Spielen wir dieses Beispiel einmal durch:

Angenommen die Adressen 0xFFF00xxx und 0xFFFFFxxx sollen auf die selbe Adresse gemappt werden.
Damit müssten sowohl der Eintrag 768 (die unteren 10Bit von F00) als auch der Eintrag 1023 (die unteren 10Bit von FFF) in der Page-Table den selben Wert enthalten. Leider ist es aber so dass man nur 10Bit hat um die insgesammt 1024 Einträge zu adressieren. Wenn nun aber 2 Einträge den selben Wert enthalten bleibt zwangsläufig ein Wert auf der Strecke, für den kein Platz in der Page-Table mehr ist. Daraus resultiert dann nicht addressierbarer Speicher, da die passenden (Teil)-Addressen einfach nicht in der Page-Table vorhanden sind. Gleiches gilt natürlich auch für das Page-Directory. Dabei ist es egal, wo jetzt Werte fehlen, der verschwendete Speicherplatz ist von der selben Größenordnung und beträgt (richtig gerechnet vorrausgesetzt) pro nicht vorhandenem Wert 4MB.

Hoffe mal ich hab da nichts übersehen, dann wäre das wahrscheinlich hinfällig.


Tante Edit sagte mir gerade dass das teilweise kompletter Unsinn ist was ich da oben geschrieben habe. Aber ich steh zu meinen Fehlern. :-D

Daher auf ein neues:
Wenn ein OS einen Neuen Task startet, dann legt es üblicherweise neue Paging-Tabllen an, damit der Task über den kompletten Adressraum verfügen kann, ohne irgendwem ins Handwerk zu pfuschen. Sinn dieser Tabellen ist nun neben der Adressumwandlung der MMU mitzuteilen, ob der betreffende Task überhaubt an diese Speicheradressen schreiben darf. Desweiteren fehlen manchmal Einträge, da diese entweder nicht in den Adressraum des Tasks gehören oder nicht im Speicher vorhanden sind (Swapping). Dies kann nun nur für eine einzige Page der Fall sein. Bei deiner Lösung müsste man dafür aber wieder einen kompletten Eintrag in deinen Tabellen löschen, womit sich direkt 4MB Speicher verabschieden.

Hoffe diesmal, das mir nicht im Nachhinein einfällt, dass das auch Unsinn ist....

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Svenska am 27. May 2013, 00:54
Hallo,

also laut Wikipedia (http://de.wikipedia.org/wiki/Paging) wird das so gemacht.
Der PD-Eintrag ergibt direkt die oberen 10 Bits der linearen Adresse, der PT-Eintrag die folgenden 10 Bits, der Offset sind dann die verbleibenden 12 Bits.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 27. May 2013, 11:34
Wie die lineare Adresse zustande kommt habe ich auch verstanden. Sieht man sich aber das Beispiel auf Wikipedia an (ich denke mal, Svenska meint das erste Schaubild), so erkennt man das dort nur eine große Tabelle existiert. Diese hat 2^n Einträge, auf Tufelix Bsp. angewandt ergeben sich damit 2^20 Einträge. Tufelix hat aber nur 2 x 2^10 = 2^11 Einträge. Irgendwo muss es also einen Haken geben, und dieser liegt darin dass in einem PT-Eintrag immer der selbe Wert steht, unabhängig vom PD-Eintrag. So steht z.B. im PT-Eintrag 127 immer der Wert 0x3FF, unabhängig davon welchen Eintrag ich im PD selektiert habe (vorausgesetzt natürlich ich habe auch wieder den Eintrag 127 im PT selektiert). Dies könnte aber unerwünscht sein, da eventuell der Wunsch aufkommen könnte, bei unterschiedlichen PD-Einträgen unterschiedliche PT-Werte im PT-Eintrag 127 zu haben.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 30. May 2013, 18:09
Mhh was sind eigentlich Translation Lookaside Buffer? Sind das die Seiten-tabellen ?
Titel: Re: Logisim CPU
Beitrag von: Jidder am 30. May 2013, 18:18
Das ist ein Cache für die Page Tables, damit die CPU nicht für jeden Speicherzugriff zusätzlich nochmal auf den Speicher zugreifen muss, um die Mappings auszulesen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 31. May 2013, 12:53
Mhh wieso baut man die Page-Tables nicht direkt in die MMU?  Wär doch praktischer :D.
Titel: Re: Logisim CPU
Beitrag von: LittleFox am 31. May 2013, 13:23
Weil vom Kernel eine beliebige Anzahl an PageDirectories (pro Prozess eine) und damit PageTables erstellt werden kann. Und damit bräuchtest du in der MMU sehr viel Speicher (genug um seeehr viele PTs zu halten, wie viele es werden kannst du ja nicht beeinflussen)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 01. June 2013, 17:36
Mhh wieso baut man die Page-Tables nicht direkt in die MMU?  Wär doch praktischer :D.
Das hat man zu Zeiten des Z80 auch gemacht. Bei 4 KB pro Page und 1 MB adressierbarem Speicher in einem 64 KB-Adressraum, ohne Flags, dafür aber mit langsamen CPUs und noch viel langsamerem Speicher kann man das machen (z.B. 74xx189).

Bei 32-Bit-x86ern müsstest du 4 MB in extrem schnellem Speicher halten (vergleiche mal, wieviel Cache in modernen CPUs drin ist und wieviel Platz (=Kosten) der auf dem Wafer wegnimmt). Außerdem müsstest du diese (bis zu) 4 MB bei jedem Taskwechsel zwischen Speicher und MMU hin- und herkopieren, was zusätzlich Speicherbandbreite kostet.

Bei 64 Bit-Adressräumen geht das überhaupt nicht mehr.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 03. June 2013, 16:39
Naja dann bau ich mal die Pages auch in den hauptspeicher ein. Auserdem leg ich die Page directory und die page table zusammen zu einer großen Tabelle damit die MMU nur ein speicherzugriff auf den hauptspeicher machen muss um eine adresse zu berechnen. Zudem bau ich so nen Translation Lookaside Buffer mit 256 wort größe in der MMU ein und dazu noch ne Daten/Befehls-Cache mit 512 wörter in der CPU ein.
Nun laut wikipedia gibts ja für die cache 2 schreib stategien -write-back und write-through. Meine frage ist etwas blöd...welche von den beiden strategien ist die bessere ?  :-D
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 03. June 2013, 17:22
Zu deiner MMU:
Ich denke mal Du versuchst folgendes: Du hast irgendwo ein Register in dem die Adresse Deiner "großen" Tabelle steht. Wenn nun ein Speicherzugriff erfolgt, braucht Deine MMU nur an "Adresse + Offset" nachsehen wohin es denn wirklich geht. In sofern funktioniert das, aber das Problem wird sein dass Du im Adressraum einen extrem großen Bereich (bei 32Bit, bei x86_64 im "Maximalausbau" dann 512GB) an zusammenhängendem Speicher reservieren musst, um dort Deine Tabelle abzulegen. Das ist in sofern unglücklich, da nun zwar jeder Prozess per Default extrem viel Speicher reservieren kann, ABER diesen vermutlich überhaubt nicht braucht (man überlege sich hier dass ein Prozess bei x86_64 allein 512GB für das Paging verschwendet, auch wenn er selbst nur 1MB wirklich braucht).

Und nun zum Cache:
Letztenendlich kommt es darauf an wie viel Aufwand Du betreiben möchtest. Geht man davon aus dass Deine CPU nur alleine arbeitet, dann ist Write-Allocation wohl die beste Wahl. Dabei wird bei einem Cache-Hit der Wert in den Cache geschrieben und mit dem sogenannten "Dirty-Bit" als "nicht mit dem Haubtspeicher übereinstimmend" markiert. Der Haubtspeicher wird dabei nicht angerührt. Bei einem Cache-Miss wird der Wert ebenfalls direkt in den Cache geschrieben, ist dieser voll muss halt irgendwas überschrieben werden (möglichst etwas was bereits im Haubtspeicher liegt). Sonst ist es wie beim Cache-Hit. Das Problem bei allen Varianten die den Zugriff auf den Haubtspeicher vermeiden ist, dass andere Geräte die auf den Haubtspeicher zugreifen (DMA, andere CPUs) eventuell mit den falschen Daten arbeiten. Das Problem mit den CPUs kann man relativ einfach umgehen, indem man einen großen (mittlerweile L3) Cache hat auf den alle CPUs zugreifen und mit dem alle CPUs ihre Daten abgleichen. Dauert zwar bei neu geschriebenen Daten (Cache-Miss) etwas länger, aber immer noch bedeutend kürzer als auf den RAM zuzugreifen. Mit DMA ist das dann etwas schwierieger, da müsstest Du Dir dann eine Lösung überlegen.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Jidder am 03. June 2013, 17:25
Wenn eine von beiden die bessere wäre, dann wäre nur diese bei Wikipedia erwähnt worden.

Write-Back: Manchmal sparst du einen unnötigen Speicherzugriff, wenn die Daten noch im Cache sind. Manchmal kann ein Miss beim Lesen aber auch dafür sorgen, dass zweimal auf den Speicher zugegriffen werden muss, weil erst der alte Inhalt zurückgeschrieben werden muss, bevor der neue gelesen werden kann. Das sorgt dafür, dass die Kosten für manche Zugriffe auf andere Zugriffe umverteilt werden, also manche Schreibzugriffe sind schnell, dafür aber ein folgender Lesezugriff langsam.

Write-Through: Mehrfache Schreibzugriffe auf die selbe Line sind langsamer. Dafür ist es einfacher zu umzusetzen.

Ich hoffe, dass du nicht vor hast, nur einzelne Worte zu cachen, sondern ganze Lines. Ansonsten verlierst du den Hauptvorteil des Caches: Ausnutzung von räumlicher und zeitlicher Lokalität (http://de.wikipedia.org/wiki/Lokalit%C3%A4tseigenschaft). In Logisim würde ich übrigens tendenziell keine Caches verwenden, weil jeder Speicher gleichschnell ist, was bei einer Harvard-Architektur jeden Vorteil aufhebt, und Caches bei einer von-Neumann-Architektur ganz schnell unnötig kompliziert werden.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 03. June 2013, 18:40
Zitat
In Logisim würde ich übrigens tendenziell keine Caches verwenden, weil jeder Speicher gleichschnell ist, was bei einer Harvard-Architektur jeden Vorteil aufhebt, und Caches bei einer von-Neumann-Architektur ganz schnell unnötig kompliziert werden.
Naja werden in der Cache die Virtuelle oder die physikalische adresse gespeichert ?
Titel: Re: Logisim CPU
Beitrag von: Jidder am 03. June 2013, 19:33
Es geht beides. Virtuelle Adresse hat den Vorteil, dass man keinen TLB-/Page-Table-Zugriff machen muss bzw. ihn parallel zum Cachezugriff ausführen kann. Physische Adresse hat den Vorteil, dass man bei einem Adressraumwechsel den Cache nicht flushen muss. Man kann für L1- und L2-Cache auch unterschiedliche Strategien fahren. Zum Beispiel kann man im L1-Cache virtuelle und im L2-Cache physische Adressen verwenden und den TLB-Zugriff parallel zum L1-Zugriff ausführen.

Mein Punkt war eher, dass ich glaube, dass Caches in Logisim einiges an zusätzlicher Logik für das Laden und Sicherstellen der Konsistenz erfordern, aber die CPU nicht wirklich beschleunigen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 03. June 2013, 22:42
Zitat
Mein Punkt war eher, dass ich glaube, dass Caches in Logisim einiges an zusätzlicher Logik für das Laden und Sicherstellen der Konsistenz erfordern, aber die CPU nicht wirklich beschleunigen.
Naja, dachte mir das wenn die Cache mit vituelle adressen arbeitet und dadurch weniger adressen von der MMU berechnet werden muss, die CPU schneller wird...aber stimmt eigentlich, der Geschwindigkeit-vorteil ist glaub in logisim so gering, da könnte ich eigentlich einfach mehr TLB buffer einbauen, das bringt glaub mehr  :roll:
Titel: Re: Logisim CPU
Beitrag von: Svenska am 04. June 2013, 01:18
Hallo,

wenn ich mir deine Konzepte so anschaue, frage ich mich ehrlich gesagt, was du eigentlich erreichen möchtest. Du fügst ununterbrochen Features hinzu. Damit verlangsamst du nicht nur die CPU in der Simulation (was sie immer nutzloser macht), sondern du schaffst dir auch noch Dutzende Fehlerquellen, die dir später das Debuggen zur Hölle machen. Real implementieren willst du die CPU auch nicht. Dafür schielst du irgendwie immer auf x86, was definitiv kein besonders gutes Vorbild ist.

Wenn du so weitermachst, wirst du vor 2035 jedenfalls nicht fertig.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 04. June 2013, 11:53
So lange er nicht die Probleme von x86 mitnimmt (A20 lässt grüßen) kann er von mir aus gerne darauf schielen, denn letztenendlich funktionieren doch alle Architekturen die so im Umlauf sind irgendwie doch alle gleich (vllt. vom eigendlichen Kern mal abgesehen). Sie haben alle einen Cache und TLB und ob ich dann CISC (x86) oder RISC (ARM, x86_64 ist dann son Mischmasch) oder VLIW (Itanium) habe ist dann denke ich mal auch egal.

Wie viel Dein Simulator aushält ist dann die andere Frage, ich hab zwar nicht den kompletten Beitrag gelesen aber es wäre vllt. besser wenn man erst einmal nur den Kern debuggt und sich erst danach an Caches und dergleichen wagt.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 12. June 2013, 18:58
Zitat
Real implementieren willst du die CPU auch nicht.
Doch eigentlich schon, wenn ich mir mal ein FGPA-Board kaufe...

Zitat
Dafür schielst du irgendwie immer auf x86, was definitiv kein besonders gutes Vorbild ist.
Naja X86 ist nicht mein Vorbild (eher arm oder atmel). Ich schau glaub einfach zu oft im wiki nach wo meistens die x86 lösung beschrieben ist...

Zitat
Damit verlangsamst du nicht nur die CPU in der Simulation (was sie immer nutzloser macht), sondern du schaffst dir auch noch Dutzende Fehlerquellen, die dir später das Debuggen zur Hölle machen.
MMh man debuggt normalerweiße ganz am schluss wenn alles fertig gebaut ist ?  :-o Ich debugge eigentlich immer dann wenn ich wieder was dazugebaut habe(schaue dann ob alles passt und so funktioniert wie ichs mir vorgestellt habe und danach bau ich das nächste Element dazu und debugge wieder)




Zitat
aber es wäre vllt. besser wenn man erst einmal nur den Kern debuggt und sich erst danach an Caches und dergleichen wagt.
Naja mein Kern von der CPU ist ja schon fast fertig, es fehlt eben nur der Interrupt controller und ein paar Befehle sind noch nicht implementiert. Hier mal ein Foto von dem Kern(habs ein wenig skalliert, und wie kann man hier im Forum ein Spoiler machen?):


(http://www.fotos-hochladen.net/uploads/cpumain1hjexgc6sr.png) (http://www.fotos-hochladen.net)

Nun zu meiner MMU, will ne besonderst einfache mmu bauen mit nur einer Pages-Größe und einfache Zugriffsrechte. Auserdem will ich die MMU als CO-Prozessor bauen ähnlich wie bei arm. Nun was soll ich noch so beachten bei der planung meiner MMU? Was sollte sie noch können?
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 12. June 2013, 20:49
Naja, ich glaube eine "einfache" MMU gibt es nicht, denn ein paar grundlegende Dinge sollte jede MMU können:
Deine MMU sollte man Ein/Ausschalten können denn sonst wird es Probleme beim booten deines OS geben. Desweiteren muss sie auf den Speicher zugreifen können um die passenden Tabellen zu laden, dabei ist zu beachten dass die MMU der CPU evtl. den Busmaster "klauen" muss (Speicherzugriff auf eine Seite die nicht im TLB ist). Dann brauchst du noch eine Logik die deine Flags prüft (welcher Ring, lesen/schreiben, ...) und bei Bedarf einen Interrupt sendet. Als Ablauf dürfte dass dann so aussehen:

Die CPU gibt die gewünschte Adresse auf den Bus, welcher direkt in die MMU führt. Dort wird geprüft, ob die entsprechende Page bereits im TLB vorhanden ist (solltest du keinen TLB haben entfällt dieser Schritt). Ist die Page vorhanden so gibt man einfach den Inhalt des TLB-Eintrags auf den Adressbus und jut is. Sollte man keinen Treffer erziehlen so teilt man die Adresse der CPU in den Eintrag für das PD, den Eintrag für die PT und den Offset auf. Dann lädt man den Wert (Adresse vom PD) + (Offset im PD) in ein Register, und prüft ob der Eintrag dem man gerade geladen hat gültig ist und natürlich auch alle Flags. Dafür muss die CPU der MMU mitteilen was sie macht, d. h. ob sie schreiben oder lesen will, in welchen Ring der Task gerade ausgeführt wird, ...). Erhält man da Unstimmigkeiten so wird ein Interrupt ausgelöst. Passt alles, so ermittelt man aus dem geladenen Eintrag die Adresse der PT, und das ganze Spiel mit laden des Eintrags und checken usw. geht noch mal los. Passt dann immer noch alles so kann man aus dem geladenen Eintrag der PT und dem Offset der Adresse der CPU die gewünschte Speicheradresse bilden und auf den Adressbus legen. Dann sollte man der CPU evtl. noch mitteilen dass die MMU fertig ist und sie den Speicher anweisen kann Daten zu liefern oder entgegenzunehmen. Ich denke mal dass sich das sehr gut und einfach umsetzten lässt, auch größere Pages sind nicht schwer zu realisieren, man muss nur nach dem ersten "Laden und Checken" direkt zu "Gebe fertige Adresse aus" springen. Hardwaremäßig lässt sich das bestimmt wie eine Pipeline organisieren, also einfach hintereinander weg. Wenn du die MMU ausschaltest kannst du dann einfach die Adressen der CPU "drumherrum" direkt auf den Adressbus leiten.

Gruß,
Streetrunner
Titel: Re: Logisim CPU
Beitrag von: Svenska am 13. June 2013, 02:10
Hallo,

Zitat
Real implementieren willst du die CPU auch nicht.
Doch eigentlich schon, wenn ich mir mal ein FGPA-Board kaufe...
Dann willst du aber lieber einen kleinen Kern (mit bekannten Einschränkungen), der auch in einen kleinen FPGA passt und dort schnell ist. Außerdem wirst du dich dann mit realen Timingbeschränkungen rumprügeln müssen, weil FPGAs nicht genug RAM haben.

MMh man debuggt normalerweiße ganz am schluss wenn alles fertig gebaut ist ?  :-o
Tests der Einzelteile ersetzen nicht den Test des Gesamtsystems. Wenn du später etwas am System ändern willst (z.B. wenn du das Betriebssystem schreibst und dir auffällt, dass du etwas wesentlich eleganter hättest lösen können), musst du das Gesamtsystem debuggen, nicht mehr die Einzelteile.

Im einfachsten Fall sitzt die MMU zwischen CPU und RAM und trennt den Speicher vollständig(!) vom normalen Bus ab. Das heißt, dass die CPU die gleichen Adressen sieht wie jedes andere Gerät auch. Die MMU ist in dem Falle gleichzeitig RAM-Controller, was den Vorteil hat, dass du die MMU für ihre eigenen Tabellen jederzeit Zugriff auf den Speicher hat und du dich an der Stelle nicht um Busarbitrierung kümmern musst. Weil die MMU extern ist, wird sie auch wie jede andere Hardware angesprochen, d.h. du brauchst keinen MMU-spezifischen Privilegierungsmechanismus mehr. Außerdem kannst du mehr Speicher anschließen, als du logischen Adressraum in der CPU verfügbar hast. Das macht natürlich Taskwechsel aufwändiger, weil du die MMU jedesmal neu konfigurieren musst. Deine Resetschaltung muss die MMU in einen definierten Zustand (z.B. 1:1-Mapping) bringen, damit du das System starten kannst und du kannst keine feinen Berechtigungen ({Kernel,User}{read,write,execute}-Niveau) machen, weil die MMU nur "read" und "write" auf dem Bus sieht. Dein Bus muss in der Lage sein, beliebig langsam auf Anfragen antworten zu können und Busmastering wird sehr schwierig.

Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.
Titel: Re: Logisim CPU
Beitrag von: kevin am 13. June 2013, 10:13
Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.
Nein, heutzutage hat jedes Gerät sein eigenes Mapping. Man nennt es IOMMU. ;)
Titel: Re: Logisim CPU
Beitrag von: Svenska am 13. June 2013, 10:27
Ok. Kann mein Computer noch nicht, darum habe ich mich damit nicht befasst. ;-)
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. June 2013, 20:01
Zitat
Dann willst du aber lieber einen kleinen Kern (mit bekannten Einschränkungen), der auch in einen kleinen FPGA passt und dort schnell ist. Außerdem wirst du dich dann mit realen Timingbeschränkungen rumprügeln müssen, weil FPGAs nicht genug RAM haben.
Mhh was heist das genau? wie klein sollte den der kern sein?  Und was sind das für Einschränkungen?

Zitat
Tests der Einzelteile ersetzen nicht den Test des Gesamtsystems. Wenn du später etwas am System ändern willst (z.B. wenn du das Betriebssystem schreibst und dir auffällt, dass du etwas wesentlich eleganter hättest lösen können), musst du das Gesamtsystem debuggen, nicht mehr die Einzelteile.
Mhh stimmt, das wird schwierig wenn ich meine CPU zu kompliziert mache.

Zitat
Alternativ ist die MMU ein Teil der CPU, d.h. sämtliche Hardware außer der CPU selbst arbeitet mit physischen Adressen. Das ist der Weg, der heutzutage gegangen wird.
Naja so hatte ich das eigentlich vor :D

Mal was anderes, braucht man eigentlich überhaupt ne mmu um ein multitasking-os laufen zu lassen ?  :roll:

Titel: Re: Logisim CPU
Beitrag von: Jidder am 13. June 2013, 20:13
Mal was anderes, braucht man eigentlich überhaupt ne mmu um ein multitasking-os laufen zu lassen ?  :roll:

Brauchen tut man es nicht. Aber du kannst dir ja mal überlegen welche Vorteile eine MMU haben würde.
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 13. June 2013, 22:07
Lies Dir dazu mal die Tutorials hier auf der Seite durch (OS-Dev für Einsteiger), da wird die MMU zu Beginn auch nicht benutzt und da steht auch drin was man machen muss um Multitasking ohne MMU zu implementieren.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 24. June 2013, 20:35
Zitat
Lies Dir dazu mal die Tutorials hier auf der Seite durch (OS-Dev für Einsteiger), da wird die MMU zu Beginn auch nicht benutzt und da steht auch drin was man machen muss um Multitasking ohne MMU zu implementieren.
Wow sieht interessant aus.

Nun ich werd jetzt wohl das Konzept der Mips-MMU übernehmen, mit nem TLB mit 32 einträge. Die größten Probleme habe ich noch mit der Verdrängungs-taktik welche eignet sich den am besten für eine einfache TLB-Cache ?
Titel: Re: Logisim CPU
Beitrag von: kevin am 24. June 2013, 21:56
Das ist doch dann sowieso das Problem der Software, oder? Ich denke, ich würde für den Anfang ein simples LRU machen.
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 24. June 2013, 22:36
Zitat
Das ist doch dann sowieso das Problem der Software, oder?
Das kommt drauf an ob der TLB direkt beschreibbar ist oder nicht. Bei den meisten Architekturen geht das überhaupt nicht, die einzige Ausnahme stellt glaube ich Itanium, wo zumindest der L2-TLB von der Software aus beschrieben werden kann. Natürlich wäre es eine Idee, auch den L1-TLB beschreibbar zu gestalten. Das wäre vermutlich die einfachste Art einen TLB zu implementieren. Aber ob es auch die beste ist glaube ich nicht, da die Software zwar einen Überblick über die benötigten Seiten hat, allerding nichts davon weiß wie oft diese Seiten verwendet werden.

Zitat
ich würde für den Anfang ein simples LRU machen
Habe lange nachgedacht was LRU bedeuten könnte, aber wenn ich so auf meine Tastatur gucke dann denke ich das Du LFU meintest??? Ich glaube das ist auch nicht das gelbe vom Ei, da man hier für jeden Eintrag sowohl die Zugriffe als auch die Zeit benötigt, welche er im Cache existiert. Am einfachsten dürfte ein FIFO sein, realisiert mit einer Art Ringspeicher, bei dem immer ein Eintrag neu beschrieben wird, falls ein bestimmter Eintrag nicht im Cache vorhanden ist. Beim nächsten Cache-Miss wird dann der nächste Eintrag überschrieben. Von der Performance her ist das ab und an auch nicht wirklich super, aber wesentlich einfacher zu implementieren.
Titel: Re: Logisim CPU
Beitrag von: kevin am 24. June 2013, 22:46
Tulefix hat MIPS erwähnt, das meines Wissens einen reinen Software-TLB hat. (Was allerdings nur Hörensagen ist, ich habe die MIPS-MMU nie selber programmiert.)

LRU ist Least Recently Used, d.h. der Eintrag, der am längsten nicht mehr benutzt wurde, fliegt raus. Die Hardware müsste dazu natürlich eine Art Reihenfolge der Einträge aktuell halten, sonst fehlt der Software die Grundlage, auf der sie LRU machen könnte. (Wobei man es mit einem Accessed-Flag pro Eintrag vielleicht ausreichend annähern könnte.)
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 25. June 2013, 11:37
Ah, ok, und wieder um eine Abkürzung schlauer  :-D. Ich denke mal dass es für LRU am einfachsten wäre einen großen Zähler mitlaufen zu lassen, welcher startet wenn die CPU aktiviert wird, oder vielleicht wenn ein Taskwechsel stattfindet. Wenn man dann noch für jeden TLB-Eintrag ein Register vorsieht, in welchem man bei Zugriff auf den Eintrag den Inhalt des Zählers speichert, dann kann man bei einem Cache-Miss den kleinsten Wert in diesen Registern raussuchen und den dazu gehörigen Eintrag überschreiben.
Titel: Re: Logisim CPU
Beitrag von: kevin am 25. June 2013, 11:44
Mit Overflows muss man wahrscheinlich noch ein bisschen aufpassen, aber wenn die Software dafür zuständig ist, den Zähler zu erhöhen, dann kann sie ja dafür sorgen, dass kurz bevor es knallt alles wieder auf die ersten paar natürlichen Zahlen zusammengestaucht wird.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 07. July 2013, 22:45
Nun ich glaub der Svenska hat recht... ich hab versucht die MMU und die CPU in VHDL zu realisieren.
Und ihrgentwie ist mir Die CPU mit der MMU zu kompliziert, daher werd ich die MMU weglassen, die CPU greift direkt mit der physischen adresse auf den bus zu und ein Co-Prozesser prüft ob die CPU gerade berechtigt ist auf die adresse zuzugreifen..

Dazu besitzt der Co-Prozessor 4 registerpaare mit je 2 registern. Jeweils eines der register in einem Registerpaar, markiert der anfang eines Bereichs auf der die CPU zugreifen darf und das andere Register markiert das Ende dieses Bereiches.(also insgesamt kann man im Co-Prozessor 4 Bereiche makieren).

Auserdem kennt sich jemand mit vivado 2013.2 aus?Ich hab da ein Problem mit dem simulator, der öffnet sich zwar aber wenn ich versuche die simulation zu starten Kommt diese Fehlermeldung:
ERROR: [Simulator 45-1] A fatal run-time error was detected. Simulation cannot continue.
Hab schon alles versucht, nicht einmal bei den Projekt-Beispiele funktioniert der simulator.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 10. July 2013, 21:19
Hallo,

irgendwie gefällt mir dein Ansatz mit den erlaubten Bereichen und dem Co-Prozessor nicht. Das klingt alles so kompliziert.

Eine MMU ist im einfachsten Fall ein SRAM. Bei jedem Speicherzugriff gehen die unteren 12 Bit der (physischen) Adresse an den Adressbus (ergibt 4 KB/Page) und die restlichen, oberen Bits an das SRAM der MMU. Das Datenwort, welches aus diesem SRAM kommt, nimmst du dann als die neuen (virtuellen) oberen Adressbits. Der Inhalt dieses SRAMs enthält dann dein Mapping und muss natürlich irgendwie vom Betriebssystem aus änderbar sein - und unterliegt damit wie jede andere Hardware auch dem Zugriffsschutz(*).

Wenn du im Betriebssystem dann noch vereinbarst, dass das oberste Bit der Einträge im SRAM eine ungültige Page markiert, dann kannst du mit der obersten Adressleitung der virtuellen Adresse direkt einen Page-Fault auslösen. (Wenn du die MMU aber gerade beschreibst, darfst du natürlich keinen Page Fault auslösen.)

(*) Wenn du für Hardware einen getrennten Adressraum vorsiehst, ist das recht einfach. IN/OUT dürfen nur im Kernelmodus verwendet werden, denn MMU und Hardware sind Aufgaben des Betriebssystems. READ/WRITE dürfen immer verwendet werden und wenn auf eine ungültige Adresse zugegriffen wird, löst die MMU nachträglich einen Page Fault aus.

Deinen Simulator kenne ich nicht.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 12. July 2013, 23:58
Zitat
irgendwie gefällt mir dein Ansatz mit den erlaubten Bereichen und dem Co-Prozessor nicht. Das klingt alles so kompliziert.

Nun ok ich wollte eigentlich auch für die interruptbehandlung nen CO-prozessor einbauen(so ähnlich wie bei mips), soll ich den auch steichen?

Zitat
Eine MMU ist im einfachsten Fall ein SRAM. Bei jedem Speicherzugriff gehen die unteren 12 Bit der (physischen) Adresse an den Adressbus (ergibt 4 KB/Page) und die restlichen, oberen Bits an das SRAM der MMU. Das Datenwort, welches aus diesem SRAM kommt, nimmst du dann als die neuen (virtuellen) oberen Adressbits. Der Inhalt dieses SRAMs enthält dann dein Mapping und muss natürlich irgendwie vom Betriebssystem aus änderbar sein - und unterliegt damit wie jede andere Hardware auch dem Zugriffsschutz(*).
Mhh der SRAM muss ja dann 1 MB groß sein oder? Ist das nicht etwas zu viel ?



Zitat
(*) Wenn du für Hardware einen getrennten Adressraum vorsiehst, ist das recht einfach. IN/OUT dürfen nur im Kernelmodus verwendet werden, denn MMU und Hardware sind Aufgaben des Betriebssystems. READ/WRITE dürfen immer verwendet werden und wenn auf eine ungültige Adresse zugegriffen wird, löst die MMU nachträglich einen Page Fault aus.
Naja hab eher an einen gemeinsamen Adressraum gedacht, wie wärs wenn ich den adressraum in 2 segmente unterteile(die größen der segmente sind immer gleich). Auf das erste Segment kann man nur im kernelmode zugreifen und auf das zweite kernelmode und usermode.



Titel: Re: Logisim CPU
Beitrag von: streetrunner am 13. July 2013, 10:47
Zitat
Mhh der SRAM muss ja dann 1 MB groß sein oder? Ist das nicht etwas zu viel ?
Doch ist es, vor allem da es nicht 1MB sondern ganze 4MB sind (jede Adresse enthält 4 Byte um 32Bit Adressen aufnehmen zu können). Das Gute daran ist, das es wenn der SRAM einmal beschrieben ist es nie zu PageFaults kommen kann. Der riesengroße Nachteil ist dass es ewig dauert bis bei einem Taskwechsel der RAM neu beschrieben ist. Den SRAM verkleinern kann man leider auch nicht so ohne weiteres, da mann ja für jede virtuelle Adresse die von der CPU kommt einen Eintrag haben muss. Jetzt könnte man ja versuchen die Adressen auf weniger Einträge zu verteilen, womit wir dann wieder am Anfang wären.

Zitat
Naja hab eher an einen gemeinsamen Adressraum gedacht, wie wärs wenn ich den adressraum in 2 segmente unterteile(die größen der segmente sind immer gleich). Auf das erste Segment kann man nur im kernelmode zugreifen und auf das zweite kernelmode und usermode.
Das klingt wieder so kompliziert und gibt bei einem sehr kleinen Kernel sehr viel verschwendeten Platz. Ich würde eher dafür sorgen dass der Kernel bestimmen kann wann er in den Usermode wechselt, und das unabhängig davon wo er sich gerade befindet. Wichtig ist nur das der Usermode nicht einfach in den Kernelmode springen kann, das sollte dann nur über Interrupts geschehen, da der dann ausgeführte Code vom Kernel ist und nicht vom User.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. July 2013, 13:04
Zitat
Doch ist es, vor allem da es nicht 1MB sondern ganze 4MB sind (jede Adresse enthält 4 Byte um 32Bit Adressen aufnehmen zu können). Das Gute daran ist, das es wenn der SRAM einmal beschrieben ist es nie zu PageFaults kommen kann. Der riesengroße Nachteil ist dass es ewig dauert bis bei einem Taskwechsel der RAM neu beschrieben ist. Den SRAM verkleinern kann man leider auch nicht so ohne weiteres, da mann ja für jede virtuelle Adresse die von der CPU kommt einen Eintrag haben muss. Jetzt könnte man ja versuchen die Adressen auf weniger Einträge zu verteilen, womit wir dann wieder am Anfang wären.
Man könnte ja die pagegröße erhöhen(z.b von 4kb auf 16 kb) dann benötigt man ja weniger Sram da es weniger Pages gibt oder ?

Zitat
Das klingt wieder so kompliziert und gibt bei einem sehr kleinen Kernel sehr viel verschwendeten Platz. Ich würde eher dafür sorgen dass der Kernel bestimmen kann wann er in den Usermode wechselt, und das unabhängig davon wo er sich gerade befindet. Wichtig ist nur das der Usermode nicht einfach in den Kernelmode springen kann, das sollte dann nur über Interrupts geschehen, da der dann ausgeführte Code vom Kernel ist und nicht vom User.
Naja wie wärs dann mit ein paar steuerbit in jedem SRAM eintrag ? Die dann bestimmen ob man auf das Page nur im kernel modus zugreifen kann oder im usermodus nur gelesen werden kann oder ob man es im usermodus lesen und beschreiben kann. Und joar, bei mir wirds auch so sein das man nur über interrupts in den kernelmode kommt.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 18. July 2013, 13:49
Hallo,

Zitat
irgendwie gefällt mir dein Ansatz mit den erlaubten Bereichen und dem Co-Prozessor nicht. Das klingt alles so kompliziert.
Nun ok ich wollte eigentlich auch für die interruptbehandlung nen CO-prozessor einbauen(so ähnlich wie bei mips), soll ich den auch steichen?
Das hängt davon ab, wie kompliziert du dein Interruptsystem haben möchtest. Wenn du nicht jedem Interrupt eine eigene Leitung spendieren möchtest, brauchst du im Chipsatz eine Logik, die die ganzen Interruptquellen für die CPU verdaulich macht.

Zitat
Eine MMU ist im einfachsten Fall ein SRAM.
Mhh der SRAM muss ja dann 1 MB groß sein oder? Ist das nicht etwas zu viel ?
Bei einer 32-Bit-Architektur sind das sogar 4 MB. Darum legt man diese Tabellen auf solchen CPUs in den normalen Arbeitsspeicher und führt ein mehrstufiges System (Page Directory, Page Tables) ein, damit sich verschiedene Tasks möglichst viel dieser Tabellen teilen können.

Zitat
Wenn du für Hardware einen getrennten Adressraum vorsiehst, ist das recht einfach.
Naja hab eher an einen gemeinsamen Adressraum gedacht, wie wärs wenn ich den adressraum in 2 segmente unterteile(die größen der segmente sind immer gleich).
Das ist dasselbe in grün. Statt einer Steuerleitung, die zwischen Speicher und Hardware umschaltet, schaltet dann die oberste Adressleitung zwischen Segment 0 (Speicher) und Segment 1 (Hardware) um. Vorteil: Du kannst mit den normalen Befehlen deine Hardware erreichen. Nachteil: Jetzt muss jeder Befehl, der Speicher adressieren kann, den aktuellen CPU-Modus kennen...

Man könnte ja die pagegröße erhöhen(z.b von 4kb auf 16 kb) dann benötigt man ja weniger Sram da es weniger Pages gibt oder ?
Ja. Dann muss die MMU pro Task statt 4 MB nur noch 1 MB speichern - immernoch zu viel.

Naja wie wärs dann mit ein paar steuerbit in jedem SRAM eintrag ?
Das geht. Aus einer 32-Bit virtuellen Adresse machst du dann eine 30-Bit physische Adresse mit zwei Zugriffsbits. Das oberste Adressbit unterscheidet dann noch zwischen Speicher und Peripherie, fertig. Ergibt 512 MB maximalen RAM. ;-)

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 18. July 2013, 14:44
Zitat
Ergibt 512 MB maximalen RAM
Aber nur wenn du darauf aus bist deine Pages kreuz und quer über den RAM zu verteilen. Wenn man die Pages z.B. 4k aligned über den Speicher verteilt dann würden zu den 29 Bit nochmal 12 dazu kommen, damit gibt das dann weit mehr als 512MB an RAM.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 18. July 2013, 22:20
Ich bin davon ausgegangen, dass die unteren 12 Adressbits an der MMU vorbei durchgeschleift werden. Dann bleiben nur 2^17 Pages á 4 KiB übrig, also maximal 512 MiB. Das hat den Vorteil, dass die MMU beim Lesen und Schreiben die gleiche Belegung der Adressleitungen verwendet und einem so einen Multiplexer erspart.
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 19. July 2013, 14:05
Ich verstehe nicht ganz was Du meinst.  :?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 19. July 2013, 23:20
Zitat
Das ist dasselbe in grün. Statt einer Steuerleitung, die zwischen Speicher und Hardware umschaltet, schaltet dann die oberste Adressleitung zwischen Segment 0 (Speicher) und Segment 1 (Hardware) um. Vorteil: Du kannst mit den normalen Befehlen deine Hardware erreichen. Nachteil: Jetzt muss jeder Befehl, der Speicher adressieren kann, den aktuellen CPU-Modus kennen...
Naja die speziellen Befehle die auf die hardware zugreifen können, müssen doch auch den CPU modus kennen oder ?  :-)

Zitat
Ja. Dann muss die MMU pro Task statt 4 MB nur noch 1 MB speichern - immernoch zu viel.
Mhh wie wärs wenn ich mein altes konzept wieder aufgreife(das mit den beschränkte bereiche und dem CO-prozessor) und anstatt es über ein co-prozessor zu integrieren ,einfach an den bus anschließe.
Titel: Re: Logisim CPU
Beitrag von: Svenska am 20. July 2013, 22:28
Ich verstehe nicht ganz was Du meinst.  :?
Du hast Recht. :oops:

Naja die speziellen Befehle die auf die hardware zugreifen können, müssen doch auch den CPU modus kennen oder?
Ja, genauso wie die Befehle für die Interruptverwaltung und ähnliches. Aber es geht dabei nur um 2 Befehle (4 Opcodes: IN Reg, Imm und IN Reg, Reg sowie OUT Reg, Imm und OUT Reg, Reg), die im Usermode immer eine Exception werfen. Für den normalen Speicheradressbereich gibt es dafür die MMU, die entsprechend Pagefaults wirft. Allerdings kannst du die MMU selbst nicht dafür benutzen, um Zugriffe zur MMU zu kontrollieren - dafür brauchst du ein eigenes System. Das kann entweder ein I/O-Adressraum (IN, OUT) sein oder eine spezielle MMU-Unterstützung in der CPU (PG-Bit in CR0, CR3 und INVLPG bei x86). Übrigens implementiert sich immer als Bedingung sehr leicht in Logik. :-P

Mhh wie wärs wenn ich mein altes konzept wieder aufgreife(das mit den beschränkte bereiche und dem CO-prozessor) und anstatt es über ein co-prozessor zu integrieren ,einfach an den bus anschließe.
Es ist deine CPU.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 22. July 2013, 17:21
Zitat
Es ist deine CPU.
Mhh nun wenn keiner ne andere idee hat, bau ich mein system ein.

Auserdem hab ich jetzt mir mal gedanken zum Interruptcontroller gemacht, kann man den ein interrupt in einer interrupt-service-routine auslösen ?
Titel: Re: Logisim CPU
Beitrag von: Svenska am 23. July 2013, 03:21
Zitat
Es ist deine CPU.
Mhh nun wenn keiner ne andere idee hat, bau ich mein system ein.
Beide Ansätze wurden aus meiner Sicht ausreichend behandelt. Für was du dich am Ende entscheidest, bleibt schlichtweg dir als Designer überlassen.

Auserdem hab ich jetzt mir mal gedanken zum Interruptcontroller gemacht, kann man den ein interrupt in einer interrupt-service-routine auslösen ?
Normale CPUs haben ein Flag, mit dem man Interrupts ein- oder ausschalten kann. Wenn die CPU in eine ISR wechselt, wird dieses Flag meistens auf "Interrupts ausschalten" gestellt. Selbstverständlich kann man dieses Flag auch zurücksetzen und Interrupts auch innerhalb einer ISR auslösen lassen, um softwareseitig priorisierte Interrupts zu realisieren; da das praktisch aber verdammt schwierig fehlerfrei hinzukriegen ist, wird das eher nur in Ausnahmefällen (Echtzeitsysteme mit garantierten geringen Latenzen bei gleichzeitig geringem Jitter) so gemacht. Allerdings sollte eine ISR sich nie selbst unterbrechen können: Ist sie nicht reentrant, zerstören die Instanzen sich gegenseitig; feuert der Interrupt zu oft, läuft der Stack über.

Wenn du diese Ausnahmefälle unterstützen möchtest, muss dein Interruptcontroller das Maskieren einzelner Interrupts unterstützen und damit eine Busschnittstelle besitzen.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 25. July 2013, 10:52
Mhh, ok. Hätte da noch eine weitere frage:
Sollte bei einem interrupt eher die adresse vom befehl der gerade unterbrochen wird, abgespeichert werden oder die Adresse die im Programmcounter steht und auf den nächsten Befehl zeigt?

Titel: Re: Logisim CPU
Beitrag von: streetrunner am 25. July 2013, 11:27
Es ist einfacher einen Befehl nicht zu unterbrechen, sondern ihn immer zu Ende laufen zu lassen. Wenn man dann den IP speichert, der ja schon auf den nächsten Befehl zeigt, kann man nach einem 'iret' einfach da weitermachen wo man unterbrochen wurde.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 25. July 2013, 18:33
Zitat
Es ist einfacher einen Befehl nicht zu unterbrechen, sondern ihn immer zu Ende laufen zu lassen. Wenn man dann den IP speichert, der ja schon auf den nächsten Befehl zeigt, kann man nach einem 'iret' einfach da weitermachen wo man unterbrochen wurde.
Ah ok, ich hab jetzt mal dann ein Interrupt-Controller entwickelt. Zunächst mal führt meine CPU jetzt ein Befehl immer in 2 takt-zykluse aus ( 1 Takt:Befehl laden,IP erhöhen ; 2 Takt: Befehl ausführen). Nun nur der erste Takt-zyklus( 1 Takt:Befehl laden,IP erhöhen) kann durch ein Interrupt  unterbrochen werden. Tritt ein Interrupt auf während sich die CPU im 2 Zyklus befindet, muss gewartet werden bis sich die CPU wieder im ersten Zyklus befindet.

So jetzt zum eigentlichem Interrupt-Controller: Es gibt 2 arten von Interrupts -die "normale Interrupts" und die "Notfall Interrupts"-  Ein Normales Interrupt kann nur durch ein Notfall-Interrupt unterbrochen werden. Und ein Notfall-interrupt kann nie unterbrochen werden. Nun der Controller ist ähnlich aufgebaut wie der Interrupt-Controller von Mips. Bei einem Interrupt wird der IP in ein sogenanntes EPC-Register geladen, danach wird die Adresse von Interrupt-Handler in den IP und die Ausnahmen-Ursache in das Register R30 geladen.Das EPC-Register und Das register für die Adresse des interrupt-Handler sind jeweils an den Bus angeschlossen.Treten 2 Interrupts vom selben Typ auf, wird nach dem round-robin-verfahren entschieden wer als erstes dran kommt. Tritt ein Notfall interrupt und ein Normales Interrupt gleichzeitig auf hat das Notfall-Interrupt natürlich vorrang.
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 25. July 2013, 18:52
Zitat
nur der erste Takt-zyklus( 1 Takt:Befehl laden,IP erhöhen) kann durch ein Interrupt  unterbrochen werden
Unterbrechen würde ich nur nach ganzen Befehlen, also jeweils am Ende deiner 2 Taktzyklen. Das erspart dir jede Menge Arbeit, da du nicht speichern musst wo dein erster Zyklus unterbrochen wurde (zu Beginn, nach dem Befehl hohlen, nach dem IP inkrementieren)

Und denke dran für deine Notfall-Interrupts ein änliches Register wie das EPC vorzusehen, sonst kann es sein dass es Probleme mit dem Wiedereintritt in deinen eigendlichen Interrupt-Handler gibt.
Titel: Re: Logisim CPU
Beitrag von: Jonathan am 25. July 2013, 23:15
Du solltest außerdem Interrupts zuerst latchen, bevor du sie ausführst, damit kein Int verloren geht, der während einem anderen gleichrangigen Int auftritt.


Gruß
Jonathan
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 25. July 2013, 23:25
Zitat
Unterbrechen würde ich nur nach ganzen Befehlen, also jeweils am Ende deiner 2 Taktzyklen. Das erspart dir jede Menge Arbeit, da du nicht speichern musst wo dein erster Zyklus unterbrochen wurde (zu Beginn, nach dem Befehl hohlen, nach dem IP inkrementieren)
Mhh bei mir dauert ein takt-zyklus ,1 takt( also 2 takte für einen befehl) Nun wird der erste Takt-zyklus unterbrochen und stattdessen der Interrupt-Befehl ausgeführt, ist das doch am ende der beiden letzten taktzyklen ?   

Zitat
Und denke dran für deine Notfall-Interrupts ein änliches Register wie das EPC vorzusehen, sonst kann es sein dass es Probleme mit dem Wiedereintritt in deinen eigendlichen Interrupt-Handler gibt.
Ah danke, das hab ich ganz übersehen :D

Zitat
Du solltest außerdem Interrupts zuerst latchen, bevor du sie ausführst, damit kein Int verloren geht, der während einem anderen gleichrangigen Int auftritt.
Joar stimmt, dann bau ich das auch ein.
Titel: Re: Logisim CPU
Beitrag von: streetrunner am 26. July 2013, 09:13
Zitat
ist das doch am ende der beiden letzten taktzyklen ?
Unterbrechen ist bei mir 'mit etwas beginnen und nicht fertig werden', was Du meinst ist das Dein erster Takt überhaupt nicht ausgeführt wird. Ja, ich denke mal so wäre es richtig, es sei denn irgendwer hätte noch eine andere Idee.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 27. July 2013, 17:31
Mhh nun der Interrupt-Controller ist dann auch schon fertig geplant.  Naja und der VHDL-Code vom meiner CPU ist auch schon fast fertig. Ich glaub jetzt kann ich mir gedanken zu hardware-umsetzung machen :D. Hat dazu jemand ne idee wie ich das am besten mache ?
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 30. July 2013, 23:20
Naja ich glaub ich überschätz mich wieder total :-D , aber ich hab jetzt ein Demoboard entwickelt. Hier mal das grobe Design.

(http://img3.fotos-hochladen.net/uploads/demoboard8ic2dzt6e9.png) (http://www.fotos-hochladen.net)

3bit - Sysbus beinhaltet : RAS0,CAS0, WE
2bit Sysbus beinhaltet : takt, WE.

Nun es gibt nur 1 SIMM-Modul das 16MB groß ist und nur bei Defekt gewechselt wird.
Bei einem Reset wird zunächst das Bios von der ROM in den Ram geladen und ausgeführt.
Und der SS-Bus ist dafür da einer der drei Slaves(Atmega16, Atmega32 & SID 6581) auszuwählen.
Auserdem kann der ATmega 32 nur einen schwarz-weiß textmode ausführen.

So was hält ihr davon, und hat jemand noch dazu ne frage ?
Titel: Re: Logisim CPU
Beitrag von: chris12 am 31. July 2013, 02:22
Du hast also extra ports an deiner cpu für diese spezielle peripherie? ich würde tatsächlich einen MMIO Design verwenden, sodass du einfach den IO in den speicher einblendest über einen AdressController, der im bestenfall einfach ein multiplexer ist. Je nach andresse kannst du dann ja die peripherie endweder nach deinem design an den bis anschliessen, sodass es einen port als controllpfad gibt und einen als datenpfad, oder aber gleich einen port je peripherie, oder mehr.

aber das ist nur meine idee
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 01. August 2013, 15:30
Zitat
Du hast also extra ports an deiner cpu für diese spezielle peripherie? ich würde tatsächlich einen MMIO Design verwenden, sodass du einfach den IO in den speicher einblendest über einen AdressController, der im bestenfall einfach ein multiplexer ist. Je nach andresse kannst du dann ja die peripherie endweder nach deinem design an den bis anschliessen, sodass es einen port als controllpfad gibt und einen als datenpfad, oder aber gleich einen port je peripherie, oder mehr.
Naja Der I/O bus und der Ram-Bus wollte ich eigentlich über einen sogenannten Bus-Controller in der CPU miteinander Verbinden. So das es zu ein MMIO design wird.

Nun,  ich glaub ich lass das wieder mit dem eigenem Demoboard sein und kauf mir ein Fertiges FPGA board. Ein eigenes Demoboard zu entwickeln wird einfach zu schwierig für mich ...
Naja kann mir einer ein FPGA board empfehlen ?
Titel: Re: Logisim CPU
Beitrag von: Jonathan am 10. August 2013, 14:54
Ich würde dir stark empfehlen, deine CPU zunächst auf einem ATMega1284P o.ä. in Software nachzubilden, damit du ein ungefähres Gefühl dafür bekommst, was wie funktioniert, und was nicht. Direkt in Hardware anzufangen ist vielleicht doch ein wenig Overkill. Der µC kann dann ja genau die selben Signale ausgeben, wie es deine spätere richtige CPU tun wird. Höchstwahrscheinlich musst du dabei auf Bus Multiplexing zurückgreifen, aber das ist ja alles mit ein paar Latches zu schaffen.

Außerdem würde ich Interrupts wie einen ganz normalen CALL ablaufen lassen. Im Z80 ist das sogar ein "echter" CALL: Kommt ein INT rein, wird zwar im nächsten M1-Zyklus die Instruktion vom Speicher gelesen, jedoch intern durch einen CALL überschrieben und die externen Daten ignoriert. Dieser CALL pusht dann eine um seine Länge verringerte Rücksprungadresse auf den Stack und springt in die entsprechende ISR. Das ist erheblich einfacher und funktioneller als eine Variante, wo die CPU weiß, in welchem Typ Interrupt-Handler sie gerade steckt usw... Dann hat der Programmierer die volle Kontrolle darüber, wie sich die CPU verhalten soll - er kann z.B. Nested Interrupts auf Wunsch zulassen und muss sich keine Gedanken darüber machen, dass so etwas zu unkontrolliertem Verhalten führen kann. Stell dir vor, ein Interrupthandler würde vom Task Switcher (jemand könnte ihn am "Notfall-Interrupt" anschließen) unterbrochen und weggeswitcht werden - kein anderer Task könnte jetzt noch Interrupts nutzen.


Gruß
Jonathan
Titel: Re: Logisim CPU
Beitrag von: Svenska am 10. August 2013, 23:42
Der µC kann dann ja genau die selben Signale ausgeben, wie es deine spätere richtige CPU tun wird.
Weiter oben im Thread kam die Aussage, dass die CPU nicht real aufgebaut werden soll... jetzt soll es ein FPGA werden. Und das Projekt wächst und wächst und wächst... :-)

Außerdem würde ich Interrupts wie einen ganz normalen CALL ablaufen lassen.
Das geht nicht, wenn du Supervisor-/User-Mode voneinander trennen willst. Ein Interrupt muss zusätzlich zum Call den alten Zustand wegspeichern und einen Ringwechsel durchführen; möglicherweise sogar noch den Speicherkontext wechseln. Den aktuellen Modus würde ich ungern im gewöhnlichen Flagregister haben, da er dort eine Sicherheitslücke darstellt.

Stell dir vor, ein Interrupthandler würde vom Task Switcher (jemand könnte ihn am "Notfall-Interrupt" anschließen) unterbrochen und weggeswitcht werden - kein anderer Task könnte jetzt noch Interrupts nutzen.
Naja, verschachtelte Interrupt braucht man jetzt nicht unbedingt. Selbst auf dem Z80 tut man gut daran, darauf zu verzichten (dann kann man Interrupts im zweiten Registersatz abhandeln und spart sich den Stack). Wenn man Interrupts verschachteln muss, ist das meist ein Zeichen für eine ungeeignete Programmstruktur (d.h. ISRs zu lang).

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 13. October 2013, 15:02
So , ich hab mich jetzt dazu entschlossen erstmal eine kleinere 16bit CPU zu bauen(hab das Datenblatt als pdf angehängt). Nun was hält ihr von meiner CPU und von meinem Datenblatt ? :D
Titel: Re: Logisim CPU
Beitrag von: Svenska am 14. October 2013, 01:49
Hallo,

16 Befehle, 16-Bit Daten, 16-Bit Adressen, 16(+1) Register: Du magst die 16, oder? Für eine 16-Bit-CPU sind 64 KB physischer Adressraum definitiv zu wenig. Das tut gleich noch ein zweites Mal weh, weil sich Code, Daten und Stack diese 64 KB auch noch teilen müssen. Jeder Befehl hat 2 Byte, jede Konstante hat 2 Byte und da du keine komplexeren Befehle hast, brauchst du auch noch sehr viele davon.

Grundsätzlich: Du möchtest mindestens einen 24-Bit Adressraum und mindestens 32 (besser: 64, wegen Erweiterungen) Befehle. Alles darunter macht keinen Spaß beim Programmieren. (Ja, ich weiß, ein Z80 hat auch nur einen 16-Bit Adressraum, aber als über 35 Jahre alter 8-Bitter darf der das.)

An Logik bietest du AND, OR und XOR an: AND und OR braucht man ständig, XOR dagegen fast nie. Ersetze es lieber durch NOT (man braucht Negation und entweder Konjunktion oder Disjunktion, um alle anderen logischen Funktionen nachbilden zu können).

Deine Sprungbefehle sind etwas dürftig. Normalerweise möchte man JUMP (unbedingt), BRANCH (bedingt), CALL (mit Rücksprungmöglichkeit) haben. Dazu gehört dann natürlich auch ein RET, für Interrupts ein IRET. Wenn du PC als direkt adressierbares Register hat, kann man das aber alles relativ einfach nachbauen.

In deinem Datenblatt steht drin, dass dein JUMP entweder die auf das JUMP folgende Adresse anspringt (wenn Bedingung falsch) oder die auf JUMP folgende Adresse als Befehl ausführt (wenn Bedingung wahr). Ich glaube, das willst du nicht. Außerdem kann dein JUMP nur eine zur Compilezeit bekannte, konstante Adresse anspringen, keine zur Laufzeit errechnete. Wenn du PC als gewöhnliches Register betrachtest, dann braucht dein JUMP kein eigenständiger Befehl zu sein.

BRANCH-Befehle sind meist PC-relativ und können nicht über den gesamten Adressraum springen. Statt einer vollen 16-Bit-Adresse reichen vier Bedingungsbits und 12 Bit Sprungweite (8 KB, da jeder Befehl auf einer geraden Adresse liegen muss) eigentlich dicke aus. An Bedingungen würde ich mindestens A==B, A<B, A<=B, immer und deren Negationen anbieten ("nie" als negiertes "immer" ist dann ein NOP).

Die Befehle IN/OUT finde ich sehr hässlich gelöst. Wenn die Tabelle deine MMU-PageTable ist, dann kann man darauf nicht wirklich zugreifen. Wenn ich Page N (aus einem Taskregister) ändern möchte, dann steht N in einem Register und ist keine Konstante. Außerdem kannst du entweder IN/OUT für allgemeine Hardwarezugriffe vorsehen (damit hast du dann einen zweiten Bus, der z.B. nur im Kernelmodus zugreifbar ist) oder du lässt die Befehle ganz weg und blendest Hardware (inklusive MMU) in den Adressraum ein.

Flags sind an sich eine feine Sache, um relativ einfach Branches anzubieten. Um mit Zahlen größer als 16 Bit zu hantieren, musst du in der Lage sein, Übertrage (Carry) zu verarbeiten. Andere praktische Flags wären dann der CPU-Modus, ob die MMU aktiv ist oder nicht (nach Reset: MMU deaktiviert), ob Interrupts aktiv sind und das, was die Bedingungen ermöglicht.

LOAD und STORE finde ich etwas seltsam, weil die zusätzlich noch eine Addition/Subtraktion beinhalten. Vielleicht verstehe ich es gerade auch einfach nicht.

Deine Interruptlogik klingt kaputt (auch vom Deutsch her). Dein 64-Word-RAM ist zufällig die gleiche Tabelle, die auch die MMU enthält? Du schreibst PC an Adresse 17, liest dann die Adresse der ISR auf Adresse 18 und überschreibst danach Adresse 18 mit irgendwelchen Bits. Das heißt, während eine ISR aktiv ist, darf kein anderer Interrupt behandelt werden, da sonst eine zufällige Adresse angesprungen wird. Da du keine Befehle hast, die Interrupts abschalten können, kann das jederzeit passieren.

Dein Datenblatt enthält keine Informationen zum Alignment (ich vermute mal ein 16-Bit-Alignment für alles, d.h. du brauchst nur 15 Bit für eine Adresse). Wenigstens eine Rechtschreibprüfung hättest du ja spendieren können, so sieht das ziemlich hingeklatscht aus.

Was mir persönlich komplett fehlt, ist die Anbindung an den Rest der Welt. Eine CPU ist ja nicht nur zum Selbstzweck da, sondern soll ja auch irgendwas mit Ein- und Ausgaben tun. Ich vermute, dass du da nicht drüber nachgedacht hast und daher alles außer MMU in den Speicher gemappt werden muss. So sieht das Interrupthandlung auch aus.

Bevor du dich daran machst, deine CPU in VHDL/Verilog/xxx zu implementieren, solltest du einen Simulator in einer Programmiersprache deiner Wahl schreiben (je nachdem, was du gut kannst) und dann mal Anwendungen dafür schreiben. Dann siehst du, was verbesserungswürdig ist, fehlt oder einfach nur kaputt ist.

Vermutlich habe ich noch einige Punkte vergessen zu erwähnen. Auf SHL, SHR, SHAR und ROR bin ich nicht eingegangen, weil ich davon keine Ahnung habe. Wie negative Zahlen realisiert werden und ob die Unterstützung dafür ausreicht, weiß ich nicht (vermute aber mal ein nein, weil ein SIGN-Flag fehlt). Außerdem fehlt mir eine übersichtliche Bitdarstellung der Opcodes (kann man sich aber vermutlich aus dem Rest denken).

Ich gebe das Datenblatt hiermit an den Autor zurück.

Gruß,
Svenska
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 16. October 2013, 22:25
Zitat
Grundsätzlich: Du möchtest mindestens einen 24-Bit Adressraum und mindestens 32 (besser: 64, wegen Erweiterungen) Befehle. Alles darunter macht keinen Spaß beim Programmieren. (Ja, ich weiß, ein Z80 hat auch nur einen 16-Bit Adressraum, aber als über 35 Jahre alter 8-Bitter darf der das.)

Nun gut dann bau ich intern meine CPU zu einer 32 bit cpu um (mit 32bit registern und einer 32bit alu) , extern hat er dann aber nur noch einen 24bit adressbus und noch den 16bit datenbus.
Die Befehlslänge Bleibt bei 16bit.

Es gibt immernoch 16 Befehle und 16 register.
Das Registerset ist folgenermaßen aufgebaut:
Reg0 = Nullregister,
Reg1-Reg12 = Normale Register
R13 = Flagregister
R14 = Linkregister
R15 = Programmcounter


So das hier sind die 16 Befehle:

die Befehle addi/subi sind nur 2 operanten Befehle(also z.b addi Reg1, 0xFF, also Reg1 = Reg1 + 0xFF )
In den Befehlen Store und Load gibts noch zusätzlich einen 4bit offset.Bei Store wird der 4bit offset von dem adressregister abgezogen und bei load draufaddiert(so kann man Load/store als normale Load/store benutzen indem man den offset auf 0 lässt, oder man verwendet die 2 Befehle als Pop/push indem man den offset auf z.b 1 setzt.)Auserdem werden Bei Load/store nur die unteren 16 bits des Quell bzw Zielregister benutzt.

der befehl shift so aufgebaut: 0-3 Opcode | 4-6 Shiftart | 8-12 shiftweite | 13-16 Register.
shiftart : srl, sll, ror, sra
die shiftweite sagt aus wie weit geshift werden soll

Beim Befehl jump werden keine Flags gesetzt sondern nur geschaut welche Flags gesetzt sind, auserdem kann man über ein Bit entscheiden -falls die richtigen flags gesetzt sind- ob ein Wert aus einem Register oder einen Kostanten wert ( der an der adresse liegt auf dem der PC zeigt) in den PC geladen wird.

Der Befehl LoadByte ladet einen 8 bitwert in das gesamt Register.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 02. November 2013, 23:11
Nun hab ein Weiteres Datenblatt geschrieben, für eine 32bit risc- CPU mit 16 bit Befehlen.
Titel: Re: Logisim CPU
Beitrag von: Tufelix am 03. November 2013, 13:15
So hab jetzt mal das datenblatt und die CPU nochmal ein wenig überarbeitet.

Edit: anscheindend ist das Datenblatt etwas zu groß, hab jetzt mal 1 satz rausgestrichen:

LoadRs und Store Rs sind nur im Systemodus aktiv, im Usermodus stellen sie ein nop dar.