forked from jamil-said/code-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpuEmulator.py
More file actions
executable file
·138 lines (120 loc) · 5.42 KB
/
cpuEmulator.py
File metadata and controls
executable file
·138 lines (120 loc) · 5.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
""" cpuEmulator -- 20 min
SpaceX is testing flight software subroutines (i.e., programs that consist
of sequences of instructions) for a custom rocket CPU. To ensure that the
software runs correctly before it's loaded into the rocket, you need to
create a CPU simulator.
The CPU has 43 32-bit unsigned integer registers, which are named R00..R42.
At the start of the program, all the registers contain 0. The CPU supports
the following instructions:
MOV Rxx,Ryy - copies the value from register Rxx to register Ryy;
MOV d,Rxx - copies the numeric constant d (specified as a decimal) to
register Rxx;
ADD Rxx,Ryy - calculates (Rxx + Ryy) MOD 232 and stores the result in Rxx;
DEC Rxx - decrements Rxx by one. Decrementing 0 causes an overflow and
results in 232-1;
INC Rxx - increments Rxx by one. Incrementing 232-1 causes an overflow and
results in 0;
INV Rxx - performs a bitwise inversion of register Rxx;
JMP d - unconditionally jumps to instruction number d (1-based). d is
guaranteed to be a valid instruction number;
JZ d - jumps to instruction d (1-based) only if R00 contains 0;
NOP - does nothing.
After the last instruction has been executed, the contents of R42 are
considered to be the result of the subroutine.
Write a software emulator for this CPU that executes the subroutines and
returns the resulting value from R42.
All the commands in the subroutine are guaranteed to be syntactically
correct and have valid register numbers, numeric constants, and jump
addresses. The maximum program length is 1024 instructions. The maximum
total number of instructions that will be executed until the value is
returned is 5 · 104. (Keep in mind that the same instruction will be
counted as many times as it will be executed.)
Example, for
subroutine = [
"MOV 5,R00",
"MOV 10,R01",
"JZ 7",
"ADD R02,R01",
"DEC R00",
"JMP 3",
"MOV R02,R42"
]
the output should be
cpuEmulator(subroutine) = "50".
Here is the information about the CPU state after certain steps:
Step Last executed command Non-zero registers Comment
1 1. MOV 5,R00 R00 = 5 Put 5 into R00
2 2. MOV 10,R01 R00 = 5, R01 = 10 Put 10 into R01
3 3. JZ 7 R00 = 5, R01 = 10 Move to the next instruction because R00 ≠ 0
4 4. ADD R02,R01 R00 = 5, R01 = 10, R02 = 10 R02 += R01
5 5. DEC R00 R00 = 4, R01 = 10, R02 = 10 R00 -= 1
6 6. JMP 3 R00 = 4, R01 = 10, R02 = 10 Jump to instruction number 3, i.e. JZ 7
7 3. JZ 7 R00 = 4, R01 = 10, RO2 = 10 Move to the next instruction because R00 ≠ 0
Information about 11 steps is skipped
19 3. JZ 7 R00 = 1, R01 = 10, RO2 = 40 Move to the next instruction because R00 ≠ 0
20 4. ADD R02,R01 R00 = 1, R01 = 10, R02 = 50 R02 += R01
21 5. DEC R00 R00 = 0, R01 = 10, R02 = 50 R00 -= 1
22 6. JMP 3 R00 = 0, R01 = 10, R02 = 50 Jump to instruction number 3, i.e. JZ 7
23 3. JZ 7 R00 = 0, R01 = 10, R02 = 50 Jump to instruction number 7 because R00 = 0
24 7. MOV R02,R42 R00 = 0, R01 = 10, R02 = 50, R42 = 50 R42 += R02
The subroutine is exited
Input/Output
[execution time limit] 4 seconds (py3)
[input] array.string subroutine
Guaranteed constraints:
1 ≤ subroutine.length ≤ 1024.
[output] string
Return the resulting 32-bit unsigned integer, converted into a string.
"""
def cpuEmulator(subRtn):
cpu = [0] * 43
cur = [0]
dicCom = {'MOV': 1, 'ADD': 2, 'DEC': 3, 'INC': 4, 'INV': 5, 'JMP': 6,
'JZ': 7, 'NOP': 8}
def funMov(arg):
fst, scd = arg.split(',')[0], arg.split(',')[1]
scd = int(''.join(i for i in scd if i.isdigit()))
if fst.isdigit(): cpu[scd] = int(fst)
else: cpu[scd] = cpu[int(''.join(i for i in fst if i.isdigit()))]
def funAdd(arg):
fst, scd = arg.split(',')[0], arg.split(',')[1]
fst = int(''.join(i for i in fst if i.isdigit()))
scd = int(''.join(i for i in scd if i.isdigit()))
cpu[fst] = (cpu[fst]+cpu[scd])%(2**32)
def funDec(arg):
fst = int(''.join(i for i in arg if i.isdigit()))
if cpu[fst] == 0: cpu[fst] = (2**32)-1
else: cpu[fst] -= 1
def funInc(arg):
fst = int(''.join(i for i in arg if i.isdigit()))
if cpu[fst] == (2**32)-1: cpu[fst] = 0
else: cpu[fst] += 1
def funInv(arg):
fst = int(''.join(i for i in arg if i.isdigit()))
cpu[fst] = ~cpu[fst] + 2**32 #adds 2**32 due to unsigned 32-bit
def funJmp(arg):
fst = int(''.join(i for i in arg if i.isdigit()))
cur[0] = fst - 2 #increment in while loop + 1 based index
def funJz(arg):
fst = int(''.join(i for i in arg if i.isdigit()))
if cpu[0] == 0: cur[0] = fst - 2 #increment in while loop + 1 based index
while cur[0] < len(subRtn):
funN = dicCom[subRtn[cur[0]].split()[0]]
if funN == 1: funMov(subRtn[cur[0]].split()[1])
elif funN == 2: funAdd(subRtn[cur[0]].split()[1])
elif funN == 3: funDec(subRtn[cur[0]].split()[1])
elif funN == 4: funInc(subRtn[cur[0]].split()[1])
elif funN == 5: funInv(subRtn[cur[0]].split()[1])
elif funN == 6: funJmp(subRtn[cur[0]].split()[1])
elif funN == 7: funJz(subRtn[cur[0]].split()[1])
cur[0] += 1
return str(cpu[42])
print(cpuEmulator([
"MOV 5,R00",
"MOV 10,R01",
"JZ 7",
"ADD R02,R01",
"DEC R00",
"JMP 3",
"MOV R02,R42"
])) # '50'