def print_obj(env, opinfo): obj = opinfo.operands[0] string = get_obj_str(env, obj) write(env, string) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')')
def get_next_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] next_prop_num = 0 if obj: if prop_num == 0: prop_start = get_prop_list_start(env, obj) next_prop_num = get_prop_num(env, prop_start) else: prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) if prop_data_ptr == 0: msg = 'get_next_prop: passed nonexistant prop ' msg += str(prop_num)+' for obj '+str(obj)+' ('+get_obj_str(env,obj)+')' print_prop_list(env, obj) err(msg) sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) next_prop_num = get_prop_num(env, prop_data_ptr + size) set_var(env, opinfo.store_var, next_prop_num) if DBG: warn(' prop_num', prop_num) warn(' next_prop_num', next_prop_num) print_prop_list(env, obj)
def insert_obj(env, opinfo): obj = opinfo.operands[0] dest = opinfo.operands[1] if not obj or not dest: return # it doesn't say explicitly to make obj's parent # field say dest, but *surely* that's the right # thing to do. Right? # (based on what the ops seems to expect, I think so) # Also, should I remove it from its old parent? # Looks like, based on the current bug I have. _remove_obj(env, obj) # Ok, Yep. That totally fixed things. dest_child = get_child_num(env, dest) set_parent_num(env, obj, dest) set_sibling_num(env, obj, dest_child) set_child_num(env, dest, obj) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' dest', dest, '(', get_obj_str(env, dest), ')')
def insert_obj(env, opinfo): obj = opinfo.operands[0] dest = opinfo.operands[1] if not obj or not dest: return # it doesn't say explicitly to make obj's parent # field say dest, but *surely* that's the right # thing to do. Right? # (based on what the ops seems to expect, I think so) # Also, should I remove it from its old parent? # Looks like, based on the current bug I have. _remove_obj(env, obj) # Ok, Yep. That totally fixed things. dest_child = get_child_num(env, dest) set_parent_num(env, obj, dest) set_sibling_num(env, obj, dest_child) set_child_num(env, dest, obj) if DBG: warn(' obj', obj, '(', get_obj_str(env,obj), ')') warn(' dest', dest, '(', get_obj_str(env,dest), ')')
def scan_table(env, opinfo): val = opinfo.operands[0] tab_addr = opinfo.operands[1] tab_len = opinfo.operands[2] if len(opinfo.operands) > 3: form = opinfo.operands[3] else: form = 0x82 val_size = (form >> 7) + 1 # word or byte field_len = form & 127 addr = 0 for i in range(tab_len): test_addr = tab_addr + i * field_len if val_size == 2: test_val = env.u16(test_addr) else: test_val = env.mem[test_addr] if val == test_val: addr = test_addr break found = addr != 0 set_var(env, opinfo.store_var, addr) if found == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' found', found) warn(' addr', addr)
def scan_table(env, opinfo): val = opinfo.operands[0] tab_addr = opinfo.operands[1] tab_len = opinfo.operands[2] if len(opinfo.operands) > 3: form = opinfo.operands[3] else: form = 0x82 val_size = (form >> 7) + 1 # word or byte field_len = form & 127 addr = 0 for i in range(tab_len): test_addr = tab_addr + i*field_len if val_size == 2: test_val = env.u16(test_addr) else: test_val = env.mem[test_addr] if val == test_val: addr = test_addr break found = addr != 0 set_var(env, opinfo.store_var, addr) if found == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' found', found) warn(' addr', addr)
def get_next_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] next_prop_num = 0 if obj: if prop_num == 0: prop_start = get_prop_list_start(env, obj) next_prop_num = get_prop_num(env, prop_start) else: prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) if prop_data_ptr == 0: msg = 'get_next_prop: passed nonexistant prop ' msg += str(prop_num) + ' for obj ' + str( obj) + ' (' + get_obj_str(env, obj) + ')' print_prop_list(env, obj) err(msg) sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) next_prop_num = get_prop_num(env, prop_data_ptr + size) set_var(env, opinfo.store_var, next_prop_num) if DBG: warn(' prop_num', prop_num) warn(' next_prop_num', next_prop_num) print_prop_list(env, obj)
def _print_addr(env, addr): packed_string = read_packed_string(env, addr) string = unpack_string(env, packed_string) write(env, string) if DBG: warn(' helper: _print_addr') warn(' addr', addr)
def get_parent(env, opinfo): obj = opinfo.operands[0] parent_num = get_parent_num(env, obj) set_var(env, opinfo.store_var, parent_num) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' parent', parent_num, '(', get_obj_str(env, parent_num), ')')
def get_parent(env, opinfo): obj = opinfo.operands[0] parent_num = get_parent_num(env, obj) set_var(env, opinfo.store_var, parent_num) if DBG: warn(' obj', obj,'(',get_obj_str(env, obj),')') warn(' parent', parent_num, '(',get_obj_str(env, parent_num),')')
def test(env, opinfo): bitmap = opinfo.operands[0] flags = opinfo.operands[1] result = bitmap & flags == flags if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' bitmap', bin(bitmap)) warn(' flags', bin(flags))
def read_char(env, opinfo): # NOTE: operands[0] must be 1, but I ran into a z5 that passed no operands # (strictz) so let's just ignore the first operand instead... if len(opinfo.operands) > 1: if len(opinfo.operands) != 3: err('read_char: num operands must be 1 or 3') if opinfo.operands[1] != 0 or opinfo.operands[2] != 0: if DBG: warn('read_char: interrupts not impl\'d yet!') c = ascii_to_zscii(env.screen.getch_or_esc_seq())[0] set_var(env, opinfo.store_var, c)
def get_child(env, opinfo): obj = opinfo.operands[0] child_num = get_child_num(env, obj) set_var(env, opinfo.store_var, child_num) result = child_num != 0 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' child', child_num, '(', get_obj_str(env, child_num), ')')
def get_sibling(env, opinfo): obj = opinfo.operands[0] sibling_num = get_sibling_num(env, obj) set_var(env, opinfo.store_var, sibling_num) result = sibling_num != 0 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj,'(',get_obj_str(env, obj),')') warn(' sibling', sibling_num, '(',get_obj_str(env, sibling_num),')')
def get_child(env, opinfo): obj = opinfo.operands[0] child_num = get_child_num(env, obj) set_var(env, opinfo.store_var, child_num) result = child_num != 0 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj,'(',get_obj_str(env, obj),')') warn(' child', child_num, '(',get_obj_str(env, child_num),')')
def save(env, opinfo): # TODO handle optional operands if len(opinfo.operands) > 0: if DBG: warn('restore: found operands (not yet impld): '+str(opinfo.operands)) set_var(env, opinfo.store_var, 0) return filename = env.screen.get_line_of_input('input save filename: ') if quetzal.write(env, filename): set_var(env, opinfo.store_var, 1) else: set_var(env, opinfo.store_var, 0)
def get_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) is_default_prop = prop_data_ptr == 0 if is_default_prop: base = env.hdr.obj_tab_base result = env.u16(base + 2*(prop_num-1)) else: sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) if size == 1: result = env.mem[prop_data_ptr] elif size == 2 or FORGIVING_GET_PROP: result = env.u16(prop_data_ptr) else: msg = 'illegal op: get_prop on outsized prop (not 1-2 bytes)' msg += ' - prop '+str(prop_num) msg += ' of obj '+str(obj)+' ('+get_obj_str(env, obj)+')' msg += ' (sized at '+str(size)+' bytes)' print_prop_list(env, obj) err(msg) set_var(env, opinfo.store_var, result) if DBG: warn(' obj', obj,'(',get_obj_str(env,obj),')') warn(' prop_num', prop_num) warn(' result', result) warn(' is_default_prop', is_default_prop) print_prop_list(env, obj)
def check_arg_count(env, opinfo): arg_num = opinfo.operands[0] frame = env.callstack[-1] result = frame.num_args >= arg_num if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' arg_num', arg_num) warn(' num args in frame', frame.num_args) warn(' branch_offset', opinfo.branch_offset) warn(' branch_on', opinfo.branch_on) warn(' result', result)
def get_sibling(env, opinfo): obj = opinfo.operands[0] sibling_num = get_sibling_num(env, obj) set_var(env, opinfo.store_var, sibling_num) result = sibling_num != 0 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' sibling', sibling_num, '(', get_obj_str(env, sibling_num), ')')
def get_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) is_default_prop = prop_data_ptr == 0 if is_default_prop: base = env.hdr.obj_tab_base result = env.u16(base + 2 * (prop_num - 1)) else: sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) if size == 1: result = env.mem[prop_data_ptr] elif size == 2 or FORGIVING_GET_PROP: result = env.u16(prop_data_ptr) else: msg = 'illegal op: get_prop on outsized prop (not 1-2 bytes)' msg += ' - prop ' + str(prop_num) msg += ' of obj ' + str(obj) + ' (' + get_obj_str(env, obj) + ')' msg += ' (sized at ' + str(size) + ' bytes)' print_prop_list(env, obj) err(msg) set_var(env, opinfo.store_var, result) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' prop_num', prop_num) warn(' result', result) warn(' is_default_prop', is_default_prop) print_prop_list(env, obj)
def save(env, opinfo): # TODO handle optional operands if len(opinfo.operands) > 0: if DBG: warn('restore: found operands (not yet impld): ' + str(opinfo.operands)) set_var(env, opinfo.store_var, 0) return filename = env.screen.get_line_of_input('input save filename: ') if quetzal.write(env, filename): set_var(env, opinfo.store_var, 1) else: set_var(env, opinfo.store_var, 0)
def clear_attr(env, opinfo): obj = opinfo.operands[0] attr = opinfo.operands[1] if obj: obj_addr = get_obj_addr(env, obj) attr_byte = attr // 8 mask = 2**(7 - attr % 8) old_val = env.mem[obj_addr + attr_byte] env.write8(obj_addr + attr_byte, old_val & ~mask) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' attr', attr)
def clear_attr(env, opinfo): obj = opinfo.operands[0] attr = opinfo.operands[1] if obj: obj_addr = get_obj_addr(env, obj) attr_byte = attr // 8 mask = 2**(7-attr%8) old_val = env.mem[obj_addr+attr_byte] env.write8(obj_addr+attr_byte, old_val & ~mask) if DBG: warn(' obj', obj, '(', get_obj_str(env,obj), ')') warn(' attr', attr)
def restore(env, opinfo): # TODO handle optional operands if len(opinfo.operands) > 0: if DBG: warn('restore: found operands (not yet impld): ' + str(opinfo.operands)) set_var(env, opinfo.store_var, 0) return loaded = restore_chooser(env) if loaded: # set and move past save inst's svar byte # (which quetzal gives as the PC) set_var(env, env.mem[env.pc], 2) env.pc += 1 else: set_var(env, opinfo.store_var, 0)
def handle_return(env, return_val): frame = env.callstack.pop() if frame.return_addr == 0: err('returned from unreturnable/nonexistant function!') if frame.return_val_loc != None: set_var(env, frame.return_val_loc, return_val) env.pc = frame.return_addr if DBG: warn(' helper: handle_return') warn(' return_val', return_val) if frame.return_val_loc: warn(' return_val_loc', get_var_name(frame.return_val_loc)) else: warn(' return_val_loc None') warn(' return_addr', hex(frame.return_addr))
def restore(env, opinfo): # TODO handle optional operands if len(opinfo.operands) > 0: if DBG: warn('restore: found operands (not yet impld): '+str(opinfo.operands)) set_var(env, opinfo.store_var, 0) return filename = env.screen.get_line_of_input('input save filename: ') loaded = quetzal.load_to_env(env, filename) if loaded: # set and move past save inst's svar byte # (which quetzal gives as the PC) set_var(env, env.mem[env.pc], 2) env.pc += 1 else: set_var(env, opinfo.store_var, 0)
def print_prop_list(env, obj): warn(' ',obj,'-',get_obj_str(env, obj)+':') ptr = get_prop_list_start(env, obj) while env.mem[ptr]: num = get_prop_num(env, ptr) size = get_prop_size(env, ptr) data_ptr = get_prop_data_ptr(env, ptr) warn(' prop #',num,' - size',size, end='') for i in range(size): warn(' ',hex(env.mem[data_ptr+i]), end='') warn() ptr = data_ptr + size
def test_attr(env, opinfo): obj = opinfo.operands[0] attr = opinfo.operands[1] if obj: obj_addr = get_obj_addr(env, obj) attr_byte = attr // 8 shift_amt = 7 - attr%8 attr_val = (env.mem[obj_addr+attr_byte] >> shift_amt) & 1 result = attr_val == 1 else: result = False if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj, '(', get_obj_str(env,obj), ')') warn(' attr', attr)
def test_attr(env, opinfo): obj = opinfo.operands[0] attr = opinfo.operands[1] if obj: obj_addr = get_obj_addr(env, obj) attr_byte = attr // 8 shift_amt = 7 - attr % 8 attr_val = (env.mem[obj_addr + attr_byte] >> shift_amt) & 1 result = attr_val == 1 else: result = False if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' attr', attr)
def _remove_obj(env, obj): obj_addr = get_obj_addr(env, obj) parent = get_parent_num(env, obj) sibling = get_sibling_num(env, obj) set_parent_num(env, obj, 0) set_sibling_num(env, obj, 0) if parent == 0: return child_num = get_child_num(env, parent) if child_num == obj: set_child_num(env, parent, sibling) else: sibling_num = get_sibling_num(env, child_num) while sibling_num and sibling_num != obj: child_num = sibling_num sibling_num = get_sibling_num(env, child_num) if sibling_num != 0: set_sibling_num(env, child_num, sibling) if DBG: warn(' helper: _remove_obj') warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' parent', parent, '(', get_obj_str(env, parent), ')')
def put_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] val = opinfo.operands[2] prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) if prop_data_ptr == 0: msg = 'illegal op: put_prop on nonexistant property' msg += ' - prop ' + str(prop_num) msg += ' not found on obj ' + str(obj) + ' (' + get_obj_str(env, obj) + ')' err(msg) sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) if size == 2: env.write16(prop_data_ptr, val) elif size == 1: env.write8(prop_data_ptr, val & 0xff) else: msg = 'illegal op: put_prop on outsized prop (not 1-2 bytes)' msg += ' - prop ' + str(prop_num) msg += ' of obj ' + str(obj) + ' (' + get_obj_str(obj) + ')' msg += ' (sized at ' + size + ' bytes)' err(msg) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' prop_num', prop_num) warn(' val', val) print_prop_list(env, obj)
def set_cursor(env, opinfo): env.screen.finish_wrapping() try: row = to_signed_word(opinfo.operands[0]) col = to_signed_word(opinfo.operands[1]) if row < 1: # why do we not error out here? row = 1 if col < 1: # same question col = 1 # ignores win 0 (S 8.7.2.3) if env.current_window == 1: if col > env.hdr.screen_width_units: if DBG: warn('set_cursor: set outside screen width', col) col = env.hdr.screen_width_units if row > env.hdr.screen_height_units: if DBG: warn('set_cursor: set outside screen height', row) row = env.hdr.screen_height_units # see 3rd to last note at bottom of section 8 env.top_window_height = max(env.top_window_height, row - 1) # fix that row,col have a 1,1 origin env.cursor[env.current_window] = row - 1, col - 1 except Exception as e: warn("Exception during set_cursor:", e, repr(opinfo))
def _remove_obj(env, obj): obj_addr = get_obj_addr(env, obj) parent = get_parent_num(env, obj) sibling = get_sibling_num(env, obj) set_parent_num(env, obj, 0) set_sibling_num(env, obj, 0) if parent == 0: return child_num = get_child_num(env, parent) if child_num == obj: set_child_num(env, parent, sibling) else: sibling_num = get_sibling_num(env, child_num) while sibling_num and sibling_num != obj: child_num = sibling_num sibling_num = get_sibling_num(env, child_num) if sibling_num != 0: set_sibling_num(env, child_num, sibling) if DBG: warn(' helper: _remove_obj') warn(' obj', obj, '(', get_obj_str(env,obj), ')') warn(' parent', parent, '(', get_obj_str(env,parent), ')')
def put_prop(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] val = opinfo.operands[2] prop_data_ptr = get_prop_data_ptr_from_obj(env, obj, prop_num) if prop_data_ptr == 0: msg = 'illegal op: put_prop on nonexistant property' msg += ' - prop '+str(prop_num) msg += ' not found on obj '+str(obj)+' ('+get_obj_str(env, obj)+')' err(msg) sizenum_ptr = get_sizenum_ptr(env, prop_data_ptr) size = get_prop_size(env, sizenum_ptr) if size == 2: env.write16(prop_data_ptr, val) elif size == 1: env.write8(prop_data_ptr, val & 0xff) else: msg = 'illegal op: put_prop on outsized prop (not 1-2 bytes)' msg += ' - prop '+str(prop_num) msg += ' of obj '+str(obj)+' ('+get_obj_str(obj)+')' msg += ' (sized at '+size+' bytes)' err(msg) if DBG: warn(' obj', obj,'(',get_obj_str(env,obj),')') warn(' prop_num', prop_num) warn(' val', val) print_prop_list(env, obj)
def restore(env, opinfo): # TODO handle optional operands if len(opinfo.operands) > 0: if DBG: warn('restore: found operands (not yet impld): ' + str(opinfo.operands)) set_var(env, opinfo.store_var, 0) return ls = '' for k in sorted(env.files): ls += str(k) + "\t" + env.files[k][0] + "\n" filename = env.screen.get_line_of_input(ls + 'input save filename: ') loaded = quetzal.load_to_env(env, filename) if loaded: # set and move past save inst's svar byte # (which quetzal gives as the PC) set_var(env, env.mem[env.pc], 2) env.pc += 1 else: set_var(env, opinfo.store_var, 0)
def verify(env, opinfo): vsum = 0 for i in range(0x40, get_file_len(env)): vsum += six.indexbytes(env.orig_mem, i) vsum &= 0xffff result = vsum == env.hdr.checksum if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' vsum', vsum) warn(' checksum in header', env.hdr.checksum) warn(' branch_on', opinfo.branch_on) warn(' result', result)
def set_cursor(env, opinfo): env.screen.finish_wrapping() row = to_signed_word(opinfo.operands[0]) col = to_signed_word(opinfo.operands[1]) if row < 1: # why do we not error out here? row = 1 if col < 1: # same question col = 1 # ignores win 0 (S 8.7.2.3) if env.current_window == 1: if col > env.hdr.screen_width_units: if DBG: warn('set_cursor: set outside screen width', col) col = env.hdr.screen_width_units if row > env.hdr.screen_height_units: if DBG: warn('set_cursor: set outside screen height', row) row = env.hdr.screen_height_units # see 3rd to last note at bottom of section 8 env.top_window_height = max(env.top_window_height, row-1) # fix that row,col have a 1,1 origin env.cursor[env.current_window] = row-1, col-1
def jin(env, opinfo): obj1 = opinfo.operands[0] obj2 = opinfo.operands[1] result = get_parent_num(env, obj1) == obj2 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj1', obj1, '(',get_obj_str(env,obj1),')') warn(' obj2', obj2, '(',get_obj_str(env,obj2),')') warn(' is_parent?', result)
def jin(env, opinfo): obj1 = opinfo.operands[0] obj2 = opinfo.operands[1] result = get_parent_num(env, obj1) == obj2 if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' obj1', obj1, '(', get_obj_str(env, obj1), ')') warn(' obj2', obj2, '(', get_obj_str(env, obj2), ')') warn(' is_parent?', result)
def get_prop_addr(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] if obj == 0: # from testing, this seems # to be the expected behavior result = 0 else: result = get_prop_data_ptr_from_obj(env, obj, prop_num) set_var(env, opinfo.store_var, result) if DBG: warn(' obj', obj,'(',get_obj_str(env,obj),')') warn(' prop_num', prop_num) warn(' result', result) if obj: print_prop_list(env, obj)
def get_prop_addr(env, opinfo): obj = opinfo.operands[0] prop_num = opinfo.operands[1] if obj == 0: # from testing, this seems # to be the expected behavior result = 0 else: result = get_prop_data_ptr_from_obj(env, obj, prop_num) set_var(env, opinfo.store_var, result) if DBG: warn(' obj', obj, '(', get_obj_str(env, obj), ')') warn(' prop_num', prop_num) warn(' result', result) if obj: print_prop_list(env, obj)
def decode(env, pc): opcode = env.mem[pc] form = get_opcode_form(env, opcode) count = get_operand_count(opcode, form) if form == ExtForm: opcode = env.mem[pc+1] if form == ShortForm: szbyte = (opcode >> 4) & 3 szbyte = (szbyte << 6) | 0x3f operand_ptr = pc+1 sizes = get_operand_sizes(szbyte) elif form == VarForm: szbyte = env.mem[pc+1] operand_ptr = pc+2 sizes = get_operand_sizes(szbyte) # handle call_vn2/vs2's extra szbyte if opcode in (236, 250): szbyte2 = env.mem[pc+2] sizes += get_operand_sizes(szbyte2) operand_ptr = pc+3 elif form == ExtForm: szbyte = env.mem[pc+2] operand_ptr = pc+3 sizes = get_operand_sizes(szbyte) elif form == LongForm: operand_ptr = pc+1 sizes = [] for offset in (6,5): if (opcode >> offset) & 1: sizes.append(VarSize) else: sizes.append(ByteSize) else: err('unknown opform specified: ' + str(form)) operands = [] var_op_info = [] for i in range(len(sizes)): size = sizes[i] if size == WordSize: operands.append(env.u16(operand_ptr)) operand_ptr += 2 elif size == ByteSize: operands.append(env.mem[operand_ptr]) operand_ptr += 1 elif size == VarSize: operands.append(None) #this is fixedup after every load from icache var_num = env.mem[operand_ptr] var_op_info.append( (i,var_num) ) operand_ptr += 1 else: err('unknown operand size specified: ' + str(size)) if form == ExtForm: dispatch = ops.ext_dispatch has_store_var = ops.ext_has_store_var has_branch_var = ops.ext_has_branch_var else: dispatch = ops.dispatch has_store_var = ops.has_store_var has_branch_var = ops.has_branch_var opinfo = OpInfo(operands, var_op_info) opinfo.opcode = opcode opinfo.is_extended = form == ExtForm if has_store_var[opcode]: opinfo.store_var = env.mem[operand_ptr] opinfo.last_pc_store_var = operand_ptr # to make quetzal saves easier operand_ptr += 1 if has_branch_var[opcode]: # std:4.7 branch_info = env.mem[operand_ptr] opinfo.last_pc_branch_var = operand_ptr # to make quetzal saves easier operand_ptr += 1 opinfo.branch_on = (branch_info & 128) == 128 if branch_info & 64: opinfo.branch_offset = branch_info & 0x3f else: branch_offset = branch_info & 0x3f branch_offset <<= 8 branch_offset |= env.mem[operand_ptr] operand_ptr += 1 # sign extend 14b # to 16b if branch_offset & 0x2000: branch_offset |= 0xc000 opinfo.branch_offset = to_signed_word(branch_offset) # handle print_ and print_ret's string operand if form != ExtForm and opcode in (178, 179): while True: word = env.u16(operand_ptr) operand_ptr += 2 operands.append(word) if word & 0x8000: break # After all that, operand_ptr should point to the next opcode next_pc = operand_ptr if DBG: def hex_out(bytes): s = '' for b in bytes: s += hex(b) + ' ' return s op_hex = hex_out(env.mem[pc:next_pc]) warn('decode: pc', hex(pc)) warn(' opcode', opcode) warn(' form', form) warn(' count', count) if opinfo.store_var: warn(' store_var', ops.get_var_name(opinfo.store_var)) warn(' sizes', sizes) warn(' operands', opinfo.operands) warn(' next_pc', hex(next_pc)) #warn(' bytes', op_hex) return dispatch[opcode], opinfo, next_pc
def call(env, opinfo): packed_addr = opinfo.operands[0] if packed_addr == 0: if opinfo.store_var != None: set_var(env, opinfo.store_var, 0) if DBG: warn('op: calling 0 (returns false)') return return_addr = env.pc fncache = env.fncache if packed_addr in fncache: call_addr, local_vars, code_ptr = fncache[packed_addr] local_vars = local_vars[:] # leave cached vars for later hits else: call_addr = unpack_addr_call(env, packed_addr) local_vars, code_ptr = parse_call_header(env, call_addr) if call_addr >= env.hdr.static_mem_base: fncache[packed_addr] = call_addr, local_vars, code_ptr local_vars = local_vars[:] # leave cached vars for later hits # args dropped if past len of locals arr num_args = min(len(opinfo.operands) - 1, len(local_vars)) local_vars[:num_args] = opinfo.operands[1:num_args + 1] env.callstack.append( Frame(return_addr, num_args, local_vars, opinfo.store_var)) env.pc = code_ptr if DBG: warn(' calling', hex(call_addr)) warn(' returning to', hex(return_addr)) warn(' using args', opinfo.operands[1:]) if opinfo.store_var == None: warn(' return val will be discarded') else: warn(' return val will be placed in', get_var_name(opinfo.store_var)) warn(' num locals:', env.mem[call_addr]) warn(' local vals:', local_vars) warn(' code ptr:', hex(code_ptr)) warn(' first inst:', env.mem[code_ptr])
def show_status(env, opinfo): if DBG: warn(' (not impld)')
def sound_effect(env, opinfo): if DBG: warn(' (not impld)')
def save_undo(env, opinfo): set_var(env, opinfo.store_var, -1) if DBG: warn(' (not impld for now)') warn(' (but at least I can notify the game of that)')
def call(env, opinfo): packed_addr = opinfo.operands[0] if packed_addr == 0: if opinfo.store_var != None: set_var(env, opinfo.store_var, 0) if DBG: warn('op: calling 0 (returns false)') return return_addr = env.pc fncache = env.fncache if packed_addr in fncache: call_addr, local_vars, code_ptr = fncache[packed_addr] local_vars = local_vars[:] # leave cached vars for later hits else: call_addr = unpack_addr_call(env, packed_addr) local_vars, code_ptr = parse_call_header(env, call_addr) if call_addr >= env.hdr.static_mem_base: fncache[packed_addr] = call_addr, local_vars, code_ptr local_vars = local_vars[:] # leave cached vars for later hits # args dropped if past len of locals arr num_args = min(len(opinfo.operands)-1, len(local_vars)) local_vars[:num_args] = opinfo.operands[1:num_args+1] env.callstack.append(Frame(return_addr, num_args, local_vars, opinfo.store_var)) env.pc = code_ptr if DBG: warn(' calling', hex(call_addr)) warn(' returning to', hex(return_addr)) warn(' using args', opinfo.operands[1:]) if opinfo.store_var == None: warn(' return val will be discarded') else: warn(' return val will be placed in', get_var_name(opinfo.store_var)) warn(' num locals:', env.mem[call_addr]) warn(' local vals:', local_vars) warn(' code ptr:', hex(code_ptr)) warn(' first inst:', env.mem[code_ptr])
def step(env): pc, icache = env.pc, env.icache if pc in icache: op, opinfo, env.pc = icache[pc] else: op, opinfo, env.pc = ops_decode.decode(env, pc) if pc >= env.hdr.static_mem_base: icache[pc] = op, opinfo, env.pc # fixup dynamic operands if opinfo.has_dynamic_operands: for i, var_num in opinfo.var_op_info: opinfo.operands[i] = ops.get_var(env, var_num) # for Quetzal if opinfo.last_pc_branch_var: env.last_pc_branch_var = opinfo.last_pc_branch_var if opinfo.last_pc_store_var: env.last_pc_store_var = opinfo.last_pc_store_var if DBG: warn(hex(pc)) warn('op:', op.__name__) warn(' operands', dbg_decode_operands(env, op.__name__, opinfo.operands)) if opinfo.branch_offset != None: warn(' branch_offset', opinfo.branch_offset) warn(' branch_to', dbg_decode_branch(env, opinfo.branch_offset)) warn(' branch_on', opinfo.branch_on) op(env, opinfo) if opinfo.store_var: warn( 'store_var', ops.get_var_name(opinfo.store_var)) warn( 'stored_result', dbg_decode_result(env, op.__name__, opinfo.store_var)) else: op(env, opinfo)
def step(env): pc, icache = env.pc, env.icache if pc in icache: op, opinfo, env.pc = icache[pc] else: op, opinfo, env.pc = ops_decode.decode(env, pc) if pc >= env.hdr.static_mem_base: icache[pc] = op, opinfo, env.pc # fixup dynamic operands if opinfo.has_dynamic_operands: for i, var_num in opinfo.var_op_info: opinfo.operands[i] = ops.get_var(env, var_num) # for Quetzal if opinfo.last_pc_branch_var: env.last_pc_branch_var = opinfo.last_pc_branch_var if opinfo.last_pc_store_var: env.last_pc_store_var = opinfo.last_pc_store_var if DBG: warn(hex(pc)) warn('op:', op.__name__) warn(' operands', dbg_decode_operands(env, op.__name__, opinfo.operands)) if opinfo.branch_offset != None: warn(' branch_offset', opinfo.branch_offset) warn(' branch_to', dbg_decode_branch(env, opinfo.branch_offset)) warn(' branch_on', opinfo.branch_on) op(env, opinfo) if opinfo.store_var: warn('store_var', ops.get_var_name(opinfo.store_var)) warn('stored_result', dbg_decode_result(env, op.__name__, opinfo.store_var)) else: op(env, opinfo)