diff --git a/debugger/breakpoints.go b/debugger/breakpoints.go index 5c109f84..d3ff6a72 100644 --- a/debugger/breakpoints.go +++ b/debugger/breakpoints.go @@ -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 } } } diff --git a/hardware/cpu/cpu.go b/hardware/cpu/cpu.go index 1811314c..498ec741 100644 --- a/hardware/cpu/cpu.go +++ b/hardware/cpu/cpu.go @@ -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) diff --git a/hardware/cpu/cpu_test.go b/hardware/cpu/cpu_test.go index acec9317..f4b66c6b 100644 --- a/hardware/cpu/cpu_test.go +++ b/hardware/cpu/cpu_test.go @@ -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 diff --git a/hardware/cpu/register/register.go b/hardware/cpu/register/register.go new file mode 100644 index 00000000..3a59dfed --- /dev/null +++ b/hardware/cpu/register/register.go @@ -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 +} diff --git a/hardware/cpu/register/register_test.go b/hardware/cpu/register/register_test.go new file mode 100644 index 00000000..d437179a --- /dev/null +++ b/hardware/cpu/register/register_test.go @@ -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) +} diff --git a/hardware/cpu/registers/generate.go b/hardware/cpu/registers/generate.go deleted file mode 100644 index e960e0f7..00000000 --- a/hardware/cpu/registers/generate.go +++ /dev/null @@ -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) -} diff --git a/hardware/cpu/registers/r16bit/conversion.go b/hardware/cpu/registers/r16bit/conversion.go deleted file mode 100644 index f41ff36d..00000000 --- a/hardware/cpu/registers/r16bit/conversion.go +++ /dev/null @@ -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) -} diff --git a/hardware/cpu/registers/r16bit/generate.go b/hardware/cpu/registers/r16bit/generate.go deleted file mode 100644 index 7a2747af..00000000 --- a/hardware/cpu/registers/r16bit/generate.go +++ /dev/null @@ -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))) -} diff --git a/hardware/cpu/registers/r16bit/registers.go b/hardware/cpu/registers/r16bit/registers.go deleted file mode 100644 index 36e2aa99..00000000 --- a/hardware/cpu/registers/r16bit/registers.go +++ /dev/null @@ -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) -} diff --git a/hardware/cpu/registers/r16bit/registers_test.go b/hardware/cpu/registers/r16bit/registers_test.go deleted file mode 100644 index e2a6b3a6..00000000 --- a/hardware/cpu/registers/r16bit/registers_test.go +++ /dev/null @@ -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) -} diff --git a/hardware/cpu/registers/rbits/conversion.go b/hardware/cpu/registers/rbits/conversion.go deleted file mode 100644 index e5150be8..00000000 --- a/hardware/cpu/registers/rbits/conversion.go +++ /dev/null @@ -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()) -} diff --git a/hardware/cpu/registers/rbits/generate.go b/hardware/cpu/registers/rbits/generate.go deleted file mode 100644 index 213b2c8f..00000000 --- a/hardware/cpu/registers/rbits/generate.go +++ /dev/null @@ -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 -} diff --git a/hardware/cpu/registers/rbits/mutate.go b/hardware/cpu/registers/rbits/mutate.go deleted file mode 100644 index e98850ec..00000000 --- a/hardware/cpu/registers/rbits/mutate.go +++ /dev/null @@ -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 -} diff --git a/hardware/cpu/registers/rbits/patterns.go b/hardware/cpu/registers/rbits/patterns.go deleted file mode 100644 index 53d2b7f3..00000000 --- a/hardware/cpu/registers/rbits/patterns.go +++ /dev/null @@ -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 -} diff --git a/hardware/cpu/registers/rbits/registers.go b/hardware/cpu/registers/rbits/registers.go deleted file mode 100644 index 5f12cf71..00000000 --- a/hardware/cpu/registers/rbits/registers.go +++ /dev/null @@ -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) -} diff --git a/hardware/cpu/registers/rbits/registers_test.go b/hardware/cpu/registers/rbits/registers_test.go deleted file mode 100644 index 78fc9a01..00000000 --- a/hardware/cpu/registers/rbits/registers_test.go +++ /dev/null @@ -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) -} diff --git a/mflib/assert.go b/mflib/assert.go index f1f9c4ad..79383df2 100644 --- a/mflib/assert.go +++ b/mflib/assert.go @@ -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))