Jump to content
IGNORED

Changing character set in cc65


Recommended Posts

Greetings,

I've just started working with programming the Atari 8-bit, and recently was attempting to convert thisBASIC program from the Atari Graphics and Arcade Game Design book into c.

 

Here is my attempt (some of the magic numbers (SAVMSC is defined in the header file as a pointer to memory location 88)

 

int main()
{
char * screen;
char char_buffer[1];
char screen_buffer[11];
unsigned char * nmemtop;
unsigned char * chrom;
unsigned char * chram;
unsigned char * charSelect;

_graphics(2);
screen = (char *) SAVMSC;	

nmemtop = PEEK(106)-4;	
chram = (int)nmemtop * 256;
chrom = PEEK(756)*256;	
charSelect = PEEK(756);

POKE(756,nmemtop);

memcpy(chram,chrom,1024);

POKE(756,nmemtop);

strcpy(screen_buffer,"aaaaaaaaaa");
memcpy(screen,screen_buffer,10);	

while(1);	

return 0;
}

 

That causes the screen to look so:

post-34966-0-52815100-1363467985_thumb.png

Could someone help me figure out what I'm doing wrong? Any help is greatly appreciated, I'd even weather some ribbing about using C instead of assembler. :D

Edited by kensu
Link to comment
Share on other sites

I would check that your screen pointer and character pointer are correct. It seems that instead of writing to your screen (or modifying your char set as the case may be), it is instead modifying your display list, which is itself stored above screen memory whenever you do your GRAPHICS call.

 

I also noticed you did your lowering of memtop after you did the graphics call. That is a no-no. I think you may need to lower MEMTOP before the GRAPHICS call for it to work properly, as it is done in the BASIC program.

Link to comment
Share on other sites

Well one problem was that I forgot that PEEK actually gives you the contents of the memory location and not the location. Perhaps I should lay off the psuedoBasic from now on....

See haven't gotten the thing working correctly yet, now it looks like this:

 

post-34966-0-41792400-1363494248_thumb.png

 

int main()
{
   char * screen;
   char char_buffer[1];
   char screen_buffer[11];
   unsigned char * nmemtop;
   unsigned char * chrom;
   unsigned char * chram;
   unsigned char * charSelect;

   POKE(106,(int)nmemtop);

   _graphics(0);
   screen = (char *) SAVMSC;    
   

   nmemtop = (unsigned char *)106 - 4;    
   chram = (int)nmemtop * 256;
   chrom = (unsigned char *)756;
   chrom *= 256;
   charSelect = (unsigned char *)756;
   
   
   
   POKE(756,nmemtop);

   memcpy(chram,chrom,1024);

   
   POKE(756,nmemtop);

   strcpy(screen_buffer,"aaaaaaaaaa");
   memcpy(screen,screen_buffer,10);    

   
   while(1);    
   
   return 0;
}

Edited by kensu
Link to comment
Share on other sites

'MEMTOP' isn't of any use in cc65, because it is introduced by Basic.

cc65's strength is to work with memory configurations where you can clearly layout your segments and take alignment restrictions (e.g. for fonts) into account. Plan your usage, make a memory configuration out of it and build with that. ATM you produce also a conflict with memory cc65 thinks it can occupy, while you're using it for font data.

 

(Oops - just seen your using RAMTOP ($6A) not MEMTOP ($90) which is more useful, but my argument above is still valid, because the cc65 std. memory configuration is for machines with 48k.)

Edited by Irgendwer
Link to comment
Share on other sites

Actually, I REALLY hope you continue with pseudoBASIC. The 5200 needs a BASIC compiler to get more enthusiasts making games. If you could turn your work into a parser peeps could go pBASIC -> C -> ROM -> Order real cart from AtariAge :)

 

This already exists: http://kidsquid.99k.org/compilers/5200bas/5200bas.html

Though for reasons beyond all know logic the programs have to be written in GWBasic and not Atari BASIC. o_O

Link to comment
Share on other sites

As a professional programmer, I should've known there was no point in taking the cargo cult route... So I've been able to figure out a lot of the "magic numbers" in the original BASIC code, but there are some parts which still elude me....

 

CHROM=PEEK(756)*256
CHRAM=NMEMTOP*256

 

What exactly does this do, and why do we want to start at 256 times NMEMTOP instead of at NMEMTOP, which should be the beginning of the chunk of memory we set aside?

Again, since the location stored at 756 is the location of the character set, why are we setting the pointer at the value times 256?

 

I noticed that NMEMTOP pointer arithmetic seems to have 1=1 page, wherease CHROM and CHRAM pointer arithmetic has 1=1 byte. Is that what the multiplication by 256 does?

 

And could someone please please PLEASE post a C program which does the same thing as the BASIC program? I would be eternally grateful.

Link to comment
Share on other sites

And could someone please please PLEASE post a C program which does the same thing as the BASIC program? I would be eternally grateful.

 

Ok, that's a motivation.

 

Just execute 'Make' in the cmd shell.

 

Please note: To make things easier, I didn't use an own memory configuration (which I would do normally!), but a 'waste alignment' to fulfil the requirement of the OS that a font has to start on a 1k boundary!

 

Principle (alignment requirement (AR) = 1k here):

 

Allocate size for object (1k for font) + AR -1.

The aligned memory location is the starting address + AR-1 masked with the inverse AR.

Using this, you 'waste' AR-1 bytes.

 

