mlkem test diagnostics and allocator updates

This commit is contained in:
2026-07-08 02:35:56 +08:00
parent 65607badd2
commit 0c85a20b4e
40 changed files with 37168 additions and 2093 deletions

1
.gitignore vendored
View File

@@ -43,6 +43,7 @@ desktop.ini
.codex/
.opencode/
.agents/
.omo/
# ========================================
# Editor / IDE

Binary file not shown.

570
doc/axi_bus_modules.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` 依据偏移分发。

49
doc/mlkem_test_results.md Normal file
View File

@@ -0,0 +1,49 @@
# ML-KEM Test Results Summary
## Test Setup
- Platform: LoongArch bare-metal target
- Test mode: `STATIC_KAT_COUNT_0`
- Levels: `k=2,3,4`
- Repeat count: `100`
- ML-KEM software allocator: `MLK_CONFIG_CUSTOM_ALLOC_FREE`
- Verification sources: KAT count 0 expected values
## Correctness
All three paths passed in isolated testing:
- `SW_ONLY_FAILS=0`
- `CPU_ONLY_FAILS=0`
- `DMA_ONLY_FAILS=0`
Final result for the isolated diagnostic run:
- `MLKEM512_RESULT=PASS`
- `MLKEM768_RESULT=PASS`
- `MLKEM1024_RESULT=PASS`
- `MLKEM_RESULT=PASS`
## Performance
### Multi-level isolated diagnostic
| Level | SW avg cycles | CPU avg cycles | DMA avg cycles | CPU vs SW | DMA vs SW | DMA vs CPU |
|---|---:|---:|---:|---:|---:|---:|
| k=2 / ML-KEM-512 | 19,684,481 | 432,358 | 189,105 | 45.5x | 104.1x | 2.29x |
| k=3 / ML-KEM-768 | 30,688,338 | 638,556 | 283,023 | 48.1x | 108.4x | 2.26x |
| k=4 / ML-KEM-1024 | 2,355,875 | 872,400 | 392,433 | 2.70x | 6.00x | 2.22x |
### k=4 recheck
| Level | SW avg cycles | CPU avg cycles | DMA avg cycles | CPU vs SW | DMA vs SW | DMA vs CPU |
|---|---:|---:|---:|---:|---:|---:|
| k=4 / ML-KEM-1024 | 6,025,486 | 718,672 | 388,959 | 8.39x | 15.49x | 1.85x |
## Notes
- CPU/DMA hardware paths were stable across 100 iterations for all levels.
- The software path showed run-to-run variance earlier; the custom allocator improved stability, but the k=4 recheck should be used as the cleaner reference for reporting.
- For the hardware accelerator claim, the most stable headline is:
- DMA path is about 2.2x faster than CPU register path.
- Hardware path is substantially faster than software, but the exact SW speedup depends on the software run used as baseline.

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"/>
@@ -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">25.00000</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">25.00000</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_OUT_FREQ">25</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>
@@ -204,7 +210,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVCLK">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE1_AUTO">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE2_AUTO">0.66</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE3_AUTO">0.33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE3_AUTO">1.32</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE4_AUTO">0.33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE5_AUTO">0.33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE6_AUTO">0.33</spirit:configurableElementValue>
@@ -259,7 +265,7 @@
<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">62</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,12 +295,12 @@
<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_ROW3">mlkem_clk__25.00000______0.000______50.0______135.799____123.600</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>
@@ -432,14 +438,14 @@
<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">135.799</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">123.600</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_OUT_FREQ">25</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>
@@ -538,7 +544,7 @@
<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">62</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,7 +572,7 @@
<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.NUM_OUT_CLKS">3</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.OVERRIDE_MMCM">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.OVERRIDE_PLL">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.PHASESHIFT_MODE">WAVEFORM</spirit:configurableElementValue>
@@ -705,17 +711,23 @@
<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_REQUESTED_OUT_FREQ" 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.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"/>

View File

@@ -0,0 +1,235 @@
// Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
// --------------------------------------------------------------------------------
// Tool Version: Vivado v.2019.2 (lin64) Build 2708876 Wed Nov 6 21:39:14 MST 2019
// Date : Tue Jul 7 23:25:51 2026
// Host : fedora running 64-bit unknown
// Command : write_verilog -force -mode funcsim
// /home/fallensigh/Dev/ciciec2026_loongson_regional/rtl/ip/PLL_2019_2/clk_pll_sim_netlist.v
// Design : clk_pll
// Purpose : This verilog netlist is a functional simulation representation of the design and should not be modified
// or synthesized. This netlist cannot be used for SDF annotated simulation.
// Device : xc7a200tfbg676-1
// --------------------------------------------------------------------------------
`timescale 1 ps / 1 ps
(* NotValidForBitStream *)
module clk_pll
(cpu_clk,
sys_clk,
mlkem_clk,
resetn,
locked,
clk_in1);
output cpu_clk;
output sys_clk;
output mlkem_clk;
input resetn;
output locked;
input clk_in1;
(* IBUF_LOW_PWR *) wire clk_in1;
wire cpu_clk;
wire locked;
wire mlkem_clk;
wire resetn;
wire sys_clk;
clk_pll_clk_pll_clk_wiz inst
(.clk_in1(clk_in1),
.cpu_clk(cpu_clk),
.locked(locked),
.mlkem_clk(mlkem_clk),
.resetn(resetn),
.sys_clk(sys_clk));
endmodule
(* ORIG_REF_NAME = "clk_pll_clk_wiz" *)
module clk_pll_clk_pll_clk_wiz
(cpu_clk,
sys_clk,
mlkem_clk,
resetn,
locked,
clk_in1);
output cpu_clk;
output sys_clk;
output mlkem_clk;
input resetn;
output locked;
input clk_in1;
wire clk_in1;
wire clk_in1_clk_pll;
wire clkfbout_buf_clk_pll;
wire clkfbout_clk_pll;
wire cpu_clk;
wire cpu_clk_clk_pll;
wire locked;
wire mlkem_clk;
wire mlkem_clk_clk_pll;
wire reset_high;
wire resetn;
wire sys_clk;
wire sys_clk_clk_pll;
wire NLW_plle2_adv_inst_CLKOUT3_UNCONNECTED;
wire NLW_plle2_adv_inst_CLKOUT4_UNCONNECTED;
wire NLW_plle2_adv_inst_CLKOUT5_UNCONNECTED;
wire NLW_plle2_adv_inst_DRDY_UNCONNECTED;
wire [15:0]NLW_plle2_adv_inst_DO_UNCONNECTED;
(* BOX_TYPE = "PRIMITIVE" *)
BUFG clkf_buf
(.I(clkfbout_clk_pll),
.O(clkfbout_buf_clk_pll));
(* BOX_TYPE = "PRIMITIVE" *)
(* CAPACITANCE = "DONT_CARE" *)
(* IBUF_DELAY_VALUE = "0" *)
(* IFD_DELAY_VALUE = "AUTO" *)
IBUF #(
.IOSTANDARD("DEFAULT"))
clkin1_ibufg
(.I(clk_in1),
.O(clk_in1_clk_pll));
(* BOX_TYPE = "PRIMITIVE" *)
BUFG clkout1_buf
(.I(cpu_clk_clk_pll),
.O(cpu_clk));
(* BOX_TYPE = "PRIMITIVE" *)
BUFG clkout2_buf
(.I(sys_clk_clk_pll),
.O(sys_clk));
(* BOX_TYPE = "PRIMITIVE" *)
BUFG clkout3_buf
(.I(mlkem_clk_clk_pll),
.O(mlkem_clk));
(* BOX_TYPE = "PRIMITIVE" *)
PLLE2_ADV #(
.BANDWIDTH("OPTIMIZED"),
.CLKFBOUT_MULT(31),
.CLKFBOUT_PHASE(0.000000),
.CLKIN1_PERIOD(20.000000),
.CLKIN2_PERIOD(0.000000),
.CLKOUT0_DIVIDE(47),
.CLKOUT0_DUTY_CYCLE(0.500000),
.CLKOUT0_PHASE(0.000000),
.CLKOUT1_DIVIDE(31),
.CLKOUT1_DUTY_CYCLE(0.500000),
.CLKOUT1_PHASE(0.000000),
.CLKOUT2_DIVIDE(78),
.CLKOUT2_DUTY_CYCLE(0.500000),
.CLKOUT2_PHASE(0.000000),
.CLKOUT3_DIVIDE(1),
.CLKOUT3_DUTY_CYCLE(0.500000),
.CLKOUT3_PHASE(0.000000),
.CLKOUT4_DIVIDE(1),
.CLKOUT4_DUTY_CYCLE(0.500000),
.CLKOUT4_PHASE(0.000000),
.CLKOUT5_DIVIDE(1),
.CLKOUT5_DUTY_CYCLE(0.500000),
.CLKOUT5_PHASE(0.000000),
.COMPENSATION("ZHOLD"),
.DIVCLK_DIVIDE(1),
.IS_CLKINSEL_INVERTED(1'b0),
.IS_PWRDWN_INVERTED(1'b0),
.IS_RST_INVERTED(1'b0),
.REF_JITTER1(0.010000),
.REF_JITTER2(0.010000),
.STARTUP_WAIT("FALSE"))
plle2_adv_inst
(.CLKFBIN(clkfbout_buf_clk_pll),
.CLKFBOUT(clkfbout_clk_pll),
.CLKIN1(clk_in1_clk_pll),
.CLKIN2(1'b0),
.CLKINSEL(1'b1),
.CLKOUT0(cpu_clk_clk_pll),
.CLKOUT1(sys_clk_clk_pll),
.CLKOUT2(mlkem_clk_clk_pll),
.CLKOUT3(NLW_plle2_adv_inst_CLKOUT3_UNCONNECTED),
.CLKOUT4(NLW_plle2_adv_inst_CLKOUT4_UNCONNECTED),
.CLKOUT5(NLW_plle2_adv_inst_CLKOUT5_UNCONNECTED),
.DADDR({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
.DCLK(1'b0),
.DEN(1'b0),
.DI({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
.DO(NLW_plle2_adv_inst_DO_UNCONNECTED[15:0]),
.DRDY(NLW_plle2_adv_inst_DRDY_UNCONNECTED),
.DWE(1'b0),
.LOCKED(locked),
.PWRDWN(1'b0),
.RST(reset_high));
LUT1 #(
.INIT(2'h1))
plle2_adv_inst_i_1
(.I0(resetn),
.O(reset_high));
endmodule
`ifndef GLBL
`define GLBL
`timescale 1 ps / 1 ps
module glbl ();
parameter ROC_WIDTH = 100000;
parameter TOC_WIDTH = 0;
//-------- STARTUP Globals --------------
wire GSR;
wire GTS;
wire GWE;
wire PRLD;
tri1 p_up_tmp;
tri (weak1, strong0) PLL_LOCKG = p_up_tmp;
wire PROGB_GLBL;
wire CCLKO_GLBL;
wire FCSBO_GLBL;
wire [3:0] DO_GLBL;
wire [3:0] DI_GLBL;
reg GSR_int;
reg GTS_int;
reg PRLD_int;
//-------- JTAG Globals --------------
wire JTAG_TDO_GLBL;
wire JTAG_TCK_GLBL;
wire JTAG_TDI_GLBL;
wire JTAG_TMS_GLBL;
wire JTAG_TRST_GLBL;
reg JTAG_CAPTURE_GLBL;
reg JTAG_RESET_GLBL;
reg JTAG_SHIFT_GLBL;
reg JTAG_UPDATE_GLBL;
reg JTAG_RUNTEST_GLBL;
reg JTAG_SEL1_GLBL = 0;
reg JTAG_SEL2_GLBL = 0 ;
reg JTAG_SEL3_GLBL = 0;
reg JTAG_SEL4_GLBL = 0;
reg JTAG_USER_TDO1_GLBL = 1'bz;
reg JTAG_USER_TDO2_GLBL = 1'bz;
reg JTAG_USER_TDO3_GLBL = 1'bz;
reg JTAG_USER_TDO4_GLBL = 1'bz;
assign (strong1, weak0) GSR = GSR_int;
assign (strong1, weak0) GTS = GTS_int;
assign (weak1, weak0) PRLD = PRLD_int;
initial begin
GSR_int = 1'b1;
PRLD_int = 1'b1;
#(ROC_WIDTH)
GSR_int = 1'b0;
PRLD_int = 1'b0;
end
initial begin
GTS_int = 1'b1;
#(TOC_WIDTH)
GTS_int = 1'b0;
end
endmodule
`endif

View File

@@ -0,0 +1,179 @@
-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-- --------------------------------------------------------------------------------
-- Tool Version: Vivado v.2019.2 (lin64) Build 2708876 Wed Nov 6 21:39:14 MST 2019
-- Date : Tue Jul 7 23:25:51 2026
-- Host : fedora running 64-bit unknown
-- Command : write_vhdl -force -mode funcsim
-- /home/fallensigh/Dev/ciciec2026_loongson_regional/rtl/ip/PLL_2019_2/clk_pll_sim_netlist.vhdl
-- Design : clk_pll
-- Purpose : This VHDL netlist is a functional simulation representation of the design and should not be modified or
-- synthesized. This netlist cannot be used for SDF annotated simulation.
-- Device : xc7a200tfbg676-1
-- --------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity clk_pll_clk_pll_clk_wiz is
port (
cpu_clk : out STD_LOGIC;
sys_clk : out STD_LOGIC;
mlkem_clk : out STD_LOGIC;
resetn : in STD_LOGIC;
locked : out STD_LOGIC;
clk_in1 : in STD_LOGIC
);
attribute ORIG_REF_NAME : string;
attribute ORIG_REF_NAME of clk_pll_clk_pll_clk_wiz : entity is "clk_pll_clk_wiz";
end clk_pll_clk_pll_clk_wiz;
architecture STRUCTURE of clk_pll_clk_pll_clk_wiz is
signal clk_in1_clk_pll : STD_LOGIC;
signal clkfbout_buf_clk_pll : STD_LOGIC;
signal clkfbout_clk_pll : STD_LOGIC;
signal cpu_clk_clk_pll : STD_LOGIC;
signal mlkem_clk_clk_pll : STD_LOGIC;
signal reset_high : STD_LOGIC;
signal sys_clk_clk_pll : STD_LOGIC;
signal NLW_plle2_adv_inst_CLKOUT3_UNCONNECTED : STD_LOGIC;
signal NLW_plle2_adv_inst_CLKOUT4_UNCONNECTED : STD_LOGIC;
signal NLW_plle2_adv_inst_CLKOUT5_UNCONNECTED : STD_LOGIC;
signal NLW_plle2_adv_inst_DRDY_UNCONNECTED : STD_LOGIC;
signal NLW_plle2_adv_inst_DO_UNCONNECTED : STD_LOGIC_VECTOR ( 15 downto 0 );
attribute BOX_TYPE : string;
attribute BOX_TYPE of clkf_buf : label is "PRIMITIVE";
attribute BOX_TYPE of clkin1_ibufg : label is "PRIMITIVE";
attribute CAPACITANCE : string;
attribute CAPACITANCE of clkin1_ibufg : label is "DONT_CARE";
attribute IBUF_DELAY_VALUE : string;
attribute IBUF_DELAY_VALUE of clkin1_ibufg : label is "0";
attribute IFD_DELAY_VALUE : string;
attribute IFD_DELAY_VALUE of clkin1_ibufg : label is "AUTO";
attribute BOX_TYPE of clkout1_buf : label is "PRIMITIVE";
attribute BOX_TYPE of clkout2_buf : label is "PRIMITIVE";
attribute BOX_TYPE of clkout3_buf : label is "PRIMITIVE";
attribute BOX_TYPE of plle2_adv_inst : label is "PRIMITIVE";
begin
clkf_buf: unisim.vcomponents.BUFG
port map (
I => clkfbout_clk_pll,
O => clkfbout_buf_clk_pll
);
clkin1_ibufg: unisim.vcomponents.IBUF
generic map(
IOSTANDARD => "DEFAULT"
)
port map (
I => clk_in1,
O => clk_in1_clk_pll
);
clkout1_buf: unisim.vcomponents.BUFG
port map (
I => cpu_clk_clk_pll,
O => cpu_clk
);
clkout2_buf: unisim.vcomponents.BUFG
port map (
I => sys_clk_clk_pll,
O => sys_clk
);
clkout3_buf: unisim.vcomponents.BUFG
port map (
I => mlkem_clk_clk_pll,
O => mlkem_clk
);
plle2_adv_inst: unisim.vcomponents.PLLE2_ADV
generic map(
BANDWIDTH => "OPTIMIZED",
CLKFBOUT_MULT => 31,
CLKFBOUT_PHASE => 0.000000,
CLKIN1_PERIOD => 20.000000,
CLKIN2_PERIOD => 0.000000,
CLKOUT0_DIVIDE => 47,
CLKOUT0_DUTY_CYCLE => 0.500000,
CLKOUT0_PHASE => 0.000000,
CLKOUT1_DIVIDE => 31,
CLKOUT1_DUTY_CYCLE => 0.500000,
CLKOUT1_PHASE => 0.000000,
CLKOUT2_DIVIDE => 78,
CLKOUT2_DUTY_CYCLE => 0.500000,
CLKOUT2_PHASE => 0.000000,
CLKOUT3_DIVIDE => 1,
CLKOUT3_DUTY_CYCLE => 0.500000,
CLKOUT3_PHASE => 0.000000,
CLKOUT4_DIVIDE => 1,
CLKOUT4_DUTY_CYCLE => 0.500000,
CLKOUT4_PHASE => 0.000000,
CLKOUT5_DIVIDE => 1,
CLKOUT5_DUTY_CYCLE => 0.500000,
CLKOUT5_PHASE => 0.000000,
COMPENSATION => "ZHOLD",
DIVCLK_DIVIDE => 1,
IS_CLKINSEL_INVERTED => '0',
IS_PWRDWN_INVERTED => '0',
IS_RST_INVERTED => '0',
REF_JITTER1 => 0.010000,
REF_JITTER2 => 0.010000,
STARTUP_WAIT => "FALSE"
)
port map (
CLKFBIN => clkfbout_buf_clk_pll,
CLKFBOUT => clkfbout_clk_pll,
CLKIN1 => clk_in1_clk_pll,
CLKIN2 => '0',
CLKINSEL => '1',
CLKOUT0 => cpu_clk_clk_pll,
CLKOUT1 => sys_clk_clk_pll,
CLKOUT2 => mlkem_clk_clk_pll,
CLKOUT3 => NLW_plle2_adv_inst_CLKOUT3_UNCONNECTED,
CLKOUT4 => NLW_plle2_adv_inst_CLKOUT4_UNCONNECTED,
CLKOUT5 => NLW_plle2_adv_inst_CLKOUT5_UNCONNECTED,
DADDR(6 downto 0) => B"0000000",
DCLK => '0',
DEN => '0',
DI(15 downto 0) => B"0000000000000000",
DO(15 downto 0) => NLW_plle2_adv_inst_DO_UNCONNECTED(15 downto 0),
DRDY => NLW_plle2_adv_inst_DRDY_UNCONNECTED,
DWE => '0',
LOCKED => locked,
PWRDWN => '0',
RST => reset_high
);
plle2_adv_inst_i_1: unisim.vcomponents.LUT1
generic map(
INIT => X"1"
)
port map (
I0 => resetn,
O => reset_high
);
end STRUCTURE;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity clk_pll is
port (
cpu_clk : out STD_LOGIC;
sys_clk : out STD_LOGIC;
mlkem_clk : out STD_LOGIC;
resetn : in STD_LOGIC;
locked : out STD_LOGIC;
clk_in1 : in STD_LOGIC
);
attribute NotValidForBitStream : boolean;
attribute NotValidForBitStream of clk_pll : entity is true;
end clk_pll;
architecture STRUCTURE of clk_pll is
begin
inst: entity work.clk_pll_clk_pll_clk_wiz
port map (
clk_in1 => clk_in1,
cpu_clk => cpu_clk,
locked => locked,
mlkem_clk => mlkem_clk,
resetn => resetn,
sys_clk => sys_clk
);
end STRUCTURE;

View File

@@ -0,0 +1,25 @@
// Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
// --------------------------------------------------------------------------------
// Tool Version: Vivado v.2019.2 (lin64) Build 2708876 Wed Nov 6 21:39:14 MST 2019
// Date : Tue Jul 7 23:25:51 2026
// Host : fedora running 64-bit unknown
// Command : write_verilog -force -mode synth_stub
// /home/fallensigh/Dev/ciciec2026_loongson_regional/rtl/ip/PLL_2019_2/clk_pll_stub.v
// Design : clk_pll
// Purpose : Stub declaration of top-level module interface
// Device : xc7a200tfbg676-1
// --------------------------------------------------------------------------------
// This empty module with port declaration file causes synthesis tools to infer a black box for IP.
// The synthesis directives are for Synopsys Synplify support to prevent IO buffer insertion.
// Please paste the declaration into a Verilog source file or add the file as an additional source.
module clk_pll(cpu_clk, sys_clk, mlkem_clk, resetn, locked,
clk_in1)
/* synthesis syn_black_box black_box_pad_pin="cpu_clk,sys_clk,mlkem_clk,resetn,locked,clk_in1" */;
output cpu_clk;
output sys_clk;
output mlkem_clk;
input resetn;
output locked;
input clk_in1;
endmodule

View File

@@ -0,0 +1,33 @@
-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-- --------------------------------------------------------------------------------
-- Tool Version: Vivado v.2019.2 (lin64) Build 2708876 Wed Nov 6 21:39:14 MST 2019
-- Date : Tue Jul 7 23:25:51 2026
-- Host : fedora running 64-bit unknown
-- Command : write_vhdl -force -mode synth_stub
-- /home/fallensigh/Dev/ciciec2026_loongson_regional/rtl/ip/PLL_2019_2/clk_pll_stub.vhdl
-- Design : clk_pll
-- Purpose : Stub declaration of top-level module interface
-- Device : xc7a200tfbg676-1
-- --------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clk_pll is
Port (
cpu_clk : out STD_LOGIC;
sys_clk : out STD_LOGIC;
mlkem_clk : out STD_LOGIC;
resetn : in STD_LOGIC;
locked : out STD_LOGIC;
clk_in1 : in STD_LOGIC
);
end clk_pll;
architecture stub of clk_pll is
attribute syn_black_box : boolean;
attribute black_box_pad_pin : string;
attribute syn_black_box of stub : architecture is true;
attribute black_box_pad_pin of stub : architecture is "cpu_clk,sys_clk,mlkem_clk,resetn,locked,clk_in1";
begin
end;

View File

@@ -1,7 +1,7 @@
//----------------------------------------------------------------------
// FFT: 1024-Point FFT Using Radix-2^2 Single-Path Delay Feedback
//----------------------------------------------------------------------
(* use_dsp = "no" *)
module FFT #(
parameter WIDTH = 32
)(

View File

@@ -1,7 +1,7 @@
//----------------------------------------------------------------------
// Multiply: Complex Multiplier
//----------------------------------------------------------------------
(* use_dsp = "no" *)
module Multiply #(
parameter WIDTH = 16
)(
@@ -13,7 +13,7 @@ module Multiply #(
output signed [WIDTH-1:0] m_im
);
(* use_dsp = "no" *) wire signed [WIDTH*2-1:0] arbr, arbi, aibr, aibi;
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

View File

@@ -1,7 +1,7 @@
//----------------------------------------------------------------------
// SdfUnit: Radix-2^2 Single-Path Delay Feedback Unit for N-Point FFT
//----------------------------------------------------------------------
(* use_dsp = "no" *)
module SdfUnit #(
parameter N = 64, // Number of FFT Point
parameter M = 64, // Twiddle Resolution
@@ -86,7 +86,7 @@ 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)
(* use_dsp = "no" *) wire[LOG_N-1:0] tw_addr; // Twiddle Table Address
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

View File

@@ -7,7 +7,7 @@
(* use_dsp = "no" *)
module fft_controller #(
parameter FFT_LEN = 1024, // FFT处理长度
parameter BRAM_RD_LATENCY = 2, // 适配 BRAM 的读延迟 (通常 Block RAM 开启输出寄存器为 2)
parameter BRAM_RD_LATENCY = 1, // 适配 BRAM 的读延迟 (通常 Block RAM 开启输出寄存器为 1)
parameter FFT_DATA_WIDTH = 16
)(
input aclk,

View File

@@ -2,7 +2,7 @@
// 3-stage pipelined multiplier (LUT-based, no DSP)
// latency=3, throughput=1 result/cycle
// ═══════════════════════════════════════════════════════
(* use_dsp = "no" *)
module pipelined_mult_32x32 (
input clk,
input rstn,

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
@@ -10,7 +11,7 @@
`include "defines.vh"
(* use_dsp = "no" *)
(* use_dsp = "yes" *)
module comp_decomp_sync (
input clk,
input rst_n,
@@ -24,52 +25,171 @@ 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;
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;
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;
// Accept a new command only when the pipeline and output slot are both free.
// Current users issue one coefficient at a time and wait for valid_o.
assign ready_o = !pipe_busy && (!valid_r || ready_i);
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;
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,7 +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,
input [11:0] b,

View File

@@ -0,0 +1,72 @@
// 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.
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;
reg [23:0] p_s1;
reg [23:0] p_s2;
reg [36:0] tk_s2;
reg [23:0] p_s3;
reg [12:0] q_s3;
reg [24:0] p_s4;
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,74 @@
// 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;
wire [11:0] diff = (b >= a) ? (b - a) : (b - a + Q12);
wire [11:0] mul_data = mode ? diff : b;
wire [11:0] mul_result;
wire mul_valid;
barrett_mul_pipe u_barrett (
.clk(clk),
.rst_n(rst_n),
.valid_i(valid_i),
.a(zeta),
.b(mul_data),
.product(mul_result),
.valid_o(mul_valid)
);
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_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
a_d0 <= a; 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; 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; 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

@@ -1,8 +1,12 @@
// ntt_core.v - NTT core with individual coefficient registers
//
// Uses 256 individual 12-bit registers and generate-based muxing
// to avoid any part-select simulation issues.
// 3-cycle butterfly: SetAddr -> Read -> Compute+Write
// Uses 256 individual 12-bit registers and a deeply pipelined butterfly path.
// The arithmetic hot path is split into:
// address/operand/zeta register -> pipelined Barrett butterfly -> writeback
// Each NTT layer is issued continuously into the butterfly pipeline, then the
// core drains pending writebacks before starting the next dependent layer.
// In inverse mode, final x3303 output scaling also uses a pipelined Barrett
// multiplier so the output path does not reintroduce a combinational reducer.
module ntt_core (
input clk, rst_n,
@@ -17,72 +21,170 @@ module ntt_core (
);
localparam N = 256, LAYERS = 7, DW = 12;
// Individual coefficient registers
reg [DW-1:0] cr [0:N-1];
integer ci;
// 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;
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;
reg [7:0] load_cnt, out_cnt;
reg [3:0] state, next_state;
reg [7:0] load_cnt;
reg [7:0] out_cnt;
reg [8:0] scale_issue_cnt;
reg [8:0] scale_emit_cnt;
reg [7:0] j, start, layer_len;
reg [6:0] zeta_idx;
reg [2:0] layer;
reg bf_done;
reg bf_done;
reg mode_r;
reg layer_issue_done;
reg [4:0] bf_inflight;
// Pipeline registers
reg [DW-1:0] r_a, r_b;
reg [7:0] r_wa, r_wb;
reg [7:0] wa_d0, wa_d1, wa_d2, wa_d3, wa_d4, wa_d5, wa_d6, wa_d7;
reg [7:0] wb_d0, wb_d1, wb_d2, wb_d3, wb_d4, wb_d5, wb_d6, wb_d7;
reg wb_valid_r;
reg [DW-1:0] wb_a_data_r, wb_b_data_r;
reg [7:0] wb_wa_r, wb_wb_r;
reg [DW-1:0] coeff_out_r;
reg valid_o_r;
reg scale_valid_i;
reg [DW-1:0] scale_a_i;
// Zeta
wire [DW-1:0] zeta;
zeta_rom u_z (.addr(zeta_idx), .zeta(zeta));
// Butterfly
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'd1 >= 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;
wire [DW-1:0] issue_a = cr[j];
wire [DW-1:0] issue_b = cr[j + layer_len];
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 bf_valid;
butterfly_unit_pipe u_bf (
.clk(clk),
.rst_n(rst_n),
.valid_i(issue_fire),
.a(issue_a),
.b(issue_b),
.zeta(zeta),
.mode(mode_r),
.a_out(bf_a_out),
.b_out(bf_b_out),
.valid_o(bf_valid)
);
// 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];
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)
);
assign ready_o = (state == S_IDLE) || (state == S_LOAD);
assign valid_o = (state == S_OUTPUT);
assign done_o = (state == S_DONE);
assign ready_o = (state == S_IDLE) || (state == S_LOAD);
assign coeff_out = 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 == 5'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 (valid_o_r && ready_i && out_cnt >= 8'd255) 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_cnt <= 8'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;
layer <= 3'd0;
bf_done <= 1'b0;
mode_r <= 1'b0;
layer_issue_done <= 1'b0;
bf_inflight <= 5'd0;
wa_d0 <= 8'd0; wa_d1 <= 8'd0; wa_d2 <= 8'd0; wa_d3 <= 8'd0;
wa_d4 <= 8'd0; wa_d5 <= 8'd0; wa_d6 <= 8'd0; wa_d7 <= 8'd0;
wb_d0 <= 8'd0; wb_d1 <= 8'd0; wb_d2 <= 8'd0; wb_d3 <= 8'd0;
wb_d4 <= 8'd0; wb_d5 <= 8'd0; wb_d6 <= 8'd0; wb_d7 <= 8'd0;
wb_valid_r <= 1'b0;
wb_a_data_r <= 12'd0;
wb_b_data_r <= 12'd0;
wb_wa_r <= 8'd0;
wb_wb_r <= 8'd0;
coeff_out_r <= 12'd0;
valid_o_r <= 1'b0;
scale_valid_i <= 1'b0;
scale_a_i <= 12'd0;
for (ci = 0; ci < N; ci = ci + 1) cr[ci] <= 12'd0;
end else begin
state <= next_state;
scale_valid_i <= 1'b0;
wa_d0 <= j; wa_d1 <= wa_d0; wa_d2 <= wa_d1; wa_d3 <= wa_d2;
wa_d4 <= wa_d3; wa_d5 <= wa_d4; wa_d6 <= wa_d5; wa_d7 <= wa_d6;
wb_d0 <= j + layer_len; wb_d1 <= wb_d0; wb_d2 <= wb_d1; wb_d3 <= wb_d2;
wb_d4 <= wb_d3; wb_d5 <= wb_d4; wb_d6 <= wb_d5; wb_d7 <= wb_d6;
if (issue_fire && !wb_valid_r)
bf_inflight <= bf_inflight + 5'd1;
else if (!issue_fire && wb_valid_r)
bf_inflight <= bf_inflight - 5'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_cnt <= 8'd0;
scale_issue_cnt <= 9'd0;
scale_emit_cnt <= 9'd0;
j <= 8'd0;
start <= 8'd0;
layer <= 3'd0;
bf_done <= 1'b0;
layer_issue_done <= 1'b0;
bf_inflight <= 5'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
@@ -90,42 +192,93 @@ module ntt_core (
load_cnt <= load_cnt + 8'd1;
end
// S_CMP_A: set read addresses (j, j+len)
if (state == S_CMP_A) begin
r_wa <= j;
r_wb <= j + layer_len;
end
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;
// 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;
if (issue_layer_last) begin
layer_issue_done <= 1'b1;
end else begin
start <= start + layer_len + layer_len;
j <= start + layer_len + layer_len;
start <= next_group_start[7:0];
j <= next_group_start[7:0];
end
end else begin
j <= j + 8'd1;
end
end
if (state == S_OUTPUT && ready_i)
out_cnt <= (out_cnt>=255) ? 0 : (out_cnt+8'd1);
if (wb_valid_r) begin
cr[wb_wa_r] <= wb_a_data_r;
cr[wb_wb_r] <= wb_b_data_r;
end
wb_valid_r <= bf_valid;
if (bf_valid) begin
wb_a_data_r <= bf_a_out;
wb_b_data_r <= bf_b_out;
wb_wa_r <= wa_d7;
wb_wb_r <= wb_d7;
end
if (state == S_CMP_DRAIN && bf_inflight == 5'd0) begin
if (layer + 3'd1 >= LAYERS) begin
bf_done <= 1'b1;
end else begin
layer <= layer + 3'd1;
layer_len <= next_layer_len;
start <= 8'd0;
j <= 8'd0;
layer_issue_done <= 1'b0;
end
end
if (state == S_OUT_PREP) begin
out_cnt <= 8'd0;
scale_issue_cnt <= 9'd0;
scale_emit_cnt <= 9'd0;
if (!mode_r) begin
coeff_out_r <= cr[0];
valid_o_r <= 1'b1;
end
end
if (state == S_OUTPUT && valid_o_r && ready_i) begin
if (out_cnt < 8'd255) begin
out_cnt <= out_cnt + 8'd1;
coeff_out_r <= cr[out_cnt + 8'd1];
valid_o_r <= 1'b1;
end else begin
out_cnt <= 8'd0;
valid_o_r <= 1'b0;
end
end
if (state == S_OUT_SCALE) begin
if (scale_issue_cnt < 9'd256) begin
scale_valid_i <= 1'b1;
scale_a_i <= cr[scale_issue_cnt[7: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_cnt <= 8'd0;
scale_issue_cnt <= 9'd0;
scale_emit_cnt <= 9'd0;
layer_issue_done <= 1'b0;
bf_inflight <= 5'd0;
wb_valid_r <= 1'b0;
valid_o_r <= 1'b0;
end
end
end

View File

@@ -0,0 +1,143 @@
// 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.
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;
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;
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.
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;
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

@@ -4,8 +4,10 @@
// 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
//
// RUN issues one base-case multiply every two cycles, matching the two-cycle
// c0/c1 output bandwidth after the basecase pipeline fills.
//
// The LOAD phase accepts both A and B coefficients simultaneously
// (one pair per cycle) on coeff_a_in/coeff_b_in.
@@ -22,7 +24,7 @@
// 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 (
@@ -37,12 +39,9 @@ module poly_mul_sync (
);
// 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;
@@ -52,14 +51,23 @@ module poly_mul_sync (
// 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
// Registered basecase_mul inputs/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
// Combinational read signals for the next base-case request.
wire [6:0] issue_k = issue_cnt[6:0];
wire [7:0] addr_even = {issue_k, 1'b0}; // issue_k * 2
wire [7:0] addr_odd = {issue_k, 1'b1}; // issue_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];
@@ -68,41 +76,42 @@ module poly_mul_sync (
// Zeta ROM
wire [11:0] zeta;
poly_mul_zeta_rom u_zeta (
.addr (comp_k),
.addr (issue_k),
.zeta (zeta)
);
// Basecase multiply
// Pipelined basecase multiply. Requests are issued every two cycles; inputs
// are registered locally so issue_cnt does not directly drive DSP input muxes.
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),
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)
.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
@@ -113,15 +122,26 @@ module poly_mul_sync (
if (!rst_n) begin
state <= S_IDLE;
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;
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;
for (i = 0; i < 256; i = i + 1) begin
mem_A[i] = 12'd0;
mem_B[i] = 12'd0;
mem_A[i] <= 12'd0;
mem_B[i] <= 12'd0;
end
end else begin
state <= next_state;
bc_valid_reg <= 1'b0;
// ---- LOAD phase ----
// First coefficient captured on IDLE → LOAD transition
@@ -129,6 +149,11 @@ module poly_mul_sync (
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
@@ -136,29 +161,65 @@ module poly_mul_sync (
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'b0;
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;
// RUN: cut issue_cnt -> memory mux -> basecase DSP with local input
// regs, then launch requests every other cycle. The two-cycle issue
// interval matches the c0/c1 output bandwidth, so no deep result FIFO
// is needed for this always-ready system.
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
// ---- final output consumed: reset counters before accepting a new op ----
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

@@ -31,7 +31,6 @@
`include "defines.vh"
/* verilator lint_off UNUSED */
(* use_dsp = "no" *)
module sample_ntt_sync #(parameter K = 4) (
/* verilator lint_on UNUSED */
input clk,

View File

@@ -44,7 +44,6 @@
`include "defines.vh"
/* verilator lint_off UNUSED */
(* use_dsp = "no" *)
module sample_ntt_sync_shared #(parameter K = 4) (
/* verilator lint_on UNUSED */
input clk,

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 UNUSEDSIGNAL */
wire [1599:0] kc_state_o;
wire kc_ready_o;
/* verilator lint_on UNUSEDSIGNAL */
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

@@ -4,13 +4,15 @@
// maps do not overlap:
// ML-KEM: 0x0000..0x3fff
// FFT: 0x8000..0xcfff
// PRNG: 0xd000..0xd0ff
// Route the low ML-KEM block to ML-KEM, the high FFT block to FFT, and the
// following 0xdxxx block to PRNG.
// Route the low ML-KEM block to ML-KEM and the remaining accelerator window to
// FFT.
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,
@@ -58,17 +60,12 @@ module fft_mlkem_axi_slave (
localparam SEL_MLKEM = 2'd0;
localparam SEL_FFT = 2'd1;
localparam SEL_PRNG = 2'd2;
wire aw_to_mlkem = (s_axi_awaddr[15:12] <= 4'h3);
wire aw_to_prng = (s_axi_awaddr[15:12] == 4'hd);
wire ar_to_mlkem = (s_axi_araddr[15:12] <= 4'h3);
wire ar_to_prng = (s_axi_araddr[15:12] == 4'hd);
wire [1:0] aw_sel = aw_to_mlkem ? SEL_MLKEM :
aw_to_prng ? SEL_PRNG : SEL_FFT;
wire [1:0] ar_sel = ar_to_mlkem ? SEL_MLKEM :
ar_to_prng ? SEL_PRNG : SEL_FFT;
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;
@@ -83,6 +80,44 @@ module fft_mlkem_axi_slave (
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;
@@ -91,52 +126,33 @@ module fft_mlkem_axi_slave (
wire [31:0] fft_rdata;
wire [1:0] fft_rresp;
wire prng_awready, prng_wready, prng_bvalid;
wire [4:0] prng_bid;
wire [1:0] prng_bresp;
wire prng_arready, prng_rvalid, prng_rlast;
wire [4:0] prng_rid;
wire [31:0] prng_rdata;
wire [1:0] prng_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 :
(aw_sel == SEL_PRNG) ? prng_awready :
fft_awready);
assign s_axi_wready = (sel_w == SEL_MLKEM) ? mlkem_wready :
(sel_w == SEL_PRNG) ? prng_wready :
fft_wready;
assign s_axi_bvalid = (sel_w == SEL_MLKEM) ? mlkem_bvalid :
(sel_w == SEL_PRNG) ? prng_bvalid :
fft_bvalid;
assign s_axi_bid = (sel_w == SEL_MLKEM) ? mlkem_bid :
(sel_w == SEL_PRNG) ? prng_bid :
fft_bid;
assign s_axi_bresp = (sel_w == SEL_MLKEM) ? mlkem_bresp :
(sel_w == SEL_PRNG) ? prng_bresp :
fft_bresp;
assign s_axi_arready = !read_active && (
(ar_sel == SEL_MLKEM) ? mlkem_arready :
(ar_sel == SEL_PRNG) ? prng_arready :
fft_arready);
assign s_axi_rvalid = (sel_r == SEL_MLKEM) ? mlkem_rvalid :
(sel_r == SEL_PRNG) ? prng_rvalid :
fft_rvalid;
assign s_axi_rlast = (sel_r == SEL_MLKEM) ? mlkem_rlast :
(sel_r == SEL_PRNG) ? prng_rlast :
fft_rlast;
assign s_axi_rid = (sel_r == SEL_MLKEM) ? mlkem_rid :
(sel_r == SEL_PRNG) ? prng_rid :
fft_rid;
assign s_axi_rdata = (sel_r == SEL_MLKEM) ? mlkem_rdata :
(sel_r == SEL_PRNG) ? prng_rdata :
fft_rdata;
assign s_axi_rresp = (sel_r == SEL_MLKEM) ? mlkem_rresp :
(sel_r == SEL_PRNG) ? prng_rresp :
fft_rresp;
always @(posedge clk or negedge resetn) begin
@@ -162,52 +178,140 @@ module fft_mlkem_axi_slave (
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 (clk),
.resetn (resetn),
.clk (mlkem_clk),
.resetn (mlkem_resetn),
.s_axi_awid (s_axi_awid),
.s_axi_awaddr (s_axi_awaddr),
.s_axi_awlen (s_axi_awlen),
.s_axi_awsize (s_axi_awsize),
.s_axi_awburst (s_axi_awburst),
.s_axi_awlock (s_axi_awlock),
.s_axi_awcache (s_axi_awcache),
.s_axi_awprot (s_axi_awprot),
.s_axi_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_MLKEM)),
.s_axi_awready (mlkem_awready),
.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 (s_axi_wid),
.s_axi_wdata (s_axi_wdata),
.s_axi_wstrb (s_axi_wstrb),
.s_axi_wlast (s_axi_wlast),
.s_axi_wvalid (s_axi_wvalid && (sel_w == SEL_MLKEM)),
.s_axi_wready (mlkem_wready),
.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_bid),
.s_axi_bresp (mlkem_bresp),
.s_axi_bvalid (mlkem_bvalid),
.s_axi_bready (s_axi_bready && (sel_w == SEL_MLKEM)),
.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 (s_axi_arid),
.s_axi_araddr (s_axi_araddr),
.s_axi_arlen (s_axi_arlen),
.s_axi_arsize (s_axi_arsize),
.s_axi_arburst (s_axi_arburst),
.s_axi_arlock (s_axi_arlock),
.s_axi_arcache (s_axi_arcache),
.s_axi_arprot (s_axi_arprot),
.s_axi_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_MLKEM)),
.s_axi_arready (mlkem_arready),
.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_rid),
.s_axi_rdata (mlkem_rdata),
.s_axi_rresp (mlkem_rresp),
.s_axi_rlast (mlkem_rlast),
.s_axi_rvalid (mlkem_rvalid),
.s_axi_rready (s_axi_rready && (sel_r == SEL_MLKEM)),
.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)
.intr (mlkem_intr_m)
);
fft_controller u_fft_controller (
@@ -258,50 +362,4 @@ module fft_mlkem_axi_slave (
.fft_finish (fft_finish)
);
prng_axi_slave u_prng_axi_slave (
.clk (clk),
.resetn (resetn),
.s_axi_awid (s_axi_awid),
.s_axi_awaddr (s_axi_awaddr),
.s_axi_awlen (s_axi_awlen),
.s_axi_awsize (s_axi_awsize),
.s_axi_awburst (s_axi_awburst),
.s_axi_awlock (s_axi_awlock),
.s_axi_awcache (s_axi_awcache),
.s_axi_awprot (s_axi_awprot),
.s_axi_awvalid (s_axi_awvalid && !write_active && (aw_sel == SEL_PRNG)),
.s_axi_awready (prng_awready),
.s_axi_wid (s_axi_wid),
.s_axi_wdata (s_axi_wdata),
.s_axi_wstrb (s_axi_wstrb),
.s_axi_wlast (s_axi_wlast),
.s_axi_wvalid (s_axi_wvalid && (sel_w == SEL_PRNG)),
.s_axi_wready (prng_wready),
.s_axi_bid (prng_bid),
.s_axi_bresp (prng_bresp),
.s_axi_bvalid (prng_bvalid),
.s_axi_bready (s_axi_bready && (sel_w == SEL_PRNG)),
.s_axi_arid (s_axi_arid),
.s_axi_araddr (s_axi_araddr),
.s_axi_arlen (s_axi_arlen),
.s_axi_arsize (s_axi_arsize),
.s_axi_arburst (s_axi_arburst),
.s_axi_arlock (s_axi_arlock),
.s_axi_arcache (s_axi_arcache),
.s_axi_arprot (s_axi_arprot),
.s_axi_arvalid (s_axi_arvalid && !read_active && (ar_sel == SEL_PRNG)),
.s_axi_arready (prng_arready),
.s_axi_rid (prng_rid),
.s_axi_rdata (prng_rdata),
.s_axi_rresp (prng_rresp),
.s_axi_rlast (prng_rlast),
.s_axi_rvalid (prng_rvalid),
.s_axi_rready (s_axi_rready && (sel_r == SEL_PRNG))
);
endmodule

View File

@@ -1,16 +1,13 @@
// mlkem_axi_slave.v — AXI4 (burst) slave wrapper for the ML-KEM core.
// Makes the ML-KEM accelerator (KeyGen / Encaps / Decaps) CPU-controllable.
//
// The bus runs at sys_clk (50 MHz). The ML-KEM core cannot close timing at
// 50 MHz, so it is clocked by mlkem_clk = sys_clk / 2 (25 MHz), produced by a
// toggle flip-flop in this wrapper. mlkem_clk is a phase-aligned synchronous
// divide of sys_clk; every signal crossing between the two domains still goes
// through an explicit synchronizer or toggle handshake.
// NOTE (FPGA): for real silicon route mlkem_clk through a BUFG/BUFGCE rather
// than a logic-generated net; kept as a plain toggle here for portability.
// This slave is placed behind an AXI clock-domain converter. Its AXI side and
// mlkem_top both run in mlkem_clk; sys_clk masters reach it through Axi_CDC in
// fft_mlkem_axi_slave.
//
// Register map (byte offsets from base, e.g. virtual 0xbf400000):
// 0x000 CTRL W bit0 = start (launches op selected in CONFIG)
// bit1 = soft_reset (resets ML-KEM core state)
// 0x004 STATUS R bit0 busy, bit1 done, bit2 preload_busy
// W1C write bit1=1 to clear the latched done flag
// 0x008 CONFIG RW [2:0] k (2/3/4), [5:4] op (0=KeyGen 1=Encaps 2=Decaps)
@@ -27,9 +24,11 @@
// 0x1000..0x1FFF EK W: preload ek_in, R: read generated ek
// 0x2000..0x2FFF DK W: preload dk_in, R: read generated full dk
// 0x3000..0x3FFF CT W: preload c_in, R: read generated ciphertext
(* use_dsp = "no" *)
module mlkem_axi_slave (
input clk, // sys_clk (AXI bus clock, 50 MHz)
input resetn, // sys_resetn (active low, already synchronized)
input clk, // mlkem_clk AXI-side clock after Axi_CDC
input resetn, // mlkem_resetn, active low
// AXI Write Address Channel
input [4:0] s_axi_awid,
@@ -153,20 +152,7 @@ module mlkem_axi_slave (
endfunction
// ==========================================
// mlkem_clk = sys_clk / 2 (25 MHz) via toggle FF.
// ==========================================
reg mlkem_clk;
always @(posedge clk or negedge resetn) begin
if (!resetn) mlkem_clk <= 1'b0;
else mlkem_clk <= ~mlkem_clk;
end
// Reset for the mlkem domain: reuse sys_resetn (async-assert, and the core's
// own rst_n is sampled on mlkem_clk edges).
wire mlkem_rstn = resetn;
// ==========================================
// sys_clk-domain config / data registers (quasi-static; fed to the core
// combinationally — written long before start, stable across the op).
// AXI/core clock-domain config / data registers.
// ==========================================
reg [2:0] cfg_k; // 2/3/4
reg [1:0] cfg_op; // 0=KeyGen 1=Encaps 2=Decaps
@@ -188,55 +174,79 @@ module mlkem_axi_slave (
reg [11:0] rdb_addr; // output byte index
// ==========================================
// CDC: start pulse (sys toggle -> mlkem edge-detect -> 1-cyc start_i)
// Start pulse: CTRL.start flips a toggle, edge-detected into start_i.
// ==========================================
reg start_tg; // sys-domain toggle, flips on CTRL.start write
reg [2:0] start_sync; // mlkem-domain 2FF sync (+1 for edge)
wire mlkem_start = start_sync[2] ^ start_sync[1]; // 1 mlkem_clk pulse
wire mlkem_start = start_sync[2] ^ start_sync[1]; // 1 clk pulse
// ==========================================
// CDC: busy / done back to sys
// Software reset pulse: CTRL.soft_reset flips a toggle and stretches reset.
// ==========================================
wire core_busy; // busy_o (mlkem domain)
wire core_done; // done_o pulse (mlkem domain)
reg done_latch; // sticky done in mlkem domain
reg [1:0] busy_sync; // -> sys
reg [1:0] done_sync; // -> sys
// done-clear: sys toggle -> mlkem edge -> clears done_latch
reg dclr_tg; // sys-domain toggle (STATUS W1C of done)
reg [2:0] dclr_sync; // mlkem-domain 2FF sync (+1 for edge)
reg srst_tg; // flips on CTRL.soft_reset
reg [2:0] srst_sync; // edge detector shift register
reg [3:0] srst_cnt; // reset stretcher in clk domain
wire mlkem_srst_edge = srst_sync[2] ^ srst_sync[1];
wire mlkem_srst_active = (srst_cnt != 4'd0);
wire core_resetn = resetn && !mlkem_srst_active;
// ==========================================
// Busy / done status.
// ==========================================
wire core_busy;
wire core_done;
reg done_latch;
reg [1:0] busy_sync;
reg [1:0] done_sync;
// done-clear: STATUS W1C flips a toggle, edge-detected to clear done_latch.
reg dclr_tg;
reg [2:0] dclr_sync;
wire mlkem_dclr = dclr_sync[2] ^ dclr_sync[1];
// ==========================================
// CDC: preload byte write handshake.
// sys: latch {sel,addr,byte}, flip pre_req_tg, hold wready low.
// mlkem: 2FF sync pre_req_tg, on edge pulse the selected *_in_we 1 cycle,
// flip pre_ack_tg.
// sys: 2FF sync pre_ack_tg, on edge release the bus (addr++).
// Preload byte write handshake.
// Latch {sel,addr,byte}, flip pre_req_tg, pulse the selected *_in_we for
// one cycle, then flip pre_ack_tg to release the AXI write beat.
// ==========================================
reg pre_req_tg; // sys toggle: a byte is pending
reg [2:0] pre_req_sync; // mlkem 2FF (+1 for edge)
reg pre_req_tg; // a byte is pending
reg [2:0] pre_req_sync; // edge detector shift register
wire mlkem_pre_we = pre_req_sync[2] ^ pre_req_sync[1];
reg pre_ack_tg; // mlkem toggle: byte consumed
reg [2:0] pre_ack_sync; // sys 2FF (+1 for edge)
reg pre_ack_tg; // byte consumed
reg [2:0] pre_ack_sync; // edge detector shift register
wire pre_ack_edge = pre_ack_sync[2] ^ pre_ack_sync[1];
reg pre_busy; // sys: a preload handshake is in flight
// latched byte/port for the in-flight preload (sys, stable while pre_busy)
reg pre_busy; // a preload handshake is in flight
// latched byte/port for the in-flight preload, stable while pre_busy
reg [1:0] pre_sel_l;
reg [11:0] pre_addr_l;
reg [7:0] pre_byte_l;
reg pre_auto_inc_l;
// ==========================================
// Bulk readback byte handshake.
// Hold {sel,addr}, flip rdb_req_tg, let the BRAM read settle, latch one
// byte, then flip rdb_ack_tg.
// ==========================================
reg rdb_req_tg; // one readback byte request
reg [2:0] rdb_req_sync; // edge detector shift register
wire mlkem_rdb_req = rdb_req_sync[2] ^ rdb_req_sync[1];
reg rdb_ack_tg; // readback byte ready
reg [2:0] rdb_ack_sync; // edge detector shift register
wire rdb_ack_edge = rdb_ack_sync[2] ^ rdb_ack_sync[1];
reg [1:0] rdb_req_sel_l; // stable while request in flight
reg [11:0] rdb_req_addr_l; // stable while request in flight
reg [1:0] rdb_sel_m; // captured request
reg [11:0] rdb_addr_m; // captured request
reg [1:0] rdb_wait_m; // waits for BRAM registered read
reg rdb_busy_m;
reg [7:0] rdb_data_m; // held stable until next ack
// ==========================================
// mlkem_top instance
// ==========================================
wire [7:0] dbg_byte_o, dbg_dk_o, dbg_ct_o;
wire [255:0] ss_o;
wire bulk_read_active;
wire [1:0] bulk_rdb_sel;
wire [11:0] bulk_rdb_addr;
wire [1:0] eff_rdb_sel = bulk_read_active ? bulk_rdb_sel : rdb_sel;
wire [11:0] eff_rdb_addr = bulk_read_active ? bulk_rdb_addr : rdb_addr;
wire [1:0] eff_rdb_sel = rdb_busy_m ? rdb_sel_m : rdb_sel;
wire [11:0] eff_rdb_addr = rdb_busy_m ? rdb_addr_m : rdb_addr;
wire dbg_byte_sel = (eff_rdb_sel == 2'd1); // 0=ek, 1=dk_pke
// The core's ek/dkp read-address muxes give dbg_dk_idx_i priority over
// dbg_byte_idx_i whenever it lands in the ek (768..1567) or dk_pke (<768)
@@ -245,21 +255,20 @@ module mlkem_axi_slave (
// it out of range (0xFFF) so an ek/dk_pke readback isn't corrupted.
wire [11:0] dbg_dk_idx = (eff_rdb_sel == 2'd2) ? eff_rdb_addr : 12'hFFF;
// one-cycle write-enable pulses into the core (combinational off the synced
// edge; pre_sel_l/pre_addr_l/pre_byte_l are stable in sys, sampled by core).
wire ek_in_we = mlkem_pre_we && (pre_sel_l == 2'd0);
wire dk_in_we = mlkem_pre_we && (pre_sel_l == 2'd1);
wire c_in_we = mlkem_pre_we && (pre_sel_l == 2'd2);
// one-cycle write-enable pulses into the core.
wire ek_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd0);
wire dk_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd1);
wire c_in_we = core_resetn && mlkem_pre_we && (pre_sel_l == 2'd2);
mlkem_top #(.KMAX(4)) u_mlkem (
.clk (mlkem_clk),
.rst_n (mlkem_rstn),
.clk (clk),
.rst_n (core_resetn),
.k_i (cfg_k),
.op_i (cfg_op),
.d_i (d_bus),
.z_i (z_bus),
.msg_i (msg_bus),
.start_i (mlkem_start),
.start_i (core_resetn ? mlkem_start : 1'b0),
.busy_o (core_busy),
.done_o (core_done),
// ek preload
@@ -302,44 +311,82 @@ module mlkem_axi_slave (
);
// ==========================================
// mlkem_clk domain: synchronizers, done latch, preload-ack toggle.
// Core/AXI clock domain: edge detectors, done latch, preload/readback acks.
// ==========================================
always @(posedge mlkem_clk or negedge mlkem_rstn) begin
if (!mlkem_rstn) begin
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
start_sync <= 3'd0;
srst_sync <= 3'd0;
srst_cnt <= 4'd0;
dclr_sync <= 3'd0;
pre_req_sync <= 3'd0;
pre_ack_tg <= 1'b0;
rdb_req_sync <= 3'd0;
rdb_ack_tg <= 1'b0;
rdb_sel_m <= 2'd0;
rdb_addr_m <= 12'd0;
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
rdb_data_m <= 8'd0;
done_latch <= 1'b0;
end else begin
// 2FF (+edge) synchronizers of sys-domain toggles
// Edge-detect request toggles.
start_sync <= {start_sync[1:0], start_tg};
srst_sync <= {srst_sync[1:0], srst_tg};
dclr_sync <= {dclr_sync[1:0], dclr_tg};
pre_req_sync <= {pre_req_sync[1:0], pre_req_tg};
rdb_req_sync <= {rdb_req_sync[1:0], rdb_req_tg};
if (mlkem_srst_edge)
srst_cnt <= 4'd8;
else if (srst_cnt != 4'd0)
srst_cnt <= srst_cnt - 4'd1;
// acknowledge a consumed preload byte (write-enable pulsed this cycle)
if (mlkem_pre_we) pre_ack_tg <= ~pre_ack_tg;
if (core_resetn && mlkem_pre_we) pre_ack_tg <= ~pre_ack_tg;
if (!core_resetn) begin
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
end else if (mlkem_rdb_req) begin
rdb_sel_m <= rdb_req_sel_l;
rdb_addr_m <= rdb_req_addr_l;
rdb_wait_m <= 2'd2;
rdb_busy_m <= 1'b1;
end else if (rdb_wait_m != 2'd0) begin
if (rdb_wait_m == 2'd1) begin
rdb_data_m <= rdb_byte;
rdb_ack_tg <= ~rdb_ack_tg;
rdb_wait_m <= 2'd0;
rdb_busy_m <= 1'b0;
end else begin
rdb_wait_m <= rdb_wait_m - 2'd1;
end
end
// sticky done: set on the core's done_o pulse, cleared by synced W1C.
// (mlkem_start also clears it so a new run starts with done low.)
if (core_done) done_latch <= 1'b1;
if (mlkem_srst_active) done_latch <= 1'b0;
else if (core_done) done_latch <= 1'b1;
else if (mlkem_dclr) done_latch <= 1'b0;
else if (mlkem_start) done_latch <= 1'b0;
end
end
// ==========================================
// sys_clk domain: sync busy/done/preload-ack back from mlkem.
// AXI clock domain: register status and acknowledge toggles.
// ==========================================
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
busy_sync <= 2'd0;
done_sync <= 2'd0;
pre_ack_sync <= 3'd0;
rdb_ack_sync <= 3'd0;
end else begin
busy_sync <= {busy_sync[0], core_busy};
busy_sync <= {busy_sync[0], core_busy | mlkem_srst_active};
done_sync <= {done_sync[0], done_latch};
pre_ack_sync <= {pre_ack_sync[1:0], pre_ack_tg};
rdb_ack_sync <= {rdb_ack_sync[1:0], rdb_ack_tg};
end
end
wire status_busy = busy_sync[1];
@@ -389,6 +436,7 @@ module mlkem_axi_slave (
rdb_sel <= 2'd0;
rdb_addr <= 12'd0;
start_tg <= 1'b0;
srst_tg <= 1'b0;
dclr_tg <= 1'b0;
pre_req_tg <= 1'b0;
pre_busy <= 1'b0;
@@ -453,8 +501,10 @@ module mlkem_axi_slave (
end else begin
// normal single-cycle register write
case (1'b1)
(w_offset == ADDR_CTRL):
(w_offset == ADDR_CTRL): begin
if (s_axi_wdata[0]) start_tg <= ~start_tg;
if (s_axi_wdata[1]) srst_tg <= ~srst_tg;
end
(w_offset == ADDR_STATUS):
if (s_axi_wdata[1]) dclr_tg <= ~dclr_tg; // clear done
(w_offset == ADDR_CONFIG): begin
@@ -541,7 +591,6 @@ module mlkem_axi_slave (
localparam R_IDLE = 3'd0;
localparam R_DATA = 3'd1;
localparam R_BULK_WAIT = 3'd2;
localparam RDB_WAIT_CYCLES = 3'd4;
reg [2:0] r_state;
reg [31:0] r_addr;
@@ -557,13 +606,8 @@ module mlkem_axi_slave (
reg [1:0] bulk_sel_r;
reg [11:0] bulk_addr_r;
reg [1:0] bulk_lane;
reg [2:0] bulk_wait;
reg [31:0] bulk_word;
assign bulk_read_active = r_bulk && (r_state == R_BULK_WAIT);
assign bulk_rdb_sel = bulk_sel_r;
assign bulk_rdb_addr = bulk_addr_r;
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
r_state <= R_IDLE;
@@ -579,8 +623,10 @@ module mlkem_axi_slave (
bulk_sel_r <= 2'd0;
bulk_addr_r <= 12'd0;
bulk_lane <= 2'd0;
bulk_wait <= 3'd0;
bulk_word <= 32'd0;
rdb_req_tg <= 1'b0;
rdb_req_sel_l <= 2'd0;
rdb_req_addr_l <= 12'd0;
end else begin
case (r_state)
R_IDLE: begin
@@ -597,8 +643,10 @@ module mlkem_axi_slave (
bulk_sel_r <= window_readback_sel(s_axi_araddr[15:12]);
bulk_addr_r <= s_axi_araddr[11:0];
bulk_lane <= 2'd0;
bulk_wait <= RDB_WAIT_CYCLES;
bulk_word <= 32'd0;
rdb_req_sel_l <= window_readback_sel(s_axi_araddr[15:12]);
rdb_req_addr_l <= s_axi_araddr[11:0];
rdb_req_tg <= ~rdb_req_tg;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
r_state <= R_BULK_WAIT;
@@ -610,14 +658,12 @@ module mlkem_axi_slave (
end
end
R_BULK_WAIT: begin
if (bulk_wait != 3'd0) begin
bulk_wait <= bulk_wait - 3'd1;
end else begin
if (rdb_ack_edge) begin
case (bulk_lane)
2'd0: bulk_word[7:0] <= rdb_byte;
2'd1: bulk_word[15:8] <= rdb_byte;
2'd2: bulk_word[23:16] <= rdb_byte;
default: bulk_word[31:24] <= rdb_byte;
2'd0: bulk_word[7:0] <= rdb_data_m;
2'd1: bulk_word[15:8] <= rdb_data_m;
2'd2: bulk_word[23:16] <= rdb_data_m;
default: bulk_word[31:24] <= rdb_data_m;
endcase
if (bulk_lane == 2'd3) begin
@@ -627,7 +673,8 @@ module mlkem_axi_slave (
end else begin
bulk_lane <= bulk_lane + 2'd1;
bulk_addr_r <= bulk_addr_r + 12'd1;
bulk_wait <= RDB_WAIT_CYCLES;
rdb_req_addr_l <= bulk_addr_r + 12'd1;
rdb_req_tg <= ~rdb_req_tg;
end
end
end
@@ -645,8 +692,10 @@ module mlkem_axi_slave (
if (r_bulk) begin
bulk_addr_r <= (r_burst == 2'b01) ? (r_offset + 12'd4) : r_offset;
bulk_lane <= 2'd0;
bulk_wait <= RDB_WAIT_CYCLES;
bulk_word <= 32'd0;
rdb_req_sel_l <= bulk_sel_r;
rdb_req_addr_l <= (r_burst == 2'b01) ? (r_offset + 12'd4) : r_offset;
rdb_req_tg <= ~rdb_req_tg;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
r_state <= R_BULK_WAIT;

File diff suppressed because it is too large Load Diff

View File

@@ -1,218 +0,0 @@
// Lightweight AXI4 register endpoint for a pseudo-random generator.
//
// Register map, byte offsets within the shared accelerator window:
// 0xd000 CTRL W bit0=mix software seed, bit1=clear counters
// 0xd004 STATUS R bit0=ready
// 0xd008 DATA R next 32-bit random word
// 0xd00c COUNT R number of DATA reads
// 0xd010 SEED W software seed/mix value
//
// This block is deterministic unless software mixes in an external seed. It
// intentionally uses only flops, XORs, shifts, and adders.
module prng_axi_slave (
input clk,
input 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 reg 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 reg [4:0] s_axi_rid,
output reg [31:0] s_axi_rdata,
output [1:0] s_axi_rresp,
output reg s_axi_rlast,
output reg s_axi_rvalid,
input s_axi_rready
);
localparam ADDR_CTRL = 12'h000;
localparam ADDR_STATUS = 12'h004;
localparam ADDR_DATA = 12'h008;
localparam ADDR_COUNT = 12'h00c;
localparam ADDR_SEED = 12'h010;
assign s_axi_bresp = 2'b00;
assign s_axi_rresp = 2'b00;
reg [4:0] awid_reg;
reg [31:0] awaddr_reg;
reg [7:0] awleft_reg;
reg write_active;
assign s_axi_awready = !write_active && !s_axi_bvalid;
assign s_axi_wready = write_active && !s_axi_bvalid;
assign s_axi_bid = awid_reg;
reg [31:0] araddr_reg;
reg [7:0] arleft_reg;
reg read_active;
assign s_axi_arready = !read_active && !s_axi_rvalid;
reg [127:0] rng_state;
reg [63:0] free_counter;
reg [31:0] seed_mix;
reg [31:0] data_reads;
wire lfsr_fb = rng_state[127] ^ rng_state[125] ^ rng_state[100] ^
rng_state[98] ^ rng_state[27] ^ rng_state[0] ^
free_counter[0];
wire [127:0] rng_next = {rng_state[126:0], lfsr_fb} ^
{free_counter, free_counter ^ {32'h0, seed_mix}};
wire [31:0] rng_word = rng_state[31:0] ^ rng_state[63:32] ^
rng_state[95:64] ^ rng_state[127:96] ^
free_counter[31:0] ^ free_counter[63:32] ^
seed_mix;
function [31:0] apply_wstrb;
input [31:0] old_value;
input [31:0] new_value;
input [3:0] strobe;
begin
apply_wstrb = old_value;
if (strobe[0]) apply_wstrb[7:0] = new_value[7:0];
if (strobe[1]) apply_wstrb[15:8] = new_value[15:8];
if (strobe[2]) apply_wstrb[23:16] = new_value[23:16];
if (strobe[3]) apply_wstrb[31:24] = new_value[31:24];
end
endfunction
function [31:0] read_reg;
input [31:0] addr;
begin
case (addr[11:0])
ADDR_STATUS: read_reg = 32'h00000001;
ADDR_DATA: read_reg = rng_word;
ADDR_COUNT: read_reg = data_reads;
ADDR_SEED: read_reg = seed_mix;
default: read_reg = 32'h00000000;
endcase
end
endfunction
wire write_fire = s_axi_wvalid && s_axi_wready;
wire read_fire = s_axi_rvalid && s_axi_rready;
wire data_read_fire = read_fire && (araddr_reg[11:0] == ADDR_DATA);
wire [31:0] next_araddr = araddr_reg + 32'd4;
wire [31:0] next_awaddr = awaddr_reg + 32'd4;
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
awid_reg <= 5'b0;
awaddr_reg <= 32'b0;
awleft_reg <= 8'b0;
write_active <= 1'b0;
s_axi_bvalid <= 1'b0;
araddr_reg <= 32'b0;
arleft_reg <= 8'b0;
read_active <= 1'b0;
s_axi_rid <= 5'b0;
s_axi_rdata <= 32'b0;
s_axi_rlast <= 1'b0;
s_axi_rvalid <= 1'b0;
rng_state <= 128'h6d5a_56c3_9e37_79b9_a5a5_3c3c_c001_c0de;
free_counter <= 64'h1;
seed_mix <= 32'h31415927;
data_reads <= 32'b0;
end else begin
free_counter <= free_counter + 64'h9e37_79b9_7f4a_7c15;
rng_state <= rng_next;
if (s_axi_awvalid && s_axi_awready) begin
awid_reg <= s_axi_awid;
awaddr_reg <= s_axi_awaddr;
awleft_reg <= s_axi_awlen;
write_active <= 1'b1;
end
if (write_fire) begin
case (awaddr_reg[11:0])
ADDR_CTRL: begin
if (s_axi_wdata[0]) begin
seed_mix <= seed_mix ^ s_axi_wdata ^ free_counter[31:0];
rng_state <= rng_next ^ {4{s_axi_wdata}};
end
if (s_axi_wdata[1])
data_reads <= 32'b0;
end
ADDR_SEED: begin
seed_mix <= apply_wstrb(seed_mix, s_axi_wdata, s_axi_wstrb);
rng_state <= rng_next ^ {s_axi_wdata, free_counter, ~s_axi_wdata};
end
default: begin
end
endcase
if (s_axi_wlast || awleft_reg == 8'b0) begin
write_active <= 1'b0;
s_axi_bvalid <= 1'b1;
end else begin
awleft_reg <= awleft_reg - 8'd1;
awaddr_reg <= next_awaddr;
end
end
if (s_axi_bvalid && s_axi_bready)
s_axi_bvalid <= 1'b0;
if (s_axi_arvalid && s_axi_arready) begin
read_active <= 1'b1;
araddr_reg <= s_axi_araddr;
arleft_reg <= s_axi_arlen;
s_axi_rid <= s_axi_arid;
s_axi_rdata <= read_reg(s_axi_araddr);
s_axi_rlast <= (s_axi_arlen == 8'b0);
s_axi_rvalid <= 1'b1;
end else if (read_fire) begin
if (data_read_fire) begin
data_reads <= data_reads + 32'd1;
rng_state <= rng_next ^ {rng_word, rng_word ^ free_counter[31:0],
free_counter[63:32], ~rng_word};
end
if (s_axi_rlast) begin
read_active <= 1'b0;
s_axi_rvalid <= 1'b0;
end else begin
araddr_reg <= next_araddr;
arleft_reg <= arleft_reg - 8'd1;
s_axi_rdata <= read_reg(next_araddr);
s_axi_rlast <= (arleft_reg == 8'd1);
end
end
end
end
endmodule

View File

@@ -83,6 +83,8 @@ wire cpu_clk;
wire cpu_resetn;
wire sys_clk;
wire sys_resetn;
wire mlkem_clk;
wire mlkem_resetn;
wire pll_locked;
generate if(SIMULATION) begin: sim_clk
@@ -91,25 +93,32 @@ generate if(SIMULATION) begin: sim_clk
initial begin
clk_sim = 1'b0;
end
always #15 clk_sim = ~clk_sim;
assign cpu_clk = clk_sim;
assign sys_clk = clk;
rst_sync u_rst_sys(
.clk(sys_clk),
.rst_n_in(~reset),
.rst_n_out(sys_resetn)
);
always #15 clk_sim = ~clk_sim;
assign cpu_clk = clk_sim;
assign sys_clk = clk;
assign mlkem_clk = sys_clk;
rst_sync u_rst_sys(
.clk(sys_clk),
.rst_n_in(~reset),
.rst_n_out(sys_resetn)
);
rst_sync u_rst_cpu(
.clk(cpu_clk),
.rst_n_in(sys_resetn),
.rst_n_out(cpu_resetn)
);
end
else begin: pll_clk
.rst_n_in(sys_resetn),
.rst_n_out(cpu_resetn)
);
rst_sync u_rst_mlkem(
.clk(mlkem_clk),
.rst_n_in(sys_resetn),
.rst_n_out(mlkem_resetn)
);
end
else begin: pll_clk
clk_pll u_clk_pll(
.cpu_clk (cpu_clk),
.sys_clk (sys_clk),
.mlkem_clk (mlkem_clk),
.resetn (~reset),
.locked (pll_locked),
.clk_in1 (clk)
@@ -124,6 +133,11 @@ else begin: pll_clk
.rst_n_in(sys_resetn),
.rst_n_out(cpu_resetn)
);
rst_sync u_rst_mlkem(
.clk(mlkem_clk),
.rst_n_in(sys_resetn),
.rst_n_out(mlkem_resetn)
);
end
endgenerate
@@ -393,15 +407,15 @@ wire dma_s_wlast ;
wire dma_s_wvalid ;
wire dma_s_wready ;
wire [4 :0] dma_s_bid ;
wire [1 :0] dma_s_bresp ;
wire dma_s_bvalid ;
wire dma_s_bready ;
wire dma_finish ;
wire cdma_dma_finish;
wire cdma_matmul_seq_irq;
assign dma_finish = cdma_dma_finish | cdma_matmul_seq_irq;
// reserved
wire [1 :0] dma_s_bresp ;
wire dma_s_bvalid ;
wire dma_s_bready ;
wire dma_finish ;
wire cdma_dma_finish;
wire cdma_matmul_seq_irq;
assign dma_finish = cdma_dma_finish | cdma_matmul_seq_irq;
// reserved
wire [4 :0] axiOut_1_arid ;
wire [31:0] axiOut_1_araddr ;
wire [7 :0] axiOut_1_arlen ;
@@ -565,7 +579,7 @@ wire [4 :0] fft_bid ;
wire [1 :0] fft_bresp ;
wire fft_bvalid ;
wire fft_bready ;
wire fft_finish;
wire fft_finish;
//slave 7
wire [4 :0] axiOut_7_arid ;
@@ -606,24 +620,24 @@ wire axiOut_7_bvalid ;
wire axiOut_7_bready ;
wire confreg_int;
wire matmul_intr;
wire matmul_ep_wr_valid;
wire [3:0] matmul_ep_wr_id;
wire [3:0] matmul_ep_wr_bank;
wire [7:0] matmul_ep_wr_word_addr;
wire [31:0] matmul_ep_wr_data;
wire matmul_ep_wr_ready;
wire matmul_ep_rd_valid;
wire [3:0] matmul_ep_rd_id;
wire [3:0] matmul_ep_rd_bank;
wire [7:0] matmul_ep_rd_word_addr;
wire [31:0] matmul_ep_rd_data;
wire matmul_ep_rd_ready;
wire matmul_direct_start_valid;
wire matmul_direct_start_bank;
wire matmul_direct_done_clear;
wire matmul_direct_crc_clear;
wire matmul_direct_done;
wire matmul_intr;
wire matmul_ep_wr_valid;
wire [3:0] matmul_ep_wr_id;
wire [3:0] matmul_ep_wr_bank;
wire [7:0] matmul_ep_wr_word_addr;
wire [31:0] matmul_ep_wr_data;
wire matmul_ep_wr_ready;
wire matmul_ep_rd_valid;
wire [3:0] matmul_ep_rd_id;
wire [3:0] matmul_ep_rd_bank;
wire [7:0] matmul_ep_rd_word_addr;
wire [31:0] matmul_ep_rd_data;
wire matmul_ep_rd_ready;
wire matmul_direct_start_valid;
wire matmul_direct_start_bank;
wire matmul_direct_done_clear;
wire matmul_direct_crc_clear;
wire matmul_direct_done;
wire mlkem_intr;
AxiCrossbar_2x8 u_AxiCrossbar_2x8 (
@@ -1446,12 +1460,14 @@ axi_dvi u_axi_dvi (
);
// slave 6 - shared FFT / ML-KEM accelerator window (0x1f400000, virtual 0xbf400000)
// ML-KEM: 0x0000..0x0114
// FFT: 0x1000/0x2000/0x3000/0x4000/0xf000
// PRNG: 0xd000..0xd010
// ML-KEM: 0x0000..0x3fff
// FFT: 0x8000..0xcfff
fft_mlkem_axi_slave u_fft_mlkem_axi_slave (
.clk (sys_clk),
.resetn (sys_resetn),
.clk (sys_clk),
.resetn (sys_resetn),
.mlkem_clk (mlkem_clk),
.mlkem_resetn (mlkem_resetn),
.s_axi_awid (fft_awid ),
.s_axi_awaddr (fft_awaddr ),
@@ -1491,12 +1507,12 @@ fft_mlkem_axi_slave u_fft_mlkem_axi_slave (
.s_axi_rdata (fft_rdata ),
.s_axi_rresp (fft_rresp ),
.s_axi_rlast (fft_rlast ),
.s_axi_rvalid (fft_rvalid),
.s_axi_rready (fft_rready),
.fft_finish (fft_finish),
.mlkem_intr (mlkem_intr)
);
.s_axi_rvalid (fft_rvalid),
.s_axi_rready (fft_rready),
.fft_finish (fft_finish),
.mlkem_intr (mlkem_intr)
);
//slave 7 - matmul accelerator
matmul_axi_slave u_matmul_axi_slave (
@@ -1537,35 +1553,35 @@ matmul_axi_slave u_matmul_axi_slave (
.s_axi_arvalid (axiOut_7_arvalid),
.s_axi_arready (axiOut_7_arready),
.s_axi_rid (axiOut_7_rid ),
.s_axi_rdata (axiOut_7_rdata ),
.s_axi_rresp (axiOut_7_rresp ),
.s_axi_rlast (axiOut_7_rlast ),
.s_axi_rvalid (axiOut_7_rvalid),
.s_axi_rready (axiOut_7_rready),
.ep_wr_valid (matmul_ep_wr_valid),
.ep_wr_id (matmul_ep_wr_id),
.ep_wr_bank (matmul_ep_wr_bank),
.ep_wr_word_addr(matmul_ep_wr_word_addr),
.ep_wr_data (matmul_ep_wr_data),
.ep_wr_ready (matmul_ep_wr_ready),
.ep_rd_valid (matmul_ep_rd_valid),
.ep_rd_id (matmul_ep_rd_id),
.ep_rd_bank (matmul_ep_rd_bank),
.ep_rd_word_addr(matmul_ep_rd_word_addr),
.ep_rd_data (matmul_ep_rd_data),
.ep_rd_ready (matmul_ep_rd_ready),
.mat_start_valid(matmul_direct_start_valid),
.mat_start_bank (matmul_direct_start_bank),
.mat_done_clear (matmul_direct_done_clear),
.mat_crc_clear (matmul_direct_crc_clear),
.mat_done (matmul_direct_done),
.intr (matmul_intr)
);
.s_axi_rid (axiOut_7_rid ),
.s_axi_rdata (axiOut_7_rdata ),
.s_axi_rresp (axiOut_7_rresp ),
.s_axi_rlast (axiOut_7_rlast ),
.s_axi_rvalid (axiOut_7_rvalid),
.s_axi_rready (axiOut_7_rready),
.ep_wr_valid (matmul_ep_wr_valid),
.ep_wr_id (matmul_ep_wr_id),
.ep_wr_bank (matmul_ep_wr_bank),
.ep_wr_word_addr(matmul_ep_wr_word_addr),
.ep_wr_data (matmul_ep_wr_data),
.ep_wr_ready (matmul_ep_wr_ready),
.ep_rd_valid (matmul_ep_rd_valid),
.ep_rd_id (matmul_ep_rd_id),
.ep_rd_bank (matmul_ep_rd_bank),
.ep_rd_word_addr(matmul_ep_rd_word_addr),
.ep_rd_data (matmul_ep_rd_data),
.ep_rd_ready (matmul_ep_rd_ready),
.mat_start_valid(matmul_direct_start_valid),
.mat_start_bank (matmul_direct_start_bank),
.mat_done_clear (matmul_direct_done_clear),
.mat_crc_clear (matmul_direct_crc_clear),
.mat_done (matmul_direct_done),
.intr (matmul_intr)
);
wire [31:0] cdma_s_awaddr;
wire [2:0] cdma_s_awprot;
@@ -1583,121 +1599,121 @@ wire [2:0] cdma_s_arprot;
wire cdma_s_arvalid;
wire cdma_s_arready;
wire [31:0] cdma_s_rdata;
wire [1:0] cdma_s_rresp;
wire cdma_s_rvalid;
wire cdma_s_rready;
wire [31:0] cdma_mux_awaddr;
wire cdma_mux_awvalid;
wire cdma_mux_awready;
wire [31:0] cdma_mux_wdata;
wire [3:0] cdma_mux_wstrb;
wire cdma_mux_wvalid;
wire cdma_mux_wready;
wire [1:0] cdma_mux_bresp;
wire cdma_mux_bvalid;
wire cdma_mux_bready;
wire [31:0] cdma_mux_araddr;
wire cdma_mux_arvalid;
wire cdma_mux_arready;
wire [31:0] cdma_mux_rdata;
wire [1:0] cdma_mux_rresp;
wire cdma_mux_rvalid;
wire cdma_mux_rready;
wire [31:0] cdma_bridge_awaddr;
wire cdma_bridge_awvalid;
wire cdma_bridge_awready;
wire [31:0] cdma_bridge_wdata;
wire [3:0] cdma_bridge_wstrb;
wire cdma_bridge_wvalid;
wire cdma_bridge_wready;
wire [1:0] cdma_bridge_bresp;
wire cdma_bridge_bvalid;
wire cdma_bridge_bready;
wire [31:0] cdma_bridge_araddr;
wire cdma_bridge_arvalid;
wire cdma_bridge_arready;
wire [31:0] cdma_bridge_rdata;
wire [1:0] cdma_bridge_rresp;
wire cdma_bridge_rvalid;
wire cdma_bridge_rready;
wire bridge_cdma_rd_req_valid;
wire bridge_cdma_rd_req_ready;
wire [31:0] bridge_cdma_rd_req_src;
wire [31:0] bridge_cdma_rd_req_bytes;
wire [3:0] bridge_cdma_rd_req_ep_id;
wire [3:0] bridge_cdma_rd_req_ep_bank;
wire [7:0] bridge_cdma_rd_req_ep_word_off;
wire bridge_cdma_rd_req_done;
wire bridge_cdma_wr_req_valid;
wire bridge_cdma_wr_req_ready;
wire [31:0] bridge_cdma_wr_req_dst;
wire [31:0] bridge_cdma_wr_req_bytes;
wire [3:0] bridge_cdma_wr_req_ep_id;
wire [3:0] bridge_cdma_wr_req_ep_bank;
wire [7:0] bridge_cdma_wr_req_ep_word_off;
wire bridge_cdma_wr_req_done;
wire cdma_axil_wr_bridge = (cdma_s_awaddr[11:8] == 4'h2);
wire cdma_axil_rd_bridge = (cdma_s_araddr[11:8] == 4'h2);
reg cdma_axil_wr_active;
reg cdma_axil_wr_bridge_hold;
reg cdma_axil_b_bridge;
reg cdma_axil_r_bridge;
wire cdma_axil_wr_sel = cdma_axil_wr_active ? cdma_axil_wr_bridge_hold : cdma_axil_wr_bridge;
assign cdma_mux_awaddr = cdma_s_awaddr;
assign cdma_mux_awvalid = cdma_s_awvalid && !cdma_axil_wr_sel;
assign cdma_mux_wdata = cdma_s_wdata;
assign cdma_mux_wstrb = cdma_s_wstrb;
assign cdma_mux_wvalid = cdma_s_wvalid && !cdma_axil_wr_sel;
assign cdma_mux_bready = cdma_s_bready && !cdma_axil_b_bridge;
assign cdma_mux_araddr = cdma_s_araddr;
assign cdma_mux_arvalid = cdma_s_arvalid && !cdma_axil_rd_bridge;
assign cdma_mux_rready = cdma_s_rready && !cdma_axil_r_bridge;
assign cdma_bridge_awaddr = cdma_s_awaddr;
assign cdma_bridge_awvalid = cdma_s_awvalid && cdma_axil_wr_sel;
assign cdma_bridge_wdata = cdma_s_wdata;
assign cdma_bridge_wstrb = cdma_s_wstrb;
assign cdma_bridge_wvalid = cdma_s_wvalid && cdma_axil_wr_sel;
assign cdma_bridge_bready = cdma_s_bready && cdma_axil_b_bridge;
assign cdma_bridge_araddr = cdma_s_araddr;
assign cdma_bridge_arvalid = cdma_s_arvalid && cdma_axil_rd_bridge;
assign cdma_bridge_rready = cdma_s_rready && cdma_axil_r_bridge;
assign cdma_s_awready = cdma_axil_wr_sel ? cdma_bridge_awready : cdma_mux_awready;
assign cdma_s_wready = cdma_axil_wr_sel ? cdma_bridge_wready : cdma_mux_wready;
assign cdma_s_bresp = cdma_axil_b_bridge ? cdma_bridge_bresp : cdma_mux_bresp;
assign cdma_s_bvalid = cdma_axil_b_bridge ? cdma_bridge_bvalid : cdma_mux_bvalid;
assign cdma_s_arready = cdma_axil_rd_bridge ? cdma_bridge_arready : cdma_mux_arready;
assign cdma_s_rdata = cdma_axil_r_bridge ? cdma_bridge_rdata : cdma_mux_rdata;
assign cdma_s_rresp = cdma_axil_r_bridge ? cdma_bridge_rresp : cdma_mux_rresp;
assign cdma_s_rvalid = cdma_axil_r_bridge ? cdma_bridge_rvalid : cdma_mux_rvalid;
always @(posedge sys_clk) begin
if (!sys_resetn) begin
cdma_axil_wr_active <= 1'b0;
cdma_axil_wr_bridge_hold <= 1'b0;
cdma_axil_b_bridge <= 1'b0;
cdma_axil_r_bridge <= 1'b0;
end else begin
if (cdma_s_awvalid && !cdma_axil_wr_active) begin
cdma_axil_wr_active <= 1'b1;
cdma_axil_wr_bridge_hold <= cdma_axil_wr_bridge;
end
if (cdma_s_awvalid && cdma_s_awready && cdma_s_wvalid && cdma_s_wready) begin
cdma_axil_b_bridge <= cdma_axil_wr_sel;
cdma_axil_wr_active <= 1'b0;
end
if (cdma_s_arvalid && cdma_s_arready)
cdma_axil_r_bridge <= cdma_axil_rd_bridge;
end
end
axi_axil_adapter #(
wire [1:0] cdma_s_rresp;
wire cdma_s_rvalid;
wire cdma_s_rready;
wire [31:0] cdma_mux_awaddr;
wire cdma_mux_awvalid;
wire cdma_mux_awready;
wire [31:0] cdma_mux_wdata;
wire [3:0] cdma_mux_wstrb;
wire cdma_mux_wvalid;
wire cdma_mux_wready;
wire [1:0] cdma_mux_bresp;
wire cdma_mux_bvalid;
wire cdma_mux_bready;
wire [31:0] cdma_mux_araddr;
wire cdma_mux_arvalid;
wire cdma_mux_arready;
wire [31:0] cdma_mux_rdata;
wire [1:0] cdma_mux_rresp;
wire cdma_mux_rvalid;
wire cdma_mux_rready;
wire [31:0] cdma_bridge_awaddr;
wire cdma_bridge_awvalid;
wire cdma_bridge_awready;
wire [31:0] cdma_bridge_wdata;
wire [3:0] cdma_bridge_wstrb;
wire cdma_bridge_wvalid;
wire cdma_bridge_wready;
wire [1:0] cdma_bridge_bresp;
wire cdma_bridge_bvalid;
wire cdma_bridge_bready;
wire [31:0] cdma_bridge_araddr;
wire cdma_bridge_arvalid;
wire cdma_bridge_arready;
wire [31:0] cdma_bridge_rdata;
wire [1:0] cdma_bridge_rresp;
wire cdma_bridge_rvalid;
wire cdma_bridge_rready;
wire bridge_cdma_rd_req_valid;
wire bridge_cdma_rd_req_ready;
wire [31:0] bridge_cdma_rd_req_src;
wire [31:0] bridge_cdma_rd_req_bytes;
wire [3:0] bridge_cdma_rd_req_ep_id;
wire [3:0] bridge_cdma_rd_req_ep_bank;
wire [7:0] bridge_cdma_rd_req_ep_word_off;
wire bridge_cdma_rd_req_done;
wire bridge_cdma_wr_req_valid;
wire bridge_cdma_wr_req_ready;
wire [31:0] bridge_cdma_wr_req_dst;
wire [31:0] bridge_cdma_wr_req_bytes;
wire [3:0] bridge_cdma_wr_req_ep_id;
wire [3:0] bridge_cdma_wr_req_ep_bank;
wire [7:0] bridge_cdma_wr_req_ep_word_off;
wire bridge_cdma_wr_req_done;
wire cdma_axil_wr_bridge = (cdma_s_awaddr[11:8] == 4'h2);
wire cdma_axil_rd_bridge = (cdma_s_araddr[11:8] == 4'h2);
reg cdma_axil_wr_active;
reg cdma_axil_wr_bridge_hold;
reg cdma_axil_b_bridge;
reg cdma_axil_r_bridge;
wire cdma_axil_wr_sel = cdma_axil_wr_active ? cdma_axil_wr_bridge_hold : cdma_axil_wr_bridge;
assign cdma_mux_awaddr = cdma_s_awaddr;
assign cdma_mux_awvalid = cdma_s_awvalid && !cdma_axil_wr_sel;
assign cdma_mux_wdata = cdma_s_wdata;
assign cdma_mux_wstrb = cdma_s_wstrb;
assign cdma_mux_wvalid = cdma_s_wvalid && !cdma_axil_wr_sel;
assign cdma_mux_bready = cdma_s_bready && !cdma_axil_b_bridge;
assign cdma_mux_araddr = cdma_s_araddr;
assign cdma_mux_arvalid = cdma_s_arvalid && !cdma_axil_rd_bridge;
assign cdma_mux_rready = cdma_s_rready && !cdma_axil_r_bridge;
assign cdma_bridge_awaddr = cdma_s_awaddr;
assign cdma_bridge_awvalid = cdma_s_awvalid && cdma_axil_wr_sel;
assign cdma_bridge_wdata = cdma_s_wdata;
assign cdma_bridge_wstrb = cdma_s_wstrb;
assign cdma_bridge_wvalid = cdma_s_wvalid && cdma_axil_wr_sel;
assign cdma_bridge_bready = cdma_s_bready && cdma_axil_b_bridge;
assign cdma_bridge_araddr = cdma_s_araddr;
assign cdma_bridge_arvalid = cdma_s_arvalid && cdma_axil_rd_bridge;
assign cdma_bridge_rready = cdma_s_rready && cdma_axil_r_bridge;
assign cdma_s_awready = cdma_axil_wr_sel ? cdma_bridge_awready : cdma_mux_awready;
assign cdma_s_wready = cdma_axil_wr_sel ? cdma_bridge_wready : cdma_mux_wready;
assign cdma_s_bresp = cdma_axil_b_bridge ? cdma_bridge_bresp : cdma_mux_bresp;
assign cdma_s_bvalid = cdma_axil_b_bridge ? cdma_bridge_bvalid : cdma_mux_bvalid;
assign cdma_s_arready = cdma_axil_rd_bridge ? cdma_bridge_arready : cdma_mux_arready;
assign cdma_s_rdata = cdma_axil_r_bridge ? cdma_bridge_rdata : cdma_mux_rdata;
assign cdma_s_rresp = cdma_axil_r_bridge ? cdma_bridge_rresp : cdma_mux_rresp;
assign cdma_s_rvalid = cdma_axil_r_bridge ? cdma_bridge_rvalid : cdma_mux_rvalid;
always @(posedge sys_clk) begin
if (!sys_resetn) begin
cdma_axil_wr_active <= 1'b0;
cdma_axil_wr_bridge_hold <= 1'b0;
cdma_axil_b_bridge <= 1'b0;
cdma_axil_r_bridge <= 1'b0;
end else begin
if (cdma_s_awvalid && !cdma_axil_wr_active) begin
cdma_axil_wr_active <= 1'b1;
cdma_axil_wr_bridge_hold <= cdma_axil_wr_bridge;
end
if (cdma_s_awvalid && cdma_s_awready && cdma_s_wvalid && cdma_s_wready) begin
cdma_axil_b_bridge <= cdma_axil_wr_sel;
cdma_axil_wr_active <= 1'b0;
end
if (cdma_s_arvalid && cdma_s_arready)
cdma_axil_r_bridge <= cdma_axil_rd_bridge;
end
end
axi_axil_adapter #(
.ADDR_WIDTH(32),
.AXI_DATA_WIDTH(32),
.AXI_ID_WIDTH(5),
@@ -1762,63 +1778,63 @@ u_axi_axil_adapter(
.m_axil_rdata(cdma_s_rdata),
.m_axil_rresp(cdma_s_rresp),
.m_axil_rvalid(cdma_s_rvalid),
.m_axil_rready(cdma_s_rready)
);
cdma_matmul_bridge #(
.ADDR_WIDTH (32),
.AXIL_ADDR_WIDTH (32),
.AXIL_DATA_WIDTH (32)
) u_cdma_matmul_bridge (
.clk (sys_clk),
.rst_n (sys_resetn),
.s_axil_awaddr (cdma_bridge_awaddr),
.s_axil_awvalid (cdma_bridge_awvalid),
.s_axil_awready (cdma_bridge_awready),
.s_axil_wdata (cdma_bridge_wdata),
.s_axil_wstrb (cdma_bridge_wstrb),
.s_axil_wvalid (cdma_bridge_wvalid),
.s_axil_wready (cdma_bridge_wready),
.s_axil_bresp (cdma_bridge_bresp),
.s_axil_bvalid (cdma_bridge_bvalid),
.s_axil_bready (cdma_bridge_bready),
.s_axil_araddr (cdma_bridge_araddr),
.s_axil_arvalid (cdma_bridge_arvalid),
.s_axil_arready (cdma_bridge_arready),
.s_axil_rdata (cdma_bridge_rdata),
.s_axil_rresp (cdma_bridge_rresp),
.s_axil_rvalid (cdma_bridge_rvalid),
.s_axil_rready (cdma_bridge_rready),
.cdma_rd_req_valid (bridge_cdma_rd_req_valid),
.cdma_rd_req_ready (bridge_cdma_rd_req_ready),
.cdma_rd_req_src (bridge_cdma_rd_req_src),
.cdma_rd_req_bytes (bridge_cdma_rd_req_bytes),
.cdma_rd_req_ep_id (bridge_cdma_rd_req_ep_id),
.cdma_rd_req_ep_bank (bridge_cdma_rd_req_ep_bank),
.cdma_rd_req_ep_word_off(bridge_cdma_rd_req_ep_word_off),
.cdma_rd_req_done (bridge_cdma_rd_req_done),
.cdma_wr_req_valid (bridge_cdma_wr_req_valid),
.cdma_wr_req_ready (bridge_cdma_wr_req_ready),
.cdma_wr_req_dst (bridge_cdma_wr_req_dst),
.cdma_wr_req_bytes (bridge_cdma_wr_req_bytes),
.cdma_wr_req_ep_id (bridge_cdma_wr_req_ep_id),
.cdma_wr_req_ep_bank (bridge_cdma_wr_req_ep_bank),
.cdma_wr_req_ep_word_off(bridge_cdma_wr_req_ep_word_off),
.cdma_wr_req_done (bridge_cdma_wr_req_done),
.mat_start_valid (matmul_direct_start_valid),
.mat_start_bank (matmul_direct_start_bank),
.mat_done_clear (matmul_direct_done_clear),
.mat_crc_clear (matmul_direct_crc_clear),
.mat_done (matmul_direct_done),
.seq_done_irq (cdma_matmul_seq_irq)
);
// 8 通道 DMA
snix_axil_cdma_mux #(
.m_axil_rready(cdma_s_rready)
);
cdma_matmul_bridge #(
.ADDR_WIDTH (32),
.AXIL_ADDR_WIDTH (32),
.AXIL_DATA_WIDTH (32)
) u_cdma_matmul_bridge (
.clk (sys_clk),
.rst_n (sys_resetn),
.s_axil_awaddr (cdma_bridge_awaddr),
.s_axil_awvalid (cdma_bridge_awvalid),
.s_axil_awready (cdma_bridge_awready),
.s_axil_wdata (cdma_bridge_wdata),
.s_axil_wstrb (cdma_bridge_wstrb),
.s_axil_wvalid (cdma_bridge_wvalid),
.s_axil_wready (cdma_bridge_wready),
.s_axil_bresp (cdma_bridge_bresp),
.s_axil_bvalid (cdma_bridge_bvalid),
.s_axil_bready (cdma_bridge_bready),
.s_axil_araddr (cdma_bridge_araddr),
.s_axil_arvalid (cdma_bridge_arvalid),
.s_axil_arready (cdma_bridge_arready),
.s_axil_rdata (cdma_bridge_rdata),
.s_axil_rresp (cdma_bridge_rresp),
.s_axil_rvalid (cdma_bridge_rvalid),
.s_axil_rready (cdma_bridge_rready),
.cdma_rd_req_valid (bridge_cdma_rd_req_valid),
.cdma_rd_req_ready (bridge_cdma_rd_req_ready),
.cdma_rd_req_src (bridge_cdma_rd_req_src),
.cdma_rd_req_bytes (bridge_cdma_rd_req_bytes),
.cdma_rd_req_ep_id (bridge_cdma_rd_req_ep_id),
.cdma_rd_req_ep_bank (bridge_cdma_rd_req_ep_bank),
.cdma_rd_req_ep_word_off(bridge_cdma_rd_req_ep_word_off),
.cdma_rd_req_done (bridge_cdma_rd_req_done),
.cdma_wr_req_valid (bridge_cdma_wr_req_valid),
.cdma_wr_req_ready (bridge_cdma_wr_req_ready),
.cdma_wr_req_dst (bridge_cdma_wr_req_dst),
.cdma_wr_req_bytes (bridge_cdma_wr_req_bytes),
.cdma_wr_req_ep_id (bridge_cdma_wr_req_ep_id),
.cdma_wr_req_ep_bank (bridge_cdma_wr_req_ep_bank),
.cdma_wr_req_ep_word_off(bridge_cdma_wr_req_ep_word_off),
.cdma_wr_req_done (bridge_cdma_wr_req_done),
.mat_start_valid (matmul_direct_start_valid),
.mat_start_bank (matmul_direct_start_bank),
.mat_done_clear (matmul_direct_done_clear),
.mat_crc_clear (matmul_direct_crc_clear),
.mat_done (matmul_direct_done),
.seq_done_irq (cdma_matmul_seq_irq)
);
// 8 通道 DMA
snix_axil_cdma_mux #(
.ADDR_WIDTH (32),
.DATA_WIDTH (32), // 适配你的 32-bit 总线
.AXIL_ADDR_WIDTH (32),
@@ -1832,23 +1848,23 @@ snix_axil_cdma_mux #(
.rst_n (sys_resetn), // 低电平复位
// AXI-Lite 从机接口 (接 CPU 发来的配置请求)
.s_axil_awaddr (cdma_mux_awaddr),
.s_axil_awvalid (cdma_mux_awvalid),
.s_axil_awready (cdma_mux_awready),
.s_axil_wdata (cdma_mux_wdata),
.s_axil_wstrb (cdma_mux_wstrb),
.s_axil_wvalid (cdma_mux_wvalid),
.s_axil_wready (cdma_mux_wready),
.s_axil_bresp (cdma_mux_bresp),
.s_axil_bvalid (cdma_mux_bvalid),
.s_axil_bready (cdma_mux_bready),
.s_axil_araddr (cdma_mux_araddr),
.s_axil_arvalid (cdma_mux_arvalid),
.s_axil_arready (cdma_mux_arready),
.s_axil_rdata (cdma_mux_rdata),
.s_axil_rresp (cdma_mux_rresp),
.s_axil_rvalid (cdma_mux_rvalid),
.s_axil_rready (cdma_mux_rready),
.s_axil_awaddr (cdma_mux_awaddr),
.s_axil_awvalid (cdma_mux_awvalid),
.s_axil_awready (cdma_mux_awready),
.s_axil_wdata (cdma_mux_wdata),
.s_axil_wstrb (cdma_mux_wstrb),
.s_axil_wvalid (cdma_mux_wvalid),
.s_axil_wready (cdma_mux_wready),
.s_axil_bresp (cdma_mux_bresp),
.s_axil_bvalid (cdma_mux_bvalid),
.s_axil_bready (cdma_mux_bready),
.s_axil_araddr (cdma_mux_araddr),
.s_axil_arvalid (cdma_mux_arvalid),
.s_axil_arready (cdma_mux_arready),
.s_axil_rdata (cdma_mux_rdata),
.s_axil_rresp (cdma_mux_rresp),
.s_axil_rvalid (cdma_mux_rvalid),
.s_axil_rready (cdma_mux_rready),
// AXI4 主机接口 (接 Crossbar 去搬运数据)
.mm2mm_awid (dma_m_awid),
@@ -1891,43 +1907,43 @@ snix_axil_cdma_mux #(
.mm2mm_rresp (dma_m_rresp),
.mm2mm_rlast (dma_m_rlast),
.mm2mm_ruser (1'b0),
.mm2mm_rvalid (dma_m_rvalid),
.mm2mm_rready (dma_m_rready),
// 本地直连到 matmul,不经过 AXI crossbar
.ep_wr_valid (matmul_ep_wr_valid),
.ep_wr_id (matmul_ep_wr_id),
.ep_wr_bank (matmul_ep_wr_bank),
.ep_wr_word_addr (matmul_ep_wr_word_addr),
.ep_wr_data (matmul_ep_wr_data),
.ep_wr_ready (matmul_ep_wr_ready),
.ep_rd_valid (matmul_ep_rd_valid),
.ep_rd_id (matmul_ep_rd_id),
.ep_rd_bank (matmul_ep_rd_bank),
.ep_rd_word_addr (matmul_ep_rd_word_addr),
.ep_rd_data (matmul_ep_rd_data),
.ep_rd_ready (matmul_ep_rd_ready),
.ext_rd_req_valid (bridge_cdma_rd_req_valid),
.ext_rd_req_ready (bridge_cdma_rd_req_ready),
.ext_rd_req_src (bridge_cdma_rd_req_src),
.ext_rd_req_bytes (bridge_cdma_rd_req_bytes),
.ext_rd_req_ep_id (bridge_cdma_rd_req_ep_id),
.ext_rd_req_ep_bank (bridge_cdma_rd_req_ep_bank),
.ext_rd_req_ep_word_off(bridge_cdma_rd_req_ep_word_off),
.ext_rd_req_done (bridge_cdma_rd_req_done),
.ext_wr_req_valid (bridge_cdma_wr_req_valid),
.ext_wr_req_ready (bridge_cdma_wr_req_ready),
.ext_wr_req_dst (bridge_cdma_wr_req_dst),
.ext_wr_req_bytes (bridge_cdma_wr_req_bytes),
.ext_wr_req_ep_id (bridge_cdma_wr_req_ep_id),
.ext_wr_req_ep_bank (bridge_cdma_wr_req_ep_bank),
.ext_wr_req_ep_word_off(bridge_cdma_wr_req_ep_word_off),
.ext_wr_req_done (bridge_cdma_wr_req_done),
// 全局中断输出
.dma_finish (cdma_dma_finish)
);
endmodule
.mm2mm_rvalid (dma_m_rvalid),
.mm2mm_rready (dma_m_rready),
// 本地直连到 matmul,不经过 AXI crossbar
.ep_wr_valid (matmul_ep_wr_valid),
.ep_wr_id (matmul_ep_wr_id),
.ep_wr_bank (matmul_ep_wr_bank),
.ep_wr_word_addr (matmul_ep_wr_word_addr),
.ep_wr_data (matmul_ep_wr_data),
.ep_wr_ready (matmul_ep_wr_ready),
.ep_rd_valid (matmul_ep_rd_valid),
.ep_rd_id (matmul_ep_rd_id),
.ep_rd_bank (matmul_ep_rd_bank),
.ep_rd_word_addr (matmul_ep_rd_word_addr),
.ep_rd_data (matmul_ep_rd_data),
.ep_rd_ready (matmul_ep_rd_ready),
.ext_rd_req_valid (bridge_cdma_rd_req_valid),
.ext_rd_req_ready (bridge_cdma_rd_req_ready),
.ext_rd_req_src (bridge_cdma_rd_req_src),
.ext_rd_req_bytes (bridge_cdma_rd_req_bytes),
.ext_rd_req_ep_id (bridge_cdma_rd_req_ep_id),
.ext_rd_req_ep_bank (bridge_cdma_rd_req_ep_bank),
.ext_rd_req_ep_word_off(bridge_cdma_rd_req_ep_word_off),
.ext_rd_req_done (bridge_cdma_rd_req_done),
.ext_wr_req_valid (bridge_cdma_wr_req_valid),
.ext_wr_req_ready (bridge_cdma_wr_req_ready),
.ext_wr_req_dst (bridge_cdma_wr_req_dst),
.ext_wr_req_bytes (bridge_cdma_wr_req_bytes),
.ext_wr_req_ep_id (bridge_cdma_wr_req_ep_id),
.ext_wr_req_ep_bank (bridge_cdma_wr_req_ep_bank),
.ext_wr_req_ep_word_off(bridge_cdma_wr_req_ep_word_off),
.ext_wr_req_done (bridge_cdma_wr_req_done),
// 全局中断输出
.dma_finish (cdma_dma_finish)
);
endmodule

BIN
sdk/sdk Normal file

Binary file not shown.

View File

@@ -2,17 +2,47 @@ TARGET = mlkem_test
CFLAGS += -O3 -g
CFLAGS += -I./mlkem_native
CFLAGS += -DMLK_CONFIG_PARAMETER_SET=512
CFLAGS += -DMLK_CONFIG_NAMESPACE_PREFIX=swmlkem
CFLAGS += -DMLK_CONFIG_NO_RANDOMIZED_API
CFLAGS += -DMLK_CONFIG_NO_ASM
CFLAGS += -DMLK_CONFIG_FILE='"sw_mlkem_config.h"'
C_SRCS := $(wildcard ./*.c )
C_SRCS += ./mlkem_native/mlkem_native.c
C_SRCS := ./dma.c ./main.c ./sw_mlkem_alloc.c
MLKEM_NATIVE_CFLAGS = \
-DMLK_CONFIG_NO_RANDOMIZED_API \
-DMLK_CONFIG_NO_SUPERCOP \
-DMLK_CONFIG_NO_ASM \
-DMLK_CONFIG_FILE='"sw_mlkem_config.h"'
MLKEM_NATIVE_OBJS = \
obj/mlkem_native_512.o \
obj/mlkem_native_768.o \
obj/mlkem_native_1024.o
LINK_OBJS += $(MLKEM_NATIVE_OBJS)
CLEAN_OBJS += $(MLKEM_NATIVE_OBJS)
OBJDIR = obj
COMMON_DIR = ../../bsp
GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0
PICOLIBC_DIR=../../../toolchains/picolibc
LA32RSOC_WINDOWS_HOME ?= ../../..
include ../../bsp/common.mk
obj/mlkem_native_512.o: ./mlkem_native/mlkem_native.c
mkdir -p obj
$(LA32R_GCC) $(CFLAGS) $(INCLUDES) $(MLKEM_NATIVE_CFLAGS) \
-DMLK_CONFIG_PARAMETER_SET=512 \
-DMLK_CONFIG_NAMESPACE_PREFIX=swmlkem512 \
-c -o $@ $<
obj/mlkem_native_768.o: ./mlkem_native/mlkem_native.c
mkdir -p obj
$(LA32R_GCC) $(CFLAGS) $(INCLUDES) $(MLKEM_NATIVE_CFLAGS) \
-DMLK_CONFIG_PARAMETER_SET=768 \
-DMLK_CONFIG_NAMESPACE_PREFIX=swmlkem768 \
-c -o $@ $<
obj/mlkem_native_1024.o: ./mlkem_native/mlkem_native.c
mkdir -p obj
$(LA32R_GCC) $(CFLAGS) $(INCLUDES) $(MLKEM_NATIVE_CFLAGS) \
-DMLK_CONFIG_PARAMETER_SET=1024 \
-DMLK_CONFIG_NAMESPACE_PREFIX=swmlkem1024 \
-c -o $@ $<

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
#include "sw_mlkem_alloc.h"
#include <stdint.h>
#define SW_MLKEM_ALLOC_ALIGN 32u
#define SW_MLKEM_ALLOC_SIZE (64u * 1024u)
static uint8_t sw_mlkem_arena[SW_MLKEM_ALLOC_SIZE] __attribute__((aligned(SW_MLKEM_ALLOC_ALIGN)));
static size_t sw_mlkem_arena_pos;
static unsigned sw_mlkem_arena_active;
static size_t align_up(size_t n)
{
return (n + (SW_MLKEM_ALLOC_ALIGN - 1u)) & ~(SW_MLKEM_ALLOC_ALIGN - 1u);
}
void *sw_mlkem_alloc(size_t size)
{
size_t pos = align_up(sw_mlkem_arena_pos);
size_t need = align_up(size);
if (pos + need > SW_MLKEM_ALLOC_SIZE)
return 0;
sw_mlkem_arena_pos = pos + need;
sw_mlkem_arena_active++;
return &sw_mlkem_arena[pos];
}
void sw_mlkem_free(void *ptr, size_t size)
{
(void)ptr;
(void)size;
if (sw_mlkem_arena_active != 0)
sw_mlkem_arena_active--;
if (sw_mlkem_arena_active == 0)
sw_mlkem_arena_pos = 0;
}

View File

@@ -0,0 +1,9 @@
#ifndef SW_MLKEM_ALLOC_H
#define SW_MLKEM_ALLOC_H
#include <stddef.h>
void *sw_mlkem_alloc(size_t size);
void sw_mlkem_free(void *ptr, size_t size);
#endif

View File

@@ -11,11 +11,19 @@
#include "mlkem_native_config.h"
#define MLK_CONFIG_CUSTOM_ZEROIZE
#define MLK_CONFIG_CUSTOM_ALLOC_FREE
#if !defined(__ASSEMBLER__)
#include <stddef.h>
#include <stdint.h>
#include "src/sys.h"
#include "sw_mlkem_alloc.h"
#define MLK_CUSTOM_ALLOC(v, T, N) \
T *(v) = (T *)sw_mlkem_alloc(sizeof(T) * (N))
#define MLK_CUSTOM_FREE(v, T, N) \
sw_mlkem_free((void *)(v), sizeof(T) * (N))
static MLK_INLINE void mlk_zeroize(void *ptr, size_t len)
{

85
test_data/README.md Normal file
View File

@@ -0,0 +1,85 @@
## KAT for FIPS-203
Compliant with FIPS-203, published on August 13, 2024.
## File format:
| Field | Meaning |
|-----------|--------------------------------------------------------|
| ``count`` | Test number |
| ``z`` | Random 32-bytes ``z`` (Algorithm 15) |
| ``d`` | Random 32-bytes ``d`` (Algorithm 12) |
| ``msg`` | Random 32-bytes ``m`` (Algorithm 16) |
| ``seed`` | AES-CTR-drbg seed |
| ``pk`` | Resulting public key |
| ``sk`` | Resulting secret key |
| ``ct`` | Resulting KEM ciphertext |
| ``ss`` | Resulting KEM shared secret |
| ``ct_n`` | Invalid KEM ciphertext |
| ``ss_n`` | Shared secret resulting from decapsulation of ``ct_n`` |
## Differences with the FIPS-203
- No tests for key validation
## How it was generated
We use DRBG based on based on AES-CTR (see [SP800-90A](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf)) for generating random bytes. For each KAT vector, the DRBG is seeded with the ``seed`` value (personalisation string is not used). The test first generates a secret and public key. Then it encapsulates and decapsulates the shared secret.
The pseudocode below may make it clearer
```
use aes_ctr_drbg::DrbgCtx; // aes_ctr_drbg = "0.0.2" crate
fn main() {
// Initialize DRBG with the magic value
let Ok(mut entropy) = hex::decode("60496cd0a12512800a79161189b055ac3996ad24e578d3c5fc57c1e60fa2eb4e550d08e51e9db7b67f1a616681d9182d") else {
... blah ...
}
let mut drbg: DrbgCtx = DrbgCtx::new();
drbg.init(&entropy, Vec::new());
for i in 0..100 {
drbg.get_random(&mut entropy);
kem::kem(i, &entropy);
}
}
pub fn kem(count: usize, entropy: &[u8]) {
let mut buf = Vec::new();
let mut drbg: DrbgCtx = DrbgCtx::new();
drbg.init(&entropy.clone(), Vec::new());
println!("count = {}", count);
// The code generates random strings in the following order: z,d,msg
// z
buf.resize(32, 0);
drbg.get_random(&mut buf);
println!("z = {}", hex::encode(&buf));
// d
drbg.get_random(&mut buf);
println!("d = {}", hex::encode(&buf));
// msg
drbg.get_random(&mut buf);
println!("msg = {}", hex::encode(&buf));
// Re-init
drbg.init(&entropy.clone(), Vec::new());
// Generate keys
kyber_keygen(&mut pk, &mut sk);
// Encapsulate
kyber_encaps(&pk, &mut ct, &mut ss);
// Decapsulate
kyber_decaps(&sk, &ct, &mut ss);
println!("seed = {}", hex::encode(&entropy));
println!("pk = {}", hex::encode(&pk));
println!("sk = {}", hex::encode(&sk));
println!("ct = {}", hex::encode(&ct));
println!("ss = {}", hex::encode(&ss1));
```

11000
test_data/kat_MLKEM_1024.rsp Normal file

File diff suppressed because one or more lines are too long

11000
test_data/kat_MLKEM_512.rsp Normal file

File diff suppressed because it is too large Load Diff

11000
test_data/kat_MLKEM_768.rsp Normal file

File diff suppressed because it is too large Load Diff