-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpu.py
More file actions
174 lines (150 loc) · 6.97 KB
/
cpu.py
File metadata and controls
174 lines (150 loc) · 6.97 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
class CPU:
KERNEL = 0x00
USER = 0x01
MASK = 0xFFFFFFFF
MSB = 0x80000000
def __init__(self, mmu):
self.MMU = mmu
self.mode = self.KERNEL
self.registers = {
# general purpose
"r0": 0, # register 1
"r1": 0, # register 2
"r2": 0, # register 3
"r3": 0, # register 4
"r4": 0, # register 5
"r5": 0, # register 6
"r6": 0, # register 7
"r7": 0, # register 8
# reserved
"sp": 0, # stack pointer
"fp": 0, # frame pointer
"pc": 0, # program counter
"l0": 0, # loop counter
"i0": 0, # index counter
"b0": 1, # bytesize write/read
# flags
"fz": 0, # flag [zero]
"fc": 0, # flag [carry]
"fn": 0, # flag [negative]
"fo": 0, # flag [overflow]
# codes
"c0": 0xFF # process code
}
def validate_register(self, register:int) -> bool:
if f"r{register}" not in self.registers:
self.registers["c0"] = 0xBB
return False
return True
def validate_registers(self, *registers:int) -> bool:
for reg in registers:
if not self.validate_register(reg):
self.registers["c0"] = 0xBB # invalid register
return False
return True
def step(self, process):
opcode = self.MMU.read_uint8(process, self.registers["pc"])
self.registers["pc"] += 1
match opcode:
case 0x00: #? [HALT]
if self.mode != self.KERNEL:
self.registers["c0"] = 0xAA # Protection error
else:
self.registers["c0"] = 0x00 # Halt signal
case 0x01: #? [MOV] [rX] [immediate] : moves immediate to rX
reg = self.MMU.read_uint8(process, self.registers["pc"])
self.registers["pc"] += 1
if not self.validate_register(reg):
return
bytesize = self.registers.get("b0", 1)
value = 0
for i in range(bytesize):
byte = self.MMU.read_uint8(process, self.registers["pc"] + i)
value |= (byte << (8 * i)) # little-endian
self.registers["pc"] += bytesize
self.registers[f"r{reg}"] = value
self.registers["c0"] = 0xFF
case 0x02: #? [ADD] [rX] [rY] : add rY to rX
reg_x = self.MMU.read_uint8(process, self.registers["pc"])
reg_y = self.MMU.read_uint8(process, self.registers["pc"]+1)
self.registers["pc"] += 2
if not self.validate_registers(reg_x, reg_y):
return
x = self.registers[f"r{reg_x}"]
y = self.registers[f"r{reg_y}"]
result_full = x + y
result = result_full & self.MASK
self.registers[f"r{reg_x}"] = result
self.registers["fz"] = int(result == 0)
self.registers["fn"] = int(result & self.MSB != 0)
self.registers["fc"] = int(result_full >> 32)
self.registers["fo"] = int(((x ^ result) & (y ^ result) & self.MSB) != 0)
case 0x03: #? [PUSH] [rX] : push from register to memory
reg = self.MMU.read_uint8(process, self.registers["pc"])
self.registers["pc"] += 1
if not self.validate_register(reg):
return
bytesize = self.registers.get("b0", 1)
value = self.registers[f"r{reg}"]
self.registers["sp"] -= bytesize
for i in range(bytesize):
self.MMU.write_uint8(process, self.registers["sp"] + i, (value >> (8 * i)) & 0xFF)
print(f"pid {process.pid} pushed {bytesize} bytes to memory")
self.registers["c0"] = 0xFF
case 0x04: #? [POP] [rX] : pop from memory to register
reg = self.MMU.read_uint8(process, self.registers["pc"])
self.registers["pc"] += 1
if not self.validate_register(reg):
return
bytesize = self.registers.get("b0", 1)
value = 0
for i in range(bytesize):
byte = self.MMU.read_uint8(process, self.registers["sp"] + i)
value |= byte << (8 * i) # little-endian
print(f"pid {process.pid} popped {bytesize} bytes from memory")
self.registers[f"r{reg}"] = value
self.registers["sp"] += bytesize
self.registers["c0"] = 0xFF
case 0x05: #? [SET] b0 [immediate] : sets b0 to byte size to work with
value = self.MMU.read_uint8(process, self.registers["pc"])
self.registers["pc"] += 1
self.registers["b0"] = value
self.registers["c0"] = 0xFF
case 0x06: #? [CALL] [addr] : call subroutine at addr
bytesize = self.registers.get("b0", 2)
addr = 0
for i in range(bytesize):
byte = self.MMU.read_uint8(process, self.registers["pc"] + i)
addr |= (byte << (8 * i)) # little-endian
self.registers["pc"] += bytesize
ret_addr = self.registers["pc"]
self.registers["sp"] -= bytesize
for i in range(bytesize):
self.MMU.write_uint8(process, self.registers["sp"] + i, (ret_addr >> (8 * i)) & 0xFF)
self.registers["pc"] = addr
self.registers["c0"] = 0xFF
case 0x07: #? [RET] : return from subroutine
bytesize = self.registers.get("b0", 2)
ret_addr = 0
for i in range(bytesize):
byte = self.MMU.read_uint8(process, self.registers["sp"] + i)
ret_addr |= (byte << (8 * i))
self.registers["sp"] += bytesize
self.registers["pc"] = ret_addr
self.registers["c0"] = 0xFF
case 0x08: #? [MOVR] [rX] [rY] : move rY to rX
reg_x = self.MMU.read_uint8(process, self.registers["pc"])
reg_y = self.MMU.read_uint8(process, self.registers["pc"]+1)
self.registers["pc"] += 2
if not self.validate_registers(reg_x, reg_y):
return
self.registers[f"r{reg_x}"] = self.registers[f"r{reg_y}"]
self.registers["c0"] = 0xFF
case 0x10: #? [SYS] [rX] : syscall with code from rX
register = self.MMU.read_uint8(process, self.registers["pc"])
if not self.validate_register(register):
return
self.registers["pc"] += 1
self.registers["c0"] = 0xD0 + register
case _:
self.registers["c0"] = 0xCC # Unknown opcode