Chisel编译成功但无法正确生成verilog

标签 chisel

我用Chisel写了一个RISC-V CPU,Chisel代码编译成功,Firrtl代码也生成成功,但是verilog代码只有一个模块语句。Verilog文件基本是空的。

它生成所有模块的Firrtl代码。当我使用Verilator模拟它时,在test_run_dir文件夹下它只是一个1kb的verilog文件和一个空的VCD文件。

这是代码

package CPUModule

import chisel3._
import chisel3.util._
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}

import IFUModule._
import IDUModule._
import MemModel._
import EXUModule._
import WBUModule._

class SingleCycleCPU extends Module {
    val io = IO(new Bundle {

        val in_enable = Input(Bool())
    })


    val MM = Module(new MemoryModel) // L1D and L1I
    val PC = Module(new PromgrameCounter) // pc
    val PD = Module(new PlexDecoder) // decoder
    val RF = Module(new RegisterFile) // regfile
    val ALU = Module(new ALU) // ALU
    val AGU = Module(new LSU) // AGU
    val WB = Module(new WriteBackUnit) // write back

    // L1I
    val MM_in_L1I_readen = Wire(Bool())
    val MM_in_L1I_readdr = Wire(UInt(32.W))
    val MM_out_L1I_readdata = Wire(UInt(32.W))

    // L1D 
    val MM_in_L1D_readen = Wire(Bool())
    val MM_in_L1D_readaddr = Wire(UInt(32.W))
    val MM_out_L1D_readdata = Wire(UInt(32.W))

    val MM_in_L1D_writeen = Wire(Bool())
    val MM_in_L1D_writeaddr = Wire(UInt(32.W))
    val MM_in_L1D_writedata = Wire(UInt(32.W))

    // not use
    MM_in_L1I_readen := false.B
    MM_in_L1I_readdr := DontCare

    MM_in_L1D_readen := false.B
    MM_in_L1D_readaddr := DontCare
    // MM_out_L1D_readdata := DontCare

    MM_in_L1D_writeen := false.B
    MM_in_L1D_writeaddr := DontCare
    MM_in_L1D_writedata := DontCare

    val MM_L1D_FLAG = Wire(Bool()) // L1D enable

    MM.io.in_L1I_readenable := MM_in_L1I_readen
    MM.io.in_L1I_readaddr := MM_in_L1I_readdr
    MM_out_L1I_readdata := MM.io.out_L1I_readdata
    MM.io.in_L1D_readenable := MM_in_L1D_readen
    MM.io.in_L1D_readaddr := MM_in_L1D_readaddr
    MM_out_L1D_readdata := MM.io.out_L1D_readdata
    MM.io.in_L1D_writeenable := MM_in_L1D_writeen
    MM.io.in_L1D_writeaddr := MM_in_L1D_writeaddr
    MM.io.in_L1D_writedata := MM_in_L1D_writedata

    // PC
    val PC_out_data = Wire(UInt(32.W))

    PC.io.in_enable := io.in_enable // 启动PC
    PC.io.in_immpcenable := false.B
    PC.io.in_immpcnumber := 0.U(32.W)
    PC_out_data := PC.io.out_pcnumber

    // get inst
    when(!MM_in_L1D_readen && !MM_in_L1D_writeen) {
        MM_in_L1I_readen := true.B
        MM_in_L1I_readdr := PC_out_data
    } .otherwise {
        MM_in_L1I_readen := false.B
        MM_in_L1I_readdr := DontCare
    }


    // decoder
    val PD_out_mircocode = Wire(UInt(32.W))
    val PD_out_rs1 = Wire(UInt(5.W))
    val PD_out_rs2 = Wire(UInt(5.W))
    val PD_out_rd = Wire(UInt(5.W))
    val PD_out_immItype = Wire(UInt(12.W))
    val PD_out_immStype5 = Wire(UInt(5.W))
    val PD_out_immStype7 = Wire(UInt(7.W))
    val PD_out_shamt = Wire(UInt(5.W))

    val reg_mircocode = RegInit(0.U(32.W))
    val reg_rs1 = RegInit(0.U(5.W))
    val reg_rs2 = RegInit(0.U(5.W))
    val reg_rd = RegInit(0.U(5.W))
    val reg_immItype = RegInit(0.U(12.W))
    val reg_immStype5 = RegInit(0.U(5.W))
    val reg_immStype7 = RegInit(0.U(7.W))
    val reg_shamt = RegInit(0.U(5.W))

