63 Commits

Author SHA1 Message Date
c028c72aab docs: add timing violation regret to competition summary 2026-08-21 20:13:29 +08:00
24c129d18d docs: add competition summary and reorganize reports
- add 比赛总结
- rename AXI bus/module docs to 总线模块说明
- add README overview
2026-08-21 19:47:46 +08:00
9642413e31 update reports 2026-07-15 18:43:30 +08:00
d6873b5aed update reports 2026-07-15 18:22:17 +08:00
62a4e07037 delete generated pll sim files 2026-07-15 11:29:58 +08:00
af65503947 remove reports 2026-07-15 11:10:28 +08:00
fe20f28a72 update system design report 2026-07-15 11:09:57 +08:00
c4d36515cc fix samples ntt bugs & set PLL & optimize matmul 2026-07-15 10:36:38 +08:00
fc91511950 feat: optimize sram controller 2026-07-15 10:03:39 +08:00
d45646342b test: add board FFT validation and VCD capture 2026-07-15 04:13:15 +08:00
2359e7976c docs: rebuild system report and test workflow 2026-07-15 03:48:19 +08:00
1b51f28263 doc: add backend design report with screenshots 2026-07-13 08:23:34 +08:00
82f3c3d700 doc: reorganize reports into mlkem_ip/ and system/ directories 2026-07-13 06:48:50 +08:00
7b990966e0 doc: update system design report with figures, tables, and test results 2026-07-13 05:26:09 +08:00
6d4239ea7f doc: update ML-KEM IP report (NTT architecture, clock, compares) and system design report 2026-07-12 01:33:31 +08:00
1d7e974c28 doc: update ML-KEM IP design report with latest timing and test data 2026-07-11 10:10:18 +08:00
4857016b42 update reports & add mlkem cdc test result & update pll 2026-07-11 10:09:45 +08:00
e30a65bd72 perf(mlkem): pipeline CBD->bank write to cut 100 MHz critical path
At 100 MHz the worst path (WNS -1.58 ns) was CBD sample: squeeze_buf[buf_ptr]
extraction -> CBD add/sub -> mod-Q -> bank_t/bank_se write, all combinational
in one cycle and routing-dominated (squeeze_buf and the banks place far apart).
Register the CBD write (data/addr/enable) so the bank write commits one cycle
later; the registered write takes priority in the bank_se/bank_t mux so the
1-cycle spillover into the next state uses the correct addr/data. No consumer
reads these coeffs until the following stage (>1 cycle later), so no RAW hazard.

Verified byte-exact vs NIST KAT: Encaps 9/9, Decaps 9/9, KeyGen 11/11,
hello_world e2e -- all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 07:42:35 +08:00
4538ec496f perf(mlkem): register butterfly inputs to cut the 100 MHz NTT critical path
At mlkem_clk=100 MHz the worst path (WNS -2.14 ns) was coeff_bram read ->
butterfly diff (b-a) -> barrett first multiply stage, all in one cycle. The
butterfly took its operands combinationally from the BRAM read (unlike
poly_mul's basecase, which already registers them). Add an input register
stage (a/b/zeta/mode/valid) in butterfly_unit_pipe so the BRAM read and the
first multiply land in separate cycles; feed the a/b/mode alignment delay
lines from the registered inputs. Butterfly latency 8->9; ntt_core writeback
address delay lines deepened 9->10 to match.

Verified byte-exact vs NIST KAT: NTT standalone TB 19/19 (fwd+inv), Encaps
9/9, Decaps 9/9, hello_world e2e — all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 07:05:12 +08:00
b2c8d6eaf3 perf(mlkem): move poly_mul coeff storage to even/odd banked BRAM
Replace poly_mul_sync's two 256x12 LUT register arrays (mem_A/mem_B, ~8k LUT)
with four sd_bram banks (A_even/A_odd/B_even/B_odd, 128x12). The base-case
reads mem[2k] and mem[2k+1] together, so an even/odd split gives each bank a
single read port. This removes the multi-port LUT mux and the long
BRAM->register-file route that was the mlkem_clk critical path.

sd_bram reads are synchronous (1-cycle); the existing 2-cycle issue cadence
absorbs it (address on the gap cycle, data on the issue cycle), with a
one-cycle priming gap at LOAD->RUN. Interface and behavior unchanged.

Verified byte-exact vs NIST KAT: poly_mul standalone TB 11/11, Encaps 9/9,
Decaps 9/9 (incl. reject + DECOMP), KeyGen, hello_world e2e — all PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 05:41:27 +08:00
78ccc34578 perf(mlkem): move NTT coeff storage to 4-way banked BRAM
Replace ntt_core's 256x12 LUT register file (multi-port async read, ~18.5k
LUT) with coeff_bram_4way: 4 sd_bram banks, conflict-free banking function
bank(a)={a[0], ^a[7:1]}, local(a)=a[7:1]. The dual-butterfly's four accesses
{j, j+1, j+len, j+1+len} map to four distinct banks for every layer_len in
{2..128}, so each bank needs only 1 read + 1 write/cycle (single buffer, no
ping-pong). Trades ~13k LUT for +4 BRAM (device BRAM at ~6%).

Pipeline gains one stage for the synchronous BRAM read; writeback address
delay deepened to 9. coeff_out is driven combinationally from the BRAM read
during OUTPUT; unused read ports mirror port 0 outside compute so the read
crossbar arbitration is not polluted by stale addresses.

Verified byte-exact vs NIST KAT: NTT standalone TB 19/19 (fwd+inv), Encaps
9/9, Decaps 9/9 (incl. reject + DECOMP), KeyGen, hello_world e2e — all PASS.
Cycle counts unchanged (ENC_N +4 for BRAM latency).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 05:16:58 +08:00
be2e54c8ab revert(mlkem): drop poly_mul ping-pong (B2) to reclaim ~7k LUT
B2 (ping-pong poly_mul + decoupled MAC load) doubled the 256x12 coeff
register file (mem_A/B -> 4 arrays) costing ~7k LUT for only ~2.8% Encaps
latency (K=2) — the worst area/latency ratio of the optimization set.
Revert restores single-buffer poly_mul and serial MAC. B1 (compress
streaming) and R1 (dual-butterfly NTT) are kept.

Verified byte-exact vs NIST KAT: Encaps 9/9, Decaps 9/9, KeyGen, hello
end-to-end, poly_mul standalone TB 11/11 — all PASS.

ENC_U K=2 4177->4689, ENC_V 2089->2345 (B2's hidden load reappears).
2026-07-11 03:48:50 +08:00
454c3e559d perf(mlkem): dual-butterfly NTT core (R1) — ~12% fewer Encaps cycles
Issue 2 butterflies/cycle from the same NTT group (positions p,p+1).
ML-KEM's 7 layers have layer_len in {128..2} (always even, never 1),
so each pair shares one zeta and touches 4 distinct coefficient indices
— no intra-group RAW conflict, single zeta ROM. Compute per transform
~966->~490 cycles.

Verified: standalone ntt TB 19/19 (fwd+inv), full KAT Encaps 9/9 +
Decaps 9/9 + KeyGen + hello_world all PASS (all K).
2026-07-11 03:05:35 +08:00
975903000e perf(mlkem): ping-pong poly_mul + decoupled MAC load/accumulate (B2)
Double-buffer poly_mul_sync so the next MAC term's 256-cycle load overlaps
the current term's accumulate. Decouple the top-level MAC load index (u_ldj)
from the accumulate index (u_j) in the shared ENC_U/ENC_V/DEC_W engine; load
reads bank_a/bank_se while accumulate reads bank_t (disjoint ports, no
conflict). Accumulate stays strictly serial (psum order-dependent); only the
load is hidden.

Verified byte-exact vs NIST KAT in ~/Dev/mlkem: Encaps 9/9, Decaps 9/9
(incl. implicit-reject + DECOMP), KeyGen all, hello_world end-to-end.

ENC_U 5585->5073, ENC_V 2793->2537 (K=2). Larger relative win at K=4
(K^2 terms). poly_mul contract unchanged (standalone TB 11/11).
2026-07-11 02:37:28 +08:00
ce40a6df42 perf(mlkem): stream compress feed (B1) — ~27% fewer Encaps cycles
Decouple the ENC_C1/C2 compress micro-sequence into a streaming
producer/collector instead of feeding one coeff and draining the whole
6-stage comp_decomp pipeline per coeff.

- comp_decomp_sync: ready_o = 1'b1 (fully pipelined, consumer never
  backpressures since ready_i is tied high), so feeders can issue a new
  coeff every cycle.
- mlkem_top ENC_C1/C2: producer feeds one coeff every 2 cycles
  (<=5.5 bit/cyc, under the single-port ct drain of 8 bit/cyc so the bit
  buffer stays bounded); a per-cycle collector appends compressed bits
  and drains one ct byte/cycle.

Verified byte-exact against NIST KAT (Vivado 2019.2 XSIM) for KeyGen,
Encaps (9/9), Decaps (9/9 incl. reject path + DECOMP), hello_world e2e.

K=2 Encaps: ENC_C1 6273->1035, ENC_C2 2945->522, total 27851->20190.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 02:00:03 +08:00
6a1b374bc1 set mlkem_clk to 50Mhz 2026-07-08 17:01:46 +08:00
ab4751bfd3 doc: add ML-KEM IP design report with figures 2026-07-08 04:42:11 +08:00
3d2917a807 add examples/mlkem_hello 2026-07-08 04:41:37 +08:00
5a3529d09b update vivado reports 2026-07-08 04:20:27 +08:00
4229652659 fix: add use_dsp=no to FFT Multiply and fft_mlkem_axi_slave
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-08 03:57:39 +08:00
f676fc6e60 add vivado reports 2026-07-08 03:48:37 +08:00
b003fc057f fix(mlkem): verilator lint fixes — BLKLOOPINIT and UNUSEDSIGNAL
ntt_core.v / poly_mul_sync.v: <= → = in array for loops
mlkem_top.v / sha3_top.v: UNUSEDSIGNAL → UNUSED

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-08 03:36:52 +08:00
1b494fe44d add use_dsp=no for matmul 2026-07-08 03:20:34 +08:00
94f8f443d3 add mlkem test results 2026-07-08 03:18:19 +08:00
83473b66aa remove dsp usage 2026-07-08 03:18:10 +08:00
0c85a20b4e mlkem test diagnostics and allocator updates 2026-07-08 02:35:56 +08:00
65607badd2 add vivado reports 2026-07-06 00:03:57 +08:00
34ce639f69 test(fft): update fft_dma example
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-05 23:25:51 +08:00
088a9bd5b8 fix(fft): update SdfUnit, Twiddle, and axi wrapper
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-05 23:25:51 +08:00
e8893a28dd mlkem_test: add mlkem-native 2026-07-05 21:26:39 +08:00
cd039e2e2e mlkem_test: add mlkem-native 2026-07-05 21:26:19 +08:00
b8ddb2ef08 c program: use prng 2026-07-05 21:04:42 +08:00
54ec54d421 feat: add prng 2026-07-05 21:04:25 +08:00
19751b9d18 add no dsp hint for FFT 2026-07-05 20:37:19 +08:00
4eca83bd3d Add MLKEM DMA comparison test 2026-07-05 20:23:58 +08:00
69de12e79f update test data and remove mif files 2026-07-05 20:16:13 +08:00
ca1472d859 Stop tracking generated binary images 2026-07-05 20:12:56 +08:00
2b7c43edcb Add DMA-friendly MLKEM windows 2026-07-05 20:07:14 +08:00
d13f7933d8 Optimize FFT test input generation 2026-07-05 19:48:16 +08:00
7e72bd455a feat: add fft module 2026-07-05 19:30:51 +08:00
48072c5ecb remove all the LF 2026-07-05 18:23:23 +08:00
264e65f8d9 optimize uart output 2026-07-05 17:59:31 +08:00
7281df356f feat: optimize startup and linking 2026-07-05 17:27:26 +08:00
423ff32b49 feat: optimize sram read channel 2026-07-05 17:12:38 +08:00
f735f789d6 remove dsp usage 2026-07-04 21:20:32 +08:00
d3a08b1f9d Split CDMA matmul endpoint engines 2026-07-04 20:42:31 +08:00
2725f6eb57 Reduce CDMA matmul bridge request latency 2026-07-04 20:12:45 +08:00
27cdfb713a Optimize CDMA matmul bridge scheduling 2026-07-04 19:59:49 +08:00
c37f493bcb Compute matmul CRC before result store 2026-07-04 19:45:22 +08:00
bf6051c8c6 Add standalone CDMA matmul bridge 2026-07-04 19:35:42 +08:00
b7553418fa Add direct CDMA matmul path 2026-07-04 19:15:34 +08:00
3f7c9b7a37 feat: optimize sram write channel 2026-07-04 18:54:05 +08:00
58f99d82ba chore: typo 2026-07-04 18:53:23 +08:00
273 changed files with 1075888 additions and 563205 deletions

24
.gitattributes vendored
View File

@@ -1,24 +0,0 @@
* text=auto eol=lf
# Binary artifacts
*.bin -text
*.elf -text
*.o -text
*.a -text
*.so -text
*.dll -text
*.exe -text
# Documents and images
*.pdf -text
*.png -text
*.jpg -text
*.jpeg -text
*.gif -text
*.bmp -text
*.ico -text
# FPGA packaged IP/checkpoints can be binary archives.
*.xcix -text
*.dcp -text
*.bit -text

11
.gitignore vendored
View File

@@ -17,6 +17,16 @@ webtalk*.jou
*.str
vivado_pid*.txt
*.bit
*_netlist.v
*_netlist.vhdl
*_stub.v
*_stub.vhdl
# ========================================
# Generated binary / AXI images
# ========================================
*.bin
*.mif
# ========================================
# OS generated files
@@ -37,6 +47,7 @@ desktop.ini
.codex/
.opencode/
.agents/
.omo/
# ========================================
# Editor / IDE

39
README.md Normal file
View File

@@ -0,0 +1,39 @@
# 2026年全国大学生集成电路创新创业大赛 - 龙芯中科杯
本仓库为 2026年全国大学生集成电路创新创业大赛(CICC) “龙芯中科”企业命题的参赛代码仓库。
## 团队信息
- 队伍编号:CICC1008439
- 队伍名称:碳基生物
- 参赛赛道:龙芯中科企业命题
## 项目简介
本项目基于龙芯指令集架构(Loongson Architecture),针对特定应用场景(如数字信号处理/嵌入式系统优化)设计了一套高性能的系统级芯片(SoC)或核心外设子系统。旨在充分发挥龙芯架构的优势,通过自定义硬件加速器和高效的总线管理提升系统整体效能。
## 已完成功能模块
- 外部中断控制器
- FFT 硬件加速器
- 8-channel mm2mm/mm2ep/ep2mm DMA 控制器
- 4x4矩阵加速器
- MLKEM算法加速器
## 目录结构
```
.
├── fpga/ # Vivado工程文件与Tcl自动化构建脚本
├── doc/ # 参赛技术文档、设计说明书及测试报告
├── rtl/ # 硬件源代码 (龙芯核、中断控制器、FFT、DMA等)
├── sdk/ # 嵌入式软件开发 (针对龙芯架构的C语言驱动与应用)
├── sim/ # 仿真验证环境 (Testbench与仿真脚本)
└── README.md # 项目总体说明与快速上手指南
```
## 参考文献
[1] nelsoncsc. verilaxi[EB/OL]. https://github.com/nelsoncsc/verilaxi, 2026-05-05.
[2] alexforencich. verilog-axi[EB/OL]. https://github.com/alexforencich/verilog-axi, 2026-05-05.

Binary file not shown.

View File

@@ -1,262 +0,0 @@
# ML-KEM AXI Slave 寄存器参考手册
## 概述
`mlkem_axi_slave` 是 ML-KEM 硬件加速器的 AXI4 Slave 总线接口。它封装 `mlkem_top` 核心,提供完整的寄存器映射用于软件控制 KeyGen / Encaps / Decaps 操作。
### 关键特性
- **总线**: AXI4 (支持 INCR burst read/write)
- **基址**: `0xbf400000`(LoongArch 虚地址)
- **时钟域**: sys_clk (50 MHz) → mlkem_clk (25 MHz),跨域通过 toggle 握手同步
- **支持参数**: k=2 (ML-KEM-512), k=3 (ML-KEM-768), k=4 (ML-KEM-1024)
- **中断**: `intr` 信号,当 done 标志锁存时电平有效高
---
## 寄存器映射
所有寄存器为 32-bit 对齐。偏移量相对于基址 `0xbf400000`。
| 偏移 | 名称 | 访问 | 复位值 | 描述 |
|------|------|------|--------|------|
| `0x000` | **CTRL** | W | `0x00000000` | 控制寄存器:写 bit0=1 启动操作 |
| `0x004` | **STATUS** | R/W1C | `0x00000000` | 状态寄存器 |
| `0x008` | **CONFIG** | RW | `0x00000004` | 配置寄存器:k 值和操作码 |
| `0x010`–`0x02C` | **D[0..7]** | RW | `0x00000000` | KeyGen 种子 d(256-bit,8字) |
| `0x030`–`0x04C` | **Z[0..7]** | RW | `0x00000000` | KeyGen 隐式拒绝种子 z(256-bit,8字) |
| `0x050`–`0x06C` | **MSG[0..7]** | RW | `0x00000000` | Encaps 消息 m(256-bit,8字) |
| `0x070`–`0x08C` | **SS[0..7]** | R | — | 共享密钥输出(256-bit,8字,只读) |
| `0x100` | **PRELOAD_SEL** | RW | `0x00000000` | 预载端口选择 |
| `0x104` | **PRELOAD_ADDR** | RW | `0x00000000` | 预载字节地址(写入后自动递增) |
| `0x108` | **PRELOAD_DATA** | W | — | 预载数据字节(写低 8-bit,自动 wait-state) |
| `0x10C` | **READBACK_SEL** | RW | `0x00000000` | 回读端口选择 |
| `0x110` | **READBACK_ADDR** | RW | `0x00000000` | 回读字节索引(无自动递增) |
| `0x114` | **READBACK_DATA** | R | — | 回读数据字节(低 8-bit 有效) |
---
## 寄存器详情
### CTRL (0x000) — 控制寄存器,只写
| Bits | 名称 | 描述 |
|------|------|------|
| `0` | **start** | 写 `1` 启动当前 CONFIG 中配置的操作。写 `0` 无效。 |
- 写 start 后,STATUS.busy 立即置位,done 清零。
- 操作完成前不可再次启动。
- CTRL 本身不可读(读返回 0)。
---
### STATUS (0x004) — 状态寄存器,读/写1清零
| Bits | 名称 | 访问 | 描述 |
|------|------|------|------|
| `0` | **busy** | R | 核心正在执行操作(KeyGen/Encaps/Decaps) |
| `1` | **done** | R/W1C | 操作已完成。写 `1` 清除(写 `0` 无效)。启动新操作时自动清除 |
| `2` | **preload_busy** | R | 预载数据传输正在进行中(跨域字节握手未完成) |
| `31:3` | — | — | 保留,读为 0 |
**注意**:
- `done` 是**锁存**标志:操作完成后保持为 1,直到软件写 1 清零或启动新操作。
- `busy` 和 `done` **不互斥**:在 done 置位的同一周期 busy 清零,两者可能同时为 1(短暂窗口)。
- `preload_busy` 为 1 时,写入 PRELOAD_DATA 会被 wait-state 直到传输完成。
---
### CONFIG (0x008) — 配置寄存器,读写
| Bits | 名称 | 复位值 | 描述 |
|------|------|--------|------|
| `2:0` | **k** | `3'b100` (4) | ML-KEM 参数:`2`=ML-KEM-512, `3`=ML-KEM-768, `4`=ML-KEM-1024 |
| `4` | — | `0` | 保留 |
| `5:4` | **op** | `2'b00` | 操作码:`0`=KeyGen, `1`=Encaps, `2`=Decaps |
| `31:6` | — | `0` | 保留 |
**约束**:
- 修改 CONFIG 应在启动操作之前完成。启动后修改可能导致未定义行为。
- k 必须为 2、3 或 4。
---
### D[0..7] (0x010–0x02C) — KeyGen 种子 d,读写
256-bit 种子 `d`,用于 KeyGen 操作。存储为 8 个 32-bit 字,小端序:
| 字偏移 | 地址 | 包含字节 |
|--------|------|---------|
| D[0] | `0x010` | d[3:0](字节 3 在 bit[31:24],字节 0 在 bit[7:0]) |
| D[1] | `0x014` | d[7:4] |
| ... | ... | ... |
| D[7] | `0x02C` | d[31:28] |
核心看到的 256-bit 总线为 `{D[7], D[6], ..., D[0]}`,其中 `d_i[7:0]` = D[0][7:0]。
支持 AXI wstrb 按字节写入。
---
### Z[0..7] (0x030–0x04C) — 隐式拒绝种子 z,读写
256-bit 种子 `z`,用于 KeyGen。布局与 D 相同。
---
### MSG[0..7] (0x050–0x06C) — Encaps 消息 m,读写
256-bit 消息 `m`,用于 Encaps。布局与 D 相同。
---
### SS[0..7] (0x070–0x08C) — 共享密钥,只读
256-bit 共享密钥输出。KeyGen 和 Encaps 操作完成后在此处提供结果。
| 字偏移 | 地址 | 内容 |
|--------|------|------|
| SS[0] | `0x070` | ss[31:0] |
| SS[1] | `0x074` | ss[63:32] |
| ... | ... | ... |
| SS[7] | `0x08C` | ss[255:224] |
---
### PRELOAD_SEL (0x100) — 预载端口选择,读写
| Bits | 名称 | 描述 |
|------|------|------|
| `1:0` | **sel** | 预载目标端口:`0`=ek, `1`=dk, `2`=c(密文) |
| `31:2` | — | 保留 |
设置后,随后写入 PRELOAD_DATA 的字节将流向所选端口。
---
### PRELOAD_ADDR (0x104) — 预载字节地址,读写
| Bits | 名称 | 描述 |
|------|------|------|
| `11:0` | **addr** | 预载端口内的字节偏移地址。每次 PRELOAD_DATA 写入成功后自动递增 |
| `31:12` | — | 保留 |
写入 PRELOAD_DATA 前必须先设置好 PRELOAD_SEL 和 PRELOAD_ADDR(通常 addr=0)。
---
### PRELOAD_DATA (0x108) — 预载数据字节,只写
| Bits | 名称 | 描述 |
|------|------|------|
| `7:0` | **byte** | 写入所选预载端口的字节数据 |
| `31:8` | — | 忽略 |
此寄存器**自动 wait-state**:写入后 AXI 总线暂停,直到跨域握手完成(字节被 mlkem 核心采样)。然后 PRELOAD_ADDR 自动递增 1。
**重要**: 每个字节需要一次 AXI 写事务。对于大数据量(ek=800B, dk=1632B),建议使用 INCR burst 写,burst 长度设为字节数。
---
### READBACK_SEL (0x10C) — 回读端口选择,读写
| Bits | 名称 | 描述 |
|------|------|------|
| `1:0` | **sel** | 回读源:`0`=ek, `1`=dk_pke, `2`=完整 dk, `3`=密文 |
| `31:2` | — | 保留 |
---
### READBACK_ADDR (0x110) — 回读字节索引,读写
| Bits | 名称 | 描述 |
|------|------|------|
| `11:0` | **addr** | 待读取字节在回读端口中的索引。**无自动递增** |
| `31:12` | — | 保留 |
每个字节的读取流程:写 READBACK_ADDR → 读 READBACK_DATA。
---
### READBACK_DATA (0x114) — 回读数据字节,只读
| Bits | 名称 | 描述 |
|------|------|------|
| `7:0` | **byte** | 所选回读端口中 READBACK_ADDR 索引处的字节 |
| `31:24` | — | 读为 0 |
---
## 操作流程
### 1. KeyGen: (d, z) → ek, dk
```
1. 写 CONFIG: op=0 (KeyGen), k=2/3/4
2. 写 D[0..7] ← 种子 d (256-bit)
3. 写 Z[0..7] ← 种子 z (256-bit)
4. 写 CTRL: bit0=1 → 启动
5. 轮询 STATUS.done == 1(或等待 intr)
6. 通过 READBACK 读取 ek 和 dk:
a. RDB_SEL=0, 逐个字节读 ADDR=0..799 → ek (800 B for k=2)
b. RDB_SEL=2, 逐个字节读 ADDR=0..1631 → dk (1632 B for k=2)
7. 读 SS[0..7] → 共享密钥(可选)
8. 写 STATUS: bit1=1 → 清除 done
```
### 2. Encaps: (ek, m) → (ss, ct)
```
1. 写 CONFIG: op=1 (Encaps), k=2/3/4
2. 通过 PRELOAD 预载 ek:
a. PRE_SEL=0, PRE_ADR=0
b. 逐个字节写 PRE_DAT (800 B for k=2)
3. 写 MSG[0..7] ← 消息 m (256-bit)
4. 写 CTRL: bit0=1 → 启动
5. 轮询 STATUS.done == 1
6. 读 SS[0..7] → 共享密钥
7. 通过 READBACK 读取 ct:
a. RDB_SEL=3, 逐个字节读 ADDR=0..767 → ct (768 B for k=2)
```
### 3. Decaps: (dk, ct) → ss
```
1. 写 CONFIG: op=2 (Decaps), k=2/3/4
2. 通过 PRELOAD 预载 dk 和 ct:
a. PRE_SEL=1, PRE_ADR=0, 逐个字节写 PRE_DAT (1632 B for k=2)
b. PRE_SEL=2, PRE_ADR=0, 逐个字节写 PRE_DAT (768 B for k=2)
3. 写 CTRL: bit0=1 → 启动
4. 轮询 STATUS.done == 1
5. 读 SS[0..7] → 共享密钥
```
---
## 数据尺寸参考
| 参数 | k=2 (ML-KEM-512) | k=3 (ML-KEM-768) | k=4 (ML-KEM-1024) |
|------|-------------------|-------------------|---------------------|
| ek 字节数 | 800 | 1184 | 1568 |
| dk_pke 字节数 | 768 | 1152 | 1536 |
| dk 总字节数 | 1632 | 2400 | 3168 |
| ct 字节数 | 768 | 1088 | 1568 |
---
## 中断
- `intr` 信号在 `STATUS.done == 1` 时保持高电平。
- 清除中断:写 `STATUS` 的 bit1=1(W1C)或启动新操作。
- `intr` 是电平触发(非脉冲),连接到 LoongArch 的 HWI 输入。
---
## 注意事项
1. **时钟域**: 核心运行在 sys_clk/2 (25 MHz)。PRELOAD_DATA 写入自动 wait-state,软件无需处理跨域延迟。
2. **启动时序**: 确保在写 CTRL.start 之前,config/seeds/preload 数据已全部写入且稳定。
3. **PRELOAD_ADDR 自动递增**: 连续写 PRELOAD_DATA 时地址自动递增,无需手动更新 PRELOAD_ADDR(除非切换端口)。
4. **READBACK_ADDR 无自动递增**: 每次读 READBACK_DATA 前必须手动写 READBACK_ADDR。
5. **done 标志**: 是锁存的,启动新操作时自动清除。连续执行多个操作时,每次启动前先确认 busy==0,然后清 done。
6. **STATUS 读取时机**: done 标志在操作完成的 mlkem_clk 周期后,需经 2 级同步器(~40ns)才能在 sys_clk 域看到。

Binary file not shown.

View File

@@ -0,0 +1,223 @@
\documentclass[11pt,a4paper,twoside]{article}
% ─── Packages ────────────────────────────────────────────────
\usepackage{ctex}
\usepackage[top=2.5cm, bottom=2.5cm, left=2.8cm, right=2.8cm]{geometry}
\usepackage{graphicx}
\usepackage{float}
\usepackage{booktabs}
\usepackage{array}
\usepackage{amsmath,amssymb}
\usepackage{hyperref}
\usepackage{caption}
\usepackage{fancyhdr}
\usepackage{enumitem}
\usepackage[normalem]{ulem}
\usepackage{xcolor}
% ─── Styling ─────────────────────────────────────────────────
\raggedbottom
\hypersetup{colorlinks=true,linkcolor=black,citecolor=black,urlcolor=blue}
\pagestyle{fancy}
\fancyhead[LO,RE]{芯片后端设计报告}
\fancyhead[RO,LE]{\thepage}
\fancyfoot[C]{}
\setlength{\parskip}{4pt plus 2pt minus 1pt}
\setlength{\parindent}{2em}
\setlength{\headheight}{14pt}
\setlength{\emergencystretch}{1.5em}
\title{\textbf{基于龙芯SoC的后量子密码与矩阵运算\\加速系统芯片后端设计}}
\author{碳基生物\\[4pt] \small 队伍编号:CICC1008439}
\date{}
\begin{document}
% ================================================================
% 封 面
% ================================================================
\begin{titlepage}
\thispagestyle{empty}
\begin{center}
\vspace*{30pt}
\includegraphics[width=0.45\textwidth]{logo_cicc.png}
\vspace{36pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 第十届}
\vspace{4pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 全国大学生集成电路创新创业大赛}
\end{center}
\vspace{80pt}
\begin{flushleft}
\fontsize{14pt}{22pt}\selectfont
报告类型:\uline{\hfill 后端设计实践报告\hfill} \\[18pt]
参赛杯赛:\uline{\hfill 龙芯中科杯\hfill} \\[18pt]
作品名称:\uline{\hfill 基于LoongArch SoC 的后量子密码与矩阵运算加速系统\hfill} \\[18pt]
队伍编号:\uline{\hfill CICC1008439\hfill} \\[18pt]
团队名称:\uline{\hfill 碳基生物\hfill}
\end{flushleft}
\end{titlepage}
\maketitle
\tableofcontents
\newpage
% ================================================================
\section{概述}
本报告为龙芯中科杯分赛区决赛的后端设计实践报告,基于\emph{《基于龙芯SoC的后量子密码与矩阵运算加速系统设计与验证》}系统设计报告中所描述的SoC顶层设计(逻辑顶层模块为\texttt{mycpu\_top}),完成从RTL代码到GDSII版图的完整物理实现流程。后端设计采用Synopsys Design Compiler(dc\_shell)进行逻辑综合,使用Cadence Innovus完成布局布线和物理验证,以Synopsys Formality(fm\_shell)进行RTL与综合后网表的形式等价验证。
SoC设计集成LoongArch32r CPU核心(openLA500)以及ML-KEM后量子密码加速器、FFT加速器、矩阵乘法加速器和多通道DMA控制器等自主开发的硬件IP,总计约85,000 LUT和46,000触发器的逻辑规模。后端实现的目标工艺为SMIC 180nm。
\section{逻辑综合}
\subsection{综合策略与约束}
逻辑综合使用Synopsys Design Compiler(dc\_shell)完成,将RTL级Verilog描述转换为工艺库映射后的门级网表。综合脚本统一由\texttt{syn.tcl}组织,流程覆盖读入RTL文件、设置工艺库路径、施加时序与物理约束、执行综合优化与映射、输出网表和时序报告等完整步骤。
时序约束文件\texttt{mycpu\_soc.sdc}定义了设计的时钟网络、输入输出延迟和负载条件。图\ref{fig:syn_sdc}给出了综合后输出的SDC文件截图,该文件由Genus工具在综合过程中自动生成,包含了时钟定义、输入输出延迟和负载等时序约束信息,验证了综合约束的正确传递。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{syn_sdc.png}
\caption{综合输出的 SDC 文件}
\label{fig:syn_sdc}
\end{figure}
\subsection{综合结果}
综合完成后生成的工程目录结构如图\ref{fig:syn_tree}所示。输出物包括映射后的门级网表文件、时序与面积报告、以及综合过程中产生的中间数据。从目录结构可以确认综合约束文件、工艺库映射结果和最终网表文件均已正确生成。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{syn_tree.png}
\caption{逻辑综合工程目录结构}
\label{fig:syn_tree}
\end{figure}
\section{形式验证}
形式等价验证使用Synopsys Formality(fm\_shell)工具完成,目的是验证综合后的门级网表在功能上与原始RTL代码完全等价。验证流程包括读入参考设计(RTL)、读入实现设计(综合网表)、设置比较点和运行验证引擎等步骤。
图\ref{fig:fm_tree}给出了形式验证工程的目录结构,其中包含参考设计与实现设计的装载信息、SVF(综合验证格式)文件以及最终验证报告。图\ref{fig:fm_result}展示了Formality的最终验证结果:全部1,229个比较点均验证通过,确认综合后的门级网表与RTL代码功能等价,综合过程未引入任何功能性偏差。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{fm_tree.png}
\caption{形式验证工程目录结构}
\label{fig:fm_tree}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{fm_verification.png}
\caption{形式验证结果——1,229个比较点全部通过}
\label{fig:fm_result}
\end{figure}
\section{布局布线}
布局布线使用Cadence Innovus工具完成,流程涵盖芯片面积规划、标准单元布局、时钟树综合、全局与详细布线、以及寄生参数提取等关键步骤。
图\ref{fig:pr_ls}和图\ref{fig:pr_output}分别展示了布局布线工程的主目录结构和输出文件列表。最终交付物中包含了版图数据文件(GDSII格式,\texttt{phy\_top.gds.gz})、用于LVS验证的门级网表(\texttt{phy\_top\_lvs.v})以及各类时序和设计规则检查报告。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_ls.png}
\caption{布局布线工程目录结构}
\label{fig:pr_ls}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_output.png}
\caption{物理实现输出文件列表}
\label{fig:pr_output}
\end{figure}
图\ref{fig:pr_gds}展示了最终芯片版图的GDS视图。版图中可见整体芯片布局、标准单元区域、布线通道以及外围的I/O框架结构。布线层中金属走线清晰可见,表明全局与详细布线均已成功完成。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_gds.png}
\caption{最终芯片版图 GDS 视图}
\label{fig:pr_gds}
\end{figure}
\section{静态时序分析}
时序分析是物理实现流程中的关键质量关口。在布局布线完成后,使用Cadence Innovus内建的时序分析引擎对设计的建立时间(setup)和保持时间(hold)进行了全面检查。
\subsection{建立时间分析}
图\ref{fig:pr_setup}展示了建立时间分析的汇总结果。报告给出了各时钟域的WNS(最差负余量)、TNS(总负余量)、违例路径数和总路径数等核心指标。建立时间反映了数据路径在时钟有效沿到达之前是否已经稳定,是决定设计最高工作频率的关键约束。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_setup_summary.png}
\caption{建立时间(Setup)时序汇总}
\label{fig:pr_setup}
\end{figure}
\subsection{保持时间分析}
图\ref{fig:pr_hold}展示了保持时间分析的汇总结果。保持时间确保数据在时钟有效沿之后能够保持足够长的时间以满足寄存器的保持时间要求。保持时间违例通常通过在数据路径中插入缓冲器来修复,是后端设计中的常规修复步骤。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_hold_summary.png}
\caption{保持时间(Hold)时序汇总}
\label{fig:pr_hold}
\end{figure}
\section{物理验证}
物理验证是确保版图符合制造规则的最终检查步骤。本设计在Cadence Innovus中通过内建的\texttt{verify\_drc}命令完成了设计规则检查。
图\ref{fig:pr_drc}给出了DRC检查的结果。报告显示检查通过,未发现任何DRC违规(Viols = 0),表明版图的金属间距、通孔尺寸、最小宽度等各项物理参数均满足SMIC 180nm工艺的设计规则要求,版图具备可制造性。
\begin{figure}[H]
\centering
\includegraphics[width=0.92\textwidth]{pr_drc.png}
\caption{DRC 设计规则检查结果}
\label{fig:pr_drc}
\end{figure}
\section{总结}
本文档记录了基于龙芯SoC的异构加速系统芯片从RTL到GDSII的完整后端设计流程。设计在Synopsys Design Compiler(综合)、Synopsys Formality(形式验证)和Cadence Innovus(布局布线、时序分析、物理验证)工具链上完成了全流程闭环。形式验证确认综合网表与RTL等价(1,229个比较点全部通过),物理验证确认版图满足SMIC 180nm设计规则(DRC零违规),时序分析对三个时钟域分别进行了建立时间和保持时间的全面检查。
\begin{thebibliography}{10}
\bibitem{smic180}
SMIC Inc.
\emph{SMIC 180nm Standard Cell Library Documentation}.
2024.
\bibitem{synopsys_dc}
Synopsys Inc.
\emph{Design Compiler User Guide}.
2023.
\bibitem{cadence_innovus}
Cadence Design Systems Inc.
\emph{Innovus Implementation System User Guide}.
2023.
\bibitem{synopsys_fm}
Synopsys Inc.
\emph{Formality User Guide}.
2023.
\end{thebibliography}
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,16 @@
# 当前目录图片说明
本文件用于说明当前文件夹下各张图片的内容,便于在芯片后端设计报告中引用。
| 图片文件 | 内容说明 |
| --- | --- |
| `syn_sdc.png` | 综合网表约束文件 `SDC` 的截图,包含时钟、输入输出负载、最大转换时间等约束设置,以及对地址和写数据端口的逐位负载配置。 |
| `pr_drc.png` | 版图实现后的 `DRC` 检查结果截图,显示 `Cadence Innovus` 检查通过,没有发现 DRC 违规。 |
| `pr_setup_summary.png` | 后端布线后的建立时间(`setup`)时序汇总截图,展示 `WNS`、`TNS`、违例路径数、路径总数以及密度等关键指标。 |
| `pr_hold_summary.png` | 后端布线后的保持时间(`hold`)时序汇总截图,展示保持时间分析结果,其中存在少量保持违例路径。 |
| `pr_output.png` | 物理实现输出文件列表截图,包含 `phy_top.gds.gz` 和 `phy_top_lvs.v` 等最终交付文件。 |
| `pr_ls.png` | 版图实现目录下的文件列表截图,用于查看 `GDS`、`LVS`、日志和报告等输出内容。 |
| `fm_tree.png` | `Formality` 形式等价检查工程目录树截图,展示 `FM_INFO`、`reports`、`formality_svf` 等目录及其文件结构。 |
| `syn_tree.png` | 综合网表综合工程目录树截图,展示综合输出、报告、重定时/映射结果以及 `syn.tcl` 等文件结构。 |
| `pr_gds.png` | 最终芯片版图 `GDS` 视图截图,显示整体芯片布局、布线结果和外围框架结构。 |
| `fm_verification.png` | `Formality` 形式等价验证结果截图,显示验证成功,`1229` 个比较点全部通过。 |

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@@ -0,0 +1,28 @@
# 答辩材料
本目录包含十分钟系统设计答辩材料:
- `ppt_template.pptx`:大赛官方答辩模板,生成时作为母版使用。
- `defense_presentation.pptx`:18页主讲内容、1页结束页和3页答疑备用内容。
- `defense_presentation.pdf`:用于快速审阅排版的导出版本。
- `defense_speech.md`:逐页演讲稿、时间分配和常见追问速答。
- `build_defense_ppt.py`:可重复生成PPTX的脚本。
当前数据基线为系统设计报告 evidence `d456463`,日期为2026-07-15。Matmul最终评测完成5000组运算,用时4.911765 ms,CRC32 `0x0417d761`匹配,得分100.00%。PPT保留官方模板的母版、主题、背景素材和嵌入字体。
重新生成PPTX需要Python 3、`python-pptx`和Pillow:
```bash
python3 -m pip install python-pptx Pillow
python3 doc/reports/defense/build_defense_ppt.py
```
可使用LibreOffice生成审阅PDF:
```bash
libreoffice --headless --convert-to pdf \
--outdir doc/reports/defense \
doc/reports/defense/defense_presentation.pptx
```
更新性能数据时,需要同时修改系统报告指标、PPT生成脚本和演讲稿,以保持证据口径一致。

View File

@@ -0,0 +1,863 @@
#!/usr/bin/env python3
"""Build the defense deck from the official CICIEC PPT template."""
from __future__ import annotations
import sys
from io import BytesIO
from pathlib import Path
from zipfile import ZipFile
try:
from pptx import Presentation
except ModuleNotFoundError:
sys.path.insert(0, "/tmp/codex_pptx")
from pptx import Presentation
from PIL import Image
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.util import Inches, Pt
ROOT = Path(__file__).resolve().parents[3]
HERE = Path(__file__).resolve().parent
SYSTEM = ROOT / "doc/reports/system"
MLKEM = ROOT / "doc/reports/mlkem_ip"
TEMPLATE = HERE / "ppt_template.pptx"
OUTPUT = HERE / "defense_presentation.pptx"
W = 13.333
H = 7.5
# Template typefaces and palette.
FONT = "HarmonyOS Sans SC"
TITLE_FONT = "Alimama ShuHeiTi Bold"
LATIN_FONT = "Arial"
INK = "202533"
MUTED = "667085"
BLUE = "142DA8"
ACCENT_BLUE = "4874CB"
ORANGE = "EE822F"
YELLOW = "F2BA02"
GREEN = "75BD42"
TEAL = "30C0B4"
RED = "E54C5E"
WHITE = "FFFFFF"
PALE_BLUE = "EDF3FF"
PALE_ORANGE = "FFF3E9"
PALE_TEAL = "EAF9F7"
PALE_GRAY = "F5F7FA"
LINE = "D7DEEA"
def color(value: str) -> RGBColor:
return RGBColor.from_string(value)
with ZipFile(TEMPLATE) as archive:
MEDIA = {
name.rsplit("/", 1)[-1]: archive.read(name)
for name in archive.namelist()
if name.startswith("ppt/media/") and not name.endswith("/")
}
prs = Presentation(str(TEMPLATE))
while len(prs.slides):
sld_id = prs.slides._sldIdLst[0]
prs.part.drop_rel(sld_id.rId)
del prs.slides._sldIdLst[0]
blank = prs.slide_layouts[6]
def add_template_image(slide, media_name, x, y, w, h):
return slide.shapes.add_picture(
BytesIO(MEDIA[media_name]), Inches(x), Inches(y), Inches(w), Inches(h)
)
def add_rect(slide, x, y, w, h, fill=WHITE, line=None, radius=False):
shape_type = MSO_SHAPE.ROUNDED_RECTANGLE if radius else MSO_SHAPE.RECTANGLE
shape = slide.shapes.add_shape(shape_type, Inches(x), Inches(y), Inches(w), Inches(h))
shape.fill.solid()
shape.fill.fore_color.rgb = color(fill)
if line:
shape.line.color.rgb = color(line)
shape.line.width = Pt(1)
else:
shape.line.fill.background()
if radius:
try:
shape.adjustments[0] = 0.06
except Exception:
pass
return shape
def add_text(
slide,
text,
x,
y,
w,
h,
size=17,
fill=INK,
bold=False,
font=FONT,
align=PP_ALIGN.LEFT,
valign=MSO_ANCHOR.TOP,
margin=0.02,
line_spacing=1.05,
):
shape = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
frame = shape.text_frame
frame.clear()
frame.margin_left = frame.margin_right = Inches(margin)
frame.margin_top = frame.margin_bottom = Inches(margin)
frame.vertical_anchor = valign
para = frame.paragraphs[0]
para.text = text
para.alignment = align
para.space_after = Pt(0)
para.line_spacing = line_spacing
para.font.name = font
para.font.size = Pt(size)
para.font.bold = bold
para.font.color.rgb = color(fill)
return shape
def add_rich(slide, runs, x, y, w, h, align=PP_ALIGN.LEFT):
shape = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
frame = shape.text_frame
frame.clear()
frame.margin_left = frame.margin_right = Inches(0.02)
frame.margin_top = frame.margin_bottom = Inches(0.02)
para = frame.paragraphs[0]
para.alignment = align
for text, size, bold, fill, font in runs:
run = para.add_run()
run.text = text
run.font.name = font
run.font.size = Pt(size)
run.font.bold = bold
run.font.color.rgb = color(fill)
return shape
def add_bullets(slide, items, x, y, w, h, size=15, fill=INK, gap=5, accent=BLUE):
shape = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
frame = shape.text_frame
frame.clear()
frame.margin_left = frame.margin_right = Inches(0.02)
frame.margin_top = frame.margin_bottom = Inches(0.02)
for index, item in enumerate(items):
para = frame.paragraphs[0] if index == 0 else frame.add_paragraph()
para.text = "• " + item
para.font.name = FONT
para.font.size = Pt(size)
para.font.color.rgb = color(fill)
para.space_after = Pt(gap)
para.line_spacing = 1.06
return shape
def add_arrow(slide, x, y, w, h, fill=BLUE):
shape = slide.shapes.add_shape(MSO_SHAPE.RIGHT_ARROW, Inches(x), Inches(y), Inches(w), Inches(h))
shape.fill.solid()
shape.fill.fore_color.rgb = color(fill)
shape.line.fill.background()
return shape
def add_line(slide, x, y, w, h=0.02, fill=LINE):
return add_rect(slide, x, y, w, h, fill)
def add_image_contain(slide, path: Path, x, y, w, h, frame=True):
if frame:
add_rect(slide, x - 0.03, y - 0.03, w + 0.06, h + 0.06, WHITE, LINE)
with Image.open(path) as image:
iw, ih = image.size
scale = min(w / iw, h / ih)
pw, ph = iw * scale, ih * scale
return slide.shapes.add_picture(
str(path), Inches(x + (w - pw) / 2), Inches(y + (h - ph) / 2), Inches(pw), Inches(ph)
)
def set_cell(cell, text, size=12, bold=False, fill=INK, bg=None, align=PP_ALIGN.LEFT):
if bg:
cell.fill.solid()
cell.fill.fore_color.rgb = color(bg)
frame = cell.text_frame
frame.clear()
frame.margin_left = frame.margin_right = Inches(0.07)
frame.margin_top = frame.margin_bottom = Inches(0.03)
frame.vertical_anchor = MSO_ANCHOR.MIDDLE
para = frame.paragraphs[0]
para.text = text
para.alignment = align
para.font.name = LATIN_FONT if "seed" in text else FONT
para.font.size = Pt(size)
para.font.bold = bold
para.font.color.rgb = color(fill)
def add_table(slide, rows, x, y, w, h, widths=None, size=12):
shape = slide.shapes.add_table(len(rows), len(rows[0]), Inches(x), Inches(y), Inches(w), Inches(h))
table = shape.table
if widths:
for index, width in enumerate(widths):
table.columns[index].width = Inches(width)
for r, row in enumerate(rows):
for c, value in enumerate(row):
set_cell(
table.cell(r, c),
value,
size=size,
bold=r == 0,
fill=WHITE if r == 0 else INK,
bg=BLUE if r == 0 else (PALE_GRAY if r % 2 == 0 else WHITE),
align=PP_ALIGN.CENTER if c else PP_ALIGN.LEFT,
)
return table
def add_metric(slide, value, label, x, y, w, accent=BLUE, suffix=""):
add_rich(
slide,
[(value, 24, True, accent, TITLE_FONT), (suffix, 13, False, accent, LATIN_FONT)],
x,
y,
w,
0.45,
PP_ALIGN.CENTER,
)
add_text(slide, label, x, y + 0.48, w, 0.45, 11, MUTED, align=PP_ALIGN.CENTER)
def add_number_badge(slide, number, x, y, fill=BLUE):
add_rect(slide, x, y, 0.47, 0.47, fill, radius=True)
add_text(slide, number, x, y + 0.08, 0.47, 0.22, 12, WHITE, True, font=LATIN_FONT, align=PP_ALIGN.CENTER)
def new_content_slide(title, number, subtitle=None):
slide = prs.slides.add_slide(blank)
add_template_image(slide, "image1.png", 0, 0, W, H)
add_template_image(slide, "image2.png", 0.28, -0.02, 1.82, 1.12)
add_text(slide, title, 2.4, 0.48, 8.55, 0.55, 24, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_rect(slide, 6.17, 1.17, 0.98, 0.07, ORANGE)
if subtitle:
add_text(slide, subtitle, 10.9, 0.53, 1.9, 0.28, 9.5, MUTED, align=PP_ALIGN.RIGHT)
add_text(slide, str(number), 12.35, 6.98, 0.72, 0.3, 9, MUTED, font=LATIN_FONT, align=PP_ALIGN.LEFT)
return slide
def new_preview_slide(number, label):
slide = prs.slides.add_slide(blank)
add_template_image(slide, "image1.png", 0, 0, W, H)
add_template_image(slide, "image2.png", 0.3, -0.02, 1.82, 1.12)
add_text(slide, "作品重要亮点预览页", 3.2, 0.48, 6.95, 0.56, 25, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_rect(slide, 6.17, 1.17, 0.98, 0.07, ORANGE)
add_text(slide, label, 10.85, 0.53, 1.95, 0.28, 10, ORANGE, True, align=PP_ALIGN.RIGHT)
add_text(slide, str(number), 12.35, 6.98, 0.72, 0.3, 9, MUTED, font=LATIN_FONT, align=PP_ALIGN.LEFT)
return slide
# 1. Cover
slide = prs.slides.add_slide(blank)
add_template_image(slide, "image3.png", 0, 0, W, H)
add_template_image(slide, "image4.png", 5.93, 0.65, 1.48, 1.48)
add_text(slide, "第十届全国大学生集成电路创新创业大赛", 1.15, 2.2, 11.05, 0.48, 24, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_text(slide, "基于龙芯SoC的后量子密码与矩阵运算加速系统", 1.1, 2.82, 11.15, 0.78, 30, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_rect(slide, 4.2, 3.9, 4.93, 0.62, BLUE, radius=True)
add_text(slide, "龙芯中科杯 · 系统设计答辩", 4.33, 4.05, 4.67, 0.26, 16, WHITE, True, align=PP_ALIGN.CENTER)
add_text(slide, "作品编号:CICC1008439 · 团队:碳基生物", 4.25, 5.25, 4.85, 0.34, 13, INK, True, align=PP_ALIGN.CENTER)
add_text(slide, "证据版本 d456463 · 2026-07-15", 4.4, 5.72, 4.55, 0.3, 11, MUTED, align=PP_ALIGN.CENTER)
# 2. Team introduction
slide = new_content_slide("团队介绍:围绕完整系统形成协同分工", 2, "团队与项目")
add_text(slide, "团队名称:碳基生物", 0.88, 1.48, 4.2, 0.36, 16, BLUE, True)
roles = [
(0.82, BLUE, PALE_BLUE, "系统架构与SoC集成", ["OpenLA500平台集成", "AXI、DMA与多时钟域", "SRAM控制器优化"]),
(4.52, TEAL, PALE_TEAL, "密码算法与RTL实现", ["全参数ML-KEM架构", "Keccak、NTT与多项式算子", "常量时间解封装"]),
(8.22, ORANGE, PALE_ORANGE, "软件验证、测试与文档", ["板级驱动与测试程序", "分层仿真和证据采集", "系统报告与答辩材料"]),
]
for x, accent, pale, title, items in roles:
add_rect(slide, x, 2.08, 3.35, 3.72, pale, accent, radius=True)
add_text(slide, title, x + 0.18, 2.38, 2.99, 0.36, 17, accent, True, TITLE_FONT, PP_ALIGN.CENTER)
add_bullets(slide, items, x + 0.32, 3.12, 2.72, 1.85, size=13, gap=10)
add_rect(slide, 1.0, 6.18, 11.15, 0.55, PALE_GRAY, LINE)
add_text(slide, "以统一接口、可重复测试和版本化证据贯通硬件、软件与文档。", 1.2, 6.34, 10.75, 0.24, 13, INK, True, align=PP_ALIGN.CENTER)
# 3. Contents
slide = prs.slides.add_slide(blank)
add_template_image(slide, "image3.png", 0, 0, W, H)
add_text(slide, "目录", 0.82, 0.48, 1.6, 0.55, 29, BLUE, True, TITLE_FONT)
add_text(slide, "CONTENTS", 0.91, 1.15, 1.5, 0.22, 11, MUTED, font=LATIN_FONT)
contents = [
("1", "项目与系统方案", "开发过程、设计目标与系统数据流", BLUE),
("2", "自主计算IP", "Matmul流水与全参数ML-KEM", ORANGE),
("3", "验证与实现结果", "分层验证、资源时序与最终性能", TEAL),
("4", "心得与后续工作", "工程认识、设计取舍与优化路线", GREEN),
]
for i, (num, title, sub, accent) in enumerate(contents):
y = 1.75 + i * 1.2
add_rect(slide, 2.25, y, 0.58, 0.58, accent)
add_text(slide, num, 2.25, y + 0.13, 0.58, 0.24, 15, WHITE, True, align=PP_ALIGN.CENTER)
add_text(slide, title, 3.18, y - 0.02, 4.35, 0.34, 17, INK, True)
add_text(slide, sub, 3.18, y + 0.42, 5.1, 0.3, 12, MUTED)
# 4. Preview: architecture and contributions
slide = new_preview_slide(4, "系统方案")
add_rect(slide, 0.78, 1.52, 7.75, 4.8, WHITE, LINE)
add_image_contain(slide, SYSTEM / "system_arch.png", 0.94, 1.7, 7.43, 4.45, frame=False)
add_text(slide, "OpenLA500 + DMA数据面 + 三个自主计算IP", 0.95, 6.4, 7.4, 0.3, 13, BLUE, True, align=PP_ALIGN.CENTER)
highlights = [
("01", "硬件自治", "五千组 Matmul 任务一次启动完成", BLUE),
("02", "存储优化", "SRAM连续突发达到1 beat/cycle", ORANGE),
("03", "全参数密码", "单比特流覆盖三等级、三操作", TEAL),
("04", "异步协同", "三时钟域通过全五通道AXI FIFO连接", GREEN),
]
for i, (num, title, desc, accent) in enumerate(highlights):
y = 1.62 + i * 1.18
add_number_badge(slide, num, 8.85, y, accent)
add_text(slide, title, 9.48, y - 0.02, 2.55, 0.3, 15, accent, True)
add_text(slide, desc, 9.48, y + 0.37, 2.85, 0.48, 11.5, INK)
add_rect(slide, 8.78, 6.25, 3.72, 0.58, PALE_BLUE, BLUE)
add_text(slide, "全系统 0 DSP · 三时钟域零违例", 8.92, 6.42, 3.44, 0.24, 12, BLUE, True, align=PP_ALIGN.CENTER)
# 5. Preview: measured results
slide = new_preview_slide(5, "关键结果")
metrics = [
("4.911765", "Matmul 5000组最终时间", BLUE, " ms"),
("827.80", "FFT DMA相对软件加速", ORANGE, "×"),
("48.95–53.33", "ML-KEM DMA相对软件加速", TEAL, "×"),
("0", "DSP48E1使用量", GREEN, " DSP"),
]
for i, (value, label, accent, suffix) in enumerate(metrics):
x = 0.72 + i * 3.12
add_rect(slide, x, 1.62, 2.77, 1.2, WHITE, accent, radius=True)
add_metric(slide, value, label, x + 0.12, 1.77, 2.53, accent, suffix)
add_table(
slide,
[
["验证对象", "测试规模", "结果"],
["ML-KEM主路径KAT", "3等级 × 3操作 × 1000", "9000 / 9000"],
["Decaps隐式拒绝", "3等级 × 100", "300 / 300"],
["ML-KEM板级诊断", "3等级 × 3路径 × 100", "900次零失败"],
["Matmul最终评测", "5000组 · seed a3772ec8", "4.911765 ms · 满分"],
["FFT板级验证", "CPU / DMA各3次", "误差Re=1、Im=2"],
],
0.92,
3.18,
7.2,
3.05,
widths=[2.25, 2.9, 2.05],
size=11.5,
)
add_rect(slide, 8.5, 3.18, 3.88, 3.05, PALE_ORANGE, ORANGE, radius=True)
add_text(slide, "实现质量", 8.82, 3.48, 3.2, 0.34, 18, ORANGE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_metric(slide, "55,066", "Slice LUT · 41.16%", 8.85, 4.04, 1.45, BLUE)
add_metric(slide, "29.5", "BRAM Tile · 8.08%", 10.48, 4.04, 1.45, TEAL)
add_metric(slide, "88,843", "时序端点", 8.85, 5.2, 1.45, GREEN)
add_metric(slide, "+0.070", "全系统最小WNS / ns", 10.48, 5.2, 1.45, ORANGE)
# 6. Development process
slide = new_content_slide("开发过程:以端到端证据驱动迭代", 6, "项目与系统方案")
stages = [
("1", "基础SoC跑通", "完成处理器取指、串口及总线外设联调", BLUE),
("2", "计算IP接入", "实现Matmul、CRC32、FFT与全参数ML-KEM", TEAL),
("3", "数据通路优化", "引入DMA端点、双Bank调度和SRAM连续突发", ORANGE),
("4", "时钟与复位收敛", "完成PLL分域、AXI CDC和复位顺序验证", GREEN),
("5", "分层验证闭环", "建立叶模块、IP、SoC与板级四层证据", BLUE),
("6", "最终性能迭代", "压缩启动与稳态空闲,Matmul评测达到100分", ORANGE),
]
for i, (num, title, desc, accent) in enumerate(stages):
col, row = i % 3, i // 3
x, y = 0.78 + col * 4.12, 1.55 + row * 2.35
add_rect(slide, x, y, 3.68, 1.75, WHITE, accent, radius=True)
add_number_badge(slide, num, x + 0.2, y + 0.25, accent)
add_text(slide, title, x + 0.88, y + 0.23, 2.55, 0.3, 15, accent, True)
add_text(slide, desc, x + 0.25, y + 0.82, 3.18, 0.68, 11.2, INK, align=PP_ALIGN.CENTER)
if i < 2 or 3 <= i < 5:
add_arrow(slide, x + 3.75, y + 0.74, 0.25, 0.17, accent)
add_rect(slide, 1.0, 6.35, 11.15, 0.44, PALE_TEAL, TEAL)
add_text(slide, "每轮迭代同时检查功能正确性、总线可观测性、时序与板级端到端时间。", 1.22, 6.48, 10.7, 0.2, 12.5, INK, True, align=PP_ALIGN.CENTER)
# 7. Contest requirements
slide = new_content_slide("赛题要求与设计响应", 7, "项目与系统方案")
add_text(slide, "赛题不是孤立IP设计,而是完整SoC中的端到端实现。", 0.82, 1.48, 8.3, 0.34, 13, MUTED)
add_table(
slide,
[
["赛题要求 / 工程约束", "本系统的设计响应"],
["基于OpenLA500构建完整SoC", "双主八从AXI架构;CPU、系统、ML-KEM三个异步时钟域"],
["5000组4×4矩阵乘法,禁止DSP", "全LUT乘加、双Bank序列器、在线CRC32与快速通道"],
["实现FIPS 203 ML-KEM", "单比特流覆盖三等级、三操作;KAT与隐式拒绝验证"],
["提高端到端性能", "四通道DMA、端点传输、SRAM连续突发与硬件自主调度"],
],
0.85,
1.98,
11.6,
3.85,
widths=[4.0, 7.6],
size=13,
)
add_rect(slide, 0.9, 6.15, 11.5, 0.58, PALE_TEAL, TEAL)
add_text(slide, "答辩主线:赛题约束 → 系统架构 → 数据流与自主IP → 分层验证 → 实测结果", 1.1, 6.32, 11.1, 0.24, 14, INK, True, align=PP_ALIGN.CENTER)
# 8. Architecture and ownership
slide = new_content_slide("总体架构与自主设计边界", 8, "项目与系统方案")
add_image_contain(slide, SYSTEM / "system_arch.png", 0.7, 1.48, 8.0, 5.15)
add_rect(slide, 9.02, 1.5, 3.45, 3.78, WHITE, TEAL, radius=True)
add_text(slide, "自主实现", 9.25, 1.78, 3.0, 0.34, 18, TEAL, True, TITLE_FONT, PP_ALIGN.CENTER)
add_bullets(
slide,
[
"四通道DMA与加速器端点",
"Matmul、批量序列器、CRC32",
"1024点Radix-2² SDF FFT",
"全参数ML-KEM硬件IP",
"两级AXI跨时钟域桥",
"SRAM控制器突发流水化",
],
9.28,
2.35,
2.95,
2.55,
size=13.2,
gap=5,
)
add_rect(slide, 9.02, 5.5, 3.45, 1.1, PALE_GRAY, LINE, radius=True)
add_text(slide, "赛事基础平台", 9.25, 5.72, 2.95, 0.28, 14, MUTED, True, align=PP_ALIGN.CENTER)
add_text(slide, "OpenLA500、板级SRAM器件、UART及基础外设", 9.25, 6.08, 2.95, 0.36, 11, INK, align=PP_ALIGN.CENTER)
# 9. Data movement, clocks and SRAM
slide = new_content_slide("数据搬运、SRAM与三时钟域协同", 9, "项目与系统方案")
clock_info = [
(0.8, BLUE, "CPU域 · 33.333 MHz", "OpenLA500 / Cache / AXI主端"),
(5.0, TEAL, "系统域 · 50 MHz", "Crossbar / DMA / SRAM / Matmul / FFT"),
(9.2, ORANGE, "ML-KEM域 · 76.923 MHz", "AXI前端 / Keccak / NTT / FSM"),
]
for x, accent, title, desc in clock_info:
add_rect(slide, x, 1.5, 3.3, 0.85, WHITE, accent, radius=True)
add_text(slide, title, x + 0.1, 1.68, 3.1, 0.28, 13.5, accent, True, align=PP_ALIGN.CENTER)
add_text(slide, desc, x + 0.1, 2.02, 3.1, 0.2, 9.5, MUTED, align=PP_ALIGN.CENTER)
add_arrow(slide, 4.26, 1.78, 0.5, 0.25, BLUE)
add_arrow(slide, 8.46, 1.78, 0.5, 0.25, TEAL)
add_text(slide, "AXI双时钟FIFO", 3.84, 2.34, 1.35, 0.2, 9, MUTED, align=PP_ALIGN.CENTER)
add_text(slide, "AXI双时钟FIFO", 8.04, 2.34, 1.35, 0.2, 9, MUTED, align=PP_ALIGN.CENTER)
add_rect(slide, 0.82, 2.85, 5.7, 3.45, WHITE, BLUE, radius=True)
add_text(slide, "硬件数据通路", 1.05, 3.08, 5.2, 0.3, 17, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
flow = [("CPU配置", BLUE), ("DMA", TEAL), ("ExtRAM", YELLOW), ("加速器", ORANGE)]
x = 1.05
for index, (name, accent) in enumerate(flow):
add_rect(slide, x, 3.72, 1.03, 0.58, PALE_GRAY, accent)
add_text(slide, name, x, 3.88, 1.03, 0.22, 11, accent, True, align=PP_ALIGN.CENTER)
if index < 3:
add_arrow(slide, x + 1.08, 3.9, 0.35, 0.18, accent)
x += 1.43
add_text(slide, "CPU只配置任务,DMA、SRAM与加速器完成批量搬运和计算。", 1.02, 4.65, 5.25, 0.5, 12, INK, align=PP_ALIGN.CENTER)
add_text(slide, "复位顺序:sys → mlkem → cpu;释放前AXI valid保持为0。", 1.02, 5.42, 5.25, 0.38, 11, MUTED, align=PP_ALIGN.CENTER)
add_rect(slide, 6.82, 2.85, 5.65, 3.45, WHITE, ORANGE, radius=True)
add_text(slide, "SRAM连续突发优化", 7.05, 3.08, 5.2, 0.3, 17, ORANGE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_text(slide, "优化前", 7.12, 3.63, 0.75, 0.24, 10.5, MUTED, True)
for i in range(4):
accent = BLUE if i % 2 == 0 else "E3E7EF"
add_rect(slide, 8.08 + i * 0.72, 3.58, 0.42, 0.36, accent)
add_text(slide, "优化后", 7.12, 4.18, 0.75, 0.24, 10.5, ORANGE, True)
for i in range(4):
add_rect(slide, 8.08 + i * 0.48, 4.13, 0.42, 0.36, TEAL)
add_metric(slide, "200", "理论单向带宽", 7.15, 4.82, 2.0, ORANGE, " MB/s")
add_metric(slide, "1", "无反压连续读写", 9.52, 4.82, 2.0, TEAL, " beat/cycle")
add_text(slide, "读数据寄存保持R通道稳定;Bank选择随事务锁存。", 7.12, 5.9, 5.0, 0.32, 11, INK, align=PP_ALIGN.CENTER)
# 10. Matmul
slide = new_content_slide("Matmul:一次启动完成5000组流水任务", 10, "自主计算IP")
add_image_contain(slide, SYSTEM / "matmul_dataflow_gantt.png", 0.65, 1.5, 9.55, 5.3)
add_rect(slide, 10.45, 1.5, 2.02, 5.3, WHITE, BLUE, radius=True)
add_text(slide, "关键节拍", 10.65, 1.78, 1.62, 0.3, 17, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
for y, value, label, accent in [
(2.26, "128 B", "每组A/B读取", BLUE),
(3.18, "≈22 cyc", "单Bank乘加延迟", GREEN),
(4.10, "2×6 B", "每元素CRC更新", ORANGE),
(5.02, "0 B", "快速模式结果写回", TEAL),
]:
add_text(slide, value, 10.66, y, 1.62, 0.3, 18, accent, True, TITLE_FONT, PP_ALIGN.CENTER)
add_text(slide, label, 10.66, y + 0.34, 1.62, 0.26, 10, MUTED, align=PP_ALIGN.CENTER)
add_text(slide, "最后一组退休后仍等待CRC FIFO排空,再产生DONE。", 10.7, 6.03, 1.55, 0.5, 10.5, INK, align=PP_ALIGN.CENTER)
# 11. ML-KEM architecture
slide = new_content_slide("ML-KEM:单比特流覆盖三等级与三操作", 11, "自主计算IP")
add_image_contain(slide, MLKEM / "mlkem_modules.png", 0.65, 1.48, 8.05, 4.8)
add_rect(slide, 9.0, 1.5, 3.45, 3.95, WHITE, TEAL, radius=True)
add_text(slide, "运行时配置", 9.25, 1.8, 2.95, 0.3, 18, TEAL, True, TITLE_FONT, PP_ALIGN.CENTER)
add_metric(slide, "3", "512 / 768 / 1024", 9.27, 2.28, 1.3, TEAL)
add_metric(slide, "3", "KeyGen / Encaps / Decaps", 10.78, 2.28, 1.35, ORANGE)
add_bullets(
slide,
[
"参数在start时锁存",
"存储按KMAX=4静态分配",
"控制、算子、BRAM三级组织",
"公钥/私钥/密文支持AXI突发窗口",
"无需按安全等级重新综合",
],
9.28,
3.38,
2.95,
1.72,
size=11.8,
gap=4,
)
add_rect(slide, 0.82, 6.36, 11.47, 0.46, PALE_TEAL, TEAL)
add_text(slide, "KeyGen 生成 ek/dk", 1.45, 6.49, 2.45, 0.2, 12, BLUE, True, align=PP_ALIGN.CENTER)
add_arrow(slide, 4.02, 6.5, 0.48, 0.17, BLUE)
add_text(slide, "Encaps 生成 c/ss", 4.62, 6.49, 2.45, 0.2, 12, TEAL, True, align=PP_ALIGN.CENTER)
add_arrow(slide, 7.18, 6.5, 0.48, 0.17, TEAL)
add_text(slide, "Decaps 恢复或拒绝 ss", 7.78, 6.49, 3.05, 0.2, 12, ORANGE, True, align=PP_ALIGN.CENTER)
# 12. ML-KEM key designs
slide = new_content_slide("ML-KEM关键设计:复用、并行与常量时间", 12, "自主计算IP")
panels = [
(0.72, BLUE, PALE_BLUE, "共享Keccak"),
(4.52, TEAL, PALE_TEAL, "双蝶形NTT"),
(8.32, ORANGE, PALE_ORANGE, "Decaps复用"),
]
for x, accent, pale, title in panels:
add_rect(slide, x, 1.55, 3.5, 4.95, pale, accent, radius=True)
add_text(slide, title, x + 0.2, 1.84, 3.1, 0.34, 18, accent, True, TITLE_FONT, PP_ALIGN.CENTER)
# Shared Keccak panel
for i, name in enumerate(["G/H/J哈希", "SampleNTT", "CBD采样"]):
add_rect(slide, 0.98, 2.55 + i * 0.62, 1.15, 0.38, WHITE, LINE)
add_text(slide, name, 0.98, 2.66 + i * 0.62, 1.15, 0.16, 9.5, INK, align=PP_ALIGN.CENTER)
add_arrow(slide, 2.22, 2.67 + i * 0.62, 0.36, 0.16, BLUE)
add_rect(slide, 2.65, 2.83, 1.25, 1.0, WHITE, BLUE)
add_text(slide, "单一\nKeccak-f[1600]", 2.72, 3.08, 1.12, 0.45, 11, BLUE, True, align=PP_ALIGN.CENTER)
add_text(slide, "避免两份额外实例\n约节省10.6k LUT", 1.05, 4.85, 2.82, 0.6, 13, BLUE, True, align=PP_ALIGN.CENTER)
# NTT panel
add_rect(slide, 4.92, 2.6, 1.1, 1.3, WHITE, TEAL)
for i in range(4):
add_rect(slide, 5.08, 2.75 + i * 0.24, 0.78, 0.14, TEAL if i % 2 == 0 else ACCENT_BLUE)
add_arrow(slide, 6.15, 3.08, 0.4, 0.2, TEAL)
add_rect(slide, 6.65, 2.6, 1.08, 1.3, WHITE, TEAL)
add_text(slide, "BU0\nBU1", 6.72, 2.99, 0.94, 0.42, 14, TEAL, True, align=PP_ALIGN.CENTER)
add_text(slide, "4路BRAM无冲突供数\n读-算-写三级调度", 4.95, 4.28, 2.75, 0.58, 12, INK, align=PP_ALIGN.CENTER)
add_text(slide, "4 coeff/cycle · 0 DSP", 4.98, 5.14, 2.72, 0.32, 15, TEAL, True, align=PP_ALIGN.CENTER)
# Decaps panel
for i, (name, accent) in enumerate([("D1–D5 解密恢复", BLUE), ("D6 复用Encaps", TEAL), ("D7 常量时间比较", ORANGE)]):
add_rect(slide, 8.7, 2.5 + i * 0.82, 2.75, 0.5, WHITE, accent)
add_text(slide, name, 8.82, 2.64 + i * 0.82, 2.51, 0.2, 11, accent, True, align=PP_ALIGN.CENTER)
if i < 2:
down = slide.shapes.add_shape(MSO_SHAPE.DOWN_ARROW, Inches(9.88), Inches(3.04 + i * 0.82), Inches(0.38), Inches(0.2))
down.fill.solid(); down.fill.fore_color.rgb = color(accent); down.line.fill.background()
add_text(slide, "Accept与Reject路径\n总周期数完全相等", 8.86, 5.25, 2.44, 0.52, 13, ORANGE, True, align=PP_ALIGN.CENTER)
add_text(slide, "设计取舍:以资源共享和运行时可配置性换取更低的面积与部署复杂度。", 1.0, 6.68, 11.3, 0.28, 13, INK, True, align=PP_ALIGN.CENTER)
# 13. Verification
slide = new_content_slide("四层验证:从算子正确到板级闭环", 13, "验证与实现结果")
bands = [
(1.55, 1.35, 8.25, "板级系统", "真实FPGA、CPU软件、DMA与串口日志", ORANGE),
(2.55, 1.95, 7.05, "SoC集成", "AXI解码、CDC、复位释放、SRAM取指", TEAL),
(3.55, 2.55, 5.85, "IP集成", "Matmul / FFT / DMA / ML-KEM端到端", BLUE),
(4.55, 3.15, 4.65, "叶模块", "Keccak、NTT、蝶形、FIFO、CRC32", GREEN),
]
for y, x, width, title, desc, accent in bands:
add_rect(slide, x, y, width, 0.7, WHITE, accent, radius=True)
add_text(slide, title, x + 0.18, y + 0.17, 1.2, 0.24, 13, accent, True)
add_text(slide, desc, x + 1.45, y + 0.16, width - 1.65, 0.26, 11.5, INK, align=PP_ALIGN.CENTER)
add_rect(slide, 9.88, 1.55, 2.5, 4.75, PALE_ORANGE, ORANGE, radius=True)
add_text(slide, "验证结果", 10.15, 1.82, 1.96, 0.3, 17, ORANGE, True, TITLE_FONT, PP_ALIGN.CENTER)
for i, (value, label, accent) in enumerate([
("9000", "主路径KAT", BLUE),
("300", "隐式拒绝向量", ORANGE),
("900", "ML-KEM板级运行", TEAL),
("100%", "Matmul最终得分", GREEN),
("6", "FFT板级测试", YELLOW),
]):
y = 2.28 + i * 0.76
add_text(slide, value, 10.05, y, 0.95, 0.28, 16, accent, True, TITLE_FONT, PP_ALIGN.RIGHT)
add_text(slide, label, 11.12, y + 0.03, 1.05, 0.26, 10, INK)
add_rect(slide, 1.0, 5.75, 8.55, 0.58, PALE_TEAL, TEAL)
add_text(slide, "算法逐字节比对;板级以零失败、CRC匹配和误差阈值为判据。", 1.18, 5.92, 8.2, 0.24, 12.5, INK, True, align=PP_ALIGN.CENTER)
add_text(slide, "全部通过", 9.98, 6.48, 2.25, 0.36, 20, GREEN, True, TITLE_FONT, PP_ALIGN.CENTER)
# 14. Resources and timing
slide = new_content_slide("实现结果:资源可控,三个时钟域全部收敛", 14, "验证与实现结果")
add_rect(slide, 0.78, 1.5, 5.72, 4.85, WHITE, BLUE, radius=True)
add_text(slide, "FPGA资源利用", 1.05, 1.78, 5.18, 0.3, 17, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
resource_data = [
("Slice LUT", 41.16, "55,066", BLUE),
("Registers", 11.58, "31,000", TEAL),
("BRAM Tile", 8.08, "29.5", YELLOW),
("DSP48E1", 0.0, "0", ORANGE),
]
for i, (label, percent, absolute, accent) in enumerate(resource_data):
y = 2.45 + i * 0.75
add_text(slide, label, 1.02, y, 1.1, 0.24, 11, INK)
add_rect(slide, 2.2, y + 0.02, 2.55, 0.22, "E5E9F1")
if percent:
add_rect(slide, 2.2, y + 0.02, 2.55 * percent / 50, 0.22, accent)
add_text(slide, f"{percent:.2f}%", 4.85, y - 0.02, 0.68, 0.26, 10.5, accent, True, align=PP_ALIGN.RIGHT)
add_text(slide, absolute, 5.6, y - 0.02, 0.55, 0.26, 10, MUTED, align=PP_ALIGN.RIGHT)
add_text(slide, "xc7a200tfbg676-1 · 布局布线100%完成", 1.1, 5.72, 5.08, 0.28, 11.5, MUTED, align=PP_ALIGN.CENTER)
add_rect(slide, 6.82, 1.5, 5.62, 4.85, WHITE, TEAL, radius=True)
add_text(slide, "布局布线后时序", 7.08, 1.78, 5.1, 0.3, 17, TEAL, True, TITLE_FONT, PP_ALIGN.CENTER)
add_table(
slide,
[
["时钟域", "频率", "Setup WNS", "端点"],
["cpu_clk", "33.333 MHz", "+0.737 ns", "17,197"],
["sys_clk", "50.000 MHz", "+0.125 ns", "22,307"],
["mlkem_clk", "76.923 MHz", "+0.070 ns", "31,646"],
],
7.08,
2.35,
5.1,
2.35,
widths=[1.15, 1.35, 1.35, 1.25],
size=10.5,
)
add_metric(slide, "88,843", "时序端点", 7.15, 5.0, 1.45, TEAL)
add_metric(slide, "0", "建立/保持违例", 8.95, 5.0, 1.45, GREEN)
add_metric(slide, "+0.070", "全系统最小WNS / ns", 10.72, 5.0, 1.45, ORANGE)
add_rect(slide, 1.0, 6.58, 11.2, 0.35, PALE_BLUE, BLUE)
add_text(slide, "ML-KEM独立高速时钟域隔离了系统总线布线压力。", 1.2, 6.66, 10.8, 0.18, 11.5, BLUE, True, align=PP_ALIGN.CENTER)
# 15. Performance
slide = new_content_slide("最终性能:Matmul满分与端到端加速", 15, "验证与实现结果")
for i, (value, label, accent, suffix) in enumerate([
("4.911765", "Matmul 5000组最终时间", BLUE, " ms"),
("827.80", "FFT DMA相对软件加速", ORANGE, "×"),
("48.95–53.33", "ML-KEM DMA相对软件加速", TEAL, "×"),
]):
x = 0.85 + i * 4.05
add_rect(slide, x, 1.5, 3.55, 1.05, WHITE, accent, radius=True)
add_metric(slide, value, label, x + 0.15, 1.66, 3.25, accent, suffix)
add_rect(slide, 0.78, 2.92, 7.2, 3.55, WHITE, ORANGE, radius=True)
add_text(slide, "ML-KEM三路径完整往返加速比", 1.02, 3.17, 6.72, 0.3, 16, ORANGE, True, TITLE_FONT, PP_ALIGN.CENTER)
levels = ["512", "768", "1024"]
cpu = [13.04, 13.84, 15.05]
dma = [48.95, 50.41, 53.33]
for i, level in enumerate(levels):
y = 3.74 + i * 0.72
add_text(slide, f"ML-KEM-{level}", 1.0, y + 0.16, 1.15, 0.22, 10.5, INK)
add_rect(slide, 2.25, y, cpu[i] / 60 * 4.65, 0.23, BLUE)
add_rect(slide, 2.25, y + 0.31, dma[i] / 60 * 4.65, 0.23, ORANGE)
add_text(slide, f"{cpu[i]:.2f}×", 2.33 + cpu[i] / 60 * 4.65, y - 0.02, 0.62, 0.2, 8.5, BLUE, True)
add_text(slide, f"{dma[i]:.2f}×", 2.33 + dma[i] / 60 * 4.65, y + 0.29, 0.62, 0.2, 8.5, ORANGE, True)
add_rect(slide, 2.15, 6.04, 0.15, 0.15, BLUE)
add_text(slide, "CPU寄存器路径", 2.4, 6.02, 1.25, 0.2, 9, MUTED)
add_rect(slide, 3.9, 6.04, 0.15, 0.15, ORANGE)
add_text(slide, "DMA窗口路径", 4.15, 6.02, 1.25, 0.2, 9, MUTED)
add_rect(slide, 8.28, 2.92, 4.15, 3.55, PALE_TEAL, TEAL, radius=True)
add_text(slide, "结果解释", 8.55, 3.18, 3.6, 0.3, 16, TEAL, True, TITLE_FONT, PP_ALIGN.CENTER)
add_bullets(
slide,
[
"Matmul CRC32 0x0417d761匹配",
"FFT DMA延迟296.73 μs,误差Re=1、Im=2",
"ML-KEM-512 DMA往返约1.605 ms",
"SRAM连续突发理论带宽200 MB/s",
],
8.55,
3.78,
3.55,
1.85,
size=12,
gap=6,
)
add_text(slide, "随机种子0xa3772ec8 · 最终得分100.00%", 8.55, 5.92, 3.55, 0.34, 10.5, ORANGE, True, align=PP_ALIGN.CENTER)
# 16. Lessons learned
slide = new_content_slide("项目心得:从单点优化走向系统工程", 16, "心得与后续工作")
lessons = [
("端到端优先", "计算核延迟不是唯一指标;启动、搬运、调度和校验共同决定评测时间。", BLUE),
("先正确再加速", "先建立CRC、状态寄存器和分层测试等可观测手段,再压缩流水空闲。", ORANGE),
("取舍必须显式", "Keccak复用、双蝶形NTT和零DSP策略是在面积、吞吐与部署复杂度间的选择。", TEAL),
("证据需要版本化", "报告、软件、RTL和实测日志必须共享同一数据基线,才能保证结论可复现。", GREEN),
]
for i, (title, desc, accent) in enumerate(lessons):
col, row = i % 2, i // 2
x, y = 0.82 + col * 6.0, 1.55 + row * 2.45
add_rect(slide, x, y, 5.55, 1.85, WHITE, accent, radius=True)
add_number_badge(slide, f"0{i+1}", x + 0.25, y + 0.28, accent)
add_text(slide, title, x + 0.95, y + 0.27, 4.2, 0.32, 16, accent, True)
add_text(slide, desc, x + 0.35, y + 0.9, 4.85, 0.58, 12, INK, align=PP_ALIGN.CENTER)
add_rect(slide, 1.0, 6.38, 11.15, 0.42, PALE_ORANGE, ORANGE)
add_text(slide, "最终满分来自软硬件协同,而不是单一模块参数的堆叠。", 1.2, 6.5, 10.75, 0.2, 13, INK, True, align=PP_ALIGN.CENTER)
# 17. Future work
slide = new_content_slide("后续工作:沿性能、验证与工程化继续演进", 17, "心得与后续工作")
future = [
(BLUE, "ML-KEM并行度", "增加Keccak并行路径,扩展NTT蝶形单元并评估面积收益比。"),
(ORANGE, "存储专项验证", "补充SRAM随机反压、跨Bank边界与持续带宽微基准。"),
(TEAL, "实现与功耗证据", "完善I/O约束,使用SAIF/VCD活动率回标提高功耗估计可信度。"),
(GREEN, "版本与回归体系", "统一RTL、软件、测试向量和报告指标,形成自动化回归基线。"),
]
for i, (accent, title, desc) in enumerate(future):
y = 1.48 + i * 1.22
add_number_badge(slide, f"0{i+1}", 0.92, y, accent)
add_text(slide, title, 1.65, y + 0.07, 2.15, 0.3, 15, accent, True)
add_text(slide, desc, 3.92, y + 0.06, 7.85, 0.4, 13, INK)
add_line(slide, 0.95, y + 0.76, 11.15, 0.012, LINE)
add_rect(slide, 1.0, 6.45, 11.15, 0.35, PALE_TEAL, TEAL)
add_text(slide, "目标:在不牺牲标准完整性和可验证性的前提下继续提高系统吞吐。", 1.2, 6.55, 10.75, 0.18, 12.5, INK, True, align=PP_ALIGN.CENTER)
# 18. Summary
slide = new_content_slide("总结:完成从算法IP到板级系统的闭环", 18, "总结与展望")
summary = [
("01", "系统", "构建CPU、DMA、存储与三个计算加速器协同的异构SoC", BLUE),
("02", "数据流", "以SRAM连续突发、DMA端点和双Bank调度降低搬运开销", ORANGE),
("03", "密码IP", "单比特流覆盖ML-KEM三等级、三操作和常量时间拒绝", TEAL),
("04", "工程验证", "零DSP、三个时钟域收敛,并通过仿真与板级分层验证", GREEN),
]
for i, (num, tag, desc, accent) in enumerate(summary):
y = 1.52 + i * 1.08
add_number_badge(slide, num, 0.95, y, accent)
add_text(slide, tag, 1.65, y + 0.08, 1.0, 0.28, 15, accent, True)
add_text(slide, desc, 2.75, y + 0.08, 8.95, 0.36, 14, INK)
add_line(slide, 0.95, y + 0.72, 11.2, 0.012, LINE)
add_rect(slide, 0.92, 6.02, 11.3, 0.62, PALE_ORANGE, ORANGE)
add_rich(
slide,
[
("最终结果:", 12.5, True, INK, FONT),
("5000", 12.5, True, INK, LATIN_FONT),
("组 Matmul 用时4.911765 ms · CRC32匹配 · 得分100.00%", 12.5, True, INK, FONT),
],
1.12,
6.2,
10.9,
0.3,
PP_ALIGN.CENTER,
)
# 19. End
slide = prs.slides.add_slide(blank)
add_template_image(slide, "image3.png", 0, 0, W, H)
add_template_image(slide, "image4.png", 5.92, 0.7, 1.48, 1.48)
add_text(slide, "感谢聆听", 3.45, 2.55, 6.45, 0.75, 34, BLUE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_rect(slide, 4.63, 3.65, 4.08, 0.72, BLUE, radius=True)
add_text(slide, "Q&A", 4.75, 3.83, 3.84, 0.3, 22, WHITE, True, LATIN_FONT, PP_ALIGN.CENTER)
add_text(slide, "中国集成电路未来之星从这里起步!", 3.2, 5.2, 6.95, 0.42, 17, INK, True, align=PP_ALIGN.CENTER)
# 20. Backup: address space
slide = new_content_slide("备用:地址空间与软件控制流程", 20, "答疑备用")
add_table(
slide,
[
["AXI从端", "基地址", "功能"],
["S0", "0x1c00_0000", "BaseRAM / ExtRAM,共8 MB"],
["S5", "0x1f30_0000", "DMA与矩阵批量序列器"],
["S6", "0x1f40_0000", "FFT / ML-KEM共享窗口"],
["S7", "0x1f50_0000", "Matmul控制与数据Bank"],
],
0.8,
1.55,
6.2,
3.75,
widths=[1.0, 2.0, 3.2],
size=12,
)
add_rect(slide, 7.4, 1.55, 4.8, 3.75, WHITE, TEAL, radius=True)
add_text(slide, "软件控制流程", 7.7, 1.83, 4.2, 0.3, 17, TEAL, True, TITLE_FONT, PP_ALIGN.CENTER)
for i, text in enumerate(["写配置寄存器", "配置DMA窗口", "启动硬件", "轮询done", "读取结果 / CRC"]):
y = 2.35 + i * 0.56
add_rect(slide, 8.05, y, 3.5, 0.38, PALE_GRAY, TEAL if i < 3 else BLUE)
add_text(slide, text, 8.15, y + 0.1, 3.3, 0.17, 10.5, INK, True, align=PP_ALIGN.CENTER)
add_rect(slide, 0.92, 5.75, 11.25, 0.62, PALE_TEAL, TEAL)
add_text(slide, "快速路径中CPU不参与逐组Matmul调度;ML-KEM DMA路径只进行少量批量窗口配置。", 1.15, 5.93, 10.8, 0.26, 12.5, INK, True, align=PP_ALIGN.CENTER)
# 21. Backup: KeyGen timing
slide = new_content_slide("备用:ML-KEM-512 KeyGen逐状态周期分解", 21, "答疑备用")
states = [
("G哈希", 27, YELLOW),
("SampleNTT矩阵A", 3213, ORANGE),
("CBD采样", 1229, TEAL),
("NTT", 4172, BLUE),
("多项式基乘", 2096, GREEN),
("密钥编码", 2081, RED),
]
for i, (name, cycles, accent) in enumerate(states):
y = 1.52 + i * 0.72
add_text(slide, name, 0.9, y + 0.1, 1.55, 0.22, 11, INK)
add_rect(slide, 2.5, y + 0.1, 6.45, 0.25, "E5E9F1")
add_rect(slide, 2.5, y + 0.1, 6.45 * cycles / 4500, 0.25, accent)
add_text(slide, f"{cycles:,} cyc", 9.1, y + 0.06, 1.0, 0.25, 10, accent, True, align=PP_ALIGN.RIGHT)
add_rect(slide, 10.45, 1.55, 2.0, 4.3, PALE_ORANGE, ORANGE, radius=True)
add_text(slide, "主要瓶颈", 10.7, 1.88, 1.5, 0.3, 16, ORANGE, True, TITLE_FONT, PP_ALIGN.CENTER)
add_text(slide, "NTT\n30.2%", 10.73, 2.5, 1.45, 0.65, 19, BLUE, True, align=PP_ALIGN.CENTER)
add_text(slide, "SampleNTT\n23.3%", 10.68, 3.55, 1.55, 0.65, 16, ORANGE, True, align=PP_ALIGN.CENTER)
add_text(slide, "两者合计\n53.5%", 10.72, 4.65, 1.48, 0.65, 15, INK, True, align=PP_ALIGN.CENTER)
add_rect(slide, 0.92, 6.25, 11.25, 0.58, PALE_ORANGE, ORANGE)
add_text(slide, "优化优先级:增加采样路径Keccak并行度,其次扩展NTT蝶形单元数量。", 1.12, 6.42, 10.85, 0.24, 12.5, INK, True, align=PP_ALIGN.CENTER)
# 22. Backup: tradeoffs
slide = new_content_slide("备用:设计取舍与优化路线", 22, "答疑备用")
add_table(
slide,
[
["维度", "当前选择", "优势", "代价"],
["安全等级", "运行时k=2/3/4", "单比特流部署", "地址与控制逻辑增加"],
["Keccak", "单核时分复用", "节省约10.6k LUT", "状态间无法重叠"],
["NTT", "双蝶形、4 coeff/cycle", "BRAM无冲突、0 DSP", "吞吐低于多BU实现"],
["控制", "30状态硬连线FSM", "行为清晰、易验证", "串行调度限制性能"],
],
0.72,
1.48,
11.85,
3.62,
widths=[1.4, 3.05, 3.35, 4.05],
size=11.3,
)
add_text(slide, "优化路线", 0.92, 5.42, 1.45, 0.3, 17, ORANGE, True, TITLE_FONT)
roadmap = [
("1", "双Keccak或专用采样核", "预计KeyGen下降15%–20%", ORANGE),
("2", "扩展多BU NTT", "提高至8 coeff/cycle", TEAL),
("3", "完善约束与活动率回标", "提高时序与功耗结论置信度", BLUE),
]
for i, (num, title, desc, accent) in enumerate(roadmap):
x = 0.95 + i * 4.05
add_number_badge(slide, num, x, 5.88, accent)
add_text(slide, title, x + 0.62, 5.86, 2.95, 0.28, 12, accent, True)
add_text(slide, desc, x + 0.62, 6.23, 2.95, 0.4, 10.5, INK)
prs.save(OUTPUT)
print(f"Wrote {OUTPUT} from {TEMPLATE}")

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,115 @@
# 系统设计答辩演讲稿
预计主讲时间:9分45秒。第1至18页为主讲内容,第19页结束,第20至22页仅用于答疑。
## 第1页:封面(0:00—0:15)
各位评委老师好。我们的作品是“基于龙芯SoC的后量子密码与矩阵运算加速系统”。系统以OpenLA500为控制核心,在Artix-7 FPGA上集成DMA、矩阵乘法、FFT和全参数ML-KEM硬件IP。
## 第2页:团队介绍(0:15—0:35)
团队围绕完整系统形成三类协同分工:系统架构与SoC集成负责AXI、DMA、多时钟域和SRAM;密码算法与RTL实现负责ML-KEM及其关键算子;软件验证、测试与文档负责板级程序、分层回归和证据整理。三部分通过统一接口和可重复测试共同迭代。
## 第3页:目录(0:35—0:45)
下面从项目与系统方案、自主计算IP、验证与实现结果,以及心得和后续工作四部分进行汇报。
## 第4页:作品亮点预览——系统方案(0:45—1:15)
系统的核心思路是让CPU负责配置与判断,让硬件负责数据搬运和计算。OpenLA500与DMA构成两个AXI主设备,Matmul、FFT和ML-KEM作为独立外设接入。一次启动可以完成5000组Matmul任务;SRAM连续突发在无反压时达到每周期一个数据拍;单一ML-KEM比特流覆盖三等级、三操作;三个异步时钟域由完整AXI双时钟FIFO连接。全系统DSP使用量为零。
## 第5页:作品亮点预览——关键结果(1:15—1:45)
先给出最终结果。5000组Matmul官方评测用时4.911765毫秒,CRC32期望值与上报值均为0x0417d761,得分100%。FFT的DMA模式相对软件加速827.80倍;ML-KEM的DMA路径相对软件加速48.95到53.33倍。ML-KEM通过9000个主路径KAT、300个隐式拒绝向量和900次板级运行。系统覆盖88843个时序端点且无时序违例。
## 第6页:开发过程总结(1:45—2:10)
开发过程分为六个阶段:先跑通基础SoC和串口,再接入各计算IP;随后以DMA端点、双Bank和SRAM连续突发优化数据通路;再完成PLL分域、AXI跨时钟域和复位验证;最后用叶模块、IP、SoC和板级四层证据持续回归。Matmul从阶段性正确结果迭代到最终满分,说明性能优化必须同时观察功能、总线状态、时序和端到端时间。
## 第7页:赛题要求与设计响应(2:10—2:40)
赛题要求的不是孤立计算核,而是能够运行和验证的完整SoC。针对5000组矩阵计算和零DSP约束,我们设计全LUT乘加核心、双Bank序列器和在线CRC32。针对FIPS 203,实现单比特流三等级、三操作的ML-KEM。针对端到端性能,扩展四通道DMA、加速器端点和SRAM连续突发,使CPU不再逐字搬运,也不参与逐组任务调度。
## 第8页:总体架构与自主设计边界(2:40—3:20)
系统采用双主八从AXI架构。CPU负责程序执行、参数配置和结果判断,DMA负责内存与加速器之间的批量传输,三个加速器具有独立地址空间。
这里明确自主设计边界。OpenLA500、板级SRAM器件、UART及基础外设来自赛事平台。我们完成四通道DMA扩展、Matmul与批量序列器、FFT、ML-KEM、两级AXI跨时钟域桥,以及基础SRAM控制器的突发流水化改造。工作重点是自主计算IP和贯穿SoC的数据通路。
## 第9页:数据搬运、SRAM与三时钟域(3:20—4:05)
CPU域为33.333兆赫;AXI互连、DMA、SRAM、Matmul和FFT位于50兆赫系统域;ML-KEM核心独立运行在76.923兆赫。CPU到系统、系统到ML-KEM的AXI五通道均通过双时钟FIFO跨域。复位按系统域、ML-KEM域、CPU域顺序释放,复位前AXI有效信号保持为零。
我们通过下一地址预驱动、读数据寄存和连续写握手,消除SRAM读数据拍之间的固定空闲周期,实现无反压时每周期一个32位数据拍。50兆赫下理论单向带宽为200 MB每秒。这个数值是接口节拍上限,不作为独立微基准实测值。
## 第10页:Matmul批量流水(4:05—4:50)
CPU只配置源地址、组数和跨步,序列器随后接管5000组任务。每组由CDMA读取128字节A、B矩阵并交替装入两个Bank;一个Bank计算时,另一个Bank可加载下一组。
计算核心使用四个32位无符号乘法器和加法树得到66位结果,稳定后每周期产生一个C元素。结果进入CRC FIFO,FIFO吸收乘加和递归CRC32之间的速率差。快速模式跳过192字节结果写回,但不会跳过计算和CRC。最后一组退休后仍等待CRC完全排空才产生DONE,因此最终CRC覆盖全部逻辑结果。
## 第11页:ML-KEM总体架构(4:50—5:30)
ML-KEM分为控制调度层、算子层和BRAM存储层。算子层包含Keccak、NTT、多项式乘法、采样和压缩解压缩。安全等级k和操作类型在start时锁存,存储按最大等级静态分配,循环边界和地址由k运行时推导。因此同一比特流支持ML-KEM-512、768、1024,以及KeyGen、Encaps和Decaps,无需重新综合。
## 第12页:ML-KEM关键设计(5:30—6:15)
第一,G、H、J哈希、SampleNTT和CBD处于互斥阶段,因此共享一个Keccak-f核,约节省10600个LUT。第二,NTT采用四路Banked BRAM和两个蝶形流水线,四个Bank无冲突提供两对系数,达到每周期四个系数且不使用DSP。第三,Decaps重加密直接复用Encaps状态序列,密文比较逐字节执行且不提前退出,Accept和Reject路径总周期完全相等。设计优先保证全参数支持、标准完整性和面积可控。
## 第13页:四层验证(6:15—6:55)
验证采用四层递进结构。叶模块层将Keccak、NTT、蝶形、FIFO和CRC32与参考模型比较;IP层验证完整控制流;SoC层验证AXI解码、跨时钟域、复位和SRAM取指;板级层由真实CPU软件形成闭环。
ML-KEM通过9000个主路径KAT和300个隐式拒绝向量,板级三等级、三路径共900次运行零失败。FFT在CPU和DMA模式下共运行六次。Matmul最终评测完成5000组随机输入,CRC32匹配并达到满分。
## 第14页:资源与时序(6:55—7:30)
系统在xc7a200tfbg676-1上完成布局布线。使用55066个LUT,占41.16%;31000个寄存器,占11.58%;29.5个BRAM Tile,占8.08%;DSP为零。CPU、系统和ML-KEM域的建立时间WNS分别为正0.737、正0.125和正0.070纳秒,没有建立或保持违例。独立ML-KEM时钟域隔离了系统总线的布线压力。
## 第15页:最终板级性能(7:30—8:20)
Matmul最终评测的随机种子为0xa3772ec8,5000组运行用时4.911765毫秒,平均每组约0.982微秒;在50兆赫系统时钟下约为49.12周期每组,CRC32完全匹配并获得100分。与阶段验证的6.944404毫秒中位值相比,最终时间降低约29.27%,收益来自启动、搬运、调度、计算和CRC全链路协同。
FFT DMA模式延迟296.73微秒,相对软件加速827.80倍,最大误差为实部1、虚部2。ML-KEM改用DMA窗口后,相对软件加速48.95到53.33倍,其中512等级完整往返约1.605毫秒。
## 第16页:项目心得体会(8:20—8:55)
本项目形成四点认识。第一,端到端性能比孤立计算核延迟更重要。第二,必须先建立CRC、状态寄存器和分层测试等可观测手段,再进行激进优化。第三,资源共享和并行度是明确的工程取舍。第四,报告、软件、RTL和实测日志必须共享版本化数据基线。最终满分来自软硬件协同,而不是单一参数堆叠。
## 第17页:后续工作(8:55—9:20)
后续从四方面推进:增加Keccak并行路径并扩展NTT蝶形单元;补充SRAM随机反压、跨Bank边界和持续带宽专项测试;使用SAIF或VCD活动率回标提高功耗结论可信度;统一RTL、软件、测试向量和报告指标,形成自动化回归基线。优化仍以标准完整性和可验证性为前提。
## 第18页:总结(9:20—9:45)
本项目构建了CPU、DMA、共享存储器与三个加速器协同的异构SoC;以SRAM连续突发、DMA端点和双Bank调度优化数据流;实现单比特流三等级、三操作的ML-KEM;并以零DSP完成布局布线和分层验证。最终5000组Matmul用时4.911765毫秒,CRC32匹配,得分100%。我的汇报完毕,谢谢各位老师。
## 常见追问速答
### 为什么设计三个时钟域?
CPU、外部SRAM和ML-KEM算法核心的时序能力不同。分域使ML-KEM运行在76.923 MHz,同时保持SRAM和系统总线在50 MHz可靠工作;跨域由五通道AXI双时钟FIFO完成。
### 200 MB/s是否为实测带宽?
不是。它是50 MHz乘以32位得到的连续传输理论单向上限。板级业务间接验证了连续突发正确性,但当前报告没有独立SRAM微基准。
### 快速模式不写回结果,如何保证正确性?
矩阵核心仍计算全部66位结果,并按标准字节序进入CRC32。DONE只在最后一组退休且CRC FIFO完全排空后产生,因此官方CRC覆盖全部逻辑结果序列。
### Matmul为何能从6.94毫秒降至4.91毫秒?
优化不只发生在乘加核心,而是同时减少软件启动开销、批量调度空闲和SRAM突发间隙,并保持计算与CRC消费重叠。最终每组从约69.4个系统周期降到约49.12个周期。
### 为什么ML-KEM慢于部分论文?
本设计支持单比特流三等级、三种完整操作、SoC接口和零DSP。部分论文针对固定等级或单一操作综合,并使用更多蝶形单元或DSP。当前单Keccak和双蝶形NTT是主要性能限制。
### 如何保证复位前没有操作?
各时钟域采用异步置位、同步撤离,并按sys、mlkem、cpu顺序释放。复位期间AXI valid、加速器start和DMA请求保持为零,系统仿真检查了首次取指前的事务状态。
### 为什么全系统不用DSP?
Matmul零DSP是赛题约束。为了统一资源策略,FFT和ML-KEM乘法也映射到LUT和进位链。这增加LUT消耗,但保证全系统DSP使用量为零。

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

View File

@@ -0,0 +1,781 @@
\documentclass[11pt,a4paper,twoside]{article}
% ─── Packages ────────────────────────────────────────────────
\usepackage{ctex}
\usepackage[top=2.5cm, bottom=2.5cm, left=2.8cm, right=2.8cm]{geometry}
\usepackage{graphicx}
\usepackage{float}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{multirow}
\usepackage{array}
\usepackage{amsmath,amssymb}
\usepackage{hyperref}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{fancyhdr}
\usepackage{tikz}
\usepackage{enumitem}
\usepackage[normalem]{ulem}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{algorithm}
\usepackage{algpseudocode}
% ─── Styling ─────────────────────────────────────────────────
\raggedbottom
\hypersetup{colorlinks=true,linkcolor=black,citecolor=black,urlcolor=blue}
\pagestyle{fancy}
\fancyhead[LO,RE]{ML-KEM硬件IP设计报告}
\fancyhead[RO,LE]{\thepage}
\fancyfoot[C]{}
\setlength{\parskip}{4pt plus 2pt minus 1pt}
\setlength{\parindent}{2em}
\setlength{\headheight}{14pt}
\setlength{\intextsep}{6pt plus 2pt}
\setlength{\textfloatsep}{8pt plus 2pt}
\captionsetup{skip=4pt}
\lstset{basicstyle=\ttfamily\small,breaklines=true,frame=single,numbers=left,numberstyle=\tiny,xleftmargin=2em,language=Verilog}
\newcommand{\Zq}{\mathbb{Z}_q}
\newcommand{\etal}{\textit{et al.}}
\title{\textbf{ML-KEM后量子密钥封装硬件IP核\\设计与验证}}
\author{碳基生物\\[4pt] \small 团队编号:CICC1008439\\[8pt] \normalsize 龙芯中科杯·2026全国大学生集成电路创新创业大赛}
\date{}
\begin{document}
% ================================================================
% 封 面
% ================================================================
\begin{titlepage}
\thispagestyle{empty}
\begin{center}
\vspace*{30pt}
\includegraphics[width=0.45\textwidth]{logo_cicc.png}
\vspace{36pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 第十届}
\vspace{4pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 全国大学生集成电路创新创业大赛}
\end{center}
\vspace{80pt}
\begin{flushleft}
\fontsize{14pt}{22pt}\selectfont
报告类型:\uline{\hfill MLKEM IP设计报告\hfill} \\[18pt]
参赛杯赛:\uline{\hfill 龙芯中科杯\hfill} \\[18pt]
作品名称:\uline{\hfill ML-KEM后量子密钥封装硬件IP核设计与验证\hfill} \\[18pt]
队伍编号:\uline{\hfill CICC1008439\hfill} \\[18pt]
团队名称:\uline{\hfill 碳基生物\hfill}
\end{flushleft}
\end{titlepage}
\tableofcontents
\newpage
% ================================================================
\section{绪论}
\subsection{设计背景}
ML-KEM(Module-Lattice-based Key-Encapsulation Mechanism,FIPS 203 \cite{fips203})是NIST于2024年8月发布的后量子密码标准,源自CRYSTALS-Kyber \cite{kyber},用于替代RSA和ECC在密钥交换中的角色。其安全性建立在模格上的带误差学习问题(MLWE)之上,多项式环为$\Zq[x]/(x^{256}+1)$,素数模$q=3329$,多项式次数$n=256$。
软件实现的ML-KEM在嵌入式处理器上存在显著性能瓶颈 \cite{dang2022,xing2023}——以ML-KEM-768为例,一轮完整的密钥生成、封装和解封装在通用CPU上需要数百万个时钟周期。本文设计的硬件IP核\texttt{mlkem\_top}旨在通过专用数据通路和计算资源时分复用,在FPGA平台上实现高性能、低面积的ML-KEM加速。
\subsection{关键设计特性}
本IP核在单一硬件模块内具有以下特性:
\begin{enumerate}[label=(\arabic*)]
\item \textbf{运行时三等级支持}:通过$k\_i\in\{2,3,4\}$端口在运行时选择ML-KEM-512/768/1024安全等级,存储资源按$K_{MAX}=4$静态分配,无需重综合。
\item \textbf{全操作覆盖}:支持KeyGen(FIPS 203算法16)、Encaps(算法17)和Decaps(算法18,含FO变换隐式拒绝)。
\item \textbf{Keccak核跨阶段复用}:单一\texttt{keccak\_core}实例在G/H/J哈希、SampleNTT采样和CBD采样三个消费者之间时分复用,是面积优化的最大贡献因素。
\item \textbf{Decaps重加密路径复用}:D6步的K-PKE重加密直接复用整条Encaps流水线的全部FSM状态,避免重复实现加密数据通路。
\item \textbf{逐字节流式I/O}:公钥$ek$、私钥$dk$和密文$c$通过BRAM窗口逐字节装载与回读,免去超宽顶层总线。
\item \textbf{NIST KAT完全验证}:三种等级、三种操作全部逐字节比对NIST FIPS 203 KAT标准答案通过。
\end{enumerate}
\subsection{代码规模}
RTL代码总计约5,517行(不含测试平台),其中\texttt{mlkem\_top.v}(顶层FSM集成+数据通路+三库存储管理)约2,320行,各叶子算子模块合计约3,197行。全部采用SystemVerilog编写,统一使用\texttt{valid/ready}流式握手接口。
% ================================================================
\section{IP模块规格}
\subsection{算法参数}
\texttt{mlkem\_top}的运行时参数由输入端口$k\_i$和$op\_i$在\texttt{start\_i}脉冲时刻锁存至内部寄存器$k\_r$和$op\_r$,后续所有数据通路宽度、存储子区间基地址和循环次数均由$k\_r$推导。表\ref{tab:params}列出三种安全等级的密钥和密文尺寸。
\begin{table}[htbp]
\centering
\caption{运行时安全等级参数}
\label{tab:params}
\begin{tabular}{cccccccc}
\toprule
$k\_i$ & 方案 & $K$ & $\eta_1$ & $(d_u,d_v)$ & ek(B) & dk(B) & ct(B) \\
\midrule
2 & ML-KEM-512 & 2 & 3 & (10,4) & 800 & 1632 & 768 \\
3 & ML-KEM-768 & 3 & 2 & (10,4) & 1184 & 2400 & 1088 \\
4 & ML-KEM-1024 & 4 & 2 & (11,5) & 1568 & 3168 & 1568 \\
\bottomrule
\end{tabular}
\end{table}
固定参数:模数$q=3329$、多项式次数$n=256$、$\eta_2=2$(所有等级)、共享密钥32字节。
\subsection{顶层端口信号}
\texttt{mlkem\_top}的端口按功能分为四组。表\ref{tab:ports}列出主要信号。
\begin{table}[htbp]
\centering
\caption{mlkem\_top主要端口}
\label{tab:ports}
\small
\begin{tabular}{lll}
\toprule
\textbf{信号} & \textbf{位宽} & \textbf{功能} \\
\midrule
clk, rst\_n & 1, 1 & 时钟与低电平异步复位 \\
k\_i, op\_i & 3, 2 & 安全等级(2/3/4)与操作码(0=KG, 1=Enc, 2=Dec) \\
d\_i, z\_i, msg\_i & 256×3 & KeyGen种子$d$、隐式拒绝种子$z$、Encaps消息$m$ \\
start\_i & 1 & 启动脉冲,锁存$k\_i$和$op\_i$ \\
busy\_o, done\_o & 1, 1 & 运行标志与完成脉冲 \\
ss\_o & 256 & 共享密钥输出(done\_o时有效) \\
ek\_in\_we/addr/byte & 1,11,8 & Encaps公钥流式预装载 \\
dk\_in\_we/addr/byte & 1,12,8 & Decaps私钥流式预装载(自动路由至dkp\_bram/ek\_bram/寄存器) \\
c\_in\_we/addr/byte & 1,11,8 & Decaps密文流式预装载 \\
dbg\_* & 多种 & 调试抽头:系数、ek/dk/ct字节、中间哈希值 \\
\bottomrule
\end{tabular}
\end{table}
握手协议分三阶段:\texttt{ST\_IDLE}状态下通过流式端口逐字节预装载数据;\texttt{start\_i}脉冲启动并锁存参数;\texttt{busy\_o}拉高期间执行计算;\texttt{done\_o}脉冲时\texttt{ss\_o}和BRAM产物有效。所有256-bit端口采用字节0在低位的约定。
Decaps私钥预装载路径中,\texttt{dk\_in\_*}端口根据写入地址自动将字节流路由至不同目的地:地址$[0,384K)$写入\texttt{dkp\_bram}($\hat{s}$编码),$[384K,768K+32)$写入\texttt{ek\_bram}($\hat{t}$编码$\|\rho$),$[768K+32,768K+64)$和$[768K+64,768K+96)$分别写入$H(ek)$和$z$的寄存器。
% ================================================================
\section{总体架构设计}
\subsection{设计原则}
\texttt{mlkem\_top}的架构遵循三条核心原则。
\textbf{原则一:存储按最大等级分配,运行时参数递推。} 多项式系数存储库以$K_{MAX}=4$(可容纳28个多项式,每个256系数)静态配置深度,$k\_r$仅影响读写地址生成逻辑中的基地址和循环边界。字节存储库(ek\_bram、dkp\_bram、ct\_bram)同样按最大密钥尺寸(1568/1536/1568字节)分配。运行时地址计算通过$k\_r$以纯组合逻辑递推完成,无需额外的运行时地址表或状态寄存器。
\textbf{原则二:Keccak核全阶段时分复用。} Keccak-f[1600]置换是设计中面积最大的单一算子(OOC综合约5,300 LUT)。G/H/J哈希族、SampleNTT(SHAKE-128)和CBD(SHAKE-256)三个消费者处于互斥的FSM阶段,设计将所有Keccak请求复用至单一\texttt{keccak\_core}实例。输入侧通过\texttt{sel\_sha3/sel\_snt/sel\_cbd}多路选择器切换,输出侧将置换结果广播至全体消费者,仅当前激活阶段采样有效信号。
\textbf{原则三:Decaps重加密完全复用Encaps流水线。} FIPS 203算法18的D6步需要以恢复的消息$m'$和随机种子$r'$重新执行一次K-PKE加密以产生参考密文$c'$。这一流程与算法17的Encaps操作的数据通路完全同构。设计将$m'$和$r'$分别写入原有的$m\_r$和$r\_r$寄存器,\texttt{ek\_bram}中保持原始公钥$ek$不变,随后将FSM直接转移至Encaps流水线的首个状态\texttt{ENC\_LOAD},整条12状态的Encaps数据通路被完整复用。
\subsection{模块层次结构}
图\ref{fig:mlkem_modules}给出\texttt{mlkem\_top}的内部层次结构。设计分为三个逻辑层:控制调度层(FSM + 地址生成 + 数据通路复用)、算子计算层(7个已验证的叶子模块)和存储层(7个BRAM实例)。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.92\textwidth]{mlkem_modules.png}
\caption{mlkem\_top内部三层模块结构}
\label{fig:mlkem_modules}
\end{figure}
\subsection{顶层FSM调度}
全部运算由5-bit状态机集中调度,从\texttt{ST\_IDLE}出发按$op\_r$分支为三条数据通路。图\ref{fig:fsm}给出状态转移图。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.92\textwidth]{fsm.png}
\caption{mlkem\_top顶层FSM状态转移图}
\label{fig:fsm}
\end{figure}
KeyGen路径对应FIPS 203算法16,共7个主状态(不含ST\_IDLE和ST\_DONE)。各状态间的数据传递通过多项式存储库完成:前序状态将结果写入BRAM,后续状态从BRAM读取。
\begin{algorithm}[H]
\caption{KeyGen数据通路(FIPS 203算法16)}
\begin{algorithmic}[1]
\State \textbf{ST\_G}:$G(d \| z) \rightarrow (\rho, \sigma)$,单块SHA3-512,约1,800周期
\State \textbf{ST\_A}:对全部$K^2$个$(j,i)$索引执行SampleNTT$(\rho \| j \| i) \rightarrow \hat{A}[i][j]$,逐系数写入\texttt{bank\_a}
\State \textbf{ST\_C}:CBD$_{\eta_1}(\sigma, i) \rightarrow s[i]$,CBD$_{\eta_1}(\sigma, K+i) \rightarrow e[i]$,写入\texttt{bank\_se}
\State \textbf{ST\_N}:NTT$(s[i]) \rightarrow \hat{s}[i]$,NTT$(e[i]) \rightarrow \hat{e}[i]$,原位更新\texttt{bank\_se}
\State \textbf{ST\_M}:$\hat{t}[i] = \hat{e}[i] + \sum_{j=0}^{K-1} \hat{A}[i][j] \circ \hat{s}[j]$,逐点乘通过\texttt{poly\_mul\_sync},累加写入\texttt{bank\_t}
\State \textbf{ST\_E}:byteEncode$_{12}(\hat{t}) \| \rho \rightarrow ek$,byteEncode$_{12}(\hat{s}) \rightarrow dk_{pke}$,写入\texttt{ek\_bram}和\texttt{dkp\_bram}
\State \textbf{ST\_H}:SHA3-256$(ek) \rightarrow H(ek)$,多块吸收(块数$=\lceil(ek\_bytes+1)/136\rceil$)
\end{algorithmic}
\end{algorithm}
Encaps路径对应FIPS 203算法17,共12个主状态。
\begin{algorithm}[H]
\caption{Encaps数据通路(FIPS 203算法17)}
\begin{algorithmic}[1]
\State \textbf{ST\_ENC\_H}:SHA3-256$(ek) \rightarrow H(ek)$
\State \textbf{ST\_ENC\_G}:$G(m \| H(ek)) \rightarrow (K, r)$,单块SHA3-512
\State \textbf{ST\_ENC\_A}:重新生成$\hat{A}^T$矩阵(SampleNTT,行列索引交换),写入\texttt{bank\_a}
\State \textbf{ST\_ENC\_TDEC}:byteDecode$_{12}(ek) \rightarrow \hat{t}[i]$,逐系数解码至\texttt{bank\_a}
\State \textbf{ST\_ENC\_C}:CBD$_{\eta_1}(r, 0) \rightarrow y$,CBD$_{\eta_2}(r, K) \rightarrow e_1$,CBD$_{\eta_2}(r, 2K) \rightarrow e_2$,写入\texttt{bank\_se}和\texttt{bank\_t}
\State \textbf{ST\_ENC\_N}:NTT$(y) \rightarrow \hat{y}$,原位更新\texttt{bank\_se}
\State \textbf{ST\_ENC\_U}:$\hat{A}^T \circ \hat{y}$逐点乘后INTT,再加$e_1$得$u$,写入\texttt{bank\_se}
\State \textbf{ST\_ENC\_C1}:Compress$_{d_u}(u)$后byteEncode$_{d_u} \rightarrow c_1$字节,写入\texttt{ct\_bram}
\State \textbf{ST\_ENC\_E2MV}:将$e_2$从\texttt{bank\_t}搬迁至\texttt{bank\_a},为V步累加准备
\State \textbf{ST\_ENC\_V}:$\hat{t} \circ \hat{y}$逐点乘后INTT,加$e_2$和Decompress$_1(m)$得$v$,写入\texttt{bank\_t}
\State \textbf{ST\_ENC\_C2}:Compress$_{d_v}(v)$后byteEncode$_{d_v} \rightarrow c_2$字节,拼接至\texttt{ct\_bram}
\State \textbf{输出}:$ss = K$
\end{algorithmic}
\end{algorithm}
Decaps路径对应FIPS 203算法18,前5个主状态完成D1--D5步解密恢复,随后复用整条Encaps流水线(D6重加密),最后以一个比较状态(D7)完成隐式拒绝密钥选择。这是硬件设计中最复杂的控制流,也是Decaps流水线复用创新的集中体现。
\begin{algorithm}[H]
\caption{Decaps数据通路(FIPS 203算法18,含流水线复用)}
\begin{algorithmic}[1]
\State \textbf{ST\_DEC\_DECOMP}(D1):byteDecode$_{d_u}(c_1) \rightarrow$ Decompress$_{d_u} \rightarrow u'$,byteDecode$_{d_v}(c_2) \rightarrow$ Decompress$_{d_v} \rightarrow v'$,写入\texttt{bank\_se}和\texttt{bank\_a}
\State \textbf{ST\_DEC\_SDEC}(D2):byteDecode$_{12}(dk_{pke}) \rightarrow \hat{s}[i]$,逐系数解码至\texttt{bank\_a}
\State \textbf{ST\_DEC\_NTT}(D2续):NTT$(u'[i]) \rightarrow \hat{u}[i]$,原位更新\texttt{bank\_se}
\State \textbf{ST\_DEC\_W}(D3):$\hat{s}[j] \circ \hat{u}[j]$逐点乘后INTT,$v'$减去累加和得$w$,写入\texttt{bank\_t}
\State \textbf{ST\_DEC\_MENC}(D4):Compress$_1(w)$后byteEncode$_1 \rightarrow m'$
\State \textbf{ST\_DEC\_G}(D5):$G(m' \| H(ek)) \rightarrow (K', r')$
\State \textbf{ST\_DEC\_J}(D5续):$J(z \| c) \rightarrow \bar{K}$(隐式拒绝备用密钥)
\State \textbf{流水线复用}(D6):将$m'$写入$m\_r$、$r'$写入$r\_r$,跳转至\textbf{ST\_ENC\_LOAD},完整复用Encaps路径全部12个状态,产生参考密文$c'$(存入\texttt{ct\_bram})
\State \textbf{ST\_DEC\_CMP}(D7):逐字节比较$c'$(\texttt{ct\_bram})与原始$c$(\texttt{c\_in\_bram}),常量时间无早退;$c' = c$时输出$K'$,否则输出$\bar{K}$
\end{algorithmic}
\end{algorithm}
% ================================================================
\section{各功能模块数据通路与控制逻辑}
\subsection{Keccak-f[1600]置换核与哈希族}
\texttt{keccak\_core}模块实现24轮连续Keccak-f[1600]置换,内部结构为简单的迭代流水线:1600-bit状态寄存器$\rightarrow$组合\texttt{keccak\_round}$\rightarrow$写回状态寄存器。\texttt{keccak\_round}为纯组合逻辑,实现Keccak \cite{fips202} 的$\theta/\rho/\pi/\chi/\iota$五步映射,其中$\theta$步的5路XOR归约和$\chi$步的非线性变换是面积消耗的主要来源。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.92\textwidth]{keccak_core.png}
\caption{Keccak-f[1600]核数据通路与共享机制}
\label{fig:keccak_core}
\end{figure}
\texttt{sha3\_top\_shared}模块在\texttt{keccak\_core}之上封装了SHA3/SHAKE协议层,包括1088-bit速率域/512-bit容量域的填充、domain separator拼接(SHA3末尾\texttt{01}、SHAKE末尾\texttt{1111})以及多块顺序吸收的状态管理。支持三种模式:SHA3-512($G$函数,单块64字节吸收)、SHA3-256($H$函数,多块吸收,块数$=\lceil(ek\_bytes+1)/136\rceil$)和SHAKE-256($J$函数和PRF派生)。
\textbf{共享Keccak的复用机制}通过两级多路选择实现。输入侧:三个消费者的1600-bit状态和\texttt{valid}信号经\texttt{sel\_*}信号选择后送入\texttt{keccak\_core};选择信号由FSM状态直接推导(例如\texttt{sel\_snt = (st==ST\_A || st==ST\_ENC\_A)})。输出侧:\texttt{keccak\_core}的置换结果和\texttt{valid\_o}广播至所有消费者,各消费者内部仅在自己激活的上下文中采样,天然实现了无冲突分派。此复用方案将Keccak的硬件开销从三份实例(约16,000 LUT)降至一份(约5,300 LUT)。
\subsection{NTT核}
\texttt{ntt\_core}模块实现256点前向/逆向数论变换,采用双蝶形流水线加4路无冲突Banked BRAM的架构。系数存储使用4个128$\times$12-bit Block RAM(\texttt{coeff\_bram\_4way})替代先前的256个离散LUT寄存器,每Bank支持1读1写(sd\_bram 1R1W端口),不同蝶形对在每层中的读写访问天然落在互斥的Bank上,因此无Bank端口竞争。图\ref{fig:ntt_core}给出数据通路与控制状态机。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.92\textwidth]{ntt_core.png}
\label{fig:ntt_core}
\end{figure}
读-算-写三级流水线的节拍如下:第t周期通过地址生成器给出两个蝶形对的读地址(从系数索引j推导),BRAM在1拍延迟后于t+1周期返回数据;两个独立的\texttt{butterfly\_unit\_pipe}(u\_bf0和u\_bf1)各自接收一对系数并送入8级流水Barrett蝶形,于t+9周期产生结果;写回逻辑通过8级延迟线将写地址与蝶形输出对齐后写入对应Bank。由于每个Bank每周期只处理1次读和1次写,整个NTT以4 coeff/cycle的吞吐率完成7层蝶形迭代。
读和写回路径均以循环迭代方式处理每一步,BRAM的同步读延迟(1拍)被融入流水线的前端而不增加额外的等待周期。每层蝶形内的所有系数对在发射完毕后,流水线排空等待约8拍。逆向NTT在完成7层蝶形后,通过\texttt{S\_OUT\_SCALE}状态将每个系数乘以$3303\bmod q$以完成末尾缩放,缩放操作复用同一个Barrett模乘流水线实例,系数通过单个Bank端口顺序读出和写回。
\texttt{zeta\_rom}存储128个12-bit旋转因子,位反转索引,ROM综合为LUT。
\subsection{多项式乘法与Barrett模乘}
\texttt{poly\_mul\_sync}实现NTT域两个多项式的逐点乘法,即对128个系数对$(a_0,a_1)$和$(b_0,b_1)$按$c_0=a_0b_0+a_1b_1\zeta\bmod q$和$c_1=a_0b_1+a_1b_0\bmod q$计算。内部调度为三阶段:LOAD(256个系数,每周期一对)$\rightarrow$ RUN(128次basecase,每次2周期)$\rightarrow$ OUTPUT(256个系数)。
\texttt{basecase\_mul}内部数据通路包含5个\texttt{barrett\_mul\_pipe}流水线实例。$c_0$路径串联两次Barrett模乘(先算$a_1b_1\bmod q$,再算$(a_1b_1)\zeta\bmod q$)再加$a_0b_0\bmod q$,在当前工作频率下不构成时序瓶颈。
\texttt{barrett\_mul} \cite{barrett} 基于恒等式$a\cdot b\bmod q\approx(a\cdot b\cdot\lfloor 2^{24}/q\rfloor)\gg 24$实现模约简。对于$q=3329$,$\lfloor 2^{24}/3329\rfloor=5039$。实现流程为:计算$p=a\cdot b$(24-bit乘积)$\rightarrow$计算$qe=(p\cdot 5039)\gg 24$(商估计)$\rightarrow$计算$r=p-qe\cdot 3329$(余数估计)$\rightarrow$两次条件减$q$修正(保证$r<q$)。该模块已通过流水线化改造支持高频率工作。
\subsection{采样模块}
\texttt{sample\_ntt\_sync\_shared}根据FIPS 203算法14(SampleNTT)从种子$\rho$和索引$(j,i)$生成$\hat{A}$矩阵的一个多项式(256个系数)。内部通过SHAKE-128吸收$\rho\|j\|i$(34字节)后连续挤出字节流,每个12-bit候选值仅在$x<q$(即$x<3329$)时被接受,接受率约81.3\%。逐系数通过\texttt{valid/ready}握手输出,直接写入\texttt{bank\_a}。
\texttt{sample\_cbd\_sync\_shared}实现中心二项分布CBD$_\eta$采样。对于$\eta=2$,从PRF(SHAKE-256)输出中取4位形成2对独立比特,计算$(\text{bit}_0+\text{bit}_1)-(\text{bit}_2+\text{bit}_3)$得到分布值。对于$\eta=3$(仅ML-KEM-512),取6位形成3对。模块通过\texttt{valid/ready}握手逐系数输出,直接写入\texttt{bank\_se}或\texttt{bank\_t}。
两个采样模块均在内部完成Keccak请求的排队:在吸收阶段结束后向共享\texttt{keccak\_core}发起置换请求,等待核返回结果后继续挤出字节。由于采样模块与SHA3族消费者处于互斥的FSM阶段,对共享核的竞争不存在。
\subsection{压缩与解压缩}
\texttt{comp\_decomp\_sync}实现Compress$_d$和Decompress$_d$函数。Compress$_d(x)=\lfloor(2^d/q\cdot x)\rfloor\bmod 2^d$,Decompress$_d(y)=\lfloor(q/2^d\cdot y)\rfloor$。实现将除数$q$替换为Barrett风格的$5039\cdot 2^{-24}$近似,避免组合除法器。模块采用全流水架构(\texttt{ready\_o}恒为高),逐系数通过\texttt{valid/ready}握手输入输出,吞吐为每周期一个系数。
\subsection{多项式存储库}
三系数存储库是数据通路的交换中枢,全部基于\texttt{sd\_bram}(1R/1W、1周期寄存读延迟,综合为Block RAM)。表\ref{tab:banks}列出配置和内容。
\begin{table}[htbp]
\centering
\small
\caption{多项式系数存储库配置}
\label{tab:banks}
\begin{tabular}{cccp{5.5cm}}
\toprule
\textbf{实例} & \textbf{尺寸} & \textbf{物理BRAM} & \textbf{存储内容} \\
\midrule
bank\_a & 12-bit $\times$ 4096 & 1 RAMB36 + 1 RAMB18 & $\hat{A}[i][j]$矩阵(slot 0至$K^2-1$) \\
bank\_se & 12-bit $\times$ 2048 & 1 $\times$ RAMB36 & $\hat{s}/\hat{e}$(KeyGen)、$\hat{y}$(Encaps)、$\hat{u}$(Decaps) \\
bank\_t & 12-bit $\times$ 1024 & 1 $\times$ RAMB18 & $\hat{t}$、MAC累加和、$v$、$w$ \\
\bottomrule
\end{tabular}
\end{table}
槽位布局为:$\hat{A}$占用slot 0至$K^2-1$(基地址0),$\hat{s}$占用slot $K^2$至$K^2+K-1$,$\hat{e}$占用slot $K^2+K$至$K^2+2K-1$,$\hat{t}$占用slot $K^2+2K$至$K^2+3K-1$。所有槽位寻址在运行时由$k\_r$递推,例如$\hat{s}$基地址$\texttt{slot\_s\_rt}=K^2$。
库的读写端口在多个FSM状态之间分时复用。\texttt{bank\_a}的读端口在\texttt{ST\_M}($\hat{A}$矩阵读取)、\texttt{ST\_ENC\_U}($\hat{A}^T$读取)、\texttt{ST\_ENC\_V}($\hat{t}$读取)和调试回读之间通过组合多路选择器切换,无额外仲裁逻辑。写端口接收来自\texttt{ST\_A}(SampleNTT输出)、\texttt{ST\_ENC\_TDEC}(字节解码)和\texttt{ST\_DEC\_DECOMP}($v'$写入)的数据。
三个字节存储库(\texttt{ek\_bram}、\texttt{dkp\_bram}、\texttt{ct\_bram})各为8-bit $\times$ 2048配置,加上\texttt{c\_in\_bram}(8-bit $\times$ 2048,Decaps输入密文专用),合计4个字节BRAM。\texttt{c\_in\_bram}与\texttt{ct\_bram}的物理分离是Decaps D7步比较器的关键设计前提——$c'$与$c$的逐字节比较需要同时从两块BRAM读取,独立端口避免了竞争。
% ================================================================
\section{验证方案}
\subsection{分层验证策略}
验证分为四个层级:
\begin{enumerate}[label=(\arabic*)]
\item \textbf{叶子模块级}:独立验证\texttt{keccak\_core}、\texttt{ntt\_core}、\texttt{sample\_ntt\_sync}、\texttt{sample\_cbd\_sync}、\texttt{poly\_mul\_sync}、\texttt{comp\_decomp\_sync}共6个算子模块与Python参考模型的一致性。每个模块通过其\texttt{TB/}子目录下的专用测试平台验证。
\item \textbf{操作级KAT验证}:对$k\in\{2,3,4\}$的每种操作,通过参数化测试平台将硬件输出与NIST FIPS 203 KAT响应文件的标准答案逐字节比对。Encaps和Decaps测试覆盖正常路径和隐式拒绝路径(损坏密文$ct\_n$)。
\item \textbf{端到端协议验证}:\texttt{tb\_mlkem\_hello\_world}验证KeyGen$\rightarrow$Encaps$\rightarrow$Decaps完整往返的共享密钥一致性;\texttt{tb\_mlkem\_two\_inst}验证两个独立实例(一侧生成+封装,另一侧解封装)的互操作性。
\item \textbf{系统级诊断}:在SoC集成环境中,通过CPU寄存器路径和DMA窗口路径各执行100次迭代,验证硬件与软件参考实现的一致性及数据传输路径的正确性。
\end{enumerate}
\subsection{测试平台与KAT测试向量}
表\ref{tab:tbs}列出全部操作级和系统级测试平台。参数化测试平台通过XSIM的\texttt{xelab -generic\_top K=n}选项编译安全等级,通过\texttt{+CASE=n}运行时选项选择KAT用例编号。
\begin{table}[htbp]
\centering
\caption{测试平台清单}
\label{tab:tbs}
\begin{tabular}{lccc}
\toprule
\textbf{测试平台} & \textbf{覆盖操作} & \textbf{安全等级} & \textbf{测试向量来源} \\
\midrule
tb\_mlkem\_kg\_katK & KeyGen & K=2/3/4 & NIST KAT 1000用例/级 \\
tb\_mlkem\_enc\_katK & Encaps & K=2/3/4 & NIST KAT 1000用例/级 \\
tb\_mlkem\_dec\_katK & Decaps & K=2/3/4 & NIST KAT 1000用例/级 + ct\_n \\
tb\_mlkem\_hello\_world & 全流程 & K=3 & 固定测试向量 \\
tb\_mlkem\_two\_inst & 双实例 & K=3 & 固定测试向量 \\
mlkem\_test (SoC) & CPU/DMA & K=2/3/4 & KAT count=0确定性输入 \\
\bottomrule
\end{tabular}
\end{table}
KAT测试向量来自NIST FIPS 203的KAT响应文件,由Python脚本解析为每用例独立的hex文件。每个KAT用例包含种子$d$、$z$、$m$以及期望的$ek$、$dk$、$c$和共享密钥。Decaps测试额外包含$ct\_n$(伪造密文)和$ss\_n$(对应拒绝路径输出),用于验证隐式拒绝机制(Decaps在$c'\neq c$时输出$J(z\|c)$而非$K'$)。
Decaps的KAT测试平台还通过\texttt{dbg\_*}调试抽头逐阶段(D0--D7)验证中间量,包括$\rho/\sigma/r$等哈希输出、D1解压缩结果、D3减法中间值、D4恢复消息$m'$等,确保问题可精确定位到具体计算步骤。
\subsection{系统级诊断测试}
SoC诊断程序\texttt{mlkem\_test}实现三条独立测试路径:
\textbf{软件参考路径}在33 MHz Loongson CPU上运行纯C语言ML-KEM实现,记录各阶段周期数作为加速比的基准,并验证结果自洽性与KAT标准答案一致性。
\textbf{CPU寄存器路径}通过AXI寄存器接口直接控制IP核:写入CONFIG配置、通过D[0..7]/Z[0..7]写入种子、通过PRE\_SEL/ADR/DAT序列逐字节预装载公钥/私钥/密文、写CTRL.start启动、轮询STATUS.done、通过RDB\_SEL/ADR/DAT读回结果。该路径验证了IP核的AXI从机接口逻辑和寄存器级控制流的正确性。
\textbf{DMA窗口路径}利用SoC的DMA控制器在系统存储器和IP核的EK/DK/CT窗口(偏移\texttt{0x1000/0x2000/0x3000})之间批量搬移数据,将数据传输开销从数千次AXI单字节事务降低为数次DMA配置操作。该路径验证了IP核存储器窗口与DMA控制器之间的数据搬移正确性,以及批量传输模式相对于逐字节读写的效率提升。
每种路径对每个安全等级执行1000次迭代,记录自洽性(\texttt{ss\_enc == ss\_dec})和KAT标准答案一致性。
% ================================================================
\section{实现结果与测试数据}
\subsection{FPGA资源利用}
ML-KEM IP核在Xilinx Artix-7 \cite{artix7} \texttt{xc7a200tfbg676-1}上完成布局布线后的独立资源利用如表\ref{tab:mlkem_util}所示。数据来自Vivado \cite{vivado} 2019.2布局布线后报告。
\begin{table}[htbp]
\centering
\caption{mlkem\_top布局布线后资源利用}
\label{tab:mlkem_util}
\begin{tabular}{lccc}
\toprule
\textbf{资源} & \textbf{已用} & \textbf{可用} & \textbf{利用率} \\
\midrule
Slice LUTs & 21,697 & 133,800 & 16.2\% \\
Slice FFs & 15,826 & 267,600 & 5.9\% \\
Block RAM Tile & 9.0 & 365 & 2.5\% \\
~~RAMB36E1 & 2 & 365 & 0.5\% \\
~~RAMB18E1 & 14 & 730 & 1.9\% \\
DSP48E1 & 0 & 740 & 0.0\% \\
\bottomrule
\end{tabular}
\end{table}
DSP使用量为零体现了设计的主动约束——所有乘法均强制映射至LUT和CARRY4逻辑,不消耗任何DSP48E1资源。ntt\_core和poly\_mul\_sync的系数存储使用Block RAM(合计8个RAMB18E1),避免了大量LUTRAM的消耗,使ML-KEM在无DSP约束下仍将LUT利用率控制在16.2\%。
表\ref{tab:modules_util}给出布局布线后的子模块级资源分解。
\begin{table}[htbp]
\centering
\small
\caption{mlkem\_top主要子模块资源利用}
\label{tab:modules_util}
\begin{tabular}{lcccr}
\toprule
\textbf{子模块} & \textbf{LUT} & \textbf{FF} & \textbf{BRAM} & \textbf{DSP} \\
\midrule
keccak\_core (Keccak-f[1600]置换核) & 5,258 & 1,618 & 0 & 0 \\
sample\_cbd\_sync\_shared & 2,739 & 3,186 & 0 & 0 \\
sample\_ntt\_sync\_shared & 2,109 & 1,669 & 0 & 0 \\
poly\_mul\_sync (含basecase\_mul) & 2,058 & 584 & 4 RAMB18 & 0 \\
sha3\_top\_shared (哈希族封装) & 1,955 & 2,378 & 0 & 0 \\
ntt\_core (蝶形流水线+系数存储) & 1,900 & 1,062 & 4 RAMB18 & 0 \\
comp\_decomp\_sync & 620 & 319 & 0 & 0 \\
系数存储BRAM(bank\_a/se/t) & 974 & 0 & 2 RAMB36 + 2 RAMB18 & 0 \\
字节BRAM(ek/dkp/ct/c\_in) & 2,600 & 0 & 4 RAMB18 & 0 \\
其它(FSM/多路复用/顶层连线) & 1,484 & 5,010 & 0 & 0 \\
\midrule
\textbf{合计} & \textbf{21,697} & \textbf{15,826} & \textbf{2 RAMB36 + 14 RAMB18} & \textbf{0} \\
\bottomrule
\end{tabular}
\end{table}
Keccak核以5,258 LUT位居子模块面积首位,其1600-bit状态寄存器和$\theta/\rho/\pi/\chi/\iota$五步全组合置换逻辑的宽数据通路是面积消耗的主要来源——若采用非共享方案,三份独立实例的累计开销将超过16,000 LUT。ntt\_core的系数存储采用4个RAMB18E1 Block RAM实现256$\times$12-bit寄存器文件,将与此相关的LUT和FF开销压缩至接近零。poly\_mul\_sync同样使用4个RAMB18E1进行数据缓冲。合计14个RAMB18E1(含系数存储bank\_a/se/t和字节存储ek/dkp/ct/c\_in)用于全部系数和中间数据的片上存储,充分体现了BRAM在数据密集型计算通路中的面积优势。
\subsection{时序性能}\label{sec:timing}
表\ref{tab:timing}列出布局布线后的时序收敛情况。系统外设工作在\texttt{sys\_clk}(50 MHz),而ML-KEM IP核内部使用独立的高速时钟\texttt{mlkem\_clk}(77 MHz),通过跨时钟域(CDC)模块与系统总线交互。
\begin{table}[htbp]
\centering
\caption{布局布线后时序收敛结果}
\label{tab:timing}
\begin{tabular}{lccr}
\toprule
\textbf{时钟域} & \textbf{周期} & \textbf{Setup WNS} & \textbf{违例端点} \\
\midrule
cpu\_clk & 30 ns (33 MHz) & +2.716 ns & 0 / 17,197 \\
sys\_clk & 20 ns (50 MHz) & +0.146 ns & 0 / 69,558 \\
mlkem\_clk & 12.98 ns (77 MHz) & +0.240 ns & 0 / 25,432 \\
\bottomrule
\end{tabular}
\end{table}
ML-KEM IP在77 MHz的\texttt{mlkem\_clk}域下通过时序收敛,模块内最差路径位于\texttt{ntt\_core}内部蝶形单元的Barrett流水线数据通路,Slack为+0.240 ns。设计采用异步时钟域方案,通过CDC逻辑隔离了SoC系统总线与高吞吐量密码核,使得ML-KEM计算通路能够脱离50 MHz的系统级走线拥塞限制。尽管CDC模块引入了少量的跨域同步延迟与硬件开销,但这使得ML-KEM能够充分利用自身的时序裕量,最大化计算性能。
\subsection{功耗分析}
布局布线后功耗估计如表\ref{tab:power}所示。ML-KEM IP核的片上功耗约0.115 W(动态),占SoC总动态功耗(0.409 W)的28.1\%。
\begin{table}[htbp]
\centering
\caption{ML-KEM IP功耗估计(布局布线后,典型工艺角)}
\label{tab:power}
\begin{tabular}{lcc}
\toprule
\textbf{功耗来源} & \textbf{功率(W)} & \textbf{说明} \\
\midrule
Slice Logic & 0.046 & LUT翻转 + FF时钟功耗 \\
Signals & 0.052 & 互联线翻转功耗 \\
Block RAM & 0.017 & 14个RAMB18 + 2个RAMB36的读写功耗 \\
\midrule
\textbf{ML-KEM合计} & \textbf{0.115} & 占SoC动态功耗28.1\% \\
\bottomrule
\end{tabular}
\end{table}
\subsection{功能验证结果}
\subsubsection{KAT逐字节比对}
表\ref{tab:kat_results}汇总全部安全等级和操作的KAT验证结果。
\begin{table}[htbp]
\centering
\caption{KAT验证结果汇总}
\label{tab:kat_results}
\begin{tabular}{lccccc}
\toprule
\textbf{操作} & \textbf{K=2} & \textbf{K=3} & \textbf{K=4} & \textbf{用例数} & \textbf{通过率} \\
\midrule
KeyGen(算法16) & PASS & PASS & PASS & 1000/级 & 100\% \\
Encaps(算法17) & PASS & PASS & PASS & 1000/级 & 100\% \\
Decaps正常路径(算法18)& PASS & PASS & PASS & 1000/级 & 100\% \\
Decaps隐式拒绝路径 & PASS & PASS & PASS & 100/级 & 100\% \\
\bottomrule
\end{tabular}
\end{table}
全部KAT测试用例均逐字节比对NIST标准答案通过,无任何字节级偏差。Decaps隐式拒绝路径($c'_n\neq c$)验证了FO变换中常量时间比较器和$J(z\|c)$拒绝密钥生成逻辑的正确性。
\subsubsection{系统级诊断测试}
SoC集成诊断测试在ML-KEM-768条件下对三种数据路径各执行100次迭代,结果如表\ref{tab:diag}所示。
\begin{table}[htbp]
\centering
\caption{系统级诊断测试结果(ML-KEM-768,100次迭代)}
\label{tab:diag}
\begin{tabular}{lccc}
\toprule
\textbf{测试路径} & \textbf{失败次数} & \textbf{自洽性通过率} & \textbf{KAT通过率} \\
\midrule
SW(纯软件参考) & 0 & 100\% & 100\% \\
CPU寄存器路径 & 0 & 100\% & 100\% \\
DMA窗口路径 & 0 & 100\% & 100\% \\
\bottomrule
\end{tabular}
\end{table}
\subsection{性能分析}
表\ref{tab:perf}列出三种安全等级下软件参考、CPU寄存器路径和DMA窗口路径完成一轮完整往返(KeyGen+Encaps+Decaps)的平均时钟周期数及加速比。数据来自SoC实际运行的100次迭代统计。
\begin{table}[htbp]
\centering
\small
\caption{三路径完整往返性能对比(100次迭代平均值)}
\label{tab:perf}
\begin{tabular}{lrrrrrr}
\toprule
\textbf{安全等级} & \textbf{SW} & \textbf{CPU} & \textbf{DMA} & \textbf{CPU加速比} & \textbf{DMA加速比} & \textbf{DMA/CPU} \\
\midrule
ML-KEM-512 (k=2) & 2,594,034 & 200,471 & 52,995 & 12.94$\times$ & 48.95$\times$ & 3.78$\times$ \\
ML-KEM-768 (k=3) & 4,065,123 & 296,193 & 80,648 & 13.72$\times$ & 50.41$\times$ & 3.67$\times$ \\
ML-KEM-1024 (k=4) & 6,041,204 & 404,476 & 113,273 & 14.94$\times$ & 53.33$\times$ & 3.57$\times$ \\
\bottomrule
\end{tabular}
\end{table}
从数据中可以得出以下结论。CPU寄存器路径相对于纯软件实现了12.94$\times$至14.94$\times$的加速比,加速比随安全等级$k$增大而略有提升——硬件加速器的固定流水线启动开销占比随总计算量的增大而降低。
DMA路径相对于CPU寄存器路径额外贡献了约3.6--3.8$\times$的效率提升。DMA批量传输将公钥、私钥和密文的数千次单字节AXI事务合并为数次Burst传输,大幅降低了总线协议开销。以ML-KEM-512为例,DMA路径的52,995周期单次往返在33 MHz CPU时钟下折算约为1.6 ms,满足了真实SoC环境下的毫秒级响应需求。
\subsection{逐状态性能分解}
为进一步分析各FSM状态对总延迟的贡献,表\ref{tab:state_timing}列出每种操作各状态的周期数(以CASE=0为代表性数据)。
\begin{table}[htbp]
\centering
\small
\caption{KeyGen逐状态性能分解(CASE=0)}
\label{tab:state_timing}
\begin{tabular}{lrrr}
\toprule
\textbf{状态} & \textbf{K=2} & \textbf{K=3} & \textbf{K=4} \\
\midrule
ST\_G($G(d\|K)$) & 27 & 27 & 27 \\
ST\_A(SampleNTT生成Â) & 3,251 & 7,233 & 12,825 \\
ST\_C(CBD采样$s/e$) & 1,229 & 1,693 & 2,257 \\
ST\_N(前向NTT) & 4,172 & 6,258 & 8,344 \\
ST\_M(矩阵向量乘累加) & 2,096 & 4,716 & 8,384 \\
ST\_E(byteEncode编码) & 2,081 & 3,105 & 4,129 \\
ST\_H($H(ek)$哈希) & 979 & 1,468 & 1,957 \\
\midrule
\textbf{总计} & \textbf{13,835} & \textbf{24,500} & \textbf{37,923} \\
\bottomrule
\end{tabular}
\end{table}
KeyGen各状态的周期数呈现出与$K$值的清晰依赖关系。ST\_A(SampleNTT)和ST\_M(矩阵向量乘累加)是最耗时的两个状态,二者合计占总周期的48.0\%(K=2)至65.1\%(K=4),且复杂度均与$K^2$成正比——ST\_A需要生成$K^2$个多项式(每个256系数通过SHAKE-128拒绝采样),ST\_M需执行$K^2$次逐点乘法及$K$路累加。ST\_G(单块SHA3-512)的周期数恒为27,与$K$无关。ST\_N(NTT)在K=3时为6,258周期、K=4时为8,344周期(对$2K$个多项式各执行一次256点NTT),总开销随$K$线性增长。
\begin{table}[htbp]
\centering
\small
\caption{Encaps逐状态性能分解(CASE=0)}
\label{tab:state_enc}
\begin{tabular}{lrrr}
\toprule
\textbf{状态} & \textbf{K=2} & \textbf{K=3} & \textbf{K=4} \\
\midrule
ENC\_LOAD(数据就绪) & 34 & 34 & 34 \\
ENC\_H($H(ek)$) & 980 & 1,469 & 1,958 \\
ENC\_G($G(m\|H(ek))$) & 26 & 26 & 26 \\
ENC\_A(重新生成Â$^T$) & 3,251 & 7,233 & 12,825 \\
ENC\_TDEC(byteDecode t̂) & 1,281 & 1,921 & 2,561 \\
ENC\_C(CBD采样$y/e_1/e_2$)& 1,461 & 1,975 & 2,539 \\
ENC\_N(NTT(y)) & 2,086 & 3,129 & 4,172 \\
ENC\_U($u$向量计算) & 4,707 & 8,632 & 13,605 \\
ENC\_C1(压缩编码$c_1$) & 1,035 & 1,547 & 2,059 \\
ENC\_E2MV($e_2$搬迁) & 258 & 258 & 258 \\
ENC\_V($v$向量计算) & 2,354 & 2,878 & 3,402 \\
ENC\_C2(压缩编码$c_2$) & 522 & 522 & 522 \\
\midrule
\textbf{总计} & \textbf{17,995} & \textbf{29,624} & \textbf{43,961} \\
\bottomrule
\end{tabular}
\end{table}
Encaps中ENC\_U($u$向量计算)是最耗时的单一状态,涉及$\hat{A}^T\circ\hat{y}$逐点乘($K^2$次\texttt{poly\_mul\_sync}调用)和INTT($K$次逆向NTT),其$O(K^2)$复杂度使其在高安全等级时占主导。ENC\_C1(压缩$c_1$)对$K$个多项式逐系数执行Compress$_{d_u}$和byteEncode,总周期数与$K$和$d_u$成正比。ENC\_C2(压缩$c_2$)仅处理单个多项式的Compress$_{d_v}$,周期数恒为522,与$K$无关。
\begin{table}[htbp]
\centering
\small
\caption{Decaps逐状态性能分解(CASE=0)}
\label{tab:state_dec}
\begin{tabular}{lrrr}
\toprule
\textbf{状态} & \textbf{K=2} & \textbf{K=3} & \textbf{K=4} \\
\midrule
DEC\_LOAD(数据就绪) & 2 & 2 & 2 \\
DEC\_DECOMP(D1解压缩) & 8,449 & 11,393 & 14,657 \\
DEC\_SDEC(D2解码ŝ) & 1,281 & 1,921 & 2,561 \\
DEC\_NTT(D2 NTT(u')) & 2,086 & 3,129 & 4,172 \\
DEC\_W(D3计算$w$) & 2,354 & 2,878 & 3,402 \\
DEC\_MENC(D4恢复$m'$) & 513 & 513 & 513 \\
DEC\_G(D5 $G(m'\|h)$) & 26 & 26 & 26 \\
\multicolumn{4}{c}{\textbf{———— D6 流水线复用(=Encaps全部状态) ————}} \\
ENC\_LOAD--ENC\_C2(重加密) & 17,995 & 29,624 & 43,961 \\
DEC\_CMP(D7常量时间比较) & 1,537 & 2,177 & 3,137 \\
\midrule
\textbf{总计} & \textbf{33,237} & \textbf{50,168} & \textbf{70,447} \\
\bottomrule
\end{tabular}
\end{table}
Decaps的性能数据直接验证了设计原则三(流水线复用)的实际效果。D6重加密段的周期数完全等于Encaps的总周期数($K=2$时17,995 vs 17,995;$K=3$时29,624 vs 29,624;$K=4$时43,961 vs 43,961),占总Decaps周期的54.1\%(K=2)至62.4\%(K=4)。D1(DECOMP)是Decaps专用状态中耗时最大的,涉及对密文$c_1$的$K\cdot 32d_u$次Decompress$_{d_u}$操作和对$c_2$的$32d_v$次Decompress$_{d_v}$操作。D7(DEC\_CMP)的常量时间比较器周期数与密文长度成正比($K=2$时768字节、$K=4$时1,568字节),无早退分支,验证了侧信道防护设计。Decaps Accept与Reject路径的总周期数完全相等,进一步确认了隐式拒绝的常量时间特性。
\subsection{其他安全等级结果}
ML-KEM-512和ML-KEM-1024的系统级诊断测试同样全部通过(各100次迭代零失败),证明IP核在全部支持的参数集下功能正确且性能稳定。
% ================================================================
\section{设计评估与对比}
\subsection{设计局限性分析}
尽管本设计在功能完整性、标准合规性和面积效率方面取得了良好结果,但在对各项设计决策进行反思后,以下局限性值得在后续迭代中重点关注。
\textbf{串行FSM架构的性能上限。} 当前30状态硬连线FSM严格按照算法步骤串行执行,各状态之间无任何重叠。以KeyGen为例,ST\_A(SampleNTT生成$\hat{A}$矩阵)与ST\_C(CBD采样)的数据依赖仅在于共享Keccak核,但FSM结构不允许二者在时间上重叠——即便ST\_A使用SHAKE-128而ST\_C使用SHAKE-256,二者完全可以并行访问不同的Keccak实例。根据逐状态性能分解数据(表\ref{tab:state_timing}至\ref{tab:state_dec}),ST\_A在所有等级中均是KeyGen最耗时的单一状态(占比29.2\%--39.4\%),若能与CBD或NTT并行调度,KeyGen总延迟可降低15\%--20\%。
\textbf{双蝶形NTT的吞吐瓶颈。} 本设计的\texttt{ntt\_core}采用双蝶形架构,每周期处理两对系数(4 coeff/cycle),KeyGen阶段完成全部所需NTT操作约4,172周期(K=2)。相比之下,HOPE-MLKEM通过可配置的多BU架构(NBU=1至4)实现2至8 coeff/cycle的吞吐率。在NBU=4配置下,单次NTT仅需约140周期。这一差距是系数级并行度的结构性差异所致——HOPE NB=4可同时处理8 coeff/cycle,而本设计为4 coeff/cycle。
\textbf{DSP零使用的面积代价。} 这一约束使得每个12$\times$12-bit Barrett模乘消耗约200 LUT,而一个DSP48E1即可在单周期内完成同等的乘积累加。ntt\_core和poly\_mul\_sync两个模块总计消耗3,958 LUT,其中大部分面积归因于无DSP的Barrett模乘,在竞赛规则允许的场景下,启用DSP可进一步降低面积。
\textbf{FSM控制逻辑的资源密度。} 硬连线FSM的30个状态各自携带独立的状态转移判据和数十路数据通路多路选择信号。HOPE-MLKEM采用微程序指令控制器,20-bit指令字在移位寄存器中逐拍推进,控制器开销更低。作为对比,本设计FSM及顶层连线归入"其它"类目的开销为1,484 LUT和5,010 FF。
\subsection{与现有工作的对比}
表\ref{tab:comparison}将本设计与近年来代表性的ML-KEM硬件实现进行对比。所有数据均取自各文献报告的FPGA实现结果(Artix-7系列器件)。对比聚焦于三个维度:资源效率(LUT/FF/BRAM/DSP)、设计灵活性(运行时等级可配置性与侧信道防护)以及架构效率(KeyGen周期数和工作频率)。其中周期数反映架构设计与并行度的优劣,工作频率则取决于关键路径延迟和FPGA布局布线质量,二者为相互独立的技术指标。
\begin{table}[htbp]
\centering
\small
\caption{ML-KEM硬件实现对比(FPGA,Artix-7系列)}
\label{tab:comparison}
\begin{tabular}{lccccccc}
\toprule
\textbf{设计} & \textbf{频率} & \textbf{LUT} & \textbf{FF} & \textbf{BRAM} & \textbf{DSP} & \textbf{KG周期} & \textbf{可配置} \\
& (MHz) & & & & & (K=2) & \\
\midrule
\textbf{本设计} & 77 & 21,697 & 15,826 & 9.0 & \textbf{0} & 13,835 & \checkmark \\
\hline
HOPE NB=1 \cite{CHES25hope} & 180 & $\sim$18,000 & $\sim$16,000 & $\sim$15 & $\sim$6 & 3,708 & $\times$ \\
HOPE NB=4 \cite{CHES25hope} & 180 & $\sim$22,000 & $\sim$22,000 & $\sim$17 & $\sim$12 & 1,296 & $\times$ \\
DMG23 \cite{DMG23} & 220 & 9,347 & 8,186 & 6 & 4 & — & $\times$ \\
NKK+23 \cite{NKK23} & 208 & 30,146 & 26,371 & 0 & 4 & 1,102 & $\times$ \\
KJSL24 \cite{KJSL24} & 210 & 25,757 & 18,629 & — & 14 & 1,806 & \checkmark \\
NKLO25 \cite{NKLO25} & 270 & 19,028 & 15,372 & — & — & 1,809 & $\times$ \\
XL21 \cite{XL21} & 161 & 14,197 & — & — & — & 3,767 & $\times$ \\
\bottomrule
\end{tabular}
\end{table}
从对比中可以得出以下观察。在资源效率维度,本设计是唯一完全不消耗DSP资源的实现(0 DSP),这在特定的竞赛约束和平台兼容性需求下具有独特价值。然而,这一约束也直接反映在较高的LUT用量上——本设计的21,697 LUT约为同等级HOPE NB=1的1.2倍。在架构效率维度,本设计13,835周期的KeyGen开销(K=2)与HOPE等设计的1,102--3,708周期存在差距,该差距源于串行FSM架构(无状态间并行)和双蝶形(4 coeff/cycle)相对于多BU架构的并行度限制,属于架构层面的结构性差异。在工作频率维度,本设计与主流设计(161--270 MHz)的时钟频率差异主要由FPGA全局布线拥塞导致——ML-KEM模块与CPU、DMA等模块共享同一器件,跨区域走线增加了路径延迟。在设计灵活性维度,本设计与KJSL24是表中仅有的两个支持运行时等级切换的方案,而本设计额外具备三项独特优势:(1)全操作覆盖,对KeyGen、Encaps和Decaps三种操作均完成了100\% NIST KAT逐字节验证,而多数文献仅报告选定操作的性能数据;(2)系统级SoC集成验证,通过CPU寄存器和DMA双路径在真实硬件平台上完成了100次迭代诊断测试;(3)单比特流三等级全覆盖,无需为不同安全等级维护多套综合结果,显著降低了工程部署复杂度。
值得注意的是,直接逐行比较资源数字存在局限性。不同设计在支持的算法操作范围、侧信道防护强度、I/O接口方式等方面存在显著差异,且各文献报告的Vivado版本、综合策略和时序约束设置均不相同。NKK+23和NKLO25在特定等级下实现了极低的周期数(约1,100--1,800 cycles),但其设计针对固定安全等级优化,不支持运行时重配置。HOPE-MLKEM同样为固定等级设计——其NBU=1配置下的LUT和延迟数据均以K=2单独综合的结果为准,三种安全等级需三套独立的比特流,与本设计的单比特流三等级全覆盖在工程实用性上有所不同。KJSL24是本设计之外唯一支持运行时等级切换的方案。综合来看,本设计在可配置性和无DSP实现方面具有独特优势,而在串行FSM导致的延迟和部分模块的面积效率上存在明确的改进空间。
\subsection{优化路线图}
基于上述分析,后续优化的优先级排序应遵循投入产出比原则。第一优先级是为采样路径(CBD和SampleNTT)引入专用Keccak实例,使ST\_A和ST\_C能够与哈希阶段(ST\_H)并行执行,预计减少KeyGen延迟15\%--20\%,代价为增加约5,300 LUT。第二优先级是实现双BU或多BU并行NTT引擎,需要设计优先级仲裁器和跨BU的数据调度逻辑,可将NTT吞吐提升至4--8 coeff/cycle,使KeyGen延迟进一步降低50\%--60\%。第三优先级是在DSP可用场景下将Barrett模乘映射至DSP48E1硬核,进一步降低ntt\_core和poly\_mul\_sync的LUT用量。
% ================================================================
\section{结论与展望}
本文设计并实现了一款完整的ML-KEM后量子密钥封装硬件IP核。核心贡献总结如下:
\textbf{运行时可重构架构}:通过存储按$K_{MAX}=4$静态分配、运行时参数动态推导的策略,单一比特流即可支持ML-KEM-512/768/1024三种安全等级的KeyGen/Encaps/Decaps全操作,无需为不同等级维护多份综合结果。这一特性在现有文献中极为稀缺——在表\ref{tab:comparison}所列的七个设计中,仅本设计与KJSL24具备运行时等级切换能力。与固定等级设计相比,单比特流方案在FPGA部署场景下避免了多套比特流管理的工程复杂性,尤其适合需要根据信道条件动态调整安全强度的通信场景。
\textbf{高效资源共享}:单一\texttt{keccak\_core}在哈希、采样和CBD三消费者间跨阶段复用,将LUT利用率控制在16.2\%;Decaps D6步重加密复用整条Encaps流水线,避免了约800行RTL的重复实现。
\textbf{完整标准合规}:360个NIST KAT测试用例全部逐字节比对通过,覆盖三种等级三种操作及隐式拒绝路径。端到端协议测试和系统级诊断验证了软硬件协同的完整正确性。
\textbf{显著性能提升}:相对于33 MHz CPU上的软件参考实现,硬件IP在CPU寄存器路径实现12.9--14.9$\times$加速比,在DMA路径实现48.9--53.3$\times$加速比。DMA路径的单次往返延迟约为1.6 ms(K=2),满足了真实SoC环境下的毫秒级响应需求。
后续工作方向包括:(1)引入多Bank交叉访问和NTT计算并行化以进一步提升吞吐;(2)添加功耗平衡和随机延迟插入等侧信道防护措施;(3)将设计移植至国产FPGA平台进行适配性验证。
\begin{thebibliography}{10}
\bibitem{fips203}
National Institute of Standards and Technology.
\emph{FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard}.
August 2024.
\bibitem{fips202}
National Institute of Standards and Technology.
\emph{FIPS 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions}.
August 2015.
\bibitem{kyber}
R.~Avanzi \etal.
\emph{CRYSTALS-Kyber: Algorithm Specifications and Supporting Documentation}.
NIST PQC Round 3 Submission, 2021.
\bibitem{dang2022}
V.~B.~Dang, F.~Farahmand, M.~Andrzejczak, and K.~Gaj.
\emph{Implementing and Benchmarking CRYSTALS-Kyber on FPGAs}.
IEEE Trans. Computers, 71(10):2475--2488, 2022.
\bibitem{xing2023}
Y.~Xing and S.~Li.
\emph{A Compact Hardware Architecture for CRYSTALS-Kyber}.
IEEE Trans. Circuits Syst. I, 70(3):1124--1137, 2023.
\bibitem{barrett}
P.~Barrett.
\emph{Implementing the Rivest Shamir and Adleman Public Key Encryption Algorithm on a Standard Digital Signal Processor}.
CRYPTO 1986, pp. 311--323.
\bibitem{CHES25hope}
E.~Camacho-Ruiz, P.~Navarro-Torrero, and A.~Cabrera~Aldaya.
\emph{HOPE-MLKEM: A Framework for Designing High-Order Side-Channel Protected Hardware Implementations of ML-KEM}.
CHES 2025 (to appear), 2025.
Available: \url{https://github.com/HWSec-CSIC/hope-mlkem}.
\bibitem{DMG23}
V.~B.~Dang, A.~Mohajerani, and K.~Gaj.
\emph{High-Speed Hardware Architectures for CRYSTALS-Kyber}.
IEEE Trans. VLSI Syst., 31(8):1185--1198, 2023.
\bibitem{NKK23}
M.~J.~Nguyen, B.~Kieu-Do, and C.~K.~Koc.
\emph{A High-Performance Hardware Implementation of CRYSTALS-Kyber}.
In Proc. HOST, pp. 123--134, 2023.
\bibitem{KJSL24}
M.~Krausz, G.~Jati, S.~Saha, and D.~Lee.
\emph{A Configurable and Efficient Hardware Implementation of ML-KEM}.
IACR Trans. CHES, 2024(2):213--236, 2024.
\bibitem{NKLO25}
P.~Navarro-Torrero, M.~Krausz, D.~Lee, and A.~O.~Otero.
\emph{Optimized Hardware Accelerator for ML-KEM}.
In Proc. DATE, pp. 1--6, 2025.
\bibitem{XL21}
Y.~Xing and S.~Li.
\emph{Hardware Implementation of CRYSTALS-Kyber}.
In Proc. FCCM, pp. 144--152, 2021.
\bibitem{vivado}
Xilinx Inc.
\emph{Vivado Design Suite User Guide: Synthesis (UG901)}.
v2019.2, 2019.
\bibitem{artix7}
Xilinx Inc.
\emph{7 Series FPGAs Data Sheet: Overview (DS180)}.
v2.6, 2020.
\end{thebibliography}
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -0,0 +1,24 @@
# Report evidence
Generated logs and Vivado reports used by `system_design_report.tex` live here:
- `soc/`: short SoC simulation evidence; `reset_window.vcd` records reset and pre-reset transaction signals
- `build/`: software build logs for the five selected examples
- `vivado/`: timing, utilization, DRC, route and power reports
- `board/`: official matmul evaluation plus FFT and ML-KEM board UART logs
The report currently consumes these board filenames:
- `fft_1.log`, `fft_2.log`, `fft_3.log`
- `fft_dma_1.log`, `fft_dma_2.log`, `fft_dma_3.log`
- `mlkem_test_512.log`, `mlkem_test_768.log`, `mlkem_test_1024.log`
- `mlkem_hello.log`
- `matmul_official.log` (three complete official runs in one file)
Reset screenshots derived from `soc/reset_window.vcd` belong in `../figures/` as
`reset_release.png` and `reset_no_transaction.png`.
Run `../tools/run_report_tests.sh refresh` after replacing evidence. Large generated
artifacts such as `.wdb`, `.jou`, `.str`, implementation checkpoints and bitstreams do
not belong in Git. The short reset VCD may be retained as report evidence; avoid tracing
the complete SoC for long software runs because the result can grow to several GB.

View File

@@ -0,0 +1,390 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:36 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_cdc -details -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/cdc.rpt
| Design : soc_top
| Device : 7a200t-fbg676
| Speed File : -1 PRODUCTION 1.23 2018-06-13
------------------------------------------------------------------------------------------------------------------------
CDC Report
ID Severity Count Description
------ -------- ----- -------------------------------------------------------
CDC-3 Info 1 1-bit synchronized with ASYNC_REG property
CDC-6 Warning 20 Multi-bit synchronized with ASYNC_REG property
CDC-7 Critical 1 Asynchronous reset unknown CDC circuitry
CDC-9 Info 3 Asynchronous reset synchronized with ASYNC_REG property
CDC-11 Critical 2 Fan-out from launch flop to destination clock
CDC-15 Warning 313 Clock enable controlled CDC structure detected
Source Clock: sys_clk
Destination Clock: cpu_clk
CDC Type: User Ignored
Row ID Severity Description Depth Exception Source (From) Destination (To)
--- ------ -------- ---------------------------------------------- ----- ------------------- ---------------------------------------------- ------------------------------------------------------------
1 CDC-11 Critical Fan-out from launch flop to destination clock 2 Asynch Clock Groups pll_clk.u_rst_sys/delay_reg[1]/C pll_clk.u_rst_cpu/delay_reg[0]/CLR
2 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/arFifo/popCC_ptrToPush_reg[2:0]/C u_Axi_CDC/arFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
3 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/awFifo/popCC_ptrToPush_reg[2:0]/C u_Axi_CDC/awFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
4 CDC-11 Critical Fan-out from launch flop to destination clock 2 Asynch Clock Groups pll_clk.u_rst_sys/delay_reg[1]/C u_Axi_CDC/bFifo/bufferCC_12/buffers_0_reg/CLR
5 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/bFifo/pushCC_pushPtrGray_reg[2:0]/C u_Axi_CDC/bFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
6 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[0]/D
7 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[1]/D
8 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[2]/D
9 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[3]/D
10 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMC/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[4]/D
11 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_0_5/RAMC_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[5]/D
12 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[6]/D
13 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[7]/D
14 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[8]/D
15 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[9]/D
16 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMC/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[10]/D
17 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_6_11/RAMC_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[11]/D
18 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[12]/D
19 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[13]/D
20 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[14]/D
21 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[15]/D
22 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMC/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[16]/D
23 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_12_17/RAMC_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[17]/D
24 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[18]/D
25 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[19]/D
26 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[20]/D
27 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[21]/D
28 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMC/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[22]/D
29 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_18_23/RAMC_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[23]/D
30 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[24]/D
31 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[25]/D
32 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[26]/D
33 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[27]/D
34 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMC/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[28]/D
35 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_24_29/RAMC_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[29]/D
36 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_30_35/RAMA/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[30]/D
37 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_30_35/RAMA_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[31]/D
38 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_30_35/RAMB/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[32]/D
39 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/rFifo/ram_reg_0_7_36_39/RAMB_D1/CLK u_Axi_CDC/rFifo/_zz_ram_port1_reg[39]/D
40 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/rFifo/pushCC_pushPtrGray_reg[3:0]/C u_Axi_CDC/rFifo/pushToPopGray_buffercc/buffers_0_reg[3:0]/D
41 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/wFifo/popCC_ptrToPush_reg[3:0]/C u_Axi_CDC/wFifo/popToPushGray_buffercc/buffers_0_reg[3:0]/D
42 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_confreg/int_out_or_q2_reg/C u_cpu/u_csr/csr_estat_reg[2]/D
43 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_cdma_matmul_bridge/seq_done_flag_reg/C u_cpu/u_csr/csr_estat_reg[3]/D
44 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_matmul_axi_slave/done_reg/C u_cpu/u_csr/csr_estat_reg[4]/D
45 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/mlkem_intr_sync_reg[1]/C u_cpu/u_csr/csr_estat_reg[5]/D
Source Clock: sys_clk
Destination Clock: mlkem_clk
CDC Type: User Ignored
Row ID Severity Description Depth Exception Source (From) Destination (To)
--- ------ -------- ------------------------------------------------------- ----- ------------------- -------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
1 CDC-7 Critical Asynchronous reset unknown CDC circuitry 0 Asynch Clock Groups pll_clk.u_rst_sys/delay_reg[1]/C pll_clk.u_rst_mlkem/delay_reg[0]/CLR
2 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[0]/D
3 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[1]/D
4 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[2]/D
5 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[3]/D
6 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[4]/D
7 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_0_5/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[5]/D
8 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[6]/D
9 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[7]/D
10 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[8]/D
11 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[9]/D
12 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[10]/D
13 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_6_11/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[11]/D
14 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_12_17/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[12]/D
15 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_12_17/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[13]/D
16 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_12_17/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[14]/D
17 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_12_17/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[15]/D
18 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_30_35/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[32]/D
19 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_30_35/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[33]/D
20 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_30_35/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[34]/D
21 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_30_35/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[35]/D
22 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[36]/D
23 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[37]/D
24 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[38]/D
25 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[39]/D
26 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[40]/D
27 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_36_41/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[41]/D
28 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_42_47/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[42]/D
29 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_42_47/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[43]/D
30 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_42_47/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[44]/D
31 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_48_53/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[48]/D
32 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/ram_reg_0_3_48_53/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/_zz_ram_port1_reg[49]/D
33 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/pushCC_pushPtrGray_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
34 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[0]/D
35 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[1]/D
36 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[2]/D
37 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[3]/D
38 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[4]/D
39 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_0_5/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[5]/D
40 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[6]/D
41 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[7]/D
42 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[8]/D
43 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[9]/D
44 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[10]/D
45 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_6_11/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[11]/D
46 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_12_17/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[12]/D
47 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_12_17/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[13]/D
48 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_12_17/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[14]/D
49 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_12_17/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[15]/D
50 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_30_35/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[32]/D
51 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_30_35/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[33]/D
52 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_30_35/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[34]/D
53 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_30_35/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[35]/D
54 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_36_41/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[36]/D
55 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_48_53/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[48]/D
56 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/ram_reg_0_3_48_53/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/_zz_ram_port1_reg[49]/D
57 CDC-9 Info Asynchronous reset synchronized with ASYNC_REG property 2 Asynch Clock Groups pll_clk.u_rst_sys/delay_reg[1]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/bufferCC_12/buffers_0_reg/CLR
58 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/pushCC_pushPtrGray_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
59 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/popCC_ptrToPush_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
60 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/popCC_ptrToPush_reg[3:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/popToPushGray_buffercc/buffers_0_reg[3:0]/D
61 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[0]/D
62 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[1]/D
63 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[2]/D
64 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[3]/D
65 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[4]/D
66 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_0_5/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[5]/D
67 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[6]/D
68 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[7]/D
69 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[8]/D
70 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[9]/D
71 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[10]/D
72 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_6_11/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[11]/D
73 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[12]/D
74 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[13]/D
75 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[14]/D
76 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[15]/D
77 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[16]/D
78 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_12_17/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[17]/D
79 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[18]/D
80 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[19]/D
81 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[20]/D
82 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[21]/D
83 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[22]/D
84 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_18_23/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[23]/D
85 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[24]/D
86 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[25]/D
87 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[26]/D
88 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[27]/D
89 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[28]/D
90 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_24_29/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[29]/D
91 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[30]/D
92 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[31]/D
93 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[32]/D
94 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[33]/D
95 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[34]/D
96 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_30_35/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[35]/D
97 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/ram_reg_0_7_36_36/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/_zz_ram_port1_reg[36]/D
98 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/pushCC_pushPtrGray_reg[3:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/pushToPopGray_buffercc/buffers_0_reg[3:0]/D
Source Clock: cpu_clk
Destination Clock: sys_clk
CDC Type: User Ignored
Row ID Severity Description Depth Exception Source (From) Destination (To)
--- ------ -------- ------------------------------------------------------- ----- ------------------- ---------------------------------------------- ------------------------------------------------------------
1 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[0]/D
2 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[1]/D
3 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[2]/D
4 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[3]/D
5 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[4]/D
6 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_0_5/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[5]/D
7 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[6]/D
8 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[7]/D
9 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[8]/D
10 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[9]/D
11 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[10]/D
12 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_6_11/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[11]/D
13 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[12]/D
14 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[13]/D
15 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[14]/D
16 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[15]/D
17 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[16]/D
18 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_12_17/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[17]/D
19 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[18]/D
20 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[19]/D
21 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[20]/D
22 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[21]/D
23 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[22]/D
24 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_18_23/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[23]/D
25 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[24]/D
26 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[25]/D
27 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[26]/D
28 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[27]/D
29 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[28]/D
30 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_24_29/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[29]/D
31 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[30]/D
32 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[31]/D
33 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[32]/D
34 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[33]/D
35 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[34]/D
36 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_30_35/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[35]/D
37 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_36_41/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[37]/D
38 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_36_41/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[38]/D
39 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_36_41/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[39]/D
40 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_36_41/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[40]/D
41 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_36_41/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[41]/D
42 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[42]/D
43 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[43]/D
44 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[44]/D
45 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[45]/D
46 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[46]/D
47 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_42_47/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[47]/D
48 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMA/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[48]/D
49 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMA_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[49]/D
50 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMB/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[50]/D
51 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMB_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[51]/D
52 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMC/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[52]/D
53 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/arFifo/ram_reg_0_3_48_53/RAMC_D1/CLK u_Axi_CDC/arFifo/_zz_ram_port1_reg[53]/D
54 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/arFifo/pushCC_pushPtrGray_reg[2:0]/C u_Axi_CDC/arFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
55 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[0]/D
56 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[1]/D
57 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[2]/D
58 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[3]/D
59 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[4]/D
60 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_0_5/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[5]/D
61 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[6]/D
62 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[7]/D
63 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[8]/D
64 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[9]/D
65 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[10]/D
66 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_6_11/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[11]/D
67 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[12]/D
68 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[13]/D
69 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[14]/D
70 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[15]/D
71 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[16]/D
72 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_12_17/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[17]/D
73 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[18]/D
74 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[19]/D
75 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[20]/D
76 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[21]/D
77 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[22]/D
78 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_18_23/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[23]/D
79 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[24]/D
80 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[25]/D
81 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[26]/D
82 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[27]/D
83 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[28]/D
84 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_24_29/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[29]/D
85 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[30]/D
86 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[31]/D
87 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[32]/D
88 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[33]/D
89 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[34]/D
90 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_30_35/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[35]/D
91 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_36_41/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[37]/D
92 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_36_41/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[38]/D
93 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_36_41/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[39]/D
94 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_36_41/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[40]/D
95 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_36_41/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[41]/D
96 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[42]/D
97 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[43]/D
98 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[44]/D
99 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[45]/D
100 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[46]/D
101 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_42_47/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[47]/D
102 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMA/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[48]/D
103 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMA_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[49]/D
104 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMB/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[50]/D
105 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMB_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[51]/D
106 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMC/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[52]/D
107 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/awFifo/ram_reg_0_3_48_53/RAMC_D1/CLK u_Axi_CDC/awFifo/_zz_ram_port1_reg[53]/D
108 CDC-9 Info Asynchronous reset synchronized with ASYNC_REG property 2 Asynch Clock Groups pll_clk.u_rst_cpu/delay_reg[1]/C u_Axi_CDC/awFifo/bufferCC_12/buffers_0_reg/CLR
109 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/awFifo/pushCC_pushPtrGray_reg[2:0]/C u_Axi_CDC/awFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
110 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/bFifo/popCC_ptrToPush_reg[2:0]/C u_Axi_CDC/bFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
111 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/rFifo/popCC_ptrToPush_reg[3:0]/C u_Axi_CDC/rFifo/popToPushGray_buffercc/buffers_0_reg[3:0]/D
112 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[0]/D
113 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[1]/D
114 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[2]/D
115 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[3]/D
116 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[4]/D
117 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_0_5/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[5]/D
118 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[6]/D
119 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[7]/D
120 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[8]/D
121 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[9]/D
122 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[10]/D
123 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_6_11/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[11]/D
124 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[12]/D
125 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[13]/D
126 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[14]/D
127 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[15]/D
128 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[16]/D
129 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_12_17/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[17]/D
130 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[18]/D
131 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[19]/D
132 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[20]/D
133 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[21]/D
134 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[22]/D
135 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_18_23/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[23]/D
136 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[24]/D
137 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[25]/D
138 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[26]/D
139 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[27]/D
140 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[28]/D
141 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_24_29/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[29]/D
142 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[30]/D
143 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMA_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[31]/D
144 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMB/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[32]/D
145 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMB_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[33]/D
146 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMC/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[34]/D
147 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_30_35/RAMC_D1/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[35]/D
148 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_Axi_CDC/wFifo/ram_reg_0_7_36_36/RAMA/CLK u_Axi_CDC/wFifo/_zz_ram_port1_reg[36]/D
149 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_Axi_CDC/wFifo/pushCC_pushPtrGray_reg[3:0]/C u_Axi_CDC/wFifo/pushToPopGray_buffercc/buffers_0_reg[3:0]/D
Source Clock: mlkem_clk
Destination Clock: sys_clk
CDC Type: User Ignored
Row ID Severity Description Depth Exception Source (From) Destination (To)
--- ------ -------- ------------------------------------------------------- ----- ------------------- ------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
1 CDC-3 Info 1-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_slave/done_sync_reg[1]/C u_fft_mlkem_axi_slave/mlkem_intr_sync_reg[0]/D
2 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/popCC_ptrToPush_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/arFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
3 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/popCC_ptrToPush_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/awFifo/popToPushGray_buffercc/buffers_0_reg[2:0]/D
4 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/ram_reg_0_3_0_5/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/_zz_ram_port1_reg[4]/D
5 CDC-9 Info Asynchronous reset synchronized with ASYNC_REG property 2 Asynch Clock Groups pll_clk.u_rst_mlkem/delay_reg[1]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/bufferCC_12/buffers_0_reg/CLR
6 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/pushCC_pushPtrGray_reg[2:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/bFifo/pushToPopGray_buffercc/buffers_0_reg[2:0]/D
7 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[0]/D
8 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[1]/D
9 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[2]/D
10 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[3]/D
11 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[4]/D
12 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_0_5/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[5]/D
13 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[6]/D
14 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[7]/D
15 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[8]/D
16 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[9]/D
17 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[10]/D
18 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_6_11/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[11]/D
19 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[12]/D
20 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[13]/D
21 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[14]/D
22 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[15]/D
23 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[16]/D
24 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_12_17/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[17]/D
25 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[18]/D
26 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[19]/D
27 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[20]/D
28 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[21]/D
29 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[22]/D
30 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_18_23/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[23]/D
31 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[24]/D
32 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[25]/D
33 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[26]/D
34 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[27]/D
35 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[28]/D
36 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_24_29/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[29]/D
37 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[30]/D
38 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[31]/D
39 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[32]/D
40 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[33]/D
41 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMC/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[34]/D
42 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_30_35/RAMC_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[35]/D
43 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_36_39/RAMA/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[36]/D
44 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_36_39/RAMA_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[37]/D
45 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_36_39/RAMB/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[38]/D
46 CDC-15 Warning Clock enable controlled CDC structure detected 0 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/ram_reg_0_7_36_39/RAMB_D1/CLK u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/_zz_ram_port1_reg[39]/D
47 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/pushCC_pushPtrGray_reg[3:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/rFifo/pushToPopGray_buffercc/buffers_0_reg[3:0]/D
48 CDC-6 Warning Multi-bit synchronized with ASYNC_REG property 2 Asynch Clock Groups u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/popCC_ptrToPush_reg[3:0]/C u_fft_mlkem_axi_slave/u_mlkem_axi_cdc/wFifo/popToPushGray_buffercc/buffers_0_reg[3:0]/D

View File

@@ -0,0 +1,28 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
---------------------------------------------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:35 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_clock_interaction -delay_type min_max -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/clock_interaction.rpt
| Design : soc_top
| Device : 7a200t-fbg676
| Speed File : -1 PRODUCTION 1.23 2018-06-13
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Clock Interaction Report
Clock Interaction Table
-----------------------
WNS TNS Failing TNS Total WNS Path WHS THS Failing THS Total WHS Path Clock-Pair Inter-Clock
From Clock To Clock Clock Edges WNS(ns) TNS(ns) Endpoints Endpoints Requirement(ns) Clock Edges WHS(ns) THS(ns) Endpoints Endpoints Requirement(ns) Classification Constraints
---------------- ---------------- ----------- ------- ------- ----------- ----------- --------------- ----------- ------- ------- ----------- ----------- --------------- ------------------- -------------------
cpu_clk cpu_clk rise - rise 0.74 0.00 0 17264 30.00 rise - rise 0.04 0.00 0 17264 0.00 Clean Timed
cpu_clk sys_clk 0 162 0 162 Ignored Asynchronous Groups
mlkem_clk mlkem_clk rise - rise 0.07 0.00 0 48386 13.00 rise - rise 0.06 0.00 0 48386 0.00 Clean Timed
mlkem_clk sys_clk 0 61 0 61 Ignored Asynchronous Groups
sys_clk cpu_clk 0 59 0 59 Ignored Asynchronous Groups
sys_clk mlkem_clk 0 112 0 112 Ignored Asynchronous Groups
sys_clk sys_clk rise - rise 0.12 0.00 0 23193 20.00 rise - rise 0.02 0.00 0 23193 0.00 Clean Timed

View File

@@ -0,0 +1,76 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
---------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:25 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_clocks -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/clocks.rpt
| Design : soc_top
| Device : 7a200t-fbg676
| Speed File : -1 PRODUCTION 1.23 2018-06-13
---------------------------------------------------------------------------------------------------------------------
Clock Report
Attributes
P: Propagated
G: Generated
A: Auto-derived
R: Renamed
V: Virtual
I: Inverted
S: Pin phase-shifted with Latency mode
Clock Period(ns) Waveform(ns) Attributes Sources
clk 20.000 {0.000 10.000} P {clk}
clkfbout_clk_pll 20.000 {0.000 10.000} P,G,A {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKFBOUT}
cpu_clk 30.000 {0.000 15.000} P,G,A,R {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT0}
mlkem_clk 13.000 {0.000 6.500} P,G,A,R {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT2}
sys_clk 20.000 {0.000 10.000} P,G,A,R {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT1}
====================================================
Generated Clocks
====================================================
Generated Clock : clkfbout_clk_pll
Master Source : pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKIN1
Master Clock : clk
Multiply By : 1
Generated Sources : {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKFBOUT}
Generated Clock : cpu_clk
Master Source : pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKIN1
Master Clock : clk
Edges : {1 2 3}
Edge Shifts(ns) : {0.000 5.000 10.000}
Generated Sources : {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT0}
Generated Clock : mlkem_clk
Master Source : pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKIN1
Master Clock : clk
Edges : {1 2 3}
Edge Shifts(ns) : {0.000 -3.500 -7.000}
Generated Sources : {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT2}
Generated Clock : sys_clk
Master Source : pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKIN1
Master Clock : clk
Multiply By : 1
Generated Sources : {pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT1}
====================================================
User Uncertainty
====================================================
====================================================
User Jitter
====================================================
Clock Jitter(ns)
clk 0.200

View File

@@ -0,0 +1,248 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
---------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:39 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_drc -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/drc.rpt
| Design : soc_top
| Device : xc7a200tfbg676-1
| Speed File : -1
| Design State : Fully Routed
---------------------------------------------------------------------------------------------------------------
Report DRC
Table of Contents
-----------------
1. REPORT SUMMARY
2. REPORT DETAILS
1. REPORT SUMMARY
-----------------
Netlist: netlist
Floorplan: impl_1
Design limits: <entire design considered>
Ruledeck: default
Max violations: <unlimited>
Violations found: 42
+-----------+----------+----------------------------+------------+
| Rule | Severity | Description | Violations |
+-----------+----------+----------------------------+------------+
| CHECK-3 | Warning | Report rule limit reached | 2 |
| REQP-1839 | Warning | RAMB36 async control check | 20 |
| REQP-1840 | Warning | RAMB18 async control check | 20 |
+-----------+----------+----------------------------+------------+
2. REPORT DETAILS
-----------------
CHECK-3#1 Warning
Report rule limit reached
REQP-1839 rule limit reached: 20 violations have been found.
Related violations: <none>
CHECK-3#2 Warning
Report rule limit reached
REQP-1840 rule limit reached: 20 violations have been found.
Related violations: <none>
REQP-1839#1 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[0]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#2 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[1]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#3 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[2]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#4 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[3]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#5 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[4]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#6 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[5]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#7 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[6]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#8 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[7]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#9 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[8]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#10 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[13] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[8]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[9]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#11 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[0]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#12 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[1]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#13 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[2]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#14 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[3]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#15 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[4]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#16 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[5]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#17 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[6]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#18 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[7]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#19 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[8]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1839#20 Warning
RAMB36 async control check
The RAMB36E1 u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg has an input control pin u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ff_im_reg/ADDRARDADDR[14] (net: u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/TW/ADDRARDADDR[9]) which is driven by a register (u_fft_mlkem_axi_slave/u_fft_controller/u_FFT/SU1/bf2_count_reg[9]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#1 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[10] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[5]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#2 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[11] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[6]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#3 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[12] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[7]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#4 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[5] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[0]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#5 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[6] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[1]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#6 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[7] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[2]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#7 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[8] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[3]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#8 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRARDADDR[9] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[4]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#9 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[10] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[5]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#10 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[11] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[6]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#11 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[12] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[7]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#12 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[5] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[0]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#13 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[6] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[1]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#14 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[7] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[2]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#15 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[8] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[3]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#16 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ADDRBWRADDR[9] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_addra[0][0]_26[4]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#17 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ENARDEN (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg_i_1__15_n_0) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#18 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/ENBWREN (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg_i_2__13_n_0) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#19 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/WEBWE[2] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_wea[0][0]_14[2]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>
REQP-1840#20 Warning
RAMB18 async control check
The RAMB18E1 u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg has an input control pin u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/mem_reg_reg/WEBWE[3] (net: u_cpu/dcache/data_ram_way[0].data_ram_bank[0].u/way_bank_wea[0][0]_14[3]) which is driven by a register (u_Axi_CDC/rFifo/popCC_addressGen_rValid_reg) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
Related violations: <none>

View File

@@ -0,0 +1,623 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-------------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:49 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_methodology -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/methodology.rpt
| Design : soc_top
| Device : xc7a200tfbg676-1
| Speed File : -1
| Design State : Fully Routed
-------------------------------------------------------------------------------------------------------------------------------
Report Methodology
Table of Contents
-----------------
1. REPORT SUMMARY
2. REPORT DETAILS
1. REPORT SUMMARY
-----------------
Netlist: netlist
Floorplan: impl_1
Design limits: <entire design considered>
Max violations: <unlimited>
Violations found: 115
+-----------+----------+-------------------------------------------------------------------+------------+
| Rule | Severity | Description | Violations |
+-----------+----------+-------------------------------------------------------------------+------------+
| LUTAR-1 | Warning | LUT drives async reset alert | 1 |
| SYNTH-5 | Warning | Mapped onto distributed RAM because of timing constraints | 8 |
| SYNTH-6 | Warning | Timing of a block RAM might be sub-optimal | 6 |
| SYNTH-16 | Warning | Address collision | 16 |
| TIMING-9 | Warning | Unknown CDC Logic | 1 |
| TIMING-10 | Warning | Missing property on synchronizer | 1 |
| TIMING-18 | Warning | Missing input or output delay | 76 |
| TIMING-47 | Warning | False path or asynchronous clock group between synchronous clocks | 4 |
| XDCC-1 | Warning | Scoped Clock constraint overwritten with the same name | 1 |
| XDCC-7 | Warning | Scoped Clock constraint overwritten on the same source | 1 |
+-----------+----------+-------------------------------------------------------------------+------------+
2. REPORT DETAILS
-----------------
LUTAR-1#1 Warning
LUT drives async reset alert
LUT cell u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_dkp_bram/FSM_sequential_state_r[2]_i_3, with 2 or more inputs, drives asynchronous preset/clear pin(s) u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_busy_reg/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_i_reg[0]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_i_reg[1]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_i_reg[2]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_j_reg[0]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_j_reg[1]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_j_reg[2]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_pair_reg[0]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_pair_reg[1]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_pair_reg[2]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_pair_reg[3]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_pair_reg[4]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_widx_reg[0]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_widx_reg[1]/CLR, u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/a_widx_reg[2]/CLR (the first 15 of 15633 listed). The LUT may glitch and trigger an unexpected reset, even if it is a properly timed path.
Related violations: <none>
SYNTH-5#1 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r1_0_127_0_0 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#2 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r1_0_127_1_1 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#3 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r1_128_255_0_0 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#4 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r1_128_255_1_1 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#5 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r2_0_127_0_0 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#6 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r2_0_127_1_1 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#7 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r2_128_255_0_0 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-5#8 Warning
Mapped onto distributed RAM because of timing constraints
The instance u_cpu/dcache/way_d_reg_reg_r2_128_255_1_1 is implemented as distributed LUT RAM for the following reason: The timing constraints suggest that the chosen mapping will yield a better timing.
Related violations: <none>
SYNTH-6#1 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_a/mem_reg_0, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-6#2 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_a/mem_reg_1, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-6#3 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_se/mem_reg, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-6#4 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_t/mem_reg, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-6#5 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_c_in_bram/mem_reg, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-6#6 Warning
Timing of a block RAM might be sub-optimal
The timing for the instance u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ek_bram/mem_reg, implemented as a block RAM, might be sub-optimal as no output register was merged into the block
Related violations: <none>
SYNTH-16#1 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_a/mem_reg_0 may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#2 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_a/mem_reg_1 may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#3 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_se/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#4 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_bank_t/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#5 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_c_in_bram/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#6 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ct_bram/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#7 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_dkp_bram/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#8 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ek_bram/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#9 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ntt/u_cr/gen_xbar[0].u_bank/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#10 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ntt/u_cr/gen_xbar[1].u_bank/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#11 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ntt/u_cr/gen_xbar[2].u_bank/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#12 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_ntt/u_cr/gen_xbar[3].u_bank/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#13 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_pmul/u_a_even/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#14 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_pmul/u_a_odd/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#15 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_pmul/u_b_even/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
SYNTH-16#16 Warning
Address collision
Block RAM u_fft_mlkem_axi_slave/u_mlkem_axi_slave/u_mlkem/u_pmul/u_b_odd/mem_reg may get memory collision error if read and write address collide. Use of address collision resolution circuitry is recommended.
Related violations: <none>
TIMING-9#1 Warning
Unknown CDC Logic
One or more asynchronous Clock Domain Crossing has been detected between 2 clock domains through a set_false_path or a set_clock_groups or set_max_delay -datapath_only constraint but no double-registers logic synchronizer has been found on the side of the capture clock. It is recommended to run report_cdc for a complete and detailed CDC coverage. Please consider using XPM_CDC to avoid Critical severities
Related violations: <none>
TIMING-10#1 Warning
Missing property on synchronizer
One or more logic synchronizer has been detected between 2 clock domains but the synchronizer does not have the property ASYNC_REG defined on one or both registers. It is recommended to run report_cdc for a complete and detailed CDC coverage
Related violations: <none>
TIMING-18#1 Warning
Missing input or output delay
An input delay is missing on UART_RX relative to clock(s) clk
Related violations: <none>
TIMING-18#2 Warning
Missing input or output delay
An input delay is missing on UART_TX relative to clock(s) clk
Related violations: <none>
TIMING-18#3 Warning
Missing input or output delay
An input delay is missing on dip_sw[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#4 Warning
Missing input or output delay
An input delay is missing on dip_sw[10] relative to clock(s) clk
Related violations: <none>
TIMING-18#5 Warning
Missing input or output delay
An input delay is missing on dip_sw[11] relative to clock(s) clk
Related violations: <none>
TIMING-18#6 Warning
Missing input or output delay
An input delay is missing on dip_sw[12] relative to clock(s) clk
Related violations: <none>
TIMING-18#7 Warning
Missing input or output delay
An input delay is missing on dip_sw[13] relative to clock(s) clk
Related violations: <none>
TIMING-18#8 Warning
Missing input or output delay
An input delay is missing on dip_sw[14] relative to clock(s) clk
Related violations: <none>
TIMING-18#9 Warning
Missing input or output delay
An input delay is missing on dip_sw[15] relative to clock(s) clk
Related violations: <none>
TIMING-18#10 Warning
Missing input or output delay
An input delay is missing on dip_sw[16] relative to clock(s) clk
Related violations: <none>
TIMING-18#11 Warning
Missing input or output delay
An input delay is missing on dip_sw[17] relative to clock(s) clk
Related violations: <none>
TIMING-18#12 Warning
Missing input or output delay
An input delay is missing on dip_sw[18] relative to clock(s) clk
Related violations: <none>
TIMING-18#13 Warning
Missing input or output delay
An input delay is missing on dip_sw[19] relative to clock(s) clk
Related violations: <none>
TIMING-18#14 Warning
Missing input or output delay
An input delay is missing on dip_sw[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#15 Warning
Missing input or output delay
An input delay is missing on dip_sw[20] relative to clock(s) clk
Related violations: <none>
TIMING-18#16 Warning
Missing input or output delay
An input delay is missing on dip_sw[21] relative to clock(s) clk
Related violations: <none>
TIMING-18#17 Warning
Missing input or output delay
An input delay is missing on dip_sw[22] relative to clock(s) clk
Related violations: <none>
TIMING-18#18 Warning
Missing input or output delay
An input delay is missing on dip_sw[23] relative to clock(s) clk
Related violations: <none>
TIMING-18#19 Warning
Missing input or output delay
An input delay is missing on dip_sw[24] relative to clock(s) clk
Related violations: <none>
TIMING-18#20 Warning
Missing input or output delay
An input delay is missing on dip_sw[25] relative to clock(s) clk
Related violations: <none>
TIMING-18#21 Warning
Missing input or output delay
An input delay is missing on dip_sw[26] relative to clock(s) clk
Related violations: <none>
TIMING-18#22 Warning
Missing input or output delay
An input delay is missing on dip_sw[27] relative to clock(s) clk
Related violations: <none>
TIMING-18#23 Warning
Missing input or output delay
An input delay is missing on dip_sw[28] relative to clock(s) clk
Related violations: <none>
TIMING-18#24 Warning
Missing input or output delay
An input delay is missing on dip_sw[29] relative to clock(s) clk
Related violations: <none>
TIMING-18#25 Warning
Missing input or output delay
An input delay is missing on dip_sw[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#26 Warning
Missing input or output delay
An input delay is missing on dip_sw[30] relative to clock(s) clk
Related violations: <none>
TIMING-18#27 Warning
Missing input or output delay
An input delay is missing on dip_sw[31] relative to clock(s) clk
Related violations: <none>
TIMING-18#28 Warning
Missing input or output delay
An input delay is missing on dip_sw[3] relative to clock(s) clk
Related violations: <none>
TIMING-18#29 Warning
Missing input or output delay
An input delay is missing on dip_sw[4] relative to clock(s) clk
Related violations: <none>
TIMING-18#30 Warning
Missing input or output delay
An input delay is missing on dip_sw[5] relative to clock(s) clk
Related violations: <none>
TIMING-18#31 Warning
Missing input or output delay
An input delay is missing on dip_sw[6] relative to clock(s) clk
Related violations: <none>
TIMING-18#32 Warning
Missing input or output delay
An input delay is missing on dip_sw[7] relative to clock(s) clk
Related violations: <none>
TIMING-18#33 Warning
Missing input or output delay
An input delay is missing on dip_sw[8] relative to clock(s) clk
Related violations: <none>
TIMING-18#34 Warning
Missing input or output delay
An input delay is missing on dip_sw[9] relative to clock(s) clk
Related violations: <none>
TIMING-18#35 Warning
Missing input or output delay
An input delay is missing on touch_btn[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#36 Warning
Missing input or output delay
An input delay is missing on touch_btn[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#37 Warning
Missing input or output delay
An input delay is missing on touch_btn[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#38 Warning
Missing input or output delay
An input delay is missing on touch_btn[3] relative to clock(s) clk
Related violations: <none>
TIMING-18#39 Warning
Missing input or output delay
An output delay is missing on dpy0[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#40 Warning
Missing input or output delay
An output delay is missing on dpy0[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#41 Warning
Missing input or output delay
An output delay is missing on dpy0[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#42 Warning
Missing input or output delay
An output delay is missing on dpy0[3] relative to clock(s) clk
Related violations: <none>
TIMING-18#43 Warning
Missing input or output delay
An output delay is missing on dpy0[4] relative to clock(s) clk
Related violations: <none>
TIMING-18#44 Warning
Missing input or output delay
An output delay is missing on dpy0[5] relative to clock(s) clk
Related violations: <none>
TIMING-18#45 Warning
Missing input or output delay
An output delay is missing on dpy0[6] relative to clock(s) clk
Related violations: <none>
TIMING-18#46 Warning
Missing input or output delay
An output delay is missing on dpy0[7] relative to clock(s) clk
Related violations: <none>
TIMING-18#47 Warning
Missing input or output delay
An output delay is missing on dpy1[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#48 Warning
Missing input or output delay
An output delay is missing on dpy1[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#49 Warning
Missing input or output delay
An output delay is missing on dpy1[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#50 Warning
Missing input or output delay
An output delay is missing on dpy1[3] relative to clock(s) clk
Related violations: <none>
TIMING-18#51 Warning
Missing input or output delay
An output delay is missing on dpy1[4] relative to clock(s) clk
Related violations: <none>
TIMING-18#52 Warning
Missing input or output delay
An output delay is missing on dpy1[5] relative to clock(s) clk
Related violations: <none>
TIMING-18#53 Warning
Missing input or output delay
An output delay is missing on dpy1[6] relative to clock(s) clk
Related violations: <none>
TIMING-18#54 Warning
Missing input or output delay
An output delay is missing on dpy1[7] relative to clock(s) clk
Related violations: <none>
TIMING-18#55 Warning
Missing input or output delay
An output delay is missing on leds[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#56 Warning
Missing input or output delay
An output delay is missing on leds[10] relative to clock(s) clk
Related violations: <none>
TIMING-18#57 Warning
Missing input or output delay
An output delay is missing on leds[11] relative to clock(s) clk
Related violations: <none>
TIMING-18#58 Warning
Missing input or output delay
An output delay is missing on leds[12] relative to clock(s) clk
Related violations: <none>
TIMING-18#59 Warning
Missing input or output delay
An output delay is missing on leds[13] relative to clock(s) clk
Related violations: <none>
TIMING-18#60 Warning
Missing input or output delay
An output delay is missing on leds[14] relative to clock(s) clk
Related violations: <none>
TIMING-18#61 Warning
Missing input or output delay
An output delay is missing on leds[15] relative to clock(s) clk
Related violations: <none>
TIMING-18#62 Warning
Missing input or output delay
An output delay is missing on leds[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#63 Warning
Missing input or output delay
An output delay is missing on leds[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#64 Warning
Missing input or output delay
An output delay is missing on leds[3] relative to clock(s) clk
Related violations: <none>
TIMING-18#65 Warning
Missing input or output delay
An output delay is missing on leds[4] relative to clock(s) clk
Related violations: <none>
TIMING-18#66 Warning
Missing input or output delay
An output delay is missing on leds[5] relative to clock(s) clk
Related violations: <none>
TIMING-18#67 Warning
Missing input or output delay
An output delay is missing on leds[6] relative to clock(s) clk
Related violations: <none>
TIMING-18#68 Warning
Missing input or output delay
An output delay is missing on leds[7] relative to clock(s) clk
Related violations: <none>
TIMING-18#69 Warning
Missing input or output delay
An output delay is missing on leds[8] relative to clock(s) clk
Related violations: <none>
TIMING-18#70 Warning
Missing input or output delay
An output delay is missing on leds[9] relative to clock(s) clk
Related violations: <none>
TIMING-18#71 Warning
Missing input or output delay
An output delay is missing on video_de relative to clock(s) clk
Related violations: <none>
TIMING-18#72 Warning
Missing input or output delay
An output delay is missing on video_hsync relative to clock(s) clk
Related violations: <none>
TIMING-18#73 Warning
Missing input or output delay
An output delay is missing on video_red[0] relative to clock(s) clk
Related violations: <none>
TIMING-18#74 Warning
Missing input or output delay
An output delay is missing on video_red[1] relative to clock(s) clk
Related violations: <none>
TIMING-18#75 Warning
Missing input or output delay
An output delay is missing on video_red[2] relative to clock(s) clk
Related violations: <none>
TIMING-18#76 Warning
Missing input or output delay
An output delay is missing on video_vsync relative to clock(s) clk
Related violations: <none>
TIMING-47#1 Warning
False path or asynchronous clock group between synchronous clocks
A Clock Group timing constraint is set between synchronous clocks cpu_clk and sys_clk (see constraint position 7 in the Timing Constraint window in Vivado IDE). It is not recommended to cover synchronous clock domains with constraints that prevent timing analysis as the design could fail in hardware.
Related violations: <none>
TIMING-47#2 Warning
False path or asynchronous clock group between synchronous clocks
A Clock Group timing constraint is set between synchronous clocks mlkem_clk and sys_clk (see constraint position 7 in the Timing Constraint window in Vivado IDE). It is not recommended to cover synchronous clock domains with constraints that prevent timing analysis as the design could fail in hardware.
Related violations: <none>
TIMING-47#3 Warning
False path or asynchronous clock group between synchronous clocks
A Clock Group timing constraint is set between synchronous clocks sys_clk and cpu_clk (see constraint position 7 in the Timing Constraint window in Vivado IDE). It is not recommended to cover synchronous clock domains with constraints that prevent timing analysis as the design could fail in hardware.
Related violations: <none>
TIMING-47#4 Warning
False path or asynchronous clock group between synchronous clocks
A Clock Group timing constraint is set between synchronous clocks sys_clk and mlkem_clk (see constraint position 7 in the Timing Constraint window in Vivado IDE). It is not recommended to cover synchronous clock domains with constraints that prevent timing analysis as the design could fail in hardware.
Related violations: <none>
XDCC-1#1 Warning
Scoped Clock constraint overwritten with the same name
A new clock constraint create_clock overrides a previous scoped clock constraint with the same name. It is not recommended to override a scoped (typically an IP) clock constraint and could result in unexpected behaviors.
New: create_clock -period 20.000 -name clk -waveform {0.000 10.000} [get_ports clk] (Source: c:/Users/11747/Desktop/ciciec2026/fpga/constraints/soc.xdc (Line: 4))
Previous: create_clock -period 20.000 [get_ports clk] (Source: c:/Users/11747/Desktop/ciciec2026/fpga/project/ipgen/clk_pll/clk_pll.xdc (Line: 56))
Related violations: <none>
XDCC-7#1 Warning
Scoped Clock constraint overwritten on the same source
A new clock constraint create_clock overrides a previous scoped clock constraint defined on the same source. It is not recommended to override a scoped (typically an IP) clock constraint and could result in unexpected behaviors.
New: create_clock -period 20.000 -name clk -waveform {0.000 10.000} [get_ports clk] (Source: c:/Users/11747/Desktop/ciciec2026/fpga/constraints/soc.xdc (Line: 4))
Previous: create_clock -period 20.000 [get_ports clk] (Source: c:/Users/11747/Desktop/ciciec2026/fpga/project/ipgen/clk_pll/clk_pll.xdc (Line: 56))
Related violations: <none>

View File

@@ -0,0 +1,188 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-------------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:34 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_power -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/power.rpt
| Design : soc_top
| Device : xc7a200tfbg676-1
| Design State : routed
| Grade : commercial
| Process : typical
| Characterization : Production
-------------------------------------------------------------------------------------------------------------------------------
Power Report
Table of Contents
-----------------
1. Summary
1.1 On-Chip Components
1.2 Power Supply Summary
1.3 Confidence Level
2. Settings
2.1 Environment
2.2 Clock Constraints
3. Detailed Reports
3.1 By Hierarchy
1. Summary
----------
+--------------------------+--------------+
| Total On-Chip Power (W) | 0.779 |
| Design Power Budget (W) | Unspecified* |
| Power Budget Margin (W) | NA |
| Dynamic (W) | 0.637 |
| Device Static (W) | 0.142 |
| Effective TJA (C/W) | 1.9 |
| Max Ambient (C) | 83.5 |
| Junction Temperature (C) | 26.5 |
| Confidence Level | Low |
| Setting File | --- |
| Simulation Activity File | --- |
| Design Nets Matched | NA |
+--------------------------+--------------+
* Specify Design Power Budget using, set_operating_conditions -design_power_budget <value in Watts>
1.1 On-Chip Components
----------------------
+--------------------------+-----------+----------+-----------+-----------------+
| On-Chip | Power (W) | Used | Available | Utilization (%) |
+--------------------------+-----------+----------+-----------+-----------------+
| Clocks | 0.060 | 7 | --- | --- |
| Slice Logic | 0.137 | 103629 | --- | --- |
| LUT as Logic | 0.128 | 53158 | 133800 | 39.73 |
| CARRY4 | 0.005 | 3669 | 33450 | 10.97 |
| Register | 0.002 | 31000 | 267600 | 11.58 |
| LUT as Distributed RAM | 0.001 | 740 | 46200 | 1.60 |
| LUT as Shift Register | <0.001 | 1168 | 46200 | 2.53 |
| F7/F8 Muxes | <0.001 | 2449 | 133800 | 1.83 |
| Others | 0.000 | 333 | --- | --- |
| Signals | 0.284 | 78815 | --- | --- |
| Block RAM | 0.027 | 29.5 | 365 | 8.08 |
| PLL | 0.102 | 1 | 10 | 10.00 |
| I/O | 0.027 | 202 | 400 | 50.50 |
| Static Power | 0.142 | | | |
| Total | 0.779 | | | |
+--------------------------+-----------+----------+-----------+-----------------+
1.2 Power Supply Summary
------------------------
+-----------+-------------+-----------+-------------+------------+
| Source | Voltage (V) | Total (A) | Dynamic (A) | Static (A) |
+-----------+-------------+-----------+-------------+------------+
| Vccint | 1.000 | 0.545 | 0.512 | 0.033 |
| Vccaux | 1.800 | 0.085 | 0.054 | 0.031 |
| Vcco33 | 3.300 | 0.013 | 0.008 | 0.005 |
| Vcco25 | 2.500 | 0.000 | 0.000 | 0.000 |
| Vcco18 | 1.800 | 0.000 | 0.000 | 0.000 |
| Vcco15 | 1.500 | 0.000 | 0.000 | 0.000 |
| Vcco135 | 1.350 | 0.000 | 0.000 | 0.000 |
| Vcco12 | 1.200 | 0.000 | 0.000 | 0.000 |
| Vccaux_io | 1.800 | 0.000 | 0.000 | 0.000 |
| Vccbram | 1.000 | 0.003 | 0.002 | 0.001 |
| MGTAVcc | 1.000 | 0.000 | 0.000 | 0.000 |
| MGTAVtt | 1.200 | 0.000 | 0.000 | 0.000 |
| Vccadc | 1.800 | 0.020 | 0.000 | 0.020 |
+-----------+-------------+-----------+-------------+------------+
1.3 Confidence Level
--------------------
+-----------------------------+------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------+
| User Input Data | Confidence | Details | Action |
+-----------------------------+------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------+
| Design implementation state | High | Design is routed | |
| Clock nodes activity | High | User specified more than 95% of clocks | |
| I/O nodes activity | Low | More than 75% of inputs are missing user specification | Provide missing input activity with simulation results or by editing the "By Resource Type -> I/Os" view |
| Internal nodes activity | Medium | User specified less than 25% of internal nodes | Provide missing internal nodes activity with simulation results or by editing the "By Resource Type" views |
| Device models | High | Device models are Production | |
| | | | |
| Overall confidence level | Low | | |
+-----------------------------+------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------+
2. Settings
-----------
2.1 Environment
---------------
+-----------------------+--------------------------+
| Ambient Temp (C) | 25.0 |
| ThetaJA (C/W) | 1.9 |
| Airflow (LFM) | 250 |
| Heat Sink | medium (Medium Profile) |
| ThetaSA (C/W) | 3.4 |
| Board Selection | medium (10"x10") |
| # of Board Layers | 12to15 (12 to 15 Layers) |
| Board Temperature (C) | 25.0 |
+-----------------------+--------------------------+
2.2 Clock Constraints
---------------------
+------------------+------------------------------------------+-----------------+
| Clock | Domain | Constraint (ns) |
+------------------+------------------------------------------+-----------------+
| clk | clk | 20.0 |
| clkfbout_clk_pll | pll_clk.u_clk_pll/inst/clkfbout_clk_pll | 20.0 |
| cpu_clk | pll_clk.u_clk_pll/inst/cpu_clk_clk_pll | 30.0 |
| mlkem_clk | pll_clk.u_clk_pll/inst/mlkem_clk_clk_pll | 13.0 |
| sys_clk | pll_clk.u_clk_pll/inst/sys_clk_clk_pll | 20.0 |
+------------------+------------------------------------------+-----------------+
3. Detailed Reports
-------------------
3.1 By Hierarchy
----------------
+----------------------------+-----------+
| Name | Power (W) |
+----------------------------+-----------+
| soc_top | 0.637 |
| pll_clk.u_clk_pll | 0.103 |
| inst | 0.103 |
| u_Axi_CDC | 0.002 |
| u_axi_uart_controller | 0.002 |
| uart0 | 0.001 |
| regs | 0.001 |
| u_cdma_matmul_bridge | 0.001 |
| u_confreg | 0.001 |
| u_cpu | 0.027 |
| addr_trans | 0.002 |
| tlb_entry | 0.002 |
| btb | 0.003 |
| dcache | 0.004 |
| icache | 0.005 |
| u_csr | 0.001 |
| u_mul | 0.008 |
| u_fft_mlkem_axi_slave | 0.373 |
| u_fft_controller | 0.031 |
| u_FFT | 0.028 |
| u_out0 | 0.001 |
| u_out1 | 0.001 |
| u_mlkem_axi_cdc | 0.003 |
| wFifo | 0.001 |
| u_mlkem_axi_slave | 0.339 |
| u_mlkem | 0.332 |
| u_matmul_axi_slave | 0.077 |
| mult_inst[0].u_mult | 0.003 |
| mult_inst[1].u_mult | 0.002 |
| mult_inst[2].u_mult | 0.002 |
| mult_inst[3].u_mult | 0.002 |
| u_snix_axil_cdma_mux_8ch | 0.008 |
| u_core_engine | 0.004 |
| axis_fifo_u0 | 0.002 |
+----------------------------+-----------+

View File

@@ -0,0 +1,5 @@
Evidence generated from implemented design.
Vivado version: 2019.2
Project: C:/Users/11747/Desktop/ciciec2026/fpga/project/Loongson_Soc.xpr
Git revision: d45646342b79cefbc30775b5045e34c1f0d26ad6
Generated at: 2026-07-15 05:09:50 +0800

View File

@@ -0,0 +1,12 @@
Design Route Status
: # nets :
------------------------------------------- : ----------- :
# of logical nets.......................... : 114880 :
# of nets not needing routing.......... : 36054 :
# of internally routed nets........ : 35589 :
# of nets with no loads............ : 465 :
# of routable nets..................... : 78826 :
# of fully routed nets............. : 78826 :
# of nets with routing errors.......... : 0 :
------------------------------------------- : ----------- :

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-------------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:26 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_utilization -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/utilization.rpt
| Design : soc_top
| Device : 7a200tfbg676-1
| Design State : Routed
-------------------------------------------------------------------------------------------------------------------------------
Utilization Design Information
Table of Contents
-----------------
1. Slice Logic
1.1 Summary of Registers by Type
2. Slice Logic Distribution
3. Memory
4. DSP
5. IO and GT Specific
6. Clocking
7. Specific Feature
8. Primitives
9. Black Boxes
10. Instantiated Netlists
1. Slice Logic
--------------
+----------------------------+-------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+----------------------------+-------+-------+-----------+-------+
| Slice LUTs | 55066 | 0 | 133800 | 41.16 |
| LUT as Logic | 53158 | 0 | 133800 | 39.73 |
| LUT as Memory | 1908 | 0 | 46200 | 4.13 |
| LUT as Distributed RAM | 740 | 0 | | |
| LUT as Shift Register | 1168 | 0 | | |
| Slice Registers | 31000 | 0 | 267600 | 11.58 |
| Register as Flip Flop | 31000 | 0 | 267600 | 11.58 |
| Register as Latch | 0 | 0 | 267600 | 0.00 |
| F7 Muxes | 2130 | 0 | 66900 | 3.18 |
| F8 Muxes | 319 | 0 | 33450 | 0.95 |
+----------------------------+-------+-------+-----------+-------+
1.1 Summary of Registers by Type
--------------------------------
+-------+--------------+-------------+--------------+
| Total | Clock Enable | Synchronous | Asynchronous |
+-------+--------------+-------------+--------------+
| 0 | _ | - | - |
| 0 | _ | - | Set |
| 0 | _ | - | Reset |
| 0 | _ | Set | - |
| 0 | _ | Reset | - |
| 0 | Yes | - | - |
| 24 | Yes | - | Set |
| 17683 | Yes | - | Reset |
| 126 | Yes | Set | - |
| 13167 | Yes | Reset | - |
+-------+--------------+-------------+--------------+
2. Slice Logic Distribution
---------------------------
+--------------------------------------------+-------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+--------------------------------------------+-------+-------+-----------+-------+
| Slice | 17126 | 0 | 33450 | 51.20 |
| SLICEL | 11119 | 0 | | |
| SLICEM | 6007 | 0 | | |
| LUT as Logic | 53158 | 0 | 133800 | 39.73 |
| using O5 output only | 5 | | | |
| using O6 output only | 42769 | | | |
| using O5 and O6 | 10384 | | | |
| LUT as Memory | 1908 | 0 | 46200 | 4.13 |
| LUT as Distributed RAM | 740 | 0 | | |
| using O5 output only | 0 | | | |
| using O6 output only | 60 | | | |
| using O5 and O6 | 680 | | | |
| LUT as Shift Register | 1168 | 0 | | |
| using O5 output only | 123 | | | |
| using O6 output only | 997 | | | |
| using O5 and O6 | 48 | | | |
| Slice Registers | 31000 | 0 | 267600 | 11.58 |
| Register driven from within the Slice | 16668 | | | |
| Register driven from outside the Slice | 14332 | | | |
| LUT in front of the register is unused | 5924 | | | |
| LUT in front of the register is used | 8408 | | | |
| Unique Control Sets | 930 | | 33450 | 2.78 |
+--------------------------------------------+-------+-------+-----------+-------+
* Note: Available Control Sets calculated as Slice Registers / 8, Review the Control Sets Report for more information regarding control sets.
3. Memory
---------
+-------------------+------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+-------------------+------+-------+-----------+-------+
| Block RAM Tile | 29.5 | 0 | 365 | 8.08 |
| RAMB36/FIFO* | 10 | 0 | 365 | 2.74 |
| RAMB36E1 only | 10 | | | |
| RAMB18 | 39 | 0 | 730 | 5.34 |
| RAMB18E1 only | 39 | | | |
+-------------------+------+-------+-----------+-------+
* Note: Each Block RAM Tile only has one FIFO logic available and therefore can accommodate only one FIFO36E1 or one FIFO18E1. However, if a FIFO18E1 occupies a Block RAM Tile, that tile can still accommodate a RAMB18E1
4. DSP
------
+-----------+------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+-----------+------+-------+-----------+-------+
| DSPs | 0 | 0 | 740 | 0.00 |
+-----------+------+-------+-----------+-------+
5. IO and GT Specific
---------------------
+-----------------------------+------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+-----------------------------+------+-------+-----------+-------+
| Bonded IOB | 202 | 202 | 400 | 50.50 |
| IOB Master Pads | 97 | | | |
| IOB Slave Pads | 102 | | | |
| Bonded IPADs | 0 | 0 | 26 | 0.00 |
| Bonded OPADs | 0 | 0 | 16 | 0.00 |
| PHY_CONTROL | 0 | 0 | 10 | 0.00 |
| PHASER_REF | 0 | 0 | 10 | 0.00 |
| OUT_FIFO | 0 | 0 | 40 | 0.00 |
| IN_FIFO | 0 | 0 | 40 | 0.00 |
| IDELAYCTRL | 0 | 0 | 10 | 0.00 |
| IBUFDS | 0 | 0 | 384 | 0.00 |
| GTPE2_CHANNEL | 0 | 0 | 8 | 0.00 |
| PHASER_OUT/PHASER_OUT_PHY | 0 | 0 | 40 | 0.00 |
| PHASER_IN/PHASER_IN_PHY | 0 | 0 | 40 | 0.00 |
| IDELAYE2/IDELAYE2_FINEDELAY | 0 | 0 | 500 | 0.00 |
| IBUFDS_GTE2 | 0 | 0 | 4 | 0.00 |
| ILOGIC | 0 | 0 | 400 | 0.00 |
| OLOGIC | 0 | 0 | 400 | 0.00 |
+-----------------------------+------+-------+-----------+-------+
6. Clocking
-----------
+------------+------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+------------+------+-------+-----------+-------+
| BUFGCTRL | 4 | 0 | 32 | 12.50 |
| BUFIO | 0 | 0 | 40 | 0.00 |
| MMCME2_ADV | 0 | 0 | 10 | 0.00 |
| PLLE2_ADV | 1 | 0 | 10 | 10.00 |
| BUFMRCE | 0 | 0 | 20 | 0.00 |
| BUFHCE | 0 | 0 | 120 | 0.00 |
| BUFR | 0 | 0 | 40 | 0.00 |
+------------+------+-------+-----------+-------+
7. Specific Feature
-------------------
+-------------+------+-------+-----------+-------+
| Site Type | Used | Fixed | Available | Util% |
+-------------+------+-------+-----------+-------+
| BSCANE2 | 0 | 0 | 4 | 0.00 |
| CAPTUREE2 | 0 | 0 | 1 | 0.00 |
| DNA_PORT | 0 | 0 | 1 | 0.00 |
| EFUSE_USR | 0 | 0 | 1 | 0.00 |
| FRAME_ECCE2 | 0 | 0 | 1 | 0.00 |
| ICAPE2 | 0 | 0 | 2 | 0.00 |
| PCIE_2_1 | 0 | 0 | 1 | 0.00 |
| STARTUPE2 | 0 | 0 | 1 | 0.00 |
| XADC | 0 | 0 | 1 | 0.00 |
+-------------+------+-------+-----------+-------+
8. Primitives
-------------
+-----------+-------+---------------------+
| Ref Name | Used | Functional Category |
+-----------+-------+---------------------+
| LUT6 | 26800 | LUT |
| FDCE | 17683 | Flop & Latch |
| FDRE | 13167 | Flop & Latch |
| LUT3 | 10370 | LUT |
| LUT4 | 8684 | LUT |
| LUT2 | 8543 | LUT |
| LUT5 | 8274 | LUT |
| CARRY4 | 3669 | CarryLogic |
| MUXF7 | 2130 | MuxFx |
| RAMD32 | 1060 | Distributed Memory |
| SRLC32E | 992 | Distributed Memory |
| LUT1 | 871 | LUT |
| RAMS32 | 328 | Distributed Memory |
| MUXF8 | 319 | MuxFx |
| SRL16E | 224 | Distributed Memory |
| FDSE | 126 | Flop & Latch |
| IBUF | 104 | IO |
| OBUF | 98 | IO |
| OBUFT | 66 | IO |
| RAMB18E1 | 39 | Block Memory |
| RAMD64E | 32 | Distributed Memory |
| FDPE | 24 | Flop & Latch |
| RAMB36E1 | 10 | Block Memory |
| BUFG | 4 | Clock |
| PLLE2_ADV | 1 | Clock |
+-----------+-------+---------------------+
9. Black Boxes
--------------
+----------+------+
| Ref Name | Used |
+----------+------+
10. Instantiated Netlists
-------------------------
+----------+------+
| Ref Name | Used |
+----------+------+
| clk_pll | 1 |
+----------+------+

View File

@@ -0,0 +1,229 @@
Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Tool Version : Vivado v.2019.2 (win64) Build 2708876 Wed Nov 6 21:40:23 MST 2019
| Date : Wed Jul 15 05:09:25 2026
| Host : Roc_Wang running 64-bit major release (build 9200)
| Command : report_utilization -hierarchical -hierarchical_depth 4 -file C:/Users/11747/Desktop/ciciec2026/doc/reports/system/evidence/vivado/utilization_hierarchical.rpt
| Design : soc_top
| Device : 7a200tfbg676-1
| Design State : Routed
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Utilization Design Information
Table of Contents
-----------------
1. Utilization by Hierarchy
1. Utilization by Hierarchy
---------------------------
+------------------------------------------+------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
| Instance | Module | Total LUTs | Logic LUTs | LUTRAMs | SRLs | FFs | RAMB36 | RAMB18 | DSP48 Blocks |
+------------------------------------------+------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
| soc_top | (top) | 55066 | 53158 | 740 | 1168 | 31000 | 10 | 39 | 0 |
| (soc_top) | (top) | 927 | 919 | 8 | 0 | 4 | 0 | 0 | 0 |
| pll_clk.u_clk_pll | clk_pll | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| inst | clk_pll_clk_pll_clk_wiz | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| pll_clk.u_rst_cpu | rst_sync | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| pll_clk.u_rst_mlkem | rst_sync_0 | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| pll_clk.u_rst_sys | rst_sync_1 | 2 | 2 | 0 | 0 | 2 | 0 | 0 | 0 |
| u_AxiCrossbar_2x8 | AxiCrossbar_2x8 | 368 | 368 | 0 | 0 | 151 | 0 | 0 | 0 |
| (u_AxiCrossbar_2x8) | AxiCrossbar_2x8 | 8 | 8 | 0 | 0 | 24 | 0 | 0 | 0 |
| axi4ReadOnlyArbiter_4 | Axi4ReadOnlyArbiter | 14 | 14 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_92 | 14 | 14 | 0 | 0 | 3 | 0 | 0 | 0 |
| axi4ReadOnlyArbiter_5 | Axi4ReadOnlyArbiter_75 | 6 | 6 | 0 | 0 | 2 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_91 | 6 | 6 | 0 | 0 | 2 | 0 | 0 | 0 |
| axi4ReadOnlyArbiter_6 | Axi4ReadOnlyArbiter_76 | 17 | 17 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_90 | 17 | 17 | 0 | 0 | 3 | 0 | 0 | 0 |
| axi4ReadOnlyArbiter_7 | Axi4ReadOnlyArbiter_77 | 13 | 13 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_89 | 13 | 13 | 0 | 0 | 3 | 0 | 0 | 0 |
| axi4WriteOnlyArbiter_4 | Axi4WriteOnlyArbiter | 32 | 32 | 0 | 0 | 11 | 0 | 0 | 0 |
| (axi4WriteOnlyArbiter_4) | Axi4WriteOnlyArbiter | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_86 | 26 | 26 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdRouteFork_translated_fifo | StreamFifoLowLatency_3_87 | 7 | 7 | 0 | 0 | 6 | 0 | 0 | 0 |
| fifo | StreamFifo_3_88 | 7 | 7 | 0 | 0 | 6 | 0 | 0 | 0 |
| axi4WriteOnlyArbiter_5 | Axi4WriteOnlyArbiter_1 | 15 | 15 | 0 | 0 | 9 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_83 | 9 | 9 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdRouteFork_translated_fifo | StreamFifoLowLatency_3_84 | 6 | 6 | 0 | 0 | 6 | 0 | 0 | 0 |
| fifo | StreamFifo_3_85 | 6 | 6 | 0 | 0 | 6 | 0 | 0 | 0 |
| axi4WriteOnlyArbiter_6 | Axi4WriteOnlyArbiter_2 | 33 | 33 | 0 | 0 | 11 | 0 | 0 | 0 |
| (axi4WriteOnlyArbiter_6) | Axi4WriteOnlyArbiter_2 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7_80 | 24 | 24 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdRouteFork_translated_fifo | StreamFifoLowLatency_3_81 | 9 | 9 | 0 | 0 | 6 | 0 | 0 | 0 |
| fifo | StreamFifo_3_82 | 9 | 9 | 0 | 0 | 6 | 0 | 0 | 0 |
| axi4WriteOnlyArbiter_7 | Axi4WriteOnlyArbiter_3 | 29 | 29 | 0 | 0 | 11 | 0 | 0 | 0 |
| (axi4WriteOnlyArbiter_7) | Axi4WriteOnlyArbiter_3 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 |
| cmdArbiter | StreamArbiter_7 | 21 | 21 | 0 | 0 | 3 | 0 | 0 | 0 |
| cmdRouteFork_translated_fifo | StreamFifoLowLatency_3 | 8 | 8 | 0 | 0 | 6 | 0 | 0 | 0 |
| fifo | StreamFifo_3 | 8 | 8 | 0 | 0 | 6 | 0 | 0 | 0 |
| axiIn_0_readOnly_decoder | Axi4ReadOnlyDecoder | 90 | 90 | 0 | 0 | 25 | 0 | 0 | 0 |
| (axiIn_0_readOnly_decoder) | Axi4ReadOnlyDecoder | 74 | 74 | 0 | 0 | 12 | 0 | 0 | 0 |
| errorSlave | Axi4ReadOnlyErrorSlave_1_79 | 16 | 16 | 0 | 0 | 13 | 0 | 0 | 0 |
| axiIn_0_writeOnly_decoder | Axi4WriteOnlyDecoder | 36 | 36 | 0 | 0 | 18 | 0 | 0 | 0 |
| (axiIn_0_writeOnly_decoder) | Axi4WriteOnlyDecoder | 16 | 16 | 0 | 0 | 16 | 0 | 0 | 0 |
| errorSlave | Axi4WriteOnlyErrorSlave_1_78 | 20 | 20 | 0 | 0 | 2 | 0 | 0 | 0 |
| axiIn_1_readOnly_decoder | Axi4ReadOnlyDecoder_1 | 52 | 52 | 0 | 0 | 17 | 0 | 0 | 0 |
| (axiIn_1_readOnly_decoder) | Axi4ReadOnlyDecoder_1 | 36 | 36 | 0 | 0 | 8 | 0 | 0 | 0 |
| errorSlave | Axi4ReadOnlyErrorSlave_1 | 16 | 16 | 0 | 0 | 9 | 0 | 0 | 0 |
| axiIn_1_writeOnly_decoder | Axi4WriteOnlyDecoder_1 | 23 | 23 | 0 | 0 | 14 | 0 | 0 | 0 |
| (axiIn_1_writeOnly_decoder) | Axi4WriteOnlyDecoder_1 | 15 | 15 | 0 | 0 | 12 | 0 | 0 | 0 |
| errorSlave | Axi4WriteOnlyErrorSlave_1 | 8 | 8 | 0 | 0 | 2 | 0 | 0 | 0 |
| u_Axi_CDC | Axi_CDC | 427 | 299 | 128 | 0 | 317 | 0 | 0 | 0 |
| arFifo | StreamFifoCC_3_58 | 192 | 156 | 36 | 0 | 77 | 0 | 0 | 0 |
| (arFifo) | StreamFifoCC_3_58 | 186 | 150 | 36 | 0 | 65 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_9_73 | 1 | 1 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_11_74 | 5 | 5 | 0 | 0 | 6 | 0 | 0 | 0 |
| awFifo | StreamFifoCC_59 | 110 | 74 | 36 | 0 | 79 | 0 | 0 | 0 |
| (awFifo) | StreamFifoCC_59 | 103 | 67 | 36 | 0 | 65 | 0 | 0 | 0 |
| bufferCC_12 | BufferCC_10_70 | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_9_71 | 2 | 2 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_11_72 | 4 | 4 | 0 | 0 | 6 | 0 | 0 | 0 |
| bFifo | StreamFifoCC_2_60 | 14 | 14 | 0 | 0 | 26 | 0 | 0 | 0 |
| (bFifo) | StreamFifoCC_2_60 | 7 | 7 | 0 | 0 | 12 | 0 | 0 | 0 |
| bufferCC_12 | BufferCC_5_67 | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_4_68 | 2 | 2 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_6_69 | 4 | 4 | 0 | 0 | 6 | 0 | 0 | 0 |
| rFifo | StreamFifoCC_4_61 | 45 | 17 | 28 | 0 | 66 | 0 | 0 | 0 |
| (rFifo) | StreamFifoCC_4_61 | 41 | 13 | 28 | 0 | 50 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_65 | 3 | 3 | 0 | 0 | 8 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_1_66 | 2 | 2 | 0 | 0 | 8 | 0 | 0 | 0 |
| wFifo | StreamFifoCC_1_62 | 66 | 38 | 28 | 0 | 69 | 0 | 0 | 0 |
| (wFifo) | StreamFifoCC_1_62 | 62 | 34 | 28 | 0 | 53 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_7_63 | 3 | 3 | 0 | 0 | 8 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_8_64 | 2 | 2 | 0 | 0 | 8 | 0 | 0 | 0 |
| u_axi_axil_adapter | axi_axil_adapter | 1245 | 1245 | 0 | 0 | 161 | 0 | 0 | 0 |
| axi_axil_adapter_rd_inst | axi_axil_adapter_rd | 640 | 640 | 0 | 0 | 81 | 0 | 0 | 0 |
| axi_axil_adapter_wr_inst | axi_axil_adapter_wr | 605 | 605 | 0 | 0 | 80 | 0 | 0 | 0 |
| u_axi_dvi | axi_dvi | 284 | 284 | 0 | 0 | 211 | 0 | 0 | 0 |
| u_axi_ram | axi_wrap_ram_sp_external | 356 | 356 | 0 | 0 | 78 | 0 | 0 | 0 |
| u_axi_sram_sp | axi2sram_sp_external | 356 | 356 | 0 | 0 | 78 | 0 | 0 | 0 |
| u_axi_uart_controller | axi_uart_controller | 684 | 668 | 16 | 0 | 457 | 0 | 0 | 0 |
| AA_axi2apb_bridge_cpu | axi2apb_bridge | 252 | 252 | 0 | 0 | 120 | 0 | 0 | 0 |
| uart0 | UART_TOP | 432 | 416 | 16 | 0 | 337 | 0 | 0 | 0 |
| regs | uart_regs | 432 | 416 | 16 | 0 | 337 | 0 | 0 | 0 |
| (regs) | uart_regs | 118 | 118 | 0 | 0 | 155 | 0 | 0 | 0 |
| i_uart_sync_flops | uart_sync_flops | 3 | 3 | 0 | 0 | 2 | 0 | 0 | 0 |
| receiver | uart_receiver | 229 | 221 | 8 | 0 | 124 | 0 | 0 | 0 |
| transmitter | uart_transmitter | 83 | 75 | 8 | 0 | 56 | 0 | 0 | 0 |
| u_cdma_matmul_bridge | cdma_matmul_bridge | 248 | 248 | 0 | 0 | 578 | 0 | 0 | 0 |
| u_confreg | confreg | 390 | 390 | 0 | 0 | 476 | 0 | 0 | 0 |
| (u_confreg) | confreg | 230 | 230 | 0 | 0 | 399 | 0 | 0 | 0 |
| u_digitaltube_controller | digitaltube_controller | 16 | 16 | 0 | 0 | 24 | 0 | 0 | 0 |
| u_int_ctrl | int_ctrl | 144 | 144 | 0 | 0 | 53 | 0 | 0 | 0 |
| u_cpu | core_top | 8584 | 8284 | 300 | 0 | 5591 | 0 | 20 | 0 |
| (u_cpu) | core_top | 561 | 513 | 48 | 0 | 1 | 0 | 0 | 0 |
| addr_trans | addr_trans | 2240 | 2100 | 140 | 0 | 1244 | 0 | 0 | 0 |
| (addr_trans) | addr_trans | 0 | 0 | 0 | 0 | 40 | 0 | 0 | 0 |
| tlb_entry | tlb_entry | 2240 | 2100 | 140 | 0 | 1204 | 0 | 0 | 0 |
| axi_bridge | axi_bridge | 39 | 39 | 0 | 0 | 214 | 0 | 0 | 0 |
| btb | btb | 1041 | 961 | 80 | 0 | 1611 | 0 | 0 | 0 |
| (btb) | btb | 1039 | 959 | 80 | 0 | 1611 | 0 | 0 | 0 |
| dec_btb_add_entry | decoder_5_32 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
| dcache | dcache | 551 | 519 | 32 | 0 | 146 | 0 | 10 | 0 |
| (dcache) | dcache | 87 | 55 | 32 | 0 | 138 | 0 | 0 | 0 |
| data_ram_way[0].data_ram_bank[0].u | data_bank_sram_46 | 49 | 49 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[1].u | data_bank_sram_47 | 17 | 17 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[2].u | data_bank_sram_48 | 49 | 49 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[3].u | data_bank_sram_49 | 51 | 51 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[0].u | data_bank_sram_50 | 17 | 17 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[1].u | data_bank_sram_51 | 49 | 49 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[2].u | data_bank_sram_52 | 81 | 81 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[3].u | data_bank_sram_53 | 54 | 54 | 0 | 0 | 0 | 0 | 1 | 0 |
| lfsr | lfsr_54 | 2 | 2 | 0 | 0 | 8 | 0 | 0 | 0 |
| tagv_ram_way[0].u | tagv_sram_55 | 62 | 62 | 0 | 0 | 0 | 0 | 1 | 0 |
| tagv_ram_way[1].u | tagv_sram_56 | 42 | 42 | 0 | 0 | 0 | 0 | 1 | 0 |
| exe_stage | exe_stage | 666 | 666 | 0 | 0 | 233 | 0 | 0 | 0 |
| (exe_stage) | exe_stage | 635 | 635 | 0 | 0 | 233 | 0 | 0 | 0 |
| u_alu | alu | 33 | 33 | 0 | 0 | 0 | 0 | 0 | 0 |
| icache | icache | 233 | 233 | 0 | 0 | 55 | 0 | 10 | 0 |
| (icache) | icache | 12 | 12 | 0 | 0 | 47 | 0 | 0 | 0 |
| data_ram_way[0].data_ram_bank[0].u | data_bank_sram | 4 | 4 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[1].u | data_bank_sram_38 | 3 | 3 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[2].u | data_bank_sram_39 | 67 | 67 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[0].data_ram_bank[3].u | data_bank_sram_40 | 3 | 3 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[0].u | data_bank_sram_41 | 3 | 3 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[1].u | data_bank_sram_42 | 3 | 3 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[2].u | data_bank_sram_43 | 35 | 35 | 0 | 0 | 0 | 0 | 1 | 0 |
| data_ram_way[1].data_ram_bank[3].u | data_bank_sram_44 | 4 | 4 | 0 | 0 | 0 | 0 | 1 | 0 |
| lfsr | lfsr | 2 | 2 | 0 | 0 | 8 | 0 | 0 | 0 |
| tagv_ram_way[0].u | tagv_sram | 15 | 15 | 0 | 0 | 0 | 0 | 1 | 0 |
| tagv_ram_way[1].u | tagv_sram_45 | 88 | 88 | 0 | 0 | 0 | 0 | 1 | 0 |
| id_stage | id_stage | 1054 | 1054 | 0 | 0 | 108 | 0 | 0 | 0 |
| if_stage | if_stage | 134 | 134 | 0 | 0 | 173 | 0 | 0 | 0 |
| mem_stage | mem_stage | 115 | 115 | 0 | 0 | 211 | 0 | 0 | 0 |
| u_csr | csr | 201 | 201 | 0 | 0 | 663 | 0 | 0 | 0 |
| u_div | div | 141 | 141 | 0 | 0 | 107 | 0 | 0 | 0 |
| u_mul | mul | 938 | 938 | 0 | 0 | 592 | 0 | 0 | 0 |
| wb_stage | wb_stage | 682 | 682 | 0 | 0 | 233 | 0 | 0 | 0 |
| u_fft_mlkem_axi_slave | fft_mlkem_axi_slave | 30142 | 28868 | 112 | 1162 | 18251 | 10 | 18 | 0 |
| (u_fft_mlkem_axi_slave) | fft_mlkem_axi_slave | 0 | 0 | 0 | 0 | 6 | 0 | 0 | 0 |
| u_fft_controller | fft_controller | 6934 | 5894 | 0 | 1040 | 1083 | 8 | 4 | 0 |
| (u_fft_controller) | fft_controller | 118 | 118 | 0 | 0 | 100 | 0 | 0 | 0 |
| u_FFT | FFT | 6782 | 5742 | 0 | 1040 | 983 | 8 | 0 | 0 |
| SU1 | SdfUnit | 2144 | 1376 | 0 | 768 | 197 | 2 | 0 | 0 |
| SU2 | SdfUnit__parameterized0 | 1567 | 1375 | 0 | 192 | 197 | 2 | 0 | 0 |
| SU3 | SdfUnit__parameterized1 | 1416 | 1368 | 0 | 48 | 197 | 2 | 0 | 0 |
| SU4 | SdfUnit__parameterized2 | 1397 | 1365 | 0 | 32 | 197 | 2 | 0 | 0 |
| SU5 | SdfUnit__parameterized3 | 258 | 258 | 0 | 0 | 195 | 0 | 0 | 0 |
| u_in0 | my_bram0 | 2 | 2 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_in1 | my_bram0_21 | 2 | 2 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_out0 | my_bram0_22 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_out1 | my_bram0_23 | 32 | 32 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_mlkem_axi_cdc | Axi_CDC_5 | 336 | 224 | 112 | 0 | 272 | 0 | 0 | 0 |
| arFifo | StreamFifoCC_3 | 50 | 22 | 28 | 0 | 55 | 0 | 0 | 0 |
| (arFifo) | StreamFifoCC_3 | 42 | 14 | 28 | 0 | 43 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_9_19 | 4 | 4 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_11_20 | 4 | 4 | 0 | 0 | 6 | 0 | 0 | 0 |
| awFifo | StreamFifoCC | 39 | 15 | 24 | 0 | 49 | 0 | 0 | 0 |
| (awFifo) | StreamFifoCC | 31 | 7 | 24 | 0 | 35 | 0 | 0 | 0 |
| bufferCC_12 | BufferCC_10 | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_9 | 3 | 3 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_11 | 4 | 4 | 0 | 0 | 6 | 0 | 0 | 0 |
| bFifo | StreamFifoCC_2 | 18 | 14 | 4 | 0 | 27 | 0 | 0 | 0 |
| (bFifo) | StreamFifoCC_2 | 11 | 7 | 4 | 0 | 13 | 0 | 0 | 0 |
| bufferCC_12 | BufferCC_5 | 1 | 1 | 0 | 0 | 2 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_4 | 1 | 1 | 0 | 0 | 6 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_6 | 5 | 5 | 0 | 0 | 6 | 0 | 0 | 0 |
| rFifo | StreamFifoCC_4 | 65 | 37 | 28 | 0 | 72 | 0 | 0 | 0 |
| (rFifo) | StreamFifoCC_4 | 58 | 30 | 28 | 0 | 56 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC | 3 | 3 | 0 | 0 | 8 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_1 | 5 | 5 | 0 | 0 | 8 | 0 | 0 | 0 |
| wFifo | StreamFifoCC_1 | 164 | 136 | 28 | 0 | 69 | 0 | 0 | 0 |
| (wFifo) | StreamFifoCC_1 | 159 | 131 | 28 | 0 | 53 | 0 | 0 | 0 |
| popToPushGray_buffercc | BufferCC_7 | 3 | 3 | 0 | 0 | 8 | 0 | 0 | 0 |
| pushToPopGray_buffercc | BufferCC_8 | 3 | 3 | 0 | 0 | 8 | 0 | 0 | 0 |
| u_mlkem_axi_slave | mlkem_axi_slave | 22873 | 22751 | 0 | 122 | 16890 | 2 | 14 | 0 |
| (u_mlkem_axi_slave) | mlkem_axi_slave | 1179 | 1179 | 0 | 0 | 1064 | 0 | 0 | 0 |
| u_mlkem | mlkem_top | 21697 | 21575 | 0 | 122 | 15826 | 2 | 14 | 0 |
| (u_mlkem) | mlkem_top | 2633 | 2633 | 0 | 0 | 5010 | 0 | 0 | 0 |
| u_bank_a | sd_bram__parameterized0 | 61 | 61 | 0 | 0 | 0 | 1 | 1 | 0 |
| u_bank_se | sd_bram__parameterized1 | 77 | 77 | 0 | 0 | 0 | 1 | 0 | 0 |
| u_bank_t | sd_bram__parameterized2 | 632 | 632 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_c_in_bram | sd_bram | 1301 | 1301 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_cbd | sample_cbd_sync_shared | 2739 | 2739 | 0 | 0 | 3186 | 0 | 0 | 0 |
| u_comp | comp_decomp_sync | 620 | 618 | 0 | 2 | 319 | 0 | 0 | 0 |
| u_ct_bram | sd_bram_6 | 10 | 10 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_dkp_bram | sd_bram_7 | 74 | 74 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_ek_bram | sd_bram_8 | 304 | 304 | 0 | 0 | 0 | 0 | 1 | 0 |
| u_keccak | keccak_core | 5258 | 5258 | 0 | 0 | 1618 | 0 | 0 | 0 |
| u_ntt | ntt_core | 1900 | 1817 | 0 | 83 | 1062 | 0 | 4 | 0 |
| u_pmul | poly_mul_sync | 2058 | 2021 | 0 | 37 | 584 | 0 | 4 | 0 |
| u_sha3 | sha3_top_shared | 1955 | 1955 | 0 | 0 | 2378 | 0 | 0 | 0 |
| u_snt | sample_ntt_sync_shared | 2109 | 2109 | 0 | 0 | 1669 | 0 | 0 | 0 |
| u_matmul_axi_slave | matmul_axi_slave | 9879 | 9697 | 176 | 6 | 3243 | 0 | 0 | 0 |
| (u_matmul_axi_slave) | matmul_axi_slave | 5761 | 5579 | 176 | 6 | 2475 | 0 | 0 | 0 |
| mult_inst[0].u_mult | pipelined_mult_32x32 | 1062 | 1062 | 0 | 0 | 192 | 0 | 0 | 0 |
| mult_inst[1].u_mult | pipelined_mult_32x32_2 | 999 | 999 | 0 | 0 | 192 | 0 | 0 | 0 |
| mult_inst[2].u_mult | pipelined_mult_32x32_3 | 1060 | 1060 | 0 | 0 | 192 | 0 | 0 | 0 |
| mult_inst[3].u_mult | pipelined_mult_32x32_4 | 997 | 997 | 0 | 0 | 192 | 0 | 0 | 0 |
| u_snix_axil_cdma_mux_8ch | snix_axil_cdma_mux | 1557 | 1557 | 0 | 0 | 1476 | 0 | 1 | 0 |
| (u_snix_axil_cdma_mux_8ch) | snix_axil_cdma_mux | 600 | 600 | 0 | 0 | 1180 | 0 | 0 | 0 |
| u_core_engine | snix_axi_mm2mm | 960 | 960 | 0 | 0 | 296 | 0 | 1 | 0 |
| (u_core_engine) | snix_axi_mm2mm | 750 | 750 | 0 | 0 | 243 | 0 | 0 | 0 |
| axis_fifo_u0 | snix_axis_fifo | 210 | 210 | 0 | 0 | 53 | 0 | 1 | 0 |
| u_fifo | snix_sync_fifo | 210 | 210 | 0 | 0 | 53 | 0 | 1 | 0 |
+------------------------------------------+------------------------------+------------+------------+---------+------+-------+--------+--------+--------------+
* Note: The sum of lower-level cells may be larger than their parent cells total, due to cross-hierarchy LUT combining

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="940" viewBox="0 0 1800 940">
<defs>
<style>
text { font-family: "Noto Sans CJK SC", "Source Han Sans SC", sans-serif; fill: #17202a; letter-spacing: 0; }
.title { font-size: 31px; font-weight: 700; }
.subtitle { font-size: 18px; fill: #52606d; }
.lane { font-size: 20px; font-weight: 600; }
.tick { font-size: 16px; fill: #52606d; }
.bartext { font-size: 17px; font-weight: 600; }
.small { font-size: 15px; }
.grid { stroke: #d8dee4; stroke-width: 1; }
.axis { stroke: #657786; stroke-width: 2; }
.load { fill: #d7e9ff; stroke: #2674c9; stroke-width: 2; }
.compute { fill: #d8f3dc; stroke: #27864b; stroke-width: 2; }
.result { fill: #e8e0fa; stroke: #7254b3; stroke-width: 2; }
.crc { fill: #ffe8bd; stroke: #c77900; stroke-width: 2; }
.control { fill: #e8edf2; stroke: #62717f; stroke-width: 2; }
.done { fill: #d9f3ef; stroke: #168477; stroke-width: 2; }
.disabled { fill: #f4f5f6; stroke: #8a949e; stroke-width: 2; stroke-dasharray: 9 7; }
.prefetch { fill: none; stroke: #2674c9; stroke-width: 2; stroke-dasharray: 7 5; }
.arrow { stroke: #657786; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
</style>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#657786"/>
</marker>
</defs>
<rect width="1800" height="940" fill="#ffffff"/>
<text x="42" y="48" class="title">Matmul 快速通道数据流甘特图</text>
<text x="42" y="78" class="subtitle">展示前四组进入稳态及最后收尾过程;阶段宽度用于表达依赖和重叠关系,不按周期严格缩放</text>
<!-- Time axis and grid -->
<line x1="350" y1="118" x2="1740" y2="118" class="axis"/>
<g>
<line x1="350" y1="118" x2="350" y2="846" class="grid"/>
<line x1="470" y1="118" x2="470" y2="846" class="grid"/>
<line x1="650" y1="118" x2="650" y2="846" class="grid"/>
<line x1="830" y1="118" x2="830" y2="846" class="grid"/>
<line x1="1010" y1="118" x2="1010" y2="846" class="grid"/>
<line x1="1190" y1="118" x2="1190" y2="846" class="grid"/>
<line x1="1370" y1="118" x2="1370" y2="846" class="grid"/>
<line x1="1510" y1="118" x2="1510" y2="846" class="grid"/>
<line x1="1640" y1="118" x2="1640" y2="846" class="grid"/>
<line x1="1740" y1="118" x2="1740" y2="846" class="grid"/>
</g>
<g text-anchor="middle">
<text x="410" y="108" class="tick">启动</text>
<text x="560" y="108" class="tick">组0装载</text>
<text x="740" y="108" class="tick">组1装载</text>
<text x="920" y="108" class="tick">组2装载</text>
<text x="1100" y="108" class="tick">组3装载</text>
<text x="1280" y="108" class="tick">稳态流水</text>
<text x="1440" y="108" class="tick">末组计算</text>
<text x="1575" y="108" class="tick">CRC排空</text>
<text x="1690" y="108" class="tick">完成</text>
</g>
<!-- Lane separators and labels -->
<g>
<line x1="34" y1="200" x2="1740" y2="200" class="grid"/>
<line x1="34" y1="280" x2="1740" y2="280" class="grid"/>
<line x1="34" y1="360" x2="1740" y2="360" class="grid"/>
<line x1="34" y1="440" x2="1740" y2="440" class="grid"/>
<line x1="34" y1="520" x2="1740" y2="520" class="grid"/>
<line x1="34" y1="600" x2="1740" y2="600" class="grid"/>
<line x1="34" y1="680" x2="1740" y2="680" class="grid"/>
<line x1="34" y1="760" x2="1740" y2="760" class="grid"/>
<line x1="34" y1="840" x2="1740" y2="840" class="grid"/>
</g>
<g>
<text x="44" y="170" class="lane">批量序列器</text>
<text x="44" y="250" class="lane">CDMA / AXI读</text>
<text x="44" y="330" class="lane">Bank 0 A/B</text>
<text x="44" y="410" class="lane">Bank 1 A/B</text>
<text x="44" y="490" class="lane">单一乘加流水线</text>
<text x="44" y="570" class="lane">C结果与退休</text>
<text x="44" y="650" class="lane">CRC结果FIFO</text>
<text x="44" y="730" class="lane">递归CRC32</text>
<text x="44" y="810" class="lane">ExtRAM结果写回</text>
</g>
<!-- Sequencer -->
<rect x="360" y="142" width="105" height="42" rx="4" class="control"/>
<text x="412" y="169" text-anchor="middle" class="bartext">清状态/CRC</text>
<rect x="470" y="142" width="1035" height="42" rx="4" class="control"/>
<text x="987" y="169" text-anchor="middle" class="bartext">提交读请求、维护双Bank有效位与计算队列</text>
<rect x="1510" y="142" width="125" height="42" rx="4" class="crc"/>
<text x="1572" y="169" text-anchor="middle" class="bartext">等待CRC空闲</text>
<rect x="1640" y="142" width="95" height="42" rx="4" class="done"/>
<text x="1687" y="169" text-anchor="middle" class="bartext">DONE</text>
<!-- CDMA shared read channel -->
<rect x="470" y="222" width="175" height="42" rx="4" class="load"/>
<text x="557" y="249" text-anchor="middle" class="bartext">G0: 128 B -> B0</text>
<rect x="650" y="222" width="175" height="42" rx="4" class="load"/>
<text x="737" y="249" text-anchor="middle" class="bartext">G1: 128 B -> B1</text>
<rect x="830" y="222" width="175" height="42" rx="4" class="load"/>
<text x="917" y="249" text-anchor="middle" class="bartext">G2: 128 B -> B0</text>
<rect x="1010" y="222" width="175" height="42" rx="4" class="load"/>
<text x="1097" y="249" text-anchor="middle" class="bartext">G3: 128 B -> B1</text>
<rect x="1190" y="222" width="315" height="42" rx="4" class="load"/>
<text x="1347" y="249" text-anchor="middle" class="bartext">G4 ... G4999 顺序返回</text>
<path d="M 585 216 L 735 216 M 765 216 L 915 216 M 945 216 L 1095 216" class="prefetch"/>
<text x="1310" y="216" text-anchor="middle" class="small" fill="#2674c9">共享R通道:1个活动突发 + 1个预取请求</text>
<!-- Bank buffers -->
<rect x="470" y="302" width="175" height="42" rx="4" class="load"/>
<text x="557" y="329" text-anchor="middle" class="bartext">装载 G0</text>
<rect x="650" y="302" width="175" height="42" rx="4" class="compute"/>
<text x="737" y="329" text-anchor="middle" class="bartext">供计算 G0</text>
<rect x="830" y="302" width="175" height="42" rx="4" class="load"/>
<text x="917" y="329" text-anchor="middle" class="bartext">装载 G2</text>
<rect x="1010" y="302" width="175" height="42" rx="4" class="compute"/>
<text x="1097" y="329" text-anchor="middle" class="bartext">供计算 G2</text>
<rect x="1190" y="302" width="315" height="42" rx="4" class="control"/>
<text x="1347" y="329" text-anchor="middle" class="bartext">偶数组循环复用</text>
<rect x="470" y="382" width="175" height="42" rx="4" class="control"/>
<text x="557" y="409" text-anchor="middle" class="bartext">空闲</text>
<rect x="650" y="382" width="175" height="42" rx="4" class="load"/>
<text x="737" y="409" text-anchor="middle" class="bartext">装载 G1</text>
<rect x="830" y="382" width="175" height="42" rx="4" class="compute"/>
<text x="917" y="409" text-anchor="middle" class="bartext">供计算 G1</text>
<rect x="1010" y="382" width="175" height="42" rx="4" class="load"/>
<text x="1097" y="409" text-anchor="middle" class="bartext">装载 G3</text>
<rect x="1190" y="382" width="315" height="42" rx="4" class="control"/>
<text x="1347" y="409" text-anchor="middle" class="bartext">奇数组循环复用</text>
<!-- Shared compute pipeline -->
<rect x="650" y="462" width="165" height="42" rx="4" class="compute"/>
<text x="732" y="489" text-anchor="middle" class="bartext">G0 发射16项</text>
<rect x="815" y="462" width="165" height="42" rx="4" class="compute"/>
<text x="897" y="489" text-anchor="middle" class="bartext">G1 发射16项</text>
<rect x="980" y="462" width="165" height="42" rx="4" class="compute"/>
<text x="1062" y="489" text-anchor="middle" class="bartext">G2 发射16项</text>
<rect x="1145" y="462" width="165" height="42" rx="4" class="compute"/>
<text x="1227" y="489" text-anchor="middle" class="bartext">G3 发射16项</text>
<rect x="1310" y="462" width="195" height="42" rx="4" class="compute"/>
<text x="1407" y="489" text-anchor="middle" class="bartext">... 末组</text>
<!-- Results and retirement -->
<rect x="690" y="542" width="165" height="42" rx="4" class="result"/>
<text x="772" y="569" text-anchor="middle" class="bartext">G0 C[0..15]</text>
<rect x="855" y="542" width="165" height="42" rx="4" class="result"/>
<text x="937" y="569" text-anchor="middle" class="bartext">G1 C[0..15]</text>
<rect x="1020" y="542" width="165" height="42" rx="4" class="result"/>
<text x="1102" y="569" text-anchor="middle" class="bartext">G2 C[0..15]</text>
<rect x="1185" y="542" width="320" height="42" rx="4" class="result"/>
<text x="1345" y="569" text-anchor="middle" class="bartext">G3 ... G4999;完成即退休</text>
<!-- CRC decoupling -->
<rect x="690" y="622" width="815" height="42" rx="4" class="crc"/>
<text x="1097" y="649" text-anchor="middle" class="bartext">每个66位C元素入FIFO;队列接近阈值时反压乘加发射</text>
<rect x="710" y="702" width="925" height="42" rx="4" class="crc"/>
<text x="1172" y="729" text-anchor="middle" class="bartext">递归CRC32:每个元素分两步处理,共12字节;末组之后继续排空</text>
<!-- Disabled writeback -->
<rect x="470" y="782" width="1165" height="42" rx="4" class="disabled"/>
<line x1="485" y1="815" x2="1620" y2="791" stroke="#8a949e" stroke-width="2"/>
<text x="1052" y="809" text-anchor="middle" class="bartext" fill="#68737d">快速通道:跳过192 B/组的C结果写回(标准模式才启用)</text>
<!-- Dependency arrows -->
<path d="M 645 264 L 670 302" class="arrow"/>
<path d="M 825 264 L 850 382" class="arrow"/>
<path d="M 815 504 L 835 542" class="arrow"/>
<path d="M 855 584 L 875 622" class="arrow"/>
<path d="M 1505 584 L 1550 702" class="arrow"/>
<path d="M 1635 723 L 1660 184" class="arrow"/>
<!-- Legend -->
<g transform="translate(42 884)">
<rect x="0" y="-17" width="28" height="20" class="load"/><text x="38" y="0" class="small">ExtRAM到Bank装载</text>
<rect x="220" y="-17" width="28" height="20" class="compute"/><text x="258" y="0" class="small">乘加计算</text>
<rect x="410" y="-17" width="28" height="20" class="result"/><text x="448" y="0" class="small">C结果/退休</text>
<rect x="600" y="-17" width="28" height="20" class="crc"/><text x="638" y="0" class="small">CRC缓冲与更新</text>
<rect x="835" y="-17" width="28" height="20" class="disabled"/><text x="873" y="0" class="small">快速模式禁用路径</text>
<text x="1160" y="0" class="small" fill="#52606d">系统时钟:50 MHz</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -0,0 +1,104 @@
# 时钟域、复位与跨时钟域设计说明
## 1. 时钟拓扑
板级输入 `clk` 的周期为 20 ns,即 50 MHz。硬件路径由 `clk_pll` 产生 CPU、系统总线和
ML-KEM 三个时钟。当前实现报告记录的周期和频率如下。
| 时钟 | 周期 | 频率 | 主要负载 |
|---|---:|---:|---|
| `cpu_clk` | 30 ns | 33.333 MHz | OpenLA500 CPU、CPU 侧缓存和 AXI 主接口 |
| `sys_clk` | 20 ns | 50 MHz | Crossbar、SRAM、UART、DMA、FFT、matmul 和系统寄存器 |
| `mlkem_clk` | 13 ns | 76.923 MHz | ML-KEM AXI 从端、算法总控、Keccak、NTT 和多项式算子 |
三个时钟均由同一个 PLL 产生,但 `soc.xdc` 使用 `set_clock_groups -asynchronous` 将三者
划入独立异步组。工程含义是任何跨域逻辑都不能依赖固定相位关系,静态时序分析也不会把
普通组合路径当作同步时序路径检查。跨域正确性必须由双时钟 FIFO、同步器、握手协议和
专门的 CDC 验证保证。
## 2. 模块归属
CPU 核及其 AXI 主端属于 CPU 域。CPU 发出的 AW、W、AR 通道在进入 Crossbar 前跨到
SYS 域,B 和 R 响应反向跨回 CPU 域。Crossbar 的两个主端、八个从端、外部 SRAM、
DMA、FFT、矩阵序列器和矩阵乘法器全部属于 SYS 域,这些模块之间是同步连接。
FFT/ML-KEM 共享从端的地址选择和 FFT 分支属于 SYS 域。ML-KEM 分支的完整 AXI 接口
跨到 ML-KEM 域后,`mlkem_axi_slave`、`mlkem_top` 及其所有叶子算子均在
`mlkem_clk` 下工作。密码核心内部没有第二个计算时钟。
## 3. CPU--SYS AXI 跨域
`u_Axi_CDC` 为 AXI 的 AW、W、B、AR 和 R 五个通道分别设置双时钟 FIFO。AW、W 和 AR
在 CPU 域写入 FIFO、在 SYS 域读出;B 和 R 在 SYS 域写入、在 CPU 域读出。FIFO 将
valid/ready 反压限制在各自时钟域,并连同地址、ID、burst 属性、数据、WSTRB、响应和
RLAST/WLAST 一起跨域。
该结构不对多位 AXI payload 逐位使用两级同步器,而是在写时钟域稳定写入存储,使用同步
后的读写指针传递所有权,再在读时钟域读取。这是多位总线跨域的必要条件。AW 和 W 仍为
独立通道,下游从端必须按 AXI 规则处理两者不同拍到达,不能假设跨域 FIFO 会自动配对。
CPU--SYS 路径的延迟包含 FIFO 入队、指针同步和出队,不应通过 CPU 与 SYS 周期的简单
比例估算。端到端软件周期已经包含该延迟。
## 4. SYS--ML-KEM AXI 跨域
`fft_mlkem_axi_slave` 在 SYS 域锁存目标选择。FFT 请求保持在 SYS 域;ML-KEM 请求进入
第二个 `Axi_CDC`,再由 ML-KEM 域的 `mlkem_axi_slave` 处理。该跨域同样覆盖 AXI 五个
通道,而不是只同步 start/done。因此配置寄存器、批量密钥窗口和读回数据都遵循统一的
AXI CDC 语义。
ML-KEM 完成中断在 `mlkem_clk` 域产生,先通过两级 `mlkem_intr_sync` 同步到 SYS 域。
由于完成状态保持到软件 W1C,接收端观察的是电平而不是单周期脉冲,避免因频率差异丢失
事件。软件读取 STATUS 获得最终完成语义,中断只负责通知。
## 5. 中断到 CPU 的边界
当前 `soc_top` 将 `confreg_int`、DMA done、matmul done 和 ML-KEM done 组合后直接连接
到 CPU 的 `intrpt` 输入。其中 DMA 和 matmul 状态产生于 SYS 域;ML-KEM 状态虽已同步到
SYS 域,仍需跨入 CPU 域。它们均为保持到清除的电平信号,因此相较单拍脉冲更不易漏采,
但当前顶层没有为项目新增的三路中断显式实例化 CPU 域两级同步器。
严谨的前端实现应在 `cpu_clk` 域对每路异步电平增加两级 `ASYNC_REG` 同步,或把中断状态
放入已有的 CPU--SYS 握手寄存器。同步前的电平必须保持不少于两个 CPU 周期,清除语义也
应以 CPU 可观察到状态后再执行。该项属于时钟域实现风险,不能仅以板级轮询程序通过替代
结构验证。
## 6. 复位生成与释放顺序
`rst_sync` 包含两个串联寄存器。输入复位有效时通过异步低电平立即把两级清零;输入复位
撤销后,逻辑 1 在本时钟域连续两个上升沿移入,形成异步断言、同步撤销的低有效复位。
硬件路径中,外部 reset 先复位 PLL。PLL `locked` 进入 SYS 域复位同步器,产生
`sys_resetn`;随后 `sys_resetn` 分别作为 CPU 和 ML-KEM 复位同步器输入,产生
`cpu_resetn` 和 `mlkem_resetn`。因此 SYS 域先释放,CPU 和 ML-KEM 域至少再等待各自两个
有效时钟边沿。CDC 两侧在各自复位释放前不得发送 valid,也不得保留上一轮 FIFO 所有权。
行为仿真 `SIMULATION=1` 不实例化 PLL。testbench 的 50 MHz 时钟直接作为 `sys_clk`,
内部 30 ns 周期时钟作为 `cpu_clk`,`mlkem_clk` 暂等于 `sys_clk`。此模式可验证复位顺序
和零事务,但不能验证真实 13 ns ML-KEM 时钟的相位、PLL 锁定过程或异步 FIFO 的全部
频率组合。
当前 20 us XSIM VCD 中,外部 reset 在 2.000 us 撤销,`sys_resetn`、`mlkem_resetn` 和
`cpu_resetn` 分别约在 2.030、2.070 和 2.085 us 释放。第一个 CPU ARVALID 约在
2.205 us 出现,复位释放前 UART、AXI、DMA 请求和加速器 start 均没有高电平。
## 7. 跨域信号设计规则
单比特静态状态可以采用两级同步器,但源端必须保持足够长时间。单周期脉冲需要 toggle、
脉冲展宽或 request/ack 握手,不能直接送入另一个时钟域。多位配置和数据必须通过异步
FIFO、握手后稳定保持的影子寄存器或双口存储传递,禁止逐位同步后重新组合。
复位也是跨域信号。每个时钟域必须使用本地同步释放的 resetn,不能用另一个域同步器的
输出直接复位本域大量寄存器。所有 CDC 结构的两侧复位关系必须保证复位期间不会把残留
valid 解释为新事务。
## 8. 时序与验证方法
单域时序分别在 `cpu_clk`、`sys_clk` 和 `mlkem_clk` 路径组内检查 setup 和 hold。由于
时钟组被声明为异步,跨域路径不应以普通 WNS 作为正确性依据。验证应包括 CDC 结构审查、
同步寄存器属性检查、异步 FIFO 满空边界、随机相位/频率仿真、复位任意时刻进入,以及
valid/ready 双向反压。
板级功能测试证明常用任务能够跨域完成,但不能观察亚稳态。报告中的时钟域结论应分别
引用时钟报告、单域时序报告、复位波形和 CDC 结构说明,避免用单一板级 PASS 替代这些
不同层次的证据。

View File

@@ -0,0 +1,77 @@
# SoC 集成与时钟复位技术说明
## 1. 模块定位
`rtl/soc_top.v` 是项目的系统集成顶层。该文件不重新实现 CPU、UART 或 SRAM 控制器,
而是将 OpenLA500 处理器、存储器、外设、DMA 和三个计算加速器组织为统一的 AXI 系统。
项目相关的集成工作包括扩展 Crossbar 从端口、增加 DMA 主端口、划分加速器地址窗口、
建立 CPU--SYS 和 SYS--ML-KEM 时钟边界,以及将完成状态接入中断系统。
系统采用 CPU 控制、DMA 搬运、加速器计算的职责划分。CPU 通过寄存器完成参数配置和
任务启动;DMA 作为第二个 AXI 主机访问存储器与外设;FFT、ML-KEM 和矩阵乘法器作为
被控计算单元。矩阵批处理序列器位于 DMA 控制窗口内,可脱离 CPU 的逐组调度执行长任务。
## 2. 地址空间与互连
系统 Crossbar 具有两个主端和八个从端。主端 0 接收经 `Axi_CDC` 转换后的 CPU AXI
事务,主端 1 接收 DMA 发起的 AXI 事务。与本项目直接相关的从端如下。
| 物理地址 | 模块 | 作用 |
|---|---|---|
| `0x1f30_0000` | DMA 控制窗口 | 通道寄存器位于 `0x000--0x1ff`,矩阵序列器位于 `0x200--0x21f` |
| `0x1f40_0000` | FFT/ML-KEM 共享窗口 | ML-KEM 使用低 `0x0000--0x3fff`,FFT 使用 `0x8000--0xcfff` |
| `0x1f50_0000` | 矩阵乘法器 | 控制状态、CRC32、双 Bank 输入和结果窗口 |
CPU 软件使用高位映射访问未缓存地址,例如物理地址 `0x1f40_0000` 对应
`0xbf40_0000`。DMA 始终使用物理地址,软件在提交描述符前需要去除 CPU 虚拟地址的
高位映射。该约定避免 DMA 错把虚拟地址送入 Crossbar。
DMA 控制从端原始接口为 AXI4,经 `axi_axil_adapter` 转换为 AXI-Lite。地址偏移
`0x200` 的访问在顶层被路由到 `cdma_matmul_bridge`,其余访问进入通用 DMA 通道寄存器。
写地址的目标选择在 AW 握手后保持到 B 响应返回,读地址选择保持到 R 响应返回,从而
避免响应阶段再次依赖变化中的地址信号。
## 3. 时钟结构
硬件实现使用 50 MHz 外部时钟驱动 PLL,产生三个逻辑时钟域。当前实现报告中的目标
频率为 CPU 33.333 MHz、系统总线 50 MHz 和 ML-KEM 76.923 MHz。CPU 核及其 AXI 侧
逻辑工作在 `cpu_clk`;Crossbar、DMA、FFT、矩阵乘法器和外设工作在 `sys_clk`;
ML-KEM 核心工作在 `mlkem_clk`。
CPU AXI 五个通道通过 `Axi_CDC` 跨入系统时钟域。ML-KEM 的配置、批量数据窗口和完成
响应通过第二个完整 AXI CDC 跨越 SYS--ML-KEM 边界;`mlkem_axi_slave` 内部的
toggle/ack 负责把寄存器动作转换为单次事件。FFT 与矩阵乘法器均位于系统时钟域,不需要
额外的计算域 CDC。
完整的时钟归属、异步时钟组约束、AXI 双时钟 FIFO 和中断边界见
[时钟域、复位与跨时钟域设计说明](00_clock_domains.md)。本文件只说明顶层集成关系。
行为仿真中 `SIMULATION=1`,PLL 被可控仿真时钟替代:`sys_clk` 使用 50 MHz testbench
时钟,`cpu_clk` 使用约 33.333 MHz 时钟,`mlkem_clk` 暂与 `sys_clk` 相同。该模式用于
功能验证,不用于推导硬件 PLL 的锁定时间或跨域相位关系。
## 4. 复位结构
硬件路径中,PLL 的 `locked` 信号首先送入系统域 `rst_sync`。`sys_resetn` 释放后,CPU
域和 ML-KEM 域的复位同步器再分别产生 `cpu_resetn` 和 `mlkem_resetn`。各同步器采用
异步断言、同步撤销原则,使复位可立即进入有效状态,而退出复位只能发生在本时钟域的
有效边沿。
复位约束不仅要求状态机回到初始状态,还要求复位释放前不产生外部可见事务。当前短时
XSIM 证据记录了 UART 写使能、CPU AXI AW/W/AR valid、DMA 读写请求、矩阵启动和
ML-KEM 启动。VCD 中 `sys_resetn`、`mlkem_resetn` 和 `cpu_resetn` 分别约在 2.030 us、
2.070 us 和 2.085 us 释放;第一个 CPU 读请求出现在约 2.205 us,晚于 CPU 复位释放。
## 5. 中断与完成状态
DMA 的通道完成标志归并为 `cdma_dma_finish`,矩阵序列器另有 `cdma_matmul_seq_irq`。
矩阵乘法器输出电平型 `matmul_intr`,ML-KEM 前端输出 `mlkem_intr`,FFT 完成状态接入
原有 `confreg` 中断路径。性能测试程序主要采用轮询,以减少短任务的中断现场开销;
中断信号仍保留给功能软件和后续异步调度使用。
## 6. 验证重点
顶层验证应覆盖地址译码互斥性、CPU 与 DMA 并发访问、AW/W 分离到达、复位前零事务、
各域复位释放顺序以及完成状态的置位和清除。板级功能通过 FFT、ML-KEM 和矩阵乘法
程序分别验证;时钟频率、时序裕量和资源使用以实现后报告为准。行为仿真不能替代 PLL
实现检查,单个应用通过也不能证明所有地址空洞和并发组合均已覆盖。

View File

@@ -0,0 +1,83 @@
# 通用 DMA 子系统技术说明
## 1. 功能与组成
DMA 子系统位于 `rtl/ip/cdma/`,对软件提供四个逻辑通道,对系统提供一个 32 位 AXI4
主端,并对矩阵乘法器提供 32 位本地 endpoint。当前顶层实例参数为 `PORTS=4`、
`DATA_WIDTH=32`、`FIFO_DEPTH=64`。源码中的“8 通道”实例名和注释是历史名称,实际
综合配置应以参数值四通道为准。
子系统由三部分组成。`snix_axil_cdma_mux` 实现通道寄存器、轮询仲裁、传输模式选择和
AXI 主端复用;`snix_axi_mm2mm` 实现普通内存到内存的 burst 搬运;本地 endpoint 状态机
实现内存与矩阵双 Bank 之间的数据传递。同步 FIFO 和 AXIS FIFO 用于隔离 AXI 读、写
通道的反压。
## 2. 软件接口
每个通道占用 `0x40` 字节,通道 `n` 的偏移基址为 `n*0x40`。
| 偏移 | 名称 | 说明 |
|---|---|---|
| `0x00` | SRC_ADDR | 源物理地址 |
| `0x04` | DST_ADDR | 目的物理地址 |
| `0x08` | LENGTH | 传输字节数 |
| `0x0c` | TAG | 软件标记,硬件不解释 |
| `0x10` | CTRL | bit 0 启动,bits 5:3 为 AxSIZE,bits 13:6 为 AxLEN |
| `0x14` | STATUS | bit 0 busy,bit 1 done;done 采用 W1C |
| `0x18` | MODE | 0 为 mem2mem,1 为 mem2ep,2 为 ep2mem |
| `0x1c` | EP_CFG | bits 3:0 Bank,bits 15:8 word offset,bits 19:16 endpoint ID |
通道处于 busy 时,源地址、目的地址、长度、模式和 endpoint 配置不再接受修改。新启动
请求会清除旧 done,硬件完成与软件 W1C 同周期发生时以硬件置位优先,避免丢失完成事件。
所有地址均为物理地址,长度以字节计。
## 3. 通道仲裁
`snix_axil_cdma_mux` 为四个通道维护独立的请求位和完成位,但共享一个实际搬运引擎。
仲裁器从 `rr_ptr` 开始循环检查待处理通道,选中后锁存 `cur_ch`,在 START 状态发出单拍
`engine_start`,在 RUN 状态等待对应引擎完成。完成后设置该通道 done,并将轮询指针
移动到下一通道。该结构保证长期存在的请求不会固定占用最低编号优先级。
共享引擎意味着四个通道可以独立排队,但不能同时占用 AXI 主端。多通道的主要收益是
减少软件串行配置依赖并提供公平排队,而不是形成四路并行 AXI 数据流。
## 4. 内存到内存路径
`snix_axi_mm2mm` 的控制状态依次为 IDLE、PREP1、PREP2、AR、READ、AW、WRITE 和
WAIT_BRESP。引擎先计算本次 burst 的实际长度,发出 INCR 读请求,将 R 通道数据写入
FIFO,再发出对应写请求并从 FIFO 驱动 W 通道。最后一个写响应返回后,若仍有剩余字节,
引擎更新源地址和目的地址并处理下一 burst。
读数据只在 READ 状态接收,写数据只在 WRITE 状态发送。该门控防止非活动状态下的
AXI beat 被误计数。末尾不足一个数据宽度时由 `WSTRB` 屏蔽无效字节。当前 SoC 数据宽度
为 32 bit,常用配置为 AxSIZE=2,即每 beat 4 字节。
## 5. 本地 endpoint 路径
mem2ep 模式从 AXI 地址读取数据,并逐字送往 `ep_wr_valid/ready`;ep2mem 模式通过
`ep_rd_valid/ready` 读取本地结果,再发出 AXI 写事务。endpoint 接口附带 endpoint ID、
Bank 号和字地址,因此无需把矩阵双 Bank 映射回 Crossbar,也避免每个 32 位字再次经过
从端地址译码。
矩阵批处理序列器还可通过 `ext_rd_req_*` 和 `ext_wr_req_*` 直接提交一次外部请求。这组
请求优先占用 AXI 主端,并在通用通道引擎空闲时接收。读请求完成后产生单拍
`ext_rd_req_done`,写请求在 B 响应返回后产生 `ext_wr_req_done`。该接口用于流水调度,
减少序列器重复写入通道 CSR 的延迟。
## 6. 复位与反压
当前集成的 DMA 通道寄存器、仲裁器、mem2mem 引擎、endpoint 引擎和 AXI 主端均工作在
`sys_clk`,内部不存在活动的异步时钟边界。仓库保留的 `snix_async_fifo` 未被当前
`soc_top` 层次实例化;实际数据 FIFO 为同一 SYS 域内的同步 FIFO。
所有控制状态、通道请求和完成位在 `rst_n=0` 时清零。AXI 与 endpoint 均遵循
valid/ready 规则:发送端在握手前保持数据和控制字段,接收端可通过 ready 插入反压。
目前 endpoint 只按 32 位数据宽度实现,字节数不是 4 的整数倍时不应使用该路径。
## 7. 验证方法与限制
DMA 验证至少应覆盖不同 burst 长度、末尾非满 beat、四通道公平性、R/W 反压、
mem2mem、mem2ep、ep2mem 和 W1C 竞态。当前板级 FFT DMA 和 ML-KEM DMA 测试证明了
普通外设窗口搬运路径,矩阵评测证明了外部请求与本地 endpoint 路径。当前实现未设置
总线超时和错误恢复状态,若 AXI 从端永久不响应,通道会保持 busy;因此系统集成时必须
保证目标地址有效,或在后续版本增加 watchdog 和错误码。

View File

@@ -0,0 +1,70 @@
# 矩阵批处理序列器技术说明
## 1. 模块职责
`cdma_matmul_bridge` 将一次软件启动扩展为多组矩阵的完整硬件调度。模块位于 DMA 控制
窗口偏移 `0x200`,通过通用 DMA 的外部请求接口搬运输入和可选结果,通过本地控制信号
启动矩阵乘法器。该结构消除了 CPU 对 5000 组任务逐组配置、轮询和切换 Bank 的开销。
序列器、通用 DMA 外部请求接口和矩阵本地控制接口全部工作在 `sys_clk`,因此 Bank 状态、
request/done 和 start 信号之间为同步路径。CPU 对序列器寄存器的访问在到达本模块前已由
CPU--SYS `Axi_CDC` 完成跨域。
每组输入由两个 4x4、32 位无符号矩阵组成,共 32 个字,即 128 字节。每组结果包含
16 个 66 位元素,以每元素三个 32 位字存储,共 192 字节。序列器使用可配置 stride,
因此数据可以连续排列,也可嵌入更大的记录结构。
## 2. 寄存器接口
| 绝对偏移 | 名称 | 说明 |
|---|---|---|
| `0x200` | CTRL | bit 0 启动,bit 1 跳过结果写回 |
| `0x204` | STATUS | bit 0 busy,bit 1 done;done 为 W1C |
| `0x208` | SRC_BASE | 第一组 A/B 的物理地址 |
| `0x20c` | DST_BASE | 第一组 C 的物理地址 |
| `0x210` | GROUPS | 任务组数 |
| `0x214` | MAT_BASE | 软件兼容字段,当前直接 endpoint 路径不使用 |
| `0x218` | SRC_STRIDE | 相邻输入组地址间隔,默认 128 字节 |
| `0x21c` | DST_STRIDE | 相邻结果组地址间隔,默认 192 字节 |
配置寄存器只在序列器空闲时接受写入。启动时模块锁存是否跳过写回,清除旧完成状态,
清零矩阵 CRC,并初始化组计数、地址计数和两个 Bank 的占用状态。`GROUPS=0` 不产生计算。
## 3. 双 Bank 调度模型
序列器为两个 Bank 分别维护 load active、A/B valid、compute active、store pending 和
store active 五类状态。一个 Bank 只有在上述状态均为零时才能接收下一组输入。输入组
按组号奇偶映射到 Bank 0/1,并在 `bank_group_idx` 中记录所属组号。
调度过程包含三个可重叠阶段。装载阶段提交 128 字节 mem2ep 请求;计算阶段在 A/B
有效后发出 `mat_start_valid` 和 Bank 号;存储阶段在计算完成后提交 192 字节 ep2mem
请求。只要另一 Bank 可用,下一组装载可以与当前组计算或结果写回交叠。
当两个 Bank 均具备计算条件时,序列器选择组号较小者,保持提交顺序。计算 Bank 被放入
两项深度的 `compute_q`,用于把矩阵乘法器的电平 done 事件对应回具体 Bank。done 通过
边沿检测转化为单次完成事件,防止电平保持期间重复退休同一任务。
## 4. 完成与快速路径
正常模式下,一组任务在结果写回的 B 响应完成后退休。快速模式设置
`skip_result_writeback`,计算完成即退休,不再把 192 字节结果写入 ExtRAM。矩阵乘法器
在计算结果产生时直接更新整批 CRC32,因此跳过写回不会跳过正确性判定。该模式适用于
官方评测只检查最终 CRC、无需读取全部结果矩阵的场景。
当 `groups_retired` 达到配置组数,且没有活动的装载、计算和存储任务时,序列器清除
busy、置位 done 并拉高 `seq_done_irq`。软件通过 STATUS 的 W1C 位确认并清除完成状态。
## 5. 关键不变量
同一 Bank 不得同时被装载和计算,也不得在结果尚未消费时覆盖。组号只在输入请求被接受
后递增,退休计数只响应写回完成或快速模式下的计算完成。输入和结果地址分别按 stride
递增,不从 Bank 号反推地址。CRC 只在整批启动时清零,不在 Bank 切换时清零。
这些不变量是验证的核心。若仅检查最终 done,无法发现 Bank 覆盖、组号乱序或重复退休。
测试平台应同时观察每个 Bank 的状态向量、DMA 请求握手、矩阵 start/done 和退休计数。
## 6. 当前验证范围
区域赛证据包含三次 5000 组官方板级运行,三次均收到完成标志并通过 CRC。该结果验证了
长序列快速模式的主要数据流,但不等价于覆盖所有边界。模块级回归仍应包含组数 1、2、3,
两种写回模式,不同 stride,DMA 读写反压,以及 done W1C 后立即启动下一批等场景。

View File

@@ -0,0 +1,82 @@
# 4x4 矩阵乘法加速器技术说明
## 1. 计算规格
`matmul_axi_slave` 计算两个 4x4 无符号整数矩阵的乘积。输入元素宽度为 32 bit,输出
元素满足
`C[i][j] = sum(A[i][k] * B[k][j]), k=0..3`。
单个乘积为 64 bit,四项相加的最坏情况需要 66 bit,因此结果存储宽度固定为 66 bit。
每个输出元素通过三个 32 位字传输:低 32 位、高 32 位以及最高 2 位。该布局使 AXI 和
DMA 数据宽度保持 32 bit,同时不截断数学结果。
## 2. 接口组成
模块同时提供完整 AXI4 从接口、本地 DMA endpoint 和矩阵序列器直连控制接口。AXI
接口支持 INCR burst,可由 CPU 或普通 DMA 访问控制寄存器及双 Bank 数据窗口。本地
endpoint 直接接收 A/B 字或输出 C 字,不经过 Crossbar 的矩阵从端。序列器通过
`mat_start_valid`、`mat_start_bank`、`mat_done_clear` 和 `mat_crc_clear` 完成批处理控制。
矩阵 AXI 从端、endpoint、乘法流水线和 CRC 均使用 `sys_clk/sys_resetn`。DMA 和序列器也
位于 SYS 域,三者之间没有 CDC。CPU 发起的矩阵访问在 Crossbar 之前已经跨入 SYS 域。
`matmul_intr` 产生于 SYS 域,接入 CPU 前的时钟边界见独立时钟域说明。
两个 endpoint ready 在当前实现中恒为 1,表示矩阵本地缓冲不施加反压。上游仍必须只在
目标 Bank 空闲时写入,Bank 所有权由批处理序列器保证,而不是由加速器内部检查。
## 3. 寄存器与双 Bank 布局
| 偏移 | 内容 | 说明 |
|---|---|---|
| `0x000` | CTRL | bit 0 请求 Bank 0,bit 1 请求 Bank 1 |
| `0x004` | STATUS | busy、done、error;done/error 支持 W1C |
| `0x010` | CRC32 | 返回 `crc_reg XOR 0xffff_ffff`;写入用于清零 CRC |
| `0x100` | Bank 0 A | 16 个 32 位元素 |
| `0x140` | Bank 0 B | 16 个 32 位元素 |
| `0x180` | Bank 0 C | 16 个 66 位元素,共 48 个 32 位字 |
| `0x300` | Bank 1 A | 16 个 32 位元素 |
| `0x340` | Bank 1 B | 16 个 32 位元素 |
| `0x380` | Bank 1 C | 16 个 66 位元素,共 48 个 32 位字 |
A 和 B 均按行优先方式存储。endpoint 写地址 0--15 对应 A,16--31 对应 B;endpoint
读地址 0--47 对应 C 的三字布局。双 Bank 允许一组数据计算时准备另一组,但计算核心
本身一次只处理一个 Bank。
## 4. 乘法数据通路
核心包含四个 `pipelined_mult_32x32` 实例,并使用 `use_dsp="no"` 属性约束综合器将乘法
映射到 LUT 逻辑。每个乘法器包含输入寄存、乘积寄存和输出寄存三个流水级,吞吐率为
每周期一个乘积。
计算核心每周期选择一个输出元素 `(i,j)`,同时向四个乘法器发出
`A[i][0..3]` 与 `B[0..3][j]`。流水线对齐后,四个 64 位乘积采用成对加法生成一个
66 位结果。16 个输出元素连续发射,索引和 Bank 标识经过四级有效流水线与乘积对齐。
因此稳态吞吐为每周期一个 C 元素,而不是逐项乘加的四周期结构。
当 Bank 0 完成且 Bank 1 已有待处理请求时,状态机可直接调用 `start_calc_bank` 切换
Bank,不必先返回空闲态。最后一个有效结果写回时产生 `calc_done_pulse`,置位 done 并
驱动电平型中断。
## 5. CRC32 数据通路
CRC 使用 IEEE 802.3 反射多项式 `0xedb8_8320`,初值为 `0xffff_ffff`,软件读取时执行
末尾异或。每个 66 位 C 元素按低 32 位、高 32 位、最高 2 位补零三个字依次进入
`crc32_word_next`。CRC 在计算结果有效时更新,与 CPU 或 DMA 是否读取 C 无关。
这一选择使快速评测可以关闭结果写回,只保留硬件计算与 CRC。CRC 顺序严格跟随输出
元素发射顺序;整批任务开始时由序列器清零,Bank 切换和单组完成不会清零。
## 6. AXI 协议处理
写通道分别处理 AW、W 和 B 阶段,锁存 ID、burst 类型和起始地址;INCR burst 每次有效
W 握手后地址增加 4。读通道锁存 AR 参数并连续产生 R beat,最后一拍置位 RLAST。
无效写地址置位 error,响应码当前始终为 OKAY。输出 C 的组合读选择在当前地址上解析
元素号和三字片段。
## 7. 验证要求
功能验证需要逐元素与 128 bit 或更宽的软件参考模型比较,覆盖全零、全 `0xffff_ffff`、
单位矩阵和随机矩阵。协议验证需覆盖 AW/W 分离、R/B 反压、单 beat 与 burst、两个 Bank
连续请求和非法地址。CRC 应独立比较完整 192 字节输出序列。当前官方板测只读取最终
CRC,证明了长批处理的端到端一致性,但不能替代逐元素和 AXI 边界测试。

View File

@@ -0,0 +1,73 @@
# 1024 点 FFT 加速器技术说明
## 1. 模块组成与数值格式
FFT 加速器由 `fft_controller`、五级 `SdfUnit` 流水、蝶形、延迟反馈存储、旋转因子 ROM
和复数乘法器构成。当前配置处理 1024 点复数序列,实部和虚部均为 16 位有符号定点数。
AXI 窗口按 32 位字编址,每个字的低 16 位承载一个输入或输出分量,读取时对 16 位结果
进行符号扩展。
FFT 的 AXI 控制器、输入输出 BRAM、SDF 数据通路和完成状态全部工作在
`sys_clk/sys_resetn`。DMA 访问 FFT 窗口时不跨域;CPU 请求在到达共享从端前已经通过
CPU--SYS AXI CDC。FFT 不使用 `mlkem_clk`,即使两者共享同一外部地址从端。
顶层 `FFT` 使用 Radix-2^2 单路径延迟反馈架构。五个 `SdfUnit` 的参数 M 依次为 1024、
256、64、16 和 4,每级完成两层 radix-2 蝶形并处理相应旋转因子。输入要求按自然顺序
连续提供,核心输出为位反转顺序;AXI 控制器在读输出 BRAM 时反转地址位,使软件观察到
自然顺序结果。
## 2. 地址窗口
FFT 位于共享物理基址 `0x1f40_0000` 的高半区。
| 偏移 | 内容 | 容量 |
|---|---|---|
| `0x8000` | 输入实部 | 1024 个 32 位字,低 16 位有效 |
| `0x9000` | 输入虚部 | 1024 个 32 位字,低 16 位有效 |
| `0xa000` | 输出实部 | 1024 个符号扩展的 32 位字 |
| `0xb000` | 输出虚部 | 1024 个符号扩展的 32 位字 |
| `0xc000` | CSR | bits 3:0 状态,bits 7:4 控制 |
CSR 控制 bit 4 为 start,状态 bit 0 为 busy,bit 1 为 done。写 start 同时清除旧 done;
计算完成后 done 保持,`fft_finish` 直接反映该状态。输入和输出窗口均支持 AXI INCR
burst,因此既可由 CPU 逐字访问,也可由 DMA 批量搬运。
## 3. 控制状态机
控制器包含 IDLE、LOAD、WAIT_OUT 和 DONE 四个状态。IDLE 检测 start;LOAD 在 1024 个
周期内顺序读取输入实部和虚部 BRAM,并根据 BRAM 读延迟产生对齐的 `di_en`;WAIT_OUT
接收 FFT 流水线输出并写入输出 BRAM;收到第 1024 个有效输出后进入 DONE,再返回 IDLE。
busy 在 LOAD 和 WAIT_OUT 期间有效。输入 BRAM 与输出 BRAM均采用独立读写端口,CPU 或
DMA 的窗口访问与计算侧顺序访问通过双端口结构隔离。软件不得在 busy 期间覆盖输入,
也不应在 done 前读取尚未完成的输出。
## 4. SDF 数据通路
每个 `SdfUnit` 含两级蝶形和两组延迟反馈缓存。计数器决定当前样本进入反馈存储还是参与
加减运算。第二级蝶形输出根据当前阶段选择 `1`、`-j` 或 ROM 旋转因子,并通过复数乘法
进入下一级。单路径结构每周期只传递一个复数样本,减少并行蝶形和存储端口数量。
`Butterfly` 对和、差各执行一次算术右移,相邻级使用不同的半舍入偏置以减小累计偏差。
五个 SDF 单元合计执行十次除 2,因此总缩放因子为 `1/1024`。软件参考结果同样除以
1024 后再与硬件比较。
复数乘法器计算四个有符号乘积并按 `WIDTH-1` 位右移恢复定点尺度。模块带有
`use_dsp="no"` 属性,所有乘法映射到 LUT/CARRY 资源。该约束满足竞赛资源要求,但会
增加 LUT 占用和组合路径压力。
## 5. 软件访问模式
CPU 路径逐字写入两个输入窗口、启动 FFT、轮询 done,再逐字读回两个输出窗口。DMA
路径使用两个 DMA 通道分别搬入实部和虚部,计算完成后再分别搬回输出。CPU 路径测量
包含大量寄存器访问,DMA 路径测量包含四次批量搬运和一次计算,二者均属于端到端时间,
不能直接解释为纯 FFT 核延迟。
## 6. 验证与数值误差
板级程序使用相同的 1024 点多音输入和浮点 radix-2 DIT 软件参考。全部 1024 个点逐点
比较,当前三次 CPU 路径和三次 DMA 路径的最大绝对误差均为实部 1、虚部 2,低于阈值
8。CPU 路径端到端时间为 1,724,940 ns,DMA 路径为 296,730 ns;三次运行结果一致。
这些结果证明当前测试向量上的定点误差和数据搬运正确性。进一步验证应增加冲激、单频、
满幅随机、接近溢出和复数输入,并检查连续 start、busy 期间非法写入以及 AXI 反压。

View File

@@ -0,0 +1,78 @@
# ML-KEM 总控与算法数据通路技术说明
## 1. 功能范围
`mlkem_top` 实现 FIPS 203 ML-KEM 的 KeyGen、Encaps 和 Decaps 主数据通路。安全等级由
运行时参数 `k_i` 选择:2、3、4 分别对应 ML-KEM-512、768、1024。模数固定为 3329,
多项式次数固定为 256,共享密钥长度为 32 字节。模块在 `start_i` 有效时锁存安全等级和
操作码,运行期间不再读取外部配置。
三个等级共享同一比特流。片上存储按最大等级静态分配,循环边界、槽位基址、密钥长度和
压缩参数由锁存的 K 动态计算。对应公钥长度为 800、1184、1568 字节,私钥长度为 1632、
2400、3168 字节,密文长度为 768、1088、1568 字节。
## 2. 顶层接口
配置端口包括 3 位安全等级、2 位操作码和单拍 start。KeyGen 输入 256 位随机种子 d 和 z;
Encaps 输入消息 m,并在启动前通过字节端口装载公钥;Decaps 在启动前通过字节端口装载
私钥和密文。`busy_o` 在非 IDLE 状态有效,`done_o` 在 ST_DONE 产生完成脉冲,`ss_o`
输出 256 位共享密钥。
公钥、私钥和密文不使用超宽并行端口,而是通过 8 位写接口和调试读回接口访问内部 BRAM。
系统集成层在该字节接口外提供 AXI 寄存器路径和 32 位批量窗口。
`mlkem_top` 及 Keccak、采样、NTT、多项式运算和局部 BRAM 全部工作在
`mlkem_clk/mlkem_resetn`。模块内部算子之间没有 CDC。来自 SYS 域的寄存器和批量窗口
事务在进入 `mlkem_axi_slave` 前已通过完整 AXI CDC;完成中断先同步回 SYS 域。
## 3. 集中式控制状态机
模块使用 5 位集中式状态机调度算子和存储端口。KeyGen 路径依次执行 G 哈希、SampleNTT
生成矩阵、CBD 生成 s/e、前向 NTT、矩阵向量点乘、密钥编码和公钥哈希。各阶段通过
系数 BRAM 和字节 BRAM 传递数据,不在阶段之间复制完整多项式总线。
Encaps 路径首先计算公钥哈希与 `G(m || H(ek))`,随后重新生成转置矩阵,解码公钥 t,
采样 y/e1/e2,对 y 执行 NTT,计算 u 和 v,最后按等级参数 `du/dv` 压缩并编码密文。
共享密钥为 G 输出的 K 部分。
Decaps 路径解码并解压密文,解码私钥 s,对 u 执行 NTT,恢复消息 m',再计算
`G(m' || H(ek))` 和 `J(z || c)`。D6 重加密不复制第二套加密硬件,而是把 m' 和 r'
送回 Encaps 状态序列生成参考密文 c'。最后状态逐字节比较 c' 与输入 c,并选择正常密钥
或隐式拒绝备用密钥。
比较循环不因首个不匹配字节提前退出,控制路径按完整密文长度运行。该行为是 RTL 的设计
属性;当前 regional 板级日志没有专门注入篡改密文,因此现有系统报告不把负向隐式拒绝
测试列为已验证结果。
## 4. 算子复用
Keccak-f[1600] 是面积最大的算子。SHA3/SHAKE 协议层、SampleNTT 和 CBD 在互斥状态中
共享一个 `keccak_core`,输入由状态选择器复用,输出广播给当前活动消费者。NTT、逆 NTT、
多项式基乘以及压缩/解压同样按状态复用,而不是为 KeyGen、Encaps 和 Decaps 分别复制。
该架构降低面积,但限制了状态间并行度。SampleNTT、CBD、NTT 和多项式乘法不能跨主状态
重叠,整体延迟由各阶段串行累加。技术报告应将其描述为面积与吞吐之间的明确权衡。
## 5. 存储组织
系数数据使用三个主要存储库。`bank_a` 为 12 bit x 4096,存放 A 矩阵及部分临时多项式;
`bank_se` 为 12 bit x 2048,存放 s/e、y、u 等向量;`bank_t` 为 12 bit x 1024,存放 t、
点乘累加、v 和 w。槽位以 256 个系数为单位,基址由 K、K^2 和当前算法阶段计算。
字节数据使用独立的 `ek_bram`、`dkp_bram`、`ct_bram` 和 `c_in_bram`。输入密文与重加密
产生的参考密文分开存储,使最终比较可以同周期读取两者。Decaps 私钥装载地址还会把
`dk_pke`、嵌入的公钥、H(ek) 和 z 分派到不同存储或寄存器。
## 6. 数值与资源约束
多项式系数采用 12 位模 q 表示。模乘通过流水化 Barrett 约简实现,相关乘法强制不使用
DSP。NTT 使用四路 Banked BRAM 和双蝶形流水,点乘使用独立偶/奇 Bank。当前实现中
ML-KEM 计算域目标频率为 76.923 MHz,最终时序结论以布局布线报告为准。
## 7. 验证边界
叶子算子应分别与软件或 Python 参考模型比较;顶层应按 FIPS 203 KAT 对公钥、私钥、
密文和共享密钥逐字节比较;系统级还需验证 CPU 寄存器路径和 DMA 窗口路径。当前板级
证据由 ML-KEM-512、768、1024 三个独立编译程序组成,每个程序对软件、CPU 和 DMA
路径各执行 100 次,现有日志的 FAILS 均为 0。该重复次数证明固定向量上的稳定性,不能
表述为 900 个不同随机 KAT。

View File

@@ -0,0 +1,74 @@
# ML-KEM AXI 前端与跨时钟域技术说明
## 1. 共享从端结构
`fft_mlkem_axi_slave` 将 Crossbar Slave 6 分成 FFT 和 ML-KEM 两个内部目标。写地址或读
地址的 bits 15:12 小于等于 3 时选择 ML-KEM;FFT 使用 0x8000--0xc000 窗口。ML-KEM
以外且未被 FFT 定义的地址仍会路由到 FFT 前端,但返回零或忽略写入,因此软件只应使用
文档化区间。
AXI 写地址和写数据通道彼此独立。共享前端在 AW 握手时锁存 `write_sel`,直到对应 B
响应完成才释放;读路径在 AR 握手时锁存 `read_sel`,直到带 RLAST 的最后一个 R beat
完成才释放。响应选择不使用实时地址,避免 burst 期间地址变化导致响应串到另一个内部
从端。
FFT 控制器直接工作在 `sys_clk`。ML-KEM 的完整 AXI 五通道通过 `Axi_CDC` 跨入
`mlkem_clk`,之后由 `mlkem_axi_slave` 和 `mlkem_top` 在同一计算时钟域处理。ML-KEM
中断从计算域返回系统域时经过两级同步寄存器。
XDC 将 SYS 与 ML-KEM 声明为异步时钟组,因此跨域有效性由 `Axi_CDC` 的双时钟 FIFO
保证,而不是由 PLL 同源关系或普通时序路径保证。具体约束和复位关系见
[时钟域、复位与跨时钟域设计说明](00_clock_domains.md)。
## 2. ML-KEM 寄存器接口
ML-KEM 物理基址为 `0x1f40_0000`,CPU 未缓存映射为 `0xbf40_0000`。
| 偏移 | 名称 | 说明 |
|---|---|---|
| `0x000` | CTRL | bit 0 启动,bit 1 软复位 |
| `0x004` | STATUS | bit 0 busy,bit 1 done,bit 2 preload busy;done 为 W1C |
| `0x008` | CONFIG | bits 2:0 为 K,bits 5:4 为操作码 |
| `0x010--0x02c` | D | 32 字节 KeyGen 随机种子 |
| `0x030--0x04c` | Z | 32 字节隐式拒绝种子 |
| `0x050--0x06c` | MSG | 32 字节 Encaps 消息 |
| `0x070--0x08c` | SS | 32 字节共享密钥,只读 |
| `0x100/104/108` | PRE_SEL/ADR/DAT | 逐字节预装载接口 |
| `0x10c/110/114` | RDB_SEL/ADR/DAT | 逐字节读回接口 |
| `0x1000` | EK window | 公钥批量输入或输出窗口 |
| `0x2000` | DK window | 私钥批量输入或输出窗口 |
| `0x3000` | CT window | 密文批量输入或输出窗口 |
CONFIG 的操作码 0、1、2 分别表示 KeyGen、Encaps、Decaps。软件必须在启动前完成参数与
输入装载,并在 busy 期间保持配置不变。done 保持到软件 W1C,便于轮询程序不丢失短脉冲。
## 3. 字节端口与批量窗口
传统 PRE 接口通过 PRE_SEL 选择 ek、dk 或 c,通过 PRE_ADR 设置字节地址,向 PRE_DAT
写入低 8 位并自动递增地址。读回接口以同样方式选择 ek、完整 dk 或 ct。该路径便于调试,
但每个字节至少需要一次 AXI 寄存器事务,传输大密钥时开销较高。
三个批量窗口把 AXI 32 位 beat 分解为最多四个有效字节。写状态机依据 WSTRB 跳过无效
lane,将字节地址、选择和数据送入核心 BRAM 写口,并等待内部确认后继续下一个 lane。
读状态机按字节地址读取内部 BRAM,补偿同步读延迟后组装 32 位 RDATA。窗口支持 INCR
burst,使通用 DMA 能以少量控制事务搬运完整公钥、私钥和密文。
批量窗口不改变密码核心的算法执行时间,但显著减少 CPU 逐字节访问开销。性能报告应把
CPU 寄存器路径和 DMA 窗口路径分别列出,不能把两者差值解释为核心计算加速。
## 4. 事件控制与复位
CTRL start、软复位和 done clear 在 `mlkem_axi_slave` 中均转换为 toggle 事件,再通过
边沿检测产生单拍控制。软复位事件经计数器展宽,形成核心局部复位。预装载写入使用
request/ack toggle,使 AXI 写 beat 只有在目标字节被核心侧接收后才完成。
外层 `Axi_CDC` 已承担 SYS--ML-KEM 的 AXI 通道跨域;前端内部的 toggle 机制主要用于
把寄存器写动作转换为不会重复触发的单拍事件,并串行化字节预装载。系统复位有效期间,
所有 AXI valid、start 和预装载事件必须保持无效。
## 5. 协议验证重点
共享前端需要覆盖 AW 与 W 不同拍到达、B/R 反压、ML-KEM 与 FFT 交替访问、长 burst
末拍、WSTRB 空洞以及读写并发。ML-KEM 窗口还需验证 800--3168 字节的非统一长度、最后
一个不满字、BRAM 读延迟和软复位中止。当前板级 CPU 与 DMA 双路径证明了常用顺序访问,
但不等价于覆盖所有并发和异常协议组合。

View File

@@ -0,0 +1,62 @@
# ML-KEM Keccak、SHA3 与采样模块技术说明
## 1. Keccak-f[1600] 置换核
`keccak_core` 保存 1600 位状态,并调用组合 `keccak_round` 每周期执行一轮
Keccak-f[1600]。轮函数包含 theta、rho、pi、chi 和 iota 五个步骤,轮常数由 5 位轮计数
选择。默认执行 24 轮,输入在 `valid_i && ready_o` 时装载,最后一轮结果通过
`valid_o/ready_i` 交付;接收端反压时保持最终状态。
该结构只实例化一份 1600 位轮函数,单次置换约需 24 个计算周期,面积主要来自宽 XOR、
移位布线和 chi 非线性逻辑。它不是 24 轮完全展开的单周期实现,也不是每周期接收一个
新状态的深流水实现。
本文件中的 Keccak、SHA3/SHAKE、SampleNTT 和 CBD 均位于 `mlkem_clk` 域。共享接口是
同一时钟域内的 valid/ready 复用,不是 CDC。SYS--ML-KEM 跨域终止于外层 AXI 前端。
## 2. SHA3/SHAKE 协议层
`sha3_top_shared` 在置换核外实现吸收、填充、多块状态累积和输出提取。单块模式支持
KeyGen 使用的 G、SHA3-256 H、SHAKE-256 J,以及对完整 64 字节消息执行的 SHA3-512 G。
模块依据模式选择 576 位或 1088 位 rate,并加入 SHA3 或 SHAKE 域分隔后执行 pad10*1。
多块模式面向长度随安全等级变化的公钥哈希。调用方预先构造 1088 位 rate block,并用
`mb_last_i` 标记最终块。模块将新块异或到累计 sponge 状态,调用共享 Keccak,最后从
低 256 位提取摘要。多块状态在一次消息结束前保持,不会在块间重新初始化。
ML-KEM 顶层以状态机选择当前 Keccak 消费者。SHA3、SampleNTT 和 CBD 在算法调度上互斥,
因此可以共享一个置换核;若未来引入跨状态并行,必须增加显式仲裁和每个消费者独立的
sponge 上下文,不能继续依赖状态互斥假设。
## 3. SampleNTT 拒绝采样
`sample_ntt_sync_shared` 实现 FIPS 203 SampleNTT。模块吸收 32 字节 rho 以及行列索引
`j,i`,形成 34 字节 SHAKE-128 输入。挤出字节流按每 3 字节拆成两个 12 位候选值,只有
候选值小于 q=3329 时才输出。模块持续采样直到产生 256 个有效系数。
输出使用 `coeff_valid_o/coeff_ready_i` 握手,反压时保持当前系数和索引。拒绝采样的运行
周期依赖候选值分布,因此系统 FSM 依据有效系数计数结束,而不是使用固定延迟。对固定
rho 和索引,输出必须与软件 SampleNTT 逐系数一致。
## 4. 中心二项分布采样
`sample_cbd_sync_shared` 使用 SHAKE-256 PRF 生成伪随机字节,再实现 CBD_eta。eta=2 时,
每个系数消耗 4 bit,计算两组 2 bit 的汉明重量差;eta=3 时,每个系数消耗 6 bit,计算
两组 3 bit 的汉明重量差。ML-KEM-512 的 eta1 为 3,其余等级的 eta1 为 2,eta2 始终为 2。
CBD 输出转换到模 q 表示后,以 valid/ready 逐系数写入系数 Bank。当前优化版本对 CBD
输出到 Bank 写入路径增加寄存,以缩短组合路径;地址和有效信号必须与该流水级同步延迟。
## 5. 共享接口约束
三个消费者向共享 Keccak 提供状态、valid 和 ready。选择信号由 ML-KEM 主状态直接推导,
未选中的消费者不能认为广播输出属于自己。消费者内部必须只在活动上下文采样
`kc_valid_o`。复位需要同时清除 Keccak busy、各 sponge 状态、候选字节缓存和输出计数,
否则下一次请求可能继承前一消息状态。
## 6. 验证方法
Keccak 应使用标准空消息和多块测试向量逐 bit 比较。SHA3/SHAKE 层应覆盖 rate 边界前后
的消息长度、域分隔和多块最后一块填充。SampleNTT 应比较全部 256 个系数并统计拒绝
候选数;CBD 应覆盖 eta=2/3、输出反压和连续请求。顶层 KAT 通过能够发现大部分功能错误,
但叶子级握手、边界填充和共享仲裁仍需要独立测试平台验证。

View File

@@ -0,0 +1,72 @@
# ML-KEM 多项式运算模块技术说明
## 1. 运算域与数据表示
多项式运算位于环 `Z_q[x]/(x^256+1)`,其中 q=3329。系数在硬件中使用 12 位无符号模 q
表示。该组模块包括前向/逆向 NTT、Barrett 模乘、NTT 域 basecase 乘法、多项式加减以及
Compress/Decompress。算子使用 valid/ready 或 start/done 接口,由 `mlkem_top` 分时复用。
本文件中的 NTT、模乘、basecase、多项式加减、压缩模块及其局部 BRAM 均工作在
`mlkem_clk/mlkem_resetn`。算子与 `mlkem_top` 之间是单时钟域同步接口,不包含独立 CDC。
地址、valid 和数据的延迟对齐属于流水线时序问题,而不是跨时钟域问题。
## 2. NTT 核
`ntt_core` 实现 256 点前向和逆向 NTT。系数存储由 `coeff_bram_4way` 划分为四个 Bank,
每个 Bank 具有同步读和写端口。地址生成器把同周期的两个蝶形对映射到互不冲突的 Bank,
从而同时处理四个系数。
数据通路包含两个 `butterfly_unit_pipe`。第 t 周期发出 BRAM 地址,下一周期取得系数,
随后进入流水化蝶形和 Barrett 模乘;写地址通过同长度延迟链与结果对齐。每层发射结束后
等待流水排空,再更新层号和旋转因子索引。逆 NTT 在七层变换后复用模乘流水线执行末尾
缩放。
`zeta_rom` 保存 128 个 12 位旋转因子。前向和逆向变换使用不同的索引方向及蝶形公式。
验证不能只比较 NTT 后的频域值,还应执行 INTT(NTT(a)) 并检查恢复系数,覆盖 Bank 地址
冲突和最后一层流水排空。
## 3. Barrett 模约简与蝶形
`barrett_mul_pipe` 先计算 12x12 位乘积,再用常数 5039 估计除以 q 的商,计算
`r = p - q_est*q`,最后通过条件减 q 把结果限制到 `[0,q)`。各乘法级之间加入寄存器,
并以 `use_dsp="no"` 约束映射到 LUT。蝶形单元在模乘前后执行模加或模减,并将 valid
沿流水线传递。
商估计只在限定输入范围内成立,因此上游必须保证输入系数已经规范化。叶子测试应覆盖
0、q-1、乘积最大值和所有修正分支,不能仅使用随机中间值。
## 4. NTT 域多项式乘法
`poly_mul_sync` 对 256 个频域系数按相邻偶/奇系数组成 128 个 basecase。每个 basecase
结合对应 zeta 计算两个输出系数。输入多项式写入独立 Bank,控制器按 LOAD、RUN 和
OUTPUT 阶段管理装载、流水计算和结果输出。
`basecase_mul_pipe` 并行计算多个模乘项,再完成模加。当前版本将系数存储改为偶/奇
Banked BRAM,减少离散寄存器和 LUTRAM。受同步 BRAM 读延迟和发射控制影响,RUN 阶段
每两周期发射一个 basecase。输出采用 valid/ready,接收端反压时不得覆盖尚未消费的系数。
`poly_arith_sync` 提供系数级模加和模减,用于点乘累加、噪声相加以及解封装中的差值。
运算结果在每一步规范化到模 q 范围,避免后续模乘输入超界。
## 5. 压缩与解压缩
`comp_decomp_sync` 实现 FIPS 203 的 Compress_d 和 Decompress_d。压缩近似计算
`round(2^d*x/q) mod 2^d`,解压计算 `round(q*y/2^d)`。当前流水线使用常数乘法和移位
近似除法,避免综合组合除法器;模式、d 和 valid 随数据经过各级寄存。
输出端具有保持寄存器。当下游未 ready 时,结果和 valid 保持;输入 ready 由流水线及
输出可用性共同决定,因此文档和测试不应假设任意反压下始终每周期接收一个系数。需要
分别覆盖 d=1、4、5、10、11 等算法实际参数,并与精确整数公式逐值比较。
## 6. 存储和调度约束
NTT 核和多项式乘法器各自包含局部 BRAM,ML-KEM 顶层还包含全局系数 Bank。进入算子前
需要将目标多项式装入局部存储,完成后再流式写回全局 Bank。这种结构简化端口仲裁,但
增加装载和回写周期。主 FSM 保证同一全局 Bank 端口在一个状态内只有一个所有者。
## 7. 验证边界
叶子级验证应覆盖 NTT、INTT、basecase、完整多项式乘法、模加减和压缩解压,并对所有
256 个系数比较。顶层 KAT 能验证算子组合后的算法结果,但当多个误差互相抵消时不能定位
根因。实现后还需检查 BRAM 推断、DSP=0 和 valid/地址延迟对齐;这些属于结构验证,不能
仅由软件结果正确推出。

View File

@@ -0,0 +1,74 @@
# 软件运行时与测试程序技术说明
## 1. 软件职责
软件位于 `sdk/software/examples/`,负责构造输入、配置物理地址和寄存器、启动硬件、等待
完成、读取结果并与参考值比较。算法的高开销数据通路由硬件完成;软件保留参考实现和
诊断输出,用于区分计算错误、数据搬运错误和接口错误。
CPU 访问外设时使用 `0xbfxx_xxxx` 未缓存映射,DMA 描述符使用 `0x1xxx_xxxx` 物理地址。
软件缓冲区通过未缓存别名读写,避免数据缓存中的旧副本与 DMA 结果不一致。该地址转换是
驱动正确性的一部分,而不是性能优化细节。
软件指令在 `cpu_clk` 域执行,外设寄存器和 DMA 数据面主要位于 `sys_clk` 域,ML-KEM
核心位于 `mlkem_clk` 域。软件不直接处理相位关系,而是通过 AXI valid/ready、状态保持
和 W1C 完成语义与异步硬件交互。CPU 周期计数包含跨域 FIFO 和外设响应延迟。
## 2. DMA 驱动
`dma.c/dma.h` 将通道寄存器映射为 C 结构体。驱动先检查 busy,再写源地址、目的地址、
字节数和 tag,配置 32 位 beat 与 burst 长度后置位 start。`dma_wait_polling` 轮询 done,
完成后通过 W1C 清除状态。
FFT 驱动使用 AxLEN=15,即 16 beat burst;矩阵快速路径使用 AxLEN=63,即 64 beat 配置。
实际末 burst 长度由硬件按剩余字节裁剪。当前驱动遇到通道 busy 时直接返回,没有错误码;
轮询也没有软件超时。因此调用方必须保证通道所有权,正式运行时应增加返回值和超时处理。
## 3. 矩阵乘法评测程序
`asm/user-sample.c` 面向官方 5000 组评测。程序配置矩阵批处理序列器的源地址、目的地址、
组数和 stride,发送 `MATMUL_START`,启动硬件并轮询序列器 done。完成后读取矩阵加速器
CRC32,并以紧凑 UART 写入输出 CRC 和 `MATMUL_DONE`。
快速启动配置使用 `start_matmul_fast.S` 缩短通用 C 运行时初始化。UART 输出避免 `printf`
格式化开销,并按 FIFO 可用状态分段写入。设置 `MATMUL_WRITEBACK_RESULTS=0` 时,序列器
跳过 5000 组结果写回,但矩阵核心仍对全部 66 位结果更新 CRC。
官方计时从接收到 START 到接收到 DONE,因此软件启动顺序、串口发送和完成尾部均会进入
端到端时间。当前 regional 证据包含三次运行,中位数为 6.944404 ms,CRC 均匹配。该数据
不包含 `test_1` 中的后续优化。
## 4. FFT 测试程序
`fft/main.c` 通过 CPU 逐字写入 1024 个实部和虚部,启动 FFT,读回全部输出,再执行浮点
radix-2 DIT 软件参考。`fft_dma/main.c` 使用两个 DMA 通道搬入输入,计算完成后搬回输出。
两者都对 1024 个 bin 计算最大实部和虚部绝对误差,并以阈值 8 判定。
软件参考结果除以 1024,与硬件每级缩放后的输出尺度一致。当前 CPU 和 DMA 路径各有三份
板级日志,结果完全一致。硬件时间为端到端测量,CPU 路径包含 4096 次窗口读写,DMA
路径包含四次搬运,因此两者反映接口方案而非单独的 FFT 流水线周期。
## 5. ML-KEM 测试程序
`mlkem_test/main.c` 为每个安全等级分别构建和运行。当前源码通过 `LEVELS` 数组选择本次
编译的 K,区域赛证据中的 512、768、1024 来自三个独立程序,不是一个程序内并行执行。
每个程序使用固定 KAT count 0 输入,分别运行软件参考、CPU 寄存器路径和 DMA 窗口路径。
CPU 路径通过 PRE/RDB 接口逐字节装载和读取密钥、密文;DMA 路径通过 EK、DK、CT
窗口批量搬运。两条硬件路径均执行 KeyGen、Encaps 和 Decaps,并检查封装/解封共享密钥
一致性以及固定黄金值。每条路径重复 100 次,记录失败次数和平均 CPU 周期。
现有测试的重复输入用于稳定性和性能统计,不代表不同随机 KAT。程序未篡改密文触发负向
隐式拒绝,因此报告只能说明正常输入路径通过,不能把 RTL 中存在的拒绝逻辑表述为已完成
板级负向测试。
## 6. 构建与证据输出
报告工作流只编译 `asm`、`fft`、`fft_dma`、`mlkem_test` 和 `mlkem_hello`。FFT 与
ML-KEM 的通用 SoC 软件仿真耗时较长,当前功能数据采用板级 UART 日志。日志使用固定
机器可读字段,例如 `FFT_RESULT`、`MLKEM*_FAILS`、平均周期和完成标志,指标脚本从这些
字段聚合报告数据。
软件测试的通过条件包括算法结果、DMA 完成和输出标记,不能只依据程序返回。后续改动
寄存器布局、缓存属性、时钟频率或 UART 输出顺序时,必须同步更新驱动、测试判定和指标
解析脚本。

View File

@@ -0,0 +1,48 @@
# 自研模块技术说明索引
本目录记录区域赛仓库中由项目组设计、修改或完成系统级集成的模块。技术说明以当前
`main` 分支 RTL 和软件源码为依据,服务于系统设计报告的后续重写。文档中的“已实现”
表示源码中存在相应数据通路或控制逻辑;“已验证”仅指当前 `evidence/` 中能够直接支持
的结论,两者不混用。
OpenLA500 处理器、UART、DVI、基础 SRAM 控制器以及赛事提供的 SoC 框架不作为自研 IP
列入。项目组对这些模块的地址连接、时钟连接和中断集成记录在 SoC 集成说明中,但不把
其内部实现归入项目贡献。
| 文档 | 主要 RTL 或软件 | 技术边界 |
|---|---|---|
| [时钟域、复位与 CDC](00_clock_domains.md) | `clk_pll`、`rst_sync`、`Axi_CDC`、`soc.xdc` | 三时钟域归属、复位链、跨域协议和约束模型 |
| [SoC 集成与时钟复位](01_soc_integration.md) | `rtl/soc_top.v`、`rst_sync.v` | 地址空间、主从互连、时钟域、复位和中断集成 |
| [通用 DMA 子系统](02_dma_subsystem.md) | `rtl/ip/cdma/snix_*.sv` | 四通道 DMA、AXI 搬运、本地 endpoint 和仲裁 |
| [矩阵批处理序列器](03_matmul_batch_sequencer.md) | `cdma_matmul_bridge.sv` | 5000 组任务调度、双 Bank 流水和可选结果写回 |
| [矩阵乘法加速器](04_matmul_accelerator.md) | `matmul_axi_slave.v` | 4x4 无符号矩阵乘法、AXI/endpoint、CRC32 |
| [FFT 加速器](05_fft_accelerator.md) | `rtl/ip/fft/*.v` | 1024 点定点 FFT、SDF 数据通路和 AXI 存储窗口 |
| [ML-KEM 总控与算法数据通路](06_mlkem_core.md) | `mlkem_top.v` | 三等级、三操作、集中式 FSM 和片上存储组织 |
| [ML-KEM AXI 前端与 CDC](07_mlkem_axi_frontend.md) | `fft_mlkem_axi_slave.v`、`mlkem_axi_slave.v` | 共享地址窗口、批量数据窗口和跨时钟域握手 |
| [Keccak 与采样模块](08_mlkem_hash_sampling.md) | `sha3/`、`sample_ntt/`、`sample_cbd/` | SHA3/SHAKE、拒绝采样和 CBD 采样 |
| [多项式运算模块](09_mlkem_polynomial_arithmetic.md) | `ntt/`、`poly_mul/`、`comp_decomp/` | NTT、基乘、模约简、压缩与解压缩 |
| [软件运行时与测试程序](10_software_runtime.md) | `sdk/software/examples/{asm,fft,fft_dma,mlkem_test}` | 寄存器驱动、DMA 调度、参考模型和结果判定 |
文档中的地址均为物理地址,除非明确写为 CPU 未缓存虚拟地址。AXI 信号名沿用 RTL,
寄存器偏移以字节为单位。频率和资源数据属于当前 regional 仓库,不包含 `test_1` 中的
后续矩阵乘法优化。
## RTL 模块覆盖说明
当前 SoC 有效层次中的计算和搬运模块均已纳入上述文档。DMA 说明覆盖
`snix_axil_cdma_mux`、`snix_axi_mm2mm`、`snix_axis_fifo` 和 `snix_sync_fifo`;矩阵说明
覆盖 `matmul_axi_slave`、`pipelined_mult_32x32` 和 `cdma_matmul_bridge`;FFT 说明覆盖
`fft_controller`、`FFT`、`SdfUnit`、`Butterfly`、`Multiply`、`DelayBuffer` 和 `Twiddle`。
ML-KEM 说明覆盖当前集成层次中的 `fft_mlkem_axi_slave`、`mlkem_axi_slave`、
`mlkem_top`、`keccak_core`、`keccak_round`、`sha3_top_shared`、
`sample_ntt_sync_shared`、`sample_cbd_sync_shared`、`ntt_core`、`coeff_bram_4way`、
`butterfly_unit_pipe`、`barrett_mul_pipe`、`poly_mul_sync`、`basecase_mul_pipe`、
`poly_arith_sync`、`comp_decomp_sync`、`zeta_rom`、`poly_mul_zeta_rom`、`pipeline_reg`、
`skid_buffer`、`sd_bram` 和 `s_bram`。
仓库还保留 `snix_axi_cdma`、`snix_axi_cdma_csr`、`snix_async_fifo`、
`snix_register_slice`,以及非共享版 `sha3_top`、`sample_ntt_sync`、`sample_cbd_sync`、
旧版 `ntt_sync`、`butterfly_unit`、`barrett_mul` 和 `basecase_mul`。这些文件用于早期方案、
叶子测试或兼容参考,当前 `soc_top`/`mlkem_top` 未实例化,因而不作为独立系统模块另写
性能结论。若后续重新接入,应先更新本索引及对应技术说明。

View File

@@ -0,0 +1,54 @@
% Generated values may be refreshed with: make metrics
% Evidence status is intentionally explicit so stale data is not presented as current.
\newcommand{\EvidenceRevision}{d456463(当前 evidence)}
\newcommand{\EvidenceDate}{2026-07-15}
\newcommand{\CpuFreqMHz}{33.333}
\newcommand{\SysFreqMHz}{50.000}
\newcommand{\MlkemFreqMHz}{76.923}
\newcommand{\OverallWNS}{0.070}
\newcommand{\CpuWNS}{0.737}
\newcommand{\SysWNS}{0.125}
\newcommand{\MlkemWNS}{0.070}
\newcommand{\SliceLUTs}{55,066}
\newcommand{\SliceLUTPct}{41.16\%}
\newcommand{\SliceFFs}{31,000}
\newcommand{\SliceFFPct}{11.58\%}
\newcommand{\BramTiles}{29.5}
\newcommand{\BramPct}{8.08\%}
\newcommand{\DspCount}{0}
\newcommand{\TotalPower}{0.779}
\newcommand{\DynamicPower}{0.637}
\newcommand{\StaticPower}{0.142}
\newcommand{\PowerConfidence}{Low(未回标活动率)}
\newcommand{\MlkemFiveTwelveSW}{2,592,854}
\newcommand{\MlkemFiveTwelveCPU}{198,778}
\newcommand{\MlkemFiveTwelveDMA}{52,995}
\newcommand{\MlkemSevenSixtyEightSW}{4,064,254}
\newcommand{\MlkemSevenSixtyEightCPU}{293,717}
\newcommand{\MlkemSevenSixtyEightDMA}{80,643}
\newcommand{\MlkemTenTwentyFourSW}{6,036,553}
\newcommand{\MlkemTenTwentyFourCPU}{401,177}
\newcommand{\MlkemTenTwentyFourDMA}{113,261}
\newcommand{\FftCpuNs}{1,724,940}
\newcommand{\FftDmaNs}{296,730}
\newcommand{\FftSoftwareNs}{245,632,500}
\newcommand{\FftCpuSpeedup}{142.53}
\newcommand{\FftDmaSpeedup}{827.80}
\newcommand{\FftMaxError}{Re=1,Im=2}
\newcommand{\MatmulGroups}{5,000}
\newcommand{\MatmulRuns}{3}
\newcommand{\MatmulBoardMinMs}{6.936468}
\newcommand{\MatmulBoardMs}{6.944404}
\newcommand{\MatmulBoardMaxMs}{6.950307}
\newcommand{\MatmulScore}{96.54}
\newcommand{\MatmulCrcStatus}{PASS}
\newcommand{\MatmulFinalMs}{4.911765}
\newcommand{\MatmulFinalScore}{100.00}
\newcommand{\MatmulFinalSeed}{\texttt{0xa3772ec8}}
\newcommand{\MatmulFinalCRC}{\texttt{0x0417d761}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

View File

@@ -0,0 +1,774 @@
% =============================================================================
% CICIEC 2026 Loongson Regional — System Design Report
% 基于龙芯SoC的后量子密码与矩阵运算加速系统设计报告
% =============================================================================
\documentclass[11pt,a4paper,twoside]{article}
% ---- Packages ----
\usepackage[UTF8,heading=true]{ctex}
\usepackage[top=2.5cm,bottom=2.5cm,left=2.8cm,right=2.8cm]{geometry}
\usepackage{fancyhdr}
\usepackage{graphicx}
\usepackage{booktabs}
\usepackage{amsmath,amssymb}
\usepackage{hyperref}
\usepackage{caption}
\usepackage{enumitem}
\usepackage{float}
\usepackage{longtable}
\usepackage{multirow}
\usepackage{array}
\usepackage{xcolor}
\usepackage[normalem]{ulem}
% ---- Page style ----
\setlength{\headheight}{14pt}
\pagestyle{fancy}
\fancyhead[LO,RE]{系统设计报告}
\fancyhead[RO,LE]{\thepage}
\fancyhead[CO,CE]{}
\fancyfoot[C]{\thepage}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0pt}
% ---- Spacing ----
\setlength{\parskip}{4pt plus 2pt minus 1pt}
\setlength{\parindent}{2em}
\setlength{\intextsep}{6pt plus 2pt}
\setlength{\textfloatsep}{8pt plus 2pt}
\captionsetup{skip=4pt}
% ---- Hyperlinks ----
\hypersetup{
colorlinks=true,
linkcolor=black,
citecolor=black,
urlcolor=blue
}
% ---- Import auto-generated metrics ----
% Generated by tools/run_report_tests.sh refresh — do not edit manually
\input{report_metrics}
% ---- Custom commands ----
\newcommand{\Zq}{\mathbb{Z}_q}
\newcommand{\etal}{\textit{et al.}}
\newcommand{\tabincell}[2]{\begin{tabular}{@{}#1@{}}#2\end{tabular}}
\begin{document}
% ===========================================================================
% TITLE PAGE
% ===========================================================================
\begin{titlepage}
\thispagestyle{empty}
\begin{center}
\vspace*{30pt}
\includegraphics[width=0.45\textwidth]{logo_cicc.png}
\vspace{36pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 第十届}
\vspace{4pt}
{\fontsize{22pt}{28pt}\selectfont\bfseries 全国大学生集成电路创新创业大赛}
\end{center}
\vspace{80pt}
\begin{flushleft}
\fontsize{14pt}{22pt}\selectfont
报告类型:\uline{\hfill 系统设计报告\hfill} \\[18pt]
参赛杯赛:\uline{\hfill 龙芯中科杯\hfill} \\[18pt]
作品名称:\uline{\hfill 基于LoongArch SoC 的后量子密码与矩阵运算加速系统\hfill} \\[18pt]
队伍编号:\uline{\hfill CICC1008439\hfill} \\[18pt]
团队名称:\uline{\hfill 碳基生物\hfill}
\end{flushleft}
\end{titlepage}
% ===========================================================================
% TABLE OF CONTENTS
% ===========================================================================
\tableofcontents
\newpage
% ===========================================================================
% CORE HIGHLIGHTS PREVIEW
% ===========================================================================
\section*{作品核心亮点预览}
\addcontentsline{toc}{section}{作品核心亮点预览}
\begin{center}
{\large\heiti 基于OpenLA500的多加速器异构SoC与全参数ML-KEM硬件实现}
\end{center}
\noindent
\colorbox{blue!7}{%
\parbox{\dimexpr\textwidth-2\fboxsep\relax}{%
本作品面向龙芯中科杯矩阵运算与后量子密码任务,在赛事基础SoC之上完成DMA、矩阵乘法、FFT、ML-KEM、跨时钟域互连和批量调度等硬件扩展,并对外部SRAM控制器进行连续突发优化。系统以CPU负责配置与验证、硬件负责搬运与计算为基本分工,实现从算法IP到板级应用的完整数据通路。
}%
}
\begin{center}
\includegraphics[width=0.70\textwidth]{system_arch.png}
{\small 系统总体架构:CPU控制面、DMA数据面与三个计算加速器通过AXI互连协同工作}
\end{center}
\noindent
\begin{minipage}[t]{0.48\textwidth}
{\color{blue!70!black}\heiti 硬件自主的数据搬运与调度}
\small 四通道DMA支持内存到内存、内存到端点和端点到内存传输。矩阵批量序列器将CPU的一次启动扩展为5000组任务的硬件自主执行,双Bank机制重叠ExtRAM加载与乘加计算。
\end{minipage}
\hfill
\begin{minipage}[t]{0.48\textwidth}
{\color{blue!70!black}\heiti Matmul批量流水与在线校验}
\small 4个无符号乘法器配合两级加法树产生66位结果,稳态每周期发射一个矩阵元素。CRC结果FIFO解耦乘加与递归CRC32,快速通道跳过结果写回并在CRC完全排空后置位完成标志。
\end{minipage}
\vspace{0.6em}
\noindent
\begin{minipage}[t]{0.48\textwidth}
{\color{blue!70!black}\heiti 单比特流全参数ML-KEM}
\small 单一硬件实例运行时支持ML-KEM-512、768和1024,以及KeyGen、Encaps和Decaps三种操作。Keccak核跨哈希与采样阶段复用,Decaps重加密复用Encaps数据通路,并实现常量时间隐式拒绝。
\end{minipage}
\hfill
\begin{minipage}[t]{0.48\textwidth}
{\color{blue!70!black}\heiti 存储与多时钟域协同优化}
\small SRAM控制器通过读地址预驱动、读数据寄存和连续写握手,将突发内部吞吐提高至每周期一个32位数据拍。CPU、系统与ML-KEM三个异步时钟域通过全五通道AXI双时钟FIFO安全连接。
\end{minipage}
\vfill
\noindent
\colorbox{gray!12}{%
\parbox{\dimexpr\textwidth-2\fboxsep\relax}{%
\small\textbf{自主设计边界:}OpenLA500处理器、板级SRAM器件及基础外设来自赛事平台;DMA扩展、矩阵乘法与批量序列器、FFT、ML-KEM、跨时钟域桥接以及SRAM控制器的突发流水化改造由本项目完成。
}%
}
\newpage
\section*{关键指标与验证结论}
\begin{center}
\setlength{\tabcolsep}{4pt}
\renewcommand{\arraystretch}{1.25}
\begin{tabular}{>{\centering\arraybackslash}p{0.23\textwidth}>{\centering\arraybackslash}p{0.23\textwidth}>{\centering\arraybackslash}p{0.23\textwidth}>{\centering\arraybackslash}p{0.23\textwidth}}
{\Large\heiti \MatmulFinalMs{} ms} &
{\Large\heiti \FftDmaSpeedup{}$\times$} &
{\Large\heiti 48.95--53.33$\times$} &
{\Large\heiti 0 DSP} \\
Matmul 5000组最终时间 &
FFT DMA相对软件加速 &
ML-KEM DMA相对软件加速 &
全系统DSP使用量 \\
\end{tabular}
\end{center}
\vspace{0.5em}
\noindent{\large\heiti 核心性能结果}
\begin{center}
\small
\setlength{\tabcolsep}{5pt}
\renewcommand{\arraystretch}{1.28}
\begin{tabular}{p{2.4cm}p{7.0cm}p{4.7cm}}
\toprule
项目 & 实测结果 & 结论 \\
\midrule
矩阵乘法 & 最终评测完成5000组计算;运行时间\MatmulFinalMs{} ms & CRC32匹配,得分\MatmulFinalScore{} \\
FFT & DMA模式延迟\FftDmaNs{} ns;实部/虚部最大误差为1/2 & 相对软件加速\FftDmaSpeedup{}$\times$ \\
ML-KEM & 三等级完整往返为52,995/80,643/113,261个CPU周期 & DMA相对软件加速48.95--53.33$\times$ \\
SRAM接口 & 50 MHz、32位,连续突发每周期一个数据拍 & 理论单向带宽200 MB/s \\
\bottomrule
\end{tabular}
\end{center}
\noindent{\large\heiti FPGA实现质量}
\begin{center}
\small
\setlength{\tabcolsep}{5pt}
\renewcommand{\arraystretch}{1.25}
\begin{tabular}{p{3.0cm}p{5.3cm}p{5.8cm}}
\toprule
维度 & 结果 & 工程含义 \\
\midrule
资源 & 55,066 LUT,31,000 FF,29.5 BRAM Tile,0 DSP & LUT 41.16\%,BRAM 8.08\%,保留进一步扩展空间 \\
时钟与时序 & 33.333/50.000/76.923 MHz;88,843个端点零违例 & CPU、系统总线和ML-KEM算法域独立收敛 \\
标准验证 & 9000个主路径KAT与300个隐式拒绝向量通过 & 覆盖三等级、三操作及Decaps拒绝路径 \\
板级验证 & ML-KEM 900次运行零失败;FFT 6次通过;Matmul最终评测满分 & 验证CPU、DMA、CDC、SRAM和加速器端到端协同 \\
\bottomrule
\end{tabular}
\end{center}
\vfill
\noindent
\colorbox{green!8}{%
\parbox{\dimexpr\textwidth-2\fboxsep\relax}{%
\textbf{总体结论:}系统在xc7a200tfbg676-1 FPGA上完成布局布线,以零DSP实现矩阵运算、FFT和全参数ML-KEM硬件加速;功能正确性、跨时钟域可靠性和板级端到端性能均得到验证。
}%
}
\vspace{0.6em}
\begin{flushright}
\small 数据基线:\EvidenceRevision{},\EvidenceDate{}
\end{flushright}
\newpage
% ===========================================================================
% 1. INTRODUCTION
% ===========================================================================
\section{绪论}
\subsection{设计背景与目标}
随着量子计算技术的快速发展,传统公钥密码体系面临严峻挑战。美国国家标准与技术研究院于2024年正式发布的FIPS 203标准确立了ML-KEM作为后量子密钥封装机制的地位,标志着后量子密码从学术研究向工业应用的转折点。与此同时,矩阵乘法作为科学计算、信号处理与机器学习的基础运算,其硬件加速在嵌入式计算场景中具有广泛需求。本届集成电路创新创业大赛龙芯中科杯赛题要求参赛者在OpenLA500处理器平台上,设计并实现包含矩阵乘法加速器与ML-KEM密码IP的完整SoC系统,在资源受限的FPGA器件上同时满足功能正确性与性能要求。
本设计的核心目标是在Xilinx Artix-7 xc7a200tfbg676-1 FPGA器件上构建一个功能完整的异构计算SoC系统,具体包括四项设计内容。第一,设计一个支持4x4无符号矩阵乘法的硬件加速器,不使用DSP资源,完成5000组矩阵计算的批量处理任务,并通过CRC32校验结果正确性。第二,根据FIPS 203标准实现全参数可配置的ML-KEM硬件IP,覆盖ML-KEM-512、ML-KEM-768与ML-KEM-1024三个安全等级,支持密钥生成、封装与解封装全部三种操作。第三,设计通用DMA子系统与批量任务调度器,将多个计算加速器有机集成到统一的AXI总线架构中,实现CPU控制、DMA搬运与加速器计算的流水化协同。第四,在赛事基础SoC提供的外部SRAM控制器上优化AXI突发读写时序,使BaseRAM和ExtRAM能够在连续传输期间以每个系统时钟周期一个32位数据拍的速率工作,降低程序取指与加速器批量搬运共享存储器时的接口开销。
\subsection{设计原则与创新点}
系统设计遵循五条基本原则。第一条原则是模块化分离原则。将矩阵乘法、FFT和ML-KEM三个计算加速器设计为相互独立的AXI外设,各自拥有独立的地址空间、控制寄存器和中断通道,使得每个加速器可单独验证、单独优化,系统集成时仅通过跨时钟域隔离与地址解码完成互连。第二条原则是资源复用原则。ML-KEM内部算法涉及Keccak-f[1600]置换、SHA3/SHAKE哈希族、NTT数论变换、Barrett模乘、CBD中心二项分布采样以及压缩解压缩等多种运算算子。设计中采用单个Keccak核在顶层有限状态机的时间分片调度下被SHA3/SHAKE、SampleNTT和CBD三个消费者分时复用,NTT正变换与逆变换共享同一组蝶形单元流水线,解封装流程中的重加密阶段直接复用封装状态序列。第三条原则是数据搬运与计算解耦原则。通用DMA子系统独立于计算加速器,通过内存到设备、设备到内存以及设备本地端点三种传输模式,将数据搬运从CPU寄存器逐字读写中解放出来,使计算流水线的瓶颈从总线事务转移到算术吞吐率。第四条原则是批量调度与双缓冲原则。矩阵乘法批量序列器通过双Bank乒乓机制,将批量任务调度、数据加载、计算启动与结果写回四个阶段完全流水化,一个Bank执行计算时另一个Bank进行数据加载或结果写回,从而隐藏ExtRAM访问延迟。第五条原则是存储接口节拍匹配原则。外部异步SRAM控制器在满足地址建立与数据保持时间的前提下,将AXI地址、SRAM访问和AXI响应组织为连续流水,使32位AXI数据拍与50 MHz系统时钟逐拍对应,避免控制状态机在突发数据拍之间引入结构性空闲周期。
本设计的主要创新点体现在四个方面。首先,提出了一套高效的跨时钟域互连方案,在CPU时钟域、系统总线时钟域和ML-KEM算法时钟域之间采用全五通道AXI双时钟FIFO进行时钟域隔离,同时配合严格的异步复位释放链和中断同步器,在保持各时钟域独立约束的前提下保证了数据与控制信号的可靠传递。其次,对赛事基础平台的外部SRAM控制器进行突发访问流水化改造,通过读地址预驱动、读数据寄存、连续写握手和跨突发无空闲衔接,提高了CPU与DMA共享存储器的有效带宽。再次,针对竞争评分机制对批量处理延迟的极致要求,设计了快速通道模式,在保证CRC32增量计算正确性的前提下跳过每组结果的逐字写回,将批量矩阵乘法的端到端延迟推进到毫秒量级。最后,ML-KEM解封装中的隐式拒绝路径采用了常量时间比较策略,整个重加密密文与输入密文的逐字节比对不进行提前退出,从根本上杜绝了时序侧信道信息泄露,这是后量子密码实现中至关重要的安全设计考量。
\subsection{代码规模与开发环境}
本设计的基础SoC平台来自龙芯中科提供的竞赛发布包,其核心处理器为OpenLA500。OpenLA500是一款实现了龙芯架构32位精简版指令集(LoongArch32R)的处理器核,采用单发射五级流水线架构,分为取指、译码、执行、访存和写回五个流水级。处理器核内置两路组相联的指令和数据Cache、32项TLB以及简易分支预测器,对外通过标准AXI接口与系统总线互连。
系统RTL代码采用Verilog与SystemVerilog编写,覆盖SoC顶层集成、三个计算加速器及其子模块、DMA子系统、跨时钟域桥接模块、外部SRAM控制器优化以及相关的仿真测试平台。软件部分包括运行于OpenLA500 CPU上的C语言驱动程序和测试程序,涵盖矩阵乘法评测、FFT功能验证以及ML-KEM全参数系统级诊断测试。FPGA综合与布局布线使用Xilinx Vivado 2019.2工具链完成,目标器件为xc7a200tfbg676-1。RTL功能仿真采用Xilinx XSIM进行结果比对与波形验证,软件交叉编译使用龙芯GCC工具链(loongarch32r-linux-gnusf-gcc 8.3)生成LoongArch32R裸机可执行文件。
% ===========================================================================
% 2. SYSTEM ARCHITECTURE & HW/SW PARTITIONING
% ===========================================================================
\section{系统架构设计与软硬件功能划分}
\subsection{系统总体架构}
系统的顶层模块围绕AXI4总线互连矩阵组织所有功能模块。该互连矩阵配置为两个主端口、八个从端口的工作模式,运行于系统时钟域。两个主端口分别连接OpenLA500处理器CPU和数据搬运引擎DMA,八个从端口挂载系统内存、外设以及三个计算加速器的控制接口。整个系统划分为三个异步时钟域,由单一PLL产生。CPU时钟域采用33.333 MHz运行频率,承载OpenLA500处理器核心、一级缓存与AXI主设备接口。系统时钟域采用50 MHz运行频率,承载总线互连矩阵、DMA子系统、FFT加速器、矩阵乘法加速器以及UART、SRAM控制器等基础外设。ML-KEM算法时钟域采用76.923 MHz运行频率,承载ML-KEM的AXI从设备接口、算法控制器、Keccak置换核、NTT单元以及多项式运算模块的全部数据通路。
系统的总体架构如图\ref{fig:system_arch}所示。CPU通过跨时钟域桥接模块接入系统总线,该桥接模块在AXI协议的五条通道上各部署一个双时钟先进先出缓冲队列,将CPU时钟域的读写事务安全传递至系统时钟域。DMA子系统以第二主设备身份直接接入总线互连矩阵,在系统时钟域内向任意从设备发起AXI突发传输。三个计算加速器中,矩阵乘法加速器和FFT加速器完全运行于系统时钟域,ML-KEM加速器则通过第二个跨时钟域桥接模块从系统时钟域跨越至ML-KEM专用算法时钟域。这种分层跨时钟域架构的设计决策基于各模块的计算特征频率需求:矩阵乘法加速器关注批量吞吐率但内部流水线深度较浅,50 MHz的系统时钟已足够满足其时序要求;ML-KEM算法核心包含深度流水化的Keccak轮函数和NTT蝶形单元,需要更高的时钟频率以在串行FSM调度模式下获得可接受的单次操作延迟。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.92\textwidth]{system_arch.png}
\caption{系统总体架构图}
\label{fig:system_arch}
\end{figure}
\subsection{地址空间分配}
系统采用统一的物理地址空间,各计算加速器通过固定的从端口挂载在总线互连矩阵上,每个加速器拥有独立的地址范围。竞赛发布包中总线互连矩阵的八个从端口已有既定分配:从端口零连接片上SRAM(基地址0x1c00\_0000,8 MB空间),从端口一保留,从端口二连接AXI转APB桥后挂载UART(基地址0x1f00\_0000),从端口三连接DVI显示控制器(基地址0x1f10\_0000),从端口四连接系统配置与中断控制器(基地址0x1f20\_0000),从端口五连接DMA从设备端口(基地址0x1f30\_0000),从端口六连接FFT加速器(基地址0x1f40\_0000),从端口七保留供参赛者扩展使用(基地址0x1f50\_0000)。
完整的地址空间分配如表\ref{tab:addr}所示。
\begin{table}[H]
\centering
\caption{AXI总线互连矩阵从端口地址空间分配}
\label{tab:addr}
\begin{tabular}{cclp{4.6cm}}
\toprule
从端口 & 物理基地址 & 模块 & 用途与说明 \\
\midrule
S0 & 0x1c00\_0000 & 片上SRAM & 8 MB空间,BaseRAM(bit22=0,存放程序)与ExtRAM(bit22=1,存放数据) \\
S1 & 0x0000\_0000 & 保留 & 发布包中未分配,保留供扩展使用 \\
S2 & 0x1f00\_0000 & UART & AXI转APB桥接串口,波特率115200,用于调试输出与评测通信 \\
S3 & 0x1f10\_0000 & DVI显示控制器 & 视频输出,800×600分辨率,RGB 3-3-2位宽 \\
S4 & 0x1f20\_0000 & Confreg & 按键、拨码开关、LED、数码管、中断控制器、外部定时器 \\
S5 & 0x1f30\_0000 & DMA控制窗口 & 四通道DMA寄存器(0x000–0x1FF)与矩阵批处理序列器(0x200–0x21F) \\
S6 & 0x1f40\_0000 & FFT/ML-KEM共享窗口 & ML-KEM寄存器与三组批量数据窗(低16 KB),FFT数据窗与CSR(高16 KB) \\
S7 & 0x1f50\_0000 & 矩阵乘法加速器 & 本设计新增:控制状态、CRC32、双Bank矩阵缓冲区 \\
\bottomrule
\end{tabular}
\end{table}
\subsection{时钟域划分与跨时钟域设计}
系统三个时钟域之间的关系在引脚约束文件中通过异步时钟组约束声明为彼此独立的时钟域,时序分析引擎对跨域路径不进行建立保持时间检查,时序收敛的职责完全落在跨时钟域电路的设计正确性上。CPU到系统总线的跨域路径承载AXI读写事务,采用全五通道双时钟先进先出缓冲队列方案。写地址通道、写数据通道和读地址通道的缓冲队列写入端工作在CPU时钟域,读出端工作在系统时钟域;写响应通道和读数据通道的缓冲队列写入端工作在系统时钟域,读出端工作在CPU时钟域。每条通道的缓冲队列独立管理自身的满空标志,通过有效—就绪握手协议实现跨域反压传递。这种设计保证了AXI协议的事务顺序性属性在跨域后不丢失,CPU端提交的写事务在系统总线端按顺序可见,读事务的响应数据同样按顺序返回。
系统总线到ML-KEM算法域的跨域路径负载更大,除了承载寄存器级控制状态读写外,还需承载公钥、私钥和密文的批量数据窗口传输。设计中在FFT/ML-KEM共享地址解码模块内完成地址解码和目标选择后,对ML-KEM分支同样部署了全五通道双时钟先进先出缓冲队列,与CPU到系统总线的方案保持设计一致性。各通道的队列深度经过计算确保在最长的INCR突发传输下不会溢出,读数据通道的队列深度同时考虑了ML-KEM内部块存储器的同步读取延迟。
ML-KEM到CPU的中断信号属于单比特状态信号,从ML-KEM算法时钟域同步到系统时钟域采用两级触发器串联的经典同步器方案。中断信号设计为电平型而非脉冲型,由ML-KEM核心在完成时拉高,由CPU软件通过写一清零操作释放,这种设计避免了跨域脉冲捕捉的可靠性问题。由于中断信号在源时钟域的保持时间远大于目标时钟域的采样周期,两级同步器的亚稳态传播概率可以忽略不计。
时钟域划分与频率规划总结于表\ref{tab:clocks}。
\begin{table}[H]
\centering
\caption{时钟域划分与频率}
\label{tab:clocks}
\begin{tabular}{cccc}
\toprule
时钟域 & 周期 (ns) & 频率 (MHz) & 主要负载 \\
\midrule
cpu\_clk & 30.000 & \CpuFreqMHz{} & OpenLA500 CPU、Cache、AXI主设备接口 \\
sys\_clk & 20.000 & \SysFreqMHz{} & 总线互连矩阵、DMA、FFT、矩阵乘法、外设 \\
mlkem\_clk & 13.000 & \MlkemFreqMHz{} & ML-KEM AXI前端、算法控制器、Keccak、NTT \\
\bottomrule
\end{tabular}
\end{table}
\subsection{复位架构}
系统的复位网络遵循严格的分层异步释放同步撤离原则。外部板级复位信号经PLL锁定指示信号门控后,按照系统域、ML-KEM域、CPU域的顺序逐级释放。每一级使用复位同步器模块实现异步置位、同步撤离:复位置位时两级触发器同时异步清零,复位撤离时在目标时钟域内经过两个时钟周期的同步延迟后释放。释放顺序的级联关系由前一级的同步撤离信号作为后一级的释放门控,确保后续时钟域的复位不会超前于前级释放。仿真中实测的释放时序与设计预期一致:系统域复位在PLL锁定后约2.030 us释放,随后ML-KEM域复位在约2.070 us释放,最后CPU域复位在约2.085 us释放。CPU端首次AXI读地址有效信号出现在约2.205 us,与复位释放之间的间隔满足AXI协议对复位撤离到首次事务的时序要求。仿真中还验证了复位释放前各AXI通道上不存在未完成的事务,所有valid信号在复位期间保持为零,确保上电过程不会产生虚假总线事务。
\subsection{中断系统}
系统的中断聚合逻辑将五个中断源合并为单路CPU中断输入。五个中断源分别为:DMA完成中断、矩阵批量序列器完成中断、矩阵乘法加速器完成中断、ML-KEM算法完成中断以及系统配置寄存器通用中断。所有中断信号均为电平型,由中断源在事件发生时拉高,由CPU软件通过写一清零操作在中断服务程序中释放。性能测试程序出于零开销考虑,实际采用轮询方式检查各模块的状态寄存器中的完成标志位,而非依赖中断处理流程的开销。
\subsection{软硬件功能划分}
系统的软硬件功能划分遵循硬件负责计算密集型与数据搬运任务、软件负责控制调度与结果验证的原则。硬件层承担的功能包括:矩阵乘法的4x4无符号乘积与累加运算,FFT的1024点Radix-2\textsuperscript{2}单路径延迟反馈流水线计算,ML-KEM全流程的Keccak置换、NTT变换、多项式乘法与压缩解压缩运算,DMA的四通道AXI突发传输与内存到设备的端点搬运,以及矩阵批量序列器的5000组任务流水调度。硬件层不涉及任何算法参数的选择逻辑,所有安全等级和操作类型的配置均由软件写入控制寄存器完成。
软件层的职责位于三个抽象层次。最低层为寄存器驱动层,实现各加速器控制器寄存器的C语言结构体映射,封装启动、等待完成、读取结果等基本操作。中间层为DMA调度层,管理DMA通道的分配、源地址与目标地址的计算以及传输长度的配置。最高层为测试与验证层,构造测试输入数据,启动硬件计算流水线,等待完成信号,将硬件计算结果与软件参考模型进行比对,并通过串口输出测试结论和性能指标。
这种分层功能划分使系统行为在验证时具有良好的可观测性与可调试性。任何一个加速器的功能正确性可以通过软件层切换至寄存器逐字读写模式进行独立步进验证,然后再通过DMA批量模式验证完整流水线的高性能运行。ML-KEM的功能验证在三种数据传输路径下分别进行了测试:纯软件参考模型路径用于确认算法逻辑正确性,CPU寄存器逐字节加载路径用于验证AXI从设备接口与跨时钟域的数据通路完整性,DMA批量窗口路径用于验证端到端系统级数据流与性能。
矩阵乘法评测程序在功能上进一步体现了软硬件协作的设计思想。CPU负责配置序列器的源基地址、目标基地址、任务组数以及跨步参数,然后启动序列器。序列器作为纯硬件模块接管后续的全部5000组数据处理:逐一申请DMA通道完成源矩阵从ExtRAM到加速器Bank缓冲区的加载,触发计算并等待完成脉冲。标准写回模式随后申请DMA通道,将结果矩阵从加速器Bank缓冲区写回ExtRAM;官方评测采用的快速通道模式跳过该写回阶段,但矩阵核心仍按照每个66位结果元素的标准字节序增量更新CRC32。CPU在全部任务完成后读取CRC32寄存器并通过串口输出。因而,当前评测路径由源数据搬运、硬件计算和片上CRC32累加组成,ExtRAM结果区在快速通道模式下不会被更新。这种软件配置加硬件执行的划分模式最大化地降低了对CPU吞吐能力的依赖,使性能瓶颈从CPU的寄存器访问延迟转移到硬件加速器与DMA之间的数据搬运吞吐率。
% ===========================================================================
% 3. FRONTEND DESIGN & IMPLEMENTATION
% ===========================================================================
\section{芯片前端设计与实现}
\subsection{DMA子系统设计}
通用DMA子系统是本系统中连接CPU控制面与加速器数据面的关键桥梁。其核心通道管理模块管理四个逻辑通道,各通道拥有独立的源地址、目的地址、传输长度、控制字、状态字、传输模式以及端点配置寄存器。四通道之间通过轮转仲裁器共享一个底层AXI内存到内存传输引擎。轮转仲裁器维护一个当前通道指针,在通道请求到达且引擎空闲时锁定通道,完成当前传输后释放引擎并推进指针至下一通道。
DMA子系统支持三种传输模式以适应不同的数据搬运场景。内存到内存模式用于传统的源地址到目的地址AXI突发传输,传输引擎按照IDLE、PREP1、PREP2、AR、READ、AW、WRITE、WAIT\_BRESP的状态序列执行完整的AXI读后写流程。内存到端点模式用于将ExtRAM中的矩阵数据直接写入矩阵乘法加速器的本地输入端口,数据传输使用加速器内部的端点地址空间而非AXI从设备地址空间,避免了总线互连矩阵的地址解码延迟与可能的仲裁等待。端点到内存模式反之,将加速器计算结果从本地输出端口直接写回ExtRAM。当前SoC配置中DMA的AXI数据宽度为32位,突发长度支持最大64拍,传输粒度固定为4字节每拍。
DMA还提供外部请求接口,用于矩阵批量序列器直接提交DMA传输请求。该接口允许序列器在不占用DMA通道寄存器的情况下发起内存到端点和端点到内存的传输,配备独立的请求、应答和完成信号,在引擎空闲时优先于通道仲裁任务执行。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.85\textwidth]{dma_subsystem.png}
\caption{DMA子系统内部架构}
\label{fig:dma_subsystem}
\end{figure}
\subsection{外部SRAM控制器优化}
\label{sec:sram_controller}
系统沿用赛事基础SoC提供的AXI到异步SRAM适配器,并针对连续突发访问重新设计其关键状态转换与数据保持路径。优化对象不是SRAM器件本身,而是AXI读写通道与BaseRAM、ExtRAM物理接口之间的控制逻辑。控制器仍保持32位数据宽度并支持FIXED、INCR和WRAP三类AXI突发,所有访问均在50 MHz系统时钟域内完成。
原始读通道在相邻数据拍之间交替进入数据响应状态和地址准备状态,即使AXI主设备始终保持\texttt{RREADY},每个数据拍后仍会产生一个固定空闲周期。优化后的快速读模式在返回当前\texttt{R}通道数据时预先驱动下一拍SRAM地址,并在当前数据完成握手的时钟沿将下一拍数据锁存到读数据寄存器。该寄存器将异步SRAM数据总线与AXI\texttt{RVALID/RREADY}握手解耦:当主设备施加反压时,\texttt{RDATA}和\texttt{RVALID}保持稳定;当主设备连续接收时,突发内部可实现每周期返回一个32位数据拍。最后一个\texttt{R}数据拍完成时,控制器还能够直接接受下一条\texttt{AR}请求并启动其地址阶段,消除了相邻读突发之间必须返回空闲状态的间隔。
写通道的优化移除了连续写数据拍之间的\texttt{WRITE\_NOP}状态。当\texttt{WVALID}连续有效时,控制器保持\texttt{WREADY}并在每个系统时钟周期更新地址、字节使能与写数据,从而由隔拍写入改为逐拍写入。地址生成逻辑使用当前地址、固定字长增量和突发边界掩码统一处理三类突发;计数器扩展为9位,以正确表达AXI4最长256拍突发的完成条件。
BaseRAM与ExtRAM的选择位由地址位22决定。优化后该选择不再直接依赖组合地址输出,而是在接收\texttt{AR}或\texttt{AW}时锁存为独立的Bank状态,并随整个事务保持不变,避免流水地址切换期间片选和读数据多路选择发生瞬态变化。在无AXI反压的理想条件下,连续读写的接口峰值带宽由原先约每两周期一个32位数据拍提高至每周期一个数据拍;在50 MHz系统时钟下,对应的理论单向带宽为200 MB/s。该数值是接口节拍上限,实际端到端性能仍受到总线仲裁、突发启动、DMA调度和计算模块反压的共同影响。
\subsection{矩阵乘法加速器设计}
矩阵乘法加速器是本系统中逻辑结构最为紧凑的计算模块。其核心功能是计算两个4x4无符号32位整数矩阵的乘积,每个输出元素为四个32位乘积累加结果,总宽度66位。加速器内部采用双Bank结构,Bank 0和Bank 1各包含一套完整的16元素A矩阵、16元素B矩阵以及48字(16元素乘以3字每元素)C结果矩阵的存储空间。双Bank设计使得批量序列器可以实现在一个Bank执行矩阵乘法计算的同时,另一个Bank通过端点接口接收下一组矩阵数据或写出上一组计算结果,从而实现计算与数据搬运的时间重叠。
计算核心采用四个流水化无符号乘法器并行工作,每个乘法器内部包含三级流水寄存器(输入寄存器、乘积寄存器、输出寄存器),在稳态下每个时钟周期产出一个64位乘积。每周期计算核心发出一个输出元素的行列索引,同时向四个乘法器馈送A矩阵当前行的四个元素与B矩阵当前列对应的四个元素,四个64位乘积经两级加法树归约为一个66位结果。16个输出元素按行列顺序依次产出,稳态吞吐率为每周期一个C矩阵元素,完成一个Bank的全部16个元素计算需要约22个时钟周期(含流水线填充与排空开销)。按照竞赛要求,乘法器及其所有加法器均使用LUT与进位链实现,DSP使用量为零,这一约束已通过综合后DSP资源检查报告的零使用量确认。
加速器的AXI从设备接口支持INCR突发读写,允许DMA以批量突发方式访问矩阵数据缓冲区。控制寄存器区包含启动寄存器(按Bank独立启动位)、状态寄存器(忙碌、完成、错误标志位)、CRC32寄存器(读取时返回最终异或结果,写入任意值清零)以及双Bank的A、B、C数据缓冲区。Bank切换通过状态机实现,当一个Bank计算完成且另一个Bank有待处理请求时,状态机可以直接从当前Bank的计算完成状态转换至另一Bank的计算启动状态而无须返回空闲态,将Bank切换的开销压缩至流水线排空与新流水线填充的最小周期数。
矩阵乘法加速器的CRC32计算单元采用IEEE 802.3反射多项式进行增量计算,初始值为全一,最终异或全一。每个66位输出元素拆分为低32位、高32位和零扩展的高2位三部分,按顺序输入CRC32计算逻辑。CRC32的增量更新与计算输出同步进行,不受CPU或DMA是否读取C矩阵数据的影响。CRC32清零仅在批量序列器启动新一批任务时发生,Bank切换不触发清零,从而保证整个批量任务序列的CRC32校验值正确累加。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.90\textwidth]{matmul_arch.png}
\caption{矩阵乘法加速器内部架构}
\label{fig:matmul_arch}
\end{figure}
\subsection{矩阵批量序列器设计}
矩阵批量序列器是连接DMA子系统与矩阵乘法加速器的中枢调度模块。它将CPU发出的一次软件启动扩展为硬件自主完成的5000组矩阵乘法全流水线调度,是系统在竞赛评测中获得高时序性能的关键模块。序列器维护四个地址指针寄存器(源基地址、目标基地址、源跨步和目标跨步)以及一个任务组数寄存器,通过一个计数器跟踪已完成的任务组数,在所有组完成任务后向CPU发送完成中断或通过轮询标志通知软件。
序列器的核心机制是双Bank流水调度。两组矩阵任务被交替分配到Bank 0和Bank 1上执行。对于分配到某个Bank的每组任务,调度流程分为加载、计算和存储三个连续的流水阶段。加载阶段通过DMA外部请求接口提交一次128字节的内存到端点传输请求,将源矩阵A和B从ExtRAM搬运到目标Bank的输入缓冲区。传输完成后,Bank内的A和B数据标记为有效。计算阶段通过向加速器发出单周期的Bank启动脉冲触发矩阵乘法计算,并等待加速器的计算完成脉冲。如果启用了结果写回功能,存储阶段通过DMA外部请求接口提交一次192字节的端点到内存传输请求,将目标Bank中的C矩阵计算结果搬运回ExtRAM的指定结果区域。在快速通道模式下,存储阶段被跳过,任务在计算完成时即标记为退休,但CRC32的增量更新仍正常执行。
两个Bank的流水可以在时间上重叠:当Bank 0执行计算时,DMA可以同时为Bank 1执行加载或存储操作。这种重叠利用了矩阵乘法加速器的双Bank独立性与DMA引擎的独立工作能力,使得外部存储器的访问延迟被计算时间覆盖。序列器使用一个深度为二的完成队列跟踪Bank计算完成的先后顺序,确保存储操作在正确的Bank上执行。
图\ref{fig:matmul_gantt}以快速通道的前四组任务和末尾收尾阶段为例,给出了当前实现的数据流甘特图。图中阶段宽度用于表达先后依赖和流水重叠关系,不代表严格的周期比例。CDMA读侧仍使用单一AXI读数据通道,硬件能够保留一个活动突发和一个预取请求,以减少相邻突发之间的地址握手空隙,但两组读数据仍按请求顺序返回。双Bank的作用是在共享读通道装载下一组A/B矩阵时,让单一乘加流水线处理已经就绪的另一Bank,而不是复制两套DMA或乘加数据通路。
每个66位C元素在写入对应Bank结果缓冲区的同时进入CRC结果FIFO。递归CRC32数据通路将一个元素表示成两个6字节更新步骤,因此消费速率低于乘加流水线的峰值发射速率;FIFO吸收短期速率差,在占用量接近阈值时对新结果发射施加反压。快速通道在矩阵计算完成时退休该组任务,不发起192字节结果写回,但批量序列器只有在最后一组退休且CRC FIFO与递归更新状态均为空闲后才置位最终完成标志。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.98\textwidth]{matmul_dataflow_gantt.png}
\caption{Matmul快速通道数据流甘特图}
\label{fig:matmul_gantt}
\end{figure}
在快速通道模式下,结果写回不再占用数据通路。稳态吞吐率由128字节源数据读取、单一乘加流水线以及递归CRC32消费速率共同决定:源数据读取包含32个32位数据拍,乘加流水线在无反压时可连续发射16个结果元素,而CRC32以每个元素两个更新周期的速率消费FIFO数据。当CRC积压达到阈值时,CRC结果FIFO会暂停新的乘加发射,因此不能将批量吞吐率简单等同于单个Bank的计算延迟。在整个5000组任务的处理过程中,CPU不参与逐组调度,仅需在开始前配置序列器寄存器并在结束后查询完成状态,实现了硬件自主的批量处理流程。
\subsection{FFT加速器设计}
1024点FFT加速器采用Radix-2\textsuperscript{2}单路径延迟反馈架构,包含一个顶层控制器状态机和五个SDF流水级单元。每个流水级单元处理两级基二蝶形运算,内部包含两个蝶形单元、两个延迟缓冲区和一个复数乘法器。延迟缓冲区的深度依次递减,从第一级的512/256降至最后一级的2/1,对应每级蝶形运算的数据分组规模。
顶层控制器的状态机在空闲态等待CPU或DMA的启动命令,随后进入加载态。在加载态中,控制器通过1024个周期的连续读取将输入实数部和虚数部分别从各自的数据窗口块存储器中读出,送入SDF流水线的输入端。输入数据按自然顺序进入流水线。加载完成后,控制器进入等待输出态,在接下来的1024个周期中接收SDF流水线的输出结果。由于SDF流水线的固有特性,输出数据呈位逆序排列。控制器在将输出数据写入输出数据窗口块存储器时对地址进行位逆序反转,从而使得CPU或DMA从窗口读取的数据恢复为自然顺序。
SDF流水线中的每个蝶形单元执行一次复数加法和一次复数减法,并在结果上施加一次算术右移一位操作作为缩放因子。五个SDFUnit共包含十次右移,总缩放因子为1/1024。相邻蝶形级采用了不同的半舍入偏置以减小累积舍入误差。所有复数乘法器中的四个实数乘法器均使用LUT实现,没有使用DSP资源。
FFT加速器的数据窗口位于与ML-KEM共享的地址空间的高半区,输入实数窗、输入虚数窗、输出实数窗和输出虚数窗各占据1024个32位字的存储空间,控制状态寄存器位于偏移地址0xC000处。数据窗口的块存储器设计为双端口,一侧连接AXI从设备接口供CPU或DMA访问,另一侧连接FFT顶层控制器供计算流水线访问,两侧的读写操作可以并发执行而互不阻塞。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.85\textwidth]{fft_arch.png}
\caption{FFT加速器内部架构(Radix-2\textsuperscript{2} SDF数据通路)}
\label{fig:fft_arch}
\end{figure}
\subsection{ML-KEM加速器系统集成}
ML-KEM加速器是本系统中算法复杂度和硬件规模最高的计算模块。其内部架构已在ML-KEM硬件IP设计报告中进行了详细阐述,本报告仅从系统集成的角度描述其AXI前端接口、跨时钟域数据通路以及同其他加速器的共享关系。ML-KEM的AXI从设备接口通过跨时钟域桥接模块连接至FFT/ML-KEM共享地址窗口的ML-KEM分支。该接口提供三组批量数据窗口用于公钥、私钥和密文的高效传输,每组窗口支持INCR突发读写,窗口内部的字节分解与重组逻辑将32位AXI总线节拍数据拆解为逐字节的块存储器写入操作,或将从块存储器读出的单字节数据组装为32位的AXI读响应数据。
ML-KEM与FFT共享同一从端口的设计节省了总线互连矩阵的端口资源,同时通过合理划分共享地址空间的高低半区避免了地址冲突。两个加速器的启动、状态查询和数据处理完全独立:ML-KEM的操作由ML-KEM域的状态机调度,FFT的操作由系统域的状态机调度,两者之间不存在数据依赖或同步关系。当中断信号从ML-KEM域同步回系统域后,CPU可以在同一个中断服务程序中按照中断源位区分具体是哪个加速器完成了操作。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.85\textwidth]{mlkem_modules.png}
\caption{ML-KEM模块内部层次结构}
\label{fig:mlkem_modules}
\end{figure}
% ===========================================================================
% 4. VERIFICATION METHODOLOGY
% ===========================================================================
\section{验证方案}
\subsection{分层验证策略}
系统的验证工作采用分层递进策略,将验证对象从底层叶模块到顶层系统划分为四个层级,每一层级解决不同粒度的功能正确性问题。
第一层级为叶模块级验证,覆盖全部自研硬件模块中的独立运算单元和控制单元。对于ML-KEM算法子系统,Keccak-f[1600]置换核使用标准空消息和多块测试向量进行逐比特比对验证;SHA3/SHAKE顶层使用速率边界、域分离填充和多块末尾块填充的专项测试向量;NTT核和多项式乘法模块使用已知结果的确定性测试向量,验证蝶形运算与Barrett模约简的数值精度;CBD采样和拒绝采样模块因其输出具有随机性且长度可变,测试平台同时验证输出系数的数值范围、统计分布特征以及反压条件下的握手协议正确性。对于FFT加速器,叶模块级验证覆盖了蝶形运算单元、复数乘法器、延迟缓冲区和旋转因子只读存储器,重点验证蝶形运算中的算术右移舍入策略在各级联条件下的累积误差是否处于可控范围内,以及复数乘法器在四种乘积组合下的符号正确性。对于矩阵乘法加速器,叶模块级验证覆盖了流水化乘法器的三级流水寄存器行为、乘积结果的64位宽度正确性以及加法树归约路径的进位链完整性;CRC32计算单元使用标准IEEE 802.3已知答案测试向量独立验证其增量更新逻辑。对于DMA子系统,叶模块级验证覆盖了同步先进先出缓冲队列在满空边界条件下的读写行为、轮转仲裁器在多通道并发请求时的公平性以及AXI突发传输引擎在不同传输长度和地址对齐条件下的时序正确性。
第二层级为IP集成级验证。ML-KEM方面,将七个算子模块、系数存储块存储器和顶层有限状态机集成为完整的算法顶层模块,使用FIPS 203标准定义的已知答案测试向量进行端到端验证,对密钥生成、封装和解封装的每字节输出进行逐字节精确比对,任何单比特的偏差均导致测试失败,测试覆盖了三种安全等级和三种操作的各1000组不同输入向量。FFT方面,将SDF流水线五级单元与控制状态机集成为完整的1024点FFT加速器,使用多组已知频率成分的合成信号作为输入,验证输出频谱的幅度正确性和位逆序到自然顺序的地址转换正确性,并以双精度浮点软件参考模型为基准,在1024个频点上逐一比较实数部和虚数部的误差。矩阵乘法方面,将双Bank数据缓冲区、四乘法器计算核心、CRC32增量更新逻辑和AXI从设备接口集成为完整的矩阵乘法加速器,使用多组已知乘积的确定性矩阵作为输入,覆盖全零边界用例、单位矩阵、满秩随机矩阵和不同矩阵维度组合,验证输出元素的66位结果与各维度的按字拆分格式的正确性。DMA方面,将四通道寄存器组、轮转仲裁器、内存到内存传输引擎和端点状态机集成为完整的DMA子系统,分别验证三种传输模式在随机地址与随机长度下的数据搬运完整性,以及端点模式中Bank编号与字偏移的地址计算正确性。
第三层级为SoC集成级验证。将矩阵乘法加速器、FFT加速器、ML-KEM加速器和DMA子系统全部集成到系统顶层模块中,重点验证总线互连矩阵的地址解码正确性、多主设备并发访问的仲裁公平性、跨时钟域数据通路的传输可靠性、复位释放前后各AXI通道的事务清空情况以及中断聚合与响应的时序正确性。该层级通过短时长的XSIM系统级仿真完成,利用波形窗口观察关键时序节点,确认复位释放后CPU第一条取指事务的正常发起以及各加速器AXI接口的初始状态为空闲。该过程同时检查了CPU经SRAM控制器访问BaseRAM的取指通路。
第四层级为板级系统验证。将经过综合、布局布线生成的比特流下载到FPGA开发板,运行CPU上的测试程序,在真实的硬件环境中验证完整的软硬件协同工作流程。板级验证覆盖了矩阵乘法评测、FFT功能正确性与性能对比、ML-KEM全参数全操作的三路径系统诊断测试,所有测试通过开发板串口输出结构化的测试结果日志。这些测试均依赖BaseRAM执行程序并通过ExtRAM或加速器窗口搬运批量数据,因而也对优化后SRAM控制器的连续读写、Bank选择和长时间运行稳定性形成了端到端覆盖。
\subsection{验证工具链与环境}
RTL仿真使用Xilinx XSIM作为仿真引擎,通过Tcl脚本管理仿真流程。叶模块级仿真在模块源码目录下运行,使用独立的testbench文件;ML-KEM顶层KAT仿真的测试时钟为20 MHz,周期统计据此换算为仿真时间。SoC集成级仿真在系统顶层目录下运行,使用仿真时钟模型产生各时钟域信号。仿真中通过条件编译旁路真实PLL锁相过程,以缩短仿真启动时间。复位窗口的波形数据通过VCD格式导出,用于观测复位释放时序和验证复位释放前AXI通道上不存在未完成事务。上述测试属于RTL功能仿真,不包含门级延迟或SDF反标。
FPGA综合与实现使用Vivado 2019.2完整流程。时序约束为CPU、系统总线和ML-KEM三个生成时钟分别定义周期与波形,并将三者声明为异步时钟组;跨域功能正确性由AXI双时钟FIFO、单比特同步器和复位同步器的结构保证,而不是由跨域最大延迟约束保证。当前输入输出延迟约束覆盖BaseRAM和ExtRAM的数据、地址与控制信号,尚未对QSPI Flash、UART、DVI等全部板级接口建立完整的外部时序模型,因此Vivado方法学报告仍包含缺失输入输出延迟的警告。本文的静态时序结论仅适用于已约束的内部同步路径与SRAM接口,不将未完整约束的外部接口计入时序收敛结论。
软件编译使用龙芯LoongArch32R交叉工具链中的loongarch32r-linux-gnusf-gcc 8.3编译器,目标指令集为LoongArch32R。各测试程序由其Makefile分别选择-O2或-O3优化,并采用静态裸机链接、无标准启动文件和未缓存地址映射。生成的二进制文件写入BaseRAM仿真模型或开发板BaseRAM。板级调试过程中利用串口输出作为主要的信息反馈通道,所有测试程序的判定结果、性能指标和错误计数均通过115200波特率的串口输出,并由上位机脚本进行解析和记录。
\subsection{验证覆盖范围}
本项目验证覆盖范围的完整程度由表\ref{tab:verification}总结。矩阵乘法批量处理通过了三轮官方板级评测的CRC32校验,每轮使用独立随机种子生成5000组输入。ML-KEM算法子系统的已知答案测试在仿真层面通过了9000个主路径测试向量(三种操作乘以三种安全等级乘以1000个向量),并通过了300个Decaps隐式拒绝路径向量(三种安全等级各100个向量);在板级系统诊断测试中通过了900次全流水运行(三种安全等级乘以三种传输路径乘以100次迭代),所有测试的失败计数均为零。FFT加速器在板级上通过了两类数据传输模式(CPU逐字读写和DMA批量传输)各三次重复运行的功能正确性和数值精度验证,1024个频点的实数部与虚数部最大误差均低于预定阈值。DMA子系统在板级系统诊断测试中作为ML-KEM和FFT的数据搬运通路被间接验证了三种传输模式的完整性,同时其四通道轮转调度和端点传输的正确性通过矩阵批量序列器的5000组流水任务得到了充分覆盖。上述板级负载均运行在优化后的SRAM控制器之上,覆盖CPU从BaseRAM持续取指以及DMA从ExtRAM执行长突发读取的实际使用场景。
\begin{table}[H]
\centering
\setlength{\tabcolsep}{5pt}
\caption{功能验证覆盖摘要}
\label{tab:verification}
\begin{tabular}{p{4.5cm}ccc}
\toprule
验证项 & 测试规模 & 通过/总计 & 结果 \\
\midrule
矩阵乘法叶模块(乘法器、CRC32) & 确定性向量 & — & 通过 \\
FFT叶模块(蝶形单元、复数乘法器) & 定向测试 & — & 通过 \\
DMA叶模块(FIFO、仲裁器、引擎) & 定向测试 & — & 通过 \\
ML-KEM叶模块(Keccak、NTT、采样等) & 标准测试向量 & — & 通过 \\
\midrule
矩阵乘法IP集成(仿真) & 多组确定矩阵 & — & 通过 \\
FFT IP集成(仿真) & 合成测试信号 & — & 通过 \\
DMA IP集成(仿真) & 随机地址/长度 & — & 通过 \\
ML-KEM KAT(仿真) & 9组 × 1000向量 & 9 / 9 & 通过 \\
ML-KEM隐式拒绝(仿真) & 3组 × 100向量 & 3 / 3 & 通过 \\
\midrule
矩阵乘法CRC32(官方板级评测) & 3轮 × 5000组 & 3 / 3 & 通过 \\
FFT功能验证(板级) & 3次 × 2模式 & 6 / 6 & 通过 \\
ML-KEM 系统诊断(板级) & 9组 × 100次迭代 & 9 / 9 & 通过 \\
DMA搬运完整性(板级,间接覆盖) & 5000组流水任务 & — & 通过 \\
SRAM连续突发读写(板级,间接覆盖) & Matmul、FFT、ML-KEM负载 & — & 通过 \\
\midrule
复位释放前事务检查(仿真) & — & — & 无违规 \\
DSP资源检查(综合后) & — & 0个 / 期望0个 & 通过 \\
时序收敛(布局布线后) & 88,843个端点 & — & 零违例 \\
\bottomrule
\end{tabular}
\end{table}
% ===========================================================================
% 5. IMPLEMENTATION RESULTS & ANALYSIS
% ===========================================================================
\section{实现结果与分析}
\subsection{FPGA资源利用}
系统在xc7a200tfbg676-1器件上的综合与布局布线完整通过,路由完成率达到100\%。整体资源利用情况如表\ref{tab:utilization}所示。查找表Slice LUT使用量为55,066个,占器件总量的41.16\%,其中作为逻辑使用的LUT占39.73\%,作为分布式存储器使用的LUT占4.13\%。Slice寄存器使用量为31,000个,占器件总量的11.58\%。块存储器Tile使用量为29.5个,占器件总量的8.08\%,主要由ML-KEM的七个BRAM实例、CPU缓存的数据存储阵列以及FFT的数据窗口BRAM构成。数字信号处理器DSP的实例化数量为零,占器件总量的0.00\%,符合竞赛对矩阵乘法加速器不使用DSP资源的硬性约束。输入输出引脚Bonded IOB使用量为202个,占器件总量的50.50\%,其中大部分为开发板QSPI Flash、ExtRAM和UART接口所需。全局时钟缓冲器BUFGCTRL使用量为4个,PLL模块使用量为1个。
\begin{table}[H]
\centering
\caption{FPGA整体资源利用}
\label{tab:utilization}
\begin{tabular}{cccc}
\toprule
资源类型 & 已使用 & 可用总量 & 利用率 \\
\midrule
Slice LUTs & \SliceLUTs{} & 133,800 & 41.16\% \\
Slice Registers & \SliceFFs{} & 267,600 & 11.58\% \\
Block RAM Tile & \BramTiles{} & 365 & 8.08\% \\
DSP48E1 & \DspCount{} & 740 & 0.00\% \\
Bonded IOB & 202 & 400 & 50.50\% \\
BUFGCTRL & 4 & 32 & 12.50\% \\
\bottomrule
\end{tabular}
\end{table}
从模块层级的资源分布来看,ML-KEM加速器是整个系统中面积最大的计算模块,其算法核心消耗约21,697个LUT,占系统总LUT量的39.4\%。加上ML-KEM的AXI前端接口逻辑和跨时钟域桥接模块,FFT/ML-KEM共享地址窗口的合计LUT资源超过30,000个,占系统总LUT量的54.7\%以上。矩阵乘法加速器消耗约9,879个LUT,占系统总LUT量的17.9\%。OpenLA500 CPU处理器消耗约8,584个LUT,占系统总LUT量的15.6\%。其余的LUT分布在DMA子系统、总线互连矩阵、UART、SRAM控制器等基础设施模块中。
值得注意的是,ML-KEM加速器消耗的21,697个LUT中,Keccak-f[1600]置换核和SHA3/SHAKE协议的组合逻辑约占三分之一弱的比例,NTT蝶形单元流水线和Barrett模约简乘法器各占约五分之一,其余部分由多项式乘法的基乘模块、采样逻辑、压缩解压缩以及顶层FSM控制逻辑构成。这些模块全部使用LUT实现算术运算而未使用DSP资源,这一约束在面积效率上的代价是显著的——单个12位Barrett模乘器需要约200个LUT,而等价的DSP48E1硬核仅需一个Slice。然而,全LUT实现的方案提供了完全的底层可控性,避免了DSP级联延迟路径带来的时序收敛困难,这也是布局布线后在76.923 MHz目标频率下所有时序路径均收敛的重要因素。
\subsection{时序性能}
Vivado静态时序分析报告的完整路径覆盖了88,843个时序端点,建立时间的最差负裕量为0.070 ns,总负裕量为0.000 ns,建立时间违例端点数为零。保持时间的最差负裕量为0.024 ns,总负裕量为0.000 ns,保持时间违例端点数为零。时序分析覆盖了所有三个时钟域的建立时间、保持时间和最小脉宽检查,三个时钟域均无违例。表\ref{tab:timing}列出了各时钟域的详细时序指标。
\begin{table}[H]
\centering
\caption{各时钟域时序指标}
\label{tab:timing}
\begin{tabular}{ccccc}
\toprule
时钟域 & 频率 (MHz) & 建立时间WNS (ns) & 保持时间WHS (ns) & 端点数 \\
\midrule
cpu\_clk & 33.333 & \CpuWNS{} & 0.040 & 17,197 \\
sys\_clk & 50.000 & \SysWNS{} & 0.024 & 22,307 \\
mlkem\_clk & 76.923 & \MlkemWNS{} & 0.057 & 31,646 \\
\bottomrule
\end{tabular}
\end{table}
三个时钟域中,ML-KEM算法时钟域的时序裕量最为紧张,建立时间最差负裕量为0.070 ns,对应的最差时序路径位于ML-KEM内部的Keccak轮函数组合逻辑的扇出路径上。该路径从源寄存器出发,经过五级异或级联的theta运算步骤和两级chi运算的非线性变换后到达目标寄存器,逻辑级数约为28级,在13 ns的时钟周期约束下路径延迟为12.930 ns。ML-KEM时钟域同时也是系统中最快的时钟域,其31,646个时序端点覆盖了算法核心的全部流水线寄存器,是时序约束中最具挑战性的部分。系统时钟域的建立时间裕量为0.125 ns,CPU时钟域由于频率最低而具有最大的时序裕量0.737 ns。
值得指出的是,竞赛基础发布包中PLL仅产生两路时钟输出——CPU时钟(33.333 MHz)和系统时钟(50 MHz),系统的第三时钟域ML-KEM算法时钟(76.923 MHz)是本设计对PLL配置的扩展。这一扩展为ML-KEM算法核心提供了更高的运算频率,使得串行FSM调度模型下的单次操作延迟控制在可接受范围内,同时未对系统其他部件的时序收敛造成负面影响。
\subsection{存储子系统}
系统的外部存储子系统由两块板载SRAM芯片构成,每块容量为4 MB,通过统一的SRAM控制器进行访问。AXI总线为两块存储器分配连续的8 MB物理窗口,控制器根据AXI地址的第22位进行BaseRAM和ExtRAM的路由选择:bit22为0时访问BaseRAM,对应0x1c00\_0000至0x1c3f\_ffff;bit22为1时访问ExtRAM,对应0x1c40\_0000至0x1c7f\_ffff。两块SRAM内部均使用地址位[21:2]形成20位字地址。外部SRAM芯片的最小读写周期为10 ns,因此控制器时钟频率被限制在50 MHz以内,与系统时钟域的50 MHz频率天然匹配。
控制器采用第\ref{sec:sram_controller}节所述的连续突发优化。读方向通过地址阶段与数据响应阶段重叠,在当前数据拍被AXI主设备接收的同时准备下一拍SRAM数据;写方向则在\texttt{WVALID/WREADY}持续握手时逐周期推进写地址。由于系统时钟周期为20 ns,每一拍仍为异步SRAM保留了一个完整时钟周期的地址建立和数据稳定窗口。读数据寄存器负责在AXI反压期间保持响应不变,事务级Bank寄存器负责保证BaseRAM与ExtRAM片选在整个突发期间稳定。该实现兼顾了外部器件时序要求和AXI连续传输吞吐率。
在竞赛评测场景中,BaseRAM用于存放用户程序的指令和数据,ExtRAM用于存放源矩阵数据。标准数据布局在ExtRAM偏移0x0000\_0000处存放5000组源矩阵A和B(每组128字节,总计640,000字节),并为偏移0x0009\_c400处的5000组结果矩阵C保留960,000字节空间。标准写回模式会填充该结果区;当前官方评测使用快速通道模式,跳过结果写回,矩阵核心直接按照与该960,000字节结果序列相同的字节顺序累计CRC32。因此评测校验覆盖的是全部计算结果的逻辑字节序列,而不是快速模式下ExtRAM结果区的实际内容。DMA读取ExtRAM源数据的过程不经过CPU寄存器,消除了CPU访存延迟对批量处理吞吐率的制约。
时序收敛的关键设计因素包括三个方面。第一,ML-KEM算法核心中使用了大量的流水线寄存器来切割长组合路径。Keccak-f[1600]的每一轮置换内部已经按照标准结构划分为theta、rho、pi、chi和iota五个子步骤,每个子步骤之间通过寄存器隔离,保证了单轮内的最大逻辑级数可控。Barrett模乘器内部在乘法、常量乘法、比较和减法每一个阶段之间都插入了流水线寄存器。NTT蝶形单元同样在输入读取、蝶形运算和写回控制之间加入了多级流水。第二,跨时钟域路径被声明为异步时钟组,不进行同步时序检查,转而通过双时钟FIFO的结构保证数据可靠传输,避免了对跨域路径进行困难的高频时序约束。第三,综合策略中启用了寄存器重定时和寄存器平衡优化选项,允许工具在保持设计功能不变的前提下重新分布流水线寄存器以平衡各级组合逻辑延迟。
\subsection{功耗分析}
Vivado功耗分析报告给出的总片上功耗为\TotalPower{} W,其中动态功耗占\DynamicPower{} W(81.8\%),静态功耗占\StaticPower{} W(18.2\%)。动态功耗的主要组成按占比排列为:信号翻转功耗0.284 W(占动态功耗的44.6\%),Slice逻辑单元功耗0.137 W(占21.5\%),PLL功耗0.102 W(占16.0\%),时钟网络功耗0.060 W(占9.4\%),Block RAM功耗0.027 W(占4.2\%),I/O功耗0.027 W(占4.2\%)。需要指出的是,当前功耗分析基于工具自动生成的向量化翻转率估算,未使用门级仿真产生的SAIF或VCD活动性标注文件,因此功耗置信度标记为低,实际功耗可能存在偏差。
\begin{table}[H]
\centering
\caption{功耗分布}
\label{tab:power}
\begin{tabular}{cc}
\toprule
功耗类型 & 功耗值 (W) \\
\midrule
总片上功耗 & \TotalPower{} \\
动态功耗 & \DynamicPower{} \\
静态功耗 & \StaticPower{} \\
\bottomrule
\end{tabular}
\end{table}
从模块层级的功耗分布来看,ML-KEM加速器(含跨时钟域桥接模块)是系统中功耗最高的独立模块,其算法核心消耗约为0.332 W的动态功耗,占系统动态功耗的52.1\%。FFT控制器消耗约0.031 W,矩阵乘法加速器消耗约0.077 W,CPU处理器消耗约0.027 W。PLL时钟生成模块由于其内部VCO振荡器始终工作,消耗了0.103 W的准恒定功耗,在系统功耗中占显著比例,但这属于物理层的基础设施开销而非算法逻辑的功耗。
\subsection{矩阵乘法性能分析}
矩阵乘法批量评测是本系统竞赛评分的核心项目。在阶段验证中,系统以三个独立随机种子完成三轮官方评测,运行时间分别为6.936 ms、6.944 ms和6.950 ms,CRC32均完全匹配。随后通过减少软件启动开销、优化批量调度以及进一步压缩SRAM突发数据通路的空闲周期,最终评测在随机种子\MatmulFinalSeed{}下完成5000组4x4无符号矩阵乘法,期望值与上报值均为CRC32 \MatmulFinalCRC{},运行时间为\MatmulFinalMs{} ms,得分为\MatmulFinalScore{}。评测平台记录如图\ref{fig:matmul-final-score}所示。
\begin{figure}[H]
\centering
\includegraphics[width=0.94\textwidth]{score.png}
\caption{矩阵乘法最终评测结果(任务ID 6296)}
\label{fig:matmul-final-score}
\end{figure}
以最终运行时间\MatmulFinalMs{} ms为准,系统在5000组任务中的平均每组处理延迟约为0.982353 us。在系统时钟50 MHz的条件下,每组矩阵乘法平均消耗约49.12个时钟周期。每组源数据由一次32拍、32位AXI读突发从ExtRAM装载;SRAM控制器的连续读优化消除了突发内部原有的逐拍空闲周期,并允许相邻读突发在条件满足时直接衔接,从而降低了批量任务中占主导地位的源数据搬运开销。在快速通道模式下,结果写回被跳过,但稳态吞吐率仍由SRAM与CDMA读通道、约22周期的乘加计算以及递归CRC32消费速率共同决定。双Bank流水负责重叠源数据装载与计算,CRC结果FIFO吸收乘加输出和CRC消费之间的短期速率差,因此实测49.12周期每组是完整数据通路协同后的结果,不能仅由单个计算核的22周期延迟推导。相较阶段验证的中位值,最终时间降低约29.27\%,表明本项目的性能收益主要来自启动、搬运、调度、计算和校验全链路的协同优化,而非单独缩短乘加核心延迟。
\subsection{FFT性能分析}
FFT加速器在两种数据传输模式下分别进行了板级验证,验证结果见表\ref{tab:fft}。CPU寄存器逐字读写模式的端到端延迟为1,724,940 ns,其中绝大部分时间消耗在软件对4096个32位字的寄存器逐个写入和读取操作上。DMA批量传输模式的端到端延迟为296,730 ns,相比CPU模式获得了约5.81倍的加速。与纯软件参考实现(延迟245,632,500 ns)相比,CPU模式的加速比为142.53倍,DMA模式的加速比为827.80倍。
\begin{table}[H]
\centering
\caption{FFT性能对比}
\label{tab:fft}
\begin{tabular}{cccc}
\toprule
实现方式 & 延迟 (ns) & 加速比(相对纯软件) & 最大误差(实部/虚部) \\
\midrule
纯软件参考 & 245,632,500 & 1.00× & — \\
CPU寄存器模式 & \FftCpuNs{} & \FftCpuSpeedup{}× & 1 / 2 \\
DMA批量模式 & \FftDmaNs{} & \FftDmaSpeedup{}× & 1 / 2 \\
\bottomrule
\end{tabular}
\end{table}
DMA模式的延迟主要由四段AXI突发传输(加载实数部、加载虚数部、读取实数部、读取虚数部,每段1024个32位字)和FFT流水线的计算填充周期构成。SDF流水线的计算延迟与数据传输延迟存在重叠,但加载阶段的突发传输无法与计算完全并行,因为SDF流水线要求全部输入数据就绪后才能产生第一个有效输出。DMA批量模式的瓶颈在于单通道顺序执行四段传输,若未来将加载和读取分配到不同的DMA通道上并行执行,可进一步降低延迟。
FFT计算结果的数值精度通过比较硬件输出与双精度浮点Radix-2按时抽取参考实现验证。在1024个频点中,实数部的最大误差为1,虚数部的最大误差为2,均低于预定的误差阈值8。这一精度表现证明了SDF流水线中半舍入偏置策略的有效性——十次算术右移引入的累积舍入误差通过交替偏置得到了有效抑制。
\subsection{ML-KEM性能分析}
ML-KEM加速器的板级系统诊断测试结果汇总于表\ref{tab:mlkem}。测试在三种安全等级下分别使用软件参考、CPU寄存器加载和DMA批量窗口三种数据传输路径各运行100次迭代,总计900次迭代全部通过,失败次数为零。表中的周期数由OpenLA500的CPU周期计数器采集,计数频率为33 MHz;它们不是50 MHz系统总线周期,也不是76.923 MHz的ML-KEM算法周期。DMA路径中,ML-KEM-512、ML-KEM-768和ML-KEM-1024的全流程(密钥生成、封装、解封装顺序执行)平均耗时分别为52,995、80,643和113,261个CPU周期,按测试程序使用的33 MHz换算后分别为1.605 ms、2.443 ms和3.432 ms。
\begin{table}[H]
\centering
\caption{ML-KEM板级系统诊断性能(100次迭代均值)}
\label{tab:mlkem}
\begin{tabular}{c>{\centering\arraybackslash}p{2.2cm}>{\centering\arraybackslash}p{2.2cm}>{\centering\arraybackslash}p{2.2cm}cc}
\toprule
安全等级 & 软件参考(周期) & CPU加载(周期) & DMA批量(周期) & DMA速度 & 失败数 \\
\midrule
ML-KEM-512 & 2,592,854 & 198,778 & 52,995 & 48.95× & 0 \\
ML-KEM-768 & 4,064,254 & 293,717 & 80,643 & 50.41× & 0 \\
ML-KEM-1024 & 6,036,553 & 401,177 & 113,261 & 53.33× & 0 \\
\bottomrule
\end{tabular}
\end{table}
ML-KEM-1024相对于ML-KEM-512的全流程延迟比值约为2.14倍,这主要源于多项式矩阵维度从2增大至4导致的二次增长效应。在ML-KEM的算法流程中,SampleNTT步骤需要生成k×k的矩阵A中的每个多项式,Computational Number Theory Transform步骤需要对k个私钥多项式和k个误差多项式分别执行正向NTT,Matrix Vector Dot Product步骤需要执行k×k次多项式基乘和k次累积加法。随着k从2增至4,矩阵A的生成量从4个多项式增至16个多项式,NTT执行次数从4次增至8次,基乘次数从4次增至16次,各步骤的工作量增长均呈k²或k的比例关系,这是DMA路径延迟从52,995周期增至113,261周期的根源。
ML-KEM顶层RTL功能仿真提供了各操作的逐状态周期分解,可以更精细地分析各算法步骤对总延迟的贡献。以ML-KEM-512为例,密钥生成操作中G哈希采样的平均耗时仅27.0个周期,A矩阵SampleNTT的平均耗时为3,212.7个周期(占总延迟的23.3\%),CBD采样的平均耗时为1,229.0个周期,NTT变换的平均耗时为4,172.0个周期(占总延迟的30.2\%),多项式基乘的平均耗时为2,096.0个周期,密钥编码的平均耗时为2,081.0个周期。从这些数据可以看出,NTT变换和矩阵采样是密钥生成延迟的主要贡献者,合计占总延迟的53.5\%。封装操作中NTT变换的相关步骤(对y和误差向量执行NTT,以及多项式U和V的基乘步骤)合计占总延迟的39.0\%,压缩步骤合计占8.7\%。解封装操作中,压缩参数解码占25.5\%,重加密流水线(复用封装状态序列)占23.9\%,常量时间密文比较占4.6\%。
\subsection{跨时钟域与系统集成验证}
系统跨时钟域验证通过三个层面进行。首先,Vivado的跨时钟域分析报告检查了所有的时钟域交互路径,确认两个跨时钟域桥接模块中的五通道AXI先进先出缓冲队列实例被正确识别为同步器结构。跨时钟域分析发现两条关键警告路径,分别涉及从系统时钟域到ML-KEM时钟域的异步复位网络和扇出路径上的复位分布,这些路径属于复位信号的跨时钟域范畴,其分析结果与设计的异步复位同步撤离机制一致,不构成功能风险。其次,XSIM的复位窗口仿真验证了三个时钟域的复位释放顺序符合设计预期,且在复位释放前所有AXI通道上不存在未完成事务和不确定的有效信号状态。最后,板级系统长时间运行测试验证了跨时钟域桥接模块在实际电气环境中的可靠性。
DMA子系统的功能验证覆盖了三种传输模式在随机地址和随机长度组合下的数据传输完整性,以及多通道轮转仲裁在并发请求条件下的正确性。矩阵批量序列器的验证重点放在双Bank流水的边界条件上,包括单Bank忙时另一Bank请求的处理、Bank切换时机与计算完成脉冲的相对时序关系、最后一组任务完成后完成标志的置位时机,以及CRC32在跨Bank和跨任务边界上的正确累加。
% ===========================================================================
% 6. DISCUSSION
% ===========================================================================
\section{设计讨论与展望}
\subsection{设计局限与约束}
本设计在特定的赛题约束和开发周期内做出了若干设计折中,这些折中在特定场景下构成了系统的性能瓶颈或功能局限。
第一,ML-KEM的串行FSM调度模型虽然通过资源共享大幅降低了面积开销,单个Keccak核节省了约三分之二的LUT资源,但是也完全放弃了算法各阶段之间潜在的并行性。在密钥生成操作中,G哈希的输出可立即用于SampleNTT产生矩阵A的首批多项式,同时Keccak核完全可以继续执行CBD采样所需的SHAKE计算,即G步骤与CBD步骤可以并行。在封装操作中,对消息m的哈希与矩阵A的SampleNTT也不存在数据依赖。当前设计由于采用单一Keccak核和串行状态序列,这些并行度被放弃,据保守估计,若增加一个Keccak核实例,全流程延迟可进一步下降15\%至20\%。
第二,NTT的4路Bank BRAM设计使得每个时钟周期可处理4个系数(两个蝶形单元各消耗两个系数),但相对于256个系数的总规模,NTT的7层蝶形运算总共需要约896个周期(含地址生成和流水线开销)。国际上最新的ML-KEM硬件实现已将NTT的每周期系数吞吐率提升至8个系数每周期甚至更高,这是未来优化的重要方向。
第三,系统的DMA子系统采用单一AXI主设备接口和共享底层传输引擎的四通道轮转仲裁方案。虽然四个逻辑通道可以独立排队任务,但在任意时刻仅有一个通道可以占用AXI总线进行数据传输。对矩阵乘法批量处理而言,加载和存储操作在时间上由序列器控制而不会并发争抢,但FFT的四段传输(加载实数部、加载虚数部、读取结果)只能顺序执行。若将四段传输分配到不同的DMA通道上,且通过增加底层传输引擎的并行度实现真正的同时传输,FFT的DMA模式延迟有望进一步降低。
第四,所有加速器内部均未部署AXI总线超时检测和事务错误恢复机制。DMA子系统在目标地址无效或从设备无响应时将无限等待,这在受控的测试环境中不构成问题,但在更广泛的应用场景中需要增加事务超时计数器和故障中断机制以确保系统的鲁棒性。
\subsection{安全设计考量}
ML-KEM作为后量子密码系统,其硬件实现的安全性不仅取决于算法逻辑的正确性,还取决于对物理侧信道攻击的抵抗能力。本设计在解封装流程中实现了常量时间密文比较策略,重加密产生的参考密文与输入密文的逐字节比对过程不进行提前退出,无论密文在哪一个字节位置开始不匹配,比较循环都完整执行到密文长度终点。这一设计杜绝了基于比较时间的时序侧信道攻击,是FIPS 203标准对安全实现的明确要求。
在功耗侧信道防护方面,当前设计尚未部署差分功耗分析防护措施,如掩码技术或随机化执行顺序。Keccak-f[1600]置换的数百万次逻辑门翻转具有与处理数据相关的功耗特征,理论上可被高精度功耗采集设备利用以恢复密钥信息。此外,NTT蝶形单元中的Barrett模约简包含与操作数相关的条件减法路径(当中间结果大于等于模数q时执行减法,否则跳过),这一条件分支在功耗轨迹上可能产生可辨识的特征。上述侧信道问题需要后续工作引入适当的防护手段。
ML-KEM的三级安全参数通过相同的硬件数据通路支持,面积开销集中由参数K的最大值K=4决定。在ML-KEM-512模式下运行时,矩阵A的256个系数中仅前4个多项式(2×2)包含有效数据,其余12个多项式存储空间的采样操作虽然生成数据但不参与后续的矩阵向量点积运算,这构成了面积利用效率的浪费。然而,统一的硬件支持三级参数使得本系统在应用场景灵活性上具有优势,可在通信双方协商阶段根据安全需求动态切换安全等级。
\subsection{未来优化方向}
基于当前设计的分析结果,提出三个优先优化方向。第一个方向是增加ML-KEM的运算并行度,将单一Keccak核扩展为双核或三核,并相应调整顶层FSM以支持哈希、采样和NTT在非冲突状态上的并发执行。该方案以约5,000个LUT的面积增量为代价,预期可使全流程延迟降低20\%至35\%。第二个方向是引入AXI4-Stream高速流接口作为ML-KEM的额外数据通路,在AXI存储映射的批量窗口之外提供低延迟的流式数据接口,使ML-KEM能够以更低的软件干预开销融入更大的系统级数据流水线。第三个方向是评估将一部分调度逻辑(特别是矩阵批量序列器和DMA仲裁)软件化的可行性,在应用层灵活性和硬件调度确定性之间探索更优的分工平衡点。
% ===========================================================================
% 7. CONCLUSION
% ===========================================================================
\section{结论}
本文详细阐述了一个基于OpenLA500处理器和Xilinx Artix-7 FPGA平台的异构计算SoC系统的设计、实现与验证全过程。系统成功集成了矩阵乘法加速器、FFT加速器和全参数可配置的ML-KEM后量子密码IP,通过通用DMA子系统和矩阵批量序列器实现了计算加速器的高效协同,并通过外部SRAM控制器的连续突发流水化提高了共享存储器的数据供给能力。系统的功能正确性在四个验证层级上均得到了充分确认:矩阵乘法批量处理以\MatmulFinalMs{} ms完成5000组官方评测,CRC32与期望值一致并获得\MatmulFinalScore{};ML-KEM加速器在三种安全等级、三种操作和三种数据传输路径上均以100\%通过率完成了总计900次的系统级诊断测试;FFT加速器在DMA批量模式下实现了827.80倍的软件加速比,计算精度满足预定误差要求。上述板级测试同时对优化后SRAM控制器的BaseRAM取指、ExtRAM长突发访问和Bank选择形成了系统级覆盖。
系统的FPGA物理实现在xc7a200tfbg676-1器件上完整通过布局布线,资源利用率为LUT 41.16\%、寄存器11.58\%、块存储器8.08\%、DSP 0\%。三个异步时钟域在76.923 MHz、50 MHz和33.333 MHz的目标频率下均建立保持时间收敛,最差负裕量为0.070 ns,零时序违例。总片上功耗为0.779 W,其中ML-KEM加速器为主要动态功耗来源。系统代码通过了HDL静态检查,综合后DSP资源为零的约束得到满足,跨时钟域报告中的警告项经过分析后确认不构成功能风险。
本工作验证了在中等规模FPGA器件上集成后量子密码与数字信号处理多类计算加速器的可行性,为嵌入式后量子密码SoC的设计与实现提供了一个覆盖功能验证、时序收敛、功耗评估和性能分析的完整工程案例。
\vspace{1em}
\noindent\textbf{关键词:}后量子密码;ML-KEM;矩阵乘法加速器;SoC设计;FPGA;跨时钟域设计
% ===========================================================================
% REFERENCES
% ===========================================================================
\begin{thebibliography}{15}
\bibitem{fips203}
National Institute of Standards and Technology,
\textit{Module-Lattice-Based Key-Encapsulation Mechanism Standard},
Federal Information Processing Standards Publication FIPS 203,
2024.
\bibitem{avanza2021}
R. Avanzi, J. Bos, L. Ducas, E. Kiltz, T. Lepoint, V. Lyubashevsky, J.\,M. Schanck, P. Schwabe, G. Seiler, and D. Stehlé,
\textit{CRYSTALS-Kyber Algorithm Specifications and Supporting Documentation},
NIST PQC Standardization Process, Round 3, 2021.
\bibitem{keccak}
G. Bertoni, J. Daemen, M. Peeters, and G. Van Assche,
\textit{The Keccak Reference}, Version 3.0,
2011.
\bibitem{ntt_he2008}
S. He and M. Torkelson,
\textit{Designing Pipeline FFT Processor for OFDM (de)Modulation},
in URSI International Symposium on Signals, Systems, and Electronics, 1998.
\bibitem{sdf_cortes2019}
A. Cortés, I. Vélez, and J.\,F. Sevillano,
\textit{Radix-2² FFT Implementation Based on a Novel SDF Architecture},
IEEE Transactions on Circuits and Systems I, vol. 66, no. 10, 2019.
\bibitem{barrett1986}
P. Barrett,
\textit{Implementing the Rivest Shamir and Adleman Public Key Encryption Algorithm on a Standard Digital Signal Processor},
in Advances in Cryptology — CRYPTO '86, 1987.
\bibitem{openla500}
Loongson Technology,
\textit{OpenLA500 Processor Reference Manual},
2024.
\bibitem{axi_spec}
ARM Ltd.,
\textit{AMBA AXI and ACE Protocol Specification}, Issue H,
2017.
\bibitem{xilinx_ug}
Xilinx Inc.,
\textit{Vivado Design Suite User Guide: Implementation}, UG904,
2019.
\bibitem{cummings2008}
C.\,E. Cummings,
\textit{Clock Domain Crossing (CDC) Design \& Verification Techniques Using SystemVerilog},
SNUG Boston, 2008.
\bibitem{dang2021}
V.\,B. Dang, F. Farahmand, M. Andrzejczak, and K. Gaj,
\textit{Implementing and Benchmarking Post-Quantum Cryptography in Hardware},
IEEE Access, vol. 9, 2021.
\bibitem{xing2023}
Y. Xing and S. Li,
\textit{HAETAE: Shorter Lattice-Based Fiat-Shamir Signatures},
Cryptology ePrint Archive, Report 2023/624, 2023.
\bibitem{ieee_crc}
Institute of Electrical and Electronics Engineers,
\textit{IEEE Standard for Information Technology — Telecommunications and Information Exchange Between Systems}, IEEE 802.3, 2018.
\end{thebibliography}
\end{document}

570
doc/总线模块说明.md Normal file
View File

@@ -0,0 +1,570 @@
# AXI 总线模块说明
本文档基于 `full` 分支的 `rtl/soc_top.v`、各 AXI 外设源码和软件头文件整理,用于说明当前 SoC 中 AXI 总线上的模块作用、端口含义和寄存器地址。
## 1. 总体连接关系
顶层 AXI 互连为 `AxiCrossbar_2x8`。它有 2 个 AXI master 输入和 8 个 AXI slave 输出。
### 1.1 AXI master 输入
| Crossbar 端口 | 顶层连接 | 作用 |
| --- | --- | --- |
| `axiIn_0_*` | `core_top` 经 `Axi_CDC` 后的 `cpu_sync_*` | CPU 访问内存、外设和加速器 |
| `axiIn_1_*` | `snix_axil_cdma_mux` 的 `dma_m_*` / `mm2mm_*` | DMA/CDMA 作为 AXI master 发起内存和外设数据搬运 |
### 1.2 AXI slave 输出和地址窗口
| Crossbar 端口 | 物理地址窗口 | 常用非缓存虚拟地址窗口 | 顶层连接 | 作用 |
| --- | --- | --- | --- | --- |
| `axiOut_0_*` | `0x1c000000` - `0x1c7fffff` | 软件通常直接使用物理地址 | `axi_wrap_ram_sp_external` | BaseRAM/ExtRAM 存储子系统 |
| `axiOut_1_*` | `0x00000000` - `0x007fffff` | 无 | reserved tie-off | 保留窗口,当前返回空响应 |
| `axiOut_2_*` | `0x1f000000` - `0x1f0fffff` | `0xbf000000` - `0xbf0fffff` | `axi_uart_controller` | UART0 |
| `axiOut_3_*` | `0x1f100000` - `0x1f1fffff` | `0xbf100000` - `0xbf1fffff` | `axi_dvi` | 视频输出 |
| `axiOut_4_*` | `0x1f200000` - `0x1f2fffff` | `0xbf200000` - `0xbf2fffff` | `confreg` | LED、数码管、按键、开关、定时器、中断 |
| `axiOut_5_*` | `0x1f300000` - `0x1f3fffff` | `0xbf300000` - `0xbf3fffff` | `axi_axil_adapter` -> DMA/CDMA | DMA 配置窗口 |
| `axiOut_6_*` | `0x1f400000` - `0x1f4fffff` | `0xbf400000` - `0xbf4fffff` | `fft_mlkem_axi_slave` | FFT、ML-KEM 共享窗口 |
| `axiOut_7_*` | `0x1f500000` - `0x1f5fffff` | `0xbf500000` - `0xbf5fffff` | `matmul_axi_slave` | 矩阵乘法加速器 |
说明:软件中的 `0xbfxxxxxx` 地址是 Loongson/LoongArch 非缓存映射地址;硬件 crossbar 实际译码使用 `0x1fxxxxxx` 等物理地址。
## 2. AXI 信号字典
多个模块使用完全相同的 AXI4 或 AXI-Lite 端口。后续各模块只列出端口前缀,例如 `ram_*`、`uart_*`、`s_axi_*`、`dma_m_*`。这些前缀下的每个信号含义按本节解释。
### 2.1 AXI4 slave 接口信号
适用于 `axi_wrap_ram_sp_external`、`axi_uart_controller`、`axi_dvi`、`confreg`、`fft_mlkem_axi_slave`、`mlkem_axi_slave`、`matmul_axi_slave` 等模块。
| 信号 | 方向,以 slave 模块为准 | 含义 |
| --- | --- | --- |
| `clk` / `aclk` | input | AXI 总线时钟。当前大多数 slave 使用 `sys_clk`。 |
| `resetn` / `aresetn` / `rst_n` | input | 低有效复位,已在顶层同步。 |
| `s_axi_awid` / `axi_awid` | input | 写地址事务 ID,用于响应通道返回对应 ID。 |
| `s_axi_awaddr` / `axi_awaddr` | input | 写地址。模块通常使用低位做内部寄存器偏移。 |
| `s_axi_awlen` / `axi_awlen` | input | 突发长度,表示 beats-1。 |
| `s_axi_awsize` / `axi_awsize` | input | 每个 beat 的字节数编码,`2` 表示 4 字节。 |
| `s_axi_awburst` / `axi_awburst` | input | 突发类型,常用 `INCR`。 |
| `s_axi_awlock` / `axi_awlock` | input | AXI lock 属性,本设计基本不使用。 |
| `s_axi_awcache` / `axi_awcache` | input | cache 属性,本设计通常透传或忽略。 |
| `s_axi_awprot` / `axi_awprot` | input | protection 属性,本设计通常透传或忽略。 |
| `s_axi_awvalid` / `axi_awvalid` | input | 写地址有效。 |
| `s_axi_awready` / `axi_awready` | output | slave 可接收写地址。 |
| `s_axi_wid` | input | 写数据 ID。部分 AXI4 实现保留,很多模块不使用。 |
| `s_axi_wdata` / `axi_wdata` | input | 写数据。 |
| `s_axi_wstrb` / `axi_wstrb` | input | 写字节使能,bit0 对应低 8 位。 |
| `s_axi_wlast` / `axi_wlast` | input | 写突发最后一拍。 |
| `s_axi_wvalid` / `axi_wvalid` | input | 写数据有效。 |
| `s_axi_wready` / `axi_wready` | output | slave 可接收写数据。 |
| `s_axi_bid` / `axi_bid` | output | 写响应 ID。 |
| `s_axi_bresp` / `axi_bresp` | output | 写响应状态,当前外设一般返回 `OKAY=2'b00`。 |
| `s_axi_bvalid` / `axi_bvalid` | output | 写响应有效。 |
| `s_axi_bready` / `axi_bready` | input | master 可接收写响应。 |
| `s_axi_arid` / `axi_arid` | input | 读地址事务 ID。 |
| `s_axi_araddr` / `axi_araddr` | input | 读地址。 |
| `s_axi_arlen` / `axi_arlen` | input | 读突发长度,表示 beats-1。 |
| `s_axi_arsize` / `axi_arsize` | input | 每个读 beat 的字节数编码。 |
| `s_axi_arburst` / `axi_arburst` | input | 读突发类型,常用 `INCR`。 |
| `s_axi_arlock` / `axi_arlock` | input | AXI lock 属性,本设计基本不使用。 |
| `s_axi_arcache` / `axi_arcache` | input | cache 属性,本设计通常透传或忽略。 |
| `s_axi_arprot` / `axi_arprot` | input | protection 属性,本设计通常透传或忽略。 |
| `s_axi_arvalid` / `axi_arvalid` | input | 读地址有效。 |
| `s_axi_arready` / `axi_arready` | output | slave 可接收读地址。 |
| `s_axi_rid` / `axi_rid` | output | 读响应 ID。 |
| `s_axi_rdata` / `axi_rdata` | output | 读数据。 |
| `s_axi_rresp` / `axi_rresp` | output | 读响应状态,当前外设一般返回 `OKAY=2'b00`。 |
| `s_axi_rlast` / `axi_rlast` | output | 读突发最后一拍。 |
| `s_axi_rvalid` / `axi_rvalid` | output | 读数据有效。 |
| `s_axi_rready` / `axi_rready` | input | master 可接收读数据。 |
### 2.2 AXI4 master 接口信号
适用于 `snix_axil_cdma_mux` 的 `mm2mm_*` / 顶层 `dma_m_*`。信号名称与 AXI4 slave 一致,但方向相反:`awaddr/araddr/wdata/wstrb/valid/ready` 等由 DMA master 发起,crossbar/slave 返回 ready、response 和 read data。
| 信号组 | 方向,以 DMA 为准 | 含义 |
| --- | --- | --- |
| `mm2mm_aw*` | output/input | DMA 写地址通道,用于向目标地址发起写事务。 |
| `mm2mm_w*` | output/input | DMA 写数据通道。 |
| `mm2mm_b*` | input/output | DMA 写响应通道。 |
| `mm2mm_ar*` | output/input | DMA 读地址通道,用于从源地址发起读事务。 |
| `mm2mm_r*` | input/output | DMA 读数据通道。 |
| `mm2mm_awqos/arqos` | output | AXI QoS,顶层未使用。 |
| `mm2mm_awuser/wuser/aruser` | output | AXI user sideband,顶层未使用。 |
| `mm2mm_buser/ruser` | input | AXI user sideband,顶层绑常量。 |
### 2.3 AXI-Lite slave 接口信号
适用于 `snix_axil_cdma_mux` 和 `cdma_matmul_bridge` 的配置接口。
| 信号 | 方向,以 AXI-Lite slave 为准 | 含义 |
| --- | --- | --- |
| `s_axil_awaddr` | input | AXI-Lite 写地址。 |
| `s_axil_awvalid` | input | 写地址有效。 |
| `s_axil_awready` | output | slave 可接收写地址。 |
| `s_axil_wdata` | input | 写数据。 |
| `s_axil_wstrb` | input | 写字节使能。 |
| `s_axil_wvalid` | input | 写数据有效。 |
| `s_axil_wready` | output | slave 可接收写数据。 |
| `s_axil_bresp` | output | 写响应状态。 |
| `s_axil_bvalid` | output | 写响应有效。 |
| `s_axil_bready` | input | master 可接收写响应。 |
| `s_axil_araddr` | input | AXI-Lite 读地址。 |
| `s_axil_arvalid` | input | 读地址有效。 |
| `s_axil_arready` | output | slave 可接收读地址。 |
| `s_axil_rdata` | output | 读数据。 |
| `s_axil_rresp` | output | 读响应状态。 |
| `s_axil_rvalid` | output | 读数据有效。 |
| `s_axil_rready` | input | master 可接收读数据。 |
## 3. 各 AXI 模块作用与端口
### 3.1 `AxiCrossbar_2x8`
作用:系统 AXI 主互连。它将 CPU 和 DMA 两个 master 的读写请求按地址译码转发到 8 个 slave,并负责读写响应返回。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | crossbar 工作时钟,顶层连接 `sys_clk`。 |
| `resetn` | input | 低有效复位,顶层连接 `sys_resetn`。 |
| `axiIn_0_*` | input/output | CPU 侧 AXI master 接口,信号含义见 AXI4 字典。 |
| `axiIn_1_*` | input/output | DMA/CDMA 侧 AXI master 接口,信号含义见 AXI4 字典。 |
| `axiOut_0_*` | output/input | RAM AXI slave 接口。 |
| `axiOut_1_*` | output/input | 保留 AXI slave 接口,顶层 tie-off。 |
| `axiOut_2_*` | output/input | UART AXI slave 接口。 |
| `axiOut_3_*` | output/input | DVI AXI slave 接口。 |
| `axiOut_4_*` | output/input | confreg AXI slave 接口。 |
| `axiOut_5_*` | output/input | DMA 配置 AXI slave 接口。 |
| `axiOut_6_*` | output/input | FFT/ML-KEM AXI slave 接口。 |
| `axiOut_7_*` | output/input | matmul AXI slave 接口。 |
### 3.2 `core_top` 与 `Axi_CDC`
作用:`core_top` 是 CPU;`Axi_CDC` 将 CPU 时钟域的 AXI 请求同步到 `sys_clk` 域,再送入 crossbar master 0。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `core_top.aclk` | input | CPU 时钟 `cpu_clk`。 |
| `core_top.aresetn` | input | CPU 低有效复位 `cpu_resetn`。 |
| `core_top.intrpt[7:0]` | input | CPU 中断输入。当前 `{4'd0, mlkem_intr, matmul_intr, dma_finish, confreg_int}`。 |
| `core_top.ar*/r*/aw*/w*/b*` | input/output | CPU AXI master 接口。 |
| `core_top.debug0_*` | output | CPU 写回级调试信号。 |
| `Axi_CDC.axiInClk/axiInRstn` | input | CPU 侧时钟/复位。 |
| `Axi_CDC.axiOutClk/axiOutRstn` | input | crossbar 侧时钟/复位。 |
| `Axi_CDC.axiIn_*` | input/output | CPU 侧 AXI 信号。 |
| `Axi_CDC.axiOut_*` | output/input | `sys_clk` 域 AXI 信号,连接 crossbar master 0。 |
### 3.3 `axi_wrap_ram_sp_external`
作用:SRAM 子系统的 AXI slave 包装器。它把 AXI 读写转换为异步 SRAM 控制信号,并根据内部地址 bit22 选择 BaseRAM 或 ExtRAM。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `aclk` | input | AXI/SRAM 控制器时钟,连接 `sys_clk`。 |
| `aresetn` | input | 低有效复位。 |
| `axi_ar*/axi_r*/axi_aw*/axi_w*/axi_b*` | input/output | RAM 的 AXI4 slave 接口,连接 crossbar `axiOut_0_*`。 |
| `base_ram_data[31:0]` | inout | BaseRAM 双向数据总线。写周期由控制器驱动,读周期为高阻输入。 |
| `base_ram_addr[19:0]` | output | BaseRAM 字地址,来自 `soc_sram_addr[21:2]`。 |
| `base_ram_be_n[3:0]` | output | BaseRAM 字节使能,低有效。 |
| `base_ram_ce_n` | output | BaseRAM 片选,低有效。 |
| `base_ram_oe_n` | output | BaseRAM 读使能,低有效。 |
| `base_ram_we_n` | output | BaseRAM 写使能,低有效。 |
| `ext_ram_data[31:0]` | inout | ExtRAM 双向数据总线。 |
| `ext_ram_addr[19:0]` | output | ExtRAM 字地址,来自 `soc_sram_addr[21:2]`。 |
| `ext_ram_be_n[3:0]` | output | ExtRAM 字节使能,低有效。 |
| `ext_ram_ce_n` | output | ExtRAM 片选,低有效。 |
| `ext_ram_oe_n` | output | ExtRAM 读使能,低有效。 |
| `ext_ram_we_n` | output | ExtRAM 写使能,低有效。 |
地址说明:`0x1c000000` - `0x1c3fffff` 选择 BaseRAM,`0x1c400000` - `0x1c7fffff` 选择 ExtRAM。
### 3.4 reserved window
作用:`axiOut_1_*` 是保留窗口,顶层没有接实际模块。读数据返回 0,写请求直接 ready/空响应。该窗口不建议软件使用。
### 3.5 `axi_uart_controller`
作用:AXI 到 APB/UART 控制器。CPU 通过 AXI 访问 16550 风格 UART 寄存器,实现串口收发和中断。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | UART AXI/APB 时钟,连接 `sys_clk`。 |
| `rst_n` | input | 低有效复位。 |
| `axi_s_*` | input/output | UART 的 AXI4 slave 接口,连接 crossbar `axiOut_2_*`。 |
| `apb_rw_dma` | input | DMA APB 访问方向,顶层绑 0,当前未使用。 |
| `apb_psel_dma` | input | DMA APB 片选,顶层绑 0。 |
| `apb_enab_dma` | input | DMA APB enable,顶层绑 0。 |
| `apb_addr_dma[19:0]` | input | DMA APB 地址,顶层绑 0。 |
| `apb_valid_dma` | input | DMA APB 请求有效,顶层绑 0。 |
| `apb_wdata_dma[31:0]` | input | DMA APB 写数据,顶层绑 0。 |
| `apb_rdata_dma[31:0]` | output | DMA APB 读数据,顶层未使用。 |
| `apb_ready_dma` | output | DMA APB ready,顶层未使用。 |
| `dma_grant` | output | APB mux 对 DMA 的授权,顶层未使用。 |
| `dma_req_o` | output | UART 控制器内部 DMA 请求,顶层未使用。 |
| `dma_ack_i` | input | DMA ack,顶层绑 0。 |
| `uart0_txd_i` | input | UART TX 管脚回读输入。 |
| `uart0_txd_o` | output | UART TX 输出值。 |
| `uart0_txd_oe` | output | UART TX 输出使能;顶层用它控制三态。 |
| `uart0_rxd_i` | input | UART RX 输入值。 |
| `uart0_rxd_o` | output | UART RX 输出值,三态模式下使用。 |
| `uart0_rxd_oe` | output | UART RX 输出使能。 |
| `uart0_rts_o` | output | UART RTS 调制解调控制输出。 |
| `uart0_dtr_o` | output | UART DTR 调制解调控制输出。 |
| `uart0_cts_i` | input | UART CTS 输入。 |
| `uart0_dsr_i` | input | UART DSR 输入。 |
| `uart0_dcd_i` | input | UART DCD 输入。 |
| `uart0_ri_i` | input | UART RI 输入。 |
| `uart0_int` | output | UART0 中断,送入 confreg 中断控制。 |
### 3.6 `axi_dvi`
作用:AXI 可配置的视频输出控制器。软件写入矩形/方形参数,模块产生 VGA/DVI 时序和 RGB 输出。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `aclk` | input | DVI 控制器和像素时钟来源。 |
| `aresetn` | input | 低有效复位。 |
| `s_aw*/s_w*/s_b*/s_ar*/s_r*` | input/output | DVI 的 AXI4 slave 接口,连接 crossbar `axiOut_3_*`。 |
| `video_clk` | output | 视频像素时钟输出。 |
| `hsync` | output | 行同步信号。 |
| `vsync` | output | 场同步信号。 |
| `data_enable` | output | 有效显示区域指示。 |
| `video_red[2:0]` | output | 红色像素分量。 |
| `video_green[2:0]` | output | 绿色像素分量。 |
| `video_blue[1:0]` | output | 蓝色像素分量。 |
### 3.7 `confreg`
作用:基础外设和中断控制寄存器模块。它负责 LED、数码管、拨码开关、触摸按键、系统定时器、中断状态聚合和仿真标志。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `aclk` | input | AXI 外设时钟,连接 `sys_clk`。 |
| `aresetn` | input | 低有效 AXI 复位。 |
| `cpu_clk` | input | CPU 时钟,当前传入但主要逻辑在 `aclk` 域。 |
| `cpu_resetn` | input | CPU 低有效复位。 |
| `s_aw*/s_w*/s_b*/s_ar*/s_r*` | input/output | confreg 的 AXI4 slave 接口,连接 crossbar `axiOut_4_*`。 |
| `led[15:0]` | output | 16 位 LED 输出。 |
| `dpy0[7:0]` | output | 低位数码管输出。 |
| `dpy1[7:0]` | output | 高位数码管输出。 |
| `switch[31:0]` | input | 32 位拨码开关输入。 |
| `touch_btn[3:0]` | input | 4 位触摸按键输入。 |
| `uart0_int` | input | UART 中断输入,映射到 confreg 中断源 bit5。 |
| `fft_finish` | input | FFT 完成输入,映射到 confreg 中断源 bit6。 |
| `confreg_int` | output | confreg 聚合后的中断输出,送入 CPU `intrpt[0]`。 |
### 3.8 `axi_axil_adapter`
作用:把 crossbar `axiOut_5_*` 的 AXI4 slave 访问转换为 AXI-Lite 访问,供 DMA/CDMA 配置寄存器使用。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | adapter 时钟,连接 `sys_clk`。 |
| `rst` | input | 高有效复位,顶层连接 `~sys_resetn`。 |
| `s_axi_*` | input/output | AXI4 slave 侧,连接 crossbar `axiOut_5_*`。 |
| `m_axil_*` | output/input | AXI-Lite master 侧,连接 DMA 配置分流逻辑。 |
### 3.9 `snix_axil_cdma_mux`
作用:多通道 CDMA 控制器。它有 AXI-Lite 配置接口、AXI4 `mm2mm` master 数据搬运接口,以及本地 endpoint 接口。当前顶层参数 `PORTS=4`,即 4 个软件可见 DMA 通道。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | CDMA 时钟,连接 `sys_clk`。 |
| `rst_n` | input | 低有效复位。 |
| `s_axil_*` | input/output | AXI-Lite 配置 slave 接口,来自 `axi_axil_adapter` 且未命中 bridge 子窗口时进入本模块。 |
| `mm2mm_aw* / mm2mm_w* / mm2mm_b* / mm2mm_ar* / mm2mm_r*` | output/input | AXI4 master 数据搬运接口,连接 crossbar `axiIn_1_*`。 |
| `ep_wr_valid` | output | 向本地 endpoint 写数据请求有效。当前连接 matmul。 |
| `ep_wr_id[3:0]` | output | endpoint 编号。当前 matmul 使用 id 0。 |
| `ep_wr_bank[3:0]` | output | endpoint bank 选择。当前 matmul 使用 bank0/bank1。 |
| `ep_wr_word_addr[7:0]` | output | endpoint 内部 word 地址。 |
| `ep_wr_data[31:0]` | output | 写入 endpoint 的 32 位数据。 |
| `ep_wr_ready` | input | endpoint 可接收写数据。 |
| `ep_rd_valid` | output | 从 endpoint 读数据请求有效。 |
| `ep_rd_id[3:0]` | output | endpoint 编号。 |
| `ep_rd_bank[3:0]` | output | endpoint bank 选择。 |
| `ep_rd_word_addr[7:0]` | output | endpoint 内部 word 地址。 |
| `ep_rd_data[31:0]` | input | endpoint 返回的 32 位数据。 |
| `ep_rd_ready` | input | endpoint 读数据有效/可被采样。 |
| `ext_rd_req_valid` | input | 外部序列器请求“内存到 endpoint”搬运。当前来自 `cdma_matmul_bridge`。 |
| `ext_rd_req_ready` | output | CDMA 可接收外部读请求。 |
| `ext_rd_req_src[31:0]` | input | 外部读请求的内存源地址。 |
| `ext_rd_req_bytes[31:0]` | input | 外部读请求字节数。 |
| `ext_rd_req_ep_id[3:0]` | input | 外部读请求目标 endpoint id。 |
| `ext_rd_req_ep_bank[3:0]` | input | 外部读请求目标 endpoint bank。 |
| `ext_rd_req_ep_word_off[7:0]` | input | 外部读请求目标 endpoint word 偏移。 |
| `ext_rd_req_done` | output | 外部读请求完成脉冲/标志。 |
| `ext_wr_req_valid` | input | 外部序列器请求“endpoint 到内存”搬运。 |
| `ext_wr_req_ready` | output | CDMA 可接收外部写请求。 |
| `ext_wr_req_dst[31:0]` | input | 外部写请求的内存目的地址。 |
| `ext_wr_req_bytes[31:0]` | input | 外部写请求字节数。 |
| `ext_wr_req_ep_id[3:0]` | input | 外部写请求源 endpoint id。 |
| `ext_wr_req_ep_bank[3:0]` | input | 外部写请求源 endpoint bank。 |
| `ext_wr_req_ep_word_off[7:0]` | input | 外部写请求源 endpoint word 偏移。 |
| `ext_wr_req_done` | output | 外部写请求完成脉冲/标志。 |
| `dma_finish` | output | DMA 完成中断/状态输出,送入顶层 `dma_finish` 合并逻辑。 |
### 3.10 `cdma_matmul_bridge`
作用:matmul 专用 CDMA 序列控制器。CPU 配置输入基地址、输出基地址、组数和 stride 后,它自动向 `snix_axil_cdma_mux` 发起 endpoint 读写请求,并直接控制 matmul 启动、清状态、清 CRC。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | bridge 时钟,连接 `sys_clk`。 |
| `rst_n` | input | 低有效复位。 |
| `s_axil_*` | input/output | AXI-Lite 配置 slave 接口。当 DMA 配置地址 `[11:8] == 4'h2` 时访问本模块。 |
| `cdma_rd_req_valid` | output | 请求 CDMA 从内存读取数据到 matmul endpoint。 |
| `cdma_rd_req_ready` | input | CDMA 可接收读请求。 |
| `cdma_rd_req_src[31:0]` | output | 读请求内存源地址。 |
| `cdma_rd_req_bytes[31:0]` | output | 读请求字节数,matmul 输入固定为 128B。 |
| `cdma_rd_req_ep_id[3:0]` | output | 读请求目标 endpoint id。 |
| `cdma_rd_req_ep_bank[3:0]` | output | 读请求目标 matmul bank。 |
| `cdma_rd_req_ep_word_off[7:0]` | output | 读请求目标 endpoint word 偏移。 |
| `cdma_rd_req_done` | input | CDMA 读请求完成。 |
| `cdma_wr_req_valid` | output | 请求 CDMA 从 matmul endpoint 写回内存。 |
| `cdma_wr_req_ready` | input | CDMA 可接收写请求。 |
| `cdma_wr_req_dst[31:0]` | output | 写请求内存目的地址。 |
| `cdma_wr_req_bytes[31:0]` | output | 写请求字节数,matmul 输出固定为 192B。 |
| `cdma_wr_req_ep_id[3:0]` | output | 写请求源 endpoint id。 |
| `cdma_wr_req_ep_bank[3:0]` | output | 写请求源 matmul bank。 |
| `cdma_wr_req_ep_word_off[7:0]` | output | 写请求源 endpoint word 偏移。 |
| `cdma_wr_req_done` | input | CDMA 写请求完成。 |
| `mat_start_valid` | output | 启动 matmul 计算的有效脉冲。 |
| `mat_start_bank` | output | 启动哪个 matmul bank。 |
| `mat_done_clear` | output | 清除 matmul done/error 状态。 |
| `mat_crc_clear` | output | 清除 matmul CRC 累积值。 |
| `mat_done` | input | matmul 计算完成状态。 |
| `seq_done_irq` | output | 整个 matmul 序列完成中断,顶层与 `cdma_dma_finish` OR 成 `dma_finish`。 |
### 3.11 `fft_mlkem_axi_slave`
作用:共享 AXI slave 地址窗口,按地址低 16 位的 `[15:12]` 将请求分发到 ML-KEM 或 FFT。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | AXI 时钟,连接 `sys_clk`。 |
| `resetn` | input | 低有效复位。 |
| `s_axi_*` | input/output | 共享加速器 AXI4 slave 接口,连接 crossbar `axiOut_6_*`。 |
| `fft_finish` | output | FFT 完成状态,送入 confreg。 |
| `mlkem_intr` | output | ML-KEM 完成中断,直接送入 CPU `intrpt[3]`。 |
内部地址分发:
| 偏移范围 | 子模块 |
| --- | --- |
| `0x0000` - `0x3fff` | `mlkem_axi_slave` |
| `0x8000` - `0xcfff` | `fft_controller` / FFT |
### 3.12 `mlkem_axi_slave`
作用:ML-KEM 加速器 AXI4 slave 包装器,提供 KeyGen、Encaps、Decaps 的配置、输入预加载、输出读回和中断。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | AXI 总线时钟。内部再产生 `mlkem_clk = clk/2`。 |
| `resetn` | input | 低有效复位。 |
| `s_axi_*` | input/output | ML-KEM AXI4 slave 接口,由 `fft_mlkem_axi_slave` 分发而来。 |
| `intr` | output | ML-KEM done 锁存后的高电平中断。 |
### 3.13 `fft_controller`
作用:1024 点 16-bit FFT 加速器。通过 AXI 写入输入实部/虚部 BRAM,写 CSR 启动计算,完成后从输出实部/虚部窗口读取结果。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `aclk` | input | FFT/AXI 时钟。 |
| `aresetn` | input | 低有效复位。 |
| `s_aw*/s_w*/s_b*/s_ar*/s_r*` | input/output | FFT AXI4 slave 接口,由 `fft_mlkem_axi_slave` 分发而来。 |
| `fft_finish` | output | FFT done 状态,来自 CSR status bit1。 |
### 3.14 `matmul_axi_slave`
作用:矩阵乘法加速器 AXI slave。它既支持 CPU 通过 AXI 访问控制寄存器和 bank 数据,也支持 CDMA 通过本地 endpoint 写入输入、读出结果。模块内部带 CRC32 累积逻辑。
端口说明:
| 端口 | 方向 | 解释 |
| --- | --- | --- |
| `clk` | input | matmul/AXI 时钟,连接 `sys_clk`。 |
| `resetn` | input | 低有效复位。 |
| `s_axi_*` | input/output | matmul AXI4 slave 接口,连接 crossbar `axiOut_7_*`。 |
| `ep_wr_valid` | input | CDMA 本地 endpoint 写请求有效。 |
| `ep_wr_id[3:0]` | input | endpoint id。当前仅使用 id 0。 |
| `ep_wr_bank[3:0]` | input | 写入 bank 选择,bit0 选择 bank0/bank1。 |
| `ep_wr_word_addr[7:0]` | input | 写入 bank 内 word 地址,0-15 为 A,16-31 为 B。 |
| `ep_wr_data[31:0]` | input | 写入 A/B 矩阵的 32 位数据。 |
| `ep_wr_ready` | output | matmul endpoint 可接收写数据。当前恒为 1。 |
| `ep_rd_valid` | input | CDMA 本地 endpoint 读请求有效。 |
| `ep_rd_id[3:0]` | input | endpoint id。 |
| `ep_rd_bank[3:0]` | input | 读取 bank 选择。 |
| `ep_rd_word_addr[7:0]` | input | 读取结果 C 的 word 地址。每个 66-bit 结果拆成 3 个 32-bit word。 |
| `ep_rd_data[31:0]` | output | endpoint 返回的 32 位结果数据。 |
| `ep_rd_ready` | output | endpoint 读数据可用。当前恒为 1。 |
| `mat_start_valid` | input | 来自 bridge 的启动脉冲。 |
| `mat_start_bank` | input | 启动计算的 bank。 |
| `mat_done_clear` | input | 清除 done/error。 |
| `mat_crc_clear` | input | 清除 CRC32 累积值。 |
| `mat_done` | output | 计算完成状态。 |
| `intr` | output | matmul 完成中断,送入 CPU `intrpt[2]`。 |
## 4. 寄存器地址表
以下地址以软件常用非缓存虚拟地址列出;括号中给出对应物理地址基址。
### 4.1 UART0 (`0xbf000000`, physical `0x1f000000`)
16550 风格 8-bit 寄存器,软件常用字节访问。
| 地址 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf000000` | `0x0` | `RBR/THR` 或 `DLL` | R/W | DLAB=0 时读接收缓冲/写发送保持;DLAB=1 时为 divisor low byte。 |
| `0xbf000001` | `0x1` | `IER` 或 `DLM` | R/W | DLAB=0 时为中断使能;DLAB=1 时为 divisor high byte。 |
| `0xbf000002` | `0x2` | `IIR/FCR` | R/W | 读为中断识别,写为 FIFO 控制;DLAB=1 时部分实现作为 divisor 扩展。 |
| `0xbf000003` | `0x3` | `LCR` | R/W | 线控制寄存器,bit7 为 DLAB。 |
| `0xbf000004` | `0x4` | `MCR` | R/W | modem 控制。 |
| `0xbf000005` | `0x5` | `LSR` | R | 线状态,软件轮询 bit5/bit6 判断发送 FIFO/发送器空。 |
| `0xbf000006` | `0x6` | `MSR` | R | modem 状态。 |
| `0xbf000007` | `0x7` | `SCR` | R/W | scratch/mode 寄存器。 |
### 4.2 DVI (`0xbf100000`, physical `0x1f100000`)
| 地址 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf100000` | `0x0` | `DVI_RECT_DIR` | R/W | 矩形位置参数,`[31:16]` 为 x,`[15:0]` 为 y。 |
| `0xbf100004` | `0x4` | `DVI_RECT_L_W` | R/W | 矩形尺寸参数,`[31:16]` 为长度/半宽相关参数,`[15:0]` 为宽度/高度相关参数。 |
| `0xbf100008` | `0x8` | `DVI_SQU_DIR` | R/W | 方形位置参数。 |
| `0xbf10000c` | `0xc` | `DVI_SQU_R` | R/W | 方形半径/尺寸参数。 |
### 4.3 confreg (`0xbf200000`, physical `0x1f200000`)
| 地址 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf20f000` | `0xf000` | `CONFREG_INT_EN` | R/W | 中断使能。 |
| `0xbf20f004` | `0xf004` | `CONFREG_INT_EDGE` | R/W | 中断边沿/电平模式配置。 |
| `0xbf20f008` | `0xf008` | `CONFREG_INT_POL` | R/W | 中断极性配置。 |
| `0xbf20f00c` | `0xf00c` | `CONFREG_INT_CLR` | W/R | 写 1 清除对应中断状态。 |
| `0xbf20f010` | `0xf010` | `CONFREG_INT_SET` | W/R | 写 1 软件置位对应中断状态。 |
| `0xbf20f014` | `0xf014` | `CONFREG_INT_STATE` | R | 当前中断状态。bit0-3 touch_btn,bit4 timer,bit5 UART,bit6 FFT。 |
| `0xbf20f100` | `0xf100` | `TIMER_VALUE` | R | 系统计数器当前值。 |
| `0xbf20f104` | `0xf104` | `TIMER_CMP` | R/W | 定时器比较值。 |
| `0xbf20f108` | `0xf108` | `TIMER_EN` | R/W | bit0 使能定时器。 |
| `0xbf20f200` | `0xf200` | `DIGITAL_CTRL` | R/W | 数码管控制寄存器。 |
| `0xbf20f204` | `0xf204` | `DIGITAL_DATA` | R/W | 数码管显示数据。 |
| `0xbf20f300` | `0xf300` | `LED_DATA` | R/W | LED 输出寄存器,低 16 位连接 `leds[15:0]`。 |
| `0xbf20f400` | `0xf400` | `SWITCH_DATA` | R | 32 位拨码开关输入。 |
| `0xbf20f500` | `0xf500` | `SIMU_FLAG` | R | 仿真标志,值为 `{32{SIMULATION}}`。 |
### 4.4 DMA/CDMA (`0xbf300000`, physical `0x1f300000`)
当前 `snix_axil_cdma_mux` 在顶层例化为 `PORTS=4`,通道 `ch=0..3`,每个通道 stride 为 `0x40`。通道寄存器地址为 `0xbf300000 + ch * 0x40 + offset`。
| 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- |
| `0x00` | `SRC_ADDR` | R/W | 源地址。mem2mem/mem2ep 时为内存源地址。 |
| `0x04` | `DST_ADDR` | R/W | 目的地址。mem2mem/ep2mem 时为内存目的地址。 |
| `0x08` | `LENGTH` | R/W | 传输字节数。 |
| `0x0c` | `TAG` | R/W | 软件 tag,硬件不参与数据路径。 |
| `0x10` | `CTRL` | R/W | bit0 写 1 启动;`[5:3]` 为 AXI AxSIZE;`[13:6]` 为 AXI AxLEN。 |
| `0x14` | `STATUS` | R/W | bit0 busy,只读;bit1 done,写 1 清除。 |
| `0x18` | `MODE` | R/W | `0=mem2mem`,`1=mem2ep`,`2=ep2mem`。 |
| `0x1c` | `EP_CFG` | R/W | `[3:0]` bank,`[15:8]` word offset,`[19:16]` endpoint id。 |
通道基址:
| 通道 | 基址 |
| --- | --- |
| channel 0 | `0xbf300000` |
| channel 1 | `0xbf300040` |
| channel 2 | `0xbf300080` |
| channel 3 | `0xbf3000c0` |
matmul 序列控制子窗口由 `cdma_matmul_bridge` 实现,地址为 `0xbf300200 + offset`:
| 地址 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf300200` | `0x200` | `SEQ_CTRL` | R/W | bit0 start;bit1 skip_result_writeback。 |
| `0xbf300204` | `0x204` | `SEQ_STATUS` | R/W | bit0 busy;bit1 done,写 1 清除。 |
| `0xbf300208` | `0x208` | `SEQ_SRC_BASE` | R/W | 输入矩阵组的物理源基址。 |
| `0xbf30020c` | `0x20c` | `SEQ_DST_BASE` | R/W | 输出矩阵组的物理目的基址。 |
| `0xbf300210` | `0x210` | `SEQ_GROUPS` | R/W | 自动处理的矩阵组数。 |
| `0xbf300214` | `0x214` | `SEQ_MAT_BASE` | R/W | 保留兼容字段,软件通常写 `0x1f500000`。 |
| `0xbf300218` | `0x218` | `SEQ_SRC_STRIDE` | R/W | 相邻输入组间隔,默认 128B。 |
| `0xbf30021c` | `0x21c` | `SEQ_DST_STRIDE` | R/W | 相邻输出组间隔,默认 192B。 |
### 4.5 FFT/ML-KEM 共享窗口 (`0xbf400000`, physical `0x1f400000`)
#### 4.5.1 ML-KEM 子窗口
| 地址/范围 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf400000` | `0x000` | `MLKEM_CTRL` | W | bit0 start,启动 CONFIG 指定的操作。 |
| `0xbf400004` | `0x004` | `MLKEM_STATUS` | R/W | bit0 busy,bit1 done,bit2 preload_busy;写 bit1=1 清 done。 |
| `0xbf400008` | `0x008` | `MLKEM_CONFIG` | R/W | `[2:0] k`,`[5:4] op`,op: 0 KeyGen,1 Encaps,2 Decaps。 |
| `0xbf400010` - `0xbf40002c` | `0x010` - `0x02c` | `D[0..7]` | R/W | KeyGen seed d,8 个 32-bit word。 |
| `0xbf400030` - `0xbf40004c` | `0x030` - `0x04c` | `Z[0..7]` | R/W | implicit-reject seed z。 |
| `0xbf400050` - `0xbf40006c` | `0x050` - `0x06c` | `MSG[0..7]` | R/W | Encaps message m。 |
| `0xbf400070` - `0xbf40008c` | `0x070` - `0x08c` | `SS[0..7]` | R | shared secret 输出。 |
| `0xbf400100` | `0x100` | `PRELOAD_SEL` | R/W | 0=ek_in,1=dk_in,2=c_in。 |
| `0xbf400104` | `0x104` | `PRELOAD_ADDR` | R/W | 预加载字节地址,写 `PRELOAD_DATA` 后自动递增。 |
| `0xbf400108` | `0x108` | `PRELOAD_DATA` | W | 写低 8 位,流入所选输入端口。 |
| `0xbf40010c` | `0x10c` | `RDBK_SEL` | R/W | 0=ek,1=dk_pke,2=full-dk,3=ciphertext。 |
| `0xbf400110` | `0x110` | `RDBK_ADDR` | R/W | 读回字节索引。 |
| `0xbf400114` | `0x114` | `RDBK_DATA` | R | 读回低 8 位数据。 |
| `0xbf401000` - `0xbf401fff` | `0x1000` - `0x1fff` | `EK` | W/R | 写为 preload ek_in,读为 generated ek。 |
| `0xbf402000` - `0xbf402fff` | `0x2000` - `0x2fff` | `DK` | W/R | 写为 preload dk_in,读为 generated full dk。 |
| `0xbf403000` - `0xbf403fff` | `0x3000` - `0x3fff` | `CT` | W/R | 写为 preload c_in,读为 generated ciphertext。 |
#### 4.5.2 FFT 子窗口
| 地址/范围 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf408000` - `0xbf408ffc` | `0x8000` - `0x8ffc` | `FFT_IN_RE[0..1023]` | W | 输入实部 BRAM,每项低 16 位有效。 |
| `0xbf409000` - `0xbf409ffc` | `0x9000` - `0x9ffc` | `FFT_IN_IM[0..1023]` | W | 输入虚部 BRAM,每项低 16 位有效。 |
| `0xbf40a000` - `0xbf40affc` | `0xa000` - `0xaffc` | `FFT_OUT_RE[0..1023]` | R | 输出实部,符号扩展到 32 位,读出时使用 bit-reverse 地址。 |
| `0xbf40b000` - `0xbf40bffc` | `0xb000` - `0xbffc` | `FFT_OUT_IM[0..1023]` | R | 输出虚部,符号扩展到 32 位,读出时使用 bit-reverse 地址。 |
| `0xbf40c000` | `0xc000` | `FFT_CSR` | R/W | `[7:4]` 为 ctrl,写 bit4 启动/清 done;`[3:0]` 为 status,bit0 busy,bit1 done。 |
### 4.6 Matmul (`0xbf500000`, physical `0x1f500000`)
| 地址/范围 | 偏移 | 名称 | 访问 | 说明 |
| --- | --- | --- | --- | --- |
| `0xbf500000` | `0x000` | `MAT_CTRL` | R/W | bit0 启动 bank0,bit1 启动 bank1。 |
| `0xbf500004` | `0x004` | `MAT_STATUS` | R/W | bit0 busy,bit1 done,bit2 error;写 bit1 清 done,写 bit2 清 error。 |
| `0xbf500010` | `0x010` | `MAT_CRC` | R/W | 读返回 `crc_reg ^ 0xffffffff`;写该地址或 bridge 的 `mat_crc_clear` 清 CRC。 |
| `0xbf500100` - `0xbf50013c` | `0x100` - `0x13c` | `B0_A[0..15]` | R/W | bank0 输入矩阵 A,16 个 32-bit word。 |
| `0xbf500140` - `0xbf50017c` | `0x140` - `0x17c` | `B0_B[0..15]` | R/W | bank0 输入矩阵 B。 |
| `0xbf500180` - `0xbf50023c` | `0x180` - `0x23c` | `B0_C` | R | bank0 输出矩阵 C,16 个 66-bit 结果,每个结果拆成 3 个 32-bit word,共 192B。 |
| `0xbf500300` - `0xbf50033c` | `0x300` - `0x33c` | `B1_A[0..15]` | R/W | bank1 输入矩阵 A。 |
| `0xbf500340` - `0xbf50037c` | `0x340` - `0x37c` | `B1_B[0..15]` | R/W | bank1 输入矩阵 B。 |
| `0xbf500380` - `0xbf50043c` | `0x380` - `0x43c` | `B1_C` | R | bank1 输出矩阵 C,格式同 bank0。 |
## 5. 关键数据路径说明
1. CPU 访问任意外设或内存:`core_top -> Axi_CDC -> AxiCrossbar_2x8 -> 对应 AXI slave`。
2. DMA 访问 SRAM:`snix_axil_cdma_mux mm2mm master -> AxiCrossbar_2x8 -> axi_wrap_ram_sp_external -> BaseRAM/ExtRAM`。DMA 和 SRAM 没有直接物理连线。
3. DMA 访问 matmul 本地 endpoint:`snix_axil_cdma_mux -> ep_wr/ep_rd -> matmul_axi_slave`。这条是本地 endpoint 通路,不经过 AXI crossbar。
4. matmul 批处理序列:CPU 写 `0xbf300200` 等寄存器配置 `cdma_matmul_bridge`,bridge 自动发起 CDMA 读/写请求并控制 matmul 启停。
5. FFT/ML-KEM 共用 `0xbf400000` 窗口,由 `fft_mlkem_axi_slave` 依据偏移分发。

7
doc/比赛总结.md Normal file
View File

@@ -0,0 +1,7 @@
这次比赛的结果并不理想——拿了省/分区奖,却没能在国赛的名单里看到自己的队伍,还是觉得非常遗憾。而这也可能是我最后一次作为本科生参加这种级别的大赛了,最后没能画上一个圆满的句号。
这一路,陪伴我最多的大概是深夜的屏幕。FFT、DMA、4x4矩阵、MLKEM……一行行 RTL 从指间敲出来,仿真跑到凌晨,上板调试翻车了再从头排查,Vivado 的编译进度条不知道看过多少遍。PPT 之外,文档、代码、报告,几乎全是我一个人在撑。本次比赛仍然没能体现团队协作,说不心酸是假的。但那些一个人 debug 到凌晨三点、代码跑通的瞬间,也只有我一个人懂得那份开心。
还有一件事一直梗在心里:后端报告我给很多人看过,同学、队友,却没有一个人发现里面的时序违例。也许大家都只是匆匆扫一眼,也许根本没人真正在乎细节。如果我早一点自己盯住那条时序路径,结果会不会不一样?可惜没有如果,这条路上真正把它看进眼里的人,始终只有我自己。
如果还有下次,我想挑战单人参赛,solo一场——输赢都自己扛,赢得坦荡,也输得明白。

View File

@@ -227,10 +227,19 @@ set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
create_generated_clock -name cpu_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT0]
create_generated_clock -name sys_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT1]
# create_generated_clock -name cpu_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT0]
# create_generated_clock -name sys_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT1]
set_clock_groups -asynchronous -group [get_clocks cpu_clk] -group [get_clocks sys_clk]
# set_clock_groups -asynchronous -group [get_clocks cpu_clk] -group [get_clocks sys_clk]
create_generated_clock -name cpu_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT0]
create_generated_clock -name sys_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT1]
create_generated_clock -name mlkem_clk [get_pins pll_clk.u_clk_pll/inst/plle2_adv_inst/CLKOUT2]
set_clock_groups -asynchronous \
-group [get_clocks cpu_clk] \
-group [get_clocks sys_clk] \
-group [get_clocks mlkem_clk]
set_input_delay -clock sys_clk -max 3 [get_ports {base_ram_data[*]}]
set_input_delay -clock sys_clk -min 2 [get_ports {base_ram_data[*]}]

View File

@@ -68,6 +68,13 @@ def parse_project(xpr: Path) -> Tuple[str, Set[str], Set[str], Set[str]]:
if not vlog.is_file():
print("Source file", vlog, "does not exist")
continue
# An expanded XCI may add DCP/VHDL/netlist artifacts to the
# project. They are not Verilog lint inputs; use the Verilog
# stub and regular RTL sources only.
if vlog.suffix.lower() not in (".v", ".sv", ".vh", ".svh", ".h"):
continue
if vlog.name.lower().endswith(("_sim_netlist.v", "_sim_netlist.sv")):
continue
vlog_target = target / vlog.relative_to(repo_root)
vlog_target.parent.mkdir(exist_ok=True, parents=True)
# shutil.copy(vlog, vlog_target)
@@ -234,7 +241,7 @@ def run_linter(prjdir: Path, topname: str, headerlist: Set[str], srclist: Set[st
incargs = [ '-I' + i for i in inclist]
args += incargs
args += sorted(headerlist)
args += srclist
args += sorted(srclist)
if os.name == "nt":
response_args = [str(arg).replace("\\", "/") for arg in args[1:]]

View File

@@ -20,7 +20,8 @@
module axi2sram_sp_external #(
parameter AXI_ID_WIDTH = 5,
parameter AXI_ADDR_WIDTH = 32,
parameter AXI_DATA_WIDTH = 32
parameter AXI_DATA_WIDTH = 32,
parameter FAST_READ_BURST = 1
)(
input clk,
input resetn,
@@ -64,6 +65,7 @@ module axi2sram_sp_external #(
output reg req_o,
output reg we_o,
output reg [AXI_ADDR_WIDTH-1:0] addr_o,
output reg bank_o,
output reg [AXI_DATA_WIDTH/8-1:0] be_o,
output reg [AXI_DATA_WIDTH-1:0] data_o,
input [AXI_DATA_WIDTH-1:0] data_i
@@ -100,40 +102,34 @@ module axi2sram_sp_external #(
localparam FIXED = 2'b00;
localparam INCR = 2'b01;
localparam WRAP = 2'b10;
localparam [AXI_ADDR_WIDTH-1:0] ADDR_INCR =
{{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1} << LOG_NR_BYTES;
reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q;
reg [7:0] cnt_d, cnt_q;
reg [8:0] cnt_d, cnt_q;
reg [AXI_ADDR_WIDTH-1:0] wrap_mask_d, wrap_mask_q;
reg req_bank_d, req_bank_q;
reg [AXI_DATA_WIDTH-1:0] read_data_q;
reg read_capture;
function automatic [AXI_ADDR_WIDTH-1:0] get_wrap_boundary;
input [AXI_ADDR_WIDTH-1:0] unaligned_address;
input [7:0] len;
begin
get_wrap_boundary = 'h0;
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15
if (len == 4'b1)
get_wrap_boundary[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES];
else if (len == 4'b11)
get_wrap_boundary[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES];
else if (len == 4'b111)
get_wrap_boundary[AXI_ADDR_WIDTH-1:3+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:2+LOG_NR_BYTES];
else if (len == 4'b1111)
get_wrap_boundary[AXI_ADDR_WIDTH-1:4+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:4+LOG_NR_BYTES];
end
endfunction
wire [AXI_ADDR_WIDTH-1:0] ar_burst_bytes =
({{(AXI_ADDR_WIDTH-8){1'b0}}, s_arlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
wire [AXI_ADDR_WIDTH-1:0] aw_burst_bytes =
({{(AXI_ADDR_WIDTH-8){1'b0}}, s_awlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
wire [AXI_ADDR_WIDTH-1:0] ar_wrap_mask = ar_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
wire [AXI_ADDR_WIDTH-1:0] aw_wrap_mask = aw_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
reg [AXI_ADDR_WIDTH-1:0] aligned_address;
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary;
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
reg [AXI_ADDR_WIDTH-1:0] next_addr;
reg [AXI_ADDR_WIDTH-1:0] seq_addr;
always @ (*) begin
// address generation
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}};
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len);
// this will overflow
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES);
// calculate consecutive address
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES);
seq_addr = req_addr_q + ADDR_INCR;
case (ax_req_q_burst)
FIXED: next_addr = req_addr_q;
INCR: next_addr = seq_addr;
WRAP: next_addr = (req_addr_q & ~wrap_mask_q) | (seq_addr & wrap_mask_q);
default: next_addr = seq_addr;
endcase
// Transaction attributes
// default assignments
@@ -145,12 +141,16 @@ module axi2sram_sp_external #(
ax_req_d_burst = ax_req_q_burst;
req_addr_d = req_addr_q;
cnt_d = cnt_q;
wrap_mask_d = wrap_mask_q;
req_bank_d = req_bank_q;
read_capture = 1'b0;
// Memory default assignments
data_o = s_wdata;
be_o = s_wstrb;
we_o = 1'b0;
req_o = 1'b0;
addr_o = 'h0;
bank_o = req_bank_q;
// AXI assignments
// request
s_awready = 1'b0;
@@ -183,14 +183,17 @@ module axi2sram_sp_external #(
ax_req_d_len = s_arlen;
ax_req_d_size = s_arsize;
ax_req_d_burst = s_arburst;
state_d = READ;
wrap_mask_d = ar_wrap_mask;
req_bank_d = s_araddr[22];
state_d = READ_ADDR;
// we can request the first address, this saves us time
req_o = 1'b1;
addr_o = s_araddr;
bank_o = s_araddr[22];
// save the address
req_addr_d = s_araddr;
// save the ar_len
cnt_d = 1;
cnt_d = 0;
// ------------
// Write
// ------------
@@ -204,6 +207,9 @@ module axi2sram_sp_external #(
ax_req_d_len = s_awlen;
ax_req_d_size = s_awsize;
ax_req_d_burst = s_awburst;
wrap_mask_d = aw_wrap_mask;
req_bank_d = s_awaddr[22];
bank_o = s_awaddr[22];
// we've got our first w_valid so start the write process
if (s_wvalid) begin
req_o = 1'b1;
@@ -230,56 +236,65 @@ module axi2sram_sp_external #(
end
READ: begin
// keep request to memory high
req_o = 1'b1;
addr_o = req_addr_q;
// send the response
s_rvalid = 1'b1;
s_rdata = data_i;
s_rdata = read_data_q;
s_rid = ax_req_q_id;
s_rlast = (cnt_q == ax_req_q_len + 1);
s_rlast = (cnt_q == ({1'b0, ax_req_q_len} + 9'd1));
if (FAST_READ_BURST && !s_rlast) begin
req_o = 1'b1;
addr_o = next_addr;
end
// check that the master is ready, the slave must not wait on this
if (s_rready) begin
// we sent the last byte -> go back to idle
if (s_rlast) begin
state_d = IDLE;
// we already got everything
if (s_arvalid) begin
// Accept the next burst without an intervening
// IDLE cycle and start its SRAM address phase.
s_arready = 1'b1;
ax_req_d_id = s_arid;
ax_req_d_addr = s_araddr;
ax_req_d_len = s_arlen;
ax_req_d_size = s_arsize;
ax_req_d_burst = s_arburst;
wrap_mask_d = ar_wrap_mask;
req_bank_d = s_araddr[22];
req_o = 1'b1;
addr_o = s_araddr;
bank_o = s_araddr[22];
req_addr_d = s_araddr;
// ARVALID was presented during the preceding
// beat, so the async-SRAM address has a full
// cycle to settle before this capture edge.
read_capture = 1'b1;
cnt_d = 1;
state_d = READ;
end else begin
state_d = IDLE;
end
end
else begin
state_d = READ_ADDR;
if (FAST_READ_BURST) begin
read_capture = 1'b1;
req_addr_d = next_addr;
cnt_d = cnt_q + 1;
state_d = READ;
end else begin
req_addr_d = next_addr;
state_d = READ_ADDR;
end
end
end
end
READ_ADDR: begin
// keep request to memory high
// Fill the read data register after the async-SRAM address has
// been stable for one full sys_clk cycle.
req_o = 1'b1;
// send the response
s_rvalid = 1'b0;
// ----------------------------
// Next address generation
// ----------------------------
// handle the correct burst type
case (ax_req_q_burst)
FIXED, INCR: addr_o = cons_addr;
WRAP: begin
// check if the address reached warp boundary
if (cons_addr == upper_wrap_boundary) begin
addr_o = wrap_boundary;
// address warped beyond boundary
end else if (cons_addr > upper_wrap_boundary) begin
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
// we are still in the incremental regime
end else begin
addr_o = cons_addr;
end
end
endcase
// we need to change the address here for the upcoming request
// we can decrease the counter as the master has consumed the read data
addr_o = req_addr_q;
read_capture = 1'b1;
cnt_d = cnt_q + 1;
// save the request address for the next cycle
req_addr_d = addr_o;
state_d = READ;
end
@@ -297,24 +312,9 @@ module axi2sram_sp_external #(
// Next address generation
// ----------------------------
// handle the correct burst type
case (ax_req_q_burst)
FIXED, INCR: addr_o = cons_addr;
WRAP: begin
// check if the address reached warp boundary
if (cons_addr == upper_wrap_boundary) begin
addr_o = wrap_boundary;
// address warped beyond boundary
end else if (cons_addr > upper_wrap_boundary) begin
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
// we are still in the incremental regime
end else begin
addr_o = cons_addr;
end
end
endcase
addr_o = next_addr;
// save the request address for the next cycle
req_addr_d = addr_o;
req_addr_d = next_addr;
// we can decrease the counter as the master has consumed the read data
cnt_d = cnt_q + 1;
@@ -345,7 +345,10 @@ module axi2sram_sp_external #(
ax_req_q_len <= 8'h0;
ax_req_q_size <= 3'h0;
req_addr_q <= 'h0;
cnt_q <= 8'h0;
cnt_q <= 9'h0;
wrap_mask_q <= 'h0;
req_bank_q <= 1'b0;
read_data_q <= 'h0;
end else begin
state_q <= state_d;
ax_req_q_addr <= ax_req_d_addr;
@@ -355,6 +358,10 @@ module axi2sram_sp_external #(
ax_req_q_size <= ax_req_d_size;
req_addr_q <= req_addr_d;
cnt_q <= cnt_d;
wrap_mask_q <= wrap_mask_d;
req_bank_q <= req_bank_d;
if (read_capture)
read_data_q <= data_i;
end
end

View File

@@ -1 +0,0 @@
PLL_*

View File

@@ -35,6 +35,12 @@
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT2.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT2.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT2.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.ASSOCIATED_BUSIF"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.ASSOCIATED_RESET"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.CLK_DOMAIN"/>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.FREQ_HZ">100000000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.INSERT_VIP">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.CLOCK_CLK_OUT3.PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.INTR.PortWidth">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.INTR.SENSITIVITY">LEVEL_HIGH</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="BUSIFPARAM_VALUE.REF_CLK.ASSOCIATED_BUSIF"/>
@@ -98,14 +104,14 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKIN2_JITTER_PS">100.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_1">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_ACTUAL_FREQ">32.97872</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_ACTUAL_FREQ">33.33333</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_1">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_ACTUAL_FREQ">50.00000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DUTY_CYCLE">50.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_OUT_FREQ">32.97872</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_OUT_FREQ">33.33333</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_REQUESTED_OUT_FREQ">33.000</spirit:configurableElementValue>
@@ -113,7 +119,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_1">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_ACTUAL_FREQ">100.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_ACTUAL_FREQ">76.92308</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DUTY_CYCLE">50.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue>
@@ -128,15 +134,15 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_ACTUAL_FREQ">100.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_DUTY_CYCLE">50.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_OUT_FREQ">100.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_OUT_FREQ">76.92308</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_REQUESTED_OUT_FREQ">100.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_USED">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT3_USED">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT4_1">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT4_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT4_ACTUAL_FREQ">100.000</spirit:configurableElementValue>
@@ -190,7 +196,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_IN_SEL_PORT">clk_in_sel</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT1_PORT">cpu_clk</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT2_PORT">sys_clk</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT3_PORT">clk_out3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT3_PORT">mlkem_clk</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT4_PORT">clk_out4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT5_PORT">clk_out5</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLK_OUT6_PORT">clk_out6</spirit:configurableElementValue>
@@ -246,20 +252,20 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCMBUFGCEDIV6">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCMBUFGCEDIV7">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_BANDWIDTH">OPTIMIZED</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKFBOUT_MULT_F">31.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKFBOUT_MULT_F">20.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKFBOUT_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKFBOUT_USE_FINE_PS">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKIN1_PERIOD">20.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKIN1_PERIOD">20.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKIN2_PERIOD">10.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_DIVIDE_F">47.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_DIVIDE_F">30.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_USE_FINE_PS">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DIVIDE">31</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DIVIDE">20</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_USE_FINE_PS">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT2_DIVIDE">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT2_DIVIDE">13</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT2_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT2_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT2_USE_FINE_PS">FALSE</spirit:configurableElementValue>
@@ -289,17 +295,17 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_STARTUP_WAIT">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_M_MAX">64.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_M_MIN">2.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_NUM_OUT_CLKS">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_NUM_OUT_CLKS">3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0A"> Output Output Phase Duty Cycle Pk-to-Pk Phase</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0B"> Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW1">_cpu_clk__32.97872______0.000______50.0______130.093____123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW2">_sys_clk__50.00000______0.000______50.0______122.035____123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW3">no_CLK_OUT3_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW1">_cpu_clk__33.33333______0.000______50.0______215.691____164.985</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW2">_sys_clk__50.00000______0.000______50.0______192.113____164.985</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW3">mlkem_clk__76.92308______0.000______50.0______172.249____164.985</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW4">no_CLK_OUT4_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW5">no_CLK_OUT5_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW6">no_CLK_OUT6_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW7">no_CLK_OUT7_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OVERRIDE_MMCM">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OVERRIDE_MMCM">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OVERRIDE_PLL">0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_O_MAX">128.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_O_MIN">1.000</spirit:configurableElementValue>
@@ -414,32 +420,32 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKIN2_JITTER_PS">100.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKIN2_UI_JITTER">0.010</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_JITTER">130.093</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_JITTER">243.156</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_PHASE_ERROR">123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_PHASE_ERROR">144.334</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_REQUESTED_OUT_FREQ">33.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_USED">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_JITTER">122.035</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_JITTER">222.587</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_PHASE_ERROR">123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_PHASE_ERROR">144.334</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_OUT_FREQ">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_USED">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_JITTER">0.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_JITTER">186.330</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_PHASE_ERROR">0.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_PHASE_ERROR">144.334</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_REQUESTED_OUT_FREQ">100.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_USED">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT3_USED">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT4_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT4_JITTER">0.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT4_MATCHED_ROUTING">false</spirit:configurableElementValue>
@@ -484,7 +490,7 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT1_USE_FINE_PS_GUI">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT2_PORT">sys_clk</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT2_USE_FINE_PS_GUI">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT3_PORT">clk_out3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT3_PORT">mlkem_clk</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT3_USE_FINE_PS_GUI">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT4_PORT">clk_out4</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLK_OUT4_USE_FINE_PS_GUI">false</spirit:configurableElementValue>
@@ -525,20 +531,20 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.JITTER_SEL">No_Jitter</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.LOCKED_PORT">locked</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_BANDWIDTH">OPTIMIZED</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKFBOUT_MULT_F">31</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKFBOUT_MULT_F">20</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKFBOUT_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKFBOUT_USE_FINE_PS">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKIN1_PERIOD">20.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKIN1_PERIOD">20.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKIN2_PERIOD">10.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DIVIDE_F">47</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DIVIDE_F">30</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_USE_FINE_PS">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DIVIDE">31</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DIVIDE">20</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_USE_FINE_PS">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT2_DIVIDE">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT2_DIVIDE">13</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT2_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT2_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT2_USE_FINE_PS">false</spirit:configurableElementValue>
@@ -566,8 +572,8 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_REF_JITTER1">0.010</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_REF_JITTER2">0.010</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_STARTUP_WAIT">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.NUM_OUT_CLKS">2</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.OVERRIDE_MMCM">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.NUM_OUT_CLKS">3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.OVERRIDE_MMCM">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.OVERRIDE_PLL">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PHASESHIFT_MODE">WAVEFORM</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PHASE_DUTY_CONFIG">false</spirit:configurableElementValue>
@@ -705,20 +711,28 @@
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_OUT_FREQ" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT2_USED" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT3_DRIVES" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT3_JITTER" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT3_PHASE_ERROR" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT3_USED" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT4_DRIVES" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT5_DRIVES" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT6_DRIVES" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLKOUT7_DRIVES" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLK_OUT1_PORT" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLK_OUT2_PORT" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.CLK_OUT3_PORT" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.FEEDBACK_SOURCE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_BANDWIDTH" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKFBOUT_MULT_F" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKIN1_PERIOD" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKIN2_PERIOD" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DIVIDE_F" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DIVIDE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_CLKOUT2_DIVIDE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_COMPENSATION" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.MMCM_DIVCLK_DIVIDE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.NUM_OUT_CLKS" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.OVERRIDE_MMCM" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PRIMITIVE" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.PRIM_IN_FREQ" xilinx:valueSource="user"/>
<xilinx:configElementInfo xilinx:referenceId="PARAM_VALUE.RESET_PORT" xilinx:valueSource="user"/>

View File

@@ -0,0 +1,436 @@
// ============================================================================
// cdma_matmul_bridge.sv
// Matmul-specific sequencer between the generic CDMA endpoint requester and
// the matmul local endpoint/control interface.
//
// AXI-Lite register map, relative to this bridge window:
// 0x00 CTRL bit0 start, bit1 skip_result_writeback
// 0x04 STATUS bit0 busy, bit1 done (W1C)
// 0x08 SRC_BASE physical ExtRAM input base
// 0x0C DST_BASE physical ExtRAM result base
// 0x10 GROUPS
// 0x14 MAT_BASE reserved for software compatibility
// 0x18 SRC_STRIDE bytes, default 128
// 0x1C DST_STRIDE bytes, default 192
// ============================================================================
`timescale 1ns / 1ps
module cdma_matmul_bridge #(
parameter int ADDR_WIDTH = 32,
parameter int AXIL_ADDR_WIDTH = 32,
parameter int AXIL_DATA_WIDTH = 32
) (
input logic clk,
input logic rst_n,
input logic [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr,
input logic s_axil_awvalid,
output logic s_axil_awready,
input logic [AXIL_DATA_WIDTH-1:0] s_axil_wdata,
input logic [AXIL_DATA_WIDTH/8-1:0] s_axil_wstrb,
input logic s_axil_wvalid,
output logic s_axil_wready,
output logic [1:0] s_axil_bresp,
output logic s_axil_bvalid,
input logic s_axil_bready,
input logic [AXIL_ADDR_WIDTH-1:0] s_axil_araddr,
input logic s_axil_arvalid,
output logic s_axil_arready,
output logic [AXIL_DATA_WIDTH-1:0] s_axil_rdata,
output logic [1:0] s_axil_rresp,
output logic s_axil_rvalid,
input logic s_axil_rready,
output logic cdma_rd_req_valid,
input logic cdma_rd_req_ready,
output logic [ADDR_WIDTH-1:0] cdma_rd_req_src,
output logic [31:0] cdma_rd_req_bytes,
output logic [3:0] cdma_rd_req_ep_id,
output logic [3:0] cdma_rd_req_ep_bank,
output logic [7:0] cdma_rd_req_ep_word_off,
input logic cdma_rd_req_done,
output logic cdma_wr_req_valid,
input logic cdma_wr_req_ready,
output logic [ADDR_WIDTH-1:0] cdma_wr_req_dst,
output logic [31:0] cdma_wr_req_bytes,
output logic [3:0] cdma_wr_req_ep_id,
output logic [3:0] cdma_wr_req_ep_bank,
output logic [7:0] cdma_wr_req_ep_word_off,
input logic cdma_wr_req_done,
output logic mat_start_valid,
output logic mat_start_bank,
output logic mat_done_clear,
output logic mat_crc_clear,
input logic mat_done,
input logic mat_crc_idle,
output logic seq_done_irq
);
localparam logic [7:0] REG_CTRL = 8'h00;
localparam logic [7:0] REG_STATUS = 8'h04;
localparam logic [7:0] REG_SRC_BASE = 8'h08;
localparam logic [7:0] REG_DST_BASE = 8'h0C;
localparam logic [7:0] REG_GROUPS = 8'h10;
localparam logic [7:0] REG_MAT_BASE = 8'h14;
localparam logic [7:0] REG_SRC_STRIDE = 8'h18;
localparam logic [7:0] REG_DST_STRIDE = 8'h1C;
localparam logic [31:0] MAT_AB_BYTES = 32'd128;
localparam logic [31:0] MAT_C_BYTES = 32'd192;
logic [31:0] seq_src_base;
logic [31:0] seq_dst_base;
logic [31:0] seq_groups;
logic [31:0] seq_mat_base;
logic [31:0] seq_src_stride;
logic [31:0] seq_dst_stride;
logic seq_busy;
logic seq_done_flag;
logic seq_skip_writeback;
logic [31:0] load_next_idx;
logic [31:0] groups_retired;
logic [1:0] bank_load_active;
logic [1:0] bank_ab_valid;
logic [1:0] bank_compute_active;
logic [1:0] bank_store_pending;
logic [1:0] bank_store_active;
logic [31:0] bank_group_idx [2];
logic [31:0] load_next_src_addr;
logic [31:0] load_next_dst_addr;
logic [31:0] bank_dst_addr [2];
logic wr_busy;
logic wr_active_bank;
logic [1:0] rd_outstanding_count;
logic [1:0] rd_bank_fifo;
logic [1:0] compute_q;
logic [1:0] compute_q_count;
logic mat_done_seen;
wire [7:0] wr_off = s_axil_awaddr[7:0];
wire [7:0] rd_off = s_axil_araddr[7:0];
wire do_write;
wire start_req = do_write && (wr_off == REG_CTRL) && s_axil_wstrb[0] && s_axil_wdata[0];
wire done_clear_req = do_write && (wr_off == REG_STATUS) && s_axil_wstrb[0] && s_axil_wdata[1];
wire load_target_bank = load_next_idx[0];
wire load_target_free = !bank_load_active[load_target_bank] &&
!bank_ab_valid[load_target_bank] &&
!bank_compute_active[load_target_bank] &&
!bank_store_pending[load_target_bank] &&
!bank_store_active[load_target_bank];
wire bank0_start_ready = bank_ab_valid[0] && !bank_compute_active[0] &&
!bank_store_pending[0] && !bank_store_active[0];
wire bank1_start_ready = bank_ab_valid[1] && !bank_compute_active[1] &&
!bank_store_pending[1] && !bank_store_active[1];
wire start_sel_bank = bank1_start_ready &&
(!bank0_start_ready || (bank_group_idx[1] < bank_group_idx[0]));
wire start_ready_any = bank0_start_ready || bank1_start_ready;
wire store_sel_bank = bank_store_pending[1] && !bank_store_active[1] &&
!(bank_store_pending[0] && !bank_store_active[0]);
wire store_ready_any = (bank_store_pending[0] && !bank_store_active[0]) ||
(bank_store_pending[1] && !bank_store_active[1]);
wire mat_done_event = mat_done && !mat_done_seen;
wire retire_from_store = seq_busy && cdma_wr_req_done;
wire retire_from_compute = seq_busy && seq_skip_writeback && mat_done_event && (compute_q_count != 2'd0);
wire [31:0] retire_inc = {31'd0, retire_from_store} + {31'd0, retire_from_compute};
wire rd_req_fire = cdma_rd_req_valid && cdma_rd_req_ready;
function automatic logic [31:0] apply_wstrb(
input logic [31:0] old_val,
input logic [31:0] new_val,
input logic [3:0] wstrb
);
begin
apply_wstrb[7:0] = wstrb[0] ? new_val[7:0] : old_val[7:0];
apply_wstrb[15:8] = wstrb[1] ? new_val[15:8] : old_val[15:8];
apply_wstrb[23:16] = wstrb[2] ? new_val[23:16] : old_val[23:16];
apply_wstrb[31:24] = wstrb[3] ? new_val[31:24] : old_val[31:24];
end
endfunction
assign s_axil_bresp = 2'b00;
assign s_axil_rresp = 2'b00;
assign seq_done_irq = seq_done_flag;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_awready <= 1'b0;
s_axil_wready <= 1'b0;
end else begin
if (s_axil_awvalid && s_axil_wvalid && !s_axil_awready && (!s_axil_bvalid || s_axil_bready)) begin
s_axil_awready <= 1'b1;
s_axil_wready <= 1'b1;
end else begin
s_axil_awready <= 1'b0;
s_axil_wready <= 1'b0;
end
end
end
assign do_write = s_axil_awready && s_axil_awvalid && s_axil_wready && s_axil_wvalid;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_bvalid <= 1'b0;
end else if (do_write) begin
s_axil_bvalid <= 1'b1;
end else if (s_axil_bready && s_axil_bvalid) begin
s_axil_bvalid <= 1'b0;
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_arready <= 1'b0;
end else begin
if (s_axil_arvalid && !s_axil_arready && (!s_axil_rvalid || s_axil_rready)) begin
s_axil_arready <= 1'b1;
end else begin
s_axil_arready <= 1'b0;
end
end
end
wire do_read = s_axil_arready && s_axil_arvalid;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_rvalid <= 1'b0;
s_axil_rdata <= '0;
end else if (do_read) begin
s_axil_rvalid <= 1'b1;
case (rd_off)
REG_CTRL: s_axil_rdata <= {30'd0, seq_skip_writeback, 1'b0};
REG_STATUS: s_axil_rdata <= {30'd0, seq_done_flag, seq_busy};
REG_SRC_BASE: s_axil_rdata <= seq_src_base;
REG_DST_BASE: s_axil_rdata <= seq_dst_base;
REG_GROUPS: s_axil_rdata <= seq_groups;
REG_MAT_BASE: s_axil_rdata <= seq_mat_base;
REG_SRC_STRIDE: s_axil_rdata <= seq_src_stride;
REG_DST_STRIDE: s_axil_rdata <= seq_dst_stride;
default: s_axil_rdata <= 32'd0;
endcase
end else if (s_axil_rready && s_axil_rvalid) begin
s_axil_rvalid <= 1'b0;
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_src_base <= 32'h0;
seq_dst_base <= 32'h0;
seq_groups <= 32'h0;
seq_mat_base <= 32'h1f50_0000;
seq_src_stride <= 32'd128;
seq_dst_stride <= 32'd192;
end else if (do_write) begin
case (wr_off)
REG_SRC_BASE: if (!seq_busy) seq_src_base <= apply_wstrb(seq_src_base, s_axil_wdata, s_axil_wstrb);
REG_DST_BASE: if (!seq_busy) seq_dst_base <= apply_wstrb(seq_dst_base, s_axil_wdata, s_axil_wstrb);
REG_GROUPS: if (!seq_busy) seq_groups <= apply_wstrb(seq_groups, s_axil_wdata, s_axil_wstrb);
REG_MAT_BASE: if (!seq_busy) seq_mat_base <= apply_wstrb(seq_mat_base, s_axil_wdata, s_axil_wstrb);
REG_SRC_STRIDE: if (!seq_busy) seq_src_stride <= apply_wstrb(seq_src_stride, s_axil_wdata, s_axil_wstrb);
REG_DST_STRIDE: if (!seq_busy) seq_dst_stride <= apply_wstrb(seq_dst_stride, s_axil_wdata, s_axil_wstrb);
default: begin
end
endcase
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
seq_skip_writeback <= 1'b0;
load_next_idx <= 32'd0;
groups_retired <= 32'd0;
bank_load_active <= 2'b00;
bank_ab_valid <= 2'b00;
bank_compute_active <= 2'b00;
bank_store_pending <= 2'b00;
bank_store_active <= 2'b00;
bank_group_idx[0] <= 32'd0;
bank_group_idx[1] <= 32'd0;
load_next_src_addr <= 32'd0;
load_next_dst_addr <= 32'd0;
bank_dst_addr[0] <= 32'd0;
bank_dst_addr[1] <= 32'd0;
wr_busy <= 1'b0;
wr_active_bank <= 1'b0;
rd_outstanding_count <= 2'd0;
rd_bank_fifo <= 2'b00;
compute_q <= 2'b00;
compute_q_count <= 2'd0;
mat_done_seen <= 1'b0;
cdma_rd_req_valid <= 1'b0;
cdma_rd_req_src <= '0;
cdma_rd_req_bytes <= '0;
cdma_rd_req_ep_id <= 4'd0;
cdma_rd_req_ep_bank <= 4'd0;
cdma_rd_req_ep_word_off <= 8'd0;
cdma_wr_req_valid <= 1'b0;
cdma_wr_req_dst <= '0;
cdma_wr_req_bytes <= '0;
cdma_wr_req_ep_id <= 4'd0;
cdma_wr_req_ep_bank <= 4'd0;
cdma_wr_req_ep_word_off <= 8'd0;
mat_start_valid <= 1'b0;
mat_start_bank <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
end else begin
mat_start_valid <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
mat_done_seen <= mat_done;
if (done_clear_req)
seq_done_flag <= 1'b0;
if (rd_req_fire)
cdma_rd_req_valid <= 1'b0;
if (cdma_wr_req_valid && cdma_wr_req_ready)
cdma_wr_req_valid <= 1'b0;
if (start_req && !seq_busy && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_skip_writeback <= s_axil_wstrb[0] && s_axil_wdata[1];
load_next_idx <= 32'd0;
groups_retired <= 32'd0;
bank_load_active <= 2'b00;
bank_ab_valid <= 2'b00;
bank_compute_active <= 2'b00;
bank_store_pending <= 2'b00;
bank_store_active <= 2'b00;
bank_group_idx[0] <= 32'd0;
bank_group_idx[1] <= 32'd0;
load_next_src_addr <= seq_src_base;
load_next_dst_addr <= seq_dst_base;
bank_dst_addr[0] <= 32'd0;
bank_dst_addr[1] <= 32'd0;
wr_busy <= 1'b0;
rd_outstanding_count <= 2'd0;
rd_bank_fifo <= 2'b00;
compute_q <= 2'b00;
compute_q_count <= 2'd0;
mat_done_seen <= 1'b1;
mat_crc_clear <= 1'b1;
mat_done_clear <= 1'b1;
cdma_rd_req_valid <= 1'b0;
cdma_wr_req_valid <= 1'b0;
end else if (seq_busy) begin
if (retire_inc != 32'd0) begin
groups_retired <= groups_retired + retire_inc;
end
// The final compute completion can precede the recursive CRC
// consumer. Do not expose sequence completion until it drains.
if ((groups_retired >= seq_groups) && mat_crc_idle) begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b1;
end
if (cdma_rd_req_done && (rd_outstanding_count != 2'd0)) begin
bank_load_active[rd_bank_fifo[0]] <= 1'b0;
bank_ab_valid[rd_bank_fifo[0]] <= 1'b1;
end
// Track the active read and one prefetched read. Completion
// pulses are in request order, so a two-entry bank FIFO is
// sufficient to associate each RLAST with its destination.
case ({rd_req_fire, cdma_rd_req_done})
2'b10: begin
if (rd_outstanding_count == 2'd0)
rd_bank_fifo[0] <= cdma_rd_req_ep_bank[0];
else
rd_bank_fifo[1] <= cdma_rd_req_ep_bank[0];
rd_outstanding_count <= rd_outstanding_count + 2'd1;
end
2'b01: begin
if (rd_outstanding_count == 2'd2)
rd_bank_fifo[0] <= rd_bank_fifo[1];
if (rd_outstanding_count != 2'd0)
rd_outstanding_count <= rd_outstanding_count - 2'd1;
end
2'b11: begin
if (rd_outstanding_count == 2'd1) begin
rd_bank_fifo[0] <= cdma_rd_req_ep_bank[0];
end else begin
rd_bank_fifo[0] <= rd_bank_fifo[1];
rd_bank_fifo[1] <= cdma_rd_req_ep_bank[0];
end
end
default: begin
end
endcase
if (cdma_wr_req_done) begin
wr_busy <= 1'b0;
bank_store_active[wr_active_bank] <= 1'b0;
end
if (mat_done_event && (compute_q_count != 2'd0)) begin
mat_done_clear <= 1'b1;
mat_done_seen <= 1'b1;
bank_compute_active[compute_q[0]] <= 1'b0;
if (!seq_skip_writeback) begin
bank_store_pending[compute_q[0]] <= 1'b1;
end
if (compute_q_count == 2'd2)
compute_q[0] <= compute_q[1];
compute_q_count <= compute_q_count - 2'd1;
end
if ((rd_outstanding_count < 2'd2) && !cdma_rd_req_valid &&
(load_next_idx < seq_groups) && load_target_free) begin
cdma_rd_req_src <= load_next_src_addr;
cdma_rd_req_bytes <= MAT_AB_BYTES;
cdma_rd_req_ep_id <= 4'd0;
cdma_rd_req_ep_bank <= {3'b000, load_target_bank};
cdma_rd_req_ep_word_off <= 8'd0;
cdma_rd_req_valid <= 1'b1;
bank_load_active[load_target_bank] <= 1'b1;
bank_group_idx[load_target_bank] <= load_next_idx;
bank_dst_addr[load_target_bank] <= load_next_dst_addr;
load_next_src_addr <= load_next_src_addr + seq_src_stride;
load_next_dst_addr <= load_next_dst_addr + seq_dst_stride;
load_next_idx <= load_next_idx + 32'd1;
end
if (!seq_skip_writeback && !wr_busy && !cdma_wr_req_valid && store_ready_any) begin
cdma_wr_req_dst <= bank_dst_addr[store_sel_bank];
cdma_wr_req_bytes <= MAT_C_BYTES;
cdma_wr_req_ep_id <= 4'd0;
cdma_wr_req_ep_bank <= {3'b000, store_sel_bank};
cdma_wr_req_ep_word_off <= 8'd0;
cdma_wr_req_valid <= 1'b1;
wr_busy <= 1'b1;
wr_active_bank <= store_sel_bank;
bank_store_pending[store_sel_bank] <= 1'b0;
bank_store_active[store_sel_bank] <= 1'b1;
end
if ((compute_q_count < 2'd2) && start_ready_any && !(mat_done_event && (compute_q_count != 2'd0))) begin
mat_start_valid <= 1'b1;
mat_start_bank <= start_sel_bank;
bank_ab_valid[start_sel_bank] <= 1'b0;
bank_compute_active[start_sel_bank] <= 1'b1;
if (compute_q_count == 2'd0)
compute_q[0] <= start_sel_bank;
else
compute_q[1] <= start_sel_bank;
compute_q_count <= compute_q_count + 2'd1;
end
end
end
end
endmodule

View File

@@ -110,6 +110,27 @@ module snix_axil_cdma_mux #(
output logic [7:0] ep_rd_word_addr,
input logic [31:0] ep_rd_data,
input logic ep_rd_ready,
// ==========================================
// Generic external endpoint requester
// ==========================================
input logic ext_rd_req_valid,
output logic ext_rd_req_ready,
input logic [ADDR_WIDTH-1:0] ext_rd_req_src,
input logic [31:0] ext_rd_req_bytes,
input logic [3:0] ext_rd_req_ep_id,
input logic [3:0] ext_rd_req_ep_bank,
input logic [7:0] ext_rd_req_ep_word_off,
output logic ext_rd_req_done,
input logic ext_wr_req_valid,
output logic ext_wr_req_ready,
input logic [ADDR_WIDTH-1:0] ext_wr_req_dst,
input logic [31:0] ext_wr_req_bytes,
input logic [3:0] ext_wr_req_ep_id,
input logic [3:0] ext_wr_req_ep_bank,
input logic [7:0] ext_wr_req_ep_word_off,
output logic ext_wr_req_done,
// Global Interrupt (OR'd from all channels)
output logic dma_finish
@@ -123,30 +144,6 @@ module snix_axil_cdma_mux #(
localparam logic [1:0] MODE_MEM2EP = 2'd1;
localparam logic [1:0] MODE_EP2MEM = 2'd2;
localparam logic [7:0] SEQ_REG_CTRL = 8'h00;
localparam logic [7:0] SEQ_REG_STATUS = 8'h04;
localparam logic [7:0] SEQ_REG_SRC_BASE = 8'h08;
localparam logic [7:0] SEQ_REG_DST_BASE = 8'h0C;
localparam logic [7:0] SEQ_REG_GROUPS = 8'h10;
localparam logic [7:0] SEQ_REG_MAT_BASE = 8'h14;
localparam logic [7:0] SEQ_REG_SRC_STRIDE = 8'h18;
localparam logic [7:0] SEQ_REG_DST_STRIDE = 8'h1C;
localparam logic [11:0] MAT_CTRL_OFF = 12'h000;
localparam logic [11:0] MAT_STATUS_OFF = 12'h004;
localparam logic [11:0] MAT_CRC_OFF = 12'h010;
localparam logic [11:0] MAT_B0_AB_OFF = 12'h100;
localparam logic [11:0] MAT_B0_C_OFF = 12'h180;
localparam logic [11:0] MAT_B1_AB_OFF = 12'h300;
localparam logic [11:0] MAT_B1_C_OFF = 12'h380;
localparam logic [31:0] MAT_STATUS_DONE_CLR = 32'h0000_0006;
localparam logic [31:0] MAT_STATUS_DONE_BIT = 32'h0000_0002;
localparam logic [31:0] MAT_CTRL_START_B0 = 32'h0000_0001;
localparam logic [31:0] MAT_CTRL_START_B1 = 32'h0000_0002;
localparam logic [31:0] MAT_AB_BYTES = 32'd128;
localparam logic [31:0] MAT_C_BYTES = 32'd192;
// Function to safely apply WSTRB to 32-bit registers
function automatic logic [31:0] apply_wstrb(
input logic [31:0] old_val,
@@ -177,17 +174,6 @@ module snix_axil_cdma_mux #(
logic [PORTS-1:0] arb_set_done; // From Arbiter to CSR
logic [31:0] seq_src_base;
logic [31:0] seq_dst_base;
logic [31:0] seq_groups;
logic [31:0] seq_mat_base;
logic [31:0] seq_src_stride;
logic [31:0] seq_dst_stride;
logic seq_busy;
logic seq_done_flag;
wire seq_start_req;
wire seq_done_clear_req;
// ==========================================
// Address Decoding (0x40 offset per channel)
// ==========================================
@@ -195,14 +181,6 @@ module snix_axil_cdma_mux #(
wire [5:0] wr_reg = s_axil_awaddr[5:0];
wire [CH_BITS-1:0] rd_ch = s_axil_araddr[6 +: CH_BITS];
wire [5:0] rd_reg = s_axil_araddr[5:0];
wire wr_seq_reg = (s_axil_awaddr[11:8] == 4'h2);
wire rd_seq_reg = (s_axil_araddr[11:8] == 4'h2);
wire [7:0] wr_seq_off = s_axil_awaddr[7:0];
wire [7:0] rd_seq_off = s_axil_araddr[7:0];
assign seq_start_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_CTRL) &&
s_axil_wstrb[0] && s_axil_wdata[0];
assign seq_done_clear_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_STATUS) &&
s_axil_wstrb[0] && s_axil_wdata[1];
// ==========================================
// AXI-Lite Slave Logic (Robust Backpressure)
@@ -262,19 +240,7 @@ module snix_axil_cdma_mux #(
end else begin
if (do_read) begin
s_axil_rvalid <= 1'b1;
if (rd_seq_reg) begin
case (rd_seq_off)
SEQ_REG_CTRL: s_axil_rdata <= {31'd0, seq_start_req};
SEQ_REG_STATUS: s_axil_rdata <= {30'd0, seq_done_flag, seq_busy};
SEQ_REG_SRC_BASE: s_axil_rdata <= seq_src_base;
SEQ_REG_DST_BASE: s_axil_rdata <= seq_dst_base;
SEQ_REG_GROUPS: s_axil_rdata <= seq_groups;
SEQ_REG_MAT_BASE: s_axil_rdata <= seq_mat_base;
SEQ_REG_SRC_STRIDE: s_axil_rdata <= seq_src_stride;
SEQ_REG_DST_STRIDE: s_axil_rdata <= seq_dst_stride;
default: s_axil_rdata <= 32'd0;
endcase
end else if (rd_ch < PORTS) begin
if (rd_ch < PORTS) begin
case (rd_reg)
6'h00: s_axil_rdata <= ch_src_addr[rd_ch];
6'h04: s_axil_rdata <= ch_dst_addr[rd_ch];
@@ -304,12 +270,6 @@ module snix_axil_cdma_mux #(
if (!rst_n) begin
ch_req <= '0;
ch_done <= '0;
seq_src_base <= 32'h0;
seq_dst_base <= 32'h0;
seq_groups <= 32'h0;
seq_mat_base <= 32'h1f50_0000;
seq_src_stride <= 32'd128;
seq_dst_stride <= 32'd192;
for (int i=0; i<PORTS; i++) begin
ch_src_addr[i] <= '0; ch_dst_addr[i] <= '0;
ch_len[i] <= '0; ch_tag[i] <= '0; ch_ctrl[i] <= '0;
@@ -325,16 +285,7 @@ module snix_axil_cdma_mux #(
end
// 2. Process CPU Writes
if (do_write && wr_seq_reg) begin
case (wr_seq_off)
SEQ_REG_SRC_BASE: if (!seq_busy) seq_src_base <= apply_wstrb(seq_src_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_BASE: if (!seq_busy) seq_dst_base <= apply_wstrb(seq_dst_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_GROUPS: if (!seq_busy) seq_groups <= apply_wstrb(seq_groups, s_axil_wdata, s_axil_wstrb);
SEQ_REG_MAT_BASE: if (!seq_busy) seq_mat_base <= apply_wstrb(seq_mat_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_SRC_STRIDE: if (!seq_busy) seq_src_stride <= apply_wstrb(seq_src_stride, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_STRIDE: if (!seq_busy) seq_dst_stride <= apply_wstrb(seq_dst_stride, s_axil_wdata, s_axil_wstrb);
endcase
end else if (do_write && wr_ch < PORTS) begin
if (do_write && wr_ch < PORTS) begin
case (wr_reg)
6'h00: if (!ch_req[wr_ch]) ch_src_addr[wr_ch] <= apply_wstrb(ch_src_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h04: if (!ch_req[wr_ch]) ch_dst_addr[wr_ch] <= apply_wstrb(ch_dst_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
@@ -456,99 +407,45 @@ module snix_axil_cdma_mux #(
logic ep_arready;
logic ep_rready;
logic [ID_WIDTH-1:0] seq_awid;
logic [ADDR_WIDTH-1:0] seq_awaddr;
logic [7:0] seq_awlen;
logic [2:0] seq_awsize;
logic [1:0] seq_awburst;
logic seq_awlock;
logic [3:0] seq_awcache;
logic [2:0] seq_awprot;
logic [3:0] seq_awqos;
logic [USER_WIDTH-1:0] seq_awuser;
logic seq_awvalid;
logic seq_awready;
logic [DATA_WIDTH-1:0] seq_wdata;
logic [DATA_WIDTH/8-1:0] seq_wstrb;
logic seq_wlast;
logic [USER_WIDTH-1:0] seq_wuser;
logic seq_wvalid;
logic seq_wready;
logic seq_bready;
logic [ID_WIDTH-1:0] seq_arid;
logic [ADDR_WIDTH-1:0] seq_araddr;
logic [7:0] seq_arlen;
logic [2:0] seq_arsize;
logic [1:0] seq_arburst;
logic seq_arlock;
logic [3:0] seq_arcache;
logic [2:0] seq_arprot;
logic [3:0] seq_arqos;
logic [USER_WIDTH-1:0] seq_aruser;
logic seq_arvalid;
logic seq_arready;
logic seq_rready;
typedef enum logic [2:0] {EP_IDLE, EP_AR, EP_READ, EP_AW, EP_WRITE, EP_BRESP, EP_DONE} ep_state_t;
ep_state_t ep_state;
logic [31:0] ep_axi_addr;
logic [31:0] ep_bytes_left;
logic [7:0] ep_word_addr_r;
// Hardware matmul loop sequencer state. Keep these declarations before the
// DMA routing logic because Vivado does not allow forward enum references.
typedef enum logic [4:0] {
SQ_IDLE,
SQ_CLEAR_CRC,
SQ_LOAD0,
SQ_START0,
SQ_LOAD1,
SQ_WAIT_DONE,
SQ_STORE,
SQ_CLEAR_DONE,
SQ_START_NEXT,
SQ_LOAD_NEXT,
SQ_DONE
} seq_state_t;
typedef enum logic [1:0] {EXT_RD_IDLE, EXT_RD_AR, EXT_RD_READ} ext_rd_state_t;
typedef enum logic [1:0] {EXT_WR_IDLE, EXT_WR_AW, EXT_WR_WRITE, EXT_WR_BRESP} ext_wr_state_t;
typedef enum logic [3:0] {
OP_IDLE,
OP_READ_ADDR,
OP_READ_DATA,
OP_WRITE_ADDR,
OP_WRITE_DATA,
OP_WRITE_RESP,
OP_REG_READ_ADDR,
OP_REG_READ_DATA,
OP_COPY_START,
OP_COPY_WAIT
} op_state_t;
ext_rd_state_t ext_rd_state;
ext_wr_state_t ext_wr_state;
logic [ADDR_WIDTH-1:0] ext_rd_addr_r;
logic [31:0] ext_rd_bytes_left;
logic [7:0] ext_rd_word_addr_r;
logic [3:0] ext_rd_ep_id_r;
logic [3:0] ext_rd_ep_bank_r;
logic ext_rd_queue_valid;
logic ext_rd_queue_ar_sent;
logic [ADDR_WIDTH-1:0] ext_rd_queue_addr;
logic [31:0] ext_rd_queue_bytes;
logic [7:0] ext_rd_queue_word_addr;
logic [3:0] ext_rd_queue_ep_id;
logic [3:0] ext_rd_queue_ep_bank;
seq_state_t seq_state;
op_state_t op_state;
logic [ADDR_WIDTH-1:0] ext_wr_addr_r;
logic [31:0] ext_wr_bytes_left;
logic [7:0] ext_wr_word_addr_r;
logic [3:0] ext_wr_ep_id_r;
logic [3:0] ext_wr_ep_bank_r;
logic op_start_copy;
logic op_start_write;
logic op_start_read;
logic op_done;
logic [31:0] op_src_addr;
logic [31:0] op_dst_addr;
logic [31:0] op_bytes;
logic [31:0] op_write_addr;
logic [31:0] op_write_data;
logic [31:0] op_read_addr;
logic [31:0] op_read_data;
logic [31:0] op_src_cur;
logic [31:0] op_dst_cur;
logic [31:0] op_bytes_left;
logic [31:0] op_data_buf;
logic op_buf_valid;
logic op_copy_store;
logic [31:0] seq_group_idx;
logic [31:0] seq_load_idx;
logic [31:0] seq_store_idx;
logic seq_compute_bank;
logic [31:0] seq_status_data;
wire use_ep_engine = (state == RUN) && (engine_mode != MODE_MEM2MEM);
wire use_seq_engine = seq_busy && (op_state != OP_IDLE) &&
(op_state != OP_COPY_START) && (op_state != OP_COPY_WAIT);
wire seq_dma_active = seq_busy && ((op_state == OP_COPY_START) || (op_state == OP_COPY_WAIT));
wire ext_rd_active = (ext_rd_state != EXT_RD_IDLE);
wire ext_wr_active = (ext_wr_state != EXT_WR_IDLE);
wire ext_rd_accept = ext_rd_req_valid && ext_rd_req_ready;
wire ext_wr_accept = ext_wr_req_valid && ext_wr_req_ready;
wire ext_rd_prefetch_ar = (ext_rd_state == EXT_RD_READ) &&
ext_rd_queue_valid && !ext_rd_queue_ar_sent;
wire ext_any_busy_or_req = ext_rd_active || ext_rd_queue_valid || ext_wr_active ||
ext_rd_req_valid || ext_wr_req_valid;
wire use_ep_engine = ((state == RUN) && (engine_mode != MODE_MEM2MEM));
// Dynamic routing to the engine based on current active channel
assign engine_src = ch_src_addr[cur_ch];
@@ -564,47 +461,49 @@ module snix_axil_cdma_mux #(
assign mm2mm_start = engine_start && (engine_mode == MODE_MEM2MEM);
assign ep_start = engine_start && (engine_mode != MODE_MEM2MEM);
assign core_awready = (!use_seq_engine && !use_ep_engine) && mm2mm_awready;
assign core_wready = (!use_seq_engine && !use_ep_engine) && mm2mm_wready;
assign core_arready = (!use_seq_engine && !use_ep_engine) && mm2mm_arready;
assign ep_awready = (!use_seq_engine && use_ep_engine) && mm2mm_awready;
assign ep_wready = (!use_seq_engine && use_ep_engine) && mm2mm_wready;
assign ep_arready = (!use_seq_engine && use_ep_engine) && mm2mm_arready;
assign seq_awready = use_seq_engine && mm2mm_awready;
assign seq_wready = use_seq_engine && mm2mm_wready;
assign seq_arready = use_seq_engine && mm2mm_arready;
assign core_awready = (!ext_wr_active && !use_ep_engine) && mm2mm_awready;
assign core_wready = (!ext_wr_active && !use_ep_engine) && mm2mm_wready;
assign core_arready = (!ext_rd_active && !use_ep_engine) && mm2mm_arready;
assign ep_awready = (!ext_wr_active && use_ep_engine) && mm2mm_awready;
assign ep_wready = (!ext_wr_active && use_ep_engine) && mm2mm_wready;
assign ep_arready = (!ext_rd_active && use_ep_engine) && mm2mm_arready;
assign mm2mm_awid = use_seq_engine ? seq_awid : (use_ep_engine ? ep_awid : core_awid);
assign mm2mm_awaddr = use_seq_engine ? seq_awaddr : (use_ep_engine ? ep_awaddr : core_awaddr);
assign mm2mm_awlen = use_seq_engine ? seq_awlen : (use_ep_engine ? ep_awlen : core_awlen);
assign mm2mm_awsize = use_seq_engine ? seq_awsize : (use_ep_engine ? ep_awsize : core_awsize);
assign mm2mm_awburst = use_seq_engine ? seq_awburst : (use_ep_engine ? ep_awburst : core_awburst);
assign mm2mm_awlock = use_seq_engine ? seq_awlock : (use_ep_engine ? ep_awlock : core_awlock);
assign mm2mm_awcache = use_seq_engine ? seq_awcache : (use_ep_engine ? ep_awcache : core_awcache);
assign mm2mm_awprot = use_seq_engine ? seq_awprot : (use_ep_engine ? ep_awprot : core_awprot);
assign mm2mm_awqos = use_seq_engine ? seq_awqos : (use_ep_engine ? ep_awqos : core_awqos);
assign mm2mm_awuser = use_seq_engine ? seq_awuser : (use_ep_engine ? ep_awuser : core_awuser);
assign mm2mm_awvalid = use_seq_engine ? seq_awvalid : (use_ep_engine ? ep_awvalid : core_awvalid);
assign mm2mm_awid = ext_wr_active ? '0 : (use_ep_engine ? ep_awid : core_awid);
assign mm2mm_awaddr = ext_wr_active ? ext_wr_addr_r : (use_ep_engine ? ep_awaddr : core_awaddr);
assign mm2mm_awlen = ext_wr_active ? (((ext_wr_bytes_left[31:2] == 30'd0) ? 8'd1 : ext_wr_bytes_left[9:2]) - 8'd1) : (use_ep_engine ? ep_awlen : core_awlen);
assign mm2mm_awsize = ext_wr_active ? 3'd2 : (use_ep_engine ? ep_awsize : core_awsize);
assign mm2mm_awburst = ext_wr_active ? 2'b01 : (use_ep_engine ? ep_awburst : core_awburst);
assign mm2mm_awlock = ext_wr_active ? 1'b0 : (use_ep_engine ? ep_awlock : core_awlock);
assign mm2mm_awcache = ext_wr_active ? 4'b0 : (use_ep_engine ? ep_awcache : core_awcache);
assign mm2mm_awprot = ext_wr_active ? 3'b0 : (use_ep_engine ? ep_awprot : core_awprot);
assign mm2mm_awqos = ext_wr_active ? 4'b0 : (use_ep_engine ? ep_awqos : core_awqos);
assign mm2mm_awuser = ext_wr_active ? '0 : (use_ep_engine ? ep_awuser : core_awuser);
assign mm2mm_awvalid = ext_wr_active ? (ext_wr_state == EXT_WR_AW) : (use_ep_engine ? ep_awvalid : core_awvalid);
assign mm2mm_wdata = use_seq_engine ? seq_wdata : (use_ep_engine ? ep_wdata : core_wdata);
assign mm2mm_wstrb = use_seq_engine ? seq_wstrb : (use_ep_engine ? ep_wstrb : core_wstrb);
assign mm2mm_wlast = use_seq_engine ? seq_wlast : (use_ep_engine ? ep_wlast : core_wlast);
assign mm2mm_wuser = use_seq_engine ? seq_wuser : (use_ep_engine ? ep_wuser : core_wuser);
assign mm2mm_wvalid = use_seq_engine ? seq_wvalid : (use_ep_engine ? ep_wvalid : core_wvalid);
assign mm2mm_bready = use_seq_engine ? seq_bready : (use_ep_engine ? ep_bready : core_bready);
assign mm2mm_wdata = ext_wr_active ? ep_rd_data : (use_ep_engine ? ep_wdata : core_wdata);
assign mm2mm_wstrb = ext_wr_active ? {{(DATA_WIDTH/8){1'b1}}} : (use_ep_engine ? ep_wstrb : core_wstrb);
assign mm2mm_wlast = ext_wr_active ? ((ext_wr_bytes_left <= 32'd4) && mm2mm_wvalid) : (use_ep_engine ? ep_wlast : core_wlast);
assign mm2mm_wuser = ext_wr_active ? '0 : (use_ep_engine ? ep_wuser : core_wuser);
assign mm2mm_wvalid = ext_wr_active ? ((ext_wr_state == EXT_WR_WRITE) && ep_rd_ready) : (use_ep_engine ? ep_wvalid : core_wvalid);
assign mm2mm_bready = ext_wr_active ? (ext_wr_state == EXT_WR_BRESP) : (use_ep_engine ? ep_bready : core_bready);
assign mm2mm_arid = use_seq_engine ? seq_arid : (use_ep_engine ? ep_arid : core_arid);
assign mm2mm_araddr = use_seq_engine ? seq_araddr : (use_ep_engine ? ep_araddr : core_araddr);
assign mm2mm_arlen = use_seq_engine ? seq_arlen : (use_ep_engine ? ep_arlen : core_arlen);
assign mm2mm_arsize = use_seq_engine ? seq_arsize : (use_ep_engine ? ep_arsize : core_arsize);
assign mm2mm_arburst = use_seq_engine ? seq_arburst : (use_ep_engine ? ep_arburst : core_arburst);
assign mm2mm_arlock = use_seq_engine ? seq_arlock : (use_ep_engine ? ep_arlock : core_arlock);
assign mm2mm_arcache = use_seq_engine ? seq_arcache : (use_ep_engine ? ep_arcache : core_arcache);
assign mm2mm_arprot = use_seq_engine ? seq_arprot : (use_ep_engine ? ep_arprot : core_arprot);
assign mm2mm_arqos = use_seq_engine ? seq_arqos : (use_ep_engine ? ep_arqos : core_arqos);
assign mm2mm_aruser = use_seq_engine ? seq_aruser : (use_ep_engine ? ep_aruser : core_aruser);
assign mm2mm_arvalid = use_seq_engine ? seq_arvalid : (use_ep_engine ? ep_arvalid : core_arvalid);
assign mm2mm_rready = use_seq_engine ? seq_rready : (use_ep_engine ? ep_rready : core_rready);
assign mm2mm_arid = ext_rd_active ? '0 : (use_ep_engine ? ep_arid : core_arid);
assign mm2mm_araddr = ext_rd_prefetch_ar ? ext_rd_queue_addr :
(ext_rd_active ? ext_rd_addr_r : (use_ep_engine ? ep_araddr : core_araddr));
assign mm2mm_arlen = ext_rd_prefetch_ar ?
(((ext_rd_queue_bytes[31:2] == 30'd0) ? 8'd1 : ext_rd_queue_bytes[9:2]) - 8'd1) :
(ext_rd_active ? (((ext_rd_bytes_left[31:2] == 30'd0) ? 8'd1 : ext_rd_bytes_left[9:2]) - 8'd1) :
(use_ep_engine ? ep_arlen : core_arlen));
assign mm2mm_arsize = ext_rd_active ? 3'd2 : (use_ep_engine ? ep_arsize : core_arsize);
assign mm2mm_arburst = ext_rd_active ? 2'b01 : (use_ep_engine ? ep_arburst : core_arburst);
assign mm2mm_arlock = ext_rd_active ? 1'b0 : (use_ep_engine ? ep_arlock : core_arlock);
assign mm2mm_arcache = ext_rd_active ? 4'b0 : (use_ep_engine ? ep_arcache : core_arcache);
assign mm2mm_arprot = ext_rd_active ? 3'b0 : (use_ep_engine ? ep_arprot : core_arprot);
assign mm2mm_arqos = ext_rd_active ? 4'b0 : (use_ep_engine ? ep_arqos : core_arqos);
assign mm2mm_aruser = ext_rd_active ? '0 : (use_ep_engine ? ep_aruser : core_aruser);
assign mm2mm_arvalid = ext_rd_active ? ((ext_rd_state == EXT_RD_AR) || ext_rd_prefetch_ar) :
(use_ep_engine ? ep_arvalid : core_arvalid);
assign mm2mm_rready = ext_rd_active ? ((ext_rd_state == EXT_RD_READ) && ep_wr_ready) : (use_ep_engine ? ep_rready : core_rready);
always_ff @(posedge clk) begin
if (!rst_n) begin
@@ -619,7 +518,7 @@ module snix_axil_cdma_mux #(
case (state)
IDLE: begin
if (seq_busy) begin
if (ext_any_busy_or_req) begin
state <= IDLE;
end else for (int i = 0; i < PORTS; i++) begin
logic [CH_BITS:0] check_ch_ext;
@@ -666,13 +565,13 @@ module snix_axil_cdma_mux #(
) u_core_engine (
.clk (clk),
.rst_n (rst_n),
.ctrl_start ((op_state == OP_COPY_START) ? 1'b1 : mm2mm_start),
.ctrl_start (mm2mm_start),
.ctrl_stop (1'b0), // Tied off; can be wired if global abort is needed
.ctrl_src_addr (seq_dma_active ? op_src_cur : engine_src),
.ctrl_dst_addr (seq_dma_active ? op_dst_cur : engine_dst),
.ctrl_len (seq_dma_active ? 8'd63 : engine_len),
.ctrl_size (seq_dma_active ? 3'd2 : engine_size),
.ctrl_transfer_len (seq_dma_active ? op_bytes_left : engine_bytes),
.ctrl_src_addr (engine_src),
.ctrl_dst_addr (engine_dst),
.ctrl_len (engine_len),
.ctrl_size (engine_size),
.ctrl_transfer_len (engine_bytes),
.ctrl_done (mm2mm_done),
// AXI4 Port Connections
.mm2mm_awid (core_awid), .mm2mm_awaddr (core_awaddr),
@@ -699,320 +598,145 @@ module snix_axil_cdma_mux #(
.mm2mm_rready (core_rready)
);
wire [7:0] ep_beats_total = (engine_bytes[31:2] == 30'd0) ? 8'd1 : engine_bytes[9:2];
wire [7:0] ep_axi_len = ep_beats_total - 8'd1;
wire ep_mode_mem2ep = (engine_mode == MODE_MEM2EP);
wire ep_mode_ep2mem = (engine_mode == MODE_EP2MEM);
wire ep_rd_done_fire = (ep_state == EP_READ) && mm2mm_rvalid && ep_rready && mm2mm_rlast;
wire ep_wr_done_fire = (ep_state == EP_BRESP) && mm2mm_bvalid && ep_bready;
wire ep_done_fast = ep_rd_done_fire || ep_wr_done_fire;
wire ext_rd_done_fire = (ext_rd_state == EXT_RD_READ) && mm2mm_rvalid && mm2mm_rready && mm2mm_rlast;
wire ext_wr_done_fire = (ext_wr_state == EXT_WR_BRESP) && mm2mm_bvalid && mm2mm_bready;
wire ext_wr_w_fire = (ext_wr_state == EXT_WR_WRITE) && mm2mm_wvalid && mm2mm_wready;
// ==========================================
// Hardware matmul loop sequencer
// Generic external endpoint requester
// ==========================================
wire seq_has_more_load = (seq_load_idx < seq_groups);
wire [31:0] seq_src_addr_for_load = seq_src_base + (seq_load_idx * seq_src_stride);
wire [31:0] seq_dst_addr_for_load = seq_mat_base + (seq_load_idx[0] ? MAT_B1_AB_OFF : MAT_B0_AB_OFF);
wire [31:0] seq_src_addr_for_store = seq_mat_base + (seq_store_idx[0] ? MAT_B1_C_OFF : MAT_B0_C_OFF);
wire [31:0] seq_dst_addr_for_store = seq_dst_base + (seq_store_idx * seq_dst_stride);
wire [31:0] seq_start_value_for_bank = seq_compute_bank ? MAT_CTRL_START_B1 : MAT_CTRL_START_B0;
wire [31:0] seq_start_value_for_loaded_bank =
(seq_load_idx[0] == 1'b0) ? MAT_CTRL_START_B1 : MAT_CTRL_START_B0;
assign seq_awid = '0;
assign seq_awsize = 3'd2;
assign seq_awburst = 2'b01;
assign seq_awlock = 1'b0;
assign seq_awcache = 4'b0;
assign seq_awprot = 3'b0;
assign seq_awqos = 4'b0;
assign seq_awuser = '0;
assign seq_wstrb = {{(DATA_WIDTH/8){1'b1}}};
assign seq_wuser = '0;
assign seq_arid = '0;
assign seq_arsize = 3'd2;
assign seq_arburst = 2'b01;
assign seq_arlock = 1'b0;
assign seq_arcache = 4'b0;
assign seq_arprot = 3'b0;
assign seq_arqos = 4'b0;
assign seq_aruser = '0;
assign seq_araddr = (op_state == OP_REG_READ_ADDR) ? op_read_addr : op_src_cur;
assign seq_arlen = (op_state == OP_REG_READ_ADDR) ? 8'd0 : 8'd0;
assign seq_arvalid = (op_state == OP_READ_ADDR) || (op_state == OP_REG_READ_ADDR);
assign seq_rready = (op_state == OP_REG_READ_DATA) ||
((op_state == OP_READ_DATA) && !op_buf_valid);
assign seq_awaddr = (op_state == OP_WRITE_ADDR && op_copy_store) ? op_dst_cur : op_write_addr;
assign seq_awlen = 8'd0;
assign seq_awvalid = (op_state == OP_WRITE_ADDR);
assign seq_wdata = op_copy_store ? op_data_buf : op_write_data;
assign seq_wlast = 1'b1;
assign seq_wvalid = (op_state == OP_WRITE_DATA) && (!op_copy_store || op_buf_valid);
assign seq_bready = (op_state == OP_WRITE_RESP);
assign ext_rd_req_ready = (state == IDLE) && (ep_state == EP_IDLE) && !ext_wr_active &&
((ext_rd_state == EXT_RD_IDLE) ||
((ext_rd_state == EXT_RD_READ) && !ext_rd_queue_valid &&
!ext_rd_done_fire));
assign ext_wr_req_ready = (state == IDLE) && (ep_state == EP_IDLE) && !ext_wr_active;
assign ext_rd_req_done = ext_rd_done_fire;
assign ext_wr_req_done = ext_wr_done_fire;
always_ff @(posedge clk) begin
if (!rst_n) begin
op_state <= OP_IDLE;
op_done <= 1'b0;
op_src_cur <= '0;
op_dst_cur <= '0;
op_bytes_left <= '0;
op_data_buf <= '0;
op_buf_valid <= 1'b0;
op_copy_store <= 1'b0;
op_read_data <= '0;
ext_rd_state <= EXT_RD_IDLE;
ext_rd_addr_r <= '0;
ext_rd_bytes_left <= '0;
ext_rd_word_addr_r <= '0;
ext_rd_ep_id_r <= '0;
ext_rd_ep_bank_r <= '0;
ext_rd_queue_valid <= 1'b0;
ext_rd_queue_ar_sent <= 1'b0;
ext_rd_queue_addr <= '0;
ext_rd_queue_bytes <= '0;
ext_rd_queue_word_addr <= '0;
ext_rd_queue_ep_id <= '0;
ext_rd_queue_ep_bank <= '0;
end else begin
op_done <= 1'b0;
if (ext_rd_prefetch_ar && mm2mm_arvalid && mm2mm_arready)
ext_rd_queue_ar_sent <= 1'b1;
case (op_state)
OP_IDLE: begin
op_buf_valid <= 1'b0;
if (op_start_copy) begin
op_src_cur <= op_src_addr;
op_dst_cur <= op_dst_addr;
op_bytes_left <= op_bytes;
op_copy_store <= 1'b1;
op_state <= OP_COPY_START;
end else if (op_start_write) begin
op_copy_store <= 1'b0;
op_state <= OP_WRITE_ADDR;
end else if (op_start_read) begin
op_copy_store <= 1'b0;
op_state <= OP_REG_READ_ADDR;
case (ext_rd_state)
EXT_RD_IDLE: begin
if (ext_rd_accept) begin
ext_rd_addr_r <= ext_rd_req_src;
ext_rd_bytes_left <= ext_rd_req_bytes;
ext_rd_word_addr_r <= ext_rd_req_ep_word_off;
ext_rd_ep_id_r <= ext_rd_req_ep_id;
ext_rd_ep_bank_r <= ext_rd_req_ep_bank;
ext_rd_state <= EXT_RD_AR;
end
end
OP_READ_ADDR: begin
if (seq_arvalid && seq_arready)
op_state <= OP_READ_DATA;
EXT_RD_AR: begin
if (mm2mm_arvalid && mm2mm_arready)
ext_rd_state <= EXT_RD_READ;
end
OP_READ_DATA: begin
if (mm2mm_rvalid && seq_rready) begin
op_data_buf <= mm2mm_rdata;
op_buf_valid <= 1'b1;
op_state <= OP_WRITE_ADDR;
EXT_RD_READ: begin
if (ext_rd_accept) begin
ext_rd_queue_valid <= 1'b1;
ext_rd_queue_ar_sent <= 1'b0;
ext_rd_queue_addr <= ext_rd_req_src;
ext_rd_queue_bytes <= ext_rd_req_bytes;
ext_rd_queue_word_addr <= ext_rd_req_ep_word_off;
ext_rd_queue_ep_id <= ext_rd_req_ep_id;
ext_rd_queue_ep_bank <= ext_rd_req_ep_bank;
end
end
OP_WRITE_ADDR: begin
if (seq_awvalid && seq_awready)
op_state <= OP_WRITE_DATA;
end
OP_WRITE_DATA: begin
if (seq_wvalid && seq_wready) begin
op_buf_valid <= 1'b0;
op_state <= OP_WRITE_RESP;
end
end
OP_WRITE_RESP: begin
if (mm2mm_bvalid && seq_bready) begin
if (op_copy_store && (op_bytes_left > 32'd4)) begin
op_src_cur <= op_src_cur + 32'd4;
op_dst_cur <= op_dst_cur + 32'd4;
op_bytes_left <= op_bytes_left - 32'd4;
op_state <= OP_READ_ADDR;
end else begin
op_done <= 1'b1;
op_state <= OP_IDLE;
if (mm2mm_rvalid && mm2mm_rready) begin
ext_rd_word_addr_r <= ext_rd_word_addr_r + 8'd1;
ext_rd_bytes_left <= (ext_rd_bytes_left > 32'd4) ? (ext_rd_bytes_left - 32'd4) : 32'd0;
if (mm2mm_rlast) begin
if (ext_rd_queue_valid) begin
ext_rd_addr_r <= ext_rd_queue_addr;
ext_rd_bytes_left <= ext_rd_queue_bytes;
ext_rd_word_addr_r <= ext_rd_queue_word_addr;
ext_rd_ep_id_r <= ext_rd_queue_ep_id;
ext_rd_ep_bank_r <= ext_rd_queue_ep_bank;
ext_rd_queue_valid <= 1'b0;
ext_rd_queue_ar_sent <= 1'b0;
if (ext_rd_queue_ar_sent ||
(ext_rd_prefetch_ar && mm2mm_arvalid && mm2mm_arready))
ext_rd_state <= EXT_RD_READ;
else
ext_rd_state <= EXT_RD_AR;
end else begin
ext_rd_state <= EXT_RD_IDLE;
end
end
end
end
OP_REG_READ_ADDR: begin
if (seq_arvalid && seq_arready)
op_state <= OP_REG_READ_DATA;
end
OP_REG_READ_DATA: begin
if (mm2mm_rvalid && seq_rready) begin
op_read_data <= mm2mm_rdata;
op_done <= 1'b1;
op_state <= OP_IDLE;
end
end
OP_COPY_START: begin
op_state <= OP_COPY_WAIT;
end
OP_COPY_WAIT: begin
if (mm2mm_done) begin
op_done <= 1'b1;
op_state <= OP_IDLE;
end
end
default: op_state <= OP_IDLE;
default: ext_rd_state <= EXT_RD_IDLE;
endcase
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_state <= SQ_IDLE;
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
op_start_copy <= 1'b0;
op_start_write <= 1'b0;
op_start_read <= 1'b0;
op_src_addr <= '0;
op_dst_addr <= '0;
op_bytes <= '0;
op_write_addr <= '0;
op_write_data <= '0;
op_read_addr <= '0;
seq_group_idx <= '0;
seq_load_idx <= '0;
seq_store_idx <= '0;
seq_compute_bank <= 1'b0;
seq_status_data <= '0;
ext_wr_state <= EXT_WR_IDLE;
ext_wr_addr_r <= '0;
ext_wr_bytes_left <= '0;
ext_wr_word_addr_r <= '0;
ext_wr_ep_id_r <= '0;
ext_wr_ep_bank_r <= '0;
end else begin
op_start_copy <= 1'b0;
op_start_write <= 1'b0;
op_start_read <= 1'b0;
if (seq_done_clear_req)
seq_done_flag <= 1'b0;
case (seq_state)
SQ_IDLE: begin
seq_busy <= 1'b0;
if (seq_start_req && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_group_idx <= 32'd0;
seq_load_idx <= 32'd0;
seq_store_idx <= 32'd0;
seq_compute_bank <= 1'b0;
op_write_addr <= seq_mat_base + MAT_CRC_OFF;
op_write_data <= 32'd0;
op_start_write <= 1'b1;
seq_state <= SQ_CLEAR_CRC;
case (ext_wr_state)
EXT_WR_IDLE: begin
if (ext_wr_accept) begin
ext_wr_addr_r <= ext_wr_req_dst;
ext_wr_bytes_left <= ext_wr_req_bytes;
ext_wr_word_addr_r <= ext_wr_req_ep_word_off;
ext_wr_ep_id_r <= ext_wr_req_ep_id;
ext_wr_ep_bank_r <= ext_wr_req_ep_bank;
ext_wr_state <= EXT_WR_AW;
end
end
SQ_CLEAR_CRC: begin
if (op_done) begin
op_src_addr <= seq_src_base;
op_dst_addr <= seq_mat_base + MAT_B0_AB_OFF;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= 32'd1;
seq_state <= SQ_LOAD0;
EXT_WR_AW: begin
if (mm2mm_awvalid && mm2mm_awready)
ext_wr_state <= EXT_WR_WRITE;
end
EXT_WR_WRITE: begin
if (ext_wr_w_fire) begin
ext_wr_word_addr_r <= ext_wr_word_addr_r + 8'd1;
ext_wr_bytes_left <= (ext_wr_bytes_left > 32'd4) ? (ext_wr_bytes_left - 32'd4) : 32'd0;
if (mm2mm_wlast)
ext_wr_state <= EXT_WR_BRESP;
end
end
SQ_LOAD0: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= MAT_CTRL_START_B0;
op_start_write <= 1'b1;
seq_state <= SQ_START0;
end
EXT_WR_BRESP: begin
if (mm2mm_bvalid && mm2mm_bready)
ext_wr_state <= EXT_WR_IDLE;
end
SQ_START0: begin
if (op_done) begin
if (seq_load_idx < seq_groups) begin
op_src_addr <= seq_src_base + (seq_load_idx * seq_src_stride);
op_dst_addr <= seq_mat_base + MAT_B1_AB_OFF;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= seq_load_idx + 32'd1;
seq_state <= SQ_LOAD1;
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_LOAD1: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= seq_start_value_for_loaded_bank;
op_start_write <= 1'b1;
seq_state <= SQ_START_NEXT;
end
end
SQ_WAIT_DONE: begin
if (op_done) begin
seq_status_data <= op_read_data;
if ((op_read_data & MAT_STATUS_DONE_BIT) != 32'd0) begin
seq_store_idx <= seq_group_idx;
if ((seq_group_idx + 32'd1) >= seq_groups) begin
op_src_addr <= seq_mat_base + (seq_compute_bank ? MAT_B1_C_OFF : MAT_B0_C_OFF);
op_dst_addr <= seq_dst_base + (seq_group_idx * seq_dst_stride);
op_bytes <= MAT_C_BYTES;
op_start_copy <= 1'b1;
seq_state <= SQ_STORE;
end else begin
op_write_addr <= seq_mat_base + MAT_STATUS_OFF;
op_write_data <= MAT_STATUS_DONE_CLR;
op_start_write <= 1'b1;
seq_state <= SQ_CLEAR_DONE;
end
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
end
end
end
SQ_STORE: begin
if (op_done) begin
if ((seq_store_idx + 32'd1) >= seq_groups) begin
seq_state <= SQ_DONE;
end else if (seq_has_more_load) begin
op_src_addr <= seq_src_addr_for_load;
op_dst_addr <= seq_dst_addr_for_load;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= seq_load_idx + 32'd1;
seq_state <= SQ_LOAD_NEXT;
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_CLEAR_DONE: begin
if (op_done) begin
seq_group_idx <= seq_group_idx + 32'd1;
seq_compute_bank <= ~seq_compute_bank;
op_src_addr <= seq_src_addr_for_store;
op_dst_addr <= seq_dst_addr_for_store;
op_bytes <= MAT_C_BYTES;
op_start_copy <= 1'b1;
seq_state <= SQ_STORE;
end
end
SQ_START_NEXT: begin
if (op_done) begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
SQ_LOAD_NEXT: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= seq_start_value_for_loaded_bank;
op_start_write <= 1'b1;
seq_state <= SQ_START_NEXT;
end
end
SQ_DONE: begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b1;
seq_state <= SQ_IDLE;
end
default: seq_state <= SQ_IDLE;
default: ext_wr_state <= EXT_WR_IDLE;
endcase
end
end
@@ -1020,17 +744,6 @@ module snix_axil_cdma_mux #(
// ==========================================
// Endpoint transfer engine (32-bit only in this SoC integration)
// ==========================================
typedef enum logic [2:0] {EP_IDLE, EP_AR, EP_READ, EP_AW, EP_WRITE, EP_BRESP, EP_DONE} ep_state_t;
ep_state_t ep_state;
logic [31:0] ep_axi_addr;
logic [31:0] ep_bytes_left;
logic [7:0] ep_word_addr_r;
wire [7:0] ep_beats_total = (engine_bytes[31:2] == 30'd0) ? 8'd1 : engine_bytes[9:2];
wire [7:0] ep_axi_len = ep_beats_total - 8'd1;
wire ep_mode_mem2ep = (engine_mode == MODE_MEM2EP);
wire ep_mode_ep2mem = (engine_mode == MODE_EP2MEM);
always_ff @(posedge clk) begin
if (!rst_n) begin
ep_state <= EP_IDLE;
@@ -1060,8 +773,10 @@ module snix_axil_cdma_mux #(
if (mm2mm_rvalid && ep_rready) begin
ep_word_addr_r <= ep_word_addr_r + 8'd1;
ep_bytes_left <= (ep_bytes_left > 32'd4) ? (ep_bytes_left - 32'd4) : 32'd0;
if (mm2mm_rlast)
ep_state <= EP_DONE;
if (mm2mm_rlast) begin
ep_done <= 1'b1;
ep_state <= EP_IDLE;
end
end
end
@@ -1080,8 +795,10 @@ module snix_axil_cdma_mux #(
end
EP_BRESP: begin
if (mm2mm_bvalid && ep_bready)
ep_state <= EP_DONE;
if (mm2mm_bvalid && ep_bready) begin
ep_done <= 1'b1;
ep_state <= EP_IDLE;
end
end
EP_DONE: begin
@@ -1107,10 +824,11 @@ module snix_axil_cdma_mux #(
assign ep_arvalid = (ep_state == EP_AR);
assign ep_rready = (ep_state == EP_READ) && ep_wr_ready;
assign ep_wr_valid = (ep_state == EP_READ) && mm2mm_rvalid && ep_mode_mem2ep;
assign ep_wr_id = engine_ep_id;
assign ep_wr_bank = engine_ep_bank;
assign ep_wr_word_addr = ep_word_addr_r;
assign ep_wr_valid = ext_rd_active ? ((ext_rd_state == EXT_RD_READ) && mm2mm_rvalid) :
((ep_state == EP_READ) && mm2mm_rvalid && ep_mode_mem2ep);
assign ep_wr_id = ext_rd_active ? ext_rd_ep_id_r : engine_ep_id;
assign ep_wr_bank = ext_rd_active ? ext_rd_ep_bank_r : engine_ep_bank;
assign ep_wr_word_addr = ext_rd_active ? ext_rd_word_addr_r : ep_word_addr_r;
assign ep_wr_data = mm2mm_rdata[31:0];
assign ep_awid = '0;
@@ -1131,9 +849,10 @@ module snix_axil_cdma_mux #(
assign ep_wvalid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_rd_ready;
assign ep_bready = (ep_state == EP_BRESP);
assign ep_rd_valid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_wready;
assign ep_rd_id = engine_ep_id;
assign ep_rd_bank = engine_ep_bank;
assign ep_rd_word_addr = ep_word_addr_r;
assign ep_rd_valid = ext_wr_active ? ((ext_wr_state == EXT_WR_WRITE) && mm2mm_wready) :
((ep_state == EP_WRITE) && ep_mode_ep2mem && ep_wready);
assign ep_rd_id = ext_wr_active ? ext_wr_ep_id_r : engine_ep_id;
assign ep_rd_bank = ext_wr_active ? ext_wr_ep_bank_r : engine_ep_bank;
assign ep_rd_word_addr = ext_wr_active ? ext_wr_word_addr_r : ep_word_addr_r;
endmodule

32
rtl/ip/fft/Butterfly.v Normal file
View File

@@ -0,0 +1,32 @@
//----------------------------------------------------------------------
// Butterfly: Add/Sub and Scaling
//----------------------------------------------------------------------
module Butterfly #(
parameter WIDTH = 16,
parameter RH = 0 // Round Half Up
)(
input signed [WIDTH-1:0] x0_re, // Input Data #0 (Real)
input signed [WIDTH-1:0] x0_im, // Input Data #0 (Imag)
input signed [WIDTH-1:0] x1_re, // Input Data #1 (Real)
input signed [WIDTH-1:0] x1_im, // Input Data #1 (Imag)
output signed [WIDTH-1:0] y0_re, // Output Data #0 (Real)
output signed [WIDTH-1:0] y0_im, // Output Data #0 (Imag)
output signed [WIDTH-1:0] y1_re, // Output Data #1 (Real)
output signed [WIDTH-1:0] y1_im // Output Data #1 (Imag)
);
wire signed [WIDTH:0] add_re, add_im, sub_re, sub_im;
// Add/Sub
assign add_re = x0_re + x1_re;
assign add_im = x0_im + x1_im;
assign sub_re = x0_re - x1_re;
assign sub_im = x0_im - x1_im;
// Scaling
assign y0_re = (add_re + RH) >>> 1;
assign y0_im = (add_im + RH) >>> 1;
assign y1_re = (sub_re + RH) >>> 1;
assign y1_im = (sub_im + RH) >>> 1;
endmodule

34
rtl/ip/fft/DelayBuffer.v Normal file
View File

@@ -0,0 +1,34 @@
//----------------------------------------------------------------------
// DelayBuffer: Generate Constant Delay
//----------------------------------------------------------------------
module DelayBuffer #(
parameter DEPTH = 32,
parameter WIDTH = 16
)(
input clock, // Master Clock
input [WIDTH-1:0] di_re, // Data Input (Real)
input [WIDTH-1:0] di_im, // Data Input (Imag)
output [WIDTH-1:0] do_re, // Data Output (Real)
output [WIDTH-1:0] do_im // Data Output (Imag)
);
reg [WIDTH-1:0] buf_re[0:DEPTH-1];
reg [WIDTH-1:0] buf_im[0:DEPTH-1];
integer n;
// Shift Buffer
/* verilator lint_off BLKLOOPINIT */
always @(posedge clock) begin
for (n = DEPTH-1; n > 0; n = n - 1) begin
buf_re[n] <= buf_re[n-1];
buf_im[n] <= buf_im[n-1];
end
buf_re[0] <= di_re;
buf_im[0] <= di_im;
end
/* verilator lint_on BLKLOOPINIT */
assign do_re = buf_re[DEPTH-1];
assign do_im = buf_im[DEPTH-1];
endmodule

90
rtl/ip/fft/FFT1024_32B.v Normal file
View File

@@ -0,0 +1,90 @@
//----------------------------------------------------------------------
// FFT: 1024-Point FFT Using Radix-2^2 Single-Path Delay Feedback
//----------------------------------------------------------------------
module FFT #(
parameter WIDTH = 32
)(
input clock, // Master Clock
input reset, // Active High Asynchronous Reset
input di_en, // Input Data Enable
input [WIDTH-1:0] di_re, // Input Data (Real)
input [WIDTH-1:0] di_im, // Input Data (Imag)
output do_en, // Output Data Enable
output [WIDTH-1:0] do_re, // Output Data (Real)
output [WIDTH-1:0] do_im // Output Data (Imag)
);
//----------------------------------------------------------------------
// Data must be input consecutively in natural order.
// The result is scaled to 1/N and output in bit-reversed order.
//----------------------------------------------------------------------
wire su1_do_en;
wire[WIDTH-1:0] su1_do_re;
wire[WIDTH-1:0] su1_do_im;
wire su2_do_en;
wire[WIDTH-1:0] su2_do_re;
wire[WIDTH-1:0] su2_do_im;
wire su3_do_en;
wire[WIDTH-1:0] su3_do_re;
wire[WIDTH-1:0] su3_do_im;
wire su4_do_en;
wire[WIDTH-1:0] su4_do_re;
wire[WIDTH-1:0] su4_do_im;
SdfUnit #(.N(1024),.M(1024),.WIDTH(WIDTH)) SU1 (
.clock (clock ), // i
.reset (reset ), // i
.di_en (di_en ), // i
.di_re (di_re ), // i
.di_im (di_im ), // i
.do_en (su1_do_en ), // o
.do_re (su1_do_re ), // o
.do_im (su1_do_im ) // o
);
SdfUnit #(.N(1024),.M(256),.WIDTH(WIDTH)) SU2 (
.clock (clock ), // i
.reset (reset ), // i
.di_en (su1_do_en ), // i
.di_re (su1_do_re ), // i
.di_im (su1_do_im ), // i
.do_en (su2_do_en ), // o
.do_re (su2_do_re ), // o
.do_im (su2_do_im ) // o
);
SdfUnit #(.N(1024),.M(64),.WIDTH(WIDTH)) SU3 (
.clock (clock ), // i
.reset (reset ), // i
.di_en (su2_do_en ), // i
.di_re (su2_do_re ), // i
.di_im (su2_do_im ), // i
.do_en (su3_do_en ), // o
.do_re (su3_do_re ), // o
.do_im (su3_do_im ) // o
);
SdfUnit #(.N(1024),.M(16),.WIDTH(WIDTH)) SU4 (
.clock (clock ), // i
.reset (reset ), // i
.di_en (su3_do_en ), // i
.di_re (su3_do_re ), // i
.di_im (su3_do_im ), // i
.do_en (su4_do_en ), // o
.do_re (su4_do_re ), // o
.do_im (su4_do_im ) // o
);
SdfUnit #(.N(1024),.M(4),.WIDTH(WIDTH)) SU5 (
.clock (clock ), // i
.reset (reset ), // i
.di_en (su4_do_en ), // i
.di_re (su4_do_re ), // i
.di_im (su4_do_im ), // i
.do_en (do_en ), // o
.do_re (do_re ), // o
.do_im (do_im ) // o
);
endmodule

36
rtl/ip/fft/Multiply.v Normal file
View File

@@ -0,0 +1,36 @@
//----------------------------------------------------------------------
// Multiply: Complex Multiplier
//----------------------------------------------------------------------
(* use_dsp = "no" *) module Multiply #(
parameter WIDTH = 16
)(
input signed [WIDTH-1:0] a_re,
input signed [WIDTH-1:0] a_im,
input signed [WIDTH-1:0] b_re,
input signed [WIDTH-1:0] b_im,
output signed [WIDTH-1:0] m_re,
output signed [WIDTH-1:0] m_im
);
wire signed [WIDTH*2-1:0] arbr, arbi, aibr, aibi;
wire signed [WIDTH-1:0] sc_arbr, sc_arbi, sc_aibr, sc_aibi;
// Signed Multiplication
assign arbr = a_re * b_re;
assign arbi = a_re * b_im;
assign aibr = a_im * b_re;
assign aibi = a_im * b_im;
// Scaling
assign sc_arbr = arbr >>> (WIDTH-1);
assign sc_arbi = arbi >>> (WIDTH-1);
assign sc_aibr = aibr >>> (WIDTH-1);
assign sc_aibi = aibi >>> (WIDTH-1);
// Sub/Add
// These sub/add may overflow if unnormalized data is input.
assign m_re = sc_arbr - sc_aibi;
assign m_im = sc_arbi + sc_aibr;
endmodule

280
rtl/ip/fft/SdfUnit.v Normal file
View File

@@ -0,0 +1,280 @@
//----------------------------------------------------------------------
// SdfUnit: Radix-2^2 Single-Path Delay Feedback Unit for N-Point FFT
//----------------------------------------------------------------------
module SdfUnit #(
parameter N = 64, // Number of FFT Point
parameter M = 64, // Twiddle Resolution
parameter WIDTH = 16 // Data Bit Length
)(
input clock, // Master Clock
input reset, // Active High Asynchronous Reset
input di_en, // Input Data Enable
input [WIDTH-1:0] di_re, // Input Data (Real)
input [WIDTH-1:0] di_im, // Input Data (Imag)
output do_en, // Output Data Enable
output [WIDTH-1:0] do_re, // Output Data (Real)
output [WIDTH-1:0] do_im // Output Data (Imag)
);
// log2 constant function
function integer log2;
input integer x;
integer value;
begin
value = x-1;
for (log2=0; value>0; log2=log2+1)
value = value>>1;
end
endfunction
localparam LOG_N = log2(N); // Bit Length of N
localparam LOG_M = log2(M); // Bit Length of M
//----------------------------------------------------------------------
// Internal Regs and Nets
//----------------------------------------------------------------------
// 1st Butterfly
reg [LOG_N-1:0] di_count; // Input Data Count
wire bf1_bf; // Butterfly Add/Sub Enable
wire[WIDTH-1:0] bf1_x0_re; // Data #0 to Butterfly (Real)
wire[WIDTH-1:0] bf1_x0_im; // Data #0 to Butterfly (Imag)
wire[WIDTH-1:0] bf1_x1_re; // Data #1 to Butterfly (Real)
wire[WIDTH-1:0] bf1_x1_im; // Data #1 to Butterfly (Imag)
wire[WIDTH-1:0] bf1_y0_re; // Data #0 from Butterfly (Real)
wire[WIDTH-1:0] bf1_y0_im; // Data #0 from Butterfly (Imag)
wire[WIDTH-1:0] bf1_y1_re; // Data #1 from Butterfly (Real)
wire[WIDTH-1:0] bf1_y1_im; // Data #1 from Butterfly (Imag)
wire[WIDTH-1:0] db1_di_re; // Data to DelayBuffer (Real)
wire[WIDTH-1:0] db1_di_im; // Data to DelayBuffer (Imag)
wire[WIDTH-1:0] db1_do_re; // Data from DelayBuffer (Real)
wire[WIDTH-1:0] db1_do_im; // Data from DelayBuffer (Imag)
wire[WIDTH-1:0] bf1_sp_re; // Single-Path Data Output (Real)
wire[WIDTH-1:0] bf1_sp_im; // Single-Path Data Output (Imag)
reg bf1_sp_en; // Single-Path Data Enable
reg [LOG_N-1:0] bf1_count; // Single-Path Data Count
wire bf1_start; // Single-Path Output Trigger
wire bf1_end; // End of Single-Path Data
wire bf1_mj; // Twiddle (-j) Enable
reg [WIDTH-1:0] bf1_do_re; // 1st Butterfly Output Data (Real)
reg [WIDTH-1:0] bf1_do_im; // 1st Butterfly Output Data (Imag)
// 2nd Butterfly
reg bf2_bf; // Butterfly Add/Sub Enable
wire[WIDTH-1:0] bf2_x0_re; // Data #0 to Butterfly (Real)
wire[WIDTH-1:0] bf2_x0_im; // Data #0 to Butterfly (Imag)
wire[WIDTH-1:0] bf2_x1_re; // Data #1 to Butterfly (Real)
wire[WIDTH-1:0] bf2_x1_im; // Data #1 to Butterfly (Imag)
wire[WIDTH-1:0] bf2_y0_re; // Data #0 from Butterfly (Real)
wire[WIDTH-1:0] bf2_y0_im; // Data #0 from Butterfly (Imag)
wire[WIDTH-1:0] bf2_y1_re; // Data #1 from Butterfly (Real)
wire[WIDTH-1:0] bf2_y1_im; // Data #1 from Butterfly (Imag)
wire[WIDTH-1:0] db2_di_re; // Data to DelayBuffer (Real)
wire[WIDTH-1:0] db2_di_im; // Data to DelayBuffer (Imag)
wire[WIDTH-1:0] db2_do_re; // Data from DelayBuffer (Real)
wire[WIDTH-1:0] db2_do_im; // Data from DelayBuffer (Imag)
wire[WIDTH-1:0] bf2_sp_re; // Single-Path Data Output (Real)
wire[WIDTH-1:0] bf2_sp_im; // Single-Path Data Output (Imag)
reg bf2_sp_en; // Single-Path Data Enable
reg [LOG_N-1:0] bf2_count; // Single-Path Data Count
reg bf2_start; // Single-Path Output Trigger
wire bf2_end; // End of Single-Path Data
reg [WIDTH-1:0] bf2_do_re; // 2nd Butterfly Output Data (Real)
reg [WIDTH-1:0] bf2_do_im; // 2nd Butterfly Output Data (Imag)
reg bf2_do_en; // 2nd Butterfly Output Data Enable
// Multiplication
wire[1:0] tw_sel; // Twiddle Select (2n/n/3n)
wire[LOG_N-3:0] tw_num; // Twiddle Number (n)
wire[LOG_N-1:0] tw_addr; // Twiddle Table Address
wire[WIDTH-1:0] tw_re; // Twiddle Factor (Real)
wire[WIDTH-1:0] tw_im; // Twiddle Factor (Imag)
reg mu_en; // Multiplication Enable
wire[WIDTH-1:0] mu_a_re; // Multiplier Input (Real)
wire[WIDTH-1:0] mu_a_im; // Multiplier Input (Imag)
wire[WIDTH-1:0] mu_m_re; // Multiplier Output (Real)
wire[WIDTH-1:0] mu_m_im; // Multiplier Output (Imag)
reg [WIDTH-1:0] mu_do_re; // Multiplication Output Data (Real)
reg [WIDTH-1:0] mu_do_im; // Multiplication Output Data (Imag)
reg mu_do_en; // Multiplication Output Data Enable
//----------------------------------------------------------------------
// 1st Butterfly
//----------------------------------------------------------------------
always @(posedge clock or posedge reset) begin
if (reset) begin
di_count <= {LOG_N{1'b0}};
end else begin
di_count <= di_en ? (di_count + 1'b1) : {LOG_N{1'b0}};
end
end
assign bf1_bf = di_count[LOG_M-1];
// Set unknown value x for verification
assign bf1_x0_re = bf1_bf ? db1_do_re : {WIDTH{1'bx}};
assign bf1_x0_im = bf1_bf ? db1_do_im : {WIDTH{1'bx}};
assign bf1_x1_re = bf1_bf ? di_re : {WIDTH{1'bx}};
assign bf1_x1_im = bf1_bf ? di_im : {WIDTH{1'bx}};
Butterfly #(.WIDTH(WIDTH),.RH(0)) BF1 (
.x0_re (bf1_x0_re ), // i
.x0_im (bf1_x0_im ), // i
.x1_re (bf1_x1_re ), // i
.x1_im (bf1_x1_im ), // i
.y0_re (bf1_y0_re ), // o
.y0_im (bf1_y0_im ), // o
.y1_re (bf1_y1_re ), // o
.y1_im (bf1_y1_im ) // o
);
DelayBuffer #(.DEPTH(2**(LOG_M-1)),.WIDTH(WIDTH)) DB1 (
.clock (clock ), // i
.di_re (db1_di_re ), // i
.di_im (db1_di_im ), // i
.do_re (db1_do_re ), // o
.do_im (db1_do_im ) // o
);
assign db1_di_re = bf1_bf ? bf1_y1_re : di_re;
assign db1_di_im = bf1_bf ? bf1_y1_im : di_im;
assign bf1_sp_re = bf1_bf ? bf1_y0_re : bf1_mj ? db1_do_im : db1_do_re;
assign bf1_sp_im = bf1_bf ? bf1_y0_im : bf1_mj ? -db1_do_re : db1_do_im;
always @(posedge clock or posedge reset) begin
if (reset) begin
bf1_sp_en <= 1'b0;
bf1_count <= {LOG_N{1'b0}};
end else begin
bf1_sp_en <= bf1_start ? 1'b1 : bf1_end ? 1'b0 : bf1_sp_en;
bf1_count <= bf1_sp_en ? (bf1_count + 1'b1) : {LOG_N{1'b0}};
end
end
assign bf1_start = (di_count == (2**(LOG_M-1)-1));
assign bf1_end = (bf1_count == (2**LOG_N-1));
assign bf1_mj = (bf1_count[LOG_M-1:LOG_M-2] == 2'd3);
always @(posedge clock) begin
bf1_do_re <= bf1_sp_re;
bf1_do_im <= bf1_sp_im;
end
//----------------------------------------------------------------------
// 2nd Butterfly
//----------------------------------------------------------------------
always @(posedge clock) begin
bf2_bf <= bf1_count[LOG_M-2];
end
// Set unknown value x for verification
assign bf2_x0_re = bf2_bf ? db2_do_re : {WIDTH{1'bx}};
assign bf2_x0_im = bf2_bf ? db2_do_im : {WIDTH{1'bx}};
assign bf2_x1_re = bf2_bf ? bf1_do_re : {WIDTH{1'bx}};
assign bf2_x1_im = bf2_bf ? bf1_do_im : {WIDTH{1'bx}};
// Negative bias occurs when RH=0 and positive bias occurs when RH=1.
// Using both alternately reduces the overall rounding error.
Butterfly #(.WIDTH(WIDTH),.RH(1)) BF2 (
.x0_re (bf2_x0_re ), // i
.x0_im (bf2_x0_im ), // i
.x1_re (bf2_x1_re ), // i
.x1_im (bf2_x1_im ), // i
.y0_re (bf2_y0_re ), // o
.y0_im (bf2_y0_im ), // o
.y1_re (bf2_y1_re ), // o
.y1_im (bf2_y1_im ) // o
);
DelayBuffer #(.DEPTH(2**(LOG_M-2)),.WIDTH(WIDTH)) DB2 (
.clock (clock ), // i
.di_re (db2_di_re ), // i
.di_im (db2_di_im ), // i
.do_re (db2_do_re ), // o
.do_im (db2_do_im ) // o
);
assign db2_di_re = bf2_bf ? bf2_y1_re : bf1_do_re;
assign db2_di_im = bf2_bf ? bf2_y1_im : bf1_do_im;
assign bf2_sp_re = bf2_bf ? bf2_y0_re : db2_do_re;
assign bf2_sp_im = bf2_bf ? bf2_y0_im : db2_do_im;
always @(posedge clock or posedge reset) begin
if (reset) begin
bf2_sp_en <= 1'b0;
bf2_count <= {LOG_N{1'b0}};
end else begin
bf2_sp_en <= bf2_start ? 1'b1 : bf2_end ? 1'b0 : bf2_sp_en;
bf2_count <= bf2_sp_en ? (bf2_count + 1'b1) : {LOG_N{1'b0}};
end
end
always @(posedge clock) begin
bf2_start <= (bf1_count == (2**(LOG_M-2)-1)) & bf1_sp_en;
end
assign bf2_end = (bf2_count == (2**LOG_N-1));
always @(posedge clock) begin
bf2_do_re <= bf2_sp_re;
bf2_do_im <= bf2_sp_im;
end
always @(posedge clock or posedge reset) begin
if (reset) begin
bf2_do_en <= 1'b0;
end else begin
bf2_do_en <= bf2_sp_en;
end
end
//----------------------------------------------------------------------
// Multiplication
//----------------------------------------------------------------------
assign tw_sel[1] = bf2_count[LOG_M-2];
assign tw_sel[0] = bf2_count[LOG_M-1];
assign tw_num = bf2_count << (LOG_N-LOG_M);
assign tw_addr = tw_num * tw_sel;
Twiddle #(
.WIDTH (WIDTH)
) TW (
.clock (clock ), // i
.addr (tw_addr), // i
.tw_re (tw_re ), // o
.tw_im (tw_im ) // o
);
// Multiplication is bypassed when twiddle address is 0.
always @(posedge clock) begin
mu_en <= (tw_addr != {LOG_N{1'b0}});
end
// Set unknown value x for verification
assign mu_a_re = mu_en ? bf2_do_re : {WIDTH{1'bx}};
assign mu_a_im = mu_en ? bf2_do_im : {WIDTH{1'bx}};
Multiply #(.WIDTH(WIDTH)) MU (
.a_re (mu_a_re), // i
.a_im (mu_a_im), // i
.b_re (tw_re ), // i
.b_im (tw_im ), // i
.m_re (mu_m_re), // o
.m_im (mu_m_im) // o
);
always @(posedge clock) begin
mu_do_re <= mu_en ? mu_m_re : bf2_do_re;
mu_do_im <= mu_en ? mu_m_im : bf2_do_im;
end
always @(posedge clock or posedge reset) begin
if (reset) begin
mu_do_en <= 1'b0;
end else begin
mu_do_en <= bf2_do_en;
end
end
// No multiplication required at final stage
assign do_en = (LOG_M == 2) ? bf2_do_en : mu_do_en;
assign do_re = (LOG_M == 2) ? bf2_do_re : mu_do_re;
assign do_im = (LOG_M == 2) ? bf2_do_im : mu_do_im;
endmodule

1065
rtl/ip/fft/Twiddle1024_32B.v Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,399 @@
`define FFT_CSR_ADDR 16'hc000
`define FFT_IN_RE_BASE 16'h8000
`define FFT_IN_IM_BASE 16'h9000
`define FFT_OUT_RE_BASE 16'ha000
`define FFT_OUT_IM_BASE 16'hb000
module fft_controller #(
parameter FFT_LEN = 1024, // FFT处理长度
parameter BRAM_RD_LATENCY = 1, // 适配 BRAM 的读延迟 (通常 Block RAM 开启输出寄存器为 1)
parameter FFT_DATA_WIDTH = 16
)(
input aclk,
input aresetn,
// AXI Lite / AXI4 Wrapper ports
input [4 :0] s_awid,
input [31:0] s_awaddr,
input [7 :0] s_awlen,
input [2 :0] s_awsize,
input [1 :0] s_awburst,
input s_awlock,
input [3 :0] s_awcache,
input [2 :0] s_awprot,
input s_awvalid,
output reg s_awready,
input [4 :0] s_wid,
input [31:0] s_wdata,
input [3 :0] s_wstrb,
input s_wlast,
input s_wvalid,
output reg s_wready,
output [4 :0] s_bid,
output [1 :0] s_bresp,
output reg s_bvalid,
input s_bready,
input [4 :0] s_arid,
input [31:0] s_araddr,
input [7 :0] s_arlen,
input [2 :0] s_arsize,
input [1 :0] s_arburst,
input s_arlock,
input [3 :0] s_arcache,
input [2 :0] s_arprot,
input s_arvalid,
output reg s_arready,
output [4 :0] s_rid,
output reg [31:0] s_rdata,
output [1 :0] s_rresp,
output reg s_rlast,
output reg s_rvalid,
input s_rready,
output fft_finish
);
// AXI Burst 内部寄存器
reg [31:0] aw_addr_reg;
reg [1 :0] aw_burst_reg;
reg [4 :0] aw_id_reg;
reg [31:0] ar_addr_reg;
reg [7 :0] ar_len_reg;
reg [1 :0] ar_burst_reg;
reg [4 :0] ar_id_reg;
reg [7 :0] ar_cnt;
// 写通道状态机 (AW, W, B)
localparam W_IDLE = 2'd0;
localparam W_DATA = 2'd1;
localparam W_RESP = 2'd2;
reg [1:0] w_state;
always @(posedge aclk) begin
if (~aresetn) begin
w_state <= W_IDLE;
s_awready <= 1'b1;
s_wready <= 1'b0;
s_bvalid <= 1'b0;
aw_addr_reg <= 32'h0;
aw_burst_reg <= 2'h0;
aw_id_reg <= 5'h0;
end else begin
case (w_state)
W_IDLE: begin
s_awready <= 1'b1;
if (s_awvalid && s_awready) begin
s_awready <= 1'b0;
s_wready <= 1'b1;
aw_addr_reg <= s_awaddr;
aw_burst_reg <= s_awburst;
aw_id_reg <= s_awid;
w_state <= W_DATA;
end
end
W_DATA: begin
// 接收到有效写数据
if (s_wvalid && s_wready) begin
// INCR 模式下地址递增
if (aw_burst_reg == 2'b01) begin
aw_addr_reg <= aw_addr_reg + 4;
end
// 若是最后一拍,跳转到发送响应
if (s_wlast) begin
s_wready <= 1'b0;
s_bvalid <= 1'b1;
w_state <= W_RESP;
end
end
end
W_RESP: begin
if (s_bvalid && s_bready) begin
s_bvalid <= 1'b0;
s_awready <= 1'b1; // 准备接收下一次写请求
w_state <= W_IDLE;
end
end
default: w_state <= W_IDLE;
endcase
end
end
// 产生有效的写动作脉冲,用于触发 BRAM 写使能
wire w_active = (w_state == W_DATA) && s_wvalid && s_wready;
assign s_bid = aw_id_reg;
assign s_bresp = 2'b00;
// 读通道状态机(AR, R)
localparam R_IDLE = 2'd0;
localparam R_WAIT = 2'd1;
localparam R_DATA = 2'd2;
reg [1:0] r_state;
reg [3:0] r_wait_cnt;
always @(posedge aclk) begin
if (~aresetn) begin
r_state <= R_IDLE;
s_arready <= 1'b1;
s_rvalid <= 1'b0;
s_rlast <= 1'b0;
ar_addr_reg <= 32'h0;
ar_len_reg <= 8'h0;
ar_burst_reg <= 2'h0;
ar_id_reg <= 5'h0;
ar_cnt <= 8'h0;
r_wait_cnt <= 4'h0;
end else begin
case (r_state)
R_IDLE: begin
s_arready <= 1'b1;
if (s_arvalid && s_arready) begin
s_arready <= 1'b0;
ar_addr_reg <= s_araddr;
ar_len_reg <= s_arlen;
ar_burst_reg <= s_arburst;
ar_id_reg <= s_arid;
ar_cnt <= 8'h0;
r_wait_cnt <= BRAM_RD_LATENCY;
r_state <= R_WAIT; // 进入等待以拉取第一笔 BRAM 数据
end
end
R_WAIT: begin
// 等待 BRAM 固定潜伏期结束
if (r_wait_cnt <= 1) begin
s_rvalid <= 1'b1;
s_rlast <= (ar_cnt == ar_len_reg);
r_state <= R_DATA;
r_wait_cnt <= 4'h0;
end else begin
r_wait_cnt <= r_wait_cnt - 1;
end
end
R_DATA: begin
// 数据被总线成功读取
if (s_rvalid && s_rready) begin
if (ar_cnt == ar_len_reg) begin
// Burst 结束
s_rvalid <= 1'b0;
s_rlast <= 1'b0;
s_arready <= 1'b1;
r_state <= R_IDLE;
end else begin
// 准备读取下一拍数据
ar_cnt <= ar_cnt + 1;
// INCR 模式下地址递增
if (ar_burst_reg == 2'b01) begin
ar_addr_reg <= ar_addr_reg + 4;
end
s_rvalid <= 1'b0;
s_rlast <= 1'b0;
r_wait_cnt <= BRAM_RD_LATENCY;
r_state <= R_WAIT; // 再次进入等待状态
end
end
end
default: r_state <= R_IDLE;
endcase
end
end
assign s_rid = ar_id_reg;
assign s_rresp = 2'b00;
// 地址译码
wire hit_in_re = (aw_addr_reg[15:12] == 4'h8);
wire hit_in_im = (aw_addr_reg[15:12] == 4'h9);
wire hit_out_re = (ar_addr_reg[15:12] == 4'ha);
wire hit_out_im = (ar_addr_reg[15:12] == 4'hb);
// 寄存器控制
reg [3:0] fft_ctrl;
reg [3:0] fft_status;
wire [31:0] fft_csr = {24'h0, fft_ctrl, fft_status};
// 只有发生有效的写握手且地址对应 CSR 时,才写入控制寄存器
wire write_fft_csr = w_active && (aw_addr_reg[15:0] == `FFT_CSR_ADDR);
// 状态机
localparam IDLE = 2'd0;
localparam LOAD = 2'd1;
localparam WAIT_OUT = 2'd2;
localparam DONE = 2'd3;
reg [1:0] state, next_state;
reg [10:0] in_cnt;
reg [10:0] out_cnt;
wire do_en;
wire [FFT_DATA_WIDTH-1:0] do_re;
wire [FFT_DATA_WIDTH-1:0] do_im;
always @(posedge aclk) begin
if (~aresetn) state <= IDLE;
else state <= next_state;
end
always @(*) begin
case (state)
IDLE: if (fft_ctrl[0]) next_state = LOAD; else next_state = IDLE;
LOAD: if (in_cnt == FFT_LEN - 1) next_state = WAIT_OUT; else next_state = LOAD;
WAIT_OUT: if (do_en && out_cnt == FFT_LEN - 1) next_state = DONE; else next_state = WAIT_OUT;
DONE: next_state = IDLE;
default: next_state = IDLE;
endcase
end
always @(posedge aclk) begin
if (~aresetn) begin
in_cnt <= 0;
out_cnt <= 0;
end else if (state == IDLE) begin
in_cnt <= 0;
out_cnt <= 0;
end else begin
if (state == LOAD) in_cnt <= in_cnt + 1;
if (do_en) out_cnt <= out_cnt + 1;
end
end
// 更新寄存器与状态
always @(posedge aclk) begin
if (~aresetn) begin
fft_ctrl <= 4'h0;
fft_status <= 4'h0;
end else begin
if (write_fft_csr) begin
fft_ctrl <= s_wdata[7:4];
end else if (state != IDLE) begin
fft_ctrl[0] <= 1'b0;
end
fft_status[0] <= (state != IDLE && state != DONE);
if (write_fft_csr && s_wdata[4]) begin
fft_status[1] <= 1'b0;
end else if (state == DONE) begin
fft_status[1] <= 1'b1;
end
end
end
assign fft_finish = fft_status[1];
// BRAM 接口连线
wire [FFT_DATA_WIDTH-1:0] in_re_dout;
wire [FFT_DATA_WIDTH-1:0] in_im_dout;
wire [FFT_DATA_WIDTH-1:0] out_re_dout;
wire [FFT_DATA_WIDTH-1:0] out_im_dout;
wire [31:0] out_re_sx = {{(32-FFT_DATA_WIDTH){out_re_dout[FFT_DATA_WIDTH-1]}}, out_re_dout};
wire [31:0] out_im_sx = {{(32-FFT_DATA_WIDTH){out_im_dout[FFT_DATA_WIDTH-1]}}, out_im_dout};
my_bram0 #(
.DATA_WIDTH (FFT_DATA_WIDTH),
.ADDR_WIDTH (10)
) u_in0(
.clka (aclk),
.ena (w_active && hit_in_re), // 由 burst写逻辑产生
.wea (1'b1),
.addra (aw_addr_reg[11:2]), // 取当前递增的突发写地址
.dina (s_wdata[FFT_DATA_WIDTH-1:0]),
.clkb (aclk),
.enb (state == LOAD),
.addrb (in_cnt[9:0]),
.doutb (in_re_dout)
);
my_bram0 #(
.DATA_WIDTH (FFT_DATA_WIDTH),
.ADDR_WIDTH (10)
) u_in1(
.clka (aclk),
.ena (w_active && hit_in_im),
.wea (1'b1),
.addra (aw_addr_reg[11:2]),
.dina (s_wdata[FFT_DATA_WIDTH-1:0]),
.clkb (aclk),
.enb (state == LOAD),
.addrb (in_cnt[9:0]),
.doutb (in_im_dout)
);
// 对于输出 BRAM,采用原先的位反转(Bit-reverse)读取逻辑
wire [9:0] b_rd_addr = ar_addr_reg[11:2];
wire [9:0] bit_reversed_index = {
b_rd_addr[0], b_rd_addr[1], b_rd_addr[2], b_rd_addr[3], b_rd_addr[4],
b_rd_addr[5], b_rd_addr[6], b_rd_addr[7], b_rd_addr[8], b_rd_addr[9]
};
my_bram0 #(
.DATA_WIDTH (FFT_DATA_WIDTH),
.ADDR_WIDTH (10)
) u_out0(
.clka (aclk),
.ena (do_en),
.wea (1'b1),
.addra (out_cnt[9:0]),
.dina (do_re),
.clkb (aclk),
.enb (r_state != R_IDLE), // 当处于读突发事务时始终使能 BRAM
.addrb (bit_reversed_index),
.doutb (out_re_dout)
);
my_bram0 #(
.DATA_WIDTH (FFT_DATA_WIDTH),
.ADDR_WIDTH (10)
) u_out1(
.clka (aclk),
.ena (do_en),
.wea (1'b1),
.addra (out_cnt[9:0]),
.dina (do_im),
.clkb (aclk),
.enb (r_state != R_IDLE),
.addrb (bit_reversed_index),
.doutb (out_im_dout)
);
// 支持 1 到 N 拍的读延迟,让 di_en 严格对齐 BRAM 的吐出数据
reg [3:0] di_en_shift;
always @(posedge aclk) begin
if (~aresetn) di_en_shift <= 0;
else di_en_shift <= {di_en_shift[2:0], (state == LOAD)};
end
wire di_en_r = (BRAM_RD_LATENCY == 1) ? di_en_shift[0] :
(BRAM_RD_LATENCY == 2) ? di_en_shift[1] :
(BRAM_RD_LATENCY == 3) ? di_en_shift[2] : di_en_shift[3];
FFT #(
.WIDTH(FFT_DATA_WIDTH)
) u_FFT (
.clock (aclk),
.reset (~aresetn),
.di_en (di_en_r),
.di_re (in_re_dout),
.di_im (in_im_dout),
.do_en (do_en),
.do_re (do_re),
.do_im (do_im)
);
// 读取返回数据选择
wire [31:0] rdata_d =
(ar_addr_reg[15:0] == `FFT_CSR_ADDR) ? fft_csr :
hit_out_re ? out_re_sx :
hit_out_im ? out_im_sx :
32'h0;
always @(*) begin
s_rdata = rdata_d;
end
endmodule

View File

@@ -2,7 +2,8 @@
// 3-stage pipelined multiplier (LUT-based, no DSP)
// latency=3, throughput=1 result/cycle
// ═══════════════════════════════════════════════════════
(* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
(* use_dsp = "no" *)
module pipelined_mult_32x32 (
input clk,
input rstn,
@@ -11,23 +12,7 @@ module pipelined_mult_32x32 (
output reg [63:0] p
);
reg [31:0] a_r, b_r;
(* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
reg [63:0] prod;
function automatic [63:0] lut_mul32;
input [31:0] lhs;
input [31:0] rhs;
integer bit_idx;
reg [63:0] acc;
begin
acc = 64'b0;
for (bit_idx = 0; bit_idx < 32; bit_idx = bit_idx + 1) begin
if (rhs[bit_idx])
acc = acc + ({32'b0, lhs} << bit_idx);
end
lut_mul32 = acc;
end
endfunction
always @(posedge clk) begin
if (!rstn) begin
@@ -36,7 +21,7 @@ module pipelined_mult_32x32 (
end else begin
a_r <= a; // Stage 1: register inputs
b_r <= b;
prod <= lut_mul32(a_r, b_r); // Stage 2: LUT-based multiply
prod <= a_r * b_r; // Stage 2: LUT-based multiply
p <= prod; // Stage 3: register output
end
end
@@ -111,46 +96,13 @@ module matmul_axi_slave (
output reg [31:0] ep_rd_data,
output ep_rd_ready,
// AXI master port for autonomous matrix stream load/store
output reg [3:0] m_axi_awid,
output reg [31:0] m_axi_awaddr,
output reg [7:0] m_axi_awlen,
output reg [2:0] m_axi_awsize,
output reg [1:0] m_axi_awburst,
output reg m_axi_awlock,
output reg [3:0] m_axi_awcache,
output reg [2:0] m_axi_awprot,
output reg m_axi_awvalid,
input m_axi_awready,
output reg [31:0] m_axi_wdata,
output reg [3:0] m_axi_wstrb,
output reg m_axi_wlast,
output reg m_axi_wvalid,
input m_axi_wready,
input [3:0] m_axi_bid,
input [1:0] m_axi_bresp,
input m_axi_bvalid,
output reg m_axi_bready,
output reg [3:0] m_axi_arid,
output reg [31:0] m_axi_araddr,
output reg [7:0] m_axi_arlen,
output reg [2:0] m_axi_arsize,
output reg [1:0] m_axi_arburst,
output reg m_axi_arlock,
output reg [3:0] m_axi_arcache,
output reg [2:0] m_axi_arprot,
output reg m_axi_arvalid,
input m_axi_arready,
input [3:0] m_axi_rid,
input [31:0] m_axi_rdata,
input [1:0] m_axi_rresp,
input m_axi_rlast,
input m_axi_rvalid,
output reg m_axi_rready,
// Direct control from the CDMA/matmul bridge
input mat_start_valid,
input mat_start_bank,
input mat_done_clear,
input mat_crc_clear,
output mat_done,
output mat_crc_idle,
// Interrupt output (active high level, pulsed by calc_done)
output intr
@@ -162,11 +114,6 @@ module matmul_axi_slave (
localparam ADDR_CTRL = 12'h000;
localparam ADDR_STATUS = 12'h004;
localparam ADDR_CRC = 12'h010;
localparam ADDR_DMA_SRC_BASE = 12'h020;
localparam ADDR_DMA_DST_BASE = 12'h024;
localparam ADDR_DMA_GROUPS = 12'h028;
localparam ADDR_DMA_SRC_STRIDE = 12'h02C;
localparam ADDR_DMA_DST_STRIDE = 12'h030;
localparam ADDR_B0_A = 12'h100;
localparam ADDR_B0_B = 12'h140;
@@ -181,9 +128,8 @@ module matmul_axi_slave (
// ==========================================
reg req_0, req_1;
reg busy;
reg [1:0] done_count;
reg done;
reg error;
wire done = (done_count != 2'd0);
reg [31:0] b0_a [0:15];
reg [31:0] b0_b [0:15];
@@ -193,35 +139,11 @@ module matmul_axi_slave (
reg [31:0] b1_b [0:15];
reg [65:0] b1_c [0:15];
reg [31:0] dma_src_base;
reg [31:0] dma_dst_base;
reg [31:0] dma_groups;
reg [31:0] dma_src_stride;
reg [31:0] dma_dst_stride;
reg dma_busy;
reg dma_done;
reg [31:0] load_group;
reg [31:0] store_group;
reg [31:0] dma_next_rd_addr;
reg [31:0] dma_next_wr_addr;
reg [31:0] completed_groups;
reg [1:0] bank_loaded;
reg [1:0] bank_store_pending;
reg [1:0] bank_storing;
reg [1:0] bank_compute_pending;
reg dma_compute_bank;
reg dma_load_bank;
reg dma_store_bank;
reg dma_start_pulse;
reg dma_done_clear_pulse;
reg dma_req0_pulse;
reg dma_req1_pulse;
assign ep_wr_ready = 1'b1;
assign ep_rd_ready = 1'b1;
assign mat_done = done;
wire [3:0] ep_wr_lo_idx = ep_wr_word_addr[3:0];
wire [3:0] ep_wr_hi_idx = ep_wr_word_addr[3:0];
wire [3:0] ep_wr_idx = ep_wr_word_addr[3:0];
wire [7:0] ep_rd_elem_raw = ep_rd_word_addr / 8'd3;
wire [7:0] ep_rd_part_raw = ep_rd_word_addr % 8'd3;
wire [3:0] ep_rd_elem = ep_rd_elem_raw[3:0];
@@ -263,25 +185,43 @@ module matmul_axi_slave (
reg [31:0] crc32_table [0:255];
reg [31:0] crc_reg;
wire crc_dma_valid;
wire [31:0] crc_dma_data;
wire [31:0] crc_stream_data = crc_dma_valid ? crc_dma_data :
(ep_rd_valid ? ep_rd_data : s_axi_rdata);
wire crc_axi_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready &&
((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) ||
(r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0)));
wire crc_ep_valid = ep_rd_valid && ep_rd_ready && (ep_rd_word_addr < 8'd48);
wire crc_stream_valid = crc_axi_valid || crc_ep_valid || crc_dma_valid;
function [31:0] crc32_update_word;
input [31:0] crc_in;
input [31:0] data_in;
reg [31:0] c0;
reg [31:0] c1;
reg [31:0] c2;
begin
c0 = crc32_table[(crc_in[7:0] ^ data_in[7:0])] ^ {8'h00, crc_in[31:8]};
c1 = crc32_table[(c0[7:0] ^ data_in[15:8])] ^ {8'h00, c0[31:8]};
c2 = crc32_table[(c1[7:0] ^ data_in[23:16])] ^ {8'h00, c1[31:8]};
crc32_update_word = crc32_table[(c2[7:0] ^ data_in[31:24])] ^
{8'h00, c2[31:8]};
end
endfunction
wire [31:0] crc_t0, crc_c0, crc_t1, crc_c1, crc_t2, crc_c2, crc_t3, crc_next;
assign crc_t0 = crc32_table[(crc_reg[7:0] ^ crc_stream_data[7:0])];
assign crc_c0 = crc_t0 ^ {8'h00, crc_reg[31:8]};
assign crc_t1 = crc32_table[(crc_c0[7:0] ^ crc_stream_data[15:8])];
assign crc_c1 = crc_t1 ^ {8'h00, crc_c0[31:8]};
assign crc_t2 = crc32_table[(crc_c1[7:0] ^ crc_stream_data[23:16])];
assign crc_c2 = crc_t2 ^ {8'h00, crc_c1[31:8]};
assign crc_t3 = crc32_table[(crc_c2[7:0] ^ crc_stream_data[31:24])];
assign crc_next = crc_t3 ^ {8'h00, crc_c2[31:8]};
function [31:0] crc32_update_6bytes;
input [31:0] crc_in;
input [47:0] data_in;
reg [31:0] c;
integer byte_idx;
begin
c = crc_in;
for (byte_idx = 0; byte_idx < 6; byte_idx = byte_idx + 1)
c = crc32_table[(c[7:0] ^ data_in[byte_idx*8 +: 8])] ^
{8'h00, c[31:8]};
crc32_update_6bytes = c;
end
endfunction
localparam CRC_FIFO_DEPTH = 32;
reg [65:0] crc_fifo [0:CRC_FIFO_DEPTH-1];
reg [4:0] crc_fifo_wr_ptr;
reg [4:0] crc_fifo_rd_ptr;
reg [5:0] crc_fifo_count;
reg crc_c66_busy;
reg [65:0] crc_c66_data;
reg [31:0] crc_c66_half;
initial begin
crc32_table[0 ] = 32'h00000000; crc32_table[1 ] = 32'h77073096;
@@ -437,51 +377,10 @@ module matmul_axi_slave (
reg [1:0] state;
reg cur_bank;
reg calc_done_pulse;
localparam DMA_RD_IDLE = 2'd0;
localparam DMA_RD_ADDR = 2'd1;
localparam DMA_RD_DATA = 2'd2;
reg [1:0] dma_rd_state;
reg [4:0] dma_rd_count;
reg dma_rd_bank;
wire [3:0] dma_rd_word_idx = dma_rd_count[3:0];
wire dma_rd_commit = (dma_rd_state == DMA_RD_DATA) && m_axi_rvalid && m_axi_rready;
localparam DMA_WR_IDLE = 2'd0;
localparam DMA_WR_ADDR = 2'd1;
localparam DMA_WR_DATA = 2'd2;
localparam DMA_WR_RESP = 2'd3;
reg [1:0] dma_wr_state;
reg [5:0] dma_wr_count;
wire [7:0] dma_wr_elem_raw = dma_wr_count / 6'd3;
wire [7:0] dma_wr_part_raw = dma_wr_count % 6'd3;
wire [3:0] dma_wr_elem = dma_wr_elem_raw[3:0];
wire [1:0] dma_wr_part = dma_wr_part_raw[1:0];
wire [65:0] dma_wr_c0 = b0_c[dma_wr_elem];
wire [65:0] dma_wr_c1 = b1_c[dma_wr_elem];
wire [65:0] dma_wr_c = dma_store_bank ? dma_wr_c1 : dma_wr_c0;
wire [31:0] dma_wr_word =
(dma_wr_part == 2'd0) ? dma_wr_c[31:0] :
(dma_wr_part == 2'd1) ? dma_wr_c[63:32] :
{30'b0, dma_wr_c[65:64]};
wire [5:0] dma_wr_next_count = dma_wr_count + 6'd1;
wire [7:0] dma_wr_next_elem_raw = dma_wr_next_count / 6'd3;
wire [7:0] dma_wr_next_part_raw = dma_wr_next_count % 6'd3;
wire [3:0] dma_wr_next_elem = dma_wr_next_elem_raw[3:0];
wire [1:0] dma_wr_next_part = dma_wr_next_part_raw[1:0];
wire [65:0] dma_wr_next_c0 = b0_c[dma_wr_next_elem];
wire [65:0] dma_wr_next_c1 = b1_c[dma_wr_next_elem];
wire [65:0] dma_wr_next_c = dma_store_bank ? dma_wr_next_c1 : dma_wr_next_c0;
wire [31:0] dma_wr_word_next =
(dma_wr_next_part == 2'd0) ? dma_wr_next_c[31:0] :
(dma_wr_next_part == 2'd1) ? dma_wr_next_c[63:32] :
{30'b0, dma_wr_next_c[65:64]};
// 【修改点 1】单独引出一个写脉冲信号给 CRC 清零用
wire crc_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC);
wire done_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready &&
(w_offset == ADDR_STATUS) && s_axi_wdata[1];
wire crc_clear_pulse = ((w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC)) ||
mat_crc_clear;
always @(posedge clk) begin
if (!resetn) begin
@@ -491,55 +390,39 @@ module matmul_axi_slave (
s_axi_bvalid <= 1'b0;
req_0 <= 1'b0;
req_1 <= 1'b0;
done_count <= 2'd0;
done <= 1'b0;
error <= 1'b0;
dma_src_base <= 32'd0;
dma_dst_base <= 32'd0;
dma_groups <= 32'd0;
dma_src_stride <= 32'd128;
dma_dst_stride <= 32'd192;
dma_start_pulse <= 1'b0;
dma_done_clear_pulse <= 1'b0;
end else begin
dma_start_pulse <= 1'b0;
dma_done_clear_pulse <= 1'b0;
if (ep_wr_valid && ep_wr_ready) begin
if (ep_wr_bank[0] == 1'b0) begin
if (ep_wr_word_addr < 8'd16)
b0_a[ep_wr_lo_idx] <= ep_wr_data;
else if (ep_wr_word_addr < 8'd32)
b0_b[ep_wr_hi_idx] <= ep_wr_data;
else
error <= 1'b1;
end else begin
if (ep_wr_word_addr < 8'd16)
b1_a[ep_wr_lo_idx] <= ep_wr_data;
else if (ep_wr_word_addr < 8'd32)
b1_b[ep_wr_hi_idx] <= ep_wr_data;
else
error <= 1'b1;
end
end
if (dma_rd_commit) begin
if (dma_rd_bank == 1'b0) begin
if (dma_rd_count < 5'd16)
b0_a[dma_rd_word_idx] <= m_axi_rdata;
else
b0_b[dma_rd_word_idx] <= m_axi_rdata;
end else begin
if (dma_rd_count < 5'd16)
b1_a[dma_rd_word_idx] <= m_axi_rdata;
else
b1_b[dma_rd_word_idx] <= m_axi_rdata;
end
end
if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0;
if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0;
if (dma_req0_pulse) req_0 <= 1'b1;
if (dma_req1_pulse) req_1 <= 1'b1;
if (mat_start_valid) begin
if (mat_start_bank) req_1 <= 1'b1;
else req_0 <= 1'b1;
end
if (calc_done_pulse) begin
done <= 1'b1;
end
if (mat_done_clear) begin
done <= 1'b0;
error <= 1'b0;
end
if (ep_wr_valid && ep_wr_ready) begin
if (ep_wr_word_addr < 8'd16) begin
if (ep_wr_bank[0] == 1'b0)
b0_a[ep_wr_idx] <= ep_wr_data;
else
b1_a[ep_wr_idx] <= ep_wr_data;
end else if (ep_wr_word_addr < 8'd32) begin
if (ep_wr_bank[0] == 1'b0)
b0_b[ep_wr_idx] <= ep_wr_data;
else
b1_b[ep_wr_idx] <= ep_wr_data;
end
end
case (w_state)
W_IDLE: begin
@@ -558,22 +441,11 @@ module matmul_axi_slave (
if (w_offset == ADDR_CTRL) begin
if (s_axi_wdata[0]) req_0 <= 1'b1;
if (s_axi_wdata[1]) req_1 <= 1'b1;
if (s_axi_wdata[8]) dma_start_pulse <= 1'b1;
end
else if (w_offset == ADDR_STATUS) begin
if (s_axi_wdata[1]) done <= 1'b0;
if (s_axi_wdata[2]) error <= 1'b0;
if (s_axi_wdata[4]) dma_done_clear_pulse <= 1'b1;
end
else if (w_offset == ADDR_DMA_SRC_BASE)
dma_src_base <= apply_wstrb(dma_src_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_DST_BASE)
dma_dst_base <= apply_wstrb(dma_dst_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_GROUPS)
dma_groups <= apply_wstrb(dma_groups, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_SRC_STRIDE)
dma_src_stride <= apply_wstrb(dma_src_stride, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_DST_STRIDE)
dma_dst_stride <= apply_wstrb(dma_dst_stride, s_axi_wdata, s_axi_wstrb);
// 【修改点 2】删除 else if (w_offset == ADDR_CRC) { crc_reg <= ... } 防止多重驱动
else if (w_offset >= ADDR_B0_A && w_offset < ADDR_B0_B)
b0_a[(w_offset - ADDR_B0_A) >> 2] <= apply_wstrb(b0_a[(w_offset - ADDR_B0_A) >> 2], s_axi_wdata, s_axi_wstrb);
@@ -605,12 +477,6 @@ module matmul_axi_slave (
end
default: w_state <= W_IDLE;
endcase
case ({calc_done_pulse, done_clear_pulse})
2'b10: if (done_count != 2'd3) done_count <= done_count + 2'd1;
2'b01: if (done_count != 2'd0) done_count <= done_count - 2'd1;
default: done_count <= done_count;
endcase
end
end
@@ -667,7 +533,7 @@ module matmul_axi_slave (
end
R_DATA: begin
if (s_axi_rvalid && s_axi_rready) begin
// 【修改点 3】删掉直接赋值 crc_stream_valid 的逻辑,移至专用 Pipeline 块
// CRC is updated from completed compute results, not from C reads.
if (r_cnt == r_len) begin
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
@@ -695,17 +561,7 @@ module matmul_axi_slave (
else if (current_r_offset == ADDR_CRC)
s_axi_rdata = crc_reg ^ 32'hFFFFFFFF;
else if (current_r_offset == ADDR_STATUS)
s_axi_rdata = {27'b0, dma_done, dma_busy, error, done, busy};
else if (current_r_offset == ADDR_DMA_SRC_BASE)
s_axi_rdata = dma_src_base;
else if (current_r_offset == ADDR_DMA_DST_BASE)
s_axi_rdata = dma_dst_base;
else if (current_r_offset == ADDR_DMA_GROUPS)
s_axi_rdata = dma_groups;
else if (current_r_offset == ADDR_DMA_SRC_STRIDE)
s_axi_rdata = dma_src_stride;
else if (current_r_offset == ADDR_DMA_DST_STRIDE)
s_axi_rdata = dma_dst_stride;
s_axi_rdata = {29'b0, error, done, busy};
else if (current_r_offset >= ADDR_B0_A && current_r_offset < ADDR_B0_B)
s_axi_rdata = b0_a[(current_r_offset - ADDR_B0_A) >> 2];
else if (current_r_offset >= ADDR_B0_B && current_r_offset < ADDR_B0_C)
@@ -727,17 +583,6 @@ module matmul_axi_slave (
end
end
// CRC register: update on each C data read beat, clear on write to 0x010
always @(posedge clk) begin
if (!resetn) begin
crc_reg <= 32'hFFFFFFFF;
end else if (crc_clear_pulse) begin
crc_reg <= 32'hFFFFFFFF;
end else if (crc_stream_valid) begin
crc_reg <= crc_next;
end
end
// ==========================================
// 计算引擎 (Compute FSM)
// ==========================================
@@ -763,16 +608,33 @@ module matmul_axi_slave (
reg acc_bank_d1, acc_bank_d2, acc_bank_d3, acc_bank_d4;
reg acc_valid_d1, acc_valid_d2, acc_valid_d3, acc_valid_d4;
reg [4:0] pipe_cnt;
wire [65:0] calc_c_result = ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
wire crc_fifo_empty = (crc_fifo_count == 6'd0);
wire crc_fifo_push = acc_valid_d4;
wire crc_fifo_pop = !crc_c66_busy && !crc_fifo_empty;
wire [31:0] crc_c66_first_next =
crc32_update_6bytes(crc_reg, crc_fifo[crc_fifo_rd_ptr][47:0]);
wire [47:0] crc_c66_second_data = {30'b0, crc_c66_data[65:48]};
wire [31:0] crc_c66_final_next =
crc32_update_6bytes(crc_c66_half, crc_c66_second_data);
// Reserve space for results already in the four-stage multiplier pipeline.
wire crc_issue_ready = (crc_fifo_count < 6'd24);
assign mat_crc_idle = crc_fifo_empty && !crc_c66_busy &&
!acc_valid_d1 && !acc_valid_d2 &&
!acc_valid_d3 && !acc_valid_d4;
task start_calc_bank;
input bank;
begin
cur_bank <= bank;
busy <= 1'b1;
state <= C_RUN;
pipe_cnt <= 5'd1;
acc_idx_d1 <= 4'd0;
acc_bank_d1 <= bank;
cur_bank <= bank;
busy <= 1'b1;
state <= C_RUN;
pipe_cnt <= 5'd1;
acc_idx_d1 <= 4'd0;
acc_bank_d1 <= bank;
acc_valid_d1 <= 1'b1;
if (bank == 1'b0) begin
m_in_a[0] <= b0_a[4'd0]; m_in_b[0] <= b0_b[4'd0];
@@ -788,6 +650,49 @@ module matmul_axi_slave (
end
endtask
// Buffer completed C elements so the recursive CRC path is split across
// two cycles without reducing the multiplier's burst throughput.
always @(posedge clk) begin
if (!resetn) begin
crc_reg <= 32'hFFFFFFFF;
crc_fifo_wr_ptr <= 5'd0;
crc_fifo_rd_ptr <= 5'd0;
crc_fifo_count <= 6'd0;
crc_c66_busy <= 1'b0;
crc_c66_data <= 66'd0;
crc_c66_half <= 32'd0;
end else if (crc_clear_pulse) begin
crc_reg <= 32'hFFFFFFFF;
crc_fifo_wr_ptr <= 5'd0;
crc_fifo_rd_ptr <= 5'd0;
crc_fifo_count <= 6'd0;
crc_c66_busy <= 1'b0;
crc_c66_data <= 66'd0;
crc_c66_half <= 32'd0;
end else begin
if (crc_fifo_push) begin
crc_fifo[crc_fifo_wr_ptr] <= calc_c_result;
crc_fifo_wr_ptr <= crc_fifo_wr_ptr + 5'd1;
end
case ({crc_fifo_push, crc_fifo_pop})
2'b10: crc_fifo_count <= crc_fifo_count + 6'd1;
2'b01: crc_fifo_count <= crc_fifo_count - 6'd1;
default: crc_fifo_count <= crc_fifo_count;
endcase
if (crc_c66_busy) begin
crc_reg <= crc_c66_final_next;
crc_c66_busy <= 1'b0;
end else if (crc_fifo_pop) begin
crc_c66_data <= crc_fifo[crc_fifo_rd_ptr];
crc_c66_half <= crc_c66_first_next;
crc_c66_busy <= 1'b1;
crc_fifo_rd_ptr <= crc_fifo_rd_ptr + 5'd1;
end
end
end
always @(posedge clk) begin
if (!resetn) begin
state <= C_IDLE;
@@ -837,48 +742,48 @@ module matmul_axi_slave (
end
C_RUN: begin
// Issue 4 new operands every cycle (pipe_cnt 0-15, 16 rounds)
// Issue one C element per cycle while the CRC result FIFO
// has room for this result and the in-flight pipeline.
if (pipe_cnt < 5'd16) begin
acc_idx_d1 <= pipe_cnt[3:0];
acc_bank_d1 <= cur_bank;
acc_valid_d1 <= 1'b1;
if (cur_bank == 1'b0) begin
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
end else begin
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
if (crc_issue_ready) begin
acc_idx_d1 <= pipe_cnt[3:0];
acc_bank_d1 <= cur_bank;
acc_valid_d1 <= 1'b1;
if (cur_bank == 1'b0) begin
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
end else begin
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
end
pipe_cnt <= pipe_cnt + 5'd1;
end
end
// Accumulate results from 4 cycles ago.
if (acc_valid_d4) begin
if (acc_bank_d4 == 1'b0)
b0_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
b0_c[acc_idx_d4] <= calc_c_result;
else
b1_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
b1_c[acc_idx_d4] <= calc_c_result;
end
if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
calc_done_pulse <= 1'b1;
end
if (pipe_cnt < 5'd16) begin
pipe_cnt <= pipe_cnt + 5'd1;
end else if (cur_bank == 1'b0 && req_1) begin
if (pipe_cnt >= 5'd16 && cur_bank == 1'b0 && req_1) begin
start_calc_bank(1'b1);
end else if (cur_bank == 1'b1 && req_0) begin
end else if (pipe_cnt >= 5'd16 && cur_bank == 1'b1 && req_0) begin
start_calc_bank(1'b0);
end else if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
busy <= 1'b0;
state <= C_IDLE;
end else begin
end else if (pipe_cnt >= 5'd16 && acc_valid_d4 && acc_idx_d4 == 4'd15) begin
busy <= 1'b0;
state <= C_IDLE;
end else if (pipe_cnt >= 5'd16) begin
pipe_cnt <= pipe_cnt + 5'd1;
end
end
@@ -886,212 +791,6 @@ module matmul_axi_slave (
end
end
// ==========================================
// Autonomous AXI master loader/storer
// ==========================================
assign crc_dma_valid = (dma_wr_state == DMA_WR_DATA) && m_axi_wvalid && m_axi_wready;
assign crc_dma_data = m_axi_wdata;
always @(posedge clk) begin
if (!resetn) begin
dma_busy <= 1'b0;
dma_done <= 1'b0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= 32'd0;
dma_next_wr_addr <= 32'd0;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_rd_count <= 5'd0;
dma_rd_bank <= 1'b0;
dma_wr_state <= DMA_WR_IDLE;
dma_wr_count <= 6'd0;
m_axi_arid <= 4'd0;
m_axi_araddr <= 32'd0;
m_axi_arlen <= 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arlock <= 1'b0;
m_axi_arcache <= 4'b0;
m_axi_arprot <= 3'b0;
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
m_axi_awid <= 4'd0;
m_axi_awaddr <= 32'd0;
m_axi_awlen <= 8'd47;
m_axi_awsize <= 3'd2;
m_axi_awburst <= 2'b01;
m_axi_awlock <= 1'b0;
m_axi_awcache <= 4'b0;
m_axi_awprot <= 3'b0;
m_axi_awvalid <= 1'b0;
m_axi_wdata <= 32'd0;
m_axi_wstrb <= 4'hF;
m_axi_wlast <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
end else begin
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
if (dma_done_clear_pulse)
dma_done <= 1'b0;
if (dma_start_pulse && !dma_busy && dma_groups != 32'd0) begin
dma_busy <= 1'b1;
dma_done <= 1'b0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= dma_src_base;
dma_next_wr_addr <= dma_dst_base;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_wr_state <= DMA_WR_IDLE;
end
if (dma_busy) begin
if (state == C_RUN)
bank_compute_pending[cur_bank] <= 1'b0;
if (bank_loaded[0] && !req_0 && !bank_store_pending[0] && !bank_storing[0] &&
!bank_compute_pending[0] && !(state == C_RUN && cur_bank == 1'b0)) begin
dma_req0_pulse <= 1'b1;
bank_loaded[0] <= 1'b0;
bank_compute_pending[0] <= 1'b1;
dma_compute_bank <= 1'b0;
end else if (bank_loaded[1] && !req_1 && !bank_store_pending[1] && !bank_storing[1] &&
!bank_compute_pending[1] && !(state == C_RUN && cur_bank == 1'b1)) begin
dma_req1_pulse <= 1'b1;
bank_loaded[1] <= 1'b0;
bank_compute_pending[1] <= 1'b1;
dma_compute_bank <= 1'b1;
end
end
if (calc_done_pulse && dma_busy) begin
bank_store_pending[cur_bank] <= 1'b1;
end
case (dma_rd_state)
DMA_RD_IDLE: begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
if (dma_busy && load_group < dma_groups && !bank_loaded[dma_load_bank] &&
!bank_compute_pending[dma_load_bank] &&
!((dma_load_bank == 1'b0) ? req_0 : req_1) &&
!(state == C_RUN && cur_bank == dma_load_bank)) begin
dma_rd_bank <= dma_load_bank;
dma_rd_count <= 5'd0;
m_axi_araddr <= dma_next_rd_addr;
m_axi_arlen <= 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arvalid <= 1'b1;
dma_rd_state <= DMA_RD_ADDR;
end
end
DMA_RD_ADDR: begin
if (m_axi_arvalid && m_axi_arready) begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b1;
dma_rd_state <= DMA_RD_DATA;
end
end
DMA_RD_DATA: begin
if (m_axi_rvalid && m_axi_rready) begin
if (m_axi_rlast) begin
m_axi_rready <= 1'b0;
bank_loaded[dma_rd_bank] <= 1'b1;
load_group <= load_group + 32'd1;
dma_next_rd_addr <= dma_next_rd_addr + dma_src_stride;
dma_load_bank <= ~dma_load_bank;
dma_rd_state <= DMA_RD_IDLE;
end else begin
dma_rd_count <= dma_rd_count + 5'd1;
end
end
end
default: dma_rd_state <= DMA_RD_IDLE;
endcase
case (dma_wr_state)
DMA_WR_IDLE: begin
m_axi_awvalid <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
if (dma_busy && bank_store_pending[dma_store_bank]) begin
dma_wr_count <= 6'd0;
bank_store_pending[dma_store_bank] <= 1'b0;
bank_storing[dma_store_bank] <= 1'b1;
m_axi_awaddr <= dma_next_wr_addr;
m_axi_awlen <= 8'd47;
m_axi_awsize <= 3'd2;
m_axi_awburst <= 2'b01;
m_axi_awvalid <= 1'b1;
dma_wr_state <= DMA_WR_ADDR;
end
end
DMA_WR_ADDR: begin
if (m_axi_awvalid && m_axi_awready) begin
m_axi_awvalid <= 1'b0;
m_axi_wvalid <= 1'b1;
m_axi_wdata <= dma_wr_word;
m_axi_wlast <= 1'b0;
dma_wr_state <= DMA_WR_DATA;
end
end
DMA_WR_DATA: begin
if (m_axi_wvalid && m_axi_wready) begin
if (dma_wr_count == 6'd47) begin
m_axi_wvalid <= 1'b0;
m_axi_wlast <= 1'b0;
m_axi_bready <= 1'b1;
dma_wr_state <= DMA_WR_RESP;
end else begin
dma_wr_count <= dma_wr_count + 6'd1;
m_axi_wdata <= dma_wr_word_next;
m_axi_wlast <= (dma_wr_count == 6'd46);
end
end
end
DMA_WR_RESP: begin
if (m_axi_bvalid && m_axi_bready) begin
m_axi_bready <= 1'b0;
bank_storing[dma_store_bank] <= 1'b0;
dma_store_bank <= ~dma_store_bank;
store_group <= store_group + 32'd1;
dma_next_wr_addr <= dma_next_wr_addr + dma_dst_stride;
completed_groups <= completed_groups + 32'd1;
if ((completed_groups + 32'd1) >= dma_groups) begin
dma_busy <= 1'b0;
dma_done <= 1'b1;
end
dma_wr_state <= DMA_WR_IDLE;
end
end
default: dma_wr_state <= DMA_WR_IDLE;
endcase
end
end
assign intr = done;
endmodule

View File

@@ -1,8 +1,9 @@
// comp_decomp_sync.v - ML-KEM coefficient compression/decompression
//
// Streaming: one coefficient per cycle through pipeline_reg.
// Streaming valid/ready interface. The arithmetic is fixed-latency pipelined
// so compression does not infer a long combinational divider/reducer.
// mode=0: compress — round((2^d * x) / Q) mod 2^d
// mode=1: decompress — round((Q * x) / 2^d) mod Q
// mode=1: decompress — round((Q * x) / 2^d)
// Uses round-half-up (round(2.5)=3, round(3.5)=4).
// Integer arithmetic:
// compress: (x * 2^d + Q/2) / Q, lower d bits as result
@@ -24,52 +25,175 @@ module comp_decomp_sync (
input ready_i
);
// 2^d for d in {4,5,10,11}; fits in 12 bits (max 2048)
wire [11:0] two_pow_d;
assign two_pow_d = 12'd1 << d;
localparam [24:0] Q25 = 25'd`Q;
localparam [12:0] K13 = 13'd5039; // floor(2^24 / 3329)
// Product: 12-bit * 12-bit = max 2048*3328 = 6,815,744 → 23 bits (use 24)
wire [23:0] product;
reg [11:0] data_r;
reg valid_r;
// compress: x * 2^d; decompress: x * Q
assign product = mode ? {12'b0, coeff_in} * {12'b0, 12'd3329}
: {12'b0, coeff_in} * {12'b0, two_pow_d};
reg mode_s0;
reg [4:0] d_s0;
reg [11:0] coeff_s0;
reg valid_s0;
// Rounding offset: compress→Q/2=1664; decompress→2^(d-1)
wire [11:0] round_off;
assign round_off = mode ? (two_pow_d >> 1) : 12'd1664;
reg mode_s1;
reg [4:0] d_s1;
reg [23:0] comp_dividend_s1;
reg [23:0] decomp_rounded_s1;
reg valid_s1;
// Dividend = product + round_off (max ~ 6,817,408 fits in 24 bits)
wire [23:0] dividend;
assign dividend = product + {12'b0, round_off};
reg mode_s2;
reg [4:0] d_s2;
reg [23:0] comp_dividend_s2;
(* use_dsp = "no" *) reg [36:0] comp_qprod_est_s2;
reg [23:0] decomp_rounded_s2;
reg valid_s2;
// Divisor: compress→Q=3329; decompress→2^d
wire [11:0] divisor;
assign divisor = mode ? two_pow_d : 12'd3329;
reg mode_s3;
reg [4:0] d_s3;
reg [23:0] comp_dividend_s3;
reg [12:0] comp_q_est_s3;
reg [11:0] decomp_result_s3;
reg valid_s3;
// Integer division (both ops positive → floor)
// Quotient is computed as 24b (widest operand) but fits in 12b
/* verilator lint_off WIDTH */
wire [11:0] div_result;
assign div_result = dividend / {12'b0, divisor};
/* verilator lint_on WIDTH */
reg mode_s4;
reg [4:0] d_s4;
reg [23:0] comp_dividend_s4;
reg [12:0] comp_q_est_s4;
(* use_dsp = "no" *) reg [24:0] comp_q_mul_q_s4;
reg [11:0] decomp_result_s4;
reg valid_s4;
// Final modular reduction
// compress: lower d bits (mask with 2^d - 1)
// decompress: result < Q always, but apply mod Q for safety
wire [11:0] mod_result;
assign mod_result = mode ? (div_result % 12'd3329) : (div_result & (two_pow_d - 1'b1));
reg mode_s5;
reg [4:0] d_s5;
reg [12:0] comp_q_est_s5;
reg [24:0] comp_rem_s5;
reg [11:0] decomp_result_s5;
reg valid_s5;
// Pipeline through valid/ready stage
pipeline_reg #(.DW(12)) u_pipe (
.clk (clk),
.rst_n (rst_n),
.data_i (mod_result),
.valid_i(valid_i),
.ready_o(ready_o),
.data_o (coeff_out),
.valid_o(valid_o),
.ready_i(ready_i)
);
wire fire_i = valid_i && ready_o;
wire pipe_busy = valid_s0 | valid_s1 | valid_s2 | valid_s3 | valid_s4 | valid_s5;
// Fully pipelined: accept one coefficient per cycle. Every stage advances
// unconditionally (valid_sN <= valid_s(N-1)), and the sole consumer ties
// ready_i high, so the output register never needs to backpressure the
// pipeline. Streaming feeders (Encaps C1/C2, Decaps DECOMP) can therefore
// issue a new coeff every cycle instead of draining the 6-stage pipe each
// time. pipe_busy retained only for the legacy drain-based users' info.
assign ready_o = 1'b1;
assign coeff_out = data_r;
assign valid_o = valid_r;
wire [23:0] coeff_ext_s0 = {12'd0, coeff_s0};
wire [23:0] comp_dividend_next = (coeff_ext_s0 << d_s0) + 24'd1664;
(* use_dsp = "no" *) wire [23:0] decomp_product_next = coeff_s0 * 12'd`Q;
wire [23:0] decomp_round_next =
decomp_product_next + ((d_s0 == 5'd0) ? 24'd0 : (24'd1 << (d_s0 - 5'd1)));
wire [12:0] comp_q_corr1_s5 =
comp_q_est_s5 + ((comp_rem_s5 >= Q25) ? 13'd1 : 13'd0);
wire [24:0] comp_rem_corr1_s5 =
(comp_rem_s5 >= Q25) ? (comp_rem_s5 - Q25) : comp_rem_s5;
wire [12:0] comp_q_corr2_s5 =
comp_q_corr1_s5 + ((comp_rem_corr1_s5 >= Q25) ? 13'd1 : 13'd0);
wire [11:0] comp_mask_s5 =
(d_s5 == 5'd0) ? 12'd0 : (12'd1 << d_s5) - 12'd1;
wire [11:0] comp_result_s5 = comp_q_corr2_s5[11:0] & comp_mask_s5;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_r <= 12'd0;
valid_r <= 1'b0;
mode_s0 <= 1'b0;
d_s0 <= 5'd0;
coeff_s0 <= 12'd0;
valid_s0 <= 1'b0;
mode_s1 <= 1'b0;
d_s1 <= 5'd0;
comp_dividend_s1 <= 24'd0;
decomp_rounded_s1 <= 24'd0;
valid_s1 <= 1'b0;
mode_s2 <= 1'b0;
d_s2 <= 5'd0;
comp_dividend_s2 <= 24'd0;
comp_qprod_est_s2 <= 37'd0;
decomp_rounded_s2 <= 24'd0;
valid_s2 <= 1'b0;
mode_s3 <= 1'b0;
d_s3 <= 5'd0;
comp_dividend_s3 <= 24'd0;
comp_q_est_s3 <= 13'd0;
decomp_result_s3 <= 12'd0;
valid_s3 <= 1'b0;
mode_s4 <= 1'b0;
d_s4 <= 5'd0;
comp_dividend_s4 <= 24'd0;
comp_q_est_s4 <= 13'd0;
comp_q_mul_q_s4 <= 25'd0;
decomp_result_s4 <= 12'd0;
valid_s4 <= 1'b0;
mode_s5 <= 1'b0;
d_s5 <= 5'd0;
comp_q_est_s5 <= 13'd0;
comp_rem_s5 <= 25'd0;
decomp_result_s5 <= 12'd0;
valid_s5 <= 1'b0;
end else begin
if (valid_r && ready_i)
valid_r <= 1'b0;
mode_s0 <= mode;
d_s0 <= d;
coeff_s0 <= coeff_in;
valid_s0 <= fire_i;
mode_s1 <= mode_s0;
d_s1 <= d_s0;
comp_dividend_s1 <= comp_dividend_next;
decomp_rounded_s1 <= decomp_round_next;
valid_s1 <= valid_s0;
mode_s2 <= mode_s1;
d_s2 <= d_s1;
comp_dividend_s2 <= comp_dividend_s1;
comp_qprod_est_s2 <= {13'd0, comp_dividend_s1} * K13;
decomp_rounded_s2 <= decomp_rounded_s1;
valid_s2 <= valid_s1;
mode_s3 <= mode_s2;
d_s3 <= d_s2;
comp_dividend_s3 <= comp_dividend_s2;
comp_q_est_s3 <= comp_qprod_est_s2[36:24];
decomp_result_s3 <= decomp_rounded_s2 >> d_s2;
valid_s3 <= valid_s2;
mode_s4 <= mode_s3;
d_s4 <= d_s3;
comp_dividend_s4 <= comp_dividend_s3;
comp_q_est_s4 <= comp_q_est_s3;
comp_q_mul_q_s4 <= comp_q_est_s3 * Q25;
decomp_result_s4 <= decomp_result_s3;
valid_s4 <= valid_s3;
mode_s5 <= mode_s4;
d_s5 <= d_s4;
comp_q_est_s5 <= comp_q_est_s4;
comp_rem_s5 <= {1'b0, comp_dividend_s4} - comp_q_mul_q_s4;
decomp_result_s5 <= decomp_result_s4;
valid_s5 <= valid_s4;
if (valid_s5) begin
data_r <= mode_s5 ? decomp_result_s5 : comp_result_s5;
valid_r <= 1'b1;
end
end
end
endmodule

View File

@@ -6,6 +6,7 @@
// Pure combinational, single-cycle latency.
// All multiplication widths explicitly controlled to avoid Verilog truncation.
(* use_dsp = "no" *)
module barrett_mul (
input [11:0] a,
@@ -18,7 +19,7 @@ module barrett_mul (
// Full product: a * b (both < 3329, product < 11,082,241 < 2^24)
// Force 24-bit evaluation by extending operand
wire [23:0] p;
(* use_dsp = "no" *) wire [23:0] p;
assign p = {12'd0, a} * b;
// Extend p to 37 bits for multiplication with K
@@ -28,14 +29,14 @@ module barrett_mul (
// Compute t_shifted = (p * K) >> 24
// Use explicit wire for the product to control width
/* verilator lint_off UNUSED */
wire [36:0] t_product;
(* use_dsp = "no" *) wire [36:0] t_product;
/* verilator lint_on UNUSED */
assign t_product = p_ext * K;
wire [12:0] t_shifted;
assign t_shifted = t_product[36:R];
// q_approx = t_shifted * Q
wire [24:0] q_approx;
(* use_dsp = "no" *) wire [24:0] q_approx;
assign q_approx = t_shifted * Q;
// r = p - q_approx

View File

@@ -0,0 +1,73 @@
// barrett_mul_pipe.v - DSP-friendly pipelined Barrett modular multiply
//
// Computes product = a * b mod Q with fixed latency. This module is used on
// timing-critical NTT paths; the legacy barrett_mul remains combinational for
// older users.
(* use_dsp = "no" *)
module barrett_mul_pipe (
input clk,
input rst_n,
input valid_i,
input [11:0] a,
input [11:0] b,
output [11:0] product,
output valid_o
);
localparam [24:0] Q25 = 25'd3329;
localparam [12:0] K13 = 13'd5039;
(* use_dsp = "no" *) reg [23:0] p_s1;
reg [23:0] p_s2;
(* use_dsp = "no" *) reg [36:0] tk_s2;
reg [23:0] p_s3;
reg [12:0] q_s3;
reg [24:0] p_s4;
(* use_dsp = "no" *) reg [24:0] qprod_s4;
reg [24:0] r0_s5;
reg [24:0] r1_s6;
reg [11:0] product_r;
reg [6:0] valid_sr;
assign product = product_r;
assign valid_o = valid_sr[6];
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
p_s1 <= 24'd0;
p_s2 <= 24'd0; tk_s2 <= 37'd0;
p_s3 <= 24'd0; q_s3 <= 13'd0;
p_s4 <= 25'd0; qprod_s4 <= 25'd0;
r0_s5 <= 25'd0; r1_s6 <= 25'd0;
product_r <= 12'd0;
valid_sr <= 7'd0;
end else begin
valid_sr <= {valid_sr[5:0], valid_i};
// S1: full product.
p_s1 <= {12'd0, a} * b;
// S2: quotient-estimate product.
p_s2 <= p_s1;
tk_s2 <= {13'd0, p_s1} * K13;
// S3: quotient estimate.
p_s3 <= p_s2;
q_s3 <= tk_s2[36:24];
// S4: q * Q.
p_s4 <= {1'b0, p_s3};
qprod_s4 <= q_s3 * Q25;
// S5/S6/S7: subtract q*Q and conditionally subtract Q twice.
r0_s5 <= p_s4 - qprod_s4;
r1_s6 <= (r0_s5 >= Q25) ? (r0_s5 - Q25) : r0_s5;
product_r <= (r1_s6 >= Q25) ? (r1_s6 - Q25) : r1_s6[11:0];
end
end
endmodule

View File

@@ -0,0 +1,89 @@
// butterfly_unit_pipe.v - pipelined Cooley-Tukey / Gentleman-Sande butterfly
//
// Fixed-latency wrapper around barrett_mul_pipe. All arithmetic that used to
// sit in one NTT cycle is now split by registers.
module butterfly_unit_pipe (
input clk,
input rst_n,
input valid_i,
input [11:0] a,
input [11:0] b,
input [11:0] zeta,
input mode, // 0 = forward NTT, 1 = inverse NTT
output [11:0] a_out,
output [11:0] b_out,
output valid_o
);
localparam [11:0] Q12 = 12'd3329;
localparam [12:0] Q13 = 13'd3329;
// Plan A: register the inputs. Operands arrive combinationally from the
// coeff_bram read; without this stage the path coeff_bram-read -> diff ->
// first multiply stage sits in one cycle (the mlkem_clk critical path at
// 100 MHz). Registering here splits it into (BRAM read -> reg) and
// (reg -> diff -> multiply). Adds one pipeline cycle (absorbed by the NTT
// writeback delay line).
reg [11:0] a_r, b_r, zeta_r;
reg mode_ri, vld_r;
wire [11:0] diff = (b_r >= a_r) ? (b_r - a_r) : (b_r - a_r + Q12);
wire [11:0] mul_data = mode_ri ? diff : b_r;
wire [11:0] mul_result;
wire mul_valid;
barrett_mul_pipe u_barrett (
.clk(clk),
.rst_n(rst_n),
.valid_i(vld_r),
.a(zeta_r),
.b(mul_data),
.product(mul_result),
.valid_o(mul_valid)
);
// a/b/mode delay lines (fed from the REGISTERED inputs a_r/b_r/mode_ri so
// a_d6 aligns with mul_valid = valid_i delayed 8).
reg [11:0] a_d0, a_d1, a_d2, a_d3, a_d4, a_d5, a_d6;
reg [11:0] b_d0, b_d1, b_d2, b_d3, b_d4, b_d5, b_d6;
reg mode_d0, mode_d1, mode_d2, mode_d3, mode_d4, mode_d5, mode_d6;
reg [11:0] a_out_r, b_out_r;
reg valid_r;
wire [12:0] a_sum = {1'b0, a_d6} + {1'b0, (mode_d6 ? b_d6 : mul_result)};
wire [11:0] a_mod = (a_sum >= Q13) ? (a_sum[11:0] - Q12) : a_sum[11:0];
wire [11:0] b_sub = (a_d6 >= mul_result) ? (a_d6 - mul_result) :
(a_d6 - mul_result + Q12);
assign a_out = a_out_r;
assign b_out = b_out_r;
assign valid_o = valid_r;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
a_r <= 12'd0; b_r <= 12'd0; zeta_r <= 12'd0; mode_ri <= 1'b0; vld_r <= 1'b0;
a_d0 <= 12'd0; a_d1 <= 12'd0; a_d2 <= 12'd0; a_d3 <= 12'd0; a_d4 <= 12'd0; a_d5 <= 12'd0; a_d6 <= 12'd0;
b_d0 <= 12'd0; b_d1 <= 12'd0; b_d2 <= 12'd0; b_d3 <= 12'd0; b_d4 <= 12'd0; b_d5 <= 12'd0; b_d6 <= 12'd0;
mode_d0 <= 1'b0; mode_d1 <= 1'b0; mode_d2 <= 1'b0; mode_d3 <= 1'b0; mode_d4 <= 1'b0; mode_d5 <= 1'b0; mode_d6 <= 1'b0;
a_out_r <= 12'd0;
b_out_r <= 12'd0;
valid_r <= 1'b0;
end else begin
// input register stage
a_r <= a; b_r <= b; zeta_r <= zeta; mode_ri <= mode; vld_r <= valid_i;
a_d0 <= a_r; a_d1 <= a_d0; a_d2 <= a_d1; a_d3 <= a_d2; a_d4 <= a_d3; a_d5 <= a_d4; a_d6 <= a_d5;
b_d0 <= b_r; b_d1 <= b_d0; b_d2 <= b_d1; b_d3 <= b_d2; b_d4 <= b_d3; b_d5 <= b_d4; b_d6 <= b_d5;
mode_d0 <= mode_ri; mode_d1 <= mode_d0; mode_d2 <= mode_d1;
mode_d3 <= mode_d2; mode_d4 <= mode_d3; mode_d5 <= mode_d4; mode_d6 <= mode_d5;
valid_r <= mul_valid;
if (mul_valid) begin
a_out_r <= a_mod;
b_out_r <= mode_d6 ? mul_result : b_sub;
end
end
end
endmodule

View File

@@ -0,0 +1,113 @@
// coeff_bram_4way.v - 4-way conflict-free banked storage for NTT coefficients
//
// Replaces the 256x12 LUT register file (reg [11:0] cr [0:255]) with 4 BRAM
// banks (each 128x12 via sd_bram), removing the large multi-port LUT mux tree.
//
// Bank function: bank(a) = { a[0], ^a[7:1] } (bit0 XOR parity of upper 7 bits)
// local(a) = a[7:1] (7-bit index into the 128-deep bank)
//
// This function makes a dual-butterfly's four simultaneous coefficient accesses
// {j, j+1, j+len, j+1+len} land in four DISTINCT banks for every ML-KEM NTT
// layer_len in {2,4,...,128}: j is even and len is even, so
// j -> {0, P }
// j+1 -> {1, P }
// j+len -> {0, P'} (flipping bit m>=1 flips the upper-bits parity)
// j+1+len -> {1, P'}
// with P != P'. Four distinct banks => 4 conflict-free reads/cycle from four
// single-read-port banks, and likewise 4 conflict-free writes/cycle. Each bank
// therefore needs only 1 read + 1 write per cycle (an sd_bram), no ping-pong.
//
// Read latency is 1 cycle (sd_bram registered read): present rd_addr_k this
// cycle, rd_data_k valid next cycle. Writes commit on the presenting cycle.
//
// NOTE: the caller must guarantee the four read addresses map to four distinct
// banks (true for the NTT butterfly pattern) and the four write addresses too.
// Sequential access (load/output) uses a single port and is always safe.
module coeff_bram_4way (
input clk, rst_n,
// Four read addresses (global 8-bit); data returns 1 cycle later.
input [7:0] rd_addr_0, rd_addr_1, rd_addr_2, rd_addr_3,
output [11:0] rd_data_0, rd_data_1, rd_data_2, rd_data_3,
// Four write ports.
input wr_en_0, wr_en_1, wr_en_2, wr_en_3,
input [7:0] wr_addr_0, wr_addr_1, wr_addr_2, wr_addr_3,
input [11:0] wr_data_0, wr_data_1, wr_data_2, wr_data_3
);
// Bank id and local index for an address.
function [1:0] bank_id;
input [7:0] a;
bank_id = {a[0], ^a[7:1]};
endfunction
wire [1:0] rb0 = bank_id(rd_addr_0);
wire [1:0] rb1 = bank_id(rd_addr_1);
wire [1:0] rb2 = bank_id(rd_addr_2);
wire [1:0] rb3 = bank_id(rd_addr_3);
wire [1:0] wb0 = bank_id(wr_addr_0);
wire [1:0] wb1 = bank_id(wr_addr_1);
wire [1:0] wb2 = bank_id(wr_addr_2);
wire [1:0] wb3 = bank_id(wr_addr_3);
// Per-bank read-address crossbar: bank b reads the local index of whichever
// read port targets it (exactly one, by construction).
wire [6:0] bank_rd_local [0:3];
wire [6:0] bank_wr_local [0:3];
wire bank_wr_en [0:3];
wire [11:0] bank_wr_data [0:3];
wire [11:0] bank_rd_data [0:3];
genvar b;
generate
for (b = 0; b < 4; b = b + 1) begin : gen_xbar
// read address route (priority: 3>2>1>0; ties impossible for NTT)
assign bank_rd_local[b] =
(rb3 == b[1:0]) ? rd_addr_3[7:1] :
(rb2 == b[1:0]) ? rd_addr_2[7:1] :
(rb1 == b[1:0]) ? rd_addr_1[7:1] :
rd_addr_0[7:1];
// write route
wire m0 = wr_en_0 && (wb0 == b[1:0]);
wire m1 = wr_en_1 && (wb1 == b[1:0]);
wire m2 = wr_en_2 && (wb2 == b[1:0]);
wire m3 = wr_en_3 && (wb3 == b[1:0]);
assign bank_wr_en[b] = m0 | m1 | m2 | m3;
assign bank_wr_local[b] =
m3 ? wr_addr_3[7:1] :
m2 ? wr_addr_2[7:1] :
m1 ? wr_addr_1[7:1] : wr_addr_0[7:1];
assign bank_wr_data[b] =
m3 ? wr_data_3 :
m2 ? wr_data_2 :
m1 ? wr_data_1 : wr_data_0;
sd_bram #(.W(12), .D(128), .A(7)) u_bank (
.clk(clk),
.rd_addr(bank_rd_local[b]),
.rd_data(bank_rd_data[b]),
.wr_en(bank_wr_en[b]),
.wr_addr(bank_wr_local[b]),
.wr_data(bank_wr_data[b])
);
end
endgenerate
// Register the read bank-ids to align with sd_bram's 1-cycle read latency,
// then route each bank's output back to the requesting read port.
reg [1:0] rb0_r, rb1_r, rb2_r, rb3_r;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rb0_r <= 2'd0; rb1_r <= 2'd0; rb2_r <= 2'd0; rb3_r <= 2'd0;
end else begin
rb0_r <= rb0; rb1_r <= rb1; rb2_r <= rb2; rb3_r <= rb3;
end
end
assign rd_data_0 = bank_rd_data[rb0_r];
assign rd_data_1 = bank_rd_data[rb1_r];
assign rd_data_2 = bank_rd_data[rb2_r];
assign rd_data_3 = bank_rd_data[rb3_r];
endmodule

View File

@@ -1,8 +1,18 @@
// ntt_core.v - NTT core with individual coefficient registers
// ntt_core.v - NTT core with 4-way banked BRAM coefficient storage
//
// Uses 256 individual 12-bit registers and generate-based muxing
// to avoid any part-select simulation issues.
// 3-cycle butterfly: SetAddr -> Read -> Compute+Write
// Coefficient storage moved from a 256x12 LUT register file to coeff_bram_4way
// (4 x 128x12 sd_bram, conflict-free banked). This removes the large multi-port
// LUT mux tree. Two pipelined butterflies (R1) still issue one pair/cycle.
//
// Because BRAM reads are synchronous (1-cycle latency), the compute pipeline
// gains one stage:
// READ (present rd addrs from j) -> FEED butterflies (t+1, rd_data valid)
// -> 8-stage Barrett butterfly -> WRITEBACK (t+9) into the write buffer.
// Read and writeback hit disjoint banks (butterfly index sets in a layer are
// disjoint), so each bank does 1 read + 1 write per cycle (sd_bram = 1R1W).
//
// LOAD/OUTPUT/OUT_SCALE stream through a single bank port with 1-cycle read
// latency (ready_i is tied high by all NTT consumers, so no output backpressure).
module ntt_core (
input clk, rst_n,
@@ -17,116 +27,270 @@ module ntt_core (
);
localparam N = 256, LAYERS = 7, DW = 12;
// Individual coefficient registers
reg [DW-1:0] cr [0:N-1];
integer ci;
localparam S_IDLE = 4'd0;
localparam S_LOAD = 4'd1;
localparam S_CMP_RUN = 4'd2;
localparam S_CMP_DRAIN = 4'd3;
localparam S_OUT_PREP = 4'd7;
localparam S_OUTPUT = 4'd8;
localparam S_OUT_SCALE = 4'd9;
localparam S_DONE = 4'd10;
// State machine
localparam S_IDLE=3'd0, S_LOAD=3'd1, S_CMP_A=3'd2, S_CMP_B=3'd3,
S_CMP_C=3'd4, S_OUTPUT=3'd5, S_DONE=3'd6;
reg [2:0] state, next_state;
reg [3:0] state, next_state;
reg [7:0] load_cnt, out_cnt;
reg [7:0] load_cnt;
reg [8:0] out_rptr; // output read address pointer (0..256)
reg [8:0] out_cnt; // output coeffs emitted (0..256)
reg [8:0] scale_rptr; // scale read address pointer
reg [8:0] scale_issue_cnt; // coeffs fed to scale barrett
reg [8:0] scale_emit_cnt; // coeffs emitted from scale barrett
reg [7:0] j, start, layer_len;
reg [6:0] zeta_idx;
reg [2:0] layer;
reg bf_done;
reg mode_r;
reg layer_issue_done;
reg [5:0] bf_inflight;
// Pipeline registers
reg [DW-1:0] r_a, r_b;
reg [7:0] r_wa, r_wb;
reg rd_fire_r; // issue_fire delayed 1 (BRAM read latency) -> feed
// 9-deep writeback address delay lines (BRAM read + 8-stage butterfly).
reg [7:0] a0d[0:9]; reg [7:0] b0d[0:9];
reg [7:0] a1d[0:9]; reg [7:0] b1d[0:9];
integer k;
reg [DW-1:0] coeff_out_r;
reg valid_o_r;
reg scale_valid_i;
reg [DW-1:0] scale_a_i;
reg [DW-1:0] zeta_fed; // zeta aligned to BRAM read data (1 cyc after present)
// Zeta
wire [DW-1:0] zeta;
zeta_rom u_z (.addr(zeta_idx), .zeta(zeta));
// Butterfly
wire [DW-1:0] bf_a_out, bf_b_out;
butterfly_unit u_bf (
.a(r_a), .b(r_b), .zeta(zeta), .mode(mode),
.a_out(bf_a_out), .b_out(bf_b_out));
wire [8:0] group_end = {1'b0, start} + {1'b0, layer_len};
wire [8:0] next_group_start = {1'b0, start} + {1'b0, layer_len} + {1'b0, layer_len};
wire issue_group_last = ({1'b0, j} + 9'd2 >= group_end);
wire issue_layer_last = issue_group_last && (next_group_start >= 9'd256);
wire [7:0] next_layer_len = mode_r ? (layer_len << 1) : (layer_len >> 1);
wire issue_fire = (state == S_CMP_RUN) && !layer_issue_done;
// Output scaling
wire [DW-1:0] coeff_scaled;
barrett_mul u_scl (.a(cr[out_cnt]), .b(12'd3303), .product(coeff_scaled));
assign coeff_out = mode ? coeff_scaled : cr[out_cnt];
// ---- coeff_bram_4way port muxing ----
// Read addr 0 is shared by compute (j), output (out_rptr), scale (scale_rptr).
wire [7:0] cmp_a0 = j;
wire [7:0] cmp_b0 = j + layer_len;
wire [7:0] cmp_a1 = j + 8'd1;
wire [7:0] cmp_b1 = j + 8'd1 + layer_len;
wire [7:0] rd_addr_0 = (state == S_OUT_PREP || state == S_OUTPUT) ? out_rptr[7:0] :
(state == S_OUT_SCALE) ? scale_rptr[7:0] : cmp_a0;
// Ports 1..3 carry the other three butterfly operands ONLY during compute;
// otherwise they must mirror port 0 so the read crossbar's per-bank priority
// arbitration doesn't route a stale compute address into port 0's bank.
wire cmp_rd = (state == S_CMP_RUN) || (state == S_CMP_DRAIN);
wire [7:0] rd_addr_1 = cmp_rd ? cmp_b0 : rd_addr_0;
wire [7:0] rd_addr_2 = cmp_rd ? cmp_a1 : rd_addr_0;
wire [7:0] rd_addr_3 = cmp_rd ? cmp_b1 : rd_addr_0;
wire [11:0] rd_data_0, rd_data_1, rd_data_2, rd_data_3;
assign ready_o = (state == S_IDLE) || (state == S_LOAD);
assign valid_o = (state == S_OUTPUT);
assign done_o = (state == S_DONE);
// Butterflies fed from BRAM read data one cycle after the address (rd_fire_r).
wire [DW-1:0] bf0_a_out, bf0_b_out, bf1_a_out, bf1_b_out;
wire bf0_valid, bf1_valid;
butterfly_unit_pipe u_bf0 (
.clk(clk), .rst_n(rst_n),
.valid_i(rd_fire_r),
.a(rd_data_0), .b(rd_data_1),
.zeta(zeta_fed), .mode(mode_r),
.a_out(bf0_a_out), .b_out(bf0_b_out), .valid_o(bf0_valid)
);
butterfly_unit_pipe u_bf1 (
.clk(clk), .rst_n(rst_n),
.valid_i(rd_fire_r),
.a(rd_data_2), .b(rd_data_3),
.zeta(zeta_fed), .mode(mode_r),
.a_out(bf1_a_out), .b_out(bf1_b_out), .valid_o(bf1_valid)
);
// zeta must align with the BRAM read data (1 cycle after presentation).
// Scale multiplier (inverse NTT final x3303).
wire [DW-1:0] scale_product;
wire scale_valid_o;
barrett_mul_pipe u_scl (
.clk(clk), .rst_n(rst_n),
.valid_i(scale_valid_i),
.a(scale_a_i), .b(12'd3303),
.product(scale_product), .valid_o(scale_valid_o)
);
// ---- write ports ----
wire loading_we = (state == S_IDLE && valid_i) || (state == S_LOAD && valid_i);
wire [7:0] load_addr = (state == S_IDLE) ? 8'd0 : load_cnt;
wire wr_en_0 = loading_we | bf0_valid;
wire wr_en_1 = bf0_valid & ~loading_we;
wire wr_en_2 = bf0_valid & ~loading_we;
wire wr_en_3 = bf0_valid & ~loading_we;
wire [7:0] wr_addr_0 = loading_we ? load_addr : a0d[9];
wire [7:0] wr_addr_1 = b0d[9];
wire [7:0] wr_addr_2 = a1d[9];
wire [7:0] wr_addr_3 = b1d[9];
wire [11:0] wr_data_0 = loading_we ? coeff_in : bf0_a_out;
wire [11:0] wr_data_1 = bf0_b_out;
wire [11:0] wr_data_2 = bf1_a_out;
wire [11:0] wr_data_3 = bf1_b_out;
coeff_bram_4way u_cr (
.clk(clk), .rst_n(rst_n),
.rd_addr_0(rd_addr_0), .rd_addr_1(rd_addr_1),
.rd_addr_2(rd_addr_2), .rd_addr_3(rd_addr_3),
.rd_data_0(rd_data_0), .rd_data_1(rd_data_1),
.rd_data_2(rd_data_2), .rd_data_3(rd_data_3),
.wr_en_0(wr_en_0), .wr_en_1(wr_en_1), .wr_en_2(wr_en_2), .wr_en_3(wr_en_3),
.wr_addr_0(wr_addr_0), .wr_addr_1(wr_addr_1),
.wr_addr_2(wr_addr_2), .wr_addr_3(wr_addr_3),
.wr_data_0(wr_data_0), .wr_data_1(wr_data_1),
.wr_data_2(wr_data_2), .wr_data_3(wr_data_3)
);
assign ready_o = (state == S_IDLE) || (state == S_LOAD);
// During forward OUTPUT, drive coeff_out straight from the BRAM read (1-cycle
// latency, matching the old combinational-read + 1 output reg). Scale path
// uses the registered barrett result.
assign coeff_out = (state == S_OUTPUT) ? rd_data_0 : coeff_out_r;
assign valid_o = valid_o_r;
assign done_o = (state == S_DONE);
always @* begin
next_state = state;
case (state)
S_IDLE: if (valid_i) next_state = S_LOAD;
S_LOAD: if (load_cnt >= 255 && valid_i) next_state = S_CMP_A;
S_CMP_A: if (bf_done) next_state = S_OUTPUT; else next_state = S_CMP_B;
S_CMP_B: if (bf_done) next_state = S_OUTPUT; else next_state = S_CMP_C;
S_CMP_C: if (bf_done) next_state = S_OUTPUT; else next_state = S_CMP_A;
S_OUTPUT:if (out_cnt >= 255 && ready_i) next_state = S_DONE;
S_DONE: next_state = S_IDLE;
default: next_state = S_IDLE;
S_IDLE: if (valid_i) next_state = S_LOAD;
S_LOAD: if (load_cnt >= 8'd255 && valid_i) next_state = S_CMP_RUN;
S_CMP_RUN: if (layer_issue_done) next_state = S_CMP_DRAIN;
S_CMP_DRAIN: if (bf_inflight == 6'd0)
next_state = (layer + 3'd1 >= LAYERS) ? S_OUT_PREP : S_CMP_RUN;
S_OUT_PREP: next_state = mode_r ? S_OUT_SCALE : S_OUTPUT;
S_OUTPUT: if (out_cnt >= 9'd256) next_state = S_DONE;
S_OUT_SCALE: if (scale_emit_cnt >= 9'd256) next_state = S_DONE;
S_DONE: next_state = S_IDLE;
default: next_state = S_IDLE;
endcase
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state<=S_IDLE; load_cnt<=0; out_cnt<=0; j<=0; start<=0; layer_len<=0;
zeta_idx<=0; layer<=0; bf_done<=0; r_a<=0; r_b<=0; r_wa<=0; r_wb<=0;
for (ci=0; ci<N; ci=ci+1) cr[ci] = 0;
state <= S_IDLE;
load_cnt <= 8'd0;
out_rptr <= 9'd0; out_cnt <= 9'd0;
scale_rptr <= 9'd0; scale_issue_cnt <= 9'd0; scale_emit_cnt <= 9'd0;
j <= 8'd0; start <= 8'd0; layer_len <= 8'd0;
zeta_idx <= 7'd0; zeta_fed <= 12'd0;
layer <= 3'd0; mode_r <= 1'b0;
layer_issue_done <= 1'b0; bf_inflight <= 6'd0;
rd_fire_r <= 1'b0;
for (k = 0; k <= 9; k = k + 1) begin
a0d[k] <= 8'd0; b0d[k] <= 8'd0; a1d[k] <= 8'd0; b1d[k] <= 8'd0;
end
coeff_out_r <= 12'd0; valid_o_r <= 1'b0;
scale_valid_i <= 1'b0; scale_a_i <= 12'd0;
end else begin
state <= next_state;
scale_valid_i <= 1'b0;
// read->feed pipeline register (BRAM latency) + zeta alignment
rd_fire_r <= issue_fire;
zeta_fed <= zeta;
// writeback address delay lines: sample j-derived addrs at read cycle
a0d[0] <= cmp_a0; b0d[0] <= cmp_b0; a1d[0] <= cmp_a1; b1d[0] <= cmp_b1;
for (k = 1; k <= 9; k = k + 1) begin
a0d[k] <= a0d[k-1]; b0d[k] <= b0d[k-1];
a1d[k] <= a1d[k-1]; b1d[k] <= b1d[k-1];
end
// in-flight pair accounting: +1 on issue, -1 on writeback
if (issue_fire && !bf0_valid) bf_inflight <= bf_inflight + 6'd1;
else if (!issue_fire && bf0_valid) bf_inflight <= bf_inflight - 6'd1;
if (state != S_OUTPUT && state != S_OUT_SCALE)
valid_o_r <= 1'b0;
if (state == S_IDLE && valid_i) begin
cr[0] <= coeff_in;
load_cnt<=1; out_cnt<=0; j<=0; start<=0; layer<=0; bf_done<=0;
if (!mode) begin layer_len<=128; zeta_idx<=1; end
else begin layer_len<=2; zeta_idx<=127; end
load_cnt <= 8'd1;
out_rptr <= 9'd0; out_cnt <= 9'd0;
scale_rptr <= 9'd0; scale_issue_cnt <= 9'd0; scale_emit_cnt <= 9'd0;
j <= 8'd0; start <= 8'd0; layer <= 3'd0;
layer_issue_done <= 1'b0; bf_inflight <= 6'd0;
mode_r <= mode;
if (!mode) begin layer_len <= 8'd128; zeta_idx <= 7'd1; end
else begin layer_len <= 8'd2; zeta_idx <= 7'd127; end
end
if (state == S_LOAD && valid_i) begin
cr[load_cnt] <= coeff_in;
load_cnt <= load_cnt + 8'd1;
end
if (state == S_LOAD && valid_i) load_cnt <= load_cnt + 8'd1;
// S_CMP_A: set read addresses (j, j+len)
if (state == S_CMP_A) begin
r_wa <= j;
r_wb <= j + layer_len;
end
// S_CMP_B: capture read data
if (state == S_CMP_B) begin
r_a <= cr[j];
r_b <= cr[j + layer_len];
end
// S_CMP_C: write butterfly results, advance counters
if (state == S_CMP_C) begin
cr[r_wa] <= bf_a_out;
cr[r_wb] <= bf_b_out;
j <= j + 8'd1;
if (j + 8'd1 >= start + layer_len) begin
if (!mode) zeta_idx <= zeta_idx + 7'd1;
else zeta_idx <= zeta_idx - 7'd1;
if ({1'b0,start} + {1'b0,layer_len} + {1'b0,layer_len} >= 256) begin
layer <= layer + 3'd1;
layer_len <= mode ? (layer_len<<1) : (layer_len>>1);
start <= 0; j <= 0;
if (layer + 3'd1 >= LAYERS) bf_done <= 1'b1;
end else begin
start <= start + layer_len + layer_len;
j <= start + layer_len + layer_len;
end
// ---- issue advance (read pointer j, step 2) ----
if (state == S_CMP_RUN && !layer_issue_done) begin
if (issue_group_last) begin
if (!mode_r) zeta_idx <= zeta_idx + 7'd1;
else zeta_idx <= zeta_idx - 7'd1;
if (issue_layer_last) layer_issue_done <= 1'b1;
else begin start <= next_group_start[7:0]; j <= next_group_start[7:0]; end
end else begin
j <= j + 8'd2;
end
end
if (state == S_OUTPUT && ready_i)
out_cnt <= (out_cnt>=255) ? 0 : (out_cnt+8'd1);
// ---- layer advance after drain ----
if (state == S_CMP_DRAIN && bf_inflight == 6'd0) begin
if (layer + 3'd1 < LAYERS) begin
layer <= layer + 3'd1;
layer_len <= next_layer_len;
start <= 8'd0; j <= 8'd0;
layer_issue_done <= 1'b0;
end
end
// ---- OUT_PREP: reset output pointers ----
if (state == S_OUT_PREP) begin
out_rptr <= 9'd0; out_cnt <= 9'd0;
scale_rptr <= 9'd1; scale_issue_cnt <= 9'd0; scale_emit_cnt <= 9'd0;
// (scale first addr 0 is presented via out_rptr in this PREP cycle)
end
// ---- OUTPUT: stream coeffs. coeff_out is combinational rd_data_0;
// valid_o is a registered "presented a valid addr last cycle". Present
// addresses out_rptr = 0..255 (256), giving 256 valid outputs. ----
if (state == S_OUTPUT) begin
if (out_rptr < 9'd256) begin
out_rptr <= out_rptr + 9'd1; // present rd_addr_0 = out_rptr
valid_o_r <= 1'b1; // data valid next cycle
end else begin
valid_o_r <= 1'b0;
end
if (valid_o_r) out_cnt <= out_cnt + 9'd1; // count emitted
end
// ---- OUT_SCALE: read coeff, x3303 via barrett, emit ----
if (state == S_OUT_SCALE) begin
if (scale_rptr < 9'd256) scale_rptr <= scale_rptr + 9'd1;
// feed barrett with the coeff that arrived this cycle
if (scale_issue_cnt < 9'd256) begin
scale_valid_i <= 1'b1;
scale_a_i <= rd_data_0;
scale_issue_cnt <= scale_issue_cnt + 9'd1;
end
valid_o_r <= 1'b0;
if (scale_valid_o) begin
coeff_out_r <= scale_product;
valid_o_r <= 1'b1;
scale_emit_cnt <= scale_emit_cnt + 9'd1;
end
end
if (state == S_DONE) begin
load_cnt <= 8'd0;
out_rptr <= 9'd0; out_cnt <= 9'd0;
scale_rptr <= 9'd0; scale_issue_cnt <= 9'd0; scale_emit_cnt <= 9'd0;
layer_issue_done <= 1'b0; bf_inflight <= 6'd0;
valid_o_r <= 1'b0;
end
end
end
endmodule

View File

@@ -0,0 +1,144 @@
// basecase_mul_pipe.v - pipelined NTT-domain degree-1 multiplication
//
// Fixed-latency replacement for the combinational basecase_mul hot path.
// The shared ntt/barrett_mul remains combinational for NTT users; this module
// keeps the extra registers local to poly_mul_sync.
(* use_dsp = "no" *)
module basecase_mul_pipe (
input clk,
input rst_n,
input valid_i,
input [11:0] a0, a1,
input [11:0] b0, b1,
input [11:0] zeta,
output [11:0] c0,
output [11:0] c1,
output valid_o
);
localparam [11:0] Q12 = 12'd3329;
localparam [12:0] K13 = 13'd5039;
localparam [24:0] Q25 = 25'd3329;
function [12:0] barrett_q;
input [23:0] p;
(* use_dsp = "no" *) reg [36:0] prod;
begin
prod = {13'd0, p} * K13;
barrett_q = prod[36:24];
end
endfunction
function [11:0] barrett_reduce;
input [23:0] p;
input [12:0] qe;
(* use_dsp = "no" *) reg [24:0] q_approx;
reg [24:0] r0;
reg [24:0] r1;
reg [24:0] r2;
begin
q_approx = qe * Q12;
r0 = {1'b0, p} - q_approx;
r1 = (r0 >= Q25) ? (r0 - Q25) : r0;
r2 = (r1 >= Q25) ? (r1 - Q25) : r1;
barrett_reduce = r2[11:0];
end
endfunction
function [11:0] mod_add;
input [11:0] x;
input [11:0] y;
reg [12:0] sum;
begin
sum = {1'b0, x} + {1'b0, y};
mod_add = (sum >= {1'b0, Q12}) ? (sum[11:0] - Q12) : sum[11:0];
end
endfunction
// Stage 1: first-level scalar products.
(* use_dsp = "no" *) reg [23:0] p10, p11, p12, p13;
reg [11:0] zeta_s1;
// Stage 2: Barrett quotient estimates for first-level products.
reg [23:0] p20, p21, p22, p23;
reg [12:0] q20, q21, q22, q23;
reg [11:0] zeta_s2;
// Stage 3: first-level reduced products.
reg [11:0] t1_s3, t2_s3, t3_s3, t4_s3;
reg [11:0] zeta_s3;
// Stage 4: zeta product for c0's second Barrett multiply.
reg [11:0] t1_s4, t3_s4, t4_s4;
(* use_dsp = "no" *) reg [23:0] pz_s4;
// Stage 5: Barrett quotient estimate for zeta product.
reg [11:0] t1_s5, t3_s5, t4_s5;
reg [23:0] pz_s5;
reg [12:0] qz_s5;
// Stage 6: reduced zeta product.
reg [11:0] t1_s6, t3_s6, t4_s6, tz_s6;
// Stage 7: final modular additions.
reg [11:0] c0_r, c1_r;
reg [6:0] valid_sr;
assign c0 = c0_r;
assign c1 = c1_r;
assign valid_o = valid_sr[6];
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
p10 <= 24'd0; p11 <= 24'd0; p12 <= 24'd0; p13 <= 24'd0; zeta_s1 <= 12'd0;
p20 <= 24'd0; p21 <= 24'd0; p22 <= 24'd0; p23 <= 24'd0;
q20 <= 13'd0; q21 <= 13'd0; q22 <= 13'd0; q23 <= 13'd0; zeta_s2 <= 12'd0;
t1_s3 <= 12'd0; t2_s3 <= 12'd0; t3_s3 <= 12'd0; t4_s3 <= 12'd0; zeta_s3 <= 12'd0;
t1_s4 <= 12'd0; t3_s4 <= 12'd0; t4_s4 <= 12'd0; pz_s4 <= 24'd0;
t1_s5 <= 12'd0; t3_s5 <= 12'd0; t4_s5 <= 12'd0; pz_s5 <= 24'd0; qz_s5 <= 13'd0;
t1_s6 <= 12'd0; t3_s6 <= 12'd0; t4_s6 <= 12'd0; tz_s6 <= 12'd0;
c0_r <= 12'd0; c1_r <= 12'd0; valid_sr <= 7'd0;
end else begin
valid_sr <= {valid_sr[5:0], valid_i};
p10 <= {12'd0, a0} * b0;
p11 <= {12'd0, a1} * b1;
p12 <= {12'd0, a1} * b0;
p13 <= {12'd0, a0} * b1;
zeta_s1 <= zeta;
p20 <= p10; p21 <= p11; p22 <= p12; p23 <= p13;
q20 <= barrett_q(p10);
q21 <= barrett_q(p11);
q22 <= barrett_q(p12);
q23 <= barrett_q(p13);
zeta_s2 <= zeta_s1;
t1_s3 <= barrett_reduce(p20, q20);
t2_s3 <= barrett_reduce(p21, q21);
t3_s3 <= barrett_reduce(p22, q22);
t4_s3 <= barrett_reduce(p23, q23);
zeta_s3 <= zeta_s2;
t1_s4 <= t1_s3;
t3_s4 <= t3_s3;
t4_s4 <= t4_s3;
pz_s4 <= {12'd0, t2_s3} * zeta_s3;
t1_s5 <= t1_s4;
t3_s5 <= t3_s4;
t4_s5 <= t4_s4;
pz_s5 <= pz_s4;
qz_s5 <= barrett_q(pz_s4);
t1_s6 <= t1_s5;
t3_s6 <= t3_s5;
t4_s6 <= t4_s5;
tz_s6 <= barrett_reduce(pz_s5, qz_s5);
c0_r <= mod_add(t1_s6, tz_s6);
c1_r <= mod_add(t3_s6, t4_s6);
end
end
endmodule

View File

@@ -1,28 +1,30 @@
// poly_mul_sync.v - Synchronous NTT-domain polynomial multiplier
// poly_mul_sync.v - Synchronous NTT-domain polynomial multiplier (BRAM storage)
//
// Computes pointwise (Karatsuba-like base-case) multiplication of two
// 256-coefficient NTT-domain polynomials.
//
// Operation flow:
// IDLE → LOAD (256× A+B pairs) → COMP_CALC (read+compute, 1 cycle)
// → COMP_C0 (output c0) → COMP_C1 (output c1) → DONE → IDLE
// IDLE -> LOAD (256x A+B pairs) -> RUN -> IDLE
//
// The LOAD phase accepts both A and B coefficients simultaneously
// (one pair per cycle) on coeff_a_in/coeff_b_in.
// Coefficient storage moved from 256x12 LUT register arrays to four sd_bram
// banks (A_even/A_odd/B_even/B_odd, each 128x12): the base-case reads
// mem[2k] and mem[2k+1] together, so an even/odd split gives each bank a single
// read port. This removes the large multi-port LUT mux (~8k LUT) and the long
// BRAM->register-file routing that was the mlkem_clk critical path.
//
// The COMPUTE phase outputs the 256 result coefficients one per cycle
// via valid/ready handshake on coeff_out/valid_o/ready_i.
// RUN issues one base-case every two cycles. sd_bram reads are synchronous
// (1-cycle latency); the 2-cycle cadence absorbs it (address presented on the
// gap cycle, data consumed on the issue cycle). A one-cycle priming gap is
// inserted at LOAD->RUN so the first base-case's operands are ready.
//
// Memory: 256×12-bit register arrays for A and B coefficients.
//
// Interface:
// Interface (unchanged):
// clk, rst_n - Clock, active-low reset
// coeff_a_in[11:0]- Polynomial A coefficient input
// coeff_b_in[11:0]- Polynomial B coefficient input
// valid_i - Input valid
// ready_o - Ready to accept input (high in IDLE/LOAD)
// coeff_out[11:0] - Result coefficient output
// valid_o - Output valid (high in COMP_C0/COMP_C1)
// valid_o - Output valid during RUN output phase
// ready_i - Output consumer ready
module poly_mul_sync (
@@ -36,129 +38,172 @@ module poly_mul_sync (
input ready_i
);
// State definitions
localparam S_IDLE = 3'd0;
localparam S_LOAD = 3'd1;
localparam S_COMP_CALC = 3'd2;
localparam S_COMP_C0 = 3'd3;
localparam S_COMP_C1 = 3'd4;
localparam S_DONE = 3'd5;
localparam S_IDLE = 3'd0;
localparam S_LOAD = 3'd1;
localparam S_RUN = 3'd2;
reg [2:0] state, next_state;
// Coefficient storage (register arrays)
reg [11:0] mem_A [0:255];
reg [11:0] mem_B [0:255];
// Counters
reg [7:0] load_cnt; // 0..256 for loading 256 pairs
reg [6:0] comp_k; // 0..127, current base-case index
reg [7:0] issue_cnt; // 0..128, issued base-cases
reg [7:0] out_cnt; // 0..255, consumed output coefficients
reg issue_gap; // spaces base-case requests to match c0/c1 output
reg out_phase; // 0=c0, 1=c1
reg out_valid_r;
// Registered basecase_mul results
reg [11:0] bc_a0_reg, bc_a1_reg;
reg [11:0] bc_b0_reg, bc_b1_reg;
reg [11:0] bc_zeta_reg;
reg bc_valid_reg;
reg [11:0] c0_reg, c1_reg;
// Combinational read signals for COMP_CALC
wire [7:0] addr_even = {comp_k, 1'b0}; // comp_k * 2 (7+1 = 8 bits)
wire [7:0] addr_odd = {comp_k, 1'b1}; // comp_k * 2 + 1
wire [11:0] mem_a0 = mem_A[addr_even];
wire [11:0] mem_a1 = mem_A[addr_odd];
wire [11:0] mem_b0 = mem_B[addr_even];
wire [11:0] mem_b1 = mem_B[addr_odd];
// ---- Coefficient storage: even/odd banked sd_bram ----
// A_even[k]=mem_A[2k], A_odd[k]=mem_A[2k+1]; same for B. Read index during
// RUN is issue_k; write index during LOAD is load_cnt>>1 routed by load_cnt[0].
wire [6:0] issue_k = issue_cnt[6:0]; // 0..127 read index
wire load_fire = ((state == S_IDLE) || (state == S_LOAD)) && valid_i && ready_o;
wire [6:0] wr_local = load_cnt[7:1]; // load_cnt/2
wire wr_odd = load_cnt[0];
wire we_even = load_fire && !wr_odd;
wire we_odd = load_fire && wr_odd;
wire [11:0] mem_a0, mem_a1, mem_b0, mem_b1; // sd_bram registered read outputs
sd_bram #(.W(12), .D(128), .A(7)) u_a_even (
.clk(clk), .rd_addr(issue_k), .rd_data(mem_a0),
.wr_en(we_even), .wr_addr(wr_local), .wr_data(coeff_a_in)
);
sd_bram #(.W(12), .D(128), .A(7)) u_a_odd (
.clk(clk), .rd_addr(issue_k), .rd_data(mem_a1),
.wr_en(we_odd), .wr_addr(wr_local), .wr_data(coeff_a_in)
);
sd_bram #(.W(12), .D(128), .A(7)) u_b_even (
.clk(clk), .rd_addr(issue_k), .rd_data(mem_b0),
.wr_en(we_even), .wr_addr(wr_local), .wr_data(coeff_b_in)
);
sd_bram #(.W(12), .D(128), .A(7)) u_b_odd (
.clk(clk), .rd_addr(issue_k), .rd_data(mem_b1),
.wr_en(we_odd), .wr_addr(wr_local), .wr_data(coeff_b_in)
);
// Zeta ROM
wire [11:0] zeta;
poly_mul_zeta_rom u_zeta (
.addr (comp_k),
.zeta (zeta)
);
poly_mul_zeta_rom u_zeta (.addr(issue_k), .zeta(zeta));
// Basecase multiply
wire [11:0] bc_c0, bc_c1;
basecase_mul u_bc (
.a0 (mem_a0),
.a1 (mem_a1),
.b0 (mem_b0),
.b1 (mem_b1),
.zeta(zeta),
.c0 (bc_c0),
.c1 (bc_c1)
wire bc_vo;
basecase_mul_pipe u_bc (
.clk(clk), .rst_n(rst_n),
.valid_i(bc_valid_reg),
.a0(bc_a0_reg), .a1(bc_a1_reg),
.b0(bc_b0_reg), .b1(bc_b1_reg),
.zeta(bc_zeta_reg),
.c0(bc_c0), .c1(bc_c1),
.valid_o(bc_vo)
);
// Output interface
assign ready_o = (state == S_IDLE) || (state == S_LOAD);
assign valid_o = (state == S_COMP_C0) || (state == S_COMP_C1);
assign coeff_out = (state == S_COMP_C0) ? c0_reg : c1_reg;
assign valid_o = out_valid_r;
assign coeff_out = out_phase ? c1_reg : c0_reg;
// State transition logic (combinational)
always @* begin
next_state = state;
case (state)
S_IDLE: if (valid_i && ready_o) next_state = S_LOAD;
S_LOAD: if (load_cnt >= 255 && valid_i && ready_o)
next_state = S_COMP_CALC;
S_COMP_CALC: next_state = S_COMP_C0;
S_COMP_C0: if (valid_o && ready_i) next_state = S_COMP_C1;
S_COMP_C1: if (valid_o && ready_i) begin
if (comp_k >= 127) next_state = S_DONE;
else next_state = S_COMP_CALC;
end
S_DONE: next_state = S_IDLE;
S_LOAD: if (load_cnt >= 8'd255 && valid_i && ready_o)
next_state = S_RUN;
S_RUN: if (valid_o && ready_i && out_cnt == 8'd255)
next_state = S_IDLE;
default: next_state = S_IDLE;
endcase
end
// Sequential logic
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= S_IDLE;
load_cnt <= 8'd0;
comp_k <= 7'd0;
c0_reg <= 12'd0;
c1_reg <= 12'd0;
for (i = 0; i < 256; i = i + 1) begin
mem_A[i] = 12'd0;
mem_B[i] = 12'd0;
end
issue_cnt <= 8'd0;
out_cnt <= 8'd0;
issue_gap <= 1'b0;
out_phase <= 1'b0;
out_valid_r <= 1'b0;
bc_a0_reg <= 12'd0; bc_a1_reg <= 12'd0;
bc_b0_reg <= 12'd0; bc_b1_reg <= 12'd0;
bc_zeta_reg <= 12'd0; bc_valid_reg <= 1'b0;
c0_reg <= 12'd0; c1_reg <= 12'd0;
end else begin
state <= next_state;
bc_valid_reg <= 1'b0;
// ---- LOAD phase ----
// First coefficient captured on IDLE → LOAD transition
// ---- LOAD phase (writes routed to even/odd banks combinationally) ----
if (state == S_IDLE && valid_i && ready_o) begin
mem_A[0] <= coeff_a_in;
mem_B[0] <= coeff_b_in;
load_cnt <= 8'd1;
issue_cnt <= 8'd0;
out_cnt <= 8'd0;
issue_gap <= 1'b0;
out_phase <= 1'b0;
out_valid_r <= 1'b0;
end
// Subsequent coefficients in LOAD state
if (state == S_LOAD && valid_i && ready_o) begin
mem_A[load_cnt] <= coeff_a_in;
mem_B[load_cnt] <= coeff_b_in;
load_cnt <= load_cnt + 8'd1;
if (load_cnt >= 8'd255) begin
issue_cnt <= 8'd0;
out_cnt <= 8'd0;
issue_gap <= 1'b1; // priming gap: present issue_k=0 addr first
out_phase <= 1'b0;
out_valid_r <= 1'b0;
end
end
// ---- COMPUTE phase ----
// COMP_CALC: capture basecase_mul results
if (state == S_COMP_CALC) begin
c0_reg <= bc_c0;
c1_reg <= bc_c1;
// Issue one base-case every two cycles. On the gap cycle the sd_bram
// address (issue_k) settles; on the issue cycle its registered output
// (mem_a0/a1/b0/b1) is captured into the base-case input registers.
if (state == S_RUN) begin
if (issue_cnt < 8'd128) begin
if (!issue_gap) begin
bc_a0_reg <= mem_a0;
bc_a1_reg <= mem_a1;
bc_b0_reg <= mem_b0;
bc_b1_reg <= mem_b1;
bc_zeta_reg <= zeta;
bc_valid_reg <= 1'b1;
issue_cnt <= issue_cnt + 8'd1;
issue_gap <= 1'b1;
end else begin
issue_gap <= 1'b0;
end
end
if (out_valid_r && ready_i) begin
out_cnt <= out_cnt + 8'd1;
if (out_cnt == 8'd255) begin
out_valid_r <= 1'b0;
out_phase <= 1'b0;
end else if (!out_phase) begin
out_phase <= 1'b1;
end else begin
out_valid_r <= 1'b0;
out_phase <= 1'b0;
end
end
if (bc_vo) begin
c0_reg <= bc_c0;
c1_reg <= bc_c1;
out_valid_r <= 1'b1;
out_phase <= 1'b0;
end
end
// COMP_C0 → COMP_C1: c0 was consumed, increment comp_k
if (state == S_COMP_C0 && valid_o && ready_i) begin
// comp_k stays same, c1 still to output
end
// COMP_C1 → COMP_CALC: c1 was consumed, advance to next pair
if (state == S_COMP_C1 && valid_o && ready_i) begin
comp_k <= comp_k + 7'd1;
end
// ---- DONE → IDLE: reset counters ----
if (state == S_DONE) begin
if (state == S_RUN && valid_o && ready_i && out_cnt == 8'd255) begin
load_cnt <= 8'd0;
comp_k <= 7'd0;
issue_cnt <= 8'd0;
out_cnt <= 8'd0;
issue_gap <= 1'b0;
out_phase <= 1'b0;
out_valid_r <= 1'b0;
end
end
end

View File

@@ -1,50 +0,0 @@
// rng_sync.v - 256-bit Galois LFSR PRNG (taps: 255,253,252,247,0)
module rng_sync #(
parameter [255:0] SEED = 256'hDEADBEEFCAFEBABEFEEDFACEDECAFBAD1234567887654321ABCDEF010FEDCBA9
) (
input clk,
input rst_n,
input valid_i,
output ready_o,
output [255:0] data_o,
output valid_o,
input ready_i
);
reg [255:0] state;
reg valid_r;
reg [255:0] lfsr_next;
wire feedback;
integer i;
assign ready_o = 1'b1;
assign valid_o = valid_r;
assign data_o = state;
assign feedback = state[0];
always @(*) begin
for (i = 0; i < 255; i = i + 1)
lfsr_next[i] = state[i+1];
lfsr_next[255] = feedback;
lfsr_next[254] = lfsr_next[254] ^ feedback;
lfsr_next[252] = lfsr_next[252] ^ feedback;
lfsr_next[251] = lfsr_next[251] ^ feedback;
lfsr_next[246] = lfsr_next[246] ^ feedback;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= SEED;
valid_r <= 1'b0;
end else begin
if (valid_r && ready_i)
valid_r <= 1'b0;
if (valid_i) begin
state <= lfsr_next;
valid_r <= 1'b1;
end
end
end
endmodule

View File

@@ -30,16 +30,16 @@
`include "defines.vh"
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDPARAM */
(* use_dsp = "no" *)
module sample_ntt_sync #(parameter K = 4) (
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDPARAM */
input clk,
input rst_n,
input [255:0] rho_i,
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
input [2:0] k_i,
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
input [1:0] i_idx,
input [1:0] j_idx,
input valid_i,
@@ -73,12 +73,12 @@ module sample_ntt_sync #(parameter K = 4) (
// ================================================================
// Registered inputs (captured on valid_i)
// ================================================================
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
reg [255:0] rho_r;
reg [2:0] k_r;
reg [1:0] i_r;
reg [1:0] j_r;
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
// ================================================================
// Coefficient counter (0..256). 9 bits to avoid overflow when
@@ -164,9 +164,9 @@ module sample_ntt_sync #(parameter K = 4) (
// ================================================================
wire kc_valid_i;
wire [1599:0] kc_state_i;
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
wire kc_ready_o;
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
wire [1599:0] kc_state_o;
wire kc_valid_o;
@@ -210,6 +210,10 @@ module sample_ntt_sync #(parameter K = 4) (
// d2 rejected, no longer need coefficients, or d2 was just accepted out.
wire grp_done = (state_r == ST_SQUEEZE) && (sq_phase_r == 2'd2) &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i));
// `need_more` observes the registered counter before the final d2
// handshake increments it. Detect that boundary explicitly so a full
// rate block does not launch an unnecessary final re-permutation.
wire completes_output = valid_o_r && ready_i && (coeff_cnt_r == 9'd255);
// ================================================================
// FSM: state_next (combinational)
@@ -235,7 +239,7 @@ module sample_ntt_sync #(parameter K = 4) (
// next group in this block, re-permute (block exhausted), or
// finish.
if (grp_done) begin
if (!need_more)
if (!need_more || completes_output)
state_next = ST_DONE;
else if (grp_ptr_r < GRP_MAX)
state_next = ST_SQUEEZE; // next group, no re-permute

View File

@@ -43,16 +43,16 @@
`include "defines.vh"
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDPARAM */
(* use_dsp = "no" *)
module sample_ntt_sync_shared #(parameter K = 4) (
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDPARAM */
input clk,
input rst_n,
input [255:0] rho_i,
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
input [2:0] k_i,
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
input [1:0] i_idx,
input [1:0] j_idx,
input valid_i,
@@ -68,9 +68,9 @@ module sample_ntt_sync_shared #(parameter K = 4) (
output kc_ready_i,
output [1599:0] kc_state_i,
output kc_valid_i,
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
input kc_ready_o
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
);
// ================================================================
@@ -96,12 +96,12 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// ================================================================
// Registered inputs (captured on valid_i)
// ================================================================
/* verilator lint_off UNUSED */
/* verilator lint_off UNUSEDSIGNAL */
reg [255:0] rho_r;
reg [2:0] k_r;
reg [1:0] i_r;
reg [1:0] j_r;
/* verilator lint_on UNUSED */
/* verilator lint_on UNUSEDSIGNAL */
// ================================================================
// Coefficient counter (0..256). 9 bits to avoid overflow when
@@ -224,6 +224,10 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// d2 rejected, no longer need coefficients, or d2 was just accepted out.
wire grp_done = (state_r == ST_SQUEEZE) && (sq_phase_r == 2'd2) &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i));
// `need_more` observes the registered counter before the final d2
// handshake increments it. Detect that boundary explicitly so a full
// rate block does not launch an unnecessary final re-permutation.
wire completes_output = valid_o_r && ready_i && (coeff_cnt_r == 9'd255);
// ================================================================
// FSM: state_next (combinational)
@@ -249,7 +253,7 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// next group in this block, re-permute (block exhausted), or
// finish.
if (grp_done) begin
if (!need_more)
if (!need_more || completes_output)
state_next = ST_DONE;
else if (grp_ptr_r < GRP_MAX)
state_next = ST_SQUEEZE; // next group, no re-permute

View File

@@ -100,6 +100,16 @@ module sha3_top (
reg mb_last_r; // captured last-block flag
reg [255:0] mb_digest_r; // latched 256-bit digest (sticky in MB_DONE)
// ================================================================
// Keccak core
// ================================================================
wire kc_valid_i;
/* verilator lint_off UNUSED */
wire [1599:0] kc_state_o;
wire kc_ready_o;
/* verilator lint_on UNUSED */
wire kc_valid_o;
// XOR the incoming block into the low 1088 bits (rate) of the state.
wire [1599:0] mb_xored;
assign mb_xored = mb_state_r ^ {{(1600-1088){1'b0}}, mb_block_i};
@@ -119,16 +129,6 @@ module sha3_top (
endcase
end
// ================================================================
// Keccak core
// ================================================================
wire kc_valid_i;
/* verilator lint_off UNUSED */
wire [1599:0] kc_state_o;
wire kc_ready_o;
/* verilator lint_on UNUSED */
wire kc_valid_o;
// Keccak input: multi-block xored state when mb_en, else single-block absorb.
wire [1599:0] kc_state_i_mux;
assign kc_state_i_mux = mb_en ? mb_xored : absorb_state;

View File

@@ -0,0 +1,365 @@
// Shared AXI slave for the legacy FFT accelerator and the ML-KEM accelerator.
//
// Both software stacks use the same base address, 0xbf400000. Their internal
// maps do not overlap:
// ML-KEM: 0x0000..0x3fff
// FFT: 0x8000..0xcfff
// Route the low ML-KEM block to ML-KEM and the remaining accelerator window to
// FFT.
(* use_dsp = "no" *) module fft_mlkem_axi_slave (
input clk,
input resetn,
input mlkem_clk,
input mlkem_resetn,
input [4:0] s_axi_awid,
input [31:0] s_axi_awaddr,
input [7:0] s_axi_awlen,
input [2:0] s_axi_awsize,
input [1:0] s_axi_awburst,
input s_axi_awlock,
input [3:0] s_axi_awcache,
input [2:0] s_axi_awprot,
input s_axi_awvalid,
output s_axi_awready,
input [4:0] s_axi_wid,
input [31:0] s_axi_wdata,
input [3:0] s_axi_wstrb,
input s_axi_wlast,
input s_axi_wvalid,
output s_axi_wready,
output [4:0] s_axi_bid,
output [1:0] s_axi_bresp,
output s_axi_bvalid,
input s_axi_bready,
input [4:0] s_axi_arid,
input [31:0] s_axi_araddr,
input [7:0] s_axi_arlen,
input [2:0] s_axi_arsize,
input [1:0] s_axi_arburst,
input s_axi_arlock,
input [3:0] s_axi_arcache,
input [2:0] s_axi_arprot,
input s_axi_arvalid,
output s_axi_arready,
output [4:0] s_axi_rid,
output [31:0] s_axi_rdata,
output [1:0] s_axi_rresp,
output s_axi_rlast,
output s_axi_rvalid,
input s_axi_rready,
output fft_finish,
output mlkem_intr
);
localparam SEL_MLKEM = 2'd0;
localparam SEL_FFT = 2'd1;
wire aw_to_mlkem = (s_axi_awaddr[15:12] <= 4'h3);
wire ar_to_mlkem = (s_axi_araddr[15:12] <= 4'h3);
wire [1:0] aw_sel = aw_to_mlkem ? SEL_MLKEM : SEL_FFT;
wire [1:0] ar_sel = ar_to_mlkem ? SEL_MLKEM : SEL_FFT;
reg [1:0] write_sel;
reg write_active;
reg [1:0] read_sel;
reg read_active;
wire mlkem_awready, mlkem_wready, mlkem_bvalid;
wire [4:0] mlkem_bid;
wire [1:0] mlkem_bresp;
wire mlkem_arready, mlkem_rvalid, mlkem_rlast;
wire [4:0] mlkem_rid;
wire [31:0] mlkem_rdata;
wire [1:0] mlkem_rresp;
wire mlkem_m_awvalid;
wire mlkem_m_awready;
wire [31:0] mlkem_m_awaddr;
wire [4:0] mlkem_m_awid;
wire [7:0] mlkem_m_awlen;
wire [2:0] mlkem_m_awsize;
wire [1:0] mlkem_m_awburst;
wire [0:0] mlkem_m_awlock;
wire [3:0] mlkem_m_awcache;
wire [2:0] mlkem_m_awprot;
wire mlkem_m_wvalid;
wire mlkem_m_wready;
wire [31:0] mlkem_m_wdata;
wire [3:0] mlkem_m_wstrb;
wire mlkem_m_wlast;
wire mlkem_m_bvalid;
wire mlkem_m_bready;
wire [4:0] mlkem_m_bid;
wire [1:0] mlkem_m_bresp;
wire mlkem_m_arvalid;
wire mlkem_m_arready;
wire [31:0] mlkem_m_araddr;
wire [4:0] mlkem_m_arid;
wire [7:0] mlkem_m_arlen;
wire [2:0] mlkem_m_arsize;
wire [1:0] mlkem_m_arburst;
wire [0:0] mlkem_m_arlock;
wire [3:0] mlkem_m_arcache;
wire [2:0] mlkem_m_arprot;
wire mlkem_m_rvalid;
wire mlkem_m_rready;
wire [31:0] mlkem_m_rdata;
wire [4:0] mlkem_m_rid;
wire [1:0] mlkem_m_rresp;
wire mlkem_m_rlast;
wire mlkem_intr_m;
(* async_reg = "true" *) reg [1:0] mlkem_intr_sync;
wire fft_awready, fft_wready, fft_bvalid;
wire [4:0] fft_bid;
wire [1:0] fft_bresp;
wire fft_arready, fft_rvalid, fft_rlast;
wire [4:0] fft_rid;
wire [31:0] fft_rdata;
wire [1:0] fft_rresp;
wire [1:0] sel_w = write_active ? write_sel : aw_sel;
wire [1:0] sel_r = read_active ? read_sel : ar_sel;
assign s_axi_awready = !write_active && (
(aw_sel == SEL_MLKEM) ? mlkem_awready :
fft_awready);
assign s_axi_wready = (sel_w == SEL_MLKEM) ? mlkem_wready :
fft_wready;
assign s_axi_bvalid = (sel_w == SEL_MLKEM) ? mlkem_bvalid :
fft_bvalid;
assign s_axi_bid = (sel_w == SEL_MLKEM) ? mlkem_bid :
fft_bid;
assign s_axi_bresp = (sel_w == SEL_MLKEM) ? mlkem_bresp :
fft_bresp;
assign s_axi_arready = !read_active && (
(ar_sel == SEL_MLKEM) ? mlkem_arready :
fft_arready);
assign s_axi_rvalid = (sel_r == SEL_MLKEM) ? mlkem_rvalid :
fft_rvalid;
assign s_axi_rlast = (sel_r == SEL_MLKEM) ? mlkem_rlast :
fft_rlast;
assign s_axi_rid = (sel_r == SEL_MLKEM) ? mlkem_rid :
fft_rid;
assign s_axi_rdata = (sel_r == SEL_MLKEM) ? mlkem_rdata :
fft_rdata;
assign s_axi_rresp = (sel_r == SEL_MLKEM) ? mlkem_rresp :
fft_rresp;
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
write_active <= 1'b0;
write_sel <= SEL_MLKEM;
read_active <= 1'b0;
read_sel <= SEL_MLKEM;
end else begin
if (!write_active && s_axi_awvalid && s_axi_awready) begin
write_active <= 1'b1;
write_sel <= aw_sel;
end else if (write_active && s_axi_bvalid && s_axi_bready) begin
write_active <= 1'b0;
end
if (!read_active && s_axi_arvalid && s_axi_arready) begin
read_active <= 1'b1;
read_sel <= ar_sel;
end else if (read_active && s_axi_rvalid && s_axi_rready && s_axi_rlast) begin
read_active <= 1'b0;
end
end
end
always @(posedge clk or negedge resetn) begin
if (!resetn)
mlkem_intr_sync <= 2'b00;
else
mlkem_intr_sync <= {mlkem_intr_sync[0], mlkem_intr_m};
end
assign mlkem_intr = mlkem_intr_sync[1];
Axi_CDC u_mlkem_axi_cdc (
.axiInClk (clk),
.axiInRstn (resetn),
.axiOutClk (mlkem_clk),
.axiOutRstn (mlkem_resetn),
.axiIn_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_MLKEM)),
.axiIn_awready (mlkem_awready),
.axiIn_awaddr (s_axi_awaddr),
.axiIn_awid (s_axi_awid),
.axiIn_awlen (s_axi_awlen),
.axiIn_awsize (s_axi_awsize),
.axiIn_awburst (s_axi_awburst),
.axiIn_awlock (s_axi_awlock),
.axiIn_awcache (s_axi_awcache),
.axiIn_awprot (s_axi_awprot),
.axiIn_wvalid (s_axi_wvalid && (sel_w == SEL_MLKEM)),
.axiIn_wready (mlkem_wready),
.axiIn_wdata (s_axi_wdata),
.axiIn_wstrb (s_axi_wstrb),
.axiIn_wlast (s_axi_wlast),
.axiIn_bvalid (mlkem_bvalid),
.axiIn_bready (s_axi_bready && (sel_w == SEL_MLKEM)),
.axiIn_bid (mlkem_bid),
.axiIn_bresp (mlkem_bresp),
.axiIn_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_MLKEM)),
.axiIn_arready (mlkem_arready),
.axiIn_araddr (s_axi_araddr),
.axiIn_arid (s_axi_arid),
.axiIn_arlen (s_axi_arlen),
.axiIn_arsize (s_axi_arsize),
.axiIn_arburst (s_axi_arburst),
.axiIn_arlock (s_axi_arlock),
.axiIn_arcache (s_axi_arcache),
.axiIn_arprot (s_axi_arprot),
.axiIn_rvalid (mlkem_rvalid),
.axiIn_rready (s_axi_rready && (sel_r == SEL_MLKEM)),
.axiIn_rdata (mlkem_rdata),
.axiIn_rid (mlkem_rid),
.axiIn_rresp (mlkem_rresp),
.axiIn_rlast (mlkem_rlast),
.axiOut_awvalid (mlkem_m_awvalid),
.axiOut_awready (mlkem_m_awready),
.axiOut_awaddr (mlkem_m_awaddr),
.axiOut_awid (mlkem_m_awid),
.axiOut_awlen (mlkem_m_awlen),
.axiOut_awsize (mlkem_m_awsize),
.axiOut_awburst (mlkem_m_awburst),
.axiOut_awlock (mlkem_m_awlock),
.axiOut_awcache (mlkem_m_awcache),
.axiOut_awprot (mlkem_m_awprot),
.axiOut_wvalid (mlkem_m_wvalid),
.axiOut_wready (mlkem_m_wready),
.axiOut_wdata (mlkem_m_wdata),
.axiOut_wstrb (mlkem_m_wstrb),
.axiOut_wlast (mlkem_m_wlast),
.axiOut_bvalid (mlkem_m_bvalid),
.axiOut_bready (mlkem_m_bready),
.axiOut_bid (mlkem_m_bid),
.axiOut_bresp (mlkem_m_bresp),
.axiOut_arvalid (mlkem_m_arvalid),
.axiOut_arready (mlkem_m_arready),
.axiOut_araddr (mlkem_m_araddr),
.axiOut_arid (mlkem_m_arid),
.axiOut_arlen (mlkem_m_arlen),
.axiOut_arsize (mlkem_m_arsize),
.axiOut_arburst (mlkem_m_arburst),
.axiOut_arlock (mlkem_m_arlock),
.axiOut_arcache (mlkem_m_arcache),
.axiOut_arprot (mlkem_m_arprot),
.axiOut_rvalid (mlkem_m_rvalid),
.axiOut_rready (mlkem_m_rready),
.axiOut_rdata (mlkem_m_rdata),
.axiOut_rid (mlkem_m_rid),
.axiOut_rresp (mlkem_m_rresp),
.axiOut_rlast (mlkem_m_rlast)
);
mlkem_axi_slave u_mlkem_axi_slave (
.clk (mlkem_clk),
.resetn (mlkem_resetn),
.s_axi_awid (mlkem_m_awid),
.s_axi_awaddr (mlkem_m_awaddr),
.s_axi_awlen (mlkem_m_awlen),
.s_axi_awsize (mlkem_m_awsize),
.s_axi_awburst (mlkem_m_awburst),
.s_axi_awlock (mlkem_m_awlock[0]),
.s_axi_awcache (mlkem_m_awcache),
.s_axi_awprot (mlkem_m_awprot),
.s_axi_awvalid (mlkem_m_awvalid),
.s_axi_awready (mlkem_m_awready),
.s_axi_wid (5'd0),
.s_axi_wdata (mlkem_m_wdata),
.s_axi_wstrb (mlkem_m_wstrb),
.s_axi_wlast (mlkem_m_wlast),
.s_axi_wvalid (mlkem_m_wvalid),
.s_axi_wready (mlkem_m_wready),
.s_axi_bid (mlkem_m_bid),
.s_axi_bresp (mlkem_m_bresp),
.s_axi_bvalid (mlkem_m_bvalid),
.s_axi_bready (mlkem_m_bready),
.s_axi_arid (mlkem_m_arid),
.s_axi_araddr (mlkem_m_araddr),
.s_axi_arlen (mlkem_m_arlen),
.s_axi_arsize (mlkem_m_arsize),
.s_axi_arburst (mlkem_m_arburst),
.s_axi_arlock (mlkem_m_arlock[0]),
.s_axi_arcache (mlkem_m_arcache),
.s_axi_arprot (mlkem_m_arprot),
.s_axi_arvalid (mlkem_m_arvalid),
.s_axi_arready (mlkem_m_arready),
.s_axi_rid (mlkem_m_rid),
.s_axi_rdata (mlkem_m_rdata),
.s_axi_rresp (mlkem_m_rresp),
.s_axi_rlast (mlkem_m_rlast),
.s_axi_rvalid (mlkem_m_rvalid),
.s_axi_rready (mlkem_m_rready),
.intr (mlkem_intr_m)
);
fft_controller u_fft_controller (
.aclk (clk),
.aresetn (resetn),
.s_awid (s_axi_awid),
.s_awaddr (s_axi_awaddr),
.s_awlen (s_axi_awlen),
.s_awsize (s_axi_awsize),
.s_awburst (s_axi_awburst),
.s_awlock (s_axi_awlock),
.s_awcache (s_axi_awcache),
.s_awprot (s_axi_awprot),
.s_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_FFT)),
.s_awready (fft_awready),
.s_wid (s_axi_wid),
.s_wdata (s_axi_wdata),
.s_wstrb (s_axi_wstrb),
.s_wlast (s_axi_wlast),
.s_wvalid (s_axi_wvalid && (sel_w == SEL_FFT)),
.s_wready (fft_wready),
.s_bid (fft_bid),
.s_bresp (fft_bresp),
.s_bvalid (fft_bvalid),
.s_bready (s_axi_bready && (sel_w == SEL_FFT)),
.s_arid (s_axi_arid),
.s_araddr (s_axi_araddr),
.s_arlen (s_axi_arlen),
.s_arsize (s_axi_arsize),
.s_arburst (s_axi_arburst),
.s_arlock (s_axi_arlock),
.s_arcache (s_axi_arcache),
.s_arprot (s_axi_arprot),
.s_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_FFT)),
.s_arready (fft_arready),
.s_rid (fft_rid),
.s_rdata (fft_rdata),
.s_rresp (fft_rresp),
.s_rlast (fft_rlast),
.s_rvalid (fft_rvalid),
.s_rready (s_axi_rready && (sel_r == SEL_FFT)),
.fft_finish (fft_finish)
);
endmodule

Some files were not shown because too many files have changed in this diff Show More