mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
o registers
- replaced both register implementations with just one that uses 32 bit integers as the underlying implementation. very smart and very quick by comparison to the bit array implementation.
This commit is contained in:
parent
b7e037a3b7
commit
eb17bc1f63
17 changed files with 486 additions and 747 deletions
|
@ -62,7 +62,7 @@ func (bp *breakpoints) parseUserInput(dbg *Debugger, parts []string) error {
|
|||
}
|
||||
|
||||
var target breakTarget
|
||||
target = &dbg.vcs.MC.PC
|
||||
target = dbg.vcs.MC.PC
|
||||
|
||||
for i := 1; i < len(parts); i++ {
|
||||
val, err := strconv.ParseUint(parts[i], 0, 16)
|
||||
|
@ -73,15 +73,15 @@ func (bp *breakpoints) parseUserInput(dbg *Debugger, parts []string) error {
|
|||
default:
|
||||
return fmt.Errorf("unrecognised target (%s) for %s command", parts[i], parts[0])
|
||||
case "PC":
|
||||
target = &dbg.vcs.MC.PC
|
||||
target = dbg.vcs.MC.PC
|
||||
case "A":
|
||||
target = &dbg.vcs.MC.A
|
||||
target = dbg.vcs.MC.A
|
||||
case "X":
|
||||
target = &dbg.vcs.MC.X
|
||||
target = dbg.vcs.MC.X
|
||||
case "Y":
|
||||
target = &dbg.vcs.MC.Y
|
||||
target = dbg.vcs.MC.Y
|
||||
case "SP":
|
||||
target = &dbg.vcs.MC.SP
|
||||
target = dbg.vcs.MC.SP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,20 +8,18 @@ package cpu
|
|||
import (
|
||||
"fmt"
|
||||
"headlessVCS/hardware/cpu/definitions"
|
||||
"headlessVCS/hardware/cpu/registers"
|
||||
"headlessVCS/hardware/cpu/registers/r16bit"
|
||||
"headlessVCS/hardware/cpu/registers/rbits"
|
||||
"headlessVCS/hardware/cpu/register"
|
||||
"headlessVCS/hardware/memory"
|
||||
"log"
|
||||
)
|
||||
|
||||
// CPU is the main container structure for the package
|
||||
type CPU struct {
|
||||
PC r16bit.Register
|
||||
A rbits.Register
|
||||
X rbits.Register
|
||||
Y rbits.Register
|
||||
SP rbits.Register
|
||||
PC *register.Register
|
||||
A *register.Register
|
||||
X *register.Register
|
||||
Y *register.Register
|
||||
SP *register.Register
|
||||
Status StatusRegister
|
||||
|
||||
memory memory.CPUBus
|
||||
|
@ -35,38 +33,35 @@ type CPU struct {
|
|||
|
||||
// NewCPU is the preferred method of initialisation for the CPU structure
|
||||
func NewCPU(memory memory.CPUBus) *CPU {
|
||||
var err error
|
||||
|
||||
mc := new(CPU)
|
||||
mc.memory = memory
|
||||
|
||||
r, err := registers.Generate(0, 16, "PC")
|
||||
mc.PC, err = register.NewRegister(0, 16, "PC")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
mc.PC = r.(r16bit.Register)
|
||||
|
||||
r, err = registers.Generate(0, 8, "A")
|
||||
mc.A, err = register.NewRegister(0, 8, "A")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
mc.A = r.(rbits.Register)
|
||||
|
||||
r, err = registers.Generate(0, 8, "X")
|
||||
mc.X, err = register.NewRegister(0, 8, "X")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
mc.X = r.(rbits.Register)
|
||||
|
||||
r, err = registers.Generate(0, 8, "Y")
|
||||
mc.Y, err = register.NewRegister(0, 8, "Y")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
mc.Y = r.(rbits.Register)
|
||||
|
||||
r, err = registers.Generate(0, 8, "SP")
|
||||
mc.SP, err = register.NewRegister(0, 8, "SP")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
mc.SP = r.(rbits.Register)
|
||||
|
||||
mc.Status = NewStatusRegister("ST")
|
||||
|
||||
|
@ -386,7 +381,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
}
|
||||
|
||||
// using 8bit addition because we don't want a page-fault
|
||||
adder, err := rbits.Generate(mc.X, 8, "")
|
||||
adder, err := register.NewRegister(mc.X, 8, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -417,7 +412,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
adder, err := rbits.Generate(mc.Y, 16, "")
|
||||
adder, err := register.NewRegister(mc.Y, 16, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -448,7 +443,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
adder, err := rbits.Generate(mc.X, 16, "")
|
||||
adder, err := register.NewRegister(mc.X, 16, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -481,7 +476,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
adder, err := rbits.Generate(mc.Y, 16, "")
|
||||
adder, err := register.NewRegister(mc.Y, 16, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -513,7 +508,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adder, err := rbits.Generate(indirectAddress, 8, "")
|
||||
adder, err := register.NewRegister(indirectAddress, 8, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -532,7 +527,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
adder, err := rbits.Generate(indirectAddress, 8, "")
|
||||
adder, err := register.NewRegister(indirectAddress, 8, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -780,7 +775,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
}
|
||||
|
||||
case "INC":
|
||||
r, err := rbits.Generate(value, 8, "")
|
||||
r, err := register.NewRegister(value, 8, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -790,7 +785,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
value = r.ToUint8()
|
||||
|
||||
case "DEC":
|
||||
r, err := rbits.Generate(value, 8, "")
|
||||
r, err := register.NewRegister(value, 8, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -800,7 +795,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
value = r.ToUint8()
|
||||
|
||||
case "CMP":
|
||||
cmp, err := rbits.Generate(mc.A, mc.A.Size(), "")
|
||||
cmp, err := register.NewRegister(mc.A, mc.A.Size(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -809,7 +804,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
mc.Status.Sign = cmp.IsNegative()
|
||||
|
||||
case "CPX":
|
||||
cmp, err := rbits.Generate(mc.X, mc.X.Size(), "")
|
||||
cmp, err := register.NewRegister(mc.X, mc.X.Size(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -818,7 +813,7 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
mc.Status.Sign = cmp.IsNegative()
|
||||
|
||||
case "CPY":
|
||||
cmp, err := rbits.Generate(mc.Y, mc.Y.Size(), "")
|
||||
cmp, err := register.NewRegister(mc.Y, mc.Y.Size(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -827,14 +822,14 @@ func (mc *CPU) ExecuteInstruction(cycleCallback func()) (*InstructionResult, err
|
|||
mc.Status.Sign = cmp.IsNegative()
|
||||
|
||||
case "BIT":
|
||||
cmp, err := rbits.Generate(mc.A, mc.A.Size(), "")
|
||||
cmp, err := register.NewRegister(mc.A, mc.A.Size(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmp.AND(value)
|
||||
mc.Status.Zero = cmp.IsZero()
|
||||
mc.Status.Sign = cmp.IsNegative()
|
||||
mc.Status.Overflow = cmp.IsOverflow()
|
||||
mc.Status.Overflow = cmp.IsBitV()
|
||||
|
||||
case "JMP":
|
||||
mc.PC.Load(address)
|
||||
|
|
|
@ -65,7 +65,7 @@ func testRegsiterArithmetic(t *testing.T, mc *cpu.CPU, mem *MockMem) {
|
|||
// LDA immediate; ADC immediate
|
||||
origin = mem.putInstructions(origin, 0xa9, 1, 0x69, 10)
|
||||
step(t, mc) // LDA #1
|
||||
step(t, mc) // ADC #1
|
||||
step(t, mc) // ADC #10
|
||||
mflib.Assert(t, mc.A, 11)
|
||||
|
||||
// SEC; SBC immediate
|
||||
|
|
295
hardware/cpu/register/register.go
Normal file
295
hardware/cpu/register/register.go
Normal file
|
@ -0,0 +1,295 @@
|
|||
package register
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Register is an array of of type bit, used for register representation
|
||||
type Register struct {
|
||||
value uint32
|
||||
size uint
|
||||
label string
|
||||
|
||||
signBit uint32
|
||||
vbit uint32
|
||||
mask uint32
|
||||
|
||||
hexformat string
|
||||
binformat string
|
||||
}
|
||||
|
||||
// NewRegister is the preferred method of initialisation for Register
|
||||
func NewRegister(value interface{}, size int, label string) (*Register, error) {
|
||||
if size != 8 && size != 16 {
|
||||
return nil, fmt.Errorf("unsupport bit size (%d)", size)
|
||||
}
|
||||
|
||||
r := new(Register)
|
||||
switch value := value.(type) {
|
||||
case *Register:
|
||||
r.value = value.value
|
||||
case int:
|
||||
r.value = uint32(value)
|
||||
case uint8:
|
||||
r.value = uint32(value)
|
||||
case uint16:
|
||||
r.value = uint32(value)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(value)))
|
||||
}
|
||||
r.size = uint(size)
|
||||
r.label = label
|
||||
if size == 8 {
|
||||
r.signBit = 0x00000080
|
||||
r.vbit = 0x00000040
|
||||
r.mask = 0x000000FF
|
||||
r.hexformat = "0x%02x"
|
||||
r.binformat = "%08b"
|
||||
} else if size == 16 {
|
||||
r.signBit = 0x00008000
|
||||
r.vbit = 0x00004000
|
||||
r.mask = 0x0000FFFF
|
||||
r.hexformat = "0x%04x"
|
||||
r.binformat = "%016b"
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Size returns the number of bits in register
|
||||
func (r Register) Size() int {
|
||||
return 8
|
||||
}
|
||||
|
||||
// Label returns the label assigned to the register
|
||||
func (r Register) Label() string {
|
||||
return r.label
|
||||
}
|
||||
|
||||
// IsNegative checks the sign bit of the register
|
||||
func (r Register) IsNegative() bool {
|
||||
return r.value&r.signBit == r.signBit
|
||||
}
|
||||
|
||||
// IsZero checks if register is zero
|
||||
func (r Register) IsZero() bool {
|
||||
return r.value == 0
|
||||
}
|
||||
|
||||
// IsBitV is used by the BIT instruction and returns the state of Bit6 (the bit
|
||||
// next to the sign bit. it's a bit odd because it is only ever used by the BIT
|
||||
// instruction and the BIT instruction only ever uses 8 bit registers.
|
||||
// none-the-less, we've generalised it so it can be used with 16 bit registers
|
||||
// too (for completion)
|
||||
func (r Register) IsBitV() bool {
|
||||
return r.value&r.vbit == r.vbit
|
||||
}
|
||||
|
||||
func (r Register) String() string {
|
||||
return fmt.Sprintf("%s: %d [%s] %s", r.label, r.ToUint(), r.ToHex(), r.ToBits())
|
||||
}
|
||||
|
||||
// ToString returns the string representation of an aribtrary value
|
||||
func (r Register) ToString(v interface{}) string {
|
||||
vr, err := NewRegister(v, r.Size(), r.Label())
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%v", vr)
|
||||
}
|
||||
|
||||
// ToBits returns the register as bit pattern (of '0' and '1')
|
||||
func (r Register) ToBits() string {
|
||||
return fmt.Sprintf(r.binformat, r.value)
|
||||
}
|
||||
|
||||
// ToHex returns value as hexidecimal string
|
||||
func (r Register) ToHex() string {
|
||||
return fmt.Sprintf(r.hexformat, r.ToUint())
|
||||
}
|
||||
|
||||
// ToUint returns value of type uint, regardless of register size
|
||||
func (r Register) ToUint() uint {
|
||||
return uint(r.value)
|
||||
}
|
||||
|
||||
// ToUint8 returns value of type uint16, regardless of register size
|
||||
func (r Register) ToUint8() uint8 {
|
||||
return uint8(r.value)
|
||||
}
|
||||
|
||||
// ToUint16 returns value of type uint16, regardless of register size
|
||||
func (r Register) ToUint16() uint16 {
|
||||
return uint16(r.value)
|
||||
}
|
||||
|
||||
// Load value into register
|
||||
func (r *Register) Load(v interface{}) {
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
r.value = v.value & r.mask
|
||||
case int:
|
||||
r.value = uint32(v) & r.mask
|
||||
case uint8:
|
||||
r.value = uint32(v) & r.mask
|
||||
case uint16:
|
||||
r.value = uint32(v) & r.mask
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
}
|
||||
|
||||
// Add value to register. Returns carry and overflow states
|
||||
func (r *Register) Add(v interface{}, carry bool) (bool, bool) {
|
||||
var preNeg, postNeg bool
|
||||
|
||||
preNeg = r.IsNegative()
|
||||
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
r.value += v.value
|
||||
if carry == true {
|
||||
r.value++
|
||||
}
|
||||
|
||||
postNeg = v.IsNegative()
|
||||
case int:
|
||||
r.value += uint32(v)
|
||||
if carry == true {
|
||||
r.value++
|
||||
}
|
||||
postNeg = uint32(v)&r.signBit == r.signBit
|
||||
case uint8:
|
||||
r.value += uint32(v)
|
||||
if carry == true {
|
||||
r.value++
|
||||
}
|
||||
postNeg = uint32(v)&r.signBit == r.signBit
|
||||
case uint16:
|
||||
r.value += uint32(v)
|
||||
if carry == true {
|
||||
r.value++
|
||||
}
|
||||
postNeg = uint32(v)&r.signBit == r.signBit
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
|
||||
carry = ^r.mask&r.value != 0
|
||||
overflow := !r.IsNegative() && preNeg && postNeg
|
||||
|
||||
if carry {
|
||||
r.value &= r.mask
|
||||
}
|
||||
|
||||
return carry, overflow
|
||||
}
|
||||
|
||||
// Subtract value from register. Returns carry and overflow states
|
||||
func (r *Register) Subtract(v interface{}, carry bool) (bool, bool) {
|
||||
var val int
|
||||
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
val = int(v.value)
|
||||
case int:
|
||||
val = v
|
||||
case uint8:
|
||||
val = int(v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
|
||||
val = ^val
|
||||
val++
|
||||
val &= int(r.mask)
|
||||
|
||||
return r.Add(val, !carry)
|
||||
}
|
||||
|
||||
// AND value with register
|
||||
func (r *Register) AND(v interface{}) {
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
r.value &= v.value
|
||||
case int:
|
||||
r.value &= uint32(v)
|
||||
case uint8:
|
||||
r.value &= uint32(v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
r.value &= r.mask
|
||||
}
|
||||
|
||||
// ASL (arithmetic shift left) shifts register one bit to the left. Returns
|
||||
// the most significant bit as it was before the shift. If we think of the
|
||||
// ASL operation as a multiply by two then the return value is the carry bit.
|
||||
func (r *Register) ASL() bool {
|
||||
carry := r.IsNegative()
|
||||
r.value <<= 1
|
||||
r.value &= r.mask
|
||||
return carry
|
||||
}
|
||||
|
||||
// EOR (exclusive or) value with register
|
||||
func (r *Register) EOR(v interface{}) {
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
r.value ^= v.value
|
||||
case int:
|
||||
r.value ^= uint32(v)
|
||||
case uint8:
|
||||
r.value ^= uint32(v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
r.value &= r.mask
|
||||
}
|
||||
|
||||
// LSR (logical shift right) shifts register one bit to the rigth.
|
||||
// the least significant bit as it was before the shift. If we think of
|
||||
// the ASL operation as a division by two then the return value is the carry bit.
|
||||
func (r *Register) LSR() bool {
|
||||
carry := r.value&1 == 1
|
||||
r.value >>= 1
|
||||
r.value &= r.mask
|
||||
return carry
|
||||
}
|
||||
|
||||
// ORA (non-exclusive or) value with register
|
||||
func (r *Register) ORA(v interface{}) {
|
||||
switch v := v.(type) {
|
||||
case *Register:
|
||||
r.value |= v.value
|
||||
case int:
|
||||
r.value |= uint32(v)
|
||||
case uint8:
|
||||
r.value |= uint32(v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported value type (%s)", reflect.TypeOf(v)))
|
||||
}
|
||||
r.value &= r.mask
|
||||
}
|
||||
|
||||
// ROL rotates register 1 bit to the left. Returns new carry status.
|
||||
func (r *Register) ROL(carry bool) bool {
|
||||
retCarry := r.IsNegative()
|
||||
r.value <<= 1
|
||||
if carry == true {
|
||||
r.value |= 1
|
||||
}
|
||||
r.value &= r.mask
|
||||
return retCarry
|
||||
}
|
||||
|
||||
// ROR rotates register 1 bit to the right. Returns new carry status.
|
||||
func (r *Register) ROR(carry bool) bool {
|
||||
retCarry := r.value&1 == 1
|
||||
r.value >>= 1
|
||||
if carry == true {
|
||||
r.value |= r.signBit
|
||||
}
|
||||
r.value &= r.mask
|
||||
return retCarry
|
||||
}
|
155
hardware/cpu/register/register_test.go
Normal file
155
hardware/cpu/register/register_test.go
Normal file
|
@ -0,0 +1,155 @@
|
|||
package register_test
|
||||
|
||||
import (
|
||||
"headlessVCS/hardware/cpu/register"
|
||||
"headlessVCS/mflib"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
r16(t)
|
||||
r8(t)
|
||||
}
|
||||
|
||||
func r16(t *testing.T) {
|
||||
var carry, overflow bool
|
||||
|
||||
// initialisation
|
||||
r16, err := register.NewRegister(0, 16, "TEST")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
mflib.Assert(t, r16.IsZero(), true)
|
||||
mflib.Assert(t, r16, 0)
|
||||
|
||||
// loading & addition
|
||||
r16.Load(127)
|
||||
mflib.Assert(t, r16, 127)
|
||||
r16.Add(2, false)
|
||||
mflib.Assert(t, r16, 129)
|
||||
mflib.Assert(t, r16, "0000000010000001")
|
||||
|
||||
r16.Load(0xffff)
|
||||
mflib.Assert(t, r16.IsNegative(), true)
|
||||
carry, overflow = r16.Add(1, false)
|
||||
mflib.Assert(t, carry, true)
|
||||
mflib.Assert(t, overflow, false)
|
||||
mflib.Assert(t, r16.IsZero(), true)
|
||||
|
||||
// register operand
|
||||
r16b, err := register.NewRegister(10, 16, "TEST B")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
mflib.Assert(t, r16b, 10)
|
||||
r16.Add(r16b, true)
|
||||
mflib.Assert(t, r16, 11)
|
||||
|
||||
// subtraction
|
||||
r16.Subtract(1, true)
|
||||
mflib.Assert(t, r16, 10)
|
||||
r16.Subtract(10, true)
|
||||
mflib.Assert(t, r16.IsZero(), true)
|
||||
mflib.Assert(t, r16.IsNegative(), false)
|
||||
r16.Subtract(1, true)
|
||||
mflib.Assert(t, r16.IsZero(), false)
|
||||
mflib.Assert(t, r16.IsNegative(), true)
|
||||
|
||||
// logical operators
|
||||
r16.Load(0x21)
|
||||
r16.AND(0x01)
|
||||
mflib.Assert(t, r16, 0x01)
|
||||
r16.EOR(0xFFFF)
|
||||
mflib.Assert(t, r16, 0xFFFE)
|
||||
r16.ORA(0x1)
|
||||
mflib.Assert(t, r16, 0xFFFF)
|
||||
|
||||
// shifts
|
||||
r16.Load(0xFF)
|
||||
carry = r16.ASL()
|
||||
mflib.Assert(t, r16, 0x01FE)
|
||||
mflib.Assert(t, carry, false)
|
||||
carry = r16.LSR()
|
||||
mflib.Assert(t, r16, 0x00FF)
|
||||
mflib.Assert(t, carry, false)
|
||||
carry = r16.LSR()
|
||||
mflib.Assert(t, carry, true)
|
||||
|
||||
// rotation
|
||||
r16.Load(0xff)
|
||||
carry = r16.ROL(false)
|
||||
mflib.Assert(t, r16, 0x1fe)
|
||||
mflib.Assert(t, carry, false)
|
||||
carry = r16.ROR(true)
|
||||
mflib.Assert(t, r16, 0x80ff)
|
||||
mflib.Assert(t, carry, false)
|
||||
}
|
||||
|
||||
func r8(t *testing.T) {
|
||||
var carry, overflow bool
|
||||
|
||||
// initialisation
|
||||
r8, err := register.NewRegister(0, 8, "TEST")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
mflib.Assert(t, r8.IsZero(), true)
|
||||
mflib.Assert(t, r8, 0)
|
||||
|
||||
// loading & addition
|
||||
r8.Load(127)
|
||||
mflib.Assert(t, r8, 127)
|
||||
r8.Add(2, false)
|
||||
mflib.Assert(t, r8, 129)
|
||||
mflib.Assert(t, r8, "10000001")
|
||||
|
||||
r8.Load(0xff)
|
||||
mflib.Assert(t, r8.IsNegative(), true)
|
||||
carry, overflow = r8.Add(1, false)
|
||||
mflib.Assert(t, carry, true)
|
||||
mflib.Assert(t, overflow, false)
|
||||
mflib.Assert(t, r8.IsZero(), true)
|
||||
|
||||
// register operand
|
||||
r8b, err := register.NewRegister(10, 8, "TEST B")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
mflib.Assert(t, r8b, 10)
|
||||
r8.Add(r8b, true)
|
||||
mflib.Assert(t, r8, 11)
|
||||
|
||||
// subtraction
|
||||
r8.Subtract(1, true)
|
||||
mflib.Assert(t, r8, 10)
|
||||
|
||||
// logical operators
|
||||
r8.Load(0x21)
|
||||
r8.AND(0x01)
|
||||
mflib.Assert(t, r8, 0x01)
|
||||
r8.EOR(0xFFFF)
|
||||
// note how we're EORing with a 16 bit value but the test
|
||||
// against an 8 value is correct (because the register is 8 bit)
|
||||
mflib.Assert(t, r8, 0x00FE)
|
||||
r8.ORA(0x1)
|
||||
mflib.Assert(t, r8, 0xFF)
|
||||
|
||||
// shifts
|
||||
carry = r8.ASL()
|
||||
mflib.Assert(t, r8, 0xFE)
|
||||
mflib.Assert(t, carry, true)
|
||||
carry = r8.LSR()
|
||||
mflib.Assert(t, r8, 0x007F)
|
||||
mflib.Assert(t, carry, false)
|
||||
carry = r8.LSR()
|
||||
mflib.Assert(t, carry, true)
|
||||
|
||||
// rotation
|
||||
r8.Load(0xff)
|
||||
carry = r8.ROL(false)
|
||||
mflib.Assert(t, r8, 0xfe)
|
||||
mflib.Assert(t, carry, true)
|
||||
carry = r8.ROR(true)
|
||||
mflib.Assert(t, r8, 0xff)
|
||||
mflib.Assert(t, carry, false)
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package registers
|
||||
|
||||
import (
|
||||
"headlessVCS/hardware/cpu/registers/r16bit"
|
||||
"headlessVCS/hardware/cpu/registers/rbits"
|
||||
)
|
||||
|
||||
// Register defines the minumum implementation for a register type. mutating
|
||||
// methods are not included because of the limitation in the language with
|
||||
// regard to implementing an interface with pointer receivers -- I'm not keen
|
||||
// on the idea on receiving and returning new values
|
||||
type Register interface {
|
||||
Size() int
|
||||
Label() string
|
||||
ToBits() string
|
||||
ToHex() string
|
||||
ToUint() uint
|
||||
ToUint16() uint16
|
||||
IsNegative() bool
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
// Generate calls the appropriate implementation's Generate function
|
||||
func Generate(v interface{}, bitlen int, label string) (Register, error) {
|
||||
if bitlen == 16 {
|
||||
return r16bit.Generate(v, bitlen, label)
|
||||
}
|
||||
|
||||
return rbits.Generate(v, bitlen, label)
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package r16bit
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ToBits returns the register as bit pattern (of '0' and '1')
|
||||
func (r Register) ToBits() string {
|
||||
return fmt.Sprintf("%016b", r.value)
|
||||
}
|
||||
|
||||
// ToHex returns value as hexidecimal string
|
||||
func (r Register) ToHex() string {
|
||||
if r.Size() <= 8 {
|
||||
return fmt.Sprintf("0x%02x", r.ToUint())
|
||||
}
|
||||
return fmt.Sprintf("0x%04x", r.ToUint())
|
||||
}
|
||||
|
||||
// ToUint returns value of type uint, regardless of register size
|
||||
func (r Register) ToUint() uint {
|
||||
return uint(r.value)
|
||||
}
|
||||
|
||||
// ToUint16 returns value of type uint16, regardless of register size
|
||||
func (r Register) ToUint16() uint16 {
|
||||
return uint16(r.value)
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package r16bit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Generate is used to create a register of bit length bitlen, using a value
|
||||
// (v) to initialise it. v can be another r16bit.Register or an integer type
|
||||
// (int, uint8 or uint16)
|
||||
func Generate(v interface{}, bitlen int, label string) (Register, error) {
|
||||
if bitlen != 16 {
|
||||
return Register{}, fmt.Errorf("bitlen of %d not allowed; only 16 bits allowed with this implementation", bitlen)
|
||||
}
|
||||
|
||||
switch v := v.(type) {
|
||||
case Register:
|
||||
return v, nil
|
||||
case uint16:
|
||||
return Register{value: v, label: label}, nil
|
||||
case uint8:
|
||||
return Register{value: uint16(v), label: label}, nil
|
||||
case uint:
|
||||
return Register{value: uint16(v), label: label}, nil
|
||||
case int:
|
||||
return Register{value: uint16(v), label: label}, nil
|
||||
}
|
||||
|
||||
return Register{}, fmt.Errorf(fmt.Sprintf("value is of an unsupported type [%s]", reflect.TypeOf(v)))
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package r16bit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Register is an array of of type bit, used for register representation
|
||||
type Register struct {
|
||||
value uint16
|
||||
label string
|
||||
}
|
||||
|
||||
// Size returns the number of bits in register
|
||||
func (r Register) Size() int {
|
||||
return 16
|
||||
}
|
||||
|
||||
// Label returns the label assigned to the register
|
||||
func (r Register) Label() string {
|
||||
return r.label
|
||||
}
|
||||
|
||||
// Load value into register
|
||||
func (r *Register) Load(v interface{}) {
|
||||
b, err := Generate(v, 16, "")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
r.value = b.value
|
||||
}
|
||||
|
||||
// Add value to register. Returns carry and overflow states -- for this native
|
||||
// implementation, carry flag is ignored and return values are undefined
|
||||
func (r *Register) Add(v interface{}, carry bool) (bool, bool) {
|
||||
b, err := Generate(v, 16, "")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
r.value += b.value
|
||||
return false, false
|
||||
}
|
||||
|
||||
// IsNegative checks the sign bit of the register
|
||||
func (r Register) IsNegative() bool {
|
||||
return r.value&0x8000 == 0x8000
|
||||
}
|
||||
|
||||
// IsZero checks if register is zero
|
||||
func (r Register) IsZero() bool {
|
||||
return r.value == 0
|
||||
}
|
||||
|
||||
func (r Register) String() string {
|
||||
return fmt.Sprintf("%s: %d [%s] %s", r.label, r.ToUint(), r.ToHex(), r.ToBits())
|
||||
}
|
||||
|
||||
// ToString returns the string representation of an aribtrary value
|
||||
func (r Register) ToString(v interface{}) string {
|
||||
vr, err := Generate(v, r.Size(), r.Label())
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%v", vr)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package r16bit_test
|
||||
|
||||
import (
|
||||
"headlessVCS/hardware/cpu/registers/r16bit"
|
||||
"headlessVCS/mflib"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
r16, _ := r16bit.Generate(0, 16, "test r16")
|
||||
mflib.Assert(t, r16.IsZero(), true)
|
||||
mflib.Assert(t, r16, 0)
|
||||
r16.Load(127)
|
||||
mflib.Assert(t, r16, 127)
|
||||
r16.Add(2, false)
|
||||
mflib.Assert(t, r16, 129)
|
||||
mflib.Assert(t, r16, "0000000010000001")
|
||||
r16.Load(0xffff)
|
||||
mflib.Assert(t, r16.IsNegative(), true)
|
||||
r16.Add(1, false)
|
||||
mflib.Assert(t, r16.IsZero(), true)
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package rbits
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// bitVals is a lookup table for pow(2,n)
|
||||
var bitVals = [...]int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536}
|
||||
|
||||
func max(a int, b int) int {
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// ToBits returns the register as bit pattern (of '0' and '1')
|
||||
func (r Register) ToBits() string {
|
||||
s := make([]string, len(r.value))
|
||||
i := 0
|
||||
for i < len(r.value) {
|
||||
if r.value[i] {
|
||||
s[i] = "1"
|
||||
} else {
|
||||
s[i] = "0"
|
||||
}
|
||||
i++
|
||||
}
|
||||
return strings.Join(s, "")
|
||||
}
|
||||
|
||||
// ToHex returns value as hexidecimal string
|
||||
func (r Register) ToHex() string {
|
||||
if r.Size() <= 8 {
|
||||
return fmt.Sprintf("0x%02x", r.ToUint())
|
||||
}
|
||||
return fmt.Sprintf("0x%04x", r.ToUint())
|
||||
}
|
||||
|
||||
// ToUint returns value as type uint, regardless of register size
|
||||
func (r Register) ToUint() uint {
|
||||
var v uint
|
||||
|
||||
i := len(r.value) - 1
|
||||
j := 0
|
||||
for i >= 0 {
|
||||
if r.value[i] {
|
||||
v += uint(bitVals[j])
|
||||
}
|
||||
i--
|
||||
j++
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// ToUint16 returns value of size uint16, regardless of register size
|
||||
func (r Register) ToUint16() uint16 {
|
||||
if len(r.value) > 16 {
|
||||
log.Print("ToUint16: register wider than 16 bits. information may be lost")
|
||||
}
|
||||
return uint16(r.ToUint())
|
||||
}
|
||||
|
||||
// ToUint8 returns value of size uint8, regardless of register size
|
||||
func (r Register) ToUint8() uint8 {
|
||||
if len(r.value) > 8 {
|
||||
log.Print("ToUint8: register wider than 8 bits. information may be lost")
|
||||
}
|
||||
return uint8(r.ToUint())
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package rbits
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Generate is used to create a register of bit length bitlen, using a value
|
||||
// (v) to initialise it. v can be another rbits.Register or an integer type
|
||||
// (int, uint8 or uint16)
|
||||
func Generate(v interface{}, bitlen int, label string) (Register, error) {
|
||||
var val int
|
||||
|
||||
switch v := v.(type) {
|
||||
default:
|
||||
return Register{}, fmt.Errorf(fmt.Sprintf("value is of an unsupported type [%s]", reflect.TypeOf(v)))
|
||||
|
||||
case Register:
|
||||
if len(v.value) > bitlen {
|
||||
return Register{}, fmt.Errorf("[1] value is too big (%d) for bit length of register (%d)", v.ToUint16(), bitlen)
|
||||
}
|
||||
|
||||
r := new(Register)
|
||||
r.value = make([]bit, bitlen)
|
||||
r.label = label
|
||||
|
||||
// we may be copying a smaller register into a larger register so we need
|
||||
// to account for the difference
|
||||
copy(r.value[bitlen-len(v.value):], v.value)
|
||||
|
||||
return *r, nil
|
||||
|
||||
case uint16:
|
||||
val = int(v)
|
||||
case uint8:
|
||||
val = int(v)
|
||||
case uint:
|
||||
val = int(v)
|
||||
case int:
|
||||
val = v
|
||||
}
|
||||
|
||||
if bitlen == 8 && val >= 0 && val < len(bitPatterns8b) {
|
||||
r := new(Register)
|
||||
r.value = make([]bit, 8)
|
||||
r.label = label
|
||||
copy(r.value, bitPatterns8b[val])
|
||||
return *r, nil
|
||||
}
|
||||
|
||||
if bitlen == 16 && val >= 0 && val < len(bitPatterns16b) {
|
||||
r := new(Register)
|
||||
r.value = make([]bit, 16)
|
||||
r.label = label
|
||||
copy(r.value, bitPatterns16b[val])
|
||||
return *r, nil
|
||||
}
|
||||
|
||||
if val >= bitVals[bitlen] {
|
||||
return Register{}, fmt.Errorf("[2] value is too big (%d) for bit length of register (%d)", val, bitlen)
|
||||
}
|
||||
|
||||
// optimally, we'll never get to this point
|
||||
|
||||
r := new(Register)
|
||||
r.value = createBitPattern(val, bitlen)
|
||||
r.label = label
|
||||
return *r, nil
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
package rbits
|
||||
|
||||
import "log"
|
||||
|
||||
// this module of the rbits packagae contains all the methods that mutate the register
|
||||
|
||||
// Load value into register
|
||||
func (r *Register) Load(v interface{}) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("Load: %s", err.Error())
|
||||
}
|
||||
|
||||
copy(r.value, b.value)
|
||||
}
|
||||
|
||||
// Add value to register. Returns carry and overflow states
|
||||
func (r *Register) Add(v interface{}, carry bool) (bool, bool) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("Add: %s", err.Error())
|
||||
}
|
||||
|
||||
sign := r.value[0]
|
||||
|
||||
i := len(b.value) - 1
|
||||
|
||||
// ripple adder
|
||||
for i >= 0 {
|
||||
if r.value[i] == false && b.value[i] == false && carry == false { // 0 0 0
|
||||
r.value[i] = false
|
||||
carry = false
|
||||
} else if r.value[i] == false && b.value[i] == false && carry == true { // 0 0 1
|
||||
r.value[i] = true
|
||||
carry = false
|
||||
} else if r.value[i] == false && b.value[i] == true && carry == false { // 0 1 0
|
||||
r.value[i] = true
|
||||
carry = false
|
||||
} else if r.value[i] == false && b.value[i] == true && carry == true { // 0 1 1
|
||||
r.value[i] = false
|
||||
carry = true
|
||||
} else if r.value[i] == true && b.value[i] == false && carry == false { // 1 0 0
|
||||
r.value[i] = true
|
||||
carry = false
|
||||
} else if r.value[i] == true && b.value[i] == false && carry == true { // 1 0 1
|
||||
r.value[i] = false
|
||||
carry = true
|
||||
} else if r.value[i] == true && b.value[i] == true && carry == false { // 1 1 0
|
||||
r.value[i] = false
|
||||
carry = true
|
||||
} else if r.value[i] == true && b.value[i] == true && carry == true { // 1 1 1
|
||||
r.value[i] = true
|
||||
carry = true
|
||||
}
|
||||
|
||||
i--
|
||||
}
|
||||
|
||||
overflow := sign == true && b.value[0] == true && r.value[0] == false
|
||||
|
||||
return carry, overflow
|
||||
}
|
||||
|
||||
// Subtract value from register. Returns carry and overflow states
|
||||
//
|
||||
// Note that carry flag is opposite of what you might expect when subtracting
|
||||
// on the 6502/6507
|
||||
func (r *Register) Subtract(v interface{}, carry bool) (bool, bool) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("Subtract: %s", err.Error())
|
||||
}
|
||||
|
||||
// generate two's complement
|
||||
i := 0
|
||||
for i < len(b.value) {
|
||||
b.value[i] = !b.value[i]
|
||||
i++
|
||||
}
|
||||
b.Add(1, false)
|
||||
|
||||
return r.Add(b, !carry)
|
||||
}
|
||||
|
||||
// EOR - XOR Register with value
|
||||
func (r *Register) EOR(v interface{}) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("EOR: %s", err.Error())
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(r.value) {
|
||||
r.value[i] = (r.value[i] || b.value[i]) && r.value[i] != b.value[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// ORA - OR Register with value
|
||||
func (r *Register) ORA(v interface{}) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("ORA: %s", err.Error())
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(r.value) {
|
||||
r.value[i] = r.value[i] || b.value[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// AND register with value
|
||||
func (r *Register) AND(v interface{}) {
|
||||
b, err := Generate(v, len(r.value), "")
|
||||
if err != nil {
|
||||
log.Fatalf("AND: %s", err.Error())
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(r.value) {
|
||||
r.value[i] = r.value[i] && b.value[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// ROR rotates register 1 bit to the right. Returns new carry status.
|
||||
func (r *Register) ROR(carry bool) bool {
|
||||
rcarry := bool(r.value[len(r.value)-1])
|
||||
copy(r.value[1:], r.value[:len(r.value)-1])
|
||||
r.value[0] = bit(carry)
|
||||
return rcarry
|
||||
}
|
||||
|
||||
// ROL rotates register 1 bit to the left. Returns new carry status.
|
||||
func (r *Register) ROL(carry bool) bool {
|
||||
rcarry := bool(r.value[0])
|
||||
copy(r.value[:len(r.value)-1], r.value[1:])
|
||||
r.value[len(r.value)-1] = bit(carry)
|
||||
return rcarry
|
||||
}
|
||||
|
||||
// ASL (Arithmetic shift Left) shifts register one bit to the left. Returns
|
||||
// the most significant bit as it was before the shift. If we think of the
|
||||
// ASL operation as a multiply by two then the return value is the carry bit.
|
||||
func (r *Register) ASL() bool {
|
||||
rcarry := bool(r.value[0])
|
||||
copy(r.value[:len(r.value)-1], r.value[1:])
|
||||
r.value[len(r.value)-1] = bit(false)
|
||||
return rcarry
|
||||
}
|
||||
|
||||
// LSR (Logical Shift Right) shifts register one bit to the rigth.
|
||||
// the least significant bit as it was before the shift. If we think of
|
||||
// the ASL operation as a division by two then the return value is the carry bit.
|
||||
func (r *Register) LSR() bool {
|
||||
rcarry := bool(r.value[len(r.value)-1])
|
||||
copy(r.value[1:], r.value[:len(r.value)-1])
|
||||
r.value[0] = bit(false)
|
||||
return rcarry
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package rbits
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// rather than generating a bit pattern every time we can look up the pattern
|
||||
// in the following slices
|
||||
|
||||
var bitPatterns8b [][]bit
|
||||
var bitPatterns16b [][]bit
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
bitPatterns8b = make([][]bit, 256)
|
||||
for i := 0; i < 256; i++ {
|
||||
bitPatterns8b[i] = createBitPattern(i, 8)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
bitPatterns16b = make([][]bit, 65536)
|
||||
for i := 0; i < 65536; i++ {
|
||||
bitPatterns16b[i] = createBitPattern(i, 16)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createBitPattern(val int, bitlen int) []bit {
|
||||
r := make([]bit, bitlen)
|
||||
i := 0
|
||||
j := bitlen - 1
|
||||
for j >= 0 {
|
||||
bv := bitVals[j]
|
||||
if val/bv != 0 {
|
||||
r[i] = true
|
||||
val = val - bv
|
||||
}
|
||||
i++
|
||||
j--
|
||||
}
|
||||
return r
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package rbits
|
||||
|
||||
import "fmt"
|
||||
|
||||
// implementing bit as a simple boolean
|
||||
type bit bool
|
||||
|
||||
// Register is an array of of type bit, used for register representation
|
||||
type Register struct {
|
||||
value []bit
|
||||
label string
|
||||
}
|
||||
|
||||
// Size returns the number of bits in register
|
||||
func (r Register) Size() int {
|
||||
return len(r.value)
|
||||
}
|
||||
|
||||
// Label returns the label assigned to the register
|
||||
func (r Register) Label() string {
|
||||
return r.label
|
||||
}
|
||||
|
||||
// IsNegative checks the sign bit of the register
|
||||
func (r Register) IsNegative() bool {
|
||||
return bool(r.value[0])
|
||||
}
|
||||
|
||||
// IsZero checks if register is zero
|
||||
func (r Register) IsZero() bool {
|
||||
for b := range r.value {
|
||||
if r.value[b] == true {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsOverflow checks the 'overflow' bit of the register
|
||||
func (r Register) IsOverflow() bool {
|
||||
return bool(r.value[1])
|
||||
}
|
||||
|
||||
func (r Register) String() string {
|
||||
return fmt.Sprintf("%s: %d [%s] %s", r.label, r.ToUint(), r.ToHex(), r.ToBits())
|
||||
}
|
||||
|
||||
// ToString returns the string representation of an aribtrary value
|
||||
func (r Register) ToString(v interface{}) string {
|
||||
vr, err := Generate(v, r.Size(), r.Label())
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%v", vr)
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package rbits_test
|
||||
|
||||
import (
|
||||
"headlessVCS/hardware/cpu/registers/rbits"
|
||||
"headlessVCS/mflib"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
r8, err := rbits.Generate(0, 8, "test 8bit")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
r16, err := rbits.Generate(0, 16, "test 16bit")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
var carry, overflow bool
|
||||
|
||||
// register loading
|
||||
r8.Load(127)
|
||||
mflib.Assert(t, r8, "01111111")
|
||||
mflib.Assert(t, r8, 127)
|
||||
|
||||
r8.Load(r8)
|
||||
mflib.Assert(t, r8, "01111111")
|
||||
|
||||
r16.Load(1)
|
||||
mflib.Assert(t, r16, "0000000000000001")
|
||||
mflib.Assert(t, r16, 1)
|
||||
|
||||
r16.Load(256)
|
||||
mflib.Assert(t, r16, "0000000100000000")
|
||||
mflib.Assert(t, r16, 256)
|
||||
|
||||
r16.Load(1024)
|
||||
mflib.Assert(t, r16, "0000010000000000")
|
||||
mflib.Assert(t, r16, 1024)
|
||||
|
||||
// arithemtic
|
||||
r16.Add(2, false)
|
||||
mflib.Assert(t, r16, "0000010000000010")
|
||||
mflib.Assert(t, r16, 1026)
|
||||
|
||||
r16.Subtract(2, true)
|
||||
mflib.Assert(t, r16, "0000010000000000")
|
||||
mflib.Assert(t, r16, 1024)
|
||||
|
||||
r8.Add(1, false)
|
||||
r8.Subtract(1, true)
|
||||
mflib.Assert(t, r8, "01111111")
|
||||
|
||||
// arithmetic - carry/overflow
|
||||
r8.Load(255)
|
||||
mflib.Assert(t, r8, 255)
|
||||
carry, overflow = r8.Add(1, false)
|
||||
mflib.Assert(t, r8, 0)
|
||||
mflib.Assert(t, carry, true)
|
||||
mflib.Assert(t, overflow, false)
|
||||
carry, overflow = r8.Subtract(1, true)
|
||||
mflib.Assert(t, r8, 255)
|
||||
mflib.Assert(t, carry, false)
|
||||
mflib.Assert(t, overflow, false)
|
||||
carry, overflow = r8.Subtract(1, true)
|
||||
mflib.Assert(t, r8, 254)
|
||||
mflib.Assert(t, carry, true)
|
||||
mflib.Assert(t, overflow, false)
|
||||
|
||||
// bitwise
|
||||
r16.EOR(65535)
|
||||
mflib.Assert(t, r16, "1111101111111111")
|
||||
|
||||
r16.ORA(65535)
|
||||
mflib.Assert(t, r16, "1111111111111111")
|
||||
|
||||
r16.AND(253)
|
||||
mflib.Assert(t, r16, "0000000011111101")
|
||||
|
||||
r8.Load(1)
|
||||
mflib.Assert(t, r8, "00000001")
|
||||
|
||||
// rotation
|
||||
r8.ROL(false)
|
||||
mflib.Assert(t, r8, "00000010")
|
||||
|
||||
r8.ROL(true)
|
||||
mflib.Assert(t, r8, "00000101")
|
||||
|
||||
r8.ROR(true)
|
||||
mflib.Assert(t, r8, "10000010")
|
||||
|
||||
r8.ROR(false)
|
||||
mflib.Assert(t, r8, "01000001")
|
||||
|
||||
// flags
|
||||
mflib.Assert(t, r8.IsZero(), false)
|
||||
mflib.Assert(t, r8.IsNegative(), false)
|
||||
r8.ROL(false)
|
||||
mflib.Assert(t, r8.IsNegative(), true)
|
||||
r8.Load(0)
|
||||
mflib.Assert(t, r8.IsZero(), true)
|
||||
|
||||
r8.Load(255)
|
||||
carry, overflow = r8.Add(2, false)
|
||||
mflib.Assert(t, carry, true)
|
||||
mflib.Assert(t, overflow, false)
|
||||
|
||||
// addition of different sized registers
|
||||
r8.Load(1)
|
||||
r16.Load(255)
|
||||
r16.Add(r8, false)
|
||||
mflib.Assert(t, r16, 256)
|
||||
}
|
|
@ -2,8 +2,7 @@ package mflib
|
|||
|
||||
import (
|
||||
"headlessVCS/hardware/cpu"
|
||||
"headlessVCS/hardware/cpu/registers/r16bit"
|
||||
"headlessVCS/hardware/cpu/registers/rbits"
|
||||
"headlessVCS/hardware/cpu/register"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
@ -22,7 +21,7 @@ func Assert(t *testing.T, r, x interface{}) {
|
|||
t.Errorf("assert StatusRegister failed (%s - wanted %s)", r.ToBits(), x.(string))
|
||||
}
|
||||
|
||||
case r16bit.Register:
|
||||
case *register.Register:
|
||||
switch x := x.(type) {
|
||||
default:
|
||||
t.Errorf("assert failed (unknown type [%s])", reflect.TypeOf(x))
|
||||
|
@ -37,25 +36,11 @@ func Assert(t *testing.T, r, x interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
case rbits.Register:
|
||||
|
||||
switch x := x.(type) {
|
||||
default:
|
||||
t.Errorf("assert failed (unknown type [%s])", reflect.TypeOf(x))
|
||||
|
||||
case int:
|
||||
if r.ToUint16() != uint16(x) {
|
||||
t.Errorf("assert Register failed (%d - wanted %d", r.ToUint16(), x)
|
||||
}
|
||||
case string:
|
||||
if r.ToBits() != x {
|
||||
t.Errorf("assert Register failed (%s - wanted %s", r.ToBits(), x)
|
||||
}
|
||||
}
|
||||
case bool:
|
||||
if r != x.(bool) {
|
||||
t.Errorf("assert Bool failed (%v - wanted %v", r, x.(bool))
|
||||
}
|
||||
|
||||
case int:
|
||||
if r != x.(int) {
|
||||
t.Errorf("assert Int failed (%d - wanted %d)", r, x.(int))
|
||||
|
|
Loading…
Add table
Reference in a new issue