A Z- 80 Cycle Waster
The Z- 80 code is in the comments alongside equivalent C code. The C program is self-contained and
runs an exhaustive test verifying that waithL() always uses h 256 + L + 100 cycles. observe that the Jr
conditional branch instructions take extra time if the branch is taken. Those time differences along with
looping are used to expand the subroutine’s running time in proportion to the requested number of cycles.
// Z- 80 registers are akin to C global variables.
unsigned char A, H, L;
unsigned char C, Z;
int cycles;
void t(int n)
{
cycles += n;
}
void waitA();
/* Cycle Cost C code
Z- 80 code */
void wait256()
{
wHL256:
}
H--; Z = H != 0;
A = 127;
waitA();
t( 4);
t( 7);
t( 17);
// DEC H
// LD A,127
// CALL wA
void waitHL()
{
wHL:
t( 4);
t( 4);
t( 7);
t( 5);
H++; Z = H == 0;
H--; Z = H == 0;
if (!Z) {
// INC H
// DEC H
// JR NZ,wHL256
t( 4);
t(0);
}
A = L;
waitA();
// LD A,L
}
void waitA()
{
wA:
t( 4);
C = A & 1; // RRCA
A = (A << 7) | (A >> 1);
if (C) { // JR C,have1
goto have1;
t( 7);
t( 5);
}
t( 4);
// NOP
have1:
t( 4);
t( 7);
t( 5);
C = A & 1; // RRCA
A = (A << 7) | (A >> 1);
if (!C) { // JR NC,no2
goto no2;
}
if (!C) {
t( 7);
t( 5);
no2:
t( 4);
t( 7);
t( 5);
C = A & 1; // RRCA
A = (A << 7) | (A >> 1);
if (!C) { // JR NC,no4
goto no4;
}
if (!C) {
t( 5);
t( 6);
// NOP
no4:
t( 4);
t( 7);
t( 5);
C = A & 1; // RRCA
A = (A << 7) | (A >> 1);
if (!C) { // JR NC,no8
goto no8;
t( 13);
}
/* *0 = A; */
// LD (0),A
no8:
t( 7);
A &= 15;
Z = A == 0;
if (Z) {
// AND A, 15
t( 5);
t( 6);
}
// RET Z
wait16:
t( 4);
t( 7);
t( 5);
A--; Z = A == 0;
if (!Z) {
// DEC A
// JR NZ,wait16
}
if (Z) {
t( 5);
t( 6);
#include <stdio.h>
int main(int argc, char *argv[])
if (cycles != hl + 100)
{
printf(“Blew it on %d (got
%d instead of %d)\n”, hl,
cycles, hl + 100);
}
}
return 0;