    PD.io.in_instruction := MM_out_L1I_readdata
    PD_out_mircocode := PD.io.out_mircocode
    PD_out_rs1 := PD.io.out_rs1
    PD_out_rs2 := PD.io.out_rs2
    PD_out_rd := PD.io.out_rd
    PD_out_immItype := PD.io.out_immItype
    PD_out_immStype5 := PD.io.out_immStype5
    PD_out_immStype7 := PD.io.out_immStype7
    PD_out_shamt := PD.io.out_shamt

    reg_mircocode := PD_out_mircocode
    reg_rs1 := PD_out_rs1
    reg_rs2 := PD_out_rs2
    reg_rd := PD_out_rd
    reg_immItype := PD_out_immItype
    reg_immStype5 := PD_out_immStype5
    reg_immStype7 := PD_out_immStype7
    reg_shamt := PD_out_shamt

    // reg file
    val RF_in_readen = Wire(Bool())
    val RF_out_readdata_1 = Wire(UInt(32.W))
    val RF_out_readdata_2 = Wire(UInt(32.W))

    val RF_in_writeen = Wire(Bool())
    val RF_in_writeaddr = Wire(UInt(32.W))
    val RF_in_writedata = Wire(UInt(32.W))

    RF_in_readen := true.B
    RF_in_writeen := false.B

    RF.io.in_read := RF_in_readen
    RF.io.in_readaddress_1 := reg_rs1
    RF.io.in_readaddress_2 := reg_rs2
    RF_out_readdata_1 := RF.io.out_readdata_1
    RF_out_readdata_2 := RF.io.out_readdata_2
    RF.io.in_write := RF_in_writeen
    RF.io.in_writeaddress_1 := RF_in_writeaddr
    RF.io.in_writedata_1 := RF_in_writedata

    val reg_rf_data_1 = RegInit(0.U(32.W))
    val reg_rf_data_2 = RegInit(0.U(32.W))

    reg_rf_data_1 := RF_out_readdata_1
    reg_rf_data_2 := RF_out_readdata_2

    // ALU AGU
    // ALU
    val ALU_out_rd = Wire(UInt(32.W))

    ALU.io.in_mircocode := reg_mircocode
    ALU.io.in_rs1data := reg_rf_data_1
    ALU.io.in_rs2data := reg_rf_data_2
    ALU.io.in_immItype := reg_immItype
    ALU.io.in_shamt := reg_shamt
    ALU_out_rd := ALU.io.out_rddata

    // AGU
    val AGU_out_L1D_readen = Wire(Bool())
    val AGU_out_L1D_readaddr = Wire(UInt(32.W))

    val AGU_out_L1D_writeen = Wire(Bool())
    val AGU_out_L1D_writeaddr = Wire(UInt(32.W))
    val AGU_out_L1D_writedata = Wire(UInt(32.W))

    val AGU_out_rdaddr = Wire(UInt(5.W))

    AGU.io.in_mircocode := reg_mircocode
    AGU.io.in_rs1data := reg_rf_data_1
    AGU.io.in_rs2data := reg_rf_data_2
    AGU.io.in_immItype := reg_immItype
    AGU.io.in_immStype5 := reg_immStype5
    AGU.io.in_immStype7 := reg_immStype7
    AGU.io.in_rdaddress := reg_rd
    AGU_out_L1D_readen := AGU.io.out_read_enable
    AGU_out_L1D_writeen := AGU.io.out_write_enable
    AGU_out_L1D_writeaddr := AGU.io.out_writeaddress
    AGU_out_L1D_writedata := AGU.io.out_writedata
    AGU_out_L1D_readaddr := AGU.io.out_readaddress
    AGU_out_rdaddr := AGU.io.out_rdaddress

