Registermaschiene Aufgabe lösen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Jinpachu
User
Beiträge: 8
Registriert: Sonntag 12. Februar 2023, 18:46

Gegeben sei eine Registermaschine bezüglich der Operationen ADD, SUB, MULT, DIV, CADD, CSUB, CMULT, CDIV. Die Maschine verwendet die Register b, c0, c1, c2, c3.

Hinweis: c1 und c2 sind Eingabewerte, c3 wird das Ergebnis enthalten

1 CLOAD 1

2 STORE 3

3 LOAD 2

4 IF c0 = 0 GOTO 12

5 LOAD 3

6 MULT 1

7 STORE 3

8 LOAD 2

9 CSUB 1

10 STORE 2

11 GOTO 4

12 END

Berechnen sie die End-Konfiguration der Maschine für die Start-Zustände

(1,0,2,1,0) (1,0,2,3,0) und (1,0,2,5,0)

Kann mir jemand erklären, wie das System funktioniert, bitte für dullis, wäre super!
Jinpachu
User
Beiträge: 8
Registriert: Sonntag 12. Februar 2023, 18:46

Es gibt den Befehlszähler B1 Arbeitsregister C0 und Speicherregister C1-C3. In dieser Aufgabe haben wir eine
"Konfiguration", da wir b1,c0,c1,c,2 und so weiter haben.

Wir sollen folgende Konfigurationen berechnen 1) (1,0,2,1,0) 2) (1,0,2,3,0) und 3) (1,0,2,5,0)

Der Aufgabenstellung können wir entnehmen, dass für jede Berechnung eine "Konfiguration" notwendig ist.

Fangen wir mit 1) (1,0,2,1,0) an. 1= Hat den 1 Befehl durchgeführt, die 0 steht für den Arbeitsregister die 2 1 0 stehen für die Speicherregister c1=2 c2=1 c3=0

Das ist alles was ich aktuell zum Thema weiß.
Qubit
User
Beiträge: 130
Registriert: Dienstag 7. Oktober 2008, 09:07

Dein Programm ist im RAM, der "Befehlszeiger" b zeigt auf die jeweilige Adresse, und wird nach jedem Befehl um 1 erhöht bzw. springt zur neuen Adresse im RAM.
Geladen, berechnet und gespeichert werden die Daten im/ausm "Akkumulator" c(0), die Daten gehen und kommen dabei entweder aus den "Registern" c(1), c(2), c(3) und werden durch ihre Nummer adressiert oder werden direkt geladen. (zB. cload).

Code: Alles auswählen

Also, zB. Startzustand (b=1, c(0)=0, c(1)=2, c(2)=1, c(3)=0) :
b=1: cload 1 -> c(0)=1 -> (2,1,2,1,0)
b=2: store 3 -> c(3)=1 -> (3,1,2,1,1)
b=3: load 2  -> c(0)=1 -> (4,1,2,1,1)
b=4: if c(0)=0 goto 12 -> b=5 -> (5,1,2,1,1)
b=5: load 3  -> c(0)=1 -> (6,1,2,1,1)
...
usw.
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das kann man ja auch mal kurz in Code ausdrücken:

Code: Alles auswählen

#!/usr/bin/env python3
from contextlib import suppress
from functools import partial

from attr import attrib, attrs

SOURCE_LINES = """\
1 CLOAD 1
2 STORE 3
3 LOAD 2
4 IF c0 = 0 GOTO 12
5 LOAD 3
6 MULT 1
7 STORE 3
8 LOAD 2
9 CSUB 1
10 STORE 2
11 GOTO 4
12 END
""".splitlines()


class Halt(Exception):
    pass


@attrs
class Machine:
    instruction_counter = attrib(default=1)
    accumulator = attrib(default=0)
    registers = attrib(factory=lambda: [0] * 3)

    @property
    def configuration(self):
        return (self.instruction_counter, self.accumulator, *self.registers)

    def run(self, program):
        with suppress(Halt):
            while True:
                program[self.instruction_counter - 1](self)
                self.instruction_counter += 1

    @classmethod
    def from_configuration(cls, configuration):
        instruction_counter, accumulator, *registers = configuration
        return cls(instruction_counter, accumulator, registers)


