Buck Blog · 博客正文

返回技术分享首页
ip_hash

IP Hash 硬件防火墙 IP 设计规格

1. 概述

1.1 功能定位

ip_hash 是一个基于 CRC32 Hash 算法的硬件查表防火墙 IP,用于千兆以太网报文的快速过滤。核心思路:

• 对每个进入的 IPv4 报文提取 {DstIP, DstPort} 作为 Hash Key

• 通过 CRC32 计算 Hash 值,索引到 4 路组相联 Hash 表中并行比较

• 命中表项后执行 Pass/Drop 决策

• 非 IPv4 报文全部透传

• 表项管理(增/删/改)由外部 CPU 通过 LCPU 总线发起,Hash 计算和桶位分配由 FPGA 硬件完成

1.2 关键指标

| 项目 | 规格 |

|------|------|

| 接口 | 1 × GMII RX (8b @125MHz) + 1 × GMII TX (8b @125MHz) |

| 时钟 | 单时钟域 125MHz |

| 表容量 | 128 条表项,4-way × 32 rows |

| Hash 算法 | CRC32(Ethernet 多项式 0x04C11DB7) |

| Hash Key | {DstIP[31:0], DstPort[15:0]} = 48b |

| 转发模式 | Store-and-Forward |

| 转发延迟 | 1~2 个包周期 |

| 最大包长 | 1522 Bytes |

| 管理总线 | LCPU (REQ/ACK, 32b ADDR/DATA, 125MHz) |

| 分片支持 | 首片查表,后续分片跟随;4 条并发流,1ms 超时 |

---

2. 系统架构

2.1 顶层框图

                  +------------------------------------------+
                  |              ip_hash_top                 |
                  |                                          |
  gmii_rx_clk --->|----+                                     |
  gmii_rx_d[7:0] ->|GMII|-->[PktBuf]-->[Parser]-->[Hash]   |
  gmii_rx_dv  --->| RX |    (W)        (L3/L4)  (CRC32)    |
                  |----+                    |        |        |
                  |                         |     [Lookup]   |
                  |                    [FragCache] (4-way)   |
                  |                         |        |        |
  gmii_tx_clk <---|----+                    +---[Decision]   |
  gmii_tx_d[7:0] <-|GMII|<--[PktBuf]<---------+   |        |
  gmii_tx_en  <---| TX |    (R)                   |        |
                  |----+                          |        |
                  |                               v        |
  lcpu_clk ------>|                                          |
  lcpu_req ------>|  [LCPU I/F] --> [CmdDec] --> [TableMgr] |
  lcpu_addr[31:0]>|                                          |
  lcpu_rdata[31:0]|                                          |
  lcpu_wdata[31:0]|                                          |
  lcpu_ack <------|                                          |
                  +------------------------------------------+

2.2 子模块划分

| 模块 | 功能 |

|------|------|

| gmii_rx_if | GMII 接收接口,提取 RX_DV/RX_ER/RXD |

| gmii_tx_if | GMII 发送接口,产生 TX_EN/TXD |

| pkt_buffer | 例化 package_fifo.v,Store-and-Forward 整包缓存 |

| pkt_parser | 解析 EtherType→IP Header→L4 Port,提取查表 Key |

| crc32_hash | 对 48b Key 做 CRC32,输出 32b Hash 值,取低 5b 作索引 |

| hash_table | 4-way × 32 rows 表体,含并行比较器和命中逻辑 |

| frag_cache | 分片状态缓存:4 条并发流,1ms 超时管理 |

| lcpu_if | LCPU 总线接口,REQ/ACK 握手,地址译码,寄存器读写 |

| cmd_decoder | 解析 CPU 命令(Insert/Delete/Modify),驱动 TableMgr |

| table_mgr | Hash 表项管理状态机:扫描桶位、写入/删除/修改表项 |

| stat_counter | 统计计数器(总包数/命中/未命中/FCS 错误) |

---

3. 接口信号

3.1 GMII 接收(GMII RX)

