Exemple #1
0
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)
Exemple #2
0
 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
Exemple #3
0
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)
Exemple #4
0
 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
Exemple #5
0
 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)
Exemple #6
0
 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)
Exemple #7
0
 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)
Exemple #8
0
 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)
Exemple #9
0
 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
Exemple #10
0
 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)
Exemple #11
0
 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)
Exemple #12
0
 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
Exemple #13
0
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
Exemple #14
0
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))
Exemple #15
0
 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
Exemple #16
0
 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
Exemple #17
0
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
Exemple #18
0
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
Exemple #19
0
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)
Exemple #20
0
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()
Exemple #21
0
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()
Exemple #22
0
 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 ''
Exemple #23
0
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
Exemple #24
0
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
Exemple #25
0
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
Exemple #26
0
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
Exemple #27
0
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
Exemple #28
0
 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
Exemple #29
0
def _get_integer(snapshot, i):
    if snapshot[i + 1]:
        return get_word(snapshot, i + 2) - 65536
    return get_word(snapshot, i + 2)
Exemple #30
0
def _get_integer(snapshot, i):
    if snapshot[i + 1]:
        return get_word(snapshot, i + 2) - 65536
    return get_word(snapshot, i + 2)
Exemple #31
0
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
Exemple #32
0
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
Exemple #33
0
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)
Exemple #34
0
 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
Exemple #35
0
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
Exemple #36
0
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
Exemple #37
0
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)