Exemple #1
0
def _write_z80(ram, options, fname):
    parent_dir = os.path.dirname(fname)
    if parent_dir and not os.path.isdir(parent_dir):
        os.makedirs(parent_dir)
    write_line('Writing {0}'.format(fname))
    with open(fname, 'wb') as f:
        f.write(bytearray(_get_z80(ram, options)))
Exemple #2
0
    def write_entry(self, entry):
        for directive in entry.asm_directives:
            self._write_entry_asm_directive(entry, directive)
        address = self.addr_str(entry.address)

        self._write_entry_ignoreua_directive(entry, TITLE)
        if BLOCKS in self.elements:
            if BLOCK_TITLES in self.elements:
                write_line('{0} {1} {2}'.format(entry.ctl, address, entry.description).rstrip())
            else:
                write_line('{0} {1}'.format(entry.ctl, address))

        self._write_entry_ignoreua_directive(entry, DESCRIPTION)
        if BLOCK_DESC in self.elements:
            for p in entry.details:
                write_line('D {0} {1}'.format(address, p))

        self._write_entry_ignoreua_directive(entry, REGISTERS)
        if REGISTERS in self.elements:
            for reg in entry.registers:
                if reg.prefix:
                    name = '{}:{}'.format(reg.prefix, reg.name)
                else:
                    name = reg.name
                write_line('R {} {} {}'.format(address, name, reg.contents).rstrip())

        self.write_body(entry)

        self._write_entry_ignoreua_directive(entry, END)
        if BLOCK_COMMENTS in self.elements:
            for p in entry.end_comment:
                write_line('E {0} {1}'.format(address, p))
Exemple #3
0
def _get_tape(urlstring, member=None):
    url = urlparse(urlstring)
    if url.scheme:
        write_line('Downloading {0}'.format(urlstring))
        u = urlopen(urlstring, timeout=30)
        f = tempfile.NamedTemporaryFile(prefix='tap2sna-')
        while 1:
            data = bytearray(u.read(4096))
            if data:
                f.write(data)
            else:
                break
    elif url.path:
        f = open_file(url.path, 'rb')

    if urlstring.lower().endswith('.zip'):
        z = zipfile.ZipFile(f)
        if member is None:
            for name in z.namelist():
                if name.lower().endswith(('.tap', '.tzx')):
                    member = name
                    break
            else:
                raise TapeError('No TAP or TZX file found')
        write_line('Extracting {0}'.format(member))
        tape = z.open(member)
        data = bytearray(tape.read())
        tape_type = member[-3:]
    else:
        tape_type = urlstring[-3:]
        f.seek(0)
        data = bytearray(f.read())

    f.close()
    return tape_type, data
Exemple #4
0
 def _write_body(self, entry, wrote_desc, write_refs, show_text):
     op_width = max((OP_WIDTH, entry.width()))
     line_width = op_width + 8
     first_block = True
     for block in entry.blocks:
         ignoreua_m = block.has_ignoreua_directive(block.start, MID_BLOCK)
         begun_header = False
         if not first_block and entry.ctl == 'c' and write_refs > -1:
             referrers = block.instructions[0].referrers
             if referrers and (write_refs == 1 or not block.header):
                 if ignoreua_m:
                     self.write_asm_directive(AD_IGNOREUA)
                 self.write_referrers(EREFS_PREFIX, referrers)
                 begun_header = True
         if block.header:
             if first_block:
                 if not wrote_desc:
                     self._write_empty_paragraph()
                 if not entry.registers:
                     self._write_empty_paragraph()
                 self.write_comment('')
             if begun_header:
                 self._write_paragraph_separator()
             elif ignoreua_m:
                 self.write_asm_directive(AD_IGNOREUA)
             self.write_paragraphs(block.header)
         comment_width = max(self.comment_width - line_width, MIN_INSTRUCTION_COMMENT_WIDTH)
         comment_lines = self._format_block_comment(block, comment_width)
         self._write_instructions(entry, block, op_width, comment_lines, write_refs, show_text)
         indent = ' ' * line_width
         for j in range(len(block.instructions), len(comment_lines)):
             write_line('{}; {}'.format(indent, comment_lines[j]))
         first_block = False
