func (this *Decoder) Run(input, output channel.Channel) { // Launch each unit as a goroutine logger.Print(" => Initializing decoder unit %d", this.Index()) go func() { for { value, running := <-input.Channel() if !running || !this.IsActive() { logger.Print(" => Flushing decoder unit %d", this.Index()) return } op := operation.Cast(value) // Iterate instructions received via the channel instruction, err := this.decodeInstruction(op) if err != nil { logger.Error(err.Error()) break } // Send data to output op.SetInstruction(instruction) output.Add(op) // Release one item from input Channel input.Release() } }() }
func (this *Executor) Run(input map[info.CategoryEnum]channel.Channel, commonDataBus channel.Channel) { // Launch each unit as a goroutine unit, event := this.getUnitFromCategory(this.Category()) logger.Print(" => Initializing execution unit (%s) %d", this.Category(), this.Index()) go func() { for { value, running := <-input[this.Category()].Channel() if !running || !this.IsActive() { logger.Print(" => Flushing execution unit (%s) %d", this.Category(), this.Index()) return } op := operation.Cast(value) for i := uint8(0); i < op.Instruction().Info.Cycles; i++ { this.Processor().Wait(1) } // Iterate instructions received via the channel op, _ = this.executeOperation(unit, event, op) // Send data to common bus for reservation station feedback commonDataBus.Add(op) // Release one item from input Channel input[this.Category()].Release() } }() }
func (this *Dispatcher) runDispatcherToReservationStation(input channel.Channel, rs *reservationstation.ReservationStation, rat *registeraliastable.RegisterAliasTable, rob *reorderbuffer.ReorderBuffer) { incomingQueue := map[uint32]*operation.Operation{} currentOperationId := this.StartOperationId() // For each operation received to schedule, process it for { value, running := <-input.Channel() if !running || !this.IsActive() { logger.Print(" => Flushing dispatcher unit %d (dispatcher to RS)", this.Index()) return } op := operation.Cast(value) // Add to current operation incomingQueue[op.Id()] = op // Send to incoming channel pending ops (if available) for op, exists := incomingQueue[currentOperationId]; exists; op, exists = incomingQueue[currentOperationId] { // Allocate in ROB if there is spacde, otherwise stall rob.Allocate(op) // Rename register in case of WAR & WAR hazards if this.RegisterAliasTableEntries() > 0 { _, destRegister := rs.GetDestinationDependency(op.Id(), op.Instruction()) if destRegister != -1 { found, _ := rat.AddMap(uint32(destRegister), op.Id()) if !found { // Need to stall for an available RAT entry logger.Collect(" => [DI%d][%03d]: No entry available in RAT. Wait for one...", this.Index(), op.Id()) break } // Rename to physical registers this.renameRegisters(op.Id(), op, rat) } } //Redirect input operations to the required execution unit channels logger.Collect(" => [DI%d][%03d]: Scheduling to RS: %s, %s", this.Index(), op.Id(), op.Instruction().Info.ToString(), op.Instruction().Data.ToString()) rs.Schedule(op) currentOperationId += 1 } input.Release() } }
func (this *Processor) RunRecovery(recoveryChannel channel.Channel, flushFunc func()) { for value := range recoveryChannel.Channel() { op := operation.Cast(value) logger.Collect(" => Recovering at OpId: %d and Address: %#04X", op.Id(), op.Address()) logger.SetVerboseQuiet(true) // Flush pipeline flushFunc() // Clean logs this.RemoveForwardLogs(op.Id() - 1) // Clear speculative jumps this.ClearSpeculativeJumps() // Start pipeline from the recovery address flushFunc = this.StartPipelineUnits(this.Config(), recoveryChannel, op.Id(), op.Address()) // Release value from channel recoveryChannel.Release() } }
func (this *ReservationStation) runCommonBusListener(commonDataBus channel.Channel) { // For each operation executed, feed reservation station to release operands for { value, running := <-commonDataBus.Channel() if !running { this.reservationStation.isActive = false logger.Print(" => Flushing reservation station unit %d (CDB listener)", this.Index()) return } op := operation.Cast(value) commonDataBus.Release() this.Lock() <- true dest, _, _ := this.getComponentsFromInstruction(op.Instruction()) entryIndex := this.getEntryIndexFromOperationId(op.Id()) entryOp := this.Entries()[entryIndex] logger.Collect(" => [RS%d][%03d]: Operation completed, releasing entry %d", this.Index(), op.Id(), entryIndex) if entryIndex != INVALID_INDEX { // Release entry this.Entries()[entryIndex].Busy = false this.Entries()[entryIndex].Free = true // Release entry from reservation station queue this.Input().Release() } // Release destination register (as RAT if enabled) if dest != INVALID_INDEX { logger.Collect(" => [RS%d][%03d]: Register %v resolved", this.Index(), op.Id(), entryOp.Destination) this.releaseOperation(entryOp.Destination) } // Release operands registers for _, operand := range entryOp.Operands { if operand.IsValid() && (operand.Type == MemoryType || len(this.RegisterAliasTable().Entries()) == 0) { logger.Collect(" => [RS%d][%03d]: Register %v resolved", this.Index(), op.Id(), operand) this.releaseOperation(operand) } } <-this.Lock() } }
func (this *Fetcher) Run(input, output channel.Channel) { logger.Print(" => Initializing fetcher unit %d", this.Index()) // Launch each unit as a goroutine go func() { for { value, running := <-input.Channel() if !running || !this.IsActive() { logger.Print(" => Flushing fetcher unit %d", this.Index()) return } // Release item from input Channel input.Release() // Initial operation (address) op := operation.Cast(value) // Load instructions data from memory data := this.Processor().InstructionsMemory().Load(op.Address(), consts.BYTES_PER_WORD*this.InstructionsFetchedPerCycle()) // Fetch instructions startCycles := this.Processor().Cycles() operations, err := this.fetchInstructions(op, data, input) if err != nil { logger.Error(err.Error()) break } // Wait cycles of a fetch stage this.Processor().Wait(consts.FETCH_CYCLES) // After wait cycle, notify decode channel with new operations for _, op := range operations { if this.IsActive() { this.Processor().LogEvent(consts.FETCH_EVENT, this.Index(), op.Id(), startCycles) output.Add(op) } } } }() }
func (this *ReservationStation) runScheduler() { // For each operation received to schedule, process it for { value, running := <-this.Input().Channel() if !running { this.reservationStation.isActive = false logger.Print(" => Flushing reservation station unit %d (scheduler)", this.Index()) return } this.Lock() <- true op := operation.Cast(value) // Get next entry free entryIndex := this.getNextIndexFreeEntry() dest, valueOperands, memoryOperands := this.getComponentsFromInstruction(op.Instruction()) // Convert to operand objects ops := []Operand{} for _, register := range memoryOperands { ops = append(ops, newMemoryOp(register)) } for _, register := range valueOperands { ratEntry, ok := this.RegisterAliasTable().GetPhysicalRegister(op.Id()-1, uint32(register)) if ok { ops = append(ops, newRegisterRatOp(register, int32(ratEntry))) } else { ops = append(ops, newRegisterOp(register)) } } // Rat Dest regDestRat := newNilDep() if dest != INVALID_INDEX { if op.RenamedDestRegister() != INVALID_INDEX { regDestRat = newRegisterRatOp(dest, op.RenamedDestRegister()) } else { regDestRat = newRegisterOp(dest) } } dependencies := this.getDependencies(op.Id(), regDestRat, ops) logger.Collect(" => [RS%d][%03d]: Adding op to entry %d [D: %v, O's: %v, V's: %v] ..", this.Index(), op.Id(), entryIndex, regDestRat, ops, dependencies) // Store entry depency into reservation station this.Entries()[entryIndex] = RsEntry{ Operation: op, Destination: regDestRat, Operands: ops, Dependencies: dependencies, Free: false, Busy: false, } // If no waiting dependencies, release and execute if len(dependencies) == 0 { this.dispatchOperation(EntryIndex(entryIndex), op) } <-this.Lock() } }