Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Binary into asm
#1
Hi everyone.

I'm trying to create a routine in assembly to copy an image from memory to the screen (a third of the screen, centered)
I know the assembly code to do this.
But, in ZX Basic, afaik, I must include the image from a bin file, and label it (I know how to do that)
So, if I need to use the address of the bin file, in Basic I would use @label (and this works)
But how to I use this label inside an asm routine?

Code:
art:
asm
incbin "final.bin"
end asm

pause 0
paper 0: ink 7: border 0: CLS

asm
ld hl,(_art)
ld de,18434
ld bc,2048
ED
LDIR
RET
end asm

It's probably some syntax issue. I need to load HL with the address of the bin file, but get "error: Undefined GLOBAL label '._art'" when compiling
Reply
#2
(07-31-2022, 12:27 AM)Nando Wrote: Hi everyone.

I'm trying to create a routine in assembly to copy an image from memory to the screen (a third of the screen, centered)
I know the assembly code to do this.
But, in ZX Basic, afaik, I must include the image from a bin file, and label it (I know how to do that)
So, if I need to use the address of the bin file, in Basic I would use @label (and this works)
But how to I use this label inside an asm routine?

Code:
art:
asm
incbin "final.bin"
end asm

pause 0
paper 0: ink 7: border 0: CLS

asm
ld hl,(_art)
ld de,18434
ld bc,2048
ED
LDIR
RET
end asm

It's probably some syntax issue. I need to load HL with the address of the bin file, but get "error: Undefined GLOBAL label '._art'" when compiling

Name mangling has changed. If you compile with
--asm
only the asm will be generated and you can inspect it ;-)

You have to use:
Code:
ld hl, (.LABEL._art)
...

and in general use the prefix .LABEL._ to use BASIC labels from ASM.
Reply
#3
Thank you. I'll try it by the end of the day Smile
Reply
#4
Ok, so I got some weird results

First I compiled the following code:


Code:
art:
asm
incbin "final.bin"
end asm

pause 0
paper 0: ink 7: border 0: CLS

asm
ld hl,(.LABEL._art)
ld de,18432
ld bc,2048
ED
LDIR
RET
end asm

and it compiled ok, but produced no result (just finished the generated basic loader at line 30)

So, after some trial and error, I decided to try a goto 10 on the first line, and label the line with pause 0 with 10, therefore skipping the asm for the incbin (as it does not need to be executed, altough I assumed it would not be an issue)
This executed the second asm code, but I got gibberish instead of the expected drawing.

To check if there was something wrong with the bin file or something like that, I added the following basic code before the asm routine:

Code:
for n=0 to 2047
poke (18432+n), peek (@art+n)
next n
pause 0

This produced the desired art (but slower than the other assembly routine would); after the pause 0/ keypress, it run the asm and I got gibberish again.

Is there something wrong with my code, or is it some sort of bug?

Another try, I replaced the code with the following, turning the bin file non-relocatable:

Code:
GOTO 10

art:
asm
org 50000
incbin "final.bin"
end asm

10 pause 0
paper 0: ink 7: border 0: CLS

asm
ld hl,50000
ld de,18432
ld bc,2048
ED
LDIR
RET
end asm

This produced the expected image, but the program ended with the following message:

C Nonsense in BASIC, 30:1

