SkoolKit components

SkoolKit relies on several components in order to function:

The objects that are used for these components can be specified in the [skoolkit] section of skoolkit.ini.

[skoolkit]

Global configuration for SkoolKit can be specified in the [skoolkit] section of a file named skoolkit.ini either in the current working directory or in ~/.skoolkit. The default contents of this section are as follows:

[skoolkit]
Assembler=skoolkit.z80.Assembler
ControlDirectiveComposer=skoolkit.skoolctl.ControlDirectiveComposer
ControlFileGenerator=skoolkit.snactl
DefaultDisassemblyStartAddress=16384
Disassembler=skoolkit.disassembler.Disassembler
HtmlTemplateFormatter=skoolkit.skoolhtml.TemplateFormatter
ImageWriter=skoolkit.image.ImageWriter
InstructionUtility=skoolkit.skoolparser.InstructionUtility
OperandEvaluator=skoolkit.z80
OperandFormatter=skoolkit.disassembler.OperandFormatter
SnapshotReader=skoolkit.snapshot
SnapshotReferenceCalculator=skoolkit.snaskool
SnapshotReferenceOperations=DJ,JR,JP,CA,RS

Most of the parameters in the [skoolkit] section specify the objects to use for SkoolKit’s pluggable components. The other recognised parameters are:

  • DefaultDisassemblyStartAddress - the address at which to start disassembling a snapshot when no control file is provided; this is used by sna2ctl.py and sna2skool.py, and also by snapinfo.py when generating a call graph
  • SnapshotReferenceOperations - the instructions whose address operands are used by the snapshot reference calculator to identify entry points in routines and data blocks

Assembler

This object is responsible for converting assembly language instructions and DEFB/DEFM/DEFS/DEFW statements into byte values, or computing their size. It must supply the following API functions, in common with skoolkit.z80.Assembler:

class skoolkit.z80.Assembler
assemble(operation, address)

Convert an assembly language instruction or DEFB/DEFM/DEFS/DEFW statement into a sequence of byte values.

Parameters:
  • operation – The operation to convert (e.g. ‘XOR A’).
  • address – The instruction address.
Returns:

A sequence of byte values (empty if the instruction cannot be assembled).

get_size(operation, address)

Compute the size (in bytes) of an assembly language instruction or DEFB/DEFM/DEFS/DEFW statement.

Parameters:
  • operation – The operation (e.g. ‘XOR A’).
  • address – The instruction address.
Returns:

The instruction size, or 0 if the instruction cannot be assembled.

Control directive composer

This class is responsible for computing the type, length and sublengths of a DEFB/DEFM/DEFS/DEFW statement, or the operand bases of a regular instruction, for the purpose of composing a control directive. It must supply the following API methods, in common with skoolkit.skoolctl.ControlDirectiveComposer:

class skoolkit.skoolctl.ControlDirectiveComposer(preserve_base)

Initialise the control directive composer.

Parameters:preserve_base – Whether to preserve the base of decimal and hexadecimal values with explicit ‘d’ and ‘h’ base indicators.
compose(operation)

Compute the type, length and sublengths of a DEFB/DEFM/DEFS/DEFW statement, or the operand bases of a regular instruction.

Parameters:operation – The operation (e.g. ‘LD A,0’ or ‘DEFB 0’).
Returns:A 3-element tuple, (ctl, length, sublengths), where:
  • ctl is ‘B’ (DEFB), ‘C’ (regular instruction), ‘S’ (DEFS), ‘T’ (DEFM) or ‘W’ (DEFW)
  • length is the number of bytes in the DEFB/DEFM/DEFS/DEFW statement, or the operand base indicator for a regular instruction (e.g. ‘b’ for ‘LD A,%00000001’)
  • sublengths is a colon-separated sequence of sublengths (e.g. ‘1:c1’ for ‘DEFB 0,”a”’), or None for a regular instruction

If compose() encounters an error while parsing an operation and cannot recover, it should raise a SkoolParsingError:

class skoolkit.SkoolParsingError

Raised when an error occurs while parsing a skool file.

