[ CHEAP ] [ CASM ] [ CSIM ] [ CSIM-P ] [ Impressum ]
Um bei der anstehenden Entwicklung der beiden Module Assembler und Simulator auf ein sicheres Fundament bauen zu können, entschieden wir uns für die eindeutige Spezifikation eines virtuellen Prozessors.
Aus dieser Überlegung heraus entstand der sog. CHEAP oder auch Cheap and Horrible Easy Architecture Processor. Die interne Befehlsverarbeitung wurde dabei jedoch nur ganz allgemein definiert. Probleme wie Pipelining oder Sprungvorhersage sind somit nicht Gegenstand der Spezifikation. Diese beschränkt sich im wesentlichen auf die unten angeführten Themen.
Dem Nutzer stehen insgesamt 32 Register mit einer Bitbreite von 32 zur Verfügung.
category | code | name | purpose |
---|---|---|---|
general | 00 .. 26 | holds user defined values | |
special | 27 | TA | holds init value of Timer Alpha |
28 | TB | holds init value of Timer Beta | |
29 | PC | holds Program Counter | |
30 | RE | holds REturn value for latest unconditional jump and return | |
31 | RI | holds Return value for latest Interrupt service routine |
Dem Nutzer stehen 16 verschieden priorisierte Interrupts zur Verfügung. Deren individuelle Abarbeitung definiert sich durch folgende Punkte.
priority | device | priority | device | |
---|---|---|---|---|
00 | system | 04 | screen | |
01 | timer alpha | 05 | reserved | |
02 | timer beta | 06 | reserved | |
03 | keyboard | 07 .. 15 | unused |
Dem Nutzer stehen 4096 bidirektionale Ports mit einer Bitbreite von 32 zur Verfügung. Die folgende Übersicht zeigt einige simulierte Geräte und die jeweils verwendeten Ports. Sender verwenden ungerade, Empfänger dagegen gerade Portnummern.
port | device |
---|---|
00 | keyboard |
01 | virtual screen |
02 | multi purpose data in |
03 | multi purpose data out |
04 | random number generator |
Dem Nutzer stehen 2 voneinander unabhängige Timer zur Verfügung. Die Initialisierung eines Timers erfolgt durch Zuweisen des gewünschten Initialwertes. Der Timer ist daraufhin aktiv und löst nach dem Verstreichen der auf Millisekundenbasis definierten Zeitspanne einen Interrupt aus. Der Timer Alpha besitzt dabei die höhere Priorität.
Der Nutzer kann mittels Tastatur einzelne Zeichen an den Prozessor senden. Bei jedem Tastendruck wird ein Interrupt ausgelöst. Bis zur Abholung werden die Daten in einem 128 Zeichen fassenden Puffer aufbewahrt. Der Puffer kann synchron zum Prozessortakt ausgelesen werden.
Der an den Prozessor angeschlossene Bildschirm arbeitet als zeichenorientiertes Ausgabegerät. Mit Einschränkung lassen sich Eigenschaften und Verhalten des Bildschirms mit denen einer Textkonsole eines IBM PC vergleichen. Es wird ein Textmodus mit 25 Zeilen und 80 Spalten bei 4 Bit Farbtiefe simuliert. Die Cursorpositionierung als auch die Farbauswahl erfolgt über die Interpretation von ANSI Escape Zeichenfolgen.
In der folgenden Übersicht werden beispielhaft zwei einfache Sequenzen aufgezeigt.
some escape sequences used for screen control |
---|
^[[30;47m -- set foreground color to black and background to white ^[[4D -- move cursor back by 4 columns |
Die an den Bildschirm gesendeten Zeichen werden in einem variabel großen Puffer abgelegt. Die Interpretation und Darstellung der im Puffer liegenden Daten erfolgt ebenfalls mit einstellbarer Geschwindigkeit. Können keine weiteren Zeichen in den Puffer geschrieben werden, wird vom Bildschirm ein Interrupt ausgelöst.
Die an den Prozessor angeschlossenen Geräte Multi Purpose Data In sowie Multi Purpose Data Out können zum Senden bzw. Empfangen beliebiger Datenmengen genutzt werden. Der Datenaustausch erfolgt, ohne Interrupts oder Polling, taktsynchron zum Prozessor. Im CSIM können Dateien des Hostsystems als Quelle bzw. Ziel spezifiziert werden.
Für die Erzeugung von Zufallszahlen wird ein entsprechendes Gerät simuliert. Die vom Generator gelesenen Zahlen werden taktsynchron erzeugt und liegen im Wertebereich 0 .. 2 ** 32 - 1 bzw. 0 .. 4294967295.
Bei der Programmierung des CHEAP kommen fünf verschiedene Befehlstypen zum Einsatz.
Die folgende Tabelle gibt eine Übersicht über alle derzeit unterstützten Befehle zum Datentransfer.
oc | sc | tp | mne | param | description |
---|---|---|---|---|---|
00 | 30 | r | LW | rg1, rg2 | Load Word to [drg] from memory position in [srg] |
00 | 31 | r | SW | rg1, rg2 | Store Word from [srg] at memory position in [srg] |
00 | 01 | r | PDI | rg1, rg2 | Peripheral Data Input to [drg] from port in [srg] |
01 | i | PDI | rg1, imm | Peripheral Data Input to [drg] from port in [imm] | |
00 | 02 | r | PDO | rg1, rg2 | Peripheral Data Output from [srg] to port in [srg] |
02 | i | PDO | rg1, imm | Peripheral Data Output from [srg] to port in [imm] |
Die folgende Tabelle gibt eine Übersicht über alle derzeit unterstützten Befehle zu Arithmetik und Logik.
oc | sc | tp | mne | param | description |
---|---|---|---|---|---|
00 | 03 | r | HI | rg1, rg2 | set the HIgher bits of [drg] to value in [srg] |
03 | i | HI | rg1, imm | set the HIgher bits of [drg] to value in [imm] | |
00 | 04 | r | SET | rg1, rg2 | Set [drg] Equal To [srg] |
04 | i | SET | rg1, imm | Set [drg] Equal To [imm] | |
i | SET | rg1, lab | Set [drg] Equal To [lab] | ||
00 | 32 | r | XCH | rg1, rg2 | eXCHange values between [drg] and [drg] |
00 | 05 | r | ADD | rg1, rg2 | ADD value to [drg], value in [srg] |
05 | i | ADD | rg1, imm | ADD value to [drg], value in [imm] | |
00 | 06 | r | SUB | rg1, rg2 | SUBtract value from [drg], value in [srg] |
06 | i | SUB | rg1, imm | SUBtract value from [drg], value in [imm] | |
00 | 07 | r | MUL | rg1, rg2 | MULtiply value in [drg] by value in [srg] |
07 | i | MUL | rg1, imm | MULtiply value in [drg] by value in [imm] | |
00 | 08 | r | DIV | rg1, rg2 | DIVide value in [drg] by value in [srg] |
08 | i | DIV | rg1, imm | DIVide value in [drg] by value in [imm] | |
00 | 09 | r | MOD | rg1, rg2 | MODulo between value in [drg] and value in [srg] |
09 | i | MOD | rg1, imm | MODulo between value in [drg] and value in [imm] | |
00 | 0A | r | PCA | rg1, rg2 | set [drg] equal to Program Counter and Add [srg] |
0A | i | PCA | rg1, imm | set [drg] equal to Program Counter and Add [imm] | |
00 | 0B | r | PCS | rg1, rg2 | set [drg] equal to Program Counter and Subtract [srg] |
0B | i | PCS | rg1, imm | set [drg] equal to Program Counter and Subtract [imm] | |
00 | 0C | r | AND | rg1, rg2 | bitwise AND between [drg] and [srg] |
0C | i | AND | rg1, imm | bitwise AND between [drg] and [imm] | |
00 | 0D | r | OR | rg1, rg2 | bitwise ORbetween [drg] and [srg] |
0D | i | OR | rg1, imm | bitwise ORbetween [drg] and [imm] | |
00 | 0E | r | XOR | rg1, rg2 | bitwise XORbetween [drg] and [srg] |
0E | i | XOR | rg1, imm | bitwise XORbetween [drg] and [imm] | |
00 | 0F | r | SHL | rg1, rg2 | SHift Left [drg] for value in [srg] times |
0F | i | SHL | rg1, imm | SHift Left [drg] for value in [imm] times | |
00 | 10 | r | SHR | rg1, rg2 | SHift Right [drg] for value in [srg] times |
10 | i | SHR | rg1, imm | SHift Right [drg] for value in [imm] times | |
00 | 11 | r | RTL | rg1, rg2 | RoTate Left [drg] for value in [srg] times |
11 | i | RTL | rg1, imm | RoTate Left [drg] for value in [imm] times | |
00 | 12 | r | RTR | rg2, rg2 | RoTate Right [drg] for value in [srg] times |
12 | i | RTR | rg2, imm | RoTate Right [drg] for value in [imm] times | |
00 | 13 | r | FBS | rg1, rg2 | in [drg] Force Bit [srg] from right to be Set |
13 | i | FBS | rg1, imm | in [drg] Force Bit [imm] from right to be Set | |
00 | 14 | r | CBS | rg1, rg2 | in [drg] Check if Bit [srg] from right is Set |
14 | i | CBS | rg1, imm | in [drg] Check if Bit [imm] from right is Set | |
00 | 15 | r | CST | rg1, rg2 | Check if Source Smaller Than value in [drg], source in [srg] |
15 | i | CST | rg1, imm | Check if Source Smaller Than value in [drg], source in [imm] | |
00 | 16 | r | CGT | rg1, rg2 | Check if Source Greater Than value in [drg], source in [srg] |
16 | i | CGT | rg1, imm | Check if Source Greater Than value in [drg], source in [imm] | |
00 | 17 | r | CE | rg1, rg2 | Check if Source Equal to value in [drg], source in [srg] |
17 | i | CE | rg1, imm | Check if Source Equal to value in [drg], source in [imm] |
Die folgende Tabelle gibt eine Übersicht über alle derzeit unterstützten Befehle zur Ablaufsteuerung.
oc | sc | tp | mne | param | description |
---|---|---|---|---|---|
00 | 18 | s | JMP | rg1 | JuMP to memory position in [srg] |
18 | j | JMP | imm | JuMP to memory position in [imm] | |
j | JMP | lab | JuMP to memory position in [lab] | ||
00 | 19 | s | JMR | rg1 | JuMp to memory position in [srg] and allow Return |
19 | j | JMR | lab | JuMp to memory position in [lab] and allow Return | |
j | JMR | imm | JuMp to memory position in [imm] and allow Return | ||
00 | 1A | r | BEZ | rg1, rg2 | Branch if value in [srg] is Equal to Zero, memory position in [srg] |
1A | i | BEZ | rg1, imm | Branch if value in [srg] is Equal to Zero, memory position in [imm] | |
i | BEZ | rg1, lab | Branch if value in [srg] is Equal to Zero, memory position in [lab] | ||
00 | 1B | r | BGZ | rg1, rg2 | Branch if value in [srg] is Greater than Zero, mem position in [srg] |
1B | i | BGZ | rg1, imm | Branch if value in [srg] is Greater than Zero, mem position in [imm] | |
i | BGZ | rg1, lab | Branch if value in [srg] is Greater than Zero, mem position in [lab] | ||
00 | 1C | r | ISP | rg1, rg2 | advise ISr belonging to priority [srg] to start at Position in [srg] |
1C | i | ISP | rg1, imm | advise ISr belonging to priority [srg] to start at Position in [imm] | |
i | ISP | rg1, lab | advise ISr belonging to priority [srg] to start at Position in [lab] | ||
00 | 33 | v | ISD | return from latest Interrupt Service and declare it Done | |
00 | 34 | v | IRD | Interrupt Requests Disabled | |
00 | 35 | v | IRE | Interrupt Requests Enabled when following operation is completed |
Die folgende Tabelle gibt eine Übersicht über alle derzeit unterstützten Befehle zur Lösung spezieller Aufgaben.
oc | sc | tp | mne | param | description |
---|---|---|---|---|---|
00 | 1D | s | LDA | rg1 | LoaD All registers using data beginning at memory position in [srg] |
1D | j | LDA | imm | LoaD All registers using data beginning at memory position in [imm] | |
j | LDA | lab | LoaD All registers using data beginning at memory position in [lab] | ||
00 | 1E | s | SVA | rg1 | SaVe All registers to memory beginning at position in [srg] |
1E | j | SVA | imm | SaVe All registers to memory beginning at position in [imm] | |
j | SVA | lab | SaVe All registers to memory beginning at position in [lab] | ||
1F | j | DTA | imm | set DaTA span that specifies next count bytes as data, count in [imm] | |
j | DTA | lab | set DaTA span that specifies following bytes as data, data end in [lab] |
Die nachfolgenden Tabellen geben Aufschluß über den Aufbau eines CHEAP Befehls. Es wird zwischen den im vorigen Abschnitt angesprochenen Befehlstypen unterschieden. Mit Hilfe dieser Übersicht ist es also möglich, manuell und am CASM vorbei, eigenen Maschinencode bzw. eigene Binärdateien zu definieren.
i-type | |||||||
---|---|---|---|---|---|---|---|
1F 1E 1D 1C | 1B 1A 19 18 | 17 16 15 14 | 13 12 11 10 | 0F 0E 0D 0C | 0B 0A 09 08 | 07 06 05 04 | 03 02 01 00 |
oc oc oc oc | oc rg rg rg | rg rg im im | im im im im | im im im im | im im im im | im im im im | im im im im |
r-type | |||||||
---|---|---|---|---|---|---|---|
1F 1E 1D 1C | 1B 1A 19 18 | 17 16 15 14 | 13 12 11 10 | 0F 0E 0D 0C | 0B 0A 09 08 | 07 06 05 04 | 03 02 01 00 |
oc oc oc oc | oc rg rg rg | rg rg rg rg | rg rg rg sc | sc sc sc sc | sc sc sc sc | sc sc sc sc | sc sc sc sc |
j-type | |||||||
---|---|---|---|---|---|---|---|
1F 1E 1D 1C | 1B 1A 19 18 | 17 16 15 14 | 13 12 11 10 | 0F 0E 0D 0C | 0B 0A 09 08 | 07 06 05 04 | 03 02 01 00 |
oc oc oc oc | oc im im im | im im im im | im im im im | im im im im | im im im im | im im im im | im im im im |
s-type | |||||||
---|---|---|---|---|---|---|---|
1F 1E 1D 1C | 1B 1A 19 18 | 17 16 15 14 | 13 12 11 10 | 0F 0E 0D 0C | 0B 0A 09 08 | 07 06 05 04 | 03 02 01 00 |
oc oc oc oc | oc rg rg rg | rg rg -- -- | -- -- -- sc | sc sc sc sc | sc sc sc sc | sc sc sc sc | sc sc sc sc |
v-type | |||||||
---|---|---|---|---|---|---|---|
1F 1E 1D 1C | 1B 1A 19 18 | 17 16 15 14 | 13 12 11 10 | 0F 0E 0D 0C | 0B 0A 09 08 | 07 06 05 04 | 03 02 01 00 |
oc oc oc oc | oc -- -- -- | -- -- -- -- | -- -- -- sc | sc sc sc sc | sc sc sc sc | sc sc sc sc | sc sc sc sc |
Im Folgenden wird am Beispiel der Addition zweier Zahlen die manuelle Übersetzung von Assemblercode aufgezeigt. Die Ergebnisse können via Hex-Editor in eine Datei eingetragen werden und sind dann vom CHEAP interpretierbar.
++ | asm to bin translation | bin to hex translation | ++ | |||
---|---|---|---|---|---|---|
JMP 4 11000 00000 00000 00000000000000100 DW 10 00000 00000 00000 00000000000001010 DW 20 00000 00000 00000 00000000000010100 DW 0 00000 00000 00000 00000000000000000 SET r01, 1 00100 00001 00000 00000000000000001 LW r02, r01 00000 00010 00001 00000000000110000 ADD r01, 1 00101 00001 00000 00000000000000001 LW r03, r01 00000 00011 00001 00000000000110000 ADD r02, r03 00000 00010 00011 00000000000000101 ADD r01, 1 00101 00001 00000 00000000000000001 SW r02, r01 00000 00010 00001 00000000000110001 JMP 4095 11000 00000 00000 00000111111111111 |
11000000000000000000000000000100 C0000004 00000000000000000000000000001010 0000000A 00000000000000000000000000010100 00000014 00000000000000000000000000000000 00000000 00100000010000000000000000000001 20400001 00000000100000100000000000110000 00820030 00101000010000000000000000000001 28400001 00000000110000100000000000110000 00C20030 00000000100001100000000000000101 00860005 00101000010000000000000000000001 28400001 00000000100000100000000000110001 00820031 11000000000000000000111111111111 C0000FFF |