Exemple #5
0
def main(args):
    parser = SkoolKitArgumentParser(
        usage='\n  tap2sna.py [options] INPUT snapshot.z80\n  tap2sna.py @FILE',
        description="Convert a TAP or TZX file (which may be inside a zip archive) into a Z80 snapshot. "
                    "INPUT may be the full URL to a remote zip archive or TAP/TZX file, or the path to a local file. "
                    "Arguments may be read from FILE instead of (or as well as) being given on the command line.",
        fromfile_prefix_chars='@',
        add_help=False
    )
    parser.add_argument('args', help=argparse.SUPPRESS, nargs='*')
    group = parser.add_argument_group('Options')
    group.add_argument('-d', '--output-dir', dest='output_dir', metavar='DIR',
                       help="Write the snapshot file in this directory.")
    group.add_argument('-f', '--force', action='store_true',
                       help="Overwrite an existing snapshot.")
    group.add_argument('-p', '--stack', dest='stack', metavar='STACK', type=integer,
                       help="Set the stack pointer.")
    group.add_argument('--ram', dest='ram_ops', metavar='OPERATION', action='append', default=[],
                       help="Perform a load, move or poke operation on the memory snapshot being built. "
                            "Do '--ram help' for more information. This option may be used multiple times.")
    group.add_argument('--reg', dest='reg', metavar='name=value', action='append', default=[],
                       help="Set the value of a register. Do '--reg help' for more information. "
                            "This option may be used multiple times.")
    group.add_argument('-s', '--start', dest='start', metavar='START', type=integer,
                       help="Set the start address to JP to.")
    group.add_argument('--state', dest='state', metavar='name=value', action='append', default=[],
                       help="Set a hardware state attribute. Do '--state help' for more information. "
                            "This option may be used multiple times.")
    group.add_argument('-u', '--user-agent', dest='user_agent', metavar='AGENT', default='',
                       help="Set the User-Agent header.")
    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 'help' in namespace.ram_ops:
        _print_ram_help()
        return
    if 'help' in namespace.reg:
        print_reg_help()
        return
    if 'help' in namespace.state:
        print_state_help()
        return
    if unknown_args or len(namespace.args) != 2:
        parser.exit(2, parser.format_help())
    url, z80 = namespace.args
    if namespace.output_dir:
        z80 = os.path.join(namespace.output_dir, z80)
    if namespace.stack is not None:
        namespace.reg.append('sp={}'.format(namespace.stack))
    if namespace.start is not None:
        namespace.reg.append('pc={}'.format(namespace.start))
    if namespace.force or not os.path.isfile(z80):
        try:
            make_z80(url, namespace, z80)
        except Exception as e:
            raise SkoolKitError("Error while getting snapshot {}: {}".format(os.path.basename(z80), e.args[0] if e.args else e))
    else:
        write_line('{0}: file already exists; use -f to overwrite'.format(z80))
Exemple #6
0
 def write_skool(self, write_refs, text):
     if not self.disassembly.contains_entry_asm_directive(AD_START):
         self.write_asm_directive(AD_START)
         if not self.disassembly.contains_entry_asm_directive(AD_ORG):
             self.write_asm_directive(AD_ORG, self.address_str(self.disassembly.org, False))
     for entry_index, entry in enumerate(self.disassembly.entries):
         if entry_index:
             write_line('')
         self._write_entry(entry, write_refs, text)
Exemple #7
0
    def write_body(self, entry):
        if entry.ctl in 'gu':
            entry_ctl = 'b'
        else:
            entry_ctl = entry.ctl
        first_instruction = entry.instructions[0]
        if entry_ctl == 'i' and not first_instruction.operation:
            # Don't write any sub-blocks for an empty 'i' entry
            return

        # Split the entry into sections separated by mid-block comments
        sections = []
        for instruction in entry.instructions:
            mbc = instruction.mid_block_comment
            if mbc or not sections:
                sections.append((mbc, [instruction]))
            else:
                sections[-1][1].append(instruction)

        for k, (mbc, instructions) in enumerate(sections):
            if BLOCK_COMMENTS in self.elements and mbc:
                first_instruction = instructions[0]
                if first_instruction.ignoremrcua and self.write_asm_dirs:
                    self._write_asm_directive('{}:{}'.format(AD_IGNOREUA, MID_BLOCK), first_instruction.address)
                address_str = self.addr_str(first_instruction.address)
                for paragraph in mbc:
                    write_line('N {} {}'.format(address_str, paragraph))

            if SUBBLOCKS in self.elements:
                sub_blocks = self.get_sub_blocks(instructions)
                for j, (ctl, instructions) in enumerate(sub_blocks):
                    has_bases = False
                    for instruction in instructions:
                        self._write_instruction_asm_directives(instruction)
                        if instruction.bases:
                            has_bases = True
                    first_instruction = instructions[0]
                    if ctl != 'M' or COMMENTS in self.elements:
                        if ctl == 'M':
                            offset = first_instruction.comment.rowspan + 1
                            if j + offset < len(sub_blocks):
                                length = sub_blocks[j + offset][1][0].address - first_instruction.address
                            elif k + 1 < len(sections):
                                length = sections[k + 1][1][0].address - first_instruction.address
                            else:
                                length = ''
                        else:
                            length = None
                        comment_text = ''
                        comment = first_instruction.comment
                        if comment and COMMENTS in self.elements:
                            comment_text = comment.text
                            if comment.rowspan > 1 and not comment_text.replace('.', ''):
                                comment_text = '.' + comment_text
                        if comment_text or ctl != entry_ctl or ctl != 'c' or has_bases:
                            self.write_sub_block(ctl, entry_ctl, comment_text, instructions, length)