def execute_end(operand, machine):
    raise Halt()


def execute_goto(operand, machine):
    machine.instruction_counter = operand - 1


def execute_goto_if_zero(operand, machine):
    if machine.accumulator == 0:
        machine.instruction_counter = operand - 1


def execute_load_constant(operand, machine):
    machine.accumulator = operand


def execute_load(operand, machine):
    machine.accumulator = machine.registers[operand - 1]


def execute_multiplication(operand, machine):
    machine.accumulator *= machine.registers[operand - 1]


def execute_store(operand, machine):
    machine.registers[operand - 1] = machine.accumulator


def execute_subtract_constant(operand, machine):
    machine.accumulator -= operand


INSTRUCTION_NAME_TO_FUNCTION = {
    "CLOAD": execute_load_constant,
    "CSUB": execute_subtract_constant,
    "END": execute_end,
    "GOTO": execute_goto,
    "IF c0 = 0 GOTO": execute_goto_if_zero,
    "LOAD": execute_load,
    "MULT": execute_multiplication,
    "STORE": execute_store,
}


def compile_instruction(expected_counter, line):
    instruction_counter_text, _, instruction_text = line.partition(" ")
    assert expected_counter == int(instruction_counter_text)
    instruction_name, _, operand_text = instruction_text.rpartition(" ")
    #
    # Instructions without operand get an implicit 0 as operand.
    #
    if not instruction_name:
        instruction_name, operand_text = operand_text, "0"

    return partial(
        INSTRUCTION_NAME_TO_FUNCTION[instruction_name], int(operand_text)
    )


def compile_program(lines):
    return [
        compile_instruction(instruction_counter, line)
        for instruction_counter, line in enumerate(lines, 1)
    ]


def main():
    program = compile_program(SOURCE_LINES)
    for machine in map(
        Machine.from_configuration,
        [(1, 0, 2, 1, 0), (1, 0, 2, 3, 0), (1, 0, 2, 5, 0)],
    ):
        machine.run(program)
        print(machine.configuration)


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
ThomasL
User
Beiträge: 1379
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich finde das immer wieder geil, wie du solche Code "Schnipsel" mal eben aus dem Handgelenk schüttelst. Daumen hoch.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Qubit
User
Beiträge: 130
Registriert: Dienstag 7. Oktober 2008, 09:07

ThomasL hat geschrieben: Freitag 23. Juni 2023, 19:37 Ich finde das immer wieder geil, wie du solche Code "Schnipsel" mal eben aus dem Handgelenk schüttelst. Daumen hoch.
Jup, das ist echt super! :cool:
So kann man auch den Algorithmus und das Endergebnis direkt nachvollziehen:

c(3)_fin = c(1)_init ** c(2)_init
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das war eine kleine Übung für den Advent of Code, da kommen ja auch immer mal wieder so ähnliche Aufgaben vor. Sozusagen zur Halbzeit vor dem nächsten AoC. 🎄
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Qubit
User
Beiträge: 130
Registriert: Dienstag 7. Oktober 2008, 09:07

Und wer nicht so ein Python-Profi wie __blackjack__ ist und trotzdem mal mit einer (etwas komplexeren) Registermaschine "spielen" will, kann sich auch ein Python-Packages installieren :), zB:
pip install py-register-machine2
https://daknuett.github.io/py_register ... hitecture
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eigentlich habe ich die Hausaufgabe mit dem Python-Programm ja zu leicht gemacht. Ich hätte klassisch erst einmal mit einem klassischen BASIC-Programm anfangen sollen, damit das auch auf dem C64 oder VIC-20 läuft. 😎

