Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Z80 Software Delay

Tags:

z80

I am trying to create a software delay. Here is a sample program of what I am doing:

    Address  Data   Opcode  Comment    
    1800      06    LD, B   Load register B with fix value
    1801      “ “           Fixed value
    1802      05    DEC, B  Decrement value in register B
    1803      C2    JP cc   Jump to 1802 if value is not 0
    1804      02    -       Address XX
    1805      18    -       Address XX

My question is how can I calculate the required fixed value to load into register B so that the process of decrementing the value until 0 takes 2 seconds?

In my manual the time given to run the instructions is based on a 4MHz CPU but the Z80 CPU I am using has a speed of 1.8MHz. Any idea how I can calculate this? Thanks. P.S here is the decrement (DEC) and jump (JP cc) instructions from the manual:

Instruction    M Cycles    T states   4 MHz E.t
DEC r             1           4         1.00
JP cc             3       10 (4,3,3)    2.50
like image 473
user3178205 Avatar asked Mar 21 '15 16:03

user3178205


2 Answers

If by 1.8MHz you mean exactly 1,800,000 Hz, then to get a 2 second delay you'd need to delay for 3,600,000 T-states. Your current delay loop takes 14 T-states per iteration, which means that your initial value for B would have to be 3600000/14 == 257143, which obviously won't fit in one byte.

The greatest number of iterations that you could specify with an 8-bit register is 256, and to reach 3,600,000 T-states with 256 iterations, each iteration would have to take 14,062 T-states. That's one big loop body.

If we use a 16-bit counter things start getting a bit more manageable. At 65,536 iterations we only need 55 T-states per iteration to reach a total of 3,600,000 T-states. Below is an example of what that could look like:

    ; Clobbers A, B and C
    ld      bc,#0
1$:
    bit     #0,a    ; 8
    bit     #0,a    ; 8
    bit     #0,a    ; 8
    and     a,#255  ; 7
    dec     bc      ; 6
    ld      a,c     ; 4
    or      a,b     ; 4
    jp      nz,1$   ; 10, total = 55 states/iteration
    ; 65536 iterations * 55 states = 3604480 states = 2.00248 seconds
like image 160
Michael Avatar answered Oct 17 '22 20:10

Michael


I'm a bit of an optimization freak, so here is my go using the syntax with which I am most familiar (from the TASM assembler and similar):

Instruction   opcode    timing
ld bc,$EE9D   ;01EE9D   10cc
ex (sp),hl    ;E3       19*(256C+B)
ex (sp),hl    ;E3       19*(256C+B)
ex (sp),hl    ;E3       19*(256C+B)
ex (sp),hl    ;E3       19*(256C+B)
djnz $-4      ;10FA     13cc*(256C+B) - 5*C
dec c         ;0D       4*C
jr nz,$-7     ;20F7     12*C-5

This code is 12 bytes and 3600002 clock cycles.

EDIT: It seems like part of my answer is gone! To answer your question better, your Z80 can process 1800000 clock cycles in one second, so you need twice that (3600000). If you add up the timings given in my code, you get:

=10+(256C+B)(19*4+13)-5C+4C+12C-5

=5+(256C+B)89+11C

=5+22795C+89B

So the code timing is largely dependent on C. 3600000/22795 is about 157, so we initialize C with 157 (0x9D). Plugging this back in, we get B to be roughly 237.9775, so we round that up to 238 (0xEE). Plugging these in gets our final timing of 3600002cc or roughly 2.000001 seconds. This assumes that the processor is running at exactly 1.8MHz which is very unlikely.

As well, if you can use interrupts, figure out roughly how many times it fires per second and use a loop like halt \ djnz $-1 . This saves a lot more in terms of power consumption.

like image 2
Zeda Avatar answered Oct 17 '22 21:10

Zeda