L1
L1 单元详细设计
把 [[Pipe]] 第 6 节 §193 的 L1 抽象展开到 RTL 起手前。每条 cacheline = 一条 data pipe 实例。L1 是被动单元:无命令队列、无 FSM、无数据搬运能力;本体 = bank 化 SRAM + count 阵列 + 控制接口。所有 count 更新由外部 master 经控制总线推 COUNT_DELTA,L1 自身不发起任何控制总线请求。
1. 顶层参数
| 参数 | 含义 | 默认 | 限制 |
|---|---|---|---|
N_CL |
cacheline 总数(= data pipe 容量) | 256 | 2 的幂 |
CL_BYTES |
每条 cacheline 字节数(物理固定) | 256 | 2 的幂 |
N_BANK |
SRAM bank 数 | 8 | 2 的幂,整除 N_CL |
N_MASTER |
NoC slave 端口数 | 4 | |
N_SYNC |
sync counter 数 | 16 | |
N_PEND_WAIT |
全单元未决 pwait 数 | 16 | cacheline + sync 共用 |
COUNT_W |
count 寄存器位宽 | 32 | |
HANDLE_W |
pipe handle 位宽 | 16 = unit_addr(8) + pipe_id(8) | |
ADDR_W |
系统地址位宽 | 48 | |
NOC_W |
NoC 数据 beat 位宽 | 512 | 每 cacheline 占 CL_BYTES*8/NOC_W beat |
容量 = N_CL × CL_BYTES 字节。物理 cacheline 大小固定 —— palloc 不接受可变 size 参数;上层若需大块容器,分配多条相邻 cacheline 用作一组。
2. 顶层框图
┌──────────────────── L1 单元 ────────────────┐
ctrl_s ────────►│ ctrl 解码 + 路由 ──┬──► CL Pool Mgr │
ctrl_s ◄────────│ ├──► Sync Pool │
│ ├──► count 阵列(分 bank)│
│ └──► pending wait CAM │
│ │
noc_s[0]◄─┐ │ ┌─────── crossbar ─┐ ┌─ Bank[0] SRAM ──┐ │
noc_s[0]─►┤ │ │ N_MASTER×N_BANK ├──► │ Bank[1] SRAM │ │
... ├──────► │ 仲裁 + routing │ │ ... │ │
noc_s[M-1]◄┘ │ └──────────────────┘ │ Bank[N_BANK-1] │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────┘
子模块:
- CL Pool Manager:data pipe 的 alloc/free + bitmap
- Count 阵列:每条 cacheline 一个 count,按 bank 分块
- Bank SRAM × N_BANK:cacheline 数据存储
- Crossbar:N_MASTER × N_BANK 路 master → bank 仲裁
- Sync Pool:N_SYNC 个独立 sync counter
- Pending Wait CAM:未决 pwait 表,共用于 cacheline + sync count
- Ctrl 解码 + 路由:单 slave 接收口
3. 顶层端口
3.1 控制端口 ctrl_s_*
完全复用 [[DMA]] §3.1 的从端定义。L1 不实例化 ctrl_m(无主端,无主动发起)。
3.2 数据端口 noc_s_[N_MASTER]
每个端口是 NoC slave,AXI4-lite 风格:
| 信号 | 方向 | 位宽 | 说明 |
|---|---|---|---|
req_valid |
in | 1 | |
req_ready |
out | 1 | |
req_addr |
in | ADDR_W | 物理字节地址 |
req_op |
in | 1 | 0=read, 1=write |
req_len |
in | log2(CL_BYTES/NOC_W*8)+1 | beats - 1;硬件约束:burst 不跨 cacheline |
req_id |
in | MASTER_ID_W = 6 | master 内的 transaction id |
wr_data |
in | NOC_W | 写数据 |
wr_strb |
in | NOC_W/8 | byte enable |
wr_last |
in | 1 | |
rd_data |
out | NOC_W | |
rd_id |
out | MASTER_ID_W | |
rd_last |
out | 1 |
约束:
- 一个 burst 必须落在单条 cacheline 内(不跨界)。跨界请求由发起方拆。
- L1 不对 master 做合法性检查(特性 6)。
4. 地址映射
4.1 物理地址 ↔ pipe_id
L1 占系统地址空间一段连续区域,基址 L1_BASE:
byte_addr = L1_BASE | (cl_id << log2(CL_BYTES)) | offset
cl_id = byte_addr[log2(CL_BYTES) +: log2(N_CL)] // 也即 data pipe 的 pipe_id 低位
offset = byte_addr[0 +: log2(CL_BYTES)]
软件经 PALLOC 拿到的 handle = {unit_addr, type=data, cl_id},使用时按上式还原成 byte_addr 配进 master 的命令。Master 与 L1 之间的 NoC 端口只传 byte_addr,不传 pipe_id —— pipe_id 由 L1 自己从地址解出。
4.2 bank 映射
bank_id = cl_id[0 +: log2(N_BANK)] // 低位选 bank
cl_in_bank = cl_id[log2(N_BANK) +: log2(N_CL/N_BANK)] // 高位选 bank 内行
连续 cl_id 自然分布到不同 bank,降低线性扫描场景的 bank 冲突。
5. 控制总线协议子集
复用 [[DMA]] §5 的 opcode 表。L1 仅处理:
| op | 行为 |
|---|---|
PALLOC(type=data, _) → cl_id handle |
见 §6 |
PALLOC(type=sync, _) → sync_id handle |
见 §9 |
PFREE(handle) |
见 §6 / §9 |
PREAD(handle) → count |
直接读 count 阵列 |
PWAIT(handle, threshold) |
见 §10 |
PSET_COUNT(handle, value) |
直接写 count 阵列 |
COUNT_DELTA(handle, delta) |
见 §7 |
COUNT_QUERY(handle, threshold) |
立即比较,回 ack(命中/未命中) |
PSIGNAL(handle, delta) |
仅对 sync pipe,等价于 COUNT_DELTA |
非法 op、handle 类型错配等不报错,行为未定义(特性 6)。
6. CL Pool 管理器
6.1 存储
| 存储 | 形式 | 容量 |
|---|---|---|
cl_alloc_bitmap |
FF | N_CL bit |
cl_valid_flag |
FF | N_CL bit(PALLOC 后 1,PFREE 后 0) |
cacheline 大小固定,无需 per-line metadata。
6.2 alloc / free
PALLOC(type=data) →
free_id = priority_encoder(~cl_alloc_bitmap)
cl_alloc_bitmap[free_id] ← 1
cl_valid_flag[free_id] ← 1
count_cl[free_id] ← 0 // 通过 count 阵列写端口
resp ← {unit_addr, type=data, free_id} // HANDLE_W
PFREE(handle) →
cl_alloc_bitmap[handle.id] ← 0
cl_valid_flag[handle.id] ← 0
// count 不主动复位,下次 alloc 时清
延迟:1 cycle(N_CL = 256 时优先编码器 8 级,单 cycle 容易达到)。
7. Count 阵列
7.1 存储与分块
count 阵列与 bank SRAM 共用 cl_id 的 bank 映射:
count_bank[N_BANK]:
每个 bank:(N_CL/N_BANK) × COUNT_W 寄存器组
每 bank 独立读写端口。每 bank 可同 cycle 处理 1 读 + 1 写(互不冲突);本 bank 多读 / 多写 round-robin。
为什么按 cl_id bank 分块(与 SRAM 一致):连续 cacheline 的 count 更新分散到不同 bank,匹配 master 通常的访问 locality。
7.2 写端竞争
可能的 count 写来源:
- PALLOC 复位
- PSET_COUNT
- COUNT_DELTA(多路并发,来自任何外部 master)
每 bank 单写端口,上一级 round-robin 仲裁器选一个胜者;其他 backpressure 到 ctrl_s_req_ready。
7.3 与 SRAM 写完成的关系
完全解耦:
- 数据路径:master → NoC → L1 SRAM bank(commit 即落地)
- 控制路径:master → ctrl bus → L1 count 阵列
L1 不在数据端口上推断"写完成 → count++"。这一语义由发起方在自己的执行 FSM 内排序保证(见 [[DMA]] §7.3:状态机先 WRITE 完成才进 NOTIFY;[[算力单元]] §7.3 同理)。
后果:若 master 提前发 COUNT_DELTA(在数据写到 SRAM 之前),L1 不能阻止;这是软件 / master 内部 RTL 的责任,不是 L1 的检查项。
8. Bank SRAM 阵列
8.1 Bank 组织
N_BANK 个 SRAM macro:
每个:(N_CL/N_BANK) × CL_BYTES bytes
端口:1R/1W 或 1RW(工艺选)
数据位宽:NOC_W
地址位宽:log2((N_CL/N_BANK) × CL_BYTES / (NOC_W/8))
CL_BYTES = 256,NOC_W = 512 时每 cacheline 占 4 beat。
8.2 Master ↔ Bank crossbar
N_MASTER × N_BANK 全连接 crossbar。
仲裁粒度:beat(不是 burst)。每 cycle 每 bank 接受一个 master 的一拍访问;冲突 round-robin。这避免某个 master 长 burst 占满 bank 期间其他 master 完全 starve。
实现:
- 每 bank 一个 N_MASTER 路 round-robin 仲裁器
- 每 master 一个 N_BANK 路 demux(按 bank_id 把请求路给对应 bank)
- 每 master 内:N_BANK 个 outstanding tracker(一个 master 的请求按 id 排序回 resp)
回程 read data:每 bank 一个回路 fifo(深度 = max-outstanding-per-master),按 master_id route 回;master 端按 req_id 重排。
8.3 同 bank R/W 冲突
- SRAM 是 1RW 时:同 cycle 同 bank 出现 R + W → 先 W 后 R(写优先一拍,读延 1 cycle);上层 master 看到 read latency 多 1 cycle
- SRAM 是 1R/1W 时:可并发,无 stall
8.4 跨 cacheline burst 拒绝
L1 不支持单 burst 跨 cacheline。req_len + offset 跨界时,行为未定义 —— master 必须自己拆 burst。
9. Sync Pipe Pool
结构同 [[DMA]] §8。N_SYNC 个独立 counter,独立 alloc bitmap,与 cl_alloc_bitmap 不共享 ID 空间(落地 A,但 sync handle 的 type 字段区分)。
每 counter 单 cycle 读写。psignal / pset_count / pread / pwait 接口同 DMA。
10. Pending Wait CAM
结构同 [[DMA]] §8.2。
容量 N_PEND_WAIT,每项 {valid, target_handle, threshold, resp_tag}。
比较广播:每 cycle 任何 count 更新事件(count_cl 或 sync_count)送入 CAM 比较口;命中条目发响应 + invalidate。
多 bank 的 count 同 cycle 都可能更新 —— CAM 比较口可以并发承接多个事件(每 bank 一个事件,单 cycle 内 N_BANK + 1 路广播)。或者把 CAM 比较端口分块:每 bank 一个独立 wait 子表。后者更省面积,前者更简单。推荐:单一 CAM,多端口同 cycle 接受 N_BANK 个更新事件。
11. 复位与启动
| 信号 / 状态 | 复位值 |
|---|---|
| cl_alloc_bitmap / sync_alloc_bitmap | 全 0 |
| cl_valid_flag | 全 0 |
| count_cl[] / sync_count[] | 0 |
| Bank SRAM 内容 | 不复位(undefined) |
| pending wait CAM | 全 invalid |
| crossbar 仲裁 round-robin pointer | 0 |
SRAM 内容不复位的影响:未 PALLOC 的 cacheline 读出是垃圾,软件不应访问;count 已复位为 0,PWAIT 不会被未初始化数据误触发。
12. 调试可观测点
| 信号 | 宽度 | 用途 |
|---|---|---|
dbg_cl_alloc_count |
log2(N_CL)+1 | 已分配 cacheline 数 |
dbg_sync_alloc_count |
log2(N_SYNC)+1 | 已分配 sync 数 |
dbg_bank_busy |
N_BANK | bank 当 cycle 是否被访问 |
dbg_bank_conflict |
N_BANK | bank 当 cycle 是否被多 master 竞争 |
dbg_master_stall |
N_MASTER | master 当 cycle 是否被 backpressure |
dbg_pend_wait_occ |
log2(N_PEND_WAIT)+1 | 未决 wait 数 |
dbg_count_cl[N_CL] |
N_CL × COUNT_W | 全部 cl count(性能区可裁掉) |
13. 待规格化参数
N_CL/CL_BYTES/N_BANK/N_MASTER的实际值- Bank SRAM 端口配置(1RW vs 1R/1W vs 2R/1W)
- Crossbar 是否带 QoS(不同 master 优先级)
- Pending Wait CAM 是统一表还是按 bank 分块
- 是否例化 ECC / parity 保护(特性 6 不要求,但产品级可加)
14. 关联回 Pipe 抽象
| 抽象层概念 | 本文档落点 |
|---|---|
| data pipe 契约(输入序列 = 写、输出序列 = 读、count + credit) | §4 地址=handle + §7 count + §8 SRAM |
| sync pipe 契约 | §9 |
| 落地 A(每单元独立 ID) | §6 + §9 各自 bitmap |
| 落地 B(控制/数据总线分开) | §3.1 vs §3.2 物理分离 |
| 落地 D(sync 独立) | §9 与 §7 不共用任何状态 |
| 特性 2(粒度顺应硬件) | cacheline = pipe 粒度,自然映射 |
| 特性 6(硬件零检查) | §5.4 + §7.3 不强制 master 顺序 |
| 特性 7(参数创建即不可变) | §6 cacheline 大小固定,alloc 后参数定 |
| 特性 8(三类 pipe) | data 在 §6-§8,sync 在 §9,无 engine |