Exemple #8
0
 def _write_blocks(self, blocks, address, footer=False):
     if NON_ENTRY_BLOCKS in self.elements:
         prefix = '> ' + address
         if footer:
             prefix += ',1'
         for index, block in enumerate(blocks):
             if index:
                 write_line(prefix)
             for line in block:
                 write_line('{} {}'.format(prefix, line))
Exemple #9
0
def clock(operation, prefix, *args, **kwargs):
    if verbose:
        if show_timings:
            write('{0} '.format(prefix))
            go = time.time()
        else:
            write_line(prefix)
    result = operation(*args, **kwargs)
    if verbose and show_timings:
        notify('({0:0.2f}s)'.format(time.time() - go))
    return result
Exemple #10
0
 def write_comment(self, text, paragraphs=False):
     if isinstance(text, str):
         lines = [text]
     elif len(text) == 1:
         lines = self.wrap(text[0])
     else:
         lines = self._trim_lines(text[:])
     for line in lines:
         if line:
             write_line('; ' + line)
         elif paragraphs:
             self._write_paragraph_separator()
         else:
             write_line(';')
Exemple #11
0
    def _write_entry(self, entry, write_refs, show_text):
        if entry.header:
            for line in entry.header:
                write_line(line)
            write_line('')

        self.write_asm_directives(*entry.asm_directives)
        if entry.has_ignoreua_directive(TITLE):
            self.write_asm_directives(AD_IGNOREUA)

        if entry.ctl == 'i' and entry.blocks[-1].end >= 65536 and not entry.has_title and all([b.ctl == 'i' for b in entry.blocks]):
            return

        for block in entry.bad_blocks:
            addr1 = self.address_str(block.instructions[-1].address, False)
            addr2 = self.address_str(block.end, False)
            warn('Instruction at {} overlaps the following instruction at {}'.format(addr1, addr2))

        if entry.has_title:
            self.write_comment(entry.title)
            wrote_desc = self._write_entry_description(entry, write_refs)
            wrote_desc = self._write_registers(entry, wrote_desc)
        else:
            wrote_desc = False

        self._write_body(entry, wrote_desc, write_refs, show_text and entry.ctl != 't')

        if entry.has_ignoreua_directive(END):
            self.write_asm_directives(AD_IGNOREUA)
        self.write_paragraphs(entry.end_comment)

        if entry.footer:
            write_line('')
            for line in entry.footer:
                write_line(line)
Exemple #12
0
    def write_sub_block(self, ctl, entry_ctl, comment, instructions, lengths):
        length = 0
        sublengths = []
        address = instructions[0].address
        if ctl == 'C':
            # Compute the sublengths for a 'C' sub-block
            for i, instruction in enumerate(instructions):
                addr = instruction.address
                if i < len(instructions) - 1:
                    sublength = instructions[i + 1].address - addr
                else:
                    sublength = get_size(instruction.operation, addr)
                if sublength > 0:
                    length += sublength
                    bases = instruction.bases
                    if sublengths and bases == sublengths[-1][0]:
                        sublengths[-1][1] += sublength
                    else:
                        sublengths.append([bases, sublength])
            if not any(comment) and len(sublengths) > 1 and entry_ctl == 'c':
                if not sublengths[-1][0]:
                    length -= sublengths.pop()[1]
                if not sublengths[0][0]:
                    sublength = sublengths.pop(0)[1]
                    length -= sublength
                    address += sublength
            lengths = ','.join(['{}{}'.format(*s) for s in sublengths])
            if len(sublengths) > 1:
                lengths = '{},{}'.format(length, lengths)
        elif ctl in 'BSTW':
            # Compute the sublengths for a 'B', 'S', 'T' or 'W' sub-block
            for statement in instructions:
                length += statement.size
                sublengths.append(statement.length)
            while len(sublengths) > 1 and sublengths[-1] == sublengths[-2]:
                sublengths.pop()
            lengths = '{},{}'.format(length, get_lengths(sublengths))

        addr_str = self.addr_str(address)
        if lengths:
            lengths = ',{}'.format(lengths)
        if isinstance(comment, str):
            write_line('{} {}{} {}'.format(ctl, addr_str, lengths, comment).rstrip())
        else:
            # Remove redundant trailing blank lines
            min_comments = min(len(instructions) - 1, 1)
            while len(comment) > min_comments and comment[-1] == ['']:
                comment.pop()
            self._write_lines(comment, ctl, addr_str + lengths, True)
