Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Headerless load routine in ZX Basic
#1
Hello,
I'm trying to code a simple headerless LOAD routine in ZX Basic using the inline assembly feature of the compiler. The basic idea here is to write a function that uses assembly to set up the necessary registers and call the ROM routine 0556h for a headerless load (e.g. to load an extra level from the tape). I have some progress in this area, but it looks like I misunderstand how to clean up things correctly after the ROM routine returns and my function ends, so the poor Speccy either hangs or is reset after the code loading routine completes. I tried a few things so far, but the experiment that went the farthest so far is this one:

Code:
function hload(addr as uInteger, size as uInteger) as uByte
    asm
        pop hl
        pop de
        pop ix
        ld a, 255
        scf
        call 0556h
        push hl
    end asm
end function


The expected result is that calling this function, for instance, in this way:
Code:
hload(16384, 6912)

should be able to load standard ZX screen data correctly. Trying to load a screen this way indicates that the screen is indeed loaded into the right area of memory, but once the loading completes, the computer is reset.

I'm pretty sure that this indicates that something is screwed up at the end of the function call. Could be due to the fact that SP or something else is modified from within 0556h and that changes the register state, or something else along those lines, but I can't quite figure it out :/ I would appreciate some help since I'm not sure how to proceed. I tried a few other cleanup tricks, but none of them worked. 

Another question is: how do I properly return a value from this function? As far as I understand, the return value can be stored in the A register. Suppose I wanted to indicate that the tape loaded correctly with a value of 0, would I simply LD A, 0 at the end of the function and that would be enough? This, of course, is a separate issue once I can actually get this function to load anything without resetting the PC or hanging Smile

Thanks in advance.
Reply
#2
Maywind Wrote:Hello,
I'm trying to code a simple headerless LOAD routine in ZX Basic using the inline assembly feature of the compiler. The basic idea here is to write a function that uses assembly to set up the necessary registers and call the ROM routine 0556h for a headerless load (e.g. to load an extra level from the tape). I have some progress in this area, but it looks like I misunderstand how to clean up things correctly after the ROM routine returns and my function ends, so the poor Speccy either hangs or is reset after the code loading routine completes. I tried a few things so far, but the experiment that went the farthest so far is this one:

Code:
function hload(addr as uInteger, size as uInteger) as uByte
    asm
        pop hl
        pop de
        pop ix
        ld a, 255
        scf
        call 0556h
        push hl
    end asm
end function


The expected result is that calling this function, for instance, in this way:
Code:
hload(16384, 6912)

should be able to load standard ZX screen data correctly. Trying to load a screen this way indicates that the screen is indeed loaded into the right area of memory, but once the loading completes, the computer is reset.

I'm pretty sure that this indicates that something is screwed up at the end of the function call. Could be due to the fact that SP or something else is modified from within 0556h and that changes the register state, or something else along those lines, but I can't quite figure it out :/ I would appreciate some help since I'm not sure how to proceed. I tried a few other cleanup tricks, but none of them worked. 

Another question is: how do I properly return a value from this function? As far as I understand, the return value can be stored in the A register. Suppose I wanted to indicate that the tape loaded correctly with a value of 0, would I simply LD A, 0 at the end of the function and that would be enough? This, of course, is a separate issue once I can actually get this function to load anything without resetting the PC or hanging Smile

Thanks in advance.

Two things:

 - IX register must be preserved. So if you're calling the ROM and it modifies IX, you have to PUSH IX, call the ROM, POP IX.
 - Also, for pure ASM functions, you can use FASTCALL, and have the stack into account.


Code:
function fastcall hload(addr as uInteger, size as uInteger) as uByte
    asm
        ; FASTCALL: 1st parameter, 16bit, comes always in HL register
        ex de, hl   ; preserves param in DE
        pop hl      ; pops Ret Addr
        ex (sp), hl ; Swaps size param, and puts Ret Addr back into the stack
        ;; At this point: DE = addr, HL = size
        ld a, 255
        scf
        push ix     ; preserves IX (must be recovered later)

        ex de, hl   ; HL = addr, DE = length
        push hl
        pop ix      ; IX = addr, DE = length

        call 0556h
        pop ix      ; recovers original IX

        ; Functions always return their value in registers. For 8bit, A register
        sbc a, a    ; 0 if No Carry, FF if Carry (Error)
    end asm
end function

This routine will return 0 if there were no errors, 255 if error.
---
Boriel
Reply
#3
Thanks a lot for help, Boriel! Makes perfect sense! Also, fastcall is a nice thing to use here. I only used it for single parameters before and was kinda reluctant to use it for two-parameter ones, turns out it's quite transparent how to use this. Thanks again!
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)