Code: Alles auswählen

   10 DIM IN$(8),I(100),O(100),C(3):FOR I=1 TO 8:READ IN$(I):NEXT
  100 PRINT"COMPILING..."
  110 READ IC:IF IC=-1 THEN 200
  120 READ C$,O(IC):F=0:FOR I=1 TO 8:F=IN$(I)=C$:IF F THEN I(IC)=I:I=8
  130 NEXT:IF F THEN 110
  140 PRINT"UNKNOWN INSTRUCTION AT";IC;C$:END
  200 PRINT"RUN CONFIGURATIONS..."
  210 READ CN:FOR I=1 TO CN:READ IC,C(0),C(1),C(2),C(3):H=0
  220 REM PRINT IC;IN$(I(IC));O(IC)
  230 ON I(IC) GOSUB 500,510,520,530,540,550,560,570
  240 IF H THEN 260
  250 IC=IC+1:GOTO 220
  260 PRINT IC;C(0);C(1);C(2);C(3):NEXT:END
  500 H=1:RETURN:REM END
  510 C(0)=O(IC):RETURN:REM CLOAD
  520 C(0)=C(O(IC)):RETURN:REM LOAD
  530 C(O(IC))=C(0):RETURN:REM STORE
  540 C(0)=C(0)-O(IC):RETURN:REM CSUB
  550 C(0)=C(0)*C(O(IC)):RETURN:REM MULT
  560 IC=O(IC)-1:RETURN:REM GOTO
  570 IF C(0)=0 THEN 560:REM IF C0 = 0 GOTO
  580 RETURN
 5000 REM INSTRUCTION NAMES.
 5010 DATA END,CLOAD,LOAD,STORE,CSUB,MULT,GOTO,IF C0 = 0 GOTO
 5100 REM THE PROGRAM.
 5110 DATA 1,CLOAD,1
 5120 DATA 2,STORE,3
 5130 DATA 3,LOAD,2
 5140 DATA 4,IF C0 = 0 GOTO,12
 5150 DATA 5,LOAD,3
 5160 DATA 6,MULT,1
 5170 DATA 7,STORE,3
 5180 DATA 8,LOAD,2
 5190 DATA 9,CSUB,1
 5200 DATA 10,STORE,2
 5210 DATA 11,GOTO,4
 5220 DATA 12,END,0
 5230 DATA -1
 6000 REM THE CONFIGURATIONS TO TEST.
 6010 DATA 3
 6020 DATA 1,0,2,1,0
 6030 DATA 1,0,2,3,0
 6040 DATA 1,0,2,5,0
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Jinpachu
User
Beiträge: 8
Registriert: Sonntag 12. Februar 2023, 18:46

Qubit hat geschrieben: Freitag 23. Juni 2023, 16:48 Dein Programm ist im RAM, der "Befehlszeiger" b zeigt auf die jeweilige Adresse, und wird nach jedem Befehl um 1 erhöht bzw. springt zur neuen Adresse im RAM.
Geladen, berechnet und gespeichert werden die Daten im/ausm "Akkumulator" c(0), die Daten gehen und kommen dabei entweder aus den "Registern" c(1), c(2), c(3) und werden durch ihre Nummer adressiert oder werden direkt geladen. (zB. cload).

Code: Alles auswählen

Also, zB. Startzustand (b=1, c(0)=0, c(1)=2, c(2)=1, c(3)=0) :
b=1: cload 1 -> c(0)=1 -> (2,1,2,1,0)
b=2: store 3 -> c(3)=1 -> (3,1,2,1,1)
b=3: load 2  -> c(0)=1 -> (4,1,2,1,1)
b=4: if c(0)=0 goto 12 -> b=5 -> (5,1,2,1,1)
b=5: load 3  -> c(0)=1 -> (6,1,2,1,1)
...
usw.
Ich habe mal die Aufgaben fertig gerechnet, jedoch habe ich bei der Aufgabe 2 ein Problem. Ich bin da bei Goto4. Wenn ich bei"IF c0= 0 geh zu goto12" lande, ist die Bedingung nicht erfüllt und ich kann nicht zu 12 springen, um fertig zu werden. Muss ich also solange immwer bis zu 11 hoch und dann wieder zu 4 runter bis ich in c0 eine 0 stehen habe? Oder wie geht man da vor?


Aufgabe 1 (1,0,2,1,0)

1 CLOAD 1 = 2.1.2.1.0

2 STORE 3 = 3.1.2.1.1

3 LOAD 2 = 4.1.2.1.1

4 IF c0= 0 geh zu goto12 = 5.1.2.1.1

5 LOAD 3 = 6.1.2.1.1

