meine cpus sind mehr oder minder sehr simpel
die erste hab ich in logisim entwickelt und konnte ganze 16Byte Ram und 256Byte Rom ansprechen. im Rom lag der einfachheit halber der programcode und im ram wurde linear das ergebnis der aluoperation abgelegt. allerdings konnte man keine daten aus dem ram lesen, aber ich war schon happy, dass es überhaupt irgendwie funktioniert hat. die cpu, kpu mit namen, war eine 4bit cpu mit einem 16bit breiten befehlssatz. die 4bit für daten resultierten daraus, dass alle operationen in diesen 16bit einzeln untergebracht wurden, da ich noch nichts vom decodieren gehört hatte.
ein befehl war also so aufgebaut:
x x x x x x x x x x x x x x x x
| | | | | | | | | | | | | | | |
- - - - - - - - - -
| | | | | |
Addr Addr Alu Reg Data
OP OP CB CA
das bedeutet ein
mov r1, 4
wurde zu 0000000000100100
und leider musste aus irgenteinem grund nach jeder aluop ein null word kommen, da sonst falsche ergebnisse in den ram geschrieben werden.
btw hatte kpu auch keinerlei jmp operationen, nicht mal einen einfachen sprung, obwohl es vorgesehen war. sie hatte 3 register r0, r1 und r2, die alle allzweck waren
die weiterentwicklung war KPU Mk 2, oder einfach KPUII. diese sollte schon besser sein. sie hatte zwar immernoch die 16bit instructionen, aber konnte schon 8bit daten verarbeiten.
eine instruction war also so aufgebaut:
x x x x x x x x x x x x x x x x
| | | | | | | | | | | | | | | |
Enable - - - - - - - - - -
| | | | | |
J A R OP Data
m L e
p U g
| |
Write Read
aus einem mov r1, 4 wurde jetzt 0010000100000100
kpuII wurde in logisim die wirklich fertiggestellt, aber dafür hab ich meinen ersten emulator in c# geschrieben KPUIIEMU
kpuII hatte 16 allzweckregister. jump operationen wie
jmp
je
jne
ja
jb
und konnte auf den ram und den rom dierekt zugreifen, zwar nur mit festwerten, aber immerhin. der programmcode lag immernoch im rom. alletdings hatte diese cpu schon einen screen port und einen keyboard port, die allerdings nie in logisim sorichtig funktioniert haben. aber dafür waren die befehle read (register) und disp (festwert | ram:[(adresse)] | rom:[(adresse)] | register) vorgesehen.
meine nächste cpu, die ich erst auf dem papier und dann in logisim umsetzen wollte, war die 140A, eine richtige multibyte 8bit cpu. daten und code lagen im ram und sogut wie alle operationen sind multibyte bishin zu 3 byte. diese cpu ist in logisim nie sorichtig fertig geworden, da ich mit probleme mit den multibyte instruktionen hatte.
die 140A hatte einen 8bit breiten adressbus und konnte somit 256byte an ram ansprechen. sie hatte 4 allzweckregister, einen ip und ein flagregister.
die instruktionen waren so aufgebaut
xxxx | xxxx | OP
-----|------|---------
0000 | 0000 | HLT
0001 | 00 # | r# = <IP+1>
0001 | 0100 | [<IP+1>] = <IP+2>
0001 | 10 # | r# = [<IP+1>]
0001 | 11 # | [<IP+1>] = r#
-----|------|---------
0111 | #1#2 | cmp r#1, r#2
0110 | 00 # | cmp r#, <IP+1>
0110 | 01 # | cmp r#, [<IP+1>]
-----|------|---------
0011 | 0000 | jmp <IP+1>
0011 | 0001 | je <IP+1>
0011 | 0010 | jne <IP+1>
0011 | 0011 | ja <IP+1>
0011 | 0100 | jb <IP+1>
0011 | 0101 | jna <IP+1>
0011 | 0110 | jnb <IP+1>
-----|------|---------
1000 | #1#2 | r#1 = r#1 + r#2
1001 | #1#2 | r#1 = r#1 - r#2
1010 | #1#2 | r#1 = r#1 * r#2
1011 | #1#2 | r#1 = r#1 / r#2
1100 | #1#2 | r#1 = r#1 & r#2
1101 | #1#2 | r#1 = r#1 | r#2
1110 | 00 # | r# = ~r#
1111 | #1#2 | r#1 = r#1 XOR r#2
wie man erkennen kann recht simpel.
flags gab es nur 3 stück: das gleichheitflag, größerflag und kleiner flag.
aus mov r0, 0xF0 wird also 00010000 11110000
einige kleinigkeiten, wie zum beispiel adressierung über register, müssen über kleinere hacks gemacht werden. wodurch dann selbstmodifizierender code entsteht.
die letzte cpu und die auch größte in meinen projekt umfang ist die XCPU, warum die so heißt weiß ich leider auch nicht.
diese cpu arbeitet mit sicherheit nicht mehr nach dem RISC prinziep sondern eher im gegenteil. sie hat einen 32 bit adressbus kann mit 32bit daten umgehen und eine ram speicherzelle hat 32 bit. somit kann diese cpu 137438953472 bit insgesamt ansprechen was 16 GB ergeben. leider kann der emulator nur ein zwanzigstel, also ca 0.8 GB, davon bereit stellen, da meine maschiene nicht mehr hergibt.
es giebt 16 register, die allzweck benutzt werden könnten, aber vom assembler für call oder stack operationen genutzt werden. die cpu beherscht diese nähmlich nicht und, desshalb habe ich diese hacks gleich in den assembler eingebaut.
die cpu kann teoretisch 2^32 in und out ports haben allerdings werden vom emulator vorerst nur 0-2 unterstützt. flags gibts 32 aber nur 4 existieren, die drei der 140A und das zero flag. interrupt, die es bei den anderen nicht gab, sollen auch implementiert werden, allerdings muss ich mir darüber nochmal gedanken machen.
zum assembler:
ich hab fast für jede meiner cpus eien eigenen assembler, in c#, geschrieben, außer für die 140A. die syntax ist für alle dem intelsyntax der x86 ähnlich, nur die register heißen anders r0-r(2, 3 oder 15 bzw 9). also mov (ziel), (quelle). bei der xcpu werden allerdings auch operationen wie add r1, r2, r3 möglich sein (r3 = r1 + r2).
der assembler für die xcpu ist noch nicht ganz fertig, aber es gibt schon labels, jmp, data anweisung, org anweisung, times anweisung und die $ anweisung.
wenn noch fragen sind beantworte ich die gerne
btw wenn ich in den rechnungen(bit -> GB) einen fehler hab korrigiert mich bitte