Jump to content
  • 0
svenvandevelde

How to load bitmaps in memory banks?

Question

So the addresses $A000 till $BFFF are banked. How can I load in assembly language binary data into these memory banks in the 512KB zone? F.e. tiles, sprites. To preload these graphical objects in the memory so that they can quickly be copied to the vram on the Vera.

But how to load files in memory banks?

Does somebody have an example assembly language routine?

Edited by svenvandevelde

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

I have a practical example using ca65 macros, you can find the relevant files here:

But essentially, it boils down to this:

	.segment "CODE"
	LOADBANK=$10
	; Select bank to load into
	lda #LOADBANK
	sta $9F61
	; Call SETLFS
	LOGICAL_NUM=$01
	DEVICE_NUM=$08
	SECONDARY_ADDR=$00
	lda #LOGICAL_NUM
	ldx #DEVICE_NUM
	ldy #SECONDARY_ADDR
	jsr $FFBA
	; Call SETNAM
	FILENAME_ADDR=FILENAME
	FILENAME_LEN=$08
	lda #FILENAME_LEN
	ldx #<FILENAME_ADDR
	ldy #>FILENAME_ADDR
	jsr $FFBD
	; Call LOAD
	lda #0
	ldx #$00
	ldy #$A0
	jsr $FFD5
	.segment "DATA"
	FILENAME: .byte "FILE.SEQ"
	

If your file can't fit into a single bank, you'll have to either break it into smaller chunks, or else open the file and read it a byte at a time. Personally, I'd suggest breaking it into multiple chunks.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
  • 0
7 hours ago, StephenHorn said:

If your file can't fit into a single bank, you'll have to either break it into smaller chunks, or else open the file and read it a byte at a time. Personally, I'd suggest breaking it into multiple chunks.

The Kernal actually does automatically increment and switch the bank when using cbm_k_load(). I'm using this in Brixx for loading the game intro music into banked RAM from a single 40kB file.

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites
  • 0
7 hours ago, AndyMt said:

The Kernal actually does automatically increment and switch the bank when using cbm_k_load(). I'm using this in Brixx for loading the game intro music into banked RAM from a single 40kB file.

Oh! My mistake then. I thought the kernal would only support loading into individual banks.

Share this post


Link to post
Share on other sites
  • 0
1 hour ago, StephenHorn said:

I thought the kernal would only support loading into individual banks.

I thought that first, too. Until version 1.0 of Brixx I did load from segmented BIN files, which is cumbersome. Then someone mentioned it in a online-chat, that loading into VRAM and also into banked RAM will work across the bank boundaries (64k in VRAM and 8k in banked RAM).

I just tried it a few days ago and indeed - it works... My title screen bitmaps are 75 kByte and the sound files are 40 kByte each.

Using the host file system of course. No idea if this works from SD card.

Share this post


Link to post
Share on other sites
  • 0
26 minutes ago, AndyMt said:

No idea if this works from SD card.

It is supposed to, but the SD card code in the emulator is far removed from what is in the current hardware, and there are several bugs. I would expect a convergence between the emulator and the hardware to happen after the rev 3 board is done.

Share this post


Link to post
Share on other sites
  • 0
49 minutes ago, AndyMt said:

I thought that first, too. Until version 1.0 of Brixx I did load from segmented BIN files, which is cumbersome. Then someone mentioned it in a online-chat, that loading into VRAM and also into banked RAM will work across the bank boundaries (64k in VRAM and 8k in banked RAM).

I just tried it a few days ago and indeed - it works... My title screen bitmaps are 75 kByte and the sound files are 40 kByte each.

Using the host file system of course. No idea if this works from SD card.

I'd say the safe thing to do right now is load byte-by-byte with GETIN, then possibly use LOAD once the code is firmed up. 

There are going to be a bunch of changes to the emulator, soon... the banking system has changed, and there are doubtless been a ton of ROM changes along the way. The master branch on the Github page hasn't changed since the last major release, so I suspect the team is working on this behind the scenes.

I guess my point is... no matter what you do right now, you're going to end up re-writing some code. 

 

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
3 hours ago, TomXP411 said:

I guess my point is... no matter what you do right now, you're going to end up re-writing some code. 

That's for sure 😀.

Share this post


Link to post
Share on other sites
  • 0

Thanks guys ... I'm really battling now for hours on this ... I have the code working to load a file, but I always get an error (4) as a return from the load statement.

What do i need to do to find the file? I though the files at the directory where the x16emu was loaded, but it can never find the file  ... grrr.

I specify the name in capital letters. The file name on the disk is lower case. it's a binary file (graphic).