6 MULT 1 = 7.2.2.1.1

7 STORE 3 = 8.2.2.1.2

8 LOAD 2 = 9.1.2.1.2

9 CSUB 1 = 10.0.2.1.2

10 STORE 2 = 11.0.2.0.2

11 GOTO 4 = 4.0.2.0.2 <Lösung

12 End

Aufgabe 2 (1,0,2,3,0)




1 CLOAD 1 = 2.1.2.3.0

2 STORE 3 = 3.1.2.3.1

3 LOAD 2 = 4.3.2.3.1

4 IF c0= 0 geh zu goto12 = 5.3.2.3.1

5 LOAD 3 = 6.1.2.3.1

6 MULT 1 = 7.2.2.3.1

7 STORE 3 = 8.2.2.3.2

8 LOAD 2 = 9.3.2.3.2

9 CSUB 1 = 10.2.2.3.2

10 STORE 2 = 11.2.2.2.2

11 GOTO 4 =????

12 End
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jinpachu: Das IF … GOTO springt ja nur wenn die Bedingung erfüllt ist, ansonsten geht es einfach mit dem nächsten Befehl weiter. Bei den Fragezeichen muss 4.2.2.2.2 stehen.

In das BASIC-Program liesse sich ganz einfach eine Tracing-Ausgabe einbauen. Die Hälfte (Ausgabe des aktuellen Befehls) ist da schon, nur auskommentiert. Hatte ich zu Testzwecken drin, weil ich mich an einer Stelle beim „instruction counter“ IP vertippt hatte und deswegen GOTO nicht funktionierte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Jinpachu
User
Beiträge: 8
Registriert: Sonntag 12. Februar 2023, 18:46

__blackjack__ hat geschrieben: Samstag 24. Juni 2023, 11:09 @Jinpachu: Das IF … GOTO springt ja nur wenn die Bedingung erfüllt ist, ansonsten geht es einfach mit dem nächsten Befehl weiter. Bei den Fragezeichen muss 4.2.2.2.2 stehen.

In das BASIC-Program liesse sich ganz einfach eine Tracing-Ausgabe einbauen. Die Hälfte (Ausgabe des aktuellen Befehls) ist da schon, nur auskommentiert. Hatte ich zu Testzwecken drin, weil ich mich an einer Stelle beim „instruction counter“ IP vertippt hatte und deswegen GOTO nicht funktionierte.
Das heißt, wenn ich in diesem Beispiel zu punkt 4 zurück springe und die Bedingung nicht erfüllt ist, schreibe ich dann einfach den nächsten Wert also 4.2.2.2.2 hin und das Programm ist dann fertig?
Qubit
User
Beiträge: 130
Registriert: Dienstag 7. Oktober 2008, 09:07

Jinpachu hat geschrieben: Samstag 24. Juni 2023, 11:47 Das heißt, wenn ich in diesem Beispiel zu punkt 4 zurück springe und die Bedingung nicht erfüllt ist, schreibe ich dann einfach den nächsten Wert also 4.2.2.2.2 hin und das Programm ist dann fertig?
Am Besten schaust du dir mal die Zustände an und vollziehst das dann daran nach..

Code: Alles auswählen

state: [1, 0, 2, 3, 0]
state: [2, 1, 2, 3, 0]
state: [3, 1, 2, 3, 1]
state: [4, 3, 2, 3, 1]
state: [5, 3, 2, 3, 1]
state: [6, 1, 2, 3, 1]
state: [7, 2, 2, 3, 1]
state: [8, 2, 2, 3, 2]
state: [9, 3, 2, 3, 2]
state: [10, 2, 2, 3, 2]
state: [11, 2, 2, 2, 2]
state: [4, 2, 2, 2, 2]
state: [5, 2, 2, 2, 2]
state: [6, 2, 2, 2, 2]
state: [7, 4, 2, 2, 2]
state: [8, 4, 2, 2, 4]
state: [9, 2, 2, 2, 4]
state: [10, 1, 2, 2, 4]
state: [11, 1, 2, 1, 4]
state: [4, 1, 2, 1, 4]
state: [5, 1, 2, 1, 4]
state: [6, 4, 2, 1, 4]
state: [7, 8, 2, 1, 4]
state: [8, 8, 2, 1, 8]
state: [9, 1, 2, 1, 8]
state: [10, 0, 2, 1, 8]
state: [11, 0, 2, 0, 8]
state: [4, 0, 2, 0, 8]
state: [12, 0, 2, 0, 8]
Jinpachu
User
Beiträge: 8
Registriert: Sonntag 12. Februar 2023, 18:46

