Jump to content
IGNORED

C64 BASIC - Quick color swap?


Herbarius

Recommended Posts

I'm doing some C64 project for fun again, and I run into some problem I couldn't figure out:

 

As we know, in text mode you can change the color of individual characters on screen by POKEing into the Color RAM (55296-56295). However, if you want to change the color of all the characters on screen and try something like this (line numbers omitted, N is the target color number):

 

FOR I=0 TO 999
POKE 55296+I,N
NEXT I

 

You'll notice it is extremely slow. It takes like 11 seconds for the whole screen. If you think you're smart and try checking every character first, and if it's a "space" (32) skip it, that won't help anything, it'll even make it slower. (Apparently there isn't a very big speed difference between PEEKing and POKEing, at least concerning these parts of RAM).

 

So I wondered, is this really the fastest way this can be accomplished? Think about it: In the time it takes to do this, the screen has refreshed more than 500 times! So I thought: Palette Swap? Is there some way to alter the internal color palette, maybe switch two of the colors, so the next time the screen refresehes it will come out as the other color, while in the Color RAM it still "looks" like the old color?

 

I am flicking back and forth through my Programmer's Manual, and I searched on the web, but I didn't come up with anything. Neither with a way to do it, nor some definitive statement that it's impossible.

 

So can anyone help me out here? Maybe it's without the reach of BASIC but can be accomplished with some machine code routine?

 

If it's impossible, exactly what's the reason? It doesn't seem logical that it can't be done.

 

 

EDIT: Oh, and yes I already tried "blanking" the screen during the operation via

POKE 53265,PEEK(53265)AND 239

, figuring that because it's manipulating what's currently on screen that slows it down, but it did only help marginally.

Edited by Herbarius
Link to comment
Share on other sites

It's my educated opinion that BASIC, especially BASIC written for any 6502 system, can't do anything quickly. Certainly not something like changing all of color nybble RAM.

 

Unfortunately, since there is only one screen of color nybble RAM available to the VIC-II, there really is no magic bullet to updating the entire screen that doesn't involve updating all 1000 locations. Fortunately, although updating that much memory takes a "little while" by machine language standards, it doesn't take anywhere NEAR as long as BASIC.

 

I don't doubt someone might come up with a better solution, but here's mine:

 

(where A = new color)
   ldy #$00
l1: sta $d800,y
   sta $d900,y
   sta $da00,y
   sta $db00,y
   dey
   bne l1
   rts

 

As somebody who is hip to the C64 will point out, this does of course write to unused memory at $dbe8-$dbff. Still, as machine language routines go, this one's pretty fast. All you need to do to implement it into BASIC then (I have no idea if you know how to do that, if you do, ignore this part), is to READ and POKE it into memory with the following DATA statements:

 

DATA 160, 0, 153, 0, 216, 153, 0, 217, 153, 0, 218
DATA 153, 0, 219, 136, 208, 241, 96

 

And then POKE memory location 780 with whatever color value you want, then do a SYS command where you POKEd the DATA into memory.

Edited by doppel
Link to comment
Share on other sites

Is it possible to change the memory location of strings in CBM basic, like what can be done with Atari Basic?

 

If so, define two strings, A$ and B$. Define B$ to be the color memory, then when you want to deal with it, set A$ = to the values you want, then do B$ = A$.

 

In Atari basic, there was a variable address table. It could be modified to have strings exist on the display screen. Scrolling and other fun little tricks were then possible just by assigning string values.

Link to comment
Share on other sites

It's my educated opinion that BASIC, especially BASIC written for any 6502 system, can't do anything quickly. Certainly not something like changing all of color nybble RAM.

 

Unfortunately, since there is only one screen of color nybble RAM available to the VIC-II, there really is no magic bullet to updating the entire screen that doesn't involve updating all 1000 locations. Fortunately, although updating that much memory takes a "little while" by machine language standards, it doesn't take anywhere NEAR as long as BASIC.

 

I don't doubt someone might come up with a better solution, but here's mine:

 

(where A = new color)
   ldy #$00
l1: sta $d800,y
   sta $d900,y
   sta $da00,y
   sta $db00,y
   dey
   bne l1
   rts

 

As somebody who is hip to the C64 will point out, this does of course write to unused memory at $dbf8-$dbff. Still, as machine language routines go, this one's pretty fast. All you need to do to implement it into BASIC then (I have no idea if you know how to do that, if you do, ignore this part), is to READ and POKE it into memory with the following DATA statements:

 

DATA 160, 0, 153, 0, 216, 153, 0, 217, 153, 0, 218
DATA 153, 0, 219, 136, 208, 241, 96

 

And then POKE memory location 780 with whatever color value you want, then do a SYS command where you POKEd the DATA into memory.

 

Wow, thanks! This works like a charm.

 

