Esempio n. 1
0
def poke(snapshot, param_str):
    try:
        addr, val = param_str.split(',', 1)
    except ValueError:
        raise SkoolKitError("Value missing in poke spec: {}".format(param_str))
    try:
        if val.startswith('^'):
            value = get_int_param(val[1:])
            poke_f = lambda b: b ^ value
        elif val.startswith('+'):
            value = get_int_param(val[1:])
            poke_f = lambda b: (b + value) & 255
        else:
            value = get_int_param(val)
            poke_f = lambda b: value
    except ValueError:
        raise SkoolKitError('Invalid value in poke spec: {}'.format(param_str))
    try:
        values = [get_int_param(i) for i in addr.split('-', 2)]
    except ValueError:
        raise SkoolKitError(
            'Invalid address range in poke spec: {}'.format(param_str))
    addr1, addr2, step = values + [values[0], 1][len(values) - 1:]
    for a in range(addr1, addr2 + 1, step):
        snapshot[a] = poke_f(snapshot[a])
Esempio n. 2
0
def set_z80_registers(z80, *specs):
    for spec in specs:
        reg, sep, val = spec.lower().partition('=')
        if sep:
            if reg.startswith('^'):
                size = len(reg) - 1
            else:
                size = len(reg)
            if reg == 'pc' and z80[6:8] != [0, 0]:
                offset = 6
            else:
                offset = Z80_REGISTERS.get(reg, -1)
            if offset >= 0:
                try:
                    value = get_int_param(val, True)
                except ValueError:
                    raise SkoolKitError("Cannot parse register value: {}".format(spec))
                lsb, msb = value % 256, (value & 65535) // 256
                if size == 1:
                    z80[offset] = lsb
                elif size == 2:
                    z80[offset:offset + 2] = [lsb, msb]
                if reg == 'r' and lsb & 128:
                    z80[12] |= 1
            else:
                raise SkoolKitError('Invalid register: {}'.format(spec))
Esempio n. 3
0
def _analyse_tzx(tzx, basic_block, options):
    if tzx[:8] != bytearray((90, 88, 84, 97, 112, 101, 33, 26)):
        raise SkoolKitError("Not a TZX file")

    try:
        version = 'Version: {}.{}'.format(tzx[8], tzx[9])
        if not basic_block:
            print(version)
    except IndexError:
        raise SkoolKitError('TZX version number not found')

    block_ids = set()
    if options.block_ids:
        for block_id in options.block_ids.split(','):
            try:
                block_ids.add(int(block_id, 16))
            except ValueError:
                block_ids.add(-1)

    block_num = 1
    i = 10
    while i < len(tzx):
        i, block_id, header, info, tape_data = _get_block_info(
            tzx, i, block_num)
        if basic_block:
            _list_basic(block_num, tape_data, *basic_block)
        elif not block_ids or block_id in block_ids:
            _print_block(block_num, tape_data, options.data, info, block_id,
                         header)
        block_num += 1
Esempio n. 4
0
    def parse_block(self, text, begin):
        try:
            index = parse_brackets(text, begin)[0]
        except ClosingBracketError:
            raise SkoolKitError("No closing ')' on parameter list: {}...".format(text[begin:begin + 15]))
        try:
            index, flag = parse_brackets(text, index, '', '<', '>')
        except ClosingBracketError:
            raise SkoolKitError("No closing '>' on flags: {}...".format(text[index:index + 15]))
        wrap_flag = 1
        if flag == 'nowrap':
            wrap_flag = 0
        elif flag == 'wrapalign':
            wrap_flag = 2

        indexes = [(index, 1)]

        # Parse the table rows or list items
        while True:
            start = text.find('{ ', index)
            if start < 0:
                break
            try:
                end = text.index(' }', start)
            except ValueError:
                raise SkoolKitError("No closing ' }}' on row/item: {}...".format(text[start:start + 15]))
            index = end + 2
            indexes.append((index, wrap_flag))


        indexes.append((len(text), 1))
        return indexes