| 信号 | 方向 | 位宽 | 说明 |

|------|------|------|------|

| gmii_rx_clk | I | 1 | 125MHz 接收时钟 |

| gmii_rx_dv | I | 1 | 接收数据有效 |

| gmii_rx_er | I | 1 | 接收错误指示 |

| gmii_rx_d | I | 8 | 接收数据总线 |

3.2 GMII 发送(GMII TX)

| 信号 | 方向 | 位宽 | 说明 |

|------|------|------|------|

| gmii_tx_clk | I | 1 | 125MHz 发送时钟(与 RX 同源) |

| gmii_tx_en | O | 1 | 发送数据有效 |

| gmii_tx_er | O | 1 | 发送错误(固定为 0) |

| gmii_tx_d | O | 8 | 发送数据总线 |

3.3 LCPU 管理总线

| 信号 | 方向 | 位宽 | 说明 |

|------|------|------|------|

| lcpu_clk | I | 1 | LCPU 操作时钟(125MHz) |

| lcpu_addr | I | 32 | 地址总线 |

| lcpu_wdata | I | 32 | 写数据总线 |

| lcpu_rdata | O | 32 | 读数据总线 |

| lcpu_req | I | 1 | 读写请求脉冲 |

| lcpu_rh_wl | I | 1 | 1=读 / 0=写 |

| lcpu_ack | O | 1 | 操作完成应答 |

> 时序参见《常用LRIP接口时序.md》LCPU 读写寄存器时序。所有信号同步于 lcpu_clk(125MHz)。

---

4. Hash 表设计

4.1 Hash 算法

• 多项式:Ethernet CRC32 0x04C11DB7(reflected: 0xEDB88320),与 GMII FCS 同款

• 输入:Key = {DstIP[31:0], DstPort[15:0]}, 48b 有效位

• Mask 控制:全局 Mask 寄存器对 Key 做屏蔽后再送入 CRC32

• mask_ip = 0 → DstIP 段清零(仅用 Port 匹配)

• mask_port = 0 → DstPort 段清零(仅用 IP 匹配)

• 默认 mask_ip=1, mask_port=1(完整 Key)

• 输出:32b CRC 结果

• 索引:hash_index = crc_result[4:0],5b → 32 rows

• Tag:hash_tag = crc_result[31:5](高 27b),用于桶内比较,降低误命中

4.2 表组织结构

          Row 0  +--------+--------+--------+--------+
                 | Way 0  | Way 1  | Way 2  | Way 3  |
          Row 1  | Entry  | Entry  | Entry  | Entry  |
          ...    | ...    | ...    | ...    | ...    |
          Row 31 | Entry  | Entry  | Entry  | Entry  |
                 +--------+--------+--------+--------+
                         ↓  并行比较  ↓
                hash_tag[27:0] vs entry_tag[27:0]

• 32 rows × 4 ways = 128 entries

• 每条表项包含:valid + tag + key + action

• 查表时并行读取同一行的 4 路 entry,同时比较 tag 和 key,选出命中的那一路

4.3 表项格式

  ┌────────┬──────────────────────────┬────────────────────────────┬────────┐
  │ valid  │  hash_tag                │  key                       │ action │
  │ [1b]   │  [27:0]                  │  {DstIP[31:0], DstPort[15:0]} │ [1b]  │
  └────────┴──────────────────────────┴────────────────────────────┴────────┘

| 字段 | 位宽 | 说明 |

|------|------|------|

| valid | 1 | 表项有效标志 |

| hash_tag | 28 | CRC32[31:5] 高 28b,桶内 Tag 比较 |

| key_ip | 32 | 目的 IP 地址匹配值 |

| key_port | 16 | 目的端口匹配值 |

| action | 1 | 0 = Pass, 1 = Drop |

| 合计 | 78b | —— |

> 存储映射:每条 entry 占 3 × 32b(96b),分配 3 个连续寄存器地址。

> 其中 78b 有效,18b reserved。

