mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
- 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.
295 lines
6.6 KiB
Go
295 lines
6.6 KiB
Go
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
|
|
}
|