我用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)
}
}
答案 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