Control directives tell the disassembler to treat specified areas of the code to be disassembled as something other than executable code. The user specifies control directives by editing (with any text editor) a control file with the same name as the file to be disassembled, but with a file extention of .ctl (eg: program.ctl to control the disassembly of the file program.hex or program.bin). A generic control file called 'generic.ctl' is provided to get the user started. Copy 'generic.ctl' to 'file.ctl' where 'file' is the name of the binary or Intel hex file to be disassembled, and modify as required based on the output of the disassembler. Then run the disassembler again to get a more readable disassembly of the code.
All directives consist of a character that specifies the type of data, followed by a hexadecimal number specifying the value or range of values of the data. In the case of a label or symbol directive, the hexadecimal number is followed by ascii text defining the label or symbol. See individual directives for examples. All directives must be in the first column of the line. Directives may be complete words, but only the first character is significant, ie:
Label | 0 | reset | and | ||||||||||||||||||||
looney | 0 | reset |
will both generate the label "reset" for address 0. Note that they are not case sensitive.
Numerical values must be in hexadecimal and may optionally be preceeded by "0x". For example, a hexadecimal number may be entered as "1234" or "0x1234". Either will be interpreted as the number 1234H.
Everything following a semi-colon (;) is a comment and will be ignored by the disassembler.
Label and symbol directives differ in that a label refers to an address and a symbol refers to any 8 or 16 bit immediate data.
Symbols apply only to immediate data. To specify a symbol for an Z80 data memory location, use the R directive , or to force name substitution for an operand at a given address, use the X directive.
Single values are specified by entering just the value; ranges of values are specified by a start and stop address separated by a dash (-), or by a start address and count separated by a plus (+), ie:
t 1000 | the data at address 1000H is ascii text. | |||||||||||
t 1000-1010 | the data from address 1000H to (and including) address 1010H is ascii text. | |||||||||||
t 1000+6 | ascii text starting at 1000H for 6 bytes. |
Directives are processed in the order in which they are read from the control file. Specifying an area as ascii data and then later specifying it as data to be ignored (uninitialized data) will cause that area to not be disassembled at all. Care must be taken in specifying areas in the control file.
A Directive (address data)
Specifies that the address contains a word value corresponding to an address for which a label should be generated. For example, a vector table may be located at address 0x1000 containing four entries. The user can modify the control file by adding the following entry:
a 1000-1007 |
This will cause the disassembler to generate the following output lines:
defw | vec1 | |||||||||
defw | vec2 | |||||||||
defw | vec3 | |||||||||
defw | vec4 |
assuming that the control file also contains entries for the values found at those addresses to generate the labels vec1 through vec4. The addresses referenced will be flagged so that labels will be generated in the output file at those addresses.
B Directive (byte binary data)
Specifies that the data is to be interpreted as 8 bit binary data. For example:
b 1000-1007 |
tells the disassembler that the data from address 1000H to 1007H should generate the line:
defb | 0,1,2,3,4,5,6,7 |
assuming that the data at address 1000H and up is 00H, 01H, etc.
C Directive (code data)
Forces the disassembler to interpret the data as executable code. This may be necessary because the disassembler skips over strings of 00H or ffH bytes that occur since they are unlikely to be real code. However, sometimes programmers insert several NOPs for timing purposes.
D Directive (define data type (label or symbol))
d address [0 or label] | search label table only | |||||||||
d address [1 or symbol] | search symbol table only | |||||||||
d address [2 or none] | don't search either table |
Forces the disassembler to search only the label or symbol table. This allows you to specify a label and a symbol for the same value.
Note that the last parameter can be either a number (0, 1, or 2) or a word (label, symbol, none). If the last parameter is a word, only the first character is checked for L, S, or N, and is not case sensitive.
I Directive (ignore data)
Tells the disassembler to ignore a range of addresses that may be initialized by the input file. This is useful when the input file is a binary file generated by an eprom programmer that dumps the entire eprom space. The valid data from a 4K eprom might only be, say, 3K in length. By adding
i c00-fff |
to the control file, you tell the disassembler to not disassemble the data from address 0c00H to 0fffH.
L Directive (label definition)
Defines a label to the disassembler. Labels are generated in the output disassembly file whenever a reference to the address is found and the label exists in the label table. Suppose that address 0000H contains the code 01 43 (ajmp 0043H). Then the entry
l 43 start |
in the control file will cause mdz80 to disassemble this code as:
JP | start |
rather than:
JP | X0043 |
The code beginning at address 43H will then have the label 'start' in the label field rather than the label 'X0043'. See the entry for the S directive for an explanation of the difference between labels and symbols and also -e command line option that can be used to automate this task.
N Directive (suppress address label generation)
The disassembler will generate labels for addresses that are referenced by code such as
LD | A,6 |
If the operand represents a constant rather than an address, you can suppress the automatic generation of a label (X0006) for address 6h by entering
n 6 |
in the control file. You'd want to make sure that address 6h isn't legitimately addressed by some other code before using this directive.
O Directive (add hexadecimal offset to addresses)
This directive causes the disassembler to add a hexadecimal offset to the address of every location in the code file. See the -x option for details. It will be overridden by any -x option specified on the command line. If the -t option (trace and analyze code) is given on the command line, the O directive has no effect since any existing control file will be rewritten. In this case you must use the command line -x option to specify an offset.
P Directive (patch inline code)
This directive is of dubious value, but has been added for anyone who might find it useful. The P directive is similar to the comment directive except that the user supplied string is patched into the output stream as code, not as a comment. You could, for instance, patch in a macro definition or an include statement. Patching in executable code is not a real good idea.
S Directive (symbol definition)
Defines a symbol to the disassembler. Symbols are output to the disassembly file whenever the value is encountered in the input file and the symbol exists in the symbol table. The user can specify a symbol for a value by a line such as:
s 20 space |
Code which uses this value, such as:
LD | A,20h |
will then be disassembled as:
LD | A,SPACE |
Labels and symbols differ in that a label applies to an address, whereas a symbol applies to any 8 or 16 bit immediate data. For code which can only refer to values, such as
LD | A,20h |
only the symbol table will be searched for a matching value. For code which could refer to either an address or a value, such as:
LD | HL,(1234h) |
the label table will be searched first, and only if no matching value is found will the symbol table then be searched.
T Directive (text [ascii] data)
Forces the data in the range specified to be disassembled as text (ascii data). Thus the code: 48 69 20 74 68 65 72 65 at address 1000H will be disassembled as:
DEFB | 'Hi there' | or | |||||||||||||||
ASCII | 'Hi there' | (command line option -a used) |
by putting the line:
t 1000-1007 |
in the control file. Data specified by this directive is not checked to verify that it really is ascii data--be careful.
W Directive (word binary data)
Specifies that the data is to be interpreted as 16 bit binary data. For example:
w 1000-1007 |
tells the disassembler that the data from address 1000H to 1007H should generate the lines:
DEFW | 0 | |||||||||
DEFW | 1 | |||||||||
DEFW | 2 | |||||||||
DEFW | 3 |
assuming that the data at address 1000H and up is 00H, 00H, 00H, 01H, 00H, 02H, etc. This differs from the A (address) directive in that the A directive also causes a reference to be made to the indirect address. In other words, if the data at address 1000H is 1234H, the A directive will cause a label (X1234) to be put in the output file at address 1234H, whereas the W directive will not.
X Directive (specify name for operand data)
Specify a name for an operand at a particular address. This is similar to the S directive except that it applies only to the given address. For example, if the symbol 'CR' is defined as 0dh, every instance of 0dh as an operand will have the symbol 'CR' substituted. It may be, however, that the value 0dh has a different meaning when used as an operand for a particular instruction. The X directive allows you to modify the interpretation of an operand at specific operand locations. Why not then use the X directive exclusively? Because that would force you to place an X directive in the control file for every instance in which that value appeared as an operand. The S directive, defined only once for an operand value, will substitute the symbol text for everyoccurrance of that operand value unless overridden by the X directive. Note that the address defined in the X directive is the address of the operand, not the address of the instruction. For example:
X 102 loopinit |
forces substitution of the text 'loopinit' for the operand located at address 102h. Therefore an instruction that should be interpreted as
LD | A,LOOPINIT |
will not be disassembled as
LD | A,CR |
if the control file contains the above x directive, and also contains an S directive defining 0dh as 'CR', and the value of the operand for the mov instruction happens to also be 0dh.
Y Directive (specify name for operand data but suppress EQU generation)
This is similar to the X directive except that the disassembler will not generate an EQU statement for the operand value in the output file. This should be used when you want to specify a name for an operand that is an assembler pseudo-op such as LOW() or HIGH().
# Directive (header comment string)
Defines a comment string to be output prior to disassembly at the specified address. For example:
# 95
# 95 Start of initialization
# 95
in the ctl file would cause the output
;
; Start of initialization
;
LD A,80H ;0095 3E 80 >.
assuming that the code 'c2 af' was located at address 0x95. Since ASCII strings consume prodigious amounts of memory, it is wise to use this directive sparingly. It is, however, useful for marking blocks of code that have been identified in previous runs of mdz80.
! Directive (inline comment string)
Defines a comment string to be output after disassembly at the specified address. For example:
! 95 Start of initialization
in the ctl file would cause the output
LD A,80H ;0095 3E 80 >. ; Start of initialization
for the above example. Note that inline comments are only available for code and word data, and will do nothing if the data at the specified address is defined as data other than code or word data (ascii text, for example).