CoCo MC6847 VDG chip “draw black” challenge

See also: challenge, responses, and more responses.

Updates:

  • 2022-07-05 – Updated with a second requirement and test program.

The 1980 Radio Shack Color Computer (and the Color Computer 2 revisions) used a Motorola MC6847 Video Display Generator chip. This video chip was used in a variety of other systems, and one can easily recognize it by its 32×16 text mode characters with the square letter “O”. I recently spotted it in a YouTube video by Atari Archives discussing the Atari VCS Hangman cartridge (see 5:04 if this direct link doesn’t work):

I was unfamiliar with the AFP Imagination Machine mentioned in the video, but CoCo Crew co-host John Linville confirmed it indeed used the same CoCo VDG chip. The “nuclear green” background color and blocky low-resolution “semigraphics” do stand out.

I also stumbled upon it in a list of unreleased Atari products. A company named Unitronics was planning an Atari VCS Expander System that would allow loading games from a built-in tape deck. In a screen shot for the device (which looked like a cassette player that plugged into the top of the Atari), the nuclear green CoCo screen can be clearly seen:

http://www.ataricompendium.com/game_library/unreleased/unreleased.html#unitronics

The screenshot in the first picture appears similar to that of Radio Shacks’ Color Computer – same color scheme and maximum of 32 characters per line.

http://www.ataricompendium.com/game_library/unreleased/unreleased.html

And, there was even going to be a conversion of the 1980 CoCo ROM-Pak Space Assault and a screen shot was used of the CoCo version

http://www.ataricompendium.com/game_library/unreleased/unreleased.html#spaceassault

The screenshot shown in a brochure for the Expander System (picture #1) is actually the Radio Shack Color Computer game Space Assault (picture #2).  The game was licensed to Tandy by Image Producers Inc. in 1981.  Perhaps Unitronics was going to license the game for the Expander.  If the game shown in the brochure is actually running on the Expander, that would mean the Expander used the same graphics chip as the CoCo – the MC6847 VDG chip.

http://www.ataricompendium.com/game_library/unreleased/unreleased.html

Until recently, I had no idea anything but the Radio Shack CoCo and MC-10s, as well as the UK’s Dragon computers (and, I guess, the French MC-10 clone, Alice) used the VDG chip.

64x32x8 … technically.

Ignoring using solid color character blocks in the 32×16 text mode, the lowest resolution graphics mode in the VDG was a 64×32 mode that could use 8 colors plus black. It did this by dividing each text block of the 32×16 text screen into a 2×2 graphics character. They weren’t true pixels, but instead where just characters made with all possible 2×2 variations in eight different colors. You could PRINT them using CHR$:

This reminds me of how the Commodore VIC-20 worked with its extended PETSCII character set, but instead of all the weird lines and shapes and card suit symbols, it was 2×2 graphics blocks with different colors. Much like the standard VIC-20 text mode, each text position could only contain one color plus black. Thus, while you could have eight colors on the screen, you could never have more than one color (plus black) in a character’s 2×2 block.

Rendering graphics in this mode was tricky, since you could not have more than a single color (plus black) in any 2×2 block.

In BASIC, you could set the top left pixel to yellow using:

SET(0,0,2)

…but you would see it would change all the other pixels in the 2×2 block to black:

CoCo SET command.

And if you tried to set two pixels side-by-side to different colors:

SET(0,0,2):SET(1,0,5)

…it would turn any other set pixel in that 2×2 block to the new color:

CoCo SET command. All pixels in a 2×2 block must be the same color. So there.

I am sure I learned this limitation when I first started playing with a CoCo in Radio Shack back in 1982.

Because of this “all pixels must be the same color” effect of the SET command, doing a random pixel plotting program…

0 REM 64x32.bas
10 POKE 65495,0:CLS 0
20 SET(RND(64)-1,RND(32)-1,RND(8)-1)
30 GOTO 20

…starts out as you might expect…

CoCo Random SET.

…but after awhile, every pixel has been set so new sets will change everything in that 2×2 block to the same color:

Random SET(x,y,c) after some time…

I know I wrote this program at that Radio Shack ;-)