Qubit hat geschrieben: Samstag 24. Juni 2023, 12:18
Jinpachu hat geschrieben: Samstag 24. Juni 2023, 11:47 Das heißt, wenn ich in diesem Beispiel zu punkt 4 zurück springe und die Bedingung nicht erfüllt ist, schreibe ich dann einfach den nächsten Wert also 4.2.2.2.2 hin und das Programm ist dann fertig?
Am Besten schaust du dir mal die Zustände an und vollziehst das dann daran nach..

Code: Alles auswählen

state: [1, 0, 2, 3, 0]
state: [2, 1, 2, 3, 0]
state: [3, 1, 2, 3, 1]
state: [4, 3, 2, 3, 1]
state: [5, 3, 2, 3, 1]
state: [6, 1, 2, 3, 1]
state: [7, 2, 2, 3, 1]
state: [8, 2, 2, 3, 2]
state: [9, 3, 2, 3, 2]
state: [10, 2, 2, 3, 2]
state: [11, 2, 2, 2, 2]
state: [4, 2, 2, 2, 2]
state: [5, 2, 2, 2, 2]
state: [6, 2, 2, 2, 2]
state: [7, 4, 2, 2, 2]
state: [8, 4, 2, 2, 4]
state: [9, 2, 2, 2, 4]
state: [10, 1, 2, 2, 4]
state: [11, 1, 2, 1, 4]
state: [4, 1, 2, 1, 4]
state: [5, 1, 2, 1, 4]
state: [6, 4, 2, 1, 4]
state: [7, 8, 2, 1, 4]
state: [8, 8, 2, 1, 8]
state: [9, 1, 2, 1, 8]
state: [10, 0, 2, 1, 8]
state: [11, 0, 2, 0, 8]
state: [4, 0, 2, 0, 8]
state: [12, 0, 2, 0, 8]
Danke jetzt habe ich es verstanden. Du Hast ein Fehler bei [6, 2, 2, 2, 2] hier musst du multiplizieren also c0 *c1. Das wäre 6.4.2.2.2
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jinpachu: Nee, das ist kein Fehler. Multipliziert wird ja erst in dem Befehl an Adresse 6. Das [6, 2, 2, 2, 2] ist aber der Zustand nach dem Befehl an Adresse 5, bevor der an Adresse 6 ausgeführt wird. Ich habe das BASIC-Programm mal auf GW-BASIC portiert, da kann man dann auch WHILE und ELSE verwenden, und da das „tracing“ eingebaut was in der vorherigen Version nur angedeutet ist:

Code: Alles auswählen

