120690005
 


How to Emulate Using Visual Basic 6

HOW-TO- CPU Emulation

*note. before you write your real cpu core make sure you have read this and the memory emulation how-to

INFORMATION..

Is the first thing you need to gather, you need as much technical and accurate information as you can find. The worst thing about writing your own CPU core is finding the documentation you've based your code on has misleading details , it maybe something as simple as where the stack is located in memory but this will have detrimental effects on your emulators core. So make sure your info is accurate and precise , check by cross referencing with other documents and ask questions on the boards at retrogames if you find conflicting views.

SMALL BEGINNING

So with Information at hand we can begin, Now for the purpose of this document we will base this around the 6502 as this is what I have used for VB64 and as such Makes it a whole lot easier for me to write :), However the principals presented can be applied to any CPU core your care to write so long as you have the CPU info at hand . lets begin.

The 6502 and indeed all CPU's have a group of internal registers, In the 6502 these are.

A = Accumulator
X = X index register
Y = Y Index register

PC = Program counter

S = Status register

OK lets define these registers for better understanding.

A - Accumulator
This register is the main register that is used by you CPU to process memory values.

X - Register
Like the Accumulator in that it can be used to process one byte of memory or it can be used as an index pointer.

Y - Register
Like the Accumulator in that it can be used to processes one byte of memory or it can be used as an index pointer.

PC - Program Counter
The program counter is a 16-bit register and stores the current location of the program being run

S - Status Register
The status register is a group of 8 flags on the 6502, Each flag is represented by one BIT of this one BYTE register. On the 6502 these are arranged as follows.

N - Flag - 128 (Sign Flag, This is set depending on the SIGN of a result)
Z - Flag - 64
(Zero flag is set if the result of an operation is ZERO)
N/A
B - Flag -16
(BRK is always set unless a software BRK IRQ occurs)
D - Flag -8
(Decimal is set when working in BCD arithmetic)
I - Flag - 4
(Interrupt Disable BIT. When set no IRQ's can occur)
V - Flag -2
(Overflow flag, Set when result is to large to represent in a byte)
C - Flag -1
(Carry is set when an addition or subtraction occurs a borrow)

OK you may not understand the above fully yet but don't worry, it WILL become clear as we progress.

Now as I said the above is based upon the 6502/10 CPU , However the same principals of emulating this and the instruction methods are not indigenous to this CPU.

Instructions and addressing modes

Before we can actually begin to write any code for our emulator we need to understand the way a CPU works, Sofar we know about these register type things inside and they do something with memory. We also now there is a special register called the program counter and that this is a 16-bit register on the 6502, So lets actually look at a snippet of 6502 assembly language and see what's going on.

Address Mnemonic value
0000 LDA #$05
0002 STA $0006
0005 RTS  
0006 ???  
     

Now unless you understand 6502 Assembly you wont have a clue what's going on so lets go through it and then we can try to work out an algorithm for emulating it.

The first instruction is LDA #$05. Simply this loads the ACCUMULATOR with the Hex value of 5

The next instruction is STA $0006. Simply this STORES the Value of the ACCUMULATOR in Memory location $0006

Lastly we come to RTS, Meaning Return from subroutine. This will exit our small Assembly subroutine program at that point.

Now lets take a look at what's happening with the registers of the 6502 so we can see how to emulate them.

Remember our Program Counter well that's were we need to start, Firstly our Program Counter is set to 0000 , that's the first line of our program . We then find that at Memory location 0000 our first instruction LDA. so now we know were dealing with the LOAD Accumulator Instruction, Now for simplicity's sake I wont go into the address mode of this instruction YET. So lets continue We know that Program Counter is pointing to LDA and with LDA we now a value is needed so if we Add one to our program counter we know we are looking at memory location $0001, In that location we find the value $05.

So now we have our imaginary Accumulator loaded with $05 if we add another 1 to our Program counter we find our next instruction which is STA. Again I wont go into the address modes yet but this has a 16 bit address stored in a Lo-Byte / Hi - byte style (Little Endian - I will go into CPU Endianess later) if we take those two values programcounter +1 & programcounter + 2 we can form a 16 bit address to store our value $05 in and as it happens it is Memory location $0006

PHEW. I know , if your a blank sheet when it comes to CPU's Don't worry I am going to show you an algorithm with which we can base our imaginary CPU emulator on.

BASIC CPU EMULATION ALGORITHM

for the sake of readability we will call our program counter PC from now on.

(Start)
Set PC to $0000
(get next opcode)
if memory(pc) is LDA then do LDA
if memory(pc) is STA then do STA
if memory(pc) is RTS then stop
(go back to get next opcode)
(LDA)
Accumulator = memory(pc+1)
PC=PC+2
(go back to get next opcode)
(STA)
LOBYTE = memory(pc+1) and HIBYTE = memory(pc+2)
HIBYTE and LOBYTE = address
memory(address) = accumulator
PC=PC+3
(go back to get next opcode)

OK so its a bit more than an algorithm. Although its quite primitive with its memoryit is a working solution to emulation the LDA and STA instructions of the 6502. OK on with the show I mentioned earlier Endianess and there roll In making the 16-BIT address that our STA Opcode was using, Well lets look at that a little then we can get on with the MEAT :).

CPU Endianess

Before we continue with our explorations into CPU emulation, Its vital we understand how our CPU stores address in memory. If we look at a simple basic program and then look how its stored this will help us understand.

10 Poke 49152,50