Exemple #13
0
    def write_sub_block(self, ctl, entry_ctl, comment, instructions, lengths):
        length = 0
        sublengths = []
        address = instructions[0].address
        if ctl == 'c':
            # Compute the sublengths for a 'C' sub-block
            for i, instruction in enumerate(instructions):
                addr = instruction.address
                if i < len(instructions) - 1:
                    sublength = instructions[i + 1].address - addr
                else:
                    sublength = get_size(instruction.operation, addr)
                if sublength > 0:
                    length += sublength
                    bases = instruction.bases
                    if sublengths and bases == sublengths[-1][0]:
                        sublengths[-1][1] += sublength
                    else:
                        sublengths.append([bases, sublength])
            if not comment and len(sublengths) > 1 and entry_ctl == 'c':
                if not sublengths[-1][0]:
                    length -= sublengths.pop()[1]
                if not sublengths[0][0]:
                    sublength = sublengths.pop(0)[1]
                    length -= sublength
                    address += sublength
            lengths = ','.join(['{}{}'.format(*s) for s in sublengths])
            if len(sublengths) > 1:
                lengths = '{},{}'.format(length, lengths)
        elif ctl in 'bstw':
            # Compute the sublengths for a 'B', 'S', 'T' or 'W' sub-block
            for statement in instructions:
                length += statement.size
                sublengths.append(statement.length)
            while len(sublengths) > 1 and sublengths[-1] == sublengths[-2]:
                sublengths.pop()
            lengths = '{},{}'.format(length, get_lengths(sublengths))

        if ctl == entry_ctl:
            sub_block_ctl = ' '
        else:
            sub_block_ctl = ctl.upper()
        addr_str = self.addr_str(address)
        if lengths:
            lengths = ',{}'.format(lengths)
        write_line('{} {}{} {}'.format(sub_block_ctl, addr_str, lengths, comment).rstrip())
Exemple #14
0
def main(args):
    parser = argparse.ArgumentParser(
        usage='snapmod.py [options] in.z80 [out.z80]',
        description="Modify a 48K Z80 snapshot.",
        add_help=False
    )
    parser.add_argument('infile', help=argparse.SUPPRESS, nargs='?')
    parser.add_argument('outfile', help=argparse.SUPPRESS, nargs='?')
    group = parser.add_argument_group('Options')
    group.add_argument('-f', '--force', dest='force', action='store_true',
                       help="Overwrite an existing snapshot.")
    group.add_argument('-m', '--move', dest='moves', metavar='src,size,dest', action='append', default=[],
                       help='Move a block of bytes of the given size from src to dest. This option may be used multiple times.')
    group.add_argument('-p', '--poke', dest='pokes', metavar='a[-b[-c]],[^+]v', action='append', default=[],
                       help="POKE N,v for N in {a, a+c, a+2c..., b}. "
                            "Prefix 'v' with '^' to perform an XOR operation, or '+' to perform an ADD operation. "
                            "This option may be used multiple times.")
    group.add_argument('-r', '--reg', dest='reg', metavar='name=value', action='append', default=[],
                       help="Set the value of a register. Do '--reg help' for more information. This option may be used multiple times.")
    group.add_argument('-s', '--state', dest='state', metavar='name=value', action='append', default=[],
                       help="Set a hardware state attribute. Do '--state help' for more information. This option may be used multiple times.")
    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 'help' in namespace.reg:
        print_reg_help('r')
        return
    if 'help' in namespace.state:
        print_state_help('s')
        return
    infile = namespace.infile
    outfile = namespace.outfile
    if unknown_args or infile is None:
        parser.exit(2, parser.format_help())
    if not infile.lower().endswith('.z80'):
        raise SkoolKitError('Unrecognised input snapshot type')

    if outfile is None:
        outfile = infile
    if namespace.force or not os.path.isfile(outfile):
        run(infile, namespace, outfile)
    else:
        write_line('{}: file already exists; use -f to overwrite'.format(outfile))
Exemple #15
0
 def _write_lines(self, lines, ctl=None, address=None, grouped=False):
     if ctl:
         write_line('{} {}'.format(ctl, address))
     if grouped:
         for index, group in enumerate(lines):
             for line_no, line in enumerate(group):
                 if line_no and index < len(lines) - 1:
                     write_line((': ' + line).rstrip())
                 else:
                     write_line(('. ' + line).rstrip())
     else:
         for line in lines:
             write_line(('. ' + line).rstrip())
