So You Want to Crack & Train Commodore 64 Games Like a Pro 1

Posts: 9
Joined: Fri Jun 19, 2015 1:42 am
Location: Quebec

So You Want to Crack & Train Commodore 64 Games Like a Pro 1

Post by mrnop » Fri Jun 19, 2015 1:44 am

So You Want To Crack and Train Commodore 64 Games Like The Pros?

Note: This article does not cover any ‘illegal’ topics. It is merely a tutorial on how to capture memory, save it to disk and manipulate it. I will not be discussing bypassing copy protection. This article is meant as an entry level tutorial as to how one can capture single file disk or tape games, and save them to disk. If any copy protection is in the game, this tutorial will not be of any assistance. I will also cover how to train games for infinite lives, etc.

It's not an advanced tutorial such as setting break points because I'd like readers to understand the basics first. There are more advanced methods as I'm sure crack groups can attest to.

Table of Contents

1.0 Introduction
1.1 Binary
1.2 The CCS 64 Emulator
2.0 Learning to use a MLM
2.1 Switching out ROM
2.2 The basics of crunching and linking
2.3 Stopping the de-crunch routine
2.4 Review
2.5 Other Examples (Bluemax, Pinball Power)
2.6 Tips and Questions
2.7 Tetris “Hello Hacker” Wildsave loader
2.8 Vixen Loader (Martech Loader)
2.9 Bosconian (Invade-A-Load)
2.10 Intros
3.0 Training Concepts
3.1 Method 1 - The Screen RAM Method
3.2 Galaxia (screen RAM method)
3.3 Method 2 – The Load and Store Method
3.4 Infinite Time
3.5 Dukes of Hazzard – Sprite Collision
3.6 Dukes of Hazzard – Character Collision
3.7 Lightforce – Infinite Lives
3.8 Toy Bizarre
3.9 Ghosts and Goblins 1994
4.0 Whittling Method

Section A – Additional Help on Op-Codes
Section B – BNE/BEQ
Section C – Final Comments

1.0– Introduction

This article is by no means meant to be a complete comprehensive guide to capturing games and saving the data. You can’t put years of experience into a single document and expect a reader to be able to become the next Eagle Soft, Hokuto Force or Ikari.

I’ve attempted to use layman terms and analogies that some advanced programmers might find amusing, but we’ve all been at the beginning stage of trying to learn how to program or crack 6502 code – and layman explanations would have been helpful back then. Explaining things to you in simple terms may help you to understand the concepts better than if I dived into full technical jargon.

You may skip to section 1.2 if you’re easily confused (or very lazy) but I recommend that you attempt to learn all sections. In fact you can skip all of the sections that you don’t understand and probably still be able to have some success in capturing game memory and training. I’m going to try to write this article so that you don’t have to know everything from the previous chapters.

Finally, we’re not going to cover actual ‘cracking’ methods so perhaps the article title is misleading. Before you can learn how to crack, you need to know how to capture the 64’s memory to disk without freezing. If you freeze a game, that doesn’t allow you to place a trainer in the game or a high score saver, etc. Saving the memory to disk however does allow you to add extra features such as cheats and high score savers, etc.

The Commodore 64 contains 64K of memory. One K or (kilobyte) is 1024 bytes. A byte is simply one location of the C64’s memory. For example if you typed “HELLO” on the C64’s screen, that would be 5 bytes. Type the word “AWESOME” in the top left of the screen and you’ve used up 7 BYTES.

So one character put into the C64’s memory uses up one BYTE. And you can place one character (or one value) in one memory location. You can place a letter A in the top corner of the screen but you can’t place two characters there at the same time. One memory location, one value placed into that location. The screen consists of actual memory locations that are part of what we call SCREEN RAM, but all you really need to know is that one memory location can hold one value. If it’s a character on the screen, that’s one byte – if it’s one character that’s part of your name in a high score table, that’s also one byte. If it’s one note played through the SID chip, that’s one byte. If it’s one letter in your word processor document, it’s one byte.

The Commodore 64 contains memory locations numbered from 0 up to 65535.

Proof of this is if you should type into the Commodore 64 the following:
POKE 65535,1
it would work whereas
POKE 65536,1
results in an “illegal quantity error” because there is no 65536th location on the C64.

And it’s no coincidence that 65535 divided by 1024 equals 64. In other words, the Commodore 64 has 64 kilobytes of memory – or 64 blocks of 1024 byte memory locations. All you really need to know is that there are 65535 locations available to you the cracker, or to you the programmer. You don’t need to understand the Kilobyte part of it.

So when it comes to learning to crack games, creating trainers or dumping tape games to disk, we need to keep this in mind – no matter what protection scheme is used, no matter what we’re trying to cheat in a game (lives, sprite collision, level skipping) it will always just be a matter of changing one or more of these memory locations.

A single file game or a 10 disk game, will still work the same way – data will be loaded into the memory and it will be executed. Change the code and you change the way it subtracts a life. Change the code and it decides not to crash if it doesn’t find the copy protection.

We know that the C64 has RAM and ROM memory. The RAM is memory you can change and you lose that data when you turn off the C64. The ROM is memory you cannot change and it remains intact when you reset the C64.

For example, the programming that allows you to type
LOAD “*”,8
have to come from somewhere. And those load routines are found in Kernel ROM. The SID chip is ROM otherwise you’d have to load in some form of sound software every time you turned on the C64. You wouldn’t even be able to see a character set on the screen were it not for a character set ROM which defines what the letters look like. How does the C64 know what pixels to light up to create the letter “A” compared to a letter “B”? All of this information is contained in ROM (character ROM to be precise).

The layout of the C64’s memory is what we refer to as the ‘memory map’ and it looks like this:

Locations 0 to 40959 are RAM. You can change these locations contents to any value you want.
Locations 40960 to 49151 are BASIC ROM. The Basic language resides here, which understands what you’re trying to do when you type PRINT “HELLO”
Locations 49152 to 53247 are RAM. You can change these locations to anything you’d like.
Locations 53248 to 57343 are Character ROM. The actual character set you get when you look at the c64’s screen. It also holds the colours for what is displayed on the screen amongst other graphic purposes. The sound chip also uses this memory.
Locations 57344 to 65535 are the Kernal ROM. These are the built in routines that allow disk loads, tape saves, flashes the cursor, etc. It is the heart of the C64 so to speak.