10 DEFINT A-Z:T=-1:REM Trace flag. If true (-1) print execution trace.
20 DIM IN$(8),I(100),O(100),C(3):FOR I=1 TO 8:READ IN$(I):NEXT
30 PRINT"Compiling..."
40 READ IC:IF IC=-1 THEN 70
50 READ C$,O(IC):F=0:FOR I=1 TO 8:F=IN$(I)=C$:IF F THEN I(IC)=I:I=8
60 NEXT:IF F THEN 40 ELSE PRINT"Unknown instruction at";IC,C$:END
70 PRINT"Run configurations...":READ CN:FOR I=1 TO CN
80 READ IC,C(0),C(1),C(2),C(3):H=0:WHILE NOT H
90 IF T THEN PRINT IC;IN$(I(IC));O(IC);TAB(22);"->";
100 ON I(IC) GOSUB 130,140,150,160,170,180,190,200:IC=IC+1:IF T THEN GOSUB 120
110 WEND:GOSUB 120:NEXT:END
120 PRINT USING"### ### ### ### ###";IC;C(0);C(1);C(2);C(3):RETURN
130 H=-1:RETURN:REM END
140 C(0)=O(IC):RETURN:REM CLOAD
150 C(0)=C(O(IC)):RETURN:REM LOAD
160 C(O(IC))=C(0):RETURN:REM STORE
170 C(0)=C(0)-O(IC):RETURN:REM CSUB
180 C(0)=C(0)*C(O(IC)):RETURN:REM MULT
190 IC=O(IC)-1:RETURN:REM GOTO
200 IF C(0)=0 THEN 190 ELSE RETURN:REM IF C0 = 0 GOTO
210 REM INSTRUCTION NAMES.
220 DATA END,CLOAD,LOAD,STORE,CSUB,MULT,GOTO,IF C0 = 0 GOTO
230 REM THE PROGRAM.
240 DATA 1,CLOAD,1
250 DATA 2,STORE,3
260 DATA 3,LOAD,2
270 DATA 4,IF C0 = 0 GOTO,12
280 DATA 5,LOAD,3
290 DATA 6,MULT,1
300 DATA 7,STORE,3
310 DATA 8,LOAD,2
320 DATA 9,CSUB,1
330 DATA 10,STORE,2
340 DATA 11,GOTO,4
350 DATA 12,END,0
360 DATA -1
370 REM THE CONFIGURATIONS TO TEST.
380 DATA 3
390 DATA 1,0,2,1,0
400 DATA 1,0,2,3,0
410 DATA 1,0,2,5,0
Unter DOS kann man die Ausgabe dann leicht in eine Datei umleiten. Hier der Ausschnitt für die zweite Konfiguration:

Code: Alles auswählen

 1 CLOAD 1           ->  2   1   2   3   0
 2 STORE 3           ->  3   1   2   3   1
 3 LOAD 2            ->  4   3   2   3   1
 4 IF C0 = 0 GOTO 12 ->  5   3   2   3   1
 5 LOAD 3            ->  6   1   2   3   1
 6 MULT 1            ->  7   2   2   3   1
 7 STORE 3           ->  8   2   2   3   2
 8 LOAD 2            ->  9   3   2   3   2
 9 CSUB 1            -> 10   2   2   3   2
 10 STORE 2          -> 11   2   2   2   2
 11 GOTO 4           ->  4   2   2   2   2
 4 IF C0 = 0 GOTO 12 ->  5   2   2   2   2
 5 LOAD 3            ->  6   2   2   2   2
 6 MULT 1            ->  7   4   2   2   2
 7 STORE 3           ->  8   4   2   2   4
 8 LOAD 2            ->  9   2   2   2   4
 9 CSUB 1            -> 10   1   2   2   4
 10 STORE 2          -> 11   1   2   1   4
 11 GOTO 4           ->  4   1   2   1   4
 4 IF C0 = 0 GOTO 12 ->  5   1   2   1   4
 5 LOAD 3            ->  6   4   2   1   4
 6 MULT 1            ->  7   8   2   1   4
 7 STORE 3           ->  8   8   2   1   8
 8 LOAD 2            ->  9   1   2   1   8
 9 CSUB 1            -> 10   0   2   1   8
 10 STORE 2          -> 11   0   2   0   8
 11 GOTO 4           ->  4   0   2   0   8
 4 IF C0 = 0 GOTO 12 -> 12   0   2   0   8
 12 END 0            -> 13   0   2   0   8
Das entspricht den „state:“-Ausgaben von Qubit.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und hier der Emulator für die Registermaschine mal näher an der Registermaschine implementiert. In Assembler für den 6510-Prozessor im C64. Der Quelltext ist deutlich länger als die BASIC-Implementierungen, das Ergebnis aber deutlich kürzer. Emulator inklusive Start-Adresse, BASIC-Startzeile, emuliertem Programm, und den drei Konfigurationen passen in 236 Bytes.

Code: Alles auswählen

;--------------------------------------
; The instruction codes.
i_end   = 0
i_cload         = 1
i_load  = 2
i_store         = 3
i_csub  = 4
i_mult  = 5
i_goto  = 6
i_if_0_goto     = 7

;--------------------------------------
tmp     = $02   ; 1 byte.
ptr     = $9e   ; 2 bytes.

