[ home ]

RC2018/09 (RetroChallenge, September 2018): info-animation for the HomeComputerMuseum

This page describes in some detail my effort for the Retro Challence 2018/09 event.

TL;DR = make an informational demo/intro/animation for the HomeComputerMuseum in Helmond (.nl). running on a Commodore 64 ("C64"). The demo-program will be hosted on some sort of EPROM/EEPROM/flash cartridge.


Background: HomeComputerMuseum, and why this mini-project

The HomeComputerMuseum is an interactive computer-museum in the center of Helmond, in the south-east of the Netherlands, opened in 2017.

The museum is located on a street with fairly much pedestrian-traffic, but it's possible to walk by without even knowing what is there, or knowing what the museum is all about.

Since a number of spare C64s + monitors are available, it is perhaps a good idea to place one behind the window facing the passers-by, running some sort of attract-screen in the form of a flashy demo/intro. (Colours, logo, movement, pictures, text.) The idea is to capture the attention of pedestrians, and give them a quick idea of what they can find inside.

The C64 can run ROM-cartridges plugged into its cartridge-port. The idea is to put the attract-screen code on some sort of mini-cartridge, so the C64 will display it automatically at power-on. The cartridge-hardware can be something existing or homebrew (EEPROM/flash + PCB).

The attract-screen code will be made in 6510/6502 assembly, and will be at most 16 kb in size (the largest program-size a simple cartridge can host). It will contain flashy graphics to catch peoples attention, but won't contain sound.

What am I planning to do for RC2018/09?

Right now, there exists nothing, except some level of 6502-clue in my head. I don't have any cartridge-hardware yet.

So, my plan for RC2018/09 is to...

Right now this is all pretty vague, so expect the above list to change along the way.

Progress & status (in chronological order)

2018-09-05: status at the start of RC2018/09

There is nothing yet! I'll be busy with work for the coming 2 weeks, so expect me to not start before half of September. Don't cry yet.

2018-09-08: preparation and some decisions

TL;DR = decided to use script-generated PPM-pictures to prototype simple visual effects, and to use a stripped-down version of the Bait-a-Cart C64 cartridge-adapter to make the final demo-code available to the C64 as a plug-in cartridge.

Cartridge-hardware: use stripped-down Bait-a-Cart

I briefly looked around to see whether a C64 EEPROM/flash cart able to host custom code was available, but the existing solutions were either too much overkill or too expensive to just stick into someone elses C64 and leave it there forever. ;-)

For the previous RetroChallenge, I already made firmware for a C64 Bait-a-Cart C64 cartridge-adapter.

Although the final result had some serious hardware-flaws, it can mimic a normal ROM-cartridge quite well - this basic behaviour is not affected by any of the flaws listed. Yay.

Since the relatively big microcontroller on the Bait-a-Cart (AVR, ATmega640) has lots of flash-memory on board, the simplest way to go, I think, is to...

  1. code the C64-demo
  2. convert this C64-binary either to object-code or C-style constants to be baked into an microcontroller-firmware
  3. flash this firmware into a stripped-down Bait-a-Cart cartridge
  4. on boot, the Bait-a-Cart copies - if necessary - the C64-binary to its parallel flash
  5. the C64 is taken out of reset, and runs demo-code from the Bait-a-Cart's parallel flash

(This approach is a bit cumbersome, but avoids serial communication to the host-PC, which is... a bit broken and would require soldering/rework. I expect to have to do this only a few times, since the C64-demo can be fully tested in an emulator instead of on real hardware.)

Prototyping visual effects: use script-generated PPM-bitmaps

The C64-demo will mainly consist of graphical effects.

Today's availability of cross-development tools have made C64-programming much easier than it once was, at least for me. However, having to code a visual effect in 6510-assembly just to see if it looks nice or not, can be a timesink.

Therefore, I would like to use generated PPM bitmaps/frames in combination with ImageMagick's convert to make animated GIFs out of separate frames.

The advantage - for me - of using PPM, is that an picture can be hand-crafted or generated from text-utilities / shellcode extremely easy - a picture is readable plaintext.

Using the C64's actual colour-palette

For the C64's 16-colour palette, I found these RGB-values somewhere on the web a while ago (sorry, forgot where):

                         R   G   B
     0 / black      :    0   0   0
     1 / white      :  255 255 255
     2 / red        :  136   0   0
     3 / cyan       :  171 255 239
     4 / purple     :  204  68 204
     5 / green      :    0 203  85
     6 / blue       :    0   0 170
     7 / yellow     :  238 238 118
     8 / orange     :  222 136  85
     9 / brown      :  102  67   0
    10 / pink       :  255 119 119
    11 / darkgrey   :   51  51  51
    12 / midgrey    :  119 119 119
    13 / lightgreen :  170 255 102
    14 / lightblue  :    0 136 255
    15 / lightgrey  :  187 187 187

