def push_pop(instructions): """substitue push and pop macros with real instructions""" new_instructions = [] i = 0 while i < len(instructions): instruction = instructions[i] trace = instruction["trace"] if i < len(instructions) - 1: next_instruction = instructions[i + 1] else: # dummy instruction next_instruction = {"op": None} if instruction["op"] == "push": # push new_instructions.append({ "trace": trace, "op": "store", "literal": 0, "z": tos, "a": instruction["reg"], "comment": "push" }) new_instructions.append({ "trace": trace, "op": "addl", "z": tos, "a": tos, "literal": scaled_byte_addr(4) }) elif instruction["op"] == "pop": # pop new_instructions.append({ "trace": trace, "op": "addl", "z": tos, "a": tos, "literal": scaled_byte_addr(-4), "comment": "pop" }) new_instructions.append({ "trace": trace, "op": "load", "z": instruction["reg"], "a": tos }) else: new_instructions.append(instruction) i += 1 return new_instructions
def load_8(self, src_addr, is_signed): if scaled_byte_addr(4) != 4: raise Exception("cannot perform byte access") ret = self[src_addr] if is_signed and ret & 0x80 != 0: return ret | 0xffffff00 return ret
def __getitem__(self, address): if address < 0 or address >= scaled_byte_addr(self.size_in_bytes): raise Exception("trying to access too large a memory address", address) # if address not in self.dict: # raise Exception("trying to access uninitialized memory") return self.dict.get(address, 0)
def store_16(self, dest_addr, value): if scaled_byte_addr(4) != 4: raise Exception("cannot perform byte access") if dest_addr % 2 != 0: raise Exception("unaligned store16", operand_a) self[dest_addr] = (value >> 8) & 0xff self[dest_addr + 1] = value & 0xff
def load_16(self, operand_a, is_signed): if scaled_byte_addr(4) != 4: raise Exception("cannot perform byte access") if operand_a % 2 != 0: raise Exception("unaligned load16", operand_a) ret = (self[operand_a] << 8) | self[operand_a + 1] if is_signed and ret & 0x8000 != 0: return ret | 0xffff0000 return ret
def store(self, operand_a, operand_b): if scaled_byte_addr(4) == 4: if operand_a % 4 != 0: raise Exception("unaligned store", operand_a) self[operand_a] = (operand_b >> 24) & 0xff self[operand_a + 1] = (operand_b >> 16) & 0xff self[operand_a + 2] = (operand_b >> 8) & 0xff self[operand_a + 3] = operand_b & 0xff else: self[operand_a] = operand_b
def load(self, operand_a): if scaled_byte_addr(4) == 4: if operand_a % 4 != 0: raise Exception("unaligned load", operand_a) result = self[operand_a] result = (result << 8) | self[operand_a + 1] result = (result << 8) | self[operand_a + 2] result = (result << 8) | self[operand_a + 3] else: result = self[operand_a] return result
def store_object(trace, instructions, n, offset, local, leave_on_stack=False): """ Store an item into the specified location if n = 1 the item is taken from the result register if n = 2 the item is taken from result and result_hi register if n > 2 the item is taken from the stack if local is true, the location is assumed to be relative to the frame register if offset is not specified, assume that address is in address if leave_on_stack is true the item is copied to the specified location, but left on the stack. if the item was not on the stack in the first place, the value is left in the result registers either way. """ if offset is not None: if local: instructions.append({ "trace": trace, "op": "addl", "z": address, "a": frame, "literal": offset }) else: instructions.append({ "trace": trace, "op": "literal", "z": address, "literal": offset }) if n == 1: instructions.append({ "trace": trace, "op": "store", "literal": 0, "a": result, "z": address }) elif n == 2: instructions.append({ "trace": trace, "op": "store", "literal": 0, "a": result, "z": address }) instructions.append({ "trace": trace, "op": "addl", "z": address, "a": address, "literal": scaled_byte_addr(4) }) instructions.append({ "trace": trace, "op": "store", "literal": 0, "a": result_hi, "z": address }) else: instructions.append({ "trace": trace, "op": "addl", "z": address, "a": address, "literal": scaled_word_addr(n - 1) }) if leave_on_stack: instructions.append({ "trace": trace, "op": "addl", "z": tos_copy, "a": tos, "literal": 0 }) for i in range(n): instructions.append({ "trace": trace, "op": "addl", "z": tos_copy, "a": tos_copy, "literal": scaled_word_addr(-1) }) instructions.append({ "trace": trace, "op": "load", "z": result, "a": tos_copy }) instructions.append({ "trace": trace, "op": "store", "literal": 0, "a": result, "z": address }) if i < n - 1: instructions.append({ "trace": trace, "op": "addl", "z": address, "a": address, "literal": scaled_word_addr(-1) }) else: for i in range(n): pop(trace, instructions, result) instructions.append({ "trace": trace, "op": "store", "literal": 0, "a": result, "z": address }) if i < n - 1: instructions.append({ "trace": trace, "op": "addl", "z": address, "a": address, "literal": scaled_word_addr(-1) }) return instructions
def store_8(self, dest_addr, value): if scaled_byte_addr(4) != 4: raise Exception("cannot perform byte access") self[dest_addr] = value & 0xff
def __setitem__(self, address, value): if address < 0 or address >= scaled_byte_addr(self.size_in_bytes): raise Exception("trying to access too large a memory address", address) self.dict[address] = value