Autor Thema: Logisim CPU  (Gelesen 159945 mal)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #100 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
« Letzte Änderung: 07. January 2013, 22:19 von Svenska »

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #101 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.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #102 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #103 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  ?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #104 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
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #105 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

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #106 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
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #107 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

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #108 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

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #109 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ß

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #110 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.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #111 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 oder hier von 2010. Da kannst du dir noch ein paar Anregungen raussuchen. Meine CPU ist allerdings im Sande verlaufen.

Gruß,
Svenska

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #112 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
Reality is that which, when you stop believing in it, doesn't go away.

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #113 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.


Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #114 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

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #115 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

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #116 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
Reality is that which, when you stop believing in it, doesn't go away.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #117 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 an und z.B. dieses Video 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

Tufelix

  • Beiträge: 103
    • Profil anzeigen
Gespeichert
« Antwort #118 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 ?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #119 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
Reality is that which, when you stop believing in it, doesn't go away.

 

Einloggen