OK, I think everyone will understand that. Were putting the value 50 into memory location 49152. Now we know our CPU is an 8-bit , So how would it store this 16-bit address in memory ?, well the 6502 stores this in a LoByte / HiByte fashion. This is called little Endian. Let me show you in one byte values the address

Decimal Hex Lo / Hi Byte
49152 $C000 $00, $C0

Right OK, so we know how to read our Little Endian address's But how do we form the value 49152 out of that ?, Easy lets imagine our program counter is pointing at an STA instruction, We know that we need an address and We know that our address are stored as little endian in a 2 byte fashion so our address is made like this

lobyte = PC +1
hibyte = PC +2

address = hibyte * 256 + lobyte

address would then point to the memory location 49152 because in decimal the hibyte $c0 = 192, and the lobyte $00 = 00 And 192 * 256 + 0 = 49152

When emulating your CPU make sure you know what endian it uses as it would be futile to use a little endian system on a big endian addressing system.

 

How to setup a CPU Emulator in VB.

Right then so now we come to actually build our VB. CPU core, First off we're going to need to setup some Constants and Declare a few variables that will serve throughout the core. Lets Imagine our CPU only has two opcodes them Being LDA and STA, You want to declare a Constant for each instruction and its addressing mode so lets do that

Const INST_LDA = &H00
Const INST_STA = &H01

OK now the BYTE value of these opcodes isn't really 00 and 01, In all reality your gonna be setting up around 150 - 200 of these instruction constants. But as I said this is just so you can see what's going.

Now lets declare some variable's

Public STATUSREG as byte
Public ACCUMULATOR as byte
Public XREGISTER as byte
Public YREGISTER as byte
Public PCOUNTER as long

Right now you can see I've declared our CPU's Register and there type value. Notice the STATUSREG is declared as a byte value So How do we control the 8 Bits that determine our Flags. Let me show you

we know that the Sign flag is the 7th Bit in the Status register and if we look at how an 8 bit value is made into a byte the penny should drop.

7
6
5
4
3
2
1
0
BIT
128
64
32
16
8
4
2
1
VAL

right we know that one byte can hold anything from 0 to 255 and we can see that bit 7 of our byte value would be 128 of that. So if we wanted to turn on the Nflag we would do something like

STATUSREG = STATUSREG or 128

with me sofar ? OK

right lets go in-depth into emulation of the LDA instruction. If we take the small program we had to begin with.

Address Mnemonic value
0000 LDA #$05
0002 STA $0006
0005 RTS  
0006 ???  
     

Our first instruction LDA uses the Immediate Addressing mode, Meaning the one byte value after the Opcode is the value that is stored in the Accumulator, So we know LDA (immediate is a 2 byte Opcode) , Now lets look at a simple VB. routine to emulate this.

Private Sub LDAim ()
Accumulator = memory(pc+1)
if Accumulator = 0 then
STATUSREG = STATUSREG or 64 ' Turns on Zero Flag (bit 6) if true
else
STATUSREG = STATUSREG and (255-64) ' Resets Zero Flag (bit 6) if false
End if
if Accumulator and 128 then ' Check the Sign bit of accumulator
STATUSREG = STATUSREG or 128 ' Turns on N flag (bit 7) if true
else
STATUSREG = STATUSREG and (255-128) ' Resets N flag (bit 7) if false
end if
pc =pc +2
Cycles=Cycles + 2
End Sub

Do you see what's happening ?. If not just take time to go through the code until you understand.

Now you will notice at the end of our Subroutine pc = pc + 2 and Cycles = Cycles + 2. I will explain

We know that LDA in immediate addressing is a 2 byte Opcode, So that tells us our next instruction is located at pc+2 OK ?.

Right Now we come to the Cycles = Cycles + 2. To pull CPU emulation off Successfully your CPU must be cycle exact meaning in emulated time each instruction must appear to take as much time as the real CPU, as on a real CPU each instruction takes a certain amount of processor time, these are called CPU cycles, your CPU information should tell you the cycle time of each instruction

Now the next instruction is the STA instruction, Now this instruction is in Absolute addressing which means that after the instruction byte value located at PC the address the next two bytes point to the Absolute address that we want our Accumulator stored in. OK lets look at how we would emulate this instruction

Private Sub STAab ()
lobyte = memory(pc+1)
hibyte = memory(pc+2)
address = hibyte * 256 + lobyte
memory(address) = accumulator
pc=pc+3
cycles = cycles + 4
end sub

As we can see STA is a fairly easy instruction to emulate in that it requires no interaction with the CPU flags. However what I have shown you here is the very basic form of how we would emulate our instruction set. We still have to cover Memory access READS / WRITES.

Refining our subroutines

now lets imagine we've got our two Opcode emulator written and it works perfect, we can now begin to refine these routines. If we look at our STAab() subroutine we can see how we've formed the 16-bit address from the 2 byte value, In place of this we could should the length of our routine by doing.

Private Sub STAab ()
memory((memory(pc+2) * 256 )+ memory(pc+1)) = accumulator
pc=pc+3
cycles = cycles + 4
end sub

This does exactly the same as our previous routine but it's shorter and ever so slightly quicker than the previous form. However before you start optimizing and crunching , get your core working first in a readable fashion as its easier to hunt gremlins on readable code than on code that takes a NASA scientist to understand.

OK if your with me this far then move on to memory emulation where you can begin to get your emulator moving.

I hope this has help you understand CPU emulation and aids you in your task. If you are unsure about anything or cant understand something. Or if I've missed anything out that you need to know then please e-mail me so I can put it right.

Amigafeeva@aol.com

If you want to use this tutorial on your website then contact me please.