forked from XS-MLVP/UnityChipForXiangShan
Add frontend.bpu.ittage test code (#41)
This commit is contained in:
parent
d7e91e08f8
commit
8e09f7c86a
|
|
@ -17,8 +17,34 @@ import os
|
|||
|
||||
|
||||
def build(cfg):
|
||||
return False
|
||||
from tempfile import NamedTemporaryFile
|
||||
from toffee_test.markers import match_version
|
||||
from comm import error, info, get_root_dir, exe_cmd, get_all_rtl_files
|
||||
|
||||
# check version
|
||||
if not match_version(cfg.rtl.version, "openxiangshan-kmh-*"):
|
||||
error(f"frontend_bpu_ittage: Unsupported RTL version {cfg.rtl.version}")
|
||||
return False
|
||||
|
||||
# find source files for ITTage
|
||||
rtl_files = get_all_rtl_files("ITTage", cfg=cfg)
|
||||
assert rtl_files, "Cannot find RTL files of Frontend.BPU.ITTage"
|
||||
|
||||
internal_signals_path = os.path.join(get_root_dir("ut_frontend/bpu/ittage/internal.yaml"))
|
||||
assert os.path.exists(internal_signals_path), "Cannot find internal signal files"
|
||||
|
||||
# export ITTage.sv
|
||||
if not os.path.exists(get_root_dir("dut/ITTage")):
|
||||
info("Exporting ITTage.sv")
|
||||
with NamedTemporaryFile("w+", encoding="utf-8", suffix=".txt") as filelist:
|
||||
filelist.write("\n".join(rtl_files))
|
||||
filelist.flush()
|
||||
s, _, err = exe_cmd(
|
||||
f"picker export --cp_lib false {rtl_files[0]} --fs {filelist.name} --lang python --tdir "
|
||||
f"{get_root_dir('dut')}/ -w ITTage.fst -c --internal={internal_signals_path}")
|
||||
assert s, err
|
||||
return True
|
||||
|
||||
|
||||
def line_coverage_files(cfg):
|
||||
return []
|
||||
return ["ITTage.v"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
__all__ = ['UpdateBundle', 'InBundle', 'OutBundle', 'PipelineCtrl']
|
||||
|
||||
from toffee import Bundle, Signals, Signal
|
||||
|
||||
class PipelineCtrl(Bundle):
|
||||
s0_fire_0, s0_fire_1, s0_fire_2, s0_fire_3 = Signals(4)
|
||||
s1_fire_0, s1_fire_1, s1_fire_2, s1_fire_3 = Signals(4)
|
||||
s2_fire_0, s2_fire_1, s2_fire_2, s2_fire_3 = Signals(4)
|
||||
|
||||
class FullPred(Bundle):
|
||||
jalr_target = Signal()
|
||||
|
||||
class FoldedHist(Bundle):
|
||||
[hist_14_folded_hist, hist_13_folded_hist , hist_12_folded_hist , hist_10_folded_hist,
|
||||
hist_6_folded_hist , hist_4_folded_hist , hist_3_folded_hist , hist_2_folded_hist] = Signals(8)
|
||||
|
||||
class FTBEntry(Bundle):
|
||||
tailSlot_offset, tailSlot_sharing, tailSlot_valid, isRet, isJalr = Signals(5)
|
||||
|
||||
class CFI(Bundle):
|
||||
valid, bits = Signals(2)
|
||||
|
||||
# io_update_
|
||||
class UpdateBundle(Bundle):
|
||||
valid, bits_pc, bits_jmp_taken, bits_mispred_mask_2, bits_meta, bits_full_target = Signals(6)
|
||||
bits_ghist = Signal()
|
||||
ftb_entry = FTBEntry.from_prefix("bits_ftb_entry_")
|
||||
# folded_hist= FoldedHist.from_prefix("bits_spec_info_folded_hist_")
|
||||
cfi = CFI.from_prefix("bits_cfi_idx_")
|
||||
|
||||
# io_in_
|
||||
class InBundle(Bundle):
|
||||
bits_s0_pc_3 = Signal()
|
||||
|
||||
folded_hist = FoldedHist.from_prefix("bits_s1_folded_hist_3_")
|
||||
pred0 = FullPred.from_prefix("bits_resp_in_0_s2_full_pred_0_")
|
||||
pred1 = FullPred.from_prefix("bits_resp_in_0_s2_full_pred_1_")
|
||||
pred2 = FullPred.from_prefix("bits_resp_in_0_s2_full_pred_2_")
|
||||
pred3 = FullPred.from_prefix("bits_resp_in_0_s2_full_pred_3_")
|
||||
|
||||
# io_out_
|
||||
class OutBundle(Bundle):
|
||||
last_stage_meta = Signal()
|
||||
|
||||
pred1 = FullPred.from_prefix("s3_full_pred_1_")
|
||||
pred0 = FullPred.from_prefix("s3_full_pred_0_")
|
||||
pred2 = FullPred.from_prefix("s3_full_pred_2_")
|
||||
pred3 = FullPred.from_prefix("s3_full_pred_3_")
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
__all__ = ["GlobalHistory"]
|
||||
|
||||
GLOBAL_HISTORY_LEN = 256
|
||||
GLOBAL_HISTORY_MASK = (1 << GLOBAL_HISTORY_LEN) - 1
|
||||
|
||||
|
||||
class GlobalHistory:
|
||||
def __init__(self, init_val: int = 0, gh_len: int = GLOBAL_HISTORY_LEN):
|
||||
self.value = init_val
|
||||
self._len = gh_len
|
||||
|
||||
def update(self, taken: bool) -> None:
|
||||
g = self.value
|
||||
self.value = (g << 1) | taken & GLOBAL_HISTORY_MASK
|
||||
|
||||
def get_fh(self, folded_len: int, hist_len: int) -> int:
|
||||
if folded_len == 0:
|
||||
return 0
|
||||
res = 0
|
||||
g = self.value & ((1 << hist_len) - 1)
|
||||
mask = (1 << folded_len) - 1
|
||||
for _ in range(0, min(self._len, hist_len), folded_len):
|
||||
res ^= g & mask
|
||||
g >>= folded_len
|
||||
|
||||
return res
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import os.path
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
import toffee
|
||||
from toffee import ClockCycles
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import get_folded_hist
|
||||
from .bundle import *
|
||||
|
||||
__all__ = ['ITTageWrapper']
|
||||
|
||||
|
||||
class ITTageWrapper:
|
||||
def __init__(self, dut: DUTITTage):
|
||||
# Create DUT
|
||||
self.dut = dut
|
||||
self.dut.InitClock("clock")
|
||||
self.xclock = self.dut.xclock # for callback function
|
||||
|
||||
# Connect Bundle
|
||||
self.update_bundle = UpdateBundle.from_prefix("io_update_").set_name("ittage_update").bind(self.dut)
|
||||
self.in_bundle = InBundle.from_prefix("io_in_").set_name("ittage_in").bind(self.dut)
|
||||
self.out_bundle = OutBundle.from_prefix("io_out_").set_name("ittage_out").bind(self.dut)
|
||||
self.pipeline_ctrl = PipelineCtrl.from_prefix("io_").set_name("ittage_pipeline_ctrl").bind(self.dut)
|
||||
|
||||
# Reset
|
||||
self.reset()
|
||||
|
||||
def finalize(self):
|
||||
self.dut.Finish()
|
||||
|
||||
async def __rst_async__(self):
|
||||
self.dut.reset.value = 1
|
||||
await ClockCycles(self.dut, 10)
|
||||
self.dut.reset.value = 0
|
||||
|
||||
def __set_fire__(self, stage):
|
||||
for i in range(0, 4):
|
||||
getattr(self.pipeline_ctrl, f"s{stage}_fire_{i}").value = 1
|
||||
|
||||
|
||||
def __unset_fire__(self, stage):
|
||||
for i in range(0, 4):
|
||||
getattr(self.pipeline_ctrl, f"s{stage}_fire_{i}").value = 0
|
||||
|
||||
async def __predict_async__(self, fh, pc, use_dummy_fh=False):
|
||||
# stage0
|
||||
self.__set_fire__(0)
|
||||
self.in_bundle.bits_s0_pc_3.value = pc
|
||||
if use_dummy_fh:
|
||||
self.in_bundle.folded_hist.set_all(0)
|
||||
else:
|
||||
self.in_bundle.folded_hist.assign(get_folded_hist(fh))
|
||||
await ClockCycles(self.dut, 1)
|
||||
self.__unset_fire__(0)
|
||||
|
||||
# stage1
|
||||
self.__set_fire__(1)
|
||||
await ClockCycles(self.dut, 1)
|
||||
self.__unset_fire__(1)
|
||||
|
||||
# stage2
|
||||
self.__set_fire__(2)
|
||||
await ClockCycles(self.dut, 1)
|
||||
self.__unset_fire__(2)
|
||||
|
||||
# stage3
|
||||
await ClockCycles(self.dut, 1)
|
||||
|
||||
return self.out_bundle.as_dict()
|
||||
|
||||
async def __update_async__(self, update_req):
|
||||
self.update_bundle.assign(update_req)
|
||||
self.update_bundle.valid.value = 1
|
||||
await ClockCycles(self.dut, 1)
|
||||
self.update_bundle.valid.value = 0
|
||||
|
||||
await ClockCycles(self.dut, 3)
|
||||
|
||||
return None
|
||||
|
||||
def predict(self, fh, pc, use_dummy_fh=False):
|
||||
# stage0
|
||||
self.__set_fire__(0)
|
||||
self.in_bundle.bits_s0_pc_3.value = pc
|
||||
if use_dummy_fh:
|
||||
self.in_bundle.folded_hist.set_all(0)
|
||||
else:
|
||||
self.in_bundle.folded_hist.assign(get_folded_hist(fh))
|
||||
self.xclock.Step(1)
|
||||
self.__unset_fire__(0)
|
||||
|
||||
# stage1
|
||||
self.__set_fire__(1)
|
||||
self.xclock.Step(1)
|
||||
self.__unset_fire__(1)
|
||||
|
||||
# stage2
|
||||
self.__set_fire__(2)
|
||||
self.xclock.Step(1)
|
||||
self.__unset_fire__(2)
|
||||
|
||||
# stage3
|
||||
self.xclock.Step(1)
|
||||
|
||||
return self.out_bundle.as_dict()
|
||||
|
||||
def predict_async(self, fh, pc, use_dummy_fh=False):
|
||||
return toffee.create_task(self.__predict_async__(fh, pc, use_dummy_fh))
|
||||
|
||||
def update(self, update_req):
|
||||
self.update_bundle.assign(update_req)
|
||||
self.update_bundle.valid.value = 1
|
||||
self.xclock.Step(1)
|
||||
self.update_bundle.valid.value = 0
|
||||
|
||||
self.xclock.Step(1)
|
||||
pass
|
||||
|
||||
def update_async(self, update_req):
|
||||
return toffee.create_task(self.__update_async__(update_req))
|
||||
|
||||
def reset(self):
|
||||
self.dut.reset.value = 1
|
||||
self.xclock.Step(1)
|
||||
self.dut.reset.value = 0
|
||||
while self.dut.io_s1_ready.value == 0:
|
||||
self.xclock.Step(1)
|
||||
self.xclock.Step(10)
|
||||
|
||||
def reset_async(self):
|
||||
return toffee.create_task(self.__rst_async__())
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
ITTage:
|
||||
- "logic s3_altProvided"
|
||||
- "logic [1:0] s3_altProviderCtr"
|
||||
- "logic [40:0] s3_altProviderTarget"
|
||||
- "logic [2:0] s3_altProvider"
|
||||
- "logic s3_provided"
|
||||
- "logic [1:0] s3_providerCtr"
|
||||
- "logic s3_providerU"
|
||||
- "logic [2:0] s3_provider"
|
||||
- "logic [40:0] s3_providerTarget"
|
||||
- "logic [7:0] tickCtr"
|
||||
- "logic updateValid"
|
||||
- tables_0:
|
||||
- "wire io_resp_valid"
|
||||
- "wire io_update_valid"
|
||||
- "wire io_update_alloc"
|
||||
- "wire io_update_correct"
|
||||
- "wire [1:0] io_update_oldCtr"
|
||||
- "wire [1:0] update_wdata_ctr"
|
||||
- "wire io_update_reset_u"
|
||||
- "wire io_update_uValid"
|
||||
- "wire io_update_u"
|
||||
- tables_1:
|
||||
- "wire io_resp_valid"
|
||||
- "wire io_update_valid"
|
||||
- "wire io_update_alloc"
|
||||
- "wire io_update_correct"
|
||||
- "wire [1:0] io_update_oldCtr"
|
||||
- "wire [1:0] update_wdata_ctr"
|
||||
- "wire io_update_reset_u"
|
||||
- "wire io_update_uValid"
|
||||
- "wire io_update_u"
|
||||
- tables_2:
|
||||
- "wire io_resp_valid"
|
||||
- "wire io_update_valid"
|
||||
- "wire io_update_alloc"
|
||||
- "wire io_update_correct"
|
||||
- "wire [1:0] io_update_oldCtr"
|
||||
- "wire [1:0] update_wdata_ctr"
|
||||
- "wire io_update_reset_u"
|
||||
- "wire io_update_uValid"
|
||||
- "wire io_update_u"
|
||||
- tables_3:
|
||||
- "wire io_resp_valid"
|
||||
- "wire io_update_valid"
|
||||
- "wire io_update_alloc"
|
||||
- "wire io_update_correct"
|
||||
- "wire [1:0] io_update_oldCtr"
|
||||
- "wire [1:0] update_wdata_ctr"
|
||||
- "wire io_update_reset_u"
|
||||
- "wire io_update_uValid"
|
||||
- "wire io_update_u"
|
||||
- tables_4:
|
||||
- "wire io_resp_valid"
|
||||
- "wire io_update_valid"
|
||||
- "wire io_update_alloc"
|
||||
- "wire io_update_correct"
|
||||
- "wire [1:0] io_update_oldCtr"
|
||||
- "wire [1:0] update_wdata_ctr"
|
||||
- "wire io_update_reset_u"
|
||||
- "wire io_update_uValid"
|
||||
- "wire io_update_u"
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
"""
|
||||
Define all the coverage group calculation here
|
||||
Author: yzcc
|
||||
"""
|
||||
from comm import UT_FCOV
|
||||
from .chk_pred import *
|
||||
from .chk_train import *
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def get_cov_grp_of_alt_pred(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
bins = {}
|
||||
for i in range(4):
|
||||
bins[f"alt_use_table_{i}"] = is_alt_from_table_i(i)
|
||||
|
||||
grp.add_watch_point(dut, bins, name="ITTAGE Alt Pred altProvider from Tn")
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_longest_and_alt_train(dut: ITTageWrapper) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
bins_as_provider = {}
|
||||
bins_as_alt = {}
|
||||
for i in range(5):
|
||||
# 第i个表被作为主预测更新
|
||||
bins_as_provider["_".join([f"table{i + 1}", "update", "as", "provider"])] = is_update_table_as_provider(i)
|
||||
|
||||
# 第i个表被作为替代预测更新
|
||||
if i != 4:
|
||||
bins_as_alt["_".join([f"table{i + 1}", "update", "as", "alt"])] = is_update_table_as_alt(i)
|
||||
|
||||
grp.add_watch_point(dut, bins_as_provider, name="ITTAGE Longest and Alt Train Update as Provider")
|
||||
grp.add_watch_point(dut, bins_as_alt, name="ITTAGE Longest and Alt Train Update as Alt Provider")
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_main_pred(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
bins = {}
|
||||
for i in range(5):
|
||||
bins[f"T{i}_hit"] = is_hit_table_i(i)
|
||||
|
||||
grp.add_watch_point(dut, bins, name="ITTAGE Main Pred Hit Tn")
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_other_pred(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
# 是否命中多个表
|
||||
grp.add_watch_point(dut, {"hit_multi": is_hit_multi_table()}, name="ITTAGE Other Pred Hit Multi Table")
|
||||
|
||||
# 是否一个表都没命中
|
||||
grp.add_watch_point(dut, {"hit_no": is_hit_no_table()}, name="ITTAGE Other Pred Hit No Table")
|
||||
|
||||
# Res src
|
||||
# 替代预测来自ftb
|
||||
bins_src = {}
|
||||
bins_src["src_from_main"] = is_src_from_main()
|
||||
bins_src["src_from_alt"] = is_src_from_alt()
|
||||
bins_src["src_from_ftb"] = is_src_from_ftb()
|
||||
grp.add_watch_point(dut, bins_src, name="ITTAGE Other Pred Result Source")
|
||||
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_other_train(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
# tickCtr -> reset
|
||||
grp.add_watch_point(dut, {"reset_us": is_reset_us}, name="ITTAGE Other Train Reset Useful Bit")
|
||||
|
||||
# 更新最长表的时候,更新/不更新替代预测
|
||||
bins_update = {}
|
||||
for update_alt in range(2):
|
||||
s = ["update", "provider", "and", "alt"] if update_alt else ["only", "update", "provider"]
|
||||
bins_update["_".join(s)] = is_update_table_as_provider(update_alt)
|
||||
grp.add_watch_point(dut, bins_update, name="ITTAGE Other Train Update Entry")
|
||||
|
||||
# 申请新表项成功/失败
|
||||
bins_alloc = {}
|
||||
for success in range(2):
|
||||
s = "succeed" if success else "fail"
|
||||
bins_alloc["allocate_" + s] = is_allocate_succeed_or_fail(success)
|
||||
grp.add_watch_point(dut, bins_alloc, name="ITTAGE Other Train Allocate Entry")
|
||||
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_train_saturation(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
for up_or_down in range(2):
|
||||
saturating_status = "up" if up_or_down else "down"
|
||||
bins = {}
|
||||
for i in range(5):
|
||||
bins[f"T{i}_{saturating_status}_saturate"] = is_table_ctr_saturing(i, up_or_down)
|
||||
grp.add_watch_point(dut, bins, name=f"ITTAGE Saturation Train {saturating_status} saturing")
|
||||
|
||||
return grp
|
||||
|
||||
|
||||
def get_cov_grp_of_us_train(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup(UT_FCOV("../UT_ITTage"))
|
||||
|
||||
bins_set = {}
|
||||
bins_clr = {}
|
||||
for i in range(5):
|
||||
bins_set[f"T{i} us set"] = is_us_set_or_clear(1, i)
|
||||
bins_clr[f"T{i} us clear"] = is_us_set_or_clear(0, i)
|
||||
grp.add_watch_point(dut, bins_set, name="ITTAGE Us Train Tn us set")
|
||||
grp.add_watch_point(dut, bins_clr, name="ITTAGE Us Train Tn us clear")
|
||||
return grp
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
"""
|
||||
Checkpoint for prediction
|
||||
"""
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
|
||||
|
||||
def is_hit_table_i(i: int):
|
||||
def hit_table_i(dut: DUTITTage):
|
||||
tn_hit = getattr(dut, f"ITTage_tables_{i}_io_resp_valid").value
|
||||
return tn_hit
|
||||
|
||||
return hit_table_i
|
||||
|
||||
|
||||
def is_hit_multi_table():
|
||||
def hit_multi_table(dut: DUTITTage):
|
||||
tn_hit = 0
|
||||
for i in range(5):
|
||||
tn_hit += is_hit_table_i(i)(dut)
|
||||
return tn_hit > 1
|
||||
|
||||
return hit_multi_table
|
||||
|
||||
|
||||
def is_hit_no_table():
|
||||
def hit_no_table(dut: DUTITTage):
|
||||
tn_hit = 0
|
||||
for i in range(5):
|
||||
tn_hit += is_hit_table_i(i)(dut)
|
||||
return tn_hit == 0
|
||||
|
||||
return hit_no_table
|
||||
|
||||
|
||||
def is_alt_from_ftb():
|
||||
def alt_from_ftb(dut: DUTITTage):
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
return alt_provided == 0 and provided == 0
|
||||
|
||||
return alt_from_ftb
|
||||
|
||||
|
||||
def is_alt_from_table_i(i: int):
|
||||
def alt_from_table_i(dut: DUTITTage):
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
alt_provider = dut.ITTage_s3_altProvider.value
|
||||
return alt_provided and alt_provider == i
|
||||
|
||||
return alt_from_table_i
|
||||
|
||||
|
||||
# final prediction target
|
||||
def is_src_from_main():
|
||||
def src_from_main(dut: DUTITTage):
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
provider_ctr = dut.ITTage_s3_providerCtr.value
|
||||
provider_target = dut.ITTage_s3_providerTarget.value
|
||||
pred_target = dut.io_out_s3_full_pred_3_jalr_target.value
|
||||
return provided > 0 and provider_ctr > 0 and provider_target == pred_target
|
||||
|
||||
return src_from_main
|
||||
|
||||
|
||||
def is_src_from_alt():
|
||||
def src_from_alt(dut: DUTITTage):
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
provider_ctr = dut.ITTage_s3_providerCtr.value
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
alt_target = dut.ITTage_s3_altProviderTarget.value
|
||||
pred_target = dut.io_out_s3_full_pred_3_jalr_target.value
|
||||
return provided > 0 and provider_ctr == 0 and alt_provided > 0 and alt_target == pred_target
|
||||
|
||||
return src_from_alt
|
||||
|
||||
|
||||
def is_src_from_ftb():
|
||||
def src_from_ftb(dut: DUTITTage):
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
ftb_target = dut.io_in_bits_resp_in_0_s2_full_pred_3_jalr_target.value
|
||||
pred_target = dut.io_out_s3_full_pred_3_jalr_target.value
|
||||
return provided == 0 and alt_provided == 0 and ftb_target == pred_target
|
||||
|
||||
return src_from_ftb
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
"""
|
||||
Checkpoint for train
|
||||
"""
|
||||
|
||||
from toffee import CovGroup
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
|
||||
|
||||
def is_table_ctr_saturing(i: int, up_or_down: int):
|
||||
sat_value = 0b11 if up_or_down else 0
|
||||
|
||||
def table_ctr_saturing(dut: DUTITTage):
|
||||
alloc = getattr(dut, f"ITTage_tables_{i}_io_update_alloc").value
|
||||
correct = getattr(dut, f"ITTage_tables_{i}_io_update_correct").value
|
||||
valid = getattr(dut, f"ITTage_tables_{i}_io_update_valid").value and not alloc and up_or_down == correct
|
||||
old_ctr = getattr(dut, f"ITTage_tables_{i}_io_update_oldCtr").value
|
||||
new_ctr = getattr(dut, f"ITTage_tables_{i}_update_wdata_ctr").value
|
||||
return valid and old_ctr == sat_value and new_ctr == sat_value
|
||||
|
||||
return table_ctr_saturing
|
||||
|
||||
|
||||
def is_update_provider(update_alt: int):
|
||||
def update_provider(dut: DUTITTage):
|
||||
valid = dut.io_update_valid.value and dut.ITTage_updateValid.value
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
if valid and provided:
|
||||
return update_alt == alt_provided
|
||||
return False
|
||||
|
||||
return update_provider
|
||||
|
||||
|
||||
def is_update_table_as_provider(i: int):
|
||||
def update_table_as_provider(dut: DUTITTage):
|
||||
valid = dut.io_update_valid.value and dut.ITTage_updateValid.value
|
||||
provided = dut.ITTage_s3_provided.value
|
||||
provider = dut.ITTage_s3_provider.value
|
||||
return valid and provided and (provider == i)
|
||||
|
||||
return update_table_as_provider
|
||||
|
||||
|
||||
def is_update_table_as_alt(i: int):
|
||||
def update_table_as_alt(dut: DUTITTage):
|
||||
valid = dut.io_update_valid.value and dut.ITTage_updateValid.value
|
||||
alt_provided = dut.ITTage_s3_altProvided.value
|
||||
alt_provider = dut.ITTage_s3_altProvider.value
|
||||
return valid and alt_provided and (alt_provider == i)
|
||||
|
||||
return update_table_as_alt
|
||||
|
||||
|
||||
def is_reset_us(dut: DUTITTage):
|
||||
valid = dut.io_update_valid.value
|
||||
tick_ctr = dut.ITTage_tickCtr.value
|
||||
reset = sum([getattr(dut, f"ITTage_tables_{i}_io_update_reset_u").value for i in range(5)])
|
||||
assert reset in {0, 5}, "Number of reset tables must be 5"
|
||||
if valid and (reset == 5):
|
||||
# assert tick_ctr == 0xff
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_allocate_succeed_or_fail(success_or_fail: int):
|
||||
def allocate_succeed_or_fail(dut: DUTITTage):
|
||||
valid = dut.io_update_valid.value and dut.ITTage_updateValid.value
|
||||
allocate_valid = MetaParser(dut.io_update_bits_meta.value).allocate_valid
|
||||
return valid and (allocate_valid == success_or_fail)
|
||||
|
||||
return allocate_succeed_or_fail
|
||||
|
||||
|
||||
def is_us_set_or_clear(set_or_clear: int, i: int):
|
||||
def us_set_or_clear(dut: DUTITTage):
|
||||
meta_wrap = MetaParser(dut.io_update_bits_meta.value)
|
||||
|
||||
altDiffer = meta_wrap.altDiffers
|
||||
providerU = meta_wrap.providerU
|
||||
provider = meta_wrap.provider
|
||||
misPred = dut.io_update_bits_mispred_mask_2.value
|
||||
|
||||
set_value = (not misPred) if altDiffer else providerU
|
||||
|
||||
valid = dut.io_update_valid.value and meta_wrap.provided
|
||||
|
||||
return valid and set_value == set_or_clear and provider == i
|
||||
|
||||
return us_set_or_clear
|
||||
|
||||
|
||||
def is_set_us_correct(dut: DUTITTage):
|
||||
meta_parser = MetaParser(dut.io_update_bits_meta.value)
|
||||
provided = meta_parser.provided
|
||||
provider = meta_parser.provider
|
||||
provider_ctr = meta_parser.providerCtr
|
||||
provider_target = meta_parser.providerTarget
|
||||
use_provider = provided and provider_ctr != 0
|
||||
real_target = dut.io_update_bits_full_target.value
|
||||
provider_correct = provider_target == real_target
|
||||
|
||||
valid = dut.io_update_valid.value and dut.ITTage_updateValid.value
|
||||
set_us_true = (getattr(dut, f"ITTage_tables_{provider}_io_update_uValid").value and
|
||||
getattr(dut, f"ITTage_tables_{provider}_io_update_u").value)
|
||||
|
||||
if valid and set_us_true:
|
||||
# 香山ITTAGE对于us置1的基本逻辑是,只要
|
||||
return use_provider and provider_correct
|
||||
return False
|
||||
|
||||
|
||||
def _get_cov_grp_of_pred(dut: DUTITTage) -> CovGroup:
|
||||
grp = CovGroup("ITTAGE Train")
|
||||
|
||||
# 第i个表计数器达到上/下饱和
|
||||
for i in range(5):
|
||||
for up_or_down in range(2):
|
||||
saturing_status = "up" if up_or_down else "down"
|
||||
grp.add_watch_point(
|
||||
dut,
|
||||
{"_".join([f"table{i + 1}", saturing_status, "saturing"]): is_table_ctr_saturing(i, up_or_down)},
|
||||
name=" ".join([f"Table{i + 1}", "is", saturing_status.capitalize(), "Saturing"]),
|
||||
)
|
||||
|
||||
for i in range(5):
|
||||
# 第i个表被作为主预测更新
|
||||
grp.add_watch_point(
|
||||
dut,
|
||||
{"_".join([f"table{i + 1}", "update", "as", "provider"]): is_update_table_as_provider(i)},
|
||||
name=" ".join([f"Table{i + 1}", "Update", "as", "Provider"]),
|
||||
)
|
||||
# 第i个表被作为替代预测更新
|
||||
grp.add_watch_point(
|
||||
dut,
|
||||
{"_".join([f"table{i + 1}", "update", "as", "alt"]): is_update_table_as_alt(i)},
|
||||
name=" ".join([f"Table{i + 1}", "Update", "as", "Alt"]),
|
||||
)
|
||||
|
||||
# 更新最长表的时候,更新/不更新替代预测
|
||||
for update_alt in range(2):
|
||||
s = ["update", "provider", "and", "alt"] if update_alt else ["only", "update", "provider"]
|
||||
grp.add_watch_point(
|
||||
dut,
|
||||
{"_".join(s): is_update_table_as_provider(update_alt)},
|
||||
name=" ".join([x.capitalize() for x in s])
|
||||
)
|
||||
|
||||
# tickCtr达到最大值,触发重置useful位
|
||||
grp.add_watch_point(dut, {"reset_us": is_reset_us}, name="Reset Useful Bit")
|
||||
|
||||
# 申请新表项成功/失败
|
||||
for success in range(2):
|
||||
s = "succeed" if success else "fail"
|
||||
grp.add_watch_point(
|
||||
dut,
|
||||
{"allocate_" + s: is_allocate_succeed_or_fail(success)},
|
||||
name="Allocate " + s.capitalize()
|
||||
)
|
||||
# 在正确的条件下us被置为1
|
||||
grp.add_watch_point(dut, {"us_set_1": is_set_us_correct}, name="Provider us bit Set 1")
|
||||
|
||||
return grp
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
"""
|
||||
Test for allocate entry
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import toffee_test
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import UpdateReq
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from .chk_helper import get_cov_grp_of_other_train, get_cov_grp_of_us_train
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def test_alloc_train(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
# Start
|
||||
pins.xclock.Step(1000)
|
||||
|
||||
pc = 0x114514
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.allocate_valid = 0
|
||||
meta_wrap.allocate_bits = 0
|
||||
|
||||
for i in range(1000):
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + 0x4, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
|
||||
# Check
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
assert meta_wrap.provided == 0 and meta_wrap.altProvided == 0 and pred_target == 0
|
||||
|
||||
fake_meta = MetaParser(0)
|
||||
|
||||
# provider is unconfident and providing an incorrect target
|
||||
fake_meta.provided = 1
|
||||
fake_meta.provider = 3
|
||||
fake_meta.providerCtr = 0
|
||||
fake_meta.providerTarget = 0x114514
|
||||
|
||||
# altProvider is unconfident and providing a correct target
|
||||
fake_meta.altProvided = 1
|
||||
fake_meta.altProvider = 1
|
||||
fake_meta.altProviderCtr = 0
|
||||
# altDiffers = s3_finalAltPred != s3_tageTaken_dup(3)
|
||||
# = Mux(altProvided, altProviderInfo.ctr(ITTageCtrBits-1), True) != True
|
||||
fake_meta.altDiffers = 1
|
||||
fake_meta.altTargetCtr = 0x1919810
|
||||
|
||||
pins.update(UpdateReq(0x123, fake_meta.meta, 0x1919810, 1, 0).asdict())
|
||||
|
||||
assert not (pins.dut.ITTage_tables_3_io_update_valid.value
|
||||
and pins.dut.ITTage_tables_3_io_update_u.value
|
||||
and pins.dut.ITTage_tables_3_io_update_uValid.value), "provider shouldn't be set useful"
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_other_train(dut),
|
||||
get_cov_grp_of_us_train(dut)
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
"""
|
||||
Test for alternative prediction
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import toffee_test
|
||||
from random import randint
|
||||
from toffee import CovGroup
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import UpdateReq
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from .chk_helper import get_cov_grp_of_alt_pred
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def test_alt_pred(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
# Start
|
||||
pins.xclock.Step(1000)
|
||||
|
||||
# Test: use T1~T4 as alt_pred
|
||||
for tab in range(4):
|
||||
pc = tab * 4
|
||||
|
||||
# Alloc Longest
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.allocate_bits = 4
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + randint(1, 0x114514), 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Alloc Second Longest
|
||||
meta_wrap.allocate_bits = tab
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + randint(1, 0x114514), 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Set longest to unconfident
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.provided = 1
|
||||
meta_wrap.provider = 4
|
||||
meta_wrap.providerCtr = 0b01
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + 0x1, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Pred and Check
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
assert meta_wrap.altProvided == 1 and meta_wrap.providerCtr == 0, "should use alternative pred"
|
||||
|
||||
pins.xclock.Step(100)
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_alt_pred(dut)
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
"""
|
||||
Test the main prediction func
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import toffee_test
|
||||
from random import randint
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import UpdateReq
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from .chk_helper import get_cov_grp_of_main_pred
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_main_pred(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
# Start
|
||||
pins.reset()
|
||||
|
||||
for tab in range(5):
|
||||
pc = tab
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.allocate_bits = tab
|
||||
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + randint(1, 0x114514), 0, 1)
|
||||
pins.update(req.asdict())
|
||||
|
||||
# Check
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
assert meta_wrap.provided == 1 and meta_wrap.provider == tab, f"T{tab} should be hit"
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_main_pred(dut)
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
"""
|
||||
Random Test
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import random
|
||||
|
||||
import toffee_test
|
||||
from toffee import CovGroup
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import UpdateReq
|
||||
|
||||
from .chk_helper import get_cov_grp_of_main_pred, get_cov_grp_of_us_train, get_cov_grp_of_other_train
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def test_random(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
# Start Test
|
||||
pins.reset()
|
||||
|
||||
random.seed(19260817)
|
||||
pc = 0x114514
|
||||
for ite in range(10000):
|
||||
pc += random.randint(0, 0x3) * 2
|
||||
|
||||
# predict
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta = dut_output["last_stage_meta"]
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
# update
|
||||
if random.randint(0, 1):
|
||||
req = UpdateReq(pc, meta, pred_target, 0, 0)
|
||||
else:
|
||||
req = UpdateReq(pc, meta, pred_target + 0x1, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_main_pred(dut),
|
||||
get_cov_grp_of_us_train(dut),
|
||||
get_cov_grp_of_other_train(dut)
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import toffee_test
|
||||
|
||||
from toffee import CovGroup
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from .chk_helper import get_cov_grp_of_main_pred
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def test_reset(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
dut_output = pins.predict(0, 0x123, True)
|
||||
|
||||
for i in range(4):
|
||||
assert dut_output[f"pred{i}"]["jalr_target"] == 0
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_main_pred(dut),
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
Test the saturation of the training
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import toffee_test
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
from ..util.common import UpdateReq
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from .chk_helper import get_cov_grp_of_train_saturation, get_cov_grp_of_other_train
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
|
||||
def test_saturation_train(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
# Start
|
||||
pins.xclock.Step(1000)
|
||||
|
||||
pc = None
|
||||
for tab in range(5):
|
||||
# Up Saturating
|
||||
pc = tab
|
||||
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.provided = 1
|
||||
meta_wrap.provider = tab
|
||||
meta_wrap.providerCtr = 0b11 # up bound
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target, 0, 0)
|
||||
pins.update(req.asdict())
|
||||
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Check
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
assert meta_wrap.provided == 1 and meta_wrap.provider == tab and meta_wrap.providerCtr == 0b11, f"T{tab} up saturation fails"
|
||||
|
||||
# Down Saturating
|
||||
pc = tab + 47
|
||||
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.allocate_valid = 0
|
||||
meta_wrap.provided = 1
|
||||
meta_wrap.provider = tab
|
||||
meta_wrap.providerCtr = 0b00
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + 1, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Check
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
assert meta_wrap.provided == 1 and meta_wrap.provider == tab and meta_wrap.providerCtr == 0b00, f"T{tab} down saturation fails"
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_train_saturation(dut),
|
||||
get_cov_grp_of_other_train(dut),
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
"""
|
||||
Src of prediction from:
|
||||
1. Main prediction
|
||||
2. Alt prediction
|
||||
3. FTB prediction
|
||||
Author: yzcc
|
||||
"""
|
||||
|
||||
import toffee_test
|
||||
from toffee import CovGroup
|
||||
from ..util.common import UpdateReq
|
||||
from ..util.meta_parser import MetaParser
|
||||
|
||||
from .chk_helper import get_cov_grp_of_other_pred
|
||||
from ..env.ittage_wrapper import ITTageWrapper
|
||||
|
||||
from dut.ITTage import DUTITTage
|
||||
|
||||
|
||||
def test_src_pred(ittage_wrapper: ITTageWrapper):
|
||||
pins = ittage_wrapper
|
||||
|
||||
# Start
|
||||
pins.xclock.Step(1000)
|
||||
|
||||
pc = 0x0
|
||||
# Test: Use Main Pred - 2
|
||||
dut_output = pins.predict(0, pc, True) # get meta, alloc
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
|
||||
meta_wrap.allocate_bits = 4 # update
|
||||
req = UpdateReq(pc, meta_wrap.value, 0x114514, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
assert dut_output["pred0"]["jalr_target"] == 0x114514, "Target should from main prediction"
|
||||
|
||||
# Test: Use Main Pred - 1
|
||||
fake_meta = MetaParser(0)
|
||||
# except provider is unconfident
|
||||
fake_meta.provided = 1
|
||||
fake_meta.provider = 3
|
||||
fake_meta.providerCtr = 0
|
||||
fake_meta.providerTarget = 0x1919810
|
||||
# except altProvider is invalid
|
||||
fake_meta.altProvided = 0
|
||||
fake_meta.altProvidedCtr = 0x114514
|
||||
|
||||
pins.update(UpdateReq(0x123, fake_meta.meta, 0xFF000, 1, 1).asdict())
|
||||
pins.in_bundle.pred3.jalr_target.value = 0xF # T0 Target
|
||||
pins.predict(1, 0x123)
|
||||
dut_output = pins.out_bundle.as_dict()
|
||||
assert dut_output['pred0']['jalr_target'] in {0xF, 0xFF000}, "Predict Target is not from known sources"
|
||||
pins.in_bundle.pred3.jalr_target.value = 0
|
||||
|
||||
# Test: Use Alt Pred
|
||||
# Alloc Second Longest
|
||||
meta_wrap.allocate_bits = 1
|
||||
req = UpdateReq(pc, meta_wrap.value, 0x1919810, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
# Set longest to unconfident
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
meta_wrap = MetaParser(dut_output["last_stage_meta"])
|
||||
pred_target = dut_output["pred0"]["jalr_target"]
|
||||
|
||||
meta_wrap.provided = 1
|
||||
meta_wrap.provider = 4
|
||||
meta_wrap.providerCtr = 0b01
|
||||
req = UpdateReq(pc, meta_wrap.value, pred_target + 0x1, 0, 1)
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
pins.update(req.asdict())
|
||||
pins.xclock.Step(10)
|
||||
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
assert dut_output["pred0"]["jalr_target"] == 0x1919810, "Target should from alt prediction"
|
||||
|
||||
# Test: Use FTB Prerd
|
||||
pc = 0x114
|
||||
dut_output = pins.predict(0, pc, True)
|
||||
assert dut_output["pred0"]["jalr_target"] == 0x0, "Target should from ftb"
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def ittage_wrapper(toffee_request: toffee_test.ToffeeRequest):
|
||||
dut: DUTITTage = toffee_request.create_dut(DUTITTage, "clock")
|
||||
wrapper = ITTageWrapper(dut)
|
||||
toffee_request.add_cov_groups([
|
||||
get_cov_grp_of_other_pred(dut)
|
||||
])
|
||||
|
||||
yield wrapper
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
__all__ = ['gen_dummy_update_req', 'UpdateReq', 'get_folded_hist']
|
||||
|
||||
from ..env.global_history import GlobalHistory
|
||||
|
||||
|
||||
def gen_dummy_update_req(pc, meta):
|
||||
update_req = {}
|
||||
update_req["valid"] = 1
|
||||
update_req["bits_pc"] = pc
|
||||
|
||||
update_req["ftb_entry"] = {}
|
||||
update_req["ftb_entry"]["tailSlot_offset"] = 0
|
||||
update_req["ftb_entry"]["tailSlot_sharing"] = 0
|
||||
update_req["ftb_entry"]["tailSlot_valid"] = 1
|
||||
update_req["ftb_entry"]["isRet"] = 0
|
||||
update_req["ftb_entry"]["isJalr"] = 1
|
||||
|
||||
update_req["cfi"] = {}
|
||||
update_req["cfi"]["valid"] = 1
|
||||
update_req["cfi"]["bits"] = 0
|
||||
|
||||
update_req["bits_jmp_taken"] = 1
|
||||
update_req["bits_mispred_mask_2"] = 1
|
||||
update_req["bits_meta"] = meta
|
||||
return update_req
|
||||
|
||||
|
||||
def get_folded_hist(hist: int) -> dict:
|
||||
ghv = GlobalHistory(hist)
|
||||
return {
|
||||
"hist_14_folded_hist": ghv.get_fh(8, 8),
|
||||
"hist_13_folded_hist": ghv.get_fh(9, 13),
|
||||
"hist_12_folded_hist": ghv.get_fh(4, 4),
|
||||
"hist_10_folded_hist": ghv.get_fh(9, 32),
|
||||
"hist_6_folded_hist": ghv.get_fh(9, 16),
|
||||
"hist_4_folded_hist": ghv.get_fh(8, 13),
|
||||
"hist_3_folded_hist": ghv.get_fh(8, 32),
|
||||
"hist_2_folded_hist": ghv.get_fh(8, 16),
|
||||
}
|
||||
|
||||
|
||||
class FtbEntry:
|
||||
def __init__(self):
|
||||
self.tailSlot_offset = 0
|
||||
self.tailSlot_sharing = 0
|
||||
self.tailSlot_valid = 1
|
||||
self.isRet = 0
|
||||
self.isJalr = 1
|
||||
|
||||
|
||||
class CfiReq:
|
||||
def __init__(self):
|
||||
self.valid = 1
|
||||
self.bits = 0
|
||||
|
||||
|
||||
class UpdateReq:
|
||||
def __init__(self, pc: int, meta: int, full_target: int, hist: int, mis_pred: int):
|
||||
self.valid = 1
|
||||
self.bits_pc = pc
|
||||
|
||||
self.ftb_entry = FtbEntry()
|
||||
|
||||
self.cfi = CfiReq()
|
||||
|
||||
self.bits_jmp_taken = 1
|
||||
self.bits_mispred_mask_2 = mis_pred
|
||||
self.bits_meta = meta
|
||||
self.hist = hist
|
||||
|
||||
self.bits_full_target = full_target
|
||||
|
||||
def asdict(self) -> dict:
|
||||
update_req = {}
|
||||
update_req["valid"] = self.valid
|
||||
update_req["bits_pc"] = self.bits_pc
|
||||
|
||||
update_req["ftb_entry"] = {}
|
||||
update_req["ftb_entry"]["tailSlot_offset"] = self.ftb_entry.tailSlot_offset
|
||||
update_req["ftb_entry"]["tailSlot_sharing"] = self.ftb_entry.tailSlot_sharing
|
||||
update_req["ftb_entry"]["tailSlot_valid"] = self.ftb_entry.tailSlot_valid
|
||||
update_req["ftb_entry"]["isRet"] = self.ftb_entry.isRet
|
||||
update_req["ftb_entry"]["isJalr"] = self.ftb_entry.isJalr
|
||||
|
||||
update_req["cfi"] = {}
|
||||
update_req["cfi"]["valid"] = self.cfi.valid
|
||||
update_req["cfi"]["bits"] = self.cfi.bits
|
||||
|
||||
update_req["bits_jmp_taken"] = self.bits_jmp_taken
|
||||
update_req["bits_mispred_mask_2"] = self.bits_mispred_mask_2
|
||||
update_req["bits_meta"] = self.bits_meta
|
||||
update_req["bits_full_target"] = self.bits_full_target
|
||||
|
||||
# update_req["folded_hist"] = get_folded_hist(self.hist)
|
||||
update_req["bits_ghist"] = self.hist
|
||||
|
||||
return update_req
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
__all__ = ['MetaParser']
|
||||
|
||||
class MetaParser:
|
||||
def __init__(self, meta: int) -> None:
|
||||
self.value = meta
|
||||
pass
|
||||
|
||||
def bits(self, high, low):
|
||||
assert low <= high
|
||||
mask = (1 << (high + 1)) - 1
|
||||
return (self.value & mask) >> low
|
||||
|
||||
def bit(self, bit):
|
||||
return (self.value >> bit) & 1
|
||||
|
||||
@property
|
||||
def meta(self) -> int:
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def provided(self) -> int:
|
||||
return self.bit(117)
|
||||
|
||||
@provided.setter
|
||||
def provided(self, value: int):
|
||||
mask = ~(1 << 117)
|
||||
self.value = (self.value & mask) | (value << 117)
|
||||
|
||||
@property
|
||||
def provider(self):
|
||||
"""The provider property."""
|
||||
return self.bits(116, 114)
|
||||
|
||||
@provider.setter
|
||||
def provider(self, value):
|
||||
mask = ~(0b111 << 114)
|
||||
self.value = (self.value & mask) | (value << 114)
|
||||
|
||||
@property
|
||||
def altProvided(self):
|
||||
"""The altProvided property."""
|
||||
return self.bit(113)
|
||||
|
||||
@altProvided.setter
|
||||
def altProvided(self, value):
|
||||
mask = ~(1 << 113)
|
||||
self.value = (self.value & mask) | (value << 113)
|
||||
|
||||
@property
|
||||
def altProvider(self):
|
||||
"""The altProvider property."""
|
||||
return self.bits(112, 110)
|
||||
|
||||
@altProvider.setter
|
||||
def altProvider(self, value):
|
||||
mask = ~(0b111 << 110)
|
||||
self.value = (self.value & mask) | (value << 110)
|
||||
|
||||
@property
|
||||
def altDiffers(self):
|
||||
"""The altDiffers property."""
|
||||
return self.bit(109)
|
||||
|
||||
@altDiffers.setter
|
||||
def altDiffers(self, value):
|
||||
mask = ~(1 << 109)
|
||||
self.value = (self.value & mask) | (value << 109)
|
||||
|
||||
@property
|
||||
def providerU(self):
|
||||
"""The providerU property."""
|
||||
return self.bit(108)
|
||||
|
||||
@providerU.setter
|
||||
def providerU(self, value):
|
||||
mask = ~(1 << 108)
|
||||
self.value = (self.value & mask) | (value << 108)
|
||||
|
||||
@property
|
||||
def providerCtr(self):
|
||||
"""The providerCtr property."""
|
||||
return self.bits(107, 106)
|
||||
|
||||
@providerCtr.setter
|
||||
def providerCtr(self, value):
|
||||
mask = ~(0b11 << 106)
|
||||
self.value = (self.value & mask) | (value << 106)
|
||||
|
||||
@property
|
||||
def altProviderCtr(self):
|
||||
"""The altProviderCtr property."""
|
||||
return self.bits(105, 104)
|
||||
|
||||
@altProviderCtr.setter
|
||||
def altProviderCtr(self, value):
|
||||
mask = ~(0b11 << 104)
|
||||
self.value = (self.value & mask) | (value << 104)
|
||||
|
||||
@property
|
||||
def allocate_valid(self):
|
||||
"""The allocate_valid property."""
|
||||
return self.bit(103)
|
||||
|
||||
@allocate_valid.setter
|
||||
def allocate_valid(self, value):
|
||||
mask = ~(1 << 103)
|
||||
self.value = (self.value & mask) | (value << 103)
|
||||
|
||||
@property
|
||||
def allocate_bits(self):
|
||||
"""The allocate_bits property."""
|
||||
return self.bits(102, 100)
|
||||
|
||||
@allocate_bits.setter
|
||||
def allocate_bits(self, value):
|
||||
mask = ~(0b111 << 100)
|
||||
self.value = (self.value & mask) | (value << 100)
|
||||
|
||||
@property
|
||||
def providerTarget(self):
|
||||
"""The providerTarget property."""
|
||||
return self.bits(95, 50)
|
||||
|
||||
@providerTarget.setter
|
||||
def providerTarget(self, value):
|
||||
mask = ~(0X3FFFFFFFFFFFF << 50)
|
||||
self.value = (self.value & mask) | (value << 50)
|
||||
|
||||
@property
|
||||
def altProviderTarget(self):
|
||||
"""The altProviderTarget property."""
|
||||
return self.bits(49, 0)
|
||||
|
||||
@altProviderTarget.setter
|
||||
def altProviderTarget(self, value):
|
||||
mask = ~(0X3FFFFFFFFFFFF << 0)
|
||||
self.value = (self.value & mask) | (value << 0)
|
||||
Loading…
Reference in New Issue