Initial encapsulation of internal signals for `Tage_SC`, and decoupling the functionality of `tage_predict` and `tage_train` from the raw DUT pins.

This commit is contained in:
FrankOu2001 2024-12-11 00:00:17 +08:00
parent 676079f8e2
commit c9ef4856fb
5 changed files with 152 additions and 232 deletions

View File

@ -1,60 +1,2 @@
from toffee import Bundle, Signal, Signals
__all__ = ["BranchPredictReq", "BranchPredictionResp", "UpdateBundle", "CtrlBundle", "PipelineBundle"]
class CtrlBundle(Bundle):
tage_enable, sc_enable = Signals(2)
class PipelineBundle(Bundle):
# 0->BPU, 1->Tage, 3->SC
s0_fire_0, s1_fire_0, s2_fire_0 = Signals(3)
s0_fire_1, s1_fire_1, s2_fire_1 = Signals(3)
s0_fire_2, s1_fire_2, s2_fire_2 = Signals(3)
s0_fire_3, s1_fire_3, s2_fire_3 = Signals(3)
class FoldedHistoryBundle(Bundle):
[hist_0_folded_hist, hist_1_folded_hist, hist_2_folded_hist, hist_3_folded_hist,
hist_4_folded_hist, hist_5_folded_hist, hist_6_folded_hist, hist_7_folded_hist,
hist_8_folded_hist, hist_9_folded_hist, hist_10_folded_hist, hist_11_folded_hist,
hist_12_folded_hist, hist_13_folded_hist, hist_14_folded_hist, hist_15_folded_hist,
hist_16_folded_hist, hist_17_folded_hist] = Signals(18)
class FTBSlotBundle(Bundle):
valid, sharing = Signals(2)
class FTBEntryBundle(Bundle):
always_taken_0, always_taken_1 = Signals(2)
br_slot = FTBSlotBundle.from_prefix("brSlots_0_")
tail_slot = FTBSlotBundle.from_prefix("tailSlot_")
class BranchPredictionBundle(Bundle):
br_taken_mask_0, br_taken_mask_1 = Signals(2)
class BranchPredictReq(Bundle):
bits_s0_pc_0, bits_s0_pc_1, bits_s0_pc_2, bits_s0_pc_3 = Signals(4)
fh_tage = FoldedHistoryBundle.from_prefix("bits_folded_hist_1_")
fh_sc = FoldedHistoryBundle.from_prefix("bits_folded_hist_3_")
class BranchPredictionResp(Bundle):
last_stage_meta = Signal()
s2 = BranchPredictionBundle.from_prefix(r"s2_full_pred_3_")
s3 = BranchPredictionBundle.from_prefix(r"s3_full_pred_3_")
class BranchPredictionUpdate(Bundle):
pc, meta, br_taken_mask_0, br_taken_mask_1, mispred_mask_0, mispred_mask_1 = Signals(6)
ghist = Signal()
ftb_entry = FTBEntryBundle.from_prefix("ftb_entry_")
class UpdateBundle(Bundle):
valid = Signal()
bits = BranchPredictionUpdate.from_prefix("bits_")
from .port import *
from .internal import *

View File

