npc: reg file access through vpi

This commit is contained in:
xinyangli 2024-03-29 10:35:49 +08:00
parent dc2cb010ce
commit 84c8de8461
Signed by: xin
SSH key fingerprint: SHA256:qZ/tzd8lYRtUFSrfBDBMcUqV4GHKxqeqRA3huItgvbk
11 changed files with 378 additions and 145 deletions

View file

@ -5,16 +5,17 @@ import chisel3._
import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse}
import chisel3.util.{SRAM}
import chisel3.util.experimental.decode.{decoder, TruthTable}
import chisel3.stage.ChiselOption
import chisel3.util.log2Ceil
import chisel3.util.BitPat
import chisel3.util.Enum
import chisel3.experimental.prefix
import chisel3.experimental.Trace._
import shapeless.{HNil, ::}
import shapeless.HList
import shapeless.ops.coproduct.Prepend
import chisel3.util.{ BinaryMemoryFile, HexMemoryFile }
import chisel3.experimental.Trace
object RV32Inst {
private val bp = BitPat
val addi = this.bp("b???????_?????_?????_000_?????_00100_11")
@ -73,7 +74,7 @@ class Control(width: Int) extends Module {
})
}
import flow.components.{RegisterFile, RegFileInterface, ProgramCounter, ALU}
import flow.components.{RegisterFile, ProgramCounter, ALU}
import chisel3.util.experimental.loadMemoryFromFileInline
class Flow extends Module {
val dataType = UInt(32.W)
@ -87,7 +88,7 @@ class Flow extends Module {
memoryFile = HexMemoryFile("./resource/addi.txt")
)
val control = Module(new Control(32))
val reg = RegisterFile(32, dataType, 2, 2)
val reg = Module(new RegisterFile(dataType, 32, 2))
val pc = Module(new ProgramCounter(dataType))
val alu = Module(new ALU(dataType))
@ -95,6 +96,9 @@ class Flow extends Module {
ram.readPorts(0).address := pc.out - 0x80000000L.U
val inst = ram.readPorts(0).data
Trace.traceName(reg.control.writeEnable)
dontTouch(reg.control.writeEnable)
import control.pc.SrcSelect._
pc.in.pcSrcs(pStaticNpc.litValue.toInt) := pc.out + 4.U
@ -125,5 +129,6 @@ class Flow extends Module {
alu.in.a(aSrcImm.litValue.toInt) := inst(31, 20)
alu.in.b := reg.out.src(1)
dontTouch(control.out)
}

View file

@ -0,0 +1 @@
package flow.components

View file

@ -4,6 +4,7 @@ import chisel3._
import chisel3.util.log2Ceil
import chisel3.util.UIntToOH
import chisel3.util.MuxLookup
import chisel3.experimental.Trace._
import shapeless.{ HNil, :: }
class RegControl extends Bundle {
@ -18,69 +19,34 @@ class RegControl extends Bundle {
def ctrlBindPorts: CtrlTypes = {
writeEnable :: writeSelect :: HNil
}
traceName(writeEnable)
}
class RegFileData[T <: Data](size:Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle {
val write = new Bundle {
val addr = Input(UInt(size.W))
val data = Vec(numWritePorts, Input(tpe))
}
val read = Vec(numReadPorts, new Bundle {
val rs = Input(UInt(size.W))
val src = Output(tpe)
})
}
class RegFileInterface[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle {
val control = new RegControl
// val data = new RegFileData(size, tpe, numReadPorts, numWritePorts)
val in = new Bundle {
val writeAddr = Input(UInt(size.W))
val writeData = Input(Vec(numWritePorts, tpe))
val rs = Input(Vec(numReadPorts, UInt(size.W)))
}
val out = new Bundle {
val src = Output(Vec(numReadPorts, tpe))
}
}
class RegisterFileCore[T <: Data](size: Int, tpe: T, numReadPorts: Int) extends Module {
class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int) extends Module {
require(numReadPorts >= 0)
val writePort = IO(new Bundle {
val enable = Input(Bool())
val addr = Input(UInt(log2Ceil(size).W))
val data = Input(tpe)
val control = IO(new RegControl)
val dataAddrWidth = log2Ceil(tpe.getWidth).W
val in = IO(new Bundle {
val writeAddr = Input(UInt(dataAddrWidth))
val writeData = Input(Vec(control.WriteSelect.all.length, tpe))
val rs = Input(Vec(numReadPorts, UInt(dataAddrWidth)))
})
val out = IO(new Bundle {
val src = Output(Vec(numReadPorts, tpe))
})
val readPorts = IO(Vec(numReadPorts, new Bundle {
val addr = Input(UInt(log2Ceil(size).W))
val data = Output(tpe)
}))
val regFile = RegInit(VecInit(Seq.fill(size)(0.U(tpe.getWidth.W))))
val writeAddrOH = UIntToOH(writePort.addr)
val regResetValue = 0.U(tpe.getWidth.W)
val regFile = RegInit(VecInit(Seq.fill(regCount)(regResetValue)))
val writeAddrOH = UIntToOH(in.writeAddr)
for ((reg, i) <- regFile.zipWithIndex.tail) {
reg := Mux(writeAddrOH(i) && writePort.enable, writePort.data, reg)
reg := Mux(writeAddrOH(i.U(log2Ceil(regCount).W)) && control.writeEnable, in.writeData(control.writeSelect.asUInt), reg)
}
regFile(0) := 0.U
for (readPort <- readPorts) {
readPort.data := regFile(readPort.addr)
for (port <- 0 until numReadPorts) {
out.src(port) := regFile(in.rs(port).asUInt)
}
traceName(regFile)
dontTouch(regFile)
}
object RegisterFile {
def apply[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int): RegFileInterface[T] = {
val core = Module(new RegisterFileCore(size, tpe, numReadPorts))
val _out = Wire(new RegFileInterface(size, tpe, numReadPorts, numWritePorts))
val clock = core.clock
for (i <- 0 until numReadPorts) {
core.readPorts(i).addr := _out.in.rs(i)
_out.out.src(i) := core.readPorts(i).data
}
core.writePort.addr := _out.in.writeAddr
core.writePort.data := _out.in.writeData(_out.control.writeSelect.asUInt)
core.writePort.enable := _out.control.writeEnable
_out
}
}

View file

@ -0,0 +1,47 @@
package flow
import scopt.{ OParser, DefaultOEffectSetup }
import java.io.File
case class CliOptions(
targetDir: File = new File("."),
configFile: Option[File] = None,
argsFile: Option[File] = None,
verilatorConfigFileOut: File = new File("conf.vlt"),
) {
val builder = OParser.builder[CliOptions]
val parser = {
import builder._
OParser.sequence(
programName("flow"),
help("help"),
opt[Option[File]]('c', "config")
.action((x, c) => c.copy(configFile = x))
.text("JSON Configuration file for generation"),
opt[Option[File]]("args-file")
.action((x, c) => c.copy(argsFile = x))
.text("Passing file content as args when emit"),
opt[File]('o', "target-dir")
.action((x, c) => c.copy(targetDir = x))
.text("Output files relative to this path"),
opt[File]("out-verilator-conf")
.action((x, c) => c.copy(verilatorConfigFileOut = x))
.text("Options needed when simulating with verilator")
)
}
def parse(args: Array[String]): CliOptions = {
OParser.runParser(parser, args, CliOptions()) match {
case (result, effects) =>
OParser.runEffects(effects, new DefaultOEffectSetup {
// ignore terminate
override def terminate(exitState: Either[String, Unit]): Unit = ()
})
result match {
case Some(cliOptions: CliOptions) => { return cliOptions }
case _ => { throw new IllegalArgumentException("Wrong command line argument") }
}
}
}
}

View file

@ -0,0 +1,16 @@
package flow
import io.circe.generic.JsonCodec
// Which group of signals to trace
@JsonCodec case class TraceConfig (
enable: Boolean = false,
registers: Array[Int] = Array(),
mem: Array[(Int, Int)] = Array(),
)
@JsonCodec case class Config(
// Whether to enable Difftest
enableDifftest: Boolean = true,
traceConfig: TraceConfig = TraceConfig(),
)

View file

@ -0,0 +1,72 @@
package flow
import flow._
import chisel3._
import chisel3.experimental.Trace._
import chisel3.stage.{ChiselGeneratorAnnotation, DesignAnnotation}
import chisel3.util.experimental.InlineInstance
import circt.stage.ChiselStage
import firrtl.AnnotationSeq
import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
import java.io.PrintWriter
import scala.io.Source
import java.io.File
// TODO: Generate verilator config file
object VerilogMain extends App {
val opt = CliOptions().parse(args)
val topName = "Flow"
val config: Config = opt.configFile match {
case Some(f) => {
val source = Source.fromFile(f)
val jsonString = source.mkString
source.close()
io.circe.parser.decode[Config](jsonString) match {
case Right(x) => x
case Left(e) => throw e
}
}
case None => Config(traceConfig = TraceConfig(enable = true))
}
val annos = (new ChiselStage).execute(
Array("--target-dir", opt.targetDir.toString, "--target", "systemverilog", "--split-verilog"),
Seq(
) ++ (if(config.traceConfig.enable) Seq(ChiselGeneratorAnnotation(() => new Flow)) else Seq())
)
if(config.traceConfig.enable) {
val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Flow]
val verilatorConfigSeq = finalTargetMap(annos)
.values
.flatten
.map(ct =>
s"""public_flat_rd -module "${
ct.tokens.collectFirst { case OfModule(m) => m }.get
}" -var "${ct.tokens.collectFirst { case Ref(r) => r }.get}"""")
finalTargetMap(annos)
.values
.flatten
.foreach(
ct => println(s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst {
case Ref(r) => r
}.get}""")
)
val verilatorConfigWriter = new PrintWriter(new File(opt.targetDir, opt.verilatorConfigFileOut.toString()))
verilatorConfigWriter.write("`verilator_config\n")
try {
for(ct <- verilatorConfigSeq) {
verilatorConfigWriter.println(ct)
}
} finally {
verilatorConfigWriter.close()
}
}
}

View file

@ -0,0 +1,11 @@
package flow.utils
import chisel3._
import chisel3.util.HasBlackBoxResource
// class DiffTester extends BlackBox with HasBlackBoxResource {
// val io = IO(new Bundle {
// val regs =
// })
// addResource("difftest.v");
// }