func (this *ReorderBuffer) commitRobEntry(robEntry RobEntry, startCycles uint32) {

	// Commit update
	opId := robEntry.Operation.Id()
	if robEntry.Type == RegisterType {

		// Register renaming (RAT)
		dest := robEntry.Destination
		if robEntry.Operation.RenamedDestRegister() != -1 {
			dest = this.RegisterAliasTable().Entries()[robEntry.Destination].ArchRegister

			// Release entry from RAT
			this.RegisterAliasTable().Release(opId)
		}

		logger.Collect(" => [RB%d][%03d]: Writing %#08X to %s%d...", this.Index(), opId, robEntry.Value, robEntry.Type, dest)
		this.Processor().RegistersMemory().StoreUint32(dest*consts.BYTES_PER_WORD, uint32(robEntry.Value))
	} else if robEntry.Type == MemoryType {
		logger.Collect(" => [RB%d][%03d]: Writing %#08X to %s[%#X]...", this.Index(), opId, robEntry.Value, robEntry.Type, robEntry.Destination)
		this.Processor().DataMemory().StoreUint32(robEntry.Destination, uint32(robEntry.Value))
	} else {
		this.Processor().SetProgramCounter(this.getNextProgramCounter(robEntry, this.Processor().ProgramCounter()))
	}

	// Increment program counter
	this.Processor().IncrementProgramCounter(consts.BYTES_PER_WORD)
	logger.Collect(" => [RB%d][%03d]: PC = %#04X", this.Index(), opId, this.Processor().ProgramCounter())

	// Release ROB entry
	delete(this.Buffer(), opId)
}
func (this *BranchPredictor) GetNextAddress(address uint32, instruction *instruction.Instruction, forceStall bool) (uint32, bool, error) {

	nextData := this.Processor().InstructionsMemory().Load(address, consts.BYTES_PER_WORD)
	opId := this.Processor().InstructionsFetchedCounter() - 1
	this.Processor().AddSpeculativeJump()

	// Check if next instruction is valid
	if this.Processor().ReachedEnd(nextData) {
		this.waitQueueInstructions()
		this.processor.Finish()
		logger.Collect(" => [BP%d][%03d]: Program reached the end", this.Index(), opId)
		return 0, false, errors.New("Program reached the end")
	}

	// If it needs to wait
	needsWait, predicted := this.needsWait(instruction.Info)
	if needsWait || forceStall {
		// Stall until previous instruction finishes
		logger.Collect(" => [BP%d][%03d]: Branch detected, wait to finish queue (%d out of %d)...",
			this.Index(), this.Processor().InstructionsFetchedCounter()-1, this.Processor().InstructionsCompletedCounter(), opId)
		this.waitQueueInstructions()
		logger.Collect(" => [BP%d][%03d]: Waited for address resolution and got %#04X", this.Index(), opId, this.Processor().ProgramCounter())
		return this.Processor().ProgramCounter(), false, nil
	} else {
		newAddress := this.guessAddress(address, instruction)
		if instruction.Info.IsBranch() {
			logger.Collect(" => [BP%d][%03d]: Predicted address: %#04X", this.Index(), opId, newAddress)
		}
		return newAddress, predicted, nil
	}
}
func (this *BranchPredictor) getGuessByAddress(address uint32) bool {
	state, exists := this.Processor().GetBranchStateByAddress(address)
	if !exists {
		logger.Collect(" => [BP0]: No history for address %#04X", address)
		return false
	}
	totalStates := uint32(math.Exp2(float64(this.PredictorBits())))
	taken := state >= totalStates/2
	logger.Collect(" => [BP0]: Address %#04X, Total States: %d, State: %d ,Taken: %v", address, totalStates, state, taken)
	return taken
}
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)
	}
}
Exemplo n.º 5
0
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 *BranchPredictor) waitQueueInstructions() {
	for !this.isInstructionCompleted(this.Processor().InstructionsFetchedCounter() - 1) {
		logger.Collect(" => [BP%d][%03d]: Branch detected, wait to finish queue (%d out of %d)...",
			this.Index(), this.Processor().InstructionsFetchedCounter()-1, this.Processor().InstructionsCompletedCounter(), this.Processor().InstructionsFetchedCounter())
		this.Processor().Wait(1)
		// Let execute stage add instruction into InstructionsCompleted queue first and then compare lenghts
		time.Sleep(this.Processor().Config().CyclePeriod() / 2)
	}
}
Exemplo n.º 7
0
func (this Channel) Add(value interface{}) {
	defer func() {
		if r := recover(); r != nil {
			logger.Collect("WARN: Recovered in %v", r)
		}
	}()
	if !this.isClosed {
		this.locks <- true
		this.channel <- value
	}
}
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()
	}
}
Exemplo n.º 9
0
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
}
Exemplo n.º 10
0
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
}
Exemplo n.º 11
0
func (this *Clock) Run() {
	this.clock.startTime = time.Now()
	this.clock.ticker = time.NewTicker(this.clock.period)

	for tickTime := range this.clock.ticker.C {
		// If event finish equals to true, then finish
		if this.finishEvent() {
			logger.Collect(" => Stopping clock...")
			this.Stop()
			break
		}

		// If paused wait until next tick
		if !this.clock.paused {

			// Update clock status
			this.clock.cycles += 1
			this.clock.duration = tickTime.Sub(this.clock.startTime)
			this.clock.tick <- true

			logger.Collect("\n-------- Cycle: %04d ------- (%04d ms)", this.clock.cycles, this.DurationMs())
		}
	}
}
Exemplo n.º 12
0
func (this *ReorderBuffer) commitRobEntries(robEntries []RobEntry) {
	startCycles := this.Processor().Cycles()
	// Commit results in order
	opIds := []uint32{}
	for _, robEntry := range robEntries {
		opIds = append(opIds, robEntry.Operation.Id())
		logger.Collect(" => [RB%d][%03d]: Commiting operation %d...", this.Index(), robEntry.Operation.Id(), robEntry.Operation.Id())
		this.commitRobEntry(robEntry, startCycles)
	}
	// Wait and log completion in a go routine
	go func(opIds []uint32, startCycles uint32) {
		this.Processor().Wait(consts.WRITEBACK_CYCLES)
		for _, opId := range opIds {
			this.Processor().LogEvent(consts.WRITEBACK_EVENT, this.Index(), opId, startCycles)
			this.Processor().LogInstructionCompleted(opId)
		}
	}(opIds, startCycles)
}
Exemplo n.º 13
0
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) 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)
	}()
}
Exemplo n.º 15
0
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
}
Exemplo n.º 16
0
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
}
Exemplo n.º 17
0
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
}
Exemplo n.º 18
0
func (this *ReorderBuffer) checkForMisprediction(targetEntry RobEntry, cachedEntries []RobEntry) (bool, uint32) {
	op := targetEntry.Operation

	if !op.Instruction().Info.IsBranch() {
		return false, 0
	}

	// If operation does not have a predicted address, then return
	if op.PredictedAddress() == -1 {
		this.Processor().LogBranchInstruction(op.Address(), op.Instruction().Info.IsConditionalBranch(), false, op.Taken())
		return false, 0
	}

	// If predicted address is equal to the computed address, then return
	computedAddress := this.getNextProgramCounter(targetEntry, this.getCachedProgramCounter(cachedEntries))
	failed := computedAddress != uint32(op.PredictedAddress())
	if failed {
		logger.Collect(" => [RB%d][%03d]: Misprediction found, it was predicted: %#04X and computed: %#04X",
			this.Index(), targetEntry.Operation.Id(), op.PredictedAddress(), computedAddress)
	}
	this.Processor().LogBranchInstruction(op.Address(), op.Instruction().Info.IsConditionalBranch(), failed, op.Taken())
	return failed, computedAddress
}
Exemplo n.º 19
0
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
}
Exemplo n.º 20
0
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
}
Exemplo n.º 21
0
func (this *Processor) Finish() {
	logger.Collect(" => Stopping processor...")
	this.processor.done = true
}
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()
	}
}