TealerKoor
TealerKoor

Reputation: 21

Chisel compiled successfully but can't generate correctly verilog

I use Chisel write an RISC-V CPU, Chisel code compiled successfully and Firrtl code generate successfully too, but the verilog code just has a module statement.The Verilog files are basically empty.

It generates all module's Firrtl code.When I use Verilator to simulation it, under the test_run_dir fold it is just a 1kb verilog file and an empty VCD file.

Here is the code

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)
    }
}

Upvotes: 2

Views: 572

Answers (1)

Jack Koenig
Jack Koenig

Reputation: 6064

The FIRRTL compiler does a fair amount of optimizations between the output of Chisel and emitting Verilog. In this case, your code is getting removed by Dead Code Elimination because there is no effect on the outside world.

I would suggest adding some output to monitor what's going on, perhaps turn PC_out_data into an output:

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

You'll have to replace references to PC_out_data with io.PC_out_data, but if you do this, anything that has an effect on the PC will no longer be deleted.

For more information, check out my answer to this question which discusses optimizations and how they remove signals (in addition to how names are propagated from Chisel to Verilog which you also might find interesting): How to keep all variable name In chisel when generate Verilog code

Upvotes: 3

Related Questions