The Commodore 64.
- Only text mode
- Simple BASIC programs work
- Inputs hacked in, needs work
- No sprites
- No I/O
- No audio
retro-cs -s c64
Control-C
: STOP key
The ROMs used from this emulator were taken from the VICE source code in the data/C64
directory. The correct SHA1 checksums are listed below.
Place these files in ~/rcs/data/c64
79015323128650c742a3694c9429aa91f355905e basic
adc7c31e18c7c7413d54802ef2f4193da14711aa chargen
1d503e56df85a62fee696e7618dc5b4e781df1bb kernal
rcs-viewer c64:chars
rcs-viewer c64:colors
c1b6f3323509a981f157c55320a97ecba8b7991a monopole.prg
db84a42bbd0de88b29a40567b465bae399f9d8d0 digiloi64.prg
These are my notes from the development work on the C64 emulator. I hope that these notes are useful for those who wish to write their own emulator.
I have some thoughts on memory.
The Commodore 64 uses a banked memory scheme and I implemented that from the beginning but completely forgot to wire it up. It actually isn't that important until much later on.
I assumed that writes to a region of memory that had ROM banked in were ignored. This is not correct. Writes will go to the RAM that is being hidden underneath the ROM. I haven't encountered this so far with the Commodore 64, but I did see it in the initialization routine for the Commodore 128. The code looks similar to this:
lda $e000,x
sta $e000,x
It does this to copy certain kernal routines that need to be available even if the ROM is banked out. It looks strange to see a load/store operation to the same address but it makes sense once you know what is going on.
See the notes on the 6502 series processor.
The Commodore 64 actually has a 6510 processor but the differences between the two have no impact on this software implementation.
The main loop started out endlessly executing CPU instructions. I loaded in the ROMs, started up the emulator, and took a look at what was in video RAM:
$0400 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0410 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0420 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
...
Cleared out with blank spaces, but no text. The emulator was stuck in a loop at this location:
$ff5e: ad 12 d0 lda $d012
$ff61: d0 fb bne $ff5e
This register value contains the current raster scan line and the code is waiting for this value to go to zero. Since nothing was implemented yet to change this value, I added code to the main loop to stuff this value with zero on each iteration. Restarting the emulator got the desired result:
$0400 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0410 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0420 20 20 20 20 20 20 20 20 20 20 20 20 2a 2a 2a 2a ****
$0430 20 03 0f 0d 0d 0f 04 0f 12 05 20 36 34 20 02 01 COMMODORE 64 BA
$0440 13 09 03 20 16 32 20 2a 2a 2a 2a 20 20 20 20 20 SIC V2 ****
$0450 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0460 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$0470 20 20 20 20 20 20 20 20 20 36 34 0b 20 12 01 0d 64K RAM
$0480 20 13 19 13 14 05 0d 20 20 33 38 39 31 31 20 02 SYSTEM 38911 B
$0490 01 13 09 03 20 02 19 14 05 13 20 06 12 05 05 20 ASIC BYTES FREE
$04a0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$04b0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$04c0 20 20 20 20 20 20 20 20 12 05 01 04 19 2e 20 20 READY.
$04d0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$04e0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
$04f0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
Except for the first time when the system reported that 0 bytes were free. That was a bug in the sdc
implementation.
Tile sheet from the chargen
ROM:
For implementing text mode:
- Draw the border
- Draw the background
- Draw the characters
The characters are drawn to the texture by copying from the tile sheet and setting a color modification.
Timing now became sort of important. The simple strategy used in Pac-Man of running 20,000 CPU instructions between VBLANKs worked here too. I put in the interrupt requests at this point too but I kept commenting it out since I was having problems. It would have been better to worry about them later as it is possible to get to a cursor-less READY prompt without them. Once I had the interrupts fixed, the emulator booted up properly.
I first checked to see if I could directly insert key presses to the keyboard buffer at $c6 and update the buffer counter in $277. That worked so I went for that method to start. I just mapped the "simple" characters for now to be able to type. The fancy symbols and color directives can come later.
I then typed in the following program to see if it worked:
10 PRINT "HELLO WORLD"
20 GOTO 10
RUN
It did, but I forgot to map the STOP key so I wasn't able to stop the loop. I then botched the stop key by mapping it to Control-C but didn't handle the key release properly. I was confused for a bit when the program would run the first time but then would immediately say "BREAK" when trying to run it again.
Now I went looking for a nice simple BASIC program that I could load in for testing. I came across a game that I remembered from my youth called Monopole. It is a two player game of Monopoly with no AI. You have to actually have another person around to play.
I loaded it up and it crashed right away. There are some pointers in zero page memory that need to be updated after a BASIC program is loaded. They are the pointer to variable storage at $2d and the pointer to array storage at $2f. They needed to be updated to the first byte after the program and then everything worked as expected.
The next program I tried is a new release called Digiloi which I saw on the 8-Bit Guy. All graphics are using PETSCII characters and there are no sprites used at all. This game does change the memory bank so this was a good time to test out that code. After fixing some small bugs with the memory handling, it booted up fine. I added in some joystick mappings and was able play. There is no audio yet but this has a kicking soundtrack that will be great for testing a SID implementation later.
More to come later.
- "Bank Switching", https://www.c64-wiki.com/wiki/Bank_Switching
- Bauer, Christian, "The MOS 6567/6569 video controller (VIC-II) and its application in the Commodore 64", http://www.zimmers.net/cbmpics/cbm/c64/vic-ii
- Butterfield, Jim, "Machine Language for the Commodore 64, 128, and Other Commodore Computers. Revised and Expanded Edition", https://archive.org/details/Machine_Language_for_the_Commodore_Revised_and_Expanded_Edition
- Davison, Lee, et al, "C64 ROM disassembly. V1.01", https://github.com/mist64/c64rom/blob/master/c64rom_en.txt
- Forster, Joe, "Commodore 64 memory map", http://sta.c64.org/cbm64mem.html
- Forster, Joe, "Commodore 64 PETSCII code to screen code conversion", http://sta.c64.org/cbm64pettoscr.html
- Leemon, Sheldon, "Mapping the Commodore 64", https://archive.org/details/Compute_s_Mapping_the_Commodore_64
- Leo, Rocco Di, "VIC-II for Beginners", https://dustlayer.com/index-vic-ii
- Turner, Rebecca, "Unicode-PETSCII", https://github.com/9999years/Unicode-PETSCII
- "The Versatile Commodore Emulator", http://vice-emu.sourceforge.net/