CoCo MC6847 VDG chip “draw black” challenge responses.

See also: challenge, responses, and more responses.

Recently, I was annoyed to find that there did not seem to be any way to set a black pixel on the CoCo’s normal green background. I have since been schooled in the simplest way to make this work, which I will share after a long digressing ramble.

Never the Same Color Twice

The CoCo’s MC6847 VDG chip provides nine colors. Commenter Jason wrote:

“It always bothered me that the CoCo had nine colors in semi-graphics modes. The number nine should raise a red flag for anyone who is familiar with computers and the tendencies for things to be powers of two.

“It’s interesting that seven of the eight colors are from the NTSC test pattern (https://en.wikipedia.org/wiki/SMPTE_color_bars) which leads me to believe they’re all a particular frequency distance from each other. This would make the circuitry simpler.”

– Jason

I suppose it’s actually eight foregrounds colors with a black background, which matches the black border of the screen. There was even a test pattern program included in one of Radio Shack’s quick reference guide that I still have:

Color Adjustment Test Display

5 FOR X = 0 TO 63
10 FOR Y = 0 TO 31
15 C = INT(X/8+1)
20 SET(X,Y,C)
25 NEXT Y,X
30 GOTO 30

That produces the following output, showing the eight possible colors (plus the black background):

Color Adjustment Test Display, Radio Shack TRS-80 Color Computer Quick Reference Guide, page 55.

And here is the NTSC test pattern Jason referenced:

By Denelson83 – Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1067498

This made me want to alter the program to make it render something with the matching colors in the correct order (and with the Xroar emulator set to not emulate a crappy 1980s RF modulated TV signal):

The 7 NTSC color bar colors that the CoCo produces.

The extra color that is not shown is orange. I wonder why those eight colors (plus black) were chosen? And what makes the colors used by the two PMODE high res graphics screens? I’ll have to revisit that in the future.

But I digress…

You can’t, even if you SET your mind to it

My original article was written because I noticed you couldn’t SET a black pixel on a normal CoCo text screen. Even though the manual listed nine colors, with zero being black, attempting to do SET(X,Y,0) would result in that pixel being set to the green background color instead of black — the same as SET(X,Y,1). While other colors acted as you expected…

CoCo SET command.

SET seemed to be treating color 0 (black) as 1 (green). Because reasons.

In order to SET a black pixel on the normal text screen, extra code would be needed.

Ciaran Anscomb

Xroar emulator author Ciaran Anscomb was the first to respond with his GOSUB routine to achieve the desired effects:

I mean I think you’re making it harder by asking for it to work with
plain CLS and not CLS1, but in that case:

100 IFPEEK(1024+INT(Y/2)*32+INT(X/2))<128THENPOKE1024+INT(Y/2)*32+INT(X/2),143
110 RESET(X,Y):RETURN

– Ciaran Anscomb

His method would PEEK the character value at the 2×2 block that was being SET and, if that value was less than 128, it would change it to 143 and then use RESET… And it works:

10 CLS
20 FOR A=0 TO 31
30 X=A:Y=A:GOSUB 100
40 NEXT
50 GOTO 50
99 ' Ciaran Anscomb
100 IFPEEK(1024+INT(Y/2)*32+INT(X/2))<128THENPOKE1024+INT(Y/2)*32+INT(X/2),143
110 RESET(X,Y):RETURN

Jim Gerrie

BASIC programmer extroidinaire Jim Gerrie provided his take on this routine:

100 SET(X,Y,1):SET(X-(X/2-INT(X/2)=.),Y,1):SET(X-(X/2-INT(X/2)=.),Y-(Y/2-INT(Y/2)=.),1):SET(X,Y-(Y/2-INT(Y/2)=.),1)
101 RESET(X,Y):RETURN

– Jim Gerrie

His version sets some pixels to color 1, and some to color 0 (using the “.” shortcut), based on some math with X and Y and divisions and integer conversions and … well, stuff I don’t grasp.

His also works! But as it draws, you can see it blipping surrounding pixels in the 2×2 block on then off. And while it passes the test case which drew a diagonal line, it doesn’t allow for setting arbitrary pixels near each other. They turn into full blocks.

However, he also added a second attempt:

I know that my first suggestion above is a bit of a cheat. Here’s a more robust suggestion:

10 CLS
20 FOR A=0 TO 31
30 X=A:Y=A:GOSUB 100
40 NEXT
50 GOTO 50
100 IFPOINT(X,Y)<.THENXX=(X/2-INT(X/2)=.)-(X/2-INT(X/2)>.):YY=(Y/2-INT(Y/2)=.)-(Y/2-INT(Y/2)>.):SET(X,Y,1):SET(X-XX,Y,1):SET(X-XX,Y-YY,1):SET(X,Y-YY,1)
101 RESET(X,Y):RETURN

– Jim Gerrie

This version passes the test as well, and looks like it better handles setting pixels at any position without impacting pixels around it.

What’s the POINT?

Ciaran made use of PEEK to detect what was on the screen before adding something new, and Jim figured out what pixels to set back to the background color. Neither did it the way I was expecting — using POINT:

POINT (X,Y) Tests whether specified graphics cell is on or off, x (horizontal) = 0-63; y (vertical) = 0-31. The value returned is -1 if the cell is in a text character mode; 0 if it is off, or the color code If it is on, See CLS for color codes.

IF POINT(10,10) THEN PRINT "ON" ELSE PRINT "OFF"

I expected I’d see folks use this to see if a pixel was set, and handle accordingly. Somehow. But as I read this description (from the Quick Reference Guide), I see that note that says “The value returned is -1 if the cell is in a text character mode.”

Text character mode? It’s just the background, isn’t it?

All green backgrounds are not the same

And that takes me back to Ciaran’s code:

IF PEEK(1024+INT(Y/2)*32+INT(X/2))<128 . . .

Less than 128 is a text character. The graphics blocks (2×2) start as 128. If the square is a text character then set it to 143. So what is that? That is a 2×2 graphics block that has all pixels set to the green color. And that green color is the same color as the background screen. Which isn’t 143 when you use CLS. Try this:

CLS:PRINT PEEK(1024)

If you clear the screen then PEEK to see what value is at the top left character (1024), it returns 96. 96 is the space character (yeah, ASCII is 32, but values in screen memory aren’t ASCII).

Ciaran’s code sees if it’s anything (including that green space), set it to 143, which is a green block that looks the same. Try this:

CLS 1:PRINT PEEK(1024)

That will print 143. Yet, visually, CLS and CLS 1 look the same. But, CLS is filling the screen with the space text character (96) and CLS 1 fills it with the green graphics character (143)! CLS 0-8 fill the screen with solid graphics characters, and CLS with no parameter is the space.

Now, I knew about character 143 looking like the normal space but not being one, because we used to use this as a cheap “copy protection” method. On DISK, you could save out a file like this:

SAVE "HELLO.BAS"

…and you’d get a file on BASIC called HELLO.BAS. But, if you did this:

SAVE "HELLO"+CHR$(143)+".BAS"

…Disk BASIC would write out a file called HELLO(char 143).BAS. When you did a DIR they would look the same, but you couldn’t do a LOAD”HELLO.BAS” to get the one with the CHR$(143) in it. Unless you exempted the disk directory bytes you would not know there was an “invisible” character at the end of the “HELLO” filename.

Sneaky. And I did this with some of my own programs.

But years later, when the CoCo 3 came out, it’s 40 and 80 column screen did NOT support the 2×2 graphics block characters, and this trick was no longer as sneaky since you would see “HELLO(some funky character).BAS” in the directory listing and know something weird had been done.

But I digress, again…

Why do it the hard way, anyway?

It turns out, even though I knew about the “add CHR$(143)” trick, I had forgotten (or never knew/realized) that CLS and CLS 1 filled the screen with different characters. And, if the screen has a graphics character at the position, RESET will then work to change that pixel back to black.

Ciaran got me exploring this because in his e-mail he added:

If you allow CLS1, the problem solves itself :)

