Jump to content
  • 0
rje

cc65: load a font into VRAM

Question

Posted (edited)

This time around, I want to load a font... in C.  Can it be done?  I'm sure it can be done.  How?

UPDATE: The solution is here.  You have to properly decompose the address and pass it to cbm_k_load().

//
// The address value of cbm_k_load() gets you 16 bits.  Of course, 
// VERA's addressing space is larger.  So you DO have to properly 
// set the FIRST parameter to cbm_k_load():
//    0 points to X16's RAM.
//    1 points to VERA $00000.
//    2 points to VERA $10000.
//
cbm_k_setnam("petfont.bin");
cbm_k_setlfs(0,8,0);
cbm_k_load(2, 0x0f800);

 

The rest of my original post follows.

The BASIC command 'LOAD' takes a device number, a bank number, and an address.  Not the same as loading into VRAM.

The docs talk about loading to VRAM (https://github.com/commanderx16/x16-docs/blob/master/Commander X16 Programmer's Reference Guide.md#load-into-vram) but that description frankly is at odds with the way I've been using LOAD, so I suspect that particular paragraph is out of date.  And besides, does that translate to SETLFS parameters?

I KNOW this can be done, because assembly language programmers are doing it. 

 

Edited by rje

Share this post


Link to post
Share on other sites

17 answers to this question

Recommended Posts

  • 0

Although the device number in that example is out of date, the rest should (probably) still work. The difference is that the secondary address must be 2 if loading to the lower half of VRAM, and 3 if loading to the upper half. Additionally, the address passed to cbm_k_load will be ignored, so you should put the destination address in the file header (I might open an issue on the x16-rom repository to see if support can be added for ignoring the header).

  • Thanks 1

Share this post


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

This time around, I want to load a font... in C.  Can it be done?  I'm sure it can be done.  How?

The BASIC command 'LOAD' takes a device number, a bank number, and an address.  Not the same as loading into VRAM.

The docs talk about loading to VRAM (https://github.com/commanderx16/x16-docs/blob/master/Commander X16 Programmer's Reference Guide.md#load-into-vram) but that description frankly is at odds with the way I've been using LOAD, so I suspect that particular paragraph is out of date.  And besides, does that translate to SETLFS parameters?

I KNOW this can be done, because assembly language programmers are doing it. 

Well this worked for me in assembly language: SETLFS parameters are the regular 1,8,0. The LOAD parameters are A=02 for VERA addresses 00000-0FFFF, and A=03 for addresses 10000-1FFFF. X and Y are the low byte and high byte respectively within those ranges. Don't know if that will translate directly to C.

One thing to note when loading from file directly to VERA is that the emulator performs this task about 50 times faster than the actual hardware will.

Share this post


Link to post
Share on other sites
  • 0

It's exactly the same as loading into VRAM. The default character set is loaded into VRAM at $0F800, so just LOAD your font to there. You can also move it somewhere else and change your layer's TILEBASE address

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)
1 hour ago, SlithyMatt said:

It's exactly the same as loading into VRAM. The default character set is loaded into VRAM at $0F800, so just LOAD your font to there. You can also move it somewhere else and change your layer's TILEBASE address

OK I need to ask a clarifying question.  You mean this sort of thing will load into VRAM?

...
#include <cbm.h>
...

   cbm_k_setnam("coolfontfile.bin");
   cbm_k_setlfs(0, 8, 0);
   cbm_k_load(0, 0x0f800);
   POKE(0x9f36,128);
   

...only it doesn't.  SO there's something I'm missing.  Maybe the SA has to be greater than zero?
 

Edited by rje

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)
49 minutes ago, rje said:

OK I need to ask a clarifying question.  You mean this sort of thing will load into VRAM?


...
#include <cbm.h>
...

   cbm_k_setnam("coolfontfile.bin");
   cbm_k_setlfs(0, 8, 0);
   cbm_k_load(0, 0x0f800);
   POKE(0x9f36,128);
   

...only it doesn't.  SO there's something I'm missing.  Maybe the SA has to be greater than zero?
 

Try cbm_k_load(2,0x0f800) instead.  2 is the VRAM range $00000-$0FFFF, 3 is the VRAM range $10000-$1FFFF, if I understand the syntax of that line, it's just the Kernel LOAD routine.

