Kürzlich gab es die Diskussion, ob man in einem FPGA einen Prozessor
implementieren kann. Und natürlich, man kann. Zu diesem Zweck (und um
VHDL zu trainieren) habe ich mich hingesetzt. Ein paar Datenpfadelemente
wie Multiplexer, Adressdecoder und Register habe ich bereits gebastelt,
jetzt geht es aber an die Frage:
** Welche Architektur solls denn werden? **
Es gibt 2 Möglichkeiten:
1. Etwas eigenes.
Nachteil:
- Man muss sich selbst Assembler und Compiler basteln, wenn man das Ding
richtig testen oder gar einsetzen möchte.
2. Eine bestehende Architektur nachbauen.
Nachteil:
- Man muss die bestehende Architektur komplett und korrekt
interpretieren und nachbauen, um eine bestehende Toolchain zu benutzen.
Vereinfachungen oder andere Modifikationen liegen nicht drin.
Jedenfalls suche ich nun nach ein paar Vorschlägen für Architekturen, es
dürfen sowohl interessante bestehende Prozessoren sein oder auch Ideen
für neue Ansätze.
AooA schrieb:> 2. Eine bestehende Architektur nachbauen.> Vereinfachungen oder andere Modifikationen liegen nicht drin.
Warum nicht?
Auch die ganzen 8051-Derivate, die seit 1995 erschienen sind, sind
Opcode-kompatibel und trotzdem bis zu 12 mal schneller als der
Original-8051. Und das nicht wegen der Erhöhung der Taktfrequenz,
sondern weil die Befehle in 1 statt in 12 Taktzyklen ausgeführt
werden...
AooA schrieb:> Kürzlich gab es die Diskussion, ob man in einem FPGA einen Prozessor> implementieren kann. Und natürlich, man kann. Zu diesem Zweck (und um> VHDL zu trainieren) habe ich mich hingesetzt. Ein paar Datenpfadelemente> wie Multiplexer, Adressdecoder und Register habe ich bereits gebastelt,> jetzt geht es aber an die Frage:>> ** Welche Architektur solls denn werden? **>> Es gibt 2 Möglichkeiten:>> 1. Etwas eigenes.> Nachteil:> - Man muss sich selbst Assembler und Compiler basteln, wenn man das Ding> richtig testen oder gar einsetzen möchte.
Oder man nimmt einen Assembler mit ähnlichen output und sortiert die
bits um. Das ist dann einfacher als einen assembler komplett selbst zu
schreiben.
Die op-codes sind nicht so unterschiedlich, irgendwelche bits
adressieren die register, andere die Operation, und da mal ein paar bits
zu verschieben sollte das nicht das problem sein. Und gab es da nicht
Assembler-Compiler?, Also Software mit der du deinen Assembler selbst
zusammenstricken kannst. Oder waren das Universalassembler?. GNU hat
bestimmt auch was im Quellcode, das sollte das assembler.basteln auch
nicht so schwierig sein.
MfG,
@AooA
ich bin gerade ebenfalls mit einem Softcore dran. Allerdings habe ich
mich für Lösung 2 entschieden. Es ist zwar kein schneller Prozessor
(durch ein langsames aber universelles Speicherinterface, kein RISC, und
"klassisches" Design brauche ich viele Takte bis der Befehl abgearbeitet
ist) aber mir geht es auch erstmal um einen Einstieg in die Softcores um
zu sehen welche Teile eines Prozessors am meisten Logik benötigen, bzw
wie man was anders gestalten kann um einen solchen Prozessor klein zu
bekommen.
Den Reiz am selbstentworfenen Design finde ich darin das ich selbst
bestimmen kann was der Prozessor kann. Ich habe bei mir z.b. eine 16-Bit
Architektur in der nahezu jeder Befehl bedingt ausführbar ist, weil ich
das von der programmierung her elegant finde. Einen Assembler dafür zu
bauen ist kein Problem. Ein C-Compiler dürfte um Klassen komplexer sein
(wenn ich das überhaupt in Angriff nehme). Aber da ist man wieder bei
pro und contra Selbstbau/Nachbau :-)
Rene Böllhoff schrieb:> kein RISC, und> "klassisches" Design brauche ich viele Takte bis der Befehl abgearbeitet> ist
Ich für meinen Teil würde schwer zu einem RISC tendieren. Es ist von
Architektur und Simulation her einfach deutlich übersichtlicher, wenn
die Daten in jedem Prozessortakt einmal durch den ganzen Datenpfad
laufen und wieder sauber zurückgeschrieben werden. Bei einem CISC
hingegen wird man die ganzen Zwischenzustände in jedem Mikroschritt
analysieren müssen.
Wie wäre es mit der Architektur von Chuck Thacker:
http://lambda-the-ultimate.org/node/3232 ?
"Presents the design of a complete CPU in under two pages of FPGA-ready
Verilog. The TC3 is a Harvard architecture 32-bit RISC with 1KB of
instruction memory, 1KB of data memory, and 128 general-purpose
registers."
Alternativ gäbe es noch MMIX von Donald Knuth:
https://secure.wikimedia.org/wikipedia/en/wiki/MMIX . Dort bekommt dann
z.B. den gcc dafür.
Ein kleiner 4-Bitter im Stil eines Intel 4004 habe ich mal
aufgezeichnet. Den dürfte man wohl fast in ein CPLD bringen, was man als
ziemlich coole Bastelei präsentieren könnte. Problematisch bei
Architekturen mit so geringer Wortbreite ist aber immer das Handling von
Programmcounter, Stack und Instruktionsregister. Diese sind viel breiter
als die Datenregister und können somit, im Gegensatz zu einer
Architektur mit grösserer Wortbreite, nicht direkt über den normalen
Datenpfad abgewickelt werden.
Beispielsweise eine call-Anweisung bei 4 Bit Wortbreite, 12 Bit
Programmcounter und 12 Bit Datenadressen. Alleine das Speichern des
Programmcounters auf dem Stack benötigt also 3 Speicherzugriffe, die
wiederum jeweils 3 Addieroperationen brauchen, um den Stackpointer
nachzuführen.
Hendrik Lipka schrieb:> Wie wäre es mit der Architektur von Chuck Thacker:> http://lambda-the-ultimate.org/node/3232 ?> Alternativ gäbe es noch MMIX von Donald Knuth:> https://secure.wikimedia.org/wikipedia/en/wiki/MMIX . Dort bekommt dann> z.B. den gcc dafür.
Der obere ist bereits von der Architectur her an (Xilinx-) FPGA's
angepasst, indem er die Prozessorregister statt aus einzelnenen FF- aus
einem Embeded DualPort bastelt. Allerdings scheint mir (nach flüchtiger
Durchsicht) ein Unterprogrammaufruf zu fehlen, ebenso wie ein Interrupt.
Ohne den MMIX genau zu kennen befürchte ich, das dieser nicht für FPGA's
angepasst wurde und daher wahrscheinlich langsam ist.
MfG,
Sorry fuer den Offtopic, ich habe aber eine Frage bezueglich ein ARM
Klon.
Ich habe hier ein Spartan 3E 500K Board und ueberlege was ich damit
machen sollte. Reicht eigentlich ein Spartan 3E fuer ein ARM Klon oder
braeuchte man mindestens ein Virtex2? Ich habe mir die ARM Architecture
Reference Manual(fast 1200 Seiten) runtergeladen und will es die Tagen
mal angucken.
Danke im voraus.
Gruss,
Valentin
Vor 30 Jahren war der 6502 der Inbegriff von RISC: wenig Register
(A,X,Y,SP,PC,Flags), hartverdrahtete Befehle (zumindest in der
NMOS-Version), einfache Architektur. Wenn Du dann noch Energie hast,
darfst Du Dich gerne bis zum 65816 hocharbeiten. Siehe 6502.org
Willst Du eine aktuelle Architektur, wäre MIPS erwähnenswert, weil
wirklich ziemlich RISCig.
fchk
Ich würde auch zu einer RISC Architektur raten.
Einen eigenen Assembler zu machen ist eigentlich kein großes Ding und
wie aufwändig die Hardware wird hängt davon ab, wie du deine Befehle
kodierst und welche Adressierungsarten du dir gönnen magst. Hinzukommen
dann evtl. noch solche Sachen wie Interrupts, Exceptions,
Branch-Prediction, Pipelining usw. je nach Zeitaufwand halt.
No RISC no fun ;)
Frank K. schrieb:> Vor 30 Jahren war der 6502 der Inbegriff von RISC: wenig Register> (A,X,Y,SP,PC,Flags),
?Ist es nicht gerade ein Merkmal von RISC viele Register in der CPU zur
Verfügung zu stellen?
MFG,
AooA schrieb:> Kürzlich gab es die Diskussion, ob man in einem FPGA einen Prozessor> implementieren kann. Und natürlich, man kann. Zu diesem Zweck (und um> VHDL zu trainieren) habe ich mich hingesetzt. Ein paar Datenpfadelemente> wie Multiplexer, Adressdecoder und Register habe ich bereits gebastelt,> jetzt geht es aber an die Frage:>> ** Welche Architektur solls denn werden? **>> Es gibt 2 Möglichkeiten:>> 1. Etwas eigenes.> Nachteil:> - Man muss sich selbst Assembler und Compiler basteln, wenn man das Ding> richtig testen oder gar einsetzen möchte.
Es sollte recht einfach sein, sich einen Quick und dirty assembler per
Spreadsheet (Excel;OO Calc)zusammenzubasteln. Ein Instruction wort mit
seiner seinen fest zugeordneten Bitfeldern ist doch recht einfach auf
einige Spalten Excel abgebildet, meinetwegen noch mit Auswahlmenü für
die Operations-Mnemonics.
zum Schluss wird dann der Inhalt eines Feldes mit einer Zweierpotenz
multipliziert, alle Felder addiert und in Hex angezeigt.
Weitere Vorschläge schnell einen Assembler zu schreiben.
MfG
D. I. schrieb:
Hinzukommen
> dann evtl. noch solche Sachen wie Interrupts, Exceptions,> Branch-Prediction, Pipelining usw. je nach Zeitaufwand halt.
Pipelining (und damit verbunden Sprungvorhersage) erfodert schon größere
Umbauten an der CPU, das ist kein "hinzukommen" mehr. Man sollte schon
im voraus eine sinvolle Anzahl von Pipelinestufen abschätzen. Bei einem
FPGA mit 6er oder 4er LUT sollten es 2 oder drei sein. Bei einer so
kurzen Pipeline macht sprungvorhersage wenig Sinn. Und mit einer
Ein-takt maschine ohne Pipeline kann man in einem FPGA schon (für
Embedded) ordentliche taktraten von 60 - 100 MHz erreichen.
Der Aufwand einen IRQ nachzurüsten ist eher gering. sollte aber meines
erachtens von anfang an in dem Programmcounter mit eingebaut sein.
Notwendigkeit von Exceptions ist nicht ersichtlich, welche
Ausnahmebehandlung meinst Du?
MfG,
Frank K. schrieb:> Vor 30 Jahren war der 6502 der Inbegriff von RISC: wenig Register> (A,X,Y,SP,PC,Flags), hartverdrahtete Befehle (zumindest in der> NMOS-Version), einfache Architektur.
Das passiert, wenn man RISC nur als Reduktion des Befehlssatzes sieht.
Sieht man es eher als Reduktion des Ablaufes (IBM Power: C=complexity
statt computing) durch ein Architekturschema mit einfachen Operationen
auf Register und davon getrennten einfachen Lade/Speicheroperationen,
also einer Load/Store-Architektur, dann ist der 6502 aufgrund des recht
komplexen Befehlsablaufs speicherindirekter Rechenoperationen kein
bischen RISC.
Unter den frühen 8-Bittern passt ins RISC-Schema eher RCA 1802.
Ich knüpfe mal an die RISC Diskussion an, da ich noch ein wenig
Schwierigkeiten habe mir bestimmte Abläufe vorzustellen.
Das Prinzip das mit jedem Takt ein Befehl abgearbeitet wird ist klar.
Das (je nach Anzahl der Stufen) dadurch eine Sprungvorhersage nötig wird
ist auch klar. Und das die Einheiten (Fetch/Decode/Execute) parallel
arbeiten und mit jedem Takt ein Ergebnis ausspucken auch.
Mein Problem beginnt bei der Umsetzung. Wenn ich z.b. einen einzigen
Speicherbereich habe greife ich mit jedem Takt ja auf diesen Speicher
lesend zu (um meinen Opcode rauszufischen). Aber wenn ich nun ein
Ergebnis in den Speicher zurückschreiben möchte, muß ich ja eine andere
Adresse, ein Datenwort und die Toggle-Leitung für RW/OE (klassisches
SRAM) bedienen. Da ich aber ja auch noch Setup/Holdzeiten beachten muß,
bzw erstmal einen Takt warten muß bevor ich mein Datenwort auf den
Datenbus lege (nachdem ich diesen vorher in Tri-State geschaltet habe,
damit möglicherweise 2 Ausgänge nicht gegeneinander treiben) habe ich ja
schon mindestens zwei Takte um den Speicherzugriff umzuschalten.
Und da ist mein Problem. Das eine ALU oder ein Dekoder in einem Takt
fertig sein kann, kein Thema. Aber wie läuft das bei Speicherzugriffen
die allein durch die Umschaltung schon evtl. mehrere Takte benötigen ?
Oder wird da unterschieden zw. Systemtakt und Prozessortakt die in einem
festen Verhältnis (2:1, 3:1, 4:1) stehen damit auch
Lese/Schreiboperationen möglich sind während die Stufen fröhlich vor
sich hintakten.
Oder ist da ein Denkfehler meinerseits ?
Grundlegend: das Speicherinterface ist nicht Bestandteil des Prozessors.
Dieses Interface muß natürlich so aufgebaut sein, dass der Code und die
Daten hinreichend schnell bereitgestellt werden. Sonst muß der Prozessor
Wartezyklen einlegen.
Auch bei AVR-Controllern brauchen Befehle, die auf den Programmspeicher
gehen, mehrere Zyklen. Zugriffe auf den Datenspeicher laufen aber wegen
der Harvard-Architektur parallel zu Programmspeicherzugriffen.
>Dieses Interface muß natürlich so aufgebaut sein, dass der Code und die>Daten hinreichend schnell bereitgestellt werden
Wäre eine Lösung dieses Problems also das Speicherinterface mit der
doppelten oder vierfachen Geschwindigkeit laufen zu lassen damit
"parallel" zu einem Lese-befehl ein Schreib-Befehl ausgeführt werden
kann ?
>Harvard-Architektur
Ok, da ist das Problem vllt nicht so gegeben, obwohl ich da ja u.u. auch
mehrere Takte benötige. Aber ich dachte eher an von-Neumann, da man dort
je nach Speicher einfach mehr "drankleben" kann, ohne direkt einen 2.
Adress/Daten/Steuer-Bus haben zu müssen.
Wie könnte ein solches Speicherinterface aussehen ? Ich meine ich
brauche ja auch u.u. noch 1-2 Takte Latenz damit der Prozessor bescheid
weiß das der Speicher mal wieder nen Snickers braucht.
Ich arbeite bei mir momentan immer mit einer Trigger und Ready-Leitung.
Dadurch kann der Speicher intern oder extern/schnell oder langsam sein.
Aber die Zugriffe da, benötigen noch mehr Zeit (zw 4-6. Takte).
Irgendwie tu ich mich mit dem Speicherzugriff bzw "parallelen" Zugriff
etwas schwer.
Rene Böllhoff schrieb:> Mein Problem beginnt bei der Umsetzung. Wenn ich z.b. einen einzigen> Speicherbereich habe greife ich mit jedem Takt ja auf diesen Speicher> lesend zu (um meinen Opcode rauszufischen).
Solange du nur ein Speicherinterface hast, ist das mit einem Takt pro
Befehl auf Lade/Speicherbefehle nicht anwendbar.
Daher führen Lade/Speicherbefehle entweder zu Befehlen, die mehr als
einen Takt benötigen, oder es existieren mehrere Interfaces, getrennt
nach Code und Daten. Letzteres ist bei Caches und bei internem Speicher
von Controllern recht verbreitet (AVR, Cortex-M3, ...).
> Und da ist mein Problem. Das eine ALU oder ein Dekoder in einem Takt> fertig sein kann, kein Thema. Aber wie läuft das bei Speicherzugriffen> die allein durch die Umschaltung schon evtl. mehrere Takte benötigen ?
Es stellt sich die Frage, ob das wirklich sein muss. Oder ob durch
geeignetes Pipelining Zugriffe teilweise überlappen können.
Lothar Miller schrieb:> Grundlegend: das Speicherinterface ist nicht Bestandteil des Prozessors.
Kommt drauf an, wo man mit dem Begriff "Speicher" ansetzt. Wenn man
Caches als Speicher sieht, dann sind diese durchaus Bestandteil des
Prozessors. Wenn man das Interface erst jenseits der Caches sieht, dann
kann man das ggf. getrennt betrachen.
Hardvard Architecture,
Contrast with von Neumann architectures
Under pure von Neumann architecture the CPU can be either reading an
instruction or reading/writing data from/to the memory. Both cannot
occur at the same time since the instructions and data use the same bus
system. In a computer using the Harvard architecture, the CPU can both
read an instruction and perform a data memory access at the same time,
even without a cache. A Harvard architecture computer can thus be faster
for a given circuit complexity because instruction fetches and data
access do not contend for a single memory pathway .
Beispiele für eine Architektur mit nur einem Speicherinterface und mit
den daraus resultierenden Nebeneffekten hinsichtlich des kritischen
Speichertimings sind die älteren ARM Cores (ARM2..ARM7).
ARM2 war noch für externen Speicher ohne Cache konzipiert und
unterschied zwischen sequentiellen Zugriffen und nichtsequentiellen.
Sprünge waren klarerweise nichtsequentiell, aber auch
Lade/Speicherbefehle führten dazu, erstens beim Datenzugriff selbst,
zweitens beim darauf folgenden Codezugriff. In vielen Systemen waren
nichtsequentielle Zugriffe einen Takt langsamer. Entsprechendes Timing
ist m.W. auch beim ARM7 noch dokumentiert.
A. K. schrieb:> ARM2 war noch für externen Speicher ohne Cache konzipiert und> unterschied zwischen sequentiellen Zugriffen und nichtsequentiellen.> Sprünge waren klarerweise nichtsequentiell, aber auch> Lade/Speicherbefehle führten dazu, erstens beim Datenzugriff selbst,> zweitens beim darauf folgenden Codezugriff. In vielen Systemen waren> nichtsequentielle Zugriffe einen Takt langsamer. Entsprechendes Timing> ist m.W. auch beim ARM7 noch dokumentiert.
Richtig. Erst mit dem ARM8 Kern wurde die Pipeline auf fünf Stufen
verlängert, so daß Address und Datenphase in unterschiedlichen Stufen
ablaufen. Seit dem kann man register- und datenunabhängige,
nichtsequentielle Speicherzugriffe ohne Wartezyklen ausführen,
vorausgesetzt, der Speicher kann mithalten.
Bei den moderneren Cores mit dreistufiger Pipeline (Cortex-M) werden
wiederum andere Tricks angewandt, um die Speicherzugriffe meist ohne
Wartezyklen ablaufen zu lassen. Das ist aber nicht immer möglich.
@Rene:
Zum Thema Tri-State: Vergiss es. Keine moderne Architektur verwendet
mehr echte Busse. Orientiere Dich lieber and den verschiedenen
"Bus"-Systemen, die kommerziell eingesetzt werden.
Ich könnte an dieser Stelle auf einen Artikel verweisen:
http://www.doulos.com/knowhow/arm/Migrating_from_AHB_to_AXI/
Mach' ich aber nicht, da es als Eigenwerbung verstanden werden könnte
:-)
Gruß
Marcus
@Markus
Hätte ich das mit dem "Tri-State-Vergessen" so zu verstehen das ähnlich
wie bei den FPGA's es keine bidirektionalen Busse mehr gibt, sondern nur
noch unidirektionale, und die "schnelle" Umschaltung an der Anbindung
zum RAM (egal ob SRAM/SDRAM/DDR-RAM) der Speichercontroller vornimmt ?
Also das intern ein Data-In- und Data-Out-Bus existiert der das Timing
auf intern einen Takt herunterbricht ?
Ich habe die Werbung gekonnt ignoriert und werde sie später gekonnt
nicht durchlesen :-) ... Danke für den Hinweis.
Für mich ist das bisher immer so gewesen das die SRAMs/SDRAMs ja noch
einen Bidirektionalen Bus haben, und die Anbindung an den
Speichercontroller muß ja genauso funktionieren. Nur was intern (zw.
Prozessor und Speichercontroller) gemacht wird ist ja was anderes. Daher
bin ich mir nicht sicher ob ich o.g. richtig dargestellt habe.
Rene Böllhoff schrieb:> SRAMs/SDRAMs ja noch> einen Bidirektionalen Bus habe
Das gilt z.B. für QDR-SRAMs nicht mehr. Durch DDR auf den Datenleitungen
bleibt die Pinzahl konstant und man trennt hin- und rücklaufende Daten.
Duke
@Duke
Ok, lassen wir mal die neuesten RAM-Typen weg. Um die
1-Takt-Zyklus-Philosophie umzusetzen müsste ich also entweder den
Prozessor-Takt im einem festen Verhältnis zueinander setzen, damit das
System dem Prozessor bei jedem Takt ein Datenwort liefert bzw eines
wegschreiben kann, oder aber dafür sorgen das der Datenbus für jede
Richtung einmal vorhanden ist.
Wie das jetzt realisiert ist, ob ich das in einem getrennten
Speichercontroller mache oder aber im FPGA "In-the-Box" ist ja erstmal
egal. Aber wäre das ein Ansatz dafür ?
Ich wüsste sonst nicht wie man allein mit Überlappung der
Schreib/Lese-Anweisungen auf einen Takt kommt ohne Wartezeiten zu
bekommen, die ich ja beim Schreiben allein schon für das setzen und
rücksetzen der WE-Leitung/Address/Datenleitungen brauche.
Irgendwie scheinen mir diese Überlegungen schwieriger zu sein, als ein
Design in CISC (oder zumindest eben nicht gepipelined). Aber vllt brauch
ich einfach mal nur ein einfaches, gut und vor allem vollständig
dokumentiertes VHDL-RISC-Beispiel um da klarer zu sehen. Hätte da jemand
mal vllt einen Link ? Ich hab schon einiges gefunden, aber eine
wirkliche detaillerte Beschreibung aber so noch nicht.
Rene Böllhoff schrieb:> Hätte ich das mit dem "Tri-State-Vergessen" so zu verstehen das ähnlich> wie bei den FPGA's es keine bidirektionalen Busse mehr gibt, sondern nur> noch unidirektionale, und die "schnelle" Umschaltung an der Anbindung> zum RAM (egal ob SRAM/SDRAM/DDR-RAM) der Speichercontroller vornimmt ?> Also das intern ein Data-In- und Data-Out-Bus existiert der das Timing> auf intern einen Takt herunterbricht ?
Genau so. Wobei bei Anbindung externer Speicher mit bidirektionalen
Datenleitungen natürlich die Read-After-Write Zyklen immer noch
auftreten können und dann auch intern sichtbar werden.
Was ich meinte bezog sich allerdings auf die internen Buszyklen. Wenn da
schon Zwangspausen eingelegt werden, kannst Du auch mit idealem Speicher
nichts mehr richten.
Bei typischen on-chip Bussen (die eigentlich keine mehr sind), kann z.B.
die Adressphase des nächsten Transfers mit der Datenphase des aktuellen
Transfers überlappen.
--
Marcus
>Bei typischen on-chip Bussen (die eigentlich keine mehr sind), kann z.B.>die Adressphase des nächsten Transfers mit der Datenphase des aktuellen>Transfers überlappen.
Genauso hab ich mir die Überlappung auch vorgestellt. Ich kam nur nicht
damit zurecht das ich u.u. eben doch mehr als nur einen Takt benötige,
das passt irgendwie nicht in das Pipelining "Muster" ohne das
Wartezyklen entstehen.
Bei einem vielfachen des Systemtaktes gegenüber dem Prozessortakt lässt
sich dann ein gepipelintes Design besser handlen denke ich. Ich glaube
ich werd (wenn mein aktuelles Design fertig ist) das mal bei einer
Überarbeitung mit einfließen lassen.
Danke für die Hinweise. Allerdings wäre ich noch dankbar wenn jemand ein
gutes Tutorial bzw ein gutes (einfaches) Design mit ausführlicher Doku
hat, damit ich mir das nochmal alles verinnerlichen kann.
Viele Infos hab ich hier aus dem Forum, aus Wikipedia, und viele Dinge
sind auch einfach klar. Aber bei so manchen "Feinheiten" da komm ich
schonmal ins Trudeln.
Sehr interessantes Thema,
Ich wollte auch eine Cpu zum Vertauschen von Werten in einem Array
bauen.
> Danke für die Hinweise. Allerdings wäre ich noch dankbar wenn jemand ein> gutes Tutorial bzw ein gutes (einfaches) Design mit ausführlicher Doku> hat, damit ich mir das nochmal alles verinnerlichen kann.> Viele Infos hab ich hier aus dem Forum, aus Wikipedia, und viele Dinge> sind auch einfach klar. Aber bei so manchen "Feinheiten" da komm ich> schonmal ins Trudeln.
vielleicht hilft Dir die Fundstelle weiter,
Yann Guidon beschäftigt sich schon länger mit CPU's
http://f-cpu.seul.org/cedric/unstable/http://yasep.org/
Gibt es noch interessante Hinweise für Assamblerprogramme für die
eigenen Softcores?
Es muss doch was Simples geben, was für den eigenen Befehlsatz
abwandelbar ist. Am liebsten wäre mir der gas aus den Binutils, doch ich
habe noch nie eine eigene CPU-Architektur angepasst.
Eine Skriptsprache würde ich auch nicht schlecht finden.
@Rene
Danke für den Link. Werd mir das mal anschauen.
Ich habe hier in der Codesammlung einen Parser geschrieben. Mit diesem
lässt sich leicht ein einfacher Assembler zusammenbauen. Für die
Simulation meines eigenen Softcores habe ich mir ein Assembler für
diesen Softcore auf Basis des Parsers geschrieben. Falls interesse
besteht kann ich das was ich dazu habe mal posten. Es lässt sich einfach
erweitern und anpassen (allerdings sollte man nicht versuchen den Code
zu verstehen wenn man mit dem Präprozessor auf Kriegsfuß steht :-))
Gruß
Rene :-)
Ja wenn du was hast, würde ich es mir schon mal anschauen.
Den Ansatz von tdasm http://www.penguin.cz/~niki/tdasm/
finde ich ganz vernünftig, Tabelle anpassen und nicht einen ganzen
Parser selberschreiben und lexikalische Ausdrücke zerpflücken.
> zu verstehen wenn man mit dem Präprozessor auf Kriegsfuß steht :-))>
So ist es nun auch wi(e)der nicht. ;-)
René
Fpga Kuechle schrieb:> Es sollte recht einfach sein, sich einen Quick und dirty assembler per> Spreadsheet (Excel;OO Calc)zusammenzubasteln. Ein Instruction wort mit> seiner seinen fest zugeordneten Bitfeldern ist doch recht einfach auf> einige Spalten Excel abgebildet, meinetwegen noch mit Auswahlmenü für> die Operations-Mnemonics.
Für einfachste Befehle dürfte das gehen. Sobald man aber Sprung- und
Speicherlabels verwendet und somit einen Relokationsmechanismus braucht,
wird es kompliziert. Von weiteren Makro-Instruktionen mal gar nicht zu
sprechen.
Rene Böllhoff schrieb:>>Harvard-Architektur>> Ok, da ist das Problem vllt nicht so gegeben, obwohl ich da ja u.u. auch> mehrere Takte benötige. Aber ich dachte eher an von-Neumann, da man dort> je nach Speicher einfach mehr "drankleben" kann, ohne direkt einen 2.> Adress/Daten/Steuer-Bus haben zu müssen.
Intern arbeiten die meisten Prozessoren mit einer Harvard-Architektur.
Es gibt dann also einen Daten- und einen Instruktionsspeicher,
ausgeführt als zwei Caches. Über die Anbindung an den externen
Hauptspeicher kümmert sich dann die Cache-Logik, während der
Prozessorkern frei von solchem Ballast ist. (Siehe beispielsweise MIPS)
Rene Böllhoff schrieb:> Bei einem vielfachen des Systemtaktes gegenüber dem Prozessortakt lässt> sich dann ein gepipelintes Design besser handlen denke ich.
> Rene Böllhoff schrieb:> Bei einem vielfachen des Systemtaktes gegenüber dem Prozessortakt lässt> sich dann ein gepipelintes Design besser handlen denke ich.
Ups, letztes Zitat nicht beantwortet: Wie erwähnt bietet sich zu diesem
Zweck eher an, zwei interne Speicher bzw. Caches zu haben und einen
Harvard-Kern zu bauen, während ein zusätzliche Logik die Anbindung an
den Hauptspeicher übernimmt. Man braucht sich dann beim Pipelining nicht
noch zusätzlich um unterschiedliche Taktraten zu kümmern.
Die Cache-Lösung ist mit grösster Wahrscheinlichkeit auch schneller:
Speicher haben gegenüber Logik verhältnismässig niedrige Taktraten. Es
macht also keinen Sinn, das Speicherinterface mit einem Vielfachen der
Logiktaktrate zu fahren, weil man dann die Logik extrem ausbremst.
Besser hält man den Prozessor von Zeit zu Zeit komplett an, um neue
Daten oder Instruktionen vom Hauptspeicher in den Cache zu laden. So oft
ist das nämlich gar nicht notwendig, da - Lokalitätsprinzip - nahe
beieinanderliegende Instruktionen und Daten auch zeitlich nahe
beieinander und oft wiederholt benötigt werden.
Beispiel Schleife: Wenn eine Schleife aus 20 Instruktionen 100 mal
ausgeführt wird, so habe ich gerademal 20 Hauptspeicherzugriffe um die
Instruktionen in den Cache zu laden. Arbeite ich direkt auf dem
Hauptspeicher, so muss ich 2000 Mal darauf zugreifen. Da ich mit der
Cache-Variante höhere Taktraten fahren kann, lohnt sich der
Zusatzaufwand allemal.
Tag,
Ich finde es richtig Interessant eine Prozessorarchitektur bzw. einen
kleinen Mikrocontroller auf dem FPGA selbst zu entwerfen.
Gibt es speziell zu diesem Thema eigentlich gute Lektüre?
Was ich jetzt beim stöbern gefunden habe ist das Buch VHDL Synthese von
Jürgen Reichert und Bernd Schwarz.
Dieses enthält laut Inhaltsverzeichnis ein komplettes Kapitel über den
Entwurf einer RISC Architektur.
Dass dieses Buch brauchbar ist glaube ich, so oft wie es hier
vorgeschlagen wird ;)
Aber wie sieht es speziell mit diesem Kapitel aus auch brauchbar oder
eher so mit eingebaut weil es grade In ist?
Gruß Tobias
Der Artikel "Building a RISC System in an FPGA" von Jan Gray ist
unbedingt lesenswert. Er beschreibt neben dem RISC Prozessor auch wie
man einen C Compiler anpasst um den Prozessor in C programmieren zu
können. Den Draft Artikel und die Dokumentation gibts auf
http://www.fpgacpu.org/xsoc/cc.html
Das Buch "FPGA prototyping by VHDL examples" von Pong P. Chu finde ich
recht gut. Es beschreibt als ein Beispiel den Xilinx Picoblaze
Prozessor.
Ich selbst habe in den letzten Jahren schon mehrere SOCs mit eigenem
Prozessoren auf Xilinx S3e und Nexys2 boards zum laufen gebracht,
inklusive eigenen Java-like Compiler, OS, GUI toolkit und Apps. Sowas
braucht natürlich einige Zeit. Das DRAM auf den FPGA boards anzusprechen
ist meist der komplexeste Teil wenn man keinen fertigen memory
controller hat.
MT schrieb:> Tag,>> Ich finde es richtig Interessant eine Prozessorarchitektur bzw. einen> kleinen Mikrocontroller auf dem FPGA selbst zu entwerfen.>> Gibt es speziell zu diesem Thema eigentlich gute Lektüre?> Was ich jetzt beim stöbern gefunden habe ist das Buch VHDL Synthese von> Jürgen Reichert und Bernd Schwarz.> Dieses enthält laut Inhaltsverzeichnis ein komplettes Kapitel über den> Entwurf einer RISC Architektur.>> Dass dieses Buch brauchbar ist glaube ich, so oft wie es hier> vorgeschlagen wird ;)>> Aber wie sieht es speziell mit diesem Kapitel aus auch brauchbar oder> eher so mit eingebaut weil es grade In ist?
Schwarz hat zwei Vorteile: Es behandelt VHDL nicht als
Programmierspracxhe aus sicht eines Informatikers und es ist auf
deutsch. Also gut für Einsteiger in VHDL, aber weniger geeignet um sich
mit dem Design eines Prozessors auseinanderzusetzen. Das Kapitel mit dem
risc -beispiel ist mir nicht besonders in Erinnerung geblieben. Da ist
besser Christian Siemers" Prozessorbau" ISBN: 3-446-19330-8. Auf der
beiliegenden CD findet sich der VHDL-Code. das Buch hat allerdings schon
über 10 jahre auf dem Buckel und ist hinsichtliche der PLD-Möglichkeiten
nicht mehr state of the art.
MfG,
Rene Böllhoff schrieb:> @Duke>> . Um die> 1-Takt-Zyklus-Philosophie umzusetzen müsste ich also entweder den> Prozessor-Takt im einem festen Verhältnis zueinander setzen, damit das> System dem Prozessor bei jedem Takt ein Datenwort liefert bzw eines> wegschreiben kann, oder aber dafür sorgen das der Datenbus für jede> Richtung einmal vorhanden ist.> Wie das jetzt realisiert ist, ob ich das in einem getrennten> Speichercontroller mache oder aber im FPGA "In-the-Box" ist ja erstmal> egal. Aber wäre das ein Ansatz dafür ?
Die FPGA internen Speicherblöcke sind in der Regel als Dual-Port
ausgeführt, Da kann man locker in einem Takt lesen und schreiben. Daher
kann man diese statt FF als Registerbank benutzen.
Hallo,
die Diskussion geht ja schon relativ tief in Details bestehender
Prozessoren, aber wie wäre es denn mit einem Java-Bytecode-Prozessor?
Dokumentation ist vorhanden, reichlich Tools gibt es auch.
Allerdings kann ich nicht abschätzen, ob sich alle Bytecode-Befehle
sinnvoll in VHDL umsetzen lassen. Vor allem virtuelle Funktionsaufrufe
(für Vererbung) könnten aufwendig werden. Auch die eigentliche Anbindung
an die Hardware ist mir unklar.
Hätte auf jeden Fall auch einen gewissen Seltenheitswert.
Gruss
Micha
Micha C. schrieb:> Allerdings kann ich nicht abschätzen, ob sich alle Bytecode-Befehle> sinnvoll in VHDL umsetzen lassen.
Naja, RISC geht anders. ;-)
Läuft bei einem Teil der Befehle auf komplexes Sequencing hinaus, für
das man in traditionellen Architekturen Microcode einsetzt. Die Jazelle
Engine in ARM9/11 erledigt nur 95% der ausgeführten Bytecodes selber und
überlässt den Rest nativem ARM Code.
Micha C. schrieb:> Vor allem virtuelle Funktionsaufrufe> (für Vererbung) könnten aufwendig werden.
Das läuft dann au eine CISC-Architektur hinaus. Die Daten laufen also
nicht mehr straight-forward durch einen fixen Datenpfad, sondern werden
von einem Mikrocodeprogramm sequentiell abgearbeitet. Und sowas ist
schwer bis gar nicht zu pipelinen. Somit lässt sich kein wirklich
schneller Prozessor bauen.
Gibt es eigentlich heute noch echte CISC-Architekturen? x86 ist ja
bekanntlich ein CISC-Instruktionssatz, wird aber intern RISC-mässig
verarbeitet.
xst schrieb:> Gibt es eigentlich heute noch echte CISC-Architekturen? x86 ist ja> bekanntlich ein CISC-Instruktionssatz, wird aber intern RISC-mässig> verarbeitet.
Die Zerlegung komplexer Befehle in einfache Operationen kennzeichnet
auch Microcode. Wenn du als x86 mit interner Befehlszerlegung in
Einzelschritte als RISC betrachtest, dann trifft dies auch VAX und 68000
zu. Nur erfolgt diese Zerlegung bei x86 meistens in Hardware statt
Microcode und die Operationen spazieren nicht mehr im Gänsemarsch.
Zwar lassen sich CISC Befehle als Einheit schlecht pipelinen, für den
Microcode muss das indes nicht gelten. Problematisch bei Java Bytecode
ist jedoch die etwas pipelinewidrige Stack-Architektur.
Microcode ist übrigens keine Bedingung für CISC. Es gab auch welche
ohne, wie Z8000. Hat Zilog zwar viele Transistörchen erspart, aber im
Ausgleich so viel Zeit gekostet, dass es bei realer Verfügbarkeit ein
Reinfall war.
Auch wenn sich Intels Core/Core i und AMDs K8 strukturell auf dieser
Ebene recht ähnlich sehen: Es gibt beispielsweise auch den Atom, der
etwas traditioneller gewirkt ist.
Ansonsten muss man nur mal von der Spitze weg in andere Gefilde blicken
und man findet CISC. Nämlich im Controller-Sektor. Renesas M16C/80 und
M32C haben eine blütenreine hochkomplexe CISC ISA, auch von der
Implementierung ist nichts Gegenteiliges bekannt. Und ARMs Java Engine
Jazelle hatte ich ja bereits genannt.
PS: Der interne Code von AMD ab K7 definiert auch Makroops wie
<mem> = <mem> <op> <reg>/<const>
was dem klassischen RISC-Bild eindeutig widerspricht. In diesem Sinn
zerlegt AMD den x86 Code also nicht in RISC Operationen sondern in
einfachere schematischere CISC Operationen.
Bei Intel war es anno PentiumPro..PentiumIII sowie Pentium 4 noch
einfach, die internen Codes waren ausgesprochen simpel strukturiert und
letzlich RISC-artig. Mit dem Pentium-M und den Core/Core i entwickelte
sich der interne Code wieder sukzessive vom RISC-Schema weg, etwas in
Richtung AMD.
@Micha
Dieser Gedanke ist mir auch schon gekommen :-))
Aber wie die beiden vorherigen Posts schon beschrieben haben, dürfte der
Java-Bytecode nicht, oder nur mit großem Aufwand auf einem FPGA direkt
interpretiert werden können. Da ist es schon einfacher eine einfache
Architektur aufzusetzen (egal ob bestehend oder eigens entworfen) und
auf dieser Basis dann einen Java-Bytecode-Interpreter aufzuziehen.
AooA schrieb:> Was meint ihr zum MSP430? Der Instruktionssatz jedenfalls scheint recht> einfach und doch mächtig.
Halt ich persönlich für eine super Idee.
Gibt da sogar was bei OpenCores in der Richtung (leider in Verilog):
OpenMSP430:
http://opencores.com/project,openmsp430
Ich hätte selber jetzt vom Instruktinossatz an etwas 8051 kompatibles
gedacht.
Ich habe schonmal einen 8051 im FPGA nachgebaut, so richtig from
scratch. Das ist schon spassig, keine Frage, allerdings braucht man dazu
auch einiges an Zeit und Ausdauer. Und man braucht eine
Vergleichsmöglichkeit mit dem Original. Die verfügbare Dokumentation hat
jedenfalls nicht gereicht. Irgendwann landet man bei so verrückten
Fragen wie: Was macht der Prozessor beim Befehl "pop SP"?
Viel Erfolg!
Harald
Harald Flügel schrieb:> jedenfalls nicht gereicht. Irgendwann landet man bei so verrückten> Fragen wie: Was macht der Prozessor beim Befehl "pop SP"?
So verrückt sind diese Fragen garnicht. Bei den ersten x86-Generationen
hat anhand genau solcher Fiesematentchen die verschiedenen Varianten
unterschieden.
Harald Flügel schrieb:> Und man braucht eine> Vergleichsmöglichkeit mit dem Original. Die verfügbare Dokumentation hat> jedenfalls nicht gereicht. Irgendwann landet man bei so verrückten> Fragen wie: Was macht der Prozessor beim Befehl "pop SP"?
Es gibt noch eine andere Alternative: eine extrem saubere Dokumentation!
Die "Principles Of Operation" der IBM /360-Architektur umfaßte -
vorsichtig geschätzt - allein gut 500 Seiten zur Beschreibung des
Instruktionssatzes einschließlich der Sonderfälle und der
modellabhängigen bzw. "kritischen" Operationen (z.B. Store an die Stelle
der nächsten Instruktion - ein Graus in der x86-Architektur).
Bernhard
Das ganze ist auch etwas globaler zu betrachten. Wollt ihr eine
theorische Rechenarchitektur bauen oder etwas was auch dann praktisch
eingesetzt werden kann?
Dann muss ein Assembler oder besser ein C-Compiler nachgezogen werden.
Der MSP430 oder ein AVR hat den Vorteil es gibt schon Tools für die
Architektur. Das muss alles bedacht werden.
Oft wird auch die MIPS Architektur nachgebaut, soll sich für FPGA
Umsetzung sehr gut eignen, die hat hier noch keiner erwählt.
Hier mal von meiner Selbstbau-CPU der Befehlssatz.
Nahezu jeder Befehl lässt sich bedingt ausführen. Ausnahmen sind die
Immediate Ladebefehle und die Befehle des Condition-Processing.
Ein Makro-Assembler dafür ist auch im Entstehen.
Das ganze ist zwar noch sehr langsam, da ich für ein universelles
Speicherinterface viele Takte benötige, aber ich denke durch pipelining
dürfte die CPU noch um einiges schneller werden. Mal schauen wie weit
ich da komme. Bei Problemen bzw Hirnknoten werd ich mich bestimmt
nochmal melden :-)
Falls interesse besteht kann ich die CPU hier ja auch mal posten bzw
einen Artikel daraus machen. Hier mal eine kurze Feature Liste :
- 16Bit Daten&Adressraum (der Adressraum wird evtl auf 32Bit
aufgestockt)
- 16x16Bit Register (im Moment nur 8x16Bit, um etwas Platz zu sparen)
- benötigt ca 47% der Slices eines Spartan 3-200
- nahezu alle Befehle bedingt ausführbar
- Bedingungsprozessor mit 4 benutzer bedingungen
- einfache Schleifenkonstrukte mit Mark/Loop (fußgesteuerte Schleife)
- Alle Instruktionen immer 16Bit breit (tlw. nachteillig, aber
übersichtlich)
Ist bestimmt kein Vorzeigeprozessor, oder besonders ausgetüftelt, aber
für meine erste Selbstbau-CPU unter VHDL denke ich brauchbar.
Wie funktioniert bei dir ein Vergleich zweier Werte mit Vorzeichen?
Traditionell gibt es da zwei Ansätze, wenn man sich schon für ein
Statusregister entscheidet: Separate Vergleichsbefehle (IBM Tradition)
oder separate Flags (z.B. Overflow-Flag).
Ist der Akkumulator ("acc") ein spezielles der 16(8) Register?
@A.K.
Ich habe in brute-force-Manier zwei Vergleicher-Zweige (einen Signed und
einen Snsigned) gemacht und die Auswahl übernimmt ein Flag im
Statusregister.
Bei den Shift Operationen geht das genauso. Da habe ich Flags für
logischen/arithmetischen Shift sowie für Rotate.
Edit : Ich habe auch noch nicht alles bis ins kleinste
durchgetestet/simuliert, da ich erstmal den Assembler fertig machen
wollte damit das Testen und Simulieren einfacher wird.
Edit 2 : Es sind noch 16 SW-Interrupts vorhanden. 15 Hardware-Interrupts
werden denke ich auch noch folgen. Aber da ist noch nicht viel getestet.
Rene Böllhoff schrieb:> Ich habe in brute-force-Manier zwei Vergleicher-Zweige (einen Signed und> einen Snsigned) gemacht und die Auswahl übernimmt ein Flag im> Statusregister.
Aua! Zuviel 6502 programmiert? Will hoffen, dass du nicht auch noch
einen Compiler dafür stricken willst... Sowas macht ähnlich viel Freude
wie Bankswitching bei den PICs.
Sorry, wills dir nicht madig machen, aber solche Stati sind ein Graus.
Der Akku ist ein 32-Bit Register (für die Multiplikation die auch im
moment nur unsigned ist). Das ist auch noch eine "unschönheit" an meinem
Design. Die ALU bedient sich zweier Register, das Ergebnis landet aber
immer im Akku und muß mit einem weiteren Befehl erst wieder in ein
Register transferiert werden. Ich hab das gemacht damit das Register
nicht automatisch überschrieben wird, sondern man sie freie wahl hat wo
das Ergebnis landen soll.
Na ja ... mit dem 6502 hab ich angefangen :-)
Die signed/unsigned Problematik (bei Vergleichen, Status-Reg und
Multiplikation und ALU) liegt mit sowieso noch was schwer im Magen.
Muß mir da auch mal anschauen wie das bei anderen Architekturen gelöst
ist. So zufrieden bin ich damit ohnehin noch nicht.
Von einem Compiler bin ich noch soweit entfernt wie ein Tretroller von
der Saturn V ;-)
Aber ich glaub aus solchen "Fehltritten" (selbst wenn es im ersten
Moment erstmal ein Erfolg ist) lernt man auch. Was mich halbwegs erfreut
ist das ich einen relativ einfachen Prozessor der aber auch schon das
was ein Prozessor können muß beherrscht entworfen hab der auch noch
einigermaßen wenig Ressourcen benötigt. Lässt sich sicherlich nicht mit
einem Picoblaze (von der Größe her) oder mit einem Microblaze (von den
Features und der Geschwindikeit) vergleichen, aber das war ja auch nicht
die Intention :-)
Edit : Was wäre denn der bessere Weg ? Die Vergleiche und
Logisch/Arithmetisch/Rotierenden Shift Befehle wirklich auszudekodieren
(also ala SLL, SLR, SAL, SAR, ROL, ROR und CMPS, CMPU) ? Evtl wäre da ja
noch Platz im Opcode-Raum.
Rene Böllhoff schrieb:> Muß mir da auch mal anschauen wie das bei anderen Architekturen gelöst> ist. So zufrieden bin ich damit ohnehin noch nicht.
Traditionell wie 68xx, 68xxxx, ARM: 4 Flags, NZVC wie 6502, aber 2*7
Bedingungen. Wird hier natürlich eng.
MIPS, Alpha: Ähnlich wie bei dir, nur Standardregister statt Flags, d.h.
Ergebnis eines Vergleichsbefehls landet als 0/1 im Zielregister. Aber da
hat man dann getrennte Vergleichsbefehle für signed/unsigned,
grösser/kleiner usw.
IBM 360/POWER: willst du nicht wirklich wissen ;-).
Kannst dir als Anregung die Thumb2-Variante vom ARM mal ansehen.
Bedingte Ausführung aller Befehle ist ziemliche Ressourcenverschwendung,
ganz besonders bei 16bit-Codierung. Dort gibt es einen Präfix-Befehl,
der den nächsten maximal 4 Befehlen die Bedingung vorgibt, d.h. eine
Bedingung für alle, und ob jeweils wahr oder falsch. Kostet zwar bei
einfachem Ablauf einen Takt, setzt aber anderswo dringender benötigte
Bits im Opcode frei.
Danke für die kleine Übersicht.
Aber soweit ich weiß gibt es beim 6502 keine speziellen signed/unsigned
Vergleichsbefehle. Da gibt es meine ich nur einen CMP-Befehl und das
wars. Ist aber auch schon ein paar Jährchen her das ganze.
Na ja. An eine IBM360 hatte ich bestimmt nicht vor mich anzulehnen :-)
>Bedingte Ausführung aller Befehle ist ziemliche Ressourcenverschwendung,>ganz besonders bei 16bit-Codierung.
Kannst du mir das mal genauer erklären ? Mir ist nicht klar wie das
zusammenhängt a) mit dem Ressourcenverbrauch und b) warum speziell
16Bit-Codierung (meinst wegen den Bits für die Bedingung die mir dann im
Opcode "fehlen") ?!
Rene Böllhoff schrieb:> Design. Die ALU bedient sich zweier Register, das Ergebnis landet aber> immer im Akku
Was eigentlich nur sinnvoll ist, wenn z.B. acc=R0 gilt. Die obere
Produkthälfte wird (wurde) nicht selten in einem separaten Register
verbuddelt. Solange man kein Pipelining im Auge hat ist das vertretbar -
IBM hatte das gemacht und anlässlich des Übergangs von Power zu PowerPC
in den Hintern gebissen.
Rene Böllhoff schrieb:> Aber soweit ich weiß gibt es beim 6502 keine speziellen signed/unsigned> Vergleichsbefehle.
Aus den 4 Flags des 6502 lassen sich alle 14 üblichen Bedingungen
ableiten, darunter sowohl "grösser mit Vorzeichen" als auch "grösser
ohne Vorzeichen". Die entsprechenden Sprungbefehle mit Vorzeichen
fehlten beim 6502, aber der Vorgänger 6800 hatte sie alle.
Wobei man natürlich bei einer Architektur mit vollständig symmetrischem
Vergleichsbefehl ein paar Bedingungen einsparen kann (z.B. "grösser" vs.
"kleiner").
> Mir ist nicht klar wie das zusammenhängt a) mit dem Ressourcenverbrauch
Alle Befehle eines konkreten Programmablaufs, die nicht wirklich bedingt
ausgeführt werden, verschwenden bei dir 3 Bits von 16 des Opcode-Space.
Die sich anderswo ggf. besser einsetzen liessen.
> und b) warum speziell 16Bit-Codierung
3 "verlorene" Bits in einem in 16 Bits codierten Befehl tun mehr weh als
4 Bits von 32 (ARM). In Thumb1 gabe es deshalb garkeine bedingte
Ausführung, was aber hinsichtlich Laufzeit auch nicht so der Knüller
war, also brachte Thumb2 den erwähnten Präfix.
Der Hintergedanke mit dem getrennten Akku (der wirklich getrennt ist,
also nicht auf irgendein Register gemappt wird) war der das ich aus dem
Akku eine MAC-Einheit mache die dann evtl über ein dann eingespartes
Flag im SR bei jedem ALU-Befehl mitläuft.
Ok. Das mit den (wir bauen uns aus den Status-Flag-bits die
entsprechende Bedigung heraus) hab ich verstanden. Das hatte ich auch so
in erinnerung.
Mit den "fehlenden" Bits ist dann klar. 3 von 16 sind eben mehr als 4
von 32 :-)
Der Ursprungsgedanke war auch so ausgelegt das ich versuche wenige
Befehle zu implementieren, habe dann aber gemerkt das das dann nur mit
immensem SW Aufwand zu machen ist. Daher z.b. auch die SWAP8 und SWAP4
Befehle. Mit der ALU hätte man sich nen Wolf programmiert (Shift-Wert
laden, shiften, zurückschreiben, usw).
Rene Böllhoff schrieb:> Der Hintergedanke mit dem getrennten Akku (der wirklich getrennt ist,> also nicht auf irgendein Register gemappt wird) war der das ich aus dem> Akku eine MAC-Einheit mache die dann evtl über ein dann eingespartes> Flag im SR bei jedem ALU-Befehl mitläuft.
Ja, aber ich fürchte du verlierst mehr als du gewinnst. Es sei denn du
baust einen DSP. Datenrechnung ist bei normalen Programmen nicht so
dominant, als dass sich sowas lohnt.
Denk übrigens auch an die Frage der Adresserzeugung. Bei dir bestehen ja
recht wenig Möglichkeiten, mit Speicher überhaupt etwas anzufangen. Die
Lade/Speicherbefehle hatte ich im zweiten Anlauf gefunden ;-) aber eine
Antwort auf die Frage, wie in leidlich ökonomischer Weise eine Adresse
der sehr beliebten Form [pointer+offset] im RegX landet, noch nicht.
Du hast mich irgendwie entlarvt :-)
Eine DSP Option hatte ich nicht nur im Kopf gehabt sondern war auch
irgendwo mit der Ausgangspunkt. Bei meinem Audio-DSP habe ich zwar reine
DSP-Befehle, aber alles andere nicht. Da kam mir der Gedanke das ich
zwar eine MAC-Einheit brauche, diese aber ja durchaus von einem 16-Bit
Core gesteuert und gefüttert werden kann. Das ganze ist aber nachher
soch "ausgeartet" das ein "normaler" Prozessor daraus entstanden ist.
Das mit der Adresserzeugung ist in der Tat echt blöd gemacht. Da hätte
ich mehr Hirnschmalz reinstecken müssen. So sachen wie Indirekt
indiziert, Autoincrement und dergleichen wären sinnvoll gewesen.
Einen Wert (egal ob Datum oder Adresse) lässt sich nur über 2 Move
Befehle machen. Dafür gibt es die Move High-Byte/Low-Byte Befehle.
Um also von Adr 0x2345 einen Wert nach Register 1 zu laden muß man
folgendes machen :
6234 MOVE H#$23, R4
7234 MOVE L#$45, R4
5041 MOVE A, [R4], R1