is_halted = $b0 ; 1 byte.
ic      = $b1   ; 1 byte.
registers = $b2 ; 4 bytes.

config_no = $f7 ; 1 byte.

;--------------------------------------
        *= $0801

        .word prgend, 2023
        .text $9e,"2061",0
prgend  .word 0

start   lda #0
        sta config_no
        
        lda #<configs
        sta ptr
        lda #>configs
        sta ptr+1
mainloop
        inc config_no
        lda config_no
        cmp #config_count+1
        beq done
        
        ldy #config_len-1 ; copy config
cc      lda (ptr),y
        sta ic,y
        dey
        bpl cc
        clc     ; ptr += config_len
        lda ptr
        adc #config_len
        sta ptr
        bcc *+4
        inc ptr+1
        
        lda #0
        sta is_halted
runloop
        lda ic  ; x = offset into
        asl     ; program.
        tax     ; y = operand
        lda program+1,x
        tay
        lda program,x ; execute opcode
        tax
        lda instruction_lo,x
        sta mod+1
        lda instruction_hi,x
        sta mod+2
mod     jsr $ffff

        inc ic
        lda is_halted
        beq runloop
        
        lda #0  ; Print config.
        sta tmp
pc0     ldy tmp
        cpy #config_len
        beq pc1
        ldx ic,y
        lda #0
        jsr $bdcd
        lda #" "
        jsr $ffd2
        inc tmp
        bne pc0
pc1     lda #13
        jsr $ffd2
        
        jmp mainloop

done    rts

;--------------------------------------
; Instructions
; Get called with the operand in Y.

end     inc is_halted
        rts
;--------------------------------------
cload   sty registers+0
        rts
;--------------------------------------
load    lda registers,y
        sta registers+0
        rts
;--------------------------------------
store   lda registers+0
        sta registers,y
        rts
;--------------------------------------
csub    lda registers+0
        sty tmp
        sec
        sbc tmp
        sta registers+0
        rts
;--------------------------------------
mult    lda registers,y
        beq mult1
        
        tay
        lda #0
mult0   clc
        adc registers+0
        dey
        bne mult0
        
mult1   sta registers+0
        rts

;--------------------------------------
goto    dey
        sty ic
        rts
;--------------------------------------
if_0_goto
        lda registers+0
        beq goto
        rts

;--------------------------------------
instruction_lo
        .byte <end,<cload,<load,<store
        .byte <csub,<mult,<goto
        .byte <if_0_goto
instruction_hi
        .byte >end,>cload,>load,>store
        .byte >csub,>mult,>goto
        .byte >if_0_goto

;--------------------------------------
; Two bytes per instruction, first
; opcode, second operand.
program
        .byte 0,0               ; 0
        .byte i_cload,1         ; 1
        .byte i_store,3         ; 2
        .byte i_load,2          ; 3
        .byte i_if_0_goto,12    ; 4
        .byte i_load,3          ; 5
        .byte i_mult,1          ; 6
        .byte i_store,3         ; 7
        .byte i_load,2          ; 8
        .byte i_csub,1          ; 9
        .byte i_store,2         ; 10
        .byte i_goto,4          ; 11
        .byte i_end,0           ; 12

configs
        .byte 1,0,2,1,0
config_len = *-configs
        .byte 1,0,2,3,0
        .byte 1,0,2,5,0
config_count = *-configs/config_len
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
__blackjack__
User
Beiträge: 14056
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch mal der Emulator in Code für eine andere Registermaschine, den 8086, dessen (kompatiblen) grosse Geschwister bei vielen im aktuellen PC werkeln. Ist mit 237 Bytes nur ein Byte länger als die 6510-Variante. Hier musste aber auch die Zahlenausgabe selbst programmiert werden, statt auf eine fertige Routine im ROM zurückgreifen zu können.

Code: Alles auswählen

    cpu 8086
    org 100h

END         equ 0
CLOAD       equ 1
LOAD        equ 2
STORE       equ 3
CSUB        equ 4
MULT        equ 5
GOTO        equ 6
IF_0_GOTO   equ 7

regs_count  equ 4

;--------------------------------------
start:
    cld
    mov     cx, config_count
    mov     si, configurations