4.4 查表流程(硬件自动完成)

  报文到达 → 解析 DstIP, DstPort
                ↓
  key = {Masked(DstIP), Masked(DstPort)}
                ↓
  crc_out = CRC32(key)                    // 组合逻辑 + 1 拍寄存
                ↓
  index = crc_out[4:0]                    // 读 Row[index] 的 4 路
  tag   = crc_out[31:5]
                ↓
  并行比较 4 路:
    hit[i] = entry[i].valid && (entry[i].tag == tag) && (entry[i].key == masked_key)
                ↓
  if any hit → action = hit_entry.action
  else       → action = default_policy    // Pass or Drop

时序:CRC32 1 拍 + 读表 1 拍 + 并行比较 1 拍 = 3 拍查表延迟(@125MHz = 24ns)。

---

5. 表项管理(CPU 命令)

5.1 命令概述

CPU 不参与 Hash 计算,仅通过 LCPU 总线向 FPGA 发送管理命令。FPGA 内部 table_mgr 状态机完成 Hash 计算、桶位扫描、表项读写。

| 命令 | 编码 | 说明 |

|------|------|------|

| NOP | 2'b00 | 无操作 |

| INSERT | 2'b01 | 插入表项:CPU 提供 {DstIP, DstPort, Action},FPGA 计算 Hash、找空桶、写入 |

| DELETE | 2'b10 | 删除表项:CPU 提供 {DstIP, DstPort},FPGA 计算 Hash、找匹配桶、清除 valid |

| MODIFY | 2'b11 | 修改表项:CPU 提供 {DstIP, DstPort, Action},FPGA 计算 Hash、找匹配桶、更新 Action |

5.2 命令执行流程

INSERT:

  CPU写 CMD_KEY_LO (DstIP)
  CPU写 CMD_KEY_HI ({DstPort, Action})
  CPU写 CMD (INSERT)
      ↓ FPGA
  1. CRC32(Masked(Key)) → index, tag
  2. 读 Row[index] 4 路
  3. 扫描 valid=0 的空桶
  4. 找到空桶 → 写入 {valid=1, tag, key, action} → status = OK
  5. 4 路全满 → status = TABLE_FULL(stat: overflow_cnt++)

DELETE:

  CPU写 CMD_KEY_LO (DstIP)
  CPU写 CMD_KEY_HI ({DstPort, ...})
  CPU写 CMD (DELETE)
      ↓ FPGA
  1. CRC32(Masked(Key)) → index, tag
  2. 读 Row[index] 4 路
  3. 查找 tag+key 均匹配的 entry
  4. 找到 → valid=0 → status = OK
  5. 未找到 → status = NOT_FOUND

MODIFY:

  CPU写 CMD_KEY_LO (DstIP)
  CPU写 CMD_KEY_HI ({DstPort, Action})
  CPU写 CMD (MODIFY)
      ↓ FPGA
  1. CRC32(Masked(Key)) → index, tag
  2. 读 Row[index] 4 路
  3. 查找 tag+key 均匹配的 entry
  4. 找到 → 更新 action → status = OK
  5. 未找到 → status = NOT_FOUND

5.3 命令时序约束

• 表项管理操作与查表操作共享同一个 Hash Table 存储器

• 若 table_mgr 占用存储器时(写/删/改进行中),数据包查表被阻塞

• 管理操作通常不超过 10 个时钟周期(读表+比较+写回)

• CPU 应避免在高流量期间频繁执行管理命令

• CPU 查询 STATUS 寄存器确认操作完成后,方可发起下一条命令

---

6. 报文处理管线

6.1 整体数据流

GMII RX → [FCS Check] ──(pass)──→ [PktBuf Write] ─→ [Parser] → [Hash Lookup] → [Decision]
       ↓                                                                              ↓
  (FCS fail)                                                                    Pass / Drop
       ↓                                                                           ↓
    丢弃                                                                   ┌───────┴───────┐
  (不写PktBuf)                                                             ↓               ↓
                                                                        Pass            Drop
                                                                          ↓               ↓
                                                                    wpkt_push=1    wpkt_push=0
                                                                          ↓               ↓
