TGI Praktikum |
Implementierung |
Leitwerk mit dem Sequencer-Baustein Am2910 | |
Rechenwerk für logische Operationen, Rechenvorgänge (Addition, Subtraktion etc.). Für unsere Aufgabe ist der Rechenwerksbaustein Am2901 besonders wichtig. | |
Speicherwerk mit einem 64 K x 16 Bit großen Hauptspeicher | |
Ein-/Ausgabewerk (auf nachfolgender Skizze nicht dargestellt) |
Mit Hilfe dieser Zeichnung muss nun überlegt werden, welche Schritte zum Erstellen des gewünschten Mikroprogramms notwendig sind.
Quellcode strtolower_1 - erste Aufgabenstellung |
Hauptspeicher:
Adresse | Wert | Mnemonic |
0000 | 0202 | move_fest |
0001 | 0050 | IFETCH |
0002 | 0320 | move_ausHS |
0003 | 0500 | jmp_z |
0004 | 0017 | IFETCH |
0005 | 0201 | move_fest |
0006 | 005A | IFETCH |
0007 | 0601 | jmp_gt |
0008 | 0011 | IFETCH |
0009 | 0201 | move_fest |
000A | 0041 | IFETCH |
000B | 0701 | jmp_lt |
000C | 0011 | IFETCH |
000D | 0201 | move_fest |
000E | 0020 | IFETCH |
000F | 0110 | add |
0010 | 0420 | move_inHS |
0011 | 0201 | move_fest |
0012 | 0001 | IFETCH |
0013 | 0112 | add |
0014 | 0320 | move_ausHS |
0015 | 0800 | jmp |
0016 | 0003 | IFETCH |
0017 | 0000 | Ende |
... | ... | ... |
0050 | 00xx | 1. Buchstabe |
... | ... | ... |
... | 0000 | Ende ZK |
OP-Code 00 : ifetch
ifetch | |||||||||||||||||||||||||||
000 | |||||||||||||||||||||||||||
001 | |||||||||||||||||||||||||||
002 | jump | ||||||||||||||||||||||||||
An der Mikroprogrammadresse 000 muß stets das Programm IFetch stehen,
denn beim Aufruf eines Mikroprogramms steht der Mikrobefehlszähler stets auf Null.
Deshalb muß an dieser Position ein Programm stehen, das den aktuellen Maschinenbefehl in das Instruktionsregister lädt
und den Maschinenbefehl decodiert.
Im ersten Takt wird nun der Befehlszählerinhalt auf den Adressbus ausgegeben und der Lesezyklus gestartet. Das geschieht durch
BZ_EA = E und MWE = R. Die Adressfortschaltbits bei Feld "ins" (für Instruktionsregister)
des Mikroleitwerks Am2910 müssen nun auf "CONT" gesetzt werden, um mit der nächsten Mikroinstruktion innerhalb dieses Befehls fortzufahren.
In dieser, also im nächsten Takt, muß der vom HS an den Datenbus
gelegte Maschinenbefehl mit IR_LD = L in das Instruktionsregister geladen werden. Auch hier wird das Adressfortschaltbit wieder auf "CONT" gesetzt.
Der Op-code des Maschinenbefehls im Instruktionsregister addressiert nun eine Speicheradresse im Mappingprom.
Diese Speicherzelle enthält die Anfangsadresse desjenigen Mikroprogramms im Mikroprogrammspeicher,
das den Maschinenbefehl mit diesem Op-code realisiert. Im 3. Takt wird dieses Mikroprogramm nun mit JMAP (im Am2910) angesprungen und gleichzeitig
wird der Befehlszähler mit BZ_INC = 1 erhöht.
OP-Code 01 : add
add | |||||||||||||||||||||||||||
010 |
Dieser add-Befehl addiert die Inhalte der Register RA und RB miteinander und schreibt das Ergebnis nach RB zurück. Dazu muss das "src"-Feld des Am2901 auf "AB", das "func"-Feld auf "add" und das "dest"-Feld auf "RAMF" gesetzt werden. "RAMF" dient zur ALU-Zielsteuerung und schreibt das Ergebnis, welches dann am Y-Ausgang des Am2901 anliegt in das Register RB. Die Registeradressen werden jeweils dem Register-A- bzw. Register-B-Adressfeld des Instruktionsregisters entnommen, was durch "ASEL" = "IR" und "BSEL" = "IR" angegeben wird. Zuletzt muß das "ins/bar"-Feld des Mikroleitwerk Am2910 nur noch auf "CJP/000" gesetzt werden, damit es wieder zur HS-Adresse "000", also zum IFetch zurückspringt.
OP-Code 02 : move_fest
move_fest | |||||||||||||||||||||||||||
020 | |||||||||||||||||||||||||||
021 |
Dieser Zweiwort-Befehl liest einen festen Wert aus dem Hauptspeicher in das Register RB ein. Der feste Wert befindet sich dabei unmittelbar hinter diesem Befehl im HS (unmittelbar adressierter Quelloperand). Dazu wird im 1. Takt der Inhalt des Befehlszählers auf den Adressbus geladen ("BZ_EA" = "E") und "MemoryWriteEnable" bleibt auf "R". Im "ins"-Feld des Am2910 ist natürlich "CONT" gesetzt, um mit der nächsten Mikroinstruktion innerhalb dieses Befehls fortfahren zu können. Im 2. Takt befindet sich der Wert nun auf dem Datenbus und dieser gelangt nun über den D-Eingang des Am2901 in die ALU. Dort wird der Wert mit Null addiert und in das Register RB geschrieben. Anschliessend wird der Befehlszähler erhöht und es erfolgt wieder ein Sprung zurück zum IFetch. (Am2901: "src" = "DZ", "func" = "add", "dest" = "RAMF"; Am2910: "ins" = "CJP", "BZ_inc" = "I")
OP-Code 03 : move_ausHS
move_ausHS | |||||||||||||||||||||||||||
030 | |||||||||||||||||||||||||||
031 |
In diesem Befehl soll nun das nächste Datum an der durch das Register RA adressierten Stelle in das Register RB geladen werden. Dazu wird der Adresswert im 1.Takt mit Hilfe einer "Addition mit 0" durch die ALU geschleust und am Y-Ausgang des Am2901 angelegt, wo die Adresse mit "ABUS" = "AB" auf den Adressbus ausgegeben wird. Auch hier wird der Lesezugriff angekündigt und mit der nächsten Mikroinstruktion innerhalb dieses Befehls fortgefahren. Im 2. Takt werden die Daten vom Datenbus in ALU geladen und mit "dest" = "RAMF" am Y-Ausgang des Am2901 angelegt und damit in das Register RB geschrieben. Zuletzt erfolgt wieder ein Sprung zurück zum IFetch.
OP-Code 04 : move_inHS
move_inHS | |||||||||||||||||||||||||||
040 | |||||||||||||||||||||||||||
041 |
Bei diesem Befehl soll nun der umgewandelte Wert in den Hauptspeicher zurückgeschrieben werden.
Die HS-Adresse, auf die geschrieben werden soll, liegt
im Register RA und muß zunächst auf den Adressbus ausgegeben werden.
Dazu wird die Adresse durch eine Addition mit Null durch die ALU (Am2901) geschleust. "src = ZA" gibt dabei die
Quelloperanden der ALU an, in diesem Fall "0" und Register RA. "func = add" bezeichnet die
Additionsfunktion der ALU. In dem Feld "dest" der ALU-Zielsteuerung wird "NOP" gesetzt (no operation),
weil der Wert am F-Ausgang der ALU dann unverändert am Y-Ausgang des Rechenwerks anliegt.
Durch Setzen des "ABUS"-Bits auf "AB" gelangt die Adresse auf den Adreßbus. Das Mikroleitwerk Am2910 muß nun noch
bei den Adressfortschaltungsbits "ins" auf "CONT" (continue) gesetzt werden, damit auch die nächste Mikroinstruktion im 2. Takt
dieses Befehls noch ausgeführt wird. Zuletzt muß durch "MWE" = "W" der Schreibzugriff angekündigt werden.
Die zu schreibenden Daten liegen im Register RB und müssen nun im 2. Takt auf den Datenbus geladen werden. Dazu muß der Inhalt nun, wie vorhin schon erklärt,
durch die ALU zum Y-Ausgang des Rechenwerks geschleust werden. Lediglich die Quelloperanden werden nun bei "src" aud "ZB" gesetzt
und die Daten sollen nun nicht am Adressbus sondern am Datenbus anliegen ("DBUS" = "DB"). Durch Setzen des "MWE"-Bits auf "R"
wird der Schreibzugriff beendet und das Mikroleitwerk muss nun mit "CJP" wieder zurück zum IFetch an die HS-Adresse "000" springen.
OP-Code 05 : jmp_z
jmp_z | |||||||||||||||||||||||||||
050 | |||||||||||||||||||||||||||
051 | |||||||||||||||||||||||||||
052 | |||||||||||||||||||||||||||
053 | |||||||||||||||||||||||||||
054 |
Dieser Befehl dient dazu um festzustellen, ob das Ende der Zeichenkette schon erreicht ist oder nicht. Falls der Wert in Register RA gleich "0" ist, so springt der Befehl zur Mikroprogrammspeicheradresse 053 innerhalb dieses Befehls, ist der Wert ungleich "0", so fährt der Befehl mit der nachfolgenden Mirkoinstruktion fort. Im ersten Takt liegt der zu vergleichende Wert im Register RA. Durch eine ALU-Operation (Addition mit null) können hier Status-Flags im Maschinenstatusregister gesetzt werden, wie z. B. das Zero-Flag, welches anzeigt, ob das Ergebnis gleich "0" ist. Diese Flags liegen dann am "CC"-Eingang des Am2910 an und können dort abgefragt werden. Dazu muß nur das "CEM"-Feld des Am2904 (Baustein für Bedingungslogik) auf "L" gesetzt werden. Die Abfrage des Z-Flags geschieht dann im nächsten Takt. Dabei ist es wichtig die "CEM"- bzw. "CEu"-Feld des Am2904 auf "H" (hold) zu setzen, um zu verhindern, daß die Flags wieder verändert werden. Im 2. Takt wird das Z-Flag mit "srtest" = "45" abgefragt. ("45" ist der Code zur Abfrage des Z-Flags im Maschinenstatusregister). Dazu muss nur noch das "CCEN"-Feld des Am2910 auf "C" gesetzt werden, damit eine Aktion in Abhängigkeit einer Testbedingung durchgeführt werden kann. Wenn das Z-Flag gesetzt wurde, so verzweigt das Programm mit "CJP" zur MPS-Adresse "053". Dort wird der aktuelle Inhalt des Befehlszählers auf den Adressbus ausgegeben und ein Lesezugriff gestartet, um die nächste Zieladresse aus dem HS zu lesen. Im darauffolgenden Takt wird nun das Instruktionsregister mit dem auf dem Datenbus anliegenden Befehl geladen und es erfolgt der Rücksprung zum IFetch. Wurde die Bedingung nicht erfüllt (d.h. wurde das Z-Flag nicht gesetzt), so springt der Befehl im 3.Takt (Adresse 052) zurück zum IFetch und erhöht den Befehlszähler.
OP-Code 06 : jmp_gt
jmp_gt | |||||||||||||||||||||||||||
060 | |||||||||||||||||||||||||||
061 | |||||||||||||||||||||||||||
062 | |||||||||||||||||||||||||||
063 | |||||||||||||||||||||||||||
064 |
Der jmp_gt-Befehl vergleicht in unserem Programm den anliegenden Zeichenwert mit 0x005A ("Z"). Ist der anliegende Wert größer, so ist das nicht der Wert eines Großbuchstabens und der Befehl verzweigt zur MPS-Adresse 063, andernfalls wird mit der nachfolgenden Mikroinstruktion fortgefahren. Zunächst liegt der Vergleichswert in Register RB und der zu vergleichende Wert in Register RA. Durch Setzen des ALU-"func"-Feldes auf "SUBS", rechnet die ALU "A-B-1". Die zusätzlich abgezogene "1" muß durch Setzen des Am2904-"cinmux"-Feldes auf "CI1" wieder hinzuaddiert werden, um das Ergebnis nicht zu verfälschen.(Ansonsten würde das Z-Flag auch dann gesetzt, wenn der zu vergleichende Wert nur um 1 größer wäre.) Zuletzt wird nur noch das Maschinenstatusregister geladen. Im 2. Takt erfolgt dann die Abfrage, diesmal mit dem "srtest"-Code "54" (für die Abfrage der Flags, die gesetzt werden falls A>B). Ist die Bedingung erfüllt so erfolgt ein Sprung zum übernächsten Takt 063. In diesem Takt wird analog zu jmp_z "BZ_ea" auf "E" gesetzt und ein Lesezugriff angekündigt. Im letzten Takt wird das Instruktionsregister geladen und zu IFetch verzweigt. Wurde die Bedingung nicht erfüllt so wird der Befehlszähler im nächsten Takt erhöht und ebenfalls zu IFetch verzweigt.
OP-Code 07 : jmp_lt
jmp_lt | |||||||||||||||||||||||||||
070 | |||||||||||||||||||||||||||
071 | |||||||||||||||||||||||||||
072 | |||||||||||||||||||||||||||
073 | |||||||||||||||||||||||||||
074 |
Der jmp_lt-Befehl ist im Wesentlichen analog zum vorhergehenden Befehl jmp_gt. Mit diesem Befehl wird in unserem Programm der anliegende Wert mit der Untergrenze der Großbuchstaben, also dem "A" verglichen. Einziger Unterschied: hier wird der Wert in Register RA vom Wert in Register RB abgezogen (d.h. Am2901 "func" = "SUBR").
OP-Code 08 : jmp
jmp | |||||||||||||||||||||||||||
080 | |||||||||||||||||||||||||||
081 |
Dieser unbedingte Sprung-Befehl verzweigt zur unmittelbar im Hs nachfolgenden Adresse (unmittelbar adressierter Quelloperand im Konstantenfeld des Zweiwortbefehls). Dazu wird der aktuelle Inhalt des Befehlszählers auf den Adressbus ausgegeben ("BZ_ea" = "E"), der Lesezugriff angekündigt und mit dem nächsten Takt fortgefahren. Das nun auf dem Datenbus liegende Datum (der nächste Befehl) wird nun mit "BZ_ld" = "L" in den Befehlszähler geladen. Anschliessend erfolgt der Rücksprung zum IFetch.
Quellcode strtolower_2 |
Hauptspeicher:
Adresse | Wert | Mnemonic |
0000 | 0100 | strtolower |
0001 | 0001 | Ende |
... | ... | ... |
0050 | 00xx | 1. Buchstabe |
... | ... | ... |
... | 0000 | Ende ZK |
OP-Code 00 : ifetch
ifetch | |||||||||||||||||||||||||||
000 | |||||||||||||||||||||||||||
001 | |||||||||||||||||||||||||||
002 | jump | ||||||||||||||||||||||||||
(siehe oben)
OP-Code 01 : strtolower
strtolower | |||||||||||||||||||||||||||
010 | Position des BZ in Q merken | ||||||||||||||||||||||||||
011 | move 0x0050 nach R2 | ||||||||||||||||||||||||||
012 | move_ausHS: Buchstabe in HS an Pos [R2] in R0 schreiben | ||||||||||||||||||||||||||
013 | |||||||||||||||||||||||||||
014 | jmp_z: wenn R0 == 0, dann springe zu 00E | ||||||||||||||||||||||||||
015 | |||||||||||||||||||||||||||
016 | jmp_gt: wenn R0 > 0x005A, dann springe zu 01D | ||||||||||||||||||||||||||
017 | |||||||||||||||||||||||||||
018 | jmp_lt: wenn R0 < 0x0041, dann springe zu 01D | ||||||||||||||||||||||||||
019 | |||||||||||||||||||||||||||
01A | add: R0 um 0x0020 erhöhen | ||||||||||||||||||||||||||
01B | move_inHS: Buchstabe (R0) zurück an Pos [R2] in HS schreiben | ||||||||||||||||||||||||||
01C | |||||||||||||||||||||||||||
01D | add: Buchstabenzähler R2 um 0x0001 erhöhen & jmp: wieder nach oben zu Pos 012 springen | ||||||||||||||||||||||||||
01E | BZ wieder zurück auf Wert im Q-Register setzen und zu ifetch springen | ||||||||||||||||||||||||||
Der Maschinenbefehl strtolower ist im Wesentlichen analog zu obigem Maschinenprogramm. Es konnte hier jedoch einiges gekürzt werden. So erfolgt nur noch ein einziger Hauptspeicherzugriff, um den Befehl strtolower überhaupt aufzurufen. Im Befehl selbst erfolgen nur noch Sprünge innerhalb des Mikroprogramms. Die einzelnen Mikroinstruktionen sind jedoch fast exakt diesselben wie die oben schon erklärten und benötigen daher keine zusätzlichen Erklärungen mehr.
zurück | 30.03.00 Katrin Stedele, Rainer Schmoll, Tanja Wojak |