dmsc / fastbasic

FastBasic - Fast BASIC interpreter for the Atari 8-bit computers
GNU General Public License v2.0
139 stars 20 forks source link

Crash on DLI #49

Closed vitococl closed 3 years ago

vitococl commented 3 years ago

I defined two DLIs in order to change between them as needed. It worked great and I got the effect I wanted.

My program crashed Altirra once, and I didn't do the forensics at the time because I thought it was related to the latest change, but after some days and many, many runs, it crached again, and this time I started Altirra's debugger, finding that the PC was stopped at a KIL instruction ($02).

The address was $9E5C, and that was in the middle of the bytecodes. I loaded the symbols and found that the bytecodes was close to one of the DLIs I defined, which it was located a $9E9F. The other DLI was located at $9F5C.

Then, it seems that a DLI was activated just in the middle of the DLI swap, where only one of the address bytes was updtated, pointing to an invalid address.

I'm not sure, but I think that a solution without the plain DLI command to deactivate the interrupt (and get a glich) or without preceding the activation of the next routine with a PAUSE 0 to get in sync with the vertical blank, it could be to emit the bytes for the pause within the (re)activation of a given DLI.

I mean, in the syntax file, instead of:

    # Activate DLI with given name
    emit { TOK_NUM, &VDSLST, TOK_SADDR, TOK_NUM, VT_ARRAY_BYTE } E_LABEL \
          emit { TOK_DPOKE, TOK_BYTE, 192, TOK_NUM_POKE, &NMIEN }

use:

    # Activate DLI with given name
    emit { TOK_0, TOK_PAUSE, TOK_NUM, &VDSLST, TOK_SADDR, TOK_NUM, VT_ARRAY_BYTE } E_LABEL \
          emit { TOK_DPOKE, TOK_BYTE, 192, TOK_NUM_POKE, &NMIEN }

(TOK_0 and TOK_PAUSE were added after the first emit).

dmsc commented 3 years ago

Hi!

Then, it seems that a DLI was activated just in the middle of the DLI swap, where only one of the address bytes was updtated, pointing to an invalid address.

Thanks for the very well researched bug report!

I'm not sure, but I think that a solution without the plain DLI command to deactivate the interrupt (and get a glich) or without preceding the activation of the next routine with a PAUSE 0 to get in sync with the vertical blank, it could be to emit the bytes for the pause within the (re)activation of a given DLI.

I like the "PAUSE 0" solution, as it will make DLI activation more consistent. I don't know if it is enough if one of the first display-list lines has a DLI active, but I suspect that this case would be rare.

I mean, in the syntax file, instead of:

    # Activate DLI with given name
    emit { TOK_NUM, &VDSLST, TOK_SADDR, TOK_NUM, VT_ARRAY_BYTE } E_LABEL \
          emit { TOK_DPOKE, TOK_BYTE, 192, TOK_NUM_POKE, &NMIEN }

use:

    # Activate DLI with given name
    emit { TOK_0, TOK_PAUSE, TOK_NUM, &VDSLST, TOK_SADDR, TOK_NUM, VT_ARRAY_BYTE } E_LABEL \
          emit { TOK_DPOKE, TOK_BYTE, 192, TOK_NUM_POKE, &NMIEN }

(TOK_0 and TOK_PAUSE were added after the first emit).

Yes, that will work. Will commit now.

Have Fun!