You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hal/hal/instructions.go

180 lines
4.2 KiB

package hal
import (
"fmt"
"strings"
)
type ProgrammedInstruction struct {
Instruction *Instruction
Operand float64
}
func (pi *ProgrammedInstruction) Execute(module *Module) error {
if pi.Instruction.ExecuteWithOperand != nil {
module.debug("Operand: %f", pi.Operand)
return pi.Instruction.ExecuteWithOperand(module, pi.Operand)
} else if pi.Instruction.Execute != nil {
return pi.Instruction.Execute(module)
} else {
return fmt.Errorf("instruction is not implemented")
}
}
type Instruction struct {
Name string
ExecuteWithOperand func(module *Module, operand float64) error
Execute func(module *Module) error
}
func FindInstructionByName(name string) *Instruction {
for _, instruction := range instructions {
if instruction.Name == strings.ToUpper(name) {
return instruction
}
}
return nil
}
var instructions = []*Instruction{
InstructionStart,
InstructionStop,
InstructionIn,
InstructionOut,
InstructionLoad,
InstructionLoadNum,
InstructionStore,
InstructionJumpNeg,
InstructionJumpPos,
InstructionJumpNull,
InstructionJump,
InstructionAdd,
InstructionAddNum,
}
var InstructionStart = &Instruction{
Name: "START",
Execute: func(module *Module) error {
// actually not required
module.isStopped = false
return nil
},
}
var InstructionStop = &Instruction{
Name: "STOP",
Execute: func(module *Module) error {
module.isStopped = true
return nil
},
}
var InstructionOut = &Instruction{
Name: "OUT",
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int(operand)
if len(module.IO) >= index {
return fmt.Errorf("index %d exceeds IO size of %d", index, len(module.IO))
}
module.IO[int64(operand)] = module.accumulator
return nil
},
}
var InstructionIn = &Instruction{
Name: "IN",
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int(operand)
if len(module.IO) >= index {
return fmt.Errorf("index %d exceeds IO size of %d", index, len(module.IO))
}
module.accumulator = module.IO[index]
return nil
},
}
var InstructionLoad = &Instruction{
Name: "LOAD",
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int(operand)
if len(module.register) >= index {
return fmt.Errorf("index %d exceeds register size of %d", index, len(module.IO))
}
module.accumulator = module.register[index]
return nil
},
}
var InstructionLoadNum = &Instruction{
Name: "LOADNUM",
ExecuteWithOperand: func(module *Module, operand float64) error {
module.accumulator = operand
return nil
},
}
var InstructionStore = &Instruction{
Name: "STORE",
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int(operand)
if len(module.register) >= index {
return fmt.Errorf("index %d exceeds register size of %d", index, len(module.IO))
}
module.register[index] = module.accumulator
return nil
},
}
func newJumpInstruction(name string, doJump func(accumulator float64) bool) *Instruction {
return &Instruction{
Name: name,
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int64(operand)
if _, ok := module.programStorage[index]; !ok {
return fmt.Errorf("index %d does not exist in program storage", index)
}
if doJump(module.accumulator) {
return module.setProgramCounter(index)
}
return nil
},
}
}
var InstructionJumpNeg = newJumpInstruction("JUMPNEG", func(accumulator float64) bool {
return accumulator > 0
})
var InstructionJumpPos = newJumpInstruction("JUMPPOS", func(accumulator float64) bool {
return accumulator < 0
})
var InstructionJumpNull = newJumpInstruction("JUMPNULL", func(accumulator float64) bool {
return accumulator == 0
})
var InstructionJump = newJumpInstruction("JUMP", func(accumulator float64) bool {
return true
})
var InstructionAdd = &Instruction{
Name: "ADD",
ExecuteWithOperand: func(module *Module, operand float64) error {
index := int(operand)
if len(module.register) <= index {
return fmt.Errorf("index %d does not exist in program storage", index)
}
module.accumulator += module.register[index]
return nil
},
}
var InstructionAddNum = &Instruction{
Name: "ADDNUM",
ExecuteWithOperand: func(module *Module, operand float64) error {
module.accumulator = module.accumulator + operand
return nil
},
}