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 *Dispatcher) runCommonBusMultiplexer(input, output1, output2 channel.Channel) { // For each result got from execution units in the common data bus send to RS and ROB for { value, running := <-input.Channel() if !running { output1.Close() output2.Close() logger.Print(" => Flushing dispatcher unit %d (CDB Mux)", this.Index()) return } output1.Add(value) output2.Add(value) input.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 *ReorderBuffer) Run(commonDataBus channel.Channel, recoveryBus channel.Channel) { // Launch unit as a goroutine logger.Print(" => Initializing re-order buffer unit %d", this.Index()) opId := this.StartOperationId() misprediction := false clockAllowed := this.Processor().Cycles() forceClose := false go func() { for { _, running := <-commonDataBus.Channel() if !running || misprediction { forceClose = true logger.Print(" => Flushing re-order buffer unit %d", this.Index()) return } commonDataBus.Release() } }() go func() { for { if forceClose { return } if this.Processor().Cycles() < clockAllowed { this.Processor().Wait(1) continue } // Commit in order, if missing an operation, wait for it computedAddress := uint32(0) robEntries := []RobEntry{} for robEntry, exists := this.Buffer()[opId]; exists; robEntry, exists = this.Buffer()[opId] { if uint32(len(robEntries)) >= this.InstructionsWrittenPerCycle() { break } // Ensure we can write results the next cycle result was written into ROB if this.Processor().Cycles() > robEntry.Cycle+1 { // Check for misprediction misprediction, computedAddress = this.checkForMisprediction(this.Buffer()[opId], robEntries) // Decrement speculative jumps this.Processor().DecrementSpeculativeJump() // Add to queue for commit robEntries = append(robEntries, robEntry) opId += 1 // If misprediction, do not process more rob entries if misprediction { break } } } this.commitRobEntries(robEntries) if misprediction { this.Processor().Wait(consts.WRITEBACK_CYCLES) recoveryBus.Add(operation.New(opId, computedAddress)) } clockAllowed = this.Processor().Cycles() + 1 } }() }