– Ciaran Anscomb

I had to follow up and ask what he meant by this. And, well, nevermrind, then. All I needed to do was start the program with CLS 1 instead of CLS 0, and then I could use RESET() to set individual black pixels on the screen.

I could have a subroutine that expect X, Y and C (for color) and if the color was 0 (black), do a RESET, else do a SET:

0 REM RESET
10 CLS 1
20 FOR A=0 TO 31
30 X=A:Y=A:C=0:GOSUB 100
40 NEXT
50 GOTO 50
100 IF C=0 THEN RESET(X,Y) ELSE SET(X,Y,C)
110 RETURN

And that works fine on any CLS 0-8 screen. Remember, SET(X,Y,0) never gives you a black pixel. 0 seems to mean “background color” instead, while RESET(X,Y) seems to mean “set to black”.

To me, this is a bit counterintuitive, since today I would expect “reset” to mean “set to background color” but this isn’t a graphics mode — it’s just graphics characters on a screen, so the only way BASIC could have done this is if it remembered what the CLS # value was, and made RESET set to that color. Which would be extra ROM space for a simple enhancement that most could work around with RESET instead.

And that, my friends, is how a rabbit hole works.

Until next time…

7 thoughts on “CoCo MC6847 VDG chip “draw black” challenge responses.

  1. William Astle

    If I’m reading the ROM code for SET correctly, the zero colour means “use whatever colour the grahpics blocks already are”. If it isn’t a graphics block, it uses hardware colour 0 (which is colour 1 as far as SET understands it). This seems to match with my very quick experimentation.

    Reply
  2. Brian H

    I wonder if they were just maintaining compatibility with the BASIC on the TRS-80 Model 1/3. On those machines, SET had no ‘c’ variable, and RESET very intuitively turned the semi-graphics pixel back OFF. I wonder if such programs run as expected on the Coco without changes to add a third variable to calls to SET.

    Reply
  3. jimgerrie

    I recall using SET(X,Y,0) in a number of programs. It is useful to be able to set a point to the color already being used in a particular character block. For even more speed use SET(X,Y,.). I always think of SET(X,Y,0) as “set to existing colour”.

    Reply
  4. jimgerrie

    I use the SET(X,Y,0) feature to advantage in my Caveraid game. The falling “drips” fall from the top, but pass through the purple rock until they emerge into the passage area. There they take on whatever color the black areas are which they pass through, which are laid out in various patterns for the various levels. Red drips are dangerous and green, blue and yellow provide points, but the same routine in the tight main loop is used for all of them. All that changes is the kind of “black” blocks of the predefined backgrounds they pass through.
    https://youtu.be/T7udmyJxW28

    Reply

Leave a Reply to Allen HuffmanCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.