Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics

Rule Clarification plus Tips and Tricks Sticky

A topic by Shallan created Dec 18, 2020 Views: 1,777 Replies: 24
Viewing posts 1 to 16
Jam Host (7 edits)

Hey All!

I wanted to write this post to clarify the competitions technical rules as there seems to be a little confusion over them. Also to show how you can test your entries to see if they conform to the rules. And finally give some pointers to help you make the most of the space you have available.

Technical Rules

First up the technical rules. 

At first glance the rules may seem strict & confusing. But while they are somewhat strict they should hopefully become less confusing with some explanation. 

The most important thing to note is that you can enter this competition at various skill levels. Games in BASIC are perfectly valid as long as they conform to the memory limitations. Simple assembly programs with no memory trickery are of course allowed too. But if you want to take up the maximum challenge, see how close you can get to 4kb and how many tricks you can use to pull it off!

So here are some clarifications:

2. Final code must be in .PRG format that loads into memory below $1000 hex, giving 4,096 bytes of address space.

For all games we expect them to be in PRG format and be able to load and run from VICE. The PRG can load at any address below, and must not run past $1000. The idea here is to create limitations which force the creation of Cassette 50 style games, but to do something other than just saying "You have 4kb" in order to create some intrigue for the more technical coders. Some valid examples:

  •  Assembly program saved as PRG that loads at $0801 (As most using some form of Kick Assemblers BasicUpstart do) and contains $7ff bytes. This program therefore loads into $0801 - $0fff.
  • 20 line BASIC program saved as PRG. This will load in at $0801 and will be short enough to not run past $1000
  • Assembly program saved as PRG that loads at $0120 and uses $edf bytes. This program loads from $0120-$0fff

All of these examples are possible to have run in VICE, although the third example requires some trickery which I will explain in a later part of this post.

3. At no point can the code write to any location at or above $1000, however using IO normally at $D000-$DFFF is allowed, as is calling BASIC or KERNAL routines. BASIC programs are welcome too, just be sure to start your program with POKE 56,16 so it conforms to the memory limits.

This is the rule that seems to have caused the most confusion, but its actually quite simple. It simply means that you must keep all your memory writes below $1000, therefore:

  •  All your variables must be below $1000 and are probably best stored in zero page
  • Your screen ram cannot be moved beyond $1000 so is probably best left at $0400 
  • All your assets, should you choose to use custom font or sprites must also live below $1000
  • You cannot unpack or unroll anything into space at or above $1000
  • You cannot use $fffe/$ffff to set interrupts as this is writing above $1000. Use $0314/$0315 instead

The ONLY exception to this rule is accessing IO area, that is memory between $d000-$dfff when and ONLY when it is banked in as IO area ram (which it is by default). You CANNOT bank out IO area RAM and use the space underneath!! This means it is OK to:

  •  Write to any VIC registers such as border color $d020, sprite registers $d000, $d027  and so on
  • Write to any SID registers e.g. $d400+
  • Write to Color RAM at $d800+

This rule also does NOT prevent you from:

  • Reading memory at any addresses at or above $1000, if there's a set of values you can use that exist in the BASIC or Kernal, go for it! Just don't write there!!
  • Calling methods in BASIC or kernal. More on this later on!

If you are writing a BASIC program makes sure the very first line is POKE 56,16. This ensures that your program and variables can never go past the $1000 limit.


Testing your game against these rules should you wish to, is actually quite straightforward. I will be testing all games this way to ensure they conform. (Additionally I will be checking for any sneaky IO banking using $01!!!). I will be using VICE 3.4 for all testing and recommend that everyone should do the same.

Start VICE and open up the monitor (Alt-H in the latest v3.4) and type the following lines pressing ENTER after each:

w exec f5da      

This sets a breakpoint at the point when the machine is  ready to load (via virtual fs or copy to d64). Now drop your PRG onto the VICE window to load it and you should see the monitor reappear due to the breakpoint we set. Now we can apply the memory rules. Type the following lines into the monitor pressing ENTER after each:

w store 1000 cfff
w store e000 ffff

Your game should now load as normal, but if at any point you write to memory above $1000 it will bring up the monitor again and this will indicate the game breaks the rules.


#1 - BASIC programs are more than enough and definitely in the spirit of Cassette 50

If you take a look at some of the 10 liner C64 BASIC competitions, there are some great games there in only 10 lines!! The C64 can only fit 80 chars on a line, so these programs take less than 1Kb to store in memory. Variables do take a little bit of memory at runtime but as long as you use the POKE 56,16  to contain everything below $1000 you should be able to create some awesome results, just take a look at some of the 10 line competition winners over the years:

For BASIC programs to conform you must limit the memory available to BASIC by doing POKE 56,16 before running the program or before a CLR. You can include it as the first line like so:

1 POKE 56,16: CLR

#2 - Using routines from Kernal and BASIC

        Some things you might want to do already exist in BASIC and Kernal, though you usually have to sacrifice some of zero page and some of the area at$200-$2ff for them. Check out the ROM disassemblies at for more details and to work out what locations you need to sacrifice. But here are some examples:

Clearing the screen and fill color ram with RED, obviously you can preload 0286 and 0288 if you want:

 lda #$02
 sta $0286
 lda #$04
 sta $0288
 jsr $e544

Note: It has been pointed out that on older kernal the color is taken from $d021, so you would want to load the color value there instead. (thanks to kakefoni for this info!)

Shift screen contents up 1 row, again preload 0288 if necessary:

lda #$04
sta $0288
ldx #$19
jsr $e967

Load the accumulator with a random number 0-255:

lda #$01
jsr $e09a
lda $63

There are many more useful routines I suggest browsing through the disassemblies of the ROMs  linked above to see whats there and what you need to sacrifice to use them.

#3 - Using screen ram for code and other data:

One sneaky way to get more space for code is to reduce the size of your screen area. You could sacrifice a few lines at the top and bottom of the screen to put code into instead, filling color ram at that location to hide the resulting garbage. Remove 4 lines from top and bottom and you can save an extra 320 bytes. 
If you additionally squash horizontally by reducing the screen width by 8 on each side you have room for some predefined tables or even some custom fonts, a screen that's 18 high and 24 wide will give you enough room on the sides to hide an enough custom font for alphabet and numbers 0-9, while still providing 280 bytes of free space at the top and bottom too!

#4 - Using very low memory locations

    The following kick assembler snippet shows how you can utilise memory way below the usual $0801 area:

//Autostarting PRG code under $1000
// 3767 bytes free for code
// 254 zero page bytes free for variables
// 18 bytes at $1ed for variables
* = $120
    ldx #$1f 
    txs    //Push stack down to $100-$11f
    //Start your code HERE (205 bytes up to $1ec)
    inc $d020
    jmp *-3    
* = $1ed
    //This area can be used for runtime vars
    //Once prg is loaded (1ed-1ff = 18 bytes)
    //But is bashed by the loading process
* = $1f8  //Override return from load vector on stack         
    .byte <[Entry-1], >[Entry-1]
* = $200
    //143 free bytes here
    .fill $8f, 0
    .byte $48,$eb //Prevent keyboard jam
    //131 free bytes here
    .fill $83, 0 
* = $314 //IRQ, BRK and NMI Vectors
    .byte $31, $ea, $66, $fe, $47,$fe
    //Keep the following vectors also
    .byte $4a,$f3,$91,$f2,$0e,$f2
    .byte $50,$f2,$33,$f3,$57,$f1,$ca,$f1
    .byte $ed,$f6 //STOP vector - Essential to avoid JAM
    //3286 free bytes here for your pleasure!
    .fill $cd6, 0

This works by overriding the stack return pointer for the load routine, which can be found at $01f8 and pointing it instead to a new Entry point found in the lower end of the stack. This entry point then moves the stack pointer to $011f reducing the stack to 32 bytes (can of course be adjusted as need be). At this point you now have 3767 free bytes between $123 and $fff where you can place anything (currently just filled with zeros). Note I used VICE 3.4 for this and recommend that everyone should do the same (VICE 3.1 has been reported to crash with this code, thanks Docster for the info)

Hopefully that's helped to alleviate some of the fears some people had about the requirements and given a few useful pointers to those that wish to enter.


Submitted (2 edits)

I think my game entry for the competition has kept to the rules.
Screen RAM uses $0400-$07e8, the only $D000-$DFFF registers used are VIC2 hardware. The $01 is set to default $37.

Since downloads are not to be public for the competition. Please can you suggest how I can get this game online in html5 like other entrants had? Which applications were used to launch the C64 emulator in HTML? 

Jam HostSubmitted (2 edits)

We have been using It has an export to HTML feature. Just drag your .png in there and once it's running, go up to the share tab. You'll get a zip file which you can upload directly on here.


Thank you. I have just submitted the PRG to the organizer of the compo. Just awaiting response before I do this. ;)


Really useful this, thanks a lot.


Setting the vectors from $0314 will kill $02a6 (NTSC/PAL detection). I have no clue why? Anyone?

lda $02a6
will be 0 no matter if it's PAL or NTSC. 


Submitted (2 edits)

A good question actually... This memory location is set by KERNAL on reset $ff5b - $ff6a. So, as long as you're not touching this memory location, it should have some value. Could you share your code?

I've read everywhere not to trust $02a6 anyway.

I've used NTSC/PAL detection by TWW from this topic: just on the boot, before initiating an IRQ to $0314. I just needed to get back the counting of CIA 1 timer as I'm using it for randomization :).

Jam Host

Fixed the first testing breakpoint, the original one was too early. The new one waits for file loading. (Thanks Docster for the heads up)

(1 edit)

The screen colour filling example in #2 doesn't work on older KERNALs, the screen colours will be set to the contents of $d021 instead of $0286.

