Block save / load

Discussion about ZX80 / ZX81 Software
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

This is an interesting thread.

Is a long time that I was thinking that in order to fully (at least to the maximum extent) utilize the 1K memory it would be good to have a extremely small piece of code that (also reusing the standard load routines) could load programs. It means that first you would load a "standard program" that is the loader, than this program will allocate itself in the last bytes of memory and then load the program itself.

Advantages:
1. will load from 4000h instead of 4009h allowing to immediately fill this space with data
2. will allow immidiate utilization and filling of system variables needed by BASIC (program will start immediately the machine code)
3. will avoid the basic program skeleton to start the machine code
4. if shor enough will probably load even more bytes (standard loader do not fully load till the very 1K end)

The loader program initiation can be articulated since it will be rewritten, just the final loading part should be very small. This mean for example that can evaluate ROM versions and put correct addresses if needed, or setup additional structures/register values before jumping to the final load.
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

marste wrote: Fri Apr 26, 2024 5:22 pm This is an interesting thread.

Is a long time that I was thinking that in order to fully (at least to the maximum extent) utilize the 1K memory it would be good to have a extremely small piece of code that (also reusing the standard load routines) could load programs. It means that first you would load a "standard program" that is the loader, than this program will allocate itself in the last bytes of memory and then load the program itself.

Advantages:
1. will load from 4000h instead of 4009h allowing to immediately fill this space with data
2. will allow immidiate utilization and filling of system variables needed by BASIC (program will start immediately the machine code)
3. will avoid the basic program skeleton to start the machine code
4. if shor enough will probably load even more bytes (standard loader do not fully load till the very 1K end)

The loader program initiation can be articulated since it will be rewritten, just the final loading part should be very small. This mean for example that can evaluate ROM versions and put correct addresses if needed, or setup additional structures/register values before jumping to the final load.
My 1K model to code ASM has start of machinecode all over sysvar so no bytes are lost on sysvar and printerbuffer. Even the end of the BASIC-line and the REM for your machinecodeline are skipped.
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

dr beep wrote: Sat Apr 27, 2024 10:17 am
marste wrote: Fri Apr 26, 2024 5:22 pm ...
Advantages:
1. will load from 4000h instead of 4009h allowing to immediately fill this space with data
2. will allow immidiate utilization and filling of system variables needed by BASIC (program will start immediately the machine code)
3. will avoid the basic program skeleton to start the machine code
4. if shor enough will probably load even more bytes (standard loader do not fully load till the very 1K end)
...
My 1K model to code ASM has start of machinecode all over sysvar so no bytes are lost on sysvar and printerbuffer. Even the end of the BASIC-line and the REM for your machinecodeline are skipped.
With "standard load" machine code can be written all over the sysvar not used by BASIC intepreter (that has to start after load finish). #2

Moreover, there should be the space (even if on sysvars, little and very optimized) of this BASIC preamble to start the ASM program. #3

And regarding #4 I checked and standard load seems cannot go after 0x43BE, meaning 66 bytes less than theoretical maximum of 0X43FF (to be added to the first 9 of #1).

PS: surely the bytes can be used after the start of the program, but with the loader you can immediately fill them with desired data or code
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

I had hoped to have a small loader that would allow loading more data in a 1K machine. Now bound on around 949 bytes.
Alas, this routine is way too large to have use in 1K. My optimized model is more effective on a 1K model.
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

I have at the moment no means to test it (my dev environment is broken), but the following program should be able to fully load 1008 bytes into memory (from 0x4000 to 0x4400 - 16 bytes)...

The block to be load should be saved with standard routines and should be equal or bigger than 1008 bytes (if bigger the remaining part will not be loaded).

Note that when load routine stops the first target loader instruction (call IN_BYTE) is already damaged.

Code: Select all

SET_FAST equ 0x2E7
IN_BYTE equ 0x34C
TARGET_LOAD equ 0x4400 + LOAD_PROG_BEG - LOAD_PROG_END
MEMORY_END equ 0x4400
PROGRAM_START equ TARGET_LOAD - 2 ; this will allow 3 bytes instruction 
                                  ; but can be moved anywhere

START:
        call SET_FAST        ; load operations to be managed in FAST mode
        ld   hl, 0x4400      ; cleanup and put stack at the very end of memory
        ld   sp, hl          ; /
        ld   hl, 0x4000      ; start loading data at 4000h
        ld   hl, LOAD_PROG_BEG ; relocate loader to end of memory
        ld   de, TARGET_LOAD ;                     /
        push de              ;                    /
        ld   bc, LOAD_PROG_END - LOAD_PROG_BEG ; /
        ldir                 ;                 _/
        pop  de              ; load up to TARGET_LOAD
        jp   TARGET_LOAD     ; start loading

LOAD_PROG_BEG: ; this label will be at "TARGET_LOAD:" address
        call IN_BYTE         ; ROM routine IN-BYTE loads a byte
        ld   (hl), c         ; insert assembled byte in memory
        or   a               ; verify if end reached
        sbc  hl, de          ;   /
        add  hl, de          ;  /
        jr   nz, LOAD_PROG_START ; (relocatable jump)
        jp   PROGRAM_START   ; program should go into SLOW mode if needed
        db   0, 0, 0, 0      ; stack space
LOAD_PROG_END:
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

marste wrote: Tue Apr 30, 2024 3:13 am I have at the moment no means to test it (my dev environment is broken), but the following program should be able to fully load 1008 bytes into memory (from 0x4000 to 0x4400 - 16 bytes)...

The block to be load should be saved with standard routines and should be equal or bigger than 1008 bytes (if bigger the remaining part will not be loaded).

Note that when load routine stops the first target loader instruction (call IN_BYTE) is already damaged.

Code: Select all

SET_FAST equ 0x2E7
IN_BYTE equ 0x34C
TARGET_LOAD equ 0x4400 + LOAD_PROG_BEG - LOAD_PROG_END
MEMORY_END equ 0x4400
PROGRAM_START equ TARGET_LOAD - 2 ; this will allow 3 bytes instruction 
                                  ; but can be moved anywhere

START:
        call SET_FAST        ; load operations to be managed in FAST mode
        ld   hl, 0x4400      ; cleanup and put stack at the very end of memory
        ld   sp, hl          ; /
        ld   hl, 0x4000      ; start loading data at 4000h
        ld   hl, LOAD_PROG_BEG ; relocate loader to end of memory
        ld   de, TARGET_LOAD ;                     /
        push de              ;                    /
        ld   bc, LOAD_PROG_END - LOAD_PROG_BEG ; /
        ldir                 ;                 _/
        pop  de              ; load up to TARGET_LOAD
        jp   TARGET_LOAD     ; start loading

LOAD_PROG_BEG: ; this label will be at "TARGET_LOAD:" address
        call IN_BYTE         ; ROM routine IN-BYTE loads a byte
        ld   (hl), c         ; insert assembled byte in memory
        or   a               ; verify if end reached
        sbc  hl, de          ;   /
        add  hl, de          ;  /
        jr   nz, LOAD_PROG_START ; (relocatable jump)
        jp   PROGRAM_START   ; program should go into SLOW mode if needed
        db   0, 0, 0, 0      ; stack space
LOAD_PROG_END:
The program itself is over 40 bytes so you can never load 1008 bytes on a 1K machine.
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

The loader routine is just 17 bytes ("_BEG" to "_END"), and it is relocated to the end of the memory at the program start. Everything else is rewritten as all the rest of the memory during the load process.
And become even 16 bytes because the loader stop when it starts overwriting itself (for now just the first byte).
Could become 15 bytes (removing "or a" instruction) if carry is always reset (or set) on the BYTE_IN routine exit: to be checked if possible.
And I'm pretty sure that you and few others here can even improve it ;)

PS: in the process of studying the internal rom LOAD routine I added more comments to this part of the ROM disassembly; in case someone is interested here the link https://github.com/stevexyz/ZX-81-ROMS/ ... s/zx81.asm

PPS: I've just noticed a typo "jr nz, LOAD_PROG_START" should be read "jr nz, LOAD_PROG_BEG"!
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

marste wrote: Tue Apr 30, 2024 12:50 pm The loader routine is just 17 bytes ("_BEG" to "_END"), and it is relocated to the end of the memory at the program start. Everything else is rewritten as all the rest of the memory during the load process.
And become even 16 bytes because the loader stop when it starts overwriting itself (for now just the first byte).
Could become 15 bytes (removing "or a" instruction) if carry is always reset (or set) on the BYTE_IN routine exit: to be checked if possible.
And I'm pretty sure that you and few others here can even improve it ;)

PS: in the process of studying the internal rom LOAD routine I added more comments to this part of the ROM disassembly; in case someone is interested here the link https://github.com/stevexyz/ZX-81-ROMS/ ... s/zx81.asm

PPS: I've just noticed a typo "jr nz, LOAD_PROG_START" should be read "jr nz, LOAD_PROG_BEG"!
I am gonna try to make a universal model to start coding in it.
Most times the screen is compressed enough I can copy routines over sysvar and decompress, but my latest game had no room for that.
This could add a lot.
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

I was thinking of this loader:

Code: Select all

START:
        call 	SET_FAST        ; load operations to be managed in FAST mode
        ld   	sp, #4400-2          ; /
        ld   	hl, 0x4000      ; start loading data at 4000h
        ld   	hl, LOAD_PROG_BEG ; relocate loader to end of memory
        ld   	de, TARGET_LOAD ;                     /
        push 	de              ;                    /
        ld   	bc, LOAD_PROG_END - LOAD_PROG_BEG ; /
        ldir                 ;                 _/
        ret

LOAD_PROG_BEG: ; this label will be at "TARGET_LOAD:" address
        call 	IN_BYTE         ; ROM routine IN-BYTE loads a byte
        ld   	(hl), c         ; insert assembled byte in memory
        jr 	LOAD_PROG_BEG ; (relocatable jump)
        db   	0, 0, 0, 0      ; stack space
	dw	start
LOAD_PROG_END:	
where the loaded code would load a RET over LOAD_PROG_BEG
and START is the start in the loaded program.

Gonna give it a try.
dr beep
Posts: 2124
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

So I have the loader starting, but how do I built my datablock to load?

I am using EightyOne to test the program.

Who can help with a working exemple?

The block to load is then 1010 bytes when my idea is working where at the end the stack will get a few more bytes.
Post Reply