6502Em - MOS Technology 6502 Processor Emulator

Introduction

This program emulates the functioning of a 6502b processor that was popular in the 1970's and 80's and was used as the basis of a number of systems such as the BBC micro and the Commodore PET to name but a few.

There is a wealth of information on the 6502 family of processors on the web so the technical coverage here is brief. The 6502 is an 8 bit processor with a 16 bit address bus that could address 64k of memory without bank switching. The version emulated here is the 6502b that ran at 1.79 MHz. The 6502 had a simple instruction set but each instruction had various address modes, all of which are emulated. Each instruction uses a 1 byte opcode followed by 0,1 or 2 bytes of data on which it operates.

Note that this emulator does not attempt to emulate any particular kind of computer or hardware, it is simply for the 6502 processor. That being said I have added some mechanisms for screen and keyboard I/O and timing. These are not based on anything in particular but were the simplest implementations I could get to work. See here.

Top

Using the Emulator

The application will run on PC's and tablets that run Windows 8 or 8.1. Since using the application is really intended as a programming environment the best experience is a PC/Tablet with a keyboard running in landscape mode, although other orientations are supported.

The top of the screen is the dashboard that has 3 sections: Left: Processor Registers, Middle: 6502 Status Registers, Right: Performance information.

Top

Dashboard

The registers are the standard 6502 registers as follows:

It is possible to overtype all registers on the left apart from SP (Stack) to directly effect their values. Note this functionality is disabled when a program is running and the values are continuously updated.

 The status register is displayed bit by bit as follows:

These individual values can set/unset by clicking on the letter next to each one. This functionality is disabled when a program is running and these registers are continually updated.

The performance information on the right is as follows:

This information is updated continuously only when a program is running.

Top

Creating and Running Programs

The remainder of the application workspace allows operation of the emulator to input and run assembler language programs. Three tabs are supplied for this accessed by the buttons Assember, Memory and VDU.

Assembly Tab

Clicking the Assembly tab shows the main windows for inputting code. Below this button is a text box, where you can freely enter assembly code. This screen also has a number of other features:

Once a program has been entered you can assemble it by clicking the Assemble button. This uses the value currently in the 6502 Program Counter as a starting memory location for assembly, although as you will see later there are instructions in the assembler that can influence where code is located.

If assembly is successful then a message "Program Compiled Succesfully" will appear below the input area. Otherwise any errors will be reported with their line number. The code view window also shows any errors against each line.

The Run button will assemble the code and then if successful run it at the location in the Program Counter.

Top

Memory Tab

Clicking the Memory button shows this tab, its primary function is debugging. It has the following features:

Top

VDU Tab

Clicking the VDU button shows this tab, its primary function is simple hardware emulation. It replaces the main memory display with 2 types of memory mapped VDU's, maintaining the other displays and buttons. It has the following features:

Details of how the hardware is programmed are given later.

Top

Bottom App Bar

The bottom app bar apppears when user right-clicks, presses Windows+Z, or swipes from the bottom edge of the screen, it has the following functions:

Top

Performance Settings

These can be found on the Windows 8 settings charm. The Wait Type and Frame rate are explained adequately on this screen. The other settings are as follows.

The "Enable Keyboard Interrupt"  - When this is true (the default), pressing a key over either of the VDU windows generates an interrupt. Unless a handler for this is installed at the correct address, the program will terminate. This can be avoided by setting this option to false. In either case the key just pressed is recorded at a particular memory location. See later for a description of how the keyboard emulation works.

Enable VDU - When this is true (the default) writing to the screen memory map will cause output to the screen displays (character or bitmap) and these are refreshed in line with the specified frame rate. When this is false writing to the screen memory has no effect and neither screen is updated.

Top

Technical Information

Assembler

The built in mnemonic assembler has the following features:

Top

Interrupts and Reset

In a 6502 processor there are three vectors at the top of memory NMI,RESET and IRQ/BRK, these are $FFFA/$FFFB, $FFFC/$FFFD and $FFEE, FFFF.

In this current implementation NMI is not implemented. This is a hardware specific 6502 pin function and in simple computers was left unused. See here.

RESET is also not implemented in that when the emulator is reset is does not automatically load the address at $FFFA/$FFFB and start executing it. It simply stops any executing code and returns the emulator to its original state.

For RESET/BRK processing a value of $F100 is used as the default location for service routines. By default this is loaded with a pseduo KIL instruction so if BRK is executed or a hardware interrupt occurs (in this implementation this could only be a keyboard interrupt) then the effect is to terminate the program. To change this behaviour a service routine can be added at location $F100.

More information on interrupts can be found by looking at the sites in the links section.

Character Based Screen Emulation

The character based screen emulation is done via a memory map.  Character are written to memory locations $C000 onwards and foreground color attributes from $C8C1 onwards, hence the following code writes a red A to the first character cell on the screen:

LDA#6
STA $C8C1
LDA#65
STA $C000

