# 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]  │ │
                 │                            └────────────────┘ │
                 └─────────────────────────────────────────────────┘
```

子模块：
1. **CL Pool Manager**：data pipe 的 alloc/free + bitmap
2. **Count 阵列**：每条 cacheline 一个 count，按 bank 分块
3. **Bank SRAM × N_BANK**：cacheline 数据存储
4. **Crossbar**：N_MASTER × N_BANK 路 master → bank 仲裁
5. **Sync Pool**：N_SYNC 个独立 sync counter
6. **Pending Wait CAM**：未决 pwait 表，共用于 cacheline + sync count
7. **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 写来源：
1. PALLOC 复位
2. PSET_COUNT
3. 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. 待规格化参数

1. `N_CL` / `CL_BYTES` / `N_BANK` / `N_MASTER` 的实际值
2. Bank SRAM 端口配置（1RW vs 1R/1W vs 2R/1W）
3. Crossbar 是否带 QoS（不同 master 优先级）
4. Pending Wait CAM 是统一表还是按 bank 分块
5. 是否例化 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 |