Black is not a color

The early “Getting Started With Color BASIC” manual that came with the CoCo described the SET() command as being able to use the following colors:

  • 0 – black
  • 1 – green
  • 2 – yellow
  • 3 – blue
  • 4 – red
  • 5 – buff
  • 6 – cyan
  • 7 – magenta
  • 8 – orange

But that manual was a bit incorrect. While you can try to SET(x,y,0), you won’t get black. The SET() command treats 0 and 1 as the same green color.

In fact, from what I can see, there is no way to set just a black pixel on the green text screen other than setting all the other pixels in that 2×2 block to the background screen green (color 1).

0 REM setblack.bas
10 CLS
20 SET(1,0,1):SET(0,1,1):SET(1,1,1)
30 GOTO 30

I guess the SET() command was really designed to work on a black screen (CLS 0). In fact, when viewing the Color BASIC disassembly in the “Color BASIC Unravelled” book, I even see it checks for this specifically:

CHANGE COLOR NUMBERS FROM 0-8 TO (-1 TO 7)
BRANCH IF SET(X,Y,0)

It looks like they could have allowed it to support this, based on how the code checks what’s in the character initially. Maybe it was an oversight, or maybe it was just a lack of ROM space.

Regardless of the reason … I recently wanted to draw a black pixel on the green screen, and found doing so quite challenging.

The “draw black” challenge

Given a clear txt screen (CLS without any color), create a BASIC subroutine starting at line 100 that will plot a single black pixel using variable X and Y. Basically, make it act as if SET(X,Y,0) would actually set a black pixel like the BASIC manual implied.

It will be called like this:

10 CLS
20 FOR A=0 TO 31
30 X=A:Y=A:GOSUB 100
40 NEXT
50 GOTO 50

That above code would draw a diagonal black line from the top left of the screen down to the middle bottom of the screen.

To erase a pixel, we’d just use SET(X,Y,1) to place a green pixel there.

Is there a clever way to do this? Leave your efforts in the comments, or send them to me via e-mail.

UPDATE: Even more challenge

Some very clever solutions have been offered which solve the issue of drawing the diagonal line. But, can they also draw horizontal? One clever one was fast, but did not work for non-diagonals. Here is the second test program to try to make work:

Draw Black challenge, more challene.
10 CLS
20 FOR A=0 TO 15

30 X=A:Y=A:GOSUB 100
31 X=15-A:Y=16+A:GOSUB 100

32 X=40+A:Y=7:GOSUB 100
33 X=40+A:Y=24:GOSUB 100

34 X=39:Y=8+A:GOSUB 100
35 X=56:Y=8+A:GOSUB 100

40 NEXT
50 GOTO 50

Have fun!

