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.
|