Commodore VIC-20 AVR Emulator


Boot up screen

Some text poked into keyboard buffer.

Current status:

Boots up Kernel and Basic ROMS, starts up correctly and fully runs the Commodore basic programming language, can poke characters into the keyboard buffer, or use emulated hardware keyboard.

The pictures above show the emulated VIC-20 running. The original Kernal and Basic ROMS (downloadable from various sites) from the Commodore computer have been loaded into the AVRs external memory and are executed via emulation on the AVR. The fact that it boots up, and that Basic commands work (ie 10 PRINT "emile") means the 6502 CPU emualtion is likly to be fully working (there could still be a couple of bugs..)


6502 CPU, all documented instructions

Most of the VIC (graphics) IC

Low level keyboard emulation (correct row/column scanning)

60HZ ISR interupt - responsible for keyboard scanning, clock update and tape control.


Tape emulation

Enable the character ROM address being moved (very important for games to work!)



Emulation state saving

loading ROMs from enternal flash


This page describes the design and build of a VIC-20 emulator on an AVR. There are lots of ROMS on the interent for the VIC-20 which are usualy run on emulators on the PC. My aim is to make a fully working stand alone portable hardware emulator of this computer which is capable of running the original software

The Commodore VIC-20 was the predecessor to the Commodore 64, It was affordable and very popular in the early 1980's, there is lots of information on the web about the machine, so I will go straight into the technical aspects.

The VIC-20 was called so due to the Video Interface Chip used inside to generate the graphics and sound

The main VIC-20 Specifications:

CPU 6502A running at 1.0227 MHz.
ROM 16Kb.
RAM 5Kb (3.5Kb user memory) expandable to 32Kb.
VIC Screen: 22 columns by 23 rows.
Character dot matrix: 8 by 8 or 8 by 16 (User programmable).
Screen dot matrix: 176 by 184 with up to 16 colors.
Sound: 3 voices plus white noise.

At the heart of the machine is the 6502 microprocessor, this is an 8-bit processor, capable of addressing 64KB of memory - all peripherals are memory mapped into this space.
The 6502 CPU has 57 Instructions, and 10 addressing modes. There are 6 registers which hold the current state of the Processor:

Accumulator: 8-bit register used for arithmetic and logic operations.

X index: 8-bit register usually used as an index in different types of index addressing modes.

Y index: 8-bit register usually used as an index in different types of index addressing modes.

Program counter: 16-bit register.

Stack pointer: 8-bit register. The processor assumes that the higher 8-bits of the stack pointer are always set to 01h thus limiting stack to memory range 100h - 1FFh.

Processor Status: register containing the following flags:

* Negative (N) - set if the most significant bit of the result is set.
* Overflow (V)
* Break command (B)
* Decimal mode (D) - set if the processor is in decimal mode.
* IRQ disable (I) - set if the IRQ interrupt is disabled.
* Zero (Z) - set if the result is zero.
* Carry (C) - set if there was a carry from or borrow to during last result calculation.

The first task was to emulate the 6502 CPU of the VIC-20

OPCODE decoding

All the code has been written is assembly, because as you can appreciate, the instruction decoding must be done as fast as possible in order to be able to emulate a 1.0227 MHz microprocessor on a 16MHz AVR. (Not to mention all the hardware emulation which has to be done at the same time!)

The 6502 instructions are 1, 2 or 3 bytes long, depending on the instruction and the addressing mode. The first byte always contains which instruction it is, and what addressing mode it is. This means there are 256 possible combinations of opcode byte. The AVR must read this byte, and go to the appropriate routine to emulate the instruction. The most obvious method of doing this is to compare the byte to each opcode and jump to the related code when its found a match. This however would mean the instructions at the bottom of the list would take much longer to be executed after all the previous comparisons.
A much faster method is to use a jump table – this table contains 256 entries, which each contain the subroutine address for the related opcode. Indirect jumping (IJMP) can then be used to go straight to the relevant assembly code needed to decode the 6502 instruction.

When decoding opcode's in software, it is beneficial to find patterns in the codes which can be used to speed up development time, and also reduce the chance of bugs in the code.
I found this site http://axis.llx.com/~nparker/a2/opcodes.html which has found such patterns in the opcodes. The patterns found there were used in my code. Using such patterns will invariably slow down the instruction decoding, however the few extra cycles needed are easily out weighed by the decreased development time and debugging.

The opcode jump table is stored in the program memory of the AVR. The table could have been entered manually; however this would have taken a very long time, and would have been extremely prone to errors. Instead I made a VB program which generates the assembly code (.DB constants) which can be directly included into the AVR project files, the program also generates a list of opcode labels needed to be pasted into the assembly code. To take advantage of patterns in the opcodes ‘don’t cares’ can be indicated in the input file.

ORA 000...01
AND 001...01
EOR 010...01
ADC 011...01
STA 100...01
LDA 101...01
CMP 110...01
SBC 111...01
ASL 000...10
ROL 001...10
LSR 010...10
ROR 011...10
STX 100...10

Above shows an extract from the input file to the VB jump table generator. The dots in the binary code are 'dont cares' and the program will fill these with all the possible combinations.

.DB low(op_BRK),high(op_BRK),low(op_ORA),high(op_ORA),low(op_ASL),high(op_ASL),
.DB low(op_BPL),high(op_BPL),low(op_ORA),high(op_ORA),low(op_ASL),high(op_ASL),
.DB low(op_JSRA),high(op_JSRA),low(op_AND),high(op_AND),low(op_ROL),high(op_ROL)
.DB low(op_BMI),high(op_BMI),low(op_AND),high(op_AND),low(op_ROL),high(op_ROL),
.DB low(op_RTI),high(op_RTI),low(op_EOR),high(op_EOR),low(op_LSR),high(op_LSR),
.DB low(op_BVC),high(op_BVC),low(op_EOR),high(op_EOR),low(op_LSR),high(op_LSR),
.DB low(op_RTS),high(op_RTS),low(op_ADC),high(op_ADC),low(op_ROR),high(op_ROR),

Above is an extract of jump table code which is to be inculed in the AVR asm code.


The associated labes which need to be inculded are also generated. Above shows an extract of the labes. The acuall code for decoding the 6502 instructions is written where the 'nops' are.

VIC (video) emulation.

The Video Interface Chip is memory mapped on to the CPU, it ALSO has address lines of its own which can access the RAM. Bascialy the VIC and the CPU can access the RAM at different address at the same time (not at the exact same time) This is achied though 2 clock which are out of phase, letting the CPU have control of the bus on one phase, and the VIC chip have control on the other phase.

The screen is mapped into 506 bytes of RAM, there is also another 506 byte of RAM which is used for the colour of each chanracter. The display can only display 'text', although the characters can be user defined to enable simple bitmaps to be displayed for games. On the VIC-20 there is included a 4KB ROM which defines charcaters, inverted characters and various other graphics.

I decided to use the hardware from a previous project to be used as the display as it was perfect for the job. It also has an AVR Mega 128 with 64 KB expanded RAM attached, exaclty what is needed for the emulator. The display allows custon characters to be inserted into its RAM, this is exaclty what is needed as the 4KB VIC-20 ROM can be directly copied to the LCD RAM to display the correct letters and fonts.

The display is refreshed every 30ms with the content of the VIC-20 VRAM, this takes just over 1ms to complete, so adds little over head.

The LCD can not display colour, so for the moment colour information is ignored.

Specification Main Features



Assembly Code, use in AVR studio 4