Control files

A control file contains a list of start addresses of code and data blocks. This information can be used by sna2skool.py to organise a skool file into corresponding code and data blocks.

Each block address in a control file is marked with a ‘control directive’, which is a single letter that indicates what the block contains:

  • b indicates a data block
  • c indicates a code block
  • g indicates a game status buffer entry
  • i indicates a block that should be ignored
  • t indicates a block containing text
  • u indicates an unused block of memory
  • w indicates a block containing words (two-byte values)
  • z indicates an unused block containing all zeroes

(If these letters remind you of the valid characters that may appear in the first column of each line of a skool file, that is no coincidence.)

For example:

c 24576 Do stuff
b 24832 Important data
t 25088 Interesting messages
u 25344 Unused

This control file declares that:

  • Everything before 24576 should be ignored
  • There is a routine at 24576-24831 which should be titled ‘Do stuff’
  • There is data at 24832-25087
  • There is text at 25088-25343
  • Everything from 25344 onwards is unused (but should still be disassembled as data)

Addresses may be written as hexadecimal numbers, too; the equivalent example control file using hexadecimal notation would be:

c $6000 Do stuff
b $6100 Important data
t $6200 Interesting messages
u $6300 Unused

Besides the declaration of block types, addresses and titles, the control file syntax also supports the declaration of the following things:

  • Block descriptions
  • Register values
  • Mid-block comments
  • Block end comments
  • Sub-block types and comments
  • DEFB/DEFM/DEFW/DEFS statement lengths in data, text and unused sub-blocks
  • ASM directives (except block directives)

The syntax for declaring these things is described in the following sections.

Block descriptions

To provide a description for a code block at 24576 (for example), use the D directive thus:

c 24576 This is the title of the routine at 24576
D 24576 This is the description of the routine at 24576.

If the description consists of two or more paragraphs, each one should be declared with a separate D directive:

D 24576 This is the first paragraph of the description of the routine at 24576.
D 24576 This is the second paragraph of the description of the routine at 24576.

Register values

To declare the values of the registers upon entry to the routine at 24576, add one line per register with the R directive thus:

R 24576 A An important value in the accumulator
R 24576 DE Display file address

Mid-block comments

To declare a mid-block comment that will appear above the instruction at 24592, use the D directive thus:

D 24592 The next section of code does something really important.

If the mid-block comment consists of two or more paragraphs, each one should be declared with a separate D directive:

D 24592 This is the first paragraph of the mid-block comment.
D 24592 This is the second paragraph of the mid-block comment.

Block end comments

To declare a comment that will appear at the end of the routine at 24576, use the E directive thus:

E 24576 And so the work of this routine is done.

If the block end comment consists of two or more paragraphs, each one should be declared with a separate E directive:

E 24576 This is the first paragraph of the end comment for the routine at 24576.
E 24576 This is the second paragraph of the end comment for the routine at 24576.

Sub-block syntax

Sometimes a block marked as one type (code, data, text, or whatever) may contain instructions or statements of another type. For example, a word (w) block may contain the odd non-word here and there. To declare such sub-blocks whose type does not match that of the containing block, use the following syntax:

w 32768 A block containing mostly words
B 32800,3 But here's a sub-block of 3 bytes at 32800
T 32809,8 And an 8-byte text string at 32809
C 32821,10 And 10 bytes of code at 32821 too?

The directives (B, T and C) used here to mark the sub-blocks are the upper case equivalents of the directives used to mark top-level blocks (b, t and c). The comments at the end of these sub-block declarations are taken as instruction-level comments and will appear as such in the resultant skool file.

If an instruction-level comment spans a group of two or more sub-blocks of different types, it must be declared with an M directive:

M 40000,21 This comment covers the following 3 sub-blocks
B 40000,3
W 40003,10
T 40013,8

If the length parameter is omitted from an M directive, the comment is assumed to cover all sub-blocks from the given start address to the end of the top-level block.

Three bits of sub-block syntax left. First, the blank sub-block directive:

c 24576 A great routine
  24580,11 A great section of code at 24580

This is equivalent to:

c 24576 A great routine
C 24580,11 A great section of code at 24580

That is, the the type of a blank sub-block directive is taken to be the same as that of the parent block.

Next, the address range:

c 24576 A great routine
  24580-24590 A great section of code at 24580

This is equivalent to:

c 24576 A great routine
  24580,11 A great section of code at 24580

That is, you can specify the extent of a sub-block using either an address range, or an address and a length.

Finally, the implicit sub-block extent:

c 24576 A great routine
  24580 A great section of code at 24580
  24588,10 Another great section of code at 24590

This is equivalent to:

c 24576 A great routine
  24580,8 A great section of code at 24580
  24588,10 Another great section of code at 24588

But the declaration of the length (8) of the sub-block at 24580 is redundant, because the sub-block is implicitly terminated by the declaration of the sub-block at 24588 that follows. This is exactly how top-level block declarations work: each top-level block is implicitly terminated by the declaration of the next one.