Now that I’ve confused you to hell and back, allow me to make sense of things:

The C64’s memory isn’t just a single chip. It’s a series of chips such as the Kernel, the SID chip (music), the Video chip and the RAM chips. These all serve to offer you 65535 locations in which you can place your information.

My first analogy – I’ll be using a lot of analogies just to forewarn you.

Think of the C64’s memory as a block of houses on your street. Your first house is Mr. RAM’s house, the next house is Mr. BASIC’s house, followed by Mr. Char Rom’s house, followed by Mr. Video’s house and finally Mr. Kernel’s house.

Together these houses make up your entire 64K of memory. When you want to write a program in BASIC, your program gets put into Mr. RAM’s house. It gets cleared when you turn off the C64. Mr. BASIC supplies the interpreter that allows the C64 to know what PRINT means, and what INPUT means, etc. Mr. Video allows you to change the colour of the screen in your BASIC program when you type POKE53280,0

Mr. Kernel’s house provides the routines that flash the cursor, or load and save data from devices. All of these neighbours of yours are used by the C64 when you write in BASIC. You don’t need to know how they work, just that they do work. They allow the C64 to translate your BASIC program into a working program, to allow disk loads, to play sound effects, to display sprites, etc.

The characters on the screen never change in physical appearance because Mr. Char Rom’s house defines what the characters look like (Character ROM). Mr. SID (who is a tenant in Mr. Video’s house) plays his music loud and annoys his neighbours but he’s the sound chip guy. If your BASIC game uses sound effects then you’re using some of his stuff.

Mr. Kernel allows us to be able to use LOAD or SAVE commands in our BASIC program and the C64 knows how to do that – because Mr. Kernel’s house tells the C64 how to be able to load and save. If Mr. Kernel wasn’t there, using the LOAD command would result in a “Syntax Error”. (The Kernel is a series of routines to allow for input and output from devices such as the keyboard, tape and disk)

So when you create a BASIC game, you can only use Mr. RAM’s house. You can of course call upon the ROM neighbours to do things as I’ve mentioned (move sprites, read the joystick port, print text to the screen, etc.). As your program grows in size though, eventually you’re going to reach the point that it hits the brick wall at location 40960 – where BASIC ROM is held.

And since that is ROM, it can’t be used to store anything. So for this reason you can only use up to location 40959 for BASIC. Anything beyond that is off limits…. Even if you could write to the memory at location 40960 and onwards, you’d be overwriting BASIC itself which would render your BASIC program a bunch of meaningless words to the C64. PRINT? What does that mean? What is a POKE command?

The television advertisements told us that the C64 was a 64K computer so we’d better be able to put 64k worth of information into it. But the reality is that the Kernel, Video chip, Sound (SID) chips are all ROM and you can’t change what’s in ROM. So did Commodore lie to us? Not exactly.

You can “page out” or “switch out” this ROM for RAM. That is, you can actually have a full 64k of RAM by telling Mr. Video, Mr. BASIC ROM, Mr. Kernel to temporarily leave their houses so you can store data in them. But you can’t do this with BASIC programs because as your program grows in size, the first house it would try to fill up with your program data would be Mr. BASIC’s.

If however you decide to write a game entirely in machine language (6502), then you don’t need Mr. BASIC to be in his home, you can evict him for the day and use his house for storage. You can also tell Mr. Char to get lost for the day and use his memory. You can also do the same for Mr. SID and Mr. Kernel provided you don’t plan to play music or use Kernel routines.


If you only want to write a program in BASIC you can use up to location 40959. Anything from 40960 up to 65535 is considered part of the ROM and you can’t change it. If you want to write entirely in machine language then you can tell the ROM houses to leave for the day through a process known as ‘switching out’ the ROM. This makes all the memory of the C64 available to you – at the price of not being able to use the ROM functions because they are now empty RAM awaiting your needs. You’ve evicted the home owners for the day, and are using their houses for RAM storage.

6502 Machine language is the native language of the C64. It doesn’t need BASIC to interpret it. We can turn off (or switch out) the ROM memory if we want, if machine language programs want to use it.

Some games you’ll be looking at may only use RAM memory (and never go beyond location 40959). Other larger games might use memory where ordinarily ROM would be. This is because the game designer chose to use these ROM houses for storage – they decided to switch out the ROM to make RAM.

In the end it doesn’t really matter if you understand this concept – but it would certainly be beneficial. Some games that were released by crack groups never worked properly (you can still find some bugged ones on Gamebase) because the cracker only saved the true RAM memory up to location 40959. They neglected to save the additional RAM memory that was underneath the ROM because the game programmer told those “houses” to leave for the day so he could use their houses to store his game.

It’s possible to switch out some ROM while leaving other ROM intact. For example you can use the BASIC ROM at 40960 as RAM, and leave the Kernel ROM intact. We’ll cover this later on.

For the purposes of dumping game memory and training, just understand that you don’t just want to save BASIC RAM, you also want to get what might be ‘hidden’ or switched out under the ROM.

1.1 Binary

Memory on the C64 ranges from 0 to 65535 however when programming in machine language we use what’s known as hexadecimal (or ‘hex’).

This can be a bit of a learning process to understand but it works like this:
When programming in machine language, numbers in the C64 range from 0-9 and then changes to numbers:

There is no hex value higher than 15.

You can only put numbers from 0-255 into a memory location. If you doubt me, try typing
POKE1024, 256
and see if that works. It won’t because 256 is too large of a number. This is an 8 bit machine and 8 bits = numbers of 255 at the most.

To convert decimal numbers into hexadecimal we break numbers into a two letter value. The first letter is a unit of 16 and the second digit is the remainder.

For example the decimal number 00 in hex is 00.
The decimal number 8 in hex is 08.
The decimal number 16 in hex is 10.
The decimal number 42 in hex is 2A.
The decimal number 255 in hex is FF (which is why we don’t need a ‘G’, ‘H’, etc.)

Take the number 42 for example… how does 2A become a value of 42? Well 2 times 16 = 32 and add ten to it (A=10) and it becomes 42.

We’d arrive at FF for the decimal number 255 because 15 (F) times 16 = 240 and the remainder is 15 (F). 240 + 15 = 255

You can use your Windows calculator to convert between decimal and hex. It will take a while to memorize the more common values. For example most programmers know that 2A is the asterix (decimal value 42) in machine language. The space character is 20 (2 *16 = 32).