Esempio n. 5
0
def move(snapshot, param_str):
    params = param_str.split(',', 2)
    if len(params) < 3:
        raise SkoolKitError("Not enough arguments in move spec (expected 3): {}".format(param_str))
    try:
        src, length, dest = [get_int_param(p, True) for p in params]
    except ValueError:
        raise SkoolKitError('Invalid integer in move spec: {}'.format(param_str))
    snapshot[dest:dest + length] = snapshot[src:src + length]
Esempio n. 6
0
def run(infile, outfile, options):
    if options.binary or options.org is not None:
        snapshot = read_bin_file(infile, 49152)
        if options.org is None:
            org = 65536 - len(snapshot)
        else:
            org = options.org
        snapshot = [0] * org + list(snapshot) + [0] * (65536 - org -
                                                       len(snapshot))
    elif infile[-4:].lower() == '.scr':
        scr = read_bin_file(infile, 6912)
        snapshot = [0] * 65536
        snapshot[16384:16384 + len(scr)] = scr
    elif infile[-4:].lower() in ('.sna', '.szx', '.z80'):
        snapshot = get_snapshot(infile)
    else:
        try:
            snapshot = BinWriter(infile, fix_mode=options.fix_mode).snapshot
        except SkoolKitError:
            raise
        except:
            raise SkoolKitError(
                'Unable to parse {} as a skool file'.format(infile))

    for spec in options.moves:
        move(snapshot, spec)
    for spec in options.pokes:
        poke(snapshot, spec)

    if options.macro is not None:
        match = re.match('(#?)(FONT|SCR|UDG|UDGARRAY)([^A-Z]|$)',
                         options.macro)
        if match:
            macro = match.group(2)
            try:
                frame = MACROS[macro](snapshot, options.macro[match.end(2):])
            except skoolmacro.MacroParsingError as e:
                raise SkoolKitError('Invalid #{} macro: {}'.format(
                    macro, e.args[0]))
        else:
            raise SkoolKitError('Macro must be #FONT, #SCR, #UDG or #UDGARRAY')
    else:
        (x, y), (w, h) = options.origin, options.size
        frame = Frame(scr_udgs(snapshot, x, y, w, h), options.scale)

    if options.invert:
        for row in frame.udgs:
            for udg in row:
                if udg.attr & 128:
                    udg.data = [b ^ 255 for b in udg.data]
                    udg.attr &= 127

    flip_udgs(frame.udgs, options.flip)
    rotate_udgs(frame.udgs, options.rotate)

    _write_image(frame, outfile, options.animated)