Exemple #16
0
    def _write_registers(self, entry, wrote_desc):
        registers = []
        for spec in entry.registers:
            if len(spec) == 1:
                reg, desc = spec[0].partition(' ')[::2]
                if reg:
                    registers.append((reg, desc))
            elif self._trim_lines(spec):
                registers.append(('', spec))

        entry.registers = registers
        if registers:
            max_indent = max(r[0].find(':') for r in registers)
            if not wrote_desc:
                self._write_empty_paragraph()
                wrote_desc = True
            self.write_comment('')
            if entry.has_ignoreua_directive(REGISTERS):
                self.write_asm_directives(AD_IGNOREUA)
            for reg, desc in registers:
                if reg:
                    reg = reg.rjust(max_indent + len(reg) - reg.find(':'))
                    desc_indent = len(reg) + 1
                    desc_lines = wrap(desc, max(self.comment_width - desc_indent, MIN_COMMENT_WIDTH)) or ['']
                    desc_prefix = '.'.ljust(desc_indent)
                    write_line('; {} {}'.format(reg, desc_lines[0]).rstrip())
                    for line in desc_lines[1:]:
                        write_line('; {}{}'.format(desc_prefix, line).rstrip())
                else:
                    for line in desc:
                        write_line('; {}'.format(line).rstrip())

        return wrote_desc
Exemple #17
0
 def _write_instructions(self, entry, block, op_width, comment_lines, write_refs, show_text):
     index = 0
     for instruction in block.instructions:
         ctl = instruction.ctl or ' '
         address = instruction.address
         operation = instruction.operation
         if block.comment:
             comment = comment_lines[index]
         elif show_text and entry.ctl != 't':
             comment = self.to_ascii(instruction.bytes)
         else:
             comment = ''
         if index > 0 and entry.ctl == 'c' and ctl == '*' and write_refs > -1:
             self.write_referrers(EREFS_PREFIX, instruction.referrers)
         self.write_asm_directives(*instruction.asm_directives)
         if block.has_ignoreua_directive(instruction.address, INSTRUCTION):
             self.write_asm_directives(AD_IGNOREUA)
         if entry.ctl == 'c' or comment:
             write_line(('{}{} {} ; {}'.format(ctl, self.address_str(address), operation.ljust(op_width), comment)).rstrip())
         else:
             write_line(('{}{} {}'.format(ctl, self.address_str(address), operation)).rstrip())
         index += 1
Exemple #18
0
def show_search_dirs():
    write(SEARCH_DIRS_MSG)
    prefix = '- '
    write_line(prefix + 'The directory that contains the skool or ref file named on the command line')
    for search_dir in SEARCH_DIRS:
        if not search_dir:
            search_dir = 'The current working directory'
        elif not os.path.split(search_dir)[0]:
            search_dir = os.path.join('.', search_dir)
        else:
            search_dir = os.path.normpath(search_dir)
        write_line(prefix + search_dir)
    write_line(prefix + 'Any other directories specified by the -S/--search option')
    sys.exit(0)
Exemple #19
0
 def _write_registers(self, entry):
     self.write_comment('')
     if entry.has_ignoreua_directive(REGISTERS):
         self.write_asm_directive(AD_IGNOREUA)
     max_indent = max([reg.find(':') for reg, desc in entry.registers])
     for reg, desc in entry.registers:
         reg = reg.rjust(max_indent + len(reg) - reg.find(':'))
         if desc:
             desc_indent = len(reg) + 1
             desc_lines = wrap(desc, max(self.comment_width - desc_indent, MIN_COMMENT_WIDTH))
             write_line('; {} {}'.format(reg, desc_lines[0]))
             desc_prefix = '.'.ljust(desc_indent)
             for line in desc_lines[1:]:
                 write_line('; {}{}'.format(desc_prefix, line))
         else:
             write_line('; {}'.format(reg))
Exemple #20
0
 def _write_instructions(self, entry, block, op_width, write_refs):
     for index, instruction in enumerate(block.instructions):
         ctl = instruction.ctl or ' '
         address = instruction.address
         operation = instruction.operation
         comment = instruction.comment.pop(0)
         if index > 0 and entry.ctl == 'c' and ctl == '*' and write_refs:
             self.write_referrers(instruction.referrers)
         self.write_asm_directives(*instruction.asm_directives)
         if block.has_ignoreua_directive(instruction.address, INSTRUCTION):
             self.write_asm_directives(AD_IGNOREUA)
         if entry.ctl in self.config['Semicolons'] or comment is not None:
             write_line(('{}{} {:{}} ; {}'.format(ctl, self.address_str(address), operation, op_width, comment or '')).rstrip())
         else:
             write_line(('{}{} {}'.format(ctl, self.address_str(address), operation)).rstrip())
         for comment in instruction.comment:
             write_line('       {:{}} ; {}'.format('', op_width, comment).rstrip())
