Jon Michael Aanes
6334d183dd
Moved the test case to its own file. Allowed the emulator to be iterated over. Minor fixes and such.
205 lines
6.4 KiB
Python
205 lines
6.4 KiB
Python
|
|
import re
|
|
import sys
|
|
|
|
REGISTERS=["%rip","%rbp","%rsp","","%rax","%rdi","%r8","%r9"]
|
|
REG_STATUS_TO_COLOR = {"insert":"green","change":"yellow","remove":"red"}
|
|
|
|
class Emulator:
|
|
|
|
def __init__ (self, source_text):
|
|
self.registers = {}
|
|
for reg_name in REGISTERS:
|
|
self.registers[reg_name] = 0
|
|
self.stack = {}
|
|
self.code = []
|
|
self.codep = []
|
|
self.linesExec = []
|
|
self.labels = {}
|
|
self.changes = {}
|
|
self.status = {}
|
|
self.text = ""
|
|
self.x_coord = 0
|
|
self.last_sp = 0
|
|
self.max_stack_size = 0
|
|
index = 0
|
|
for line in iter(source_text.splitlines()):
|
|
index = self.processSourceLine(line, index)
|
|
|
|
def setStack (self, *stack_list):
|
|
i = 0
|
|
for element in stack_list:
|
|
self.stack[i] = element
|
|
i += 1
|
|
|
|
def setRegs (self, **reg_dict):
|
|
for reg_name, reg_val in reg_dict.iteritems():
|
|
self.registers["%"+reg_name] = reg_val
|
|
|
|
def getVal (self, val_text):
|
|
if val_text[0] == "$":
|
|
return int(val_text[1:])
|
|
elif val_text[0] == "%":
|
|
return self.registers[val_text]
|
|
else:
|
|
raise "NOT A VALUE! UGHGUIHGUE!"
|
|
|
|
def compareVal (self, valT1, valT2):
|
|
val1 = self.getVal(valT2)
|
|
val2 = self.getVal(valT1)
|
|
self.status = {"g":val1>val2}
|
|
|
|
def changedRegisters (self, *args):
|
|
for reg, val in args:
|
|
self.changes[reg] = val
|
|
|
|
def processSourceLine(self, line_text, index):
|
|
tokens = re.findall(r'[\w%:$#]+', line_text)
|
|
if len(tokens) <= 0:
|
|
return index
|
|
if tokens[0][-1] == ':':
|
|
self.labels[tokens[0][:-1]] = index
|
|
tokens = tokens[1:]
|
|
for i in range(len(tokens)):
|
|
if tokens[i][0] == "#":
|
|
tokens = tokens[:i]
|
|
break
|
|
self.code.append(tokens)
|
|
self.codep.append(line_text)
|
|
return index + 1
|
|
|
|
def getRegColor (self, reg_name):
|
|
if reg_name in self.changes:
|
|
return REG_STATUS_TO_COLOR[self.changes[reg_name]]
|
|
else:
|
|
return "black"
|
|
|
|
def getLineSignature (self, line_nr):
|
|
return [ "\\"+token if token[0]=="$" or token[0]=="%" else token for token in self.code[line_nr] ]
|
|
|
|
def draw (self, x, line_nr=None):
|
|
x = str(x)
|
|
text = ""
|
|
pos = 0
|
|
for reg_name in REGISTERS:
|
|
reg_dect = "register_node, fill=" + self.getRegColor(reg_name)+"!10"
|
|
if reg_name != "":
|
|
text += "\t\\node["+reg_dect+"]("+reg_name[1:]+") at ("+x+", "+str(pos)+"){"+str(self.registers[reg_name])+"};\n"
|
|
pos -= 0.5
|
|
|
|
pos -= 1
|
|
base_sp = max(self.last_sp,self.registers['%rsp'])
|
|
if self.last_sp - 1 == self.registers['%rsp']:
|
|
pos += 0.5
|
|
for index in range(base_sp, -1,-1):
|
|
mem_name = "m"+str(index)
|
|
reg_dect = "register_node, fill=" + self.getRegColor(mem_name)+"!10"
|
|
text += "\t\\node["+reg_dect+"]("+mem_name+") at ("+x+", "+str(pos)+"){"+str(self.stack[index])+"};\n"
|
|
pos -= 0.5
|
|
|
|
if line_nr != None:
|
|
pos = 2
|
|
signature = self.getLineSignature(line_nr)
|
|
try:
|
|
for i in range(3):
|
|
text += "\t\\node[text_node]() at ("+str(float(x)-1.25)+", "+str(pos)+"){"+signature[i]+"};\n"
|
|
pos -= 0.5
|
|
except:
|
|
pass
|
|
#for line_nr in self.linesExec:
|
|
# text += "\t\\node[text_node]() at ("+x+", "+str(pos)+"){"+self.codep[line_nr]+"};\n"
|
|
self.linesExec = []
|
|
|
|
return text
|
|
|
|
def drawRegs (self, line_nr=None):
|
|
self.text += self.draw((self.x_coord+1)*2.5-0.5, line_nr)
|
|
self.text += "\n"
|
|
self.x_coord += 1
|
|
|
|
def drawNames (self, x, stack_size=8):
|
|
x = str(x)
|
|
text = ""
|
|
pos = 0
|
|
for reg_name in REGISTERS:
|
|
text += "\t\\node[text_node]("+reg_name[1:]+") at ("+x+", "+str(pos)+"){"+reg_name[1:]+"};\n"
|
|
pos -= 0.5
|
|
|
|
text += "\t\\node[text_node]() at ("+x+", "+str(pos-0.5)+"){TOS+1};\n"
|
|
text += "\t\\node[text_node]() at ("+x+", "+str(pos-1)+"){TOS};\n"
|
|
pos -= 1.5
|
|
for index in range(1,stack_size+1):
|
|
mem_name = "m"+str(index)
|
|
text += "\t\\node[text_node]() at ("+x+", "+str(pos)+"){TOS-"+str(index)+"};\n"
|
|
pos -= 0.5
|
|
|
|
return text
|
|
|
|
def iterate (self):
|
|
old_rip = self.registers['%rip']
|
|
self.last_sp = self.registers['%rsp']
|
|
#self.linesExec.append(old_rip)
|
|
if self.registers['%rip'] >= len(self.code):
|
|
return False
|
|
instruct = self.code[self.registers['%rip']]
|
|
opcode = instruct[0]
|
|
self.changes = {}
|
|
if opcode == "push" or opcode == "pushq":
|
|
self.registers['%rsp'] = self.registers['%rsp'] + 1
|
|
self.stack[self.registers['%rsp']] = self.registers[instruct[1]]
|
|
self.changedRegisters(('%rsp',"change"),("m"+str(self.registers['%rsp']),"insert"))
|
|
self.max_stack_size = max(self.registers['%rsp'], self.max_stack_size)
|
|
elif opcode == "popq":
|
|
self.registers[instruct[1]] = self.stack[self.registers['%rsp']]
|
|
self.registers['%rsp'] = self.registers['%rsp'] - 1
|
|
self.changedRegisters(('%rsp',"change"),("m"+str(self.registers['%rsp']+1),"remove"))
|
|
elif opcode == "movq" or opcode == "mov":
|
|
self.changedRegisters((instruct[2],"change"))
|
|
self.registers[instruct[2]] = self.getVal(instruct[1])
|
|
elif opcode == "cmpq":
|
|
self.compareVal(instruct[1],instruct[2])
|
|
elif opcode == "addq":
|
|
self.changedRegisters((instruct[2],"change"))
|
|
self.registers[instruct[2]] = self.getVal(instruct[2]) + self.getVal(instruct[1])
|
|
elif opcode == "subq":
|
|
self.changedRegisters((instruct[2],"change"))
|
|
self.registers[instruct[2]] = self.getVal(instruct[2]) - self.getVal(instruct[1])
|
|
elif opcode == "jg":
|
|
if self.status["g"]:
|
|
self.registers['%rip'] = self.labels[instruct[1]]
|
|
elif opcode == "jmp":
|
|
self.registers['%rip'] = self.labels[instruct[1]]
|
|
|
|
elif opcode == "call":
|
|
self.registers['%rsp'] = self.registers['%rsp'] + 1
|
|
self.stack[self.registers['%rsp']] = self.registers['%rip']+1
|
|
self.registers['%rip'] = self.labels[instruct[1]]
|
|
self.changedRegisters(('%rsp',"change"),("m"+str(self.registers['%rsp']),"insert"))
|
|
self.max_stack_size = max(self.registers['%rsp'], self.max_stack_size)
|
|
elif opcode == "leave":
|
|
self.registers["%rsp"] = self.registers["%rbp"]
|
|
self.registers["%rbp"] = self.stack[self.registers['%rsp']]
|
|
self.registers['%rsp'] = self.registers['%rsp'] - 1
|
|
self.changedRegisters(('%rbp',"change"))
|
|
self.changedRegisters(('%rsp',"change"),("m"+str(self.registers['%rsp']+1),"remove"))
|
|
elif opcode == "ret":
|
|
self.registers['%rip'] = self.stack[self.registers['%rsp']]
|
|
self.registers['%rsp'] = self.registers['%rsp'] - 1
|
|
self.changedRegisters(('%rsp',"change"),("m"+str(self.registers['%rsp']+1),"remove"))
|
|
|
|
if self.registers['%rip'] == old_rip:
|
|
self.registers['%rip'] += 1
|
|
else:
|
|
self.changedRegisters(('%rip',"change"))
|
|
|
|
self.drawRegs(old_rip)
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def next(self):
|
|
if self.iterate() == False:
|
|
raise StopIteration()
|
|
else:
|
|
return self
|