diff --git a/scripts/build_ut_frontend_ftq_ftq_top.py b/scripts/build_ut_frontend_ftq_ftq_top.py new file mode 100644 index 00000000..da7b98c5 --- /dev/null +++ b/scripts/build_ut_frontend_ftq_ftq_top.py @@ -0,0 +1,17 @@ +from comm.export_dut import picker_export + +TARGET_NAME = "FtqTop" + + +def build(cfg): + return picker_export( + source_name="Ftq", + target_name=TARGET_NAME, + access_mode=1, + cfg=cfg, + ) + + +## set coverage +def line_coverage_files(cfg): + return ["Ftq.v"] diff --git a/scripts/build_ut_frontend_ftq_top.py b/scripts/build_ut_frontend_ftq_top.py deleted file mode 100644 index aee304a1..00000000 --- a/scripts/build_ut_frontend_ftq_top.py +++ /dev/null @@ -1,12 +0,0 @@ -from comm.export_dut import picker_export - -TARGET_NAME = "Ftq" - - -def build(cfg): - return picker_export(TARGET_NAME, cfg) - - -## set coverage -def line_coverage_files(cfg): - return ["Ftq.v"] diff --git a/ut_frontend/ftq/ftq_top/README.md b/ut_frontend/ftq/ftq_top/README.md new file mode 100644 index 00000000..fff678e4 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/README.md @@ -0,0 +1,36 @@ +这是对香山RISC-V处理器中FtqTop模块的验证代码。FtqTop是指令取指目标队列模块,负责管理处理器前端的指令流。 + +验证内容 + +验证覆盖了FtqTop模块的7个主要功能: +向IFU发送取指目标 +接收并处理IFU预译码信息 +响应后端重定向 +响应IFU重定向 +向后端发送取指目标 +响应重定向并更新内部状态 +冲刷指针和状态队列 + + +测试环境 + +操作系统:Ubuntu 22.04 +Python版本:3.10.12 +使用工具:Picker 0.9.0, Verilator 5.027, pytest 8.4.0 + + +测试用例 + +共有7个测试文件,对应不同的功能点: +test_ftq_top3.py:测试取指目标发送功能 +test_ftq_top4.py:测试预译码处理功能 +test_ftq_top5.py:测试后端重定向响应 +test_ftq_top6.py:测试IFU重定向响应 +test_ftq_top7.py:测试向后端发送目标 +test_ftq_top8.py:测试状态更新 +test_ftq_top9.py:测试冲刷逻辑 + +运行方式:make run CASE=数字(3-9) + + +所有测试用例均通过,行覆盖率达到76.2%,模块功能符合设计预期。 \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/__init__.py b/ut_frontend/ftq/ftq_top/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ut_frontend/ftq/ftq_top/env/__init__.py b/ut_frontend/ftq/ftq_top/env/__init__.py new file mode 100644 index 00000000..23d9b130 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/env/__init__.py @@ -0,0 +1,13 @@ +from toffee import Env # 导入基类 Env + +# 相对导入 FtqBundle 和 FtqAgent(从同级 bundle/ 和 agent/) +from .ftq_bundle import FtqBundle +from .ftq_agent import FtqAgent + + + +class FtqEnv(Env): + def __init__(self, ftq_bundle, dut=None): # 接收 bundle 和 dut + super().__init__() + self.ftq_agent = FtqAgent(ftq_bundle) # 设置 agent + self.dut = dut # 存储 dut 作为实例属性 \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/env/ftq_agent.py b/ut_frontend/ftq/ftq_top/env/ftq_agent.py new file mode 100644 index 00000000..a0cd4d66 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/env/ftq_agent.py @@ -0,0 +1,545 @@ +from toffee import * + + +class FtqAgent(Agent): + def __init__(self, ftq_bundle): + super().__init__(ftq_bundle) + + + + + @driver_method() + async def drive_backend_inputs( + self, + valid=None, + ftqIdx_value=None, + ftqOffset=None, + cfiUpdate_target=None, + cfiUpdate_taken=None, + cfiUpdate_isMisPred=None, + ftqIdx_flag=None, + level=None, + debugIsCtrl=None, + debugIsMemVio=None, + ftqIdxAhead_0_valid=None, + ftqIdxAhead_0_bits_value=None, + ftqIdxSelOH_bits=None, + ): + if valid is not None: + self.bundle.fromBackend.redirect_valid.value = 1 if valid else 0 + if ftqIdx_value is not None: + self.bundle.fromBackend.redirect_bits_ftqIdx_value.value = ftqIdx_value + if ftqOffset is not None: + self.bundle.fromBackend.redirect_bits_ftqOffset.value = ftqOffset + if cfiUpdate_target is not None: + self.bundle.fromBackend.redirect_bits_cfiUpdate_target.value = cfiUpdate_target + if cfiUpdate_taken is not None: + self.bundle.fromBackend.redirect_bits_cfiUpdate_taken.value = 1 if cfiUpdate_taken else 0 + if cfiUpdate_isMisPred is not None: + self.bundle.fromBackend.redirect_bits_cfiUpdate_isMisPred.value = 1 if cfiUpdate_isMisPred else 0 + if ftqIdx_flag is not None: + self.bundle.fromBackend.redirect_bits_ftqIdx_flag.value = 1 if ftqIdx_flag else 0 + if level is not None: + self.bundle.fromBackend.redirect_bits_level.value = level + if debugIsCtrl is not None: + self.bundle.fromBackend.redirect_bits_debugIsCtrl.value = 1 if debugIsCtrl else 0 + if debugIsMemVio is not None: + self.bundle.fromBackend.redirect_bits_debugIsMemVio.value = 1 if debugIsMemVio else 0 + if ftqIdxAhead_0_valid is not None: + self.bundle.fromBackend.ftqIdxAhead_0_valid.value = 1 if ftqIdxAhead_0_valid else 0 + if ftqIdxAhead_0_bits_value is not None: + self.bundle.fromBackend.ftqIdxAhead_0_bits_value.value = ftqIdxAhead_0_bits_value + if ftqIdxSelOH_bits is not None: + self.bundle.fromBackend.ftqIdxSelOH_bits.value = ftqIdxSelOH_bits + return self.bundle.as_dict() + + @driver_method() + async def set_rob_commit(self, idx: int, valid=None, commitType=None, ftqIdx_flag=None, ftqIdx_value=None, ftqOffset=None): + assert 0 <= idx <= 7, "rob commit idx 必须在 [0..7]" + rb = getattr(self.bundle.fromBackend, f'rob_commits_{idx}') + if valid is not None: rb.valid.value = 1 if valid else 0 + if commitType is not None: rb.bits_commitType.value = commitType + if ftqIdx_flag is not None: rb.bits_ftqIdx_flag.value = 1 if ftqIdx_flag else 0 + if ftqIdx_value is not None: rb.bits_ftqIdx_value.value = ftqIdx_value + if ftqOffset is not None: rb.bits_ftqOffset.value = ftqOffset + return self.bundle.as_dict() + + + @driver_method() + async def drive_ifu_inputs( + self, + valid=None, + ftqIdx_value=None, + misOffset_bits=None, + target=None, + misOffset_valid=None, + cfiOffset_valid=None, + ftqIdx_flag=None, + ): + if valid is not None: + self.bundle.fromIfu.pdWb_valid.value = 1 if valid else 0 + if ftqIdx_value is not None: + self.bundle.fromIfu.pdWb_bits_ftqIdx_value.value = ftqIdx_value + if misOffset_bits is not None: + self.bundle.fromIfu.pdWb_bits_misOffset_bits.value = misOffset_bits + if target is not None: + self.bundle.fromIfu.pdWb_bits_target.value = target + if misOffset_valid is not None: + self.bundle.fromIfu.pdWb_bits_misOffset_valid.value = 1 if misOffset_valid else 0 + if cfiOffset_valid is not None: + self.bundle.fromIfu.pdWb_bits_cfiOffset_valid.value = 1 if cfiOffset_valid else 0 + if ftqIdx_flag is not None: + self.bundle.fromIfu.pdWb_bits_ftqIdx_flag.value = 1 if ftqIdx_flag else 0 + return self.bundle.as_dict() + + + + @driver_method() + async def drive_toifu_ready(self, ready): + self.bundle.toIfu.req_ready.value = 1 if ready else 0 + + return self.bundle.as_dict() + + + + @driver_method() + async def drive_s1_signals(self, valid=None, pc=None, fallThruError=None): + if valid is not None: + self.bundle.fromBpu.resp_valid.value = 1 if valid else 0 + if pc is not None: + self.bundle.fromBpu.resp_bits_s1_pc_3.value = pc + if fallThruError is not None: + self.bundle.fromBpu.resp_bits_s1_full_pred_3_fallThroughErr.value = 1 if fallThruError else 0 + return self.bundle.as_dict() + + @driver_method() + async def drive_s2_signals( + self, + valid=None, hasRedirect=None, pc=None, + redirect_idx=None, redirect_flag=None, fallThruError=None, + full_pred_3_hit=None, + ): + if valid is not None: + self.bundle.fromBpu.resp_bits_s2_valid_3.value = 1 if valid else 0 + if hasRedirect is not None: + self.bundle.fromBpu.resp_bits_s2_hasRedirect_3.value = 1 if hasRedirect else 0 + if pc is not None: + self.bundle.fromBpu.resp_bits_s2_pc_3.value = pc + if redirect_idx is not None: + self.bundle.fromBpu.resp_bits_s2_ftq_idx_value.value = redirect_idx + if redirect_flag is not None: + self.bundle.fromBpu.resp_bits_s2_ftq_idx_flag.value = redirect_flag + if fallThruError is not None: + self.bundle.fromBpu.resp_bits_s2_full_pred_3_fallThroughErr.value = 1 if fallThruError else 0 + if full_pred_3_hit is not None: + self.bundle.fromBpu.resp_bits_s2_full_pred_3_hit.value = 1 if full_pred_3_hit else 0 + return self.bundle.as_dict() + + + + @driver_method() + async def drive_s3_signals( + self, + valid=None, hasRedirect=None, pc=None, + redirect_idx=None, redirect_flag=None, fallThruError=None, + ): + if valid is not None: + self.bundle.fromBpu.resp_bits_s3_valid_3.value = 1 if valid else 0 + if hasRedirect is not None: + self.bundle.fromBpu.resp_bits_s3_hasRedirect_3.value = 1 if hasRedirect else 0 + if pc is not None: + self.bundle.fromBpu.resp_bits_s3_pc_3.value = pc + if redirect_idx is not None: + self.bundle.fromBpu.resp_bits_s3_ftq_idx_value.value = redirect_idx + if redirect_flag is not None: + self.bundle.fromBpu.resp_bits_s3_ftq_idx_flag.value = redirect_flag + if fallThruError is not None: + self.bundle.fromBpu.resp_bits_s3_full_pred_3_fallThroughErr.value = 1 if fallThruError else 0 + return self.bundle.as_dict() + + + @driver_method() + async def drive_s3_last_stage( + self, + isJalr=None, isCall=None, isRet=None, + brSlots_0_valid=None, brSlots_0_offset=None, + tailSlot_valid=None, tailSlot_offset=None, tailSlot_sharing=None, + valid=None, + ): + ls = self.bundle.fromBpu.last_stage_ftb_entry + if valid is not None: ls.valid.value = 1 if valid else 0 + if isJalr is not None: ls.isJalr.value = 1 if isJalr else 0 + if isCall is not None: ls.isCall.value = 1 if isCall else 0 + if isRet is not None: ls.isRet.value = 1 if isRet else 0 + if brSlots_0_valid is not None: ls.brSlots_0_valid.value = 1 if brSlots_0_valid else 0 + if brSlots_0_offset is not None: ls.brSlots_0_offset.value = brSlots_0_offset + if tailSlot_valid is not None: ls.tailSlot_valid.value = 1 if tailSlot_valid else 0 + if tailSlot_offset is not None: ls.tailSlot_offset.value = tailSlot_offset + if tailSlot_sharing is not None: ls.tailSlot_sharing.value = 1 if tailSlot_sharing else 0 + return self.bundle.as_dict() + + @driver_method() + async def set_ifu_pd(self, slot: int, brType=None, isCall=None, isRet=None, valid=None): + assert 0 <= slot <= 15, "slot 必须在 [0..15]" + if slot == 0: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_0.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_0.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_0.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_0.valid.value = 1 if valid else 0 + elif slot == 1: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_1.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_1.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_1.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_1.valid.value = 1 if valid else 0 + elif slot == 2: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_2.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_2.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_2.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_2.valid.value = 1 if valid else 0 + elif slot == 3: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_3.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_3.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_3.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_3.valid.value = 1 if valid else 0 + elif slot == 4: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_4.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_4.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_4.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_4.valid.value = 1 if valid else 0 + elif slot == 5: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_5.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_5.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_5.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_5.valid.value = 1 if valid else 0 + elif slot == 6: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_6.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_6.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_6.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_6.valid.value = 1 if valid else 0 + elif slot == 7: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_7.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_7.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_7.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_7.valid.value = 1 if valid else 0 + elif slot == 8: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_8.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_8.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_8.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_8.valid.value = 1 if valid else 0 + elif slot == 9: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_9.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_9.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_9.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_9.valid.value = 1 if valid else 0 + elif slot == 10: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_10.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_10.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_10.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_10.valid.value = 1 if valid else 0 + elif slot == 11: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_11.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_11.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_11.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_11.valid.value = 1 if valid else 0 + elif slot == 12: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_12.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_12.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_12.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_12.valid.value = 1 if valid else 0 + elif slot == 13: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_13.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_13.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_13.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_13.valid.value = 1 if valid else 0 + elif slot == 14: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_14.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_14.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_14.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_14.valid.value = 1 if valid else 0 + elif slot == 15: + if brType is not None: self.bundle.fromIfu.pdWb_bits_pd_15.brType.value = int(brType) + if isCall is not None: self.bundle.fromIfu.pdWb_bits_pd_15.isCall.value = 1 if isCall else 0 + if isRet is not None: self.bundle.fromIfu.pdWb_bits_pd_15.isRet.value = 1 if isRet else 0 + if valid is not None: self.bundle.fromIfu.pdWb_bits_pd_15.valid.value = 1 if valid else 0 + return self.bundle.as_dict() + + + @driver_method() + async def set_ifu_pc(self, slot: int, pc): + assert 0 <= slot <= 15, "必须在0-15" + if slot == 0: self.bundle.fromIfu.pdWb_bits_pc_0.value = pc + elif slot == 1: self.bundle.fromIfu.pdWb_bits_pc_1.value = pc + elif slot == 2: self.bundle.fromIfu.pdWb_bits_pc_2.value = pc + elif slot == 3: self.bundle.fromIfu.pdWb_bits_pc_3.value = pc + elif slot == 4: self.bundle.fromIfu.pdWb_bits_pc_4.value = pc + elif slot == 5: self.bundle.fromIfu.pdWb_bits_pc_5.value = pc + elif slot == 6: self.bundle.fromIfu.pdWb_bits_pc_6.value = pc + elif slot == 7: self.bundle.fromIfu.pdWb_bits_pc_7.value = pc + elif slot == 8: self.bundle.fromIfu.pdWb_bits_pc_8.value = pc + elif slot == 9: self.bundle.fromIfu.pdWb_bits_pc_9.value = pc + elif slot == 10: self.bundle.fromIfu.pdWb_bits_pc_10.value = pc + elif slot == 11: self.bundle.fromIfu.pdWb_bits_pc_11.value = pc + elif slot == 12: self.bundle.fromIfu.pdWb_bits_pc_12.value = pc + elif slot == 13: self.bundle.fromIfu.pdWb_bits_pc_13.value = pc + elif slot == 14: self.bundle.fromIfu.pdWb_bits_pc_14.value = pc + else: self.bundle.fromIfu.pdWb_bits_pc_15.value = pc + return self.bundle.as_dict() + + @driver_method() + async def set_rob_commit(self, idx: int, valid=None, commitType=None, ftqIdx_flag=None, ftqIdx_value=None, ftqOffset=None): + + assert 0 <= idx <= 7, "必须在0-7" + rb = getattr(self.bundle.fromBackend, f'rob_commits_{idx}') + if valid is not None: rb.valid.value = 1 if valid else 0 + if commitType is not None: rb.bits_commitType.value = commitType + if ftqIdx_flag is not None: rb.bits_ftqIdx_flag.value = 1 if ftqIdx_flag else 0 + if ftqIdx_value is not None: rb.bits_ftqIdx_value.value = ftqIdx_value + if ftqOffset is not None: rb.bits_ftqOffset.value = ftqOffset + return self.bundle.as_dict() + + @driver_method() + async def reset_inputs(self): + + self.bundle.fromBackend.redirect_valid.value = 0 + self.bundle.fromBackend.redirect_bits_ftqIdx_value.value = 0 + self.bundle.fromBackend.redirect_bits_ftqIdx_flag.value = 0 + self.bundle.fromBackend.redirect_bits_ftqOffset.value = 0 + self.bundle.fromBackend.redirect_bits_cfiUpdate_target.value = 0 + self.bundle.fromBackend.redirect_bits_cfiUpdate_taken.value = 0 + self.bundle.fromBackend.redirect_bits_cfiUpdate_isMisPred.value = 0 + self.bundle.fromBackend.redirect_bits_level.value = 0 + self.bundle.fromBackend.redirect_bits_debugIsCtrl.value = 0 + self.bundle.fromBackend.redirect_bits_debugIsMemVio.value = 0 + self.bundle.fromBackend.ftqIdxSelOH_bits.value = 0 + self.bundle.fromBackend.ftqIdxAhead_0_valid.value = 0 + self.bundle.fromBackend.ftqIdxAhead_0_bits_value.value = 0 + + + for i in range(8): + rb = getattr(self.bundle.fromBackend, f'rob_commits_{i}') + rb.valid.value = 0 + rb.bits_commitType.value = 0 + rb.bits_ftqIdx_flag.value = 0 + rb.bits_ftqIdx_value.value = 0 + rb.bits_ftqOffset.value = 0 + + + self.bundle.fromIfu.pdWb_bits_target.value = 0 + self.bundle.fromIfu.pdWb_bits_cfiOffset_valid.value = 0 + self.bundle.fromIfu.pdWb_bits_misOffset_valid.value = 0 + self.bundle.fromIfu.pdWb_bits_ftqIdx_value.value = 0 + self.bundle.fromIfu.pdWb_bits_ftqIdx_flag.value = 0 + self.bundle.fromIfu.pdWb_bits_misOffset_bits.value = 0 + self.bundle.fromIfu.pdWb_valid.value = 0 + + + self.bundle.toIfu.req_ready.value = 0 + + + self.bundle.fromBpu.resp_valid.value = 0 + self.bundle.fromBpu.resp_bits_s1_pc_3.value = 0 + self.bundle.fromBpu.resp_bits_s1_full_pred_3_fallThroughErr.value = 0 + self.bundle.fromBpu.resp_bits_s2_valid_3.value = 0 + self.bundle.fromBpu.resp_bits_s2_hasRedirect_3.value = 0 + self.bundle.fromBpu.resp_bits_s2_pc_3.value = 0 + self.bundle.fromBpu.resp_bits_s2_ftq_idx_value.value = 0 + self.bundle.fromBpu.resp_bits_s2_ftq_idx_flag.value = 0 + self.bundle.fromBpu.resp_bits_s2_full_pred_3_fallThroughErr.value = 0 + self.bundle.fromBpu.resp_bits_s2_full_pred_3_hit.value = 0 + self.bundle.fromBpu.resp_bits_s3_valid_3.value = 0 + self.bundle.fromBpu.resp_bits_s3_hasRedirect_3.value = 0 + self.bundle.fromBpu.resp_bits_s3_pc_3.value = 0 + self.bundle.fromBpu.resp_bits_s3_ftq_idx_value.value = 0 + self.bundle.fromBpu.resp_bits_s3_ftq_idx_flag.value = 0 + self.bundle.fromBpu.resp_bits_s3_full_pred_3_fallThroughErr.value = 0 + + self.bundle.fromBpu.last_stage_ftb_entry.valid.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.isJalr.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.isCall.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.isRet.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.brSlots_0_valid.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.brSlots_0_offset.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.tailSlot_valid.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.tailSlot_offset.value = 0 + self.bundle.fromBpu.last_stage_ftb_entry.tailSlot_sharing.value = 0 + + + self.bundle.fromIfu.pdWb_bits_pd_0.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_0.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_0.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_0.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_1.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_1.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_1.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_1.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_2.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_2.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_2.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_2.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_3.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_3.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_3.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_3.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_4.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_4.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_4.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_4.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_5.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_5.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_5.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_5.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_6.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_6.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_6.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_6.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_7.brType.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_7.isCall.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_7.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_7.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_8.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_8.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_9.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_9.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_10.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_10.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_11.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_11.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_12.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_12.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_13.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_13.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_14.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_14.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pd_15.isRet.value = 0 + self.bundle.fromIfu.pdWb_bits_pd_15.valid.value = 0 + + self.bundle.fromIfu.pdWb_bits_pc_0.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_1.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_2.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_3.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_4.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_5.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_6.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_7.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_8.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_9.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_10.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_11.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_12.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_13.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_14.value = 0 + self.bundle.fromIfu.pdWb_bits_pc_15.value = 0 + + for i in range(8): + rb = getattr(self.bundle.fromBackend, f'rob_commits_{i}') + rb.valid.value = 0 + rb.bits_commitType.value = 0 + rb.bits_ftqIdx_flag.value = 0 + rb.bits_ftqIdx_value.value = 0 + rb.bits_ftqOffset.value = 0 + + return self.bundle.as_dict() + + @driver_method() + async def set_write_mode_as_imme(self): + + self.bundle.set_write_mode_as_imme() + print("already set immediate mode") + + return self.bundle.as_dict() + + @driver_method() + async def set_write_mode_as_rise(self): + + self.bundle.set_write_mode_as_rise() + print("already set immediate mode") + + return self.bundle.as_dict() + + @driver_method() + async def set_write_mode_as_fall(self): + + self.bundle.set_write_mode_as_fall() + print("already set immediate mode") + + return self.bundle.as_dict() + + @driver_method() + async def reset5(self, dut): + + dut.reset.value = 1 + await self.bundle.step(5) + dut.reset.value = 0 + return self.bundle.as_dict() + + @driver_method() + async def get_toicache_outputs(self): + + outputs = { + 'req_valid': self.bundle.toICache.req_valid.value, + 'readValid': { + '0': self.bundle.toICache.req_bits_readValid_0.value, + '1': self.bundle.toICache.req_bits_readValid_1.value, + '2': self.bundle.toICache.req_bits_readValid_2.value, + '3': self.bundle.toICache.req_bits_readValid_3.value, + '4': self.bundle.toICache.req_bits_readValid_4.value, + }, + 'startAddr': { + '0': self.bundle.toICache.req_bits_pcMemRead_0_startAddr.value, + '1': self.bundle.toICache.req_bits_pcMemRead_1_startAddr.value, + '2': self.bundle.toICache.req_bits_pcMemRead_2_startAddr.value, + '3': self.bundle.toICache.req_bits_pcMemRead_3_startAddr.value, + '4': self.bundle.toICache.req_bits_pcMemRead_4_startAddr.value, + }, + 'nextlineStart': { + '0': self.bundle.toICache.req_bits_pcMemRead_0_nextlineStart.value, + '1': self.bundle.toICache.req_bits_pcMemRead_1_nextlineStart.value, + '2': self.bundle.toICache.req_bits_pcMemRead_2_nextlineStart.value, + '3': self.bundle.toICache.req_bits_pcMemRead_3_nextlineStart.value, + '4': self.bundle.toICache.req_bits_pcMemRead_4_nextlineStart.value, + } + } + return outputs + + @driver_method() + async def get_toprefetch_outputs(self): + + outputs = { + 'req_ready': self.bundle.toPrefetch.req_ready.value, + 'req_valid': self.bundle.toPrefetch.req_valid.value, + 'flushFromBpu': { + 's2': { + 'valid': self.bundle.toPrefetch.flushFromBpu_s2_valid.value, + 'flag': self.bundle.toPrefetch.flushFromBpu_s2_bits_flag.value, + 'value': self.bundle.toPrefetch.flushFromBpu_s2_bits_value.value, + }, + 's3': { + 'valid': self.bundle.toPrefetch.flushFromBpu_s3_valid.value, + 'flag': self.bundle.toPrefetch.flushFromBpu_s3_bits_flag.value, + 'value': self.bundle.toPrefetch.flushFromBpu_s3_bits_value.value, + } + } + } + return outputs + + @driver_method() + async def get_fromBpu_resp_ready(self): + + return self.bundle.fromBpu.resp_ready.value + + \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/env/ftq_bundle.py b/ut_frontend/ftq/ftq_top/env/ftq_bundle.py new file mode 100644 index 00000000..54a3c767 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/env/ftq_bundle.py @@ -0,0 +1,174 @@ +from toffee import * + +class IfuPdSlotBundle(Bundle): + brType = Signal() + isCall = Signal() + isRet = Signal() + valid = Signal() + +class RobCommitBundle(Bundle): + valid = Signal() + bits_commitType = Signal() + bits_ftqIdx_flag = Signal() + bits_ftqIdx_value = Signal() + bits_ftqOffset = Signal() + +class LastStageFtbEntryBundle(Bundle): + valid = Signal() + isJalr = Signal() + isCall = Signal() + isRet = Signal() + brSlots_0_valid = Signal() + brSlots_0_offset = Signal() + tailSlot_valid = Signal() + tailSlot_offset = Signal() + tailSlot_sharing = Signal() + + +class ToIfuBundle(Bundle): + req_ready = Signal() + req_valid = Signal() + + + +class ToICacheBundle(Bundle): + req_valid = Signal() + req_bits_readValid_0 = Signal() + req_bits_readValid_1 = Signal() + req_bits_readValid_2 = Signal() + req_bits_readValid_3 = Signal() + req_bits_readValid_4 = Signal() + req_bits_pcMemRead_0_startAddr = Signal() + req_bits_pcMemRead_1_startAddr = Signal() + req_bits_pcMemRead_2_startAddr = Signal() + req_bits_pcMemRead_3_startAddr = Signal() + req_bits_pcMemRead_4_startAddr = Signal() + req_bits_pcMemRead_0_nextlineStart = Signal() + req_bits_pcMemRead_1_nextlineStart = Signal() + req_bits_pcMemRead_2_nextlineStart = Signal() + req_bits_pcMemRead_3_nextlineStart = Signal() + req_bits_pcMemRead_4_nextlineStart = Signal() + +class ToPrefetchBundle(Bundle): + req_ready = Signal() + req_valid = Signal() + + flushFromBpu_s2_valid = Signal() + flushFromBpu_s2_bits_flag = Signal() + flushFromBpu_s2_bits_value = Signal() + flushFromBpu_s3_valid = Signal() + flushFromBpu_s3_bits_flag = Signal() + flushFromBpu_s3_bits_value = Signal() + + + +class FromBpuBundle(Bundle): + + resp_valid = Signal() + resp_ready = Signal() + resp_bits_s1_pc_3 = Signal() + resp_bits_s1_full_pred_3_fallThroughErr = Signal() + + resp_bits_s2_valid_3 = Signal() + resp_bits_s2_hasRedirect_3 = Signal() + resp_bits_s2_pc_3 = Signal() + resp_bits_s2_ftq_idx_value = Signal() + resp_bits_s2_ftq_idx_flag = Signal() + resp_bits_s2_full_pred_3_fallThroughErr = Signal() + resp_bits_s2_full_pred_3_hit = Signal() + + resp_bits_s3_valid_3 = Signal() + resp_bits_s3_hasRedirect_3 = Signal() + resp_bits_s3_pc_3 = Signal() + resp_bits_s3_ftq_idx_value = Signal() + resp_bits_s3_ftq_idx_flag = Signal() + resp_bits_s3_full_pred_3_fallThroughErr = Signal() + + + last_stage_ftb_entry = LastStageFtbEntryBundle.from_prefix("resp_bits_last_stage_ftb_entry_") + +class FromBackendBundle(Bundle): + redirect_valid = Signal() + redirect_bits_ftqIdx_value = Signal() + redirect_bits_ftqIdx_flag = Signal() + redirect_bits_ftqOffset = Signal() + redirect_bits_cfiUpdate_target = Signal() + redirect_bits_cfiUpdate_taken = Signal() + redirect_bits_cfiUpdate_isMisPred = Signal() + + redirect_bits_level = Signal() + redirect_bits_debugIsCtrl = Signal() + redirect_bits_debugIsMemVio = Signal() + + ftqIdxSelOH_bits = Signal() + ftqIdxAhead_0_valid = Signal() + ftqIdxAhead_0_bits_value = Signal() + + rob_commits_0 = RobCommitBundle.from_prefix("rob_commits_0_") + rob_commits_1 = RobCommitBundle.from_prefix("rob_commits_1_") + rob_commits_2 = RobCommitBundle.from_prefix("rob_commits_2_") + rob_commits_3 = RobCommitBundle.from_prefix("rob_commits_3_") + rob_commits_4 = RobCommitBundle.from_prefix("rob_commits_4_") + rob_commits_5 = RobCommitBundle.from_prefix("rob_commits_5_") + rob_commits_6 = RobCommitBundle.from_prefix("rob_commits_6_") + rob_commits_7 = RobCommitBundle.from_prefix("rob_commits_7_") + +class FromIfuBundle(Bundle): + pdWb_bits_target = Signal() + pdWb_bits_cfiOffset_valid = Signal() + pdWb_bits_misOffset_valid = Signal() + pdWb_bits_ftqIdx_value = Signal() + pdWb_bits_ftqIdx_flag = Signal() + pdWb_bits_misOffset_bits = Signal() + pdWb_valid = Signal() + + + + + + + + pdWb_bits_pd_0 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_0_") + pdWb_bits_pd_1 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_1_") + pdWb_bits_pd_2 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_2_") + pdWb_bits_pd_3 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_3_") + pdWb_bits_pd_4 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_4_") + pdWb_bits_pd_5 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_5_") + pdWb_bits_pd_6 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_6_") + pdWb_bits_pd_7 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_7_") + pdWb_bits_pd_8 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_8_") + pdWb_bits_pd_9 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_9_") + pdWb_bits_pd_10 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_10_") + pdWb_bits_pd_11 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_11_") + pdWb_bits_pd_12 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_12_") + pdWb_bits_pd_13 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_13_") + pdWb_bits_pd_14 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_14_") + pdWb_bits_pd_15 = IfuPdSlotBundle.from_prefix("pdWb_bits_pd_15_") + + pdWb_bits_pc_0 = Signal() + pdWb_bits_pc_1 = Signal() + pdWb_bits_pc_2 = Signal() + pdWb_bits_pc_3 = Signal() + pdWb_bits_pc_4 = Signal() + pdWb_bits_pc_5 = Signal() + pdWb_bits_pc_6 = Signal() + pdWb_bits_pc_7 = Signal() + pdWb_bits_pc_8 = Signal() + pdWb_bits_pc_9 = Signal() + pdWb_bits_pc_10 = Signal() + pdWb_bits_pc_11 = Signal() + pdWb_bits_pc_12 = Signal() + pdWb_bits_pc_13 = Signal() + pdWb_bits_pc_14 = Signal() + pdWb_bits_pc_15 = Signal() + +class FtqBundle(Bundle): + + + fromBackend = FromBackendBundle.from_prefix("fromBackend_") + fromIfu = FromIfuBundle.from_prefix("fromIfu_") + fromBpu = FromBpuBundle.from_prefix("fromBpu_") + toIfu = ToIfuBundle.from_prefix("toIfu_") + toICache = ToICacheBundle.from_prefix("toICache_") + toPrefetch = ToPrefetchBundle.from_prefix("toPrefetch_") + diff --git a/ut_frontend/ftq/ftq_top/ref/__init__.py b/ut_frontend/ftq/ftq_top/ref/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ut_frontend/ftq/ftq_top/ref/ftq_ref.py b/ut_frontend/ftq/ftq_top/ref/ftq_ref.py new file mode 100644 index 00000000..ded92ca2 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/ref/ftq_ref.py @@ -0,0 +1,74 @@ +from collections import namedtuple +import random + +# --- 数据结构定义 --- +BpuPacket = namedtuple('BpuPacket', ['pc', 'fallThruError']) +FtqPointer = namedtuple('FtqPointer', ['value', 'flag']) +FTQ_SIZE = 64 +# --- 最终版参考模型 --- + +def get_random_ptr_before_bpu(bpu_ptr: FtqPointer) -> FtqPointer: + steps_to_go_back = random.randint(1, FTQ_SIZE - 1) + new_value = bpu_ptr.value + new_flag = bpu_ptr.flag + for _ in range(steps_to_go_back): + if new_value == 0: + new_value = FTQ_SIZE - 1 + new_flag = not new_flag + else: + new_value -= 1 + + return FtqPointer(new_value, new_flag) + +class FtqAccurateRef: + """参考模型,所有指针计算和逻辑判断直接内联执行""" + + + def __init__(self, ftq_size=64): + self.FTQ_SIZE = ftq_size + self.bpu_ptr = FtqPointer(0, False) + self.ifu_ptr = FtqPointer(0, False) + self.mem = {} + + def enqueue(self, data_packet): + if FtqPointer( + (self.bpu_ptr.value + 1) % self.FTQ_SIZE, + self.bpu_ptr.flag if self.bpu_ptr.value != self.FTQ_SIZE - 1 else not self.bpu_ptr.flag + ) == self.ifu_ptr: + return False + + self.mem[self.bpu_ptr.value] = data_packet + self.bpu_ptr = FtqPointer( + (self.bpu_ptr.value + 1) % self.FTQ_SIZE, + self.bpu_ptr.flag if self.bpu_ptr.value != self.FTQ_SIZE - 1 else not self.bpu_ptr.flag + ) + return True + + def dequeue(self): + if self.bpu_ptr == self.ifu_ptr: + return None + + data = self.mem[self.ifu_ptr.value] + self.ifu_ptr = FtqPointer( + (self.ifu_ptr.value + 1) % self.FTQ_SIZE, + self.ifu_ptr.flag if self.ifu_ptr.value != self.FTQ_SIZE - 1 else not self.ifu_ptr.flag + ) + + + return data + + + + def redirect(self, redirect_idx, redirect_flag, redirect_packet): + self.mem[redirect_idx] = redirect_packet + + self.bpu_ptr = FtqPointer( + (redirect_idx + 1) % self.FTQ_SIZE, + bool(redirect_flag) if redirect_idx != self.FTQ_SIZE - 1 else not bool(redirect_flag) + ) + + if (((bool(redirect_flag) == self.ifu_ptr.flag) and (redirect_idx <= self.ifu_ptr.value)) or \ + ((bool(redirect_flag) != self.ifu_ptr.flag) and (redirect_idx > self.ifu_ptr.value))): + self.ifu_ptr = FtqPointer(redirect_idx, bool(redirect_flag)) + # 假设 FtqPointer 是一个已定义的类 + # 假设 self.mem = {} \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/test/__init__.py b/ut_frontend/ftq/ftq_top/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ut_frontend/ftq/ftq_top/test/ftq_cover_points.py b/ut_frontend/ftq/ftq_top/test/ftq_cover_points.py new file mode 100644 index 00000000..fd1d4055 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/ftq_cover_points.py @@ -0,0 +1,132 @@ +import toffee.funcov as fc +from toffee.funcov import CovGroup +from .test_configs import C_EMPTY, C_FLUSHED, C_COMMITTED + +def toifu_cov_points(g, dut, bundle): + g.add_cover_point(bundle.toICache.req_valid, {"toicache_req_valid is 0": fc.Eq(0)}, name="ToICache req_valid is 0", once=True) + g.add_cover_point(bundle.toICache.req_valid, {"toicache_req_valid is 1": fc.Eq(1)}, name="ToICache req_valid is 1", once=True) + for i in range(5): + signal = getattr(bundle.toICache, f"req_bits_readValid_{i}") + g.add_cover_point(signal, {"toicache_readValid[{i}] is 0": fc.Eq(0)}, name=f"ToICache readValid[{i}] is 0", once=True) + g.add_cover_point(signal, {"toicache_readValid[{i}] is 1": fc.Eq(1)}, name=f"ToICache readValid[{i}] is 1", once=True) + for i in range(5): + signal = getattr(bundle.toICache, f"req_bits_pcMemRead_{i}_startAddr") + g.add_cover_point(signal, {"toicache_startAddr[{i}] non-zero": fc.Ne(0)}, name=f"ToICache startAddr[{i}] non-zero", once=True) + for i in range(5): + signal = getattr(bundle.toICache, f"req_bits_pcMemRead_{i}_nextlineStart") + g.add_cover_point(signal, {"toicache_nextlineStart[{i}] non-zero": fc.Ne(0)}, name=f"ToICache nextlineStart[{i}] non-zero", once=True) + s3_signals = [ + (bundle.toPrefetch.flushFromBpu_s3_valid, "toprefetch_s3_valid", [fc.Eq(0), fc.Eq(1)]), + (bundle.toPrefetch.flushFromBpu_s3_bits_flag, "toprefetch_s3_flag", [fc.Eq(0), fc.Eq(1)]), + (bundle.toPrefetch.flushFromBpu_s3_bits_value, "toprefetch_s3_value", [fc.Eq(0), fc.Ne(0)]) + ] + for signal, prefix, bins_list in s3_signals: + for bin_cond in bins_list: + bin_suffix = "non-zero" if isinstance(bin_cond, fc.CovNe) else f"is {bin_cond.value}" + g.add_cover_point(signal, {f"{prefix} {bin_suffix}": bin_cond}, name=f"{prefix.capitalize()} {bin_suffix}", once=True) + +def wb_from_ifu_cov_points(g, dut, bundle): + g.add_cover_point(dut.has_false_hit.value, {"has_false_hit is 1": fc.Eq(1)}, name="Has false hit is 1", once=True) + +def redirect_from_backend_cov_points(g, dut, bundle): + prefix = "toBpu_redirect_bits_cfiUpdate_" + zero_bin = {"{signal} is 0": fc.Eq(0)} + one_bin = {"{signal} is 1": fc.Eq(1)} + signals = ["br_hit", "jr_hit", "shift", "addIntoHist"] + for signal_name in signals: + signal = getattr(dut, f"{prefix}{signal_name}") + g.add_cover_point(signal, zero_bin, name=f"ToBPU redirect {signal_name} is 0", once=True) + g.add_cover_point(signal, one_bin, name=f"ToBPU redirect {signal_name} is 1", once=True) + +def redirect_from_ifu_cov_points(g, dut, bundle): + prefix = "ifu_redirect_" + non_zero_bin = {"{name} non-zero": fc.Ne(0)} + eq_one_bin = {"{name} is 1": fc.Eq(1)} + range_bin = {"{name} low": fc.IsInRange(0, 63)} + prefixed_signals = [ + ("pc", non_zero_bin, "pc non-zero"), + ("pd_valid", eq_one_bin, "pd valid is 1"), + ("target", non_zero_bin, "target non-zero"), + ("taken", eq_one_bin, "taken is 1"), + ("ftq_idx", range_bin, "ftq idx low (0-31)"), + ("ftq_offset", non_zero_bin, "ftq offset non-zero") + ] + + for attr, bin_template, name_suffix in prefixed_signals: + signal = getattr(dut, f"{prefix}{attr}") + full_name = f"IFU redirect {name_suffix}" + g.add_cover_point(signal.value, bin_template, name=full_name, once=True) + g.add_cover_point(dut.ifu_flush.value, {"ifu_flush is 1": fc.Eq(1)}, name="IFU flush is 1", once=True) + +def tobackend_cov_points(g, dut, bundle): + prefix = "tobackend_" + eq_one_bin = {"{name} is 1": fc.Eq(1)} + range_bin = {"{name} high": fc.IsInRange(0, 63)} + non_zero_bin = {"{name} non-zero": fc.Ne(0)} + signals = [ + ("pc_mem_wen", eq_one_bin, "pc mem wen is 1"), + ("pc_mem_waddr", range_bin, "pc mem waddr high (32-63)"), + ("pc_mem_wdata_start", non_zero_bin, "pc mem wdata start non-zero"), + ("newest_entry_ptr", non_zero_bin, "newest entry ptr non-zero"), + ("newest_target", non_zero_bin, "newest target non-zero") + ] + for attr, bin_template, name_suffix in signals: + signal = getattr(dut, f"{prefix}{attr}") + full_name = f"ToBackend {name_suffix}" + g.add_cover_point(signal.value, bin_template, name=full_name, once=True) + +def flush_and_queue_cov_points(g, dut, bundle): + range_bin = {"{name}": fc.IsInRange(0, 63)} + ptr_signals = [ + (dut.bpu_ptr, "BPU ptr"), + (dut.ifu_ptr_write, "IFU ptr write"), + (dut.ifu_wb_ptr_write, "IFU wb ptr write"), + (dut.ifu_ptr_plus1_write, "IFU ptr plus1 write"), + (dut.ifu_ptr_plus2_write, "IFU ptr plus2 write"), + (dut.pf_ptr_write, "PF ptr write"), + (dut.pf_ptr_plus1_write, "PF ptr plus1 write high (32-63)") + ] + for signal, name_prefix in ptr_signals: + g.add_cover_point(signal.value, range_bin, name=name_prefix, once=True) + is_one_signals = [ + (dut.topdown_redirect_debugIsCtrl, "Topdown debugIsCtrl is 1"), + (dut.topdown_redirect_debugIsMemVio, "Topdown debugIsMemVio is 1"), + (dut.toifu_redirect_level, "ToIFU redirect level is 1") + ] + for signal, name in is_one_signals: + g.add_cover_point(signal.value, {"{name} is 1": fc.Eq(1)}, name=name, once=True) + g.add_cover_point(dut.toifu_redirect_ftqIdx_value.value, {"toifu_redirect_ftqIdx_value": fc.IsInRange(0, 63)}, name="ToIFU redirect ftqIdx value high (32-63)", once=True) + g.add_cover_point(dut.toifu_redirect_ftqOffset.value, {"toifu_redirect_ftqOffset non-zero": fc.Ne(0)}, name="ToIFU redirect ftqOffset non-zero", once=True) + +def wb_from_exu_cov_points(g, dut, bundle): + non_zero_bin = {"{name} non-zero": fc.Ne(0)} + eq_zero_bin = {"{name} is 0": fc.Eq(0)} + eq_one_bin = {"{name} is 1": fc.Eq(1)} + range_bin = {"{name} high": fc.IsInRange(0, 63)} + range_bin_small = {"{name} high": fc.IsInRange(0, 7)} + signals = [ + (dut.get_update_target(0), non_zero_bin, "update_target[0] non-zero"), + (dut.newest_entry_target, eq_zero_bin, "Newest entry target is 0"), + (dut.newest_entry_target, non_zero_bin, "Newest entry target non-zero"), + (dut.newest_entry_ptr_value, range_bin, "Newest entry ptr high (32-63)"), + (dut.newest_entry_target_modified, eq_zero_bin, "Newest entry target modified is 0"), + (dut.newest_entry_target_modified, eq_one_bin, "Newest entry target modified is 1"), + (dut.get_mispredict_vec(0, 0), eq_zero_bin, "Mispredict vec[0][0] is 0"), + (dut.get_mispredict_vec(0, 0), eq_one_bin, "Mispredict vec[0][0] is 1"), + (dut.get_cfi_index_valid(0), eq_one_bin, "Cfi index valid[0] is 1"), + (dut.get_cfi_index_bits(0), range_bin_small, "Cfi index bits[0] high (4-7)") + ] + for signal, bin_template, name_suffix in signals: + full_name = name_suffix + g.add_cover_point(signal, bin_template, name=full_name, once=True) + +def ftq_cover_points(dut, bundle): + g = CovGroup("FTQ redirect and management function") + toifu_cov_points(g, dut, bundle) + wb_from_ifu_cov_points(g, dut, bundle) + redirect_from_backend_cov_points(g, dut, bundle) + redirect_from_ifu_cov_points(g, dut, bundle) + tobackend_cov_points(g, dut, bundle) + wb_from_exu_cov_points(g, dut, bundle) + flush_and_queue_cov_points(g, dut, bundle) + return g diff --git a/ut_frontend/ftq/ftq_top/test/test_configs.py b/ut_frontend/ftq/ftq_top/test/test_configs.py new file mode 100644 index 00000000..e67c7625 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_configs.py @@ -0,0 +1,44 @@ + + + +test_scenarios = [ + "br_true_hit", "br_false_hit", + "jal_true_hit", "jal_false_hit", + "jalr_true_hit", "jalr_false_hit", + "call_true_hit", "call_false_hit", + "ret_true_hit", "ret_false_hit", + "shared_br_true_hit", "shared_br_false_hit", + "pd_mispred_hit", +] + +BACKEND_REDIRECT_LOGIC_GOALS = [ + 'VERIFY_BR_HIT', + 'VERIFY_JR_HIT', + 'HIT_SHIFT_1_ADDHIST_1', + 'MISS_SHIFT_1_ADDHIST_1' +] + +BACKEND_REDIRECT_PATHS = ['AHEAD_REDIRECT', 'NORMAL_REDIRECT'] + +BPU_REDIRECT_EVENT_TYPES = ['S1', 'S2_REDIRECT', 'S3_REDIRECT', 'IDLE'] +BPU_REDIRECT_EVENT_WEIGHTS = [0.6, 0.05, 0.05, 0.3] + + +FTQ_BACKEND_UPDATE_SCENARIOS = ['s1', 's2', 's3', 'ifu_redirect', 'backend_redirect'] + + +FTQ_REDIRECT_SCENARIOS = ["backend_redirect", "ifu_redirect"] + + +CFI_INDEX_UPDATE_STRATEGIES = ["cfiindex_bits_wen", "cfiindex_valid_wen"] + +FTQ_FLUSH_REDIRECT_TYPES = ["backend_only", "ifu_only", "both"] + + + +PREDICT_WIDTH = 16 +FTQ_SIZE = 64 +C_EMPTY = 0 +C_FLUSHED = 3 +C_COMMITTED = 2 +COMMIT_WIDTH = 8 \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top3.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top3.py new file mode 100644 index 00000000..b89029da --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top3.py @@ -0,0 +1,86 @@ +# ut_frontend/ftq/ftq_top/test/test_ftq_top3.py +import random +import toffee_test +import pytest +from collections import namedtuple +from ..ref.ftq_ref import FtqAccurateRef, BpuPacket, FtqPointer, get_random_ptr_before_bpu +from .top_test_fixture import ftq_env +from .test_configs import BPU_REDIRECT_EVENT_TYPES, BPU_REDIRECT_EVENT_WEIGHTS + +@toffee_test.testcase +async def test_example_integration(ftq_env): + dut = ftq_env.dut + ref = FtqAccurateRef() + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_rise() + for cycle in range(300): + event_type = random.choices(BPU_REDIRECT_EVENT_TYPES, + weights=BPU_REDIRECT_EVENT_WEIGHTS)[0] + s1_valid = s2_valid = s2_hasRedirect = s3_valid = s3_hasRedirect = False + if event_type == 'S1': + s1_valid = True + elif event_type == 'S2_REDIRECT': + s2_valid = s2_hasRedirect = True + elif event_type == 'S3_REDIRECT': + s3_valid = s3_hasRedirect = True + s1_packet = BpuPacket(pc=0x8000_0000 | (cycle << 4), fallThruError=(random.random() < 0.05)) + s2_redirect_ptr = get_random_ptr_before_bpu(ref.bpu_ptr) + s2_redirect_idx = s2_redirect_ptr.value + s2_redirect_flag = s2_redirect_ptr.flag + s2_packet = BpuPacket(pc=0x9000_0000 | (s2_redirect_idx << 4), fallThruError=(random.random() < 0.05)) + s3_redirect_ptr = get_random_ptr_before_bpu(ref.bpu_ptr) + s3_redirect_idx = s3_redirect_ptr.value + s3_redirect_flag = s3_redirect_ptr.flag + s3_packet = BpuPacket(pc=0xA000_0000 | (s3_redirect_idx << 4), fallThruError=(random.random() < 0.05)) + to_ifu_ready = random.choice([True, True, False]) + await ftq_env.ftq_agent.drive_toifu_ready(to_ifu_ready) + await ftq_env.ftq_agent.drive_s1_signals( + valid=s1_valid, + pc=s1_packet.pc, + fallThruError=s1_packet.fallThruError + ) + await ftq_env.ftq_agent.drive_s2_signals( + valid=s2_valid, + hasRedirect=s2_hasRedirect, + pc=s2_packet.pc, + redirect_idx=s2_redirect_ptr.value, + redirect_flag=s2_redirect_ptr.flag, + fallThruError=s2_packet.fallThruError + ) + await ftq_env.ftq_agent.drive_s3_signals( + valid=s3_valid, + hasRedirect=s3_hasRedirect, + pc=s3_packet.pc, + redirect_idx=s3_redirect_ptr.value, + redirect_flag=s3_redirect_ptr.flag, + fallThruError=s3_packet.fallThruError + ) + await ftq_env.ftq_agent.bundle.step(1) + s3_redirect_fire = s3_valid and s3_hasRedirect + s2_redirect_fire = s2_valid and s2_hasRedirect + s1_enqueue_fire = s1_valid and await ftq_env.ftq_agent.get_fromBpu_resp_ready() + toicache_outputs = await ftq_env.ftq_agent.get_toicache_outputs() + toprefetch_outputs = await ftq_env.ftq_agent.get_toprefetch_outputs() + if toicache_outputs['req_valid'] and to_ifu_ready : + expected_packet = ref.dequeue() + assert toicache_outputs['startAddr']['0'] == expected_packet.pc, f"PC mismatch! Expected {hex(expected_packet.pc)}, got {hex(actual_pc)}" + for i in range(5): + str_i = str(i) + assert toicache_outputs['readValid'][str_i] == 1, f"ICache readValid[{i}] should be 1, but got {read_valid}" + assert toicache_outputs['startAddr'][str_i] == expected_packet.pc, f"ICache startAddr[{i}] mismatch! Expected {hex(expected_packet.pc)}, got {hex(start_addr)}" + assert toicache_outputs['nextlineStart'][str_i] == expected_packet.pc + 64, f"ICache nextlineStart[{i}] mismatch! Expected {hex(expected_packet.pc + 64)}, got {hex(nextline_start)}" + if s3_valid and s3_hasRedirect: + assert toprefetch_outputs['flushFromBpu']['s3']['valid'] == 1, f"S3 redirect valid should be 1 when s3_redirect_fire=True" + assert toprefetch_outputs['flushFromBpu']['s3']['flag'] == s3_redirect_flag, f"S3 redirect flag mismatch! Expected {s3_redirect_flag}, got {dut_s3_flag}" + assert toprefetch_outputs['flushFromBpu']['s3']['value'] == s3_redirect_idx, f"S3 redirect value mismatch! Expected {s3_redirect_idx}, got {dut_s3_value}" + for condition, action, *args in [ + (s3_redirect_fire, 'redirect', s3_redirect_ptr.value, s3_redirect_ptr.flag, s3_packet), + (s2_redirect_fire, 'redirect', s2_redirect_ptr.value, s2_redirect_ptr.flag, s2_packet), + (s1_enqueue_fire, 'enqueue', s1_packet) + ]: + if condition: + if action == 'redirect': + ref.redirect(args[0], args[1], args[2]) + elif action == 'enqueue': + ref.enqueue(args[0]) + break diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top4.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top4.py new file mode 100644 index 00000000..ac3a08fb --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top4.py @@ -0,0 +1,85 @@ +import random +import toffee_test +from .top_test_fixture import ftq_env +from .test_configs import test_scenarios + +@toffee_test.testcase +async def test_example4_integration_with_agent(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_imme() + for i in range(300): + scenario = random.choice(test_scenarios) + test_idx = random.randint(0, 63) + pred_offset = random.randint(0, 7) + await ftq_env.ftq_agent.drive_s1_signals(valid=True) + await ftq_env.ftq_agent.drive_s2_signals( + valid=True, + full_pred_3_hit=True, + redirect_idx=test_idx + ) + await ftq_env.ftq_agent.bundle.step(3) + await ftq_env.ftq_agent.drive_s2_signals( + valid=False, + full_pred_3_hit=False, + redirect_idx=0 + ) + await ftq_env.ftq_agent.drive_s1_signals(valid=True) + await ftq_env.ftq_agent.drive_s3_signals(valid=True, redirect_idx=test_idx) + drive_configs = { + "br_true_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": True, "brSlots_0_offset": pred_offset, "tailSlot_valid": False, "tailSlot_offset": 0, "tailSlot_sharing": False}, + "br_false_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": True, "brSlots_0_offset": pred_offset, "tailSlot_valid": False, "tailSlot_offset": 0, "tailSlot_sharing": False}, + "shared_br_true_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": True}, + "shared_br_false_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": True}, + "jalr_true_hit": {"isJalr": True, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "jalr_false_hit": {"isJalr": True, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "call_true_hit": {"isJalr": False, "isCall": True, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "call_false_hit": {"isJalr": False, "isCall": True, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "ret_true_hit": {"isJalr": False, "isCall": False, "isRet": True, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "ret_false_hit": {"isJalr": False, "isCall": False, "isRet": True, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "jal_true_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False}, + "jal_false_hit": {"isJalr": False, "isCall": False, "isRet": False, "brSlots_0_valid": False, "brSlots_0_offset": 0, "tailSlot_valid": True, "tailSlot_offset": pred_offset, "tailSlot_sharing": False} + } + config = drive_configs.get(scenario) + config and await ftq_env.ftq_agent.drive_s3_last_stage(**config) + await ftq_env.ftq_agent.bundle.step(1) + await ftq_env.ftq_agent.drive_s1_signals(valid=False) + await ftq_env.ftq_agent.drive_s3_signals(valid=False, redirect_idx=0) + await ftq_env.ftq_agent.drive_s3_last_stage( + isJalr=False, isCall=False, isRet=False, + brSlots_0_valid=False, brSlots_0_offset=0, + tailSlot_valid=False, tailSlot_offset=0, tailSlot_sharing=False + ) + await ftq_env.ftq_agent.drive_ifu_inputs( + valid=True, + ftqIdx_value=test_idx, + misOffset_valid=(scenario == "pd_mispred_hit") + ) + await ftq_env.ftq_agent.set_ifu_pd( + slot=pred_offset, + brType=0, + isCall=False, + isRet=False, + valid=True + ) + scenario_configs = { + "br_true_hit": {"brType": 1, "isCall": False, "isRet": False, "valid": True}, + "shared_br_true_hit": {"brType": 1, "isCall": False, "isRet": False, "valid": True}, + "shared_br_false_hit": {"brType": 1, "isCall": False, "isRet": False, "valid": False}, # 添加这个 + "jal_true_hit": {"brType": 2, "isCall": False, "isRet": False, "valid": True}, + "jalr_true_hit": {"brType": 3, "isCall": False, "isRet": False, "valid": True}, + "call_true_hit": {"brType": 2, "isCall": True, "isRet": False, "valid": True}, + "ret_true_hit": {"brType": 2, "isCall": False, "isRet": True, "valid": True} + } + config = scenario_configs.get(scenario) + config and await ftq_env.ftq_agent.set_ifu_pd(pred_offset, **config) + await ftq_env.ftq_agent.bundle.step(1) + await ftq_env.ftq_agent.drive_ifu_inputs(valid=False, ftqIdx_value=0, misOffset_valid=False) + for s in range(8): + await ftq_env.ftq_agent.set_ifu_pd(s, valid=False) + expected_br_false_hit = 1 if scenario in ["br_false_hit", "shared_br_false_hit"] else 0 + expected_jal_false_hit = 1 if ("false_hit" in scenario and scenario.startswith(("jal", "jalr", "call", "ret"))) else 0 + expected_pd_mispred = 1 if scenario == "pd_mispred_hit" else 0 + expected_has_false_hit = 1 if (expected_br_false_hit or expected_jal_false_hit or expected_pd_mispred) else 0 + assert dut.has_false_hit.value == expected_has_false_hit, \ + f"[{i}] scenario={scenario} has_false_hit mismatch: expect={expected_has_false_hit}, actual={actual_has_false_hit}" \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top5.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top5.py new file mode 100644 index 00000000..3dce1ff6 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top5.py @@ -0,0 +1,100 @@ +import random +import toffee_test +from .top_test_fixture import ftq_env +from .test_configs import BACKEND_REDIRECT_LOGIC_GOALS, BACKEND_REDIRECT_PATHS + + +@toffee_test.testcase +async def test_example5_integration_with_agent(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.set_write_mode_as_imme() + await ftq_env.ftq_agent.reset5(ftq_env.dut) + num_experiments = 3000 + for i in range(num_experiments): + logic_goal = random.choice(BACKEND_REDIRECT_LOGIC_GOALS) + redirect_path = random.choice(BACKEND_REDIRECT_PATHS) # << 随机选择时序路径 + ftq_idx = random.randint(0, 63) + ftq_offset = random.randint(4, 15) + await ftq_env.ftq_agent.reset_inputs() + await ftq_env.ftq_agent.drive_s3_signals(valid=1, redirect_idx=ftq_idx) + ftb_configs = { + 'VERIFY_BR_HIT': { + 'brSlots_0_valid': 1, + 'brSlots_0_offset': ftq_offset + }, + 'VERIFY_JR_HIT': { + 'isJalr': 1, + 'tailSlot_valid': 1, + 'tailSlot_offset': ftq_offset + }, + 'HIT_SHIFT_1_ADDHIST_1': { + 'brSlots_0_valid': 1, + 'brSlots_0_offset': ftq_offset + }, + 'HIT_SHIFT_2_ADDHIST_1': { + 'brSlots_0_valid': 1, + 'brSlots_0_offset': ftq_offset - 1, + 'tailSlot_valid': 1, + 'tailSlot_offset': ftq_offset + 1, + 'tailSlot_sharing': 1 + } + } + config = ftb_configs.get(logic_goal, {}) + await ftq_env.ftq_agent.drive_s3_last_stage( + valid=1, + **config + ) + await ftq_env.ftq_agent.drive_ifu_inputs(valid=1, ftqIdx_value=ftq_idx) + await ftq_env.ftq_agent.set_ifu_pd( + slot=ftq_offset, + valid=1, + brType=1, + ) + hit_value = 0 if 'MISS_' in logic_goal else 1 + await ftq_env.ftq_agent.drive_s2_signals( + valid=1, + redirect_idx=ftq_idx, + full_pred_3_hit=hit_value + ) + await ftq_env.ftq_agent.bundle.step(2) + await ftq_env.ftq_agent.reset_inputs() + if redirect_path == 'AHEAD_REDIRECT': + await ftq_env.ftq_agent.drive_backend_inputs( + ftqIdxAhead_0_valid=1, + ftqIdxAhead_0_bits_value=ftq_idx + ) + await ftq_env.ftq_agent.bundle.step(1) + await ftq_env.ftq_agent.drive_backend_inputs( + valid=1, + ftqIdx_value=ftq_idx, + ftqOffset=ftq_offset, + cfiUpdate_taken=1, + ftqIdxSelOH_bits=1 + ) + dut.RefreshComb() + elif redirect_path == 'NORMAL_REDIRECT': + await ftq_env.ftq_agent.drive_backend_inputs( + valid=1, + ftqIdx_value=ftq_idx, + ftqOffset=ftq_offset, + cfiUpdate_taken=1 + ) + await ftq_env.ftq_agent.bundle.step(2) + verify_map = { + 'VERIFY_BR_HIT': lambda: + dut.toBpu_redirect_bits_cfiUpdate_br_hit.value == 1, + 'VERIFY_JR_HIT': lambda: + dut.toBpu_redirect_bits_cfiUpdate_jr_hit.value == 1, + 'HIT_SHIFT_1_ADDHIST_1': lambda: + dut.toBpu_redirect_bits_cfiUpdate_shift.value == 1 and dut.toBpu_redirect_bits_cfiUpdate_addIntoHist.value == 1, + 'HIT_SHIFT_2_ADDHIST_1': lambda: + dut.toBpu_redirect_bits_cfiUpdate_shift.value == 2 and dut.toBpu_redirect_bits_cfiUpdate_addIntoHist.value == 1, + 'MISS_SHIFT_1_ADDHIST_1': lambda: + dut.toBpu_redirect_bits_cfiUpdate_shift.value == 1 and dut.toBpu_redirect_bits_cfiUpdate_addIntoHist.value == 1, + } + verify_func = verify_map.get(logic_goal) + if verify_func: + assert verify_func(), f"{logic_goal} verification failed" + else: + raise ValueError(f"Unknown logic goal: {logic_goal}") + await ftq_env.ftq_agent.bundle.step(3) diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top6.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top6.py new file mode 100644 index 00000000..06a47e3e --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top6.py @@ -0,0 +1,53 @@ +import random +import toffee_test +from .top_test_fixture import ftq_env +from .test_configs import ( + PREDICT_WIDTH +) + + +@toffee_test.testcase +async def test_example6_integration_with_agent(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_imme() + for i in range(300): + rand_pdwb_valid = random.choice([0, 1]) + rand_misoffset_valid = random.choice([0, 1]) + rand_backend_redirect_valid = random.choice([0, 1]) + rand_ftq_idx = random.randint(0, 63) + rand_misoffset_bits = random.randint(0, PREDICT_WIDTH - 1) + rand_pc_val = random.randint(0, (1 << 39) - 1) + rand_target = random.randint(0, (1 << 39) - 1) + rand_cfiOffset_valid = random.choice([0, 1]) + expected_fromIfuRedirect_valid = 1 if (rand_pdwb_valid and rand_misoffset_valid and not rand_backend_redirect_valid) else 0 + expected_pc = rand_pc_val + expected_pd_valid = 1 + expected_pd_isRet = 1 + expected_ifuFlush = expected_fromIfuRedirect_valid + await ftq_env.ftq_agent.drive_backend_inputs(valid=bool(rand_backend_redirect_valid)) + # IFU 头部 + 数据域(按需赋值一次性设置) + await ftq_env.ftq_agent.drive_ifu_inputs( + valid=bool(rand_pdwb_valid), + ftqIdx_value=rand_ftq_idx, + misOffset_bits=rand_misoffset_bits, + target=rand_target, + misOffset_valid=bool(rand_misoffset_valid), + cfiOffset_valid=bool(rand_cfiOffset_valid), + ) + await ftq_env.ftq_agent.set_ifu_pc(slot=rand_misoffset_bits, pc=rand_pc_val) + await ftq_env.ftq_agent.set_ifu_pd(slot=rand_misoffset_bits, valid=True, isRet=True) + await ftq_env.ftq_agent.bundle.step(1) + assert dut.ifu_redirect_valid.value == expected_fromIfuRedirect_valid, \ + f"[{i}] fromIfuRedirect.valid mismatch, expect={expected_fromIfuRedirect_valid}, actual={actual_toBpu_valid}" + if expected_fromIfuRedirect_valid: + assert dut.ifu_redirect_pc.value == expected_pc, f"[{i}] pc mismatch exp={hex(expected_pc)} act={hex(actual_pc)}" + assert dut.ifu_redirect_pd_valid.value == expected_pd_valid, f"[{i}] pd.valid mismatch exp={expected_pd_valid} act={actual_pd_valid}" + assert dut.ifu_redirect_pd_isRet.value == expected_pd_isRet, f"[{i}] pd.isRet mismatch exp={expected_pd_isRet} act={actual_pd_isRet}" + assert dut.ifu_redirect_target.value == rand_target, f"[{i}] target mismatch exp={hex(rand_target)} act={hex(actual_target)}" + assert dut.ifu_redirect_taken.value == rand_cfiOffset_valid, f"[{i}] taken mismatch exp={rand_cfiOffset_valid} act={actual_taken}" + assert dut.ifu_flush.value == expected_ifuFlush, f"[{i}] ifuFlush mismatch exp={expected_ifuFlush} act={actual_ifuFlush}" + assert dut.ifu_redirect_ftq_idx.value == rand_ftq_idx, f"[{i}] ftqIdx mismatch exp={rand_ftq_idx} act={actual_ftq_idx}" + assert dut.ifu_redirect_ftq_offset.value== rand_misoffset_bits, f"[{i}] ftqOffset mismatch exp={rand_misoffset_bits} act={actual_ftq_offset}" + await ftq_env.ftq_agent.reset_inputs() + await ftq_env.ftq_agent.bundle.step(3) \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top7.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top7.py new file mode 100644 index 00000000..87cc3183 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top7.py @@ -0,0 +1,66 @@ +import random +import toffee_test +from .top_test_fixture import ftq_env +from .test_configs import FTQ_BACKEND_UPDATE_SCENARIOS + +@toffee_test.testcase +async def test_example7_integration_with_agent(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_imme() + bpu_value = 0 + bpu_flag = 0 + for test_iter in range(3000): + selected = random.choice(FTQ_BACKEND_UPDATE_SCENARIOS) + random_pc = random.randint(0, 0xFFFFFFFF) + random_target = random.randint(0, 0xFFFFFFFF) + random_ftq_idx_value = random.randint(0, 63) + random_ftq_idx_flag = random.randint(0, 1) + random_mis_offset = random.randint(0, 7) + random_cfi_offset = random.randint(0, 7) + selected_configs = { + "s1": {"method": "drive_s1_signals", "params": {"valid": True, "pc": random_pc}, "check_ready": True}, + "s2": {"method": "drive_s2_signals", "params": {"pc": random_pc, "valid": True, "hasRedirect": True, "redirect_idx": random_ftq_idx_value, "redirect_flag": random_ftq_idx_flag}, "check_ready": False}, + "s3": {"method": "drive_s3_signals", "params": {"pc": random_pc, "valid": True, "hasRedirect": True, "redirect_idx": random_ftq_idx_value, "redirect_flag": random_ftq_idx_flag}, "check_ready": False}, + "ifu_redirect": {"method": "drive_ifu_inputs", "params": {"valid": True, "misOffset_valid": True, "target": random_target, "ftqIdx_value": random_ftq_idx_value, "ftqIdx_flag": random_ftq_idx_flag}, "check_ready": False}, + "backend_redirect": {"method": "drive_backend_inputs", "params": {"valid": True, "cfiUpdate_target": random_target, "ftqIdx_value": random_ftq_idx_value, "ftqIdx_flag": random_ftq_idx_flag}, "check_ready": False} + } + config = selected_configs.get(selected) + if config: + if config["check_ready"] and dut.io_fromBpu_resp_ready.value != 1: + continue + await getattr(ftq_env.ftq_agent, config["method"])(**config["params"]) + await ftq_env.ftq_agent.bundle.step(1) + await ftq_env.ftq_agent.drive_s1_signals(valid=False) + await ftq_env.ftq_agent.bundle.step(1) + if selected == 's1': + assert dut.tobackend_pc_mem_wen.value == 1 + assert dut.tobackend_pc_mem_waddr.value == bpu_value + assert dut.tobackend_pc_mem_wdata_start.value == random_pc + elif selected in ['s2', 's3']: + assert dut.tobackend_pc_mem_wen.value == 1 + assert dut.tobackend_pc_mem_waddr.value == random_ftq_idx_value + assert dut.tobackend_pc_mem_wdata_start.value == random_pc + if selected in ['s2', 's3', 'ifu_redirect', 'backend_redirect']: + await ftq_env.ftq_agent.bundle.step(2) + else: + await ftq_env.ftq_agent.bundle.step(1) + config = { + 's1': (bpu_value, random_pc + 32, bpu_value + 1), + 's2': (random_ftq_idx_value, random_pc + 32, random_ftq_idx_value + 1), + 's3': (random_ftq_idx_value, random_pc + 32, random_ftq_idx_value + 1), + 'ifu_redirect': (random_ftq_idx_value, random_target, random_ftq_idx_value + 1), + 'backend_redirect': (random_ftq_idx_value, random_target, random_ftq_idx_value + 1) + } + entry_ptr, target, new_bpu_value = config[selected] + assert dut.tobackend_newest_entry_en.value == 1 + assert dut.tobackend_newest_entry_ptr.value == entry_ptr + assert dut.tobackend_newest_target.value == target + bpu_value = new_bpu_value + if bpu_value == 64: + bpu_flag = 1 - bpu_flag + bpu_value = 0 + await ftq_env.ftq_agent.reset_inputs() + await ftq_env.ftq_agent.bundle.step(1) + + \ No newline at end of file diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top8.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top8.py new file mode 100644 index 00000000..3aa3999f --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top8.py @@ -0,0 +1,48 @@ +import random +import toffee_test +import toffee +from .top_test_fixture import ftq_env +from .test_configs import FTQ_REDIRECT_SCENARIOS, CFI_INDEX_UPDATE_STRATEGIES + +@toffee_test.testcase +async def test_integration8(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_imme() + for cycle in range(300): + await ftq_env.ftq_agent.reset_inputs() + scenario = random.choice(FTQ_REDIRECT_SCENARIOS) + ftqIdx_value = random.randint(0, 63) + target = random.randint(0, 2**4 - 1) + isMisPred = random.randint(0, 1) + r_idx = ftqIdx_value + hist_bits = dut.get_cfi_index_bits(r_idx).value + hist_valid = dut.get_cfi_index_valid(r_idx).value + if hist_bits == 0: + strategy = "cfiindex_valid_wen" + else: + strategy = random.choice(CFI_INDEX_UPDATE_STRATEGIES) + valid = 1 + taken = 1 + offset = 0 + offset_strategies = { + "cfiindex_bits_wen": lambda: random.randint(0, hist_bits - 1), + "cfiindex_valid_wen": lambda: hist_bits + } + offset = offset_strategies[strategy]() + if scenario == "backend_redirect": + await ftq_env.ftq_agent.drive_backend_inputs(valid, ftqIdx_value, offset, target, taken, isMisPred) + elif scenario == "ifu_redirect": + await ftq_env.ftq_agent.drive_ifu_inputs(valid, ftqIdx_value, offset, target, 1, taken) # misOffset_valid 固定为 1, cfiOffset_valid = taken + await ftq_env.ftq_agent.bundle.step(3) + assert dut.get_update_target(r_idx).value == target, f"update_target[{r_idx}] mismatch: expected {target}, got {update_target}" + assert dut.newest_entry_target.value == target, f"newest_entry_target mismatch: expected {target}, got {newest_target}" + assert dut.newest_entry_ptr_value.value == ftqIdx_value, f"newest_entry_ptr mismatch: expected {ftqIdx_value}, got {newest_ptr}" + assert dut.newest_entry_target_modified.value == 1, f"newest_entry_target_modified not true: got {target_modified}" + if scenario == "backend_redirect": + assert dut.get_mispredict_vec(r_idx, offset).value == isMisPred, \ + f"mispredict_vec[{r_idx}][{offset}] mismatch: expected {isMisPred}, got {dut.get_mispredict_vec(r_idx, offset).value}" + assert dut.get_cfi_index_valid(r_idx).value == 1, f"cfiIndex valid mismatch for {strategy}: expected 1, got {new_valid}" + if strategy == "cfiindex_bits_wen": + assert dut.get_cfi_index_bits(r_idx).value == offset, f"cfiIndex bits mismatch for {strategy}: expected {offset}, got {new_bits}" + diff --git a/ut_frontend/ftq/ftq_top/test/test_ftq_top9.py b/ut_frontend/ftq/ftq_top/test/test_ftq_top9.py new file mode 100644 index 00000000..d1316443 --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/test_ftq_top9.py @@ -0,0 +1,114 @@ +import random +import toffee_test +from .top_test_fixture import ftq_env +from .test_configs import FTQ_FLUSH_REDIRECT_TYPES +from .test_configs import ( + FTQ_FLUSH_REDIRECT_TYPES, + PREDICT_WIDTH, FTQ_SIZE, C_EMPTY, C_FLUSHED, C_COMMITTED, COMMIT_WIDTH +) + +@toffee_test.testcase +async def test_example9_integration_with_agent(ftq_env): + dut = ftq_env.dut + await ftq_env.ftq_agent.reset5(ftq_env.dut) + await ftq_env.ftq_agent.set_write_mode_as_imme() + for cycle in range(300): + await ftq_env.ftq_agent.drive_backend_inputs( + valid=False, ftqIdx_value=0, ftqOffset=0, + level=0, debugIsCtrl=False, debugIsMemVio=False + ) + await ftq_env.ftq_agent.drive_ifu_inputs( + valid=False, misOffset_valid=False, + ftqIdx_value=0, misOffset_bits=0 + ) + for i in range(COMMIT_WIDTH): + await ftq_env.ftq_agent.set_rob_commit( + i, valid=False, commitType=0, ftqIdx_flag=False, ftqIdx_value=0, ftqOffset=0 + ) + redirect_type = random.choice(FTQ_FLUSH_REDIRECT_TYPES) + idx = random.randint(0, FTQ_SIZE - 1) + offset = random.randint(0, PREDICT_WIDTH - 1) + flush_itself = random.randint(0, 1) + commit_valid = 1 + commit_type = random.randint(0, 7) + commit_ftq_idx = random.randint(0, 63) + commit_offset = random.randint(0, 15) + commit_idx = random.randint(0, COMMIT_WIDTH - 1) + random_i = random.randint(0, PREDICT_WIDTH - 1) + expected_next = (idx + 1) % 64 + expected_idx_plus2 = (idx + 2) % 64 + expected_idx_plus3 = (idx + 3) % 64 + expected_debugIsCtrl = random.randint(0, 1) + expected_debugIsMemVio = random.randint(0, 1) + backend_poked = False + ifu_poked = False + if redirect_type in ("backend_only", "both"): + backend_poked = True + await ftq_env.ftq_agent.drive_backend_inputs( + valid=True, + ftqIdx_value=idx, + ftqOffset=offset, + level=flush_itself, + debugIsCtrl=bool(expected_debugIsCtrl), + debugIsMemVio=bool(expected_debugIsMemVio), + ) + if redirect_type in ("ifu_only", "both"): + ifu_poked = True + await ftq_env.ftq_agent.drive_ifu_inputs( + valid=True, + misOffset_valid=True, + ftqIdx_value=idx, + misOffset_bits=offset + ) + await ftq_env.ftq_agent.bundle.step(5) + assert dut.icache_flush.value == (1 if (backend_poked or ifu_poked) else 0) + assert dut.bpu_ptr.value == expected_next + assert dut.ifu_ptr_write.value == expected_next + assert dut.ifu_wb_ptr_write.value == expected_next + assert dut.ifu_ptr_plus1_write.value == expected_idx_plus2 + assert dut.ifu_ptr_plus2_write.value == expected_idx_plus3 + assert dut.pf_ptr_write.value == expected_next + assert dut.pf_ptr_plus1_write.value == expected_idx_plus2 + if redirect_type in ("backend_only", "both"): + assert dut.topdown_redirect_valid.value == 1 + assert dut.topdown_redirect_debugIsCtrl.value == expected_debugIsCtrl + assert dut.topdown_redirect_debugIsMemVio.value == expected_debugIsMemVio + after_state = dut.get_commit_state_queue_reg(idx, random_i).value + if random_i > offset: + assert after_state == C_EMPTY + elif random_i == offset and flush_itself: + assert after_state == C_FLUSHED + assert dut.toifu_redirect_valid.value == 1 + assert dut.toifu_redirect_ftqIdx_value.value == idx + assert dut.toifu_redirect_ftqOffset.value == offset + assert dut.toifu_redirect_level.value == flush_itself + await ftq_env.ftq_agent.set_rob_commit( + commit_idx, + valid=commit_valid, + commitType=commit_type, + ftqIdx_flag=False, + ftqIdx_value=commit_ftq_idx, + ftqOffset=commit_offset + ) + await ftq_env.ftq_agent.bundle.step(5) + def get_target_coords(c_type, current_ftq_idx, current_offset): + if c_type <= 3: + return current_ftq_idx, current_offset + elif c_type == 4: + return current_ftq_idx, (current_offset + 1) % PREDICT_WIDTH + elif c_type == 5: + return current_ftq_idx, (current_offset + 2) % PREDICT_WIDTH + elif c_type == 6: + return (current_ftq_idx + 1) % FTQ_SIZE, 0 + elif c_type == 7: + return (current_ftq_idx + 1) % FTQ_SIZE, 1 + else: + raise ValueError(f"Unknown commit_type: {c_type}") + #expected_state = 2 + target_ftq_idx, target_offset = get_target_coords(commit_type, commit_ftq_idx, commit_offset) + reg_state_signal = dut.get_commit_state_queue_reg(target_ftq_idx, target_offset).value + assert reg_state_signal == C_COMMITTED, \ + f"commitStateQueueReg[{target_ftq_idx}][{target_offset}] mismatch: " \ + f"expected {C_COMMITTED}, got {reg_state_signal} (commit_type={commit_type})" + + diff --git a/ut_frontend/ftq/ftq_top/test/top_test_fixture.py b/ut_frontend/ftq/ftq_top/test/top_test_fixture.py new file mode 100644 index 00000000..8fe174cf --- /dev/null +++ b/ut_frontend/ftq/ftq_top/test/top_test_fixture.py @@ -0,0 +1,84 @@ +import random +import toffee_test +from ..env import FtqBundle +from ..env import FtqEnv +import toffee + +from dut.FtqTop import DUTFtqTop +import toffee.funcov as fc +from toffee.funcov import CovGroup +from .ftq_cover_points import ftq_cover_points + +class NewDUTFtqTop(DUTFtqTop): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.newest_entry_target = self.GetInternalSignal("FtqTop_top.Ftq.newest_entry_target") + self.newest_entry_ptr_value = self.GetInternalSignal("FtqTop_top.Ftq.newest_entry_ptr_value") + self.newest_entry_target_modified = self.GetInternalSignal("FtqTop_top.Ftq.newest_entry_target_modified") + self.has_false_hit = self.GetInternalSignal("FtqTop_top.Ftq.has_false_hit") + self.ifu_redirect_valid = self.GetInternalSignal("FtqTop_top.Ftq.fromIfuRedirect_valid_probe") + self.ifu_redirect_pc = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_cfiUpdate_pc") + self.ifu_redirect_pd_valid = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_cfiUpdate_pd_valid") + self.ifu_redirect_pd_isRet = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_cfiUpdate_pd_isRet") + self.ifu_redirect_target = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_cfiUpdate_target") + self.ifu_redirect_taken = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_cfiUpdate_taken") + self.ifu_flush = self.GetInternalSignal("FtqTop_top.Ftq.ifuFlush") + self.ifu_redirect_ftq_idx = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_ftqIdx_value") + self.ifu_redirect_ftq_offset = self.GetInternalSignal("FtqTop_top.Ftq.ifuRedirectReg_next_bits_r_ftqOffset") + self.tobackend_newest_entry_en = self.GetInternalSignal("FtqTop_top.io_toBackend_newest_entry_en") + self.tobackend_newest_entry_ptr = self.GetInternalSignal("FtqTop_top.io_toBackend_newest_entry_ptr_value") + self.tobackend_newest_target = self.GetInternalSignal("FtqTop_top.io_toBackend_newest_entry_target") + self.tobackend_pc_mem_wen = self.GetInternalSignal("FtqTop_top.io_toBackend_pc_mem_wen") + self.tobackend_pc_mem_waddr = self.GetInternalSignal("FtqTop_top.io_toBackend_pc_mem_waddr") + self.tobackend_pc_mem_wdata_start = self.GetInternalSignal("FtqTop_top.io_toBackend_pc_mem_wdata_startAddr") + self.icache_flush = self.GetInternalSignal("FtqTop_top.io_icacheFlush") + self.toBpu_redirect_bits_cfiUpdate_br_hit = self.GetInternalSignal("FtqTop_top.io_toBpu_redirect_bits_cfiUpdate_br_hit") + self.toBpu_redirect_bits_cfiUpdate_jr_hit = self.GetInternalSignal("FtqTop_top.io_toBpu_redirect_bits_cfiUpdate_jr_hit") + self.toBpu_redirect_bits_cfiUpdate_shift = self.GetInternalSignal("FtqTop_top.io_toBpu_redirect_bits_cfiUpdate_shift") + self.toBpu_redirect_bits_cfiUpdate_addIntoHist = self.GetInternalSignal("FtqTop_top.io_toBpu_redirect_bits_cfiUpdate_addIntoHist") + self.bpu_ptr = self.GetInternalSignal("FtqTop_top.Ftq.bpuPtr_value") + self.ifu_ptr_write = self.GetInternalSignal("FtqTop_top.Ftq.ifuPtr_write_value") + self.ifu_wb_ptr_write = self.GetInternalSignal("FtqTop_top.Ftq.ifuWbPtr_value") + self.ifu_ptr_plus1_write = self.GetInternalSignal("FtqTop_top.Ftq.ifuPtrPlus1_value") + self.ifu_ptr_plus2_write = self.GetInternalSignal("FtqTop_top.Ftq.ifuPtrPlus2_value") + self.pf_ptr_write = self.GetInternalSignal("FtqTop_top.Ftq.pfPtr_value") + self.pf_ptr_plus1_write = self.GetInternalSignal("FtqTop_top.Ftq.pfPtrPlus1_value") + self.topdown_redirect_valid = self.GetInternalSignal("FtqTop_top.io_toIfu_topdown_redirect_valid") + self.topdown_redirect_debugIsCtrl = self.GetInternalSignal("FtqTop_top.io_toIfu_topdown_redirect_bits_debugIsCtrl") + self.topdown_redirect_debugIsMemVio = self.GetInternalSignal("FtqTop_top.io_toIfu_topdown_redirect_bits_debugIsMemVio") + self.toifu_redirect_valid = self.GetInternalSignal("FtqTop_top.io_toIfu_redirect_valid") + self.toifu_redirect_ftqIdx_value = self.GetInternalSignal("FtqTop_top.io_toIfu_redirect_bits_ftqIdx_value") + self.toifu_redirect_ftqOffset = self.GetInternalSignal("FtqTop_top.io_toIfu_redirect_bits_ftqOffset") + self.toifu_redirect_level = self.GetInternalSignal("FtqTop_top.io_toIfu_redirect_bits_level") + def get_update_target(idx): + return self.GetInternalSignal(f"FtqTop_top.Ftq.update_target_{idx}") + + def get_cfi_index_bits(idx): + return self.GetInternalSignal(f"FtqTop_top.Ftq.cfiIndex_vec_{idx}_bits") + + def get_cfi_index_valid(idx): + return self.GetInternalSignal(f"FtqTop_top.Ftq.cfiIndex_vec_{idx}_valid") + + def get_mispredict_vec(idx, offset): + return self.GetInternalSignal(f"FtqTop_top.Ftq.mispredict_vec_{idx}_{offset}") + + def get_commit_state_queue_reg(ftq_idx, offset): + return self.GetInternalSignal(f"FtqTop_top.Ftq.commitStateQueueReg_{ftq_idx}_{offset}") + + self.get_update_target = get_update_target + self.get_cfi_index_bits = get_cfi_index_bits + self.get_cfi_index_valid = get_cfi_index_valid + self.get_mispredict_vec = get_mispredict_vec + self.get_commit_state_queue_reg = get_commit_state_queue_reg + + +@toffee_test.fixture +async def ftq_env(toffee_request: toffee_test.ToffeeRequest): + toffee.setup_logging(toffee.WARNING) + dut = toffee_request.create_dut(NewDUTFtqTop,"clock") + toffee.start_clock(dut) + ftq_bundle = FtqBundle.from_prefix('io_') + ftq_bundle.bind(dut) + toffee_request.add_cov_groups(ftq_cover_points(dut, ftq_bundle)) + yield FtqEnv(ftq_bundle, dut=dut) + \ No newline at end of file