This repository has been archived on 2026-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ciciec2026/doc/mlkem_axi_slave_regs.md

9.0 KiB
Raw Blame History

ML-KEM AXI Slave 寄存器参考手册

概述

mlkem_axi_slave 是 ML-KEM 硬件加速器的 AXI4 Slave 总线接口。它封装 mlkem_top 核心,提供完整的寄存器映射用于软件控制 KeyGen / Encaps / Decaps 操作。

关键特性

  • 总线: AXI4 (支持 INCR burst read/write)
  • 基址: 0xbf400000(LoongArch 虚地址)
  • 时钟域: sys_clk (50 MHz) → mlkem_clk (25 MHz),跨域通过 toggle 握手同步
  • 支持参数: k=2 (ML-KEM-512), k=3 (ML-KEM-768), k=4 (ML-KEM-1024)
  • 中断: intr 信号,当 done 标志锁存时电平有效高

寄存器映射

所有寄存器为 32-bit 对齐。偏移量相对于基址 0xbf400000。

偏移 名称 访问 复位值 描述
0x000 CTRL W 0x00000000 控制寄存器:写 bit0=1 启动操作
0x004 STATUS R/W1C 0x00000000 状态寄存器
0x008 CONFIG RW 0x00000004 配置寄存器:k 值和操作码
0x010–0x02C D[0..7] RW 0x00000000 KeyGen 种子 d(256-bit,8字)
0x030–0x04C Z[0..7] RW 0x00000000 KeyGen 隐式拒绝种子 z(256-bit,8字)
0x050–0x06C MSG[0..7] RW 0x00000000 Encaps 消息 m(256-bit,8字)
0x070–0x08C SS[0..7] R — 共享密钥输出(256-bit,8字,只读)
0x100 PRELOAD_SEL RW 0x00000000 预载端口选择
0x104 PRELOAD_ADDR RW 0x00000000 预载字节地址(写入后自动递增)
0x108 PRELOAD_DATA W — 预载数据字节(写低 8-bit,自动 wait-state)
0x10C READBACK_SEL RW 0x00000000 回读端口选择
0x110 READBACK_ADDR RW 0x00000000 回读字节索引(无自动递增)
0x114 READBACK_DATA R — 回读数据字节(低 8-bit 有效)

寄存器详情

CTRL (0x000) — 控制寄存器,只写

Bits 名称 描述
0 start 写 1 启动当前 CONFIG 中配置的操作。写 0 无效。
  • 写 start 后,STATUS.busy 立即置位,done 清零。
  • 操作完成前不可再次启动。
  • CTRL 本身不可读(读返回 0)。

STATUS (0x004) — 状态寄存器,读/写1清零

Bits 名称 访问 描述
0 busy R 核心正在执行操作(KeyGen/Encaps/Decaps)
1 done R/W1C 操作已完成。写 1 清除(写 0 无效)。启动新操作时自动清除
2 preload_busy R 预载数据传输正在进行中(跨域字节握手未完成)
31:3 — — 保留,读为 0

注意:

  • done 是锁存标志:操作完成后保持为 1,直到软件写 1 清零或启动新操作。
  • busy 和 done 不互斥:在 done 置位的同一周期 busy 清零,两者可能同时为 1(短暂窗口)。
  • preload_busy 为 1 时,写入 PRELOAD_DATA 会被 wait-state 直到传输完成。

CONFIG (0x008) — 配置寄存器,读写

Bits 名称 复位值 描述
2:0 k 3'b100 (4) ML-KEM 参数:2=ML-KEM-512, 3=ML-KEM-768, 4=ML-KEM-1024
4 — 0 保留
5:4 op 2'b00 操作码:0=KeyGen, 1=Encaps, 2=Decaps
31:6 — 0 保留

约束:

  • 修改 CONFIG 应在启动操作之前完成。启动后修改可能导致未定义行为。
  • k 必须为 2、3 或 4。

D[0..7] (0x010–0x02C) — KeyGen 种子 d,读写

256-bit 种子 d,用于 KeyGen 操作。存储为 8 个 32-bit 字,小端序:

字偏移 地址 包含字节
D[0] 0x010 d[3:0](字节 3 在 bit[31:24],字节 0 在 bit[7:0])
D[1] 0x014 d[7:4]
... ... ...
D[7] 0x02C d[31:28]

核心看到的 256-bit 总线为 {D[7], D[6], ..., D[0]},其中 d_i[7:0] = D[0][7:0]。

支持 AXI wstrb 按字节写入。


Z[0..7] (0x030–0x04C) — 隐式拒绝种子 z,读写

256-bit 种子 z,用于 KeyGen。布局与 D 相同。


MSG[0..7] (0x050–0x06C) — Encaps 消息 m,读写

256-bit 消息 m,用于 Encaps。布局与 D 相同。


SS[0..7] (0x070–0x08C) — 共享密钥,只读

256-bit 共享密钥输出。KeyGen 和 Encaps 操作完成后在此处提供结果。

字偏移 地址 内容
SS[0] 0x070 ss[31:0]
SS[1] 0x074 ss[63:32]
... ... ...
SS[7] 0x08C ss[255:224]

PRELOAD_SEL (0x100) — 预载端口选择,读写