Control file generator

This object is reponsible for generating a dictionary of control directives from a snapshot. Each key in the dictionary is an address, and the associated value is the control directive (e.g. ‘b’ or ‘c’) for that address. The control file generator object must supply the following API function, in common with skoolkit.snactl:

skoolkit.snactl.generate_ctls(snapshot, start, end, code_map, config)

Generate control directives from a snapshot.

Parameters:
  • snapshot – The snapshot.
  • start – Start address. No control directives should be generated before this address.
  • end – End address. No control directives should be generated after this address.
  • code_map – Code map filename (may be None).
  • config

    Configuration object with the following attributes:

    • text_chars - string of characters eligible for being marked as text
    • text_min_length_code - minimum length of a string of characters eligible for being marked as text in a block identified as code
    • text_min_length_data - minimum length of a string of characters eligible for being marked as text in a block identified as data
    • words - collection of allowed words; if not empty, a string of characters should be marked as text only if it contains at least one of the words in this collection
Returns:

A dictionary of control directives.

Disassembler

This class is responsible for converting byte values into assembly language instructions and DEFB/DEFM/DEFS/DEFW statements. It must supply the following API methods, in common with skoolkit.disassembler.Disassembler:

class skoolkit.disassembler.Disassembler(snapshot, config)

Initialise the disassembler.

Parameters:
  • snapshot – The snapshot (list of 65536 byte values) to disassemble.
  • config

    Configuration object with the following attributes:

    • asm_hex - if True, produce a hexadecimal disassembly
    • asm_lower - if True, produce a lower case disassembly
    • defb_size - default maximum number of bytes in a DEFB statement
    • defm_size - default maximum number of characters in a DEFM statement
    • defw_size - default maximum number of words in a DEFW statement
    • wrap - if True, disassemble an instruction that wraps around the 64K boundary
defb_range(start, end, sublengths)

Produce a sequence of DEFB statements for an address range.

Parameters:
  • start – The start address.
  • end – The end address.
  • sublengths – Sequence of sublength identifiers.
Returns:

A list of tuples of the form (address, operation, bytes).

defm_range(start, end, sublengths)

Produce a sequence of DEFM statements for an address range.

Parameters:
  • start – The start address.
  • end – The end address.
  • sublengths – Sequence of sublength identifiers.
Returns:

A list of tuples of the form (address, operation, bytes).

defs_range(start, end, sublengths)

Produce a sequence of DEFS statements for an address range.

Parameters:
  • start – The start address.
  • end – The end address.
  • sublengths – Sequence of sublength identifiers.
Returns:

A list of tuples of the form (address, operation, bytes).

defw_range(start, end, sublengths)

Produce a sequence of DEFW statements for an address range.

Parameters:
  • start – The start address.
  • end – The end address.
  • sublengths – Sequence of sublength identifiers.
Returns:

A list of tuples of the form (address, operation, bytes).

disassemble(start, end, base)

Disassemble an address range.

Parameters:
  • start – The start address.
  • end – The end address.
  • base – Base indicator (‘b’, ‘c’, ‘d’, ‘h’, ‘m’ or ‘n’). For instructions with two numeric operands (e.g. ‘LD (IX+d),n’), the indicator may consist of two letters, one for each operand (e.g. ‘dh’).
Returns:

A list of tuples of the form (address, operation, bytes).

The 3-element tuples returned by these methods should have the form (address, operation, bytes), where:

  • address is the address of the instruction
  • operation is the operation (e.g. ‘XOR A’, ‘DEFB 1’)
  • bytes is a sequence of byte values for the instruction (e.g. (62, 0) for ‘LD A,0’)

The sublengths argument of the defb_range(), defm_range(), defs_range() and defw_range() methods is a sequence of 2-element tuples of the form (size, base), each of which specifies the desired size (in bytes) and number base for an item in the DEFB/DEFM/DEFS/DEFW statement. base may have one of the following values:

  • ‘b’ - binary
  • ‘c’ - character
  • ‘d’ - decimal
  • ‘h’ - hexadecimal
  • ‘m’ - negative
  • ‘n’ - default base

