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
4 changes: 2 additions & 2 deletions .github/native-dependencies.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"xcomm": {
"repository": "XS-MLVP/xcomm",
"ref": "c39db6652cd08d46df05d08f0bb5a033b83e4d2f",
"package_version": "0.3.0.dev3",
"ref": "69e993d4fc0c8786819d2beae50a2197ea4ab124",
"package_version": "1.1.0",
"native_abi": 3,
"coverage_protocol": 5
}
Expand Down
35 changes: 25 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,25 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends build-essential cmake ninja-build lcov verilator
python -m pip install 'swig>=4.2,<5' '.[test]'
- name: Install pinned native backend
run: python -m pip install ./_deps/xcomm
python -m pip install 'build>=1,<2'
- name: Build pinned native backend
# This wheel is reused by another runner during isolated installation.
run: python -m build --wheel ./_deps/xcomm --outdir native-wheel -Ccmake.define.XSPCOMM_NATIVE=OFF
env:
BUILD_XSPCOMM_SWIG: python
XSPCOMM_BUILD_WHEEL: "1"
CMAKE_BUILD_PARALLEL_LEVEL: "2"
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_XSPCOMM: ${{ steps.native.outputs.package_version }}
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_UC_XCOMM: ${{ steps.native.outputs.package_version }}
- name: Install Toffee with the pinned dependency
run: |
python -m pip install native-wheel/*.whl '.[test]'
python -m pip check
- uses: actions/upload-artifact@v4
if: matrix.python-version == '3.12'
with:
name: ${{ inputs.artifact-name || 'toffee-dist' }}-native-cp312
path: native-wheel/*.whl
if-no-files-found: error
- name: Require the tested package, native ABI and coverage protocol
env:
EXPECTED_PACKAGE_VERSION: ${{ steps.native.outputs.package_version }}
Expand All @@ -78,7 +89,7 @@ jobs:
python - <<'PY'
from importlib.metadata import version
import os, xspcomm
assert version('xspcomm') == os.environ['EXPECTED_PACKAGE_VERSION']
assert version('uc-xcomm') == os.environ['EXPECTED_PACKAGE_VERSION']
assert xspcomm.version() == os.environ['EXPECTED_PACKAGE_VERSION']
assert xspcomm.abi_version() == int(os.environ['EXPECTED_NATIVE_ABI'])
assert xspcomm.XTriggerEngine.CoverageVersion() == int(os.environ['EXPECTED_COVERAGE_PROTOCOL'])
Expand Down Expand Up @@ -111,7 +122,7 @@ jobs:
with:
python-version: "3.12"
cache: pip
- run: python -m pip install '.[docs]'
- run: python -m pip install 'mkdocs>=1.6'
- run: mkdocs build --strict

package:
Expand All @@ -137,18 +148,22 @@ jobs:
- name: Rebuild from the source distribution without Git metadata
run: |
mkdir -p "$RUNNER_TEMP/sdist-source" "$RUNNER_TEMP/sdist-wheel"
tar -xf dist/pytoffee-*.tar.gz -C "$RUNNER_TEMP/sdist-source"
source_dir=("$RUNNER_TEMP"/sdist-source/pytoffee-*)
tar -xf dist/uc_toffee-*.tar.gz -C "$RUNNER_TEMP/sdist-source"
source_dir=("$RUNNER_TEMP"/sdist-source/uc_toffee-*)
python -m build --wheel "${source_dir[0]}" --outdir "$RUNNER_TEMP/sdist-wheel"
original=(dist/*.whl)
rebuilt=("$RUNNER_TEMP"/sdist-wheel/*.whl)
test "$(basename "${original[0]}")" = "$(basename "${rebuilt[0]}")"
- uses: actions/download-artifact@v4
with:
name: ${{ inputs.artifact-name || 'toffee-dist' }}-native-cp312
path: native-wheel
- name: Install the wheel in an isolated environment
run: |
python -m venv "$RUNNER_TEMP/wheel-test"
"$RUNNER_TEMP/wheel-test/bin/python" -m pip install --no-index dist/*.whl
"$RUNNER_TEMP/wheel-test/bin/python" -m pip install --no-index --find-links=native-wheel dist/*.whl
"$RUNNER_TEMP/wheel-test/bin/python" -m pip check
"$RUNNER_TEMP/wheel-test/bin/python" -I -c 'from importlib.metadata import version; from importlib.resources import files; import toffee; assert files("toffee").joinpath("templates/unified_coverage.html").is_file(); print(version("pytoffee"), toffee.__file__)'
"$RUNNER_TEMP/wheel-test/bin/python" -I -c 'from importlib.metadata import version; from importlib.resources import files; import toffee; assert files("toffee").joinpath("templates/unified_coverage.html").is_file(); print(version("uc-toffee"), toffee.__file__)'
- name: Record exact tested build provenance
env:
EXPECTED_VERSION: ${{ inputs.expected-version }}
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,25 @@ jobs:
files: release-assets/*
fail_on_unmatched_files: true
overwrite_files: false

pypi:
needs: [resolve, publish]
runs-on: ubuntu-24.04
environment:
name: pypi
url: https://pypi.org/p/uc-toffee
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: release-dist-${{ needs.resolve.outputs.tag }}
path: verified-assets
- name: Select the verified Python distributions
run: |
mkdir dist
cp verified-assets/*.whl verified-assets/*.tar.gz dist/
- name: Publish with Trusted Publishing
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
10 changes: 9 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ Toffee 负责 Python API、仿真调度、验证组件和报告。

## 提交前检查

先安装开发依赖:
先准备 `uc-xcomm>=1.1,<2`,再安装开发依赖。开发跨仓库未发布修改时,
按 `.github/native-dependencies.json` 检出 xcomm 的固定提交,再运行:

```bash
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_UC_XCOMM=1.1.0 \
python3 -m pip install /path/to/xcomm
```

这里的版本覆盖仅用于本地和 CI 验证目标依赖范围,不发布该测试包。随后安装开发依赖:

```bash
python3 -m pip install -e '.[test,docs]'
Expand Down
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Toffee

[![PyPI](https://img.shields.io/pypi/v/uc-toffee?style=flat-square&logo=pypi&logoColor=white)](https://pypi.org/project/uc-toffee/)
[![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12-blue?style=flat-square&logo=python&logoColor=white)](https://github.com/XS-MLVP/toffee/blob/main/docs/getting-started/installation.md)
[![CI](https://img.shields.io/github/actions/workflow/status/XS-MLVP/toffee/ci.yml?branch=main&style=flat-square&label=CI&logo=github)](https://github.com/XS-MLVP/toffee/actions/workflows/ci.yml?query=branch%3Amain)
[![License](https://img.shields.io/badge/license-MulanPSL--2.0-blue?style=flat-square)](https://github.com/XS-MLVP/toffee/blob/main/LICENSE)
[![Docs](https://img.shields.io/badge/docs-Guide-0A7EA4?style=flat-square)](https://github.com/XS-MLVP/toffee/blob/main/docs/index.md)
[![GitHub Stars](https://img.shields.io/github/stars/XS-MLVP/toffee?style=social)](https://github.com/XS-MLVP/toffee/tree/main)

Toffee 是一个 Python 硬件验证框架。用 `async` / `await` 描述输入时序与条件等待,
用 pytest 运行测试,再通过参考模型、结果检查和覆盖率构建完整的验证环境。

Expand All @@ -9,7 +16,9 @@ Toffee 是一个 Python 硬件验证框架。用 `async` / `await` 描述输入

## 快速开始

需要 **Python 3.11+**。在仓库根目录创建环境并从源码安装:
需要 **Python 3.11+**。PyPI 分发名为 `uc-toffee`,导入名为 `toffee`,
原生绑定由依赖 `uc-xcomm` 提供。可用 `python3 -m pip install "uc-toffee[runner]"` 安装。
下面在仓库根目录创建环境并从源码安装,以便运行仓库自带的例子:

```bash
python3 -m venv .venv
Expand Down Expand Up @@ -45,19 +54,19 @@ async def test_one_input_and_idle():
dut.close()
```

这个用例已包含在[示例文件](examples/getting_started/test_accumulator.py)中,可以直接运行:
这个用例已包含在[示例文件](https://github.com/XS-MLVP/toffee/blob/main/examples/getting_started/test_accumulator.py)中,可以直接运行:

```bash
python3 -m pytest -q examples/getting_started/test_accumulator.py::test_one_input_and_idle
```

预期得到 `1 passed`。继续阅读[累加器教程](docs/getting-started/index.md),
预期得到 `1 passed`。继续阅读[累加器教程](https://github.com/XS-MLVP/toffee/blob/main/docs/getting-started/index.md),
逐步加入边界测试、Driver、Monitor、参考模型与覆盖率。

## 用于项目验证

接入真实 RTL 时,使用 Picker 生成的 DUT Python 包,通过 `XCommClockBackend`
连接 xspcomm 的时钟与信号。具体准备和依赖要求见[真实 DUT 接入指南](docs/getting-started/native-and-next.md)。
连接 xspcomm 的时钟与信号。具体准备和依赖要求见[真实 DUT 接入指南](https://github.com/XS-MLVP/toffee/blob/main/docs/getting-started/native-and-next.md)。

测试增多后,用 `toffee run` 并行执行并汇总覆盖率。例如,运行整个入门示例目录:

Expand All @@ -66,15 +75,15 @@ toffee run examples/getting_started --workers 4
```

终端会显示本次运行的产物目录;有覆盖数据时会生成 `coverage.html`。
将示例路径换成项目测试目录即可运行自己的回归,更多选项见[回归运行指南](docs/guides/runner.md)。
将示例路径换成项目测试目录即可运行自己的回归,更多选项见[回归运行指南](https://github.com/XS-MLVP/toffee/blob/main/docs/guides/runner.md)。

## 文档

- [入门教程](docs/getting-started/index.md):从一条断言到完整的验证环境。
- [操作指南](docs/guides/index.md):接入 DUT、组织组件、采集覆盖率和运行回归。
- [接口参考](docs/reference/index.md):API、命令行参数和行为限制。
- [原理说明](docs/explanation/index.md):仿真调度、资源归属与覆盖率含义。
- [可运行示例](docs/examples.md) · [参与开发](CONTRIBUTING.md)
- [入门教程](https://github.com/XS-MLVP/toffee/blob/main/docs/getting-started/index.md):从一条断言到完整的验证环境。
- [操作指南](https://github.com/XS-MLVP/toffee/blob/main/docs/guides/index.md):接入 DUT、组织组件、采集覆盖率和运行回归。
- [接口参考](https://github.com/XS-MLVP/toffee/blob/main/docs/reference/index.md):API、命令行参数和行为限制。
- [原理说明](https://github.com/XS-MLVP/toffee/blob/main/docs/explanation/index.md):仿真调度、资源归属与覆盖率含义。
- [可运行示例](https://github.com/XS-MLVP/toffee/blob/main/docs/examples.md) · [参与开发](https://github.com/XS-MLVP/toffee/blob/main/CONTRIBUTING.md)

## Toffee Legacy

Expand Down
11 changes: 8 additions & 3 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ cd toffee

以下所有命令都在这个目录运行。不要进入 `src/` 或 `examples/` 再执行。

分发包名是 `pytoffee`,Python 导入名是 `toffee`。Toffee 2 当前从源码安装;
PyPI 上的旧包不等同于这条新主线。需要固定版本时可检出 `v2.0.0` 标签。
分发包名是 `uc-toffee`,Python 导入名是 `toffee`。可以用
`python3 -m pip install "uc-toffee[runner]"` 安装;它会自动安装 `uc-xcomm>=1.1,<2`,
由后者提供 `xspcomm` 原生绑定。旧 `pytoffee` 对应 Legacy,不是这条新主线。

下面从源码安装,以便运行仓库中的教程。
开发未发布版本时,按[贡献指南](https://github.com/XS-MLVP/toffee/blob/main/CONTRIBUTING.md)准备固定提交的原生依赖。

## 安装到独立的 Python 环境

Expand Down Expand Up @@ -48,4 +52,5 @@ python3 -c 'import toffee; print(toffee.__file__)'
| 后续提示 `No module named examples` / `file not found` | 回到仓库根目录,使用文档中的 `python3 -m pytest ...` |

先继续 [1. 第一次 PASS 和 FAIL](first-test.md)。
需要原生 XClock 时再看 [接入 native](native-and-next.md),不必在这里被 绑定 构建挡住。
需要使用原生 XClock 时再看 [接入 native](native-and-next.md)。匹配的预编译包无需本地编译;
其他环境安装 `uc-xcomm` 源码包时,需要系统提供 C++20 编译器、CMake 和 Python 开发头文件。
2 changes: 1 addition & 1 deletion docs/getting-started/native-and-next.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## 先确认加载的是哪个 绑定

Toffee 不附带 xspcomm。原生后端需要 `XClock.StepHalf`、`GetHalfTick`、`GetPhase`、
Toffee 通过常规依赖 `uc-xcomm` 安装 `xspcomm` 绑定。原生后端需要 `XClock.StepHalf`、`GetHalfTick`、`GetPhase`、
`XData` 和 `XTriggerEngine` 等接口。开发使用的提交、包版本、ABI 和协议版本以
[依赖清单](https://github.com/XS-MLVP/toffee/blob/main/.github/native-dependencies.json)为准,
不要只按包名判断版本是否匹配。安装到当前 Python 环境后,先运行:
Expand Down
10 changes: 6 additions & 4 deletions docs/guides/toffee-v2-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
Toffee 2 基于 XReactor 1.1.0 的实现迁入,提供驱动、监视、参考模型、结果检查和覆盖率。
**Toffee Legacy(旧版)的实现与提交历史保留在
[`master`](https://github.com/XS-MLVP/toffee/tree/master);新实现位于 `main`。**
两代实现的安装包名都是 `pytoffee`,Python 导入名都是 `toffee`,但 API 与运行语义不兼容。
旧版安装包名为 `pytoffee`,新版为 `uc-toffee`;Python 导入名都为 `toffee`,但 API 与运行语义不兼容。
两代实现应放在不同的虚拟环境中。
旧验证环境需要按本文调整运行作用域、信号绑定、模型接线和采样语义。

本次迁移基线为 [XReactor 1.1.0 `3017293`](https://github.com/XS-MLVP/xreactor/tree/3017293a7597c39adbae883e15d63d727bcbf6ae)
和 [旧 Toffee `f57dd6f`](https://github.com/XS-MLVP/toffee/tree/f57dd6ffc295b9b8bad3e3b3ce040b8a849f5c91)。
旧版本实际发布在 `0.x` 系列,本文使用“旧版”指代,不将其称为已发布的 1.x。
Toffee 2 暂未发布到 PyPI,请从 `main` 或 `v2.0.0` 标签安装。
Toffee 2 从 `2.0.0` 开始以 `uc-toffee` 分发,可用
`python3 -m pip install "uc-toffee[runner]"` 安装。

## 旧项目如何选择

Expand All @@ -18,7 +20,7 @@ Toffee 2 暂未发布到 PyPI,请从 `main` 或 `v2.0.0` 标签安装。

迁移到 Toffee 2 时:

1. 建立独立的 Python 3.11+ 环境,从 `main` 或 `v2.0.0` 标签安装。
1. 建立独立的 Python 3.11+ 环境,运行 `python3 -m pip install "uc-toffee[runner]"`。
2. 按下表迁移测试入口、Bundle、Driver、Monitor 与参考模型接线。
3. 根据采样和条件等待章节检查周期边界、事务完成条件与清理行为。
4. 运行项目已有回归,验证结果后再更新项目依赖。
Expand All @@ -28,7 +30,7 @@ Toffee 2 暂未发布到 PyPI,请从 `main` 或 `v2.0.0` 标签安装。
## 从 XReactor 1.1 迁入

Python 导入由 `xreactor` 改为 `toffee`,命令由 `xreactor`、`xreactor-coverage-report`
改为 `toffee`、`toffee-coverage-report`;分发包名为 `pytoffee`。
改为 `toffee`、`toffee-coverage-report`;分发包名为 `uc-toffee`。
底层公开类 `XReactor` 更名为 `Reactor`。项目中的 `pytest_xreactor_coverage` hook、
`xreactor_register_dut` fixture 和 `xreactor_functional_coverage` marker 分别改用 `toffee` 前缀。
框架自带的 runner 继续使用 pytest、pytest-asyncio 和 pytest-xdist,无需 `toffee-test`。
Expand Down
41 changes: 31 additions & 10 deletions docs/guides/versioning-and-releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ Toffee 的版本来自 Git tag,正式版本使用 `vX.Y.Z`。维护者不需
版本字符串:例如 `v1.0.0` 构建为 `1.0.0`,后续未打 tag 的提交构建为开发版本。
`setuptools-scm` 只参与构建,使用已安装的包不需要 Git 或该工具。

## 首次迁入与手动标签
## 新版与 Legacy 的版本

Toffee 2 的首次迁入保留 XReactor 的提交历史,以手动标签 `v2.0.0` 标记源码版本。
Toffee 2 的 `main` 保留 XReactor 的提交历史,首次通过合并 PR 发布为 `v2.0.0`,
对应 PyPI 分发包 `uc-toffee==2.0.0`。
旧 `master` 与 `0.x` 标签保持原样,XReactor 的 `1.x` 标签保留在原仓库。
首次迁入是直接推送,因此不满足下文发布工作流要求的“本仓库已合并 PR”来源校验;
该标签触发的自动发布任务可能失败,但不会改变标签或源码。此次不发布 PyPI 包,
也不以 GitHub Release 资产上传作为源码迁移的完成条件。
后续通过 `main` 的正常 PR 继续使用现有版本与发布流程,版本从 `2.0.0` 递增。
Legacy 的标签不参与新 `main` 的版本计算,旧 PyPI 项目 `pytoffee` 也不由新版流程发布。
后续版本按合并 PR 的增量标签从 `2.0.0` 递增。

## 提交与版本选择

Expand All @@ -23,8 +22,9 @@ Toffee 2 的首次迁入保留 XReactor 的提交历史,以手动标签 `v2.0.
| `release:minor` | 新增公共能力,保留已有调用方式 | 1.1.0 |
| `release:major` | 移除接口或改变已有语义 | 2.0.0 |

没有正式 tag 时从 `0.0.0` 计算增量。标签缺失或同时选择多个增量会使版本检查失败。
版本工作流针对默认分支 `main` 运行。
`main` 第一父链上没有正式 tag 时,首次版本固定为 `2.0.0`;后续才应用版本增量。
每个 PR 仍须选择一个增量标签,缺失或同时选择多个增量会使版本检查失败。
版本工作流针对仓库默认分支 `main` 运行;`master` 保留为 Legacy。

PR 合并后,Version policy 工作流确认目标提交是 `main` 第一父链上的实际 PR 合并
结果,再创建带注释的 tag。分支中的 tag、PR 内部提交和直接 push 不触发自动发布。
Expand Down Expand Up @@ -68,14 +68,35 @@ Tagged release 接受 tag push、Version policy 的 dispatch 或维护者手动
发布前再次核对清单、当前 tag、依赖、run ID 和文件集合。已有发布资产不覆盖;
若已有文件与本次验证产物完全一致,可以补齐缺失资产;校验和不同则拒绝混合发布。
发布中断时优先只重跑失败的发布 job,复用原 CI artifact。
当前流程发布到 GitHub Releases,PyPI 发布尚未配置。
GitHub Release 成功后,使用同一组 wheel 和源码包发布到 PyPI 的 `uc-toffee`。
校验清单与原生依赖测试 wheel 保留为 CI/GitHub 资产,不上传到 `uc-toffee` 的 PyPI 项目。
普通 CI 也保留分发包 artifact,便于提交评审;覆盖数据库、日志和源码覆盖 HTML
继续作为本地产物,不上传。

Version policy 使用 `repository_dispatch` 启动后续验证,因为由 `GITHUB_TOKEN`
创建的 tag push 不会自动启动其他工作流,而 dispatch 支持这种调用。
见 [GitHub 触发规则](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow)。

## PyPI 配置

先发布满足依赖范围的 `uc-xcomm`,再发布 `uc-toffee`。首次在
[PyPI Publishing](https://pypi.org/manage/account/publishing/) 添加 pending GitHub publisher:

| 字段 | 值 |
| --- | --- |
| Project name | `uc-toffee` |
| Owner | `XS-MLVP` |
| Repository | `toffee` |
| Workflow filename | `release.yml` |
| Environment | `pypi` |

在 GitHub 创建同名 `pypi` 环境,并允许该环境从 `main` 或经过验证的发行标签部署。
不需要 PyPI API token。首次成功上传时创建项目;配置完成前,PyPI job 可以失败,
补齐后重跑该 job 即可。已有版本不能用不同内容覆盖。

`repository_dispatch` 使用仓库默认分支上的工作流,因此默认分支须保持为 `main`。
Legacy `master` 的源码和旧 `pytoffee` 发布配置独立保留。

## 首次启用与失败恢复

仓库管理员先创建三个 `release:*` 标签,并将 `CI / test` 的两个 Python job、
Expand All @@ -101,7 +122,7 @@ python3 scripts/release/verify_dist.py --manifest --verify-manifest
git diff --check
```

读取安装版本使用 `importlib.metadata.version("pytoffee")`。发布时 CI 必须具有完整
读取安装版本使用 `importlib.metadata.version("uc-toffee")`。发布时 CI 必须具有完整
Git 历史;源码包已经包含构建时确定的版本,在解包后重建不依赖原仓库。
没有 Git 和源码包元数据的普通源码副本才使用 `2.0.0.dev0` fallback。
配置依据见 [setuptools-scm 文档](https://setuptools-scm.readthedocs.io/en/v9.2.0/usage/)。
Loading
Loading