Processors need to be
able to manipulate things very quickly but he amount of space on a processor is
limited, so memory is stored outside of the processor. To work with memory
then, a processor needs to load it into its own memory, manipulate it, then
store it back in the computer’s memory. In modern computers, memory is slow taking
many cycles to get from RAM into the processor where it can be used which is
why they have multiple levels of caches to speed things up. Back in the early
days processors ran at near the same speed as memory so this was not as much of
a problem. Still, the processor needs to hold some information to work with,
which it stores in registers.
The number and type of
registers that a processor has varies between models of processors. The 6502
has 3 main registers which are used by the programmer. It also has three
special registers which are indirectly manipulated by the programmer. The
following diagram shows the registers.
The three main
registers are the accumulator, index register x (x), and index register y (y).
The x and y registers can be used for storing temporary information but are
generally used as indexes for several addressing modes. The accumulator is
where the bulk of the work is done and is the only register that many math
related commands will work with.
The special registers
are where things get interesting. The stack index register is an index register
like x and y but is used for holding the stack index. We will be covering the
stack in a later section but essentially you add and remove things from the stack
and the stack index controls where in stack memory that item will be written to
or retrieved from. It can directly be changed with the TXS instruction and is
indirectly changed with the PHA, PHP. PLA, and PLP instructions.
The IP register is a
16 bit register and holds the address of the current instruction that is being
executed. Every time an instruction is executed it is updated to the next
instruction, which can be changed through branching instructions.
The most interesting
special register is the processor status register which holds the flags. This
is an 8 bit register but there are only 6 flags used by programmers. One of the
additional bits is always 1 and the other bit is for the break instruction. These
flags are Negative, Overflow, Decimal, Interrupt, Zero and Carry. The purpose
of each of these flags will be discussed in the section that is related to the
commands that implement them. The flags are set up as constants within the a2600Dragons.m6502
package as follows:
const val CARRY_FLAG = 1
const val ZERO_FLAG = 2
const val INTERRUPT_FLAG = 4
const val DECIMAL_FLAG = 8
const val BREAK_FLAG = 16
const val OVERFLOW_FLAG = 64
const val NEGATIVE_FLAG = 128
While I could have had
the processor state right within the M6502 class, I opted to keep the processor
state outside of the processor class to make it easy to make snapshots of the
processor state for the eventual debugger that I will be developing as well as
for the testing routines that I will be writing. Here is the processor state
class.
data class ProcessorState(var acc:Int, var x:Int, var
y:Int, var ip:Int, var flags:Int, var sp:Int, var tick:Long) {
var ipNext = ip
fun
checkState(regmem:String, expected:Int, mem:MemoryManager? = null):Boolean {
var reg =
regmem.toUpperCase()
var addr = 0
if
(reg.startsWith("M")) {
addr =
reg.substring(1).toInt(16)
reg =
"M"
}
return when
(reg) {
"A", "ACC" -> acc == expected
"X" -> x == expected
"Y" -> y == expected
"IP" -> ip == expected
"FLAGS" -> flags == expected
"C" -> ((flags and CARRY_FLAG) > 0) == (expected > 0)
"Z" -> ((flags and ZERO_FLAG) > 0) == (expected > 0)
"I"-> ((flags and INTERRUPT_FLAG) > 0) == (expected >
0)
"D"-> ((flags and DECIMAL_FLAG) > 0) == (expected >
0)
"B"-> ((flags and BREAK_FLAG) > 0) == (expected > 0)
"V"-> ((flags and OVERFLOW_FLAG) > 0) == (expected >
0)
"N" -> ((flags and NEGATIVE_FLAG) > 0) == (expected >
0)
"M" -> if (mem != null) mem.read(addr) == expected else
false
else
-> {
println("Error: unknown register or memory request $regmem.")
false
}
}
}
}
Note the checkState
function which is used to quickly check that a register, flag, or memory
address is a specific value. This is
used in testing where I simply have a bit of test code to test the instruction
followed by the list of expected valued for key registers and memory locations.
This makes writing small snippets of test code to test each of the instructions
much easier.
No comments:
Post a Comment