GMII TX ← [Preamble] ← [PktBuf Read] ←── rpkt_pop ←────────── [Forward]        (数据块不提交)
  ↑                                                              
  └── (非IPv4: 直接透传, 也走 wpkt_push=1)

关键机制:报文边接收边写入 PktBuf,此时尚未完成查表、不知道最终决策。查表完成获得 Pass/Drop 结果后,通过控制 wpkt_push 信号决定该包是否提交到读侧队列:

• Pass:wpkt_push = 1,数据块提交,读侧可 rpkt_pop 读出转发

• Drop:wpkt_push = 0,数据块不提交,已被写入的 RAM 空间将在下一个报文到来时被覆盖(相当于静默丢弃)

6.2 非 IPv4 报文

EtherType != 0x0800 → 不查表 → 直接透传(Default Pass)

• ARP(0x0806)、VLAN(0x8100)、IPv6(0x86DD)等全部放行

• 不计入 Hash 命中/未命中统计

6.3 FCS 校验

• 输入 GMII → 接收时逐字节送入 CRC32 校验器

• 若 crc_result != 0xC704DD7B(Magic Number)→ 丢弃报文,fcs_err_cnt++

• 丢弃的报文不写入 PktBuf

• 输出 GMII → TX 侧不重新计算 FCS(透传原始 FCS 或由下游处理)

> 说明:store-and-forward 模式下转发的是包含原始 FCS 的完整报文。若需要 FCS 刷新,下游 MAC IP 自行处理。

6.4 转发时序

  RX:  | Preamble | SFD | MAC Header | IP Header | Payload | FCS |
        ←────────── 存入 PktBuf ──────────→
                                             ↓ wpkt_push
                            PktBuf 短暂同步延迟
                                             ↓ rpkt_pop
  TX:                           | Preamble | SFD | MAC Header | IP Header | Payload | FCS |

• 延迟范围:1~2 个最大包周期(约 12~24μs @ 1.5KB / 125MHz)

• 存入整包 → wpkt_push → rpkt_pop → 读出整包转发

• Preamble / SFD 不存入缓存,由出向 GMII TX 模块重新生成

6.5 丢弃机制

核心原理:利用 package_fifo.v 的 block_mode 特性——wpkt_push 是数据块提交到读侧队列的唯一入口,不 push 则数据不可见。

时序流程:

  GMII RX:  |  DstMAC | SrcMAC | EtherType | IP Header | Payload | FCS |
              ↓         ↓        ↓           ↓           ↓         ↓
  PktBuf:    写addr=0  写addr=1  写addr=2    ...         ...      写addr=N-1
              ↓
  Parser:                  开始解析 EtherType → IP Header → DstIP, DstPort
              ↓
  Hash:                                     CRC32(HashKey)
              ↓
  Lookup:                                          并行比较4路
              ↓
  Decision:                                                        → Pass/Drop
              ↓                                                         ↓
  wpkt_push:                                                  (Pass) 1  (Drop) 0

关键时序说明:

1. 边收边写:GMII RX 字节流到达即写入 PktBuf,wen=1 持续有效,waddr 递增。此时 FCS 校验和 Hash 查表均在并行进行中,尚不知道处理结果。

2. 先写后判:报文接收完毕(gmii_rx_dv 下降沿)后,Hash 查表结果已经稳定(查表仅 3 拍延迟,远小于最小报文 64B 的传输时间 512ns),可以获得 Pass/Drop 决策。

3. push 即放行:若 DstIP/DstPort 匹配白名单规则 → wpkt_push=1(需同时满足 FCS 校验通过),PktBuf 将当前数据块提交到读侧参数 FIFO,后续 rpkt_pop 读出转发。

4. 不 push 即丢弃:若匹配黑名单规则(action=Drop)或 FCS 校验失败 → wpkt_push=0。当前 block_waddr_pt 不递增,下一个报文将从同一数据块的起始地址覆盖写入,已被写入的废弃数据自然消失。