We’re getting into hexadecimal values because when we examine machine language, the values are all displayed in hex. There’s no decimal being used.

We use this process when determining what number to put into a memory location on the C64.

Now as far as the actual memory locations in the C64, because they are significantly larger than 255 numbers, the two digit hex formula doesn’t work here. We need a four digit formula but it works much the same.

A hexadecimal value representing the C64’s memory looks like this:
MUST KNOW: The first digit is multiplied by 4096, the second by 256, the third by 16 and the last one is the remainder. It’s an extension of the two digit hex formula.

So location 49152 in decimal is really C000 in machine language because we know C = 12, and 12 * 4096 = 49152.

1234 in hexadecimal is 4660 in decimal because 1*4096, 2*256, 3*16 and adding 4 = 4660.

I’m not going to get involved into how to convert decimal to hex and vice versa – if you’re having difficulties use the calculator built into Windows.

Wrap Up Summary

The C64 has 65535 locations in which you can place information. Not all of these are available for BASIC programs because the C64 needs some memory to serve as the “BASIC intepretor”, to provide sound, video (screen colours, sprites, etc.) and Input/Outut functions. These functions are stored in ROM chips in the computer.

We can turn off/switch out/page out (basically all the same meaning) the ROM functions to create temporary RAM provided we’re not going to be doing our programming in BASIC. BASIC needs the BASIC ROM memory to function. If you’re using your own custom character set you can switch out the Character ROM. If you aren’t using Kernel routines (disk saving, etc.) you can switch out the Kernel ROM.

Of the C64’s memory locations we can put numbers from 0-255 in them. In BASIC this is done by typing:
POKE (location), (value)
POKE 1024, 42 places a star in the top left of the screen
POKE 53280,1 places a value of 1 in the VIC-chip memory (the border colour)

In machine language we use a formula known as hexadecimal when reading and wrting to the memory of the C64. It’s the equivalent of the BASIC POKE command.

Values from 0-255 in hexadecimal translate into 00-FF
Memory locations translate into 0000 up to FFFF (0-65535 in decimal)

We use a math formula whereby we multiply:
For two digit numbers (what you’d be placing in memory locations) it’s: XX where the first X is * 16, and you carry (add) the second X value.
For four digit numbers (memory locations) 4096, 256, 16 and carry the remainder. So 49152 is really C000 (c=12, and 12*4096=49152)

If you’re confused as to why some are two digit and others are four (I know I was when I first tried learning 6502), here’s a simpler explanation: The C64 only needs 2 digit numbers when placing information into memory locations because we’re never using numbers higher than 255. You can’t use values such as 256 or 1000 as in POKE 1024, 256 or POKE 53280, 1000.

Because memory locations can, and do, go beyond 256 though, we need a four digit number to represent the memory location in hexadecimal.

The memory map of the C64 in hex looks like this (the same as the one I gave you earlier but represented in hex this time):
0000-A000 RAM MEMORY
A000-C000 BASIC ROM (*)
C000-D000 RAM

(*) means that this can be used as temporary RAM if you’re not planning on using BASIC.

Now you might have seen some games written in BASIC that also contained portions of machine language. Perhaps the machine language was for playing music or displaying a scrolling background. The most common area for this machine code to go was 49152 (or $C000 in hex). This is because there’s a little window in the A000 to FFFF ROM that is still usable as RAM. Everything else above A000 is considered unusable for placing BASIC code. The window of C000 to CFFF is usable though. I’m sure we’ve all seen a
SYS49152 command in a BASIC game. This is why, it’s away from BASIC and in no danger of being overwritten by your BASIC program.

1.2 The CCS 64 Emulator

For the purposes of dumping memory and training, I’ll be looking at using CCS64 emulator. This is available online at

I’m not going to be using Vice because I find the machine language monitor built into it to be not very friendly. If you’re using a REAL C64, you will absolutely need a freeze cartridge such as the Action Replay or Final Cartridge. It’s essential that you have a cartridge that has a built in machine language monitor that you can ‘jump into’ at any point. Without one, you’ll have to do all your cracking and training through an emulator.

A machine language monitor is a tool to examine the C64’s memory and to write to that memory. It’s no different than the POKE command in BASIC. In fact some game cheats of the past were published as POKE’s that you entered in before RUN’ing a game.

A machine language monitor allows you to halt a program, enter the C64’s memory and change the memory, then resume the program. For example, you can break into memory while playing Pac Man and decide to turn off all the bad guy sprites so that you have the maze to yourself. Then you can resume the game. You could break into a machine language monitor and fill the screen with blank characters so that once you exited the monitor, you’re joystick controlled man (or ship) can move anywhere – now that there are no walls or barriers on the screen.

2.0 Learning to use a MLM

MLM = machine language monitor, the tool that allows you to view and change the C64’s memory as a program is running. I’ll be using the term MLM from here on in.

For the purposes of this article we’re only going to focus on tapes and disks that are one file (or multiple files that load just once before the game begins). When we get into multiple disk games, multiple file games or multiple file tape games, there are other considerations that are just too extensive to cover at this time.

Essentially we’re just going to be looking at ‘capturing’ a game in memory so that we can save it and play it. If it’s a single file tape, the game should play fine. It’s not really a crack if it’s not doing any copy protection checks, and single tape files rarely do. There are too many scenarios to cover, to cover all disk copy protection methods so again we’re only going to capturing the game and saving it.

Once you’ve learned how to ‘capture’ a game, and save the memory to disk, you can advance to the ‘Training’ section and learn how to train games (cheat). We’re not going to be ‘freezing’ games because freezing is not cracking, and it’s a practice generally frowned upon.

So… we know that there are 65535 locations of memory that could be potentially loaded with data. How do we crack or capture a game? How do we know what area of memory is actually being used? We’ll discuss this later.

The first 256 bytes of memory in the C64 is referred to as “zero page” memory because it’s the first page, the first section, the beginning, of the C64’s memory. These locations are most often the area used by games to hold temporary data and we’ll discuss that in the ‘Training’ section. It’s not common for games to actually load themselves into this area, but they frequently use this area while you’re a playing the game.

TAKE NOTE: Hexadecimal is represented by a dollar sign ($) to differentiate it from decimal numbers. So if I write “20” I mean 20. If I were to write $20 I’d mean a hex number (in this case decimal value of 32 because 2*16 = 32).

