Cramming a C64 BASIC program into 32 bytes (and my 23 byte version)

Here's a video showing how someone crammed a BASIC program into 32 bytes:

0 PRINTMID$("XXXX-|",RAND(0)*6+1,1);:GOTO

https://www.youtube.com/watch?v=oPtjcSsS2MI

Normally this would save to a 35 byte file, but certain tricks and a possibly dubious assumption (that works on emulators but not necessarily real hardware) shave off a few bytes.

Anyway, inspired by this I crammed my own version into only 23 bytes using machine code instead of BASIC. I had never written an autostarting prg so that was an interesting learning experience.

There are a few ways to autorun, but most require a lot of bytes of boiler plate. In order to cram my version into 23 bytes, I had to figure out a method that I eventually reduced to zero bytes of boiler plate (by reusing bytes that would become part of my lookup table). This stack overwrite method involves locating the program on the 6502 stack, such that it overwrites the pending JSR return address. I had to figure out how to ensure both of these bytes would be non-printing character codes. Furthermore, the program requires calling the CHROUT routine, meaning it would ALSO be pushing an address onto the stack. I needed this address to also consist of non-printing characters.

I also saved a byte by finding some place in zero page guaranteed to have a pointer I could use for an indirect table lookup (one byte zero page address indirect lookup rather than two byte address direct lookup). That was a crazy wild goose chase, but I did eventually find a couple bytes guaranteed to have 255, 0 in them. At that point, all I needed to do was refactor things to generate 248...255 randomly rather than 0...7 randomly.

So basically, I started off with something I fit in 27 bytes, with reasonably elegant comprehensible code. And then I shrunk it down to 23 bytes with increasingly obtuse hacks.

; Program: maze23byte.asm
; About: 23 byte print maze

; machine code version of 32 byte BASIC maze program:

; Size Optimizing Tricks in 10 PRINT Orthogonal for Commodore 64
; Jul 28, 2021
; https://www.youtube.com/watch?v=oPtjcSsS2MI

; autorun ref https://www.pagetable.com/?p=568

; target processor
  processor 6502

; code origin
  .org $01F8-1          ; Writing to stack for JSR return

table:                  ; PETSCII print code table at 255+248 ... 255+255
                        ; This is because I found PEEK(58)+PEEK(59)*256 = 255 in zero page.
                        ; Thus, letting me replace a 3 byte table lookup with a 2 byte indirect lookup

  .byte 96              ; horizontal bar - located here to align $01F8 JSR return address as needed

  .word autostart-1     ; JSR return will increment by 1
                        ; autostart-1 is non-printing chars
                        ; Also important is that JSR return address will also be non-printing chars

  .byte 171,177,178,179 ; T shapes
  .byte 125             ; vertical bar

CHROUT = $FFD2     ; KERNAL CHROUT
RASTER = $D012     ; Raster counter

loop:
  lda (58),y       ; shaves a byte compared to normal table lookup PEEK(58)=255, PEEK(59)=0

  jsr CHROUT       ; location of this JSR needs to end on address that will be non-printing chars

autostart:         ; autostart starts here, address chosen to be non-printing chars

  eor RASTER       ; generate kinda random byte
  ora #248         ; modulo 8 + 248
  tay
  bmi loop         ; branch shaves a byte compared to JMP

Source and prg here: http://isaackuo.cloudapp.net/stuff/maze27byte/

#RetroComputing #6502 #C64 #Commodore64 #Commodore