非 IPv4 报文:跳过 Hash 查表,直接 wpkt_push=1 透传。

极端情况:最小报文 64B → 64 × 8ns = 512ns = 64 个时钟周期,远远大于 Hash 查表的 3 个周期延迟。因此查表决策必然在报文接收完成之前就已得出,不需要等待。wpkt_push 的时机完全由报文边界决定,不存在查表延迟导致 push 延迟的问题。

---

7. 分片处理

7.1 分片识别

IPv4 Header 中的分片相关字段:

| 字段 | 位宽 | 位置 | 说明 |

|------|------|------|------|

| Identification | 16b | IP Header[18:19] | 分片组 ID |

| Flags[MF] | 1b | IP Header[20].bit5 | 0=最后一片 |

| Fragment Offset | 13b | IP Header[20:21] | 8-byte 为单位 |

分片判断逻辑:

• Offset=0 && MF=0:非分片报文,正常查表

• Offset=0 && MF=1:首片,查表并记录决策

• Offset>0:后续分片,查 FragCache 获取决策

7.2 分片状态缓存(FragCache)

| 项目 | 规格 |

|------|------|

| 容量 | 4 条并发分片流 |

| 索引 Key | {SrcIP[31:0], DstIP[31:0], Identification[15:0]} = 80b |

| 存储内容 | {Key, Action, Timestamp} |

| 超时 | 1ms(125,000 cycles @125MHz) |

| 替换策略 | 满时淘汰最旧 entry |

| 超时默认 | Drop |

7.3 分片处理流程

  报文到达 → 解析 IP 头分片字段
                    ↓
  ┌── Offset=0 && MF=0 ──→ 正常查表流程
  │
  ├── Offset=0 && MF=1 ──→ Hash Lookup → 记录 {SrcIP, DstIP, ID, Action} 到 FragCache
  │                        ↓
  │                    按查表结果 Pass/Drop
  │
  └── Offset>0 ──→ 查 FragCache {SrcIP, DstIP, ID}
                    ↓
        ┌── Hit ──→ 按记录 Action 处理,刷新 Timestamp
        └── Miss ─→ Drop(首片已超时或从未到达)

---

8. 寄存器映射

8.1 LCPU 地址空间

| 地址偏移 | 名称 | 类型 | 位宽 | 说明 |

|----------|------|------|------|------|

| 0x00 | HASH_CMD | WO | 32 | [1:0] cmd_type,写即触发执行 |

| 0x04 | HASH_CMD_KEY_LO | WO | 32 | DstIP[31:0] |

| 0x08 | HASH_CMD_KEY_HI | WO | 32 | [16] action, [15:0] DstPort |

| 0x0C | HASH_MASK | RW | 32 | [1] mask_port, [0] mask_ip |

| 0x10 | HASH_DEFAULT_POLICY | RW | 32 | [0] default_action(0=Pass, 1=Drop) |

| 0x14 | HASH_STATUS | RO | 32 | [2] not_found, [1] table_full, [0] busy |

| 0x18 | PKT_CNT_TOTAL | RO | 32 | 接收报文总数(不含 FCS 错误包) |

| 0x1C | PKT_CNT_HIT | RO | 32 | Hash 表命中计数 |

| 0x20 | PKT_CNT_MISS | RO | 32 | Hash 表未命中计数 |

| 0x24 | PKT_CNT_FCS_ERR | RO | 32 | FCS 校验错误计数 |

| 0x28 | OVERFLOW_CNT | RO | 32 | 表项 insert 失败(4 路全满)次数 |

8.2 寄存器详细描述

HASH_CMD (0x00, WO)

  ┌──────────┬─────┬─────┐
  │ reserved │ cmd │     │
  │ [31:2]   │[1:0]│     │
  └──────────┴─────┴─────┘
  cmd: 00=NOP, 01=INSERT, 10=DELETE, 11=MODIFY

写入任何命令字触发状态机执行。执行期间 STATUS.busy = 1。