Therefore zero page in decimal is 0-255, and in hex it’s $0000-$0100 (because 0*4096, 1*256, 0*16, plus 0)=256

So if you typed
FOR I = 0 TO 255: POKE I, 0 : NEXT
you’d wipe out all of zero page (and cause a crash)
in machine language this would be the same as filling in $0000 to $0100 with $00’s.

I know this is probably overwhelming – I once struggled with the concept of how to print just a single character to the screen in machine language. This is why I’ll repeat myself and use analogies.

There are several memory maps online that you can Google, that will explain the C64’s memory layout to you. The main areas to know (print this out and tape to your wall):
$0000-$0100 – zero page
$0400-$07E7 – screen RAM (what you type on the screen is held in here)
$0800 – start of BASIC (all basic programs load from this location upward)
$9FFF – end of BASIC (all basic programs stop at this point)
A000-C000 BASIC ROM (this is BASIC, the actual language)
C000-D000 RAM (free to use for any purpose)
D000-E000 CHARACTER SET ROM (what defines your characters)
E000-FFFF KERNAL ROM (Special functions for I/O devices, etc.)

In most (but not all) cases, once a game has loaded, and just a split second before it starts to run, you can get away with saving memory from $0400-$FFFF (which would be 1024 decimal to 65535 decimal) and you’d have all of the game code you need. Most games don’t touch below $0400 for purposes of loading, but they may use this memory once you’re playing them.

So…. Let’s begin shall we.

2.1 Switching out ROM

First, I’m assuming you’ve installed CCS64 by now or you have a real C64 with a cartridge.

I also assume that you know that the memory from $A000-$FFFF is mostly ROM but if needed, it can be called upon to serve as RAM if you want to turn off or “switch out” the ROM.

1) Start CCS64 (or turn on your c64 and enter your freeze cartridge and find the Machine Language Monitor option)
2) In CCS64 press ALT-M for the machine language monitor.
3) In both cases you should now see a prompt and should be able to type commands. Most commands are universal as it pertains to machine language monitors:
L – load
S – save
F – fill
H – hunt
M – view memory
I – visual display of memory
X – exit

Whether you’re using Vice, CCS64, or a cartridge, try typing in:
M 0400
Remember, we’re talking hex now – the decimal world has been left behind. So $0400 is 1024 decimal which we know is screen RAM. That is, if you look at $0400 you should see whatever was on your screen before you started the monitor. If you had typed your name into the upper left corner of the screen and then entered the machine language monitor (heron referred to as MLM) you’d see your name at $0400.

Let’s try it…
Press ‘X’ to exit the monitor and type your name in the top left of the screen then re-enter the monitor (ALT-M on CCS64, pressing the cartridge button on a real 64)
then type M 0400 0420
and you should see your name in the memory dump

The MLM is displaying the RAM memory to you…. But this is also a two way street. You can also write to memory from within the MLM. Remember, a machine language monitor allows you to not just inspect memory but also write to memory.

So on a new line type in “F 0400 07E7 2A” (without quotes)
this is the Fill command and fills in $0400 to $07E7 with the value of $2A. The format of the Fill command is : F (start address) (end address) (value)

Going back to the section on hexadecimal, $2A (2*16 plus A [where A=10] is 32+10 or 42) and $0400 is (4 * 256 = 1024) and 1024 is the top left of the screen (POKE 1024, 42 puts a star in the top left of the screen).

Type X and press return to exit the MLM. Now look at the result… the screen SHOULD be full of stars now because we’ve just FILLed in the entire screen memory with $2A’s.

Let’s try again….
Enter the MLM and type
F D020 D021 04
This will fill $D020 to $D021 with a value of $04 (4 decimal).

$D020 and $D021 happen to be 53280 and 53281, the border and screen colours. So when you press X to exit the monitor, the screen’s colours should be changed.

And this is the way you crack and train games… by entering the MLM and modifying some of the 64’s 65535 various locations. You can inspect memory but you can also change memory and when you exit the MLM, those changes take effect be it screen colour, screen RAM, sprite data, etc.

It’s entirely possible to fill random areas of memory with zeroes and see what effect it has on a game. Maybe a ship disappears, maybe half of an alien disappears, maybe you overwrite the music, etc.

For fun, enter the MLM (ALT-M on CCS, or press the button on your cartridge and find the built in monitor)
Now type:
F 0000 FFFF 00
This will FILL $0000 to $FFFF with 00’s (fill the entire 64’s memory with zeros)
If your computer hasn’t crashed yet, press X to exit the MLM and the 64 should crash. You went and filled in the video memory with zero’s as well as the zero page memory ($0000 to $0100) and the C64 doesn’t like that at all.

Restart your C64.

Now I want you enter the MLM and type
M A000 A050
To view memory from $A000 to $A050. This is Bill Gate’s BASIC you’re looking at. You can actually see the words “CBMBASIC” in the result.


Let’s tell these people living in the ROM houses to take a trip for the day, so we can use their houses for RAM. In CCS64 you will type:


In other monitors you may have to change the value of location 1 to a $34. The most universal way I can think of doing this is to type
F 0001 0001 34
We’re using the Fill command to fill location 1 to location 1 with the value of $34

IMPORTANT: Location 1 is very important to us. It tells the C64 which houses we want to keep using as ROM and which ones to page out and use as RAM. If we change the value of 1 to something different, we can use the entire C64 memory for our own purposes.

The hex value of $34 placed in location 1 turns off ALL the ROM chips. Since you read my section on hex, you know that $34 is 52 in decimal because 16*3 = 48 and adding the remainder of 4 = 52. So the BASIC equivalent of putting $34 in location 1 is going to be POKE 1, 52

Try it sometime … turn on your c64 and type POKE 1, 52 and it will surely crash. Why? Because you entered a BASIC command that told the C64 to turn off BASIC (you told Mr. BASIC to leave his house and use his house for RAM). Naturally without a BASIC language, you can’t proceed so it locks up.

So… back to the MLM. You’ve now typed in:
F 0001 0001 34
which is a simple way to change the value of memory location 1 to $34 hex. This effectively turns off all ROM and allows you full 64K of memory. If you’re using CCS64 you would have typed BANK0 instead.

Now type in:
M A000 A050
And look at the results…


No longer should you see anything… no random characters, no “CBMBASIC” word. In fact as you scroll through memory, you see nothing at all because we’ve switched out the ROM for RAM. BASIC is now gone.

