A 6 byte Commodore 64 Demo

What if I told you ... 7e 00 8d 20 d0 50 is a Commodore 64 demo

If you thought my last post about a 32 byte (plus 2 byte load address) Commodore 64 demo was esoteric, wait until you burrow into this one.

Back in March at Lovebyte I released a C64 demo that is a total of 6 bytes. I contrived this one so that the 4b of code ends up overwriting part of a zero-page routine that runs every time RETURN is pressed. The effect is a pulsing pattern on the border. (You can just as easily make the screen pulse, which I personally find less aesthetically pleasing because the pulsing in that case happens over any text that is on the screen. It’s also a bit more eye watering and more likely to trigger seizures.) While it’s a very simple effect, I don’t know of any demo at all for this platform that has this file size or any smaller one. Some extensive trickery was involved in injecting my code into existing memory contents to produce this effect.

You can download the demo, NONMONOCHROME.

For my several readers who enjoy reading 6502 assembly, here’s what I did:

; 6b C64 demo (2b header + 4b)
; by nom de nom/TROPE

; RETURN to begin.
; This demo loops about every 1.45 seconds (on an NTSC
; machine).
; Holding down a key while this runs will produce an extra
; effect.
; RUN STOP - RESTORE will stop the program, but as soon as
; RETURN is pressed the demo will just start again. To
; restore normal function, it's necessary to power-cycle
; the C64.

.outfile    "nonmonochrome"

.word $007e  ; Wedge the code into CHRGET on the zero page.
.org  $007e  ; Note that CHRGET itself begins at $0073.

sta $d020    ; Set the border color with whatever's in the
; accumulator. The value varies as the code from $73
; through $7e runs. It oscillates between black and white
; for one phase and colorful for another phase. A detailed
; explanation of why is provided below.

.byte $50    ; This makes the next instruction bvc, clobbering
; $20. The following value in memory, $f0, had been used as
; beq. $50 $f0 = bvc $73, which (infinitely) takes us back to
; the beginning of CHRGET at $0073.

; A disassembly of CHRGET, left, and how it's been modified,
; right:
; .org  $0073                 .org  $0073
; chrget   inc txtptr         nonmono  inc txtptr
;          bne chrgot                  bne chrgot
;          inc txtptr+1                inc txtptr+1
; chrgot   lda                chrgot   lda
; txtptr   .word $0207        txtptr   .word $0207
; pointb   cmp #$3a                    cmp #$3a
;          bcs exit                    sta $d020
;          cmp #$20                    bvc nonmono
;          beq chrget
;          sec
;          sbc #$30
;          sec
;          sbc #$d0
; exit     rts

; CHRGET keeps increasing TXTPTR until it reaches the end of
; whatever BASIC input it's reading -- whether in immediate
; mode or when reading a BASIC program.
; NONMONO, however, loops forever and keeps increasing TXTPTR
; until it overflows past $ffff back to $0000.
; Because of the LDA TXTPTR, the accumulator is being
; consecutively loaded with each of the bytes in the C64's
; 64kb of accessible RAM and ROM. Then, after the CMP
; (which does nothing but slow the demo down by two cycles
; per loop), the contents of the accumulator are stored
; so as to set the border color.
; A large region of the C64's memory has $0 or $1 as the
; low nibble -- at least at power on, with no BASIC program
; loaded. Thus, black or white. Then, another large region
; (including ROM and the zeropage) has more "interesting"
; contents which manifest themselves as colors.

My demo was also taken up as an object of discussion in the first 7 minutes and 30 seconds of this YouTube video, where some of this explanation is provided as the demo runs on a C64c. This a later model of the Commodore 64, not the system I used in testing it, so the pulsing effect is slightly different. Among other things, my name for the demo, NONMONOCHROME, makes less sense when it’s running on this computer!

It could be an interesting challenge for others to try writing a Commodore 64 demo of only 6 bytes total, or of fewer bytes. For reasons I’d be glad to discuss, it seems to me that injecting the code into some productive context (an existing routine such as CHRGET or elsewhere in memory) is the only workable approach.

C64 Coding Under (Many) Constraints

Screenshot from Tyger Tyger; black and white border, scattering of orange and black characters on blue

Yesterday I wrote a little demoscene production, an intro, called “Tyger Tyger.” It’s a Commodore 64 machine language program with 32 bytes of code and the requisite 2 byte header, found on all C64 PRG files. It only garnered third place out of five entries in the 256b compos at @party 2021, behind two impressive entries that were for a different platform (DOS) and went to the limit of allowable code (eight times as much).

I wrote this intro under a formal constraint (32 bytes of machine language code) and several process constraints. Specifically, I wrote it all yesterday, mostly on a Amtrak train, finishing up the sound once I got to the party itself in Somverville. I also exclusively used a hardware Commodore 64 running Turbo Macro Pro v1.2, rather than cross-assembling the code on a contemporary computer and testing it on an emulator. To be specific, I used an unofficial hardware version of the Commodore 64 called the Ultimate 64, which is a modern FPGA implementation of Commodore’s hardware—not, however, an emulator. I placed a SID chip (a 6581) in the machine, so the only analog component that would otherwise need to be emulated was an authentic original.

Writing the code exclusively on the train provided me with some additional challenges, because the power kept cutting out and my system (which has to be plugged into AC power) shut off each time.

I’d never used any version of Turbo Macro Pro before, neither the C64 assembler nor TMPx, the cross-assembler. I figured out the basics of how to use the editor and learned the syntax the assembler used. It’s quite an excellent piece of software—thanks, Style!

And tremendous thanks to Dr. Claw, who put on a safe, responsible, demoparty—masks required when not eating, full vaccination required for all. It was a tiny one, yes, but it was a party! The event continues the important social and artistic traditions of the North American demoscene.