Statement lengths in ‘B’, ‘T’, ‘W’ and ‘Z’ sub-blocks

Normally, a B sub-block declared thus:

B 24580,12 Interesting data

would result in something like this in the corresponding skool file:

24580 DEFB 1,2,3,4,5,6,7,8 ; {Interesting data
24588 DEFB 9,10,11,12      ; }

But what if you wanted to split the data in this sub-block into groups of 3 bytes each? That can be achieved with:

B 24580,12,3 Interesting data

which would give:

24580 DEFB 1,2,3    ; {Interesting data
24583 DEFB 4,5,6
24586 DEFB 7,8,9
24589 DEFB 10,11,12 ; }

That is, in a B directive, the desired DEFB statement lengths may be given as a comma-separated list of numbers following the sub-block length parameter, and the final number in the list is used for all remaining data in the block. So, for example:

B 24580,12,1,2,3 Interesting data

would give:

24580 DEFB 1        ; {Interesting data
24581 DEFB 2,3
24583 DEFB 4,5,6
24586 DEFB 7,8,9
24589 DEFB 10,11,12 ; }

If the statement length list contains sequences of two or more identical lengths, as in:

B 24580,21,2,2,2,2,2,2,1,1,1,3

then it may be abbreviated thus:

B 24580,21,2*6,1*3,3

The same syntax can be used for T, W and Z sub-blocks too. For example:

Z 32768,100,25 Four 25-byte chunks of zeroes

would give:

32768 DEFS 25 ; {Four 25-byte chunks of zeroes
32793 DEFS 25
32818 DEFS 25
32843 DEFS 25 ; }

DEFB and DEFM statements may contain both bytes and strings; for example:

40000 DEFM "Hi ",5
40004 DEFB 4,"go"

Such statements can be encoded in a control file thus:

T 40000,4,3:B1
B 40004,3,1:T2

That is, the length of a string in a DEFB statement is prefixed by T, the length of a sequence of bytes in a DEFM statement is prefixed by B, and the lengths of all strings and byte sequences are separated by colons. This notation can also be combined with the ‘*’ notation; for example:

T 50000,8,2:B2*2

which is equivalent to:

T 50000,8,2:B2,2:B2

ASM directives

To declare an ASM directive for a block or an individual instruction, use the following syntax:

; @directive:address[=value]

where:

  • directive is the directive name
  • address is the address of the block or instruction to which the directive applies
  • value is the value of the directive (if it requires one)

For example, to declare a @label directive for the instruction at 32768:

; @label:32768=LOOP

Note that neither ASM block directives (such as the @bfix block directives) nor the exact location of @org, @writer, @start, @end, @ignoreua and @set ASM directives can be preserved using this syntax.

Instruction-level comments

One limitation of storing instruction-level comments as shown so far is that there is no way to distinguish between a blank comment that spans two or more instructions and no comment at all. For example, both:

30000 DEFB 0 ; {
30001 DEFB 0 ; }

and:

30000 DEFB 0 ;
30001 DEFB 0 ;

would be preserved thus:

B 30000,2,1

To solve this problem, a special syntax is used to preserve blank multi-instruction comments:

B 30000,2,1 .

When restored, this comment is reduced to an empty string.

But how then to preserve a multi-instruction comment consisting of a single dot (.), or a sequence of two or more dots? In that case, another dot is prefixed to the comment. So:

30000 DEFB 0 ; {...
30001 DEFB 0 ; }

is preserved thus:

B 30000,2,1 ....

Note that this scheme does not apply to multi-instruction comments that contain at least one character other than a dot; such comments are preserved verbatim (that is, without a dot prefix).

Control file comments

A comment may be added to a control file by starting a line with something other than a space, a control directive, or ; @. For example:

; This is a comment
# This is another comment
% This is yet another comment

Limitations

A control file can be useful in the early stages of developing a skool file for reorganising code and data blocks, but it cannot preserve the following elements:

  • ASM block directives
  • the exact locations of @org, @writer, @start, @end, @ignoreua and @set ASM directives
  • data definition entries (‘d’ blocks) and remote entries (‘r’ blocks)
  • comments that are not part of a code or data block

Skool file templates, however, can preserve all of these elements, and so may be a better choice for skool files that contain any of them.

Revision history

Version Changes
1.0.7 Added support for block titles, block descriptions, register values, mid-block comments, block end comments, sub-block types and instruction-level comments
2.0.6 Added support for hexadecimal numbers
2.1 Added support for DEFB statement lengths in B sub-blocks
2.1.1 Added the M directive
2.1.2 Added support for DEFM, DEFW and DEFS statement lengths in T, W and Z sub-blocks
2.2 Added support for the * notation in DEFB, DEFM, DEFW and DEFS statement length lists in B, T, W and Z sub-blocks
2.4 Added support for non-block ASM directives
3.1.4 Added support for DEFB and DEFM statements that contain both strings and bytes
3.6 Added support for preserving blank comments that span two or more instructions