config_loop:
    push    cx
    ;
    ; Copy configuration.
    ;
    mov     di, instruction_counter
    mov     cx, config_size
    rep movsb
    push    si
    ;
    ; Run configuration.
    ;
    ; `instruction_counter` is not updated!
    ;
    ; BX = operand (BH must stay 0 all the time!)
    ; DL = `is_halted`
    ; SI = address of the instruction to be executed.
    ;
    xor     dl, dl      ; un-halt machine.
    
    mov     bl, [instruction_counter]    ; GOTO instruction_counter
    xor     bh, bh      ; BH = 0.  Must stay 0.
    call    goto

run_loop:
    or      dl, dl      ; Check for halt.
    jnz     halted

    lodsw               ; BX = operand, DI = offset into instruction jump table.
    mov     bl, ah
    xor     ah, ah
    mov     di, ax
    shl     di, 1
    
    call    [instructions+di]
    jmp     run_loop
    
halted:
    ;
    ; Print configuration.
    ;
    mov     ax, si      ; AX = instruction counter
    sub     ax, program
    shr     ax, 1
    
    call    print_number
    ;
    ; Print registers.
    ;
    mov     cx, regs_count
    mov     si, regs
.L:
    lodsb
    xor     ah, ah
    push    cx
    call    print_number
    pop     cx
    loop    .L
    
    mov     ah, 9       ; Newline.
    mov     dx, crlf
    int     21h

    pop     si          ; SI = pointer to next configuration.
    pop     cx          ; CX = configuration loop counter
    loop    config_loop
    
    ret

;--------------------------------------
; In AX = number to print.
; Changes: AX, CX, DX
print_number:
    xor     cx, cx      ; CX to count the decimal digits pushed to the stack.
    mov     bx, 10      ; Base 10.
.loop_1:
    xor     dx, dx      ; AX := AX/DX DIV 10; DX := AX/DX MOD 10
    div     bx
    or      dl, '0'     ; Push remainder as ASCII digit to the stack.
    push    dx
    inc     cx          ; Increase digit counter.
    
    or      ax, ax      ; Are we done?
    jnz      .loop_1

    mov     dx, " "     ; Leading space.
    push    dx
    inc     cx
    
    mov     ah, 2       ; Print CX digits from stack.
.loop_2:
    pop     dx
    int     21h
    loop    .loop_2

    ret

;--------------------------------------
; Instructions.
;
; In: BX = operand.
; Out: DL = `is_halted` flag.
; Changes: AX, SI, regs

end:
    inc     dl
    ret

cload:
    mov     [regs+0], bl
    ret

load:
    mov     al, [regs+bx]
    mov     [regs+0], al
    ret

store:
    mov     al, [regs+0]
    mov     [regs+bx], al
    ret

csub:
    mov     al, [regs+0]
    sub     al, bl
    mov     [regs+0], al
    ret

mult:
    mov     al, [regs+0]
    mul     byte [regs+bx]
    mov     [regs+0], al
    ret

goto:
    mov     si, bx
    shl     si, 1
    add     si, program
    ret

if_0_goto:
    mov     al, [regs+0]
    or      al, al
    jz      goto
    ret

instructions:
    dw end, cload, load, store, csub, mult, goto, if_0_goto

;--------------------------------------
crlf:
    db 13, 10, '$'

program:
    db 0, 0
    db CLOAD, 1         ; 1
    db STORE, 3         ; 2
    db LOAD, 2          ; 3
    db IF_0_GOTO, 12    ; 4
    db LOAD, 3          ; 5
    db MULT, 1          ; 6
    db STORE, 3         ; 7
    db LOAD, 2          ; 8
    db CSUB, 1          ; 9
    db STORE, 2         ; 10
    db GOTO, 4          ; 11
    db END, 0           ; 12

configurations:
    db 1, 0, 2, 1, 0
    db 1, 0, 2, 3, 0
    db 1, 0, 2, 5, 0
config_count    equ ($ - configurations) / config_size

;--------------------------------------
section .bss

instruction_counter:
    resb 1
regs:
    resb regs_count

config_size     equ $ - instruction_counter
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten