def _read_z80(z80file): data = read_bin_file(z80file) if get_word(data, 6) > 0: header = data[:30] else: header_len = 32 + get_word(data, 30) header = data[:header_len] return list(header), get_snapshot(z80file)
def _get_num_array_var(self, name, i): v_start = i + 4 + 2 * self.snapshot[i + 3] v_end = i + 3 + get_word(self.snapshot, i + 1) dims = [get_word(self.snapshot, c) for c in range(i + 4, v_start, 2)] dims_str = ','.join([str(d) for d in dims]) values = _unflatten([_get_number(self.snapshot, c) for c in range(v_start, v_end, 5)], dims) line = '{}({})={}'.format(name, dims_str, values) return v_end, line
def _get_num_array_var(self, name, i): v_start = i + 4 + 2 * self.snapshot[i + 3] v_end = i + 3 + get_word(self.snapshot, i + 1) dims = [get_word(self.snapshot, c) for c in range(i + 4, v_start, 2)] dims_str = ','.join([str(d) for d in dims]) values = _unflatten( [_get_number(self.snapshot, c) for c in range(v_start, v_end, 5)], dims) line = '{}({})={}'.format(name, dims_str, values) return v_end, line
def test_tzx_block_0x12(self): block = [18] # Block ID block.extend((2, 2)) # Pulse length block.extend((3, 3)) # Number of pulses exp_output = """ 1: Pure tone (0x12) Pulse length: {} T-states Pulses: {} """.format(get_word(block, 1), get_word(block, 3)) self._test_tzx_block(block, exp_output)
def test_tzx_block_0x12(self): block = [18] # Block ID block.extend((2, 2)) # Pulse length block.extend((3, 3)) # Number of pulses exp_output = [ '1: Pure tone (0x12)', ' Pulse length: {} T-states'.format(get_word(block, 1)), ' Pulses: {}'.format(get_word(block, 3)) ] self._test_tzx_block(block, exp_output)
def _get_char_array_var(self, name, i): v_start = i + 4 + 2 * self.snapshot[i + 3] v_end = i + 3 + get_word(self.snapshot, i + 1) dims = [get_word(self.snapshot, c) for c in range(i + 4, v_start, 2)] dims_str = ','.join([str(d) for d in dims]) str_len = dims[-1] strings = [''.join([self.text.get_chars(self.snapshot[k]) for k in range(j, j + str_len)]) for j in range(v_start, v_end, str_len)] if len(dims) > 1: values = _unflatten(strings, dims[:-1]) else: values = strings[0] line = '{}$({})={!r}'.format(name, dims_str, values) return v_end, line
def list_variables(self, snapshot): lines = [] self.snapshot = snapshot i = snapshot[23627] + 256 * snapshot[23628] while i < len(snapshot) and snapshot[i] != 128: self.text.lspace = True varname = chr((snapshot[i] & 31) + 96) variable_type = snapshot[i] & 224 if variable_type == 64: # String (010xxxxx) i, line = self._get_string_var(varname, i) elif variable_type == 128: # Array of numbers (100xxxxx) i, line = self._get_num_array_var(varname, i) elif variable_type == 160: # Number whose name is longer than one letter (101xxxxx) i, line = self._get_long_num_var(varname, i) elif variable_type == 192: # Array of characters (110xxxxx) i, line = self._get_char_array_var(varname, i) elif variable_type == 224: # Control variable of a FOR-NEXT loop (111xxxxx) i, line = self._get_control_var(varname, i) elif variable_type == 96: # Number whose name is one letter (011xxxxx) i, line = self._get_short_num_var(varname, i) else: # Basic line (00xxxxxx) i += get_word(snapshot, i + 2) + 4 continue lines.append(line) return '\n'.join(lines)
def _get_control_var(self, name, i): value = _get_number(self.snapshot, i + 1) limit = _get_number(self.snapshot, i + 6) step = _get_number(self.snapshot, i + 11) line_number = get_word(self.snapshot, i + 16) statement = self.snapshot[i + 18] line = '{}={} (limit={}, step={}, line={}, statement={})'.format(name, value, limit, step, line_number, statement) return i + 19, line
def _analyse_tap(tap): i = 0 block_num = 1 while i < len(tap): block_len = get_word(tap, i) _print_block(block_num, tap[i + 2 : i + 2 + block_len]) i += block_len + 2 block_num += 1
def _print_block(index, data, show_data, info=(), block_id=None, header=None): if block_id is None: print("{}:".format(index)) else: print("{}: {} (0x{:02X})".format(index, header, block_id)) for line in info: _print_info(line) if data and block_id in (None, 16): data_type = "Unknown" name_str = None start = None if len(data) == 19 and data[0] == 0: block_type = data[1] if block_type == 0: name_str = 'Program' elif block_type == 1: name_str = 'Number array' elif block_type == 2: name_str = 'Character array' elif block_type == 3: name_str = 'Bytes' size = get_word(data, 12) start = get_word(data, 14) if name_str: data_type = "Header block" name = _get_str(data[2:12]) elif data[0] == 255: data_type = "Data block" _print_info("Type: {}".format(data_type)) if name_str: _print_info("{}: {}".format(name_str, name)) if start is not None: _print_info("CODE: {},{}".format(start, size)) if data: _print_info("Length: {}".format(len(data))) if show_data: for line in _hex_dump(data): _print_info(line) else: if len(data) > 14: data_summary = "{} ... {}".format(_bytes_to_str(data[:7]), _bytes_to_str(data[-7:])) else: data_summary = _bytes_to_str(data) _print_info("Data: {}".format(data_summary))
def _get_char_array_var(self, name, i): v_start = i + 4 + 2 * self.snapshot[i + 3] v_end = i + 3 + get_word(self.snapshot, i + 1) dims = [get_word(self.snapshot, c) for c in range(i + 4, v_start, 2)] dims_str = ','.join([str(d) for d in dims]) str_len = dims[-1] strings = [ ''.join([ self.text.get_chars(self.snapshot[k]) for k in range(j, j + str_len) ]) for j in range(v_start, v_end, str_len) ] if len(dims) > 1: values = _unflatten(strings, dims[:-1]) else: values = strings[0] line = '{}$({})={!r}'.format(name, dims_str, values) return v_end, line
def _get_control_var(self, name, i): value = _get_number(self.snapshot, i + 1) limit = _get_number(self.snapshot, i + 6) step = _get_number(self.snapshot, i + 11) line_number = get_word(self.snapshot, i + 16) statement = self.snapshot[i + 18] line = '{}={} (limit={}, step={}, line={}, statement={})'.format( name, value, limit, step, line_number, statement) return i + 19, line
def _analyse_tap(tap, basic_block, show_data): i = 0 block_num = 1 while i < len(tap): block_len = get_word(tap, i) data = tap[i + 2:i + 2 + block_len] if basic_block: _list_basic(block_num, data, *basic_block) else: _print_block(block_num, data, show_data) i += block_len + 2 block_num += 1
def _analyse_tap(tap, basic_block): i = 0 block_num = 1 while i < len(tap): block_len = get_word(tap, i) data = tap[i + 2:i + 2 + block_len] if basic_block: _list_basic(block_num, data, *basic_block) else: _print_block(block_num, data) i += block_len + 2 block_num += 1
def _print_block(index, data, info=(), block_id=None, header=None): if block_id is None: print("{}:".format(index)) else: print("{}: {} (0x{:02X})".format(index, header, block_id)) if data and block_id in (None, 16): data_type = "Unknown" name_str = None start = None if len(data) == 19 and data[0] == 0: block_type = data[1] if block_type == 0: name_str = "Program" elif block_type == 1: name_str = "Number array" elif block_type == 2: name_str = "Character array" elif block_type == 3: name_str = "Bytes" size = get_word(data, 12) start = get_word(data, 14) if name_str: data_type = "Header block" name = _get_str(data[2:12]) elif data[0] == 255: data_type = "Data block" _print_info("Type: {}".format(data_type)) if name_str: _print_info("{}: {}".format(name_str, name)) if start is not None: _print_info("CODE: {},{}".format(start, size)) if data: _print_info("Length: {}".format(len(data))) if len(data) > 14: data_summary = "{} ... {}".format(_bytes_to_str(data[:7]), _bytes_to_str(data[-7:])) else: data_summary = _bytes_to_str(data) _print_info("Data: {}".format(data_summary)) for line in info: _print_info(line)
def _print_z80r(block, variables): lines = [] lines.append('Interrupts: {}abled'.format('en' if block[27] else 'dis')) lines.append('Interrupt mode: {}'.format(block[28])) reg = Registers() reg.f = block[0] reg.a = block[1] reg.bc = get_word(block, 2) reg.de = get_word(block, 4) reg.hl = get_word(block, 6) reg.f2 = block[8] reg.a2 = block[9] reg.bc2 = get_word(block, 10) reg.de2 = get_word(block, 12) reg.hl2 = get_word(block, 14) reg.ix = get_word(block, 16) reg.iy = get_word(block, 18) reg.sp = get_word(block, 20) reg.pc = get_word(block, 22) reg.i = block[24] reg.r = block[25] return lines + reg.get_lines()
def _get_fp_num(self, i): num_str = self._get_num_str(i - 1) if num_str: if self.snapshot[i + 1] == 0: # Small integer (unsigned) num = get_word(self.snapshot, i + 3) else: # Floating point number (unsigned) exponent = self.snapshot[i + 1] - 160 mantissa = float(16777216 * (self.snapshot[i + 2] | 128) + 65536 * self.snapshot[i + 3] + 256 * self.snapshot[i + 4] + self.snapshot[i + 5]) num = mantissa * (2 ** exponent) if num and abs(1 - float(num_str) / num) > 1e-9: return '{{{}}}'.format(num) return ''
def _print_ramp(block, variables): lines = [] flags = get_word(block, 0) compressed = 'compressed' if flags & 1 else 'uncompressed' page = block[2] ram = block[3:] lines.append("Page: {}".format(page)) machine_id = variables['chMachineId'] addresses = '' if page == 5: addresses = '16384-32767 4000-7FFF' elif page == 2: addresses = '32768-49151 8000-BFFF' elif machine_id > 1 and page == variables['ch7ffd'] & 7: addresses = '49152-65535 C000-FFFF' if addresses: addresses += ': ' lines.append("RAM: {}{} bytes, {}".format(addresses, len(ram), compressed)) return lines
def _get_tzx_block(data, i): # http://www.worldofspectrum.org/TZXformat.html block_id = data[i] tape_data = None i += 1 if block_id == 16: # Standard speed data block length = get_word(data, i + 2) tape_data = data[i + 4:i + 4 + length] i += 4 + length elif block_id == 17: # Turbo speed data block length = get_word3(data, i + 15) tape_data = data[i + 18:i + 18 + length] i += 18 + length elif block_id == 18: # Pure tone i += 4 elif block_id == 19: # Sequence of pulses of various lengths i += 2 * data[i] + 1 elif block_id == 20: # Pure data block length = get_word3(data, i + 7) tape_data = data[i + 10:i + 10 + length] i += 10 + length elif block_id == 21: # Direct recording block i += get_word3(data, i + 5) + 8 elif block_id == 24: # CSW recording block i += get_dword(data, i) + 4 elif block_id == 25: # Generalized data block i += get_dword(data, i) + 4 elif block_id == 32: # Pause (silence) or 'Stop the tape' command i += 2 elif block_id == 33: # Group start i += data[i] + 1 elif block_id == 34: # Group end pass elif block_id == 35: # Jump to block i += 2 elif block_id == 36: # Loop start i += 2 elif block_id == 37: # Loop end pass elif block_id == 38: # Call sequence i += get_word(data, i) * 2 + 2 elif block_id == 39: # Return from sequence pass elif block_id == 40: # Select block i += get_word(data, i) + 2 elif block_id == 42: # Stop the tape if in 48K mode i += 4 elif block_id == 43: # Set signal level i += 5 elif block_id == 48: # Text description i += data[i] + 1 elif block_id == 49: # Message block i += data[i + 1] + 2 elif block_id == 50: # Archive info i += get_word(data, i) + 2 elif block_id == 51: # Hardware type i += data[i] * 3 + 1 elif block_id == 53: # Custom info block i += get_dword(data, i + 16) + 20 elif block_id == 90: # "Glue" block i += 9 else: raise TapeError('Unknown TZX block ID: 0x{:X}'.format(block_id)) return i, tape_data
def _get_block_info(data, i, block_num): # http://www.worldofspectrum.org/TZXformat.html block_id = data[i] info = [] tape_data = [] i += 1 if block_id == 16: header = "Standard speed data" length = get_word(data, i + 2) tape_data = data[i + 4 : i + 4 + length] i += 4 + length elif block_id == 17: header = "Turbo speed data" length = get_word3(data, i + 15) tape_data = data[i + 18 : i + 18 + length] i += 18 + length elif block_id == 18: header = "Pure tone" info.append("Pulse length: {} T-states".format(get_word(data, i))) info.append("Pulses: {}".format(get_word(data, i + 2))) i += 4 elif block_id == 19: header = "Pulse sequence" info.append("Pulses: {}".format(data[i])) i += 2 * data[i] + 1 elif block_id == 20: header = "Pure data" length = get_word3(data, i + 7) tape_data = data[i + 10 : i + 10 + length] i += length + 10 elif block_id == 21: header = "Direct recording" i += get_word3(data, i + 5) + 8 elif block_id == 24: header = "CSW recording" i += get_dword(data, i) + 4 elif block_id == 25: header = "Generalized data" i += get_dword(data, i) + 4 elif block_id == 32: duration = get_word(data, i) if duration: header = "Pause (silence)" info.append("Duration: {}ms".format(duration)) else: header = "'Stop the tape' command" i += 2 elif block_id == 33: header = "Group start" length = data[i] info.extend(_format_text("Name", data, i + 1, length)) i += length + 1 elif block_id == 34: header = "Group end" elif block_id == 35: header = "Jump to block" offset = get_word(data, i) if offset > 32767: offset -= 65536 info.append("Destination block: {}".format(block_num + offset)) i += 2 elif block_id == 36: header = "Loop start" info.append("Repetitions: {}".format(get_word(data, i))) i += 2 elif block_id == 37: header = "Loop end" elif block_id == 38: header = "Call sequence" i += get_word(data, i) * 2 + 2 elif block_id == 39: header = "Return from sequence" elif block_id == 40: header = "Select block" index = i + 3 for j in range(data[i + 2]): offset = get_word(data, index) length = data[index + 2] prefix = "Option {} (block {})".format(j + 1, block_num + offset) info.extend(_format_text(prefix, data, index + 3, length)) index += length + 3 i += get_word(data, i) + 2 elif block_id == 42: header = "Stop the tape if in 48K mode" i += 4 elif block_id == 43: header = "Set signal level" i += 5 elif block_id == 48: header = "Text description" length = data[i] info.extend(_format_text("Text", data, i + 1, length)) i += length + 1 elif block_id == 49: header = "Message" length = data[i + 1] info.extend(_format_text("Message", data, i + 2, length)) i += length + 2 elif block_id == 50: header = "Archive info" num_strings = data[i + 2] j = i + 3 for k in range(num_strings): try: str_len = data[j + 1] except IndexError: raise SkoolKitError("Unexpected end of file") info.extend(_format_text(ARCHIVE_INFO.get(data[j], str(data[j])), data, j + 2, str_len)) j += 2 + str_len i += get_word(data, i) + 2 elif block_id == 51: header = "Hardware type" i += data[i] * 3 + 1 elif block_id == 53: header = "Custom info" i += get_dword(data, i + 16) + 20 elif block_id == 90: header = '"Glue" block' i += 9 else: raise SkoolKitError("Unknown block ID: 0x{:02X}".format(block_id)) return i, block_id, header, info, tape_data
def _get_block_info(data, i, block_num): # https://worldofspectrum.net/features/TZXformat.html block_id = data[i] info = [] tape_data = [] i += 1 if block_id == 16: header = 'Standard speed data' length = get_word(data, i + 2) tape_data = data[i + 4:i + 4 + length] i += 4 + length elif block_id == 17: header = 'Turbo speed data' length = get_word3(data, i + 15) tape_data = data[i + 18:i + 18 + length] i += 18 + length elif block_id == 18: header = 'Pure tone' info.append('Pulse length: {} T-states'.format(get_word(data, i))) info.append('Pulses: {}'.format(get_word(data, i + 2))) i += 4 elif block_id == 19: header = 'Pulse sequence' num_pulses = data[i] i += 1 for pulse in range(num_pulses): info.append('Pulse {}/{}: {}'.format(pulse + 1, num_pulses, get_word(data, i))) i += 2 elif block_id == 20: header = 'Pure data' info.append('0-pulse: {}'.format(get_word(data, i))) info.append('1-pulse: {}'.format(get_word(data, i + 2))) info.append('Used bits in last byte: {}'.format(data[i + 4])) info.append('Pause: {}ms'.format(get_word(data, i + 5))) length = get_word3(data, i + 7) tape_data = data[i + 10:i + 10 + length] i += length + 10 elif block_id == 21: header = 'Direct recording' i += get_word3(data, i + 5) + 8 elif block_id == 24: header = 'CSW recording' i += get_dword(data, i) + 4 elif block_id == 25: header = 'Generalized data' i += get_dword(data, i) + 4 elif block_id == 32: duration = get_word(data, i) if duration: header = "Pause (silence)" info.append('Duration: {}ms'.format(duration)) else: header = "'Stop the tape' command" i += 2 elif block_id == 33: header = 'Group start' length = data[i] info.extend(_format_text('Name', data, i + 1, length)) i += length + 1 elif block_id == 34: header = 'Group end' elif block_id == 35: header = 'Jump to block' offset = get_word(data, i) if offset > 32767: offset -= 65536 info.append('Destination block: {}'.format(block_num + offset)) i += 2 elif block_id == 36: header = 'Loop start' info.append('Repetitions: {}'.format(get_word(data, i))) i += 2 elif block_id == 37: header = 'Loop end' elif block_id == 38: header = 'Call sequence' i += get_word(data, i) * 2 + 2 elif block_id == 39: header = 'Return from sequence' elif block_id == 40: header = 'Select block' index = i + 3 for j in range(data[i + 2]): offset = get_word(data, index) length = data[index + 2] prefix = 'Option {} (block {})'.format(j + 1, block_num + offset) info.extend(_format_text(prefix, data, index + 3, length)) index += length + 3 i += get_word(data, i) + 2 elif block_id == 42: header = 'Stop the tape if in 48K mode' i += 4 elif block_id == 43: header = 'Set signal level' i += 5 elif block_id == 48: header = 'Text description' length = data[i] info.extend(_format_text('Text', data, i + 1, length)) i += length + 1 elif block_id == 49: header = 'Message' length = data[i + 1] info.extend(_format_text('Message', data, i + 2, length)) i += length + 2 elif block_id == 50: header = 'Archive info' num_strings = data[i + 2] j = i + 3 for k in range(num_strings): try: str_len = data[j + 1] except IndexError: raise SkoolKitError('Unexpected end of file') info.extend( _format_text(ARCHIVE_INFO.get(data[j], str(data[j])), data, j + 2, str_len)) j += 2 + str_len i += get_word(data, i) + 2 elif block_id == 51: header = 'Hardware type' i += 1 for j in range(data[i - 1]): hw_type, hw_ids = HARDWARE_TYPE.get(data[i], ('Unknown', {})) info.extend(('- Type: {}'.format(hw_type), ' Name: {}'.format( hw_ids.get(data[i + 1], 'Unknown')), ' Info: {}'.format( HARDWARE_INFO[data[i] > 0].get(data[i + 2], 'Unknown')))) i += 3 elif block_id == 53: header = 'Custom info' ident = _get_str(data[i:i + 16]).strip() length = get_dword(data, i + 16) info.extend(_format_text(ident, data, i + 20, length, True)) i += length + 20 elif block_id == 90: header = '"Glue" block' i += 9 else: raise SkoolKitError('Unknown block ID: 0x{:02X}'.format(block_id)) return i, block_id, header, info, tape_data
def _get_string_var(self, name, i): end = i + 3 + get_word(self.snapshot, i + 1) value = ''.join([self.text.get_chars(c) for c in self.snapshot[i + 3:end]]) line = '{}$="{}"'.format(name, value) return end, line
def _get_integer(snapshot, i): if snapshot[i + 1]: return get_word(snapshot, i + 2) - 65536 return get_word(snapshot, i + 2)
def _get_block_info(data, i, block_num): # http://www.worldofspectrum.org/TZXformat.html block_id = data[i] info = [] tape_data = [] i += 1 if block_id == 16: header = 'Standard speed data' length = get_word(data, i + 2) tape_data = data[i + 4:i + 4 + length] i += 4 + length elif block_id == 17: header = 'Turbo speed data' length = get_word3(data, i + 15) tape_data = data[i + 18:i + 18 + length] i += 18 + length elif block_id == 18: header = 'Pure tone' info.append('Pulse length: {} T-states'.format(get_word(data, i))) info.append('Pulses: {}'.format(get_word(data, i + 2))) i += 4 elif block_id == 19: header = 'Pulse sequence' num_pulses = data[i] i += 1 for pulse in range(num_pulses): info.append('Pulse {}/{}: {}'.format(pulse + 1, num_pulses, get_word(data, i))) i += 2 elif block_id == 20: header = 'Pure data' info.append('0-pulse: {}'.format(get_word(data, i))) info.append('1-pulse: {}'.format(get_word(data, i + 2))) info.append('Used bits in last byte: {}'.format(data[i + 4])) info.append('Pause: {}ms'.format(get_word(data, i + 5))) length = get_word3(data, i + 7) tape_data = data[i + 10:i + 10 + length] i += length + 10 elif block_id == 21: header = 'Direct recording' i += get_word3(data, i + 5) + 8 elif block_id == 24: header = 'CSW recording' i += get_dword(data, i) + 4 elif block_id == 25: header = 'Generalized data' i += get_dword(data, i) + 4 elif block_id == 32: duration = get_word(data, i) if duration: header = "Pause (silence)" info.append('Duration: {}ms'.format(duration)) else: header = "'Stop the tape' command" i += 2 elif block_id == 33: header = 'Group start' length = data[i] info.extend(_format_text('Name', data, i + 1, length)) i += length + 1 elif block_id == 34: header = 'Group end' elif block_id == 35: header = 'Jump to block' offset = get_word(data, i) if offset > 32767: offset -= 65536 info.append('Destination block: {}'.format(block_num + offset)) i += 2 elif block_id == 36: header = 'Loop start' info.append('Repetitions: {}'.format(get_word(data, i))) i += 2 elif block_id == 37: header = 'Loop end' elif block_id == 38: header = 'Call sequence' i += get_word(data, i) * 2 + 2 elif block_id == 39: header = 'Return from sequence' elif block_id == 40: header = 'Select block' index = i + 3 for j in range(data[i + 2]): offset = get_word(data, index) length = data[index + 2] prefix = 'Option {} (block {})'.format(j + 1, block_num + offset) info.extend(_format_text(prefix, data, index + 3, length)) index += length + 3 i += get_word(data, i) + 2 elif block_id == 42: header = 'Stop the tape if in 48K mode' i += 4 elif block_id == 43: header = 'Set signal level' i += 5 elif block_id == 48: header = 'Text description' length = data[i] info.extend(_format_text('Text', data, i + 1, length)) i += length + 1 elif block_id == 49: header = 'Message' length = data[i + 1] info.extend(_format_text('Message', data, i + 2, length)) i += length + 2 elif block_id == 50: header = 'Archive info' num_strings = data[i + 2] j = i + 3 for k in range(num_strings): try: str_len = data[j + 1] except IndexError: raise SkoolKitError('Unexpected end of file') info.extend(_format_text(ARCHIVE_INFO.get(data[j], str(data[j])), data, j + 2, str_len)) j += 2 + str_len i += get_word(data, i) + 2 elif block_id == 51: header = 'Hardware type' i += data[i] * 3 + 1 elif block_id == 53: header = 'Custom info' i += get_dword(data, i + 16) + 20 elif block_id == 90: header = '"Glue" block' i += 9 else: raise SkoolKitError('Unknown block ID: 0x{:02X}'.format(block_id)) return i, block_id, header, info, tape_data
def _analyse_z80(z80file): data = read_bin_file(z80file) # Extract header and RAM block(s) if get_word(data, 6) > 0: version = 1 header = data[:30] ram_blocks = data[30:] else: header_len = 32 + get_word(data, 30) header = data[:header_len] ram_blocks = data[header_len:] version = 2 if header_len == 55 else 3 # Print file name, version, machine, interrupt status, border, port $7FFD print('Z80 file: {}'.format(z80file)) print('Version: {}'.format(version)) bank = None if version == 1: machine = '48K Spectrum' block_dict = BLOCK_ADDRESSES_48K else: machine_dict = V2_MACHINES if version == 2 else V3_MACHINES machine_id = header[34] index = header[37] // 128 machine_spec = machine_dict.get(machine_id, MACHINES.get(machine_id, ('Unknown', 'Unknown', True))) machine = machine_spec[index] if machine_spec[2]: block_dict = BLOCK_ADDRESSES_48K else: block_dict = BLOCK_ADDRESSES_128K bank = header[35] & 7 print('Machine: {}'.format(machine)) print('Interrupts: {}abled'.format('en' if header[28] else 'dis')) print('Interrupt mode: {}'.format(header[29] & 3)) print('Border: {}'.format((header[12] // 2) & 7)) if bank is not None: print('Port $7FFD: {} - bank {} (block {}) paged into 49152-65535 C000-FFFF'.format(header[35], bank, bank + 3)) # Print register contents reg = Registers() reg.a = header[0] reg.f = header[1] reg.bc = get_word(header, 2) reg.hl = get_word(header, 4) if version == 1: reg.pc = get_word(header, 6) else: reg.pc = get_word(header, 32) reg.sp = get_word(header, 8) reg.i = header[10] reg.r = 128 * (header[12] & 1) + (header[11] & 127) reg.de = get_word(header, 13) reg.bc2 = get_word(header, 15) reg.de2 = get_word(header, 17) reg.hl2 = get_word(header, 19) reg.a2 = header[21] reg.f2 = header[22] reg.iy = get_word(header, 23) reg.ix = get_word(header, 25) print('Registers:') for line in reg.get_lines(): print(' ' + line) # Print RAM block info if version == 1: block_len = len(ram_blocks) prefix = '' if header[12] & 32 else 'un' print('48K RAM block (16384-65535 4000-FFFF): {} bytes ({}compressed)'.format(block_len, prefix)) else: i = 0 while i < len(ram_blocks): block_len = get_word(ram_blocks, i) page_num = ram_blocks[i + 2] addr_range = block_dict.get(page_num) if addr_range is None and page_num - 3 == bank: addr_range = '49152-65535 C000-FFFF' if addr_range: addr_range = ' ({})'.format(addr_range) else: addr_range = '' i += 3 if block_len == 65535: block_len = 16384 prefix = 'un' else: prefix = '' print('RAM block {}{}: {} bytes ({}compressed)'.format(page_num, addr_range, block_len, prefix)) i += block_len
def _analyse_sna(snafile): sna = read_bin_file(snafile, 147488) if len(sna) not in (49179, 131103, 147487): raise SkoolKitError('{}: not a SNA file'.format(snafile)) is128 = len(sna) > 49179 print('RAM: {}K'.format(128 if is128 else 48)) print('Interrupts: {}abled'.format('en' if sna[19] & 4 else 'dis')) print('Interrupt mode: {}'.format(sna[25])) print('Border: {}'.format(sna[26] & 7)) # Print register contents reg = Registers() reg.i = sna[0] reg.hl2 = get_word(sna, 1) reg.de2 = get_word(sna, 3) reg.bc2 = get_word(sna, 5) reg.f2 = sna[7] reg.a2 = sna[8] reg.hl = get_word(sna, 9) reg.de = get_word(sna, 11) reg.bc = get_word(sna, 13) reg.iy = get_word(sna, 15) reg.ix = get_word(sna, 17) reg.r = sna[20] reg.f = sna[21] reg.a = sna[22] reg.sp = get_word(sna, 23) if is128: reg.pc = get_word(sna, 49179) else: reg.pc = get_word(sna, reg.sp - 16357) print('Registers:') for line in reg.get_lines(): print(' ' + line) if is128: _print_ram_banks(sna)
def _get_string_var(self, name, i): end = i + 3 + get_word(self.snapshot, i + 1) value = ''.join( [self.text.get_chars(c) for c in self.snapshot[i + 3:end]]) line = '{}$="{}"'.format(name, value) return end, line
def _analyse_z80(z80file): data = read_bin_file(z80file) # Extract header and RAM block(s) if get_word(data, 6) > 0: version = 1 header = data[:30] ram_blocks = data[30:] else: header_len = 32 + get_word(data, 30) header = data[:header_len] ram_blocks = data[header_len:] version = 2 if header_len == 55 else 3 # Print file name, version, machine, interrupt status, border, port $7FFD print('Z80 file: {}'.format(z80file)) print('Version: {}'.format(version)) bank = None if version == 1: machine = '48K Spectrum' block_dict = BLOCK_ADDRESSES_48K else: machine_dict = V2_MACHINES if version == 2 else V3_MACHINES machine_id = header[34] index = header[37] // 128 machine_spec = machine_dict.get( machine_id, MACHINES.get(machine_id, ('Unknown', 'Unknown', True))) machine = machine_spec[index] if machine_spec[2]: block_dict = BLOCK_ADDRESSES_48K else: block_dict = BLOCK_ADDRESSES_128K bank = header[35] & 7 print('Machine: {}'.format(machine)) print('Interrupts: {}abled'.format('en' if header[28] else 'dis')) print('Interrupt mode: {}'.format(header[29] & 3)) print('Border: {}'.format((header[12] // 2) & 7)) if bank is not None: print( 'Port $7FFD: {} - bank {} (block {}) paged into 49152-65535 C000-FFFF' .format(header[35], bank, bank + 3)) # Print register contents reg = Registers() reg.a = header[0] reg.f = header[1] reg.bc = get_word(header, 2) reg.hl = get_word(header, 4) if version == 1: reg.pc = get_word(header, 6) else: reg.pc = get_word(header, 32) reg.sp = get_word(header, 8) reg.i = header[10] reg.r = 128 * (header[12] & 1) + (header[11] & 127) reg.de = get_word(header, 13) reg.bc2 = get_word(header, 15) reg.de2 = get_word(header, 17) reg.hl2 = get_word(header, 19) reg.a2 = header[21] reg.f2 = header[22] reg.iy = get_word(header, 23) reg.ix = get_word(header, 25) print('Registers:') for line in reg.get_lines(): print(' ' + line) # Print RAM block info if version == 1: block_len = len(ram_blocks) prefix = '' if header[12] & 32 else 'un' print('48K RAM block (16384-65535 4000-FFFF): {} bytes ({}compressed)'. format(block_len, prefix)) else: i = 0 while i < len(ram_blocks): block_len = get_word(ram_blocks, i) page_num = ram_blocks[i + 2] addr_range = block_dict.get(page_num) if addr_range is None and page_num - 3 == bank: addr_range = '49152-65535 C000-FFFF' if addr_range: addr_range = ' ({})'.format(addr_range) else: addr_range = '' i += 3 if block_len == 65535: block_len = 16384 prefix = 'un' else: prefix = '' print('RAM block {}{}: {} bytes ({}compressed)'.format( page_num, addr_range, block_len, prefix)) i += block_len