HASH_CMD_KEY_LO (0x04, WO)

  ┌────────────────────┐
  │ DstIP              │
  │ [31:0]             │
  └────────────────────┘

HASH_CMD_KEY_HI (0x08, WO)

  ┌──────────┬────────┬────────────────────┐
  │ reserved │ action │ DstPort            │
  │ [31:17]  │ [16]   │ [15:0]             │
  └──────────┴────────┴────────────────────┘

• DELETE 命令无需 action 字段(忽略)

• action 仅 INSERT 和 MODIFY 有效

HASH_MASK (0x0C, RW)

  ┌──────────┬───────────┬──────────┐
  │ reserved │ mask_port │ mask_ip  │
  │ [31:2]   │ [1]       │ [0]      │
  └──────────┴───────────┴──────────┘
  1 = 参与 Hash, 0 = 屏蔽
  默认: 2'b11(完整 Key 匹配)

> 注意:修改 HASH_MASK 将改变所有 Hash 计算的索引和 Tag。运行中修改 Mask 后,之前插入的所有表项将无法被命中(Hash 索引已变)。应在修改 Mask 前将所有表项 valid 清零,修改后重新下发。建议在系统初始化时配置 Mask 后不再变更。

HASH_DEFAULT_POLICY (0x10, RW)

  ┌──────────┬─────────┐
  │ reserved │ default │
  │ [31:1]   │ [0]     │
  └──────────┴─────────┘
  default: 0=Pass, 1=Drop
  用于 Hash 未命中时的默认动作

HASH_STATUS (0x14, RO)

  ┌──────────┬───────────┬────────────┬──────┐
  │ reserved │ not_found │ table_full │ busy │
  │ [31:3]   │ [2]       │ [1]        │ [0]  │
  └──────────┴───────────┴────────────┴──────┘
  busy:       命令执行中
  table_full: INSERT 时 4 路全满
  not_found:  DELETE/MODIFY 时目标表项不存在

读后自动清零(clear-on-read),busy 除外。

---

9. 时钟与复位

9.1 时钟方案

| 时钟 | 频率 | 驱动模块 |

|------|------|----------|

| clk_125m | 125MHz | 全局统一时钟:GMII、数据通路、Hash 表、LCPU 总线 |

• 单时钟域设计,GMII RX/TX 和 LCPU 共享同一 125MHz 时钟

• 无跨时钟域 CDC 逻辑需求

• SDC 约束:create_clock -name clk_125m -period 8.000 [get_ports clk_125m]

9.2 复位

• reset_l 异步复位、同步释放

• 复位后:

• 所有表项 valid = 0(空表)

• 统计计数器归零

• FragCache 清空

• 寄存器恢复默认值

---

10. PktBuf 配置

例化 linkreal_common/ip/package_fifo.v,参数如下:

| 参数 | 取值 | 说明 |

|------|------|------|

| dual_clock | 0 | 单时钟域 |

| block_mode | "true" | 块模式,整包写入/整包读出 |

| addr_width | 11 | 每块 2048 × 8b(可容纳 1522B) |

| block_addr_width | 2 | 4 个数据块 |

| data_width | 8 | GMII 字节流接口 |

| para_width | 16 | 附参位宽 |

| max_pkt_length | 1522 | 最大报文长度 |

| data_ram_type | "M9K" | Cyclone IV M9K Block RAM |

| para_ram_type | "registers" | 参数 FIFO 用寄存器实现 |

---

11. 统计计数器

| 计数器 | 位宽 | 说明 | 饱和处理 |

|--------|------|------|----------|

| pkt_cnt_total | 32 | 接收的合法报文总数(FCS 通过,含 IPv4 和非 IPv4) | 饱和不翻转 |

| pkt_cnt_hit | 32 | Hash 查表命中次数 | 饱和不翻转 |

| pkt_cnt_miss | 32 | Hash 查表未命中次数 | 饱和不翻转 |

| pkt_cnt_fcs_err | 32 | FCS 校验错误包数 | 饱和不翻转 |

| overflow_cnt | 32 | 表项插入失败次数 | 饱和不翻转 |

