diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/bitfield.iml b/.idea/bitfield.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/bitfield.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..304887c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/gmachine/calc.go b/gmachine/calc.go new file mode 100644 index 0000000..df6cb8c --- /dev/null +++ b/gmachine/calc.go @@ -0,0 +1,14 @@ +package gmachine + +func Calc() uint64 { + g := New() + g.Memory = []uint64{ + OpSETA, + 3, + OpDECA, + OpDECA, + OpHALT, + } + g.Run() + return g.A +} diff --git a/gmachine/calc_test.go b/gmachine/calc_test.go new file mode 100644 index 0000000..9d59f34 --- /dev/null +++ b/gmachine/calc_test.go @@ -0,0 +1,15 @@ +package gmachine + +import "testing" + +func TestCalc(t *testing.T) { + t.Parallel() + + var wants uint64 = 1 + + got := Calc() + + if wants != got { + t.Errorf("want %d, got %d", wants, got) + } +} diff --git a/gmachine/gmachine.go b/gmachine/gmachine.go new file mode 100644 index 0000000..f3e4e38 --- /dev/null +++ b/gmachine/gmachine.go @@ -0,0 +1,75 @@ +package gmachine + +import ( + "fmt" + "log" +) + +// DefaultMemSize is the number of 64-bit words of memory which will be +// allocated to a new G-machine by default. +const DefaultMemSize = 1024 + +const ( + OpHALT uint64 = iota + OpNOOP + OpINCA + OpDECA + OpSETA +) + +type gMachine struct { + // Memory 64-bit words of memory + Memory []uint64 + // P (Program counter) + P uint64 + // A (Register A) + A uint64 + // Debugging flag, if turned on will print OpCodes + DebugOn bool +} + +func New() *gMachine { + return &gMachine{ + P: 0, + Memory: make([]uint64, DefaultMemSize), + DebugOn: false, + } +} + +func (m *gMachine) NewProgram(program []uint64) { + copy(m.Memory, program) + m.Run() +} + +func (m *gMachine) Run() { + for { + pointer := m.P + m.P++ + switch m.Memory[pointer] { + case OpHALT: + m.printIfDebug("OpHALT") + return + case OpNOOP: + m.printIfDebug("OpNOOP") + case OpINCA: + m.printIfDebug("OpINCA") + m.A++ + case OpDECA: + m.printIfDebug("OpDECA") + m.A-- + case OpSETA: + m.A = m.Memory[m.P] + m.P++ + m.printIfDebug(fmt.Sprintf("OpSETA %d", m.A)) + default: + m.printIfDebug(fmt.Sprintf("COULD NOT DETERMINE OP CODE, code:%d, pointer:%d", m.Memory[pointer], pointer)) + panic(pointer) + } + } +} + +func (m *gMachine) printIfDebug(message string) { + if m.DebugOn { + log.Println(message) + } +} diff --git a/gmachine/gmachine_test.go b/gmachine/gmachine_test.go new file mode 100644 index 0000000..bf3bafb --- /dev/null +++ b/gmachine/gmachine_test.go @@ -0,0 +1,108 @@ +package gmachine_test + +import ( + "gmachine" + "testing" +) + +func TestNew(t *testing.T) { + t.Parallel() + g := gmachine.New() + wantMemSize := gmachine.DefaultMemSize + gotMemSize := len(g.Memory) + if wantMemSize != gotMemSize { + t.Errorf("want %d words of memory, got %d", wantMemSize, gotMemSize) + } + var wantP uint64 = 0 + if wantP != g.P { + t.Errorf("want initial P value %d, got %d", wantP, g.P) + } + var wantMemValue uint64 = 0 + gotMemValue := g.Memory[gmachine.DefaultMemSize-1] + if wantMemValue != gotMemValue { + t.Errorf("want last memory location to contain %d, got %d", wantMemValue, gotMemValue) + } + var wantRegisterA uint64 = 0 + gotRegisterA := g.A + if wantRegisterA != gotRegisterA { + t.Errorf("want registerA with data %d, got %d", wantRegisterA, gotRegisterA) + } + +} + +func TestHalt(t *testing.T) { + t.Parallel() + var wants uint64 = 1 + + g := gmachine.New() + g.Run() + got := g.P + + if wants != got { + t.Errorf("want P == %d, got %d", wants, got) + } +} + +func TestNOOP(t *testing.T) { + t.Parallel() + + var wants uint64 = 2 + + g := gmachine.New() + g.NewProgram([]uint64{ + gmachine.OpNOOP, + gmachine.OpHALT, + }) + got := g.P + + if wants != got { + t.Errorf("want P == %d, got %d", wants, got) + } +} + +func TestINCA(t *testing.T) { + t.Parallel() + + var wants uint64 = 1 + + g := gmachine.New() + g.Memory[0] = gmachine.OpINCA + g.Run() + got := g.A + + if wants != got { + t.Errorf("want A == %d, got %d", wants, got) + } +} + +func TestDECA(t *testing.T) { + t.Parallel() + + var wants uint64 = 1 + + g := gmachine.New() + g.A = 2 + g.Memory[0] = gmachine.OpDECA + g.Run() + got := g.A + + if wants != got { + t.Errorf("want A == %d, got %d", wants, got) + } +} + +func TestSETA(t *testing.T) { + t.Parallel() + + var wants uint64 = 3 + + g := gmachine.New() + g.Memory[0] = gmachine.OpSETA + g.Memory[1] = wants + g.Run() + got := g.A + + if wants != got { + t.Errorf("want A == %d, got %d", wants, got) + } +} diff --git a/gmachine/go.mod b/gmachine/go.mod new file mode 100644 index 0000000..3fe6e5f --- /dev/null +++ b/gmachine/go.mod @@ -0,0 +1,3 @@ +module gmachine + +go 1.17