    // connect AGU output to L1D input
    when(AGU_out_L1D_readen) {
        // connect
        MM_in_L1D_readen := AGU_out_L1D_readen
        MM_in_L1D_readaddr := AGU_out_L1D_readaddr
        // not use
        MM_in_L1D_writeen := false.B
        MM_in_L1D_writeaddr := DontCare
        MM_in_L1D_writedata := DontCare
        MM_L1D_FLAG := true.B
    } .elsewhen(AGU_out_L1D_writeen) {
        // connect
        MM_in_L1D_writeen := AGU_out_L1D_writeen
        MM_in_L1D_writeaddr := AGU_out_L1D_writeaddr
        MM_in_L1D_writedata := AGU_out_L1D_writedata
        // not use
        MM_in_L1D_readen := false.B
        MM_in_L1D_readaddr := DontCare
        MM_L1D_FLAG := false.B
    } .otherwise {
        // not use
        MM_in_L1D_readen := false.B
        MM_in_L1D_readaddr := DontCare
        MM_in_L1D_writeen := false.B
        MM_in_L1D_writeaddr := DontCare
        MM_in_L1D_writedata := DontCare
        MM_L1D_FLAG := true.B
    }

    val reg_L1D_readdata = RegInit(0.U(32.W))
    reg_L1D_readdata := MM_out_L1D_readdata
    val reg_ALU_rddata = RegInit(0.U(32.W))
    reg_ALU_rddata := ALU_out_rd
    val reg_AGU_rdaddr = RegInit(0.U(4.W))
    reg_AGU_rdaddr := AGU_out_rdaddr

    // write back
    val WB_in_enable = Wire(Bool())
    val WB_out_rdaddr = Wire(UInt(32.W))
    val WB_out_rddata = Wire(UInt(32.W))

    WB_in_enable := true.B

    WB.io.in_enable := WB_in_enable
    WB.io.in_address_1 := reg_AGU_rdaddr
    WB.io.in_needwritedata_1 := reg_L1D_readdata
    WB.io.in_mircocode := reg_mircocode
    WB.io.in_address_2 := reg_rd
    WB.io.in_needwritedata_2 := reg_ALU_rddata
    WB_out_rdaddr := WB.io.out_address
    WB_out_rddata := WB.io.out_data

    val reg_wb_addr = RegInit(0.U(5.W))
    val reg_wb_data = RegInit(0.U(32.W))

    reg_wb_addr := WB_out_rdaddr
    reg_wb_data := WB_out_rddata

    // close read com
    RF_in_readen := false.B
    // open write com
    RF_in_writeen := true.B
    RF_in_writeaddr := reg_wb_addr
    RF_in_writedata := reg_wb_data
}

// Tester
class TestSingleCycleCPU(c: SingleCycleCPU) extends PeekPokeTester(c) {
    // poke
    poke(c.io.in_enable, true.B)
    // wait
    step(1)
}

object SingleCycleCPU {
    def main(args: Array[String]): Unit = {
        val args = Array("--backend-name", "verilator")
        chisel3.iotesters.Driver.execute(args, () => new SingleCycleCPU) { c => new TestSingleCycleCPU(c) }
        // chisel3.Driver.execute(args, () => new SingleCycleCPU)
    }
}

最佳答案

FIRRTL 编译器在 Chisel 的输出和发出 Verilog 之间进行了大量的优化。在这种情况下,您的代码将被死代码消除删除,因为对外界没有影响。

我建议添加一些输出来监视正在发生的情况,也许将 PC_out_data 转换为输出:

    val io = IO(new Bundle {
        val in_enable = Input(Bool())
        val PC_out_data = Output(UInt(32.W))
    })

您必须将 PC_out_data 的引用替换为 io.PC_out_data,但如果您这样做,任何对 PC 产生影响的内容都将不再被删除.

有关更多信息,请查看我对此问题的回答,其中讨论了优化以及如何删除信号(除了名称如何从 Chisel 传播到 Verilog 之外,您可能也会感兴趣):How to keep all variable name In chisel when generate Verilog code

关于Chisel编译成功但无法正确生成verilog,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59005845/

相关文章:

chisel - Chisel3 中 Flipped() 的作用是什么?

chisel - firrtl.Driver 已被弃用 - 但我们应该使用什么来代替呢?

scala - 如何使用uint进行位提取

scala - 在 Mem (Chisel) 中初始化数据

chisel - 在 Chisel3 中 BlackBoxing 后生成 Verilog 代码

scala - 在 chisel 中动态创建模块,同时将动态参数传递给这些模块

chisel - 如何将已弃用的低 Firrtl 转换转换为依赖项 API

scala - 如何将 Vec(n,Bool()) 转换为 UInt 值

chisel - chisel3 中的 BlackBox 功能

chisel - 不绑定(bind)到 chisel 内存中的可综合节点异常