@ -1,118 +1,104 @@
__all__ = ["get_coverage_group_of_tage_predict"]
from toffee.funcov import CovGroup
from comm import UT_FCOV
from dut.Tage_SC import DUTTage_SC
__all__ = ["get_coverage_group_of_tage_predict"]
from ut_frontend.bpu.tagesc.bundle.internal import StatusBundle
def is_ti_provider(way: int, ti: int):
def ti_provider(dut: DUTTage_SC) -> bool:
provided = getattr(dut, f"Tage_SC_s2_provideds_{way}").value
provider = getattr(dut, f"Tage_SC_s2_providers_{way}").value
return dut.io_s1_ready.value and dut.io_s2_fire_1.value and provided and provider == ti
def ti_provider(status: StatusBundle) -> bool:
s2_internal = status.internal.s2
return status.s2_valid(1) and s2_internal.provided(way) and s2_internal.provider(way) == ti
return ti_provider
def is_hit_no_table(way: int):
def hit_no_table(dut: DUTTage_SC) -> bool:
provided = getattr(dut, f"Tage_SC_s2_provideds_{way}").value
return dut.io_s1_ready.value != 0 and dut.io_s2_fire_1.value != 0 and provided == 0
def hit_no_table(status: StatusBundle) -> bool:
s2_internal = status.internal.s2
return status.s2_valid(1) and (not s2_internal.provided(way))
return hit_no_table
def is_all_slots_the_same_provider(dut: DUTTage_SC) -> bool:
provided_0 = dut.Tage_SC_s2_provideds_0.value
provided_1 = dut.Tage_SC_s2_provideds_1.value
valid = provided_0 and provided_1
provider_0 = dut.Tage_SC_s2_providers_0.value
provider_1 = dut.Tage_SC_s2_providers_1.value
return dut.io_s1_ready.value and dut.io_s2_fire_1.value and valid and provider_0 == provider_1
def is_all_slots_the_same_provider(status: StatusBundle) -> bool:
valid = all(status.internal.s2.provided(w) for w in range(2))
provider = status.internal.s2.provider
return status.s2_valid(1) and valid and provider(0) == provider(1)
def is_hit_multiple_tables(way: int):
def hit_multiple_tables(dut: DUTTage_SC) -> bool:
provided = getattr(dut, f"Tage_SC_s2_provideds_{way}").value
count = sum([getattr(dut, f"Tage_SC_tables_{i}_io_resps_{way}_valid").value for i in range(4)])
return dut.io_s1_ready.value and dut.io_s2_fire_1.value and provided and count > 1
def hit_multiple_tables(status: StatusBundle) -> bool:
provided = status.internal.s2.provided(way)
count = status.internal.tage_table.hit_count(way)
return status.s2_valid(1) and provided and count > 1
return hit_multiple_tables
def is_ti_unconf_provider(way: int, t_i: int, use_alt: int):
def ti_unconf_provider(dut: DUTTage_SC) -> bool:
provided = getattr(dut, f"Tage_SC_s2_provideds_{way}").value
provider = getattr(dut, f"Tage_SC_s2_providers_{way}").value
unconfident = getattr(dut, f"Tage_SC_s2_providerResps_{way}_ctr").value in {0b011, 0b100}
alt_used = getattr(dut, f"Tage_SC_s2_altUsed_{way}").value
return (dut.io_s1_ready.value and dut.io_s2_fire_1.value and provided and provider == t_i
and unconfident and alt_used == use_alt)
def ti_unconf_provider(status: StatusBundle) -> bool:
provided = status.internal.s2.provided(way)
provider = status.internal.s2.provider(way)
unconfident = status.internal.s2.provider_weak(way)
alt_used = status.internal.s2.alt_used(way)
return status.s2_valid(1) and provided and provider == t_i and unconfident and alt_used == use_alt
return ti_unconf_provider
def is_provider_unconf_and_multiple_hit(way: int, use_alt: int):
def provider_unconf_and_multiple_hit(dut: DUTTage_SC) -> bool:
provided = getattr(dut, f"Tage_SC_s2_provideds_{way}").value
# provider = getattr(dut, f"Tage_SC_s2_providers_{way}")
unconfident = getattr(dut, f"Tage_SC_s2_providerResps_{way}_ctr").value in {0b011, 0b100}
alt_used = getattr(dut, f"Tage_SC_s2_altUsed_{way}").value
count = sum([getattr(dut, f"Tage_SC_tables_{i}_io_resps_{way}_valid").value for i in range(4)])
return (dut.io_s1_ready.value and dut.io_s2_fire_1.value and provided and count > 0
and unconfident and alt_used == use_alt)
def provider_unconf_and_multiple_hit(status: StatusBundle) -> bool:
provided = status.internal.s2.provided(way)
unconfident = status.internal.s2.provider_weak(way)
alt_used = status.internal.s2.alt_used(way)
count = status.internal.tage_table.hit_count(way)
return status.s2_valid(1) and provided and count > 1 and unconfident and alt_used == use_alt
return provider_unconf_and_multiple_hit
def is_all_slots_use_same_unconf_provider_and_both(use_alt: int):
def all_slots_use_same_unconf_provider(dut: DUTTage_SC) -> bool:
provided_0 = dut.Tage_SC_s2_provideds_0.value
provided_1 = dut.Tage_SC_s2_provideds_1.value
provider_0 = dut.Tage_SC_s2_providers_0.value
provider_1 = dut.Tage_SC_s2_providers_1.value
alt_used_0 = dut.Tage_SC_s2_altUsed_0.value
alt_used_1 = dut.Tage_SC_s2_altUsed_1.value
valid = provided_0 and provided_1 and alt_used_0 and alt_used_1
return dut.io_s1_ready.value and dut.io_s2_fire_1.value and valid and (provider_0 == provider_1)
def all_slots_use_same_unconf_provider(status: StatusBundle) -> bool:
s2 = status.internal.s2
provider = s2.provider
valid = all([s2.provided(w) and s2.alt_used(w) for w in range(2)])
return status.s2_valid(1) and valid and (provider(0) == provider(1))
return all_slots_use_same_unconf_provider
def get_coverage_group_of_tage_predict(dut: DUTTage_SC) -> CovGroup:
def get_coverage_group_of_tage_predict(status: StatusBundle) -> CovGroup:
slot_name = ["br_slot_0", "tail_slot"]
group = CovGroup(UT_FCOV("../UT_Tage_SC"))
# Tn is provider
group.add_watch_point(dut, {
group.add_watch_point(status, {
"_".join([f"T{i}", "provider", slot_name[w]]): is_ti_provider(w, i) for i in range(4) for w in range(2)
}, name="Tn is Provider")
group.add_watch_point(dut, {
group.add_watch_point(status, {
"_".join([slot_name[w], "miss"]): is_hit_no_table(w) for w in range(2)
}, name="All Tn Miss")
# Multi tables hit
group.add_watch_point(dut, {
group.add_watch_point(status, {
slot_name[w]: is_hit_multiple_tables(w) for w in range(2)
}, name="Multi Tables Hit")
# All slots miss all tables
group.add_watch_point(
dut, {"no_slot_hits": is_hit_no_table(w) for w in range(2)}, name="No Slot Hits"
status, {"no_slot_hits": is_hit_no_table(w) for w in range(2)}, name="No Slot Hits"
)
# All slots are the same provider
group.add_watch_point(
dut, {"same_provider": is_all_slots_the_same_provider},
status, {"same_provider": is_all_slots_the_same_provider},
name="All Slots use the Same Provider"
)
# Tn is unconfident provider and use/doesn't use alt
alt_use_str = ["NOT use_alt", "use_alt"]
for use_alt in range(2):
group.add_watch_point(
dut,
status,
{slot_name[w]: is_ti_unconf_provider(w, i, use_alt) for i in range(4) for w in range(2)},
name=" ".join(["Tn is Unconfident Provider and ", alt_use_str[use_alt]]),
)
@ -120,7 +106,7 @@ def get_coverage_group_of_tage_predict(dut: DUTTage_SC) -> CovGroup:
for use_alt in range(2):
point_name = f"Multiple Tables Hit&Provider is Unconf and {alt_use_str[use_alt]}"
group.add_watch_point(
dut,
status,
{slot_name[w]: is_provider_unconf_and_multiple_hit(w, use_alt) for w in range(2)},
name=point_name
)
@ -129,7 +115,7 @@ def get_coverage_group_of_tage_predict(dut: DUTTage_SC) -> CovGroup:
for use_alt in range(2):
point_name = f"All Slots Use the Same Unconfident Provider and {alt_use_str[use_alt]}"
group.add_watch_point(
dut,
status,
{"valid": is_all_slots_use_same_unconf_provider_and_both(use_alt)},
name=point_name
)

View File

@ -1,11 +1,11 @@
__all__ = ["get_coverage_group_of_tage_train"]
from toffee.funcov import CovGroup
from comm import UT_FCOV
from dut.Tage_SC import DUTTage_SC
from ..bundle.internal import StatusBundle
from ..util.meta_parser import MetaParser
__all__ = ["get_coverage_group_of_tage_train"]
slot_name = ["br_slot_0", "tail_slot"]
@ -14,112 +14,101 @@ def get_idx(pc: int, way: int):
def is_update_t0_saturing_ctr(way: int, up_or_down: int):
def update_t0_saturing(dut: DUTTage_SC) -> bool:
def update_t0_saturing(status: StatusBundle) -> bool:
v = 0b11 if up_or_down else 0
w_idx = get_idx(dut.io_update_bits_pc.value, way)
valid = dut.io_s1_ready.value and dut.Tage_SC_bt_bt_io_w_req_valid.value \
and ((dut.Tage_SC_bt_bt_io_w_req_bits_waymask.value >> w_idx) & 1)
old_ctr = getattr(dut, f"Tage_SC_bt_oldCtrs_{way}").value
new_ctr = getattr(dut, f"Tage_SC_bt_newCtrs_{way}").value
taken = getattr(dut, f"Tage_SC_bt_io_update_takens_{w_idx}").value
return valid and new_ctr == v and old_ctr == v and (taken == up_or_down)
pc = status.update.bits.pc.value
base_table = status.internal.base_table
valid = status.pipline.s1_ready.value and base_table.write_valid() \
and base_table.write_mask(pc, way)
old_ctr = base_table.old_ctr(way)
new_ctr = base_table.new_ctr(way)
update_taken = base_table.update_taken(pc, way)
return valid and new_ctr == v and old_ctr == v and (update_taken == up_or_down)
return update_t0_saturing
def is_update_tn_saturing_ctr(way: int, t_i: int, up_or_down: int):
def update_tn_saturing(dut: DUTTage_SC) -> bool:
for b in range(4):
silent = getattr(dut, f"Tage_SC_tables_{t_i}_per_bank_not_silent_update_{b}_{way}").value == 0
w_idx = get_idx(dut.io_update_bits_pc.value, way)
update_mask = getattr(dut, f"Tage_SC_tables_{t_i}_io_update_mask_{w_idx}").value != 0
valid = dut.io_s1_ready.value and update_mask
taken = getattr(dut, f"Tage_SC_tables_{t_i}_io_update_takens_{w_idx}").value
if valid and silent and (taken == up_or_down):
return True
return False
def is_update_tn_saturing_ctr(way: int, ti: int, up_or_down: int):
def update_tn_saturing(status: StatusBundle) -> bool:
pc = status.update.bits.pc.value
tage_table = status.internal.tage_table
has_silent = tage_table.has_silent(ti, way)
mask = tage_table.get_table(ti).update_mask(pc, way)
valid = status.pipline.s1_ready.value and mask
taken = tage_table.get_table(ti).update_taken(pc, way)
return valid and has_silent and (taken == up_or_down)
return update_tn_saturing
def is_allocate_new_entry(way: int, except_success_or_failure: int):
"""
#WARNING: 目前的判断逻辑还是按照Chisel代码进行的, 所以可用表项信息失效的bug依旧存在.
"""
need_to_allocates = ["Tage_SC_needToAllocate", "Tage_SC_needToAllocate_1"]
def allocate_new_entry(dut: DUTTage_SC) -> bool:
valid = getattr(dut, f"Tage_SC_updateValids_{way}").value and dut.io_update_valid.value
need_to_allocate = getattr(dut, need_to_allocates[way]).value
with MetaParser(dut.io_update_bits_meta.value) as meta_parser:
# WARNING: 目前的判断逻辑还是按照Chisel代码进行的, 所以可用表项信息失效的bug依旧存在.
def allocate_new_entry(status: StatusBundle) -> bool:
valid = status.internal.update.valid(way) and status.update.valid.value and status.pipline.s1_ready.value
need_to_allocate = status.internal.need_to_allocate(way)
with MetaParser(status.update.bits.meta.value) as meta_parser:
allocatable_count = sum([x.value for x in meta_parser.allocates])
return dut.io_s1_ready.value and valid and need_to_allocate \
return valid and need_to_allocate \
and ((allocatable_count > 0) if except_success_or_failure else (allocatable_count == 0))
return allocate_new_entry
def is_allocate_as_provider_predict_incorrectly(way: int):
def allocate_as_provider(dut: DUTTage_SC) -> bool:
with MetaParser(dut.io_update_bits_meta.value) as meta_parser:
incorrect = getattr(dut, "Tage_SC_updateProviderCorrect" + ("_1" if way else "")).value == 0
valid = dut.io_s1_ready.value and dut.io_update_valid.value and meta_parser.providers_valid[
way].value and incorrect
def allocate_as_provider(status: StatusBundle) -> bool:
with MetaParser(status.update.bits.meta.value) as meta_parser:
incorrect = not status.internal.update.provider_correct(way)
valid = status.pipline.s1_ready.value and status.update.valid.value \
and meta_parser.providers_valid[way].value and incorrect
return valid
return allocate_as_provider
def is_update_predict_from_tagged(way: int):
def update_predict_from_tagged(dut: DUTTage_SC) -> bool:
with MetaParser(dut.io_update_bits_meta.value) as meta_parser:
valid = getattr(dut, f"Tage_SC_updateValids_{way}").value and dut.io_update_valid.value
def update_predict_from_tagged(status: StatusBundle) -> bool:
with MetaParser(status.update.bits.meta.value) as meta_parser:
valid = status.internal.update.valid(way) and status.update.valid.value
provided = meta_parser.providers_valid[way].value
alt_used = meta_parser.altUsed[way].value
return valid and provided and not alt_used
return update_predict_from_tagged
def is_update_use_alt_on_na_ctrs(way: int):
def update_use_alt_on_na_ctrs(dut: DUTTage_SC) -> bool:
with MetaParser(dut.io_update_bits_meta.value) as meta_parser:
valid = getattr(dut, f"Tage_SC_updateValids_{way}").value and dut.io_s1_ready.value
def update_use_alt_on_na_ctrs(status: StatusBundle) -> bool:
with MetaParser(status.update.bits.meta.value) as meta_parser:
valid = status.internal.update.valid(way) and status.update.valid.value
provided = meta_parser.providers_valid[way].value
weak = meta_parser.providerResps_ctr[way].value in {0b100, 0b011}
alt_diff = (meta_parser.basecnts[way].value >= 0b10) != (meta_parser.providerResps_ctr[way].value >= 0b100)
return valid and provided and weak and alt_diff
return update_use_alt_on_na_ctrs
def is_reset_us(way: int):
def reset_us(dut: DUTTage_SC) -> bool:
valid = dut.io_s1_ready.value != 0
bank_tick_ctr = getattr(dut, f"Tage_SC_bankTickCtrs_{way}").value
reset_u = getattr(dut, f"Tage_SC_updateResetU_{way}").value != 0
def reset_us(status: StatusBundle) -> bool:
valid = status.pipline.s1_ready.value
bank_tick_ctr = status.internal.bank_tick_ctr(way)
reset_u = status.internal.update.reset_u(way)
return valid and reset_u and bank_tick_ctr == 0x7f
return reset_us
def is_update_always_taken(way: int):
def update_always_taken(dut: DUTTage_SC) -> bool:
always_taken = getattr(dut, f"io_update_bits_ftb_entry_always_taken_{way}").value != 0
return dut.io_s1_ready.value != 0 and dut.io_update_valid.value != 0 and always_taken
def update_always_taken(status: StatusBundle) -> bool:
always_taken = getattr(status.update.bits.ftb_entry, f"always_taken_{way}").value
valid = status.pipline.s1_ready.value and status.update.valid.value
return valid and always_taken
return update_always_taken
def get_coverage_group_of_tage_train(dut: DUTTage_SC) -> CovGroup:
def get_coverage_group_of_tage_train(status: StatusBundle) -> CovGroup:
g = CovGroup(UT_FCOV("../UT_Tage_SC"))
# T0 up/down saturing update
for up_or_down in range(2):
s = "up saturing" if up_or_down else "down saturing"
g.add_watch_point(
dut,
status,
{slot_name[w]: is_update_t0_saturing_ctr(w, up_or_down) for w in range(2)},
name=" ".join(["T0", s.capitalize()])
)
@ -127,7 +116,7 @@ def get_coverage_group_of_tage_train(dut: DUTTage_SC) -> CovGroup:
for up_or_down in range(2):
s = "up saturing" if up_or_down else "down saturing"
g.add_watch_point(
dut,
status,
{"_".join([f"T{i}", slot_name[w]]): is_update_tn_saturing_ctr(w, i, up_or_down) for i in range(4) for w in
range(2)},
name=" ".join(["Tn", s.capitalize()])
@ -146,27 +135,26 @@ def get_coverage_group_of_tage_train(dut: DUTTage_SC) -> CovGroup:
alloc_as_provider_mis_pred[f"{slot_name[w]} provider incorrect"] \
= is_allocate_as_provider_predict_incorrectly(w)
g.add_watch_point(dut, alloc, name="Tn Allocate " + cond)
g.add_watch_point(dut, alloc_as_provider_mis_pred, name="Tn Allocate As Provider MisPredict " + cond)
g.add_watch_point(status, alloc, name="Tn Allocate " + cond)
g.add_watch_point(status, alloc_as_provider_mis_pred, name="Tn Allocate As Provider MisPredict " + cond)
# Reset useful counter
g.add_watch_point(dut, {slot_name[w]: is_reset_us(w) for w in range(2)}, name="Reset us")
g.add_watch_point(status, {slot_name[w]: is_reset_us(w) for w in range(2)}, name="Reset us")
# Train Information's `always_taken` Bit is True
g.add_watch_point(dut, {slot_name[w]: is_update_always_taken(w) for w in range(2)}, name="Always Taken is True")
g.add_watch_point(status, {slot_name[w]: is_update_always_taken(w) for w in range(2)}, name="Always Taken is True")
g.add_watch_point(
dut,
status,
{
slot_name[0]: lambda d: d.Tage_SC_updateValids_0.value and d.io_s0_fire_1.value,
slot_name[1]: lambda d: d.Tage_SC_updateValids_1.value and d.io_s0_fire_1.value,
slot_name[0]: lambda d: d.internal.update.valid(0) and d.pipline.s0_fire_1.value,
slot_name[1]: lambda d: d.internal.update.valid(1) and d.pipline.s0_fire_1.value,
},
name="Update When Predict"
)
# useAltOnNaCtrs update
g.add_watch_point(
dut,
status,
{"_".join([slot_name[w], "useAltOnNaCtrs", "update"]): is_update_use_alt_on_na_ctrs(w) for w in range(2)},
name="Update useAltOnNaCtrs"
)

View File

@ -8,6 +8,7 @@ from dut.Tage_SC import DUTTage_SC
from .checkpoints_sc_predict import get_coverage_group_of_sc_predict
from .checkpoints_tage_predict import get_coverage_group_of_tage_predict
from .checkpoints_tage_train import get_coverage_group_of_tage_train
from ..bundle.internal import StatusBundle
from ..env.fake_global_history import TageSCFakeGlobalHistory
from ..env.tage_sc_env import TageSCEnv
@ -37,9 +38,10 @@ async def test_random(tage_sc_env: TageSCEnv, pc_bound: int):
async def tage_sc_env(toffee_request: toffee_test.ToffeeRequest):
import asyncio
dut = toffee_request.create_dut(DUTTage_SC, "clock")
status = StatusBundle.from_prefix("").bind(dut)
toffee_request.add_cov_groups([
get_coverage_group_of_tage_predict(dut),
get_coverage_group_of_tage_train(dut),
get_coverage_group_of_tage_predict(status),
get_coverage_group_of_tage_train(status),
get_coverage_group_of_sc_predict(dut),
])
toffee.start_clock(dut)

View File

@ -6,15 +6,16 @@ from .checkpoints_sc_predict import get_coverage_group_of_sc_predict
from .checkpoints_sc_train import get_coverage_group_of_sc_train
from .checkpoints_tage_predict import get_coverage_group_of_tage_predict
from .checkpoints_tage_train import get_coverage_group_of_tage_train
from ..bundle.internal import StatusBundle
from ..env.tage_sc_env import TageSCEnv
from ..util.meta_parser import MetaParser
@toffee_test.testcase
async def test_tage_tn_saturing_ctr_update(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_tage_tn_saturing_ctr_update(test_env: TageSCEnv):
env = test_env
await env.reset_dut()
await tage_sc_dut.AStep(1)
await test_env.__dut__.AStep(1)
pc = 0x80000002
with MetaParser(0) as parser:
for x in parser.providers_valid:
@ -28,7 +29,7 @@ async def test_tage_tn_saturing_ctr_update(tage_sc_dut: DUTTage_SC):
x.value = ti
await env.train_agent.exec_update(pc, 1, 1, 1, parser.value, 0, 0, 0, 1, 1, 0, 0)
for w in range(2):
assert getattr(tage_sc_dut, f"Tage_SC_tables_{ti}_per_bank_update_wdata_0_{w}_ctr").value == 0, \
assert getattr(test_env.__dut__, f"Tage_SC_tables_{ti}_per_bank_update_wdata_0_{w}_ctr").value == 0, \
f"TageTable{ti} down saturation-update failed!"
# ctr up saturing
@ -40,21 +41,21 @@ async def test_tage_tn_saturing_ctr_update(tage_sc_dut: DUTTage_SC):
for x in parser.providers:
x.value = ti
await env.train_agent.exec_update(pc, w, 1, 1, parser.value, 0, w, 1, 1, 1, 0, 0)
assert getattr(tage_sc_dut, f"Tage_SC_tables_{ti}_per_bank_update_wdata_0_{w}_ctr").value == 0b111, \
assert getattr(test_env.__dut__, f"Tage_SC_tables_{ti}_per_bank_update_wdata_0_{w}_ctr").value == 0b111, \
f"TageTable{ti} up saturation-update failed!"
@toffee_test.testcase
async def test_bank_tick_ctrs(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_bank_tick_ctrs(test_env: TageSCEnv):
env = test_env
async def expect_reset_u(way: int):
await tage_sc_dut.AStep(1)
assert getattr(tage_sc_dut, f"Tage_SC_updateResetU_{way}").value == 1, "ResetU should be high!"
await test_env.__dut__.AStep(1)
assert getattr(test_env.__dut__, f"Tage_SC_updateResetU_{way}").value == 1, "ResetU should be high!"
##### Test Code Start #####
await env.reset_dut()
await tage_sc_dut.AStep(1)
await test_env.__dut__.AStep(1)
pc = 0x80000002
with MetaParser(0) as parser:
for x in parser.allocates:
@ -75,13 +76,13 @@ async def test_bank_tick_ctrs(tage_sc_dut: DUTTage_SC):
x.value = 0xf
for w in range(2):
await env.train_agent.exec_update(pc, w, 1, 1, parser.value, 2, w, 1, 1, 1, 0, 0)
bank_tick_ctrs = [getattr(tage_sc_dut, f"Tage_SC_bankTickCtrs_{w}").value for w in range(2)]
bank_tick_ctrs = [getattr(test_env.__dut__, f"Tage_SC_bankTickCtrs_{w}").value for w in range(2)]
assert sum(bank_tick_ctrs) == 0, "BankTickCtrs is not down saturation update"
@toffee_test.testcase
async def test_tage_alt_predict_keep_true_and_false(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_tage_alt_predict_keep_true_and_false(test_env: TageSCEnv):
env = test_env
await env.reset_dut()
# Alt prediction is false, provider is true
with MetaParser(0) as parser:
@ -100,7 +101,7 @@ async def test_tage_alt_predict_keep_true_and_false(tage_sc_dut: DUTTage_SC):
await env.train_agent.exec_update(i * 2, 1, 1, 1, parser.value, 0, 0, 0, 1, 1, 0, 0)
for w in range(2):
for i in range(128):
ctr_val = getattr(tage_sc_dut, f"Tage_SC_useAltOnNaCtrs_{w}_{i}").value
ctr_val = getattr(test_env.__dut__, f"Tage_SC_useAltOnNaCtrs_{w}_{i}").value
assert ctr_val == 0xf, f"useAltOnNaCtrs_{w}_{i} should be 0xf!"
# Alt prediction is true, provider is false
for x in parser.basecnts:
@ -112,17 +113,17 @@ async def test_tage_alt_predict_keep_true_and_false(tage_sc_dut: DUTTage_SC):
await env.train_agent.exec_update(i * 2, 1, 1, 1, parser.value, 0, 0, 0, 1, 1, 0, 0)
for w in range(2):
for i in range(128):
ctr_val = getattr(tage_sc_dut, f"Tage_SC_useAltOnNaCtrs_{w}_{i}").value
ctr_val = getattr(test_env.__dut__, f"Tage_SC_useAltOnNaCtrs_{w}_{i}").value
assert ctr_val == 0, f"useAltOnNaCtrs_{w}_{i} should be 0!"
@toffee_test.testcase
async def test_sc_threshold_saturation_update(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_sc_threshold_saturation_update(test_env: TageSCEnv):
env = test_env
await env.reset_dut()
pc = 0x80000004
ctrs = [getattr(tage_sc_dut, f"Tage_SC_scThresholds_{i}_ctr") for i in range(2)]
thresholds = [getattr(tage_sc_dut, f"Tage_SC_scThresholds_{i}_thres") for i in range(2)]
ctrs = [getattr(test_env.__dut__, f"Tage_SC_scThresholds_{i}_ctr") for i in range(2)]
thresholds = [getattr(test_env.__dut__, f"Tage_SC_scThresholds_{i}_thres") for i in range(2)]
with MetaParser(0) as parser:
for x in parser.sc_ctrs:
for y in x[1:]:
@ -170,8 +171,8 @@ async def test_sc_threshold_saturation_update(tage_sc_dut: DUTTage_SC):
@toffee_test.testcase
async def test_sc_table_saturation(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_sc_table_saturation(test_env: TageSCEnv):
env = test_env
await env.reset_dut()
pc = 0x1919810
# SC Table down saturation update
@ -191,7 +192,7 @@ async def test_sc_table_saturation(tage_sc_dut: DUTTage_SC):
await env.train_agent.exec_update(pc, 1, 1, 1, parser.value, 2, 0, 0, 1, 1, 0, 0)
for i in range(4):
for w in range(2):
update_write_val = getattr(tage_sc_dut, f"Tage_SC_scTables_{i}_update_wdata_{w}").S() # read as signed
update_write_val = getattr(test_env.__dut__, f"Tage_SC_scTables_{i}_update_wdata_{w}").S() # read as signed
assert update_write_val == -32, f"Slot{w} of SC Table{i} is not signed down saturation update"
# SC Table up saturation update
@ -213,18 +214,18 @@ async def test_sc_table_saturation(tage_sc_dut: DUTTage_SC):
for i in range(4):
for w in range(2):
update_write_val = getattr(tage_sc_dut, f"Tage_SC_scTables_{i}_update_wdata_{w}").S() # read as signed
update_write_val = getattr(test_env.__dut__, f"Tage_SC_scTables_{i}_update_wdata_{w}").S() # read as signed
assert update_write_val == 31, f"Slot{w} of SC Table{i} is not signed up saturation update"
@toffee_test.testcase
async def test_sc_total_sum_correctness(tage_sc_dut: DUTTage_SC):
async def test_sc_total_sum_correctness(test_env: TageSCEnv):
def get_total_sum(sc_sum: int, tage_ctr: int):
sc_ctr_sum = sc_sum * 2 + 4
tage_ctr_centered = ((tage_ctr - 4) * 2 + 1) * 8
return sc_ctr_sum + tage_ctr_centered
env = TageSCEnv(tage_sc_dut)
env = test_env
##### Test Code Start #####
await env.reset_dut()
pc = 0x80000000
@ -242,9 +243,9 @@ async def test_sc_total_sum_correctness(tage_sc_dut: DUTTage_SC):
update_tage_ctr = parser.providerResps_ctr
sc_table_sum = sum([parser.sc_ctrs[w][i].S() for i in range(4)])
total_sum_attr = "Tage_SC_sumAboveThreshold_totalSum" + ("_1" if w else "")
real_val_xdata = getattr(tage_sc_dut, total_sum_attr)
real_val_xdata = getattr(test_env.__dut__, total_sum_attr)
expect_val = get_total_sum(sc_table_sum, update_tage_ctr[w].value)
await tage_sc_dut.AStep(1)
await test_env.__dut__.AStep(1)
assert expect_val == real_val_xdata.S(), "TotalSum in train is not correct"
async with toffee.Executor() as _exec:
@ -255,15 +256,15 @@ async def test_sc_total_sum_correctness(tage_sc_dut: DUTTage_SC):
# Test total sum of predict
async def assert_predict_total_sum(w: int):
_suffix = "_1" if w else ""
tage = getattr(tage_sc_dut, f"Tage_SC_s2_tagePrvdCtrCentered_r" + _suffix).value
tage = getattr(test_env.__dut__, f"Tage_SC_s2_tagePrvdCtrCentered_r" + _suffix).value
tage_centered = ((tage - 4) * 2 + 1) * 8
high_sc_sum = getattr(tage_sc_dut, f"Tage_SC_s2_scTableSums{_suffix}_1").S()
low_sc_sum = getattr(tage_sc_dut, f"Tage_SC_s2_scTableSums{_suffix}_0").S()
high_sc_sum = getattr(test_env.__dut__, f"Tage_SC_s2_scTableSums{_suffix}_1").S()
low_sc_sum = getattr(test_env.__dut__, f"Tage_SC_s2_scTableSums{_suffix}_0").S()
expect_high = high_sc_sum + tage_centered
expect_low = low_sc_sum + tage_centered
real_high = getattr(tage_sc_dut, "Tage_SC_s2_totalSums_1" + _suffix)
real_low = getattr(tage_sc_dut, "Tage_SC_s2_totalSums_0" + _suffix)
await tage_sc_dut.AStep(1)
real_high = getattr(test_env.__dut__, "Tage_SC_s2_totalSums_1" + _suffix)
real_low = getattr(test_env.__dut__, "Tage_SC_s2_totalSums_0" + _suffix)
await test_env.__dut__.AStep(1)
assert expect_high == real_high.S() and expect_low == real_low.S(), "TotalSum in predict is not correct"
async with toffee.Executor() as _exec:
@ -273,8 +274,8 @@ async def test_sc_total_sum_correctness(tage_sc_dut: DUTTage_SC):
@toffee_test.testcase
async def test_update_when_predict(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_update_when_predict(test_env: TageSCEnv):
env = test_env
await env.reset_dut()
async with toffee.Executor() as _exec:
_exec(env.predict_agent.exec_predict(0x114514, 1))
@ -289,8 +290,8 @@ async def test_update_when_predict(tage_sc_dut: DUTTage_SC):
@toffee_test.testcase
async def test_always_taken(tage_sc_dut: DUTTage_SC):
env = TageSCEnv(tage_sc_dut)
async def test_always_taken(test_env: TageSCEnv):
env = test_env
pc = 0x800013
await env.reset_dut()
@ -300,24 +301,25 @@ async def test_always_taken(tage_sc_dut: DUTTage_SC):
async with toffee.Executor() as _exec:
_exec(env.ctrl_agent.exec_activate())
_exec(env.predict_agent.exec_predict(pc, 1))
await tage_sc_dut.AStep(1)
await test_env.__dut__.AStep(1)
s3 = env.predict_agent.io_out.s3
assert (s3.br_taken_mask_1.value, s3.br_taken_mask_0.value) == (1, 1), "Predict result should be true"
@toffee_test.fixture
async def tage_sc_dut(toffee_request: toffee_test.ToffeeRequest):
async def test_env(toffee_request: toffee_test.ToffeeRequest):
import asyncio
dut = toffee_request.create_dut(DUTTage_SC, "clock")
status = StatusBundle.from_prefix("").bind(dut)
toffee_request.add_cov_groups([
get_coverage_group_of_tage_predict(dut),
get_coverage_group_of_tage_train(dut),
get_coverage_group_of_tage_predict(status),
get_coverage_group_of_tage_train(status),
get_coverage_group_of_sc_predict(dut),
get_coverage_group_of_sc_train(dut),
])
toffee.start_clock(dut)
yield dut
yield TageSCEnv(dut)
cur_loop = asyncio.get_event_loop()
for task in asyncio.all_tasks(cur_loop):