From 6b1da92a3a9aab5b8205b517fc72ec8db118a92c Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Mon, 15 Nov 2021 20:44:26 -1000 Subject: [PATCH] Split files --- instruction.go | 30 +++++ opcode.go | 51 +++++++++ operand.go | 15 +++ ophandler.go | 149 +++++++++++++++++++++++++ stackframe.go | 9 ++ state.go | 291 ------------------------------------------------- 6 files changed, 254 insertions(+), 291 deletions(-) create mode 100644 instruction.go create mode 100644 opcode.go create mode 100644 operand.go create mode 100644 ophandler.go create mode 100644 stackframe.go diff --git a/instruction.go b/instruction.go new file mode 100644 index 0000000..40dace8 --- /dev/null +++ b/instruction.go @@ -0,0 +1,30 @@ +package vm + +import "bytes" + +import "github.com/lunixbochs/struc" +import "github.com/pkg/errors" + +const InstructionBytes = 32 + +type Instruction struct { + OpCode OpCodeType + Reserved [4]byte + Operand1 Operand + Operand2 Operand + + opHandler OpHandler `struc:"skip"` +} + +func NewInstruction(byteCode []byte) (*Instruction, error) { + instr := &Instruction{} + + reader := bytes.NewReader(byteCode) + + err := struc.Unpack(reader, instr) + if err != nil { + return nil, errors.Wrap(err, "Error decoding instruction") + } + + return instr, nil +} diff --git a/opcode.go b/opcode.go new file mode 100644 index 0000000..20c583b --- /dev/null +++ b/opcode.go @@ -0,0 +1,51 @@ +package vm + +type OpCodeType uint32 + +const ( + OpNoOp OpCodeType = 0x00000000 + OpNop = OpNoOp + OpCall = 0x00000001 + OpCal = OpCall + OpReturn = 0x00000002 + OpRet = OpReturn + + OpMove = 0x00000100 + OpMov = OpMove + + OpAdd = 0x00000200 + OpSubtract = 0x00000201 + OpSub = OpSubtract + OpMultiply = 0x00000202 + OpMul = OpMultiply + OpDivideUnsigned = 0x00000203 + OpDivU = OpDivideUnsigned + OpDivideSigned = 0x00000204 + OpDivS = OpDivideSigned + + OpIsEqual = 0x00000300 + OpEq = OpIsEqual + OpIsLessThanUnsigned = 0x00000301 + OpLTU = OpIsLessThanUnsigned + OpIsLessThanSigned = 0x00000302 + OpLTS = OpIsLessThanSigned + OpIsGreaterThanUnsigned = 0x00000303 + OpGTU = OpIsGreaterThanUnsigned + OpIsGreaterThanSigned = 0x00000304 + OpGTS = OpIsGreaterThanSigned + OpIsLessThanOrEqualUnsigned = 0x00000305 + OpLTEU = OpIsLessThanOrEqualUnsigned + OpIsLessThanOrEqualSigned = 0x00000306 + OpLTES = OpIsLessThanOrEqualSigned + OpIsGreaterThanOrEqualUnsigned = 0x00000307 + OpGTEU = OpIsGreaterThanOrEqualUnsigned + OpIsGreaterThanOrEqualSigned = 0x00000308 + OpGTES = OpIsGreaterThanOrEqualSigned + + OpJump = 0x00000400 + OpJmp = OpJump + OpJumpIfTrue = 0x00000401 + OpJmpT = OpJumpIfTrue + OpJumpIfFalse = 0x00000402 + OpJmpF = OpJumpIfFalse +) diff --git a/operand.go b/operand.go new file mode 100644 index 0000000..fa6546d --- /dev/null +++ b/operand.go @@ -0,0 +1,15 @@ +package vm + +type OperandType uint8 + +const ( + Literal OperandType = 0 + FunctionMemoryIndex = 1 + GlobalMemoryIndex = 2 +) + +type Operand struct { + Type OperandType + Reserved [3]byte + Value uint64 +} diff --git a/ophandler.go b/ophandler.go new file mode 100644 index 0000000..d9db672 --- /dev/null +++ b/ophandler.go @@ -0,0 +1,149 @@ +package vm + +type OpHandler func(*State, *Instruction) + +var OpHandlers = map[OpCodeType]OpHandler{ + OpNoOp: (*State).NoOp, + OpCall: (*State).Call, + OpReturn: (*State).Return, + + OpMove: (*State).Move, + + OpAdd: (*State).Add, + OpSubtract: (*State).Subtract, + OpMultiply: (*State).Multiply, + OpDivideUnsigned: (*State).DivideUnsigned, + OpDivideSigned: (*State).DivideSigned, + + OpIsEqual: (*State).IsEqual, + OpIsLessThanUnsigned: (*State).IsLessThanUnsigned, + OpIsLessThanSigned: (*State).IsLessThanSigned, + OpIsGreaterThanUnsigned: (*State).IsGreaterThanUnsigned, + OpIsGreaterThanSigned: (*State).IsGreaterThanSigned, + OpIsLessThanOrEqualUnsigned: (*State).IsLessThanOrEqualUnsigned, + OpIsLessThanOrEqualSigned: (*State).IsLessThanOrEqualSigned, + OpIsGreaterThanOrEqualUnsigned: (*State).IsGreaterThanOrEqualUnsigned, + OpIsGreaterThanOrEqualSigned: (*State).IsGreaterThanOrEqualSigned, + + OpJump: (*State).Jump, + OpJumpIfTrue: (*State).JumpIfTrue, + OpJumpIfFalse: (*State).JumpIfFalse, +} + +func (state *State) NoOp(instr *Instruction) { +} + +func (state *State) Call(instr *Instruction) { + in := state.ReadSigned(&instr.Operand1) + state.call(in) +} + +func (state *State) Return(instr *Instruction) { + state.ret() +} + +func (state *State) Move(instr *Instruction) { + in := state.ReadUnsigned(&instr.Operand2) + state.WriteUnsigned(&instr.Operand1, in) +} + +func (state *State) Add(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.WriteUnsigned(&instr.Operand1, in1+in2) +} + +func (state *State) Subtract(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.WriteUnsigned(&instr.Operand1, in1-in2) +} + +func (state *State) Multiply(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.WriteUnsigned(&instr.Operand1, in1*in2) +} + +func (state *State) DivideUnsigned(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.WriteUnsigned(&instr.Operand1, in1/in2) +} + +func (state *State) DivideSigned(instr *Instruction) { + in1 := state.ReadSigned(&instr.Operand1) + in2 := state.ReadSigned(&instr.Operand2) + state.WriteSigned(&instr.Operand1, in1/in2) +} + +func (state *State) IsEqual(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.ComparisonResult = (in1 == in2) +} + +func (state *State) IsLessThanUnsigned(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.ComparisonResult = (in1 < in2) +} + +func (state *State) IsLessThanSigned(instr *Instruction) { + in1 := state.ReadSigned(&instr.Operand1) + in2 := state.ReadSigned(&instr.Operand2) + state.ComparisonResult = (in1 < in2) +} + +func (state *State) IsGreaterThanUnsigned(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.ComparisonResult = (in1 > in2) +} + +func (state *State) IsGreaterThanSigned(instr *Instruction) { + in1 := state.ReadSigned(&instr.Operand1) + in2 := state.ReadSigned(&instr.Operand2) + state.ComparisonResult = (in1 > in2) +} + +func (state *State) IsLessThanOrEqualUnsigned(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.ComparisonResult = (in1 <= in2) +} + +func (state *State) IsLessThanOrEqualSigned(instr *Instruction) { + in1 := state.ReadSigned(&instr.Operand1) + in2 := state.ReadSigned(&instr.Operand2) + state.ComparisonResult = (in1 <= in2) +} + +func (state *State) IsGreaterThanOrEqualUnsigned(instr *Instruction) { + in1 := state.ReadUnsigned(&instr.Operand1) + in2 := state.ReadUnsigned(&instr.Operand2) + state.ComparisonResult = (in1 >= in2) +} + +func (state *State) IsGreaterThanOrEqualSigned(instr *Instruction) { + in1 := state.ReadSigned(&instr.Operand1) + in2 := state.ReadSigned(&instr.Operand2) + state.ComparisonResult = (in1 >= in2) +} + +func (state *State) Jump(instr *Instruction) { + in := state.ReadSigned(&instr.Operand1) + state.InstructionIndex += in - 1 +} + +func (state *State) JumpIfTrue(instr *Instruction) { + if state.ComparisonResult == true { + state.Jump(instr) + } +} + +func (state *State) JumpIfFalse(instr *Instruction) { + if state.ComparisonResult == false { + state.Jump(instr) + } +} diff --git a/stackframe.go b/stackframe.go new file mode 100644 index 0000000..259eae1 --- /dev/null +++ b/stackframe.go @@ -0,0 +1,9 @@ +package vm + +const FunctionMemoryEntries = 16 + +type StackFrame struct { + PreviousFunctionIndex int64 + PreviousInstructionIndex int64 + FunctionMemory [FunctionMemoryEntries]uint64 +} diff --git a/state.go b/state.go index 170eb21..515e762 100644 --- a/state.go +++ b/state.go @@ -1,90 +1,10 @@ package vm -import "bytes" -import "encoding/hex" import "fmt" -import "strings" -import "github.com/lunixbochs/struc" import "github.com/pkg/errors" -type OperandType uint8 -type OpCodeType uint32 - -const ( - Literal OperandType = 0 - FunctionMemoryIndex = 1 - GlobalMemoryIndex = 2 -) - -const ( - OpNoOp OpCodeType = 0x00000000 - OpNop = OpNoOp - OpCall = 0x00000001 - OpCal = OpCall - OpReturn = 0x00000002 - OpRet = OpReturn - - OpMove = 0x00000100 - OpMov = OpMove - - OpAdd = 0x00000200 - OpSubtract = 0x00000201 - OpSub = OpSubtract - OpMultiply = 0x00000202 - OpMul = OpMultiply - OpDivideUnsigned = 0x00000203 - OpDivU = OpDivideUnsigned - OpDivideSigned = 0x00000204 - OpDivS = OpDivideSigned - - OpIsEqual = 0x00000300 - OpEq = OpIsEqual - OpIsLessThanUnsigned = 0x00000301 - OpLTU = OpIsLessThanUnsigned - OpIsLessThanSigned = 0x00000302 - OpLTS = OpIsLessThanSigned - OpIsGreaterThanUnsigned = 0x00000303 - OpGTU = OpIsGreaterThanUnsigned - OpIsGreaterThanSigned = 0x00000304 - OpGTS = OpIsGreaterThanSigned - OpIsLessThanOrEqualUnsigned = 0x00000305 - OpLTEU = OpIsLessThanOrEqualUnsigned - OpIsLessThanOrEqualSigned = 0x00000306 - OpLTES = OpIsLessThanOrEqualSigned - OpIsGreaterThanOrEqualUnsigned = 0x00000307 - OpGTEU = OpIsGreaterThanOrEqualUnsigned - OpIsGreaterThanOrEqualSigned = 0x00000308 - OpGTES = OpIsGreaterThanOrEqualSigned - - OpJump = 0x00000400 - OpJmp = OpJump - OpJumpIfTrue = 0x00000401 - OpJmpT = OpJumpIfTrue - OpJumpIfFalse = 0x00000402 - OpJmpF = OpJumpIfFalse -) - -const InstructionBytes = 32 const GlobalMemoryEntries = 16 -const FunctionMemoryEntries = 16 - -type OpHandler func(*State, *Instruction) - -type Operand struct { - Type OperandType - Reserved [3]byte - Value uint64 -} - -type Instruction struct { - OpCode OpCodeType - Reserved [4]byte - Operand1 Operand - Operand2 Operand - - opHandler OpHandler `struc:"skip"` -} type State struct { Running bool @@ -99,53 +19,6 @@ type State struct { Stack []*StackFrame } -type StackFrame struct { - PreviousFunctionIndex int64 - PreviousInstructionIndex int64 - FunctionMemory [FunctionMemoryEntries]uint64 -} - -var OpHandlers = map[OpCodeType]OpHandler{ - OpNoOp: (*State).NoOp, - OpCall: (*State).Call, - OpReturn: (*State).Return, - - OpMove: (*State).Move, - - OpAdd: (*State).Add, - OpSubtract: (*State).Subtract, - OpMultiply: (*State).Multiply, - OpDivideUnsigned: (*State).DivideUnsigned, - OpDivideSigned: (*State).DivideSigned, - - OpIsEqual: (*State).IsEqual, - OpIsLessThanUnsigned: (*State).IsLessThanUnsigned, - OpIsLessThanSigned: (*State).IsLessThanSigned, - OpIsGreaterThanUnsigned: (*State).IsGreaterThanUnsigned, - OpIsGreaterThanSigned: (*State).IsGreaterThanSigned, - OpIsLessThanOrEqualUnsigned: (*State).IsLessThanOrEqualUnsigned, - OpIsLessThanOrEqualSigned: (*State).IsLessThanOrEqualSigned, - OpIsGreaterThanOrEqualUnsigned: (*State).IsGreaterThanOrEqualUnsigned, - OpIsGreaterThanOrEqualSigned: (*State).IsGreaterThanOrEqualSigned, - - OpJump: (*State).Jump, - OpJumpIfTrue: (*State).JumpIfTrue, - OpJumpIfFalse: (*State).JumpIfFalse, -} - -func NewInstruction(byteCode []byte) (*Instruction, error) { - instr := &Instruction{} - - reader := bytes.NewReader(byteCode) - - err := struc.Unpack(reader, instr) - if err != nil { - return nil, errors.Wrap(err, "Error decoding instruction") - } - - return instr, nil -} - func NewState(byteCodes [][]byte) (*State, error) { state := &State{} @@ -272,14 +145,6 @@ func (state *State) WriteSigned(op *Operand, value int64) { state.WriteUnsigned(op, uint64(value)) } -func (state *State) NoOp(instr *Instruction) { -} - -func (state *State) Call(instr *Instruction) { - in := state.ReadSigned(&instr.Operand1) - state.call(in) -} - func (state *State) call(functionOffset int64) { if state.FunctionIndex+functionOffset >= int64(len(state.Functions)) { state.setError(fmt.Errorf("Invalid function call index: %d + %d = %d", state.FunctionIndex, functionOffset, state.FunctionIndex+functionOffset)) @@ -295,10 +160,6 @@ func (state *State) call(functionOffset int64) { state.InstructionIndex = 0 } -func (state *State) Return(instr *Instruction) { - state.ret() -} - func (state *State) ret() { state.FunctionIndex = state.StackFrame().PreviousFunctionIndex state.InstructionIndex = state.StackFrame().PreviousInstructionIndex @@ -307,155 +168,3 @@ func (state *State) ret() { state.Running = false } } - -func (state *State) Move(instr *Instruction) { - in := state.ReadUnsigned(&instr.Operand2) - state.WriteUnsigned(&instr.Operand1, in) -} - -func (state *State) Add(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.WriteUnsigned(&instr.Operand1, in1+in2) -} - -func (state *State) Subtract(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.WriteUnsigned(&instr.Operand1, in1-in2) -} - -func (state *State) Multiply(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.WriteUnsigned(&instr.Operand1, in1*in2) -} - -func (state *State) DivideUnsigned(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.WriteUnsigned(&instr.Operand1, in1/in2) -} - -func (state *State) DivideSigned(instr *Instruction) { - in1 := state.ReadSigned(&instr.Operand1) - in2 := state.ReadSigned(&instr.Operand2) - state.WriteSigned(&instr.Operand1, in1/in2) -} - -func (state *State) IsEqual(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.ComparisonResult = (in1 == in2) -} - -func (state *State) IsLessThanUnsigned(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.ComparisonResult = (in1 < in2) -} - -func (state *State) IsLessThanSigned(instr *Instruction) { - in1 := state.ReadSigned(&instr.Operand1) - in2 := state.ReadSigned(&instr.Operand2) - state.ComparisonResult = (in1 < in2) -} - -func (state *State) IsGreaterThanUnsigned(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.ComparisonResult = (in1 > in2) -} - -func (state *State) IsGreaterThanSigned(instr *Instruction) { - in1 := state.ReadSigned(&instr.Operand1) - in2 := state.ReadSigned(&instr.Operand2) - state.ComparisonResult = (in1 > in2) -} - -func (state *State) IsLessThanOrEqualUnsigned(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.ComparisonResult = (in1 <= in2) -} - -func (state *State) IsLessThanOrEqualSigned(instr *Instruction) { - in1 := state.ReadSigned(&instr.Operand1) - in2 := state.ReadSigned(&instr.Operand2) - state.ComparisonResult = (in1 <= in2) -} - -func (state *State) IsGreaterThanOrEqualUnsigned(instr *Instruction) { - in1 := state.ReadUnsigned(&instr.Operand1) - in2 := state.ReadUnsigned(&instr.Operand2) - state.ComparisonResult = (in1 >= in2) -} - -func (state *State) IsGreaterThanOrEqualSigned(instr *Instruction) { - in1 := state.ReadSigned(&instr.Operand1) - in2 := state.ReadSigned(&instr.Operand2) - state.ComparisonResult = (in1 >= in2) -} - -func (state *State) Jump(instr *Instruction) { - in := state.ReadSigned(&instr.Operand1) - state.InstructionIndex += in - 1 -} - -func (state *State) JumpIfTrue(instr *Instruction) { - if state.ComparisonResult == true { - state.Jump(instr) - } -} - -func (state *State) JumpIfFalse(instr *Instruction) { - if state.ComparisonResult == false { - state.Jump(instr) - } -} - -func main() { - asm := [][]string{ - []string{ - "0000020000000000010000000000000000000000000000000000000000000001", - "0000000100000000000000000000000000000001000000000000000000000000", - "0000030100000000010000000000000000000000000000000000000000000003", - "000004010000000000000000fffffffffffffffd000000000000000000000000", - }, - []string{ - "0000020000000000020000000000000000000000000000000000000000000001", - }, - } - - functionByteCode := [][]byte{} - - for _, fnc := range asm { - fncString := strings.Join(fnc, "") - - byteCode, err := hex.DecodeString(fncString) - if err != nil { - panic(err) - } - - functionByteCode = append(functionByteCode, byteCode) - } - - state, err := NewState(functionByteCode) - if err != nil { - panic(err) - } - - state.Execute() - - if state.Error != nil { - fmt.Printf("ERROR: %s\n", state.Error) - fmt.Printf("\tNext function index: 0x%016x\n", state.FunctionIndex) - fmt.Printf("\tNext instruction index: 0x%016x\n", state.InstructionIndex) - fmt.Printf("\n") - } - - fmt.Printf("Global memory:\n") - for i, v := range state.GlobalMemory { - fmt.Printf("\t0x%08x: 0x%016x %d %d\n", i, v, v, int64(v)) - } -}