凿子编译成功,但无法正确生成Verilog

时间:2019-11-23 08:25:17

标签: 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)
    }
}

1 个答案:

答案 0 :(得分:2)

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