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!
Registermaschiene Aufgabe lösen?
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ß.
"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ß.
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).
usw.
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)
...
- __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
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
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Jup, das ist echt super!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.

So kann man auch den Algorithmus und das Endergebnis direkt nachvollziehen:
c(3)_fin = c(1)_init ** c(2)_init
- __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
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:

https://daknuett.github.io/py_register ... hitecturepip install py-register-machine2
- __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
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?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).
usw.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) ...
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
- __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.
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
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?__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.
Am Besten schaust du dir mal die Zustände an und vollziehst das dann daran nach..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?
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.2Qubit hat geschrieben: Samstag 24. Juni 2023, 12:18Am Besten schaust du dir mal die Zustände an und vollziehst das dann daran nach..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?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]
- __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:
Unter DOS kann man die Ausgabe dann leicht in eine Datei umleiten. Hier der Ausschnitt für die zweite Konfiguration:
Das entspricht den „state:“-Ausgaben von Qubit.
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
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
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
- __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
- __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