func (this *ReorderBuffer) LoadData(op *operation.Operation, address uint32) uint32 { robEntry, ok := this.getEntryByDestination(op.Id(), MemoryType, address) if ok { return uint32(robEntry.Value) } return this.Processor().DataMemory().LoadUint32(address) }
func (this *ReorderBuffer) SetProgramCounter(op *operation.Operation, value uint32) { this.Buffer()[op.Id()] = RobEntry{ Operation: op, Type: ProgramCounterType, Destination: AbsoluteType, Value: int32(value), Cycle: this.Processor().Cycles(), } }
func (this *ReorderBuffer) IncrementProgramCounter(op *operation.Operation, value int32) { this.Buffer()[op.Id()] = RobEntry{ Operation: op, Type: ProgramCounterType, Destination: OffsetType, Value: value, Cycle: this.Processor().Cycles(), } }
func (this *ReorderBuffer) StoreData(op *operation.Operation, address, value uint32) { this.Buffer()[op.Id()] = RobEntry{ Operation: op, Type: MemoryType, Destination: address, Value: int32(value), Cycle: this.Processor().Cycles(), } }
func (this *ReorderBuffer) StoreRegister(op *operation.Operation, index, value uint32) { dest := index // If renaming register enabled if op.RenamedDestRegister() != -1 { dest = uint32(op.RenamedDestRegister()) } this.Buffer()[op.Id()] = RobEntry{ Operation: op, Type: RegisterType, Destination: dest, Value: int32(value), Cycle: this.Processor().Cycles(), } }
func (this *ReservationStation) dispatchOperation(entryIndex EntryIndex, op *operation.Operation) { // Lock a slot in max quantity of instructions dispatcher per cycle this.AddInstructionsFetchedStack() // Release reservation station entry this.Entries()[entryIndex].Busy = true go func() { // Release one entry and send operation to execution, when output channel (execution unit) is free logger.Collect(" => [RS%d][%03d]: Sending entry %d to %s queue...", this.Index(), op.Id(), entryIndex, op.Instruction().Info.Category) // Wait dispatch cycles startCycles := this.Processor().Cycles() this.Processor().Wait(consts.DISPATCH_CYCLES) // Log completion this.Processor().LogEvent(consts.DISPATCH_EVENT, this.Index(), op.Id(), startCycles) // Send data to execution unit in a go routine, when execution unit is available go this.Output()[op.Instruction().Info.Category].Add(op) }() }
func (this *Decoder) decodeInstruction(op *operation.Operation) (*instruction.Instruction, error) { startCycles := this.Processor().Cycles() // Do decode once a data instruction is received instruction, err := this.Processor().InstructionsSet().GetInstructionFromBytes(op.Word()) if err != nil { return nil, errors.New(fmt.Sprintf("Failed decoding instruction %#04X. %s]", op.Word(), err.Error())) } logger.Collect(" => [DE%d][%03d]: %#04X = %s, %s", this.Index(), op.Id(), op.Word(), instruction.Info.ToString(), instruction.Data.ToString()) // Wait cycles of a decode stage this.Processor().Wait(consts.DECODE_CYCLES) // Log event if this.IsActive() { this.Processor().LogEvent(consts.DECODE_EVENT, this.Index(), op.Id(), startCycles) } return instruction, nil }
func (this *Executor) executeOperation(unit IExecutor, event string, op *operation.Operation) (*operation.Operation, error) { startCycles := this.Processor().Cycles() // Do decode once a data instruction is received var err error op, err = unit.Process(op) if err != nil { return op, errors.New(fmt.Sprintf("Failed executing instruction. %s]", err.Error())) } // Wait cycles of a execution stage logger.Collect(" => [%s%d][%03d]: Executing %s, %s", event, this.Index(), op.Id(), op.Instruction().Info.ToString(), op.Instruction().Data.ToString()) for i := uint8(0); i < op.Instruction().Info.Cycles; i++ { this.Processor().Wait(1) } // Log completion if this.IsActive() { this.Processor().LogEvent(event, this.Index(), op.Id(), startCycles) } return op, nil }
func (this *Fpu) Process(operation *operation.Operation) (*operation.Operation, error) { instruction := operation.Instruction() outputAddress, err := this.compute(operation, instruction.Info, instruction.Data) if err != nil { return operation, err } logger.Collect(" => [FPU][%03d]: [R%d(%#02X) = %#08X]", operation.Id(), outputAddress, outputAddress*consts.BYTES_PER_WORD, this.Result()) // Persist output data this.Bus().StoreRegister(operation, outputAddress, this.Result()) return operation, nil }
func (this *ReorderBuffer) LoadRegister(op *operation.Operation, index uint32) uint32 { lookupRegister := index // If renaming register enabled if len(this.RegisterAliasTable().Entries()) > 0 { ratEntry, ok := this.RegisterAliasTable().GetPhysicalRegister(op.Id()-1, index) if ok { // Proceed to search register in ROB with renamed dest from RAT lookupRegister = ratEntry } else { // Alias does not exist, value was already commited (search on memory) return this.Processor().RegistersMemory().LoadUint32(index * consts.BYTES_PER_WORD) } } // Search register on ROB robEntry, ok := this.getEntryByDestination(op.Id(), RegisterType, lookupRegister) if ok { return uint32(robEntry.Value) } return this.Processor().RegistersMemory().LoadUint32(index * consts.BYTES_PER_WORD) }
func (this *Branch) Process(operation *operation.Operation) (*operation.Operation, error) { instruction := operation.Instruction() info := instruction.Info operands := instruction.Data switch info.Type { case data.TypeI: registerD := operands.(*data.DataI).RegisterD.ToUint32() op1 := this.Bus().LoadRegister(operation, registerD) registerS := operands.(*data.DataI).RegisterS.ToUint32() op2 := this.Bus().LoadRegister(operation, registerS) logger.Collect(" => [BR][%03d]: [R%d(%#02X) = %#08X ? R%d(%#02X) = %#08X]", operation.Id(), registerD, registerD*consts.BYTES_PER_WORD, op1, registerS, registerS*consts.BYTES_PER_WORD, op2) taken, err := processOperation(op1, op2, info.Opcode) if err != nil { return operation, nil } operation.SetBranchResult(taken) if taken { offsetAddress := ComputeOffsetTypeI(operands) this.Bus().IncrementProgramCounter(operation, offsetAddress) logger.Collect(" => [BR][%03d]: [PC(offset) = 0x%06X", operation.Id(), offsetAddress) } else { // Notify ROB this.Bus().IncrementProgramCounter(operation, 0) } case data.TypeJ: address := ComputeAddressTypeJ(operands) this.Bus().SetProgramCounter(operation, uint32(address-consts.BYTES_PER_WORD)) logger.Collect(" => [BR][%03d]: [Address = %06X]", operation.Id(), address) default: return operation, errors.New(fmt.Sprintf("Invalid data type to process by Branch unit. Type: %d", info.Type)) } return operation, nil }
func (this *ReorderBuffer) waitStallOperationIfFull(op *operation.Operation) { for uint32(len(this.Buffer())) >= this.RobEntries() { lastCompletedOpId := this.Processor().LastOperationIdCompleted() if op.Id() == lastCompletedOpId+1 { logger.Collect(" => [RB%d][%03d]: Writing latest instruction.", this.Index(), op.Id()) return } logger.Collect(" => [RB%d][%03d]: ROB is full, wait for free entries. Current: %d, Max: %d, LastOpId: %d...", this.Index(), op.Id(), len(this.Buffer()), this.RobEntries(), lastCompletedOpId) this.Processor().Wait(1) } }
func (this *Alu) Process(operation *operation.Operation) (*operation.Operation, error) { instruction := operation.Instruction() // Clean Status this.CleanStatus() outputAddress, err := this.compute(operation, instruction.Info, instruction.Data) if err != nil { return operation, err } logger.Collect(" => [ALU][%03d]: [R%d(%#02X) = %#08X]", operation.Id(), outputAddress, outputAddress*consts.BYTES_PER_WORD, this.Result()) // Set status flags this.SetStatusFlag(this.Result()%2 == 0, consts.FLAG_PARITY) this.SetStatusFlag(this.Result() == 0, consts.FLAG_ZERO) this.SetStatusFlag(getSign(this.Result()), consts.FLAG_SIGN) // Persist output data this.Bus().StoreRegister(operation, outputAddress, this.Result()) return operation, nil }
func (this *LoadStore) Process(operation *operation.Operation) (*operation.Operation, error) { instruction := operation.Instruction() rdAddress := instruction.Data.(*data.DataI).RegisterD.ToUint32() rsAddress := instruction.Data.(*data.DataI).RegisterS.ToUint32() immediate := instruction.Data.(*data.DataI).Immediate.ToUint32() switch instruction.Info.Opcode { case set.OP_LW: rsValue := this.Bus().LoadRegister(operation, rsAddress) value := this.Bus().LoadData(operation, rsValue+immediate) this.Bus().StoreRegister(operation, rdAddress, value) logger.Collect(" => [LS][%03d]: [R%d(%#02X) = MEM(%#02X) = %#08X]", operation.Id(), rdAddress, rdAddress*consts.BYTES_PER_WORD, rsValue+immediate, value) case set.OP_SW: rdValue := this.Bus().LoadRegister(operation, rdAddress) rsValue := this.Bus().LoadRegister(operation, rsAddress) this.Bus().StoreData(operation, rdValue+immediate, rsValue) logger.Collect(" => [LS][%03d]: [MEM(%#02X) = %#08X]", operation.Id(), rdValue+immediate, rsValue) case set.OP_LLI: this.Bus().StoreRegister(operation, rdAddress, immediate) logger.Collect(" => [LS][%03d]: [R%d(%#02X) = %#08X]", operation.Id(), rdAddress, rdAddress*consts.BYTES_PER_WORD, immediate) case set.OP_SLI: rdValue := this.Bus().LoadRegister(operation, rdAddress) this.Bus().StoreData(operation, rdValue, immediate) logger.Collect(" => [LS][%03d]: [MEM(%#02X) = %#08X]", operation.Id(), rdValue, immediate) case set.OP_LUI: this.Bus().StoreRegister(operation, rdAddress, immediate<<16) logger.Collect(" => [LS][%03d]: [R%d(%#02X) = %#08X]", operation.Id(), rdAddress, rdAddress*consts.BYTES_PER_WORD, immediate<<16) case set.OP_SUI: rdValue := this.Bus().LoadRegister(operation, rdAddress) this.Bus().StoreData(operation, rdValue, immediate<<16) logger.Collect(" => [LS][%03d]: [MEM(%#02X) = %#08X]", operation.Id(), rdValue, immediate<<16) default: return operation, errors.New(fmt.Sprintf("Invalid operation to process by Data unit. Opcode: %d", instruction.Info.Opcode)) } return operation, nil }