(PS: It's not my intention to hardcode the image file)
Reply
#5
What happens is what you suspected: this is machine code now, not BASIC, and the CPU executing is reaching the binary file ("final.bin").

Instead, jump over it with a GOTO, or better, put an END instruction before the incbin. Don't use RET in the ASM region. The compiler has an epilogue to return to the ROM BASIC safely:

Try this and tell me if it works: Shy
Code:
paper 0: ink 7: border 0: CLS

asm
ld hl,(.LABEL._art)
ld de,18432
ld bc,2048
LDIR
end asm

END: REM the program ends and returns to BASIC. This prevents executing the following lines.

art:
asm
incbin "final.bin"
end asm

Let me know!
Reply
#6
(08-02-2022, 10:21 PM)boriel Wrote: What happens is what you suspected: this is machine code now, not BASIC, and the CPU executing is reaching the binary file ("final.bin").

Instead, jump over it with a GOTO, or better, put an END instruction before the incbin. Don't use RET in the ASM region. The compiler has an epilogue to return to the ROM BASIC safely:

Try this and tell me if it works: Shy
Code:
paper 0: ink 7: border 0: CLS

asm
ld hl,(.LABEL._art)
ld de,18432
ld bc,2048
LDIR
end asm

END: REM the program ends and returns to BASIC. This prevents executing the following lines.

art:
asm
incbin "final.bin"
end asm

Let me know!

Ok, removing the assembly instruction RET did the trick (in my code)
I'm still starting on zx basic, and actually forgot I placed some asm on other program without using ret Smile

But it does not solve the issue with the label.
If I use the label in asm, it returns gibberish instead of the image (I'm guessing it's not pointing correctly)
If I hardcode the bin location, it will work.

Therefore, this will work:
Code:
paper 0: ink 7: border 0: CLS

asm
ld hl,50000
ld de,18432
ld bc,2048
LDIR
end asm

END: REM the program ends and returns to BASIC. This prevents executing the following lines.

art:
asm
org 50000
incbin "final.bin"
end asm

but using ".LABEL._art" (and without the org 50000) will just show a bunch of random pixels.
Reply
#7
Ok, I found the issue (should have been obvious but I'm not proficient in assembly)
Where the code is
ld hl,(.LABEL._art)
It must be
ld hl,.LABEL._art

Otherwise its loading hl with the value at the address rather than the address itself

Thanks Smile
Reply
#8
Sorry for the delay (I've been out for a while).
Glad you found it!!
Cheers!
Reply
#9
(08-09-2022, 06:26 AM)boriel Wrote: Sorry for the delay (I've been out for a while).
Glad you found it!!
Cheers!
Yep, with a bit of trial and error, but thank you.
I was wondering if you could give me some tips regarding memory allocation.
I'm using some music written using beepola, which must be hardcoded because of how the software compiles (I'm still not it the level where I can disassemble and modify that code). I'm planning on saving the player and music data above 62000-63000, up to ramtop (I assume I can write up to 65535, as I think ZX Basic will locate my udg sets somewhere else - I include them with incbin and let the compiler decide their location, am I correct?)
I'm trying to figure how heap space works and where the assembly locates it. Is there a way to figure how much heap space my code will actually require? Is it allocated at the end of the code, or somewhere else? If I hardcode the music at 63000, for instance, will the heap space be reserved after that, or between the compiled code and that address?
Also, the compiler saves the code starting at 32768 unless otherwise specified. Is there a reason for that address? I assume I can start somewhere after 23755 with --org, as long as I leave some bytes for the sinclair basic loader, is this correct?
Reply
#10
The ramtop here does not make much sense: you're compiling your program to *machine code*! hence your program is already over the ramtop!

This is a difficult question as, for the moment, I'm still developing a linker to deal with memory allocation. The heap space starts at the very beginning of your program along with your variables. This is done to make SAVE "" DATA to work and preserve the heap and the program state (i.e. if you want to implement the feature of saving the game and resume it later).

The ramtop is, by default 32768 (non-contended RAM). Your program starts at 32768 with a jump (JP) over the HEAP. You can generate the assembly with
--asm
and see the resulting ASM listing.

Have you read this thread?
https://www.boriel.com/forum/showthread.php?tid=368 ("Using Beepola with ZX BASIC")
Reply
#11
(08-10-2022, 11:07 AM)boriel Wrote: The ramtop here does not make much sense: you're compiling your program to *machine code*! hence your program is already over the ramtop!

This is a difficult question as, for the moment, I'm still developing a linker to deal with memory allocation. The heap space starts at the very beginning of your program along with your variables. This is done to make SAVE "" DATA to work and preserve the heap and the program state (i.e. if you want to implement the feature of saving the game and resume it later).

The ramtop is, by default 32768 (non-contended RAM). Your program starts at 32768 with a jump (JP) over the HEAP. You can generate the assembly with
--asm
and see the resulting ASM listing.

Have you read this thread?
https://www.boriel.com/forum/showthread.php?tid=368 ("Using Beepola with ZX BASIC")

I used the term ramtop incorrectly, my mistake. What I meant to say was up to the memory limit, ie, 65535. I believe the ugds I use (including the bin files at a location defined by the compiler) should not be placed in the upper ram limit, therefore my music routines should be able to be placed between the hardcoded address and 65535. Is this correct?
From my understanding, using the contended RAM "only" results in slower code running at that location. So far my tests produce proper speed in gameplay (I actually had to slow the game down with a few "halts") to I think the memory for speed trade is favorable in this case. I may also probably move the basic code for the menus to the begining (at this point it's at the end) assuming it will compile in that order, therefore placing the pseudo-sprite routines above the contended memory limit.
I read the Beepola thread, and actually the last replies are mine. My workaround to joining the tap files is to hardcode the music bin file into basic, which supposedly should also prevent it from overwritting any other code or data when loading separate files.
For some reason I haven't figured out yet, when I tried to hardcode the 1162bytes long music bin @63800 it produced a tzx that would not work (can´t remember the error exactly, I'll try again and post it). I included the music routine @54200 and it's working now, but I'm not sure if it's restricting my available space in some way (my incomplete game is at the moment saved with org 24100, heap-size 2000, and is 36880 bytes long, so it's saving data after the music routine - I am not sure wheter it's the other bins - a few character/ udg sets and 1 1/3 monochrome screen images), or actual code.
Reply
#12
Starting your code at, let's stay --org 26000 it's a safe value. From that point downwards to 0 it's used for the stack.
Placing binaries at random locations will mostly not work and will overlap with your compiled code. Currently ZX Basic does not support that. It's a long road to implement that feature (I'm working on it)

Instead, you should use INCBIN with labels as you already did, and get their address with @label

There are several approaches to this in the thread I posted above. Hope this help.
Reply
#13
(08-11-2022, 08:59 AM)boriel Wrote: Starting your code at, let's stay --org 26000 it's a safe value. From that point downwards to 0 it's used for the stack.
Placing binaries at random locations will mostly not work and will overlap with your compiled code. Currently ZX Basic does not support that. It's a long road to implement that feature (I'm working on it)

Instead, you should use INCBIN with labels as you already did, and get their address with @label

There are several approaches to this in the thread I posted above. Hope this help.
I just noticed there are some tips there to include beepola's asm into zx basic, I had tried that but I see I need to change some code first. I only remembered the use of a separate tap file, which was not my intention. If I manage to include the asm, that would be the perfect solution for me (I may even manage to change some stuff in the background of the menu while the music is playing which was my intention).
Thank you ?
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)