They look like this:

If interested, this is the same palette for use in the GNU Gimp program:

    GIMP Palette
    Name: C64_bright
    Columns: 0
      0   0   0	Untitled
    255 255 255	Untitled
    136   0   0	Untitled
    171 255 239	Untitled
    204  68 204	Untitled
      0 203  85	Untitled
      0   0 170	Untitled
    238 238 118	Untitled
    222 136  85	Untitled
    102  67   0	Untitled
    255 119 119	Untitled
     51  51  51	Untitled
    119 119 119	Untitled
    170 255 102	Untitled
      0 136 255	Untitled
    187 187 187	Untitled

(I guess you can drop this into ~/.gimp-*/palettes/)

Sample code to generate a simple PPM-bitmap

To generate the picture below containing the full C64 colour-palette...

...the following shellcode can be used:

    #!/usr/bin/env bash
    . ../common.inc
    writeHeader $[ ( $BARHEIGHT + 1 ) * 16 ]
    for colour in $( seq 0 15 ); do
        writeLines $colour $BARHEIGHT
        writeLine $WHITE

(A "line" in this context means "C64 rasterline", i.e. a 1-pixel high horizontal line spanning the whole screen.)

This script makes use of "common.inc" given verbatim at the end of this page, containing some utility-functions and palette-definitions.

Simple shell-generated animation: rotating 4-sided bar

Using a script "animate_bar" repeatedly calling script "paint_bar", PPM-pictures of a rotating horizontal bar are generated, and combined into an animated GIF-picture:

(Both scripts are given verbatim at the end of this page.)

2018-09-09: deciding on a composition

TL;DR = visual composition will consist of a logo- and text-area, separated by a spacer (the rotating bar from a previous post).

Overall idea

Since the animation would normally be viewed from a few meters away by passers-by, it probably makes sense to show relatively large effects instead of itty gritty details.

So, what I would like to do, is to divide the screen into logo- and text-area, separated by a horizontal spacer (e.g. the rotating bar from a previous post). Impression:

The numbers on the right indicate height of that area, in characters. The screen-boundary is indicated by a grey rectangle - beyond that is the border. I am not clued enough, and also too lazy, to place anything other than raster-graphics there. (The grey rectangle as well as the orange ones will of course not be shown in the actual demo.)

The logo would swing left to right and up and down inside the orange rectangle around the logo, and the spacer would rotate and swing up/down, inside the lines above and below the spacer.

To make it a bit less boring, top- and bottom-halves (logo and text) would occasionally exchange place due to some transition-effect.

The logo will consist of a monocolour-rendering of the museum's logo seen at the top of this page:

Size is 200x48 pixels, or 25x6 characters. (A character on the C64 is 8x8 pixels in size.) Rounded border and letters of the logo, shown here in pink, could be displayed in different colours, or could go through some fade-in/-out effect.

The coloured bars will probably be done using 5 double-width sprites (48 pixels each), so they can wobble around a bit inside the logo.

2018-09-10: pixeled a vanilla 2x2 charset

Well... an unspectacular charset for displaying informative text:

At least it's readable. (Background-colours just to show char-boundaries - will be gone in the final result.) This pic is made in GNU Gimp. I'll use a Ruby-script to convert it to charset-data.

2018-09-12: made text-decoration drawings and emergency-plan

TL;DR = pixeled some small retro-related bitmaps, and made a priority-list in case I run out of time to finish everything before the end of September...


To make the text-area of the demo a bit less boring, I made the following drawings. They are approximately 40 characters (320 bytes) each.

Something resembling a C64 breadbox:

Classic Mac:

A nice compact cassette tape (if you don't remember these, you missed out on so much):

Demo-effect priorities / emergency-exit

So... we're almost halfway in, and I'm nowhere near halfway done.

PANIC!!! :-)

To increase the likelyhood I will actually finish something around the end of September, let's order all intended demo-effects according to necessity. From "vital" to "meh":

  1. museum-logo moving around
  2. rotating bar
  3. several pages with text (no pictures) in text-area
  4. add pictures to text-area
  5. colour-bars inside logo moving on their own
  6. smooth screen-transition to swap logo- and text-areas
  7. colour-shine effect along the edge of the logo
  8. use moving colour-effect for letters in text-area
  9. more interesting motion-/rotation-patterns, e.g. using combination of sines

Something like that. Probably makes little sense when reading it in a boring list like this - we need pictures!

