Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions scripts/build_ut_frontend_ftq_ftq_top.py
Original file line number Diff line number Diff line change
@@ -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"]
12 changes: 0 additions & 12 deletions scripts/build_ut_frontend_ftq_top.py

This file was deleted.

36 changes: 36 additions & 0 deletions ut_frontend/ftq/ftq_top/README.md
Original file line number Diff line number Diff line change
@@ -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%,模块功能符合设计预期。
Empty file.
13 changes: 13 additions & 0 deletions ut_frontend/ftq/ftq_top/env/__init__.py
Original file line number Diff line number Diff line change
@@ -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 作为实例属性
545 changes: 545 additions & 0 deletions ut_frontend/ftq/ftq_top/env/ftq_agent.py

Large diffs are not rendered by default.

174 changes: 174 additions & 0 deletions ut_frontend/ftq/ftq_top/env/ftq_bundle.py
Original file line number Diff line number Diff line change
@@ -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_")

Empty file.
74 changes: 74 additions & 0 deletions ut_frontend/ftq/ftq_top/ref/ftq_ref.py
Original file line number Diff line number Diff line change
@@ -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 = {}
Empty file.
Loading
Loading