Add conditional call instructions
This commit is contained in:
@@ -5,8 +5,6 @@ import "github.com/firestuff/subcoding/vm"
|
|||||||
var opCodeByName = map[string]vm.OpCodeType{
|
var opCodeByName = map[string]vm.OpCodeType{
|
||||||
"noop": vm.OpNoOp,
|
"noop": vm.OpNoOp,
|
||||||
"nop": vm.OpNop,
|
"nop": vm.OpNop,
|
||||||
"call": vm.OpCall,
|
|
||||||
"cal": vm.OpCal,
|
|
||||||
"return": vm.OpReturn,
|
"return": vm.OpReturn,
|
||||||
"ret": vm.OpRet,
|
"ret": vm.OpRet,
|
||||||
|
|
||||||
@@ -48,6 +46,13 @@ var opCodeByName = map[string]vm.OpCodeType{
|
|||||||
"jmpt": vm.OpJmpT,
|
"jmpt": vm.OpJmpT,
|
||||||
"jumpiffalse": vm.OpJumpIfFalse,
|
"jumpiffalse": vm.OpJumpIfFalse,
|
||||||
"jmpf": vm.OpJmpF,
|
"jmpf": vm.OpJmpF,
|
||||||
|
|
||||||
|
"call": vm.OpCall,
|
||||||
|
"cal": vm.OpCal,
|
||||||
|
"calliftrue": vm.OpCallIfTrue,
|
||||||
|
"calt": vm.OpCalT,
|
||||||
|
"calliffalse": vm.OpCallIfFalse,
|
||||||
|
"calf": vm.OpCalF,
|
||||||
}
|
}
|
||||||
|
|
||||||
type operandType int
|
type operandType int
|
||||||
@@ -61,7 +66,6 @@ const (
|
|||||||
|
|
||||||
var operandsByOpCode = map[vm.OpCodeType][]operandType{
|
var operandsByOpCode = map[vm.OpCodeType][]operandType{
|
||||||
vm.OpNop: []operandType{},
|
vm.OpNop: []operandType{},
|
||||||
vm.OpCal: []operandType{s},
|
|
||||||
vm.OpRet: []operandType{},
|
vm.OpRet: []operandType{},
|
||||||
|
|
||||||
vm.OpMov: []operandType{r, us},
|
vm.OpMov: []operandType{r, us},
|
||||||
@@ -84,4 +88,8 @@ var operandsByOpCode = map[vm.OpCodeType][]operandType{
|
|||||||
vm.OpJmp: []operandType{s},
|
vm.OpJmp: []operandType{s},
|
||||||
vm.OpJmpT: []operandType{s},
|
vm.OpJmpT: []operandType{s},
|
||||||
vm.OpJmpF: []operandType{s},
|
vm.OpJmpF: []operandType{s},
|
||||||
|
|
||||||
|
vm.OpCal: []operandType{s},
|
||||||
|
vm.OpCalT: []operandType{s},
|
||||||
|
vm.OpCalF: []operandType{s},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,20 +11,6 @@ functions:
|
|||||||
expectGlobalMemory(t, state, 0, 0)
|
expectGlobalMemory(t, state, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCal(t *testing.T) {
|
|
||||||
state := assembleAndExecute(t, `
|
|
||||||
functions:
|
|
||||||
- - [cal, +1]
|
|
||||||
- [add, g0, 1]
|
|
||||||
- [cal, +2] # Function doesn't exist, immediate implicit return
|
|
||||||
- [add, g0, 2]
|
|
||||||
|
|
||||||
- - [mov, g0, 5]
|
|
||||||
`)
|
|
||||||
|
|
||||||
expectGlobalMemory(t, state, 0, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRet(t *testing.T) {
|
func TestRet(t *testing.T) {
|
||||||
state := assembleAndExecute(t, `
|
state := assembleAndExecute(t, `
|
||||||
functions:
|
functions:
|
||||||
@@ -324,3 +310,53 @@ functions:
|
|||||||
|
|
||||||
expectGlobalMemory(t, state, 0, 5)
|
expectGlobalMemory(t, state, 0, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCal(t *testing.T) {
|
||||||
|
state := assembleAndExecute(t, `
|
||||||
|
functions:
|
||||||
|
- - [cal, +1]
|
||||||
|
- [add, g0, 1]
|
||||||
|
- [cal, +2] # Function doesn't exist, immediate implicit return
|
||||||
|
- [add, g0, 2]
|
||||||
|
|
||||||
|
- - [mov, g0, 5]
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectGlobalMemory(t, state, 0, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalT(t *testing.T) {
|
||||||
|
state := assembleAndExecute(t, `
|
||||||
|
functions:
|
||||||
|
- - [eq, 0, 0]
|
||||||
|
- [calt, +1]
|
||||||
|
- [add, g0, 1]
|
||||||
|
- [eq, 0, 1]
|
||||||
|
- [calt, +2]
|
||||||
|
- [add, g0, 2]
|
||||||
|
|
||||||
|
- - [add, g0, 5]
|
||||||
|
|
||||||
|
- - [add, g0, 13]
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectGlobalMemory(t, state, 0, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalF(t *testing.T) {
|
||||||
|
state := assembleAndExecute(t, `
|
||||||
|
functions:
|
||||||
|
- - [eq, 0, 0]
|
||||||
|
- [calf, +1]
|
||||||
|
- [add, g0, 1]
|
||||||
|
- [eq, 0, 1]
|
||||||
|
- [calf, +2]
|
||||||
|
- [add, g0, 2]
|
||||||
|
|
||||||
|
- - [add, g0, 5]
|
||||||
|
|
||||||
|
- - [add, g0, 13]
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectGlobalMemory(t, state, 0, 16)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ type OpCodeType uint32
|
|||||||
const (
|
const (
|
||||||
OpNoOp OpCodeType = 0x00000000
|
OpNoOp OpCodeType = 0x00000000
|
||||||
OpNop = OpNoOp
|
OpNop = OpNoOp
|
||||||
OpCall = 0x00000001
|
|
||||||
OpCal = OpCall
|
|
||||||
OpReturn = 0x00000002
|
OpReturn = 0x00000002
|
||||||
OpRet = OpReturn
|
OpRet = OpReturn
|
||||||
|
|
||||||
@@ -48,4 +46,11 @@ const (
|
|||||||
OpJmpT = OpJumpIfTrue
|
OpJmpT = OpJumpIfTrue
|
||||||
OpJumpIfFalse = 0x00000402
|
OpJumpIfFalse = 0x00000402
|
||||||
OpJmpF = OpJumpIfFalse
|
OpJmpF = OpJumpIfFalse
|
||||||
|
|
||||||
|
OpCall = 0x00000500
|
||||||
|
OpCal = OpCall
|
||||||
|
OpCallIfTrue = 0x00000501
|
||||||
|
OpCalT = OpCallIfTrue
|
||||||
|
OpCallIfFalse = 0x00000502
|
||||||
|
OpCalF = OpCallIfFalse
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ type opHandler func(*State, *Instruction)
|
|||||||
|
|
||||||
var opHandlers = map[OpCodeType]opHandler{
|
var opHandlers = map[OpCodeType]opHandler{
|
||||||
OpNoOp: (*State).handleNoOp,
|
OpNoOp: (*State).handleNoOp,
|
||||||
OpCall: (*State).handleCall,
|
|
||||||
OpReturn: (*State).handleReturn,
|
OpReturn: (*State).handleReturn,
|
||||||
|
|
||||||
OpMove: (*State).handleMove,
|
OpMove: (*State).handleMove,
|
||||||
@@ -28,16 +27,15 @@ var opHandlers = map[OpCodeType]opHandler{
|
|||||||
OpJump: (*State).handleJump,
|
OpJump: (*State).handleJump,
|
||||||
OpJumpIfTrue: (*State).handleJumpIfTrue,
|
OpJumpIfTrue: (*State).handleJumpIfTrue,
|
||||||
OpJumpIfFalse: (*State).handleJumpIfFalse,
|
OpJumpIfFalse: (*State).handleJumpIfFalse,
|
||||||
|
|
||||||
|
OpCall: (*State).handleCall,
|
||||||
|
OpCallIfTrue: (*State).handleCallIfTrue,
|
||||||
|
OpCallIfFalse: (*State).handleCallIfFalse,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *State) handleNoOp(instr *Instruction) {
|
func (state *State) handleNoOp(instr *Instruction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *State) handleCall(instr *Instruction) {
|
|
||||||
in := state.readSigned(&instr.Operand1)
|
|
||||||
state.call(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (state *State) handleReturn(instr *Instruction) {
|
func (state *State) handleReturn(instr *Instruction) {
|
||||||
state.ret()
|
state.ret()
|
||||||
}
|
}
|
||||||
@@ -147,3 +145,20 @@ func (state *State) handleJumpIfFalse(instr *Instruction) {
|
|||||||
state.handleJump(instr)
|
state.handleJump(instr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (state *State) handleCall(instr *Instruction) {
|
||||||
|
in := state.readSigned(&instr.Operand1)
|
||||||
|
state.call(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (state *State) handleCallIfTrue(instr *Instruction) {
|
||||||
|
if state.comparisonResult == true {
|
||||||
|
state.handleCall(instr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (state *State) handleCallIfFalse(instr *Instruction) {
|
||||||
|
if state.comparisonResult == false {
|
||||||
|
state.handleCall(instr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user