def get_basic_memory(addr): """ Retrieve data from BASIC memory. """ addr -= memory.data_segment*0x10 # DS:2c, DS:2d end of memory available to BASIC if addr == 0x2C: return memory.total_memory % 256 elif addr == 0x2D: return memory.total_memory // 256 # DS:30, DS:31: pointer to start of program, excluding initial \0 elif addr == 0x30: return (memory.code_start+1) % 256 elif addr == 0x31: return (memory.code_start+1) // 256 # DS:358, DS:359: start of variable space elif addr == 0x358: return memory.var_start() % 256 elif addr == 0x359: return memory.var_start() // 256 # DS:35A, DS:35B: start of array space elif addr == 0x35A: return state.basic_state.var_current % 256 elif addr == 0x35B: return state.basic_state.var_current // 256 # DS:35C, DS:35D: end of array space elif addr == 0x35C: return (state.basic_state.var_current + state.basic_state.array_current) % 256 elif addr == 0x35D: return (state.basic_state.var_current + state.basic_state.array_current) // 256 elif addr == protection_flag_addr: return state.basic_state.protected * 255 return -1
def get_basic_memory(addr): """ Retrieve data from BASIC memory. """ addr -= memory.data_segment * 0x10 # DS:2c, DS:2d end of memory available to BASIC if addr == 0x2C: return memory.total_memory % 256 elif addr == 0x2D: return memory.total_memory // 256 # DS:30, DS:31: pointer to start of program, excluding initial \0 elif addr == 0x30: return (memory.code_start + 1) % 256 elif addr == 0x31: return (memory.code_start + 1) // 256 # DS:358, DS:359: start of variable space elif addr == 0x358: return memory.var_start() % 256 elif addr == 0x359: return memory.var_start() // 256 # DS:35A, DS:35B: start of array space elif addr == 0x35A: return state.basic_state.var_current % 256 elif addr == 0x35B: return state.basic_state.var_current // 256 # DS:35C, DS:35D: end of array space elif addr == 0x35C: return (state.basic_state.var_current + state.basic_state.array_current) % 256 elif addr == 0x35D: return (state.basic_state.var_current + state.basic_state.array_current) // 256 elif addr == protection_flag_addr: return state.basic_state.protected * 255 return -1
def set_memory(addr, val): """ Set the value at an emulated memory location. """ if addr >= memory.rom_segment*0x10: # ROM includes font memory pass elif addr >= memory.ram_font_segment*0x10: # RAM font memory set_font_memory(addr, val) elif addr >= memory.video_segment*0x10: # graphics and text memory set_video_memory(addr, val) elif addr >= memory.data_segment*0x10 + memory.var_start(): # POKING in variables set_data_memory(addr, val) elif addr >= memory.data_segment*0x10 + memory.code_start: # code memory set_code_memory(addr, val) elif addr >= memory.data_segment*0x10 + memory.field_mem_start: # file & FIELD memory set_field_memory(addr, val) elif addr >= memory.data_segment*0x10: set_basic_memory(addr, val) elif addr >= low_segment*0x10: set_low_memory(addr, val) else: pass
def get_memory(addr): """ Retrieve the value at an emulated memory location. """ try: # try if there's a preset value return peek_values[addr] except KeyError: if addr >= memory.rom_segment*0x10: # ROM font return max(0, get_rom_memory(addr)) elif addr >= memory.ram_font_segment*0x10: # RAM font return max(0, get_font_memory(addr)) elif addr >= memory.video_segment*0x10: # graphics and text memory return max(0, get_video_memory(addr)) elif addr >= memory.data_segment*0x10 + memory.var_start(): # variable memory return max(0, get_data_memory(addr)) elif addr >= memory.data_segment*0x10 + memory.code_start: # code memory return max(0, get_code_memory(addr)) elif addr >= memory.data_segment*0x10 + memory.field_mem_start: # file & FIELD memory return max(0, get_field_memory(addr)) elif addr >= memory.data_segment*0x10: # other BASIC data memory return max(0, get_basic_memory(addr)) elif addr >= low_segment*0x10: return max(0, get_low_memory(addr)) else: return 0
def string_assign_unpacked_into(sequence, offset, num, val): """ Write an unpacked value into a string buffer for given 3-byte sequence. """ # don't overwrite more of the old string than the length of the new string num = min(num, len(val)) # ensure the length of val is num, cut off any extra characters val = val[:num] length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if offset + num > length: num = length - offset if num <= 0: return if address >= memory.var_start(): # string stored in string space state.basic_state.strings.retrieve(sequence)[offset:offset+num] = val else: # string stored in field buffers # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset field_offset = start % memory.field_mem_offset try: state.io_state.fields[number][field_offset+offset:field_offset+offset+num] = val except KeyError, IndexError: raise KeyError('Not a field string')
def set_memory(addr, val): """ Set the value at an emulated memory location. """ if addr >= memory.rom_segment * 0x10: # ROM includes font memory pass elif addr >= memory.ram_font_segment * 0x10: # RAM font memory set_font_memory(addr, val) elif addr >= memory.video_segment * 0x10: # graphics and text memory set_video_memory(addr, val) elif addr >= memory.data_segment * 0x10 + memory.var_start(): # POKING in variables set_data_memory(addr, val) elif addr >= memory.data_segment * 0x10 + memory.code_start: # code memory set_code_memory(addr, val) elif addr >= memory.data_segment * 0x10 + memory.field_mem_start: # file & FIELD memory set_field_memory(addr, val) elif addr >= memory.data_segment * 0x10: set_basic_memory(addr, val) elif addr >= low_segment * 0x10: set_low_memory(addr, val) else: pass
def get_memory(addr): """ Retrieve the value at an emulated memory location. """ try: # try if there's a preset value return peek_values[addr] except KeyError: if addr >= memory.rom_segment * 0x10: # ROM font return max(0, get_rom_memory(addr)) elif addr >= memory.ram_font_segment * 0x10: # RAM font return max(0, get_font_memory(addr)) elif addr >= memory.video_segment * 0x10: # graphics and text memory return max(0, get_video_memory(addr)) elif addr >= memory.data_segment * 0x10 + memory.var_start(): # variable memory return max(0, get_data_memory(addr)) elif addr >= memory.data_segment * 0x10 + memory.code_start: # code memory return max(0, get_code_memory(addr)) elif addr >= memory.data_segment * 0x10 + memory.field_mem_start: # file & FIELD memory return max(0, get_field_memory(addr)) elif addr >= memory.data_segment * 0x10: # other BASIC data memory return max(0, get_basic_memory(addr)) elif addr >= low_segment * 0x10: return max(0, get_low_memory(addr)) else: return 0
def string_assign_unpacked_into(sequence, offset, num, val): """ Write an unpacked value into a string buffer for given 3-byte sequence. """ # don't overwrite more of the old string than the length of the new string num = min(num, len(val)) # ensure the length of val is num, cut off any extra characters val = val[:num] length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if offset + num > length: num = length - offset if num <= 0: return if address >= memory.var_start(): # string stored in string space state.basic_state.strings.retrieve(sequence)[offset:offset + num] = val else: # string stored in field buffers # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset field_offset = start % memory.field_mem_offset try: state.io_state.fields[number].buffer[field_offset + offset:field_offset + offset + num] = val except KeyError, IndexError: raise KeyError('Not a field string')
def clear_variables(preserve_common=False, preserve_all=False, preserve_deftype=False): """ Reset and clear variables, arrays, common definitions and functions. """ if not preserve_deftype: # deftype is not preserved on CHAIN with ALL, but is preserved with MERGE state.basic_state.deftype = ['!']*26 if not preserve_all: if preserve_common: # preserve COMMON variables (CHAIN does this) common, common_arrays = {}, {} for varname in state.basic_state.common_names: try: common[varname] = state.basic_state.variables[varname] except KeyError: pass for varname in state.basic_state.common_array_names: try: common_arrays[varname] = state.basic_state.arrays[varname] except KeyError: pass else: # clear option base state.basic_state.array_base = None common = {} common_arrays = {} # at least I think these should be cleared by CLEAR? state.basic_state.common_names = [] state.basic_state.common_array_names = [] # restore only common variables # this is a re-assignment which is not FOR-safe; but clear_variables is only called in CLEAR which also clears the FOR stack state.basic_state.variables = {} state.basic_state.arrays = {} state.basic_state.var_memory = {} state.basic_state.array_memory = {} state.basic_state.var_current = memory.var_start() # arrays are always kept after all vars state.basic_state.array_current = 0 # functions are cleared except when CHAIN ... ALL is specified state.basic_state.functions = {} # reset string space new_strings = StringSpace() # preserve common variables # use set_scalar and dim_array to rebuild memory model for v in common: full_var = (v[-1], common[v]) if v[-1] == '$': full_var = new_strings.store(copy_str(full_var)) set_scalar(v, full_var) for a in common_arrays: dim_array(a, common_arrays[a][0]) if a[-1] == '$': s = bytearray() for i in range(0, len(common_arrays[a][1]), vartypes.byte_size['$']): old_ptr = vartypes.bytes_to_string(common_arrays[a][1][i:i+vartypes.byte_size['$']]) new_ptr = new_strings.store(copy_str(old_ptr)) s += vartypes.string_to_bytes(new_ptr) state.basic_state.arrays[a][1] = s else: state.basic_state.arrays[a] = common_arrays[a] state.basic_state.strings = new_strings
def set_str(basic_string, in_str, offset=None, num=None): """ Assign a new string into an existing buffer. """ # if it is a code literal, we now do need to allocate space for a copy address = vartypes.string_address(basic_string) if address >= memory.code_start and address < memory.var_start(): basic_string = state.basic_state.strings.store(copy_str(basic_string)) if num is None: view_str(basic_string)[:] = in_str else: view_str(basic_string)[offset:offset+num] = in_str return basic_string
def get_string_copy_packed(sequence): """ Return a packed copy of a string from its 3-byte sequence. """ length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if address >= memory.var_start(): # string is stored in string space return state.basic_state.strings.copy_packed(sequence) else: # string is stored in code space or field buffers if address < memory.field_mem_start: return vartypes.pack_string('\0' * length) # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset offset = start % memory.field_mem_offset try: return vartypes.pack_string(state.io_state.fields[number][offset:offset+length]) except KeyError, IndexError: return vartypes.pack_string('\0' * length)
def get_string_copy_packed(sequence): """ Return a packed copy of a string from its 3-byte sequence. """ length = ord(sequence[0:1]) address = vartypes.uint_to_value(sequence[-2:]) if address >= memory.var_start(): # string is stored in string space return state.basic_state.strings.copy_packed(sequence) else: # string is stored in code space or field buffers if address < memory.field_mem_start: return vartypes.pack_string('\0' * length) # find the file we're in start = address - memory.field_mem_start number = 1 + start // memory.field_mem_offset offset = start % memory.field_mem_offset try: return vartypes.pack_string( state.io_state.fields[number].buffer[offset:offset + length]) except KeyError, IndexError: return vartypes.pack_string('\0' * length)