所有计数器 readable,CPU 读后不自动清除(如需清除需增加 CLEAR 命令或在后续版本中扩展)。

---

12. 资源预估

以下为 Cyclone IV E(EP4CE10)平台参考估算:

| 资源项 | 参考用量 | 说明 |

|--------|----------|------|

| Logic Elements | ~2500 LEs | CRC32 + 比较器 + 控制状态机 |

| Block RAM (M9K) | ~12 个 | PktBuf: 8K×8b=64Kb ≈ 8 M9K;Hash Table: 128×78b ≈ 2 M9K(双口);FragCache: 4×80b ≈ 1 M9K |

| DSP Blocks | 0 | 无可乘累加 |

| fMAX | >150MHz | 关键路径:4-way 并行比较器 + MUX |

> 注:以上为粗略估算,以实际综合结果为准。

---

13. 参数汇总

| 参数 | 默认值 | 说明 |

|------|--------|------|

| TABLE_SIZE | 128 | 表项总数 |

| TABLE_WAYS | 4 | 组相联路数 |

| TABLE_ROWS | 32 | Hash 索引行数 |

| HASH_KEY_WIDTH | 48 | Hash key 位宽 |

| HASH_TAG_WIDTH | 28 | Hash tag 位宽(CRC32[31:5]) |

| HASH_IDX_WIDTH | 5 | Hash 索引位宽(CRC32[4:0]) |

| GMII_DATA_WIDTH | 8 | GMII 数据位宽 |

| LCPU_DATA_WIDTH | 32 | LCPU 数据位宽 |

| LCPU_ADDR_WIDTH | 32 | LCPU 地址位宽 |

| MAX_PKT_LENGTH | 1522 | 最大报文长度 (Bytes) |

| FRAG_CACHE_ENTRIES | 4 | 分片缓存条数 |

| FRAG_TIMEOUT_CYCLES | 125000 | 分片超时 (cycles @125MHz = 1ms) |

| DEFAULT_POLICY | 0 (Pass) | 默认策略 |

---

14. 附录

14.1 目录结构(参考 WebServer 项目)

HashSearch/
├── doc/
│   └── ip_hash.md            ← 本设计规格文档
├── rtl/
│   ├── ip_hash_top.v         # 顶层集成
│   ├── ip_hash_gmii_rx.v     # GMII RX 接口
│   ├── ip_hash_gmii_tx.v     # GMII TX 接口
│   ├── ip_hash_parser.v      # 报文解析 + Key 提取
│   ├── ip_hash_crc32.v       # CRC32 Hash 计算
│   ├── ip_hash_table.v       # 4-way Hash 表 + 并行比较
│   ├── ip_hash_table_mgr.v   # 表项管理状态机
│   ├── ip_hash_frag_cache.v  # 分片状态缓存
│   ├── ip_hash_lcpu_if.v     # LCPU 总线接口 + 寄存器
│   ├── ip_hash_decision.v    # Pass/Drop 决策 + 统计
│   └── ip_hash_pkg.sv        # 参数 / typedef 定义
├── sim/
│   ├── tb_ip_hash.sv         # 顶层 Testbench
│   ├── define.sv             # 仿真定义
│   ├── filelist.f            # 文件列表
│   ├── run_questa.do         # Questa 仿真脚本
│   └── pkt_gen/              # 测试激励(报文模板)
├── par_intel/
│   ├── ip_hash.qpf           # Quartus 工程
│   ├── ip_hash.qsf           # Quartus 约束
│   └── ip_hash.sdc           # 时序约束
└── par_xilinx/
    ├── (预留)
    └── ...

14.2 待定/未来扩展

• [ ] 每表项独立命中统计(按需后续添加)

• [ ] 支持背靠背报文的 Ping-Pong Buffer

• [ ] 支持多端口队列(多个 GMII 出向)

• [ ] 支持 IPv6 报文的五元组过滤

• [ ] 表项读回功能(Debug 用)

• [ ] 统计计数器清零命令