31 thoughts on “CoCo MC6847 VDG chip “draw black” challenge

      1. MiaM

        What happens if you prefill the screen with CHR$(143)?

        (143 = 128 + 15, I assume that the green “graphics chars” are 128-143 given the screen dump you show)

        Reply
  1. MiaM

    Are you required to use the basic commands to set/clear pixels?

    If not you could use the print chr$ codes to output the appropriate “chars”.

    If the task is specifically to draw a diagonal line, nothing more and nothing less, you could even draw it by printing the char for one “dot”, do a short delay and then replace it with the char for two diagonal dots, and then loop to the next “char” position on screen.

    Reply
    1. Allen Huffman Post author

      I suppose it’s open ended enough that any approach would be allowed …. SET/RESET/POINT, POKE/PEEK, etc. the first submission used POKE/PEEK, and he also let me know a much simpler solution I was unaware of which solves the whole issue I was experiencing.

      Reply
  2. Jason

    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. Turns out the colors used four bits, three the determine which of the eight colors to show and the fourth bit for on or off. It’s too bad the fourth bit wasn’t light/dark instead of on/off. We could have had sixteen colors instead of just eight/nine with no extra cost in memory usage. Perhaps on/off instead of light intensity was easier to implement in the VDC, still a pity as it would have made the CoCo and all other machines with the MC6847 that much more colorful.

    Reply
    1. Allen Huffman Post author

      Is it 8 colors, and black, then? It’s a pity those modes were not put in BASIC back then. We’d have seen a much larger set of programs showing off those colors. I think we’ve had more demographics demos and games put out in the past year or so than during the original run of the computer.

      Reply
      1. Jason

        It might be because they were somewhat rarely used that the semi-graphics modes have become popular for tinkering with lately. Plus as you pointed out, most of the modes weren’t easily accessible from BASIC which only makes them that much more fun to play with now.

        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. The downside is that some of the color combinations on the four color PMODE screens are rather garish. Later graphic generators such as the GIME likely used lookup tables, which allowed for more pleasant colors.

        Had that fourth bit been used for luminance instead of simply black/color, we probably would have lost orange (the one CoCo color that’s not part of the NTSC color bars) but gained light and dark versions of the other seven colors. Plus we would have had black and a shade of gray. If I think about it this weekend, I might mock up what that would have looked like. The ultimate fun would be to alter the MC6847 emulation to enable this behavior but that’s a bit beyond my capabilities.

        Reply
  3. jimgerrie

    10 CLS
    20 FOR A=0 TO 31
    30 X=A:Y=A:GOSUB 100
    40 NEXT
    50 GOTO 50
    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

    Reply
  4. jimgerrie

    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

    Reply
  5. Pingback: CoCo MC6847 VDG chip “draw black” challenge responses. | Sub-Etha Software

  6. freed

    Hello
    I recently read about the vtech Laser 100/200 line in wikipedia and recognize the atomic green color we’re used to.
    Here is the quote from wikipedia:
    The VZ200 uses the Motorola 6847 video processor, which has a resolution of 256 × 192 pixels made from either 8 × 8 pixel character blocks in a 32 × 24 block screen, or a monochrome bitmapped mode.

    Reply
  7. Sebastian Tepper

    I think this is much faster and avoids unnecessary SETs. Instruction 100 will do the POKE only once per character block.

    10 CLS
    20 FOR A=0 TO 31
    30 X=A:Y=A:GOSUB 100
    40 NEXT
    50 GOTO 50
    100 IF POINT(X,Y)<0 THEN POKE 1024+Y*16+X/2,143
    101 RESET(X,Y):RETURN

    Reply
    1. Allen Huffman Post author

      I applaud you. And after testing, here’s a downside… if you try to draw a vertical line with this, I see it ends up setting the whole block. HOWEVER, changing it from A RESET to a SET appears to work for a vertical line, but then won’t work for the diagonal.

      Ugh.

      Reply
    2. Allen Huffman Post author

      Since you have an excellent solution to the specific challenge, let’s make it more challegning: (Article updated with this secondary program.)

      10 CLS
      20 FOR A=0 TO 15

      30 X=A:Y=A:GOSUB 100
      31 X=15-A:Y=16+A:GOSUB 100

      32 X=40+A:Y=7:GOSUB 100
      33 X=40+A:Y=24:GOSUB 100

      34 X=39:Y=8+A:GOSUB 100
      35 X=56:Y=8+A:GOSUB 100

      40 NEXT
      50 GOTO 50

      Reply
  8. Sebastian Tepper

    Ready! Slight correction to line 100 and voilá.

    0 CLS
    20 FOR A=0 TO 15
    30 X=A:Y=A:GOSUB 100
    31 X=15-A:Y=16+A:GOSUB 100
    32 X=40+A:Y=7:GOSUB 100
    33 X=40+A:Y=24:GOSUB 100
    34 X=39:Y=8+A:GOSUB 100
    35 X=56:Y=8+A:GOSUB 100
    40 NEXT
    50 GOTO 50
    100 IF POINT(X,Y)<0 THEN POKE 1024+INT(Y/2)*32+INT(X/2),143
    101 RESET(X,Y):RETURN

    Reply
    1. Allen Huffman Post author

      Wow, nicely done. So the concept is, if POINT returns -1, it’s not a graphics block. Then you set it to the green graphics block for the X,Y and use RESET. Do I have it?

      Reply
  9. Sebastian Tepper

    And for maximum speed you could change line 100 from:

    100 IF POINT(X,Y)<0 THEN POKE 1024+INT(Y/2)*32+INT(X/2),143

    to:

    100 IFPOINT(X,Y)<.THEN POKE&H400+INT(Y/2)*&H20+INT(X/2),&H8F

    To time the difference, I added these extra lines:

    15 TIMER=0

    and:

    45 PRINT TIMER

    This lowers execution time from 188 to 163 timer units, i.e., down to 87% of the original time.

    Reply
  10. Sebastian Tepper

    Of course!

    I forgot to delete the space between THEN and POKE, however I don’t think it will make a noticeable difference.

    Also, in doing speed tests about the number format I verified that using hexadecimal numbers was more convenient only when the numbers in question have two or more digits.

    Reply
    1. Allen Huffman Post author

      That is good to note. I seem to recall checking . versus 0 versus &H0 but I don’t remember the outcome. Pretty sure . was always fastest. That was one I never knew about until recent years.

      Reply
  11. Sebastian Tepper

    I sucseeded in a few ore optimizations:

    *** (1) “Canonic” solution to the problem
    *** I decided to keep blank spaces for clarity because their impact on speed is very small
    *** Execution time: 184 TU (timer units)
    10 CLS
    15 TIMER=0
    20 FOR A=0 TO 15
    30 X=A:Y=A:GOSUB 100
    31 X=15-A:Y=16+A:GOSUB 100
    32 X=40+A:Y=7:GOSUB 100
    33 X=40+A:Y=24:GOSUB 100
    34 X=39:Y=8+A:GOSUB 100
    35 X=56:Y=8+A:GOSUB 100
    40 NEXT
    45 PRINT TIMER
    50 GOTO 50
    100 IF POINT(X,Y)<0 THEN POKE 1024+INT(Y/2)*32+INT(X/2),143
    101 RESET(X,Y):RETURN

    *** (2) Avoiding PPOINT and using PEEK instead; auxiliary variable ‘M’ is introduced
    *** Contrary to what I expected, now it takes about 42% longer than the canonic case!
    *** Execution time: 261 TU (timer units)
    100 M=1024+INT(Y/2)*32+INT(X/2):IF PEEK(M)<128 THEN POKE M,143

    *** (3) Canonic solution with special zero “.” and hexadecimal constants
    *** Now this takes about 90% of the canonic solution
    *** Execution time: 165 TU (timer units)
    100 IF POINT(X,Y)<. THEN POKE &H400+INT(Y/2)*&H20+INT(X/2),&H8F

    *** (4) Let’s relax a bit since the POKE function truncates decimals anyway, so we can use X/2 instead of INT(X2)
    *** Now this takes about 86% of the canonic solution
    *** Execution time: 159 TU (timer units)
    100 IF POINT(X,Y)<. THEN POKE &H400+INT(Y/2)*&H20+X/2,&H8F

    *** (5) Let’s avoid the division in INT(Y/2)&H20 and use (Y AND &H1E)&H10 instead
    *** Now this takes about 82% of the canonic solution!
    *** Execution time: 151 TU (timer units)
    100 IF POINT(X,Y)<. THEN POKE &H400+(Y AND &H1E)*&H10+X/2,&H8F

    All spaces could be removed, except the one between “Y AND”, however this provides a marginal speed increase at the expense of clarity.

    Feel free and encouraged to use/repost/share this information.

    Reply

Leave a Reply to Allen HuffmanCancel reply

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