If the first element of sublengths has a size value of 0, then the method should produce a list of statements with default sizes (as determined by defb_size, defm_size and defw_size), using the specified base.

Changed in version 8.5: Added the ability to disassemble an instruction that wraps around the 64K boundary, along with the wrap attribute on the disassembler configuration object to control this behaviour.

HTML template formatter

This class is responsible for formatting HTML templates. It must supply the following API methods, in common with skoolkit.skoolhtml.TemplateFormatter:

class skoolkit.skoolhtml.TemplateFormatter(templates)

Initialise the template formatter.

Parameters:templates – A dictionary of templates keyed by template name.
format_template(page_id, name, fields)

Format a template.

Parameters:
  • page_id – The ID of the current page.
  • name – The template name.
  • fields – A dictionary of replacement field values.
Returns:

The text of the formatted template.

Image writer

This class is responsible for constructing images and writing them to files. It must supply the following API methods, in common with skoolkit.image.ImageWriter:

class skoolkit.image.ImageWriter(config=None, palette=None)

Initialise the image writer.

Parameters:
  • config – A dictionary constructed from the contents of the [ImageWriter] section of the ref file.
  • palette – A dictionary constructed from the contents of the [Colours] section of the ref file. Each key is a colour name, and each value is a three-element tuple representing an RGB triplet.

If config or palette is None, empty, or missing values, default values are used.

image_fname(fname)

Convert the fname parameter of an image macro into an image filename with an appropriate extension.

Parameters:fname – The fname parameter of the image macro.
Returns:The image filename.
write_image(frames, img_file)

Write an image file. If this method leaves the image file empty, the file will be removed.

Parameters:
  • frames – A list of Frame objects from which to build the image.
  • img_file – The file object to write the image to.
Returns:

The content with which the image macro is replaced; if None, an appropriate <img .../> element is used.

Instruction utility

This object is responsible for performing various operations on the instructions in a skool file:

  • converting base and case
  • replacing addresses with labels (or other addresses) in instruction operands; this is required both for ASM output and for binary output
  • generating a dictionary of references (for each instruction that refers to another instruction); this is required for hyperlinking instruction operands in HTML output
  • generating a dictionary of referrers (for each instruction that is referred to by other instructions); this is required by the special EREF and REF variables of the #FOREACH macro
  • deciding whether to set byte values; this affects the #PEEK macro and the image macros, and instruction byte values in HTML output

The object must supply the following API functions, in common with skoolkit.skoolparser.InstructionUtility:

class skoolkit.skoolparser.InstructionUtility
calculate_references(entries, remote_entries)

Generate a dictionary of references (for each instruction that refers to another instruction) and a dictionary of referrers (for each instruction that is referred to by other instructions) from the instructions in a skool file.

Parameters:
  • entries – A collection of memory map entries.
  • remote_entries – A collection of remote entries (as defined by @remote directives).
Returns:

A tuple containing the two dictionaries.

convert(entries, base, case)

Convert the base and case of every instruction in a skool file.

Parameters:
  • entries – A collection of memory map entries.
  • base – The base to convert to: 0 for no conversion, 10 for decimal, or 16 for hexadecimal.
  • case – The case to convert to: 0 for no conversion, 1 for lower case, or 2 for upper case.
set_byte_values(instruction, assemble)

Decide whether to set byte values in the memory snapshot and for an instruction.

If byte values are set in the memory snapshot, then they are available to the #PEEK macro and the image macros. If byte values are set for an instruction, then they are available for display in HTML output via the instruction[bytes] replacement field in the asm template.

Parameters:
  • instruction – The instruction.
  • assemble – The current value of the assemble property (as set by the @assemble directive).
Returns:

2 if both the snapshot and the instruction should have byte values defined, 1 if only the snapshot should, or 0 if neither should.

substitute_labels(entries, remote_entries, labels, mode, warn)

Replace addresses with labels in the operands of every instruction in a skool file.

