6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 2:35 pm

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Fri Aug 23, 2024 8:21 am 
Offline

Joined: Fri Aug 23, 2024 8:09 am
Posts: 2
Hi there,


after a while I've found time to study my beloved C64 asm, and I've done a setup with Kick Assembly chained with VSCode.

I've tried to study alone, but after I while i think i can declare myself completely stuck and as a newbie I've found this forum for help!

I've already made some sprite with the help of SpritePad, now i'm facing a new challenge: print a charmap!

So i've made a new charmap with CharpadPro, made by 40x8 chars, 320 in total.

I've put up this snippet to print it on screen:

Code:
BasicUpstart2(main)
#import "screenConstants.asm"
#import "memoryMap.asm"
 
*=CHARSET_ADDRESS "Charset"
.import binary "test/FancyMap_CharMapFull - Chars.bin" //

*=CHARSET_ATTRIB_ADDRESS "Charset Attrib"
.import binary "test/FancyMap_CharMapFull - CharAttribs_L1.bin" //

*=HUD_ADDRESS "MAKA_TITLE"
.import binary "test/FancyMap_CharMapFull - (8bpc, 40x8) Map.bin" //
 
*=GAME_CODE_ADDRESS "Game Code"
main:
    jsr SCREEN_CLEAR

    lda #%11011000   // enable MULTICOLOR - Bit #4: 1 = Multicolor mode on.
    sta $d016
     
     lda #%00011110       
     sta $d018
 
lda #BLUE
sta $d023 //extra color 2

lda #BLACK
sta $d022 //extra color 1
 
lda #RED
sta $d021 //BG color

ldx #00            // Initialize loop counter to 0
ldy #00 //#$192             // Initialize counter for adding $28  //192

jmp loop_start

exit:
    rts
   
loop_start:
    lda loop_counter
    tax
    tay
    lda HUD_ADDRESS, x  // Load the char B
    sta $0400, x  // Screen RAM
    tax // Transfer the numer of B to the x-register
    lda CHARSET_ATTRIB_ADDRESS,x
    sta $d800, y // Color RAM
    inc loop_counter
   
    jmp loop_start
 
loop_counter: .word 0 //192       // Define a temporary variable (initialized to 0)
loop_row_limit: .byte 0
 



But I probably hit the 255 limit.
With sprites, I've overcome affecting $D010 location, but now I don't know how to do it.

Any advice?

Thanks in advance!


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2024 8:44 am 
Offline

Joined: Wed Nov 16, 2011 9:39 am
Posts: 68
Not entirely sure if this is what you are asking about but:

The screen is 1000 bytes, but the X/Y registers can only hold 256 values, so either one need to do a nested loop, or unroll it:

Code:
  ldx #0
copyscreen:
  lda TILEDATA,x
  sta $0400,x
  lda TILEDATA+$100,x
  sta $0500,x
  lda TILEDATA+$200,x
  sta $0600,x
  lda TILEDATA+$300,x
  sta $0700,x
  inx
  bne copyscreen


As you are using Kickassembler, you can take advantage of its script language, making the code more compact:

Code:
  ldx #0
copyscreen:
  .for (var i = 0; i < 4; i++) {
    lda TILEDATA+i*$100,x
    sta $0400+i*$100,x
  }
  inx
  bne copyscreen
 


This will overwrite the sprite pointers at the end of the screen area, so make sure you update those after. Alternatively, do the above for 3 out of the 4 pages, and have a fourth loop not go all 256 bytes.

Same thing for your color ram code.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2024 8:53 am 
Offline

Joined: Wed Nov 16, 2011 9:39 am
Posts: 68
Sorry, forgive my previous answer, answering something you didn't ask. I didn't read properly.

But I would take advantage of the Kickassembler's script-language to do loop unrolling anyway. Something like:

Code:
  ldx #39
loop_start:
  .for (var i = 0; i < NUMBER_OF_ROWS; i++) {
    lda HUD_ADDRESS+i*40, x  // Load the char B
    sta $0400+i*40, x  // Screen RAM
    tay // Transfer the number of B to the y-register
    lda CHARSET_ATTRIB_ADDRESS,y
    sta $d800+i*40, x // Color RAM
  }
  dex
  bpl loop_start


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2024 9:01 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
(Welcome, Saturn78!)


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2024 9:13 am 
Offline

