Jump to content
  • 0
desertfish

how to set a character at x,y in given color?

Question

Hi,

I want to set characters on the screen at arbitrary locations x,y  with arbitrary color, from assembly.

On the C64 this can be efficently done by just writing the screencode into the correct location in screen matrix at $0400 in memory and the color in the corresponding color matrix location at $d800.   Also, I can simply write the desired color for text output in to memory location 646 if I want to change it.

I know I can use the PLOT kernel routine and then CHROUT but this seems inefficient and I haven't figured out yet how to change the text color.

How are these things better accomplished on the CommanderX16?

 

Share this post


Link to post
Share on other sites

10 answers to this question

Recommended Posts

  • 0

If you want to use the kernal routines, I believe that the most efficient way to do it using the routines currently implemented is using PLOT and CHROUT. To change colors using these routines, output the color control characters listed in the Programmer's Reference Guide. However, the fastest way to do it would most likely be by directly accessing the VERA registers. The default layout of screen memory allocates 256 bytes for each row, meaning that to access a specific X and Y, the high byte of the address is the Y, and the low byte is X*2 (which is easy to calculate using ASL). Even numbered bytes store character codes, and odd numbered bytes store color data. In 16-color mode, the lower 4 bits of each color byte store the foreground color, and the upper 4 bits store the background color.

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

The Characters are stored in VRAM and can only be accessed via the VPOKE command (or via VERA registers directly). The standard location of Screen starts at 0,$0000. Each character has two bytes.

Mode 0
1. Byte is the Screencode (not PETSCII - same as C64)
2. Byte is the color entry from the Palette 16 colors 4bit for foreground and 4bit for background color. 

The Screenram is organized in rows of 256 bytes, where 160 are used for each line. (80x2). 
First line starts a $0000, second line at $0100 and so on. Easy, right? You have 60 lines of Characters. (16kb). So the screen goes from $0000-$3FFF in VRAM.
 

Screenlayout (S=Screencode,C=Color)
$0000 SCSCSCSCSCSC ... (256 bytes)
$0100 SCSCSCSCSCSC ...

 

In other words, if you want to out an A in 20,40 you do the following

10 X=20:Y=40:C=5
20 AD=(Y-1)*256+(X-1) *2
30 VPOKE 0,AD,$01:REM PUT CODE A
40 VPOKE 0,AD+1,C:REM PUT PALLETTE COLOR 5

Hope that helps.

/edited: some errors in there as Mode0 is 16 color mode and the color byte has a different setup.

Edited by SerErris

Share this post


Link to post
Share on other sites
  • 0

Thanks so much.   I have to figure out what VPOKE translates to in assembly though.

For now, I'll stick with just the kernel routines and @Elektron72 thanks for the tip about the color control characters, I forgot about those.   Just printing them out via a small translation table does the trick for now.   I'll investigate the VERA chip later it is a bit too much for me to dive into that right now as well I think (I just started programming on the CommanderX16)

Share this post


Link to post
Share on other sites
  • 0

VPOKE is quite simply translated to assembly.

If you want to write $AB to VRAM address $10246 do this:

VPOKE 1,$0246,$AB

Or in assembly

stz $9F25 ; select VERA address 0

lda $46

sta $9F20 ; set VRAM address low byte

lda $02

sta $9F21 ; set VRAM address high byte

lda $01

sta $9F22 ; set VRAM bank, stride of zero to write a single byte

lda $AB

sta $9F23 ; write to VRAM address 0

Share this post


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

Thanks so much.   I have to figure out what VPOKE translates to in assembly though.

For now, I'll stick with just the kernel routines and @Elektron72 thanks for the tip about the color control characters, I forgot about those.   Just printing them out via a small translation table does the trick for now.   I'll investigate the VERA chip later it is a bit too much for me to dive into that right now as well I think (I just started programming on the CommanderX16)

It's explained in the Programmer's Reference and the VERA manual. 

you set the address in the address registers, then push the character and color data into the data registers. 

 

Share this post


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

stz $9F25 ; select VERA address 0

lda $46
sta $9F20 ; set VRAM address low byte

I had an discussion on the github repository with some other guys. They pointed out that this is a bad idea to just store a 0 in the CTRL register, as it also holds another value (bit1). So you should leave the rest of the byte intact. Therefore this should be a better way of doing so (only works on 65c02 - not on 6502).

 

Quote

LDA #$01
TRB $9F25

The TRB instruction (test reset bit) clears a bit in the memory (and actually tests its status before clearing) indicated by the value in A. So with this (and the TSB instrcution (set) ) you can influence just the bits you want. Same is btw true for the VRAM highbyte - even if that can be set completely as no other registers are depending on that and it just defines the highest bit and the increment amount and inc/dec flag.

C64 style would be:

Quote

Set bit 0
LDA $9F25
ORA #$01
STA $9F25

Reset bit 0
LDA $9F25
AND #$FE
STA $9F25

 

Edited by SerErris

Share this post


Link to post
Share on other sites
  • 0
41 minutes ago, SerErris said:

 They pointed out that this is a bad idea to just store a 0 in the CTRL register, as it also holds another value (bit1). So you should leave the rest of the byte intact.

In all of my projects, I am running in either 640x480 or (the vast majority of cases) 320x240. So, I always want DCSEL to be zero as well, so I can save a few cycles. Something to consider if you want to have a non-standard display.

Share this post


Link to post
Share on other sites
  • 0
34 minutes ago, SlithyMatt said:

In all of my projects, I am running in either 640x480 or (the vast majority of cases) 320x240. So, I always want DCSEL to be zero as well, so I can save a few cycles. Something to consider if you want to have a non-standard display.

Tbh, the dual-port techniques really conflict with being able to use the VERA PSG in your music/SFX engine. In my case, when wanting to write to the PSG, I'd save the values of the CTRL register and the Port 0 address/stride to 4 locations in RAM, so I can restore them back when the PSG writes are done.

Share this post


Link to post
Share on other sites
  • 0
56 minutes ago, StinkerB06 said:

In my case, when wanting to write to the PSG, I'd save the values of the CTRL register and the Port 0 address/stride to 4 locations in RAM, so I can restore them back when the PSG writes are done.

That's another perfectly valid approach. It's not that storing a fixed value in the CTRL register is a bad idea, per se, I just felt that in a general case, TSB/TRB on just the bit you want to manipulate represents a best practice. If you know the other bits are irrelevant, STA is perfectly fine.

But also, maybe I'm overthinking things, or making things difficult by choosing instructions folks might not be so familiar with. Everyone that's been introduced to 6502 assembly knows LDA/STA, they might have overlooked or be unfamiliar with TSB/TRB.

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
On 8/30/2020 at 9:49 AM, SerErris said:

I had a discussion on the Github repository with some other guys. They pointed out that this is a bad idea to just store a 0 in the CTRL register, as it also holds another value (bit1).

They were wrong -- for most uses of the control register!

The value of a control bit matters only while you're accessing the I/O registers that it controls.  You set the control register for the accesses that you will do next.

While you're accessing the address registers for the data ports, you aren't touching the Display Composer.  Therefore, the value of DCSEL is irrelevant then.  While you're changing the Display Composer, you aren't touching the port address registers.  Therefore, the value of ADDRSEL is irrelevant then.

`stz $9F25` is the best way to zero either bit -- the other bit doesn't matter, at that time.

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