Parameters:
  • entries – A collection of memory map entries.
  • remote_entries – A collection of remote entries (as defined by @remote directives).
  • labels – A dictionary mapping addresses to labels.
  • mode – The substitution mode: 1 (@isub), 2 (@ssub), 3 (@rsub), or 0 (none).
  • warn

    A function to be called if a warning is generated when attempting to replace an address in an instruction operand with a label. The function must accept two arguments:

    • message - the warning message.
    • instruction - the instruction object.

Memory map entries and remote entries have the following attributes:

  • ctl - the entry’s control directive (‘b’, ‘c’, ‘g’, ‘i’, ‘s’, ‘t’, ‘u’ or ‘w’ for a memory map entry; None for a remote entry)
  • instructions - a collection of instruction objects

Each instruction object has the following attributes:

  • address - the address of the instruction as stated in the skool file; note that this will not be the same as the actual address of the instruction if it has been moved by the insertion, removal or replacement of other instructions by @*sub or @*fix directives
  • keep - None if the instruction has no @keep directive; an empty collection if it has a bare @keep directive; or a collection of addresses if it has a @keep directive with one or more values
  • nowarn - None if the instruction has no @nowarn directive; an empty collection if it has a bare @nowarn directive; or a collection of addresses if it has a @nowarn directive with one or more values
  • operation - the operation (e.g. ‘XOR A’) after any @*sub or @*fix directives have been applied; for an instruction in a remote entry, this is an empty string
  • refs - the addresses of the instruction’s indirect referrers, as declared by a @refs directive
  • rrefs - the addresses of the instruction’s direct referrers to be removed, as declared by a @refs directive
  • sub - True if the operation was supplied by @*sub or @*fix directive, False otherwise

Each key in the references dictionary should be an instruction object, and the corresponding value should be a 3-element tuple:

(ref_instruction, address_s, use_label)
  • ref_instruction - the instruction referred to
  • address_s - the address string in the operand of the referring instruction (to be replaced by a hyperlink in HTML output)
  • use_label - whether to use a label as the link text for the hyperlink in HTML output; if no label for ref_instruction is defined, or use_label is False, the address string (address_s) will be used as the link text

Each key in the referrers dictionary should be an instruction object, and the corresponding value should be a collection of the entries that refer to that instruction.

Changed in version 8.2: Added the refs and rrefs attributes to instruction objects.

Changed in version 8.1: Added the mode parameter to the substitute_labels() method, and changed the required signature of the warn function. Added the nowarn and sub attributes to instruction objects.

Operand evaluator

This object is used by the assembler to evaluate instruction operands, and by the control directive composer to determine the length and sublengths of DEFB, DEFM and DEFS statements. It must supply the following API functions, in common with skoolkit.z80:

skoolkit.z80.eval_int(text)

Evaluate an integer operand.

Parameters:text – The operand.
Returns:The integer value.
Raises:ValueError if the operand is not a valid integer.
skoolkit.z80.eval_string(text)

Evaluate a string operand.

Parameters:text – The operand, including enclosing quotes.
Returns:A list of byte values.
Raises:ValueError if the operand is not a valid string.
skoolkit.z80.split_operands(text)

Split a comma-separated list of operands.

Parameters:text – The operands.
Returns:A list of individual operands.

Operand formatter

This class is used by the disassembler to format numeric instruction operands. It must supply the following API methods, in common with skoolkit.disassembler.OperandFormatter:

class skoolkit.disassembler.OperandFormatter(config)

Initialise the operand formatter.

Parameters:config

Configuration object with the following attributes:

  • asm_hex - if True, default base is hexadecimal
  • asm_lower - if True, format operands in lower case
format_byte(value, base)

Format a byte value.

Parameters:
  • value – The byte value.
  • base – The desired base (‘b’, ‘c’, ‘d’, ‘h’, ‘m’ or ‘n’).
Returns:

The formatted byte value.

format_word(value, base)

Format a word (2-byte) value.

Parameters:
  • value – The word value.
  • base – The desired base (‘b’, ‘c’, ‘d’, ‘h’, ‘m’ or ‘n’).