Try typing M E000
It’s also blank…. There’s simply nobody home on the street in the $E000 house. All the ROM guys have left for the day.

The only reason I’m teaching you about turning off ROM is because when it comes to capturing C64 games in memory, often times you’ll need to save the hidden RAM that the game might be using where ROM normally is (the houses on the street).

To turn off all ROM and make it RAM, we change location 1 to $34.

There’s another way to change the value of 1 other than using the fill command. If you type:
M 0001 (press return)
You should see something like:
0001: 37 00 AA B1 91 B2 22 22
0009: 00 10 00 00 FF 00 00 00


This would mean location 1 is $37, location 2 is $02, location 3 is $03, location 4 is $44, location 5 is $55. You read it left to right. Each new line shows you eight memory locations. The very first number is the starting memory location for that line.

Line two would mean that location 9 has a $00 in it, location 0A has a $10. Each line is 8 bytes of memory.

In the event you type M 0001 and the whole screen begins to scroll data up the screen too quick to read, it’s because you need to set a limit on what memory you want to view. I suggest:
M 0001 000A
instead. This will say “I only want to see memory from location 1 up to location 10 ($0A in hex).

You SHOULD be able to scroll the cursor up and type over top of the 37 and change it to a 34. This should work in Action Replay and other cartridges. If you exit your cartridge and return back to the READY prompt, it might crash though. This is because you’ve told Mr. BASIC to leave for the day – and without BASIC, your computer is a dumb terminal that doesn’t know what to do. So always remember to change the value of location 1 back to $37 before you exit to BASIC. CCS64 users don’t have to do this, the BANK command works great for this because you can exit without changing the value of 1 back to $37.


Summarizing so far

The C64 contains RAM and ROM memory.

Basic programs that we type in, begin growing in the C64’s memory at $0800 (looking at the memory map I told you to print out). As we add more and more lines of code to our BASIC program, that memory gets used up until it hits the brick wall at $9FFF. It’s a brick wall because $A000 is the BASIC language itself stored on a ROM chip. Even if we could overwrite that memory, we’d be overwriting BASIC which would leave our program a series of commands that meant nothing.

In machine code though, we aren’t running any BASIC program and so we can use memory from $A000 right on through to $FFFF. To do this, we change the value of location 1 in the C64. We know that if we change the location 1 to a value of 54 decimal ($34 hex) that we do away with ALL ROM. Naturally we cannot change the value of 1 to a $34 and still be able to type things like PRINT or LOAD on the screen though because that’s the job of BASIC to interpret what we typed. So if we do change the value of 1, we need to set it back to it’s normal value of $37 when we’re done. That will allow us to exit our MLM and still be able to see the READY prompt on the screen.

It’s the equivalent of telling Mr. BASIC to come back home to his house before we exit the MLM. Otherwise the C64 won’t know what to do. Fortunately in CCS64 you can exit the MLM regardless because the BANK 0 command only unlocks our RAM until we exit the MLM.

TEST YOURSELF: Do you know how you’d enter your monitor, examine all the memory to see if anything was hidden under the ROM, and exit again without crashing if you had an Action Replay or machine language monitor cartridge? Try to figure it on your own before I tell you how.

Answer: First you change the value of location 1 to a $34 to open up the houses of these ROM guys by telling them to leave for the day (“Hey I want use you for RAM, see you later”)

Type: F 0001 0001 34
Then you can use the M command to view memory.
Type: M A000 (press return)
And you can scroll down until you reach $FFFF the very last memory location in the C64. Notice that most of that memory will appear as 00’s and FF’s which is the default blank values put there. Perhaps you’ll see all 00’s. This is unused area, it’s empty.

Before you exit, put the value of 1 back to $37 by typing
F 0001 0001 37
$37 is the normal value of location 1 and it tells the C64 to bring all of the ROM guys back home into their houses. If you try exiting the MLM without changing the value of 1 back, it might crash the computer because Mr. BASIC is not home – and the C64 needs him to interpret whatever you’d be typing once you exited the MLM. Needless to say without Mr. Kernel either, there’s no cursor flashing.

And again, typing ‘x’ and pressing return is how you exit the MLM.

We also know that in friendly MLM’s like CCS, we can just scroll the cursor up and type in new numbers over top of the old ones. For example we can change that $37 to a $34 without using the F (fill) command. I use the F command because it should work in most variants of machine language monitors.

Quick Tip:

If location 1 = $37 then all is normal. BASIC is working.
If location 1 = $34 then BASIC is turned off, you have 100% RAM, but can’t type things like PRINT, etc. because BASIC is turned off.
Always set location 1 back to $37 if you plan to exit back to BASIC (except if you use CCS64 and the BANK 0 command)

2.2 The basics of crunching and linking

From here on I’m going to assume that you know how to:
- enter the machine language monitor
- understand that memory ranges from $0000 to $FFFF (or 0000 to 65535 decimal)
- vaguely understand hexadecimal
- Know that ROM can be turned off temporarily to allow us full 64K of memory
- Know that some games may or may not use ROM memory ($A000-$FFFF)
- Know that location 1 when it is set to $37 is normal, and $34 means that all memory is RAM, no ROM.

Most single file games are compressed. Compression makes games smaller in size. For example let’s say that a game had all of it’s game code at memory $0800 to $4000
(that’s 2048 to 16384 in decimal). Now let’s also say that the game had music at $C000-$CFFF. In order to save all of this game memory to disk, using our machine language monitor we’d have to save from: $0800 through to $CFFF right? We need both the game code and the music but they’re at different ‘ends’ of the C64’s memory. One is down low, the other is up high in memory.

We need to capture both $0800 to $4000 for the game code and then get the music at $C000 to $CFFF. But what about that large gap from $4000 through to $BFFF?? That’s a lot of empty space… wasted space (128 blocks of disk space). Many utilities exist that will allow you compress that large amount of wasted space into a tighter smaller file. It does so by recognizing the repetitive characters in that wasted space. For example if $4000 to $BFFF is blank memory filled with zeroes, the compression program can reduce that 128 blocks of disk space down to less than 1 block. It does this by crunching the repetitive data and writing a little ‘decrunch’ routine that unpacks everything again. It says “I know there are 128 blocks of empty space here, I need you to place that many zeroes right after the game at memory location $4000. Then put the music at $C000”.