When the submissions are put on tape, do they have to follow the same memory rules? It's much, much harder to avoid writing to addresses above $0fff then (or having the file fit below $1000 since we can't easily load from as low as $0120).

Jam Host

Putting the games onto tape will be the responsibility of myself and the competition team. We of course will not be needing to follow the same rules, as they are just for the initial entries. Most likely we will load games into $1000+ and relocate them once loaded, for games that require special loading.
Also good note on the screen colors, I will add a note to the text to say as such. Thank you! :)

Jam Host (1 edit)

Added another note about BASIC programs:

For BASIC programs to conform you must limit the memory available to BASIC by doing POKE 56,16 before running the program or before a CLR. You can include it as the first line like so:

1 POKE 56,16: CLR
Deleted 2 years ago
Jam Host

The CLR ensures that all the variable space pointers are moved to match the end of basic pointer just set by POKE 56,16. Without it the program would seemingly run fine the first time and possibly be using memory >$1000. However a second run of such a program would correctly result in out of memory error

Deleted 2 years ago

See, loads of space to play with... ;)

Submitted (2 edits)

C64 ACME/C64 Studio source for preventing to overwrite $1000. To test this issue, you could write at the end of file:

_memory = *
   !if _memory > $1000  {    !error "memory overflows $1000 - write less code!"

This should prevent you from writing code that overflows the $1000 memory range.


There is a little problem on your really helping code

if i place a value $FF (but i suspect <> $00) in $2A1 :

        *= $02A1        
        byte $FF

your example freezes!

(1 edit) (+1)

Interesting .. the C64 memory map I normally use says $02a1 just used for saving CIA2 interrupt control register during RS232 I/O.

Edit: I reproduced this issue too.


taht part of memory seems rewrited after program starts ... i tested avoiding 02a1 initially but placing sprites data at run time . Sprites show an Hole!


What exactly means "The games must be previously unreleased", please? I published my development code openly on GitHub ( but not the final version so far. Can I still send my prg file in?


It means that the competition submission should *not* be publicly released from any other web site, i.e. CSDB, etc. All entries should be *exclusive* for the competition. 


Thanks, Richard. So I guess having the source code on GitHub does not count.


No problem. I'm currently working on a second quick entry for the competition. This time I am writing my little game on theC64 computer, with Action Replay cartridge plugin, Turbo Assembler and a couple of Public Domain utilities (Sprite Editor and Char Editor V2). The game idea is based on an old BASIC PD game. 

(1 edit) (+1)

Thanks for the clarifications. I noticed there is a new version of Vice released - version 3.5. Will you still be using 3.4 for judging?

Also, will you be testing on real hardware at all?

Submitted (3 edits)

Just one question. If I was to develop an improved version of one of the competition entries by making a deluxe version. Then releasing it outside the competition while the competition is still in place. Would this violate any of the compo rules? I had fun making one of my compo entries on theC64 and would love make a deluxe edition of the game with full presentation, enhancements and music. ;)


Deluxe Version, hmmm? I would second the motion that the organisers allow such "Deluxe Versions". Pretty please!?

Submitted (1 edit)

Using the suggested code to develop a game i realized that a game that works perfectly on vice  , it freeze itself at beginning on the real hardware and in some other emulators.
In this case the game is eligible for the cassette 50  compo?

I used the Shallan code against this emulator (but the problem is in the real hardware too) :

Loading the generated prg it freeze and looking at the disassembly i see that the execution is in an infinite loop at $E5CD ,:

this is the pure Shallan code converted for cbm studio asm (DASM):

ENTRYM1 = Entry-1           ; Entry point minus one for the stack hacking

        *= $120
        ldx #$1F            
        txs                 ; Forzatura dello stack pointer per abbassarlo a $100-$11f
                            ; ---------- Codice di partenza (205 bytes fino a $1ec)
        inc $D020
        jmp loop
                            ; ---------- Fine codice di partenza --------------------
                            ; Quest’area di memoria può essere usata per le variabili a run time
                            ; Una volta che il programma è caricato (1ed-1ff = 18 bytes)
                            ; è stato sovrascritto dal processo di caricamento

        *= $01F8            ; Sovrascrittura del vettore di ritorno nello stack
        byte <ENTRYM1, >ENTRYM1 ; Stack hacking

        * = $200
            ;143 free bytes here
            byte $8f, 0
            byte $48,$eb //Prevent keyboard jam
            ;131 free bytes here
            byte $83, 0

        *= $0314            ; Vettori per IRQ, BRK e NMI
        byte $31,$ea,$66,$fe,$47,$fe
                            ; Vanno mantenuti anche i seguenti Vettori
        byte $4a,$f3,$91,$f2,$0e,$f2
        byte $50,$f2,$33,$f3,$57,$f1,$c1,$f1
        byte $ed,$f6        ; vettore di STOP - essenzialmente per evitare JAM nella memoria

                            ; 3286 bytes liberi per tutto ciò che si desidera
        bytes $00 * 3286    ; Riempito di zeri