A86: Interrupts & the "Down-Left" bug
[Prev][Next][Index][Thread]
A86: Interrupts & the "Down-Left" bug
I've made some research on what causes the famous down-left freeze
bug (or is it a feature!?) and how to get around it when programming.
I hope some programmers find this information useful - the routines
below is at least used in the upcoming Sqrxz 1.0.
So - how do you do to avoid the freeze bug? I've found three major
ways to solve the problem:
* Disable Interrupts (chicken way :) )
* set 2,(iy+$12)
* Creating your own interrupt handler which ends with a RETI, not a JP
$38
Disabling interrupts
--------------------
In most games, this method is enough to avoid the problems. There are
two
disadvantages doing it this way though. Those are
- keypresses must be read through ports
- you can't create your own interrupt handlers
The first disadvantage is not much of a problem, most of the time. And
the second disadvantage is usually not a problem either. But sometimes
you want stuff to go on in the background (a timer for example) and
then disabling interrupts is not a good way to prevent the down-left
bug.
SET 2,(IY+$12)
--------------
When disassembling the ROM I found that if the second bit at (IY+$12)
is set, there will be no call to the routine that check port 1 for
keypresses. That routine lies at $01A1, and if that routine is not
called,
the down-left bug is gone. This is also a very simple way to get around
the problem, but it still has the disadvantage that you have to read
keypresses through ports. And most of the time when method 1 (Disabling
interrupts) isn't enough, it usually means you want to make your
own interrupt handler, and then method 3 is best suited for it (see
below).
If you use this method, you MUST reset the flag with RES 2,(IY+$12)
before
the program terminates - else the calc freezes.
Creating your own interrupthandler
----------------------------------
This is the most complex method, which I had some problems with first.
Creating an interrupt handler is not much of a problem really. This
is easily done with the following code:
ld hl,$8E00
ld de,$8E01
ld (hl),$8F
ld bc,256
ldir
ld hl,inthandler
ld de,$8F8F
ld bc,intend-inthandler
ldir
ld a,$8E
ld i,a
im 2
This code stores a vector table at $8E00-$8F00 and the interrupt handler
at $8F8F. Since most of RAM page 1 is free to use (????), this seems to
work without problems. The interrupt handler could then look something
like
inthandler:
ex af,af'
exx
<do something>
ex af,af'
exx
jp $38
intend:
This method is used in Sqrxz 0.9. The problem is that each interrupt
ends with a jump to the default interrupt at $38 - which has the
down-left bug. So, I tried to replace jp $38 with EI \ RETI (which
is how the default interrupt handler ends) but that didn't work -
The calc crashed :( To find out what was wrong, I had to play around
with the default interrupt handler. Anyway, this is how a "homemade"
interrupt handler should look like, that doesn't use the buggy handler
in the ROM AND still uses ROM routines for reading keys (without having
the down-left bug):
inthandler:
ex af,af'
exx
<do something>
in a,(3)
rra
push af ; This three lines are not needed
call nc,$01A1 ; if you only read keys through ports
pop af
ld a,9
adc a,0
out (3),a
ld a,$0B
out (3),a
ex af,af'
exx
ei
reti
intend:
It's necessary to send $09 $0B to port 3 when ON is _NOT_ pressed and
when
ON is pressed, you have to send $0A $0B to port 3 - else the calc
crashes.
This method works very well - it allows the user to create his own
interrupt
handler and still use the ROM routines to convert port 1 bit code to
scancodes
without having the annoying down-left bug.
--
Jimmy Mårdell "The nice thing about standards is that
mailto:mja@algonet.se there are so many of them to choose from."
http://www.algonet.se/~mja
IRC: Yarin "Sanity? I'm sure I have it on tape
somewhere!"
Follow-Ups: