Block save / load

Discussion about ZX80 / ZX81 Software
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

dr beep wrote: Tue Apr 30, 2024 8:19 pm 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.
The code is a bit different

Code: Select all


TARGET_LOAD 	equ 0x4400-4 + LOAD_PROG_BEG - LOAD_PROG_END

START:
        	ld   	sp, #4400          ; /
		ld	hl,program_start
		push	hl
	        call 	SET_FAST        ; load operations to be managed in FAST mode
        	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                 ;                 _/
        	ld   	hl, 0x4000      ; start loading data at 4000h
        	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
LOAD_PROG_END:	

User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

With the deletions you've done I do not understand how you will stop loading (before in loading loop I've put the checking of hl against de)
and how you start the loaded program (before I've put a jp after the load loop completed)

PS: the stack should be set at 4400 (call and push will start decreasing sp and then putting in the data), else you would need 6 bytes since if I remember well IN_BYTE make another internal call
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

I put a startaddress on the stack, therefore the stack comes at 43fe. Then the loader will overwrite first byte with RET
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

D was set to same highbyte as RET-address and test in ROM sees that as a stop in loading.
After the LDIR I did a INC D and now tape stays in loader.

Next step is actual loading.
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

Ok, my findings sofar:

On EightyOne you can only get it a bit working when using WAV-loader.
With .P and .TZX EightyOne uses a different loading trick.

Even with WAV I don't return to the loader I defined (yet).
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

The program with the small loader never gets to the LD (HL),C since the ROM
takes off the RET in IN-BYTE when tape is waiting for a signal.

The IN-BYTE must be customized too for a loader.

Code: Select all

;; IN-BYTE
L034C:  LD      C,$01           ; prepare an eight counter 00000001.

;; NEXT-BIT
L034E:  LD      B,$00           ; set counter to 256

;; BREAK-3
L0350:  LD      A,$7F           ; read the keyboard row 
        IN      A,($FE)         ; with the SPACE key.

        OUT     ($FF),A         ; output signal to screen.

        RRA                     ; test for SPACE pressed.
        JR      NC,L03A2        ; forward if so to BREAK-4

        RLA                     ; reverse above rotation
        RLA                     ; test tape bit.
        JR      C,L0385         ; forward if set to GET-BIT

        DJNZ    L0350           ; loop back to BREAK-3

; HERE THE ROM FAILS THE LOADING!
        POP     AF              ; drop the return address.
        CP      D               ; ugh.

;; RESTART
L0361:  JP      NC,L03E5        ; jump forward to INITIAL if D is zero 
                                ; to reset the system
                                ; if the tape signal has timed out for example
                                ; if the tape is stopped. Not just a simple 
                                ; report as some system variables will have
                                ; been overwritten.

        LD      H,D             ; else transfer the start of name
        LD      L,E             ; to the HL register


dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

I had an idea how to solve the ROM-loader in the final step.

EightyOne does not seem to read the tape when not in the ROM.
So it might only work on real hardware.
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

If it is a problem of timeout waiting for a signal,
a trick maybe to wait for the signal in the "pre loading" setup part, and immediately jump to the loop as soon as the signal is detected!
(code size there do not count :))
dr beep
Posts: 2129
Joined: Thu Jun 16, 2011 8:35 am
Location: Boxmeer

Re: Block save / load

Post by dr beep »

marste wrote: Wed May 01, 2024 10:58 pm If it is a problem of timeout waiting for a signal,
a trick maybe to wait for the signal in the "pre loading" setup part, and immediately jump to the loop as soon as the signal is detected!
(code size there do not count :))
That is exactly what I am doing, except the signal of the cassetteport is not read in EightyOne on a different location than IN-BYTE ROM-routine.
User avatar
marste
Posts: 266
Joined: Sun Aug 10, 2014 9:58 pm
Location: Italy
Contact:

Re: Block save / load

Post by marste »

Mixing a bit of ROM in the initial part it should work.
Moreover I checked and carry is always set on IN-BYTE return, so "or a" could be removed, but I noticed that IN_BYTE didn't increment hl, so I changed de to be a counter.
With a program able to start with 4C high address another byte of stack could have been saved (putting as last code jp with only one byte of low address), but else I didn't get the other optimizations.

Code: Select all

MEMORY_END equ 0x4400    ; 1k

SET_FAST equ 0x2E7       ; ROM routines
IN_BYTE equ 0x34C        ;  /
GET_BIT equ 0x385        ; /

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_LOOP   ; relocate loader to end of memory
    ld   de, 0x4400 + LOAD_LOOP - LOAD_LOOP_END ; /
    push de              ;                       /
    ld   bc, LOAD_LOOP_END - LOAD_LOOP ;        /
    ldir                 ;                    _/
    pop  de              ; load up to TARGET_LOAD
    ld   hl, de          ; the inital GET-BIT ret will be inside the loop
    inc  hl              ; skipping the first call IN_BYTE to avoid
    inc  hl              ; timeout problems
    inc  hl
    push hl              ; return address for GET-BIT (that will load a byte)
    ld   de, LOAD_LOOP - 0x4000 ; de bytes will be load
    ld   c, $01          ; prepare an eight counter 00000001.
    ld   b, $00          ; set counter to 256
WAIT:
    ld   a, $7F          ; read tape bit 
    in   a, ($FE)        ; /
    rla                  ; test tape bit.
    jp   C, GET_BIT      ; forward if set to GET-BIT (return will be in the loop)
    jp   WAIT            ; loop back infinitely

LOAD_LOOP: ; 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
    inc  hl
    dec  de              ; verify if end reached
    jr   nz, LOAD_LOOP   ; loop until finished (relocatable jump)
    jp   PROGRAM_START   ; program should go into SLOW mode if needed
    db   0, 0, 0, 0      ; stack space (for the call and push de inside IN_BYTE)
LOAD_LOOP_END:
Post Reply