Hardware-part of the demo (i.e. getting it into a physical cartridge) needs to be done no matter what. I still have 1 PCB left over from RC2018/04, and just ordered components, so nothing can possibly go wrong there (...) - PCB-assembly will probably happen somewhere this weekend.

2018-09-15: assembled and tested cartridge-board

TL;DR = populated leftover Bait-a-Cart PCB and tested it in an actual C64 with minimal cartridge-code

Assembling a crippled Bait-a-Cart board

Placed only necessary components onto a Bait-a-Cart PCB, and omitted some components (purple areas) that weren't necessary to host a single cartridge-image:


Shown is the underside of the PCB.

This is serious overkill for what could have been an EEPROM-/flash-board BTW.

A minimal ROM-image

To test this thing in an actual C64, I used a simple loop toggling the background colour, namely the "minicart" code ripped out of the original Bait-a-Cart source:

    * = $8000
            .word Start                     ; cold-start vector
            .word Start                     ; warm-start vector
            .byte $c3, $c2, $cd, $38, $30   ; "CBM80"
            lda #4 
            sta $d020
            lda #0
            sta $d020
            jmp Start
    * = $9fff                               ; fill
            .byte $0

Or if you prefer hex/pain:

    0x09, 0x80, 0x09, 0x80, 0xc3, 0xc2, 0xcd, 0x38, 0x30, 0xa9, 0x04,
    0x8d, 0x20, 0xd0, 0xa9, 0x00, 0x8d, 0x20, 0xd0, 0x4c, 0x09, 0x80,
    0x00, ...



Since I gave away all of my C64-stuff a while ago, I had to actually go to the HomeComputerMuseum to test this. It worked straight away, so I was happy. Forgot to take a picture, but here's a VICE screenshot:

Oh BTW, on the Bait-a-Cart page, I was wondering why VICE had apparently already sort of enabled the video before cartridge-code was started, shown by a black inner screen like this:

Turns out that using x64sc (accurate C64 emulator) instead of x64 (fast C64 emulator) fixed this. (The black inner screen is not present when running this code on real hardware.)

2018-09-18: change blog to chronological order (yay!)

If you found this text, I guess you know this page (now) gives progress in chronological order, because it probably makes more sense - at least in my head.

2018-09-21: at least some code, planning and regaining clue

TL;DR = no actual work done except writing some minimal code, deciding on memory-layout and re-reading how VIC II banks worked again

Ok... brain violently protested against actual RC-work being done, so here we are - some more fluffy background-/meta-info.

More silly graphics, and fitting everything into 1 charset

Behold, a floppy. Not quite that retro, but it will do, I guess.

(Pictures like this are meant to occur within the info-text half of the screen, and make it look a bit less boring.)

So far, we have (width and height given in 8x8-pixel characters)...

The maximum number of characters per picture is thus 40.

Overall, the demo should show a logo and a big 2x2 font adorned with small pictures like the floppy above. (Pictures of these are shown in a previous post.)

I would like textmode and custom character-set(s) instead of bitmap, mainly to save on size. Doing the math to see how many characters would be used in total:

...we can conveniently fit everything into 1 charset (256 chars):

    logo            58
    big font       154
    whitespace       1
    picture-slot    40
                  ----- +

Lo and behold, we even have 3 characters free. What a waste.

So, by copying 40-char-max pictures into a reserved slot within a single charset - when requested during runtime - we can stuff everything into 1 charset. Is this really an advantage? Hardly, but that's just what I wanted to do now. (Can save a tiny bit of work during debugging, bitmap-conversion and programming.)

Furthermore, we could get rid of one 40-character picture. This would leave 3x40 = 120 chars, or 960 bytes for picture-data. Since this is conveniently almost 1 kb, we could layout charset (2 kb), screenchar-memory (1000 bytes) and picture-data as follows:

     $4000:  screenchar-memory   (1000 bytes)
     $4400:  picture-data        (960 bytes)
     $4800:  charset             (2 kb)
    ($5000:  writable data)

(Screenchar-memory needs to be aligned on 1 kb boundary, and charset needs to be aligned at 2 kb boundary, so it all fits nicely.)

Choosing a memory-layout

To be honest, I forgot how the C64 / VIC II handles memory, so I had to re-read this from existing code. was helpful to show which of the 4 selectable VIC-banks corresponded to which memory-regions, with which quirks (picture from their site):

As can be seen, VIC bank 1 ($4000-$7fff) is nice, since it doesn't have a copy of the C64's ROM charset and sits conveniently outside of the ROM-cartridge space ($8000 onwards). So let's use bank 1, at $4000, not just for graphics but all writable data too.

Copying data-region from ROM to RAM upon start