Exemple #21
0
    def write_entry(self, entry):
        address = self.addr_str(entry.address)

        self._write_blocks(entry.header, address)

        for directive in entry.asm_directives:
            self._write_asm_directive(directive, entry.address)

        self._write_entry_ignoreua_directive(entry, TITLE)
        if BLOCKS in self.elements:
            if BLOCK_TITLES in self.elements and not self.keep_lines:
                write_line('{} {} {}'.format(entry.ctl, address,
                                             entry.title).rstrip())
            else:
                write_line('{0} {1}'.format(entry.ctl, address))
                if self.keep_lines:
                    self._write_lines(entry.title)

        self._write_entry_ignoreua_directive(entry, DESCRIPTION)
        if entry.description and BLOCK_DESC in self.elements:
            self._write_block_comments(entry.description, 'D', address)

        self._write_entry_ignoreua_directive(entry, REGISTERS)
        if entry.registers and REGISTERS in self.elements:
            if self.keep_lines:
                self._write_lines(entry.registers[0].contents, 'R', address)
            else:
                for reg in entry.registers:
                    if reg.prefix:
                        name = '{}:{}'.format(reg.prefix, reg.name)
                    else:
                        name = reg.name
                    write_line('R {} {} {}'.format(address,
                                                   name.join(reg.delimiters),
                                                   reg.contents).rstrip())

        self.write_body(entry)

        self._write_entry_ignoreua_directive(entry, END)
        if entry.end_comment and BLOCK_COMMENTS in self.elements:
            self._write_block_comments(entry.end_comment, 'E', address)

        self._write_blocks(entry.footer, address, True)
Exemple #22
0
    def write_entry(self, entry):
        address = self.addr_str(entry.address)

        self._write_blocks(entry.header, address)

        for directive in entry.asm_directives:
            self._write_entry_asm_directive(entry, directive)

        self._write_entry_ignoreua_directive(entry, TITLE)
        if BLOCKS in self.elements:
            if BLOCK_TITLES in self.elements and not self.keep_lines:
                write_line('{} {} {}'.format(entry.ctl, address, entry.title).rstrip())
            else:
                write_line('{0} {1}'.format(entry.ctl, address))
                if self.keep_lines:
                    self._write_lines(entry.title)

        self._write_entry_ignoreua_directive(entry, DESCRIPTION)
        if entry.description and BLOCK_DESC in self.elements:
            self._write_block_comments(entry.description, 'D', address)

        self._write_entry_ignoreua_directive(entry, REGISTERS)
        if entry.registers and REGISTERS in self.elements:
            if self.keep_lines:
                self._write_lines(entry.registers[0].contents, 'R', address)
            else:
                for reg in entry.registers:
                    if reg.prefix:
                        name = '{}:{}'.format(reg.prefix, reg.name)
                    else:
                        name = reg.name
                    write_line('R {} {} {}'.format(address, name, reg.contents).rstrip())

        self.write_body(entry)

        self._write_entry_ignoreua_directive(entry, END)
        if entry.end_comment and BLOCK_COMMENTS in self.elements:
            self._write_block_comments(entry.end_comment, 'E', address)

        self._write_blocks(entry.footer, address, True)
Exemple #23
0
 def _write_instructions(self, entry, block, op_width, write_refs):
     for index, instruction in enumerate(block.instructions):
         ctl = instruction.ctl or ' '
         address = instruction.address
         operation = instruction.operation
         comment = instruction.comment.pop(0)
         if index > 0 and entry.ctl == 'c' and ctl == '*' and write_refs:
             self.write_referrers(instruction.referrers)
         self.write_asm_directives(*instruction.asm_directives)
         self.write_asm_directives(
             block.get_ignoreua_directive(INSTRUCTION, instruction.address))
         if entry.ctl in self.config['Semicolons'] or comment is not None:
             write_line(('{}{} {:{}} ; {}'.format(ctl,
                                                  self.address_str(address),
                                                  operation, op_width,
                                                  comment or '')).rstrip())
         else:
             write_line(('{}{} {}'.format(ctl, self.address_str(address),
                                          operation)).rstrip())
         for comment in instruction.comment:
             write_line('       {:{}} ; {}'.format('', op_width,
                                                   comment).rstrip())
Exemple #24
0
 def _write_asm_directive(self, directive, address):
     write_line('@ {} {}'.format(self.addr_str(address), directive))
Exemple #25
0
 def write(self):
     for entry in self.parser.memory_map:
         self.write_entry(entry)
     if self.parser.end_address < 65536:
         write_line('i {}'.format(self.addr_str(self.parser.end_address)))
Exemple #26
0
 def write_asm_directives(self, *directives):
     for directive in directives:
         write_line('@' + directive)
Exemple #27
0
 def write_comment(self, text):
     if text:
         for line in self.wrap(text):
             write_line('; {0}'.format(line))
     else:
         write_line(';')
Exemple #28
0
 def write_skool(self, write_refs, text):
     for entry_index, entry in enumerate(self.disassembly.entries):
         if entry_index:
             write_line('')
         self._write_entry(entry, write_refs, text)
Exemple #29
0
 def _write_block_comments(self, comments, ctl, address):
     if self.keep_lines:
         self._write_lines(comments, ctl, address)
     else:
         for p in comments:
             write_line('{} {} {}'.format(ctl, address, p))
