Compare commits

...

2 commits

Author SHA1 Message Date
24aeabee4f
npc,fix: bugs of new arch in cpu-tests
All checks were successful
Build npc tests / npc-build (flow) (push) Successful in 3m7s
Build npc tests / npc-build (flow-simlib) (push) Successful in 3m13s
Build abstract machine with nix / build-packages (nemu) (pull_request) Successful in 25s
Build abstract machine with nix / build-packages (nemu-lib) (pull_request) Successful in 19s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (pull_request) Successful in 7s
Build abstract machine with nix / build-packages (abstract-machine) (pull_request) Successful in 1m23s
2024-09-06 14:57:11 +08:00
fd1aae7c33 npc,wip: group components into stages 2024-09-03 11:29:22 +08:00
41 changed files with 3295 additions and 739 deletions

4
.gitignore vendored
View file

@ -6,3 +6,7 @@ difftest/
**/result
/.pre-commit-config.yaml
**/.vscode/
*.sock
logs/
**/.envrc
**/.gdbinit

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,23 @@
};
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
spike-diff.url = "git+https://git.xinyang.life/xin/spike-diff.git";
};
outputs = { self, flake-utils, nixpkgs, nixpkgs-circt162, pre-commit-hooks, nur-xin, diffu, am-kernels }@inputs:
flake-utils.lib.eachDefaultSystem (system:
outputs =
{
self,
flake-utils,
nixpkgs,
nixpkgs-circt162,
pre-commit-hooks,
nur-xin,
diffu,
am-kernels,
spike-diff,
}@inputs:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
@ -39,6 +52,8 @@
};
};
};
am-kernels-nemu = am-kernels.packages.${system}.rv32Cross.am-kernels-nemu;
in
{
checks = {
@ -50,7 +65,10 @@
cmake-format.enable = true;
clang-format = {
enable = true;
types_or = pkgs.lib.mkForce [ "c" "c++" ];
types_or = pkgs.lib.mkForce [
"c"
"c++"
];
};
scalafmt = {
enable = true;
@ -63,13 +81,19 @@
};
};
packages = rec {
packages = {
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
nemu = pkgs.callPackage ./nemu { };
nemu-lib = pkgs.callPackage ./nemu { };
nemu = pkgs.callPackage ./nemu { am-kernels = am-kernels-nemu; };
nemu-lib = pkgs.callPackage ./nemu { defconfig = "libdefconfig"; };
rv32Cross = rec {
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
rv32Cross = {
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine {
isa = "riscv";
platform = [
"nemu"
"npc"
];
};
};
};
@ -92,7 +116,7 @@
self.packages.${system}.nemu
];
NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu";
# NEMU_IMAGES_PATH = self.packages.${system}.rv32Cross.am-kernels-nemu + "/share/am-kernels";
NEMU_IMAGES_PATH = am-kernels.packages.${system}.rv32Cross.am-kernels-nemu + "/share/am-kernels";
};
devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
@ -125,7 +149,9 @@
verilator
];
buildInputs = with pkgs; [
buildInputs =
with pkgs;
[
spdlog
nvboard
openssl
@ -133,15 +159,26 @@
libxml2
readline
mini-gdbstub
] ++ self.checks.${system}.pre-commit-check.enabledPackages;
]
++ self.checks.${system}.pre-commit-check.enabledPackages;
};
devShells.difftest = pkgs.mkShell {
devShells.default = pkgs.mkShell {
inherit (self.checks.${system}.pre-commit-check) shellHook;
buildInputs = self.checks.${system}.pre-commit-check.enabledPackages;
packages = [
diffu.packages.${system}.default
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
self.packages.${system}.nemu-lib
spike-diff.packages.${system}.default
pkgs.gef
pkgs.gtkwave
];
DIFFU_IMAGES_PATH = "${am-kernels.packages.${system}.rv32Cross.am-kernels-npc}";
NEMU_SO = "${self.packages.${system}.nemu-lib}/lib/riscv32-nemu-interpreter-so";
NPC_SO = "/home/xin/repo/ysyx-workbench/npc/build/csrc/Flow/libFlow.so";
};
}
);

View file

@ -1 +1 @@
use flake ".?submodules=1#npc"
use flake

2
npc/.gitignore vendored
View file

@ -17,3 +17,5 @@ hs_err_pid*
compile_commands.json
*.vcd
*.gtkw
*.sock

29
npc/CMakePresets.json Normal file
View file

@ -0,0 +1,29 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ENABLE_YSYX_GIT_TRACKER": "ON",
"BUILD_CHISEL_EMIT_TARGET": "ON",
"TOPMODULE": "Flow",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"BUILD_USE_BLOOP": "ON"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default"
}
]
}

View file

@ -1,7 +1,7 @@
ThisBuild / scalaVersion := "2.13.12"
ThisBuild / version := "0.1.0"
ThisBuild / version := "0.1.1"
val chiselVersion = "6.2.0"
val chiselVersion = "6.5.0"
val circeVersion = "0.14.1"
lazy val root = (project in file("."))

View file

@ -1 +1 @@
sbt.version=1.9.9
sbt.version=1.10.1

View file

