Posts: 22
Threads: 6
Joined: Feb 2021
Reputation:
2
03-15-2021, 09:21 PM
(This post was last modified: 03-15-2021, 09:32 PM by georgeo.)
Hi everyone (probably for the attention of Boriel),
My search for the source of instability in my game continues, though I no longer think it is to do with memory management, but a possible bug in the compiler, for the implementation of LOAD "..." CODE. I have noticed that part of my program gets corrupted after I use LOAD "..." CODE to load some UDGs at the top of memory. Digging in to the implementation of the function, I found the following code (sorry, I can't copy and paste code out of the emulator I am using):
https://1drv.ms/u/s!Atca6hVb5b8Tp5JxCEWC...g?e=qGHdEg
At the end of the snippet, a call is made to 0xE6E1, which is a wrapper to the ROM loader routine (in this case, to load a tape header). IX points to the place in memory where the header should be loaded, which -- in this case -- is inside my program code. If I understand correctly what is going on, the snippet starts with a call to MEM_FREE (0xDB56, in this case) which returns a pointer to space in the heap (perhaps where the header can be stored?). However, the IX register is loaded with 2*SP and passed to the tape loader, which I think is a mistake.
Is that a possible bug?
If this is indeed a bug, it fits with my experience. As the size of my program grows, I need to raise the origin address to avoid random crashes. For example, if I have a 30kb program with origin address at 29,000, then the stack will reside somewhere near the start of the heap, so 2*SP will be around 58,000 which will be near the end of my program. However, if I up the origin to 31,000, then 2*SP will be more like 62,000, which will be just past the end of my program. As the size of my program increases, it will eventually grow past 2*SP and then will start to get corrupted and crash randomly, when I load from tape, so I again need to raise the origin address.
It all seems to fit, but maybe I've just convinced myself,
Georgeo.
Posts: 1,789
Threads: 56
Joined: Aug 2019
Reputation:
25
(03-15-2021, 09:21 PM)georgeo Wrote: Hi everyone (probably for the attention of Boriel),
My search for the source of instability in my game continues, though I no longer think it is to do with memory management, but a possible bug in the compiler, for the implementation of LOAD "..." CODE. I have noticed that part of my program gets corrupted after I use LOAD "..." CODE to load some UDGs at the top of memory. Digging in to the implementation of the function, I found the following code (sorry, I can't copy and paste code out of the emulator I am using):
https://1drv.ms/u/s!Atca6hVb5b8Tp5JxCEWC...g?e=qGHdEg
At the end of the snippet, a call is made to 0xE6E1, which is a wrapper to the ROM loader routine (in this case, to load a tape header). IX points to the place in memory where the header should be loaded, which -- in this case -- is inside my program code. If I understand correctly what is going on, the snippet starts with a call to MEM_FREE (0xDB56, in this case) which returns a pointer to space in the heap (perhaps where the header can be stored?). However, the IX register is loaded with 2*SP and passed to the tape loader, which I think is a mistake.
Is that a possible bug?
If this is indeed a bug, it fits with my experience. As the size of my program grows, I need to raise the origin address to avoid random crashes. For example, if I have a 30kb program with origin address at 29,000, then the stack will reside somewhere near the start of the heap, so 2*SP will be around 58,000 which will be near the end of my program. However, if I up the origin to 31,000, then 2*SP will be more like 62,000, which will be just past the end of my program. As the size of my program increases, it will eventually grow past 2*SP and then will start to get corrupted and crash randomly, when I load from tape, so I again need to raise the origin address.
It all seems to fit, but maybe I've just convinced myself,
Georgeo.
To use UDG you have to do
Code: LOAD "" CODE USR "a"
This is because USR "a" always point to the address of the "\a" UDG, which is also stored in the ROM variable UDG. PRINT PEEK(UInteger, 23675) will give you the value.
If you compile with --sinclair then you can use LOAD "" CODE USR "a". Otherwise you have to reserve memory for UDGs. A way to do that is to declare an empty array an declare the UDG there. For example:
Code: DIM UDG(10 * 8) AS UByte : REM 10 UDGs * 8 Bytes each
POKE UInteger 23675, @UDG(0): REM Sets UDG var to point to 1st element
LOAD "" CODE USR "a": REM Here LOAD "" CODE @UDG(0) will also work
If you load "" CODE anywhere, it will overwrite your program as you said. A compiled program is no longer BASIC, but machine code.
Posts: 22
Threads: 6
Joined: Feb 2021
Reputation:
2
03-16-2021, 08:23 AM
(This post was last modified: 03-16-2021, 08:24 AM by georgeo.)
Hi Boriel,
Thanks for the swift reply. I am able to load the UDGs, using the method that you suggest (and making sure my program does not extend into the UDG space). However, the routine that loads in the UDGs causes corruption in my program when it reads in a header from tape (not the actual data). The address calculated for holding the 17-byte tape-header information is in the middle of my program code, rather than in the heap area or, as is done in Sinclair BASIC, the workspace. I'm pretty sure this is a mistake.
Thanks again
Posts: 1,789
Threads: 56
Joined: Aug 2019
Reputation:
25
03-16-2021, 09:55 PM
(This post was last modified: 03-16-2021, 09:58 PM by boriel.)
The sequence shown in your screenshot is, indeed, this one:
Code: ld hl, 0
add hl, sp
ld (TMP_SP), hl ;; Stores current SP for later
ld bc, -18
add hl, sp
ld sp, hl ;; Reserves 18 bytes in the stack (like doing PUSH HL 9 times)
LOAD_CONT3:
ld (TMP_HEADER), hl ;; Stores current SP Value in TMP_HEADER
push hl
pop ix ;; Make IX to point to this stack space
;; LD-LOOK-H --- RIPPED FROM ROM at 0x767
LD_LOOK_H:
push ix
Yes, this looks like a bug in LOAD "" CODE, since it shoud be add hl, bc!
Will send you a fixed version.
Remeber the stack grows down, as you probably already know, and must be set *below* your program. If you compile with -taB a BASIC loader will be generated. This BASIC loader will set SP (with CLEAR) correctly. For example, is your programs is at 32768 (the default), there will be a CLEAR 32767 (so the stack will start below this position and never overlap with your compiled code).
Posts: 22
Threads: 6
Joined: Feb 2021
Reputation:
2
Hi Boriel,
Thanks. I am using -taB as you suggest, so stack pointer gets set to a reasonable value. I tried an experiment, bypassing the loading of the UDGs, and now my program works reliably with any origin address, which is great as I can now lower it down to something like 26,000 and fit in a couple more kilobytes of code.
Let me know if you want me to test the fix. Thanks again,
Georgeo.
Posts: 1,789
Threads: 56
Joined: Aug 2019
Reputation:
25
03-18-2021, 07:28 PM
(This post was last modified: 03-18-2021, 07:28 PM by boriel.)
Posts: 22
Threads: 6
Joined: Feb 2021
Reputation:
2
Hi Boriel,
Thanks. I'll try over the weekend and report back.
Thanks again,
Posts: 22
Threads: 6
Joined: Feb 2021
Reputation:
2
Hi Boriel,
I've been trying the new beta version of the compiler and the problem with LOAD ... CODE looks to be fixed. I also delved into the compiled code and can see the program now makes space for the tape header by moving the stack down a little.
Looks good. Thanks,
Georgeo.
Posts: 1,789
Threads: 56
Joined: Aug 2019
Reputation:
25
(03-21-2021, 07:45 PM)georgeo Wrote: Hi Boriel,
I've been trying the new beta version of the compiler and the problem with LOAD ... CODE looks to be fixed. I also delved into the compiled code and can see the program now makes space for the tape header by moving the stack down a little.
Looks good. Thanks,
Georgeo.
Thanks for the confirmation
Now I can put this into the next release!
|