Exemple #30
0
 def _write_asm_directive(self, directive, address):
     if self.write_asm_dirs:
         write_line('@ {} {}'.format(self.addr_str(address), directive))
Exemple #31
0
def _write_z80(ram, options, fname):
    parent_dir = os.path.dirname(fname)
    if parent_dir and not os.path.isdir(parent_dir):
        os.makedirs(parent_dir)
    write_line('Writing {0}'.format(fname))
    write_z80v3(fname, ram, options.reg, options.state)
Exemple #32
0
def main(args):
    parser = SkoolKitArgumentParser(
        usage='\n  tap2sna.py [options] INPUT snapshot.z80\n  tap2sna.py @FILE',
        description=
        "Convert a TAP or TZX file (which may be inside a zip archive) into a Z80 snapshot. "
        "INPUT may be the full URL to a remote zip archive or TAP/TZX file, or the path to a local file. "
        "Arguments may be read from FILE instead of (or as well as) being given on the command line.",
        fromfile_prefix_chars='@',
        add_help=False)
    parser.add_argument('args', help=argparse.SUPPRESS, nargs='*')
    group = parser.add_argument_group('Options')
    group.add_argument('-d',
                       '--output-dir',
                       dest='output_dir',
                       metavar='DIR',
                       help="Write the snapshot file in this directory.")
    group.add_argument('-f',
                       '--force',
                       action='store_true',
                       help="Overwrite an existing snapshot.")
    group.add_argument('-p',
                       '--stack',
                       dest='stack',
                       metavar='STACK',
                       type=integer,
                       help="Set the stack pointer.")
    group.add_argument(
        '--ram',
        dest='ram_ops',
        metavar='OPERATION',
        action='append',
        default=[],
        help=
        "Perform a load, move or poke operation on the memory snapshot being built. "
        "Do '--ram help' for more information. This option may be used multiple times."
    )
    group.add_argument(
        '--reg',
        dest='reg',
        metavar='name=value',
        action='append',
        default=[],
        help=
        "Set the value of a register. Do '--reg help' for more information. "
        "This option may be used multiple times.")
    group.add_argument('-s',
                       '--start',
                       dest='start',
                       metavar='START',
                       type=integer,
                       help="Set the start address to JP to.")
    group.add_argument(
        '--state',
        dest='state',
        metavar='name=value',
        action='append',
        default=[],
        help=
        "Set a hardware state attribute. Do '--state help' for more information. "
        "This option may be used multiple times.")
    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 'help' in namespace.ram_ops:
        _print_ram_help()
        return
    if 'help' in namespace.reg:
        print_reg_help()
        return
    if 'help' in namespace.state:
        print_state_help()
        return
    if unknown_args or len(namespace.args) != 2:
        parser.exit(2, parser.format_help())
    url, z80 = namespace.args
    if namespace.output_dir:
        z80 = os.path.join(namespace.output_dir, z80)
    if namespace.stack is not None:
        namespace.reg.append('sp={}'.format(namespace.stack))
    if namespace.start is not None:
        namespace.reg.append('pc={}'.format(namespace.start))
    if namespace.force or not os.path.isfile(z80):
        try:
            make_z80(url, namespace, z80)
        except Exception as e:
            raise SkoolKitError("Error while getting snapshot {0}: {1}".format(
                os.path.basename(z80), e.args[0]))
    else:
        write_line('{0}: file already exists; use -f to overwrite'.format(z80))
Exemple #33
0
 def write(self, min_address=0, max_address=65536):
     for line in self._parse_skool(min_address, max_address):
         write_line(str(line))
Exemple #34
0
def notify(notice):
    if verbose:
        write_line(notice)
Exemple #35
0
 def write_skool(self, write_refs, text):
     for entry_index, entry in enumerate(self.disassembly.entries):
         if entry_index:
             write_line('')
         self._write_entry(entry, write_refs, text)
Exemple #36
0
 def write_asm_directives(self, *directives):
     for directive in directives:
         write_line('@' + directive)