Joined: Wed Nov 16, 2011 9:39 am
Posts: 68
If you want the purist approach without using script language, you can use zero page pointers for the screen ram, color ram and the hud, or self modifying code:

Code:
  .const SCREEN=$0400
  .const COLORRAM=$d800
  .const HUD=$XXXX

  lda #<SCREEN   // Get the low byte of screen address
  sta load_screen  // Update the low byte address of the self modified lda nnnn,x instruction
  lda #>SCREEN  // Get the high byte of the screen address
  sta load_screen+1  // Update the high byte address of the self modified lda nnnn,x instruction
  lda #<HUD
  sta save_hud
  lda #>HUD
  sta save_hud+1
  lda #<COLORRAM
  sta save_colorram
  lda #>COLORRAM
  sta save_colorram+1

  ldy #NUMBER_OF_ROWS
  ldx #39

nextrow:
  sty save_y
nextchar:
  lda load_screen:$0000,x  // Self modified code. Will overwrite the $0000 in the init code above and in the adc code below
  sta save_hud:$0000,x // Self modified code. Will overwrite the $0000 in the init code above and in the adc code below
  tay
  lda CHARSET_ATTRIB_ADDRESS,y
  sta save_colorram:$0000,x // Self modified code. Will overwrite the $0000 in the init code above and in the adc code below
  dex
  bpl nextchar

  clc
  lda load_screen
  adc #40
  sta load_screen
  bcc !+
  inc load_screen+1
  clc

!:
  lda save_hud
  adc #40
  sta save_hud
  bcc !+
  inc save_hud+1
  clc

!:
  lda save_colorram
  adc #40
  sta save_colorram
  bcc !+
  inc save_colorram+1

!:
  ldy save_y:#00
  dey
  bpl nextrow 
 


EDIT: I guess I ended up using the scriptlanguage for the selfmodifying code anyway. I'll be quiet now :)
EDIT2: Disclaimer, this was written without any assembling whatsoever so the code might be full of bugs. Hopefully it is helpful anyway :)


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 23, 2024 10:30 pm 
Offline

Joined: Fri Aug 23, 2024 8:09 am
Posts: 2
Here we are: first of all big thanks to JohanFr, it gives lots to study!

I've spent pretty much all day testing, and even if the "zero page" approach is theorically something i've read about, it still won't work, i need further investigations, when i'll be more confident I'll try to explain better my attempt if still won't succeed!

For what concerns the "syntactic sugar" of "KickAss" 8) , well after lots of try and error I made it work with following approach:

Code:
BasicUpstart2(main)
#import "screenConstants.asm"
#import "memoryMap.asm"
 
*=CHARSET_ADDRESS "Charset"
.import binary "test_big/testimura_CharMapBig - Chars.bin" 

*=CHARSET_ATTRIB_ADDRESS "Charset Attrib"
.import binary "test_big/testimura_CharMapBig - CharAttribs_L1.bin" 

*=HUD_ADDRESS "test_TITLE"
.import binary "test_big/testimura_CharMapBig - (8bpc, 40x12) Map.bin" 
 
main:
    jsr SCREEN_CLEAR

    lda #%11011000   // enable MULTICOLOR - Bit #4: 1 = Multicolor mode on.
    sta $d016
     
     lda #%00011110       
     sta $d018
 
lda #BLUE
sta $d023 //extra color 2

lda #BLACK
sta $d022 //extra color 1
 
lda #RED
sta $d021 //BG color

ldx #00            // Initialize loop counter to 0
ldy #00 //#$192             // Initialize counter for adding $28  //192

jmp loop_start

exit:
    rts
   
.var NUMBER_OF_CHARS =  480
 
loop_start:
  .for (var i = 0; i < NUMBER_OF_CHARS; i++) {
 
   lda HUD_ADDRESS + i  // Load the "ith" char
    sta $0400 + i  // Screen RAM
    tay // Transfer the number of B to the y-register
    lda CHARSET_ATTRIB_ADDRESS,y
    sta $d800 + i // Color RAM 
  }
  jmp exit


Attention: when I've noticed that I would be able to overcome 255 limitation I've decided to use a much bigger charMap made of 40 columns x 12 rows, this explains 480 as char number :wink:

With this i got full control of each char printed on screen, but after going back to suggested approach, I'm start thinking that probably i'm not doing this in most efficient way, maybe considering nested loop Cols\Rows or better way to save iterations\logic...

