z80 » Intermediate
Written by Jimmy Mårdell
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 majorways to solve the problem:
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.
When disassembling the ROM I found that if the second bit at
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 (Your Handler). 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 Interrupt Handler
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
$8f8f. Since most of RAM Page 1 is free to use, this seems to
work without problems. The interrupt handler could then look something
inthandler: ex af,af' exx . . . . . . ;interrupt code . . . 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 . . . . . . ;interrupt code . . . 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,$00 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 (Key Port) bit code to scancodes
without having the annoying Down-Left Bug.
More from z80 » Intermediate
All the Flags // Debugging // Down-Left Bug // _GetKey Codes // Logical Operators // Memory, ROM, RAM, and Safe Areas // Miscellaneous Instructions // PC and SP // Random Numbers // TI's ROM Calls // Restart Commands // Simulated 16-bit Addition // The Stack // Tables and Arrays // Text Display // Variables