refactor-npc #4
27 changed files with 2456 additions and 673 deletions
870
flake.lock
generated
870
flake.lock
generated
File diff suppressed because it is too large
Load diff
71
flake.nix
71
flake.nix
|
@ -13,10 +13,23 @@
|
||||||
};
|
};
|
||||||
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
|
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
|
||||||
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
|
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:
|
outputs =
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
{
|
||||||
|
self,
|
||||||
|
flake-utils,
|
||||||
|
nixpkgs,
|
||||||
|
nixpkgs-circt162,
|
||||||
|
pre-commit-hooks,
|
||||||
|
nur-xin,
|
||||||
|
diffu,
|
||||||
|
am-kernels,
|
||||||
|
spike-diff,
|
||||||
|
}@inputs:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
|
@ -39,6 +52,8 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
am-kernels-nemu = am-kernels.packages.${system}.rv32Cross.am-kernels-nemu;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = {
|
checks = {
|
||||||
|
@ -50,7 +65,10 @@
|
||||||
cmake-format.enable = true;
|
cmake-format.enable = true;
|
||||||
clang-format = {
|
clang-format = {
|
||||||
enable = true;
|
enable = true;
|
||||||
types_or = pkgs.lib.mkForce [ "c" "c++" ];
|
types_or = pkgs.lib.mkForce [
|
||||||
|
"c"
|
||||||
|
"c++"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
scalafmt = {
|
scalafmt = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -63,13 +81,19 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = rec {
|
packages = {
|
||||||
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
|
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
|
||||||
nemu = pkgs.callPackage ./nemu { };
|
nemu = pkgs.callPackage ./nemu { am-kernels = am-kernels-nemu; };
|
||||||
nemu-lib = pkgs.callPackage ./nemu { };
|
nemu-lib = pkgs.callPackage ./nemu { defconfig = "libdefconfig"; };
|
||||||
|
|
||||||
rv32Cross = rec {
|
rv32Cross = {
|
||||||
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
|
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine {
|
||||||
|
isa = "riscv";
|
||||||
|
platform = [
|
||||||
|
"nemu"
|
||||||
|
"npc"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,7 +116,7 @@
|
||||||
self.packages.${system}.nemu
|
self.packages.${system}.nemu
|
||||||
];
|
];
|
||||||
NEMU_HOME = "/home/xin/repo/ysyx-workbench/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; } {
|
devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
|
||||||
|
@ -125,15 +149,18 @@
|
||||||
verilator
|
verilator
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = with pkgs; [
|
buildInputs =
|
||||||
spdlog
|
with pkgs;
|
||||||
nvboard
|
[
|
||||||
openssl
|
spdlog
|
||||||
libllvm
|
nvboard
|
||||||
libxml2
|
openssl
|
||||||
readline
|
libllvm
|
||||||
mini-gdbstub
|
libxml2
|
||||||
] ++ self.checks.${system}.pre-commit-check.enabledPackages;
|
readline
|
||||||
|
mini-gdbstub
|
||||||
|
]
|
||||||
|
++ self.checks.${system}.pre-commit-check.enabledPackages;
|
||||||
};
|
};
|
||||||
|
|
||||||
devShells.difftest = pkgs.mkShell {
|
devShells.difftest = pkgs.mkShell {
|
||||||
|
@ -141,7 +168,15 @@
|
||||||
diffu.packages.${system}.default
|
diffu.packages.${system}.default
|
||||||
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
|
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
|
||||||
self.packages.${system}.nemu-lib
|
self.packages.${system}.nemu-lib
|
||||||
|
spike-diff.packages.${system}.default
|
||||||
];
|
];
|
||||||
|
|
||||||
|
DIFFU_IMAGES_PATH = "${am-kernels.packages.${system}.rv32Cross.am-kernels-npc}/share";
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||||
|
buildInputs = self.checks.${system}.pre-commit-check.enabledPackages;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
use flake ".?submodules=1#npc"
|
use flake
|
||||||
|
|
|
@ -3,11 +3,14 @@ package flow.components
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
import shapeless.{HNil, ::}
|
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 {
|
object OpSelect extends ChiselEnum {
|
||||||
val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll,
|
val aOpAdd, aOpSub, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll, aOpSrl,
|
||||||
aOpSrl, aOpSra = Value
|
aOpSra = Value
|
||||||
}
|
}
|
||||||
object SrcASelect extends ChiselEnum {
|
object SrcASelect extends ChiselEnum {
|
||||||
val aSrcARs1, aSrcAPc, aSrcAZero = Value
|
val aSrcARs1, aSrcAPc, aSrcAZero = Value
|
||||||
|
@ -15,21 +18,27 @@ class ALUControlInterface extends Bundle {
|
||||||
object SrcBSelect extends ChiselEnum {
|
object SrcBSelect extends ChiselEnum {
|
||||||
val aSrcBRs2, aSrcBImmI, aSrcBImmJ, aSrcBImmS, aSrcBImmU = Value
|
val aSrcBRs2, aSrcBImmI, aSrcBImmJ, aSrcBImmS, aSrcBImmU = Value
|
||||||
}
|
}
|
||||||
val op = Input(OpSelect())
|
class ALUControlInterface extends Bundle {
|
||||||
val srcASelect = Input(SrcASelect())
|
val op = Input(OpSelect())
|
||||||
val srcBSelect = Input(SrcBSelect())
|
val srcASelect = Input(SrcASelect())
|
||||||
val signExt = Input(Bool())
|
val srcBSelect = Input(SrcBSelect())
|
||||||
|
val signExt = Input(Bool())
|
||||||
|
|
||||||
def ctrlBindPorts = {
|
def ctrlBindPorts = {
|
||||||
op :: srcASelect :: srcBSelect :: signExt :: HNil
|
op :: srcASelect :: srcBSelect :: signExt :: HNil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def apply() = new ALUControlInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ALU[T <: UInt](tpe: T) extends Module {
|
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 in = IO(new Bundle {
|
||||||
val a = Input(Vec(control.SrcASelect.all.length, tpe))
|
val a = Input(Vec(SrcASelect.all.length, tpe))
|
||||||
val b = Input(Vec(control.SrcBSelect.all.length, tpe))
|
val b = Input(Vec(SrcBSelect.all.length, tpe))
|
||||||
})
|
})
|
||||||
val out = IO(new Bundle {
|
val out = IO(new Bundle {
|
||||||
val eq = Output(Bool())
|
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)
|
val sra = a.asSInt >> b(log2Ceil(tpe.getWidth), 0)
|
||||||
out.eq := a === b
|
out.eq := a === b
|
||||||
|
|
||||||
import control.OpSelect._
|
import ALUControlInterface.OpSelect._
|
||||||
|
|
||||||
out.result := MuxLookup(control.op, 0.U)(
|
out.result := MuxLookup(control.op, 0.U)(
|
||||||
Seq(
|
Seq(
|
||||||
aOpAdd -> add,
|
aOpAdd -> add,
|
||||||
aOpSub -> sub,
|
aOpSub -> sub,
|
||||||
aOpNot -> not,
|
|
||||||
aOpAnd -> and,
|
aOpAnd -> and,
|
||||||
aOpOr -> or,
|
aOpOr -> or,
|
||||||
aOpXor -> xor,
|
aOpXor -> xor,
|
||||||
|
@ -77,3 +85,140 @@ object ALU {
|
||||||
Module(new ALU(tpe))
|
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 eq = 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.eq := 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)
|
||||||
|
}
|
||||||
|
|
|
@ -11,25 +11,28 @@ import flow.Params
|
||||||
import chisel3.util.BitPat
|
import chisel3.util.BitPat
|
||||||
import chisel3.util.Fill
|
import chisel3.util.Fill
|
||||||
|
|
||||||
class CSRControlInterface extends Bundle {
|
object CSRControlInterface extends Bundle {
|
||||||
object csrRead extends ChiselEnum {
|
object csrRead extends ChiselEnum {
|
||||||
val csrReadDisabled, csrReadEnabled = Value
|
val csrReadDisabled, csrReadEnabled = Value
|
||||||
}
|
}
|
||||||
|
|
||||||
object csrWrite extends ChiselEnum {
|
object csrWrite extends ChiselEnum {
|
||||||
val csrWriteDisabled, csrWriteEnabled = Value
|
val csrWriteDisabled, csrWriteData, csrSetBit, csrClearBit = Value
|
||||||
}
|
}
|
||||||
|
|
||||||
val readEnable = Input(csrRead())
|
class CSRControlInterface extends Bundle {
|
||||||
val writeEnable = Input(csrWrite())
|
val readEnable = Input(csrRead())
|
||||||
|
val writeEnable = Input(csrWrite())
|
||||||
|
|
||||||
def ctrlBindPorts = {
|
def ctrlBindPorts = {
|
||||||
readEnable :: writeEnable :: HNil
|
readEnable :: writeEnable :: HNil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
def apply() = new CSRControlInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
class CSRCore(implicit val p: Params) extends Module {
|
class CSRCore(implicit val p: Params) extends Module {
|
||||||
val control = IO(new CSRControlInterface)
|
val control = IO(CSRControlInterface())
|
||||||
|
|
||||||
val in = IO(new Bundle {
|
val in = IO(new Bundle {
|
||||||
val csrAddr = Input(UInt(p.csrAddrWidth))
|
val csrAddr = Input(UInt(p.csrAddrWidth))
|
||||||
|
|
|
@ -5,11 +5,16 @@ import chisel3.experimental.noPrefix
|
||||||
import chisel3.util.HasBlackBoxPath
|
import chisel3.util.HasBlackBoxPath
|
||||||
import chisel3.util.HasBlackBoxResource
|
import chisel3.util.HasBlackBoxResource
|
||||||
import chisel3.util.log2Ceil
|
import chisel3.util.log2Ceil
|
||||||
|
import chisel3.util.BitPat
|
||||||
import flow.components
|
import flow.components
|
||||||
|
import flow.Params
|
||||||
import shapeless.::
|
import shapeless.::
|
||||||
import shapeless.HNil
|
import shapeless.HNil
|
||||||
|
|
||||||
import scala.collection.SeqMap
|
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 {
|
class RamControlInterface(addrWidth: Int) extends Bundle {
|
||||||
val valid = Input(Bool())
|
val valid = Input(Bool())
|
||||||
|
@ -40,3 +45,55 @@ class RamDpi extends BlackBox with HasBlackBoxResource {
|
||||||
val io = IO((new RamInterface(UInt(32.W), 32)))
|
val io = IO((new RamInterface(UInt(32.W), 32)))
|
||||||
addResource("/RamDpi.v")
|
addResource("/RamDpi.v")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DpiRamControlInterface(implicit p: Params) extends Bundle {
|
||||||
|
val valid = Input(Bool())
|
||||||
|
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 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, writeMaskMapping)
|
||||||
|
out.writeMask := decoder(in.inst, writeMaskMapping)
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
package flow.components
|
package flow.components
|
||||||
import chisel3._
|
import chisel3._
|
||||||
|
import chisel3.util.experimental.decode.{decoder, TruthTable}
|
||||||
import chisel3.util.{Valid, log2Ceil}
|
import chisel3.util.{Valid, log2Ceil}
|
||||||
import chisel3.util.MuxLookup
|
import chisel3.util.MuxLookup
|
||||||
|
import chisel3.util.BitPat
|
||||||
import shapeless.{HNil, ::}
|
import shapeless.{HNil, ::}
|
||||||
|
import shapeless.HList
|
||||||
|
import flow.Params
|
||||||
|
import RV32InstSubfields._
|
||||||
|
import flow.components.util._
|
||||||
|
|
||||||
class PcControlInterface extends Bundle {
|
class PcControlInterface extends Bundle {
|
||||||
object SrcSelect extends ChiselEnum {
|
object SrcSelect extends ChiselEnum {
|
||||||
|
@ -46,3 +52,68 @@ object ProgramCounter {
|
||||||
pc
|
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 brAddr = 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.brAddr,
|
||||||
|
pBR -> in.jAddr
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -4,31 +4,38 @@ import chisel3._
|
||||||
import chisel3.util.log2Ceil
|
import chisel3.util.log2Ceil
|
||||||
import chisel3.util.UIntToOH
|
import chisel3.util.UIntToOH
|
||||||
import chisel3.util.MuxLookup
|
import chisel3.util.MuxLookup
|
||||||
|
import chisel3.util.BitPat
|
||||||
|
import chisel3.util.experimental.decode.{decoder, TruthTable}
|
||||||
import chisel3.experimental.Trace._
|
import chisel3.experimental.Trace._
|
||||||
import shapeless.{HList, HNil, ::}
|
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 {
|
object WriteSelect extends ChiselEnum {
|
||||||
val rAluOut, rMemOut, rNpc = Value
|
val rAluOut, rMemOut, rNpc = Value
|
||||||
}
|
}
|
||||||
|
class RegControl extends Bundle {
|
||||||
|
val writeEnable = Input(Bool())
|
||||||
|
val writeSelect = Input(WriteSelect())
|
||||||
|
|
||||||
val writeEnable = Input(Bool())
|
def ctrlBindPorts = {
|
||||||
val writeSelect = Input(WriteSelect())
|
writeEnable :: writeSelect :: HNil
|
||||||
|
}
|
||||||
def ctrlBindPorts = {
|
|
||||||
writeEnable :: writeSelect :: HNil
|
|
||||||
}
|
}
|
||||||
traceName(writeEnable)
|
|
||||||
|
def apply() = new RegControl
|
||||||
}
|
}
|
||||||
|
|
||||||
class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int)
|
class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int)
|
||||||
extends Module {
|
extends Module {
|
||||||
require(numReadPorts >= 0)
|
require(numReadPorts >= 0)
|
||||||
val control = IO(new RegControl)
|
val control = IO(RegControl())
|
||||||
val dataAddrWidth = log2Ceil(regCount).W
|
val dataAddrWidth = log2Ceil(regCount).W
|
||||||
val in = IO(new Bundle {
|
val in = IO(new Bundle {
|
||||||
val writeAddr = Input(UInt(dataAddrWidth))
|
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 rs = Input(Vec(numReadPorts, UInt(dataAddrWidth)))
|
||||||
})
|
})
|
||||||
val out = IO(new Bundle {
|
val out = IO(new Bundle {
|
||||||
|
@ -54,3 +61,85 @@ class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int)
|
||||||
traceName(regFile)
|
traceName(regFile)
|
||||||
dontTouch(regFile)
|
dontTouch(regFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
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(true.B))
|
||||||
|
),
|
||||||
|
BitPat(false.B)
|
||||||
|
)
|
||||||
|
|
||||||
|
out.writeSelect := RegControl.WriteSelect
|
||||||
|
.safe(
|
||||||
|
decoder(in.inst, writeSelectMapping)
|
||||||
|
)
|
||||||
|
._1
|
||||||
|
out.writeEnable := decoder(in.inst, writeEnableMapping)
|
||||||
|
}
|
||||||
|
|
28
npc/core/src/main/scala/components/util.scala
Normal file
28
npc/core/src/main/scala/components/util.scala
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
npc/core/src/main/scala/stages/Base.scala
Normal file
74
npc/core/src/main/scala/stages/Base.scala
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
72
npc/core/src/main/scala/stages/EX.scala
Normal file
72
npc/core/src/main/scala/stages/EX.scala
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
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.inst.rs1
|
||||||
|
alu.in.a(aSrcAPc) := _in.pc
|
||||||
|
alu.in.a(aSrcAZero) := 0.U
|
||||||
|
|
||||||
|
import flow.components.ALUControlInterface.SrcBSelect._
|
||||||
|
alu.in.b(aSrcBRs2) := _in.inst.rs2
|
||||||
|
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.exeEq := alu.out.result
|
||||||
|
_out.exeOut := alu.out.eq
|
||||||
|
|
||||||
|
_toIF.jAddr := alu.out.result
|
||||||
|
_toIF.brAddr := _in.inst.immB
|
||||||
|
|
||||||
|
import flow.components.newPcControlInterface.SrcSelect._
|
||||||
|
when(_in.pcCtrl.srcSelect === pBR) {
|
||||||
|
val branchUseSlt = _in.inst(14)
|
||||||
|
val branchInvertResult = _in.inst(12)
|
||||||
|
val _branchResult = Mux(branchUseSlt, alu.out.result(0), alu.out.eq)
|
||||||
|
val branchResult = Mux(branchInvertResult, !_branchResult, _branchResult)
|
||||||
|
_toIF.pcCtrl.srcSelect := Mux(branchInvertResult, 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
|
||||||
|
}
|
62
npc/core/src/main/scala/stages/ID.scala
Normal file
62
npc/core/src/main/scala/stages/ID.scala
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
46
npc/core/src/main/scala/stages/IF.scala
Normal file
46
npc/core/src/main/scala/stages/IF.scala
Normal 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.brAddr := _fromEx.brAddr
|
||||||
|
pc.in.jAddr := _fromEx.jAddr
|
||||||
|
|
||||||
|
pc.control := _fromEx.pcCtrl
|
||||||
|
|
||||||
|
// Instruction fetch
|
||||||
|
_toRam.pc := pc.out
|
||||||
|
_out.inst := _fromRam.inst
|
||||||
|
_out.pc := pc.out
|
||||||
|
}
|
51
npc/core/src/main/scala/stages/LS.scala
Normal file
51
npc/core/src/main/scala/stages/LS.scala
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
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.src1
|
||||||
|
ram.io.writeMask := _in.ramCtrl.writeMask
|
||||||
|
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.pc
|
||||||
|
|
||||||
|
_out.memOut := ram.io.readData
|
||||||
|
_out.exeOut := _in.exeOut
|
||||||
|
|
||||||
|
// passthrough
|
||||||
|
_out.regCtrl := _in.regCtrl
|
||||||
|
_out.rd := _in.rd
|
||||||
|
_out.pc := _in.pc
|
||||||
|
}
|
73
npc/core/src/main/scala/stages/Messages.scala
Normal file
73
npc/core/src/main/scala/stages/Messages.scala
Normal 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)
|
||||||
|
val exeEq = Bool()
|
||||||
|
|
||||||
|
// 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 brAddr = 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)
|
||||||
|
}
|
28
npc/core/src/main/scala/stages/WB.scala
Normal file
28
npc/core/src/main/scala/stages/WB.scala
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package flow.stages
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util.Decoupled
|
||||||
|
import chisel3.util.DecoupledIO
|
||||||
|
import flow.Params
|
||||||
|
import flow.stages.utils._
|
||||||
|
import flow.stages.messages._
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
|
@ -18,6 +18,11 @@ import io.circe.generic.JsonCodec
|
||||||
import chisel3._
|
import chisel3._
|
||||||
case class Params(
|
case class Params(
|
||||||
XLEN: Width,
|
XLEN: Width,
|
||||||
|
instWidth: Width = 32.W,
|
||||||
|
regsCount: Int = 32,
|
||||||
|
regsAddrWidth: Width = 5.W,
|
||||||
|
regsResetValue: BigInt = 0L,
|
||||||
arch: String,
|
arch: String,
|
||||||
csrAddrWidth: Width = 12.W
|
csrAddrWidth: Width = 12.W,
|
||||||
|
resetVector: BigInt = BigInt(0x80000000L)
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,451 +16,472 @@ import shapeless.Poly1
|
||||||
import flow.components.RamControlInterface
|
import flow.components.RamControlInterface
|
||||||
import flow.components.RV32Inst
|
import flow.components.RV32Inst
|
||||||
import flow.components.RV32InstSubfields._
|
import flow.components.RV32InstSubfields._
|
||||||
|
import flow.components.util._
|
||||||
|
|
||||||
import flow.components.{RegControl, PcControlInterface, ALUControlInterface}
|
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._
|
||||||
|
|
||||||
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)))
|
|
||||||
|
|
||||||
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 {
|
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)
|
IF.io.fromRam := LS.io.toIF
|
||||||
val ram = Module(new RamDpi)
|
IF.io.fromEx := EX.io.toIF
|
||||||
val control = Module(new Control(32))
|
LS.io.fromIF := IF.io.toRam
|
||||||
val reg = Module(new RegisterFile(dataType, 32, 2))
|
ID.io.fromWB := WB.io.toID
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)))
|
||||||
|
//
|
||||||
|
// val reg = IO(Flipped(RegControl()))
|
||||||
|
// val pc = IO(Flipped(PcControlInterface()))
|
||||||
|
// val alu = IO(Flipped(ALUControlInterface()))
|
||||||
|
// val ram = IO(Flipped(RamControlInterface(32)))
|
||||||
|
//
|
||||||
|
// 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(controWidth.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)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class Flow extends Module {
|
||||||
|
// def lit(x: Data) = { x.litValue.toInt }
|
||||||
|
//
|
||||||
|
// 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(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(rMemOut) := maskedData
|
||||||
|
// // printf(cf"!doSignExt\n")
|
||||||
|
// }.elsewhen(signExt16) {
|
||||||
|
// reg.in.writeData(rMemOut) := Cat(
|
||||||
|
// Fill(16, maskedData(15)),
|
||||||
|
// maskedData(15, 0)
|
||||||
|
// )
|
||||||
|
// // printf(cf"elsewhen\n")
|
||||||
|
// }.otherwise {
|
||||||
|
// reg.in
|
||||||
|
// .writeData(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(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(aSrcARs1) := reg.out.src(0)
|
||||||
|
// alu.in.a(aSrcAPc) := pc.out
|
||||||
|
// alu.in.a(aSrcAZero) := 0.U
|
||||||
|
//
|
||||||
|
// alu.in.b(aSrcBRs2) := reg.out.src(1)
|
||||||
|
// // alu.in.b(lit(aSrcBImmI)) := inst(31, 20).pad(aSrcBImmI.getWidth)
|
||||||
|
// alu.in.b(aSrcBImmI) := inst.immI
|
||||||
|
// alu.in.b(aSrcBImmJ) := inst.immJ
|
||||||
|
// alu.in.b(aSrcBImmS) := inst.immS
|
||||||
|
// alu.in.b(aSrcBImmU) := inst.immU
|
||||||
|
//
|
||||||
|
// Trace.traceName(pc.out)
|
||||||
|
// dontTouch(control.out)
|
||||||
|
// }
|
||||||
|
|
|
@ -7,7 +7,6 @@ import chisel3.experimental.Trace._
|
||||||
import chisel3.stage.{ChiselGeneratorAnnotation, DesignAnnotation}
|
import chisel3.stage.{ChiselGeneratorAnnotation, DesignAnnotation}
|
||||||
import chisel3.util.experimental.InlineInstance
|
import chisel3.util.experimental.InlineInstance
|
||||||
import circt.stage.ChiselStage
|
import circt.stage.ChiselStage
|
||||||
import firrtl.AnnotationSeq
|
|
||||||
import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
|
import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
|
@ -10,50 +10,51 @@ import flow.tests.defaultParams
|
||||||
|
|
||||||
class CSRSpec extends AnyFreeSpec with ChiselScalatestTester {
|
class CSRSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||||
implicit val p: flow.Params = defaultParams()
|
implicit val p: flow.Params = defaultParams()
|
||||||
"should compile" in {
|
// import flow.components.CSRControlInterface
|
||||||
test(new CSRCore) { c =>
|
// "should compile" in {
|
||||||
c.clock.step(1)
|
// test(new CSRCore) { c =>
|
||||||
}
|
// c.clock.step(1)
|
||||||
}
|
// }
|
||||||
"Write" - {
|
// }
|
||||||
"delayed" in {
|
// "Write" - {
|
||||||
test(new CSRCore) { c =>
|
// "delayed" in {
|
||||||
val tv = BigInt("deadbeef", 16)
|
// test(new CSRCore) { c =>
|
||||||
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
// val tv = BigInt("deadbeef", 16)
|
||||||
c.in.writeData.poke(tv)
|
// c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
||||||
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
|
// c.in.writeData.poke(tv)
|
||||||
c.clock.step(1)
|
// c.control.writeEnable.poke(CSRControlInterface.csrWrite.csrWriteData)
|
||||||
|
// c.clock.step(1)
|
||||||
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
|
//
|
||||||
c.out.readData.expect(0)
|
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadEnabled)
|
||||||
c.out.readValid.expect(1)
|
// c.out.readData.expect(0)
|
||||||
|
// c.out.readValid.expect(1)
|
||||||
c.clock.step(1)
|
//
|
||||||
c.out.readValid.expect(1)
|
// c.clock.step(1)
|
||||||
c.out.readData.expect(tv)
|
// c.out.readValid.expect(1)
|
||||||
}
|
// c.out.readData.expect(tv)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
"Read" - {
|
//
|
||||||
"controlled by readEnable" in {
|
// "Read" - {
|
||||||
test(new CSRCore) { c =>
|
// "controlled by readEnable" in {
|
||||||
val tv = BigInt("deadbeef", 16)
|
// test(new CSRCore) { c =>
|
||||||
c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
// val tv = BigInt("deadbeef", 16)
|
||||||
c.in.writeData.poke(tv)
|
// c.in.csrAddr.poke(c.nameToAddr("mstatus"))
|
||||||
c.control.readEnable.poke(c.control.csrRead.csrReadEnabled)
|
// c.in.writeData.poke(tv)
|
||||||
c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled)
|
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadEnabled)
|
||||||
c.clock.step(1)
|
// c.control.writeEnable.poke(CSRControlInterface.csrWrite.csrWriteData)
|
||||||
|
// c.clock.step(1)
|
||||||
c.control.readEnable.poke(c.control.csrRead.csrReadDisabled)
|
//
|
||||||
c.out.readData.expect(0)
|
// c.control.readEnable.poke(CSRControlInterface.csrRead.csrReadDisabled)
|
||||||
c.out.readValid.expect(0)
|
// c.out.readData.expect(0)
|
||||||
|
// c.out.readValid.expect(0)
|
||||||
c.clock.step(1)
|
//
|
||||||
c.out.readData.expect(0)
|
// c.clock.step(1)
|
||||||
c.out.readValid.expect(0)
|
// c.out.readData.expect(0)
|
||||||
}
|
// c.out.readValid.expect(0)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,44 +4,28 @@ import chisel3._
|
||||||
import chiseltest._
|
import chiseltest._
|
||||||
import org.scalatest.freespec.AnyFreeSpec
|
import org.scalatest.freespec.AnyFreeSpec
|
||||||
import chiseltest.simulator.WriteVcdAnnotation
|
import chiseltest.simulator.WriteVcdAnnotation
|
||||||
|
import flow.stages._
|
||||||
|
import flow.Params
|
||||||
|
|
||||||
import flow.Flow
|
import flow.Flow
|
||||||
|
import flow.tests.defaultParams
|
||||||
|
import flow.stages.messages._
|
||||||
|
|
||||||
class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester {
|
class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||||
"MemoryFile" - {
|
"IF" - {
|
||||||
"correctly load" in {
|
implicit val p: Params = defaultParams()
|
||||||
import chisel3.util.{SRAM, SRAMInterface, HexMemoryFile}
|
class TestIF extends Module {
|
||||||
class UserMem extends Module {
|
val IF = Module(new IF)
|
||||||
val io = IO(new SRAMInterface(1024, UInt(32.W), 1, 1, 0))
|
val io = IO(new Bundle {
|
||||||
val memoryFile = HexMemoryFile("../resource/addi.txt")
|
val out = Output(new IF2ID)
|
||||||
io :<>= SRAM(
|
})
|
||||||
size = 1024,
|
io.out := IF.msgio.out
|
||||||
tpe = UInt(32.W),
|
IF.msgio.out.ready := DontCare
|
||||||
numReadPorts = 1,
|
IF.io.fromRam := DontCare
|
||||||
numWritePorts = 1,
|
IF.io.fromEx := DontCare
|
||||||
numReadwritePorts = 0,
|
}
|
||||||
memoryFile = memoryFile
|
"should compile" in {
|
||||||
)
|
test(new TestIF) { c => }
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"should compile" in {
|
|
||||||
test(new Flow) { c =>
|
|
||||||
c.clock.step(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
24
npc/core/src/test/scala/ProgramCounter.scala
Normal file
24
npc/core/src/test/scala/ProgramCounter.scala
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,81 +1,81 @@
|
||||||
package flow
|
// package flow
|
||||||
|
|
||||||
import chisel3._
|
// import chisel3._
|
||||||
import chiseltest._
|
// import chiseltest._
|
||||||
import org.scalatest.freespec.AnyFreeSpec
|
// import org.scalatest.freespec.AnyFreeSpec
|
||||||
import chiseltest.simulator.WriteVcdAnnotation
|
// import chiseltest.simulator.WriteVcdAnnotation
|
||||||
|
|
||||||
import flow.components._
|
// import flow.components._
|
||||||
class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester {
|
// class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester {
|
||||||
"RegisterFileCore" - {
|
// "RegisterFileCore" - {
|
||||||
"register 0 is always 0" in {
|
// "register 0 is always 0" in {
|
||||||
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
// test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
||||||
c.readPorts(0).addr.poke(0)
|
// c.readPorts(0).addr.poke(0)
|
||||||
c.readPorts(1).addr.poke(0)
|
// c.readPorts(1).addr.poke(0)
|
||||||
c.writePort.enable.poke(true)
|
// c.writePort.enable.poke(true)
|
||||||
c.writePort.addr.poke(0)
|
// c.writePort.addr.poke(0)
|
||||||
c.writePort.data.poke(0x1234)
|
// c.writePort.data.poke(0x1234)
|
||||||
|
|
||||||
c.readPorts(0).data.expect(0)
|
// c.readPorts(0).data.expect(0)
|
||||||
c.readPorts(1).data.expect(0)
|
// c.readPorts(1).data.expect(0)
|
||||||
c.clock.step(2)
|
// c.clock.step(2)
|
||||||
c.readPorts(0).data.expect(0)
|
// c.readPorts(0).data.expect(0)
|
||||||
c.readPorts(1).data.expect(0)
|
// c.readPorts(1).data.expect(0)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"register other than 0 can be written" in {
|
// "register other than 0 can be written" in {
|
||||||
test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
// test(new RegisterFileCore(32, UInt(32.W), 2)) { c =>
|
||||||
import scala.util.Random
|
// import scala.util.Random
|
||||||
val r = new Random()
|
// val r = new Random()
|
||||||
for (i <- 1 until 32) {
|
// for (i <- 1 until 32) {
|
||||||
val v = r.nextLong() & 0xFFFFFFFFL
|
// val v = r.nextLong() & 0xFFFFFFFFL
|
||||||
c.readPorts(0).addr.poke(i)
|
// c.readPorts(0).addr.poke(i)
|
||||||
c.writePort.enable.poke(true)
|
// c.writePort.enable.poke(true)
|
||||||
c.writePort.addr.poke(i)
|
// c.writePort.addr.poke(i)
|
||||||
c.writePort.data.poke(v)
|
// c.writePort.data.poke(v)
|
||||||
|
|
||||||
c.clock.step(1)
|
// c.clock.step(1)
|
||||||
c.readPorts(0).data.expect(v)
|
// c.readPorts(0).data.expect(v)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"RegisterInterface" - {
|
// "RegisterInterface" - {
|
||||||
class Top extends Module {
|
// class Top extends Module {
|
||||||
val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2))
|
// val io = IO(new RegFileInterface(32, UInt(32.W), 2, 2))
|
||||||
val rf = RegisterFile(32, UInt(32.W), 2, 2)
|
// val rf = RegisterFile(32, UInt(32.W), 2, 2)
|
||||||
io :<>= rf
|
// io :<>= rf
|
||||||
}
|
// }
|
||||||
"write" in {
|
// "write" in {
|
||||||
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
// test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||||
import c.io.control.WriteSelect._
|
// import c.io.control.WriteSelect._
|
||||||
val writePort = rAluOut.litValue.toInt
|
// val writePort = rAluOut.litValue.toInt
|
||||||
c.io.control.writeEnable.poke(true)
|
// c.io.control.writeEnable.poke(true)
|
||||||
c.io.control.writeSelect.poke(rAluOut)
|
// c.io.control.writeSelect.poke(rAluOut)
|
||||||
c.io.in.writeAddr.poke(5)
|
// c.io.in.writeAddr.poke(5)
|
||||||
c.io.in.writeData(writePort).poke(0xcdef)
|
// c.io.in.writeData(writePort).poke(0xcdef)
|
||||||
c.io.in.rs(0).poke(5)
|
// c.io.in.rs(0).poke(5)
|
||||||
c.clock.step(1)
|
// c.clock.step(1)
|
||||||
c.io.out.src(0).expect(0xcdef)
|
// c.io.out.src(0).expect(0xcdef)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
"no data is written when not enabled" in {
|
// "no data is written when not enabled" in {
|
||||||
test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
// test(new Top).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
|
||||||
import c.io.control.WriteSelect._
|
// import c.io.control.WriteSelect._
|
||||||
val writePort = rAluOut.litValue.toInt
|
// val writePort = rAluOut.litValue.toInt
|
||||||
c.io.control.writeEnable.poke(true)
|
// c.io.control.writeEnable.poke(true)
|
||||||
c.io.control.writeSelect.poke(rAluOut)
|
// c.io.control.writeSelect.poke(rAluOut)
|
||||||
c.io.in.writeAddr.poke(5)
|
// c.io.in.writeAddr.poke(5)
|
||||||
c.io.in.writeData(writePort).poke(0xcdef)
|
// c.io.in.writeData(writePort).poke(0xcdef)
|
||||||
c.io.in.rs(0).poke(5)
|
// c.io.in.rs(0).poke(5)
|
||||||
c.clock.step(1)
|
// c.clock.step(1)
|
||||||
|
|
||||||
c.io.control.writeEnable.poke(false)
|
// c.io.control.writeEnable.poke(false)
|
||||||
c.io.in.writeData(writePort).poke(0x1234)
|
// c.io.in.writeData(writePort).poke(0x1234)
|
||||||
c.clock.step(1)
|
// c.clock.step(1)
|
||||||
|
|
||||||
c.io.out.src(0).expect(0xcdef)
|
// c.io.out.src(0).expect(0xcdef)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
70
npc/core/src/test/scala/StageConnect.scala
Normal file
70
npc/core/src/test/scala/StageConnect.scala
Normal 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,5 +4,5 @@ import chisel3._
|
||||||
import flow.Params
|
import flow.Params
|
||||||
|
|
||||||
object defaultParams {
|
object defaultParams {
|
||||||
def apply(): Params = new Params(XLEN = 32.W)
|
def apply(): Params = new Params(XLEN = 32.W, arch = "single")
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,5 +37,28 @@
|
||||||
inherit flow;
|
inherit flow;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
cmake
|
||||||
|
ninja
|
||||||
|
flex
|
||||||
|
bison
|
||||||
|
nvboard
|
||||||
|
verilator
|
||||||
|
flow
|
||||||
|
espresso
|
||||||
|
bloop
|
||||||
|
coursier
|
||||||
|
sbt
|
||||||
|
];
|
||||||
|
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
cli11
|
||||||
|
spdlog
|
||||||
|
mini-gdbstub
|
||||||
|
];
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ public:
|
||||||
Memory(std::filesystem::path filepath, bool is_binary, paddr_t pmem_start,
|
Memory(std::filesystem::path filepath, bool is_binary, paddr_t pmem_start,
|
||||||
paddr_t pmem_end)
|
paddr_t pmem_end)
|
||||||
: pmem_start(pmem_start), pmem_end(pmem_end) {
|
: pmem_start(pmem_start), pmem_end(pmem_end) {
|
||||||
read_memory(filepath, is_binary);
|
if (!filepath.empty()) {
|
||||||
|
read_memory(filepath, is_binary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const word_t &operator[](std::size_t addr) { return this->read(addr); }
|
const word_t &operator[](std::size_t addr) { return this->read(addr); }
|
||||||
|
|
Loading…
Add table
Reference in a new issue