-
Notifications
You must be signed in to change notification settings - Fork 1
/
rammodel.py
132 lines (118 loc) · 5.54 KB
/
rammodel.py
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
import sys, re
# Define all the regular expressions
LABEL = r"([a-zA-Z0-9]*)"
REGISTER = r"[Rr]([0-9]{1,2})"
ARROW = r"\s*<-\s*"
MEMORY = r"mem\[" + REGISTER + r"\]"
LABEL_PATTERN = re.compile(LABEL + r":$")
REGISTER_SET_PATTERN = re.compile(REGISTER + ARROW + r"([0-9]*)$")
ARITHMETIC_PATTERN = re.compile(REGISTER + ARROW + REGISTER + r"\s*([\/\+\-\*])\s*" + REGISTER + r"$")
CONDITIONAL_PATTERN = re.compile(REGISTER + r"\s*([<=>])\s*" + REGISTER + r"\s*\?\s*" + LABEL + r"$")
MEMORY_SET_PATTERN = re.compile(MEMORY + ARROW + REGISTER + r"$")
MEMORY_GET_PATTERN = re.compile(REGISTER + ARROW + MEMORY + r"$")
class RAMModel:
def __init__(self, filename):
with open(filename) as f:
# read file to string array called lines and remove leading/trailing whitespace
lines = [l.split("//")[0].strip() for l in f.read().splitlines()]
# get the initial memory from the first line
self._memory = [int(x) & 0xffffffff for x in lines[0].split()]
# remove the first line which is no longer needed
self._code = lines[1:]
# this will store any branches to return to
self._branches = {}
for line_num in range(len(self._code)):
c = self._code[line_num]
match = LABEL_PATTERN.match(c)
if match:
self._branches[match.group(1)] = line_num
self._program_counter = 0
self._registers = [0] * 32
self._running_time = 0
def display_vals(self):
print("Register Values: " + ' '.join(str(n) for n in self._registers))
print("Memory Values: " + ' '.join(str(n) for n in self._memory))
print("Running Time: " + str(self._running_time))
def interpret_instruction(self):
line = self._code[self._program_counter]
register_set_match = REGISTER_SET_PATTERN.match(line)
arithmetic_match = ARITHMETIC_PATTERN.match(line)
conditional_match = CONDITIONAL_PATTERN.match(line)
memory_set_match = MEMORY_SET_PATTERN.match(line)
memory_get_match = MEMORY_GET_PATTERN.match(line)
if register_set_match:
self.set_register(register_set_match.group(1), register_set_match.group(2))
elif arithmetic_match:
self.arithmetic(arithmetic_match.group(1), arithmetic_match.group(2), arithmetic_match.group(3), arithmetic_match.group(4))
elif conditional_match:
self.conditional(conditional_match.group(1), conditional_match.group(2), conditional_match.group(3), conditional_match.group(4))
elif memory_set_match:
self.mem_set(memory_set_match.group(1), memory_set_match.group(2))
elif memory_get_match:
self.mem_get(memory_get_match.group(2), memory_get_match.group(1))
else:
self._program_counter += 1
def set_register(self, reg_num, value):
reg_num = int(reg_num)
value = int(value) & 0xffffffff
if 0 <= reg_num < 32:
self._registers[reg_num] = value
self._program_counter += 1
self._running_time += 1
def arithmetic(self, reg_store, reg_lhs, operation, reg_rhs):
reg_store = int(reg_store)
reg_lhs = int(reg_lhs)
reg_rhs = int(reg_rhs)
if 0 <= reg_store < 32 and 0 <= reg_lhs < 32 and 0 <= reg_rhs < 32:
lhs = self._registers[reg_lhs]
rhs = self._registers[reg_rhs]
if operation == '/' and rhs == 0:
print("Division by zero on line " + self._program_counter + ": " + self._code[self._program_counter])
else:
# evaluate result of expression
self._registers[reg_store] = int(eval(str(lhs) + operation + str(rhs))) & 0xffffffff
self._program_counter += 1
self._running_time += 1
def conditional(self, reg_lhs, comparison, reg_rhs, label):
reg_lhs = int(reg_lhs)
reg_rhs = int(reg_rhs)
if (0 <= reg_lhs < 32) and (0 <= reg_rhs < 32) and (label in self._branches):
if comparison == "=":
comparison = "=="
lhs = self._registers[reg_lhs]
rhs = self._registers[reg_rhs]
result = eval(str(lhs) + comparison + str(rhs))
if result:
self._program_counter = self._branches[label]
else:
self._program_counter += 1
self._running_time += 1
def mem_set(self, reg_address, reg_value):
reg_address = int(reg_address)
reg_value = int(reg_value)
if 0 <= reg_address < 32 and 0 <= reg_value < 32:
address = self._registers[reg_address]
value = self._registers[reg_value]
if (address >= len(self._memory)):
difference = address - (len(self._memory) - 1)
self._memory += [0] * difference
self._memory[address] = value
self._program_counter += 1
self._running_time += 1
def mem_get(self, reg_address, reg_store):
reg_address = int(reg_address)
reg_store = int(reg_store)
if 0 <= reg_address < 32 and 0 <= reg_store < 32:
address = self._registers[reg_address]
if (address >= len(self._memory)):
difference = address - (len(self._memory) - 1)
self._memory += [0] * difference
self._registers[reg_store] = self._memory[address]
self._program_counter += 1
self._running_time += 1
def run(self):
while self._program_counter < len(self._code):
self.interpret_instruction()
self.display_vals()
model = RAMModel(sys.argv[1])
model.run()