# Cycle Counting for D52

# and D48 and DZ80

by Jan Waclawek, wek at efton dot sk, Feb 2007

## Some pseudo-legal stuff

Absolutely no guarantee. Use at your own risk. What else would you expect?

## How?

Add Z directives to the .ctl file, with range for which the cycle counting has to be performed.

The output file will contain a cycle number for each instruction in the comment field, and a summary after end of each range.

Ranges for Z directives can be nested and can be defined in any order, but must not partially overlap.

All cycle counts are in given in instruction cycles. For clock cycles, multiply by clock/instruction value.

## More details...

Z[range][suffix[value]]

Range can be defined as usual with other directives in .ctl files - either as start‑end or as start+length. Range can also be a single number (except where the "-" suffix is needed - see known issues), which is equivalent to a start-start range.

Suffix is one of:

* - the total cycle count of this range is multiplied by the given value, and this value will be added to the parent range cycle count. Useful for cycle counting in cycles. See also (auto)repeat in special cases below.

- - this range (including its subranges) will be excluded from cycle count of the parent; however, the total count of this range will be written to output file. No value needed. The individual instructions' cycle count will be suffixed by “-” in the output file for this range. See also taken/not taken in special cases below.

= - the calculated cycle count for this range will be overriden by the given value. Intended to be used for individual instructions, use for a bigger range for extra fun with unexpected results. The individual instructions' cycle count will be prefixed by “=” in the output file for this range.

^ - in this range, the alternative (higher) cycle count is always used, if available. The individual instructions' cycle count will be prefixed by “^” in the output file for this range. See also taken/not taken in special cases below.

Caution, value is entered in hexadecimal with no prefix nor suffix, just as the addresses in the range.

## Special cases

Some processors, such as the Z80 and the SiLabs singleclock '51 core, have some instructions with two different cycle counts - conditional jumps (calls, returns), with different timing for the taken/not taken jump; and autorepeated instructions. The default value is the smaller, jump-not-taken, or, for the autorepeated instructions, last-repeat (single-pass), value. However, there are exceptions.

Repeated and autorepeated instructions can be properly counted, if a single-address range is given for the first byte of the instruction, with a * suffix, giving the number of repeats. In this case, the instruction's cycle count is calculated as the number of repeats less one times the bigger count, plus the smaller count. This calculation is written to the comment field and there will be no summary for this range.

For example, if Z addr*23 directive is used for a djnz at address addr, the following will be output (note that value is 23 hexadecimal = 35 decimal):

addr: djnz begin ;450 = 13 * 34x + 8 ;

Note, that this won't work if the range is bigger than this. Thus, for example, if there is a cycle ending by a djnz (Z80-style) executed multiple times, the proper cycle count cannot be obtained using a single Z begin-end*repeats directive; the following construction has to be used instead:

Z begin-addr1*repeats ;addr1 is the address just before djnz (addr1=addr2-1)

Z addr2*repeats ;addr2 is the address of djnz

Z begin-addr2 ;this range gives the final count

A similar construction can be used for a cycle ending by any conditional jump.

Conditional jumps are guessed to be taken, if the following instruction falls outside any range, or an excluding range (suffix -) begins on the following instruction, or, of course, if “explicit taken” has been defined (see ^ suffix). In this case, the jump instruction's cycle count will be prefixed by “^” in the output file.

If the guesses work out bad, try to use the = prefix for overriding it by explicit cycle count value.

## Customized cycle files

The default cycles counts can be overriden by a user-definable list of cycle counts. This is imported using a command-line –z switch. The filename must be added immediately after –z, with not space.

The format of each line in the file is the following:

[opcode - cycle count[/ alternative cycle count]][; comment][# comment]

Opcode and cycle counts are given in hexadecimal with no prefix/suffix, maximum two digits. Alternative cycle count is for conditional jumps and autorepeated instructions, see special cases above. Opcodes can be in any order. Missing opcodes will be given cycle count = 0. Comment with ; is ignored, comment with # is printed to console when file is read in.

## Known issues

There is no 8080 support in DZ80.

In the import of user definable cycle files, there is no support for the prefixed Z80 instructions.

If the - suffix has to be used to specify an excluded range for a single instruction, the one-address format cannot be used, i.e. Z address- won't work properly. Use Z address‑address‑ instead.

## Why in disassembler?

Cycle counting is used usually to optimize a certain section of a newly written program. It would be more convenient to have the cycle count in assembler and/or compiler output, no doubt.

However, having it in disassembler, the cycle counting gets assembler/compiler independent. Most of assemblers/compilers are closed source, even if some of them are provided free. Support for cycle counting is therefore upon to the goodwill of the assembler/compiler author. Also, it is not likely that a common library would fit universally, which makes cycle counting availability accross multiple tools less likely.

That's why.