@ -1,4 +1,4 @@
import "DPI-C" function int pmem_read(input int addr);
import "DPI-C" function int pmem_read(input int addr, input byte rmask);
import "DPI-C" function void pmem_write(input int waddr, input int wdata, input byte wmask);
module RamDpi (
@ -9,6 +9,7 @@ module RamDpi (
input [31:0] writeAddr,
input [31:0] writeData,
input [3:0] writeMask,
input [3:0] readMask,
input reg [31:0] readAddr,
output reg [31:0] readData,
input reg [31:0] pc,
@ -16,7 +17,7 @@ module RamDpi (
);
always @(posedge clock) begin
if (valid) begin // 有读写请求时
readData = pmem_read(readAddr);
readData = pmem_read(readAddr, { 4'h0, readMask });
if (writeEnable) begin // 有写请求时
pmem_write(writeAddr, writeData, { 4'h0, writeMask });
end
@ -25,5 +26,5 @@ module RamDpi (
readData = 32'h80000000;
end
end
assign inst = pmem_read(pc);
assign inst = pmem_read(pc, 8'hF);
endmodule

View file

@ -3,11 +3,14 @@ package flow.components
import chisel3._
import chisel3.util._
import shapeless.{HNil, ::}
import flow.Params
import flow.components.util._
import chisel3.util.experimental.decode.{decoder, TruthTable}
class ALUControlInterface extends Bundle {
object ALUControlInterface {
object OpSelect extends ChiselEnum {
val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll,
aOpSrl, aOpSra = Value
val aOpAdd, aOpSub, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll, aOpSrl,
aOpSra = Value
}
object SrcASelect extends ChiselEnum {
val aSrcARs1, aSrcAPc, aSrcAZero = Value
@ -15,6 +18,7 @@ class ALUControlInterface extends Bundle {
object SrcBSelect extends ChiselEnum {
val aSrcBRs2, aSrcBImmI, aSrcBImmJ, aSrcBImmS, aSrcBImmU = Value
}
class ALUControlInterface extends Bundle {
val op = Input(OpSelect())
val srcASelect = Input(SrcASelect())
val srcBSelect = Input(SrcBSelect())
@ -25,11 +29,16 @@ class ALUControlInterface extends Bundle {
}
}
def apply() = new ALUControlInterface;
}
class ALU[T <: UInt](tpe: T) extends Module {
val control = IO(new ALUControlInterface)
import ALUControlInterface._
val control = IO(ALUControlInterface())
val in = IO(new Bundle {
val a = Input(Vec(control.SrcASelect.all.length, tpe))
val b = Input(Vec(control.SrcBSelect.all.length, tpe))
val a = Input(Vec(SrcASelect.all.length, tpe))
val b = Input(Vec(SrcBSelect.all.length, tpe))
})
val out = IO(new Bundle {
val eq = Output(Bool())
@ -53,13 +62,12 @@ class ALU[T <: UInt](tpe: T) extends Module {
val sra = a.asSInt >> b(log2Ceil(tpe.getWidth), 0)
out.eq := a === b
import control.OpSelect._
import ALUControlInterface.OpSelect._
out.result := MuxLookup(control.op, 0.U)(
Seq(
aOpAdd -> add,
aOpSub -> sub,
aOpNot -> not,
aOpAnd -> and,
aOpOr -> or,
aOpXor -> xor,
@ -77,3 +85,140 @@ object ALU {
Module(new ALU(tpe))
}
}
class newALU(implicit p: Params) extends Module {
import ALUControlInterface._
val control = IO(ALUControlInterface())
val in = IO(new Bundle {
val a = Input(Vec(SrcASelect.all.length, UInt(p.XLEN)))
val b = Input(Vec(SrcBSelect.all.length, UInt(p.XLEN)))
})
val out = IO(new Bundle {
val isEqual = Output(Bool())
val result = Output(UInt(p.XLEN))
})
val a = in.a(control.srcASelect.asUInt)
val b = in.b(control.srcBSelect.asUInt)
// val adder_b = (Fill(tpe.getWidth, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub
val add = a + b
val sub = a - b
val and = a & b
val not = ~a
val or = a | b
val xor = a ^ b
val slt = a.asSInt < b.asSInt
val sltu = a < b
val sll = a << b(5, 0)
val srl = a >> b(5, 0)
val sra = a.asSInt >> b(5, 0)
out.isEqual := a === b
import OpSelect._
out.result := MuxLookup(control.op, 0.U)(
Seq(
aOpAdd -> add,
aOpSub -> sub,
aOpAnd -> and,
aOpOr -> or,
aOpXor -> xor,
aOpSlt -> slt,
aOpSltu -> sltu,
aOpSll -> sll,
aOpSrl -> srl,
aOpSra -> sra.asUInt
)
)
}
class AluController(implicit p: Params) extends Module {
val out = IO(Flipped(ALUControlInterface()))
val in = IO(new Bundle {
val inst = Input(UInt(p.XLEN))
})
import flow.components.RV32Inst._
import ALUControlInterface._
// OpSelect
// format: off
val aOpAdd = Array(
lui, auipc,
jal, jalr,
lb, lbu, lh, lhu, lw,
sb, sh, sw,
addi, add
).map(_ -> OpSelect.aOpAdd.BP)
// format: on
val aOpAnd = Array(and, andi).map(_ -> OpSelect.aOpAnd.BP)
val aOpSub = Array(sub).map(_ -> OpSelect.aOpSub.BP)
val aOpOr = Array(ori, or).map(_ -> OpSelect.aOpOr.BP)
val aOpXor = Array(xori, xor).map(_ -> OpSelect.aOpXor.BP)
val aOpSlt = Array(beq, bne, blt, bge, slti, slt).map(_ -> OpSelect.aOpSlt.BP)
val aOpSltu = Array(sltiu, sltu, bltu, bgeu).map(_ -> OpSelect.aOpSltu.BP)
val aOpSll = Array(slli, sll).map(_ -> OpSelect.aOpSll.BP)
val aOpSrl = Array(srli, srl).map(_ -> OpSelect.aOpSrl.BP)
val aOpSra = Array(
sra,
srai
).map(_ -> OpSelect.aOpSra.BP)
val OpCodeMapping = TruthTable(
aOpAdd ++ aOpAnd ++ aOpSub ++ aOpOr ++ aOpXor ++ aOpSlt ++ aOpSltu ++ aOpSll ++ aOpSrl ++ aOpSra,
BitPat.dontCare(OpSelect.getWidth)
)
val aSrcAZero = Array(
lui
).map(_ -> SrcASelect.aSrcAZero.BP)
val aSrcAPc = Array(
auipc,
jal
).map(_ -> SrcASelect.aSrcAPc.BP)
val srcAMapping = TruthTable(
aSrcAZero ++ aSrcAPc,
SrcASelect.aSrcARs1.BP
)
val aSrcBImmS = Array(sb, sh, sw).map(_ -> SrcBSelect.aSrcBImmS.BP)
val aSrcBImmU = Array(lui, auipc).map(_ -> SrcBSelect.aSrcBImmU.BP)
val aSrcBImmJ = Array(jal).map(_ -> SrcBSelect.aSrcBImmJ.BP)
// format: off
val aSrcBImmI = Array(
jalr,
lb, lbu, lh, lhu, lw,
addi, slti, sltiu, xori, ori, andi, slli, srli, srai
).map(_ -> SrcBSelect.aSrcBImmI.BP)
// format: on
val srcBMapping = TruthTable(
aSrcBImmI ++ aSrcBImmJ ++ aSrcBImmU ++ aSrcBImmS,
SrcBSelect.aSrcBRs2.BP
)
val doSignExt = Array(blt, bge, slt, slti).map(_ -> BitPat(true.B))
val noSignExt = Array(lui, auipc, jal, jalr, bltu, bgeu, sltiu, sltu).map(
_ -> BitPat(false.B)
)
val signExtMapping = TruthTable(doSignExt ++ noSignExt, BitPat.dontCare(1))
out.op := OpSelect.safe(decoder(in.inst, OpCodeMapping))._1
out.srcASelect := SrcASelect.safe(decoder(in.inst, srcAMapping))._1
out.srcBSelect := SrcBSelect.safe(decoder(in.inst, srcBMapping))._1
out.signExt := decoder(in.inst, signExtMapping)
}

View file

@ -11,15 +11,16 @@ import flow.Params
import chisel3.util.BitPat
import chisel3.util.Fill
class CSRControlInterface extends Bundle {
object CSRControlInterface extends Bundle {
object csrRead extends ChiselEnum {
val csrReadDisabled, csrReadEnabled = Value
}
object csrWrite extends ChiselEnum {
val csrWriteDisabled, csrWriteEnabled = Value
val csrWriteDisabled, csrWriteData, csrSetBit, csrClearBit = Value
}
class CSRControlInterface extends Bundle {
val readEnable = Input(csrRead())
val writeEnable = Input(csrWrite())
@ -27,9 +28,11 @@ class CSRControlInterface extends Bundle {
readEnable :: writeEnable :: HNil
}
}
def apply() = new CSRControlInterface
}
class CSRCore(implicit val p: Params) extends Module {
val control = IO(new CSRControlInterface)
val control = IO(CSRControlInterface())
val in = IO(new Bundle {
val csrAddr = Input(UInt(p.csrAddrWidth))

View file

@ -5,38 +5,81 @@ import chisel3.experimental.noPrefix
import chisel3.util.HasBlackBoxPath
import chisel3.util.HasBlackBoxResource
import chisel3.util.log2Ceil
import chisel3.util.BitPat
import flow.components
import flow.Params
import shapeless.::
import shapeless.HNil
import scala.collection.SeqMap
import chisel3.util.experimental.decode.{decoder, TruthTable}
import flow.components.util._
import flow.components.RV32Inst._
class RamControlInterface(addrWidth: Int) extends Bundle {
val valid = Input(Bool())
val writeMask = Input(UInt((addrWidth / 8).W))
val writeEnable = Input(Bool())
def ctrlBindPorts = {
valid :: writeMask :: writeEnable :: HNil
}
}
/* FIXME: Extends here might not be the best solution.
* We need a way to merge two bundles together
*/
class RamInterface[T <: Data](tpe: T, addrWidth: Int)
extends RamControlInterface(addrWidth) {
val clock = Input(Clock())
val reset = Input(Reset())
val writeAddr = Input(UInt(addrWidth.W))
val writeData = Input(tpe)
val readAddr = Input(UInt(addrWidth.W))
val readData = Output(tpe)
val pc = Input(UInt(addrWidth.W))
val inst = Output(tpe)
}
class RamDpi extends BlackBox with HasBlackBoxResource {
val io = IO((new RamInterface(UInt(32.W), 32)))
class RamDpi(implicit p: Params) extends BlackBox with HasBlackBoxResource {
val io = IO(new DpiRamInterface)
addResource("/RamDpi.v")
}
class DpiRamControlInterface(implicit p: Params) extends Bundle {
val valid = Input(Bool())
val readMask = Input(UInt((p.XLEN.get / 8).W))
val writeMask = Input(UInt((p.XLEN.get / 8).W))
val writeEnable = Input(Bool())
}
class DpiRamInterface(implicit p: Params) extends DpiRamControlInterface {
val clock = Input(Clock())
val reset = Input(Reset())
// Data
val writeAddr = Input(UInt(p.XLEN))
val writeData = Input(UInt(p.XLEN))
val readAddr = Input(UInt(p.XLEN))
val readData = Output(UInt(p.XLEN))
val pc = Input(UInt(p.XLEN))
val inst = Output(UInt(p.XLEN))
}
class RamController(implicit p: Params) extends Module {
val in = new Bundle {
val inst = IO(Flipped(UInt(p.XLEN)))
}
val out = IO(Flipped(new DpiRamControlInterface))
private val validMapping = TruthTable(
Array(sb, sh, sw, lb, lbu, lh, lhu, lw).map(_ -> BitPat("b1")),
BitPat("b0")
)
private val writeMaskMapping = TruthTable(
Array(
sb -> BitPat("b0001"),
sh -> BitPat("b0011"),
sw -> BitPat("b1111")
),
BitPat.dontCare(out.writeMask.getWidth)
)
private val readMaskMapping = TruthTable(
Array(
lb -> BitPat("b0001"),
lh -> BitPat("b0011"),
lw -> BitPat("b1111")
),
BitPat.dontCare(out.readMask.getWidth)
)
private val writeEnableMapping = TruthTable(
Array(
sb -> BitPat("b1"),
sh -> BitPat("b1"),
sw -> BitPat("b1")
),
BitPat("b0")
)
out.valid := decoder(in.inst, validMapping)
out.writeEnable := decoder(in.inst, writeEnableMapping)
out.writeMask := decoder(in.inst, writeMaskMapping)
out.readMask := decoder(in.inst, readMaskMapping)
}

View file

@ -1,8 +1,14 @@
package flow.components
import chisel3._
import chisel3.util.experimental.decode.{decoder, TruthTable}
import chisel3.util.{Valid, log2Ceil}
import chisel3.util.MuxLookup
import chisel3.util.BitPat
import shapeless.{HNil, ::}
import shapeless.HList
import flow.Params
import RV32InstSubfields._
import flow.components.util._
class PcControlInterface extends Bundle {
object SrcSelect extends ChiselEnum {
@ -46,3 +52,68 @@ object ProgramCounter {
pc
}
}
object newPcControlInterface {
object SrcSelect extends ChiselEnum {
val pStatic, pJmp, pBR = Value
}
class newPcControlInterface extends Bundle {
val srcSelect = Input(SrcSelect())
def ctrlBindPorts = {
srcSelect :: HNil
}
}
def apply() = new newPcControlInterface;
}
class newProgramCounter(implicit p: Params) extends Module {
val control = IO(newPcControlInterface())
import newPcControlInterface.SrcSelect._
val in = IO(new Bundle {
val brOffset = Input(UInt(p.XLEN))
val jAddr = Input(UInt(p.XLEN))
})
val out = IO(Output(UInt(p.XLEN)))
private val pcReg = RegInit(p.resetVector.U)
out := pcReg
private val npc = MuxLookup(control.srcSelect, 4.U)(
Seq(
pStatic -> (pcReg + 4.U),
pJmp -> in.jAddr,
pBR -> (pcReg + in.brOffset)
)
)
pcReg := npc
}
class PcController(implicit p: Params) extends Module {
val in = IO(new Bundle {
val inst = Input(UInt(p.instWidth))
})
val out = IO(Flipped(newPcControlInterface()))
import RV32Inst._
import newPcControlInterface.SrcSelect._
private val _jmpMapping = Array(jal, jalr).map(_ -> pJmp.BP)
private val _brMapping =
Array(beq, bne, blt, bge, bltu, bgeu).map(_ -> pBR.BP)
val mapping = TruthTable(
_jmpMapping ++ _brMapping,
pStatic.BP
)
out.srcSelect := newPcControlInterface.SrcSelect
.safe(
(
decoder(in.inst, mapping)
)
)
._1
}

View file

@ -4,31 +4,38 @@ import chisel3._
import chisel3.util.log2Ceil
import chisel3.util.UIntToOH
import chisel3.util.MuxLookup
import chisel3.util.BitPat
import chisel3.util.experimental.decode.{decoder, TruthTable}
import chisel3.experimental.Trace._
import shapeless.{HList, HNil, ::}
import flow.Params
import flow.components.util._
import flow.components.RV32Inst._
class RegControl extends Bundle {
object RegControl {
object WriteSelect extends ChiselEnum {
val rAluOut, rMemOut, rNpc = Value
}
class RegControl extends Bundle {
val writeEnable = Input(Bool())
val writeSelect = Input(WriteSelect())
def ctrlBindPorts = {
writeEnable :: writeSelect :: HNil
}
traceName(writeEnable)
}
def apply() = new RegControl
}
class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int)
extends Module {
require(numReadPorts >= 0)
val control = IO(new RegControl)
val control = IO(RegControl())
val dataAddrWidth = log2Ceil(regCount).W
val in = IO(new Bundle {
val writeAddr = Input(UInt(dataAddrWidth))
val writeData = Input(Vec(control.WriteSelect.all.length, tpe))
val writeData = Input(Vec(RegControl.WriteSelect.all.length, tpe))
val rs = Input(Vec(numReadPorts, UInt(dataAddrWidth)))
})
val out = IO(new Bundle {
@ -51,6 +58,90 @@ class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int)
for (port <- 0 until numReadPorts) {
out.src(port) := regFile(in.rs(port).asUInt)
}
}
class newRegisterFile(implicit p: Params) extends Module {
val in = IO(new Bundle {
val rd = Input(UInt(p.regsAddrWidth))
val writeData = Input(Vec(RegControl.WriteSelect.all.length, UInt(p.XLEN)))
val rs1 = Input(UInt(p.regsAddrWidth))
val rs2 = Input(UInt(p.regsAddrWidth))
})
val out = IO(new Bundle {
val src1 = Output(UInt(p.XLEN))
val src2 = Output(UInt(p.XLEN))
})
val control = IO(RegControl())
val regFile = RegInit(
VecInit(Seq.fill(p.regsCount)(p.regsResetValue.U(p.XLEN)))
)
// 0.U -> writeData(0), ...
val writeDataMux =
MuxBindCtrlSrc(control.writeSelect, in.writeData, regFile(in.rd))
regFile(in.rd) := Mux(
control.writeEnable,
writeDataMux,
regFile(in.rd)
)
regFile(0) := 0.U
out.src1 := regFile(in.rs1)
out.src2 := regFile(in.rs2)
traceName(regFile)
dontTouch(regFile)
}
class RegisterFileController(implicit p: Params) extends Module {
val in = IO(new Bundle {
val inst = Input(UInt(p.XLEN))
})
val out = IO(Flipped(RegControl()))
// format: off
import RegControl._
private val aluOutMapping =
Array(
lui, auipc,
addi, slti, sltiu, xori, ori, andi, slli, srli, srai,
add, sub, sll, slt, sltu, xor, srl, sra, or, and,
).map(_ -> WriteSelect.rAluOut.BP)
private val memOutMapping =
Array(
lb, lbu, lh, lhu, lw
).map(_ -> WriteSelect.rMemOut.BP)
private val npcMapping =
Array(
jal, jalr
).map(_ -> WriteSelect.rNpc.BP)
// format: on
private val writeSelectMapping = TruthTable(
aluOutMapping ++ memOutMapping ++ npcMapping,
BitPat.dontCare(out.writeSelect.getWidth)
)
// enable write if instruction belongs to any mapping above
private val writeEnableMapping = TruthTable(
(aluOutMapping ++ memOutMapping ++ npcMapping).map(x =>
(x._1 -> BitPat("b1"))
),
BitPat("b0")
)
println(writeEnableMapping)
out.writeSelect := RegControl.WriteSelect
.safe(
decoder(in.inst, writeSelectMapping)
)
._1
out.writeEnable := decoder(in.inst, writeEnableMapping)
}

View file

@ -0,0 +1,28 @@
package flow.components
import chisel3._
import chisel3.util.BitPat
import chisel3.util.MuxLookup
object util {
implicit class enumToUInt[T <: EnumType](e: T) {
def U = {
e.asUInt
}
def BP = {
BitPat(e.litValue.toInt.U(e.getWidth.W))
}
}
import scala.language.implicitConversions
implicit def chiselEnumAsInt[T <: EnumType](e: T): Int = {
e.litValue.toInt
}
object MuxBindCtrlSrc {
def apply[E <: EnumType, T <: Data](ctrl: E, src: Vec[T], default: T) = {
val map = (0 until src.length).map(_.U).zip(src)
MuxLookup(ctrl.U, default)(map)
}
}
}

View file

@ -0,0 +1,74 @@
package flow.stages
import chisel3._
import flow.Params
import chisel3.util.Decoupled
import chisel3.util.DecoupledIO
import chisel3.util.ReadyValidIO
class DecoupledMsgIO[Tin <: Data, Tout <: Data](
_in: => Option[DecoupledIO[Tin]],
_out: => Option[DecoupledIO[Tout]]
)(implicit
p: Params
) extends Bundle {
implicit class optionWithGetThrow[T](o: Option[T]) {
def getOrThrow[E <: Exception](e: E): T = o match {
case Some(x) => x
case None => throw e
}
}
lazy val in = _in.getOrThrow(new Exception(s"No input port at $this"))
lazy val out = _out.getOrThrow(new Exception(s"No output port at $this"))
def connect[Tout_ <: Data](
other: DecoupledMsgIO[Tout, Tout_]
) = {
if (p.arch == "single") {
// out.ready := DontCare
// out.valid := DontCare
// other.in.valid := DontCare
// other.in.ready := DontCare
other.in.bits := out.bits
} else if (p.arch == "multi") {
out :<>= other.in
} else {
throw new Exception("Unknown architecture")
}
other
}
}
object DecoupledMsgIO {
import scala.language.implicitConversions
/** Wrap input and output messages in ReadValidIO
*/
def apply[Tin <: Data, Tout <: Data](
in: Option[Tin] = None,
out: Option[Tout] = None,
isIO: Boolean = true
)(implicit
p: Params
) = {
val _in = in match {
case Some(d) =>
if (isIO) Some(Flipped(Decoupled(d)))
else Some(Wire(Flipped(Decoupled(d))))
case None => None
}
val _out = out match {
case Some(d) =>
if (isIO) Some(Decoupled(d)) else Some(Decoupled(d))
case None => None
}
new DecoupledMsgIO(_in, _out)
}
}
object utils {
implicit class dataWrapBySome[T <: Data](d: T) {
def S = Some(d)
}
}

View file

@ -0,0 +1,75 @@
package flow.stages
import chisel3._
import chisel3.util.Decoupled
import chisel3.util.DecoupledIO
import flow.Params
import flow.stages.utils._
import flow.components.newALU
import flow.components.ALUControlInterface
import flow.stages.messages._
import flow.components.RV32InstSubfields._
class EX(implicit val p: Params) extends Module {
// val msgio = IO(DecoupledMsgIO((new ID2EX).S, (new EX2LS).S))
val msgio = IO(new Bundle {
val in = Flipped(DecoupledIO(new ID2EX))
val out = DecoupledIO(new EX2LS)
})
msgio.in.ready := DontCare
msgio.out.valid := DontCare
val io = IO(new Bundle {
val toIF = Output(new EX2IF)
})
private val _toIF = io.toIF
private val _in = msgio.in.bits
private val _out = msgio.out.bits
val alu = Module(new newALU)
alu.control := _in.aluCtrl;
{
import flow.components.ALUControlInterface.SrcASelect._
import flow.components.util.chiselEnumAsInt
alu.in.a(aSrcARs1) := _in.src1
alu.in.a(aSrcAPc) := _in.pc
alu.in.a(aSrcAZero) := 0.U
import flow.components.ALUControlInterface.SrcBSelect._
alu.in.b(aSrcBRs2) := _in.src2
alu.in.b(aSrcBImmI) := _in.inst.immI
alu.in.b(aSrcBImmJ) := _in.inst.immJ
alu.in.b(aSrcBImmU) := _in.inst.immU
alu.in.b(aSrcBImmS) := _in.inst.immS
}
_out.exeOut := alu.out.result
_toIF.jAddr := alu.out.result
_toIF.brOffset := _in.inst.immB
_toIF.pc := _in.pc
import flow.components.newPcControlInterface.SrcSelect._
val regSrcEq = Wire(Bool());
regSrcEq := (_in.src1 === _in.src2);
when(_in.pcCtrl.srcSelect === pBR) {
val branchUseSlt = _in.inst(14)
val branchInvertResult = _in.inst(12)
val _branchResult =
Mux(branchUseSlt, alu.out.result(0), regSrcEq)
val branchResult = Mux(branchInvertResult, !_branchResult, _branchResult)
_toIF.pcCtrl.srcSelect := Mux(branchResult, pBR, pStatic)
}.otherwise {
_toIF.pcCtrl.srcSelect := _in.pcCtrl.srcSelect
}
_out.ramCtrl := _in.ramCtrl
_out.pc := _in.pc
_out.rd := _in.inst.rd
_out.src1 := _in.src1
_out.src2 := _in.src2
_out.regCtrl := _in.regCtrl
}

View file

@ -0,0 +1,64 @@
package flow.stages
import chisel3._
import flow.Params
import flow.stages.utils._
import flow.stages.messages._
import flow.components._
import flow.components.RV32InstSubfields._
import chisel3.util.DecoupledIO
import chisel3.experimental.Trace._
import chisel3.util.experimental.InlineInstance
class ID(implicit val p: Params) extends Module {
val io = IO(new Bundle {
val fromWB = Input(new WB2ID)
})
// val msgio = IO(DecoupledMsgIO((new IF2ID).S, (new ID2EX).S))
val msgio = IO(new Bundle {
val in = Flipped(DecoupledIO(new IF2ID))
val out = DecoupledIO(new ID2EX)
})
msgio.in.ready := DontCare
msgio.out.valid := DontCare
val _in = msgio.in.bits
val _out = msgio.out.bits
val _fromWB = io.fromWB
val regs = Module(new newRegisterFile with InlineInstance)
// Controllers
val pcController = Module(new PcController)
val regFileController = Module(new RegisterFileController)
val aluController = Module(new AluController)
val ramController = Module(new RamController)
pcController.in.inst := _in.inst
regFileController.in.inst := _in.inst
aluController.in.inst := _in.inst
ramController.in.inst := _in.inst
regs.in.rs1 := _in.inst.rs1
regs.in.rs2 := _in.inst.rs2
_out.src1 := regs.out.src1
_out.src2 := regs.out.src2
_out.pc := _in.pc
_out.pcCtrl := pcController.out
_out.regCtrl := regFileController.out
_out.aluCtrl := aluController.out
_out.ramCtrl := ramController.out
_out.inst := _in.inst
// register file write back
import flow.components.RegControl.WriteSelect._
import flow.components.util.chiselEnumAsInt
regs.control := _fromWB.regCtrl
regs.in.rd := _fromWB.rd
regs.in.writeData(rAluOut) := _fromWB.exeOut
regs.in.writeData(rMemOut) := _fromWB.memOut
regs.in.writeData(rNpc) := _fromWB.npc
}

View file

@ -0,0 +1,46 @@
package flow.stages
import chisel3._
import flow.Params
import flow.components.newProgramCounter
import flow.components.newPcControlInterface
import flow.stages.utils._
import flow.stages.messages._
import chisel3.util.DecoupledIO
class IF(implicit val p: Params) extends Module {
import flow.components.RV32InstSubfields._
// Use DPI-C for instant instruction fetch for now
val io = IO(new Bundle {
val fromRam = Input(new Ram2IF)
val toRam = Output(new IF2Ram)
val fromEx = Input(new EX2IF)
})
val msgio = IO(new Bundle {
val out = DecoupledIO(new IF2ID)
})
msgio.out.valid := DontCare
// val msgio = IO(DecoupledMsgIO(out = (new IF2ID).S))
val _out = msgio.out.bits
val _fromRam = io.fromRam
val _toRam = io.toRam
val _fromEx = io.fromEx
// Program Counter
private val pc = Module(new newProgramCounter)
// PC update
pc.in.brOffset := _fromEx.brOffset
pc.in.jAddr := _fromEx.jAddr
pc.control := _fromEx.pcCtrl
// Instruction fetch
_toRam.pc := pc.out
_out.inst := _fromRam.inst
_out.pc := pc.out
}

View file

@ -0,0 +1,53 @@
package flow.stages
import chisel3._
import chisel3.util.Decoupled
import chisel3.util.DecoupledIO
import flow.Params
import flow.stages.utils._
import flow.stages.messages._
import flow.components.RamDpi
class LS(implicit val p: Params) extends Module {
val io = IO(new Bundle {
val toIF = Output(new Ram2IF)
val fromIF = Input(new IF2Ram)
})
// val msgio = IO(DecoupledMsgIO((new EX2LS).S, (new LS2WB).S))
val msgio = IO(new Bundle {
val in = Flipped(DecoupledIO(new EX2LS))
val out = DecoupledIO(new LS2WB)
})
msgio.in.ready := DontCare
msgio.out.valid := DontCare
private val _in = msgio.in.bits
private val _out = msgio.out.bits
private val _toIF = io.toIF
private val _fromIF = io.fromIF
val ram = Module(new RamDpi)
ram.io.clock := clock
ram.io.reset := reset
ram.io.writeAddr := _in.exeOut
ram.io.writeData := _in.src2
ram.io.writeMask := _in.ramCtrl.writeMask
ram.io.readMask := _in.ramCtrl.readMask
ram.io.writeEnable := _in.ramCtrl.writeEnable
ram.io.valid := _in.ramCtrl.valid // TODO: change to a better name
ram.io.readAddr := _in.exeOut
// TODO: Change to icache, and move to IF stage.
// Change to arbitor here
ram.io.pc := _fromIF.pc
_toIF.inst := ram.io.inst
_out.memOut := ram.io.readData
_out.exeOut := _in.exeOut
// passthrough
_out.regCtrl := _in.regCtrl
_out.rd := _in.rd
_out.pc := _in.pc
}

View file

@ -0,0 +1,73 @@
package flow.stages.messages
import chisel3._
import flow.Params
import flow.components._
class IF2ID(implicit p: Params) extends Bundle {
val inst = UInt(p.instWidth)
val pc = UInt(p.XLEN)
}
class ID2EX(implicit p: Params) extends Bundle {
// Data
val pc = UInt(p.XLEN)
val inst = UInt(p.XLEN)
val src1 = UInt(p.XLEN)
val src2 = UInt(p.XLEN)
// Control
val aluCtrl = Flipped(ALUControlInterface())
val ramCtrl = Flipped(new DpiRamControlInterface)
val pcCtrl = Flipped(newPcControlInterface())
val regCtrl = Flipped(RegControl())
}
class EX2LS(implicit p: Params) extends Bundle {
val pc = UInt(p.XLEN)
val rd = UInt(p.regsAddrWidth)
val src1 = UInt(p.XLEN)
val src2 = UInt(p.XLEN)
val exeOut = UInt(p.XLEN)
// Control
val ramCtrl = Flipped(new DpiRamControlInterface)
val regCtrl = Flipped(RegControl())
}
class LS2WB(implicit p: Params) extends Bundle {
val pc = UInt(p.XLEN)
val rd = UInt(p.regsAddrWidth)
val memOut = UInt(p.XLEN)
val exeOut = UInt(p.XLEN)
val regCtrl = Flipped(RegControl())
}
class EX2IF(implicit p: Params) extends Bundle {
val pc = UInt(p.XLEN)
val brOffset = UInt(p.XLEN)
val jAddr = UInt(p.XLEN)
// Control
val pcCtrl = Flipped(newPcControlInterface())
}
class IF2Ram(implicit p: Params) extends Bundle {
val pc = UInt(p.XLEN)
}
class Ram2IF(implicit p: Params) extends Bundle {
val inst = UInt(p.XLEN)
}
/** Commit result back to registers
*/
class WB2ID(implicit p: Params) extends Bundle {
val regCtrl = Flipped(RegControl())
val exeOut = UInt(p.XLEN)
val memOut = UInt(p.XLEN)
val rd = UInt(p.regsAddrWidth)
val npc = UInt(p.XLEN)
}

View file

@ -0,0 +1,32 @@
package flow.stages
import chisel3._
import chisel3.util.Decoupled
import chisel3.util.DecoupledIO
import flow.Params
import flow.stages.utils._
import flow.stages.messages._
import chisel3.experimental.Trace._
class WB(implicit val p: Params) extends Module {
// val msgio = IO(DecoupledMsgIO(in = (new LS2WB).S))
val io = IO(new Bundle {
val toID = Output(new WB2ID)
})
val msgio = IO(new Bundle {
val in = Flipped(DecoupledIO(new LS2WB))
})
msgio.in.ready := DontCare
private val _in = msgio.in.bits
private val _toID = io.toID
_toID.exeOut := _in.exeOut;
_toID.memOut := _in.memOut;
_toID.regCtrl := _in.regCtrl;
_toID.rd := _in.rd
_toID.npc := _in.pc + 4.U
traceName(_in.pc)
traceName(_in.rd)
}

View file

@ -18,6 +18,11 @@ import io.circe.generic.JsonCodec
import chisel3._
case class Params(
XLEN: Width,
instWidth: Width = 32.W,
regsCount: Int = 32,
regsAddrWidth: Width = 5.W,
regsResetValue: BigInt = 0L,
arch: String,
csrAddrWidth: Width = 12.W
csrAddrWidth: Width = 12.W,
resetVector: BigInt = BigInt(0x80000000L)
)

View file

@ -13,454 +13,35 @@ import chisel3.util.{BinaryMemoryFile, HexMemoryFile}
import chisel3.experimental.Trace
import scala.collection.IndexedSeqView
import shapeless.Poly1
import flow.components.RamControlInterface
import flow.components.DpiRamControlInterface
import flow.components.RV32Inst
import flow.components.RV32InstSubfields._
import flow.components.util._
import flow.components.{RegControl, PcControlInterface, ALUControlInterface}
class Control(width: Int) extends RawModule {
// Helpers
class WrapList[T](vl: T) { type Type = T; val v = vl }
object wrap extends Poly1 {
implicit def default[A] = at[A](Right(_).withLeft[Int])
}
def lit(x: Element) = { x.litValue.toInt }
def toBits(t: dst.Type): BitPat = {
val list = t.toList
list
.map(e =>
e match {
case Right(x) => BitPat(lit(x).U(x.getWidth.W))
case Left(x) => BitPat.dontCare(x)
}
)
.reduceLeft(_ ## _)
}
val r = Right
def l[T <: Any](x: T) = x match {
case x: ChiselEnum => Left(log2Ceil(x.all.length))
case x: Data => Left(x.getWidth)
case _ => throw new IllegalArgumentException
}
val inst = IO(Input(UInt(width.W)))
import flow.stages._
import chisel3.experimental.annotate
import chisel3.experimental.ChiselAnnotation
val reg = IO(Flipped(new RegControl))
val pc = IO(Flipped(new PcControlInterface))
val alu = IO(Flipped(new ALUControlInterface))
val ram = IO(Flipped(new RamControlInterface(32)))
import chisel3.Data
import chisel3.experimental.{annotate, requireIsAnnotatable, ChiselAnnotation}
val dst = new WrapList(
(reg.ctrlBindPorts ++
pc.ctrlBindPorts ++
alu.ctrlBindPorts ++
ram.ctrlBindPorts).map(wrap)
)
val dstList = dst.v.toList
val controlWidth = dstList.map(_.toOption.get.getWidth).reduce(_ + _)
val reversePrefixSum = dstList.scanLeft(0)(_ + _.toOption.get.getWidth)
val sliceIndex = reversePrefixSum.map(controlWidth - _)
val slices = sliceIndex.map(_ - 1).zip(sliceIndex.tail)
import reg.WriteSelect._
import reg._
import pc.SrcSelect._
import pc._
import alu.OpSelect._
import alu.SrcASelect._
import alu.SrcBSelect._
import pc._
import RV32Inst._
// format: off
val ControlMapping: Array[(BitPat, dst.Type)] = Array(
// Regs | writeEnable :: writeSelect :: HNil
// PC | useImmB :: srcSelect :: HNil
// Exe | op :: srcASelect :: srcBSelect :: signExt :: HNil
// Mem | valid :: writeMask :: writeEnable :: HNil
(lui , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc)::
r(aOpAdd) :: r(aSrcAZero) :: r(aSrcBImmU) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(auipc , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc)::
r(aOpAdd) :: r(aSrcAPc) :: r(aSrcBImmU) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
// ---- Control Transfer Instructions ----
(jal , (
r(true.B) :: r(rNpc) ::
r(false.B) :: r(pExeOut) ::
r(aOpAdd) :: r(aSrcAPc) :: r(aSrcBImmJ) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(jalr , (
r(true.B) :: r(rNpc) ::
r(false.B) :: r(pExeOut) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(beq , (
r(false.B) :: l(WriteSelect) ::
r(true.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(bne , (
r(false.B) :: l(WriteSelect) ::
r(true.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(blt , (
r(false.B) :: l(WriteSelect) ::
r(true.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(bge , (
r(false.B) :: l(WriteSelect) ::
r(true.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(bltu , (
r(false.B) :: l(WriteSelect)::
r(true.B) :: r(pStaticNpc) ::
r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil
)),
(bgeu , (
r(false.B) :: l(WriteSelect)::
r(true.B) :: r(pStaticNpc) ::
r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil
)),
// ---- Memory Access Instructions ----
(lb , (
r(true.B) :: r(rMemOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(true.B) :: r(1.U(4.W)) :: r(false.B) :: HNil
)),
(lbu , (
r(true.B) :: r(rMemOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(true.B) :: r(0.U(4.W)) :: r(false.B) :: HNil
)),
(lh , (
r(true.B) :: r(rMemOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(true.B) :: r(3.U(4.W)) :: r(false.B) :: HNil
)),
(lhu , (
r(true.B) :: r(rMemOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(true.B) :: r(2.U(4.W)) :: r(false.B) :: HNil
)),
(lw , (
r(true.B) :: r(rMemOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(true.B) :: r(14.U(4.W)) :: r(false.B) :: HNil
)),
(sb , (
r(false.B) :: l(WriteSelect)::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) ::
r(true.B) :: r(1.U(4.W)) :: r(true.B) :: HNil
)),
(sh , (
r(false.B) :: l(WriteSelect)::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) ::
r(true.B) :: r(3.U(4.W)) :: r(true.B) :: HNil
)),
(sw , (
r(false.B) :: l(WriteSelect)::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) ::
r(true.B) :: r(15.U(4.W)) :: r(true.B) :: HNil
)),
// ---- Integer Computational Instructions ---
(addi , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(slti , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(true.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(sltiu , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(xori , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpXor) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(ori , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpOr) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(andi , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(slli , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSll) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(srli , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(srai , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSra) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(add , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(sub , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSub) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(sll , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSll) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(slt , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(sltu , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(xor , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpXor) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(srl , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(sra , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpSra) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(or , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpOr) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
(and , (
r(true.B) :: r(rAluOut) ::
r(false.B) :: r(pStaticNpc) ::
r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) ::
r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil
)),
)
// format: on
val default = BitPat(0.U(controlWidth.W))
// println(s"ControlMapping = ${ControlMapping.map(it => (it._1 -> toBits(it._2))).foreach(x => println(x._2))}\n")
val out = decoder(
inst,
TruthTable(ControlMapping.map(it => (it._1 -> toBits(it._2))), default)
)
val srcList = slices.map(s => out(s._1, s._2))
assert(out != default)
println(s"out = $out, default = $default\n")
println(s"dstList = ${dstList}\n")
println(s"srcList = ${srcList}\n")
srcList
.zip(dstList)
.foreach({ case (src, dst) =>
dst.toOption.get := src.asTypeOf(dst.toOption.get)
})
}
import flow.components.{RegisterFile, ProgramCounter, ALU, RamDpi}
import chisel3.util.experimental.loadMemoryFromFileInline
class Flow extends Module {
def lit(x: Data) = { x.litValue.toInt }
implicit val p: Params = new Params(XLEN = 32.W, arch = "single")
val IF = Module(new IF)
val ID = Module(new ID)
val EX = Module(new EX)
val LS = Module(new LS)
val WB = Module(new WB)
// IF.msgio connect ID.msgio connect EX.msgio connect LS.msgio connect [Nothing] WB.msgio
ID.msgio.in :<>= IF.msgio.out
EX.msgio.in :<>= ID.msgio.out
LS.msgio.in :<>= EX.msgio.out
WB.msgio.in :<>= LS.msgio.out
val dataType = UInt(32.W)
val ram = Module(new RamDpi)
val control = Module(new Control(32))
val reg = Module(new RegisterFile(dataType, 32, 2))
val pc = Module(new ProgramCounter(dataType))
val alu = Module(new ALU(dataType))
// TODO: Switch to Decoupled and Arbiter later
ram.io.pc := pc.out
val inst = ram.io.inst
dontTouch(reg.control.writeEnable)
import control.pc.SrcSelect._
val npc = Wire(dataType)
npc := pc.out + 4.U
pc.in.exeOut := alu.out.result
pc.in.immB := inst.immB
control.inst := inst
reg.control <> control.reg
// FIXME: Probably optimizable with bulk connection
pc.control <> control.pc
pc.control.useImmB := control.pc.useImmB
alu.control <> control.alu
val branchUseSlt = Wire(Bool())
val branchInvertResult = Wire(Bool())
branchUseSlt := inst(14)
branchInvertResult := inst(12)
val _branchResult = Mux(branchUseSlt, alu.out.result(0), alu.out.eq)
val branchResult = Mux(branchInvertResult, !_branchResult, _branchResult)
pc.control.useImmB := control.pc.useImmB && branchResult
// printf(cf"_branchResult = ${_branchResult}, branchResult = ${branchResult}\n")
// printf(cf"pcin.useImmB = ${pc.control.useImmB}, control.out.useImmB = ${control.pc.useImmB} \n")
import control.reg.WriteSelect._
reg.in.writeData(lit(rAluOut)) := alu.out.result
val maskedData = ram.io.readData & Cat(
Fill(8, ram.io.writeMask(3)),
Fill(8, ram.io.writeMask(2)),
Fill(8, ram.io.writeMask(1)),
"b11111111".U
)
val doSignExt = control.ram.writeMask(0)
val signExt16 = control.ram.writeMask(1)
when(!doSignExt) {
reg.in.writeData(lit(rMemOut)) := maskedData
// printf(cf"!doSignExt\n")
}.elsewhen(signExt16) {
reg.in.writeData(lit(rMemOut)) := Cat(
Fill(16, maskedData(15)),
maskedData(15, 0)
)
// printf(cf"elsewhen\n")
}.otherwise {
reg.in
.writeData(lit(rMemOut)) := Cat(Fill(24, maskedData(7)), maskedData(7, 0))
// printf(cf"otherwise\n")
}
// printf(cf"maskedData = ${maskedData}, writeData = ${reg.in.writeData(lit(rMemOut))}\n")
reg.in.writeData(lit(rNpc)) := npc
reg.in.writeAddr := inst.rd
reg.in.rs(0) := inst.rs1
reg.in.rs(1) := inst.rs2
// TODO: Bulk connection here
ram.io.clock := clock
ram.io.reset := reset
ram.io.writeAddr := alu.out.result
ram.io.writeData := reg.out.src(1)
ram.io.writeMask := control.ram.writeMask
ram.io.writeEnable := control.ram.writeEnable
ram.io.valid := control.ram.valid
ram.io.readAddr := alu.out.result
import control.alu.SrcASelect._
import control.alu.SrcBSelect._
alu.in.a(lit(aSrcARs1)) := reg.out.src(0)
alu.in.a(lit(aSrcAPc)) := pc.out
alu.in.a(lit(aSrcAZero)) := 0.U
alu.in.b(lit(aSrcBRs2)) := reg.out.src(1)
// alu.in.b(lit(aSrcBImmI)) := inst(31, 20).pad(aSrcBImmI.getWidth)
alu.in.b(lit(aSrcBImmI)) := inst.immI
alu.in.b(lit(aSrcBImmJ)) := inst.immJ
alu.in.b(lit(aSrcBImmS)) := inst.immS
alu.in.b(lit(aSrcBImmU)) := inst.immU
Trace.traceName(pc.out)
dontTouch(control.out)
IF.io.fromRam := LS.io.toIF
IF.io.fromEx := EX.io.toIF
LS.io.fromIF := IF.io.toRam
ID.io.fromWB := WB.io.toID
}

View file

@ -7,11 +7,10 @@ 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
import firrtl.annotations.TargetToken.{OfModule, Instance, Ref}
// TODO: Generate verilator config file

View file

@ -10,50 +10,51 @@ import flow.tests.defaultParams
class CSRSpec extends AnyFreeSpec with ChiselScalatestTester {
implicit val p: flow.Params = defaultParams()
"should compile" in {
test(new CSRCore) { c =>
c.clock.step(1)
}
}
"Write" - {
"delayed" in {
test(new CSRCore) { c =>
val tv = BigInt("deadbeef", 16)
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
c.in.writeData.poke(tv)
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
c.clock.step(1)
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
c.out.readData.expect(0)
c.out.readValid.expect(1)
c.clock.step(1)
c.out.readValid.expect(1)
c.out.readData.expect(tv)
}
}
}
"Read" - {
"controlled by readEnable" in {
test(new CSRCore) { c =>
val tv = BigInt("deadbeef", 16)
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
c.in.writeData.poke(tv)
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
c.clock.step(1)
c.control.readEnable.poke(c.control.csrRead.csrReadDisabled)
c.out.readData.expect(0)
c.out.readValid.expect(0)
c.clock.step(1)
c.out.readData.expect(0)
c.out.readValid.expect(0)
}
}
}
// import flow.components.CSRControlInterface
// "should compile" in {
// test(new CSRCore) { c =>
// c.clock.step(1)
// }
// }
// "Write" - {
// "delayed" in {
// test(new CSRCore) { c =>
// val tv = BigInt("deadbeef", 16)
// c.in.csrAddr.poke(c.nameToAddr("mstatus"))
// c.in.writeData.poke(tv)
// c.control.writeEnable.poke(CSRControlInterface.csrWrite.csrWriteData)
// c.clock.step(1)
//
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadEnabled)
// c.out.readData.expect(0)
// c.out.readValid.expect(1)
//
// c.clock.step(1)
// c.out.readValid.expect(1)
// c.out.readData.expect(tv)
// }
// }
// }
//
// "Read" - {
// "controlled by readEnable" in {
// test(new CSRCore) { c =>
// val tv = BigInt("deadbeef", 16)
// c.in.csrAddr.poke(c.nameToAddr("mstatus"))
// c.in.writeData.poke(tv)
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadEnabled)
// c.control.writeEnable.poke(CSRControlInterface.csrWrite.csrWriteData)
// c.clock.step(1)
//
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadDisabled)
// c.out.readData.expect(0)
// c.out.readValid.expect(0)
//
// c.clock.step(1)
// c.out.readData.expect(0)
// c.out.readValid.expect(0)
// }
// }
// }
}

View file

@ -4,44 +4,28 @@ import chisel3._
import chiseltest._
import org.scalatest.freespec.AnyFreeSpec
import chiseltest.simulator.WriteVcdAnnotation
import flow.stages._
import flow.Params
import flow.Flow
import flow.tests.defaultParams
import flow.stages.messages._
class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester {
"MemoryFile" - {
"correctly load" in {
import chisel3.util.{SRAM, SRAMInterface, HexMemoryFile}
class UserMem extends Module {
val io = IO(new SRAMInterface(1024, UInt(32.W), 1, 1, 0))
val memoryFile = HexMemoryFile("../resource/addi.txt")
io :<>= SRAM(
size = 1024,
tpe = UInt(32.W),
numReadPorts = 1,
numWritePorts = 1,
numReadwritePorts = 0,
memoryFile = memoryFile
)
val read = io.readPorts(0).data
printf(cf"memoryFile=$memoryFile, readPort=$read%x\n")
}
test(new UserMem).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
c.io.readPorts(0).enable.poke(true.B)
c.io.writePorts(0).enable.poke(false.B)
c.io.writePorts(0).address.poke(0.U)
c.io.writePorts(0).data.poke(0.U)
for (i <- 0 until 32) {
c.io.readPorts(0).address.poke(i.U)
c.clock.step(1)
}
}
}
"IF" - {
implicit val p: Params = defaultParams()
class TestIF extends Module {
val IF = Module(new IF)
val io = IO(new Bundle {
val out = Output(new IF2ID)
})
io.out := IF.msgio.out
IF.msgio.out.ready := DontCare
IF.io.fromRam := DontCare
IF.io.fromEx := DontCare
}
"should compile" in {
test(new Flow) { c =>
c.clock.step(1)
test(new TestIF) { c => }
}
}
}

View file

@ -0,0 +1,24 @@
package flow.tests
import chisel3._
import chiseltest._
import org.scalatest.freespec.AnyFreeSpec
import flow.components._
class ProgramCounterSpec extends AnyFreeSpec with ChiselScalatestTester {
implicit val p: flow.Params = defaultParams()
"should compile" in {
test(new newProgramCounter) { c =>
c.clock.step(1)
}
}
"Static next pc" in {
test(new newProgramCounter) { c =>
import flow.components.newPcControlInterface.SrcSelect._
c.control.srcSelect.poke(pStatic)
c.clock.step(1)
c.out.expect(p.resetVector + 4)
}
}
}

View file

@ -1,81 +1,81 @@
package flow
// package flow
import chisel3._
import chiseltest._
import org.scalatest.freespec.AnyFreeSpec
import chiseltest.simulator.WriteVcdAnnotation
// import chisel3._
// import chiseltest._
// import org.scalatest.freespec.AnyFreeSpec
// import chiseltest.simulator.WriteVcdAnnotation
import flow.components._
class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester {
"RegisterFileCore" - {
"register 0 is always 0" in {
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
c.readPorts(0).addr.poke(0)
c.readPorts(1).addr.poke(0)
c.writePort.enable.poke(true)
c.writePort.addr.poke(0)
c.writePort.data.poke(0x1234)
// import flow.components._
// class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester {
// "RegisterFileCore" - {
// "register 0 is always 0" in {
// test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
// c.readPorts(0).addr.poke(0)
// c.readPorts(1).addr.poke(0)
// c.writePort.enable.poke(true)
// c.writePort.addr.poke(0)
// c.writePort.data.poke(0x1234)
c.readPorts(0).data.expect(0)
c.readPorts(1).data.expect(0)
c.clock.step(2)
c.readPorts(0).data.expect(0)
c.readPorts(1).data.expect(0)
}
}
"register other than 0 can be written" in {
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
import scala.util.Random
val r = new Random()
for (i <- 1 until 32) {
val v = r.nextLong() & 0xFFFFFFFFL
c.readPorts(0).addr.poke(i)
c.writePort.enable.poke(true)
c.writePort.addr.poke(i)
c.writePort.data.poke(v)
// c.readPorts(0).data.expect(0)
// c.readPorts(1).data.expect(0)
// c.clock.step(2)
// c.readPorts(0).data.expect(0)
// c.readPorts(1).data.expect(0)
// }
// }
// "register other than 0 can be written" in {
// test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
// import scala.util.Random
// val r = new Random()
// for (i <- 1 until 32) {
// val v = r.nextLong() & 0xFFFFFFFFL
// c.readPorts(0).addr.poke(i)
// c.writePort.enable.poke(true)
// c.writePort.addr.poke(i)
// c.writePort.data.poke(v)
c.clock.step(1)
c.readPorts(0).data.expect(v)
}
}
}
}
"RegisterInterface" - {
class Top extends Module {
val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2))
val rf = RegisterFile(32, UInt(32.W), 2, 2)
io :<>= rf
}
"write" in {
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
import c.io.control.WriteSelect._
val writePort = rAluOut.litValue.toInt
c.io.control.writeEnable.poke(true)
c.io.control.writeSelect.poke(rAluOut)
c.io.in.writeAddr.poke(5)
c.io.in.writeData(writePort).poke(0xcdef)
c.io.in.rs(0).poke(5)
c.clock.step(1)
c.io.out.src(0).expect(0xcdef)
}
}
"no data is written when not enabled" in {
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
import c.io.control.WriteSelect._
val writePort = rAluOut.litValue.toInt
c.io.control.writeEnable.poke(true)
c.io.control.writeSelect.poke(rAluOut)
c.io.in.writeAddr.poke(5)
c.io.in.writeData(writePort).poke(0xcdef)
c.io.in.rs(0).poke(5)
c.clock.step(1)
// c.clock.step(1)
// c.readPorts(0).data.expect(v)
// }
// }
// }
// }
// "RegisterInterface" - {
// class Top extends Module {
// val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2))
// val rf = RegisterFile(32, UInt(32.W), 2, 2)
// io :<>= rf
// }
// "write" in {
// test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
// import c.io.control.WriteSelect._
// val writePort = rAluOut.litValue.toInt
// c.io.control.writeEnable.poke(true)
// c.io.control.writeSelect.poke(rAluOut)
// c.io.in.writeAddr.poke(5)
// c.io.in.writeData(writePort).poke(0xcdef)
// c.io.in.rs(0).poke(5)
// c.clock.step(1)
// c.io.out.src(0).expect(0xcdef)
// }
// }
// "no data is written when not enabled" in {
// test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
// import c.io.control.WriteSelect._
// val writePort = rAluOut.litValue.toInt
// c.io.control.writeEnable.poke(true)
// c.io.control.writeSelect.poke(rAluOut)
// c.io.in.writeAddr.poke(5)
// c.io.in.writeData(writePort).poke(0xcdef)
// c.io.in.rs(0).poke(5)
// c.clock.step(1)
c.io.control.writeEnable.poke(false)
c.io.in.writeData(writePort).poke(0x1234)
c.clock.step(1)
// c.io.control.writeEnable.poke(false)
// c.io.in.writeData(writePort).poke(0x1234)
// c.clock.step(1)
c.io.out.src(0).expect(0xcdef)
}
}
}
}
// c.io.out.src(0).expect(0xcdef)
// }
// }
// }
// }

View file

@ -0,0 +1,70 @@
package flow.tests
import chisel3._
import chiseltest._
import org.scalatest.freespec.AnyFreeSpec
import chiseltest.simulator.WriteVcdAnnotation
import flow.tests.defaultParams
import flow.stages.utils._
import flow.stages.DecoupledMsgIO
import chisel3.util.Decoupled
class StageConnect extends AnyFreeSpec with ChiselScalatestTester {
"should compile" in {
implicit val p: flow.Params = defaultParams().copy(arch = "single")
class stage1 extends Module {
val io = DecoupledMsgIO(out = (new Bundle {
val data = UInt(12.W)
}).S)
io.out.valid := true.B
io.out.bits.data := 1.U
}
class stage2 extends Module {
val io = DecoupledMsgIO(Some(new Bundle {
val data = UInt(12.W)
}))
io.in.ready := true.B
}
class stage3 extends Module {
val wireOut = DecoupledMsgIO(
out = Some(new Bundle {
val data = UInt(12.W)
}),
isIO = false
)
val wireIn = DecoupledMsgIO(
Some(new Bundle {
val data = UInt(12.W)
}),
isIO = false
)
wireOut connect [Nothing] wireIn
wireOut.out.valid := true.B
wireOut.out.bits.data := 1.U
wireIn.in.ready := true.B
}
class stage extends Module {
val s1 = Module(new stage1)
val s2 = Module(new stage2)
s1.io connect [Nothing] s2.io
}
import circt.stage.ChiselStage
println(ChiselStage.emitSystemVerilog(new stage1))
test(new stage) { c =>
println(c)
}
test(new stage3) { c =>
println(c)
}
}
}

View file

@ -4,5 +4,5 @@ import chisel3._
import flow.Params
object defaultParams {
def apply(): Params = new Params(XLEN = 32.W)
def apply(): Params = new Params(XLEN = 32.W, arch = "single")
}

View file

@ -19,4 +19,4 @@ void Config::cli_parse(int argc, char **argv) {
}
}
Config config;
Config config{.wavefile = "flowwave.vcd"};

View file

@ -7,6 +7,7 @@ extern "C" {
#include <cstdint>
#include <cstdlib>
#include <devices.hpp>
#include <string>
#include <types.h>
#include <vl_wrapper.hpp>
#include <vpi_user.h>
@ -39,21 +40,19 @@ void *pmem_get() {
return pmem;
}
int pmem_read(int raddr) {
int pmem_read(int raddr, int rmask) {
void *pmem = pmem_get();
auto mem = static_cast<MMap *>(pmem);
// TODO: Do memory difftest at memory read and write to diagnose at a finer
// granularity
mem->trace(raddr, true, regs->get_pc());
if (g_skip_memcheck)
return mem->read(PMEM_START);
return mem->read(raddr);
return mem->read(PMEM_START, rmask);
return mem->read(raddr, rmask);
}
void pmem_write(int waddr, int wdata, char wmask) {
void *pmem = pmem_get();
auto mem = static_cast<MMap *>(pmem);
mem->trace((std::size_t)waddr, false, regs->get_pc(), wdata);
return mem->write((std::size_t)waddr, wdata, wmask);
}
@ -146,13 +145,37 @@ void npc_init(void *args) {
DbgState *dbg = (DbgState *)args;
void *mem = pmem_get();
dbg->bp = new std::vector<Breakpoint>;
dbg->cmd_return_buf = new std::string;
top = new VlModule;
regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out");
regs = new Registers("TOP.Flow.ID.regs_regFile_",
"TOP.Flow.WB.msgio_in_bits_pc");
top->setup(config.wavefile, regs);
top->reset_eval(10);
}
char *npc_monitor(void *args, char **argv, int argc) {
DbgState *dbg = (DbgState *)args;
std::string *cmd_return_buf = dbg->cmd_return_buf;
if (strncmp(argv[0], "trace", 5) == 0) {
if (strncmp(argv[1], "on", 2) == 0) {
*cmd_return_buf = "Tracing turned on\n";
if (!top->start_trace())
*cmd_return_buf = "Failed to turn on tracing\n";
return cmd_return_buf->data();
} else if (strncmp(argv[1], "off", 3) == 0) {
*cmd_return_buf = "Tracing turned off\n";
if (!top->end_trace())
*cmd_return_buf = "Failed to turn on tracing\n";
return cmd_return_buf->data();
}
}
*cmd_return_buf = "Command not found\n";
return cmd_return_buf->data();
}
bool npc_do_difftest = true;
static gdbstub_t gdbstub_priv;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7";
nur-xin = {
url = "git+https://git.xinyang.life/xin/nur.git";
@ -11,11 +12,18 @@
url = "github:zaninime/sbt-derivation";
inputs.nixpkgs.follows = "nixpkgs";
};
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
};
outputs = { self, nixpkgs, flake-utils, nur-xin, nixpkgs-circt162, sbt-derivation }:
outputs = { self, nixpkgs, nixpkgs-stable, flake-utils, nur-xin, nixpkgs-circt162, sbt-derivation, am-kernels }:
flake-utils.lib.eachDefaultSystem (system:
let
stablePkgs = import nixpkgs-stable {
inherit system;
config.allowUnfree = true;
overlays = [
];
};
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
@ -37,5 +45,29 @@
inherit flow;
};
};
devShells.default = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
nativeBuildInputs = with pkgs; [
cmake
ninja
flex
bison
nvboard
flow
espresso
bloop
coursier
sbt
gef
] ++ [stablePkgs.verilator];
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
NPC_IMAGES_PATH = "${am-kernels.packages.${system}.rv32Cross.am-kernels-npc}/share";
buildInputs = with pkgs; [
cli11
spdlog
mini-gdbstub
];
};
});
}

View file

@ -31,8 +31,10 @@ public:
Memory(std::filesystem::path filepath, bool is_binary, paddr_t pmem_start,
paddr_t pmem_end)
: pmem_start(pmem_start), pmem_end(pmem_end) {
if (!filepath.empty()) {
read_memory(filepath, is_binary);
}
}
const word_t &operator[](std::size_t addr) { return this->read(addr); }
@ -86,14 +88,18 @@ public:
ram->transfer(waddr, (uint8_t *)&wdata, len, true);
} else if (devices->handle(waddr, (uint8_t *)&wdata, len, true)) {
}
logger->trace("[W] 0x{:x}: 0x{:x}", waddr, wdata);
}
word_t read(paddr_t raddr) const {
word_t read(paddr_t raddr, int rmask) const {
word_t res = 0;
size_t len = (rmask & 1) + ((rmask & 2) >> 1) + ((rmask & 4) >> 2) +
((rmask & 8) >> 3);
if (ram->in_pmem(raddr)) {
ram->transfer(raddr, (uint8_t *)&res, 4, false);
ram->transfer(raddr, (uint8_t *)&res, len, false);
} else if (devices->handle(raddr, (uint8_t *)&res, 4, false)) {
}
logger->trace("[R] 0x{:x}: 0x{:x}", raddr, res);
return res;
}
@ -118,7 +124,7 @@ public:
void *get_pmem() { return ram->mem.data(); }
void trace(paddr_t addr, bool is_read, word_t pc = 0, word_t value = 0) {
logger->trace("[{}] 0x{:x}", is_read ? 'R' : 'W', this->read(addr));
logger->trace("[{}] 0x{:x}", is_read ? 'R' : 'W', this->read(addr, value));
}
private:

View file

@ -1,6 +1,7 @@
#ifndef _NPC_TYPES_H__
#define _NPC_TYPES_H__
#ifdef __cplusplus
#include <string>
extern "C" {
#endif
#include <gdbstub.h>
@ -32,6 +33,7 @@ struct Breakpoint {
struct DbgState {
std::vector<Breakpoint> *bp;
std::string *cmd_return_buf;
};
#endif

View file

@ -34,6 +34,7 @@ template <typename T, typename R> class VlModuleInterfaceCommon : public T {
uint64_t sim_time = 0;
uint64_t posedge_cnt = 0;
std::unique_ptr<Tracer<T>> tracer;
std::filesystem::path wavefile;
public:
const R *registers;
@ -43,8 +44,7 @@ public:
}
void setup(std::filesystem::path wavefile, const R *r) {
if (!wavefile.empty())
tracer = std::make_unique<Tracer<T>>(this, wavefile);
wavefile = "wave.vcd";
registers = r;
}
@ -89,10 +89,30 @@ public:
this->reset = 0;
g_skip_memcheck = false;
}
bool is_posedge() {
// Will be posedge when eval is called
return T::clock == 0;
}
bool start_trace() { return init_tracer(wavefile); }
bool end_trace() {
tracer.reset();
return true;
}
private:
bool init_tracer(std::filesystem::path wavefile) {
fmt::print("wavefile: {}", wavefile.string());
std::filesystem::path wav = "wave.vcd";
if (!wav.empty()) {
// Creating of tracer must happen after this class fully initialized
tracer = std::make_unique<Tracer<T>>(this, wav);
return true;
}
return false;
}
};
#endif

View file

@ -27,18 +27,23 @@ public:
}
private:
static vpiHandle get_handle(const std::string name) {
vpiHandle hdl = vpi_handle_by_name((PLI_BYTE8 *)name.c_str(), nullptr);
if (hdl == nullptr) {
SPDLOG_ERROR("VPI Handle {} not found", name);
exit(EXIT_FAILURE);
} else {
SPDLOG_INFO("Found VPI handle {} at {}", name, (void *)hdl);
}
return hdl;
}
void init_handlers(const std::string regs_prefix, const std::string pcname) {
pc_handle = get_handle(pcname);
for (int i = 0; i < nr; i++) {
std::string regname = regs_prefix + std::to_string(i);
vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), nullptr);
if (vh == nullptr) {
std::cerr << "vpiHandle " << regname.c_str() << " not found"
<< std::endl;
exit(EXIT_FAILURE);
reg_handles[i] = get_handle(regname);
}
reg_handles[i] = vh;
}
pc_handle = vpi_handle_by_name((PLI_BYTE8 *)pcname.c_str(), nullptr);
}
};

86
scripts/difftests.py Normal file
View file

@ -0,0 +1,86 @@
#/usr/bin/env python
"""
This script is used to provide a wrapper to difftest, so that they can be easily
deployed on ci environment.
"""
import os
import os.path as osp
import sys
from multiprocessing import Pool, Process
from functools import partial
def find_all_test_images(path):
tests = []
for root, dirs, files in os.walk(path):
for file in files:
# Get file extensions and select files with .bin
ext = osp.splitext(file)[1]
if ext == ".bin":
tests.append(osp.join(root, file))
return tests
def run_test(test_image, ref, ref_prefix, dut, dut_prefix):
diffu = "diffu"
args = [
"--images-path", "/",
"-m", test_image,
"--ref", ref,
"--ref-prefix", ref_prefix,
"--dut", dut,
"--dut-prefix", dut_prefix,
"> logs/" + osp.basename(test_image) + ".log",
"2>&1"
]
status = os.system(diffu + " " + " ".join(args))
exitcode = os.waitstatus_to_exitcode(status)
image_shortname = osp.basename(test_image)
print(f"{ 'FAILED' if exitcode else 'PASSED' } {image_shortname}")
if exitcode:
print(f"cmd: {diffu + ' ' + ' '.join(args)}")
print(f"exitcode: {exitcode}")
sys.exit(exitcode)
def print_statistics(results):
pass
def main():
DIFFU_IMAGES_PATH = os.environ["DIFFU_IMAGES_PATH"]
print(DIFFU_IMAGES_PATH)
assert(osp.isdir(DIFFU_IMAGES_PATH))
os.makedirs("logs", exist_ok = True)
# Run tests in a multiprocess pool
tests = find_all_test_images(DIFFU_IMAGES_PATH)
ref, ref_prefix, dut, dut_prefix = sys.argv[1:]
ref_shortname = osp.basename(ref)
dut_shortname = osp.basename(dut)
print(f"[{ref_shortname}, {dut_shortname}]")
procs = []
for test in tests:
image_shortname = osp.basename(test)
p = Process(target=run_test, args=(test, ref, ref_prefix, dut, dut_prefix), name=image_shortname, daemon=True)
procs.append(p)
p.start()
timeout = 0
for p in procs:
p.join(5)
if p.exitcode is None:
print(f"{ 'TIMEOUT' } {p.name}")
p.terminate()
p.join()
timeout += 1
not_success = sum((1 for p in procs if p.exitcode != 0))
failed = not_success - timeout
print("==========")
print(f"TOTAL {len(procs)}\tFAILED: {failed}\tTIMEOUT: {timeout}")
return not_success
if __name__ == "__main__":
sys.exit(main())