def jg(env, opinfo): a = to_signed_word(opinfo.operands[0]) b = to_signed_word(opinfo.operands[1]) result = a > b if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset)
def mod(env, opinfo): a = to_signed_word(opinfo.operands[0]) b = to_signed_word(opinfo.operands[1]) result = abs(a) % abs(b) if a < 0: # spec says a determines sign result = -result set_var(env, opinfo.store_var, result)
def div(env, opinfo): a = to_signed_word(opinfo.operands[0]) b = to_signed_word(opinfo.operands[1]) num_neg = (a < 0) + (b < 0) result = abs(a) // abs(b) if num_neg == 1: result = -result set_var(env, opinfo.store_var, result)
def dec(env, opinfo): var_num = opinfo.operands[0] var_val = to_signed_word(get_var(env, var_num)) var_val = var_val - 1 & 0xffff set_var(env, var_num, var_val) if DBG: warn(' var_num', var_num) warn(' new_val', to_signed_word(var_val))
def inc(env, opinfo): var_num = opinfo.operands[0] var_val = to_signed_word(get_var(env, var_num)) var_val = var_val + 1 & 0xffff set_var(env, var_num, var_val) if DBG: warn(' var', get_var_name(var_num)) warn(' new_val', to_signed_word(var_val))
def art_shift(env, opinfo): number = to_signed_word(opinfo.operands[0]) places = to_signed_word(opinfo.operands[1]) if places < 0: result = number >> abs(places) else: result = number << places set_var(env, opinfo.store_var, result) if DBG: warn(' result', result)
def dbg_decode_result(env, opname, store_var): if 'call' in opname: return 'unknown (just called)' var = ops.get_var(env, store_var, pop_stack=False) if opname in ['add', 'sub', 'mul', 'div', 'mod']: return to_signed_word(var) return var
def storew(env, opinfo): array_addr = opinfo.operands[0] word_index = to_signed_word(opinfo.operands[1]) val = opinfo.operands[2] word_loc = 0xffff & (array_addr + 2 * word_index) env.write16(word_loc, val)
def dec_chk(env, opinfo): var_loc = opinfo.operands[0] chk_val = to_signed_word(opinfo.operands[1]) var_val = to_signed_word(get_var(env, var_loc)) var_val = var_val - 1 & 0xffff set_var(env, var_loc, var_val) var_val = to_signed_word(var_val) result = var_val < chk_val if result == opinfo.branch_on: handle_branch(env, opinfo.branch_offset) if DBG: warn(' var_loc', get_var_name(var_loc)) warn(' var_val', var_val)
def storeb(env, opinfo): array_addr = opinfo.operands[0] byte_index = to_signed_word(opinfo.operands[1]) val = opinfo.operands[2] & 0xff mem_loc = 0xffff & (array_addr + byte_index) env.write8(mem_loc, val)
def random_(env, opinfo): rand_max = to_signed_word(opinfo.operands[0]) if rand_max < 0: random.seed(rand_max) result = 0 elif rand_max == 0: random.seed() result = 0 else: result = random.randint(1, rand_max) set_var(env, opinfo.store_var, result)
def dbg_decode_operands(env, opname, operands): if opname in ['add', 'sub', 'mul', 'div', 'mod', 'jump', 'random_', 'print_num']: return map(to_signed_word, operands) elif opname in ['loadw', 'loadb', 'storew', 'storeb', 'inc_chk', 'dec_chk']: return [operands[0], to_signed_word(operands[1])] + operands[2:] elif opname in ['print_', 'print_ret']: result = ops.unpack_string(env, operands) if len(result) > 40: return repr(result[:40] + '...') return result return operands
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 erase_window(env, opinfo): env.screen.finish_wrapping() window = to_signed_word(opinfo.operands[0]) if window in [0, -1, -2]: env.screen.blank_bottom_win() if window in [1, -1, -2]: env.screen.blank_top_win() if window == -1: env.top_window_height = 0 env.current_window = 0 if window in [0, -1, -2]: env.cursor[0] = get_cursor_loc_after_erase(env, 0) if window in [1, -1, -2]: env.cursor[1] = get_cursor_loc_after_erase(env, 1)
def copy_table(env, opinfo): first = opinfo.operands[0] second = opinfo.operands[1] size = to_signed_word(opinfo.operands[2]) if second == 0: # zeros out first size = abs(size) for i in xrange(size): env.write8(first + i, 0) elif size > 0: # protects against corruption of overlapping tables tab = env.mem[first:first + size] for i in xrange(size): env.write8(second + i, tab[i]) elif size < 0: # allows for the corruption of overlapping tables size = abs(size) for i in xrange(size): env.write8(second + i, env.mem[first + i])
def output_stream(env, opinfo): stream = to_signed_word(opinfo.operands[0]) if stream < 0: stream = abs(stream) if stream == 3: table_addr = env.memory_ostream_stack.pop() zscii_buffer = ascii_to_zscii(env.output_buffer[stream]) buflen = len(zscii_buffer) env.write16(table_addr, buflen) for i in xrange(len(zscii_buffer)): env.write8(table_addr + 2 + i, zscii_buffer[i]) env.output_buffer[stream] = '' if len(env.memory_ostream_stack) == 0: env.selected_ostreams.discard(stream) else: env.selected_ostreams.discard(stream) elif stream > 0: env.selected_ostreams.add(stream) if stream == 3: table_addr = opinfo.operands[1] if len(env.memory_ostream_stack) == 16: err('too many memory-based ostreams (>16)') env.memory_ostream_stack.append(table_addr)
def mul(env, opinfo): a = to_signed_word(opinfo.operands[0]) b = to_signed_word(opinfo.operands[1]) result = a * b set_var(env, opinfo.store_var, result)
def print_num(env, opinfo): num = to_signed_word(opinfo.operands[0]) write(env, str(num))
def loadb(env, opinfo): array_addr = opinfo.operands[0] byte_index = to_signed_word(opinfo.operands[1]) byte_loc = 0xffff & (array_addr + byte_index) set_var(env, opinfo.store_var, env.u8(byte_loc))
def loadw(env, opinfo): array_addr = opinfo.operands[0] word_index = to_signed_word(opinfo.operands[1]) word_loc = 0xffff & (array_addr + 2 * word_index) set_var(env, opinfo.store_var, env.u16(word_loc))
def jump(env, opinfo): offset = to_signed_word(opinfo.operands[0]) env.pc += offset - 2
def decode(env, pc): opcode = env.u8(pc) form = get_opcode_form(env, opcode) count = get_operand_count(opcode, form) if form == ExtForm: opcode = env.u8(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.u8(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.u8(pc+2) sizes += get_operand_sizes(szbyte2) operand_ptr = pc+3 elif form == ExtForm: szbyte = env.u8(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 xrange(len(sizes)): size = sizes[i] if size == WordSize: operands.append(env.u16(operand_ptr)) operand_ptr += 2 elif size == ByteSize: operands.append(env.u8(operand_ptr)) operand_ptr += 1 elif size == VarSize: operands.append(None) #this is fixedup after every load from icache by opinfo method var_num = env.u8(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.u8(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.u8(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.u8(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 s16(self, i): return to_signed_word(self.u16(i))