Loading files
dbfa8e081This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2019- RSD contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
//
// Recovery Manager
// リカバリに遷移する信号を各モジュールにブロードキャストするモジュール
// モジュールのリカバリ自体はそれぞれのモジュール中で記述される
//
// 例外が起きてリカバリが行われる様子は以下のようになっている
// 1. RwStageもしくはCmStageからexceptionDetected信号が, RecoveryManagerに発信される
// 2. exceptionDetected信号があさーとされた次のサイクルに, 各モジュールにtoRecoveryPhase信号が発信される(PHASE_RECOVER_0)
// 3. すべてのモジュールのリカバリが終わったことを確認したら, 各モジュールにtoCommitPhase信号を送り, リカバリ終了
`include "BasicMacros.sv"
import BasicTypes::*;
import MemoryMapTypes::*;
import PipelineTypes::*;
import RenameLogicTypes::*;
import SchedulerTypes::*;
import ActiveListIndexTypes::*;
module RecoveryManager(
RecoveryManagerIF.RecoveryManager port,
ActiveListIF.RecoveryManager activeList,
CSR_UnitIF.RecoveryManager csrUnit,
ControllerIF.RecoveryManager ctrl,
PerformanceCounterIF.RecoveryManager perfCounter
);
typedef struct packed
{
// リカバリのフェーズ
// 実行ステージからリカバリがかかる場合もあるので,
// コミットステージのフェーズと同期しているわけではない
PipelinePhase phase;
// リカバリ要求
// これらはステージの終わりのあたりで来ることが多いので,一旦レジスタに積んで
// パイプライン化する
logic exceptionDetectedInCommitStage;
AddrPath recoveredPC_FromRwStage;
AddrPath recoveredPC_FromCommitStage;
// Related to CSR
// これらもパイプライン化のため
ExecutionState excptCause; // Trap vector or MRET return target
AddrPath excptCauseDataAddr; // fault 発生時のデータアドレス
// ActiveList中のどのエントリがどのエントリまでをフラッシュするかを示すポインタ
ActiveListIndexPath flushRangeHeadPtr;
ActiveListIndexPath flushRangeTailPtr;
logic recoveryFromRwStage; // 例外がどこのステージで検出されたか
RefetchType refetchType; // リフェッチのタイプ
} RecoveryManagerStatePath;
RecoveryManagerStatePath regState;
RecoveryManagerStatePath nextState;
// 各モジュールに送られる信号
// リカバリ時の動作自体は各モジュールで記述される
logic toRecoveryPhase, toCommitPhase;
// CSR からリフェッチするかどうか
logic refetchFromCSR;
//リカバリによって回復されるPC
PC_Path recoveredPC;
// 例外を起こした命令のActiveListのポインタ
ActiveListIndexPath exceptionOpPtr;
// 例外が検出された後リカバリ状態に移行する
logic exceptionDetected;
always_ff@(posedge port.clk) begin // synchronous rst
if (!port.rst) begin
regState <= nextState;
end
else begin
regState.phase <= PHASE_COMMIT;
regState.flushRangeHeadPtr <= '0;
regState.flushRangeTailPtr <= '0;
regState.recoveryFromRwStage <= FALSE;
regState.refetchType <= REFETCH_TYPE_THIS_PC;
regState.exceptionDetectedInCommitStage <= '0;
regState.recoveredPC_FromRwStage <= '0;
regState.recoveredPC_FromCommitStage <= '0;
regState.excptCause <= EXEC_STATE_NOT_FINISHED;
regState.excptCauseDataAddr <= '0;
end
end
always_comb begin
// To Recovery 0
toRecoveryPhase =
port.exceptionDetectedInCommitStage ||
port.exceptionDetectedInRwStage;
if (toRecoveryPhase) begin
nextState.recoveryFromRwStage = port.exceptionDetectedInRwStage;
end
else begin
nextState.recoveryFromRwStage = FALSE;
end
// Return to COMMIT_PHASE
toCommitPhase =
(regState.phase == PHASE_RECOVER_1) && // must be PHASE_RECOVER_1 because PHASE_RECOVER_0 procedures has been finished
!(port.renameLogicRecoveryRMT || port.issueQueueReturnIndex); // LSQ は1サイクルでリカバリが行われるので待つべきは RMT と IQ
nextState.refetchType =
port.exceptionDetectedInCommitStage ?
port.refetchTypeFromCommitStage :
port.refetchTypeFromRwStage;
// Trap/fault origin
// これらの要求は一旦レジスタに積む
nextState.excptCause = port.recoveryCauseFromCommitStage;
nextState.excptCauseDataAddr = port.faultingDataAddr;
nextState.exceptionDetectedInCommitStage = port.exceptionDetectedInCommitStage;
nextState.recoveredPC_FromRwStage = port.recoveredPC_FromRwStage;
nextState.recoveredPC_FromCommitStage = port.recoveredPC_FromCommitStage;
// CSR への要求はすべて PHASE_RECOVER_0 に行う
refetchFromCSR = regState.refetchType inside {
REFETCH_TYPE_NEXT_PC_TO_CSR_TARGET, REFETCH_TYPE_THIS_PC_TO_CSR_TARGET
};
csrUnit.triggerExcpt = (regState.phase == PHASE_RECOVER_0) && refetchFromCSR;
csrUnit.excptCauseAddr = ToPC_FromAddr(regState.recoveredPC_FromCommitStage);
csrUnit.excptCause = regState.excptCause;
csrUnit.excptCauseDataAddr = regState.excptCauseDataAddr;
// Recovered PC
if(regState.phase == PHASE_RECOVER_0) begin
if (refetchFromCSR) begin
recoveredPC = ToPC_FromAddr(csrUnit.excptTargetAddr);
end
else begin
if (regState.refetchType == REFETCH_TYPE_THIS_PC) begin
recoveredPC = regState.exceptionDetectedInCommitStage ?
ToPC_FromAddr(regState.recoveredPC_FromCommitStage) :
ToPC_FromAddr(regState.recoveredPC_FromRwStage);
end
else if (regState.refetchType inside{REFETCH_TYPE_NEXT_PC, REFETCH_TYPE_STORE_NEXT_PC}) begin
recoveredPC = regState.exceptionDetectedInCommitStage ?
ToPC_FromAddr(regState.recoveredPC_FromCommitStage) + INSN_BYTE_WIDTH :
ToPC_FromAddr(regState.recoveredPC_FromRwStage) + INSN_BYTE_WIDTH;
end
else begin // REFETCH_TYPE_BRANCH_TARGET
recoveredPC = regState.exceptionDetectedInCommitStage ?
ToPC_FromAddr(regState.recoveredPC_FromCommitStage) :
ToPC_FromAddr(regState.recoveredPC_FromRwStage);
end
end
end
else begin
recoveredPC = '0;
end
if(port.rst) begin
nextState.phase = PHASE_COMMIT;
end
else if(regState.phase == PHASE_COMMIT) begin
nextState.phase = toRecoveryPhase ? PHASE_RECOVER_0 : PHASE_COMMIT;
end
else if(regState.phase == PHASE_RECOVER_0) begin
nextState.phase = PHASE_RECOVER_1;
end
else begin
nextState.phase = toCommitPhase ? PHASE_COMMIT : regState.phase;
end
port.phase = regState.phase;
// Update a PC in a fetcher if branch misprediction occurs.
port.recoveredPC_FromRwCommit = recoveredPC;
port.toCommitPhase = toCommitPhase;
// To each logic to be recovered.
port.toRecoveryPhase = regState.phase == PHASE_RECOVER_0;
port.recoveryFromRwStage = regState.recoveryFromRwStage;
// 選択的フラッシュにおいても,フロントエンドは全てフラッシュされる
ctrl.cmStageFlushUpper = regState.phase == PHASE_RECOVER_0;
// フラッシュする命令の範囲の管理
exceptionDetected = port.exceptionDetectedInCommitStage || port.exceptionDetectedInRwStage;
exceptionOpPtr = activeList.exceptionOpPtr;
nextState.flushRangeHeadPtr =
(nextState.refetchType inside {REFETCH_TYPE_THIS_PC, REFETCH_TYPE_THIS_PC_TO_CSR_TARGET}) ?
exceptionOpPtr : exceptionOpPtr + 1;
nextState.flushRangeTailPtr = activeList.detectedFlushRangeTailPtr;
port.loadQueueRecoveryTailPtr = activeList.loadQueueRecoveryTailPtr;
port.storeQueueRecoveryTailPtr =
regState.refetchType == REFETCH_TYPE_STORE_NEXT_PC ?
(activeList.storeQueueRecoveryTailPtr + 1): activeList.storeQueueRecoveryTailPtr;
port.flushRangeHeadPtr = regState.flushRangeHeadPtr;
port.flushRangeTailPtr = regState.flushRangeTailPtr;
//
port.unableToStartRecovery =
(regState.phase != PHASE_COMMIT) ||
port.renameLogicRecoveryRMT ||
port.issueQueueReturnIndex ||
port.replayQueueFlushedOpExist ||
port.wakeupPipelineRegFlushedOpExist;
// Hardware Counter
`ifndef RSD_DISABLE_PERFORMANCE_COUNTER
perfCounter.storeLoadForwardingFail =
regState.phase == PHASE_RECOVER_0 && (regState.refetchType == REFETCH_TYPE_THIS_PC);
perfCounter.memDepPredMiss =
regState.phase == PHASE_RECOVER_0 && (regState.refetchType inside {REFETCH_TYPE_NEXT_PC, REFETCH_TYPE_STORE_NEXT_PC});
perfCounter.branchPredMiss =
regState.phase == PHASE_RECOVER_0 && (regState.refetchType == REFETCH_TYPE_BRANCH_TARGET);
`endif
end
// Commit/Recovery state manage
`RSD_ASSERT_CLK(
port.clk,
!(toCommitPhase && toRecoveryPhase),
"Tried to start the commit phase and the recovery phase at the same time"
);
`RSD_ASSERT_CLK(
port.clk,
!(port.exceptionDetectedInRwStage && nextState.refetchType inside {REFETCH_TYPE_NEXT_PC_TO_CSR_TARGET, REFETCH_TYPE_THIS_PC_TO_CSR_TARGET} ),
"RW stage recovery is not allowed in REFETCH_TYPE_CSR_UNIT_TARGET"
);
endmodule : RecoveryManager