Another analogy…. You have 10 houses on a street. Each of those houses is RAM in the C64 in chronological order. You fill the first house with code for your game. The code flies a ship around the screen. You then use the last house for the game’s music. In between the first and last house are 8 empty houses with nothing in them. When you go to save the memory to disk, you can’t just save the first house. You also need the last house too. So you have to save the whole block of houses to disk… that’s a lot of empty space in between.

Then you have a large file on disk that’s over 120 blocks in size when you’ve only needed 72 blocks of actual memory. You decide to download a ‘cruncher’ that will make your game smaller. It works by realizing 8 of your 10 houses are empty (blank memory) and strips all that empty space out. It’s like putting those 10 houses into a vice and turning the handle to squeeze them all into one small little house.

When your cruncher is done, you have a final product. A small file you can load and run. When you run it, using our vice/house analogy, it unsqueezes the small file back into the large 10 houses including the large gap of empty memory.

Crunchers work using a variety of methods – just know that it’s capable of squeezing out all the repetitive characters in memory and putting them back in when you run the final product. Without a cruncher (or a packer or a squeezer) we might see large 200+ block games instead of 50 block games.

Now what if a game only uses memory from $0800-$4000 and that’s it? There’s no music at $C000. Well you wouldn’t have to worry about saving any memory beyond $4000 or worry about empty gaps. Regardless, music, sprite data, character set data all contain repetitive characters that can be crunched. So even if there are no ‘gaps’ of unused memory in your program, there’s usually something that a cruncher can do to make your game smaller.

Crunchers (also known as packers, squeezers) are used very frequently. Sometimes even store bought commercial games have been crunched with public domain crunchers.

(Side note: There are programs such as ECA Linker that will link multiple files into a single file. A better way than saving all the memory from $0800 to $CFFF would be to just save two files to disk. File “1” would be your game code from $0800 to $4000 and file “2” would be the music at $C000 to $CFFF. ECA Linker will not worry about the memory in between, it crunches only the files that you give it. However this is not covered in this article.)

Let’s download the game Blue Max 2001
Here’s the download link

Unzip the file and place the tape file into your CCS directory (or another folder). If you use a real C64, you’ll have to transfer the tape image to your C64. This is a commercial game so be sure to delete the file after you’re done with this tutorial.

If you have a real C64 then I would suggest for now you use the CCS64 emulator on your Windows machine or try to copy the tape file to a real disk drive.

Now lets look at the game blue Max:

Load it but don’t run it (in CCS you’ll have to attach a tape image, the same as you’d do under Vice emulator). You do this by pressing ALT & 1 and then selecting the tape image.

Type LIST and you’ll see:
0 SYS2061


That’s a BASIC program. It loads into the C64’s memory at the start of BASIC which is $0800 ($0801 to be exact because $0800 is always a value of zero). You run it and you have a game to play….. this game has been crunched using a cruncher.

But what if the game programmer decided to put game data at $0800? How can the cruncher unpack the data and place it at $0800 without overwriting the uncrunch program that’s currently already at $0800?

Another analogy… you have a program written in BASIC.
20 END
You crunch it with a cruncher (why, I don’t know why) and the final result is a file that reads:
10 SYS 2061
You run the crunched program and voila!, there’s your BASIC program again. You type LIST and your two line program is there but the 10 SYS 2061 crunched program is long gone.

Well what happened to the old program?

This is something you’re going to have to understand…. Unlike some of the previous content, you need to understand how this works. Crunchers usually work in the same fashion. First, the final product is a program you can LOAD and LIST and RUN. It is a basic program with one line of code: an SYS command. SYS of course calls a machine language routine that’s in memory. The purpose of the program being LISTable is that you can load it and run it like any other BASIC program. The code that does the de-crunching however is all machine code.

What happens is that when someone takes a large file from disk and crunches it, the output is a smaller file that you can then RUN. But no matter how much we crunch and squeeze, we still need all the original information back. We still need the cruncher to put everything back the way it was before we crunched it… squeezing out repetitive characters isn’t a one way process. You don’t know if all of that empty space is needed or not… maybe you have a very large graphic picture that’s nothing more than a KoalaPad picture of the word “Hi” in the middle of the screen.

You could crunch that Koala picture, and all the empty blank space around the word “Hi” would be crunchable because it’s likely just zeroes in memory. But when it comes time to run that crunched Koala picture, unless you filled back all that empty space with zeroes, you’d have “garbage” or “static” hires all around the word “Hi”.

Crunching isn’t ever one way removing of redundant data, ever! Crunching is reducing while also putting EVERTHING back as it was after de-crunching. Think of your Windows computer and WinZIP or WinRAR. Do they make your programs smaller? Yes, but they also expand them back to their original sizes after you unZip them.

Still not following? Think of it like this: You have a word processor document with a story in it. You crunch the document. Pretend that the first line of your document reads as follows:
“…………………………..My Story………………………….”

The cruncher might crunch that down to “$eMy Story$e.”
but when you decrunch it, you want those repetitive periods back. This is what I mean when I say that crunching always puts back what it has crunched. It doesn’t just condense, it also expands. You don’t lose the original uncrunched data.

So in answer to how does a cruncher put data back as it was without writing over itself, this is the answer….

If you turn on your C64 and type:
And go into your MLM (machine language monitor) and type:
M 0801
You’ll see your BASIC program. It resides at $0801 which is the Start of BASIC as I’ve told you. ($0800 is the start of basic but $0800 will always be a zero, so technically your program loads at $0801)

A cruncher will provide you with a final product that you can LOAD and RUN because it has a line number -in this case of the game Blue Max it’s:
0 SYS 2061

When you run the program, the cruncher copies a little bit of code down into lower memory (most often $0100 or the $0300 area). This memory isn’t often used by games. Once it’s copied itself to that area, it then proceeds to go through everything it once crunched and puts it back into place. This is why you can crunch data at $0800 and still be able to unpack it even though the crunched program loads in at $0800. By copying itself to lower memory, it provides itself a safe area in which to unpack the data, out of way.

Having difficulty understanding this? If the answer is no, continue to Section 2.4. If the answer is yes, read on….

Take a piece of paper and draw 5 boxes to represent the C64’s memory.
[1] [2] [3] [4] [5]
The first box is the C64’s memory from $0000 to $0800. No matter what program you load from disk, that area is not being used at this time because we know that BASIC programs always load in at $0801. Box 2 is memory starting at $0800.

