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.
105 lines
2.6 KiB
105 lines
2.6 KiB
package hal
|
|
|
|
import "fmt"
|
|
|
|
const maxInstructions = 10000
|
|
|
|
type Program map[int64]*ProgrammedInstruction
|
|
|
|
type IO interface {
|
|
Read() (float64, error)
|
|
Write(output float64) error
|
|
}
|
|
|
|
type Module struct {
|
|
mmu *MMU
|
|
pCounter int64
|
|
accumulator float64
|
|
programStorage Program
|
|
register []float64
|
|
IO map[int64]IO
|
|
pageTable *PageTable
|
|
|
|
isStopped bool
|
|
debugEnabled bool
|
|
name string // Used to print the module name when debugging
|
|
}
|
|
|
|
func (h *Module) programCounter() int64 {
|
|
return h.pCounter
|
|
}
|
|
func (h *Module) setProgramCounter(counter int64) error {
|
|
h.pCounter = counter
|
|
if _, ok := h.programStorage[counter]; !ok {
|
|
return fmt.Errorf("index %d does not exist in program storage", counter)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *Module) increaseProgramCounter() {
|
|
h.pCounter++
|
|
}
|
|
|
|
func (h *Module) debug(format string, args ...interface{}) {
|
|
if !h.debugEnabled {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("[DEBUG] ["+h.name+"] "+format+"\n", args...)
|
|
}
|
|
|
|
func (h *Module) Step() error {
|
|
instruction := h.programStorage[h.programCounter()]
|
|
h.increaseProgramCounter()
|
|
if instruction == nil {
|
|
//h.debug("Skip undefined instruction %d", h.programCounter())
|
|
return nil
|
|
}
|
|
h.debug("Instruction: %s", instruction.Instruction.Name)
|
|
h.debug("Accumulator before: %f", h.accumulator)
|
|
if err := instruction.Execute(h); err != nil {
|
|
return err
|
|
}
|
|
h.debug("Accumulator after: %f", h.accumulator)
|
|
return nil
|
|
}
|
|
|
|
func (h *Module) Run() error {
|
|
for !h.isStopped && h.programCounter() <= maxInstructions {
|
|
if err := h.Step(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if h.programCounter() > maxInstructions {
|
|
return fmt.Errorf("module exceeded max instructions without being stopped")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func NewHALModule(program Program, registerSize uint64, ioSize int64, debug bool, handler PageErrorHandler) (*Module, error) {
|
|
return NewNamedHALModule(program, registerSize, ioSize, debug, "", handler)
|
|
}
|
|
|
|
func NewNamedHALModule(program Program, registerSize uint64, ioSize int64, debug bool, name string, handler PageErrorHandler) (*Module, error) {
|
|
if registerSize <= 10 {
|
|
return nil, fmt.Errorf("register size must be greater then 10 [ registerSize = %d ]", registerSize)
|
|
}
|
|
ios := make(map[int64]IO)
|
|
if ioSize < 0 {
|
|
return nil, fmt.Errorf("io size must positive")
|
|
}
|
|
for i := int64(0); i <= ioSize; i++ {
|
|
ios[i] = NewCommandLineIO(i, name)
|
|
}
|
|
|
|
module := &Module{
|
|
pCounter: 1,
|
|
programStorage: program,
|
|
register: make([]float64, registerSize),
|
|
IO: ios,
|
|
debugEnabled: debug,
|
|
name: name,
|
|
}
|
|
module.mmu = NewMMU(module, handler)
|
|
return module, nil
|
|
}
|
|
|