More important than everything is that I feel now i'm in the right place to learn :D


Top
 Profile  
Reply with quote  
PostPosted: Sat Aug 24, 2024 7:36 am 
Offline

Joined: Wed Nov 16, 2011 9:39 am
Posts: 68
Saturn78 wrote:
Here we are: first of all big thanks to JohanFr, it gives lots to study!

I've spent pretty much all day testing, and even if the "zero page" approach is theorically something i've read about, it still won't work, i need further investigations, when i'll be more confident I'll try to explain better my attempt if still won't succeed!

For what concerns the "syntactic sugar" of "KickAss" 8) , well after lots of try and error I made it work with following approach:

Code:
BasicUpstart2(main)
#import "screenConstants.asm"
#import "memoryMap.asm"
 
*=CHARSET_ADDRESS "Charset"
.import binary "test_big/testimura_CharMapBig - Chars.bin" 

*=CHARSET_ATTRIB_ADDRESS "Charset Attrib"
.import binary "test_big/testimura_CharMapBig - CharAttribs_L1.bin" 

*=HUD_ADDRESS "test_TITLE"
.import binary "test_big/testimura_CharMapBig - (8bpc, 40x12) Map.bin" 
 
main:
    jsr SCREEN_CLEAR

    lda #%11011000   // enable MULTICOLOR - Bit #4: 1 = Multicolor mode on.
    sta $d016
     
     lda #%00011110       
     sta $d018
 
lda #BLUE
sta $d023 //extra color 2

lda #BLACK
sta $d022 //extra color 1
 
lda #RED
sta $d021 //BG color

ldx #00            // Initialize loop counter to 0
ldy #00 //#$192             // Initialize counter for adding $28  //192

jmp loop_start

exit:
    rts
   
.var NUMBER_OF_CHARS =  480
 
loop_start:
  .for (var i = 0; i < NUMBER_OF_CHARS; i++) {
 
   lda HUD_ADDRESS + i  // Load the "ith" char
    sta $0400 + i  // Screen RAM
    tay // Transfer the number of B to the y-register
    lda CHARSET_ATTRIB_ADDRESS,y
    sta $d800 + i // Color RAM 
  }
  jmp exit


Attention: when I've noticed that I would be able to overcome 255 limitation I've decided to use a much bigger charMap made of 40 columns x 12 rows, this explains 480 as char number :wink:

With this i got full control of each char printed on screen, but after going back to suggested approach, I'm start thinking that probably i'm not doing this in most efficient way, maybe considering nested loop Cols\Rows or better way to save iterations\logic...

More important than everything is that I feel now i'm in the right place to learn :D


Programming 6502/6510 is fun. Do note that your version takes quite a bit of memory (the code in the loop is essentially duplicated 480 times). It may or may not pose a problem, but just something to be aware of. I usually use a hybrid solution for loop-unrolling (i.e. instead of having two nested loops i have one loop unrolled), which saves me an index-register to use for other things. But it is always a tradeoff between speed, code size and readability.


Top
 Profile  
Reply with quote  
PostPosted: Sat Aug 24, 2024 6:34 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Be aware that the VIC-II chip in the C64 can only "see" 16Kb of RAM at one time. Aside from the screen color memory at $D800, everything you want to display has to fit into that 16Kb.

You can re-define the character set and point the VIC-II at your re-defined characters. However, a single character set is limited to 256 8x8 glyphs. If you want to display more than that on a single screen, you may have to re-point the VIC-II "on the fly", ie., using raster interrupts. Once the raster reaches whatever line you want to change character sets at, you'll need to re-point the VIC-II to wherever your additional definitions are. And of course change that back once the raster is off the screen, so the top of the screen uses the first 256 characters again.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 25, 2024 4:48 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
...although it has belatedly occurred to me that it another way it might be possible to get beyond the 256-glyph limit would be to re-define not what the VIC-II is pointing at, but the glyphs themselves. Whenever the VIC-II is not "looking" at a particular glyph (ie., in the process of copying it to the output stream), that image could be overwritten with another. The source could be anywhere in the C64's memory, just as long as the character set itself was somewhere the VIC-II could "see" it. Any number of glyphs could be accommodated this way. It would probably still require watching the raster beam to be sure it was safe to overwrite any particular glyph.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 23 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron