Repository navigation
zh guides scoreboard
Scoreboard.check() 比较调用方提供的 expected/actual;异步模式则消费 driver 的接受通知和
monitor 的观察值,关联后复用同一比较入口。框架不定义握手、reset 或 flush 规则。
| 目的 | 接口 | 返回或结束条件 |
|---|---|---|
| 比较已经得到的两个值 | scoreboard.check(expected=..., actual=...) |
比较完成,无需绑定 Driver/Monitor |
| 等输入被接受 | await driver.send(request) |
返回接受事件,不等待响应 |
| 提交输入,不跟踪响应 | async_driver.send(request) |
立即返回 XTransfer,接受时自动完成,await 得到接受事件 |
| 提交并自动检查响应 | scoreboard.submit(request) |
立即返回 XTransfer,由 Scoreboard 关联并完成 |
| 自己处理响应 | driver.submit(request) |
返回 XTransfer,调用方负责关联并完成句柄 |
| 等一笔响应 |
await transfer(由 submit 返回) |
返回响应或抛出失败;提交一笔就等一笔会使场景串行 |
| 等当前批次,随后还要提交 | await scoreboard.drain(timeout_cycles=...) |
等调用前提交的事务,不代表严格结束 |
| 结束提交并检查 | await scoreboard.finish(timeout_cycles=..., observe_cycles=...) |
排空、有限观察、检查残余输入输出 |
| 退出或异常清理 | context manager / aclose()
|
检查当前状态并释放资源,不等待 DUT 排空 |
Transfer 是 Monitor 交付的观察记录;XTransfer 是跟踪接受与完成的句柄。
SyncDriver.send() 是 async 函数,其 Sync 表示调用方等待输入完成。
AsyncDriver.send() 和 submit() 都在调用时提交并立即返回句柄:前者等待接受,
后者等待响应;二者都不阻塞 Python event loop。“调用即提交”是 AsyncDriver 模板
及其子类的保证,不向 Driver/SignalDriver 基类或其他具体 Driver 强加后台执行能力。
input-only 句柄的接受就是完成,不需要伪造响应,也不进入 recv_accepted 流。 如果 DUT 实际会返回需要检查的响应,应通过 scoreboard.submit 跟踪;send 不会抑制 DUT 输出,也不会让 Scoreboard 忽略未匹配响应。
from toffee import Scoreboard
scoreboard = Scoreboard("prediction")
scoreboard.check(expected=wanted, actual=prediction)默认递归比较 dataclass、mapping、sequence、BundleValue 和标量。失败抛出
ScoreboardMismatch(AssertionError 子类),包含字段路径、期望、实际值和事务上下文。
默认差异只计算一次,最多保留 max_differences=20 项。可传入 compare(expected, actual)
函数或覆写 compare();自定义断言保留为异常 cause。
async with (
Execution(backend) as execution,
prediction_driver as driver,
Scoreboard(
"prediction", expected=lambda request, _: model.predict(request),
).bind(
execution, driver=driver, monitor=prediction_monitor,
clock=clock, response_timeout_cycles=20,
) as scoreboard,
):
for request in requests:
scoreboard.submit(request)
status = await scoreboard.finish(timeout_cycles=200, observe_cycles=2)多项 async with 按顺序进入、逆序退出,与逐层嵌套等价。重复的环境创建可以放入项目 自己的 pytest fixture 或 asynccontextmanager,测试仍显式选择 finish 的预算。 backend 由创建者关闭,见 Execution 与 Backend。
clock 和 response_timeout_cycles 必须显式传入。绑定要求当前活动的 Execution,
一个 Scoreboard 只绑定一次。Driver 只需提供 submit() 和 recv_accepted();Monitor
提供 start(execution)、recv()、aclose()。Scoreboard 独占 Monitor 的消费和启停;
Driver 的生命周期由外层 context manager 管理。
Agent 已在内部完成响应接线,普通用例只需 connect(ref)。
需要独立组合检查器和外部 Monitor 生命周期时,可传入 manage_monitor=False:
Scoreboard 独占消费,但不启动/关闭 Monitor,外层必须先启动它并在 Scoreboard 退出后关闭。
同一个 Monitor 不能同时由两个 Scoreboard 消费。默认 manage_monitor=True 保持原行为。
Monitor 在进入 Scoreboard context 或第一次提交时启动,跨提交批次保持运行,直到
aclose()。匹配完最后一笔事务不会停止监视,也不会调用 driver 的协议 idle/复位操作。
不使用 context manager 时,必须在 finally 中 await scoreboard.aclose()。
接受和观察事件都必须来自指定单 XClock 的 rising-stable phase。Monitor 应及时交付该 phase 的快照,不能在交付前等待任意 HTTP、wall delay 或未来仿真事件。周期预算以事件 的 half-tick 时间戳计算;框架在截止 rising phase 后的 falling 屏障检查缺失响应,暂停 推进并让就绪的 source consumer 处理完毕,因此截止周期内的正确响应优先于超时。
# 向量给出预期值;优先于 expected source。
transfer = scoreboard.submit(request, expected=wanted)
# 只有控制流需要结果时才等待;逐次等待会使激励串行化。
actual = await transferexpected source 在 accepted stream 被消费时调用,按 driver 的接受通知顺序更新模型;
CheckContext.accepted_event 保留实际接受时间。既没有显式 expected、也没有 source
时抛出 MissingExpectedError。提交后不要修改 request 或 expected 对象。
source 必须同步,异步函数或 awaitable 返回值会明确报错。显式 expected 会跳过 source, 直接使用此回调接有状态模型时不要混用覆盖值。Agent.connect(ref) 则独立更新模型, 不会因为覆盖 expected 而跳过状态推进;更新顺序、异常和多接口边界见 Agent 与 reference model。
XTransfer 的状态为 PENDING → PROCESSING → COMPLETED,失败进入 FAILED。
cancel() 只撤销 PENDING 请求;PROCESSING 请求已经被接受,调用 cancel 会报错,仍需
等待其响应或超时。取消等待 transfer 的协程不会取消事务,也不算观察过它的失败。
异常关闭时,已接受但未完成的事务进入 FAILED,而非 CANCELLED。
bind() 支持三种一对一关联:
- 默认 FIFO:按接受顺序关联有效响应。
-
request_key=...、response_key=...:按 key 关联,允许乱序完成;同时在途的重复 key 抛出ScoreboardAssociationError。 -
latency_cycles=N:仅匹配 accepted tick 后 N 个周期的观察,支持 N=0;错过该周期 也会主动超时,而非一直缓存迟到结果。N 不得超过 response timeout。
默认把每笔观察当作有效响应;额外、重复或无法关联的输出在严格结束检查时失败。
如果 monitor 每个周期都发布样本、包含空闲值,显式设置
latency_cycles=N, sampled=True,只检查目标窗口内的样本,忽略窗口外的值。
sampled=True 不能单独使用,也不能与 key 匹配组合。
特殊关联可以覆写同步、无副作用的 associate(observation, pending):返回其中一项表示
匹配,返回 None 暂存观察,等待更多接受通知。它不运行参考模型、不比较数据、不等待事件。
这也允许观察先进入 Python 队列、对应的 accepted 通知随后到达。
| 预算 | 从何时开始 | 覆盖范围 |
|---|---|---|
response_timeout_cycles |
每笔输入被接受时 | 该事务的响应;固定延迟模式实际以 latency_cycles 为截止窗口 |
drain/finish(timeout_cycles=...) |
本次方法调用时 | 排空,包括等待尚未接受的输入;finish 还包含 observe_cycles |
asyncio.timeout(seconds) |
进入该 context 时 | 墙钟总时间,由调用方按测试环境选择 |
周期预算必须显式给出,框架不猜测 DUT 的合理延迟。
-
await drain(timeout_cycles=N)等待调用前的提交 watermark,后续新提交不扩大此次等待。 已接受请求另受 response timeout 约束;drain 的预算也覆盖尚未被接受的输入。 -
await finish(timeout_cycles=N, observe_cycles=M)封闭提交、排空、继续观察 M 个周期, 然后检查事务守恒。M 默认 0;总预算包含排空和观察窗口。finish 后不能再提交。 -
await aclose()不等待 DUT 排空;它处理已经就绪的通知、检查当前状态并关闭任务和 Monitor。未完成请求报ScoreboardIncompleteError,未匹配输出报ScoreboardAssociationError。它不是 finish 的无限等待版本。
ScoreboardTimeoutError 同时继承 ScoreboardError 和 TimeoutError。消息区分响应、
固定延迟、drain 和 finish 预算;finish 的排空阶段失败也标记为 finish。
无需解析消息,可直接读取以下属性:
| 属性 | 含义 |
|---|---|
name, operation
|
Scoreboard 名称;operation 为 response / fixed_latency / drain / finish |
budget_cycles, elapsed_cycles
|
此次生效的周期预算与已过时间,后者可含半周期 |
start_tick, deadline_tick, current_tick
|
起始、截止和发现超时的 half-tick(迟到响应使用观察 tick) |
context |
响应失败的 CheckContext,包含 sequence_id、request、accepted_event;总预算失败为 None |
status |
失败发生时的统计快照 |
reason |
截止时间已过,或剩余预算不足以容纳结束观察窗口等原因 |
例如输入在 tick 20 接受,响应预算为 4 cycles,截止 tick 为 28;在 tick 29 的 falling 检查发现缺失时,elapsed_cycles 为 4.5。这包含了截止采样后的半周期检查屏障。 若结束观察窗口已无法放进剩余预算,会立即报错,elapsed_cycles 可能尚未达到预算。
后台错误可从 await transfer、drain、finish 或关闭到达 pytest;同一个已观察失败不在 关闭时重复报告。context 中已有异常时仍清理;独立清理异常和原始异常一起保留为异常组。
构造参数 capacity=64 分别限制活跃请求和未匹配观察数量,超限显式失败。
已完成事务从内部活跃表删除,统计累计保留;完整请求历史由调用方按需记录。
ScoreboardStatus 仅用于诊断,不替代 pytest verdict 或覆盖率。
可运行示例使用 MemoryBackend 和普通请求/响应队列,不需要 RTL 或任何握手协议:
python3 examples/transactions/scoreboard.py源码见 scoreboard.py。
连续输入、FIFO/固定延迟/乱序 key 匹配,以及漏响应、迟到与关联错误的可运行演示, 见流水输入与阶段重叠示例。
内容由 CI 自动同步;请编辑主仓库文档。 Automatically synced by CI; edit the source documentation.
- 首页
- 教程
- 操作指南
- 参考
- 原理说明
- Home
-
Tutorials
- Learning path
- 0. Prepare your environment
- 1. Your first PASS and FAIL
- 2. Inputs and clocks
- 3. More cases and boundaries
- 4. Extract a Driver
- 5. Delayed output and a Monitor
- 6. Assemble an Agent
- 7. Models and the test environment
- 8. Pipelines, batches, and cancellation
- 9. Understand failures
- 10. Functional coverage
- Optional: out-of-order responses
- Optional: native clocks and project DUTs
-
How-to guides
- Find your task
- Simulation and events
- Verification components
- Coverage and regressions
- Migration and maintenance
- Runnable examples
- Reference
- Explanation