作者:felipegs0
项目:processor_simulato
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()
}
}()
}
作者:felipegs0
项目:processor_simulato
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()
}
}
作者:felipegs0
项目:processor_simulato
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()
}
}
作者:felipegs0
项目:processor_simulato
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()
}
}
作者:felipegs0
项目:processor_simulato
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()
}
}()
}
作者:felipegs0
项目:processor_simulato
func (this *Dispatcher) Run(input channel.Channel, output map[info.CategoryEnum]channel.Channel, commonDataBus, recoveryBus channel.Channel) {
// Create register alias table
rat := registeraliastable.New(this.Index(), this.RegisterAliasTableEntries())
// Create re-order buffer
rob := reorderbuffer.New(this.Index(),
this.Processor(),
this.StartOperationId(),
this.ReorderBufferEntries(),
this.InstructionsWrittenPerCycle(),
rat)
commonDataBusROB := channel.New(commonDataBus.Capacity())
// Create reservation station
rs := reservationstation.New(this.Index(), this.Processor(),
this.Registers(),
this.ReservationStationEntries(),
this.InstructionsFetchedPerCycle(),
rat, rob.Bus())
commonDataBusRS := channel.New(commonDataBus.Capacity())
// Create storage bus
this.dispatcher.bus = rob.Bus()
// Launch each unit as a goroutine
logger.Print(" => Initializing dispatcher unit %d", this.Index())
// Start dispatcher of operations to be executed into reservation station
go this.runDispatcherToReservationStation(input, rs, rat, rob)
// Start common bus multiplexer to send ack to reservation station and reorder buffer
go this.runCommonBusMultiplexer(commonDataBus, commonDataBusRS, commonDataBusROB)
// Run reservation station
rs.Run(commonDataBusRS, output)
// Run re-order buffer
rob.Run(commonDataBusROB, recoveryBus)
}
作者:felipegs0
项目:processor_simulato
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)
}
}
}
}()
}
作者:felipegs0
项目:processor_simulato
func (this *Fetcher) fetchInstructions(op *operation.Operation, bytes []byte, input channel.Channel) ([]*operation.Operation, error) {
initialAddress := op.Address()
totalInstructions := len(bytes) / consts.BYTES_PER_WORD
ops := []*operation.Operation{}
// Analyze each instruction loaded
for i := 0; i < totalInstructions; i += 1 {
data := bytes[i*consts.BYTES_PER_WORD : (i+1)*consts.BYTES_PER_WORD]
// Check program reach end
if this.Processor().ReachedEnd(data) {
this.processor.Finish()
return ops, nil
}
// Do fetch once a new address is received
msg := fmt.Sprintf(" => [FE%d][%03d]: INS[%#04X] = %#04X", this.Index(), this.Processor().InstructionsFetchedCounter(), op.Address(), data)
value, ok := this.Processor().InstructionsMap()[op.Address()]
if ok {
msg = fmt.Sprintf("%s // %s", msg, strings.TrimSpace(strings.Split(value, "=>")[1]))
}
logger.Collect(msg)
// Log event
this.Processor().LogInstructionFetched(op.Address())
// Update data into operation and add to array for post-events
op.SetWord([]byte{data[0], data[1], data[2], data[3]})
// Add operation to be sent to decode channel
ops = append(ops, op)
// Do pre-decode
needsWait, instruction := this.BranchPredictor().PreDecodeInstruction(op.Address())
// If is not pipelined than wait instruction to finish
if !this.Processor().Config().Pipelined() {
go func() {
address, _, err := this.BranchPredictor().GetNextAddress(op.Address(), instruction, true)
newOp := operation.New(this.Processor().InstructionsFetchedCounter(), address)
if err == nil {
input.Add(newOp)
}
}()
return ops, nil
}
// Add next instruction for fetching (as many instructions as it supports per cycle)
if needsWait {
logger.Collect(" => [FE%d][%03d]: Wait detected, no fetching more instructions this cycle", this.Index(), this.Processor().InstructionsFetchedCounter()-1)
// Add next instruction in a go routine as it need to be stalled
go func() {
address, _, err := this.BranchPredictor().GetNextAddress(op.Address(), instruction, false)
newOp := operation.New(this.Processor().InstructionsFetchedCounter(), address)
if err == nil {
input.Add(newOp)
}
}()
return ops, nil
} else {
address, predicted, err := this.BranchPredictor().GetNextAddress(op.Address(), instruction, false)
// Set current operation added to be decoded the predicted address
if predicted {
ops[len(ops)-1].SetNextPredictedAddress(address)
}
// Create new operation object
op = operation.New(this.Processor().InstructionsFetchedCounter(), address)
// If is the last instruction from the package or the predicted address is outside of the address package
if err == nil && (i >= totalInstructions-1 || initialAddress+(uint32(i+1)*consts.BYTES_PER_WORD) != op.Address()) {
input.Add(op)
return ops, nil
}
}
}
return ops, nil
}
作者:felipegs0
项目:processor_simulato
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()
}
}
作者:felipegs0
项目:processor_simulato
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
}
}()
}