You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Chisel3/Firrtl中将SRAM移至顶层层级?

解决方案:将Chisel3 RISCV核中的SRAM迁移至顶层作为黑盒

要把内部SRAM移到顶层并作为黑盒处理,不能依赖topWiring(它仅暴露信号而非迁移模块),正确的方式是手动拆分模块接口,将SRAM实例移至顶层,再通过端口映射连接核内部逻辑。以下是完整示例:

1. 定义SRAM黑盒模块

先写一个符合流片需求的SRAM黑盒,接口匹配你要使用的物理SRAM:

import chisel3._
import chisel3.experimental.{BlackBox, HasBlackBoxResource}

// 流片用SRAM黑盒,接口可根据实际物理SRAM调整
class SramBlackBox(addrWidth: Int, dataWidth: Int) extends BlackBox with HasBlackBoxResource {
  val io = IO(new Bundle {
    val clk = Input(Clock())
    val we  = Input(Bool())       // 写使能
    val addr = Input(UInt(addrWidth.W)) // 地址总线
    val din  = Input(UInt(dataWidth.W)) // 写数据
    val dout = Output(UInt(dataWidth.W))// 读数据
  })

  // 若有预先编写的SRAM Verilog黑盒文件,可通过addResource引入
  // addResource("/path/to/your/sram_blackbox.v")
}

2. 修改顶层模块:实例化SRAM黑盒并暴露端口

顶层模块需要同时包含RISCV核和SRAM黑盒,并将SRAM的端口暴露到顶层外部(供后续综合工具绑定物理库):

class TopRiscvCore(addrWidth: Int = 12, dataWidth: Int = 32) extends Module {
  val io = IO(new Bundle {
    // RISCV核的外部接口(示例:指令访存接口)
    val instr_req   = Output(Bool())
    val instr_addr  = Output(UInt(addrWidth.W))
    val instr_rdata = Input(UInt(dataWidth.W))
    // ... 补充你的核其他外部端口(如中断、调试接口等)

    // 暴露SRAM的所有端口到顶层
    val sram_clk  = Input(Clock())
    val sram_we   = Output(Bool())
    val sram_addr = Output(UInt(addrWidth.W))
    val sram_din  = Output(UInt(dataWidth.W))
    val sram_dout = Input(UInt(dataWidth.W))
  })

  // 实例化SRAM黑盒
  val sram = Module(new SramBlackBox(addrWidth, dataWidth))
  // 连接黑盒与顶层端口
  sram.io.clk  := io.sram_clk
  sram.io.we   := io.sram_we
  sram.io.addr := io.sram_addr
  sram.io.din  := io.sram_din
  io.sram_dout := sram.io.dout

  // 实例化RISCV核
  val core = Module(new RiscvCore(addrWidth, dataWidth))
  // 连接核的常规外部端口
  io.instr_req   := core.io.instr_req
  io.instr_addr  := core.io.instr_addr
  core.io.instr_rdata := io.instr_rdata
  // ... 映射其他核端口

  // 连接核的SRAM接口到顶层SRAM端口
  io.sram_we   := core.io.sram_we
  io.sram_addr := core.io.sram_addr
  io.sram_din  := core.io.sram_din
  core.io.sram_dout := io.sram_dout
}

3. 修改RISCV核:移除内部SRAM,添加SRAM接口

把核内部原本的SRAM实例删除,替换成对外的SRAM接口,让核的内存访问逻辑直接通过这些端口与顶层黑盒交互:

class RiscvCore(addrWidth: Int, dataWidth: Int) extends Module {
  val io = IO(new Bundle {
    // 核的常规外部端口
    val instr_req   = Output(Bool())
    val instr_addr  = Output(UInt(addrWidth.W))
    val instr_rdata = Input(UInt(dataWidth.W))
    // ... 补充其他端口

    // 新增SRAM交互接口,用于连接顶层黑盒
    val sram_we   = Output(Bool())
    val sram_addr = Output(UInt(addrWidth.W))
    val sram_din  = Output(UInt(dataWidth.W))
    val sram_dout = Input(UInt(dataWidth.W))
  })

  // --- 核内部内存访问逻辑修改 ---
  // 原本的内部SRAM实例(删除):
  // val internalSram = Module(new SyncSram(addrWidth, dataWidth))
  // internalSram.io.clk := clock
  // internalSram.io.we := memWriteEn
  // internalSram.io.addr := memAddr
  // internalSram.io.din := memWriteData
  // val memReadData = internalSram.io.dout

  // 替换为:直接通过顶层SRAM接口交互
  val memWriteEn = Wire(Bool())    // 核内部生成的写使能信号
  val memAddr = Wire(UInt(addrWidth.W)) // 核内部生成的内存地址
  val memWriteData = Wire(UInt(dataWidth.W)) // 核内部写数据

  // 连接到顶层SRAM接口
  io.sram_we   := memWriteEn
  io.sram_addr := memAddr
  io.sram_din  := memWriteData
  val memReadData = io.sram_dout // 从顶层SRAM读取数据

  // 后续核内部逻辑正常使用memReadData即可
}

关键注意事项

  • 多SRAM场景:如果核内有多个SRAM(如指令SRAM和数据SRAM),只需在顶层实例化多个SramBlackBox,并在核内添加多组对应接口即可。
  • 黑盒保留:生成Verilog时,Chisel会自动将SramBlackBox标记为黑盒,不会展开其内部逻辑,后续综合工具可直接绑定流片用的物理SRAM库。
  • 时序约束:可在顶层模块的注释中添加SRAM的时序约束,或在综合脚本中单独配置。

内容的提问来源于stack exchange,提问作者DDK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:10:41