Exemple #37
0
    def write_body(self, entry):
        if entry.ctl in 'gu':
            entry_ctl = 'b'
        else:
            entry_ctl = entry.ctl
        first_instruction = entry.instructions[0]
        if entry_ctl == 'i' and not first_instruction.operation:
            # Don't write any sub-blocks for an empty 'i' entry
            return

        # Split the entry into sections separated by mid-block comments
        sections = []
        for instruction in entry.instructions:
            mbc = instruction.mid_block_comment
            if mbc or not sections:
                sections.append((mbc, [instruction]))
            else:
                sections[-1][1].append(instruction)

        for k, (mbc, instructions) in enumerate(sections):
            if BLOCK_COMMENTS in self.elements and mbc:
                first_instruction = instructions[0]
                if first_instruction.ignoremrcua and self.write_asm_dirs:
                    self._write_asm_directive(
                        '{}:{}'.format(AD_IGNOREUA, MID_BLOCK),
                        first_instruction.address)
                address_str = self.addr_str(first_instruction.address)
                for paragraph in mbc:
                    write_line('N {} {}'.format(address_str, paragraph))

            if SUBBLOCKS in self.elements:
                sub_blocks = self.get_sub_blocks(instructions)
                for j, (ctl, instructions) in enumerate(sub_blocks):
                    has_bases = False
                    for instruction in instructions:
                        self._write_instruction_asm_directives(instruction)
                        if instruction.bases:
                            has_bases = True
                    first_instruction = instructions[0]
                    if ctl != 'M' or COMMENTS in self.elements:
                        if ctl == 'M':
                            offset = first_instruction.comment.rowspan + 1
                            if j + offset < len(sub_blocks):
                                length = sub_blocks[j + offset][1][
                                    0].address - first_instruction.address
                            elif k + 1 < len(sections):
                                length = sections[k + 1][1][
                                    0].address - first_instruction.address
                            else:
                                length = ''
                        else:
                            length = None
                        comment_text = ''
                        comment = first_instruction.comment
                        if comment and COMMENTS in self.elements:
                            comment_text = comment.text
                            if comment.rowspan > 1 and not comment_text.replace(
                                    '.', ''):
                                comment_text = '.' + comment_text
                        if comment_text or ctl != entry_ctl or ctl != 'c' or has_bases:
                            self.write_sub_block(ctl, entry_ctl, comment_text,
                                                 instructions, length)
Exemple #38
0
 def write_skool(self, min_address=0, max_address=65536):
     for line in self._parse_sft(min_address, max_address):
         write_line(str(line))
Exemple #39
0
def notify(notice):
    if verbose:
        write_line(notice)
Exemple #40
0
 def write_comment(self, text):
     if text:
         for line in self.wrap(text):
             write_line('; {0}'.format(line))
     else:
         write_line(';')
Exemple #41
0
 def write(self):
     for entry in self.parser.memory_map:
         self.write_entry(entry)
     if self.parser.end_address < 65536:
         write_line('i {}'.format(self.addr_str(self.parser.end_address)))
Exemple #42
0
 def write_asm_directive(self, directive, value=None):
     if value is None:
         suffix = ''
     else:
         suffix = '={0}'.format(value)
     write_line('@{}{}'.format(directive, suffix))
Exemple #43
0
 def _write_block_comments(self, comments, ctl, address):
     if self.keep_lines:
         self._write_lines(comments, ctl, address)
     else:
         for p in comments:
             write_line('{} {} {}'.format(ctl, address, p))
Exemple #44
0
def main(args):
    parser = argparse.ArgumentParser(
        usage='snapmod.py [options] in.z80 [out.z80]',
        description="Modify a 48K Z80 snapshot.",
        add_help=False)
    parser.add_argument('infile', help=argparse.SUPPRESS, nargs='?')
    parser.add_argument('outfile', help=argparse.SUPPRESS, nargs='?')
    group = parser.add_argument_group('Options')
    group.add_argument('-f',
                       '--force',
                       dest='force',
                       action='store_true',
                       help="Overwrite an existing snapshot.")
    group.add_argument(
        '-m',
        '--move',
        dest='moves',
        metavar='src,size,dest',
        action='append',
        default=[],
        help=
        'Move a block of bytes of the given size from src to dest. This option may be used multiple times.'
    )
    group.add_argument(
        '-p',
        '--poke',
        dest='pokes',
        metavar='a[-b[-c]],[^+]v',
        action='append',
        default=[],
        help="POKE N,v for N in {a, a+c, a+2c..., b}. "
        "Prefix 'v' with '^' to perform an XOR operation, or '+' to perform an ADD operation. "
        "This option may be used multiple times.")
    group.add_argument(
        '-r',
        '--reg',
        dest='reg',
        metavar='name=value',
        action='append',
        default=[],
        help=
        "Set the value of a register. Do '--reg help' for more information. This option may be used multiple times."
    )
    group.add_argument(
        '-s',
        '--state',
        dest='state',
        metavar='name=value',
        action='append',
        default=[],
        help=
        "Set a hardware state attribute. Do '--state help' for more information. This option may be used multiple times."
    )
    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 'help' in namespace.reg:
        _print_reg_help()
        return
    if 'help' in namespace.state:
        _print_state_help()
        return
    infile = namespace.infile
    outfile = namespace.outfile
    if unknown_args or infile is None:
        parser.exit(2, parser.format_help())
    if not infile.lower().endswith('.z80'):
        raise SkoolKitError('Unrecognised input snapshot type')

    if outfile is None:
        outfile = infile
    if namespace.force or not os.path.isfile(outfile):
        run(infile, namespace, outfile)
    else:
        write_line(
            '{}: file already exists; use -f to overwrite'.format(outfile))