Skip to content

Commit 826dd7e

Browse files
test(FTQ): verify BPU response to FTQ and FTQ commit to BPU (#194)
* feat: utils handling ftqPtr * feat: ftq_pc_mem * feat: driver method for BPU full resp * feat: monitor method check bpu resp valid req * feat: connect dut to FTQ SUB QUEUES and STATUS QUEUES * feat: test bpu resp enqueue for ftq_pc_mem * feat: test bpu resp enqueue for ftq_redirect_mem * feat: draft pr about FTQ test * fix: now the test can completely run * feat: create dynamic FTQ Bundle to fit different testcase * refactor: ajust the iteration time to big numbers to simulate the real * refactor: modify the name of testcase_1 to test_ftq_top2 to fit the verification doc
1 parent 797e6e9 commit 826dd7e

16 files changed

Lines changed: 3288 additions & 12 deletions

ut_frontend/ftq/ftq_top/env/ftq_agent.py

Lines changed: 225 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import random
12
from toffee import *
2-
3+
FTQSIZE = 64
34

45
class FtqAgent(Agent):
56
def __init__(self, ftq_bundle):
@@ -542,4 +543,226 @@ async def get_fromBpu_resp_ready(self):
542543

543544
return self.bundle.fromBpu.resp_ready.value
544545

545-
546+
@driver_method()
547+
async def drive_s1_full_signals(self, dict):
548+
self.bundle.fromBpuNew.valid.value = dict['valid']
549+
self.bundle.fromBpuNew.s1.pc_3.value = dict['pc_3']
550+
self.bundle.fromBpuNew.s1.full_pred_3_fallThroughErr.value = dict['full_pred_3_fallThroughErr']
551+
self.bundle.fromBpuNew.s1.full_pred_3_br_taken_mask_0.value = dict['full_pred_3_br_taken_mask_0']
552+
self.bundle.fromBpuNew.s1.full_pred_3_br_taken_mask_1.value = dict['full_pred_3_br_taken_mask_1']
553+
self.bundle.fromBpuNew.s1.full_pred_3_slot_valids_0.value = dict['full_pred_3_slot_valids_0']
554+
self.bundle.fromBpuNew.s1.full_pred_3_slot_valids_1.value = dict['full_pred_3_slot_valids_1']
555+
self.bundle.fromBpuNew.s1.full_pred_3_targets_0.value = dict['full_pred_3_targets_0']
556+
self.bundle.fromBpuNew.s1.full_pred_3_targets_1.value = dict['full_pred_3_targets_1']
557+
self.bundle.fromBpuNew.s1.full_pred_3_offsets_0.value = dict['full_pred_3_offsets_0']
558+
self.bundle.fromBpuNew.s1.full_pred_3_offsets_1.value = dict['full_pred_3_offsets_1']
559+
self.bundle.fromBpuNew.s1.full_pred_3_fallThroughAddr.value = dict['full_pred_3_fallThroughAddr']
560+
self.bundle.fromBpuNew.s1.full_pred_3_is_br_sharing.value = dict['full_pred_3_is_br_sharing']
561+
self.bundle.fromBpuNew.s1.full_pred_3_hit.value = dict['full_pred_3_hit']
562+
return self.bundle.as_dict()
563+
564+
@driver_method()
565+
async def drive_s2_full_signals(self, dict):
566+
self.bundle.fromBpuNew.s2.pc_3.value = dict['pc_3']
567+
self.bundle.fromBpuNew.s2.full_pred_3_fallThroughErr.value = dict['full_pred_3_fallThroughErr']
568+
self.bundle.fromBpuNew.s2.full_pred_3_br_taken_mask_0.value = dict['full_pred_3_br_taken_mask_0']
569+
self.bundle.fromBpuNew.s2.full_pred_3_br_taken_mask_1.value = dict['full_pred_3_br_taken_mask_1']
570+
self.bundle.fromBpuNew.s2.full_pred_3_slot_valids_0.value = dict['full_pred_3_slot_valids_0']
571+
self.bundle.fromBpuNew.s2.full_pred_3_slot_valids_1.value = dict['full_pred_3_slot_valids_1']
572+
self.bundle.fromBpuNew.s2.full_pred_3_targets_0.value = dict['full_pred_3_targets_0']
573+
self.bundle.fromBpuNew.s2.full_pred_3_targets_1.value = dict['full_pred_3_targets_1']
574+
self.bundle.fromBpuNew.s2.full_pred_3_offsets_0.value = dict['full_pred_3_offsets_0']
575+
self.bundle.fromBpuNew.s2.full_pred_3_offsets_1.value = dict['full_pred_3_offsets_1']
576+
self.bundle.fromBpuNew.s2.full_pred_3_fallThroughAddr.value = dict['full_pred_3_fallThroughAddr']
577+
self.bundle.fromBpuNew.s2.full_pred_3_is_br_sharing.value = dict['full_pred_3_is_br_sharing']
578+
self.bundle.fromBpuNew.s2.full_pred_3_hit.value = dict['full_pred_3_hit']
579+
self.bundle.fromBpuNew.s2.valid_3.value = dict['valid_3']
580+
self.bundle.fromBpuNew.s2.hasRedirect_3.value = dict['hasRedirect_3']
581+
self.bundle.fromBpuNew.s2.ftq_idx_flag.value = dict['ftq_idx_flag']
582+
self.bundle.fromBpuNew.s2.ftq_idx_value.value = dict['ftq_idx_value']
583+
return self.bundle.as_dict()
584+
585+
@driver_method()
586+
async def drive_s3_full_signals(self, dict):
587+
self.bundle.fromBpuNew.s3.pc_3.value = dict['pc_3']
588+
self.bundle.fromBpuNew.s3.full_pred_3_fallThroughErr.value = dict['full_pred_3_fallThroughErr']
589+
self.bundle.fromBpuNew.s3.full_pred_3_br_taken_mask_0.value = dict['full_pred_3_br_taken_mask_0']
590+
self.bundle.fromBpuNew.s3.full_pred_3_br_taken_mask_1.value = dict['full_pred_3_br_taken_mask_1']
591+
self.bundle.fromBpuNew.s3.full_pred_3_slot_valids_0.value = dict['full_pred_3_slot_valids_0']
592+
self.bundle.fromBpuNew.s3.full_pred_3_slot_valids_1.value = dict['full_pred_3_slot_valids_1']
593+
self.bundle.fromBpuNew.s3.full_pred_3_targets_0.value = dict['full_pred_3_targets_0']
594+
self.bundle.fromBpuNew.s3.full_pred_3_targets_1.value = dict['full_pred_3_targets_1']
595+
self.bundle.fromBpuNew.s3.full_pred_3_offsets_0.value = dict['full_pred_3_offsets_0']
596+
self.bundle.fromBpuNew.s3.full_pred_3_offsets_1.value = dict['full_pred_3_offsets_1']
597+
self.bundle.fromBpuNew.s3.full_pred_3_fallThroughAddr.value = dict['full_pred_3_fallThroughAddr']
598+
self.bundle.fromBpuNew.s3.full_pred_3_is_br_sharing.value = dict['full_pred_3_is_br_sharing']
599+
self.bundle.fromBpuNew.s3.full_pred_3_hit.value = dict['full_pred_3_hit']
600+
self.bundle.fromBpuNew.s3.valid_3.value = dict['valid_3']
601+
self.bundle.fromBpuNew.s3.hasRedirect_3.value = dict['hasRedirect_3']
602+
self.bundle.fromBpuNew.s3.ftq_idx_flag.value = dict['ftq_idx_flag']
603+
self.bundle.fromBpuNew.s3.ftq_idx_value.value = dict['ftq_idx_value']
604+
return self.bundle.as_dict()
605+
606+
@driver_method()
607+
async def drive_last_stage_ftb_entry_signals(self, dict):
608+
self.bundle.fromBpuNew.last_stage_ftb_entry.valid.value = dict['valid']
609+
self.bundle.fromBpuNew.last_stage_ftb_entry.isJalr.value = dict['isJalr']
610+
self.bundle.fromBpuNew.last_stage_ftb_entry.isCall.value = dict['isCall']
611+
self.bundle.fromBpuNew.last_stage_ftb_entry.isRet.value = dict['isRet']
612+
self.bundle.fromBpuNew.last_stage_ftb_entry.last_may_be_rvi_call.value = dict['last_may_be_rvi_call']
613+
self.bundle.fromBpuNew.last_stage_ftb_entry.carry.value = dict['carry']
614+
self.bundle.fromBpuNew.last_stage_ftb_entry.pftAddr.value = dict['pftAddr']
615+
self.bundle.fromBpuNew.last_stage_ftb_entry.brSlots_0_valid.value = dict['brSlots_0_valid']
616+
self.bundle.fromBpuNew.last_stage_ftb_entry.brSlots_0_sharing.value = dict['brSlots_0_sharing']
617+
self.bundle.fromBpuNew.last_stage_ftb_entry.brSlots_0_offset.value = dict['brSlots_0_offset']
618+
self.bundle.fromBpuNew.last_stage_ftb_entry.tailSlot_valid.value = dict['tailSlot_valid']
619+
self.bundle.fromBpuNew.last_stage_ftb_entry.tailSlot_offset.value = dict['tailSlot_offset']
620+
self.bundle.fromBpuNew.last_stage_ftb_entry.tailSlot_sharing.value = dict['tailSlot_sharing']
621+
622+
return self.bundle.as_dict()
623+
624+
@driver_method()
625+
async def drive_last_stage_spec_info_signals(self, dict):
626+
self.bundle.fromBpuNew.last_stage_spec_info.histPtr_flag.value = dict['histPtr_flag']
627+
self.bundle.fromBpuNew.last_stage_spec_info.histPtr_value.value = dict['histPtr_value']
628+
self.bundle.fromBpuNew.last_stage_spec_info.ssp.value = dict['ssp']
629+
self.bundle.fromBpuNew.last_stage_spec_info.sctr.value = dict['sctr']
630+
self.bundle.fromBpuNew.last_stage_spec_info.TOSW_flag.value = dict['TOSW_flag']
631+
self.bundle.fromBpuNew.last_stage_spec_info.TOSW_value.value = dict['TOSW_value']
632+
self.bundle.fromBpuNew.last_stage_spec_info.TOSR_flag.value = dict['TOSR_flag']
633+
self.bundle.fromBpuNew.last_stage_spec_info.TOSR_value.value = dict['TOSR_value']
634+
self.bundle.fromBpuNew.last_stage_spec_info.NOS_flag.value = dict['NOS_flag']
635+
self.bundle.fromBpuNew.last_stage_spec_info.NOS_value.value = dict['NOS_value']
636+
self.bundle.fromBpuNew.last_stage_spec_info.topAddr.value = dict['topAddr']
637+
self.bundle.fromBpuNew.last_stage_spec_info.sc_disagree_0.value = dict['sc_disagree_0']
638+
self.bundle.fromBpuNew.last_stage_spec_info.sc_disagree_1.value = dict['sc_disagree_1']
639+
return self.bundle.as_dict()
640+
641+
@driver_method()
642+
async def drive_last_stage_meta_signals(self):
643+
self.bundle.fromBpuNew.last_stage_meta.last_stage_meta.value = random.randint(0, (1 << 516) - 1)
644+
645+
@driver_method()
646+
async def drive_backend_inputs_full(self, dict):
647+
b = self.bundle.fromBackend
648+
# simple direct mappings where fields are known to exist in FtqBundle.fromBackend
649+
if 'io_fromBackend_redirect_valid' in dict:
650+
b.redirect_valid.value = dict['io_fromBackend_redirect_valid']
651+
if 'io_fromBackend_redirect_bits_ftqIdx_flag' in dict:
652+
b.redirect_bits_ftqIdx_flag.value = dict['io_fromBackend_redirect_bits_ftqIdx_flag']
653+
if 'io_fromBackend_redirect_bits_ftqIdx_value' in dict:
654+
b.redirect_bits_ftqIdx_value.value = dict['io_fromBackend_redirect_bits_ftqIdx_value']
655+
if 'io_fromBackend_redirect_bits_ftqOffset' in dict:
656+
b.redirect_bits_ftqOffset.value = dict['io_fromBackend_redirect_bits_ftqOffset']
657+
if 'io_fromBackend_redirect_bits_level' in dict:
658+
b.redirect_bits_level.value = dict['io_fromBackend_redirect_bits_level']
659+
# cfi update fields (map to known names if present)
660+
if 'io_fromBackend_redirect_bits_cfiUpdate_target' in dict:
661+
b.redirect_bits_cfiUpdate_target.value = dict['io_fromBackend_redirect_bits_cfiUpdate_target']
662+
if 'io_fromBackend_redirect_bits_cfiUpdate_taken' in dict:
663+
b.redirect_bits_cfiUpdate_taken.value = dict['io_fromBackend_redirect_bits_cfiUpdate_taken']
664+
if 'io_fromBackend_redirect_bits_cfiUpdate_isMisPred' in dict:
665+
b.redirect_bits_cfiUpdate_isMisPred.value = dict['io_fromBackend_redirect_bits_cfiUpdate_isMisPred']
666+
# debug fields
667+
if 'io_fromBackend_redirect_bits_debugIsCtrl' in dict:
668+
b.redirect_bits_debugIsCtrl.value = dict['io_fromBackend_redirect_bits_debugIsCtrl']
669+
if 'io_fromBackend_redirect_bits_debugIsMemVio' in dict:
670+
b.redirect_bits_debugIsMemVio.value = dict['io_fromBackend_redirect_bits_debugIsMemVio']
671+
# ftq ahead / selector
672+
if 'io_fromBackend_ftqIdxAhead_0_valid' in dict:
673+
b.ftqIdxAhead_0_valid.value = dict['io_fromBackend_ftqIdxAhead_0_valid']
674+
if 'io_fromBackend_ftqIdxAhead_0_bits_value' in dict:
675+
b.ftqIdxAhead_0_bits_value.value = dict['io_fromBackend_ftqIdxAhead_0_bits_value']
676+
if 'io_fromBackend_ftqIdxSelOH_bits' in dict:
677+
b.ftqIdxSelOH_bits.value = dict['io_fromBackend_ftqIdxSelOH_bits']
678+
679+
# For any extra cfi fields that may exist on the bundle, set them if present
680+
# e.g., cfiUpdate_pc, backendIGPF/IPF/IAF — only set if those attributes exist.
681+
try:
682+
if 'io_fromBackend_redirect_bits_cfiUpdate_pc' in dict and hasattr(b, 'redirect_bits_cfiUpdate_pc'):
683+
b.redirect_bits_cfiUpdate_pc.value = dict['io_fromBackend_redirect_bits_cfiUpdate_pc']
684+
except Exception:
685+
pass
686+
for extra in ('io_fromBackend_redirect_bits_cfiUpdate_backendIGPF',
687+
'io_fromBackend_redirect_bits_cfiUpdate_backendIPF',
688+
'io_fromBackend_redirect_bits_cfiUpdate_backendIAF'):
689+
if extra in dict:
690+
# try common attribute name pattern on bundle; ignore if not present
691+
attr = extra.replace('io_fromBackend_redirect_bits_', 'redirect_bits_')
692+
if hasattr(b, attr):
693+
getattr(b, attr).value = dict[extra]
694+
695+
# rob_commits: handle 0..7 RobCommitBundle entries if present in bundle and dict
696+
for i in range(8):
697+
rb_name = f'rob_commits_{i}'
698+
key_base = f'io_fromBackend_rob_commits_{i}_'
699+
if not hasattr(b, rb_name):
700+
continue
701+
rb = getattr(b, rb_name)
702+
if key_base + 'valid' in dict and hasattr(rb, 'valid'):
703+
rb.valid.value = dict[key_base + 'valid']
704+
if key_base + 'bits_commitType' in dict and hasattr(rb, 'bits_commitType'):
705+
rb.bits_commitType.value = dict[key_base + 'bits_commitType']
706+
if key_base + 'bits_ftqIdx_flag' in dict and hasattr(rb, 'bits_ftqIdx_flag'):
707+
rb.bits_ftqIdx_flag.value = dict[key_base + 'bits_ftqIdx_flag']
708+
if key_base + 'bits_ftqIdx_value' in dict and hasattr(rb, 'bits_ftqIdx_value'):
709+
rb.bits_ftqIdx_value.value = dict[key_base + 'bits_ftqIdx_value']
710+
if key_base + 'bits_ftqOffset' in dict and hasattr(rb, 'bits_ftqOffset'):
711+
rb.bits_ftqOffset.value = dict[key_base + 'bits_ftqOffset']
712+
713+
return self.bundle.as_dict()
714+
715+
@driver_method()
716+
async def drive_ifu_inputs_full(self, dict):
717+
f = self.bundle.fromIfu
718+
# top-level valid / ftqIdx fields
719+
if 'io_fromIfu_pdWb_valid' in dict:
720+
f.pdWb_valid.value = dict['io_fromIfu_pdWb_valid']
721+
if 'io_fromIfu_pdWb_bits_ftqIdx_flag' in dict:
722+
f.pdWb_bits_ftqIdx_flag.value = dict['io_fromIfu_pdWb_bits_ftqIdx_flag']
723+
if 'io_fromIfu_pdWb_bits_ftqIdx_value' in dict:
724+
f.pdWb_bits_ftqIdx_value.value = dict['io_fromIfu_pdWb_bits_ftqIdx_value']
725+
726+
# pc entries
727+
for i in range(16):
728+
key = f"io_fromIfu_pdWb_bits_pc_{i}"
729+
attr = f"pdWb_bits_pc_{i}"
730+
if key in dict and hasattr(f, attr):
731+
getattr(f, attr).value = dict[key]
732+
733+
# per-slot pd fields (brType, isCall, isRet, valid, isRVC) if present
734+
for i in range(16):
735+
base = f"pdWb_bits_pd_{i}"
736+
if hasattr(f, base):
737+
pd_obj = getattr(f, base)
738+
if f"io_fromIfu_pdWb_bits_pd_{i}_valid" in dict and hasattr(pd_obj, "valid"):
739+
pd_obj.valid.value = dict[f"io_fromIfu_pdWb_bits_pd_{i}_valid"]
740+
if f"io_fromIfu_pdWb_bits_pd_{i}_isRVC" in dict and hasattr(pd_obj, "isRVC"):
741+
pd_obj.isRVC.value = dict[f"io_fromIfu_pdWb_bits_pd_{i}_isRVC"]
742+
if f"io_fromIfu_pdWb_bits_pd_{i}_brType" in dict and hasattr(pd_obj, "brType"):
743+
pd_obj.brType.value = dict[f"io_fromIfu_pdWb_bits_pd_{i}_brType"]
744+
if f"io_fromIfu_pdWb_bits_pd_{i}_isCall" in dict and hasattr(pd_obj, "isCall"):
745+
pd_obj.isCall.value = dict[f"io_fromIfu_pdWb_bits_pd_{i}_isCall"]
746+
if f"io_fromIfu_pdWb_bits_pd_{i}_isRet" in dict and hasattr(pd_obj, "isRet"):
747+
pd_obj.isRet.value = dict[f"io_fromIfu_pdWb_bits_pd_{i}_isRet"]
748+
749+
# misOffset / cfiOffset / target / jalTarget / instrRange
750+
if 'io_fromIfu_pdWb_bits_misOffset_valid' in dict:
751+
f.pdWb_bits_misOffset_valid.value = dict['io_fromIfu_pdWb_bits_misOffset_valid']
752+
if 'io_fromIfu_pdWb_bits_misOffset_bits' in dict:
753+
f.pdWb_bits_misOffset_bits.value = dict['io_fromIfu_pdWb_bits_misOffset_bits']
754+
if 'io_fromIfu_pdWb_bits_cfiOffset_valid' in dict:
755+
f.pdWb_bits_cfiOffset_valid.value = dict['io_fromIfu_pdWb_bits_cfiOffset_valid']
756+
if 'io_fromIfu_pdWb_bits_target' in dict and hasattr(f, 'pdWb_bits_target'):
757+
f.pdWb_bits_target.value = dict['io_fromIfu_pdWb_bits_target']
758+
if 'io_fromIfu_pdWb_bits_jalTarget' in dict and hasattr(f, 'pdWb_bits_jalTarget'):
759+
f.pdWb_bits_jalTarget.value = dict['io_fromIfu_pdWb_bits_jalTarget']
760+
761+
# instrRange entries if they exist on bundle
762+
for i in range(16):
763+
key = f"io_fromIfu_pdWb_bits_instrRange_{i}"
764+
attr = f"pdWb_bits_instrRange_{i}"
765+
if key in dict and hasattr(f, attr):
766+
getattr(f, attr).value = dict[key]
767+
768+
return self.bundle.as_dict()

0 commit comments

Comments
 (0)