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 }