Even if it’s a single line program that calls a machine language game, it’s still considered BASIC if you can LIST it.

So the second box (memory beginning at $0800) will always contain our program…. And depending on the size of the program, it might also use up the 3rd and 4th box of RAM memory. The final box, the fifth one, is the ROM memory. Our BASIC program doesn’t ever touch that area. In fact we can draw a large X through the last box.

Now say that you have a very large BASIC program that uses the 2nd, 3rd and fourth boxes of memory. You want to crunch that program with a cruncher. So you crunch it and end up with a final product that’s almost ONE THIRD the size of your original program.

Now… you load in your crunched program and type RUN. Your BASIC program starts right away. When you loaded in your crunched program, where did it load into? It loaded into the second box of course. All BASIC programs load into $0801. In fact the new file is so small that the third and fourth boxes aren’t even needed. Your crunched file is so small that it now only occupies one ‘box’ instead of the original three, the rest is free memory.

Still…. With our crunched program in the second box, it needs to uncrunch into something that is your full blown BASIC program. A BASIC program that was so large that it used to fill the 2nd, 3rd and fourth boxes. Remember, crunching isn’t a one way process, we need our original program back – the very large program that uses up three boxes of memory.

But how can we have our crunched program in box 2 AND overwrite it with our uncompressed program that also belongs in box 2 (and boxes 3 and 4)? Won’t the crunched program and the uncrunched program overwrite one another in box #2? Yes.

The solution:

When you run a crunched game, the cruncher copies part of itself into the box #1, the area BELOW where BASIC programs load. That little piece of code handles all of the de-runching so that it can take your data and decrunch it without overwriting itself. I’m sure you’ve seen programs that, when you ran them, the border changes colours, maybe you heard a bunch of static noise from the speaker, maybe some characters on the screen change, the entire screen might flash colours… this is the program ‘uncrunching’. And it’s uncrunching process is happening BELOW where BASIC is, so that it doesn’t overwrite itself.

2.3 Stopping the decrunch routine

When trying to crack a single file game, or training (cheating) a game or just trying to capture a game from disk or tape, it’s not recommended to do so once the game has started. The game might overwrite part of itself once the code has been executed. Some memory locations might have been changed. You might not be able to find out what the ‘start address’ is.

We always want to save a game to disk AFTER it’s de-crunched but BEFORE it begins to play. A crunched game is of no use to us, we can’t examine the true data nor could we make a cheat for it, or add a high score saver, etc. It’s all squeezed into a small file. We want the original game de-crunched. (uncrunched and de-crunched mean the same)

So how does one accomplish this? It can be impossible to enter your machine language monitor in the split second between the end of the de-crunching and the game starting. We need something more practical.

To accomplish this… we need to create a ‘loop’. A loop that will cause the computer to go into an endless circle, doing nothing. We want the equivalent of typing:
10 GOTO 10

The process will usually be the same.
1) Load in the single file game.
2) RUN
3) Right away enter the machine language monitor (ALT-M in CCS64 emulator, or pressing the appropriate button on your cartridge)
4) Once you enter your MLM, there’s something you need to pay attention to.
There is immediately a series of numbers and letters on the screen:

It looks something like:
0231 0001 36 00 00 F4 0000 0000 00


These are very important. Much of the information shown is beyond the scope of the article but the IRQ and NMI tells us what ‘interrupts’ are being used. The AC/XR/YR shows us whats in the Accumulator, X and Y registers. But the one we want to look at is the PC.

PC means Program Counter. You know that when you run a BASIC program it starts with the first line number and works its way down. It might branch off for a GOSUB but it will come back on a RETURN.

20 GOSUB 100
30 END

Machine language works the very same way. It has a starting address (in BASIC that would be line 10), it can branch off like a GOSUB (line 100) and it can return (to line 30) like the RETURN command. By looking at the PC number, we can tell what memory location the C64 is currently processing. It’s like pressing RUN STOP and seeing
BREAK IN LINE 100 and knowing the C64 is processing Line 100 and then type CONT to continue the program.

PC is like telling us the line number, only it’s a memory location. It’s not all that different from BASIC line numbers.

I’m going to give you a trick, it doesn’t always work but it will work in about 50% of the games you try. In fact this is the trick I use all the time for my own cracks. I recommend that you use this trick all the time. You don’t even need to look at what the PC number is because this trick works so well. It will work with tape loaders, it may also work with full disk games where there’s only a single auto-run file.

The Trick

By now we know that some games will use that ‘hidden’ RAM that’s under the ROM chips. We know that if you set the value of location 1 to $37 or $34 that we can turn on and off this hidden RAM.

In any de-crunch routine, it’s going to turn off the ROM and turn on the RAM (it’s going to switch out the ROM). It has to do this because as it decrunches, we know that we can’t just write on top of ROM. In our analogy speak – a decrunch routine is going to always tell the ROM guys to get out of their houses while we depack just in case our game needs to place code in memory originally used by ROM. We can’t write to ROM memory so we change location 1 to allow us to use the ‘houses’ as RAM.

So what if we look for the part where the decruncher turns ROM back on when its done uncrunching? That is… what if we look for the part where it says, “Okay guys I’m done uncrunching the game, I’m ready to start the game. I’m going to bring the ROM guys back to their houses and away we go.”

And for this, we look for the following 6502 commands:
LDA #$37
STA $01
JMP $xxxx
Usually the line JMP $xxxx is the start address of the game we want. It’s not always going to be that easy, but sometimes it is.

In English the above code means LOAD A with a value of #$37
STORE A in location $01 (turn our ROM back on)
JUMP to location xxxx (where xxxx can be anything)

This code is essentially is the same as typing POKE 1, 55 and it’s the final stage before a decruncher starts a game. Why am I so sure this trick will work? Well I can’t say it will work 100% of the time but 90% of the time it’s the very last line of code the decruncher does before starting the game – or it’s not too far off from the code that does start the game.

The reason that a decruncher will set the value of location 1 back to $37 is that it doesn’t know if the game wants to use the ROM or not. It just wants to be safe… if the game programmer wants to use the memory under ROM, he’ll change the value of 1 to $34 on his own.

Every command in machine language has a two digit ‘op code’ associated with it. You can see these op-codes when you disassemble the code in CCS.

Do you understand what you’re looking at when you disassemble a program? Are you comfortable with using the D and M commands in a MLM? If you’re comfortable with using a MLM, proceed. Otherwise please read Section A – Additioanl Help on Op-codes