Example: We need an even starting address (AR=2) for three bytes:

 

char buffer[3+AR-1];

char* evenStartOfBuffer = (char*)((unsigned int)buffer)+AR-1 & 0xFFFE;

 

Got it?

FontSample.zip

Edited by Irgendwer
Link to comment
Share on other sites

Thanks Irgendwer!

However, when I try to compile this I get the following error:

main.c(18): Error: Too many local variables

 

o_O I didn't even know there was such an error.

Anyone familiar with cc65 have a clue about this one?

Link to comment
Share on other sites

This seems to have fixed it:

int main(void)
{
char* pcFontSpace; // perform 'waste'-alignment...
char* pOwnFont;
char* pOSFont = (char*)(PEEK(756) << ; // get OS-Font address

// = (char*)(((unsigned int)pcFontSpace+FONTSIZE-1) & 0xFC00); // ...on 1k boundary

pcFontSpace = malloc(FONTSIZE*2-1);
pOwnFont = (unsigned int)pcFontSpace+FONTSIZE-1 & 0xFC00;



memcpy(pOwnFont, pOSFont, FONTSIZE);
memcpy(pOwnFont + 97*8, pFontPatch, sizeof(pFontPatch));

POKE(756, ((unsigned int)pOwnFont) >> ;

puts("\n");
puts("ab");
puts("cd");

while(1);
return 0;
}

 

I was also running into problems on Atari800Win because I had the memory set to 16K (since I was trying to write a program that could run on the 5200). Hopefully I can get it to work at 16K with a custom memory config file....

Link to comment
Share on other sites

... to fulfil the requirement of the OS that a font has to start on a 1k boundary!

 

Sorry for that (obviously I was too tired). It is of course a requirement from the hardware.

 

However, when I try to compile this I get the following error:

main.c(18): Error: Too many local variables

 

Strange (shoudn't happen) - which version are you using?

(Unfortunately the maintainer of cc65 just resigned, so help might be harder to get now.)

 

pcFontSpace = malloc(FONTSIZE*2-1);

 

If you go the dynamic memory allocation way, you also could use directly

 

int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size);

 

which does the same. Best solution is the memory config (which is also good to avoid fragmentation).

 

I was also running into problems on Atari800Win because I had the memory set to 16K (since I was trying to write a program that could run on the 5200). Hopefully I can get it to work at 16K with a custom memory config file....

 

Think so. You definitely need an own configuration, since mem-low in the std. config is set to (AFAIR) $2E00 to let programs work with most DOSes.

My 5200 knowledge is very limited, but for cartridges you have to tweak the configuration anyway.

Edited by Irgendwer
Link to comment
Share on other sites

Irgendwer's point about config files is right on. CC65 is extremely powerful, but you have to know how to set up your memory configs, especially for targets like the 5200.

 

My experience with the 'too many local variables' error relates to having too many bytes declared as 'local' ( ie., as a function local variable instead of declared outside of a function ). I think it has to do with CC65 putting these on the parameter stack instead of the heap, at any rate a fix is to move the declaration outside of the function. So instead of

 

int foo( void )

{

char big[1024];

}

 

you'd do

 

char big[1024];

 

int foo( void )

{

}

Link to comment
Share on other sites

Irgendwer's point about config files is right on. CC65 is extremely powerful, but you have to know how to set up your memory configs, especially for targets like the 5200.

 

My experience with the 'too many local variables' error relates to having too many bytes declared as 'local' ( ie., as a function local variable instead of declared outside of a function ). I think it has to do with CC65 putting these on the parameter stack instead of the heap, at any rate a fix is to move the declaration outside of the function. So instead of

 

int foo( void )

{

char big[1024];

}

 

you'd do

 

char big[1024];

 

int foo( void )

{

}

 

 

You might also be able to declare it static within the function.

Edited by kenfused
Link to comment
Share on other sites

Hmm, ran into an interesting problem when I set graphics mode 1 and 2. It switched to displaying the uppercase version of the letters instead of the pumpkin. I remember reading that the lower rez text modes don't have lowercase letters, so the computer displays them as uppercase letters in a different color. So I suspected this needed to be changed:

memcpy(pOwnFont + 97*8, pFontPatch, sizeof(pFontPatch));

Where the magic number 97 is actually the location of "a" in the character set. So I changed this to 65, the location of "A". However, this didn't change anything.

I'm assuming the other magic number 8 is to blame. I'm assuming this is 8 bytes, the size of a character. But don't all the screen modes use the same character set?

 

I placed the _graphics(2) call right after all the variables are declared, if that helps.

Link to comment
Share on other sites

Where the magic number 97 is actually the location of "a" in the character set. So I changed this to 65, the location of "A". However, this didn't change anything.

 

Yes, without doing a test, I think you problem is that you apply the change with ATASCII-offset calculation, while you have to take the internal one:

 

ATASCII Internal Operation

0-31 64-95 +64

32-95 0-63 -32

96-127 same

128-159 192-223 +64

160-223 128-191 -32

224-255 same

 

So 65 ('A') should be 33 internal offset. Lower case letters where the lucky case...

Link to comment
Share on other sites

  • 2 weeks later...

Here is my sample CC65 game with changed characterset and music in RMT

To compile it you probably need a newer atari.cfg file that can be generated by ld65.

 

Useful stuff in there, thank you :thumbsup: . Nice font, can I use the font in a small game I am working on?

Link to comment
Share on other sites

  • 2 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...