Share this post


Link to post
Share on other sites
  • 0
7 minutes ago, svenvandevelde said:

The file name on the disk is lower case.

That won't work. You need to have all-caps for the filename in your FAT, and your code needs to specify all-caps as well, but depending on what language and compiler you are using, the code may have to show lower-case letters, but in the end the machine code needs to use all caps ($41-$5A).

Share this post


Link to post
Share on other sites
  • 0

Thank you but still no succes. Tomorrow is another day. Closing the laptop and going to dream about the solution. I think tomorrow I'll make a test program to scan all possible combinations quickly until I find it. Opening a file shouldn't be that hard. 

Share this post


Link to post
Share on other sites
  • 0

It's UPPER-CASE on the host; and, lower-case in your (PetSCII) source code.

Edited by Greg King

Share this post


Link to post
Share on other sites
  • 0
2 hours ago, SlithyMatt said:

That won't work. You need to have all-caps for the filename in your FAT, and your code needs to specify all-caps as well, but depending on what language and compiler you are using, the code may have to show lower-case letters, but in the end the machine code needs to use all caps ($41-$5A).

There are several possible mappings, and some compilers actually map ASCII text to screen codes, making things more complicated.

First, remember that with a 1:1 mapping, lower case ASCII text gets converted to graphic symbols in PETSCII. So yes - use upper case text in your file names and make sure the text is being mapped 1:1 - ie, no PETSCII or screen code translation.

Which assembler are you using? It would help to know so we can suggest the correct command in the assembler to map your string correctly. 

Share this post


Link to post
Share on other sites
  • 0

I agree, it looks like character mapping problem. I saw some other posts from svenvandevelde and I believe he is working in C. So my suggestion would be to check the generated assembly and see how were the filename characters converted.

Share this post


Link to post
Share on other sites
  • 0
45 minutes ago, DusanStrakl said:

I agree, it looks like character mapping problem. I saw some other posts from svenvandevelde and I believe he is working in C. So my suggestion would be to check the generated assembly and see how were the filename characters converted.

I've run into that already with KickC. Turns out there is an undocumented "magic suffix" that changes the character mapping .

"abcABC1"pm

I also did some file testing in cc65, and that was able to open files without incident; my cc65 program worked on the first try.... then gave me endless fits as I worked to buffer data to RAM.  😉

 

 

 

Share this post


Link to post
Share on other sites
  • 0

Thanks all for your reactions and help. Just would like to say that I could resolve all my issues! Even more, I've created some exciting functions in C to load now files into banked memory, but also to copy banked memory directly into the VERA VRAM.

The issue with the files not loading had nothing to do with the logic being wrong, it had to do with the location (work directory) from where the x16emu was loading.

So, as a summary these are some rules:

1. Always check and ensure that x16emu can "see" the files. The directory from where x16emu is loaded (through the path), is the working directory, and x16emu will only see files in this directory. If you're not sure the files are there, just load x16emu. And type in x16emu LOAD "$" and then LIST.

2. The files should be written on your folder in UPPER case. The file name in your compiler should be also written in UPPER case. Then you'll be fine.

 

Share this post


Link to post
Share on other sites
  • 0

That being said, I experience some weird phenomenon. 

When I load a binary file in banked memory using the LOAD kernal API, it seems that the data loaded is shifted with 2 bytes in the memory!

Let's say I load a file in memory bank 3 at address A000. Then it really appears that the data loaded through the kernal api is starting at address 9FFE ... thus at A000 - 2!

Do you experience a similar issue? Is there something I should know extra, about the LOAD api at $FFD5?

 

Share this post


Link to post
Share on other sites
  • 0
28 minutes ago, svenvandevelde said:

When I load a binary file in banked memory using the LOAD Kernal API, it seems that the data loaded is shifted by 2 bytes in the memory!

Let's say I load a file in memory bank 3 at address $A000. Then, it really appears that the data loaded through the Kernal API is starting at address $9FFE ... thus, at $A000 - 2!

Do you experience a similar issue? Is there something I should know extra, about the LOAD API at $FFD5?

How do you create that file?  Does it have a load-address (it needs one, even if you never use it)?

Edited by Greg King

Share this post


Link to post
Share on other sites
  • 0

The kernal expects the first two bytes of every file it opens with LOAD to have the default load address. Even if you specify a different address, it is going to expect the default to still be there and skip over it to the payload. If you are going to specify a load address in your code, just go ahead and prefix your file with two bytes, both can be zero or whatever.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
  • 0
8 hours ago, SlithyMatt said:

The kernal expects the first two bytes of every file it opens with LOAD to have the default load address. Even if you specify a different address, it is going to expect the default to still be there and skip over it to the payload. If you are going to specify a load address in your code, just go ahead and prefix your file with two bytes, both can be zero or whatever.

nooooo..... don't ever set the load address to zero. If someone tries to LOAD the file, it'll end up overwriting zero page and crashing the computer. If you're writing a data file that's not tied to a particular address, either use $0801 to cause it to load into BASIC RAM, or $A000 to cause it to load into banked memory. 

In this case, since you actually are trying to load the data into banked memory, make the first two bytes of your file $00 A0. 

 

 

Edited by TomXP411
  • Thanks 1

Share this post


Link to post
Share on other sites
  • 0
2 minutes ago, TomXP411 said:

If someone tries to LOAD the file, it'll end up overwriting zero page and crashing the computer.

Oh well, turn the machine off and on again... Try again ... Continue until you figure out not to LOAD that file directly. 😉

But you are right, ensuring that a wrong LOADing does not crash the computer is the nice thing to do 🙂

  • Like 1
  • Haha 1

Share this post


Link to post
Share on other sites
  • 0
38 minutes ago, TomXP411 said:

nooooo..... don't ever set the load address to zero. If someone tries to LOAD the file, it'll end up overwriting zero page and crashing the computer. If you're writing a data file that's not tied to a particular address, either use $0801 to cause it to load into BASIC RAM, or $A000 to cause it to load into banked memory. 

In this case, since you actually are trying to load the data into banked memory, make the first two bytes of your file $00 A0. 

 

 

Thank you! I'll try that. I generate these files using kickc and kickasm graphic file scanning capabilities. Upon example of @Jesper Gravgaard but having extendedit it heavily. I'll create in the data segments 2 bytes with the load address A000. This can be easily done and I'll let you know the result. 

Share this post


Link to post
Share on other sites
  • 0
2 hours ago, svenvandevelde said:

Thank you! I'll try that. I generate these files using kickc and kickasm graphic file scanning capabilities. Upon example of @Jesper Gravgaard but having extendedit it heavily. I'll create in the data segments 2 bytes with the load address A000. This can be easily done and I'll let you know the result. 

As a note, I've been working on some APIs for KickC to handle KERNAL calls. I've got opening files and reading sequential files working; the next step is to write files. 

We came up with a naming convention for the new APIs that you might want to adopt, so you can submit your I/O code to the KickC project (if you're interested in doing so)

cbm_k_name() for KERNAL wrappers: a function that just makes one KERNAL call. 

So for LOAD, you'd name it cbm_k_load()

And for functions that combine several KERNAL calls (ie: combine SETNAM, SETLFS, and LOAD in one function), just prefix with cbm_, so cbm_load(char* name, word bank word address) would load a binary file. (

If you check over on the KickC thread, they're hungry for Commander API implementations, so it might be nice if you send your file load code, once it's working. 

 

Share this post


Link to post
Share on other sites
  • 0
18 hours ago, svenvandevelde said:

I generate those files using KickC and KickAsm graphic file scanning capabilities. Upon example of @Jesper Gravgaard, but having extended it heavily. I'll create, in the data segments, 2 bytes with the load address $A000. That easily can be done; and, I'll let you know the result.

Would changing "space.ld" work?  Mark those data files as "prg".  Give their segments a start address.

Share this post


Link to post
Share on other sites
  • 0
16 hours ago, TomXP411 said:

As a note, I've been working on some APIs for KickC to handle KERNAL calls. I've got opening files and reading sequential files working; the next step is to write files. 

We came up with a naming convention for the new APIs that you might want to adopt, so you can submit your I/O code to the KickC project (if you're interested in doing so)

cbm_k_name() for KERNAL wrappers: a function that just makes one KERNAL call. 

So for LOAD, you'd name it cbm_k_load()

And for functions that combine several KERNAL calls (ie: combine SETNAM, SETLFS, and LOAD in one function), just prefix with cbm_, so cbm_load(char* name, word bank word address) would load a binary file. (

If you check over on the KickC thread, they're hungry for Commander API implementations, so it might be nice if you send your file load code, once it's working. 

 

Now I'm a bit confused because I'm helping jesper with vera code etc. He has been merging stuff for me already into the compiler pack. Im fine to do so but where exactly do I need to put that? I've created a cx16-kernal.h and cx16-kernal.c file in the compiler. It still needs merging though. But happy to follow your guidance. The cbm api is probably a direct copy from the cc65? Correct?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

Please review our Terms of Use