Bits 名称 描述
1:0 sel 预载目标端口:0=ek, 1=dk, 2=c(密文)
31:2 — 保留

设置后,随后写入 PRELOAD_DATA 的字节将流向所选端口。


PRELOAD_ADDR (0x104) — 预载字节地址,读写

Bits 名称 描述
11:0 addr 预载端口内的字节偏移地址。每次 PRELOAD_DATA 写入成功后自动递增
31:12 — 保留

写入 PRELOAD_DATA 前必须先设置好 PRELOAD_SEL 和 PRELOAD_ADDR(通常 addr=0)。


PRELOAD_DATA (0x108) — 预载数据字节,只写

Bits 名称 描述
7:0 byte 写入所选预载端口的字节数据
31:8 — 忽略

此寄存器自动 wait-state:写入后 AXI 总线暂停,直到跨域握手完成(字节被 mlkem 核心采样)。然后 PRELOAD_ADDR 自动递增 1。

重要: 每个字节需要一次 AXI 写事务。对于大数据量(ek=800B, dk=1632B),建议使用 INCR burst 写,burst 长度设为字节数。


READBACK_SEL (0x10C) — 回读端口选择,读写

Bits 名称 描述
1:0 sel 回读源:0=ek, 1=dk_pke, 2=完整 dk, 3=密文
31:2 — 保留

READBACK_ADDR (0x110) — 回读字节索引,读写

Bits 名称 描述
11:0 addr 待读取字节在回读端口中的索引。无自动递增
31:12 — 保留

每个字节的读取流程:写 READBACK_ADDR → 读 READBACK_DATA。


READBACK_DATA (0x114) — 回读数据字节,只读

Bits 名称 描述
7:0 byte 所选回读端口中 READBACK_ADDR 索引处的字节
31:24 — 读为 0

操作流程

1. KeyGen: (d, z) → ek, dk

1. 写 CONFIG: op=0 (KeyGen), k=2/3/4
2. 写 D[0..7]  ← 种子 d (256-bit)
3. 写 Z[0..7]  ← 种子 z (256-bit)
4. 写 CTRL: bit0=1 → 启动
5. 轮询 STATUS.done == 1(或等待 intr)
6. 通过 READBACK 读取 ek 和 dk:
   a. RDB_SEL=0, 逐个字节读 ADDR=0..799 → ek  (800 B for k=2)
   b. RDB_SEL=2, 逐个字节读 ADDR=0..1631 → dk (1632 B for k=2)
7. 读 SS[0..7] → 共享密钥(可选)
8. 写 STATUS: bit1=1 → 清除 done

2. Encaps: (ek, m) → (ss, ct)

1. 写 CONFIG: op=1 (Encaps), k=2/3/4
2. 通过 PRELOAD 预载 ek:
   a. PRE_SEL=0, PRE_ADR=0
   b. 逐个字节写 PRE_DAT (800 B for k=2)
3. 写 MSG[0..7] ← 消息 m (256-bit)
4. 写 CTRL: bit0=1 → 启动
5. 轮询 STATUS.done == 1
6. 读 SS[0..7] → 共享密钥
7. 通过 READBACK 读取 ct:
   a. RDB_SEL=3, 逐个字节读 ADDR=0..767 → ct (768 B for k=2)

3. Decaps: (dk, ct) → ss

1. 写 CONFIG: op=2 (Decaps), k=2/3/4
2. 通过 PRELOAD 预载 dk 和 ct:
   a. PRE_SEL=1, PRE_ADR=0, 逐个字节写 PRE_DAT (1632 B for k=2)
   b. PRE_SEL=2, PRE_ADR=0, 逐个字节写 PRE_DAT (768 B for k=2)
3. 写 CTRL: bit0=1 → 启动
4. 轮询 STATUS.done == 1
5. 读 SS[0..7] → 共享密钥

数据尺寸参考

参数 k=2 (ML-KEM-512) k=3 (ML-KEM-768) k=4 (ML-KEM-1024)
ek 字节数 800 1184 1568
dk_pke 字节数 768 1152 1536
dk 总字节数 1632 2400 3168
ct 字节数 768 1088 1568

中断

  • intr 信号在 STATUS.done == 1 时保持高电平。
  • 清除中断:写 STATUS 的 bit1=1(W1C)或启动新操作。
  • intr 是电平触发(非脉冲),连接到 LoongArch 的 HWI 输入。

注意事项

  1. 时钟域: 核心运行在 sys_clk/2 (25 MHz)。PRELOAD_DATA 写入自动 wait-state,软件无需处理跨域延迟。
  2. 启动时序: 确保在写 CTRL.start 之前,config/seeds/preload 数据已全部写入且稳定。
  3. PRELOAD_ADDR 自动递增: 连续写 PRELOAD_DATA 时地址自动递增,无需手动更新 PRELOAD_ADDR(除非切换端口)。
  4. READBACK_ADDR 无自动递增: 每次读 READBACK_DATA 前必须手动写 READBACK_ADDR。
  5. done 标志: 是锁存的,启动新操作时自动清除。连续执行多个操作时,每次启动前先确认 busy==0,然后清 done。
  6. STATUS 读取时机: done 标志在操作完成的 mlkem_clk 周期后,需经 2 级同步器(~40ns)才能在 sys_clk 域看到。