未验证 提交 ee2a1c39 编写于 作者: L ljw 提交者: GitHub

Merge pull request #220 from RISCVERS/xs-fpu

Remove all 'BoringUtils'
#!/bin/bash
echo $1
echo $2
grep -rn $1 $2/src/main/scala/xiangshan
if [[ $? == 0 ]];
then
exit 1
fi
exit 0
......@@ -3,7 +3,7 @@ name: EMU Test
on:
push:
branches: [ master, update-ci ]
branches: [ master, update-ci]
pull_request:
branches: [ master ]
......@@ -15,6 +15,8 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Check Wiring
run: bash .github/workflows/check-usage.sh "BoringUtils" $GITHUB_WORKSPACE
- name: Set env
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
......@@ -70,7 +72,7 @@ jobs:
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run 2> /dev/null
riscv-tests:
runs-on: self-hosted
......@@ -87,5 +89,5 @@ jobs:
echo $NEMU_HOME
echo $NOOP_HOME
echo $RVTEST_HOME
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run 2> /dev/null
......@@ -57,7 +57,7 @@ EMU_CXXFLAGS += -DVERILATOR -Wno-maybe-uninitialized
EMU_LDFLAGS = -lpthread -lSDL2 -ldl
EMU_THREADS = 1
ifeq ($(EMU_THREADS), 1)
VTHREAD_FLAGS =
VTHREAD_FLAGS = --threads 1
else
VTHREAD_FLAGS = --threads $(EMU_THREADS) --threads-dpi none
endif
......@@ -69,8 +69,8 @@ VERILATOR_FLAGS = --top-module $(SIM_TOP) \
+define+RANDOMIZE_REG_INIT \
+define+RANDOMIZE_MEM_INIT \
$(VTHREAD_FLAGS) \
--assert \
--trace \
--assert \
--savable \
--stats-vars \
--output-split 5000 \
......
......@@ -48,7 +48,7 @@ microbench_train:
cat microbench.log | grep IPC
coremark:
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run
#2 > coremark.log
cat coremark.log | grep IPC
......
此差异已折叠。
/**************************************************************************************
* Copyright (c) 2020 Institute of Computing Technology, CAS
* Copyright (c) 2020 University of Chinese Academy of Sciences
*
* NutShell is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
* FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
package bus.simplebus
import chisel3._
import chisel3.util._
import utils._
class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module {
val io = IO(new Bundle {
val in = Flipped(new SimpleBusUC)
val out = Vec(addressSpace.length, new SimpleBusUC)
})
val s_idle :: s_resp :: s_error :: Nil = Enum(3)
val state = RegInit(s_idle)
// select the output channel according to the address
val addr = io.in.req.bits.addr
val outSelVec = VecInit(addressSpace.map(
range => (addr >= range._1.U && addr < (range._1 + range._2).U)))
val outSelIdx = PriorityEncoder(outSelVec)
val outSel = io.out(outSelIdx)
val outSelIdxResp = RegEnable(outSelIdx, outSel.req.fire() && (state === s_idle))
val outSelResp = io.out(outSelIdxResp)
val reqInvalidAddr = io.in.req.valid && !outSelVec.asUInt.orR
when(!(!io.in.req.valid || outSelVec.asUInt.orR) || !(!(io.in.req.valid && outSelVec.asUInt.andR))){printf("[ERROR] bad addr %x, time %d\n", addr, GTimer())}
// assert(!io.in.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr)
assert(!(io.in.req.valid && outSelVec.asUInt.andR), "address decode error, bad addr = 0x%x\n", addr)
// bind out.req channel
(io.out zip outSelVec).map { case (o, v) => {
o.req.bits := io.in.req.bits
o.req.valid := v && (io.in.req.valid && (state === s_idle))
o.resp.ready := v
}}
switch (state) {
is (s_idle) {
when (outSel.req.fire()) { state := s_resp }
when (reqInvalidAddr) { state := s_error }
}
is (s_resp) { when (outSelResp.resp.fire()) { state := s_idle } }
is (s_error) { when(io.in.resp.fire()){ state := s_idle } }
}
io.in.resp.valid := outSelResp.resp.fire() || state === s_error
io.in.resp.bits <> outSelResp.resp.bits
// io.in.resp.bits.exc.get := state === s_error
outSelResp.resp.ready := io.in.resp.ready
io.in.req.ready := outSel.req.ready || reqInvalidAddr
Debug() {
when (state === s_idle && io.in.req.valid) {
printf(p"${GTimer()}: xbar: in.req: ${io.in.req.bits}\n")
}
when (outSel.req.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx = ${outSelIdx}, outSel.req: ${outSel.req.bits}\n")
}
when (outSel.resp.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx= ${outSelIdx}, outSel.resp: ${outSel.resp.bits}\n")
}
when (io.in.resp.fire()) {
printf(p"${GTimer()}: xbar: in.resp: ${io.in.resp.bits}\n")
}
}
}
class SimpleBusCrossbarNto1(n: Int, userBits:Int = 0) extends Module {
val io = IO(new Bundle {
val in = Flipped(Vec(n, new SimpleBusUC(userBits)))
val out = new SimpleBusUC(userBits)
})
val s_idle :: s_readResp :: s_writeResp :: Nil = Enum(3)
val state = RegInit(s_idle)
val lockWriteFun = ((x: SimpleBusReqBundle) => x.isWrite() && x.isBurst())
val inputArb = Module(new LockingArbiter(chiselTypeOf(io.in(0).req.bits), n, 8, Some(lockWriteFun)))
(inputArb.io.in zip io.in.map(_.req)).map{ case (arb, in) => arb <> in }
val thisReq = inputArb.io.out
assert(!(thisReq.valid && !thisReq.bits.isRead() && !thisReq.bits.isWrite()))
val inflightSrc = Reg(UInt(log2Up(n).W))
io.out.req.bits := thisReq.bits
// bind correct valid and ready signals
io.out.req.valid := thisReq.valid && (state === s_idle)
thisReq.ready := io.out.req.ready && (state === s_idle)
io.in.map(_.resp.bits := io.out.resp.bits)
io.in.map(_.resp.valid := false.B)
(io.in(inflightSrc).resp, io.out.resp) match { case (l, r) => {
l.valid := r.valid
r.ready := l.ready
}}
switch (state) {
is (s_idle) {
when (thisReq.fire()) {
inflightSrc := inputArb.io.chosen
when (thisReq.bits.isRead()) { state := s_readResp }
.elsewhen (thisReq.bits.isWriteLast() || thisReq.bits.isWriteSingle()) { state := s_writeResp }
}
}
is (s_readResp) { when (io.out.resp.fire() && io.out.resp.bits.isReadLast()) { state := s_idle } }
is (s_writeResp) { when (io.out.resp.fire()) { state := s_idle } }
}
}
class SimpleBusCrossbar(n: Int, addressSpace: List[(Long, Long)]) extends Module {
val io = IO(new Bundle {
val in = Flipped(Vec(n, new SimpleBusUC))
val out = Vec(addressSpace.length, new SimpleBusUC)
})
val inXbar = Module(new SimpleBusCrossbarNto1(n))
val outXbar = Module(new SimpleBusCrossbar1toN(addressSpace))
inXbar.io.in <> io.in
outXbar.io.in <> inXbar.io.out
io.out <> outXbar.io.out
}
package bus.simplebus
import chisel3._
import chisel3.util._
import chisel3.util.experimental.loadMemoryFromFile
import noop.HasNOOPParameter
class DistributedMem(memByte: Int, dualPort: Boolean, delayCycles: Int = 0, dataFile: String = "")
extends Module with HasNOOPParameter {
val io = IO(new Bundle {
val rw = Flipped(new SimpleBusUC)
val ro = Flipped(new SimpleBusUC)
})
val wordNum = memByte / 8
val nBank = XLEN / 8
val memAddrBits = log2Up(wordNum)
def Index(addr: UInt): UInt = addr(memAddrBits + 2 - 1, 2)
val rwIdx = Index(io.rw.req.bits.addr)
val roIdx = Index(io.ro.req.bits.addr)
val wen = io.rw.isWrite()
val wdataVec = VecInit.tabulate(nBank) { i => io.rw.req.bits.wdata(8 * (i + 1) - 1, 8 * i) }
val wmask = VecInit.tabulate(nBank) { i => io.rw.req.bits.wmask(i).asBool() }
val rwData = Wire(UInt(XLEN.W))
val roData = Wire(UInt(XLEN.W))
val mem = Mem(wordNum, Vec(nBank, UInt(8.W)))
if (dataFile != "")
loadMemoryFromFile(mem, dataFile)
rwData := Cat(mem.read(rwIdx).reverse)
roData := Cat(mem.read(roIdx).reverse)
when (wen) { mem.write(rwIdx, wdataVec, wmask) }
def readPort(p: SimpleBusUC, rdata: UInt) = {
val s_idle :: s_reading :: Nil = Enum(2)
val state = RegInit(s_idle)
switch (state) {
is (s_idle) {
when (p.req.fire()) { state := Mux(p.resp.fire(), s_idle, s_reading) }
}
is (s_reading) {
when (p.resp.fire()) { state := s_idle }
}
}
p.req.ready := state === s_idle
p.resp.bits.rdata := rdata
p.resp.valid := (if (delayCycles == 0) p.req.fire() else Counter(state === s_reading, delayCycles)._2)
}
readPort(io.rw, rwData)
if (dualPort) {
readPort(io.ro, roData)
}
else {
io.ro := DontCare
}
}
package bus.simplebus
import chisel3._
import chisel3.util._
import noop.HasNOOPParameter
import utils._
import bus.axi4._
sealed abstract class SimpleBusBundle extends Bundle with HasNOOPParameter
object SimpleBusCmd {
// req
// hit | miss
def read = "b0000".U // read | refill
def write = "b0001".U // write | refill
def readBurst = "b0010".U // read | refill
def writeBurst = "b0011".U // write | refill
def writeLast = "b0111".U // write | refill
def probe = "b1000".U // read | do nothing
def prefetch = "b0100".U // read | refill
// resp
def readLast = "b0110".U
def writeResp = "b0101".U
def probeHit = "b1100".U
def probeMiss = "b1000".U
def apply() = UInt(4.W)
}
class SimpleBusReqBundle(val userBits: Int = 0, val addrBits: Int = 32) extends SimpleBusBundle {
val addr = Output(UInt(addrBits.W))
val size = Output(UInt(3.W))
val cmd = Output(SimpleBusCmd())
val wmask = Output(UInt((DataBits / 8).W))
val wdata = Output(UInt(DataBits.W))
val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None
override def toPrintable: Printable = {
p"addr = 0x${Hexadecimal(addr)}, cmd = ${cmd}, size = ${size}, " +
p"wmask = 0x${Hexadecimal(wmask)}, wdata = 0x${Hexadecimal(wdata)}"
}
def apply(addr: UInt, cmd: UInt, size: UInt, wdata: UInt, wmask: UInt, user: UInt = 0.U) {
this.addr := addr
this.cmd := cmd
this.size := size
this.wdata := wdata
this.wmask := wmask
this.user.map(_ := user)
}
def isRead() = !cmd(0) && !cmd(3)
def isWrite() = cmd(0)
def isBurst() = cmd(1)
def isReadBurst() = cmd === SimpleBusCmd.readBurst
def isWriteSingle() = cmd === SimpleBusCmd.write
def isWriteLast() = cmd === SimpleBusCmd.writeLast
def isProbe() = cmd === SimpleBusCmd.probe
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
class SimpleBusRespBundle(val userBits: Int = 0) extends SimpleBusBundle {
val cmd = Output(SimpleBusCmd())
val rdata = Output(UInt(DataBits.W))
val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None
override def toPrintable: Printable = p"rdata = ${Hexadecimal(rdata)}, cmd = ${cmd}"
def isReadLast() = cmd === SimpleBusCmd.readLast
def isProbeHit() = cmd === SimpleBusCmd.probeHit
def isProbeMiss() = cmd === SimpleBusCmd.probeMiss
def isWriteResp() = cmd === SimpleBusCmd.writeResp
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
// Uncache
class SimpleBusUC(val userBits: Int = 0, val addrBits: Int = 32) extends SimpleBusBundle {
val req = Decoupled(new SimpleBusReqBundle(userBits, addrBits))
val resp = Flipped(Decoupled(new SimpleBusRespBundle(userBits)))
def isWrite() = req.valid && req.bits.isWrite()
def isRead() = req.valid && req.bits.isRead()
def toAXI4Lite() = SimpleBus2AXI4Converter(this, new AXI4Lite)
def toAXI4() = SimpleBus2AXI4Converter(this, new AXI4)
def dump(name: String) = {
when (req.fire()) { printf(p"${GTimer()},[${name}] ${req.bits}\n") }
when (resp.fire()) { printf(p"${GTimer()},[${name}] ${resp.bits}\n") }
}
}
// Cache
class SimpleBusC(val userBits: Int = 0) extends SimpleBusBundle {
val mem = new SimpleBusUC(userBits)
val coh = Flipped(new SimpleBusUC(userBits))
def memtoAXI4() = this.mem.toAXI4
}
package bus.simplebus
import chisel3._
import chisel3.util._
import bus.axi4._
import utils._
class AXI42SimpleBusConverter() extends Module {
val io = IO(new Bundle {
val in = Flipped(new AXI4(idBits = 18))
val out = new SimpleBusUC()
})
val (axi, mem) = (io.in, io.out)
val (ar, aw, w, r, b) = (axi.ar.bits, axi.aw.bits, axi.w.bits, axi.r.bits, axi.b.bits)
val (req, resp) = (mem.req.bits, mem.resp.bits)
// Default value
val inflight_id_reg = RegInit(0.U)
val axi_na :: axi_read :: axi_write :: Nil = Enum(3)
val inflight_type = RegInit(axi_na)
private def setState(axi_type: UInt, id: UInt) = {
inflight_id_reg := id
inflight_type := axi_type;
}
private def resetState() = {
inflight_type := axi_na
inflight_id_reg := 0.U
}
private def is_inflight() = {
inflight_type =/= axi_na
}
// Default
val default_mem = 0.U.asTypeOf(new SimpleBusUC)
val default_axi = 0.U.asTypeOf(new AXI4)
req := default_mem.req.bits
r := default_axi.r.bits
b := default_axi.b.bits
// Read Path
when (axi.ar.valid) {
mem.req.valid := true.B
req.addr := ar.addr
req.cmd := Mux(ar.len === 0.U, SimpleBusCmd.read, SimpleBusCmd.readBurst)
// TODO: consider ar.burst
req.size := ar.size
req.user.foreach(_ := ar.user)
req.wmask := 0.U
req.wdata := 0.U
when (mem.req.fire) {
setState(axi_read, ar.id)
}
}
when (mem.resp.valid) {
axi.r.valid := true.B
r.data := resp.rdata
r.id := inflight_id_reg
// TODO: r.resp handling
r.resp := AXI4Parameters.RESP_OKAY
r.last := resp.isReadLast
resp.user.foreach(r.user := _)
when (axi.r.fire && resp.isReadLast) {
resetState()
}
}
// Write Path
val aw_reg = Reg(new AXI4BundleA(AXI4Parameters.idBits))
val bresp_en = RegInit(false.B)
when (axi.aw.valid && !axi.ar.valid) {
aw_reg := aw
when (axi.aw.fire) {
setState(axi_write, aw.id)
}
}
when (axi.w.valid) {
mem.req.valid := true.B
req.cmd := Mux(aw_reg.len === 0.U, SimpleBusCmd.write,
Mux(w.last, SimpleBusCmd.writeLast, SimpleBusCmd.writeBurst))
req.addr := aw_reg.addr
req.size := aw_reg.size
req.wmask := w.strb
req.wdata := w.data
req.user.foreach(_ := aw.user)
when (axi.w.fire && w.last) {
bresp_en := true.B
}
}
when (axi.b.fire) {
bresp_en := false.B
resetState()
}
// Arbitration
// Slave's ready maybe generated according to valid signal, so let valid signals go through.
mem.req.valid := axi.ar.valid || axi.w.valid
mem.resp.ready := true.B || (inflight_type === axi_read && axi.r.ready) || (inflight_type === axi_write && axi.b.ready)
axi.ar.ready := !is_inflight && mem.req.ready
axi.r.valid := inflight_type === axi_read && mem.resp.valid
// AW should be buffered so no ready is considered.
axi.aw.ready := !is_inflight && !axi.ar.valid
axi.w.ready := inflight_type === axi_write && mem.req.ready
axi.b.valid := bresp_en && mem.resp.valid
axi.b.bits.resp := AXI4Parameters.RESP_OKAY
}
class SimpleBus2AXI4Converter[OT <: AXI4Lite](outType: OT) extends Module {
val io = IO(new Bundle {
val in = Flipped(new SimpleBusUC)
val out = Flipped(Flipped(outType))
})
val toAXI4Lite = !(io.in.req.valid && io.in.req.bits.isBurst()) && (outType.getClass == classOf[AXI4Lite]).B
val toAXI4 = (outType.getClass == classOf[AXI4]).B
assert(toAXI4Lite || toAXI4)
val (mem, axi) = (io.in, io.out)
val (ar, aw, w, r, b) = (axi.ar.bits, axi.aw.bits, axi.w.bits, axi.r.bits, axi.b.bits)
ar.addr := mem.req.bits.addr
ar.prot := AXI4Parameters.PROT_PRIVILEDGED
w.data := mem.req.bits.wdata
w.strb := mem.req.bits.wmask
def LineBeats = 8
val wlast = WireInit(true.B)
val rlast = WireInit(true.B)
if (outType.getClass == classOf[AXI4]) {
val axi4 = io.out.asInstanceOf[AXI4]
axi4.ar.bits.id := 0.U
axi4.ar.bits.len := Mux(mem.req.bits.isBurst(), (LineBeats - 1).U, 0.U)
axi4.ar.bits.size := mem.req.bits.size
axi4.ar.bits.burst := AXI4Parameters.BURST_WRAP
axi4.ar.bits.lock := false.B
axi4.ar.bits.cache := 0.U
axi4.ar.bits.qos := 0.U
axi4.ar.bits.user := 0.U
axi4.w.bits.last := mem.req.bits.isWriteLast() || mem.req.bits.isWriteSingle()
wlast := axi4.w.bits.last
rlast := axi4.r.bits.last
}
aw := ar
mem.resp.bits.rdata := r.data
mem.resp.bits.cmd := Mux(rlast, SimpleBusCmd.readLast, 0.U)
val wSend = Wire(Bool())
val awAck = BoolStopWatch(axi.aw.fire(), wSend)
val wAck = BoolStopWatch(axi.w.fire() && wlast, wSend)
wSend := (axi.aw.fire() && axi.w.fire() && wlast) || (awAck && wAck)
val wen = RegEnable(mem.req.bits.isWrite(), mem.req.fire())
axi.ar.valid := mem.isRead()
axi.aw.valid := mem.isWrite() && !awAck
axi.w .valid := mem.isWrite() && !wAck
mem.req.ready := Mux(mem.req.bits.isWrite(), !wAck && axi.w.ready, axi.ar.ready)
axi.r.ready := mem.resp.ready
axi.b.ready := mem.resp.ready
mem.resp.valid := Mux(wen, axi.b.valid, axi.r.valid)
}
object SimpleBus2AXI4Converter {
def apply[OT <: AXI4Lite](in: SimpleBusUC, outType: OT): OT = {
val bridge = Module(new SimpleBus2AXI4Converter(outType))
bridge.io.in <> in
bridge.io.out
}
}
package bus.tilelink
import chisel3._
import chisel3.util._
import utils.{Debug, GTimer}
// Only support A and D channel, very naive...
class NaiveTL1toN
(
addressSpace: List[(Long, Long)],
para: TLParameters
) extends Module{
val io = IO(new Bundle() {
val in = Flipped(TLCached(para))
val out = Vec(addressSpace.length, TLCached(para))
})
io.in <> DontCare
io.out <> DontCare
val s_idle :: s_resp :: s_error :: Nil = Enum(3)
val state = RegInit(s_idle)
// select the output channel according to the address
val addr = io.in.a.bits.address
val outSelVec = VecInit(addressSpace.map(
range => addr >= range._1.U && addr < (range._1 + range._2).U
))
val outSelIdx = PriorityEncoder(outSelVec)
val outSel = io.out(outSelIdx)
val outSelIdxResp = RegEnable(outSelIdx, outSel.a.fire() && (state === s_idle))
val outSelResp = io.out(outSelIdxResp)
val reqInvalidAddr = io.in.a.valid && !outSelVec.asUInt.orR
when(
!(!io.in.a.valid || outSelVec.asUInt.orR) || (io.in.a.valid && outSelVec.asUInt.andR)
){
printf("[ERROR] bad addr %x, time %d\n", addr, GTimer())
}
// assert(!io.in.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr)
assert(
!(io.in.a.valid && outSelVec.asUInt.andR),
"address decode error, bad addr = 0x%x\n", addr
)
// bind out.req channel
(io.out zip outSelVec).foreach { case (o, v) =>
o.a.bits := io.in.a.bits
o.a.valid := v && (io.in.a.valid && (state === s_idle))
o.d.ready := v
}
switch (state) {
is (s_idle) {
when (outSel.a.fire()) { state := s_resp }
when (reqInvalidAddr) { state := s_error }
}
is (s_resp) { when (outSelResp.d.fire()) { state := s_idle } }
is (s_error) { when(io.in.d.fire()){ state := s_idle } }
}
io.in.d.valid := outSelResp.d.fire() || state === s_error
io.in.d.bits <> outSelResp.d.bits
// io.in.resp.bits.exc.get := state === s_error
outSelResp.d.ready := io.in.d.ready
io.in.a.ready := outSel.a.ready || reqInvalidAddr
Debug() {
when (state === s_idle && io.in.a.valid) {
printf(p"${GTimer()}: req: ")
io.in.a.bits.dump()
}
when (outSel.a.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx = $outSelIdx, outSel.req: ")
outSel.a.bits.dump()
}
when (outSel.d.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx= $outSelIdx, outSel.resp: ")
outSel.d.bits.dump()
}
when (io.in.d.fire()) {
printf(p"${GTimer()}: xbar: in.resp: ")
io.in.d.bits.dump()
}
}
}
package device
import chisel3._
import chisel3.util.experimental.BoringUtils
import chipsalliance.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy.AddressSet
import utils._
......@@ -31,12 +30,6 @@ class AXI4Timer
val tick = (nextCnt === freq)
when (tick) { mtime := mtime + inc }
if (sim) {
val isWFI = WireInit(false.B)
BoringUtils.addSink(isWFI, "isWFI")
when (isWFI) { mtime := mtime + 100000.U }
}
val mapping = Map(
RegMap(0x4000, mtimecmp),
RegMap(0x8000, freq),
......
......@@ -4,7 +4,6 @@ import chisel3._
import chisel3.util._
import bus.axi4._
import chipsalliance.rocketchip.config.Parameters
import chisel3.util.experimental.BoringUtils
import freechips.rocketchip.diplomacy.AddressSet
import utils._
......
......@@ -4,7 +4,6 @@ import chisel3._
import chisel3.util._
import freechips.rocketchip.tilelink._
import chipsalliance.rocketchip.config._
import chisel3.util.experimental.BoringUtils
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.RegField
import utils.{HasTLDump, XSDebug}
......@@ -35,12 +34,6 @@ class TLTimer(address: Seq[AddressSet], sim: Boolean)(implicit p: Parameters) ex
val tick = (nextCnt === freq)
when (tick) { mtime := mtime + inc }
if (sim) {
val isWFI = WireInit(false.B)
ExcitingUtils.addSink(isWFI, "isWFI")
when (isWFI) { mtime := mtime + 100000.U }
}
node.regmap( mapping =
0x0000 -> RegField.bytes(msip),
0x4000 -> RegField.bytes(mtimecmp),
......
package fpu
import chisel3._
import chisel3.util._
class FPUSubModuleInput extends Bundle{
val op = UInt(3.W)
val isDouble = Bool()
val a, b, c = UInt(64.W)
val rm = UInt(3.W)
}
class FPUSubModuleOutput extends Bundle{
val fflags = new Fflags
val result = UInt(64.W)
}
class FPUSubModuleIO extends Bundle{
val in = Flipped(DecoupledIO(new FPUSubModuleInput))
val out = DecoupledIO(new FPUSubModuleOutput)
}
trait HasPipelineReg { this: FPUSubModule =>
def latency: Int
val ready = Wire(Bool())
val cnt = RegInit(0.U((log2Up(latency)+1).W))
ready := (cnt < latency.U) || (cnt === latency.U && io.out.ready)
cnt := cnt + io.in.fire() - io.out.fire()
val valids = io.in.valid +: Array.fill(latency)(RegInit(false.B))
for(i <- 1 to latency){
when(ready){ valids(i) := valids(i-1) }
}
def PipelineReg[T<:Data](i: Int)(next: T) = RegEnable(next, enable = valids(i-1) && ready)
def S1Reg[T<:Data](next: T):T = PipelineReg[T](1)(next)
def S2Reg[T<:Data](next: T):T = PipelineReg[T](2)(next)
def S3Reg[T<:Data](next: T):T = PipelineReg[T](3)(next)
def S4Reg[T<:Data](next: T):T = PipelineReg[T](4)(next)
def S5Reg[T<:Data](next: T):T = PipelineReg[T](5)(next)
io.in.ready := ready
io.out.valid := valids.last
}
trait HasUIntToSIntHelper {
implicit class UIntToSIntHelper(x: UInt){
def toSInt: SInt = Cat(0.U(1.W), x).asSInt()
}
}
abstract class FPUSubModule extends Module with HasUIntToSIntHelper {
val io = IO(new FPUSubModuleIO)
}
import chisel3._
import chisel3.util._
package object fpu {
object FPUOpType {
def funcWidth = 6
def FpuOp(fu: String, op: String): UInt = ("b" + fu + op).U(funcWidth.W)
// FMA
def fadd:UInt = FpuOp("000", "000")
def fsub:UInt = FpuOp("000", "001")
def fmadd:UInt = FpuOp("000", "100")
def fmsub:UInt = FpuOp("000", "101")
def fnmsub:UInt = FpuOp("000", "110")
def fnmadd:UInt = FpuOp("000", "111")
def fmul:UInt = FpuOp("000", "010")
// FCMP
def fmin:UInt = FpuOp("001", "000")
def fmax:UInt = FpuOp("001", "001")
def fle:UInt = FpuOp("001", "010")
def flt:UInt = FpuOp("001", "011")
def feq:UInt = FpuOp("001", "100")
// FMV
def fmv_f2i:UInt= FpuOp("010", "000")
def fmv_i2f:UInt= FpuOp("010", "001")
def fclass:UInt = FpuOp("010", "010")
def fsgnj:UInt = FpuOp("010", "110")
def fsgnjn:UInt = FpuOp("010", "101")
def fsgnjx:UInt = FpuOp("010", "100")
// FloatToInt
def f2w:UInt = FpuOp("011", "000")
def f2wu:UInt = FpuOp("011", "001")
def f2l:UInt = FpuOp("011", "010")
def f2lu:UInt = FpuOp("011", "011")
// IntToFloat
def w2f:UInt = FpuOp("100", "000")
def wu2f:UInt = FpuOp("100", "001")
def l2f:UInt = FpuOp("100", "010")
def lu2f:UInt = FpuOp("100", "011")
// FloatToFloat
def s2d:UInt = FpuOp("101", "000")
def d2s:UInt = FpuOp("110", "000")
// Div/Sqrt
def fdiv:UInt = FpuOp("111", "000")
def fsqrt:UInt = FpuOp("111", "001")
}
object FPUIOFunc {
def in_raw = 0.U(1.W)
def in_unbox = 1.U(1.W)
def out_raw = 0.U(2.W)
def out_box = 1.U(2.W)
def out_sext = 2.U(2.W)
def out_zext = 3.U(2.W)
def apply(inputFunc: UInt, outputFunc:UInt) = Cat(inputFunc, outputFunc)
}
class Fflags extends Bundle {
val invalid = Bool() // 4
val infinite = Bool() // 3
val overflow = Bool() // 2
val underflow = Bool() // 1
val inexact = Bool() // 0
}
object RoudingMode {
val RNE = "b000".U(3.W)
val RTZ = "b001".U(3.W)
val RDN = "b010".U(3.W)
val RUP = "b011".U(3.W)
val RMM = "b100".U(3.W)
}
class FloatPoint(val expWidth: Int, val mantWidth:Int) extends Bundle{
val sign = Bool()
val exp = UInt(expWidth.W)
val mant = UInt(mantWidth.W)
def defaultNaN: UInt = Cat(0.U(1.W), Fill(expWidth+1,1.U(1.W)), Fill(mantWidth-1,0.U(1.W)))
def posInf: UInt = Cat(0.U(1.W), Fill(expWidth, 1.U(1.W)), 0.U(mantWidth.W))
def negInf: UInt = Cat(1.U(1.W), posInf.tail(1))
def maxNorm: UInt = Cat(0.U(1.W), Fill(expWidth-1, 1.U(1.W)), 0.U(1.W), Fill(mantWidth, 1.U(1.W)))
def expBias: UInt = Fill(expWidth-1, 1.U(1.W))
def expBiasInt: Int = (1 << (expWidth-1)) - 1
def mantExt: UInt = Cat(exp=/=0.U, mant)
def apply(x: UInt): FloatPoint = x.asTypeOf(new FloatPoint(expWidth, mantWidth))
}
object Float32 extends FloatPoint(8, 23)
object Float64 extends FloatPoint(11, 52)
def expOverflow(sexp: SInt, expWidth: Int): Bool = sexp >= Cat(0.U(1.W), Fill(expWidth, 1.U(1.W))).asSInt()
def expOverflow(uexp: UInt, expWidth: Int): Bool = expOverflow(Cat(0.U(1.W), uexp).asSInt(), expWidth)
def boxF32ToF64(x: UInt): UInt = Cat(Fill(32, 1.U(1.W)), x(31, 0))
def unboxF64ToF32(x: UInt): UInt = Mux(x(63, 32)===Fill(32, 1.U(1.W)), x(31, 0), Float32.defaultNaN)
def extF32ToF64(x: UInt): UInt = {
val f32 = Float32(x)
Cat(
f32.sign,
Mux(f32.exp === 0.U,
0.U(Float64.expWidth.W),
Mux((~f32.exp).asUInt() === 0.U,
Cat("b111".U(3.W), f32.exp),
Cat("b0111".U(4.W) + f32.exp.head(1), f32.exp.tail(1))
)
),
Cat(f32.mant, 0.U((Float64.mantWidth - Float32.mantWidth).W))
)
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class TableAddr(val idxBits: Int) extends NOOPBundle {
def tagBits = VAddrBits - 2 - idxBits
//val res = UInt((AddrBits - VAddrBits).W)
val tag = UInt(tagBits.W)
val idx = UInt(idxBits.W)
val pad = UInt(2.W)//TODO
def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
def getTag(x: UInt) = fromUInt(x).tag
def getIdx(x: UInt) = fromUInt(x).idx
}
object BTBtype {
def B = "b00".U // branch
def J = "b01".U // jump
def I = "b10".U // indirect
def R = "b11".U // return
def apply() = UInt(2.W)
}
class BPUUpdateReq extends NOOPBundle {
val valid = Output(Bool())
val pc = Output(UInt(VAddrBits.W))
val isMissPredict = Output(Bool())
val actualTarget = Output(UInt(VAddrBits.W))
val actualTaken = Output(Bool()) // for branch
val fuOpType = Output(FuOpType())
val btbType = Output(BTBtype())
val isRVC = Output(Bool()) // for ras, save PC+2 to stack if is RVC
}
class BPU1 extends NOOPModule {
val io = IO(new Bundle {
val in = new Bundle { val pc = Flipped(Valid((UInt(VAddrBits.W)))) }
val out = new RedirectIO
val flush = Input(Bool())
val brIdx = Output(UInt(3.W))
val lateJump = Output(Bool())
})
val flush = BoolStopWatch(io.flush, io.in.pc.valid, startHighPriority = true)
// BTB
val NRbtb = 512
val btbAddr = new TableAddr(log2Up(NRbtb))
def btbEntry() = new Bundle {
val tag = UInt(btbAddr.tagBits.W)
val _type = UInt(2.W)
val target = UInt(VAddrBits.W)
val brIdx = UInt(3.W)
val valid = Bool()
}
val btb = Module(new SRAMTemplate(btbEntry(), set = NRbtb, shouldReset = true, holdRead = true, singlePort = true))
// flush BTB when executing fence.i
val flushBTB = WireInit(false.B)
val flushTLB = WireInit(false.B)
BoringUtils.addSink(flushBTB, "MOUFlushICache")
BoringUtils.addSink(flushTLB, "MOUFlushTLB")
btb.reset := reset.asBool || (flushBTB || flushTLB)
Debug(false) {
when (reset.asBool || (flushBTB || flushTLB)) {
printf("[BPU-RESET] %d bpu-reset flushBTB:%d flushTLB:%d\n", GTimer(), flushBTB, flushTLB)
}
}
btb.io.r.req.valid := io.in.pc.valid
btb.io.r.req.bits.setIdx := btbAddr.getIdx(io.in.pc.bits)
val btbRead = Wire(btbEntry())
btbRead := btb.io.r.resp.data(0)
// since there is one cycle latency to read SyncReadMem,
// we should latch the input pc for one cycle
val pcLatch = RegEnable(io.in.pc.bits, io.in.pc.valid)
val btbHit = btbRead.tag === btbAddr.getTag(pcLatch) && !flush && RegNext(btb.io.r.req.fire(), init = false.B) && !(pcLatch(1) && btbRead.brIdx(0)) && btbRead.valid
// btbHit will ignore pc(1,0). pc(1,0) is used to build brIdx
// !(pcLatch(1) && btbRead.brIdx(0)) is used to deal with the following case:
// -------------------------------------------------
// 0 jump rvc // marked as "take branch" in BTB
// 2 xxx rvc <-- jump to here
// -------------------------------------------------
val lateJump = btbRead.brIdx(2) && btbHit
io.lateJump := lateJump
// val lateJumpLatch = RegNext(lateJump)
// val lateJumpTarget = RegEnable(btbRead.target, lateJump)
Debug(false){
//printf("[BTBHT] lateJump %x lateJumpLatch %x lateJumpTarget %x\n", lateJump, lateJumpLatch, lateJumpTarget)
when(btbHit){
printf("[BTBHT1] %d pc=%x tag=%x,%x index=%x bridx=%x tgt=%x,%x flush %x type:%x\n", GTimer(), pcLatch, btbRead.tag, btbAddr.getTag(pcLatch), btbAddr.getIdx(pcLatch), btbRead.brIdx, btbRead.target, io.out.target, flush,btbRead._type)
printf("[BTBHT2] btbRead.brIdx %x mask %x\n", btbRead.brIdx, Cat(lateJump, Fill(2, io.out.valid)))
printf("[BTBHT5] btbReqValid:%d btbReqSetIdx:%x\n",btb.io.r.req.valid, btb.io.r.req.bits.setIdx)
}
}
// PHT
val pht = Mem(NRbtb, UInt(2.W))
val phtTaken = RegEnable(pht.read(btbAddr.getIdx(io.in.pc.bits))(1), io.in.pc.valid)
// RAS
val NRras = 16
val ras = Mem(NRras, UInt(VAddrBits.W))
// val raBrIdxs = Mem(NRras, UInt(2.W))
val sp = Counter(NRras)
val rasTarget = RegEnable(ras.read(sp.value), io.in.pc.valid)
// val rasBrIdx = RegEnable(raBrIdxs.read(sp.value), io.in.pc.valid)
// update
val req = WireInit(0.U.asTypeOf(new BPUUpdateReq))
val btbWrite = WireInit(0.U.asTypeOf(btbEntry()))
BoringUtils.addSink(req, "bpuUpdateReq")
Debug(false){
when(req.valid){
printf("[BTBUP] pc=%x tag=%x index=%x bridx=%x tgt=%x type=%x\n", req.pc, btbAddr.getTag(req.pc), btbAddr.getIdx(req.pc), Cat(req.pc(1), ~req.pc(1)), req.actualTarget, req.btbType)
}
}
//val fflag = req.btbType===3.U && btb.io.w.req.valid && btb.io.w.req.bits.setIdx==="hc9".U
//when(fflag && GTimer()>2888000.U) {
// printf("%d\n", GTimer())
// printf("[BTBHT6] btbWrite.type is BTBtype.R/RET!!! Inpc:%x btbWrite.brIdx:%x setIdx:%x\n", io.in.pc.bits, btbWrite.brIdx, btb.io.w.req.bits.setIdx)
// printf("[BTBHT6] tag:%x target:%x _type:%x bridx:%x\n", btbWrite.tag,btbWrite.target,btbWrite._type,btbWrite.brIdx)
// printf(p"[BTBHT6] req:${req} \n")
//}
//printf("[BTBHT5] tag: target:%x type:%d brIdx:%d\n", req.actualTarget, req.btbType, Cat(req.pc(2,0)==="h6".U && !req.isRVC, req.pc(1), ~req.pc(1)))
btbWrite.tag := btbAddr.getTag(req.pc)
btbWrite.target := req.actualTarget
btbWrite._type := req.btbType
btbWrite.brIdx := Cat(req.pc(2,0)==="h6".U && !req.isRVC, req.pc(1), ~req.pc(1))
btbWrite.valid := true.B
// NOTE: We only update BTB at a miss prediction.
// If a miss prediction is found, the pipeline will be flushed
// in the next cycle. Therefore it is safe to use single-port
// SRAM to implement BTB, since write requests have higher priority
// than read request. Again, since the pipeline will be flushed
// in the next cycle, the read request will be useless.
btb.io.w.req.valid := req.isMissPredict && req.valid
btb.io.w.req.bits.setIdx := btbAddr.getIdx(req.pc)
btb.io.w.req.bits.data := btbWrite
//Debug(true) {
//when (btb.io.w.req.valid && btbWrite.tag === btbAddr.getTag("hffffffff803541a4".U)) {
// printf("[BTBWrite] %d setIdx:%x req.valid:%d pc:%x target:%x bridx:%x\n", GTimer(), btbAddr.getIdx(req.pc), req.valid, req.pc, req.actualTarget, btbWrite.brIdx)
//}
//}
//when (GTimer() > 77437484.U && btb.io.w.req.valid) {
// printf("[BTBWrite-ALL] %d setIdx:%x req.valid:%d pc:%x target:%x bridx:%x\n", GTimer(), btbAddr.getIdx(req.pc), req.valid, req.pc, req.actualTarget, btbWrite.brIdx)
//}
val cnt = RegNext(pht.read(btbAddr.getIdx(req.pc)))
val reqLatch = RegNext(req)
when (reqLatch.valid && ALUOpType.isBranch(reqLatch.fuOpType)) {
val taken = reqLatch.actualTaken
val newCnt = Mux(taken, cnt + 1.U, cnt - 1.U)
val wen = (taken && (cnt =/= "b11".U)) || (!taken && (cnt =/= "b00".U))
when (wen) {
pht.write(btbAddr.getIdx(reqLatch.pc), newCnt)
//Debug(){
//printf("BPUPDATE: pc %x cnt %x\n", reqLatch.pc, newCnt)
//}
}
}
when (req.valid) {
when (req.fuOpType === ALUOpType.call) {
ras.write(sp.value + 1.U, Mux(req.isRVC, req.pc + 2.U, req.pc + 4.U))
// raBrIdxs.write(sp.value + 1.U, Mux(req.pc(1), 2.U, 1.U))
sp.value := sp.value + 1.U
}
.elsewhen (req.fuOpType === ALUOpType.ret) {
when(sp.value === 0.U) {
//printf("ATTTTT: sp.value is 0.U\n") //TODO: sp.value may equal to 0.U
}
sp.value := Mux(sp.value===0.U, 0.U, sp.value - 1.U) //TODO: sp.value may less than 0.U
}
}
io.out.target := Mux(btbRead._type === BTBtype.R, rasTarget, btbRead.target)
// io.out.target := Mux(lateJumpLatch && !flush, lateJumpTarget, Mux(btbRead._type === BTBtype.R, rasTarget, btbRead.target))
// io.out.brIdx := btbRead.brIdx & Fill(3, io.out.valid)
io.brIdx := btbRead.brIdx & Cat(true.B, lateJump, Fill(2, io.out.valid))
io.out.valid := btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B && rasTarget=/=0.U) //TODO: add rasTarget=/=0.U, need fix
// io.out.valid := btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B) && !lateJump || lateJumpLatch && !flush && !lateJump
// Note:
// btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B) && !lateJump : normal branch predict
// lateJumpLatch && !flush && !lateJump : cross line branch predict, bpu will require imem to fetch the next 16bit of current inst in next instline
// `&& !lateJump` is used to make sure this logic will run correctly when imem stalls (pcUpdate === false)
// by using `instline`, we mean a 64 bit instfetch result from imem
// ROCKET uses a 32 bit instline, and its IDU logic is more simple than this implentation.
}
class BPU2 extends NOOPModule {
val io = IO(new Bundle {
val in = Flipped(Valid(new CtrlFlowIO))
val out = new RedirectIO
})
val instr = io.in.bits.instr
val immJ = SignExt(Cat(instr(31), instr(19, 12), instr(20), instr(30, 21), 0.U(1.W)), XLEN)
val immB = SignExt(Cat(instr(31), instr(7), instr(30, 25), instr(11, 8), 0.U(1.W)), XLEN)
val table = Array(
RV32I_BRUInstr.JAL -> List(immJ, true.B),
RV32I_BRUInstr.BNE -> List(immB, instr(31)),
RV32I_BRUInstr.BEQ -> List(immB, instr(31)),
RV32I_BRUInstr.BLT -> List(immB, instr(31)),
RV32I_BRUInstr.BGE -> List(immB, instr(31)),
RV32I_BRUInstr.BLTU -> List(immB, instr(31)),
RV32I_BRUInstr.BGEU -> List(immB, instr(31))
)
val default = List(immB, false.B)
val offset :: predict :: Nil = ListLookup(instr, default, table)
io.out.target := io.in.bits.pc + offset
io.out.valid := io.in.valid && predict(0)
}
package noop
import chisel3._
import chisel3.util._
class CtrlSignalIO extends NOOPBundle {
val src1Type = Output(SrcType())
val src2Type = Output(SrcType())
val src3Type = Output(SrcType())
val fuType = Output(FuType())
val fuOpType = Output(FuOpType())
val rfSrc1 = Output(UInt(5.W))
val rfSrc2 = Output(UInt(5.W))
val rfWen = Output(Bool())
val fpWen = Output(Bool())
val fpInputFunc = Output(UInt(1.W))
val fpOutputFunc = Output(UInt(2.W))
val rfDest = Output(UInt(5.W))
val isNoopTrap = Output(Bool())
val isSrc1Forward = Output(Bool())
val isSrc2Forward = Output(Bool())
}
class DataSrcIO extends NOOPBundle {
val src1 = Output(UInt(XLEN.W))
val src2 = Output(UInt(XLEN.W))
val imm = Output(UInt(XLEN.W))
}
class RedirectIO extends NOOPBundle {
val target = Output(UInt(VAddrBits.W))
// val brIdx = Output(UInt(3.W)) // for RVC
val valid = Output(Bool())
}
// class IRIDCtrlFlowIO extends NOOPBundle {
// val instr = Output(UInt(64.W))
// val pc = Output(UInt(VAddrBits.W))
// val pnpc = Output(UInt(VAddrBits.W))
// val brIdx = Output(UInt(3.W))
// val redirect = new RedirectIO
// }
class CtrlFlowIO extends NOOPBundle {
val instr = Output(UInt(64.W))
val pc = Output(UInt(VAddrBits.W))
val pnpc = Output(UInt(VAddrBits.W))
val redirect = new RedirectIO
val exceptionVec = Output(Vec(16, Bool()))
val intrVec = Output(Vec(12, Bool()))
val brIdx = Output(UInt(4.W))
val crossPageIPFFix = Output(Bool())
}
class DecodeIO extends NOOPBundle {
val cf = new CtrlFlowIO
val ctrl = new CtrlSignalIO
val data = new DataSrcIO
}
class WriteBackIO extends NOOPBundle {
val rfWen = Output(Bool())
val fpWen = Output(Bool())
val rfDest = Output(UInt(5.W))
val rfData = Output(UInt(XLEN.W))
}
class CommitIO extends NOOPBundle {
val decode = new DecodeIO
val isMMIO = Output(Bool())
val intrNO = Output(UInt(XLEN.W))
val commits = Output(Vec(FuType.num, UInt(XLEN.W)))
}
class FunctionUnitIO extends NOOPBundle {
val in = Flipped(Decoupled(new Bundle {
val src1 = Output(UInt(XLEN.W))
val src2 = Output(UInt(XLEN.W))
val func = Output(FuOpType())
}))
val out = Decoupled(Output(UInt(XLEN.W)))
}
class ForwardIO extends NOOPBundle {
val valid = Output(Bool())
val wb = new WriteBackIO
val fuType = Output(FuType())
}
class MMUIO extends NOOPBundle {
// val ptev = Output(Bool())
// val pteu = Output(Bool())
// val ptex = Output(Bool())
// val valid = Output(Bool())
// val isStore = Output(Bool())
val priviledgeMode = Input(UInt(2.W))
val status_sum = Input(Bool())
val status_mxr = Input(Bool())
val loadPF = Output(Bool())
val storePF = Output(Bool())
val addr = Output(UInt(VAddrBits.W))
def isPF() = loadPF || storePF
}
class MemMMUIO extends NOOPBundle {
val imem = new MMUIO
val dmem = new MMUIO
}
class TLBExuIO extends NOOPBundle {
val satp = Output(UInt(XLEN.W))
val sfence = new Bundle {
val valid = Output(Bool())
val asid = Output(UInt(9.W))
val vaddr = Output(UInt(XLEN.W))
}
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt, satp: UInt) = {//func no use here for just sfence.vma only
this.sfence.valid := valid
this.sfence.vaddr := src1
this.sfence.asid := src2(8,0)
this.satp := satp
}
}
\ No newline at end of file
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import noop.isa.{RVDInstr, RVFInstr}
trait HasInstrType {
def InstrN = "b0000".U
def InstrI = "b0100".U
def InstrR = "b0101".U
def InstrS = "b0010".U
def InstrB = "b0001".U
def InstrU = "b0110".U
def InstrJ = "b0111".U
def InstrA = "b1110".U
def InstrSA = "b1111".U // Atom Inst: SC
def isrfWen(instrType : UInt): Bool = instrType(2)
}
// trait CompInstConst {
// val RVCRegNumTable = Array(
// BitPat("b000") -> 8.U,
// BitPat("b001") -> 9.U,
// BitPat("b010") -> 10.U,
// BitPat("b011") -> 11.U,
// BitPat("b100") -> 12.U,
// BitPat("b101") -> 13.U,
// BitPat("b110") -> 14.U,
// BitPat("b111") -> 15.U
// )
// }
object SrcType {
def reg = "b00".U
def pc = "b01".U
def imm = "b01".U
def fp = "b10".U
def apply() = UInt(2.W)
}
object FuType {
def num = 6
def alu = "b000".U
def lsu = "b001".U
def mdu = "b010".U
def csr = "b011".U
def mou = "b100".U
def fpu = "b101".U
def apply() = UInt(log2Up(num).W)
}
object FuOpType {
def apply() = UInt(6.W)
}
object Instructions extends HasInstrType with HasNOOPParameter {
def NOP = 0x00000013.U
val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp)
def DecodeTable = RVIInstr.table ++ NOOPTrap.table ++
(if (HasMExtension) RVMInstr.table else Nil) ++
(if (HasCExtension) RVCInstr.table else Nil) ++
(if (HasFPU) RVFInstr.table ++ RVDInstr.table else Nil) ++
Priviledged.table ++
RVAInstr.table ++
RVZicsrInstr.table ++ RVZifenceiInstr.table
}
object CInstructions extends HasInstrType with HasNOOPParameter{
def NOP = 0x00000013.U
val DecodeDefault = List(RVCInstr.ImmNone, RVCInstr.DtCare, RVCInstr.DtCare, RVCInstr.DtCare)
// val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp)
def CExtraDecodeTable = RVCInstr.cExtraTable
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
import bus.simplebus._
import noop.fu.FPU
class EXU(implicit val p: NOOPConfig) extends NOOPModule {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new DecodeIO))
val out = Decoupled(new CommitIO)
val flush = Input(Bool())
val dmem = new SimpleBusUC(addrBits = VAddrBits)
val forward = new ForwardIO
val memMMU = Flipped(new MemMMUIO)
})
val src1 = io.in.bits.data.src1
val src2 = io.in.bits.data.src2
val (fuType, fuOpType) = (io.in.bits.ctrl.fuType, io.in.bits.ctrl.fuOpType)
val fuValids = Wire(Vec(FuType.num, Bool()))
(0 until FuType.num).map (i => fuValids(i) := (fuType === i.U) && io.in.valid && !io.flush)
val alu = Module(new ALU)
val aluOut = alu.access(valid = fuValids(FuType.alu), src1 = src1, src2 = src2, func = fuOpType)
alu.io.cfIn := io.in.bits.cf
alu.io.offset := io.in.bits.data.imm
alu.io.out.ready := true.B
val lsu = Module(new LSU)
val lsuTlbPF = WireInit(false.B)
val lsuOut = lsu.access(valid = fuValids(FuType.lsu), src1 = src1, src2 = io.in.bits.data.imm, func = fuOpType, dtlbPF = lsuTlbPF)
lsu.io.wdata := src2
lsu.io.instr := io.in.bits.cf.instr
io.out.bits.isMMIO := lsu.io.isMMIO || (AddressSpace.isMMIO(io.in.bits.cf.pc) && io.out.valid)
io.dmem <> lsu.io.dmem
lsu.io.out.ready := true.B
val mdu = Module(new MDU)
val mduOut = mdu.access(valid = fuValids(FuType.mdu), src1 = src1, src2 = src2, func = fuOpType)
mdu.io.out.ready := true.B
val csr = Module(new CSR)
val csrOut = csr.access(valid = fuValids(FuType.csr), src1 = src1, src2 = src2, func = fuOpType)
csr.io.cfIn := io.in.bits.cf
csr.io.cfIn.exceptionVec(loadAddrMisaligned) := lsu.io.loadAddrMisaligned
csr.io.cfIn.exceptionVec(storeAddrMisaligned) := lsu.io.storeAddrMisaligned
csr.io.instrValid := io.in.valid && !io.flush
io.out.bits.intrNO := csr.io.intrNO
csr.io.out.ready := true.B
csr.io.imemMMU <> io.memMMU.imem
csr.io.dmemMMU <> io.memMMU.dmem
val mou = Module(new MOU)
// mou does not write register
mou.access(valid = fuValids(FuType.mou), src1 = src1, src2 = src2, func = fuOpType)
mou.io.cfIn := io.in.bits.cf
mou.io.out.ready := true.B
val (fpuOut,fpuOutValid) = if(HasFPU){
val fpu = Module(new FPU)
Debug(){
when(io.in.valid){
printf(p"[EXU] at pc=${Hexadecimal(io.in.bits.cf.pc)} " +
p"fpu in valid=${fpu.io.in.valid} " +
p"fpu out valid=${fpu.io.out.valid}\n")
}
}
fpu.io.out.ready := true.B
csr.io.fpu_csr <> fpu.io.fpu_csr
fpu.io.fpWen := io.in.bits.ctrl.fpWen
fpu.io.inputFunc := io.in.bits.ctrl.fpInputFunc
fpu.io.outputFunc := io.in.bits.ctrl.fpOutputFunc
fpu.io.instr := io.in.bits.cf.instr
(fpu.access(fuValids(FuType.fpu), src1, src2, io.in.bits.data.imm, io.in.bits.ctrl.fuOpType), fpu.io.out.valid)
} else {
csr.io.fpu_csr <> DontCare
(0.U,false.B)
}
io.out.bits.decode := DontCare
(io.out.bits.decode.ctrl, io.in.bits.ctrl) match { case (o, i) =>
o.rfWen := i.rfWen && (!lsuTlbPF && !lsu.io.loadAddrMisaligned && !lsu.io.storeAddrMisaligned || !fuValids(FuType.lsu)) && !(csr.io.wenFix && fuValids(FuType.csr))
o.rfDest := i.rfDest
o.fuType := i.fuType
o.fpWen := i.fpWen && (!lsuTlbPF && !lsu.io.loadAddrMisaligned && !lsu.io.storeAddrMisaligned || !fuValids(FuType.lsu)) && !(csr.io.wenFix && fuValids(FuType.csr))
}
io.out.bits.decode.cf.pc := io.in.bits.cf.pc
io.out.bits.decode.cf.instr := io.in.bits.cf.instr
io.out.bits.decode.cf.redirect <>
Mux(mou.io.redirect.valid, mou.io.redirect,
Mux(csr.io.redirect.valid, csr.io.redirect, alu.io.redirect))
Debug(){
//when(mou.io.redirect.valid || csr.io.redirect.valid || alu.io.redirect.valid){
printf("[REDIRECT] inValid:%d mou %x csr %x alu %x \n", io.in.valid, mou.io.redirect.valid, csr.io.redirect.valid, alu.io.redirect.valid)
printf("[REDIRECT] flush: %d mou %x csr %x alu %x\n", io.flush, mou.io.redirect.target, csr.io.redirect.target, alu.io.redirect.target)
//}
}
// FIXME: should handle io.out.ready == false
io.out.valid := io.in.valid && MuxLookup(fuType, true.B, List(
FuType.lsu -> lsu.io.out.valid,
FuType.mdu -> mdu.io.out.valid,
FuType.fpu -> fpuOutValid
))
io.out.bits.commits(FuType.alu) := aluOut
io.out.bits.commits(FuType.lsu) := lsuOut
io.out.bits.commits(FuType.csr) := csrOut
io.out.bits.commits(FuType.mdu) := mduOut
io.out.bits.commits(FuType.mou) := 0.U
io.out.bits.commits(FuType.fpu) := fpuOut
io.in.ready := !io.in.valid || io.out.fire()
io.forward.valid := io.in.valid
io.forward.wb.rfWen := io.in.bits.ctrl.rfWen
io.forward.wb.fpWen := io.in.bits.ctrl.fpWen
io.forward.wb.rfDest := io.in.bits.ctrl.rfDest
io.forward.wb.rfData := Mux(alu.io.out.fire(), aluOut, lsuOut)
io.forward.fuType := io.in.bits.ctrl.fuType
val isBru = ALUOpType.isBru(fuOpType)
BoringUtils.addSource(alu.io.out.fire() && !isBru, "perfCntCondMaluInstr")
BoringUtils.addSource(alu.io.out.fire() && isBru, "perfCntCondMbruInstr")
BoringUtils.addSource(lsu.io.out.fire(), "perfCntCondMlsuInstr")
BoringUtils.addSource(mdu.io.out.fire(), "perfCntCondMmduInstr")
BoringUtils.addSource(csr.io.out.fire(), "perfCntCondMcsrInstr")
if (!p.FPGAPlatform) {
val nooptrap = io.in.bits.ctrl.isNoopTrap && io.in.valid
val cycleCnt = WireInit(0.U(XLEN.W))
val instrCnt = WireInit(0.U(XLEN.W))
BoringUtils.addSink(cycleCnt, "simCycleCnt")
BoringUtils.addSink(instrCnt, "simInstrCnt")
BoringUtils.addSource(nooptrap, "trapValid")
BoringUtils.addSource(io.in.bits.data.src1, "trapCode")
BoringUtils.addSource(io.in.bits.cf.pc, "trapPC")
BoringUtils.addSource(cycleCnt, "trapCycleCnt")
BoringUtils.addSource(instrCnt, "trapInstrCnt")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class IDU1 extends NOOPModule with HasInstrType with HasExceptionNO {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CtrlFlowIO))
val out = Decoupled(new CtrlFlowIO)
val flush = Input(Bool())
val redirect = new RedirectIO
})
val instr = Wire(UInt(32.W))
val isRVC = instr(1,0) =/= "b11".U
//RVC support FSM
//only ensure pnpc given by this FSM is right. May need flush after 6 offset 32 bit inst
val s_idle :: s_extra :: s_waitnext :: s_waitnext_thenj :: Nil = Enum(4)
val state = RegInit(UInt(2.W), s_idle)
val pcOffsetR = RegInit(UInt(3.W), 0.U)
val pcOffset = Mux(state === s_idle, io.in.bits.pc(2,0), pcOffsetR)
val instIn = Cat(0.U(16.W), io.in.bits.instr)
// val nextState = WireInit(0.U(2.W))
val canGo = WireInit(false.B)
val canIn = WireInit(false.B)
val brIdx = io.in.bits.brIdx
// val brIdx = 0.U
val rvcFinish = pcOffset === 0.U && (!isRVC || brIdx(0)) || pcOffset === 4.U && (!isRVC || brIdx(0)) || pcOffset === 2.U && (isRVC || brIdx(1)) || pcOffset === 6.U && isRVC
// if brIdx(0) (branch taken at inst with offest 0), ignore the rest part of this instline
// just get next pc and instline from IFU
val rvcNext = pcOffset === 0.U && (isRVC && !brIdx(0)) || pcOffset === 4.U && (isRVC && !brIdx(0)) || pcOffset === 2.U && !isRVC && !brIdx(1)
val rvcSpecial = pcOffset === 6.U && !isRVC && !brIdx(2)
val rvcSpecialJump = pcOffset === 6.U && !isRVC && brIdx(2)
val pnpcIsSeq = brIdx(3)
// val pnpcIsSeqRight = io.in.bits.pnpc === (Cat(io.in.bits.pc(VAddrBits-1,2), 0.U(2.W)) + 4.U) // TODO: add a new user bit bpRight to do this
// assert(pnpcIsSeq === pnpcIsSeqRight)
val flushIFU = (state === s_idle || state === s_extra) && rvcSpecial && io.in.valid && !pnpcIsSeq
when(flushIFU){printf("flushIFU at pc %x offset %x timer:%d\n", io.in.bits.pc, pcOffset, GTimer())}
assert(!flushIFU)
val loadNextInstline = (state === s_idle || state === s_extra) && (rvcSpecial || rvcSpecialJump) && io.in.valid && pnpcIsSeq
// val loadNextInstline =false.B
val pcOut = WireInit(0.U(VAddrBits.W))
val pnpcOut = WireInit(0.U(VAddrBits.W))
val specialPCR = Reg(UInt(VAddrBits.W)) // reg for full inst that cross 2 inst line
val specialNPCR = Reg(UInt(VAddrBits.W)) // reg for pnc for full inst jump that cross 2 inst line
val specialInstR = Reg(UInt(16.W))
val specialIPFR = RegInit(Bool(), false.B)
val redirectPC = Cat(io.in.bits.pc(VAddrBits-1,3), 0.U(3.W))+"b1010".U // IDU can got get full inst from a single inst line
val rvcForceLoadNext = (pcOffset === 2.U && !isRVC && io.in.bits.pnpc(2,0) === 4.U && !brIdx(1))
//------------------------------------------------------
// rvcForceLoadNext is used to deal with:
// case 1:
// 8010004a: 406007b7 lui a5,0x40600
// 8010004e: 470d li a4,3
// 80100050: 00e78623 sb a4,12(a5) # 4060000c <_start-0x3faffff4>
// For icache req inst in seq, if there is no rvcForceLoadNext,
// after 8010004e there will be 8010004c instead of 80100050
//------------------------------------------------------
// case 2:
// 80100046: 406007b7 lui a5,0x40600
// 8010004a: 470d li a4,3
// force load next instline into ID stage, if bp wrong, it will be flushed by flushIFU
//------------------------------------------------------
// if there is a j inst in current inst line, a redirect req will be sent by ALU before invalid inst exception being committed
// when brIdx(1), next instline will just be branch target, eatline is no longer needed
// only for test, add this to pipeline when do real implementation
// val predictBranch = io.in.valid && Mux(io.in.bits.pc(1), io.in.bits.pc + 2.U === io.in.bits.pnpc, io.in.bits.pc + 4.U === io.in.bits.pnpc)
// val flush = rvcSpecial
instr := Mux((state === s_waitnext || state === s_waitnext_thenj), Cat(instIn(15,0), specialInstR), LookupTree(pcOffset, List(
"b000".U -> instIn(31,0),
"b010".U -> instIn(31+16,16),
"b100".U -> instIn(63,32),
"b110".U -> instIn(63+16,32+16)
)))
io.redirect.target := redirectPC
io.redirect.valid := flushIFU
when(!io.flush){
switch(state){
is(s_idle){//decode current pc in pipeline
canGo := rvcFinish || rvcNext
canIn := rvcFinish || rvcForceLoadNext
pcOut := io.in.bits.pc
pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, io.in.bits.pc+2.U, io.in.bits.pc+4.U))
when(io.out.fire() && rvcFinish){state := s_idle}
when(io.out.fire() && rvcNext){
state := s_extra
pcOffsetR := pcOffset + Mux(isRVC, 2.U, 4.U)
}
when(rvcSpecial && io.in.valid){
state := s_waitnext
specialPCR := pcOut
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
when(rvcSpecialJump && io.in.valid){
state := s_waitnext_thenj
specialPCR := pcOut
specialNPCR := io.in.bits.pnpc
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
}
is(s_extra){//get 16 aligned inst, pc controled by this FSM
canGo := rvcFinish || rvcNext
canIn := rvcFinish || rvcForceLoadNext
pcOut := Cat(io.in.bits.pc(VAddrBits-1,3), pcOffsetR(2,0))
pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
when(io.out.fire() && rvcFinish){state := s_idle}
when(io.out.fire() && rvcNext){
state := s_extra
pcOffsetR := pcOffset + Mux(isRVC, 2.U, 4.U)
}
when(rvcSpecial && io.in.valid){
state := s_waitnext
specialPCR := pcOut
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
when(rvcSpecialJump && io.in.valid){
state := s_waitnext_thenj
specialPCR := pcOut
specialNPCR := io.in.bits.pnpc
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
}
is(s_waitnext){//require next 64bits, for this inst has size 32 and offset 6
//ignore bp result, use pc+4 instead
pcOut := specialPCR
pnpcOut := specialPCR + 4.U
// pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
canGo := io.in.valid
canIn := false.B
when(io.out.fire()){
state := s_extra
pcOffsetR := "b010".U
}
}
is(s_waitnext_thenj){//require next 64bits, for this inst has size 32 and offset 6
//use bp result
pcOut := specialPCR
pnpcOut := specialNPCR
// pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
canGo := io.in.valid
canIn := true.B
when(io.out.fire()){
state := s_idle
}
}
// is(s_readnext){//npc right, get next 64 inst bits, flush pipeline is not needed
// //ignore bp result, use pc+4 instead
// pcOut := specialPCR
// pnpcOut := specialPCR + 4.U
// // pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
// canGo := io.in.valid
// canIn := false.B
// when(io.out.fire()){
// state := s_extra
// pcOffsetR := "b010".U
// }
// }
}
}.otherwise{
state := s_idle
canGo := DontCare
canIn := DontCare
pcOut := DontCare
pnpcOut := DontCare
}
//output signals
io.out.bits := DontCare
io.out.bits.redirect.valid := false.B
io.out.bits.pc := pcOut
io.out.bits.pnpc := pnpcOut
io.out.bits.instr := instr
io.out.bits.brIdx := io.in.bits.brIdx
io.out.valid := io.in.valid && canGo
io.in.ready := (!io.in.valid || (io.out.fire() && canIn) || loadNextInstline)
io.out.bits.exceptionVec := io.in.bits.exceptionVec/*.map(_ := false.B)*/ //Fix by zhangzifei from false.B
io.out.bits.exceptionVec(instrPageFault) := io.in.bits.exceptionVec(instrPageFault) || specialIPFR && (state === s_waitnext_thenj || state === s_waitnext)
io.out.bits.crossPageIPFFix := io.in.bits.exceptionVec(instrPageFault) && (state === s_waitnext_thenj || state === s_waitnext) && !specialIPFR
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import noop.isa.{RVDInstr, RVFInstr, RVF_LSUInstr, RVD_LSUInstr}
import utils._
class IDU2(implicit val p: NOOPConfig) extends NOOPModule with HasInstrType {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CtrlFlowIO))
val out = Decoupled(new DecodeIO)
val flush = Input(Bool())
})
val hasIntr = Wire(Bool())
val hasIntrOrExceptino = hasIntr || io.in.bits.exceptionVec(instrPageFault)
val instr = io.in.bits.instr(31, 0)
val decodeList = ListLookup(instr, Instructions.DecodeDefault, Instructions.DecodeTable)
val commonInstrType :: commonFuType :: commonFuOpType :: Nil = decodeList
val intrInstrType :: intrFuType :: intrFuOpType :: Nil = Instructions.DecodeDefault
//(isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
val fpExtraDecodeTable = RVFInstr.extraTable ++ RVDInstr.extraTable
val isFp :: fpSrc1Type :: fpSrc2Type :: fpSrc3Type :: fpRfWen :: fpWen :: fpFuOpType :: fpInputFunc :: fpOutputFunc :: Nil =
if(HasFPU) ListLookup(instr, RVFInstr.extraTableDefault, fpExtraDecodeTable) else RVFInstr.extraTableDefault
val floatLdStInstrs = List(
RVF_LSUInstr.FLW,
RVF_LSUInstr.FSW,
RVD_LSUInstr.FLD,
RVCInstr.C_FLD,
RVCInstr.C_FLDSP,
RVD_LSUInstr.FSD,
RVCInstr.C_FSD,
RVCInstr.C_FSDSP
)
def treeCmp(key: UInt, cmpList: List[BitPat]): Bool = {
cmpList.size match {
case 1 =>
key === cmpList.head
case n =>
treeCmp(key, cmpList take n/2) || treeCmp(key, cmpList drop n/2)
}
}
val isFloatLdSd = if(HasFPU) treeCmp(instr, floatLdStInstrs) else false.B
val isRVFD = isFp.asBool()
val instrType = Mux(hasIntrOrExceptino,
intrInstrType,
commonInstrType
)
val fuType = Mux(hasIntrOrExceptino,
intrFuType,
Mux(isRVFD && !isFloatLdSd,
FuType.fpu,
commonFuType
)
)
val fuOpType = Mux(hasIntrOrExceptino,
intrFuOpType,
Mux(isRVFD, fpFuOpType, commonFuOpType)
)
val isRVC = instr(1,0) =/= "b11".U
val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
ListLookup(instr, CInstructions.DecodeDefault, CInstructions.CExtraDecodeTable)
io.out.bits := DontCare
io.out.bits.ctrl.fuType := fuType
io.out.bits.ctrl.fuOpType := fuOpType
io.out.bits.ctrl.fpInputFunc := fpInputFunc
io.out.bits.ctrl.fpOutputFunc := fpOutputFunc
val SrcTypeTable = List(
InstrI -> (SrcType.reg, SrcType.imm),
InstrR -> (SrcType.reg, SrcType.reg),
InstrS -> (SrcType.reg, SrcType.reg),
InstrSA-> (SrcType.reg, SrcType.reg),
InstrB -> (SrcType.reg, SrcType.reg),
InstrU -> (SrcType.pc , SrcType.imm),
InstrJ -> (SrcType.pc , SrcType.imm),
InstrN -> (SrcType.pc , SrcType.imm)
)
val src1Type = Mux(isRVFD,
fpSrc1Type,
LookupTree(instrType, SrcTypeTable.map(p => (p._1, p._2._1)))
)
val src2Type = Mux(isRVFD,
fpSrc2Type,
LookupTree(instrType, SrcTypeTable.map(p => (p._1, p._2._2)))
)
val (rs, rt, rd) = (instr(19, 15), instr(24, 20), instr(11, 7))
// see riscv-spec vol1, Table 16.1: Compressed 16-bit RVC instruction formats.
val rs1 = instr(11,7)
val rs2 = instr(6,2)
val rs1p = LookupTree(instr(9,7), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
val rs2p = LookupTree(instr(4,2), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
val rvc_shamt = Cat(instr(12),instr(6,2))
// val rdp_rs1p = LookupTree(instr(9,7), RVCRegNumTable)
// val rdp = LookupTree(instr(4,2), RVCRegNumTable)
val RegLookUpTable = List(
RVCInstr.DtCare -> 0.U,
RVCInstr.REGrs -> rs,
RVCInstr.REGrt -> rt,
RVCInstr.REGrd -> rd,
RVCInstr.REGrs1 -> rs1,
RVCInstr.REGrs2 -> rs2,
RVCInstr.REGrs1p -> rs1p,
RVCInstr.REGrs2p -> rs2p,
RVCInstr.REGx1 -> 1.U,
RVCInstr.REGx2 -> 2.U
)
val rvc_src1 = LookupTree(rvcSrc1Type, RegLookUpTable.map(p => (p._1, p._2)))
val rvc_src2 = LookupTree(rvcSrc2Type, RegLookUpTable.map(p => (p._1, p._2)))
val rvc_dest = LookupTree(rvcDestType, RegLookUpTable.map(p => (p._1, p._2)))
val rfSrc1 = Mux(isRVC, rvc_src1, rs)
val rfSrc2 = Mux(isRVC, rvc_src2, rt)
val rfDest = Mux(isRVC, rvc_dest, rd)
val rfWen = !hasIntrOrExceptino && Mux(isRVFD, fpRfWen.asBool(), isrfWen(instrType))
// TODO: refactor decode logic
// make non-register addressing to zero, since isu.sb.isBusy(0) === false.B
io.out.bits.ctrl.rfSrc1 := Mux(src1Type === SrcType.pc, 0.U, rfSrc1)
io.out.bits.ctrl.rfSrc2 := Mux(src2Type === SrcType.imm, 0.U, rfSrc2)
io.out.bits.ctrl.rfWen := rfWen
io.out.bits.ctrl.fpWen := fpWen.asBool()
io.out.bits.ctrl.rfDest := Mux(fpWen.asBool() || rfWen, rfDest, 0.U)
io.out.bits.data := DontCare
val imm = LookupTree(instrType, List(
InstrI -> SignExt(instr(31, 20), XLEN),
InstrS -> SignExt(Cat(instr(31, 25), instr(11, 7)), XLEN),
InstrSA -> SignExt(Cat(instr(31, 25), instr(11, 7)), XLEN),
InstrB -> SignExt(Cat(instr(31), instr(7), instr(30, 25), instr(11, 8), 0.U(1.W)), XLEN),
InstrU -> SignExt(Cat(instr(31, 12), 0.U(12.W)), XLEN),//fixed
InstrJ -> SignExt(Cat(instr(31), instr(19, 12), instr(20), instr(30, 21), 0.U(1.W)), XLEN)
))
val immrvc = LookupTree(rvcImmType, List(
// InstrIW -> Cat(Fill(20+32, instr(31)), instr(31, 20)),//fixed
RVCInstr.ImmNone -> 0.U(XLEN.W),
RVCInstr.ImmLWSP -> ZeroExt(Cat(instr(3,2), instr(12), instr(6,4), 0.U(2.W)), XLEN),
RVCInstr.ImmLDSP -> ZeroExt(Cat(instr(4,2), instr(12), instr(6,5), 0.U(3.W)), XLEN),
RVCInstr.ImmSWSP -> ZeroExt(Cat(instr(8,7), instr(12,9), 0.U(2.W)), XLEN),
RVCInstr.ImmSDSP -> ZeroExt(Cat(instr(9,7), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmSW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
RVCInstr.ImmSD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmLW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
RVCInstr.ImmLD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmJ -> SignExt(Cat(instr(12), instr(8), instr(10,9), instr(6), instr(7), instr(2), instr(11), instr(5,3), 0.U(1.W)), XLEN),
RVCInstr.ImmB -> SignExt(Cat(instr(12), instr(6,5), instr(2), instr(11,10), instr(4,3), 0.U(1.W)), XLEN),
RVCInstr.ImmLI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
RVCInstr.ImmLUI -> SignExt(Cat(instr(12), instr(6,2), 0.U(12.W)), XLEN),
RVCInstr.ImmADDI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
RVCInstr.ImmADDI16SP-> SignExt(Cat(instr(12), instr(4,3), instr(5), instr(2), instr(6), 0.U(4.W)), XLEN),
RVCInstr.ImmADD4SPN-> ZeroExt(Cat(instr(10,7), instr(12,11), instr(5), instr(6), 0.U(2.W)), XLEN)
// ImmFLWSP ->
// ImmFLDSP ->
))
io.out.bits.data.imm := Mux(isRVC, immrvc, imm)
when (fuType === FuType.alu) {
def isLink(reg: UInt) = (reg === 1.U || reg === 5.U)
when (isLink(rfDest) && fuOpType === ALUOpType.jal) { io.out.bits.ctrl.fuOpType := ALUOpType.call }
when (fuOpType === ALUOpType.jalr) {
when (isLink(rfSrc1)) { io.out.bits.ctrl.fuOpType := ALUOpType.ret }
when (isLink(rfDest)) { io.out.bits.ctrl.fuOpType := ALUOpType.call }
}
}
// fix LUI
io.out.bits.ctrl.src1Type := Mux(instr(6,0) === "b0110111".U, SrcType.reg, src1Type)
io.out.bits.ctrl.src2Type := src2Type
io.out.bits.ctrl.src3Type := fpSrc3Type
// io.out.bits.ctrl.isInvOpcode := (instrType === InstrN) && io.in.valid
io.out.bits.ctrl.isNoopTrap := (instr(31,0) === NOOPTrap.TRAP) && io.in.valid
//output signals
io.out.valid := io.in.valid
io.in.ready := !io.in.valid || io.out.fire() && !hasIntr
io.out.bits.cf <> io.in.bits
Debug(){
when(io.out.fire()){printf("[IDU] issue: pc %x npc %x instr %x\n", io.out.bits.cf.pc, io.out.bits.cf.pnpc, io.out.bits.cf.instr)}
}
val intrVec = WireInit(0.U(12.W))
BoringUtils.addSink(intrVec, "intrVecIDU")
io.out.bits.cf.intrVec.zip(intrVec.asBools).map{ case(x, y) => x := y }
hasIntr := intrVec.orR
io.out.bits.cf.exceptionVec.map(_ := false.B)
io.out.bits.cf.exceptionVec(illegalInstr) := (!isRVFD && instrType === InstrN && !hasIntr) && io.in.valid
io.out.bits.cf.exceptionVec(instrPageFault) := io.in.bits.exceptionVec(instrPageFault)
io.out.bits.ctrl.isNoopTrap := (instr === NOOPTrap.TRAP) && io.in.valid
if (!p.FPGAPlatform) {
val isWFI = (instr === Priviledged.WFI) && io.in.valid
BoringUtils.addSource(isWFI, "isWFI")
}
}
// Note
// C.LWSP is only valid when rd̸=x0; the code points with rd=x0 are reserved
// C.LDSP is only valid when rd̸=x0; the code points with rd=x0 are reserved.
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
import bus.simplebus._
trait HasResetVector {
val resetVector = 0x40000000L//TODO: set reset vec
}
class IFU extends NOOPModule with HasResetVector {
val io = IO(new Bundle {
val imem = new SimpleBusUC(userBits = VAddrBits*2 + 4, addrBits = VAddrBits)
// val pc = Input(UInt(VAddrBits.W))
val out = Decoupled(new CtrlFlowIO)
val redirect = Flipped(new RedirectIO)
val flushVec = Output(UInt(4.W))
val bpFlush = Output(Bool())
val ipf = Input(Bool())
})
// pc
val pc = RegInit(resetVector.U(VAddrBits.W))
val pcUpdate = io.redirect.valid || io.imem.req.fire()
val snpc = Mux(pc(1), pc + 2.U, pc + 4.U) // sequential next pc
val bp1 = Module(new BPU1)
//
val lateJump = bp1.io.lateJump
val lateJumpLatch = RegInit(false.B)
when(pcUpdate || bp1.io.flush) {
lateJumpLatch := Mux(bp1.io.flush, false.B, lateJump && !lateJumpLatch)
}
val lateJumpTarget = RegEnable(bp1.io.out.target, lateJump)
val lateJumpForceSeq = lateJump && bp1.io.out.valid
val lateJumpForceTgt = lateJumpLatch && !bp1.io.flush
// predicted next pc
val pnpc = Mux(lateJump, snpc, bp1.io.out.target)
val pbrIdx = bp1.io.brIdx
val npc = Mux(io.redirect.valid, io.redirect.target, Mux(lateJumpLatch, lateJumpTarget, Mux(bp1.io.out.valid, pnpc, snpc)))
val npcIsSeq = Mux(io.redirect.valid , false.B, Mux(lateJumpLatch, false.B, Mux(lateJump, true.B, Mux(bp1.io.out.valid, false.B, true.B))))
// Debug(){
// printf("[NPC] %x %x %x %x %x %x\n",lateJumpLatch, lateJumpTarget, lateJump, bp1.io.out.valid, pnpc, snpc)
// }
// val npc = Mux(io.redirect.valid, io.redirect.target, Mux(io.redirectRVC.valid, io.redirectRVC.target, snpc))
val brIdx = Wire(UInt(4.W))
// brIdx(0) -> branch at pc offset 0 (mod 4)
// brIdx(1) -> branch at pc offset 2 (mod 4)
// brIdx(2) -> branch at pc offset 6 (mod 8), and this inst is not rvc inst
brIdx := Cat(npcIsSeq, Mux(io.redirect.valid, 0.U, pbrIdx))
//TODO: BP will be disabled shortly after a redirect request
bp1.io.in.pc.valid := io.imem.req.fire() // only predict when Icache accepts a request
bp1.io.in.pc.bits := npc // predict one cycle early
// bp1.io.flush := io.redirect.valid
bp1.io.flush := io.redirect.valid
//val bp2 = Module(new BPU2)
//bp2.io.in.bits := io.out.bits
//bp2.io.in.valid := io.imem.resp.fire()
when (pcUpdate) {
pc := npc
// printf("[IF1] pc=%x\n", pc)
}
Debug(){
when(pcUpdate) {
printf("[IFUPC] pc:%x pcUpdate:%d npc:%x RedValid:%d RedTarget:%x LJL:%d LJTarget:%x LJ:%d snpc:%x bpValid:%d pnpn:%x \n",pc, pcUpdate, npc, io.redirect.valid,io.redirect.target,lateJumpLatch,lateJumpTarget,lateJump,snpc,bp1.io.out.valid,pnpc)
//printf(p"[IFUIN] redirect: ${io.redirect} \n")
}
}
io.flushVec := Mux(io.redirect.valid, "b1111".U, 0.U)
io.bpFlush := false.B
io.imem.req.bits.apply(addr = Cat(pc(VAddrBits-1,1),0.U(1.W)), //cache will treat it as Cat(pc(63,3),0.U(3.W))
size = "b11".U, cmd = SimpleBusCmd.read, wdata = 0.U, wmask = 0.U, user = Cat(brIdx(3,0), npc(VAddrBits-1, 0), pc(VAddrBits-1, 0)))
io.imem.req.valid := io.out.ready
//TODO: add ctrlFlow.exceptionVec
io.imem.resp.ready := io.out.ready || io.flushVec(0)
io.out.bits := DontCare
//inst path only uses 32bit inst, get the right inst according to pc(2)
Debug(){
when(io.imem.req.fire()){
printf("[IFI] pc=%x user=%x %x %x %x \n", io.imem.req.bits.addr, io.imem.req.bits.user.getOrElse(0.U), io.redirect.valid, pbrIdx, brIdx)
}
when (io.out.fire()) {
printf("[IFO] pc=%x inst=%x\n", io.out.bits.pc, io.out.bits.instr)
}
}
// io.out.bits.instr := (if (XLEN == 64) io.imem.resp.bits.rdata.asTypeOf(Vec(2, UInt(32.W)))(io.out.bits.pc(2))
// else io.imem.resp.bits.rdata)
io.out.bits.instr := io.imem.resp.bits.rdata
io.imem.resp.bits.user.map{ case x =>
io.out.bits.pc := x(VAddrBits-1,0)
io.out.bits.pnpc := x(VAddrBits*2-1,VAddrBits)
io.out.bits.brIdx := x(VAddrBits*2 + 3, VAddrBits*2)
}
io.out.bits.exceptionVec(instrPageFault) := io.ipf
io.out.valid := io.imem.resp.valid && !io.flushVec(0)
BoringUtils.addSource(BoolStopWatch(io.imem.req.valid, io.imem.resp.fire()), "perfCntCondMimemStall")
BoringUtils.addSource(io.flushVec.orR, "perfCntCondMifuFlush")
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
trait HasRegFileParameter {
val NRReg = 32
}
class RegFile(width:Int, hasZero:Boolean = true) extends HasRegFileParameter with HasNOOPParameter {
val rf = Mem(NRReg, UInt(width.W))
def read(addr: UInt) : UInt = if(hasZero) Mux(addr === 0.U, 0.U, rf(addr)) else rf(addr)
def write(addr: UInt, data: UInt) = { rf(addr) := data }
}
class ScoreBoard(hasZero:Boolean = true) extends HasRegFileParameter {
val busy = RegInit(0.U(NRReg.W))
def isBusy(idx: UInt): Bool = busy(idx)
def mask(idx: UInt) = (1.U(NRReg.W) << idx)(NRReg-1, 0)
def update(setMask: UInt, clearMask: UInt) = {
// When clearMask(i) and setMask(i) are both set, setMask(i) wins.
// This can correctly record the busy bit when reg(i) is written
// and issued at the same cycle.
// Note that rf(0) is always free when hasZero==true.
if(hasZero) busy := Cat(((busy & ~clearMask) | setMask)(NRReg-1, 1), 0.U(1.W))
else busy := ((busy & ~clearMask) | setMask)
}
}
class ISU(implicit val p: NOOPConfig) extends NOOPModule with HasRegFileParameter {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new DecodeIO))
val out = Decoupled(new DecodeIO)
val wb = Flipped(new WriteBackIO)
val flush = Input(Bool())
val forward = Flipped(new ForwardIO)
})
io.out.bits := DontCare
val rfSrc1 = io.in.bits.ctrl.rfSrc1
val rfSrc2 = io.in.bits.ctrl.rfSrc2
val rfDest = io.in.bits.ctrl.rfDest
def isDepend(rfSrc: UInt, rfDest: UInt, wen: Bool): Bool = (rfSrc =/= 0.U) && (rfSrc === rfDest) && wen
val forwardRfWen = io.forward.wb.rfWen && io.forward.valid
val dontForward = (io.forward.fuType =/= FuType.alu) && (io.forward.fuType =/= FuType.lsu)
val src1DependEX = isDepend(rfSrc1, io.forward.wb.rfDest, forwardRfWen)
val src2DependEX = isDepend(rfSrc2, io.forward.wb.rfDest, forwardRfWen)
val src1DependWB = isDepend(rfSrc1, io.wb.rfDest, io.wb.rfWen)
val src2DependWB = isDepend(rfSrc2, io.wb.rfDest, io.wb.rfWen)
val src1ForwardNextCycle = src1DependEX && !dontForward
val src2ForwardNextCycle = src2DependEX && !dontForward
val src1Forward = src1DependWB && Mux(dontForward, !src1DependEX, true.B)
val src2Forward = src2DependWB && Mux(dontForward, !src2DependEX, true.B)
val sb = new ScoreBoard
val src1Ready = !sb.isBusy(rfSrc1) || src1ForwardNextCycle || src1Forward
val src2Ready = !sb.isBusy(rfSrc2) || src2ForwardNextCycle || src2Forward
val fpr = new RegFile(width = XLEN, hasZero = false)
val (fprSrcReady,fprSrcData):(Bool,Array[UInt]) = if(HasFPU){
val fsb = new ScoreBoard(hasZero = false)
val forwardFpWen = io.forward.wb.fpWen && io.forward.valid
when (io.wb.fpWen) {
fpr.write(io.wb.rfDest, io.wb.rfData)
}
val fsbClearMask = Mux(io.wb.fpWen && !isDepend(io.wb.rfDest, io.forward.wb.rfDest, forwardFpWen),
fsb.mask(io.wb.rfDest), 0.U(NRReg.W))
val fsbSetMask = Mux(io.out.fire() && io.in.bits.ctrl.fpWen, fsb.mask(rfDest), 0.U)
when (io.flush) { fsb.update(0.U, Fill(NRReg, 1.U(1.W))) }
.otherwise { fsb.update(fsbSetMask, fsbClearMask) }
val instr = io.in.bits.cf.instr
val (fpSrc1,fpSrc2,fpSrc3) = (rfSrc1, rfSrc2, instr(31, 27))
val srcs = Seq(fpSrc1, fpSrc2, fpSrc3).zip(Seq(
io.in.bits.ctrl.src1Type,
io.in.bits.ctrl.src2Type,
io.in.bits.ctrl.src3Type
))
val dataVec = Array.fill(3)(Wire(UInt(XLEN.W)))
// result
(srcs.zipWithIndex.map({
case ((src, t),i) =>
val dependEX = isDepend(src, io.forward.wb.rfDest, forwardFpWen)
val dependWB = isDepend(src, io.wb.rfDest, io.wb.fpWen)
val forwardEX = dependEX && !dontForward
val forwardWB = dependWB && Mux(dontForward, !dependEX, true.B)
dataVec(i) := MuxCase(fpr.read(src), Seq(
forwardEX -> io.forward.wb.rfData,
forwardWB -> io.wb.rfData
))
(!fsb.busy(src) || forwardEX || forwardWB) || (t =/= SrcType.fp)
}).reduceLeft(_ && _), dataVec)
} else (true.B, Array.fill(3)(0.U))
io.out.valid := io.in.valid && src1Ready && src2Ready && fprSrcReady
val rf = new RegFile(XLEN)
// io.out.bits.data.src1 := Mux1H(List(
// (io.in.bits.ctrl.src1Type === SrcType.pc) -> SignExt(io.in.bits.cf.pc, AddrBits),
// src1ForwardNextCycle -> io.forward .wb.rfData,
// (src1Forward && !src1ForwardNextCycle) -> io.wb.rfData,
// ((io.in.bits.ctrl.src1Type =/= SrcType.pc) && !src1ForwardNextCycle && !src1Forward) -> rf.read(rfSrc1)
// ))
// io.out.bits.data.src2 := Mux1H(List(
// (io.in.bits.ctrl.src2Type =/= SrcType.reg) -> io.in.bits.data.imm,
// src2ForwardNextCycle -> io.forward.wb.rfData,
// (src2Forward && !src2ForwardNextCycle) -> io.wb.rfData,
// ((io.in.bits.ctrl.src2Type === SrcType.reg) && !src2ForwardNextCycle && !src2Forward) -> rf.read(rfSrc2)
// ))
io.out.bits.data.src1 := MuxCase(rf.read(rfSrc1), Seq(
(io.in.bits.ctrl.src1Type === SrcType.fp) -> fprSrcData(0),
(io.in.bits.ctrl.src1Type === SrcType.pc) -> SignExt(io.in.bits.cf.pc, AddrBits),
src1ForwardNextCycle -> io.forward.wb.rfData,
src1Forward -> io.wb.rfData
))
io.out.bits.data.src2 := MuxCase(rf.read(rfSrc2), Seq(
(io.in.bits.ctrl.src2Type === SrcType.fp) -> fprSrcData(1),
(io.in.bits.ctrl.src2Type =/= SrcType.reg) -> io.in.bits.data.imm,
src2ForwardNextCycle -> io.forward.wb.rfData,
src2Forward -> io.wb.rfData
))
io.out.bits.data.imm := Mux(io.in.bits.ctrl.src3Type===SrcType.fp, fprSrcData(2), io.in.bits.data.imm)
io.out.bits.cf <> io.in.bits.cf
io.out.bits.ctrl := io.in.bits.ctrl
io.out.bits.ctrl.isSrc1Forward := src1ForwardNextCycle
io.out.bits.ctrl.isSrc2Forward := src2ForwardNextCycle
when (io.wb.rfWen) { rf.write(io.wb.rfDest, io.wb.rfData) }
val wbClearMask = Mux(io.wb.rfWen && !isDepend(io.wb.rfDest, io.forward.wb.rfDest, forwardRfWen), sb.mask(io.wb.rfDest), 0.U(NRReg.W))
val isuFireSetMask = Mux(io.out.fire() && io.in.bits.ctrl.rfWen, sb.mask(rfDest), 0.U)
when (io.flush) { sb.update(0.U, Fill(NRReg, 1.U(1.W))) }
.otherwise { sb.update(isuFireSetMask, wbClearMask) }
io.in.ready := !io.in.valid || io.out.fire()
// read after write
BoringUtils.addSource(io.in.valid && !io.out.valid, "perfCntCondMrawStall")
BoringUtils.addSource(io.out.valid && !io.out.fire(), "perfCntCondMexuBusy")
if (!p.FPGAPlatform) {
val gRegs = (0 until NRReg).map(i => rf.read(i.U))
val fRegs = (0 until NRReg).map(i => if(HasFPU) fpr.read(i.U) else 0.U)
BoringUtils.addSource(VecInit(gRegs ++ fRegs), "difftestRegs")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import bus.simplebus._
import bus.axi4._
import utils._
trait HasNOOPParameter {
val XLEN = 64
val HasMExtension = true
val HasCExtension = true
val HasDiv = true
val HasIcache = true
val HasDcache = true
val EnableStoreQueue = false
val AddrBits = 64 // AddrBits is used in some cases
val VAddrBits = 39 // VAddrBits is Virtual Memory addr bits
val PAddrBits = 32 // PAddrBits is Phyical Memory addr bits
val AddrBytes = AddrBits / 8 // unused
val DataBits = XLEN
val DataBytes = DataBits / 8
val HasFPU = true
}
abstract class NOOPModule extends Module with HasNOOPParameter with HasExceptionNO
abstract class NOOPBundle extends Bundle with HasNOOPParameter
case class NOOPConfig (
FPGAPlatform: Boolean = true,
EnableDebug: Boolean = false
)
object AddressSpace {
// (start, size)
def mmio = List((0x0000000040000000L, 0x0000000010000000L))
def dram = (0x0000000080000000L, 0x0000000010000000L)
//def isMMIO(addr: UInt) = mmio.map(range => ((addr & ~((range._2 - 1).U(32.W))) === range._1.U)).reduce(_ || _)
def isMMIO(addr: UInt) = addr(31,28) === "h4".U
}
class NOOP(implicit val p: NOOPConfig) extends NOOPModule {
val io = IO(new Bundle {
val imem = new SimpleBusC
val dmem = new SimpleBusC
val mmio = new SimpleBusUC
val frontend = Flipped(new SimpleBusUC)
})
val ifu = Module(new IFU)
val idu1 = Module(new IDU1)
val idu2 = Module(new IDU2)
val isu = Module(new ISU)
val exu = Module(new EXU)
val wbu = Module(new WBU)
def pipelineConnect2[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T],
isFlush: Bool, entries: Int = 4, pipe: Boolean = false) = {
right <> FlushableQueue(left, isFlush, entries = entries, pipe = pipe)
}
pipelineConnect2(ifu.io.out, idu1.io.in, ifu.io.flushVec(0))
PipelineConnect(idu1.io.out, idu2.io.in, idu2.io.out.fire(), ifu.io.flushVec(1))
PipelineConnect(idu2.io.out, isu.io.in, isu.io.out.fire(), ifu.io.flushVec(1))
PipelineConnect(isu.io.out, exu.io.in, exu.io.out.fire(), ifu.io.flushVec(2))
PipelineConnect(exu.io.out, wbu.io.in, true.B, ifu.io.flushVec(3))
idu1.io.flush := ifu.io.flushVec(1)
idu2.io.flush := ifu.io.flushVec(1)
isu.io.flush := ifu.io.flushVec(2)
exu.io.flush := ifu.io.flushVec(3)
Debug() {
printf("------------------------ TIMER: %d ------------------------\n", GTimer())
printf("flush = %b, ifu:(%d,%d), idu1:(%d,%d), idu2:(%d,%d), isu:(%d,%d), exu:(%d,%d), wbu: (%d,%d)\n",
ifu.io.flushVec.asUInt, ifu.io.out.valid, ifu.io.out.ready,
idu1.io.in.valid, idu1.io.in.ready, idu2.io.in.valid, idu2.io.in.ready, isu.io.in.valid, isu.io.in.ready,
exu.io.in.valid, exu.io.in.ready, wbu.io.in.valid, wbu.io.in.ready)
when (ifu.io.out.valid) { printf("IFU: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", ifu.io.out.bits.pc, ifu.io.out.bits.instr, ifu.io.out.bits.pnpc)} ;
when (idu1.io.in.valid) { printf("ID1: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu1.io.in.bits.pc, idu1.io.in.bits.instr, idu1.io.in.bits.pnpc) }
when (idu2.io.in.valid) { printf("ID2: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu2.io.in.bits.pc, idu2.io.in.bits.instr, idu2.io.in.bits.pnpc) }
when (isu.io.in.valid) { printf("ISU: pc = 0x%x, pnpc = 0x%x\n", isu.io.in.bits.cf.pc, isu.io.in.bits.cf.pnpc)} ;
when (exu.io.in.valid) { printf("EXU: pc = 0x%x, pnpc = 0x%x\n", exu.io.in.bits.cf.pc, exu.io.in.bits.cf.pnpc)} ;
when (wbu.io.in.valid) { printf("WBU: pc = 0x%x rfWen:%d rfDest:%d rfData:%x Futype:%x\n", wbu.io.in.bits.decode.cf.pc, wbu.io.in.bits.decode.ctrl.rfWen, wbu.io.in.bits.decode.ctrl.rfDest, wbu.io.wb.rfData, wbu.io.in.bits.decode.ctrl.fuType )}
// when (io.in.valid) { printf("TIMER: %d WBU: pc = 0x%x wen %x wdata %x mmio %x intrNO %x\n", GTimer(), io.in.bits.decode.cf.pc, io.wb.rfWen, io.wb.rfData, io.in.bits.isMMIO, io.in.bits.intrNO) }
// printf(p"IFUO: redirectIO:${ifu.io.out.bits.redirect}\n") ; printf("IFUO: exceptionVec: %x\n", ifu.io.out.bits.exceptionVec.asUInt)}
// printf(p"IDUO: redirectIO:${idu.io.out.bits.cf.redirect} redirectIOC:${idu.io.redirect}\n") ; printf("IDUO: exceptionVec:%x\n", idu.io.out.bits.cf.exceptionVec.asUInt)}
// printf(p"ISUO: ${isu.io.out.bits.cf.redirect}\n") ; printf("ISUO: exceptionVec:%x\n", isu.io.out.bits.cf.exceptionVec.asUInt)}
when (exu.io.out.bits.decode.cf.redirect.valid) { printf("EXUO: redirect valid:%d target:%x\n", exu.io.out.bits.decode.cf.redirect.valid, exu.io.out.bits.decode.cf.redirect.target) }
// when (wbu.io.in.valid) { printf("WBU: pc = 0x%x rfWen:%d rfDest:%d rfData:%x Futype:%x commits(0):%x commits(1):%x commits(3):%x\n", wbu.io.in.bits.decode.cf.pc, wbu.io.in.bits.decode.ctrl.rfWen, wbu.io.in.bits.decode.ctrl.rfDest, wbu.io.wb.rfData, wbu.io.in.bits.decode.ctrl.fuType, wbu.io.in.bits.commits(0), wbu.io.in.bits.commits(1), wbu.io.in.bits.commits(3)) }
}
isu.io.wb <> wbu.io.wb
ifu.io.redirect <> wbu.io.redirect
// forward
isu.io.forward <> exu.io.forward
val mmioXbar = Module(new SimpleBusCrossbarNto1(if (HasDcache) 2 else 3))
val dmemXbar = Module(new SimpleBusCrossbarNto1(4))
val itlb = TLB(in = ifu.io.imem, mem = dmemXbar.io.in(1), flush = ifu.io.flushVec(0) | ifu.io.bpFlush, csrMMU = exu.io.memMMU.imem)(TLBConfig(name = "itlb", userBits = VAddrBits*2 + 4, totalEntry = 4))
ifu.io.ipf := itlb.io.ipf
io.imem <> Cache(in = itlb.io.out, mmio = mmioXbar.io.in.take(1), flush = Fill(2, ifu.io.flushVec(0) | ifu.io.bpFlush), empty = itlb.io.cacheEmpty)(
CacheConfig(ro = true, name = "icache", userBits = VAddrBits*2 + 4))
val dtlb = TLB(in = exu.io.dmem, mem = dmemXbar.io.in(2), flush = false.B, csrMMU = exu.io.memMMU.dmem)(TLBConfig(name = "dtlb", totalEntry = 64))
dmemXbar.io.in(0) <> dtlb.io.out
io.dmem <> Cache(in = dmemXbar.io.out, mmio = mmioXbar.io.in.drop(1), flush = "b00".U, empty = dtlb.io.cacheEmpty, enable = HasDcache)(CacheConfig(ro = false, name = "dcache"))
// Make DMA access through L1 DCache to keep coherence
dmemXbar.io.in(3) <> io.frontend
io.mmio <> mmioXbar.io.out
}
package noop
import chisel3._
import chisel3.util._
object NOOPTrap extends HasInstrType {
def StateGoodTrap = 0.U
def StateBadTrap = 1.U
def StateInvOpcode = 2.U
def StateRunning = 3.U
def TRAP = BitPat("b????????????_?????_000_?????_1101011")
val table = Array(TRAP -> List(InstrI, FuType.alu, ALUOpType.add))
}
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class WBU(implicit val p: NOOPConfig) extends NOOPModule{
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CommitIO))
val wb = new WriteBackIO
val redirect = new RedirectIO
})
io.wb.rfWen := io.in.bits.decode.ctrl.rfWen && io.in.valid
io.wb.fpWen := io.in.bits.decode.ctrl.fpWen && io.in.valid
io.wb.rfDest := io.in.bits.decode.ctrl.rfDest
io.wb.rfData := io.in.bits.commits(io.in.bits.decode.ctrl.fuType)
io.in.ready := true.B
io.redirect := io.in.bits.decode.cf.redirect
io.redirect.valid := io.in.bits.decode.cf.redirect.valid && io.in.valid
Debug(){
when (io.in.valid) { printf("[COMMIT] TIMER: %d WBU: pc = 0x%x inst %x wen %x wdata %x mmio %x intrNO %x\n", GTimer(), io.in.bits.decode.cf.pc, io.in.bits.decode.cf.instr, io.wb.rfWen, io.wb.rfData, io.in.bits.isMMIO, io.in.bits.intrNO) }
}
BoringUtils.addSource(io.in.valid, "perfCntCondMinstret")
if (!p.FPGAPlatform) {
BoringUtils.addSource(RegNext(io.in.valid), "difftestCommit")
BoringUtils.addSource(RegNext(SignExt(io.in.bits.decode.cf.pc, AddrBits)), "difftestThisPC")
BoringUtils.addSource(RegNext(io.in.bits.decode.cf.instr), "difftestThisINST")
BoringUtils.addSource(RegNext(io.in.bits.isMMIO), "difftestIsMMIO")
BoringUtils.addSource(RegNext(io.in.bits.decode.cf.instr(1,0)=/="b11".U), "difftestIsRVC")
BoringUtils.addSource(RegNext(io.in.bits.intrNO), "difftestIntrNO")
} else {
BoringUtils.addSource(io.in.valid, "ilaWBUvalid")
BoringUtils.addSource(io.in.bits.decode.cf.pc, "ilaWBUpc")
BoringUtils.addSource(io.wb.rfWen, "ilaWBUrfWen")
BoringUtils.addSource(io.wb.rfDest, "ilaWBUrfDest")
BoringUtils.addSource(io.wb.rfData, "ilaWBUrfData")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
object ALUOpType {
def add = "b000000".U
def sll = "b000001".U
def slt = "b000010".U
def sltu = "b000011".U
def xor = "b000100".U
def srl = "b000101".U
def or = "b000110".U
def and = "b000111".U
def sub = "b001000".U
def sra = "b001101".U
def addw = "b100000".U
def subw = "b101000".U
def sllw = "b100001".U
def srlw = "b100101".U
def sraw = "b101101".U
def isWordOp(func: UInt) = func(5)
def jal = "b011000".U
def jalr = "b011010".U
// def cjalr= "b111010".U // pc + 2 instead of 4
def beq = "b010000".U
def bne = "b010001".U
def blt = "b010100".U
def bge = "b010101".U
def bltu = "b010110".U
def bgeu = "b010111".U
// for RAS
def call = "b011100".U
def ret = "b011110".U
def isBru(func: UInt) = func(4)//[important]
def pcPlus2(func: UInt) = func(5)//[important]
def isBranch(func: UInt) = !func(3)
def isJump(func: UInt) = isBru(func) && !isBranch(func)
def getBranchType(func: UInt) = func(2, 1)
def isBranchInvert(func: UInt) = func(0)
}
class ALUIO extends FunctionUnitIO {
val cfIn = Flipped(new CtrlFlowIO)
val redirect = new RedirectIO
val offset = Input(UInt(XLEN.W))
}
class ALU extends NOOPModule {
val io = IO(new ALUIO)
val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.func := func
io.out.bits
}
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw) && !ALUOpType.isJump(func)
val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
val xorRes = src1 ^ src2
val sltu = !adderRes(XLEN)
val slt = xorRes(XLEN-1) ^ sltu
val shsrc1 = LookupTreeDefault(func, src1, List(
ALUOpType.srlw -> ZeroExt(src1(31,0), 64),
ALUOpType.sraw -> SignExt(src1(31,0), 64)
))
val shamt = Mux(ALUOpType.isWordOp(func), src2(4, 0), src2(5, 0))
val res = LookupTreeDefault(func(3, 0), adderRes, List(
ALUOpType.sll -> ((shsrc1 << shamt)(XLEN-1, 0)),
ALUOpType.slt -> ZeroExt(slt, XLEN),
ALUOpType.sltu -> ZeroExt(sltu, XLEN),
ALUOpType.xor -> xorRes,
ALUOpType.srl -> (shsrc1 >> shamt),
ALUOpType.or -> (src1 | src2),
ALUOpType.and -> (src1 & src2),
ALUOpType.sra -> ((shsrc1.asSInt >> shamt).asUInt)
))
val aluRes = Mux(ALUOpType.isWordOp(func), SignExt(res(31,0), 64), res)
val branchOpTable = List(
ALUOpType.getBranchType(ALUOpType.beq) -> !xorRes.orR,
ALUOpType.getBranchType(ALUOpType.blt) -> slt,
ALUOpType.getBranchType(ALUOpType.bltu) -> sltu
)
val isBranch = ALUOpType.isBranch(func)
val isBru = ALUOpType.isBru(func)
// val pcPlus2 = ALUOpType.pcPlus2(func)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, io.cfIn.pc + io.offset, adderRes)(VAddrBits-1,0)
val predictWrong = (io.redirect.target =/= io.cfIn.pnpc)
val isRVC = (io.cfIn.instr(1,0) =/= "b11".U)
io.redirect.target := Mux(!taken && isBranch, Mux(isRVC, io.cfIn.pc + 2.U, io.cfIn.pc + 4.U), target)
// with branch predictor, this is actually to fix the wrong prediction
io.redirect.valid := valid && isBru && predictWrong
// may be can be moved to ISU to calculate pc + 4
// this is actually for jal and jalr to write pc + 4/2 to rd
io.out.bits := Mux(isBru, Mux(!isRVC, SignExt(io.cfIn.pc, AddrBits) + 4.U, SignExt(io.cfIn.pc, AddrBits) + 2.U), aluRes)
// when(pcPlus2 && isBru){
// printf("CJALR %x %x \n ", io.cfIn.instr, io.cfIn.pc)
// }
Debug(){
when(valid && isBru){
printf("[BRU] tgt %x, valid:%d, npc: %x, pdwrong: %x\n", io.redirect.target, io.redirect.valid, io.cfIn.pnpc, predictWrong)
printf("[BRU] taken:%d addrRes:%x src1:%x src2:%x func:%x\n", taken, adderRes, src1, src2, func)
}
}
Debug(false){
when(valid && isBru){
printf("[BPW] pc %x tgt %x, npc: %x, pdwrong: %x type: %x%x%x%x\n", io.cfIn.pc, io.redirect.target, io.cfIn.pnpc, predictWrong, isBranch, (func === ALUOpType.jal || func === ALUOpType.call), func === ALUOpType.jalr, func === ALUOpType.ret)
}
when(true.B) {
printf("[ALUIN0] valid:%d isBru:%d isBranch:%d \n", valid, isBru, isBranch)
printf("[ALUIN1] pc %x instr %x tgt %x, npc: %x, pdwrong: %x type: %x%x%x%x\n", io.cfIn.pc, io.cfIn.instr, io.redirect.target, io.cfIn.pnpc, predictWrong, isBranch, (func === ALUOpType.jal || func === ALUOpType.call), func === ALUOpType.jalr, func === ALUOpType.ret)
printf("[ALUIN2] func:%b ", func)
printf(" bpuUpdateReq: valid:%d pc:%x isMissPredict:%d actualTarget:%x actualTaken:%x fuOpType:%x btbType:%x isRVC:%d \n", valid && isBru, io.cfIn.pc, predictWrong, target, taken, func, LookupTree(func, RV32I_BRUInstr.bruFuncTobtbTypeTable), isRVC)
printf("[ALUIN3]tgt %x, npc: %x, pdwrong: %x\n", io.redirect.target, io.cfIn.pnpc, predictWrong)
printf("[ALUIN4]taken:%d addrRes:%x src1:%x src2:%x func:%x\n", taken, adderRes, src1, src2, func)
}
}
io.in.ready := true.B
io.out.valid := valid
val bpuUpdateReq = WireInit(0.U.asTypeOf(new BPUUpdateReq))
bpuUpdateReq.valid := valid && isBru
bpuUpdateReq.pc := io.cfIn.pc
bpuUpdateReq.isMissPredict := predictWrong
bpuUpdateReq.actualTarget := target
bpuUpdateReq.actualTaken := taken
bpuUpdateReq.fuOpType := func
bpuUpdateReq.btbType := LookupTree(func, RV32I_BRUInstr.bruFuncTobtbTypeTable)
bpuUpdateReq.isRVC := isRVC
BoringUtils.addSource(RegNext(bpuUpdateReq), "bpuUpdateReq")
val right = valid && isBru && !predictWrong
val wrong = valid && isBru && predictWrong
BoringUtils.addSource(right && isBranch, "MbpBRight")
BoringUtils.addSource(wrong && isBranch, "MbpBWrong")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h0".U && isRVC, "Custom1")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h0".U && !isRVC, "Custom2")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h2".U && isRVC, "Custom3")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h2".U && !isRVC, "Custom4")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h4".U && isRVC, "Custom5")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h4".U && !isRVC, "Custom6")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h6".U && isRVC, "Custom7")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h6".U && !isRVC, "Custom8")
BoringUtils.addSource(right && (func === ALUOpType.jal || func === ALUOpType.call), "MbpJRight")
BoringUtils.addSource(wrong && (func === ALUOpType.jal || func === ALUOpType.call), "MbpJWrong")
BoringUtils.addSource(right && func === ALUOpType.jalr, "MbpIRight")
BoringUtils.addSource(wrong && func === ALUOpType.jalr, "MbpIWrong")
BoringUtils.addSource(right && func === ALUOpType.ret, "MbpRRight")
BoringUtils.addSource(wrong && func === ALUOpType.ret, "MbpRWrong")
}
此差异已折叠。
package noop.fu
import chisel3.{util, _}
import chisel3.util._
import utils._
import noop._
import fpu._
import fpu.FPUIOFunc._
import fpu.divsqrt.DivSqrt
import fpu.fma.FMA
class FpInstr extends NOOPBundle {
val func5 = UInt(5.W)
val fmt = UInt(2.W)
val rs2 = UInt(5.W)
val rs1 = UInt(5.W)
val rm = UInt(3.W)
val rd = UInt(5.W)
val op = UInt(7.W)
assert(this.getWidth == 32)
}
class FpuCsrIO extends NOOPBundle {
val fflags = Output(new Fflags)
val isIllegal = Output(Bool())
val dirty_fs = Output(Bool())
val frm = Input(UInt(3.W))
}
class FPUIO extends FunctionUnitIO{
// use XLEN because fpu share data path with cpu
val src3 = Input(UInt(XLEN.W))
val fpu_csr = new FpuCsrIO
val fpWen = Input(Bool())
val instr = Input(UInt(32.W))
val inputFunc = Input(UInt(1.W))
val outputFunc = Input(UInt(2.W))
}
class FPU extends NOOPModule{
// require(XLEN >= FLEN)
val io = IO(new FPUIO)
val (valid, src1, src2, src3, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.src3, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, src3: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.src3 := src3
this.func := func
io.out.bits
}
val instr = io.instr.asTypeOf(new FpInstr)
val isRVD = instr.fmt(0)
val src = VecInit(Seq(src1, src2, src3)).map(x =>
Mux(io.inputFunc === in_unbox, unboxF64ToF32(x), x)
)
val roudingMode = Mux(instr.rm===7.U, io.fpu_csr.frm, instr.rm)
val op = func(2, 0)
val fu = func(5, 3)
val s_ready :: s_wait :: Nil = Enum(2)
val state = RegInit(s_ready)
switch(state){
is(s_ready){
when(io.in.valid){
state := s_wait
}
}
is(s_wait){
when(io.out.fire()){
state := s_ready
}
}
}
val subModuleInput = Wire(new FPUSubModuleInput)
subModuleInput.a := src(0)
subModuleInput.b := src(1)
subModuleInput.c := src(2)
subModuleInput.op := op
subModuleInput.isDouble := isRVD
subModuleInput.rm := roudingMode
val subModules = Array[FPUSubModule](
Module(new FMA), // 0
Module(new FCMP), // 1
Module(new FMV(XLEN)), // 2
Module(new FloatToInt), // 3
Module(new IntToFloat), // 4
Module(new F32toF64), // 5
Module(new F64toF32), // 6
Module(new DivSqrt) //7
)
val outFuncReg = RegEnable(io.outputFunc, io.in.fire())
val fuReg = RegEnable(fu, io.in.fire())
for((module, idx) <- subModules.zipWithIndex){
module.io.in.bits := subModuleInput
module.io.in.valid := io.in.fire() && idx.U===fu
module.io.out.ready := true.B
}
val subModuleOutput = Wire(Decoupled(new FPUSubModuleOutput))
subModuleOutput := LookupTree(fuReg, subModules.zipWithIndex.map({
case (module, idx) =>
idx.U -> module.io.out
}))
val result = subModuleOutput.bits.result
io.in.ready := state===s_ready
io.out.valid := subModuleOutput.valid
io.out.bits := MuxLookup(outFuncReg, result, Seq(
out_sext -> SignExt(result(31, 0), XLEN),
out_box -> boxF32ToF64(result)
))
//TODO: check illegal rounding mode exception
io.fpu_csr.isIllegal := false.B
io.fpu_csr.dirty_fs := io.in.fire() && io.fpWen
io.fpu_csr.fflags := Mux(io.out.valid, subModuleOutput.bits.fflags, 0.U.asTypeOf(new Fflags))
}
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
object MDUOpType {
def mul = "b0000".U
def mulh = "b0001".U
def mulhsu = "b0010".U
def mulhu = "b0011".U
def div = "b0100".U
def divu = "b0101".U
def rem = "b0110".U
def remu = "b0111".U
def mulw = "b1000".U
def divw = "b1100".U
def divuw = "b1101".U
def remw = "b1110".U
def remuw = "b1111".U
def isDiv(op: UInt) = op(2)
def isDivSign(op: UInt) = isDiv(op) && !op(0)
def isW(op: UInt) = op(3)
}
class MulDivIO(val len: Int) extends Bundle {
val in = Flipped(DecoupledIO(Vec(2, Output(UInt(len.W)))))
val sign = Input(Bool())
val out = DecoupledIO(Output(UInt((len * 2).W)))
}
class Multiplier(len: Int) extends NOOPModule {
val io = IO(new MulDivIO(len))
val latency = 1
def DSPInPipe[T <: Data](a: T) = RegNext(a)
def DSPOutPipe[T <: Data](a: T) = RegNext(RegNext(RegNext(a)))
val mulRes = (DSPInPipe(io.in.bits(0)).asSInt * DSPInPipe(io.in.bits(1)).asSInt)
io.out.bits := DSPOutPipe(mulRes).asUInt
io.out.valid := DSPOutPipe(DSPInPipe(io.in.fire()))
val busy = RegInit(false.B)
when (io.in.valid && !busy) { busy := true.B }
when (io.out.valid) { busy := false.B }
io.in.ready := (if (latency == 0) true.B else !busy)
}
class Divider(len: Int = 64) extends NOOPModule {
val io = IO(new MulDivIO(len))
def abs(a: UInt, sign: Bool): (Bool, UInt) = {
val s = a(len - 1) && sign
(s, Mux(s, -a, a))
}
val s_idle :: s_log2 :: s_shift :: s_compute :: s_finish :: Nil = Enum(5)
val state = RegInit(s_idle)
val newReq = (state === s_idle) && io.in.fire()
val (a, b) = (io.in.bits(0), io.in.bits(1))
val divBy0 = b === 0.U(len.W)
val shiftReg = Reg(UInt((1 + len * 2).W))
val hi = shiftReg(len * 2, len)
val lo = shiftReg(len - 1, 0)
val (aSign, aVal) = abs(a, io.sign)
val (bSign, bVal) = abs(b, io.sign)
val aSignReg = RegEnable(aSign, newReq)
val qSignReg = RegEnable((aSign ^ bSign) && !divBy0, newReq)
val bReg = RegEnable(bVal, newReq)
val aValx2Reg = RegEnable(Cat(aVal, "b0".U), newReq)
val cnt = Counter(len)
when (newReq) {
state := s_log2
} .elsewhen (state === s_log2) {
// `canSkipShift` is calculated as following:
// bEffectiveBit = Log2(bVal, XLEN) + 1.U
// aLeadingZero = 64.U - aEffectiveBit = 64.U - (Log2(aVal, XLEN) + 1.U)
// canSkipShift = aLeadingZero + bEffectiveBit
// = 64.U - (Log2(aVal, XLEN) + 1.U) + Log2(bVal, XLEN) + 1.U
// = 64.U + Log2(bVal, XLEN) - Log2(aVal, XLEN)
// = (64.U | Log2(bVal, XLEN)) - Log2(aVal, XLEN) // since Log2(bVal, XLEN) < 64.U
val canSkipShift = (64.U | Log2(bReg)) - Log2(aValx2Reg)
// When divide by 0, the quotient should be all 1's.
// Therefore we can not shift in 0s here.
// We do not skip any shift to avoid this.
cnt.value := Mux(divBy0, 0.U, Mux(canSkipShift >= (len-1).U, (len-1).U, canSkipShift))
state := s_shift
} .elsewhen (state === s_shift) {
shiftReg := aValx2Reg << cnt.value
state := s_compute
} .elsewhen (state === s_compute) {
val enough = hi.asUInt >= bReg.asUInt
shiftReg := Cat(Mux(enough, hi - bReg, hi)(len - 1, 0), lo, enough)
cnt.inc()
when (cnt.value === (len-1).U) { state := s_finish }
} .elsewhen (state === s_finish) {
state := s_idle
}
val r = hi(len, 1)
val resQ = Mux(qSignReg, -lo, lo)
val resR = Mux(aSignReg, -r, r)
io.out.bits := Cat(resR, resQ)
io.out.valid := (if (HasDiv) (state === s_finish) else io.in.valid) // FIXME: should deal with ready = 0
io.in.ready := (state === s_idle)
}
class MDUIO extends FunctionUnitIO {
}
class MDU extends NOOPModule {
val io = IO(new MDUIO)
val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.func := func
io.out.bits
}
val isDiv = MDUOpType.isDiv(func)
val isDivSign = MDUOpType.isDivSign(func)
val isW = MDUOpType.isW(func)
val mul = Module(new Multiplier(XLEN + 1))
val div = Module(new Divider(64))
List(mul.io, div.io).map { case x =>
x.sign := isDivSign
x.out.ready := io.out.ready
}
val signext = SignExt(_: UInt, XLEN+1)
val zeroext = ZeroExt(_: UInt, XLEN+1)
val mulInputFuncTable = List(
MDUOpType.mul -> (zeroext, zeroext),
MDUOpType.mulh -> (signext, signext),
MDUOpType.mulhsu -> (signext, zeroext),
MDUOpType.mulhu -> (zeroext, zeroext)
)
mul.io.in.bits(0) := LookupTree(func(1,0), mulInputFuncTable.map(p => (p._1(1,0), p._2._1(src1))))
mul.io.in.bits(1) := LookupTree(func(1,0), mulInputFuncTable.map(p => (p._1(1,0), p._2._2(src2))))
val divInputFunc = (x: UInt) => Mux(isW, Mux(isDivSign, SignExt(x(31,0), XLEN), ZeroExt(x(31,0), XLEN)), x)
div.io.in.bits(0) := divInputFunc(src1)
div.io.in.bits(1) := divInputFunc(src2)
mul.io.in.valid := io.in.valid && !isDiv
div.io.in.valid := io.in.valid && isDiv
val mulRes = Mux(func(1,0) === MDUOpType.mul(1,0), mul.io.out.bits(XLEN-1,0), mul.io.out.bits(2*XLEN-1,XLEN))
val divRes = Mux(func(1) /* rem */, div.io.out.bits(2*XLEN-1,XLEN), div.io.out.bits(XLEN-1,0))
val res = Mux(isDiv, divRes, mulRes)
io.out.bits := Mux(isW, SignExt(res(31,0),XLEN), res)
val isDivReg = Mux(io.in.fire(), isDiv, RegNext(isDiv))
io.in.ready := Mux(isDiv, div.io.in.ready, mul.io.in.ready)
io.out.valid := Mux(isDivReg, div.io.out.valid, mul.io.out.valid)
BoringUtils.addSource(mul.io.out.fire(), "perfCntCondMmulInstr")
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
// memory order unit
object MOUOpType {
def fence = "b00".U
def fencei = "b01".U
def sfence_vma = "b10".U
}
class MOUIO extends FunctionUnitIO {
val cfIn = Flipped(new CtrlFlowIO)
val redirect = new RedirectIO
}
class MOU extends NOOPModule {
val io = IO(new MOUIO)
val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.func := func
io.out.bits
}
io.redirect.target := io.cfIn.pc + 4.U
io.redirect.valid := valid
val flushICache = valid && (func === MOUOpType.fencei)
BoringUtils.addSource(flushICache, "MOUFlushICache")
Debug(false){
when(flushICache){
printf("%d: [MOU] Flush I$ at %x\n", GTimer(), io.cfIn.pc)
}
}
val flushTLB = valid && (func === MOUOpType.sfence_vma)
BoringUtils.addSource(flushTLB, "MOUFlushTLB")
Debug(false) {
when (flushTLB) {
printf("%d: [MOU] Flush TLB at %x\n", GTimer(), io.cfIn.pc)
}
}
io.out.bits := 0.U
io.in.ready := true.B
io.out.valid := valid
}
package noop
import chisel3._
import chisel3.util._
object Priviledged extends HasInstrType {
def ECALL = BitPat("b000000000000_00000_000_00000_1110011")
def MRET = BitPat("b001100000010_00000_000_00000_1110011")
def SRET = BitPat("b000100000010_00000_000_00000_1110011")
def SFANCE_VMA = BitPat("b0001001_?????_?????_000_00000_1110011")
def FENCE = BitPat("b????????????_?????_000_?????_0001111")
def WFI = BitPat("b0001000_00101_00000_000_00000_1110011")
val table = Array(
ECALL -> List(InstrI, FuType.csr, CSROpType.jmp),
MRET -> List(InstrI, FuType.csr, CSROpType.jmp),
SRET -> List(InstrI, FuType.csr, CSROpType.jmp),
SFANCE_VMA -> List(InstrR, FuType.mou, MOUOpType.sfence_vma),
FENCE -> List(InstrS, FuType.alu, ALUOpType.add), // nop InstrS -> !wen
WFI -> List(InstrI, FuType.alu, ALUOpType.add) // nop
// FENCE -> List(InstrB, FuType.mou, MOUOpType.fencei)
)
}
package noop
import chisel3._
import chisel3.util._
object RVAInstr extends HasInstrType {
// Note: use instr(14,12) to distinguish D/W inst
// def LR = BitPat("b00010??00000_?????_???_?????_0101111")
// def SC = BitPat("b00011??00000_?????_???_?????_0101111")
def LR_D = BitPat("b00010_??_00000_?????_011_?????_0101111")
def SC_D = BitPat("b00011_??_?????_?????_011_?????_0101111")
def LR_W = BitPat("b00010_??_00000_?????_010_?????_0101111")
def SC_W = BitPat("b00011_??_?????_?????_010_?????_0101111")
def AMOSWAP = BitPat("b00001_??_?????_?????_01?_?????_0101111")
def AMOADD = BitPat("b00000_??_?????_?????_01?_?????_0101111")
def AMOXOR = BitPat("b00100_??_?????_?????_01?_?????_0101111")
def AMOAND = BitPat("b01100_??_?????_?????_01?_?????_0101111")
def AMOOR = BitPat("b01000_??_?????_?????_01?_?????_0101111")
def AMOMIN = BitPat("b10000_??_?????_?????_01?_?????_0101111")
def AMOMAX = BitPat("b10100_??_?????_?????_01?_?????_0101111")
def AMOMINU = BitPat("b11000_??_?????_?????_01?_?????_0101111")
def AMOMAXU = BitPat("b11100_??_?????_?????_01?_?????_0101111")
// funct3 === 010 or 011
val table = Array(
// LR -> List(InstrI, FuType.lsu, LSUOpType.lr),
LR_D -> List(InstrI, FuType.lsu, LSUOpType.lr),
LR_W -> List(InstrI, FuType.lsu, LSUOpType.lr),
// SC -> List(InstrS, FuType.lsu, LSUOpType.sc),
SC_D -> List(InstrSA, FuType.lsu, LSUOpType.sc),
SC_W -> List(InstrSA, FuType.lsu, LSUOpType.sc),
AMOSWAP -> List(InstrR, FuType.lsu, LSUOpType.amoswap),
AMOADD -> List(InstrR, FuType.lsu, LSUOpType.amoadd),
AMOXOR -> List(InstrR, FuType.lsu, LSUOpType.amoxor),
AMOAND -> List(InstrR, FuType.lsu, LSUOpType.amoand),
AMOOR -> List(InstrR, FuType.lsu, LSUOpType.amoor),
AMOMIN -> List(InstrR, FuType.lsu, LSUOpType.amomin),
AMOMAX -> List(InstrR, FuType.lsu, LSUOpType.amomax),
AMOMINU -> List(InstrR, FuType.lsu, LSUOpType.amominu),
AMOMAXU -> List(InstrR, FuType.lsu, LSUOpType.amomaxu)
)
}
此差异已折叠。
package noop.isa
import Chisel.BitPat
import noop._
import noop.SrcType.{fp, imm, reg}
import RVF_FPUInstr.{Y, N}
import RVCInstr._
import fpu.FPUIOFunc._
import fpu.FPUOpType._
object RVD_LSUInstr extends HasInstrType{
def FLD = BitPat("b?????????????????011?????0000111")
def FSD = BitPat("b?????????????????011?????0100111")
val table = Array(
FLD -> List(InstrI, FuType.lsu, LSUOpType.ld),
C_FLD -> List(InstrI, FuType.lsu, LSUOpType.ld),
C_FLDSP -> List(InstrI, FuType.lsu, LSUOpType.ld),
FSD -> List(InstrS, FuType.lsu, LSUOpType.sd),
C_FSD -> List(InstrS, FuType.lsu, LSUOpType.sd),
C_FSDSP -> List(InstrS, FuType.lsu, LSUOpType.sd)
)
}
object RVD_FPUInstr extends HasNOOPParameter {
def FADD_D = BitPat("b0000001??????????????????1010011")
def FSUB_D = BitPat("b0000101??????????????????1010011")
def FMUL_D = BitPat("b0001001??????????????????1010011")
def FDIV_D = BitPat("b0001101??????????????????1010011")
def FSGNJ_D = BitPat("b0010001??????????000?????1010011")
def FSGNJN_D = BitPat("b0010001??????????001?????1010011")
def FSGNJX_D = BitPat("b0010001??????????010?????1010011")
def FMIN_D = BitPat("b0010101??????????000?????1010011")
def FMAX_D = BitPat("b0010101??????????001?????1010011")
def FCVT_S_D = BitPat("b010000000001?????????????1010011")
def FCVT_D_S = BitPat("b010000100000?????????????1010011")
def FSQRT_D = BitPat("b010110100000?????????????1010011")
def FLE_D = BitPat("b1010001??????????000?????1010011")
def FLT_D = BitPat("b1010001??????????001?????1010011")
def FEQ_D = BitPat("b1010001??????????010?????1010011")
def FCVT_W_D = BitPat("b110000100000?????????????1010011")
def FCVT_WU_D = BitPat("b110000100001?????????????1010011")
def FCVT_L_D = BitPat("b110000100010?????????????1010011")
def FCVT_LU_D = BitPat("b110000100011?????????????1010011")
def FMV_X_D = BitPat("b111000100000?????000?????1010011")
def FCLASS_D = BitPat("b111000100000?????001?????1010011")
def FCVT_D_W = BitPat("b110100100000?????????????1010011")
def FCVT_D_WU = BitPat("b110100100001?????????????1010011")
def FCVT_D_L = BitPat("b110100100010?????????????1010011")
def FCVT_D_LU = BitPat("b110100100011?????????????1010011")
def FMV_D_X = BitPat("b111100100000?????000?????1010011")
def FLD = BitPat("b?????????????????011?????0000111")
def FSD = BitPat("b?????????????????011?????0100111")
def FMADD_D = BitPat("b?????01??????????????????1000011")
def FMSUB_D = BitPat("b?????01??????????????????1000111")
def FNMSUB_D = BitPat("b?????01??????????????????1001011")
def FNMADD_D = BitPat("b?????01??????????????????1001111")
// (isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
val table = Array(
FLD -> List(Y, reg, imm, imm, N, Y, LSUOpType.ld, in_raw, out_raw),
C_FLD -> List(Y, reg, imm, imm, N, Y, LSUOpType.ld, in_raw, out_raw),
C_FLDSP -> List(Y, reg, imm, imm, N, Y, LSUOpType.ld, in_raw, out_raw),
FSD -> List(Y, reg, fp, imm, N, N, LSUOpType.sd, in_raw, out_raw),
C_FSD -> List(Y, reg, fp, imm, N, N, LSUOpType.sd, in_raw, out_raw),
C_FSDSP -> List(Y, reg, fp, imm, N, N, LSUOpType.sd, in_raw, out_raw),
// fp fp -> fp
FADD_D -> List(Y, fp, fp, imm, N, Y, fadd, in_raw, out_raw),
FSUB_D -> List(Y, fp, fp, imm, N, Y, fsub, in_raw, out_raw),
FMUL_D -> List(Y, fp, fp, imm, N, Y, fmul, in_raw, out_raw),
FDIV_D -> List(Y, fp, fp, imm, N, Y, fdiv, in_raw, out_raw),
FMIN_D -> List(Y, fp, fp, imm, N, Y, fmin, in_raw, out_raw),
FMAX_D -> List(Y, fp, fp, imm, N, Y, fmax, in_raw, out_raw),
FSGNJ_D -> List(Y, fp, fp, imm, N, Y, fsgnj, in_raw, out_raw),
FSGNJN_D -> List(Y, fp, fp, imm, N, Y, fsgnjn, in_raw, out_raw),
FSGNJX_D -> List(Y, fp, fp, imm, N, Y, fsgnjx, in_raw, out_raw),
// fp -> fp
FSQRT_D -> List(Y, fp, imm, imm, N, Y, fsqrt, in_raw, out_raw),
FCVT_S_D -> List(Y, fp, imm, imm, N, Y, d2s, in_raw, out_box),
FCVT_D_S -> List(Y, fp, imm, imm, N, Y, s2d, in_unbox, out_raw),
// fp fp fp -> fp
FMADD_D -> List(Y, fp, fp, fp, N, Y, fmadd, in_raw, out_raw),
FNMADD_D -> List(Y, fp, fp, fp, N, Y, fnmadd, in_raw, out_raw),
FMSUB_D -> List(Y, fp, fp, fp, N, Y, fmsub, in_raw, out_raw),
FNMSUB_D -> List(Y, fp, fp, fp, N, Y, fnmsub, in_raw, out_raw),
// fp -> gp
FCLASS_D -> List(Y, fp, imm, imm, Y, N, fclass, in_raw, out_raw),
FMV_X_D -> List(Y, fp, imm, imm, Y, N, fmv_f2i, in_raw, out_raw),
FCVT_W_D -> List(Y, fp, imm, imm, Y, N, f2w, in_raw, out_sext),
FCVT_WU_D -> List(Y, fp, imm, imm, Y, N, f2wu, in_raw, out_sext),
FCVT_L_D -> List(Y, fp, imm, imm, Y, N, f2l, in_raw, out_raw),
FCVT_LU_D -> List(Y, fp, imm, imm, Y, N, f2lu, in_raw, out_raw),
// fp fp -> gp
FLE_D -> List(Y, fp, fp, imm, Y, N, fle, in_raw, out_raw),
FLT_D -> List(Y, fp, fp, imm, Y, N, flt, in_raw, out_raw),
FEQ_D -> List(Y, fp, fp, imm, Y, N, feq, in_raw, out_raw),
// gp -> fp
FMV_D_X -> List(Y, reg, imm, imm, N, Y, fmv_i2f, in_raw, out_raw),
FCVT_D_W -> List(Y, reg, imm, imm, N, Y, w2f, in_raw, out_raw),
FCVT_D_WU -> List(Y, reg, imm, imm, N, Y, wu2f, in_raw, out_raw),
FCVT_D_L -> List(Y, reg, imm, imm, N, Y, l2f, in_raw, out_raw),
FCVT_D_LU -> List(Y, reg, imm, imm, N, Y, lu2f, in_raw, out_raw)
)
}
object RVDInstr {
val table = RVD_LSUInstr.table
val extraTable = RVD_FPUInstr.table
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
object RVZicsrInstr extends HasInstrType {
def CSRRW = BitPat("b????????????_?????_001_?????_1110011")
def CSRRS = BitPat("b????????????_?????_010_?????_1110011")
def CSRRC = BitPat("b????????????_?????_011_?????_1110011")
def CSRRWI = BitPat("b????????????_?????_101_?????_1110011")
def CSRRSI = BitPat("b????????????_?????_110_?????_1110011")
def CSRRCI = BitPat("b????????????_?????_111_?????_1110011")
val table = Array(
CSRRW -> List(InstrI, FuType.csr, CSROpType.wrt),
CSRRS -> List(InstrI, FuType.csr, CSROpType.set),
CSRRC -> List(InstrI, FuType.csr, CSROpType.clr),
CSRRWI -> List(InstrI, FuType.csr, CSROpType.wrti),
CSRRSI -> List(InstrI, FuType.csr, CSROpType.seti),
CSRRCI -> List(InstrI, FuType.csr, CSROpType.clri)
)
}
package noop
import chisel3._
import chisel3.util._
object RVZifenceiInstr extends HasInstrType {
def FENCEI = BitPat("b000000000000_00000_001_00000_0001111")
val table = Array(
FENCEI -> List(InstrB, FuType.mou, MOUOpType.fencei)
)
}
此差异已折叠。
此差异已折叠。
......@@ -67,12 +67,9 @@ class XSSoc()(implicit p: Parameters) extends LazyModule with HasSoCParameter {
val meip = Input(Bool())
val ila = if(env.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
})
val mtipSync = clint.module.io.mtip
val msipSync = clint.module.io.msip
val meipSync = RegNext(RegNext(io.meip))
ExcitingUtils.addSource(mtipSync, "mtip")
ExcitingUtils.addSource(msipSync, "msip")
ExcitingUtils.addSource(meipSync, "meip")
xsCore.module.io.externalInterrupt.mtip := clint.module.io.mtip
xsCore.module.io.externalInterrupt.msip := clint.module.io.msip
xsCore.module.io.externalInterrupt.meip := RegNext(RegNext(io.meip))
}
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册