This is not rocket-science. In my previous Bait-a-Cart C64 software, I specified logical (runtime-) address for data to be in the $4000 area, while the ROM-image including code was sitting at $8000. This allowed the code to copy parts of its own image to RAM upon start:

I use 64tass as assembler, for which I wrote a quick reference earlier. </plug>. Using the .logical....here directive, you can use different runtime- and assembly-time locations for emitted code and data:

    VIC_BANK_BASE = $4000
    * = $8000
    .dsection code              ; All code-sections are emitted from $8000 onwards.
    DATA_ROM_START = *          ; Remember start of data-in-ROM-image region to be able to copy this to VIC_BANK_BASE ($4000) at program start.
    .logical VIC_BANK_BASE      ; Runtime-address for data-in-ROM is at VIC_BANK_BASE ($4000).
    .dsection data
    DATA_ROM_END = *            ; Remember end of data-in-ROM-image region to be able to copy it at program start (see above).

Some code, finally

Right, this is all I did for now - simple code to verify the correct VIC-banks are selected.

Looks like garbage? Yes, that's right. To be continued, hopefully.

2018-09-30: UH-OH! Time's up!

There's no way I'm gonna finish this project in time for RC2018/09. What I want to do is continue with it, and perhaps add some snapshots of progress below this line - the Line of Shame.

Or else, make a YT-video of the result. Or else, do nothing.


Appendices: code

"common.inc": shell-include for generating PPM-bitmaps

        "  0   0   0"
        "255 255 255"
        "136   0   0"
        "171 255 239"
        "204  68 204"
        "  0 203  85"
        "  0   0 170"
        "238 238 118"
        "222 136  85"
        "102  67   0"
        "255 119 119"
        " 51  51  51"
        "119 119 119"
        "170 255 102"
        "  0 136 255"
        "187 187 187"
    function writeLine () {
        for i in $( seq $IMGWIDTH ); do  echo -n "${palette[$colour]} ";  done
    function writeLines () {
        if [ $N -gt 0 ]; then
            for i in $( seq $N ); do  writeLine $colour;  done
    function writeHeader () {
        echo "P3"
        echo "$IMGWIDTH $imgheight"
        echo "255"

"paint_bar": shell-script to draw a 4-sided horizontal bar, rotated by a given angle

    #!/usr/bin/env bash
    # This script takes as arguments an angle in degrees [0..90) and 2 colours, and 
    # generates a picture showing a horizontal 4-sided bar, rotated around its axis
    # by the given angle. 
    # The 2 colours given are applied to the "front-/top-facing" and "bottom-/front-facing" 
    # sides of the bar, to allow for some sort of shading-effect.
    . ../common.inc
    if [ $# -lt 3 ]; then  echo "expect 3 args"; exit;  fi
    RAD=$( echo "$ANGLE * 3.14159 / 180" | calc -p | tr -d \~ )
    TOPFACEHEIGHT=$( echo "round( $BARSIDELENGTH * cos( $RAD ) )" | calc -p | tr -d \~ )
    BOTFACEHEIGHT=$( echo "round( $BARSIDELENGTH * sin( $RAD ) )" | calc -p | tr -d \~ )
    ABOVEBARHEIGHT=$( echo "( $IMGHEIGHT / 2 ) - round( ( $TOPFACEHEIGHT + $BOTFACEHEIGHT ) / 2 ) - $SPACERHEIGHT" | calc -p )
    function writeSpacer ()   { writeLines $SPACERCOLOUR $SPACERHEIGHT; }
    writeHeader $IMGHEIGHT

"animate_bar": shell-script to make an animation out of still picture-frames of a horizontal rotated bar

    #!/usr/bin/env bash
    . ../common.inc
    rm *.ppm *.png *.gif
    echo "generating frames..."
    ./paint_bar  0   $CYAN   $PINK   > 00.ppm
    ./paint_bar  15  $CYAN   $RED    > 01.ppm
    ./paint_bar  30  $WHITE  $RED    > 02.ppm
    ./paint_bar  45  $WHITE  $RED    > 03.ppm
    ./paint_bar  60  $WHITE  $PINK   > 04.ppm
    ./paint_bar  75  $CYAN   $PINK   > 05.ppm
    ./paint_bar  0   $YELLOW $LBLUE  > 10.ppm
    ./paint_bar  15  $YELLOW $BLUE   > 11.ppm
    ./paint_bar  30  $WHITE  $BLUE   > 12.ppm
    ./paint_bar  45  $WHITE  $BLUE   > 13.ppm
    ./paint_bar  60  $WHITE  $LBLUE  > 14.ppm
    ./paint_bar  75  $YELLOW $LBLUE  > 15.ppm
    echo "animating..."
    convert -delay 6 -loop 0 $( ls *.ppm | sort -n ) out.gif