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

248 lines
6.0 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,
InstructionAddNum,
InstructionSubNum,
InstructionMulNum,
InstructionDivNum,
InstructionAdd,
InstructionSub,
InstructionMul,
InstructionDiv,
InstructionLoadInd,
InstructionStoreInd,
InstructionDumpReg,
InstructionDumpProg,
}
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 := int64(operand)
if _, ok := module.IO[index]; !ok {
return fmt.Errorf("IO[%d] is not registered", index)
}
return module.IO[index].Write(module.accumulator)
},
}
var InstructionIn = &Instruction{
Name: "IN",
ExecuteWithOperand: func(module *Module, operand float64) (err error) {
index := int64(operand)
if _, ok := module.IO[index]; !ok {
return fmt.Errorf("IO[%d] is not registered", index)
}
module.accumulator, err = module.IO[index].Read()
return
},
}
var InstructionLoad = &Instruction{
Name: "LOAD",
ExecuteWithOperand: func(module *Module, operand float64) error {
module.accumulator = module.mmu.Read(Address(operand))
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 {
module.mmu.Write(Address(operand), 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 addInstr = func(accumulator, value float64) float64 {
return accumulator + value
}
var subInstr = func(accumulator, value float64) float64 {
return accumulator - value
}
var mulInstr = func(accumulator, value float64) float64 {
return accumulator * value
}
var divInstr = func(accumulator, value float64) float64 {
return accumulator / value
}
func newMathNumInstruction(name string, operation func(accumulator, value float64) float64) *Instruction {
return &Instruction{
Name: name,
ExecuteWithOperand: func(module *Module, operand float64) error {
module.accumulator = operation(module.accumulator, operand)
return nil
},
}
}
var InstructionAddNum = newMathNumInstruction("ADDNUM", addInstr)
var InstructionSubNum = newMathNumInstruction("SUBNUM", subInstr)
var InstructionMulNum = newMathNumInstruction("MULNUM", mulInstr)
var InstructionDivNum = newMathNumInstruction("DIVNUM", divInstr)
func newMathInstruction(name string, operation func(accumulator, register float64) float64) *Instruction {
return &Instruction{
Name: name,
ExecuteWithOperand: func(module *Module, operand float64) error {
param := module.mmu.Read(Address(operand))
module.accumulator = operation(module.accumulator, param)
return nil
},
}
}
var InstructionAdd = newMathInstruction("ADD", addInstr)
var InstructionSub = newMathInstruction("SUB", subInstr)
var InstructionMul = newMathInstruction("MUL", mulInstr)
var InstructionDiv = newMathInstruction("DIV", divInstr)
var InstructionLoadInd = &Instruction{
Name: "LOADIND",
ExecuteWithOperand: func(module *Module, operand float64) error {
module.mmu.Read(Address(module.register[int(operand)]))
return nil
},
}
var InstructionStoreInd = &Instruction{
Name: "STOREIND",
ExecuteWithOperand: func(module *Module, operand float64) error {
module.mmu.Write(Address(module.register[int(operand)]), module.accumulator)
return nil
},
}
var InstructionDumpReg = &Instruction{
Name: "DUMPREG",
Execute: func(module *Module) error {
for index, content := range module.register {
module.debug("%d:\t%d", index, content)
}
return nil
},
}
var InstructionDumpProg = &Instruction{
Name: "DUMPPROG",
Execute: func(module *Module) error {
for index, content := range module.programStorage {
module.debug("%d\t%s\t%d", index, content.Instruction.Name, content.Operand)
}
return nil
},
}