Reputation: 21
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
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