Even if I add the overhead of POKEing the procedure to RAM, it still does the trick in 0.2 seconds total! Compared to the 10-11 seconds with the pure BASIC approach that's wizardry! :D

Link to comment
Share on other sites

I have no doubt you'll prefer the machine code version,

but you should be able to improve the BASIC by taking

the constant evaluations and the redundant math

out of the loop.

 

Try this:

 

F=55296:L=56295:FOR I=F TO L:POKE I,N:NEXT

 

I don't recall how muti statement lines compare

speed wise to going to the next line, but I'd put

it all on one line just in case :)

 

Also I don't think you need to get the constant out of

the initial asignment of I, but I did that just in case too :)

Link to comment
Share on other sites

I have no doubt you'll prefer the machine code version,

but you should be able to improve the BASIC by taking

the constant evaluations and the redundant math

out of the loop.

 

Try this:

 

F=55296:L=56295:FOR I=F TO L:POKE I,N:NEXT

 

I don't recall how muti statement lines compare

speed wise to going to the next line, but I'd put

it all on one line just in case :)

 

I'm actually impressed by that... I expected only a minimal speed improvement by this, but it's gone from 11 seconds to 3.75! The machine code version is of course still much faster, but a improvement by like 66% is more than expected.

 

To answer your curiosity about the multi-statement lines: Yes there is a speed difference, little but it can add up. I tested with this same code as above, but each command into its own line. The result was 4.3 seconds to finish the loop, compared to the 3.75 above.

 

Well, I guess those are just some hints that something's seriously wrong with (CBM)BASIC... :D

Or to put it positively: There's lots of potential to optimize your (CBM)BASIC code today! ;)

 

Also I don't think you need to get the constant out of

the initial asignment of I, but I did that just in case too :)

Well, now that I think of it, shouldn't it be FASTER if you leave the constants in? [EDIT: Yes, it is.]

Edited by Herbarius
Link to comment
Share on other sites

 

Well, I guess those are just some hints that something's seriously wrong with (CBM)BASIC... :D

Or to put it positively: There's lots of potential to optimize your (CBM)BASIC code today! ;)

 

Also I don't think you need to get the constant out of

the initial asignment of I, but I did that just in case too :)

Well, now that I think of it, shouldn't it be FASTER if you leave the constants in? [EDIT: Yes, it is.]

 

I mucked it up some what.

I have seen BASICs where it appeared that the end value expression

was re interpreted each time through the loop, I couldn't remember if

the CBM BASIC was one of them.

However I'd expect to initialize the beginning and ending "constants"

near the beginning of the program and then just use the loop as needed.

 

As an aside on optimizing BASIC programs, it is (iirc) usually faster

to use a dummy FOR-NEXT loop than a GOTO if possible.

The FOR-NEXT remembers where it's supposed to go, the GOTO has to scan the

line list.

 

And there's lots of other stuff you can do.

A little Googling should turn up more.

 

Years ago I timed all that stuff on the VIC20

Some where I've got a compilation of times in "milli-jiffies"

No idea where it's gotten to now though :)

Link to comment
Share on other sites

  • 2 weeks later...

This might not work for you, but you could use the Reverse character set, and then change the color of all the text on the screen at once by changing the screen background color. You would need to fill in all the unused space on the screen with reversed blank characters to make this work.

 

Another possibility might be to use the Wait command to wait for the raster to reach the bottom line before the border, then switch the video ram to another 1K bank. Use the PRINT command to quickly print into this other RAM which will also write into color RAM. Then switch back to the original Screen RAM before the visible scanlines are drawn again.

 

5 Print "<HOME>"

10 For J = 0 to 23: REM Loop for each screen line.

20 WAIT <for raster>:POKE <change SCREEN RAM to unused mememory>:PRINT"<color char><40 spaces>":POKE<Switch back to Text video RAM>

30 NEXT

35 REM Don't print to last character of the screen or a scroll will occur.

40 WAIT <for raster>:POKE <change SCREEN RAM to unused mememory>:PRINT"<color char><39 spaces>":POKE<Switch back to Text video RAM>

 

Sorry I didn't provide real memory locations or parameter values, I don't have my reference books handy.

 

Cheers!

Link to comment
Share on other sites

Or one more option is that you could use ECM text mode where one of 4 background colours can be selected on a per character basis by using the top 2 bits of the character code to select it's background colour, and with inverting the character set you can essentially have 4 foreground colours coming from ($D021 - $D024) each selectable without any changing of colour RAM at all..

 

So:

0-63 use $D021

64-127 use $D022

128-191 use $D023

192-255 use $D024

The empty pixel colours come from the top 2 bits of the character code using the above registers, set pixels come from the colour RAM..

 

Just adding that for completeness of options available to you ;)

Link to comment
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.
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...