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:
steve 2018-04-29 21:56:01 +01:00
parent b7e037a3b7
commit eb17bc1f63
17 changed files with 486 additions and 747 deletions

View file

@ -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
}
}
}

View file

@ -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)

View file

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

View 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
}

View 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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)))
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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())
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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))