The color numbers are:
Black = 0
White = 1
Yellow = 2
Blue = 3
Green = 4
Pink = 5
Red = 6
Brown = 7

Note that the screen memory is not protected in any way so that any bytes written in to it or programs compiled in to it will cause characters to appear.

The following memory locations are memory mapped to perform screen functions:

$10 - specify current X location of flashing cursor.
$11 - specify current Y location of flashing cursor.
$12 - hardware scroll, scroll the screen this number of lines down to simulate a hardware scroll. Setting to 127 clears the screen.
$13 - set the background color of the entire screen, this cannot be done on a character basis.
$14 - number of screen rows, use to override the default.
$15 - number of screen columns, use to override the default

Top

Bitmap Based Screen Emulation

The bitmap based screen emulation is also done with a memory map.  Pixels are written to memory locations $C000 onwards. Because of the addressing limitation of 64K, each byte covers 2 pixels and allows each pixel to be colored in one of 8 colors (0000 to 0111) so that the value 00010001 will color 2 consective pixels white. The color numbers are the same as the character mapped screen.

The implementation gives a screen size of 160x256 pixels.

The implementation allows for double-buffering which produces a smooth screen refresh.

Note that the screen memory is not protected in any way so that any bytes written in to it or programs compiled in to it will cause characters to appear.

The following memory locations are memory mapped to perform screen functions:

$08 - Hardware clear screen, writing any value other than zero to this location causes the screen to be cleared and this memory location to be reset to 0.   

Top

Timer

The application provides one hardware timer emulation. The timer is of 10ms granularity and counts down from the specified value. The memory mapped I/O location is $F003.

A subroutine to do a wait is of the time specified in TIMERDELAY, if TIMERDELAY is 10 this will wait for 100ms.

WAIT:
LDA #TIMERDELAY
STA TIMERLOCATION

WAITLOOP:
LDA TIMERLOCATION
BNE WAITLOOP:

RTS

Keyboard

While the processor is running, keystrokes that occur over either of the VDU screens are captured and a hardware interrupt is generated. The following I/O locations are used:

$F000 - set to one to indicate a keyboard interrupt occurred.
$F001 - set to the scan code of the last key.
$F002 - set to the actual character generated by the last keypress $F004 - bit flags that indicate whether shift (bit 0), control (bit 1) or shift (bit 2) were pressed, 1 is pressed, 0 is not pressed.
$f004 - flags to indicate which modifier keys are pressed, the following bits are set: 0-CTRL, 1-SHIFT, 2-ALT.

One of the samples shows how to install an interrupt handler to process key presses and echo them to the screen.

The scan codes captured are the windows 8 Virtual Key Codes and are as follows:

None = 0,
LeftButton = 1,
RightButton = 2,
Cancel = 3,
MiddleButton = 4,
XButton1 = 5,
XButton2 = 6,
Back = 8,
Tab = 9,
Clear = 12,
Enter = 13,
Shift = 16,
Control = 17,
Menu = 18,
Pause = 19,
CapitalLock = 20,
Hangul = 21,
Kana = 21,
Junja = 23,
Final = 24,
Hanja = 25,
Kanji = 25,
Escape = 27,
Convert = 28,
NonConvert = 29,
Accept = 30,
ModeChange = 31,
Space = 32,
PageUp = 33,
PageDown = 34,
End = 35,
Home = 36,
Left = 37,
Up = 38,
Right = 39,
Down = 40,
Select = 41,
Print = 42,
Execute = 43,
Snapshot = 44,
Insert = 45,
Delete = 46,
Help = 47,
Number0 = 48,
Number1 = 49,
Number2 = 50,
Number3 = 51,
Number4 = 52,
Number5 = 53,
Number6 = 54,
Number7 = 55,
Number8 = 56,
Number9 = 57,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftWindows = 91,
RightWindows = 92,
Application = 93,
Sleep = 95,
NumberPad0 = 96,
NumberPad1 = 97,
NumberPad2 = 98,
NumberPad3 = 99,
NumberPad4 = 100,
NumberPad5 = 101,
NumberPad6 = 102,
NumberPad7 = 103,
NumberPad8 = 104,
NumberPad9 = 105,
Multiply = 106,
Add = 107,
Separator = 108,
Subtract = 109,
Decimal = 110,
Divide = 111,
F1 = 112,
F2 = 113,
F3 = 114,
F4 = 115,
F5 = 116,
F6 = 117,
F7 = 118,
F8 = 119,
F9 = 120,
F10 = 121,
F11 = 122,
F12 = 123,
F13 = 124,
F14 = 125,
F15 = 126,
F16 = 127,
F17 = 128,
F18 = 129,
F19 = 130,
F20 = 131,
F21 = 132,
F22 = 133,
F23 = 134,
F24 = 135,
NumberKeyLock = 144,
Scroll = 145,
LeftShift = 160,
RightShift = 161,
LeftControl = 162,
RightControl = 163,
LeftMenu = 164,
RightMenu = 165,

Top