Putting it all together

- We know we need to intercept the game before it starts and after it’s de-crunched
- We know that the location of 1 will probably be set back to $37
- We know that op-codes are the numbers found in memory that also represent actual machine language commands.

I’d like you to now load the game Blue Max which can be found here:

RUN the game Blue Max and WAIT until the scroller and loading music starts. This tape loader played a little tune to keep you entertained during the old days of long tape loads. Once you hear the loading music but the actual game hasn’t begun yet, enter your MLM by pressing ALT-M in CCS64.


So we want to search for LDA #$37 and STA $01 and how we do this is through opcodes:
Type in:
H 0000 0800 A9 37 85 01
This says “hunt from memory location $0000 to $0800 for the following: $A9 $37 $85 $01”


IMPORTANT TIP: Remember, no matter what the game, no matter what the decruncher you should always start with this line:
H 0000 0800 A9 37 85 01

Now I chose $0000 and $0800 as a ‘safe zone’ to search. I don’t know exactly how much of the C64’s memory is being used for the decrunch routine. I just know that most decrunch routines are below BASIC (that is, less than $0800). You normally don’t put decrunch code higher than $0800 because that’s memory we want to keep free for our game as it loads and then decrunches. A decruncher doesn’t know how much of the C64’s memory your game will use, it might only need a little bit or it might need the full RAM. Just to be safe a decruncher will usually do its magic BELOW BASIC (that is, in memory less than $0800).

By typing
H 0000 0800 A9 37 85 01
I’m searching from $0000 to $0800 which should be 99% of any and all decrunch routines out there (that’s quite a claim but I think it’s true).

As for what we’re searching for, I can break down the op-codes:
A9 means LDA (“Load A with a value”), 37 is just the value to load into “A”. Put together this means LDA #$37 or “Load A with a value of $37”
85 means STA and 01 means, well location 1. Put together it means “Store A into location 1”
It’s just like saying in BASIC
A = 37
(except that 37 is hex so it would actually be A=55). However aside from that, this is exactly what those two lines of machine code accomplish. We just want to find where the decruncher is setting 1 back to it’s normal value because the next line of code will probably be the command to start the game.

And voila!!! Location $3EE has what we’re looking for.

If we type D 3EE to see what’s going on here… it shows:
:03EE a9 37 lda #$37
:03F0 85 01 sta $01
:03F2 20 84 ff jsr $ff84
:03F5 4c 00 40 jmp $4000


This says, load “a” with $37, store “a” into $01 (turning ROM back on) and JSR (jump to $4000).

I suspect that $4000 is going to be the start of our game. Why not $FF84 as seen at memory location $03F2? Because $F000 bank is ROM, and we see location 1 is set to $37 so we know ROM is turned on. There’s no way this is game code.

Since location $03F5 is a JMP $4000 let’s change that to make an indefinite loop. We’re going to use a new command, the ASSEMBLE command. The A command is used to assemble and it allows us to create 6502 code.

So on a new line type
A 03F5 JMP $03F5


We’re saying, assemble code into location $03F5. And that code is telling the 64 to JUMP to location $03F5 (jump back to yourself). It’s like typing 10 GOTO 10.

Now exit the MLM and wait…. (if the game starts, you didn’t do it right. You have to enter the loop AFTER the loader scroller and music begin to play)

Note: While testing this, I found that around the last two “blocks to load”, the loader puts back the code to “JMP $4000”. So even if you change it, it puts it back. I recommend waiting until the Blocks to Load reaches the 01 mark and then quickly break into the MLM and change $03F5 to JMP $03F5.

And once the counter reaches zero, we press ALT-M to check the PC value which should show $3F5. so yes, we’re in the endless loop now because PC tells us what line number (err location) is currently being executed.

Now what?

We want to save memory to disk. To do this we use the “S” command in our MLM. First we want to avoid mistakes like those other crackers used to make – we want to turn off ROM. Type “BANK 0” in your CCS64 MLM, or using your cartridge monitor change the value of location 1 to a $34. Remember you can do this using the F command to fill, or you can scroll up to the 37 and change it to a 34.

The format for Save is:
S “filename” (device) (start address) (end address)
So for cartridge users it would be
S “bluemax” 08 0800 FFFF

In CCS64 you’re going to type:
SP “bluemax” 0800 FFFF
instead of S, and you also don’t need to supply a device.


I’m not sure how other monitors save, but you want to capture $0800 to $FFFF. You’ll have to read up on how you cartridge loads and saves.

And just to test it… completely reset the CCS emulator by pressing Alt-Shift-R to do a hard reset (or exit and reload CCS). And we’re going to load in our Blue Max 2001 game as raw data, no compression and no tape loader. In your MLM first, turn off ROM because we saved what was under the ROM and when we load it back in, it will try to load into ROM. Type BANK 0 (or change location 1 to a $34)
In CCS64 type: LP “bluemax”
Or with your cartridge, something like L “bluemax” 08
Now exit the monitor (be sure to set $01 back to $37 if not using CCS64)




And remember that JMP $4000? We know that 4*4096 = 16384 so type
And tell me how you think you did :) If you see the game running, you did just fine!

2.4 Review

Games that are single file LOAD and RUN programs, will always load in at $0801 (I say $0800 but $0800 always holds a value of zero).

De-crunch routines will always be found in memory above $0800 *before* you run the game because, well… where else do programs load when you type LOAD? They load in at $0801 and proceed from there. These de-crunch routines will copy themselves to below $0800 once you type in RUN.

We know that we have to intercept the de-crunch after we’ve typed RUN and BEFORE the game starts,

We know that once we type RUN we can immediately so a search for these bytes:
A9 37 85 01 which translates to:
LDA #$37
STA $01

We know that if there’s a JMP command immediately after the above two lines of code, it’s going to be the start of the game (or a trainer).

Posts: 9
Joined: Sun Jun 07, 2015 5:35 pm
Location: USA

Re: So You Want to Crack & Train Commodore 64 Games Like a P

Post by retrohoarder » Sat Jun 20, 2015 3:38 am

I'm not really looking to learn how to crack/train games, but I've got to say that I've learned A LOT more about the C64 reading/working through this.

Thank you!

Post Reply Previous topicNext topic

Who is online

Users browsing this forum: No registered users and 1 guest