Returns:

The formatted word value.

is_char(value)

Return whether a byte value can be formatted as a character.

Parameters:value – The byte value.

Snapshot reader

This object is responsible for producing a 65536-element list of byte values from a snapshot file. It must supply the following API functions, in common with skoolkit.snapshot:

skoolkit.snapshot.can_read(fname)

Return whether this snapshot reader can read the file fname.

skoolkit.snapshot.get_snapshot(fname, page=None)

Read a snapshot file and produce a 65536-element list of byte values.

Parameters:
  • fname – The snapshot filename.
  • page – The page number to map to addresses 49152-65535 (C000-FFFF). This is relevant only when reading a 128K snapshot file.
Returns:

A 65536-element list of byte values.

If get_snapshot() encounters an error while reading a snapshot file, it should raise a SnapshotError:

class skoolkit.snapshot.SnapshotError

Raised when an error occurs while reading a snapshot file.

Snapshot reference calculator

This object is responsible for generating a dictionary of entry point addresses from a snapshot. Each key in the dictionary is an entry point address, and the associated value is a collection of entries that jump to, call or otherwise refer to that entry point. This dictionary is needed by sna2skool.py for marking each entry point in a skool file with an asterisk, and listing its referrers.

The snapshot reference calculator must supply the following API function, in common with skoolkit.snaskool:

skoolkit.snaskool.calculate_references(entries, operations)

For each instruction address in a memory map entry, calculate a list of the entries containing instructions that jump to, call or otherwise refer to that address.

Parameters:
  • entries – A collection of memory map entries.
  • operations – A tuple of regular expression patterns. The address operand of any instruction whose operation matches one of these patterns identifies an entry point that will be marked with an asterisk in the skool file.
Returns:

A dictionary of entry point addresses.

The value of the operations argument is derived from the SnapshotReferenceOperations parameter in the [skoolkit] section of skoolkit.ini. In its default form, this parameter is a comma-separated list of regular expression patterns that designates ‘DJNZ’, ‘JR’, ‘JP’, ‘CALL’ and ‘RST’ operations as those whose address operands will be used to identify entry points in the skool file:

SnapshotReferenceOperations=DJ,JR,JP,CA,RS

To use a pattern that contains a comma, an alternative (non-alphabetic) separator can be specified in the first character of the parameter value. For example:

SnapshotReferenceOperations=;DJ;JR;JP;CA;RS;LD A,\(\i\);LD \(\i\),A

This would additionally designate the ‘LD A,(nn)’ and ‘LD (nn),A’ operations as identifying entry points. As a convenience for dealing with decimal and hexadecimal numbers, wherever \i appears in a pattern, it is replaced by a pattern that matches a decimal number or a hexadecimal number preceded by $.

Each memory map entry has the following attributes:

  • ctl - the entry’s control directive (‘b’, ‘c’, ‘g’, ‘i’, ‘s’, ‘t’, ‘u’ or ‘w’)
  • instructions - a collection of instruction objects

Each instruction object has the following attributes:

  • address - the address of the instruction
  • bytes - the byte values of the instruction
  • label - the instruction’s label, as defined by a @label directive
  • operation - the operation (e.g. ‘XOR A’)
  • refs - the addresses of the instruction’s indirect referrers, as declared by a @refs directive
  • rrefs - the addresses of the instruction’s direct referrers to be removed, as declared by a @refs directive

Changed in version 8.5: The SnapshotReferenceOperations parameter defines a list of regular expression patterns.

Changed in version 8.2: Added the refs and rrefs attributes to instruction objects.

Component API

The following functions are provided to facilitate access to the components and other values declared in the [skoolkit] section of skoolkit.ini.

skoolkit.components.get_component(name, *args)

Return a component declared in the [skoolkit] section of skoolkit.ini.

Parameters:
  • name – The component name.
  • args – Arguments passed to the component’s constructor.
skoolkit.components.get_value(name)

Return a parameter value from the [skoolkit] section of skoolkit.ini.

Parameters:name – The parameter name.