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