Edited to add: you have set the layer 1 tilebase to 128, but that's bits 16-11 of the tile base address, so you're pointing to $10000.  If you want your tile data at 0x0f800 (which is where you're loading), you need to set 0x9f36 to (binary) 01111100 = decimal 60, hex 7E.  

Edited by Ed Minchau
  • Like 2
  • Thanks 1

Share this post


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

Try cbm_k_load(2,0x0f800) instead.  2 is the VRAM range $00000-$0FFFF, 3 is the VRAM range $10000-$1FFFF, if I understand the syntax of that line, it's just the Kernel LOAD routine.

Edited to add: you have set the layer 1 tilebase to 128, but that's bits 16-11 of the tile base address, so you're pointing to $10000.  If you want your tile data at 0x0f800 (which is where you're loading), you need to set 0x9f36 to (binary) 01111100 = decimal 60, hex 7E.  

Thank you, that worked, although the poke value is $7c (decimal 124).

  • Haha 1

Share this post


Link to post
Share on other sites
  • 0
6 hours ago, Elektron72 said:

Additionally, the address passed to cbm_k_load() will be ignored, so you should put the destination address in the file header (I might open an issue on the x16-rom repository to see if support can be added for ignoring the header).

A pull request already was posted for it:
https://github.com/commanderx16/x16-rom/pull/173

Share this post


Link to post
Share on other sites
  • 0
6 minutes ago, Greg King said:

A pull request already was posted for it:
https://github.com/commanderx16/x16-rom/pull/173

The address passed to cbm_k_load is not ignored unless you are using cbm_k_load (1, address), in which case the first two bytes  of the file are the starting address.  If it's zero then the address is the start location in RAM, if it's 2 or 3 it's the start location in VRAM.

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
24 minutes ago, rje said:

Thank you, that worked, although the poke value is $7c (decimal 124).

Hah! not enough coffee!

  • Haha 1

Share this post


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

Thank you, that worked, although the poke value is $7c (decimal 124).

The POKE() isn't needed.  You're replacing the firmware's font.  Therefore, that location already has 0x7C.

  • Thanks 1

Share this post


Link to post
Share on other sites
  • 0

Decided to check the ROM source code to determine the current functionality of LOAD. According to the comments in the source, it appears to currently work as follows:

  • Secondary Address
    • If the secondary address is 0, get address from X and Y. (I believe this might be broken right now)
    • If the secondary address is 1, get address from the header.
  • Accumulator
    • If A is 0 when the routine is called, load to RAM.
    • If A is 1, verify the file.
    • If A is 2, load to the lower half of VRAM.
    • If A is 3, load to the upper half of VRAM.

Share this post


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

Decided to check the ROM source code to determine the current functionality of LOAD. According to the comments in the source, it appears to currently work as follows:

  • Secondary Address
    • If the secondary address is 0, get address from X and Y. (I believe this might be broken right now)
    • If the secondary address is 1, get address from the header.
  • Accumulator
    • If A is 0 when the routine is called, load to RAM.
    • If A is 1, verify the file.
    • If A is 2, load to the lower half of VRAM.
    • If A is 3, load to the upper half of VRAM.

That looks about right.  The secondary address being 0 case is broken right now, but only for SD card images (which actually uses the kernel).  It should work fine if you're using the host filesystem, which uses a bypass in the emulator to handle it.  As Greg King pointed out above, there is a PR for this bug, but since Michael Steil hasn't been active lately, it hasn't been accepted or reviewed yet.

Share this post


Link to post
Share on other sites
  • 0

I find these functions difficult to track down documentation for - The C64 Kernal functions themselves are well-documented, and the official X16-Documentation repository on Github defines some of the system-specific Kernal APIs, but I recall once coming across a complete list of the X16 Kernal API somewhere off the beaten path, and for the life of me I can't find it.

I find it much harder to locate a good reference for the cc65 functionality, especially where system-specific funtionality is concerned. Anyone with a good link to a C reference for this stuff?

  • Like 1

Share this post


Link to post
Share on other sites
  • 0

The X16 documentation also lists all kernal functions inherited from the C64 and C128, although it provides no description (this is particularly annoying for functions that have been modified, such as LOAD). As for C functions, the cc65 documentation has a list of all C equivalents of system functions from various machines, including the C64, at https://cc65.github.io/doc/funcref.html. This list will eventually include X16 functions, but for now, you can find any X16 C functions that have been implemented so far in the header file at https://github.com/cc65/cc65/blob/master/include/cx16.h. I believe any functionality not in either list currently has no C implementation, and must be called manually.

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
5 hours ago, Elektron72 said:

The X16 documentation also lists all kernal functions inherited from the C64 and C128, although it provides no description (this is particularly annoying for functions that have been modified, such as LOAD). As for C functions, the cc65 documentation has a list of all C equivalents of system functions from various machines, including the C64, at https://cc65.github.io/doc/funcref.html. This list will eventually include X16 functions, but for now, you can find any X16 C functions that have been implemented so far in the header file at https://github.com/cc65/cc65/blob/master/include/cx16.h. I believe any functionality not in either list currently has no C implementation, and must be called manually.

Not everything is documented in funcref.html, but most of it is.  Sometimes it will say "incomplete", others functions are simply missing from the documentation, but the headers do at least show the function prototype, sometimes with some additional documentation about the function in the comments.

  • Like 1

Share this post


Link to post
Share on other sites
  • 0

Maybe I was just spoiled by the documentation for PHP, but I find the cc65 function reference to be barely useful at all other than seeing what the function prototype is. It's one thing to know you want to use function X() and see how it's called and what its return type is, but it doesn't say much about what the actual return values are, etc (in many cases anyway) and it would be nice if there were code examples to help internalize the information.

What I find more difficult is when I know I want to do thing_x, and would know how to do it in assembly, but not what the C abstraction for that functionality is (or even if any such thing even exists). Often times, you can use the kernal call function wrappers, but cc65 also has already done the work in their own APIs such as cbm.h, etc, and it wasn't even necessary to re-invent the wheel.

I found the comments in source files themselves to be more helpful than the documentation. For instance, cbm_read() actually gives example code and discusses how the function works, etc.

It's a long row to hoe but I'm plowing ahead.

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