Consider a program which sets the interrupt routine to "ini:ei:ret" and
then waits for one interrupt with c set to 249 and hl set to a storage
area.  This will tell us approximately how long the interrupt lasts for by
storing one byte per loop round, and it will also tell us whether the status
register kept its value for the whole interrupt.

Also, by inserting more "ini" instructions we can vary the length of time
taken by the interrupt and so narrow it down further.  Or by changing the
"ini" to "inc l" we can shorten the interrupt routine and perhaps get a more
precise answer.

By my estimation it takes 16 cycles to enter the interrupt routine.
SimCoupe agrees with this but doesn't count it towards the length of time
the interrupt is active.  The ini takes 20, ei takes 4 and ret takes 12.
(If the screen is active then these times are 24, 32, 8 and 24 respectively
(the first 24 is again my estimate of the interrupt latency) but this is
unimportant as everything seems to take place off the screen even if a line
interrupt is being tested).

An interrupt will not occur between "ei" and "ret" so the interrupt routine
will execute a whole number of times.  Timings for various interrupt
routines and the number of times round it goes (in the format "52x3" where
the routine takes 52 cycles and goes round 3 times) based on the above are
as follows.

   Code                    My sam  SimCoupe

1. ini:ini:ini:ei:ret       92x2     76x4
2. ini:ini:ei:ret           72x2     56x5
3. ini:ei:ret               52x3     36x7
4. inc l:nop:nop:nop:ei:ret 48x3     32x8
5. inc l:nop:nop:ei:ret     44x3     28x9
6. inc l:nop:ei:ret         40x4     24x11
7. inc l:ei:ret             36x4     20x13

>From this we can gather that SimCoupe keeps the interrupt active for somewhere
between 240 and 252 cycles.  But then we know that as it tells us each time on
startup.  The real Sam is keeping the interrupt active for somewhere between
120 and 132 cycles.

The values stored in the data area from the ini instruction for the real Sam
are as follows (SimCoupe is uninteresting because the interrupt line is equal
to "status<255").

1. ini:ini:ini:ei:ret     247 247 247 255 255 255
2. ini:ini:ei:ret         247 247 247 255
3. ini:ei:ret             247 247 255

Line 2 is interesting because the two consecutive "ini" instructions gave
different answers on the second time round.  This means that if you execute
"ini:ini" exactly 88 cycles after the interrupt occurs then the first
one gives 247 and the second one gives 255.  So (based on my approximate
interpretation of the "ini" instruction) the status register keeps its value
for somewhere between 100 and 116 cycles.

The z80 code and a short binary follow.  You can test the binary by loading
it at the start of a page (avoiding 49152 because it must start in section
C) - let's say &10000 - and printing its usr (or letting a variable equal
its usr).  This value will be the number of bytes saved.  You can then print
out that many bytes starting at &10100 (unless you used "inc l" instead of
"ini").  Initially it has "ini:ini:ini:ei:ret" as the interrupt routine -
you can poke any shorter routine in at &10038.

To test the line interrupts you can say "pause 1:out 249,191" just before
calling the routine.

 ;start on page boundary, execute in section C
 di
 ld (spstore+&c000),sp
 ld sp,&c000
 in a,(251)
 and 31
 or 32
 out (250),a
 jp lmem
hmem:
 ld a,31
 out (250),a
 ld sp,(spstore+&c000)
 ei
 ret
spstore:
 defw 0
 defs 56-p

int:
      ; getting here takes 16/24 cycles (?)
 ini  ; 20/32
 ei   ; 4 /8
 ret  ; 12/24
      ; total to service interrupt = 52/88 cycles

lmem:
 ld hl,data
 push hl
 ld bc,249
 im1
 ei
 halt
 di
 ld (hl),0
 pop de
 and a
 sbc hl,de
 ld c,l
 ld b,h
 jp hmem+&8000
 defs 256-p
data:

begin 644 ints.bin
M\^US'<`Q`,#;^^8?]B#3^L-``#X?T_KM>QW`^\D``"@`"?%O/38P,#`P#3(`
J"5MO<'1X*S0-/`#MHNVB[:+[R2$``>4!^0#M1OMV\S8`T:?M4DU$PQ.`
`
end

imc

Reply via email to