# MU1-Rechner ## Was kann er mehr: - Indirekte Adressierung - Schleifen - Unterprogramme (Strukturen) - Optimieren der Datenzugriffe (schneller) ## ALU ### Verbesserungen - Funktionen der ALU - **A+B** ist der Ausgang des Addierers - **A-B** wird gebildet als **A+nichtB+1** - **B** wird implementiert, indem A fest auf 0 gesetzt wird - **A+1** wird implementiert, indem Eingang B fest auf 0 und Carry-Eingang auf 1 gesetzt wird ![image_54.png](image_54.png) ### Grundfunktionen MU1-ALU _Im Praktikum wird nur erwartet, dass Funktion bekannt ist, nicht bspw FA, FIA, etc._ - FA: Funktion (0, A) (also eig. F0A) - FB: Funktion (0, B) - FIA: Funktion (Inverter, A) - FIB: Funktion (Inverter, B) - FC: Funktion (F1, Carry-Flag) - F1: Funktion (0/1) - FS: Funktionsergebnis Statusregister - C: Funktionsergebnis C ![image_56.png](image_56.png) ![image_55.png](image_55.png) ## Der MU1-Datenpfad - Das erweiterte Modell besitzt - Stackpointer SP - Register Din und Dout - Laufzeiten sind kürzer pro Takt - Takt kann erhöht werden - Durch Din und Dout braucht es mehr Taktzyklen, diese sind aber schneller durchlaufen ![image_57.png](image_57.png) ## Der Reset - Jeder Prozessor hat einen Reset-Eingang - ist negiert angelegt → 0 macht [reset](MU1Rechner.md#reset) - [Program Counter](MU0Rechner.md#steuerwerk) wird auf 0 gestellt, [Microprogram-Counter step](MU1Rechner.md#micro-program-counter-step) ebenfalls - ALU wird auf Funktion NULL gesetzt - Beim Einschalten wird Reset-Signal verzögert gesetzt - Prozessor braucht Zeit um Startzustand herzustellen ## Micro-Program-Counter Step - Step ist ein Speicher in der Steuereinheit (_Timing/Control Unit_) - meiste Befehle benötigen mehrere Takte - Micro-Program-Counter Step gibt Steuerlogik Informationen - welche Aktionen sind auszuführen - Step = Eingangsinformation für jeden Schritt - Steuerungstabelle weiß welcher step welcher Schritt ist ## Befehlsablauf MU1 ![image_58.png](image_58.png) - Step == Null - **Fetch** (lesen des Befehls in das Instruction Register) - letzter Schritt: Step = Null - Step wird meistens um 1 erhöht - falls nicht → Schleife ### Fetch-Zyklus - findet in einem Takt statt - 1. Taktflanke - Program Counter wird auf Adressbus und auf ALU[A] geschaltet - An der ALU ist Befehl=A+1, S=0 - 2. Taktflanke - Speicher liest nächste Instruktion und speichert in IR - PC wird über ALU um 1 erhöht ![image_59.png](image_59.png) ![image_80.png](image_80.png) ### Befehl LDA (Laden des AKK aus Speicher) - Zwei Takte - ![image_60.png](image_60.png) - ![image_81.png](image_81.png) ### Zustandsbeschreibung des Ladebefehls ![image_61.png](image_61.png) - Nach Fetch entscheidet Opcode im IR und Schrittnummer, welchen Zustand der Automat als nächstes annimmt - Step ist PC im Microcode und beschreibt Abfolge der Befehle im Microcode - Zu jedem Schritt gehört eindeutige Funktion - Lässt sich in Timing-Control-Logik umsetzen ## Adressierung ### Direkte Adressierung (STO/LDA) ![image_62.png](image_62.png) - Befehl erhält direkt die Speicheradresse - Adresse kann zur Laufzeit nicht mehr verändert werden ### Indirekte Adressierung (STR/LDR) ![image_63.png](image_63.png) - Adresse steht an Speicherstelle - effektive Adresse kann noch berechnet werden - Schleifen können programmiert werden ### Adressierungsarten #### Unmittelbare Adressierung (_immediate_) - Befehl erhält Konstante - bspw.: _ADD #1_ #### Direkte Adressierung (_direct, absolute_) - Befehlt enthält Adresse im Speicher, an der sich Operand befindet - bspw.: _LDA S_ (_S gibt Adresse im Speicher an_) #### Indirekte Adressierung (_indirect_) - Befehl enthält Adresse, an der dich effektive Adresse mit Inhalt befindet - bspw.: _LDR S_ (_S gibt indirekte Adresse an_) ## Der Stack - stellt dynamischen Zwischenspeicher dar - Grundoperationen: [Push](MU1Rechner.md#stack-push), [Pop](MU1Rechner.md#stack-pop) - Meiste Speicherlayouts (_Konventionen_) sehen vor: - wächst von oben nach unten - wächst von großen zu kleinen Adressen ### Stack - PUSH ![image_65.png](image_65.png) - erniedrigt Stackpointer - schiebt einen Wert in Speicherwort, auf das der Stackpointer zeigt ### Stack - POP ![image_66.png](image_66.png) - liest ein Speicherwort von Adresse auf den der Stackpointer zeigt - erhöht den Stackpointer ### Der Stack im Speicher ![image_64.png](image_64.png) - Stackpointer wird auf Adresse am Ende des Speicherbereichs gesetzt - Programme werden im unteren Speicherbereich platziert - Programm-Counter auf Adresse 0 - Programmbereich schließt sich nach oben an Datenbereich an - Zwischen Daten und Stack findet man Heap ### Zugriffe auf den Speicher ![image_67.png](image_67.png) ## Unterprogramme ![image_68.png](image_68.png) - wichtiges Strukturierungsmittel für Programmierung - werden mit Sprungbefehl (_call, bl_) angesprungen - Nach Verlassen des UP wird ursprüngliches Programm wieder fortgesetzt - Rücksprung erfolgt indem gespeicherte Adresse wieder in PC übertragen wird ### Unterprogramm Aufrufe #### Call ![image_69.png](image_69.png) - nächster nach der Rückkehr auszuführende Befehl wird auf den Stack gespeichert - Sprungadresse wird aus IR in PC geladen #### Return ![image_70.png](image_70.png) - Rücksprungadresse von Stack in PC geschrieben - fetch-Zyklus lädt neue Instruktion ## MU1-Befehlssatz ![image_71.png](image_71.png) ## Micro-Codes **X = Y** - Inhalt des Registers Y wird nach X verschoben **X = [Y]** - Inhalt von Adresse in Y wird nach X verschoben **X = Y op Z** - Inhalt von Y (A-Bus der ALU) wird mit Z (B-Bus der ALU) verrechnet und nach X transportiert **[X] = Y** - In Adresse in X wird Inhalt von Y geschrieben **ACC = Din** - ACC & Din sind Registernamen - Inhalt von Din wird nach ACC transportiert - in Din muss oe gesetzt sein, in ACC muss ie gesetzt sein - Transport über ALU - [ALU Funktion](MU1Rechner.md#grundfunktionen-mu1-alu) muss B sein - Da Speicher nicht angesprochen wird (keine [ ]) - [MEMeq=0](MU0Rechner.md#speicher-des-mu0) und [RnW beliebig (laut Rapp lieber 1)](MU0Rechner.md#speicher-des-mu0) **Din = [SP]** - Inhalt von SP ist Adressinformation - Adressmultiplexer muss auf 0 stehen - Da Speicher angesprochen wird - MEMrq = 1, RnW = 1 - Da ALU nicht benutzt wird - ALU-Funktion kann beliebig gesetzt werden **PC = PC + 1** - ALU-Funktion muss [A+1](MU1Rechner.md#grundfunktionen-mu1-alu) sein - PC wird auf A-Bus gelegt - in der zweiten Hälfte des Takts wird Ergebnis in PC geschrieben - oe und ie von PC müssen 1 sein **Din = [SP], SP = SP+1** - Beide Operationen können in einem Takt durchgeführt werden - Adressierung in der ersten Takthälfte - Zurückschreiben in der zweiten Takthälfte ## Regeln für MU1 **[X] = Dout** - wird in den Speicher geschrieben, muss rechte Seite [Dout](MU1Rechner.md#der-mu1-datenpfad) sein - [MEMrq = 1, RnW = 0](MU0Rechner.md#speicher-des-mu0) - zu schreibender Wert muss VORHER nach Dout gebracht werden **X = [Y]** - wird vom Speicher gelesen - linke Seite muss IR oder Din sein - [MEMrq = 1, RnW = 1](MU0Rechner.md#speicher-des-mu0) **keine Adresse** - wird keine Adresse verwendet - [MEMrq = 0, RnW = 1](MU0Rechner.md#speicher-des-mu0) - **Nur ein Register darf jeweils auf einen Bus schreiben (A- oder B-Bus), aber alle dürfen lesen** ## Die Addition ADD S - IR wird zur Adressierung verwendet und der Wert nach Din gebracht - **Din = [IR]** - Inhalt des AKK wird auf A-Bus gelegt, Inhalt von Din auf B-Bus - [ALU-Funktion](MU1Rechner.md#grundfunktionen-mu1-alu) ist **A+B, S: ACC = ACC + DIN** ![image_72.png](image_72.png) ## Die Operation PUSH **Akkumulator wird auf den Stack geschoben** - Besteht aus 3 Schritten 1. **SP = SP-1** - ![image_73.png](image_73.png) 2. **Dout = ACC** - ![image_74.png](image_74.png) 3. **[SP] = Dout** - ![image_75.png](image_75.png) - [Micro-Program-Counter Step](MU1Rechner.md#micro-program-counter-step) wird auf 0 gesetzt - Fetch-Zyklus schließt sich an ## MU1-Zustandsautomat für LDA, ADD, PUSH ![image_76.png](image_76.png) - Nach dem Holen des Opcodes im Fetch-Zyklus - Zustand des OpCode wird angesprungen - Step-Variable (PC im Micro-Code) wird in Schleife durchlaufen - endet bei 0 im Fetch-Zyklus ## Bedingte Sprünge - Bedingter Sprung **JGE** (_Jump on greater or equal_) - in Abhängigkeit des Negative-Flags im Statusregisters (~15 Bit des ACC, ACC >=0 oder ACC <0) wird ein unterschiedlicher Zustand angesprungen - ? N = 0 (ACC >= 0) - PC = IR - ? N = 1 (ACC < 0) - keine Operation wird ausgeführt (NOP) - Bedingter Sprung **JNE** (_Jump on not equal) - strukturell gleich, Zusatzbedingung: - Accumulator = Null (Zero-Flag = 1) ### MU1-Steuerlogik für bedingte Sprünge - Beide Befehle weisen 2 Zustände auf - unterscheiden sich durch Statusbits des Akkumulators - Beide Zustände haben Schrittnummer 1 und Folgeschritt 0 - Funktion **NOP** (**N**o **Op**eration) ist gekennzeichnet - kein Registerinhalt wird verändert - Alle Register haben oe und ie auf 0 - Speicher wird nicht angesprochen - MEMrq = 0 - ![image_77.png](image_77.png) ## Der Stop-Befehl - hat als Folgezustand _stop_ - kein Fetch-Zyklus mehr - Zustandsmaschine wird in der Stellung angehalten - ![image_78.png](image_78.png) ## Reset - Zustandsmaschine geht in Zustand _reset_ - PC = 0 - Step = 0 - Beendigung des Reset-Signals mit dem fetch fortgefahren und Befehl von Adresse 0 wiederholt - ![image_79.png](image_79.png) ## Zusammenfassung - Funktionen ALU - Neue Register Stackpointer, Din, Dout - Micro-Programm-Counter Step - Fetch-Zyklus - Micro Programm + Micro Codes + Zustandsautomaten für LDA, ADD, Push, JGE, Stop, Reset - Direkt und indirekte Adressierung - Stack, Unterprogramme - Beschreibung der Microcode-Funktion durch einfache Sprache - Zentrales Register: ACC → Akkumulator-Architektur ## Probleme des MU1-Designs - **Speichergröße** - begrenzt auf 4096 Worte (12Bit) bzw. 65k Worte (16Bit) - **Anzahl Befehle** - Begrenzung auf 4 Bit breiten Opcode - **Absolute Adressierung** - **Adressberechnungen** - Müssen in einem Register zwischengespeichert werden - **Nur ein Datenregister** - **Berechnung Programmcounter** - Muss jedes Mal durch ALU erhöht werden → verlangsamt Prozessor ## [Weiterentwicklung MU2](MU2-3Rechner.md)