Esempio n. 7
0
def _get_code_blocks(snapshot, start, end, fname):
    if os.path.isdir(fname):
        raise SkoolKitError('{0} is a directory'.format(fname))
    try:
        size = os.path.getsize(fname)
    except OSError as e:
        if e.errno == 2:
            raise SkoolKitError('{0}: file not found'.format(fname))
        raise SkoolKitError('Failed to get size of {}: {}'.format(
            fname, e.strerror))

    if size == 8192:
        # Assume this is a Z80 map file
        sys.stderr.write('Reading {0}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        address = start & 65528
        for b in data[start // 8:end // 8 + 1]:
            for i in range(8):
                if b & 1 and start <= address < end:
                    addresses.append(address)
                b >>= 1
                address += 1
    elif size == 65536:
        # Assume this is a SpecEmu map file
        sys.stderr.write('Reading {}'.format(fname))
        sys.stderr.flush()
        addresses = []
        data = read_bin_file(fname)
        for address in range(start, end):
            if data[address] & 1:
                addresses.append(address)
    else:
        sys.stderr.write('Reading {0}: '.format(fname))
        sys.stderr.flush()
        with open_file(fname) as f:
            addresses = _get_addresses(f, fname, size, start, end)
    sys.stderr.write('\n')

    code_blocks = []
    disassembler = Disassembler(snapshot)
    for address in addresses:
        size = disassembler.disassemble(address, address + 1)[0].size()
        if code_blocks and address <= sum(code_blocks[-1]):
            if address == sum(code_blocks[-1]):
                code_blocks[-1][1] += size
        else:
            code_blocks.append([address, size])

    return code_blocks
Esempio n. 8
0
def copy_resources(search_dir,
                   extra_search_dirs,
                   root_dir,
                   fnames,
                   dest_dir,
                   themes=(),
                   suffix=None,
                   single_css=None,
                   indent=0):
    if not fnames:
        return

    files = []

    for fname in fnames.split(';'):
        f = find(fname, extra_search_dirs, search_dir)
        if f:
            files.append(f)
        else:
            raise SkoolKitError('{}: file not found'.format(normpath(fname)))
        if themes and fname.endswith(suffix):
            for theme in themes:
                f = find('{}-{}{}'.format(fname[:-len(suffix)], theme, suffix),
                         extra_search_dirs, search_dir)
                if f:
                    files.append(f)

    for theme in themes:
        f = find('{}{}'.format(theme, suffix), extra_search_dirs, search_dir)
        if f:
            files.append(f)

    if single_css:
        dest_css = normpath(root_dir, dest_dir, single_css)
        if isdir(dest_css):
            raise SkoolKitError(
                "Cannot write CSS file '{}': {} already exists and is a directory"
                .format(normpath(single_css), dest_css))
        with open(dest_css, 'w') as css:
            for f in files:
                notify('{}Appending {} to {}'.format(indent * ' ', normpath(f),
                                                     dest_css))
                with open(f) as src:
                    for line in src:
                        css.write(line)
                css.write('\n')
        return single_css

    for f in files:
        copy_resource(f, root_dir, dest_dir, indent)
    return ';'.join([basename(f) for f in files])
Esempio n. 9
0
 def pop_snapshot(self):
     """Discard the current memory snapshot and replace it with the one that
     was most recently saved (by
     :meth:`~skoolkit.skoolasm.AsmWriter.push_snapshot`)."""
     if len(self._snapshots) < 2:
         raise SkoolKitError("Cannot pop snapshot when snapshot stack is empty")
     self.snapshot = self._snapshots.pop()[0]
Esempio n. 10
0
    def parse_blocks(self, text):
        markers = ((TABLE_MARKER, TABLE_END_MARKER), (UDGTABLE_MARKER, TABLE_END_MARKER), (LIST_MARKER, LIST_END_MARKER))
        indexes = []

        # Find table/list markers and row/item definitions
        index = 0
        while True:
            starts = [text.find(marker[0], index) for marker in markers]
            for i, start in enumerate(starts):
                if start >= 0:
                    if start > 0:
                        indexes.append(start - 1)
                    marker, end_marker = markers[i]
                    try:
                        end = text.index(end_marker, start) + len(end_marker)
                    except ValueError:
                        raise SkoolKitError("No end marker found: {}...".format(text[start:start + len(marker) + 15]))
                    indexes.extend(self.parse_block(text[:end], start + len(marker)))
                    break
            else:
                break
            index = indexes[-1] + 1

        # Insert newlines
        end = len(text)
        if end not in indexes:
            indexes.append(end)
        indexes.sort()
        lines = []
        start = 0
        for end in indexes:
            lines.append(text[start:end])
            start = end + 1
        return lines
Esempio n. 11
0
def add_lines(ref_parser, config_specs, section=None):
    for config_spec in config_specs:
        section_name, sep, line = config_spec.partition('/')
        if not sep:
            raise SkoolKitError("Malformed SectionName/Line spec: {0}".format(config_spec))
        if section is None or section_name == section:
            ref_parser.add_line(section_name, line)
Esempio n. 12
0
    def parse_blocks(self, text):
        markers = ((TABLE_MARKER, TABLE_END_MARKER), (UDGTABLE_MARKER, TABLE_END_MARKER), (LIST_MARKER, LIST_END_MARKER))
        indexes = []

        # Find table/list markers and row/item definitions
        index = 0
        while True:
            starts = [(marker[0], marker[1], text.find(marker[0], index)) for marker in markers]
            for marker, end_marker, start in starts:
                if start >= 0:
                    if start > 0:
                        indexes.append((start - 1, 1))
                    try:
                        end = text.index(end_marker, start) + len(end_marker)
                    except ValueError:
                        raise SkoolKitError("No end marker found: {}...".format(text[start:start + len(marker) + 15]))
                    indexes.extend(self.parse_block(text[:end], start + len(marker)))
                    break
            else:
                break
            index = indexes[-1][0] + 1

        if not indexes or indexes[-1][0] != len(text):
            indexes.append((len(text), 1))
        indexes.sort(key=lambda e: e[0])
        lines = []
        start = 0
        for end, wrap_flag in indexes:
            lines.append((text[start:end].strip(), wrap_flag))
            start = end
        return lines
Esempio n. 13
0
def set_z80_state(z80, *specs):
    for spec in specs:
        name, sep, val = spec.lower().partition('=')
        try:
            if name == 'iff':
                z80[27] = z80[28] = get_int_param(val) & 255
            elif name == 'im':
                z80[29] &= 252 # Clear bits 0 and 1
                z80[29] |= get_int_param(val) & 3
            elif name == 'border':
                z80[12] &= 241 # Clear bits 1-3
                z80[12] |= (get_int_param(val) & 7) * 2 # Border colour
            else:
                raise SkoolKitError("Invalid parameter: {}".format(spec))
        except ValueError:
            raise SkoolKitError("Cannot parse integer: {}".format(spec))
Esempio n. 14
0
def _load(snapshot, counters, blocks, param_str):
    try:
        block_num, start, length, step, offset, inc = _get_load_params(
            param_str)
    except ValueError:
        raise SkoolKitError(
            'Invalid integer in load spec: {}'.format(param_str))
    default_index = 1
    load_last = False
    if block_num.startswith('+'):
        block_num = block_num[1:]
        default_index = 0
    if block_num.endswith('+'):
        block_num = block_num[:-1]
        load_last = True
    block_num = get_int_param(block_num)
    index = counters.setdefault(block_num, default_index)
    try:
        block = blocks[block_num - 1]
    except IndexError:
        raise TapeError("Block {} not found".format(block_num))
    if length is None and load_last:
        length = len(block) - index
    length = _load_block(snapshot, block, start, length, step, offset, inc,
                         index)
    counters[block_num] += length
Esempio n. 15
0
def main(args):
    parser = argparse.ArgumentParser(
        usage="tapinfo.py FILE",
        description="Show the blocks in a TAP or TZX file.",
        add_help=False
    )
    parser.add_argument('infile', help=argparse.SUPPRESS, nargs='?')
    group = parser.add_argument_group('Options')
    group.add_argument('-b', '--tzx-blocks', dest='block_ids', metavar='IDs',
                       help="Show TZX blocks with these IDs only. "
                            "'IDs' is a comma-separated list of hexadecimal block IDs, e.g. 10,11,2a.")
    group.add_argument('-B', '--basic', metavar='N[,A]',
                       help='List the BASIC program in block N loaded at address A (default 23755).')
    group.add_argument('-V', '--version', action='version', version='SkoolKit {}'.format(VERSION),
                       help='Show SkoolKit version number and exit.')
    namespace, unknown_args = parser.parse_known_args(args)
    if unknown_args or namespace.infile is None:
        parser.exit(2, parser.format_help())
    infile = namespace.infile
    tape_type = infile[-4:].lower()
    if tape_type not in ('.tap', '.tzx'):
        raise SkoolKitError('Unrecognised tape type')

    basic_block = _get_basic_block(namespace.basic)

    with open(infile, 'rb') as f:
        tape = f.read()

    if tape_type == '.tap':
        _analyse_tap(tape, basic_block)
    else:
        _analyse_tzx(tape, basic_block, namespace)
Esempio n. 16
0
 def pop_snapshot(self):
     """Replace the current memory snapshot with the one most recently saved
     by :meth:`~skoolkit.skoolasm.AsmWriter.push_snapshot`."""
     if len(self._snapshots) < 2:
         raise SkoolKitError(
             "Cannot pop snapshot when snapshot stack is empty")
     self.snapshot[:] = self._snapshots.pop()[0]
Esempio n. 17
0
def _get_basic_block(spec):
    if spec:
        try:
            if ',' in spec:
                return [get_int_param(i) for i in spec.split(',', 1)]
            return get_int_param(spec), 23755
        except ValueError:
            raise SkoolKitError('Invalid block specification: {}'.format(spec))
Esempio n. 18
0
def _get_address_ranges(specs, step=1):
    addr_ranges = []
    for addr_range in specs:
        try:
            values = [get_int_param(i, True) for i in addr_range.split('-', 2)]
        except ValueError:
            raise SkoolKitError('Invalid address range: {}'.format(addr_range))
        addr_ranges.append(values + [values[0], step][len(values) - 1:])
    return addr_ranges
Esempio n. 19
0
def _get_basic_block(spec):
    if spec:
        try:
            if ',' in spec:
                params = spec.split(',', 1)
                return get_int_param(params[0]), get_int_param(params[1], True)
            return get_int_param(spec), 23755
        except ValueError:
            raise SkoolKitError('Invalid block specification: {}'.format(spec))
Esempio n. 20
0
def parse_ref_files(reffiles, ref_parser, fnames, search_dir=''):
    for f in fnames:
        if f:
            ref_f = normpath(search_dir, f)
            if not isfile(os.path.join(search_dir, f)):
                raise SkoolKitError('{}: file not found'.format(ref_f))
            if ref_f not in reffiles:
                reffiles.append(ref_f)
                ref_parser.parse(ref_f)
Esempio n. 21
0
def main(args):
    parser = argparse.ArgumentParser(
        usage='snapinfo.py [options] file',
        description="Analyse an SNA, SZX or Z80 snapshot.",
        add_help=False
    )
    parser.add_argument('infile', help=argparse.SUPPRESS, nargs='?')
    group = parser.add_argument_group('Options')
    group.add_argument('-b', '--basic', action='store_true',
                       help='List the BASIC program.')
    group.add_argument('-f', '--find', metavar='A[,B...[-M[-N]]]',
                       help='Search for the byte sequence A,B... with distance ranging from M to N (default=1) between bytes.')
    group.add_argument('-p', '--peek', metavar='A[-B[-C]]', action='append',
                       help='Show the contents of addresses A TO B STEP C. This option may be used multiple times.')
    group.add_argument('-t', '--find-text', dest='text', metavar='TEXT',
                       help='Search for a text string.')
    group.add_argument('-T', '--find-tile', dest='tile', metavar='X,Y[-M[-N]]',
                       help='Search for the graphic data of the tile at (X,Y) with distance ranging from M to N (default=1) between bytes.')
    group.add_argument('-v', '--variables', action='store_true',
                       help='List variables.')
    group.add_argument('-V', '--version', action='version', version='SkoolKit {}'.format(VERSION),
                       help='Show SkoolKit version number and exit.')
    group.add_argument('-w', '--word', metavar='A[-B[-C]]', action='append',
                       help='Show the words at addresses A TO B STEP C. This option may be used multiple times.')
    namespace, unknown_args = parser.parse_known_args(args)
    if unknown_args or namespace.infile is None:
        parser.exit(2, parser.format_help())
    infile = namespace.infile
    snapshot_type = infile[-4:].lower()
    if snapshot_type not in ('.sna', '.szx', '.z80'):
        raise SkoolKitError('Unrecognised snapshot type')

    if any((namespace.find, namespace.tile, namespace.text, namespace.peek, namespace.word, namespace.basic, namespace.variables)):
        snapshot = get_snapshot(infile)
        if namespace.find:
            _find(snapshot, namespace.find)
        elif namespace.tile:
            _find_tile(snapshot, namespace.tile)
        elif namespace.text:
            _find_text(snapshot, namespace.text)
        elif namespace.peek:
            _peek(snapshot, namespace.peek)
        elif namespace.word:
            _word(snapshot, namespace.word)
        else:
            if namespace.basic:
                print(BasicLister().list_basic(snapshot))
            if namespace.variables:
                print(VariableLister().list_variables(snapshot))
    elif snapshot_type == '.sna':
        _analyse_sna(infile)
    elif snapshot_type == '.z80':
        _analyse_z80(infile)
    else:
        _analyse_szx(infile)
Esempio n. 22
0
def _find(snapshot, byte_seq, base_addr=16384):
    steps = '1'
    if '-' in byte_seq:
        byte_seq, steps = byte_seq.split('-', 1)
    try:
        byte_values = [get_int_param(i, True) for i in byte_seq.split(',')]
    except ValueError:
        raise SkoolKitError('Invalid byte sequence: {}'.format(byte_seq))
    try:
        if '-' in steps:
            limits = [get_int_param(n, True) for n in steps.split('-', 1)]
            steps = range(limits[0], limits[1] + 1)
        else:
            steps = [get_int_param(steps, True)]
    except ValueError:
        raise SkoolKitError('Invalid distance: {}'.format(steps))
    for step in steps:
        offset = step * len(byte_values)
        for a in range(base_addr, 65537 - offset):
            if snapshot[a:a + offset:step] == byte_values:
                print("{0}-{1}-{2} {0:04X}-{1:04X}-{2:X}: {3}".format(a, a + offset - step, step, byte_seq))
Esempio n. 23
0
def copy_resource(fname, root_dir, dest_dir):
    base_f = basename(fname)
    dest_f = normpath(root_dir, dest_dir, base_f)
    if not isfile(dest_f) or os.stat(fname).st_mtime > os.stat(dest_f).st_mtime:
        fname_n = normpath(fname)
        dest_d = dirname(dest_f)
        if isfile(dest_d):
            raise SkoolKitError("Cannot copy {0} to {1}: {1} is not a directory".format(fname_n, normpath(dest_dir)))
        if not isdir(dest_d):
            os.makedirs(dest_d)
        notify('Copying {} to {}'.format(fname_n, normpath(dest_dir, base_f)))
        shutil.copy2(fname, dest_f)
Esempio n. 24
0
def _find_tile(snapshot, coords):
    steps = '1'
    if '-' in coords:
        coords, steps = coords.split('-', 1)
    try:
        x, y = [get_int_param(i) for i in coords.split(',', 1)]
        if not 0 <= x < 32 or not 0 <= y < 24:
            raise ValueError
    except ValueError:
        raise SkoolKitError('Invalid tile coordinates: {}'.format(coords))
    df_addr = 16384 + 2048 * (y // 8) + 32 * (y & 7) + x
    byte_seq = snapshot[df_addr:df_addr + 2048:256]
    for b in byte_seq:
        print('|{:08b}|'.format(b).replace('0', ' ').replace('1', '*'))
    _find(snapshot, '{}-{}'.format(','.join([str(b) for b in byte_seq]), steps), 23296)
Esempio n. 25
0
def _get_ram(blocks, options):
    snapshot = [0] * 65536

    operations = []
    standard_load = True
    for spec in options.ram_ops:
        op_type, sep, param_str = spec.partition('=')
        if op_type in ('load', 'move', 'poke', 'sysvars'):
            operations.append((op_type, param_str))
            if op_type == 'load':
                standard_load = False
        else:
            raise SkoolKitError("Invalid operation: {}".format(spec))

    if standard_load:
        start = None
        for block_num, block in enumerate(blocks, 1):
            if block:
                if block[0] == 0 and len(block) >= 19:
                    # Header
                    block_type = block[1]
                    if block_type == 3:
                        # Bytes
                        start = block[14] + 256 * block[15]
                    elif block_type == 0:
                        # Program
                        start = 23755
                    else:
                        raise TapeError(
                            'Unknown block type ({}) in header block {}'.
                            format(block_type, block_num))
                elif block[0] == 255 and start is not None:
                    # Data
                    _load_block(snapshot, block, start)
                    start = None

    counters = {}
    for op_type, param_str in operations:
        if op_type == 'load':
            _load(snapshot, counters, blocks, param_str)
        elif op_type == 'move':
            move(snapshot, param_str)
        elif op_type == 'poke':
            poke(snapshot, param_str)
        elif op_type == 'sysvars':
            snapshot[23552:23755] = SYSVARS

    return snapshot[16384:]
Esempio n. 26
0
    def parse_block(self, text, start):
        indexes = []
        index = text.index(' ', start)
        indexes.append(index)
        index += 1

        # Parse the table rows or list items
        while True:
            start = text.find('{ ', index)
            if start < 0:
                break
            try:
                end = text.index(' }', start)
            except ValueError:
                raise SkoolKitError("No closing ' }}' on row/item: {}...".format(text[start:start + 15]))
            index = end + 2
            indexes.append(index)

        indexes.append(len(text))
        return indexes
Esempio n. 27
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)
Esempio n. 28
0
def _analyse_szx(szxfile):
    szx = read_bin_file(szxfile)

    magic = _get_block_id(szx, 0)
    if magic != 'ZXST':
        raise SkoolKitError("{} is not an SZX file".format(szxfile))

    print('Version: {}.{}'.format(szx[4], szx[5]))
    machine_id = szx[6]
    print('Machine: {}'.format(SZX_MACHINES.get(machine_id, 'Unknown')))
    variables = {'chMachineId': machine_id}

    i = 8
    while i < len(szx):
        block_id = _get_block_id(szx, i)
        block_size = get_dword(szx, i + 4)
        i += 8
        print('{}: {} bytes'.format(block_id, block_size))
        printer = SZX_BLOCK_PRINTERS.get(block_id)
        if printer:
            for line in printer(szx[i:i + block_size], variables):
                print("  " + line)
        i += block_size
Esempio n. 29
0
def write_disassembly(html_writer, files, search_dir, extra_search_dirs, pages,
                      css_themes, single_css):
    game_dir = html_writer.file_info.game_dir
    paths = html_writer.paths
    game_vars = html_writer.game_vars

    # Create the disassembly subdirectory if necessary
    odir = html_writer.file_info.odir
    if not isdir(odir):
        notify('Creating directory {0}'.format(odir))
        os.makedirs(odir)

    # Copy CSS, JavaScript and font files if necessary
    html_writer.set_style_sheet(
        copy_resources(search_dir, extra_search_dirs, odir,
                       game_vars.get('StyleSheet'),
                       paths.get('StyleSheetPath', ''), css_themes, '.css',
                       single_css))
    js_path = paths.get('JavaScriptPath', '')
    copy_resources(search_dir, extra_search_dirs, odir,
                   game_vars.get('JavaScript'), js_path)
    copy_resources(search_dir, extra_search_dirs, odir, game_vars.get('Font'),
                   paths.get('FontPath', ''))

    # Copy resources named in the [Resources] section
    resources = html_writer.ref_parser.get_dictionary('Resources')
    for f, dest_dir in resources.items():
        fname = find(f, extra_search_dirs, search_dir)
        if not fname:
            raise SkoolKitError(
                'Cannot copy resource "{}": file not found'.format(
                    normpath(f)))
        copy_resource(fname, odir, dest_dir)

    # Write disassembly files
    if 'd' in files:
        if html_writer.asm_single_page_template:
            message = 'Writing {}'.format(
                normpath(game_dir, paths['AsmSinglePage']))
        else:
            message = 'Writing disassembly files in {}'.format(
                normpath(game_dir, html_writer.code_path))
        clock(html_writer.write_asm_entries, '  ' + message)

    # Write the memory map files
    if 'm' in files:
        for map_name in html_writer.main_memory_maps:
            clock(html_writer.write_map,
                  '  Writing {}'.format(normpath(game_dir,
                                                 paths[map_name])), map_name)

    # Write pages defined by [Page:*] sections
    if 'P' in files:
        for page_id in pages:
            page_details = html_writer.pages[page_id]
            copy_resources(search_dir,
                           extra_search_dirs,
                           odir,
                           page_details.get('JavaScript'),
                           js_path,
                           indent=2)
            clock(html_writer.write_page,
                  '  Writing {}'.format(normpath(game_dir,
                                                 paths[page_id])), page_id)

    # Write other code files
    if 'o' in files:
        for code_id, code in html_writer.other_code:
            skoolfile = find(code['Source'], extra_search_dirs, search_dir)
            if not skoolfile:
                raise SkoolKitError('{}: file not found'.format(
                    normpath(code['Source'])))
            skool2_parser = clock(html_writer.parser.clone,
                                  '  Parsing {0}'.format(skoolfile), skoolfile)
            html_writer2 = html_writer.clone(skool2_parser, code_id)
            map_name = code['IndexPageId']
            map_path = paths[map_name]
            asm_path = paths[code['CodePathId']]
            clock(html_writer2.write_map,
                  '    Writing {}'.format(normpath(game_dir,
                                                   map_path)), map_name)
            if html_writer.asm_single_page_template:
                message = 'Writing {}'.format(
                    normpath(game_dir, paths[code['AsmSinglePageId']]))
            else:
                message = 'Writing disassembly files in {}'.format(
                    normpath(game_dir, asm_path))
            clock(html_writer2.write_entries, '    ' + message, asm_path,
                  map_path)

    # Write index.html
    if 'i' in files:
        clock(html_writer.write_index,
              '  Writing {}'.format(normpath(game_dir, paths['GameIndex'])))
Esempio n. 30
0
def process_file(infile, topdir, options):
    extra_search_dirs = options.search
    pages = options.pages
    stdin = False

    skoolfile_f = reffile_f = None
    ref_search_dir = module_path = ''
    if infile.endswith('.ref'):
        reffile_f = find(infile, extra_search_dirs)
        if reffile_f:
            ref_search_dir = module_path = dirname(reffile_f)
            prefix = get_prefix(basename(reffile_f))
    elif infile == '-':
        stdin = True
        skoolfile_f = infile
        prefix = 'program'
    else:
        skoolfile_f = find(infile, extra_search_dirs)
        if skoolfile_f:
            ref_search_dir = module_path = dirname(skoolfile_f)
            prefix = get_prefix(basename(skoolfile_f))
            reffile_f = find('{}.ref'.format(prefix), extra_search_dirs,
                             ref_search_dir)
            if reffile_f:
                ref_search_dir = dirname(reffile_f)
    if skoolfile_f is reffile_f is None:
        raise SkoolKitError('{}: file not found'.format(normpath(infile)))

    reffiles = []
    if reffile_f:
        reffiles.append(normpath(reffile_f))
    base_ref = prefix + '.ref'
    for f in sorted(os.listdir(ref_search_dir or '.')):
        if isfile(os.path.join(ref_search_dir, f)) and f.endswith(
                '.ref') and f.startswith(prefix) and f != base_ref:
            reffiles.append(normpath(ref_search_dir, f))
    ref_parser = RefParser()
    ref_parser.parse(StringIO(defaults.get_section('Config')))
    config = ref_parser.get_dictionary('Config')
    for oreffile_f in reffiles:
        ref_parser.parse(oreffile_f)
    add_lines(ref_parser, options.config_specs, 'Config')
    config.update(ref_parser.get_dictionary('Config'))
    extra_reffiles = config.get('RefFiles')
    if extra_reffiles:
        for f in extra_reffiles.split(';'):
            if isfile(os.path.join(ref_search_dir, f)):
                ref_f = normpath(ref_search_dir, f)
                if ref_f not in reffiles:
                    reffiles.append(ref_f)
                    ref_parser.parse(ref_f)
    add_lines(ref_parser, options.config_specs)

    if skoolfile_f is None:
        skoolfile = config.get('SkoolFile', '{}.skool'.format(prefix))
        skoolfile_f = find(skoolfile, extra_search_dirs, ref_search_dir)
        if skoolfile_f is None:
            raise SkoolKitError('{}: file not found'.format(
                normpath(skoolfile)))

    skoolfile_n = normpath(skoolfile_f)
    if not stdin:
        notify('Using skool file: {}'.format(skoolfile_n))
    if reffiles:
        if len(reffiles) > 1:
            suffix = 's'
        else:
            suffix = ''
        notify('Using ref file{0}: {1}'.format(suffix, ', '.join(reffiles)))
    elif not stdin:
        notify('Found no ref file for {}'.format(skoolfile_n))

    html_writer_class = get_class(config['HtmlWriterClass'], module_path)
    game_dir = config.get('GameDir', prefix)

    # Parse the skool file and initialise the writer
    if stdin:
        fname = 'skool file from standard input'
    else:
        fname = skoolfile_f
    skool_parser = clock(SkoolParser,
                         'Parsing {}'.format(fname),
                         skoolfile_f,
                         case=options.case,
                         base=options.base,
                         html=True,
                         create_labels=options.create_labels,
                         asm_labels=options.asm_labels)
    file_info = FileInfo(topdir, game_dir, options.new_images)
    html_writer = html_writer_class(skool_parser, ref_parser, file_info)

    # Check that the specified pages exist
    all_page_ids = html_writer.get_page_ids()
    for page_id in pages:
        if page_id not in all_page_ids:
            raise SkoolKitError('Invalid page ID: {0}'.format(page_id))
    pages = pages or all_page_ids

    write_disassembly(html_writer, options.files, ref_search_dir,
                      extra_search_dirs, pages, options.themes,
                      options.single_css)