1
0

reorganize moving non-submodule packages into src/main/scala

This commit is contained in:
Howard Mao
2016-08-19 10:58:56 -07:00
parent f78da0b0ea
commit 7b20609d4d
110 changed files with 3 additions and 381 deletions

View File

@ -0,0 +1,113 @@
// See LICENSE for license details.
package rocket
import Chisel._
import cde.{Parameters, Field}
import junctions.{ParameterizedBundle, DecoupledHelper}
class HellaCacheArbiter(n: Int)(implicit p: Parameters) extends Module
{
val io = new Bundle {
val requestor = Vec(n, new HellaCacheIO).flip
val mem = new HellaCacheIO
}
if (n == 1) {
io.mem <> io.requestor.head
} else {
val s1_id = Reg(UInt())
val s2_id = Reg(next=s1_id)
io.mem.invalidate_lr := io.requestor.map(_.invalidate_lr).reduce(_||_)
io.mem.req.valid := io.requestor.map(_.req.valid).reduce(_||_)
io.requestor(0).req.ready := io.mem.req.ready
for (i <- 1 until n)
io.requestor(i).req.ready := io.requestor(i-1).req.ready && !io.requestor(i-1).req.valid
for (i <- n-1 to 0 by -1) {
val req = io.requestor(i).req
def connect_s0() = {
io.mem.req.bits.cmd := req.bits.cmd
io.mem.req.bits.typ := req.bits.typ
io.mem.req.bits.addr := req.bits.addr
io.mem.req.bits.phys := req.bits.phys
io.mem.req.bits.tag := Cat(req.bits.tag, UInt(i, log2Up(n)))
s1_id := UInt(i)
}
def connect_s1() = {
io.mem.s1_kill := io.requestor(i).s1_kill
io.mem.s1_data := io.requestor(i).s1_data
}
if (i == n-1) {
connect_s0()
connect_s1()
} else {
when (req.valid) { connect_s0() }
when (s1_id === UInt(i)) { connect_s1() }
}
}
for (i <- 0 until n) {
val resp = io.requestor(i).resp
val tag_hit = io.mem.resp.bits.tag(log2Up(n)-1,0) === UInt(i)
resp.valid := io.mem.resp.valid && tag_hit
io.requestor(i).xcpt := io.mem.xcpt
io.requestor(i).ordered := io.mem.ordered
io.requestor(i).s2_nack := io.mem.s2_nack && s2_id === UInt(i)
resp.bits := io.mem.resp.bits
resp.bits.tag := io.mem.resp.bits.tag >> log2Up(n)
io.requestor(i).replay_next := io.mem.replay_next
}
}
}
class InOrderArbiter[T <: Data, U <: Data](reqTyp: T, respTyp: U, n: Int)
(implicit p: Parameters) extends Module {
val io = new Bundle {
val in_req = Vec(n, Decoupled(reqTyp)).flip
val in_resp = Vec(n, Decoupled(respTyp))
val out_req = Decoupled(reqTyp)
val out_resp = Decoupled(respTyp).flip
}
if (n > 1) {
val route_q = Module(new Queue(UInt(width = log2Up(n)), 2))
val req_arb = Module(new RRArbiter(reqTyp, n))
req_arb.io.in <> io.in_req
val req_helper = DecoupledHelper(
req_arb.io.out.valid,
route_q.io.enq.ready,
io.out_req.ready)
io.out_req.bits := req_arb.io.out.bits
io.out_req.valid := req_helper.fire(io.out_req.ready)
route_q.io.enq.bits := req_arb.io.chosen
route_q.io.enq.valid := req_helper.fire(route_q.io.enq.ready)
req_arb.io.out.ready := req_helper.fire(req_arb.io.out.valid)
val resp_sel = route_q.io.deq.bits
val resp_ready = io.in_resp(resp_sel).ready
val resp_helper = DecoupledHelper(
resp_ready,
route_q.io.deq.valid,
io.out_resp.valid)
val resp_valid = resp_helper.fire(resp_ready)
for (i <- 0 until n) {
io.in_resp(i).bits := io.out_resp.bits
io.in_resp(i).valid := resp_valid && resp_sel === UInt(i)
}
route_q.io.deq.ready := resp_helper.fire(route_q.io.deq.valid)
io.out_resp.ready := resp_helper.fire(io.out_resp.valid)
} else {
io.out_req <> io.in_req.head
io.in_resp.head <> io.out_resp
}
}

View File

@ -0,0 +1,82 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Util._
import cde.Parameters
class TDRSelect(implicit p: Parameters) extends CoreBundle()(p) {
val tdrmode = Bool()
val reserved = UInt(width = xLen - 1 - log2Up(nTDR))
val tdrindex = UInt(width = log2Up(nTDR))
def nTDR = p(NBreakpoints)
}
class BPControl(implicit p: Parameters) extends CoreBundle()(p) {
val tdrtype = UInt(width = 4)
val bpamaskmax = UInt(width = 5)
val reserved = UInt(width = xLen-28)
val bpaction = UInt(width = 8)
val bpmatch = UInt(width = 4)
val m = Bool()
val h = Bool()
val s = Bool()
val u = Bool()
val r = Bool()
val w = Bool()
val x = Bool()
def tdrType = 1
def bpaMaskMax = 4
def enabled(mstatus: MStatus) = Cat(m, h, s, u)(mstatus.prv)
}
class BP(implicit p: Parameters) extends CoreBundle()(p) {
val control = new BPControl
val address = UInt(width = vaddrBits)
def mask(dummy: Int = 0) = {
var mask: UInt = control.bpmatch(1)
for (i <- 1 until control.bpaMaskMax)
mask = Cat(mask(i-1) && address(i-1), mask)
mask
}
def pow2AddressMatch(x: UInt) =
(~x | mask()) === (~address | mask())
}
class BreakpointUnit(implicit p: Parameters) extends CoreModule()(p) {
val io = new Bundle {
val status = new MStatus().asInput
val bp = Vec(p(NBreakpoints), new BP).asInput
val pc = UInt(INPUT, vaddrBits)
val ea = UInt(INPUT, vaddrBits)
val xcpt_if = Bool(OUTPUT)
val xcpt_ld = Bool(OUTPUT)
val xcpt_st = Bool(OUTPUT)
}
io.xcpt_if := false
io.xcpt_ld := false
io.xcpt_st := false
for (bp <- io.bp) {
when (bp.control.enabled(io.status)) {
when (bp.pow2AddressMatch(io.pc) && bp.control.x) { io.xcpt_if := true }
when (bp.pow2AddressMatch(io.ea) && bp.control.r) { io.xcpt_ld := true }
when (bp.pow2AddressMatch(io.ea) && bp.control.w) { io.xcpt_st := true }
}
}
if (!io.bp.isEmpty) for ((bpl, bph) <- io.bp zip io.bp.tail) {
def matches(x: UInt) = !(x < bpl.address) && x < bph.address
when (bph.control.enabled(io.status) && bph.control.bpmatch === 1) {
when (matches(io.pc) && bph.control.x) { io.xcpt_if := true }
when (matches(io.ea) && bph.control.r) { io.xcpt_ld := true }
when (matches(io.ea) && bph.control.w) { io.xcpt_st := true }
}
}
}

View File

@ -0,0 +1,269 @@
// See LICENSE for license details.
package rocket
import Chisel._
import junctions._
import cde.{Parameters, Field}
import Util._
import uncore.util._
case object BtbKey extends Field[BtbParameters]
case class BtbParameters(
nEntries: Int = 62,
nRAS: Int = 2,
updatesOutOfOrder: Boolean = false)
abstract trait HasBtbParameters extends HasCoreParameters {
val matchBits = pgIdxBits
val entries = p(BtbKey).nEntries
val nRAS = p(BtbKey).nRAS
val updatesOutOfOrder = p(BtbKey).updatesOutOfOrder
val nPages = ((1 max(log2Up(entries)))+1)/2*2 // control logic assumes 2 divides pages
val opaqueBits = log2Up(entries)
val nBHT = 1 << log2Up(entries*2)
}
abstract class BtbModule(implicit val p: Parameters) extends Module with HasBtbParameters
abstract class BtbBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
with HasBtbParameters
class RAS(nras: Int) {
def push(addr: UInt): Unit = {
when (count < nras) { count := count + 1 }
val nextPos = Mux(Bool(isPow2(nras)) || pos < nras-1, pos+1, UInt(0))
stack(nextPos) := addr
pos := nextPos
}
def peek: UInt = stack(pos)
def pop(): Unit = when (!isEmpty) {
count := count - 1
pos := Mux(Bool(isPow2(nras)) || pos > 0, pos-1, UInt(nras-1))
}
def clear(): Unit = count := UInt(0)
def isEmpty: Bool = count === UInt(0)
private val count = Reg(UInt(width = log2Up(nras+1)))
private val pos = Reg(UInt(width = log2Up(nras)))
private val stack = Reg(Vec(nras, UInt()))
}
class BHTResp(implicit p: Parameters) extends BtbBundle()(p) {
val history = UInt(width = log2Up(nBHT).max(1))
val value = UInt(width = 2)
}
// BHT contains table of 2-bit counters and a global history register.
// The BHT only predicts and updates when there is a BTB hit.
// The global history:
// - updated speculatively in fetch (if there's a BTB hit).
// - on a mispredict, the history register is reset (again, only if BTB hit).
// The counter table:
// - each counter corresponds with the address of the fetch packet ("fetch pc").
// - updated when a branch resolves (and BTB was a hit for that branch).
// The updating branch must provide its "fetch pc".
class BHT(nbht: Int)(implicit val p: Parameters) extends HasCoreParameters {
val nbhtbits = log2Up(nbht)
def get(addr: UInt, update: Bool): BHTResp = {
val res = Wire(new BHTResp)
val index = addr(nbhtbits+1, log2Up(coreInstBytes)) ^ history
res.value := table(index)
res.history := history
val taken = res.value(0)
when (update) { history := Cat(taken, history(nbhtbits-1,1)) }
res
}
def update(addr: UInt, d: BHTResp, taken: Bool, mispredict: Bool): Unit = {
val index = addr(nbhtbits+1, log2Up(coreInstBytes)) ^ d.history
table(index) := Cat(taken, (d.value(1) & d.value(0)) | ((d.value(1) | d.value(0)) & taken))
when (mispredict) { history := Cat(taken, d.history(nbhtbits-1,1)) }
}
private val table = Mem(nbht, UInt(width = 2))
val history = Reg(UInt(width = nbhtbits))
}
// BTB update occurs during branch resolution (and only on a mispredict).
// - "pc" is what future fetch PCs will tag match against.
// - "br_pc" is the PC of the branch instruction.
class BTBUpdate(implicit p: Parameters) extends BtbBundle()(p) {
val prediction = Valid(new BTBResp)
val pc = UInt(width = vaddrBits)
val target = UInt(width = vaddrBits)
val taken = Bool()
val isValid = Bool()
val isJump = Bool()
val isReturn = Bool()
val br_pc = UInt(width = vaddrBits)
}
// BHT update occurs during branch resolution on all conditional branches.
// - "pc" is what future fetch PCs will tag match against.
class BHTUpdate(implicit p: Parameters) extends BtbBundle()(p) {
val prediction = Valid(new BTBResp)
val pc = UInt(width = vaddrBits)
val taken = Bool()
val mispredict = Bool()
}
class RASUpdate(implicit p: Parameters) extends BtbBundle()(p) {
val isCall = Bool()
val isReturn = Bool()
val returnAddr = UInt(width = vaddrBits)
val prediction = Valid(new BTBResp)
}
// - "bridx" is the low-order PC bits of the predicted branch (after
// shifting off the lowest log(inst_bytes) bits off).
// - "mask" provides a mask of valid instructions (instructions are
// masked off by the predicted taken branch from the BTB).
class BTBResp(implicit p: Parameters) extends BtbBundle()(p) {
val taken = Bool()
val mask = Bits(width = fetchWidth)
val bridx = Bits(width = log2Up(fetchWidth))
val target = UInt(width = vaddrBits)
val entry = UInt(width = opaqueBits)
val bht = new BHTResp
}
class BTBReq(implicit p: Parameters) extends BtbBundle()(p) {
val addr = UInt(width = vaddrBits)
}
// fully-associative branch target buffer
// Higher-performance processors may cause BTB updates to occur out-of-order,
// which requires an extra CAM port for updates (to ensure no duplicates get
// placed in BTB).
class BTB(implicit p: Parameters) extends BtbModule {
val io = new Bundle {
val req = Valid(new BTBReq).flip
val resp = Valid(new BTBResp)
val btb_update = Valid(new BTBUpdate).flip
val bht_update = Valid(new BHTUpdate).flip
val ras_update = Valid(new RASUpdate).flip
}
val idxs = Reg(Vec(entries, UInt(width=matchBits - log2Up(coreInstBytes))))
val idxPages = Reg(Vec(entries, UInt(width=log2Up(nPages))))
val tgts = Reg(Vec(entries, UInt(width=matchBits - log2Up(coreInstBytes))))
val tgtPages = Reg(Vec(entries, UInt(width=log2Up(nPages))))
val pages = Reg(Vec(nPages, UInt(width=vaddrBits - matchBits)))
val pageValid = Reg(init = UInt(0, nPages))
val idxPagesOH = idxPages.map(UIntToOH(_)(nPages-1,0))
val tgtPagesOH = tgtPages.map(UIntToOH(_)(nPages-1,0))
val isValid = Reg(init = UInt(0, entries))
val isReturn = Reg(UInt(width = entries))
val isJump = Reg(UInt(width = entries))
val brIdx = Reg(Vec(entries, UInt(width=log2Up(fetchWidth))))
private def page(addr: UInt) = addr >> matchBits
private def pageMatch(addr: UInt) = {
val p = page(addr)
pageValid & pages.map(_ === p).asUInt
}
private def tagMatch(addr: UInt, pgMatch: UInt) = {
val idxMatch = idxs.map(_ === addr(matchBits-1, log2Up(coreInstBytes))).asUInt
val idxPageMatch = idxPagesOH.map(_ & pgMatch).map(_.orR).asUInt
idxMatch & idxPageMatch & isValid
}
val r_btb_update = Pipe(io.btb_update)
val update_target = io.req.bits.addr
val pageHit = pageMatch(io.req.bits.addr)
val hitsVec = tagMatch(io.req.bits.addr, pageHit)
val hits = hitsVec.asUInt
val updatePageHit = pageMatch(r_btb_update.bits.pc)
val updateHits = tagMatch(r_btb_update.bits.pc, updatePageHit)
val updateHit = if (updatesOutOfOrder) updateHits.orR else r_btb_update.bits.prediction.valid
val updateHitAddr = if (updatesOutOfOrder) OHToUInt(updateHits) else r_btb_update.bits.prediction.bits.entry
val nextRepl = Counter(r_btb_update.valid && !updateHit, entries)._1
val useUpdatePageHit = updatePageHit.orR
val usePageHit = pageHit.orR
val doIdxPageRepl = !useUpdatePageHit
val nextPageRepl = Reg(UInt(width = log2Ceil(nPages)))
val idxPageRepl = Mux(usePageHit, Cat(pageHit(nPages-2,0), pageHit(nPages-1)), UIntToOH(nextPageRepl))
val idxPageUpdateOH = Mux(useUpdatePageHit, updatePageHit, idxPageRepl)
val idxPageUpdate = OHToUInt(idxPageUpdateOH)
val idxPageReplEn = Mux(doIdxPageRepl, idxPageRepl, UInt(0))
val samePage = page(r_btb_update.bits.pc) === page(update_target)
val doTgtPageRepl = !samePage && !usePageHit
val tgtPageRepl = Mux(samePage, idxPageUpdateOH, Cat(idxPageUpdateOH(nPages-2,0), idxPageUpdateOH(nPages-1)))
val tgtPageUpdate = OHToUInt(Mux(usePageHit, pageHit, tgtPageRepl))
val tgtPageReplEn = Mux(doTgtPageRepl, tgtPageRepl, UInt(0))
when (r_btb_update.valid && (doIdxPageRepl || doTgtPageRepl)) {
val both = doIdxPageRepl && doTgtPageRepl
val next = nextPageRepl + Mux[UInt](both, 2, 1)
nextPageRepl := Mux(next >= nPages, next(0), next)
}
when (r_btb_update.valid) {
val waddr = Mux(updateHit, updateHitAddr, nextRepl)
val mask = UIntToOH(waddr)
idxs(waddr) := r_btb_update.bits.pc(matchBits-1, log2Up(coreInstBytes))
tgts(waddr) := update_target(matchBits-1, log2Up(coreInstBytes))
idxPages(waddr) := idxPageUpdate
tgtPages(waddr) := tgtPageUpdate
isValid := Mux(r_btb_update.bits.isValid, isValid | mask, isValid & ~mask)
isReturn := Mux(r_btb_update.bits.isReturn, isReturn | mask, isReturn & ~mask)
isJump := Mux(r_btb_update.bits.isJump, isJump | mask, isJump & ~mask)
if (fetchWidth > 1)
brIdx(waddr) := r_btb_update.bits.br_pc >> log2Up(coreInstBytes)
require(nPages % 2 == 0)
val idxWritesEven = !idxPageUpdate(0)
def writeBank(i: Int, mod: Int, en: UInt, data: UInt) =
for (i <- i until nPages by mod)
when (en(i)) { pages(i) := data }
writeBank(0, 2, Mux(idxWritesEven, idxPageReplEn, tgtPageReplEn),
Mux(idxWritesEven, page(r_btb_update.bits.pc), page(update_target)))
writeBank(1, 2, Mux(idxWritesEven, tgtPageReplEn, idxPageReplEn),
Mux(idxWritesEven, page(update_target), page(r_btb_update.bits.pc)))
pageValid := pageValid | tgtPageReplEn | idxPageReplEn
}
io.resp.valid := hits.orR
io.resp.bits.taken := true
io.resp.bits.target := Cat(Mux1H(Mux1H(hitsVec, tgtPagesOH), pages), Mux1H(hitsVec, tgts) << log2Up(coreInstBytes))
io.resp.bits.entry := OHToUInt(hits)
io.resp.bits.bridx := (if (fetchWidth > 1) Mux1H(hitsVec, brIdx) else UInt(0))
io.resp.bits.mask := Cat((UInt(1) << ~Mux(io.resp.bits.taken, ~io.resp.bits.bridx, UInt(0)))-1, UInt(1))
if (nBHT > 0) {
val bht = new BHT(nBHT)
val isBranch = !(hits & isJump).orR
val res = bht.get(io.req.bits.addr, io.req.valid && io.resp.valid && isBranch)
val update_btb_hit = io.bht_update.bits.prediction.valid
when (io.bht_update.valid && update_btb_hit) {
bht.update(io.bht_update.bits.pc, io.bht_update.bits.prediction.bits.bht, io.bht_update.bits.taken, io.bht_update.bits.mispredict)
}
when (!res.value(0) && isBranch) { io.resp.bits.taken := false }
io.resp.bits.bht := res
}
if (nRAS > 0) {
val ras = new RAS(nRAS)
val doPeek = (hits & isReturn).orR
when (!ras.isEmpty && doPeek) {
io.resp.bits.target := ras.peek
}
when (io.ras_update.valid) {
when (io.ras_update.bits.isCall) {
ras.push(io.ras_update.bits.returnAddr)
when (doPeek) {
io.resp.bits.target := io.ras_update.bits.returnAddr
}
}.elsewhen (io.ras_update.bits.isReturn && io.ras_update.bits.prediction.valid) {
ras.pop()
}
}
}
}

View File

@ -0,0 +1,61 @@
// See LICENSE for license details.
package rocket
package constants
import Chisel._
import scala.math._
trait ScalarOpConstants {
val MT_SZ = 3
val MT_X = BitPat("b???")
val MT_B = UInt("b000")
val MT_H = UInt("b001")
val MT_W = UInt("b010")
val MT_D = UInt("b011")
val MT_BU = UInt("b100")
val MT_HU = UInt("b101")
val MT_WU = UInt("b110")
def mtSize(mt: UInt) = mt(MT_SZ-2, 0)
def mtSigned(mt: UInt) = !mt(MT_SZ-1)
val SZ_BR = 3
val BR_X = BitPat("b???")
val BR_EQ = UInt(0, 3)
val BR_NE = UInt(1, 3)
val BR_J = UInt(2, 3)
val BR_N = UInt(3, 3)
val BR_LT = UInt(4, 3)
val BR_GE = UInt(5, 3)
val BR_LTU = UInt(6, 3)
val BR_GEU = UInt(7, 3)
val A1_X = BitPat("b??")
val A1_ZERO = UInt(0, 2)
val A1_RS1 = UInt(1, 2)
val A1_PC = UInt(2, 2)
val IMM_X = BitPat("b???")
val IMM_S = UInt(0, 3)
val IMM_SB = UInt(1, 3)
val IMM_U = UInt(2, 3)
val IMM_UJ = UInt(3, 3)
val IMM_I = UInt(4, 3)
val IMM_Z = UInt(5, 3)
val A2_X = BitPat("b??")
val A2_ZERO = UInt(0, 2)
val A2_SIZE = UInt(1, 2)
val A2_RS2 = UInt(2, 2)
val A2_IMM = UInt(3, 2)
val X = BitPat("b?")
val N = BitPat("b0")
val Y = BitPat("b1")
val SZ_DW = 1
val DW_X = X
val DW_32 = Bool(false)
val DW_64 = Bool(true)
val DW_XPR = DW_64
}

View File

@ -0,0 +1,589 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Util._
import Instructions._
import cde.{Parameters, Field}
import uncore.devices._
import uncore.util._
import junctions.AddrMap
class MStatus extends Bundle {
val debug = Bool() // not truly part of mstatus, but convenient
val prv = UInt(width = PRV.SZ) // not truly part of mstatus, but convenient
val sd = Bool()
val zero3 = UInt(width = 31)
val sd_rv32 = Bool()
val zero2 = UInt(width = 2)
val vm = UInt(width = 5)
val zero1 = UInt(width = 4)
val mxr = Bool()
val pum = Bool()
val mprv = Bool()
val xs = UInt(width = 2)
val fs = UInt(width = 2)
val mpp = UInt(width = 2)
val hpp = UInt(width = 2)
val spp = UInt(width = 1)
val mpie = Bool()
val hpie = Bool()
val spie = Bool()
val upie = Bool()
val mie = Bool()
val hie = Bool()
val sie = Bool()
val uie = Bool()
}
class DCSR extends Bundle {
val xdebugver = UInt(width = 2)
val ndreset = Bool()
val fullreset = Bool()
val hwbpcount = UInt(width = 12)
val ebreakm = Bool()
val ebreakh = Bool()
val ebreaks = Bool()
val ebreaku = Bool()
val zero2 = Bool()
val stopcycle = Bool()
val stoptime = Bool()
val cause = UInt(width = 3)
val debugint = Bool()
val zero1 = Bool()
val halt = Bool()
val step = Bool()
val prv = UInt(width = PRV.SZ)
}
class MIP extends Bundle {
val rocc = Bool()
val meip = Bool()
val heip = Bool()
val seip = Bool()
val ueip = Bool()
val mtip = Bool()
val htip = Bool()
val stip = Bool()
val utip = Bool()
val msip = Bool()
val hsip = Bool()
val ssip = Bool()
val usip = Bool()
}
class PTBR(implicit p: Parameters) extends CoreBundle()(p) {
require(maxPAddrBits - pgIdxBits + asIdBits <= xLen)
val asid = UInt(width = asIdBits)
val ppn = UInt(width = maxPAddrBits - pgIdxBits)
}
object PRV
{
val SZ = 2
val U = 0
val S = 1
val H = 2
val M = 3
}
object CSR
{
// commands
val SZ = 3
val X = BitPat.dontCare(SZ)
val N = UInt(0,SZ)
val W = UInt(1,SZ)
val S = UInt(2,SZ)
val C = UInt(3,SZ)
val I = UInt(4,SZ)
val R = UInt(5,SZ)
val ADDRSZ = 12
}
class CSRFileIO(implicit p: Parameters) extends CoreBundle {
val prci = new PRCITileIO().flip
val rw = new Bundle {
val addr = UInt(INPUT, CSR.ADDRSZ)
val cmd = Bits(INPUT, CSR.SZ)
val rdata = Bits(OUTPUT, xLen)
val wdata = Bits(INPUT, xLen)
}
val csr_stall = Bool(OUTPUT)
val csr_xcpt = Bool(OUTPUT)
val eret = Bool(OUTPUT)
val singleStep = Bool(OUTPUT)
val status = new MStatus().asOutput
val ptbr = new PTBR().asOutput
val evec = UInt(OUTPUT, vaddrBitsExtended)
val exception = Bool(INPUT)
val retire = UInt(INPUT, log2Up(1+retireWidth))
val custom_mrw_csrs = Vec(nCustomMrwCsrs, UInt(INPUT, xLen))
val cause = UInt(INPUT, xLen)
val pc = UInt(INPUT, vaddrBitsExtended)
val badaddr = UInt(INPUT, vaddrBitsExtended)
val fatc = Bool(OUTPUT)
val time = UInt(OUTPUT, xLen)
val fcsr_rm = Bits(OUTPUT, FPConstants.RM_SZ)
val fcsr_flags = Valid(Bits(width = FPConstants.FLAGS_SZ)).flip
val rocc = new RoCCInterface().flip
val interrupt = Bool(OUTPUT)
val interrupt_cause = UInt(OUTPUT, xLen)
val bp = Vec(p(NBreakpoints), new BP).asOutput
}
class CSRFile(implicit p: Parameters) extends CoreModule()(p)
{
val io = new CSRFileIO
val reset_mstatus = Wire(init=new MStatus().fromBits(0))
reset_mstatus.mpp := PRV.M
reset_mstatus.prv := PRV.M
val reg_mstatus = Reg(init=reset_mstatus)
val new_prv = Wire(init = reg_mstatus.prv)
reg_mstatus.prv := legalizePrivilege(new_prv)
val reset_dcsr = Wire(init=new DCSR().fromBits(0))
reset_dcsr.xdebugver := 1
reset_dcsr.prv := PRV.M
val reg_dcsr = Reg(init=reset_dcsr)
val (supported_interrupts, delegable_interrupts) = {
val sup = Wire(init=new MIP().fromBits(0))
sup.ssip := Bool(p(UseVM))
sup.msip := true
sup.stip := Bool(p(UseVM))
sup.mtip := true
sup.meip := true
sup.seip := Bool(p(UseVM))
sup.rocc := usingRoCC
val del = Wire(init=sup)
del.msip := false
del.mtip := false
del.meip := false
(sup.asUInt, del.asUInt)
}
val delegable_exceptions = UInt(Seq(
Causes.misaligned_fetch,
Causes.fault_fetch,
Causes.breakpoint,
Causes.fault_load,
Causes.fault_store,
Causes.user_ecall).map(1 << _).sum)
val exception = io.exception || io.csr_xcpt
val reg_debug = Reg(init=Bool(false))
val reg_dpc = Reg(UInt(width = vaddrBitsExtended))
val reg_dscratch = Reg(UInt(width = xLen))
val reg_singleStepped = Reg(Bool())
when (io.retire(0) || exception) { reg_singleStepped := true }
when (!io.singleStep) { reg_singleStepped := false }
assert(!io.singleStep || io.retire <= UInt(1))
assert(!reg_singleStepped || io.retire === UInt(0))
val reg_tdrselect = Reg(new TDRSelect)
val reg_bp = Reg(Vec(1 << log2Up(p(NBreakpoints)), new BP))
val reg_mie = Reg(init=UInt(0, xLen))
val reg_mideleg = Reg(init=UInt(0, xLen))
val reg_medeleg = Reg(init=UInt(0, xLen))
val reg_mip = Reg(new MIP)
val reg_mepc = Reg(UInt(width = vaddrBitsExtended))
val reg_mcause = Reg(Bits(width = xLen))
val reg_mbadaddr = Reg(UInt(width = vaddrBitsExtended))
val reg_mscratch = Reg(Bits(width = xLen))
val reg_mtvec = Reg(init=UInt(p(MtvecInit), paddrBits min xLen))
val reg_sepc = Reg(UInt(width = vaddrBitsExtended))
val reg_scause = Reg(Bits(width = xLen))
val reg_sbadaddr = Reg(UInt(width = vaddrBitsExtended))
val reg_sscratch = Reg(Bits(width = xLen))
val reg_stvec = Reg(UInt(width = vaddrBits))
val reg_sptbr = Reg(new PTBR)
val reg_wfi = Reg(init=Bool(false))
val reg_fflags = Reg(UInt(width = 5))
val reg_frm = Reg(UInt(width = 3))
val reg_instret = WideCounter(64, io.retire)
val reg_cycle: UInt = if (enableCommitLog) { reg_instret } else { WideCounter(64) }
val mip = Wire(init=reg_mip)
mip.rocc := io.rocc.interrupt
val read_mip = mip.asUInt & supported_interrupts
val pending_interrupts = read_mip & reg_mie
val m_interrupts = Mux(!reg_debug && (reg_mstatus.prv < PRV.M || (reg_mstatus.prv === PRV.M && reg_mstatus.mie)), pending_interrupts & ~reg_mideleg, UInt(0))
val s_interrupts = Mux(!reg_debug && (reg_mstatus.prv < PRV.S || (reg_mstatus.prv === PRV.S && reg_mstatus.sie)), pending_interrupts & reg_mideleg, UInt(0))
val all_interrupts = m_interrupts | s_interrupts
val interruptMSB = BigInt(1) << (xLen-1)
val interruptCause = interruptMSB + PriorityEncoder(all_interrupts)
io.interrupt := all_interrupts.orR && !io.singleStep || reg_singleStepped
io.interrupt_cause := interruptCause
io.bp := reg_bp take p(NBreakpoints)
val debugIntCause = reg_mip.getWidth
// debug interrupts are only masked by being in debug mode
when (Bool(usingDebug) && reg_dcsr.debugint && !reg_debug) {
io.interrupt := true
io.interrupt_cause := interruptMSB + debugIntCause
}
val system_insn = io.rw.cmd === CSR.I
val cpu_ren = io.rw.cmd =/= CSR.N && !system_insn
val isa_string = "IM" +
(if (usingVM) "S" else "") +
(if (usingUser) "U" else "") +
(if (usingAtomics) "A" else "") +
(if (usingFPU) "FD" else "") +
(if (usingRoCC) "X" else "")
val isa = (BigInt(log2Ceil(xLen) - 4) << (xLen-2)) |
isa_string.map(x => 1 << (x - 'A')).reduce(_|_)
val read_mstatus = io.status.asUInt()(xLen-1,0)
val read_mapping = collection.mutable.LinkedHashMap[Int,Bits](
CSRs.tdrselect -> reg_tdrselect.asUInt,
CSRs.tdrdata1 -> reg_bp(reg_tdrselect.tdrindex).control.asUInt,
CSRs.tdrdata2 -> reg_bp(reg_tdrselect.tdrindex).address,
CSRs.mimpid -> UInt(0),
CSRs.marchid -> UInt(0),
CSRs.mvendorid -> UInt(0),
CSRs.mcycle -> reg_cycle,
CSRs.minstret -> reg_instret,
CSRs.mucounteren -> UInt(0),
CSRs.mutime_delta -> UInt(0),
CSRs.mucycle_delta -> UInt(0),
CSRs.muinstret_delta -> UInt(0),
CSRs.misa -> UInt(isa),
CSRs.mstatus -> read_mstatus,
CSRs.mtvec -> reg_mtvec,
CSRs.mip -> read_mip,
CSRs.mie -> reg_mie,
CSRs.mideleg -> reg_mideleg,
CSRs.medeleg -> reg_medeleg,
CSRs.mscratch -> reg_mscratch,
CSRs.mepc -> reg_mepc.sextTo(xLen),
CSRs.mbadaddr -> reg_mbadaddr.sextTo(xLen),
CSRs.mcause -> reg_mcause,
CSRs.mhartid -> io.prci.id)
if (usingDebug) {
read_mapping += CSRs.dcsr -> reg_dcsr.asUInt
read_mapping += CSRs.dpc -> reg_dpc.asUInt
read_mapping += CSRs.dscratch -> reg_dscratch.asUInt
}
if (usingFPU) {
read_mapping += CSRs.fflags -> reg_fflags
read_mapping += CSRs.frm -> reg_frm
read_mapping += CSRs.fcsr -> Cat(reg_frm, reg_fflags)
}
if (usingVM) {
val read_sie = reg_mie & reg_mideleg
val read_sip = read_mip & reg_mideleg
val read_sstatus = Wire(init=io.status)
read_sstatus.vm := 0
read_sstatus.mprv := 0
read_sstatus.mpp := 0
read_sstatus.hpp := 0
read_sstatus.mpie := 0
read_sstatus.hpie := 0
read_sstatus.mie := 0
read_sstatus.hie := 0
read_mapping += CSRs.sstatus -> (read_sstatus.asUInt())(xLen-1,0)
read_mapping += CSRs.sip -> read_sip.asUInt
read_mapping += CSRs.sie -> read_sie.asUInt
read_mapping += CSRs.sscratch -> reg_sscratch
read_mapping += CSRs.scause -> reg_scause
read_mapping += CSRs.sbadaddr -> reg_sbadaddr.sextTo(xLen)
read_mapping += CSRs.sptbr -> reg_sptbr.asUInt
read_mapping += CSRs.sepc -> reg_sepc.sextTo(xLen)
read_mapping += CSRs.stvec -> reg_stvec.sextTo(xLen)
read_mapping += CSRs.mscounteren -> UInt(0)
read_mapping += CSRs.mstime_delta -> UInt(0)
read_mapping += CSRs.mscycle_delta -> UInt(0)
read_mapping += CSRs.msinstret_delta -> UInt(0)
}
if (xLen == 32) {
read_mapping += CSRs.mcycleh -> (reg_cycle >> 32)
read_mapping += CSRs.minstreth -> (reg_instret >> 32)
read_mapping += CSRs.mutime_deltah -> UInt(0)
read_mapping += CSRs.mucycle_deltah -> UInt(0)
read_mapping += CSRs.muinstret_deltah -> UInt(0)
if (usingVM) {
read_mapping += CSRs.mstime_deltah -> UInt(0)
read_mapping += CSRs.mscycle_deltah -> UInt(0)
read_mapping += CSRs.msinstret_deltah -> UInt(0)
}
}
for (i <- 0 until nCustomMrwCsrs) {
val addr = 0xff0 + i
require(addr < (1 << CSR.ADDRSZ))
require(!read_mapping.contains(addr), "custom MRW CSR address " + i + " is already in use")
read_mapping += addr -> io.custom_mrw_csrs(i)
}
val decoded_addr = read_mapping map { case (k, v) => k -> (io.rw.addr === k) }
val addr_valid = decoded_addr.values.reduce(_||_)
val fp_csr =
if (usingFPU) decoded_addr(CSRs.fflags) || decoded_addr(CSRs.frm) || decoded_addr(CSRs.fcsr)
else Bool(false)
val csr_debug = Bool(usingDebug) && io.rw.addr(5)
val csr_addr_priv = Cat(io.rw.addr(6,5).andR, io.rw.addr(9,8))
val priv_sufficient = Cat(reg_debug, reg_mstatus.prv) >= csr_addr_priv
val read_only = io.rw.addr(11,10).andR
val cpu_wen = cpu_ren && io.rw.cmd =/= CSR.R && priv_sufficient
val wen = cpu_wen && !read_only
val wdata = (Mux(io.rw.cmd.isOneOf(CSR.S, CSR.C), io.rw.rdata, UInt(0)) |
Mux(io.rw.cmd =/= CSR.C, io.rw.wdata, UInt(0))) &
~Mux(io.rw.cmd === CSR.C, io.rw.wdata, UInt(0))
val do_system_insn = priv_sufficient && system_insn
val opcode = UInt(1) << io.rw.addr(2,0)
val insn_call = do_system_insn && opcode(0)
val insn_break = do_system_insn && opcode(1)
val insn_ret = do_system_insn && opcode(2)
val insn_sfence_vm = do_system_insn && opcode(4)
val insn_wfi = do_system_insn && opcode(5)
io.csr_xcpt := (cpu_wen && read_only) ||
(cpu_ren && (!priv_sufficient || !addr_valid || fp_csr && !io.status.fs.orR)) ||
(system_insn && !priv_sufficient) ||
insn_call || insn_break
when (insn_wfi) { reg_wfi := true }
when (pending_interrupts.orR) { reg_wfi := false }
val cause =
Mux(!io.csr_xcpt, io.cause,
Mux(insn_call, reg_mstatus.prv + Causes.user_ecall,
Mux[UInt](insn_break, Causes.breakpoint, Causes.illegal_instruction)))
val cause_lsbs = cause(log2Up(xLen)-1,0)
val causeIsDebugInt = cause(xLen-1) && cause_lsbs === debugIntCause
val causeIsDebugBreak = cause === Causes.breakpoint && Cat(reg_dcsr.ebreakm, reg_dcsr.ebreakh, reg_dcsr.ebreaks, reg_dcsr.ebreaku)(reg_mstatus.prv)
val trapToDebug = Bool(usingDebug) && (reg_singleStepped || causeIsDebugInt || causeIsDebugBreak || reg_debug)
val delegate = Bool(p(UseVM)) && reg_mstatus.prv < PRV.M && Mux(cause(xLen-1), reg_mideleg(cause_lsbs), reg_medeleg(cause_lsbs))
val debugTVec = Mux(reg_debug, UInt(0x808), UInt(0x800))
val tvec = Mux(trapToDebug, debugTVec, Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec))
val epc = Mux(csr_debug, reg_dpc, Mux(Bool(p(UseVM)) && !csr_addr_priv(1), reg_sepc, reg_mepc))
io.fatc := insn_sfence_vm
io.evec := Mux(exception, tvec, epc)
io.ptbr := reg_sptbr
io.eret := insn_ret
io.singleStep := reg_dcsr.step && !reg_debug
io.status := reg_mstatus
io.status.sd := io.status.fs.andR || io.status.xs.andR
io.status.debug := reg_debug
if (xLen == 32)
io.status.sd_rv32 := io.status.sd
when (exception) {
val epc = ~(~io.pc | (coreInstBytes-1))
val pie = read_mstatus(reg_mstatus.prv)
val write_badaddr = cause isOneOf (Causes.breakpoint,
Causes.misaligned_load, Causes.misaligned_store, Causes.misaligned_fetch,
Causes.fault_load, Causes.fault_store, Causes.fault_fetch)
when (trapToDebug) {
reg_debug := true
reg_dpc := epc
reg_dcsr.cause := Mux(reg_singleStepped, UInt(4), Mux(causeIsDebugInt, UInt(3), UInt(1)))
reg_dcsr.prv := trimPrivilege(reg_mstatus.prv)
}.elsewhen (delegate) {
reg_sepc := epc
reg_scause := cause
when (write_badaddr) { reg_sbadaddr := io.badaddr }
reg_mstatus.spie := pie
reg_mstatus.spp := reg_mstatus.prv
reg_mstatus.sie := false
new_prv := PRV.S
}.otherwise {
reg_mepc := epc
reg_mcause := cause
when (write_badaddr) { reg_mbadaddr := io.badaddr }
reg_mstatus.mpie := pie
reg_mstatus.mpp := trimPrivilege(reg_mstatus.prv)
reg_mstatus.mie := false
new_prv := PRV.M
}
}
when (insn_ret) {
when (Bool(p(UseVM)) && !csr_addr_priv(1)) {
when (reg_mstatus.spp.toBool) { reg_mstatus.sie := reg_mstatus.spie }
reg_mstatus.spie := false
reg_mstatus.spp := PRV.U
new_prv := reg_mstatus.spp
}.elsewhen (csr_debug) {
new_prv := reg_dcsr.prv
reg_debug := false
}.otherwise {
when (reg_mstatus.mpp(1)) { reg_mstatus.mie := reg_mstatus.mpie }
.elsewhen (Bool(usingVM) && reg_mstatus.mpp(0)) { reg_mstatus.sie := reg_mstatus.mpie }
reg_mstatus.mpie := false
reg_mstatus.mpp := legalizePrivilege(PRV.U)
new_prv := reg_mstatus.mpp
}
}
assert(PopCount(insn_ret :: io.exception :: io.csr_xcpt :: Nil) <= 1, "these conditions must be mutually exclusive")
io.time := reg_cycle
io.csr_stall := reg_wfi
io.rw.rdata := Mux1H(for ((k, v) <- read_mapping) yield decoded_addr(k) -> v)
io.fcsr_rm := reg_frm
when (io.fcsr_flags.valid) {
reg_fflags := reg_fflags | io.fcsr_flags.bits
}
when (wen) {
when (decoded_addr(CSRs.mstatus)) {
val new_mstatus = new MStatus().fromBits(wdata)
reg_mstatus.mie := new_mstatus.mie
reg_mstatus.mpie := new_mstatus.mpie
if (usingUser) {
reg_mstatus.mprv := new_mstatus.mprv
reg_mstatus.mpp := trimPrivilege(new_mstatus.mpp)
if (usingVM) {
reg_mstatus.mxr := new_mstatus.mxr
reg_mstatus.pum := new_mstatus.pum
reg_mstatus.spp := new_mstatus.spp
reg_mstatus.spie := new_mstatus.spie
reg_mstatus.sie := new_mstatus.sie
}
}
if (usingVM) {
require(if (xLen == 32) pgLevels == 2 else pgLevels > 2 && pgLevels < 6)
val vm_on = 6 + pgLevels // TODO Sv48 support should imply Sv39 support
when (new_mstatus.vm === 0) { reg_mstatus.vm := 0 }
when (new_mstatus.vm === vm_on) { reg_mstatus.vm := vm_on }
}
if (usingVM || usingFPU) reg_mstatus.fs := Fill(2, new_mstatus.fs.orR)
if (usingRoCC) reg_mstatus.xs := Fill(2, new_mstatus.xs.orR)
}
when (decoded_addr(CSRs.mip)) {
val new_mip = new MIP().fromBits(wdata)
if (usingVM) {
reg_mip.ssip := new_mip.ssip
reg_mip.stip := new_mip.stip
}
}
when (decoded_addr(CSRs.mie)) { reg_mie := wdata & supported_interrupts }
when (decoded_addr(CSRs.mepc)) { reg_mepc := ~(~wdata | (coreInstBytes-1)) }
when (decoded_addr(CSRs.mscratch)) { reg_mscratch := wdata }
if (p(MtvecWritable))
when (decoded_addr(CSRs.mtvec)) { reg_mtvec := wdata >> 2 << 2 }
when (decoded_addr(CSRs.mcause)) { reg_mcause := wdata & UInt((BigInt(1) << (xLen-1)) + 31) /* only implement 5 LSBs and MSB */ }
when (decoded_addr(CSRs.mbadaddr)) { reg_mbadaddr := wdata(vaddrBitsExtended-1,0) }
if (usingFPU) {
when (decoded_addr(CSRs.fflags)) { reg_fflags := wdata }
when (decoded_addr(CSRs.frm)) { reg_frm := wdata }
when (decoded_addr(CSRs.fcsr)) { reg_fflags := wdata; reg_frm := wdata >> reg_fflags.getWidth }
}
if (usingDebug) {
when (decoded_addr(CSRs.dcsr)) {
val new_dcsr = new DCSR().fromBits(wdata)
reg_dcsr.halt := new_dcsr.halt
reg_dcsr.step := new_dcsr.step
reg_dcsr.ebreakm := new_dcsr.ebreakm
if (usingVM) reg_dcsr.ebreaks := new_dcsr.ebreaks
if (usingUser) reg_dcsr.ebreaku := new_dcsr.ebreaku
if (usingUser) reg_dcsr.prv := trimPrivilege(new_dcsr.prv)
}
when (decoded_addr(CSRs.dpc)) { reg_dpc := ~(~wdata | (coreInstBytes-1)) }
when (decoded_addr(CSRs.dscratch)) { reg_dscratch := wdata }
}
if (usingVM) {
when (decoded_addr(CSRs.sstatus)) {
val new_sstatus = new MStatus().fromBits(wdata)
reg_mstatus.sie := new_sstatus.sie
reg_mstatus.spie := new_sstatus.spie
reg_mstatus.spp := new_sstatus.spp
reg_mstatus.pum := new_sstatus.pum
reg_mstatus.fs := Fill(2, new_sstatus.fs.orR) // even without an FPU
if (usingRoCC) reg_mstatus.xs := Fill(2, new_sstatus.xs.orR)
}
when (decoded_addr(CSRs.sip)) {
val new_sip = new MIP().fromBits(wdata)
reg_mip.ssip := new_sip.ssip
}
when (decoded_addr(CSRs.sie)) { reg_mie := (reg_mie & ~reg_mideleg) | (wdata & reg_mideleg) }
when (decoded_addr(CSRs.sscratch)) { reg_sscratch := wdata }
when (decoded_addr(CSRs.sptbr)) { reg_sptbr.ppn := wdata(ppnBits-1,0) }
when (decoded_addr(CSRs.sepc)) { reg_sepc := ~(~wdata | (coreInstBytes-1)) }
when (decoded_addr(CSRs.stvec)) { reg_stvec := wdata >> 2 << 2 }
when (decoded_addr(CSRs.scause)) { reg_scause := wdata & UInt((BigInt(1) << (xLen-1)) + 31) /* only implement 5 LSBs and MSB */ }
when (decoded_addr(CSRs.sbadaddr)) { reg_sbadaddr := wdata(vaddrBitsExtended-1,0) }
when (decoded_addr(CSRs.mideleg)) { reg_mideleg := wdata & delegable_interrupts }
when (decoded_addr(CSRs.medeleg)) { reg_medeleg := wdata & delegable_exceptions }
}
if (p(NBreakpoints) > 0) {
val newTDR = new TDRSelect().fromBits(wdata)
when (decoded_addr(CSRs.tdrselect)) { reg_tdrselect.tdrindex := newTDR.tdrindex }
when (reg_tdrselect.tdrmode || reg_debug) {
when (decoded_addr(CSRs.tdrdata1)) {
val newBPC = new BPControl().fromBits(wdata)
reg_bp(reg_tdrselect.tdrindex).control := newBPC
reg_bp(reg_tdrselect.tdrindex).control.bpmatch := newBPC.bpmatch & 2 /* exact/NAPOT only */
}
when (decoded_addr(CSRs.tdrdata2)) { reg_bp(reg_tdrselect.tdrindex).address := wdata }
}
}
}
reg_mip := io.prci.interrupts
reg_dcsr.debugint := io.prci.interrupts.debug
reg_dcsr.hwbpcount := UInt(p(NBreakpoints))
reg_sptbr.asid := 0
reg_tdrselect.reserved := 0
reg_tdrselect.tdrmode := true // TODO support D-mode breakpoint theft
if (reg_bp.isEmpty) reg_tdrselect.tdrindex := 0
for (bpc <- reg_bp map {_.control}) {
bpc.tdrtype := bpc.tdrType
bpc.bpamaskmax := bpc.bpaMaskMax
bpc.reserved := 0
bpc.bpaction := 0
bpc.h := false
if (!usingVM) bpc.s := false
if (!usingUser) bpc.u := false
if (!usingVM && !usingUser) bpc.m := true
when (reset) {
bpc.r := false
bpc.w := false
bpc.x := false
}
}
for (bp <- reg_bp drop p(NBreakpoints))
bp := new BP().fromBits(0)
def legalizePrivilege(priv: UInt): UInt =
if (usingVM) Mux(priv === PRV.H, PRV.U, priv)
else if (usingUser) Fill(2, priv(0))
else PRV.M
def trimPrivilege(priv: UInt): UInt =
if (usingVM) priv
else legalizePrivilege(priv)
}

View File

@ -0,0 +1,444 @@
// See LICENSE for license details.
package rocket
import Chisel._
import junctions._
import uncore.tilelink._
import uncore.agents._
import uncore.coherence._
import uncore.util._
import uncore.constants._
import cde.{Parameters, Field}
import Util._
class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val addr = Bits(width = untagBits)
val write = Bool()
val wdata = Bits(width = rowBits)
val wmask = Bits(width = rowBytes)
val way_en = Bits(width = nWays)
}
class DCacheDataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle {
val req = Valid(new DCacheDataReq).flip
val resp = Vec(nWays, Bits(OUTPUT, rowBits))
}
val addr = io.req.bits.addr >> rowOffBits
for (w <- 0 until nWays) {
val array = SeqMem(nSets*refillCycles, Vec(rowBytes, Bits(width=8)))
val valid = io.req.valid && (Bool(nWays == 1) || io.req.bits.way_en(w))
when (valid && io.req.bits.write) {
val data = Vec.tabulate(rowBytes)(i => io.req.bits.wdata(8*(i+1)-1, 8*i))
array.write(addr, data, io.req.bits.wmask.toBools)
}
io.resp(w) := array.read(addr, valid && !io.req.bits.write).asUInt
}
}
class DCache(implicit p: Parameters) extends L1HellaCacheModule()(p) {
val io = new Bundle {
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val mem = new ClientTileLinkIO
}
val fq = Module(new FinishQueue(1))
require(rowBits == encRowBits) // no ECC
require(refillCyclesPerBeat == 1)
require(rowBits >= coreDataBits)
// tags
val replacer = p(Replacer)()
def onReset = L1Metadata(UInt(0), ClientMetadata.onReset)
val meta = Module(new MetadataArray(onReset _))
val metaReadArb = Module(new Arbiter(new MetaReadReq, 3))
val metaWriteArb = Module(new Arbiter(new L1MetaWriteReq, 3))
meta.io.read <> metaReadArb.io.out
meta.io.write <> metaWriteArb.io.out
// data
val data = Module(new DCacheDataArray)
val dataArb = Module(new Arbiter(new DCacheDataReq, 4))
data.io.req <> dataArb.io.out
dataArb.io.out.ready := true
val s1_valid = Reg(next=io.cpu.req.fire(), init=Bool(false))
val s1_probe = Reg(next=io.mem.probe.fire(), init=Bool(false))
val probe_bits = RegEnable(io.mem.probe.bits, io.mem.probe.fire())
val s1_nack = Wire(init=Bool(false))
val s1_valid_masked = s1_valid && !io.cpu.s1_kill && !io.cpu.xcpt.asUInt.orR
val s1_valid_not_nacked = s1_valid_masked && !s1_nack
val s1_req = Reg(io.cpu.req.bits)
when (metaReadArb.io.out.valid) {
s1_req := io.cpu.req.bits
s1_req.addr := Cat(io.cpu.req.bits.addr >> untagBits, metaReadArb.io.out.bits.idx, io.cpu.req.bits.addr(blockOffBits-1,0))
}
val s1_read = isRead(s1_req.cmd)
val s1_write = isWrite(s1_req.cmd)
val s1_readwrite = s1_read || s1_write
val s1_flush_valid = Reg(Bool())
val s_ready :: s_grant_wait :: s_voluntary_writeback :: s_probe_rep_dirty :: s_probe_rep_clean :: s_probe_rep_miss :: s_voluntary_write_meta :: s_probe_write_meta :: Nil = Enum(UInt(), 8)
val grant_wait = Reg(init=Bool(false))
val release_ack_wait = Reg(init=Bool(false))
val release_state = Reg(init=s_ready)
val pstore1_valid = Wire(Bool())
val pstore2_valid = Reg(Bool())
val inWriteback = release_state.isOneOf(s_voluntary_writeback, s_probe_rep_dirty)
val releaseWay = Wire(UInt())
io.cpu.req.ready := (release_state === s_ready) && !grant_wait && !s1_nack
// hit initiation path
dataArb.io.in(3).valid := io.cpu.req.valid && isRead(io.cpu.req.bits.cmd)
dataArb.io.in(3).bits.write := false
dataArb.io.in(3).bits.addr := io.cpu.req.bits.addr
dataArb.io.in(3).bits.way_en := ~UInt(0, nWays)
when (!dataArb.io.in(3).ready && isRead(io.cpu.req.bits.cmd)) { io.cpu.req.ready := false }
metaReadArb.io.in(2).valid := io.cpu.req.valid
metaReadArb.io.in(2).bits.idx := io.cpu.req.bits.addr(idxMSB, idxLSB)
metaReadArb.io.in(2).bits.way_en := ~UInt(0, nWays)
when (!metaReadArb.io.in(2).ready) { io.cpu.req.ready := false }
// address translation
val tlb = Module(new TLB)
io.ptw <> tlb.io.ptw
tlb.io.req.valid := s1_valid_masked && s1_readwrite
tlb.io.req.bits.passthrough := s1_req.phys
tlb.io.req.bits.vpn := s1_req.addr >> pgIdxBits
tlb.io.req.bits.instruction := false
tlb.io.req.bits.store := s1_write
when (!tlb.io.req.ready && !io.cpu.req.bits.phys) { io.cpu.req.ready := false }
when (s1_valid && s1_readwrite && tlb.io.resp.miss) { s1_nack := true }
val s1_paddr = Cat(tlb.io.resp.ppn, s1_req.addr(pgIdxBits-1,0))
val s1_tag = Mux(s1_probe, probe_bits.addr_block >> idxBits, s1_paddr(paddrBits-1, untagBits))
val s1_hit_way = meta.io.resp.map(r => r.coh.isValid() && r.tag === s1_tag).asUInt
val s1_hit_state = ClientMetadata.onReset.fromBits(
meta.io.resp.map(r => Mux(r.tag === s1_tag, r.coh.asUInt, UInt(0)))
.reduce (_|_))
val s1_data_way = Mux(inWriteback, releaseWay, s1_hit_way)
val s1_data = Mux1H(s1_data_way, data.io.resp) // retime into s2 if critical
val s1_victim_way = Wire(init = replacer.way)
val s2_valid = Reg(next=s1_valid_masked, init=Bool(false))
val s2_probe = Reg(next=s1_probe, init=Bool(false))
val releaseInFlight = s1_probe || s2_probe || release_state =/= s_ready
val s2_valid_masked = s2_valid && Reg(next = !s1_nack)
val s2_req = Reg(io.cpu.req.bits)
val s2_uncached = Reg(Bool())
when (s1_valid_not_nacked || s1_flush_valid) {
s2_req := s1_req
s2_req.addr := s1_paddr
s2_uncached := !tlb.io.resp.cacheable
}
val s2_read = isRead(s2_req.cmd)
val s2_write = isWrite(s2_req.cmd)
val s2_readwrite = s2_read || s2_write
val s2_flush_valid = RegNext(s1_flush_valid)
val s2_data = RegEnable(s1_data, s1_valid || inWriteback)
val s2_probe_way = RegEnable(s1_hit_way, s1_probe)
val s2_probe_state = RegEnable(s1_hit_state, s1_probe)
val s2_hit_way = RegEnable(s1_hit_way, s1_valid_not_nacked)
val s2_hit_state = RegEnable(s1_hit_state, s1_valid_not_nacked)
val s2_hit = s2_hit_state.isHit(s2_req.cmd)
val s2_valid_hit = s2_valid_masked && s2_readwrite && s2_hit
val s2_valid_miss = s2_valid_masked && s2_readwrite && !s2_hit && !(pstore1_valid || pstore2_valid) && !release_ack_wait
val s2_valid_cached_miss = s2_valid_miss && !s2_uncached
val s2_victimize = s2_valid_cached_miss || s2_flush_valid
val s2_valid_uncached = s2_valid_miss && s2_uncached
val s2_victim_way = Mux(s2_hit_state.isValid() && !s2_flush_valid, s2_hit_way, UIntToOH(RegEnable(s1_victim_way, s1_valid_not_nacked || s1_flush_valid)))
val s2_victim_tag = RegEnable(meta.io.resp(s1_victim_way).tag, s1_valid_not_nacked || s1_flush_valid)
val s2_victim_state = Mux(s2_hit_state.isValid() && !s2_flush_valid, s2_hit_state, RegEnable(meta.io.resp(s1_victim_way).coh, s1_valid_not_nacked || s1_flush_valid))
val s2_victim_valid = s2_victim_state.isValid()
val s2_victim_dirty = s2_victim_state.requiresVoluntaryWriteback()
val s2_new_hit_state = s2_hit_state.onHit(s2_req.cmd)
val s2_update_meta = s2_hit_state =/= s2_new_hit_state
io.cpu.s2_nack := s2_valid && !s2_valid_hit && !(s2_valid_uncached && io.mem.acquire.ready)
when (s2_valid && (!s2_valid_hit || s2_update_meta)) { s1_nack := true }
// exceptions
val misaligned = new StoreGen(s1_req.typ, s1_req.addr, UInt(0), wordBytes).misaligned
io.cpu.xcpt.ma.ld := s1_read && misaligned
io.cpu.xcpt.ma.st := s1_write && misaligned
io.cpu.xcpt.pf.ld := s1_read && tlb.io.resp.xcpt_ld
io.cpu.xcpt.pf.st := s1_write && tlb.io.resp.xcpt_st
// load reservations
val s2_lr = Bool(usingAtomics) && s2_req.cmd === M_XLR
val s2_sc = Bool(usingAtomics) && s2_req.cmd === M_XSC
val lrscCount = Reg(init=UInt(0))
val lrscValid = lrscCount > 0
val lrscAddr = Reg(UInt())
val s2_sc_fail = s2_sc && !(lrscValid && lrscAddr === (s2_req.addr >> blockOffBits))
when (s2_valid_hit && s2_lr) {
lrscCount := lrscCycles - 1
lrscAddr := s2_req.addr >> blockOffBits
}
when (lrscValid) { lrscCount := lrscCount - 1 }
when ((s2_valid_hit && s2_sc) || io.cpu.invalidate_lr) { lrscCount := 0 }
// pending store buffer
val pstore1_cmd = RegEnable(s1_req.cmd, s1_valid_not_nacked && s1_write)
val pstore1_typ = RegEnable(s1_req.typ, s1_valid_not_nacked && s1_write)
val pstore1_addr = RegEnable(s1_paddr, s1_valid_not_nacked && s1_write)
val pstore1_data = RegEnable(io.cpu.s1_data, s1_valid_not_nacked && s1_write)
val pstore1_way = RegEnable(s1_hit_way, s1_valid_not_nacked && s1_write)
val pstore1_storegen = new StoreGen(pstore1_typ, pstore1_addr, pstore1_data, wordBytes)
val pstore1_storegen_data = Wire(init = pstore1_storegen.data)
val pstore1_amo = Bool(usingAtomics) && isRead(pstore1_cmd)
val pstore_drain_structural = pstore1_valid && pstore2_valid && ((s1_valid && s1_write) || pstore1_amo)
val pstore_drain_opportunistic = !(io.cpu.req.valid && isRead(io.cpu.req.bits.cmd))
val pstore_drain_on_miss = releaseInFlight || io.cpu.s2_nack
val pstore_drain =
Bool(usingAtomics) && pstore_drain_structural ||
(((pstore1_valid && !pstore1_amo) || pstore2_valid) && (pstore_drain_opportunistic || pstore_drain_on_miss))
pstore1_valid := {
val s2_store_valid = s2_valid_hit && s2_write && !s2_sc_fail
val pstore1_held = Reg(Bool())
assert(!s2_store_valid || !pstore1_held)
pstore1_held := (s2_store_valid || pstore1_held) && pstore2_valid && !pstore_drain
s2_store_valid || pstore1_held
}
val advance_pstore1 = pstore1_valid && (pstore2_valid === pstore_drain)
pstore2_valid := pstore2_valid && !pstore_drain || advance_pstore1
val pstore2_addr = RegEnable(pstore1_addr, advance_pstore1)
val pstore2_way = RegEnable(pstore1_way, advance_pstore1)
val pstore2_storegen_data = RegEnable(pstore1_storegen_data, advance_pstore1)
val pstore2_storegen_mask = RegEnable(pstore1_storegen.mask, advance_pstore1)
dataArb.io.in(0).valid := pstore_drain
dataArb.io.in(0).bits.write := true
dataArb.io.in(0).bits.addr := Mux(pstore2_valid, pstore2_addr, pstore1_addr)
dataArb.io.in(0).bits.way_en := Mux(pstore2_valid, pstore2_way, pstore1_way)
dataArb.io.in(0).bits.wdata := Fill(rowWords, Mux(pstore2_valid, pstore2_storegen_data, pstore1_storegen_data))
val pstore_mask_shift = Mux(pstore2_valid, pstore2_addr, pstore1_addr).extract(rowOffBits-1,offsetlsb) << wordOffBits
dataArb.io.in(0).bits.wmask := Mux(pstore2_valid, pstore2_storegen_mask, pstore1_storegen.mask) << pstore_mask_shift
// store->load RAW hazard detection
val s1_idx = s1_req.addr(idxMSB, wordOffBits)
val s1_raw_hazard = s1_read &&
((pstore1_valid && pstore1_addr(idxMSB, wordOffBits) === s1_idx) ||
(pstore2_valid && pstore2_addr(idxMSB, wordOffBits) === s1_idx))
when (s1_valid && s1_raw_hazard) { s1_nack := true }
metaWriteArb.io.in(0).valid := (s2_valid_hit && s2_update_meta) || (s2_victimize && !s2_victim_dirty)
metaWriteArb.io.in(0).bits.way_en := s2_victim_way
metaWriteArb.io.in(0).bits.idx := s2_req.addr(idxMSB, idxLSB)
metaWriteArb.io.in(0).bits.data.coh := Mux(s2_hit, s2_new_hit_state, ClientMetadata.onReset)
metaWriteArb.io.in(0).bits.data.tag := s2_req.addr(paddrBits-1, untagBits)
// acquire
val cachedGetMessage = s2_hit_state.makeAcquire(
client_xact_id = UInt(0),
addr_block = s2_req.addr(paddrBits-1, blockOffBits),
op_code = s2_req.cmd)
val uncachedGetMessage = Get(
client_xact_id = UInt(0),
addr_block = s2_req.addr(paddrBits-1, blockOffBits),
addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
addr_byte = s2_req.addr(beatOffBits-1, 0),
operand_size = s2_req.typ,
alloc = Bool(false))
val uncachedPutOffset = s2_req.addr.extract(beatOffBits-1, wordOffBits)
val uncachedPutMessage = Put(
client_xact_id = UInt(0),
addr_block = s2_req.addr(paddrBits-1, blockOffBits),
addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
data = Fill(beatWords, pstore1_storegen.data),
wmask = Some(pstore1_storegen.mask << (uncachedPutOffset << wordOffBits)),
alloc = Bool(false))
val uncachedPutAtomicMessage = PutAtomic(
client_xact_id = UInt(0),
addr_block = s2_req.addr(paddrBits-1, blockOffBits),
addr_beat = s2_req.addr(blockOffBits-1, beatOffBits),
addr_byte = s2_req.addr(beatOffBits-1, 0),
atomic_opcode = s2_req.cmd,
operand_size = s2_req.typ,
data = Fill(beatWords, pstore1_storegen.data))
io.mem.acquire.valid := ((s2_valid_cached_miss && !s2_victim_dirty) || s2_valid_uncached) && fq.io.enq.ready
io.mem.acquire.bits := cachedGetMessage
when (s2_uncached) {
assert(!s2_valid_masked || !s2_hit_state.isValid(), "cache hit on uncached access")
io.mem.acquire.bits := uncachedGetMessage
when (s2_write) {
io.mem.acquire.bits := uncachedPutMessage
when (pstore1_amo) {
io.mem.acquire.bits := uncachedPutAtomicMessage
}
}
}
when (io.mem.acquire.fire()) { grant_wait := true }
// grant
val grantIsRefill = io.mem.grant.bits.hasMultibeatData()
val grantIsVoluntary = io.mem.grant.bits.isVoluntary()
val grantIsUncached = !grantIsRefill && !grantIsVoluntary
when (io.mem.grant.valid) {
assert(grant_wait || grantIsVoluntary && release_ack_wait, "unexpected grant")
when (grantIsUncached) { s2_data := io.mem.grant.bits.data }
when (grantIsVoluntary) { release_ack_wait := false }
}
val (refillCount, refillDone) = Counter(io.mem.grant.fire() && grantIsRefill, refillCycles)
val grantDone = refillDone || grantIsUncached
when (io.mem.grant.fire() && grantDone) { grant_wait := false }
// data refill
dataArb.io.in(1).valid := grantIsRefill && io.mem.grant.valid
io.mem.grant.ready := true
assert(dataArb.io.in(1).ready || !dataArb.io.in(1).valid)
dataArb.io.in(1).bits.write := true
dataArb.io.in(1).bits.addr := Cat(s2_req.addr(paddrBits-1, blockOffBits), io.mem.grant.bits.addr_beat) << beatOffBits
dataArb.io.in(1).bits.way_en := s2_victim_way
dataArb.io.in(1).bits.wdata := io.mem.grant.bits.data
dataArb.io.in(1).bits.wmask := ~UInt(0, rowBytes)
// tag updates on refill
metaWriteArb.io.in(1).valid := refillDone
assert(!metaWriteArb.io.in(1).valid || metaWriteArb.io.in(1).ready)
metaWriteArb.io.in(1).bits.way_en := s2_victim_way
metaWriteArb.io.in(1).bits.idx := s2_req.addr(idxMSB, idxLSB)
metaWriteArb.io.in(1).bits.data.coh := s2_hit_state.onGrant(io.mem.grant.bits, s2_req.cmd)
metaWriteArb.io.in(1).bits.data.tag := s2_req.addr(paddrBits-1, untagBits)
// finish
fq.io.enq.valid := io.mem.grant.fire() && io.mem.grant.bits.requiresAck() && (!grantIsRefill || refillDone)
fq.io.enq.bits := io.mem.grant.bits.makeFinish()
io.mem.finish <> fq.io.deq
when (fq.io.enq.valid) { assert(fq.io.enq.ready) }
when (refillDone) { replacer.miss }
// probe
val block_probe = releaseInFlight || lrscValid || (s2_valid_hit && s2_lr)
metaReadArb.io.in(1).valid := io.mem.probe.valid && !block_probe
io.mem.probe.ready := metaReadArb.io.in(1).ready && !block_probe && !s1_valid && (!s2_valid || s2_valid_hit)
metaReadArb.io.in(1).bits.idx := io.mem.probe.bits.addr_block
metaReadArb.io.in(1).bits.way_en := ~UInt(0, nWays)
// release
val (writebackCount, writebackDone) = Counter(io.mem.release.fire() && inWriteback, refillCycles)
val releaseDone = writebackDone || (io.mem.release.fire() && !inWriteback)
val releaseRejected = io.mem.release.valid && !io.mem.release.ready
val s1_release_data_valid = Reg(next = dataArb.io.in(2).fire())
val s2_release_data_valid = Reg(next = s1_release_data_valid && !releaseRejected)
val releaseDataBeat = Cat(UInt(0), writebackCount) + Mux(releaseRejected, UInt(0), s1_release_data_valid + Cat(UInt(0), s2_release_data_valid))
io.mem.release.valid := s2_release_data_valid
io.mem.release.bits := ClientMetadata.onReset.makeRelease(probe_bits)
val voluntaryReleaseMessage = s2_victim_state.makeVoluntaryWriteback(UInt(0), UInt(0))
val voluntaryNewCoh = s2_victim_state.onCacheControl(M_FLUSH)
val probeResponseMessage = s2_probe_state.makeRelease(probe_bits)
val probeNewCoh = s2_probe_state.onProbe(probe_bits)
val newCoh = Wire(init = probeNewCoh)
releaseWay := s2_probe_way
when (s2_victimize && s2_victim_dirty) {
assert(!s2_hit_state.isValid())
release_state := s_voluntary_writeback
probe_bits.addr_block := Cat(s2_victim_tag, s2_req.addr(idxMSB, idxLSB))
}
when (s2_probe) {
when (s2_probe_state.requiresVoluntaryWriteback()) { release_state := s_probe_rep_dirty }
.elsewhen (s2_probe_state.isValid()) { release_state := s_probe_rep_clean }
.otherwise {
io.mem.release.valid := true
release_state := s_probe_rep_miss
}
}
when (releaseDone) { release_state := s_ready }
when (release_state.isOneOf(s_probe_rep_miss, s_probe_rep_clean)) {
io.mem.release.valid := true
}
when (release_state.isOneOf(s_probe_rep_clean, s_probe_rep_dirty)) {
io.mem.release.bits := probeResponseMessage
when (releaseDone) { release_state := s_probe_write_meta }
}
when (release_state.isOneOf(s_voluntary_writeback, s_voluntary_write_meta)) {
io.mem.release.bits := voluntaryReleaseMessage
newCoh := voluntaryNewCoh
releaseWay := s2_victim_way
when (releaseDone) {
release_state := s_voluntary_write_meta
release_ack_wait := true
}
}
when (s2_probe && !io.mem.release.fire()) { s1_nack := true }
io.mem.release.bits.addr_block := probe_bits.addr_block
io.mem.release.bits.addr_beat := writebackCount
io.mem.release.bits.data := s2_data
dataArb.io.in(2).valid := inWriteback && releaseDataBeat < refillCycles
dataArb.io.in(2).bits.write := false
dataArb.io.in(2).bits.addr := Cat(io.mem.release.bits.addr_block, releaseDataBeat(log2Up(refillCycles)-1,0)) << rowOffBits
dataArb.io.in(2).bits.way_en := ~UInt(0, nWays)
metaWriteArb.io.in(2).valid := release_state.isOneOf(s_voluntary_write_meta, s_probe_write_meta)
metaWriteArb.io.in(2).bits.way_en := releaseWay
metaWriteArb.io.in(2).bits.idx := io.mem.release.bits.full_addr()(idxMSB, idxLSB)
metaWriteArb.io.in(2).bits.data.coh := newCoh
metaWriteArb.io.in(2).bits.data.tag := io.mem.release.bits.full_addr()(paddrBits-1, untagBits)
when (metaWriteArb.io.in(2).fire()) { release_state := s_ready }
// cached response
io.cpu.resp.valid := s2_valid_hit
io.cpu.resp.bits := s2_req
io.cpu.resp.bits.has_data := s2_read
io.cpu.resp.bits.replay := false
io.cpu.ordered := !(s1_valid || s2_valid || grant_wait)
// uncached response
io.cpu.replay_next := io.mem.grant.valid && grantIsUncached
val doUncachedResp = Reg(next = io.cpu.replay_next)
when (doUncachedResp) {
assert(!s2_valid_hit)
io.cpu.resp.valid := true
io.cpu.resp.bits.replay := true
}
// load data subword mux/sign extension
val s2_word_idx = s2_req.addr.extract(log2Up(rowBits/8)-1, log2Up(wordBytes))
val s2_data_word = s2_data >> Cat(s2_word_idx, UInt(0, log2Up(coreDataBits)))
val loadgen = new LoadGen(s2_req.typ, mtSigned(s2_req.typ), s2_req.addr, s2_data_word, s2_sc, wordBytes)
io.cpu.resp.bits.data := loadgen.data | s2_sc_fail
io.cpu.resp.bits.data_word_bypass := loadgen.wordData
io.cpu.resp.bits.store_data := pstore1_data
// AMOs
if (usingAtomics) {
val amoalu = Module(new AMOALU(xLen))
amoalu.io.addr := pstore1_addr
amoalu.io.cmd := pstore1_cmd
amoalu.io.typ := pstore1_typ
amoalu.io.lhs := s2_data_word
amoalu.io.rhs := pstore1_data
pstore1_storegen_data := amoalu.io.out
} else {
assert(!(s1_valid_masked && s1_read && s1_write), "unsupported D$ operation")
}
// flushes
val flushed = Reg(init=Bool(true))
val flushing = Reg(init=Bool(false))
val flushCounter = Counter(nSets * nWays)
when (io.mem.acquire.fire()) { flushed := false }
when (s2_valid_masked && s2_req.cmd === M_FLUSH_ALL) {
io.cpu.s2_nack := !flushed
when (!flushed) {
flushing := !release_ack_wait
}
}
s1_flush_valid := metaReadArb.io.in(0).fire() && !s1_flush_valid && !s2_flush_valid && release_state === s_ready && !release_ack_wait
metaReadArb.io.in(0).valid := flushing
metaReadArb.io.in(0).bits.idx := flushCounter.value
metaReadArb.io.in(0).bits.way_en := ~UInt(0, nWays)
when (flushing) {
s1_victim_way := flushCounter.value >> log2Up(nSets)
when (s2_flush_valid) {
when (flushCounter.inc()) {
flushed := true
}
}
when (flushed && release_state === s_ready && !release_ack_wait) {
flushing := false
}
}
}

View File

@ -0,0 +1,203 @@
// See LICENSE for license details.
package rocket
import Chisel._
object DecodeLogic
{
def term(lit: BitPat) =
new Term(lit.value, BigInt(2).pow(lit.getWidth)-(lit.mask+1))
def logic(addr: UInt, addrWidth: Int, cache: scala.collection.mutable.Map[Term,Bool], terms: Seq[Term]) = {
terms.map { t =>
cache.getOrElseUpdate(t, (if (t.mask == 0) addr else addr & Bits(BigInt(2).pow(addrWidth)-(t.mask+1), addrWidth)) === Bits(t.value, addrWidth))
}.foldLeft(Bool(false))(_||_)
}
def apply(addr: UInt, default: BitPat, mapping: Iterable[(BitPat, BitPat)]): UInt = {
val cache = caches.getOrElseUpdate(addr, collection.mutable.Map[Term,Bool]())
val dterm = term(default)
val (keys, values) = mapping.unzip
val addrWidth = keys.map(_.getWidth).max
val terms = keys.toList.map(k => term(k))
val termvalues = terms zip values.toList.map(term(_))
for (t <- keys.zip(terms).tails; if !t.isEmpty)
for (u <- t.tail)
assert(!t.head._2.intersects(u._2), "DecodeLogic: keys " + t.head + " and " + u + " overlap")
Cat((0 until default.getWidth.max(values.map(_.getWidth).max)).map({ case (i: Int) =>
val mint = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 1 }.map(_._1)
val maxt = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 0 && ((t.value >> i) & 1) == 0 }.map(_._1)
val dc = termvalues.filter { case (k,t) => ((t.mask >> i) & 1) == 1 }.map(_._1)
if (((dterm.mask >> i) & 1) != 0) {
logic(addr, addrWidth, cache, SimplifyDC(mint, maxt, addrWidth))
} else {
val defbit = (dterm.value.toInt >> i) & 1
val t = if (defbit == 0) mint else maxt
val bit = logic(addr, addrWidth, cache, Simplify(t, dc, addrWidth))
if (defbit == 0) bit else ~bit
}
}).reverse)
}
def apply(addr: UInt, default: Seq[BitPat], mappingIn: Iterable[(BitPat, Seq[BitPat])]): Seq[UInt] = {
val mapping = collection.mutable.ArrayBuffer.fill(default.size)(collection.mutable.ArrayBuffer[(BitPat, BitPat)]())
for ((key, values) <- mappingIn)
for ((value, i) <- values zipWithIndex)
mapping(i) += key -> value
for ((thisDefault, thisMapping) <- default zip mapping)
yield apply(addr, thisDefault, thisMapping)
}
def apply(addr: UInt, default: Seq[BitPat], mappingIn: List[(UInt, Seq[BitPat])]): Seq[UInt] =
apply(addr, default, mappingIn.map(m => (BitPat(m._1), m._2)).asInstanceOf[Iterable[(BitPat, Seq[BitPat])]])
def apply(addr: UInt, trues: Iterable[UInt], falses: Iterable[UInt]): Bool =
apply(addr, BitPat.dontCare(1), trues.map(BitPat(_) -> BitPat("b1")) ++ falses.map(BitPat(_) -> BitPat("b0"))).toBool
private val caches = collection.mutable.Map[UInt,collection.mutable.Map[Term,Bool]]()
}
class Term(val value: BigInt, val mask: BigInt = 0)
{
var prime = true
def covers(x: Term) = ((value ^ x.value) &~ mask | x.mask &~ mask) == 0
def intersects(x: Term) = ((value ^ x.value) &~ mask &~ x.mask) == 0
override def equals(that: Any) = that match {
case x: Term => x.value == value && x.mask == mask
case _ => false
}
override def hashCode = value.toInt
def < (that: Term) = value < that.value || value == that.value && mask < that.mask
def similar(x: Term) = {
val diff = value - x.value
mask == x.mask && value > x.value && (diff & diff-1) == 0
}
def merge(x: Term) = {
prime = false
x.prime = false
val bit = value - x.value
new Term(value &~ bit, mask | bit)
}
override def toString = value.toString(16) + "-" + mask.toString(16) + (if (prime) "p" else "")
}
object Simplify
{
def getPrimeImplicants(implicants: Seq[Term], bits: Int) = {
var prime = List[Term]()
implicants.foreach(_.prime = true)
val cols = (0 to bits).map(b => implicants.filter(b == _.mask.bitCount))
val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))
for (i <- 0 to bits) {
for (j <- 0 until bits-i)
table(i)(j).foreach(a => table(i+1)(j) ++= table(i)(j+1).filter(_.similar(a)).map(_.merge(a)))
for (r <- table(i))
for (p <- r; if p.prime)
prime = p :: prime
}
prime.sortWith(_<_)
}
def getEssentialPrimeImplicants(prime: Seq[Term], minterms: Seq[Term]): (Seq[Term],Seq[Term],Seq[Term]) = {
for (i <- 0 until prime.size) {
val icover = minterms.filter(prime(i) covers _)
for (j <- 0 until prime.size) {
val jcover = minterms.filter(prime(j) covers _)
if (icover.size > jcover.size && jcover.forall(prime(i) covers _))
return getEssentialPrimeImplicants(prime.filter(_ != prime(j)), minterms)
}
}
val essentiallyCovered = minterms.filter(t => prime.count(_ covers t) == 1)
val essential = prime.filter(p => essentiallyCovered.exists(p covers _))
val nonessential = prime.filterNot(essential contains _)
val uncovered = minterms.filterNot(t => essential.exists(_ covers t))
if (essential.isEmpty || uncovered.isEmpty)
(essential, nonessential, uncovered)
else {
val (a, b, c) = getEssentialPrimeImplicants(nonessential, uncovered)
(essential ++ a, b, c)
}
}
def getCost(cover: Seq[Term], bits: Int) = cover.map(bits - _.mask.bitCount).sum
def cheaper(a: List[Term], b: List[Term], bits: Int) = {
val ca = getCost(a, bits)
val cb = getCost(b, bits)
def listLess(a: List[Term], b: List[Term]): Boolean = !b.isEmpty && (a.isEmpty || a.head < b.head || a.head == b.head && listLess(a.tail, b.tail))
ca < cb || ca == cb && listLess(a.sortWith(_<_), b.sortWith(_<_))
}
def getCover(implicants: Seq[Term], minterms: Seq[Term], bits: Int) = {
if (minterms.nonEmpty) {
val cover = minterms.map(m => implicants.filter(_.covers(m)).map(i => collection.mutable.Set(i)))
val all = cover.reduceLeft((c0, c1) => c0.map(a => c1.map(_ ++ a)).reduceLeft(_++_))
all.map(_.toList).reduceLeft((a, b) => if (cheaper(a, b, bits)) a else b)
} else
Seq[Term]()
}
def stringify(s: Seq[Term], bits: Int) = s.map(t => (0 until bits).map(i => if ((t.mask & (1 << i)) != 0) "x" else ((t.value >> i) & 1).toString).reduceLeft(_+_).reverse).reduceLeft(_+" + "+_)
def apply(minterms: Seq[Term], dontcares: Seq[Term], bits: Int) = {
val prime = getPrimeImplicants(minterms ++ dontcares, bits)
minterms.foreach(t => assert(prime.exists(_.covers(t))))
val (eprime, prime2, uncovered) = getEssentialPrimeImplicants(prime, minterms)
val cover = eprime ++ getCover(prime2, uncovered, bits)
minterms.foreach(t => assert(cover.exists(_.covers(t)))) // sanity check
cover
}
}
object SimplifyDC
{
def getImplicitDC(maxterms: Seq[Term], term: Term, bits: Int, above: Boolean): Term = {
for (i <- 0 until bits) {
var t: Term = null
if (above && ((term.value | term.mask) & (BigInt(1) << i)) == 0)
t = new Term(term.value | (BigInt(1) << i), term.mask)
else if (!above && (term.value & (BigInt(1) << i)) != 0)
t = new Term(term.value & ~(BigInt(1) << i), term.mask)
if (t != null && !maxterms.exists(_.intersects(t)))
return t
}
null
}
def getPrimeImplicants(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
var prime = List[Term]()
minterms.foreach(_.prime = true)
var mint = minterms.map(t => new Term(t.value, t.mask))
val cols = (0 to bits).map(b => mint.filter(b == _.mask.bitCount))
val table = cols.map(c => (0 to bits).map(b => collection.mutable.Set(c.filter(b == _.value.bitCount):_*)))
for (i <- 0 to bits) {
for (j <- 0 until bits-i) {
table(i)(j).foreach(a => table(i+1)(j) ++= table(i)(j+1).filter(_ similar a).map(_ merge a))
}
for (j <- 0 until bits-i) {
for (a <- table(i)(j).filter(_.prime)) {
val dc = getImplicitDC(maxterms, a, bits, true)
if (dc != null)
table(i+1)(j) += dc merge a
}
for (a <- table(i)(j+1).filter(_.prime)) {
val dc = getImplicitDC(maxterms, a, bits, false)
if (dc != null)
table(i+1)(j) += a merge dc
}
}
for (r <- table(i))
for (p <- r; if p.prime)
prime = p :: prime
}
prime.sortWith(_<_)
}
def verify(cover: Seq[Term], minterms: Seq[Term], maxterms: Seq[Term]) = {
assert(minterms.forall(t => cover.exists(_ covers t)))
assert(maxterms.forall(t => !cover.exists(_ intersects t)))
}
def apply(minterms: Seq[Term], maxterms: Seq[Term], bits: Int) = {
val prime = getPrimeImplicants(minterms, maxterms, bits)
val (eprime, prime2, uncovered) = Simplify.getEssentialPrimeImplicants(prime, minterms)
val cover = eprime ++ Simplify.getCover(prime2, uncovered, bits)
verify(cover, minterms, maxterms)
cover
}
}

View File

@ -0,0 +1,96 @@
// See LICENSE for license details.
package rocket
import Chisel._
import cde.{Parameters, Field}
import Instructions._
object ALU
{
val SZ_ALU_FN = 4
val FN_X = BitPat("b????")
val FN_ADD = UInt(0)
val FN_SL = UInt(1)
val FN_SEQ = UInt(2)
val FN_SNE = UInt(3)
val FN_XOR = UInt(4)
val FN_SR = UInt(5)
val FN_OR = UInt(6)
val FN_AND = UInt(7)
val FN_SUB = UInt(10)
val FN_SRA = UInt(11)
val FN_SLT = UInt(12)
val FN_SGE = UInt(13)
val FN_SLTU = UInt(14)
val FN_SGEU = UInt(15)
val FN_DIV = FN_XOR
val FN_DIVU = FN_SR
val FN_REM = FN_OR
val FN_REMU = FN_AND
val FN_MUL = FN_ADD
val FN_MULH = FN_SL
val FN_MULHSU = FN_SLT
val FN_MULHU = FN_SLTU
def isMulFN(fn: UInt, cmp: UInt) = fn(1,0) === cmp(1,0)
def isSub(cmd: UInt) = cmd(3)
def isCmp(cmd: UInt) = cmd === FN_SEQ || cmd === FN_SNE || cmd >= FN_SLT
def cmpUnsigned(cmd: UInt) = cmd(1)
def cmpInverted(cmd: UInt) = cmd(0)
def cmpEq(cmd: UInt) = !cmd(3)
}
import ALU._
class ALU(implicit p: Parameters) extends CoreModule()(p) {
val io = new Bundle {
val dw = Bits(INPUT, SZ_DW)
val fn = Bits(INPUT, SZ_ALU_FN)
val in2 = UInt(INPUT, xLen)
val in1 = UInt(INPUT, xLen)
val out = UInt(OUTPUT, xLen)
val adder_out = UInt(OUTPUT, xLen)
val cmp_out = Bool(OUTPUT)
}
// ADD, SUB
val in2_inv = Mux(isSub(io.fn), ~io.in2, io.in2)
val in1_xor_in2 = io.in1 ^ in2_inv
io.adder_out := io.in1 + in2_inv + isSub(io.fn)
// SLT, SLTU
io.cmp_out := cmpInverted(io.fn) ^
Mux(cmpEq(io.fn), in1_xor_in2 === UInt(0),
Mux(io.in1(xLen-1) === io.in2(xLen-1), io.adder_out(xLen-1),
Mux(cmpUnsigned(io.fn), io.in2(xLen-1), io.in1(xLen-1))))
// SLL, SRL, SRA
val (shamt, shin_r) =
if (xLen == 32) (io.in2(4,0), io.in1)
else {
require(xLen == 64)
val shin_hi_32 = Fill(32, isSub(io.fn) && io.in1(31))
val shin_hi = Mux(io.dw === DW_64, io.in1(63,32), shin_hi_32)
val shamt = Cat(io.in2(5) & (io.dw === DW_64), io.in2(4,0))
(shamt, Cat(shin_hi, io.in1(31,0)))
}
val shin = Mux(io.fn === FN_SR || io.fn === FN_SRA, shin_r, Reverse(shin_r))
val shout_r = (Cat(isSub(io.fn) & shin(xLen-1), shin).asSInt >> shamt)(xLen-1,0)
val shout_l = Reverse(shout_r)
val shout = Mux(io.fn === FN_SR || io.fn === FN_SRA, shout_r, UInt(0)) |
Mux(io.fn === FN_SL, shout_l, UInt(0))
// AND, OR, XOR
val logic = Mux(io.fn === FN_XOR || io.fn === FN_OR, in1_xor_in2, UInt(0)) |
Mux(io.fn === FN_OR || io.fn === FN_AND, io.in1 & io.in2, UInt(0))
val shift_logic = (isCmp(io.fn) && io.cmp_out) | logic | shout
val out = Mux(io.fn === FN_ADD || io.fn === FN_SUB, io.adder_out, shift_logic)
io.out := out
if (xLen > 32) {
require(xLen == 64)
when (io.dw === DW_32) { io.out := Cat(Fill(32, out(31)), out(31,0)) }
}
}

View File

@ -0,0 +1,654 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Instructions._
import Util._
import FPConstants._
import uncore.constants.MemoryOpConstants._
import uncore.util._
import cde.{Parameters, Field}
case class FPUConfig(
divSqrt: Boolean = true,
sfmaLatency: Int = 2,
dfmaLatency: Int = 3
)
object FPConstants
{
val FCMD_ADD = BitPat("b0??00")
val FCMD_SUB = BitPat("b0??01")
val FCMD_MUL = BitPat("b0??10")
val FCMD_MADD = BitPat("b1??00")
val FCMD_MSUB = BitPat("b1??01")
val FCMD_NMSUB = BitPat("b1??10")
val FCMD_NMADD = BitPat("b1??11")
val FCMD_DIV = BitPat("b?0011")
val FCMD_SQRT = BitPat("b?1011")
val FCMD_SGNJ = BitPat("b??1?0")
val FCMD_MINMAX = BitPat("b?01?1")
val FCMD_CVT_FF = BitPat("b??0??")
val FCMD_CVT_IF = BitPat("b?10??")
val FCMD_CMP = BitPat("b?01??")
val FCMD_MV_XF = BitPat("b?11??")
val FCMD_CVT_FI = BitPat("b??0??")
val FCMD_MV_FX = BitPat("b??1??")
val FCMD_X = BitPat("b?????")
val FCMD_WIDTH = 5
val RM_SZ = 3
val FLAGS_SZ = 5
}
class FPUCtrlSigs extends Bundle
{
val cmd = Bits(width = FCMD_WIDTH)
val ldst = Bool()
val wen = Bool()
val ren1 = Bool()
val ren2 = Bool()
val ren3 = Bool()
val swap12 = Bool()
val swap23 = Bool()
val single = Bool()
val fromint = Bool()
val toint = Bool()
val fastpipe = Bool()
val fma = Bool()
val div = Bool()
val sqrt = Bool()
val round = Bool()
val wflags = Bool()
}
class FPUDecoder extends Module
{
val io = new Bundle {
val inst = Bits(INPUT, 32)
val sigs = new FPUCtrlSigs().asOutput
}
val decoder = DecodeLogic(io.inst,
List (FCMD_X, X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X),
Array(FLW -> List(FCMD_X, Y,Y,N,N,N,X,X,Y,N,N,N,N,N,N,N,N),
FLD -> List(FCMD_X, Y,Y,N,N,N,X,X,N,N,N,N,N,N,N,N,N),
FSW -> List(FCMD_MV_XF, Y,N,N,Y,N,Y,X,Y,N,Y,N,N,N,N,N,N),
FSD -> List(FCMD_MV_XF, Y,N,N,Y,N,Y,X,N,N,Y,N,N,N,N,N,N),
FMV_S_X -> List(FCMD_MV_FX, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,N),
FMV_D_X -> List(FCMD_MV_FX, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,N),
FCVT_S_W -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
FCVT_S_WU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
FCVT_S_L -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
FCVT_S_LU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,Y,Y,N,N,N,N,N,Y,Y),
FCVT_D_W -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
FCVT_D_WU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
FCVT_D_L -> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
FCVT_D_LU-> List(FCMD_CVT_FI, N,Y,N,N,N,X,X,N,Y,N,N,N,N,N,Y,Y),
FMV_X_S -> List(FCMD_MV_XF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,N),
FMV_X_D -> List(FCMD_MV_XF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,N),
FCLASS_S -> List(FCMD_MV_XF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,N),
FCLASS_D -> List(FCMD_MV_XF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,N),
FCVT_W_S -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
FCVT_WU_S-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
FCVT_L_S -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
FCVT_LU_S-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,Y,N,Y,N,N,N,N,Y,Y),
FCVT_W_D -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
FCVT_WU_D-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
FCVT_L_D -> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
FCVT_LU_D-> List(FCMD_CVT_IF, N,N,Y,N,N,N,X,N,N,Y,N,N,N,N,Y,Y),
FCVT_S_D -> List(FCMD_CVT_FF, N,Y,Y,N,N,N,X,Y,N,N,Y,N,N,N,Y,Y),
FCVT_D_S -> List(FCMD_CVT_FF, N,Y,Y,N,N,N,X,N,N,N,Y,N,N,N,Y,Y),
FEQ_S -> List(FCMD_CMP, N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
FLT_S -> List(FCMD_CMP, N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
FLE_S -> List(FCMD_CMP, N,N,Y,Y,N,N,N,Y,N,Y,N,N,N,N,N,Y),
FEQ_D -> List(FCMD_CMP, N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
FLT_D -> List(FCMD_CMP, N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
FLE_D -> List(FCMD_CMP, N,N,Y,Y,N,N,N,N,N,Y,N,N,N,N,N,Y),
FSGNJ_S -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
FSGNJN_S -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
FSGNJX_S -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,N),
FSGNJ_D -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
FSGNJN_D -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
FSGNJX_D -> List(FCMD_SGNJ, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,N),
FMIN_S -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,Y),
FMAX_S -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,Y,N,N,Y,N,N,N,N,Y),
FMIN_D -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,Y),
FMAX_D -> List(FCMD_MINMAX, N,Y,Y,Y,N,N,N,N,N,N,Y,N,N,N,N,Y),
FADD_S -> List(FCMD_ADD, N,Y,Y,Y,N,N,Y,Y,N,N,N,Y,N,N,Y,Y),
FSUB_S -> List(FCMD_SUB, N,Y,Y,Y,N,N,Y,Y,N,N,N,Y,N,N,Y,Y),
FMUL_S -> List(FCMD_MUL, N,Y,Y,Y,N,N,N,Y,N,N,N,Y,N,N,Y,Y),
FADD_D -> List(FCMD_ADD, N,Y,Y,Y,N,N,Y,N,N,N,N,Y,N,N,Y,Y),
FSUB_D -> List(FCMD_SUB, N,Y,Y,Y,N,N,Y,N,N,N,N,Y,N,N,Y,Y),
FMUL_D -> List(FCMD_MUL, N,Y,Y,Y,N,N,N,N,N,N,N,Y,N,N,Y,Y),
FMADD_S -> List(FCMD_MADD, N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
FMSUB_S -> List(FCMD_MSUB, N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
FNMADD_S -> List(FCMD_NMADD, N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
FNMSUB_S -> List(FCMD_NMSUB, N,Y,Y,Y,Y,N,N,Y,N,N,N,Y,N,N,Y,Y),
FMADD_D -> List(FCMD_MADD, N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
FMSUB_D -> List(FCMD_MSUB, N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
FNMADD_D -> List(FCMD_NMADD, N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
FNMSUB_D -> List(FCMD_NMSUB, N,Y,Y,Y,Y,N,N,N,N,N,N,Y,N,N,Y,Y),
FDIV_S -> List(FCMD_DIV, N,Y,Y,Y,N,N,N,Y,N,N,N,N,Y,N,Y,Y),
FSQRT_S -> List(FCMD_SQRT, N,Y,Y,N,N,Y,X,Y,N,N,N,N,N,Y,Y,Y),
FDIV_D -> List(FCMD_DIV, N,Y,Y,Y,N,N,N,N,N,N,N,N,Y,N,Y,Y),
FSQRT_D -> List(FCMD_SQRT, N,Y,Y,N,N,Y,X,N,N,N,N,N,N,Y,Y,Y)
))
val s = io.sigs
val sigs = Seq(s.cmd, s.ldst, s.wen, s.ren1, s.ren2, s.ren3, s.swap12,
s.swap23, s.single, s.fromint, s.toint, s.fastpipe, s.fma,
s.div, s.sqrt, s.round, s.wflags)
sigs zip decoder map {case(s,d) => s := d}
}
class FPUIO(implicit p: Parameters) extends CoreBundle {
val inst = Bits(INPUT, 32)
val fromint_data = Bits(INPUT, xLen)
val fcsr_rm = Bits(INPUT, FPConstants.RM_SZ)
val fcsr_flags = Valid(Bits(width = FPConstants.FLAGS_SZ))
val store_data = Bits(OUTPUT, 64)
val toint_data = Bits(OUTPUT, xLen)
val dmem_resp_val = Bool(INPUT)
val dmem_resp_type = Bits(INPUT, 3)
val dmem_resp_tag = UInt(INPUT, 5)
val dmem_resp_data = Bits(INPUT, 64)
val valid = Bool(INPUT)
val fcsr_rdy = Bool(OUTPUT)
val nack_mem = Bool(OUTPUT)
val illegal_rm = Bool(OUTPUT)
val killx = Bool(INPUT)
val killm = Bool(INPUT)
val dec = new FPUCtrlSigs().asOutput
val sboard_set = Bool(OUTPUT)
val sboard_clr = Bool(OUTPUT)
val sboard_clra = UInt(OUTPUT, 5)
val cp_req = Decoupled(new FPInput()).flip //cp doesn't pay attn to kill sigs
val cp_resp = Decoupled(new FPResult())
}
class FPResult extends Bundle
{
val data = Bits(width = 65)
val exc = Bits(width = 5)
}
class FPInput extends FPUCtrlSigs {
val rm = Bits(width = 3)
val typ = Bits(width = 2)
val in1 = Bits(width = 65)
val in2 = Bits(width = 65)
val in3 = Bits(width = 65)
}
object ClassifyRecFN {
def apply(expWidth: Int, sigWidth: Int, in: UInt) = {
val sign = in(sigWidth + expWidth)
val exp = in(sigWidth + expWidth - 1, sigWidth - 1)
val sig = in(sigWidth - 2, 0)
val code = exp(expWidth,expWidth-2)
val codeHi = code(2, 1)
val isSpecial = codeHi === UInt(3)
val isHighSubnormalIn = exp(expWidth-2, 0) < UInt(2)
val isSubnormal = code === UInt(1) || codeHi === UInt(1) && isHighSubnormalIn
val isNormal = codeHi === UInt(1) && !isHighSubnormalIn || codeHi === UInt(2)
val isZero = code === UInt(0)
val isInf = isSpecial && !exp(expWidth-2)
val isNaN = code.andR
val isSNaN = isNaN && !sig(sigWidth-2)
val isQNaN = isNaN && sig(sigWidth-2)
Cat(isQNaN, isSNaN, isInf && !sign, isNormal && !sign,
isSubnormal && !sign, isZero && !sign, isZero && sign,
isSubnormal && sign, isNormal && sign, isInf && sign)
}
}
class FPToInt extends Module
{
val io = new Bundle {
val in = Valid(new FPInput).flip
val as_double = new FPInput().asOutput
val out = Valid(new Bundle {
val lt = Bool()
val store = Bits(width = 64)
val toint = Bits(width = 64)
val exc = Bits(width = 5)
})
}
val in = Reg(new FPInput)
val valid = Reg(next=io.in.valid)
def upconvert(x: UInt) = {
val s2d = Module(new hardfloat.RecFNToRecFN(8, 24, 11, 53))
s2d.io.in := x
s2d.io.roundingMode := UInt(0)
s2d.io.out
}
val in1_upconvert = upconvert(io.in.bits.in1)
val in2_upconvert = upconvert(io.in.bits.in2)
when (io.in.valid) {
in := io.in.bits
when (io.in.bits.single && !io.in.bits.ldst && io.in.bits.cmd =/= FCMD_MV_XF) {
in.in1 := in1_upconvert
in.in2 := in2_upconvert
}
}
val unrec_s = hardfloat.fNFromRecFN(8, 24, in.in1)
val unrec_d = hardfloat.fNFromRecFN(11, 53, in.in1)
val unrec_out = Mux(in.single, Cat(Fill(32, unrec_s(31)), unrec_s), unrec_d)
val classify_s = ClassifyRecFN(8, 24, in.in1)
val classify_d = ClassifyRecFN(11, 53, in.in1)
val classify_out = Mux(in.single, classify_s, classify_d)
val dcmp = Module(new hardfloat.CompareRecFN(11, 53))
dcmp.io.a := in.in1
dcmp.io.b := in.in2
dcmp.io.signaling := Bool(true)
val dcmp_out = (~in.rm & Cat(dcmp.io.lt, dcmp.io.eq)).orR
val dcmp_exc = dcmp.io.exceptionFlags
val d2l = Module(new hardfloat.RecFNToIN(11, 53, 64))
val d2w = Module(new hardfloat.RecFNToIN(11, 53, 32))
d2l.io.in := in.in1
d2l.io.roundingMode := in.rm
d2l.io.signedOut := ~in.typ(0)
d2w.io.in := in.in1
d2w.io.roundingMode := in.rm
d2w.io.signedOut := ~in.typ(0)
io.out.bits.toint := Mux(in.rm(0), classify_out, unrec_out)
io.out.bits.store := unrec_out
io.out.bits.exc := Bits(0)
when (in.cmd === FCMD_CMP) {
io.out.bits.toint := dcmp_out
io.out.bits.exc := dcmp_exc
}
when (in.cmd === FCMD_CVT_IF) {
io.out.bits.toint := Mux(in.typ(1), d2l.io.out.asSInt, d2w.io.out.asSInt).asUInt
val dflags = Mux(in.typ(1), d2l.io.intExceptionFlags, d2w.io.intExceptionFlags)
io.out.bits.exc := Cat(dflags(2, 1).orR, UInt(0, 3), dflags(0))
}
io.out.valid := valid
io.out.bits.lt := dcmp.io.lt
io.as_double := in
}
class IntToFP(val latency: Int) extends Module
{
val io = new Bundle {
val in = Valid(new FPInput).flip
val out = Valid(new FPResult)
}
val in = Pipe(io.in)
val mux = Wire(new FPResult)
mux.exc := Bits(0)
mux.data := hardfloat.recFNFromFN(11, 53, in.bits.in1)
when (in.bits.single) {
mux.data := Cat(SInt(-1, 32), hardfloat.recFNFromFN(8, 24, in.bits.in1))
}
val longValue =
Mux(in.bits.typ(1), in.bits.in1.asSInt,
Mux(in.bits.typ(0), in.bits.in1(31,0).zext, in.bits.in1(31,0).asSInt))
val l2s = Module(new hardfloat.INToRecFN(64, 8, 24))
l2s.io.signedIn := ~in.bits.typ(0)
l2s.io.in := longValue.asUInt
l2s.io.roundingMode := in.bits.rm
val l2d = Module(new hardfloat.INToRecFN(64, 11, 53))
l2d.io.signedIn := ~in.bits.typ(0)
l2d.io.in := longValue.asUInt
l2d.io.roundingMode := in.bits.rm
when (in.bits.cmd === FCMD_CVT_FI) {
when (in.bits.single) {
mux.data := Cat(SInt(-1, 32), l2s.io.out)
mux.exc := l2s.io.exceptionFlags
}.otherwise {
mux.data := l2d.io.out
mux.exc := l2d.io.exceptionFlags
}
}
io.out <> Pipe(in.valid, mux, latency-1)
}
class FPToFP(val latency: Int) extends Module
{
val io = new Bundle {
val in = Valid(new FPInput).flip
val out = Valid(new FPResult)
val lt = Bool(INPUT) // from FPToInt
}
val in = Pipe(io.in)
// fp->fp units
val isSgnj = in.bits.cmd === FCMD_SGNJ
def fsgnjSign(in1: Bits, in2: Bits, pos: Int, en: Bool, rm: Bits) =
Mux(rm(1) || !en, in1(pos), rm(0)) ^ (en && in2(pos))
val sign_s = fsgnjSign(in.bits.in1, in.bits.in2, 32, in.bits.single && isSgnj, in.bits.rm)
val sign_d = fsgnjSign(in.bits.in1, in.bits.in2, 64, !in.bits.single && isSgnj, in.bits.rm)
val fsgnj = Cat(sign_d, in.bits.in1(63,33), sign_s, in.bits.in1(31,0))
val s2d = Module(new hardfloat.RecFNToRecFN(8, 24, 11, 53))
val d2s = Module(new hardfloat.RecFNToRecFN(11, 53, 8, 24))
s2d.io.in := in.bits.in1
s2d.io.roundingMode := in.bits.rm
d2s.io.in := in.bits.in1
d2s.io.roundingMode := in.bits.rm
val isnan1 = Mux(in.bits.single, in.bits.in1(31,29).andR, in.bits.in1(63,61).andR)
val isnan2 = Mux(in.bits.single, in.bits.in2(31,29).andR, in.bits.in2(63,61).andR)
val issnan1 = isnan1 && ~Mux(in.bits.single, in.bits.in1(22), in.bits.in1(51))
val issnan2 = isnan2 && ~Mux(in.bits.single, in.bits.in2(22), in.bits.in2(51))
val minmax_exc = Cat(issnan1 || issnan2, Bits(0,4))
val isMax = in.bits.rm(0)
val isLHS = isnan2 || isMax =/= io.lt && !isnan1
val mux = Wire(new FPResult)
mux.exc := minmax_exc
mux.data := in.bits.in2
when (isSgnj) { mux.exc := UInt(0) }
when (isSgnj || isLHS) { mux.data := fsgnj }
when (in.bits.cmd === FCMD_CVT_FF) {
when (in.bits.single) {
mux.data := Cat(SInt(-1, 32), d2s.io.out)
mux.exc := d2s.io.exceptionFlags
}.otherwise {
mux.data := s2d.io.out
mux.exc := s2d.io.exceptionFlags
}
}
io.out <> Pipe(in.valid, mux, latency-1)
}
class FPUFMAPipe(val latency: Int, expWidth: Int, sigWidth: Int) extends Module
{
val io = new Bundle {
val in = Valid(new FPInput).flip
val out = Valid(new FPResult)
}
val width = sigWidth + expWidth
val one = UInt(1) << (width-1)
val zero = (io.in.bits.in1(width) ^ io.in.bits.in2(width)) << width
val valid = Reg(next=io.in.valid)
val in = Reg(new FPInput)
when (io.in.valid) {
in := io.in.bits
val cmd_fma = io.in.bits.ren3
val cmd_addsub = io.in.bits.swap23
in.cmd := Cat(io.in.bits.cmd(1) & (cmd_fma || cmd_addsub), io.in.bits.cmd(0))
when (cmd_addsub) { in.in2 := one }
unless (cmd_fma || cmd_addsub) { in.in3 := zero }
}
val fma = Module(new hardfloat.MulAddRecFN(expWidth, sigWidth))
fma.io.op := in.cmd
fma.io.roundingMode := in.rm
fma.io.a := in.in1
fma.io.b := in.in2
fma.io.c := in.in3
val res = Wire(new FPResult)
res.data := Cat(SInt(-1, 32), fma.io.out)
res.exc := fma.io.exceptionFlags
io.out := Pipe(valid, res, latency-1)
}
class FPU(cfg: FPUConfig)(implicit p: Parameters) extends CoreModule()(p) {
require(xLen == 64, "RV32 Rocket FP support missing")
val io = new FPUIO
val ex_reg_valid = Reg(next=io.valid, init=Bool(false))
val req_valid = ex_reg_valid || io.cp_req.valid
val ex_reg_inst = RegEnable(io.inst, io.valid)
val ex_cp_valid = io.cp_req.valid && !ex_reg_valid
val mem_reg_valid = Reg(next=ex_reg_valid && !io.killx || ex_cp_valid, init=Bool(false))
val mem_reg_inst = RegEnable(ex_reg_inst, ex_reg_valid)
val mem_cp_valid = Reg(next=ex_cp_valid, init=Bool(false))
val killm = (io.killm || io.nack_mem) && !mem_cp_valid
val wb_reg_valid = Reg(next=mem_reg_valid && (!killm || mem_cp_valid), init=Bool(false))
val wb_cp_valid = Reg(next=mem_cp_valid, init=Bool(false))
val fp_decoder = Module(new FPUDecoder)
fp_decoder.io.inst := io.inst
val cp_ctrl = Wire(new FPUCtrlSigs)
cp_ctrl <> io.cp_req.bits
io.cp_resp.valid := Bool(false)
io.cp_resp.bits.data := UInt(0)
val id_ctrl = fp_decoder.io.sigs
val ex_ctrl = Mux(ex_reg_valid, RegEnable(id_ctrl, io.valid), cp_ctrl)
val mem_ctrl = RegEnable(ex_ctrl, req_valid)
val wb_ctrl = RegEnable(mem_ctrl, mem_reg_valid)
// load response
val load_wb = Reg(next=io.dmem_resp_val)
val load_wb_single = RegEnable(!io.dmem_resp_type(0), io.dmem_resp_val)
val load_wb_data = RegEnable(io.dmem_resp_data, io.dmem_resp_val)
val load_wb_tag = RegEnable(io.dmem_resp_tag, io.dmem_resp_val)
val rec_s = hardfloat.recFNFromFN(8, 24, load_wb_data)
val rec_d = hardfloat.recFNFromFN(11, 53, load_wb_data)
val load_wb_data_recoded = Mux(load_wb_single, Cat(SInt(-1, 32), rec_s), rec_d)
// regfile
val regfile = Mem(32, Bits(width = 65))
when (load_wb) {
regfile(load_wb_tag) := load_wb_data_recoded
if (enableCommitLog) {
printf ("f%d p%d 0x%x\n", load_wb_tag, load_wb_tag + UInt(32),
Mux(load_wb_single, load_wb_data(31,0), load_wb_data))
}
}
val ex_ra1::ex_ra2::ex_ra3::Nil = List.fill(3)(Reg(UInt()))
when (io.valid) {
when (id_ctrl.ren1) {
when (!id_ctrl.swap12) { ex_ra1 := io.inst(19,15) }
when (id_ctrl.swap12) { ex_ra2 := io.inst(19,15) }
}
when (id_ctrl.ren2) {
when (id_ctrl.swap12) { ex_ra1 := io.inst(24,20) }
when (id_ctrl.swap23) { ex_ra3 := io.inst(24,20) }
when (!id_ctrl.swap12 && !id_ctrl.swap23) { ex_ra2 := io.inst(24,20) }
}
when (id_ctrl.ren3) { ex_ra3 := io.inst(31,27) }
}
val ex_rs1::ex_rs2::ex_rs3::Nil = Seq(ex_ra1, ex_ra2, ex_ra3).map(regfile(_))
val ex_rm = Mux(ex_reg_inst(14,12) === Bits(7), io.fcsr_rm, ex_reg_inst(14,12))
val cp_rs1 = io.cp_req.bits.in1
val cp_rs2 = Mux(io.cp_req.bits.swap23, io.cp_req.bits.in3, io.cp_req.bits.in2)
val cp_rs3 = Mux(io.cp_req.bits.swap23, io.cp_req.bits.in2, io.cp_req.bits.in3)
val req = Wire(new FPInput)
req := ex_ctrl
req.rm := Mux(ex_reg_valid, ex_rm, io.cp_req.bits.rm)
req.in1 := Mux(ex_reg_valid, ex_rs1, cp_rs1)
req.in2 := Mux(ex_reg_valid, ex_rs2, cp_rs2)
req.in3 := Mux(ex_reg_valid, ex_rs3, cp_rs3)
req.typ := Mux(ex_reg_valid, ex_reg_inst(21,20), io.cp_req.bits.typ)
val sfma = Module(new FPUFMAPipe(cfg.sfmaLatency, 8, 24))
sfma.io.in.valid := req_valid && ex_ctrl.fma && ex_ctrl.single
sfma.io.in.bits := req
val dfma = Module(new FPUFMAPipe(cfg.dfmaLatency, 11, 53))
dfma.io.in.valid := req_valid && ex_ctrl.fma && !ex_ctrl.single
dfma.io.in.bits := req
val fpiu = Module(new FPToInt)
fpiu.io.in.valid := req_valid && (ex_ctrl.toint || ex_ctrl.div || ex_ctrl.sqrt || ex_ctrl.cmd === FCMD_MINMAX)
fpiu.io.in.bits := req
io.store_data := fpiu.io.out.bits.store
io.toint_data := fpiu.io.out.bits.toint
when(fpiu.io.out.valid && mem_cp_valid && mem_ctrl.toint){
io.cp_resp.bits.data := fpiu.io.out.bits.toint
io.cp_resp.valid := Bool(true)
}
val ifpu = Module(new IntToFP(3))
ifpu.io.in.valid := req_valid && ex_ctrl.fromint
ifpu.io.in.bits := req
ifpu.io.in.bits.in1 := Mux(ex_reg_valid, io.fromint_data, cp_rs1)
val fpmu = Module(new FPToFP(2))
fpmu.io.in.valid := req_valid && ex_ctrl.fastpipe
fpmu.io.in.bits := req
fpmu.io.lt := fpiu.io.out.bits.lt
val divSqrt_wen = Reg(next=Bool(false))
val divSqrt_inReady = Wire(init=Bool(false))
val divSqrt_waddr = Reg(Bits())
val divSqrt_wdata = Wire(Bits())
val divSqrt_flags = Wire(Bits())
val divSqrt_in_flight = Reg(init=Bool(false))
val divSqrt_killed = Reg(Bool())
// writeback arbitration
case class Pipe(p: Module, lat: Int, cond: (FPUCtrlSigs) => Bool, res: FPResult)
val pipes = List(
Pipe(fpmu, fpmu.latency, (c: FPUCtrlSigs) => c.fastpipe, fpmu.io.out.bits),
Pipe(ifpu, ifpu.latency, (c: FPUCtrlSigs) => c.fromint, ifpu.io.out.bits),
Pipe(sfma, sfma.latency, (c: FPUCtrlSigs) => c.fma && c.single, sfma.io.out.bits),
Pipe(dfma, dfma.latency, (c: FPUCtrlSigs) => c.fma && !c.single, dfma.io.out.bits))
def latencyMask(c: FPUCtrlSigs, offset: Int) = {
require(pipes.forall(_.lat >= offset))
pipes.map(p => Mux(p.cond(c), UInt(1 << p.lat-offset), UInt(0))).reduce(_|_)
}
def pipeid(c: FPUCtrlSigs) = pipes.zipWithIndex.map(p => Mux(p._1.cond(c), UInt(p._2), UInt(0))).reduce(_|_)
val maxLatency = pipes.map(_.lat).max
val memLatencyMask = latencyMask(mem_ctrl, 2)
class WBInfo extends Bundle {
val rd = UInt(width = 5)
val single = Bool()
val cp = Bool()
val pipeid = UInt(width = log2Ceil(pipes.size))
override def cloneType: this.type = new WBInfo().asInstanceOf[this.type]
}
val wen = Reg(init=Bits(0, maxLatency-1))
val wbInfo = Reg(Vec(maxLatency-1, new WBInfo))
val mem_wen = mem_reg_valid && (mem_ctrl.fma || mem_ctrl.fastpipe || mem_ctrl.fromint)
val write_port_busy = RegEnable(mem_wen && (memLatencyMask & latencyMask(ex_ctrl, 1)).orR || (wen & latencyMask(ex_ctrl, 0)).orR, req_valid)
for (i <- 0 until maxLatency-2) {
when (wen(i+1)) { wbInfo(i) := wbInfo(i+1) }
}
wen := wen >> 1
when (mem_wen) {
when (!killm) {
wen := wen >> 1 | memLatencyMask
}
for (i <- 0 until maxLatency-1) {
when (!write_port_busy && memLatencyMask(i)) {
wbInfo(i).cp := mem_cp_valid
wbInfo(i).single := mem_ctrl.single
wbInfo(i).pipeid := pipeid(mem_ctrl)
wbInfo(i).rd := mem_reg_inst(11,7)
}
}
}
val waddr = Mux(divSqrt_wen, divSqrt_waddr, wbInfo(0).rd)
val wdata = Mux(divSqrt_wen, divSqrt_wdata, (pipes.map(_.res.data): Seq[UInt])(wbInfo(0).pipeid))
val wexc = (pipes.map(_.res.exc): Seq[UInt])(wbInfo(0).pipeid)
when ((!wbInfo(0).cp && wen(0)) || divSqrt_wen) {
regfile(waddr) := wdata
if (enableCommitLog) {
val wdata_unrec_s = hardfloat.fNFromRecFN(8, 24, wdata(64,0))
val wdata_unrec_d = hardfloat.fNFromRecFN(11, 53, wdata(64,0))
printf ("f%d p%d 0x%x\n", waddr, waddr+ UInt(32),
Mux(wbInfo(0).single, Cat(UInt(0,32), wdata_unrec_s), wdata_unrec_d))
}
}
when (wbInfo(0).cp && wen(0)) {
io.cp_resp.bits.data := wdata
io.cp_resp.valid := Bool(true)
}
io.cp_req.ready := !ex_reg_valid
val wb_toint_valid = wb_reg_valid && wb_ctrl.toint
val wb_toint_exc = RegEnable(fpiu.io.out.bits.exc, mem_ctrl.toint)
io.fcsr_flags.valid := wb_toint_valid || divSqrt_wen || wen(0)
io.fcsr_flags.bits :=
Mux(wb_toint_valid, wb_toint_exc, UInt(0)) |
Mux(divSqrt_wen, divSqrt_flags, UInt(0)) |
Mux(wen(0), wexc, UInt(0))
val units_busy = mem_reg_valid && (mem_ctrl.div || mem_ctrl.sqrt) && (!divSqrt_inReady || wen.orR) // || mem_reg_valid && mem_ctrl.fma && Reg(next=Mux(ex_ctrl.single, io.sfma.valid, io.dfma.valid))
io.fcsr_rdy := !(ex_reg_valid && ex_ctrl.wflags || mem_reg_valid && mem_ctrl.wflags || wb_reg_valid && wb_ctrl.toint || wen.orR || divSqrt_in_flight)
io.nack_mem := units_busy || write_port_busy || divSqrt_in_flight
io.dec <> fp_decoder.io.sigs
def useScoreboard(f: ((Pipe, Int)) => Bool) = pipes.zipWithIndex.filter(_._1.lat > 3).map(x => f(x)).fold(Bool(false))(_||_)
io.sboard_set := wb_reg_valid && !wb_cp_valid && Reg(next=useScoreboard(_._1.cond(mem_ctrl)) || mem_ctrl.div || mem_ctrl.sqrt)
io.sboard_clr := !wb_cp_valid && (divSqrt_wen || (wen(0) && useScoreboard(x => wbInfo(0).pipeid === UInt(x._2))))
io.sboard_clra := waddr
// we don't currently support round-max-magnitude (rm=4)
io.illegal_rm := ex_rm(2) && ex_ctrl.round
divSqrt_wdata := 0
divSqrt_flags := 0
if (cfg.divSqrt) {
val divSqrt_single = Reg(Bool())
val divSqrt_rm = Reg(Bits())
val divSqrt_flags_double = Reg(Bits())
val divSqrt_wdata_double = Reg(Bits())
val divSqrt = Module(new hardfloat.DivSqrtRecF64)
divSqrt_inReady := Mux(divSqrt.io.sqrtOp, divSqrt.io.inReady_sqrt, divSqrt.io.inReady_div)
val divSqrt_outValid = divSqrt.io.outValid_div || divSqrt.io.outValid_sqrt
divSqrt.io.inValid := mem_reg_valid && (mem_ctrl.div || mem_ctrl.sqrt) && !divSqrt_in_flight
divSqrt.io.sqrtOp := mem_ctrl.sqrt
divSqrt.io.a := fpiu.io.as_double.in1
divSqrt.io.b := fpiu.io.as_double.in2
divSqrt.io.roundingMode := fpiu.io.as_double.rm
when (divSqrt.io.inValid && divSqrt_inReady) {
divSqrt_in_flight := true
divSqrt_killed := killm
divSqrt_single := mem_ctrl.single
divSqrt_waddr := mem_reg_inst(11,7)
divSqrt_rm := divSqrt.io.roundingMode
}
when (divSqrt_outValid) {
divSqrt_wen := !divSqrt_killed
divSqrt_wdata_double := divSqrt.io.out
divSqrt_in_flight := false
divSqrt_flags_double := divSqrt.io.exceptionFlags
}
val divSqrt_toSingle = Module(new hardfloat.RecFNToRecFN(11, 53, 8, 24))
divSqrt_toSingle.io.in := divSqrt_wdata_double
divSqrt_toSingle.io.roundingMode := divSqrt_rm
divSqrt_wdata := Mux(divSqrt_single, divSqrt_toSingle.io.out, divSqrt_wdata_double)
divSqrt_flags := divSqrt_flags_double | Mux(divSqrt_single, divSqrt_toSingle.io.exceptionFlags, Bits(0))
} else {
when (ex_ctrl.div || ex_ctrl.sqrt) { io.illegal_rm := true }
}
}

View File

@ -0,0 +1,133 @@
package rocket
import Chisel._
import uncore.tilelink._
import Util._
import cde.{Parameters, Field}
class FrontendReq(implicit p: Parameters) extends CoreBundle()(p) {
val pc = UInt(width = vaddrBitsExtended)
val speculative = Bool()
}
class FrontendResp(implicit p: Parameters) extends CoreBundle()(p) {
val btb = Valid(new BTBResp)
val pc = UInt(width = vaddrBitsExtended) // ID stage PC
val data = UInt(width = fetchWidth * coreInstBits)
val mask = Bits(width = fetchWidth)
val xcpt_if = Bool()
val replay = Bool()
}
class FrontendIO(implicit p: Parameters) extends CoreBundle()(p) {
val req = Valid(new FrontendReq)
val resp = Decoupled(new FrontendResp).flip
val btb_update = Valid(new BTBUpdate)
val bht_update = Valid(new BHTUpdate)
val ras_update = Valid(new RASUpdate)
val flush_icache = Bool(OUTPUT)
val flush_tlb = Bool(OUTPUT)
val npc = UInt(INPUT, width = vaddrBitsExtended)
}
class Frontend(implicit p: Parameters) extends CoreModule()(p) with HasL1CacheParameters {
val io = new Bundle {
val cpu = new FrontendIO().flip
val ptw = new TLBPTWIO()
val mem = new ClientUncachedTileLinkIO
}
val icache = Module(new ICache(latency = 2))
val tlb = Module(new TLB)
val s1_pc_ = Reg(UInt(width=vaddrBitsExtended))
val s1_pc = ~(~s1_pc_ | (coreInstBytes-1)) // discard PC LSBS (this propagates down the pipeline)
val s1_speculative = Reg(Bool())
val s1_same_block = Reg(Bool())
val s2_valid = Reg(init=Bool(true))
val s2_pc = Reg(init=UInt(p(ResetVector)))
val s2_btb_resp_valid = Reg(init=Bool(false))
val s2_btb_resp_bits = Reg(new BTBResp)
val s2_xcpt_if = Reg(init=Bool(false))
val s2_speculative = Reg(init=Bool(false))
val s2_cacheable = Reg(init=Bool(false))
val ntpc = ~(~s1_pc | (coreInstBytes*fetchWidth-1)) + UInt(coreInstBytes*fetchWidth)
val ntpc_same_block = (ntpc & rowBytes) === (s1_pc & rowBytes)
val predicted_npc = Wire(init = ntpc)
val predicted_taken = Wire(init = Bool(false))
val icmiss = s2_valid && !icache.io.resp.valid
val npc = Mux(icmiss, s2_pc, predicted_npc)
val s0_same_block = !predicted_taken && !icmiss && !io.cpu.req.valid && ntpc_same_block
val stall = io.cpu.resp.valid && !io.cpu.resp.ready
when (!stall) {
s1_same_block := s0_same_block && !tlb.io.resp.miss
s1_pc_ := io.cpu.npc
// consider RVC fetches across blocks to be non-speculative if the first
// part was non-speculative
val s0_speculative =
if (usingCompressed) s1_speculative || s2_valid && !s2_speculative || predicted_taken
else Bool(true)
s1_speculative := Mux(icmiss, s2_speculative, s0_speculative)
s2_valid := !icmiss
when (!icmiss) {
s2_pc := s1_pc
s2_speculative := s1_speculative
s2_cacheable := tlb.io.resp.cacheable
s2_xcpt_if := tlb.io.resp.xcpt_if
}
}
when (io.cpu.req.valid) {
s1_same_block := Bool(false)
s1_pc_ := io.cpu.npc
s1_speculative := io.cpu.req.bits.speculative
s2_valid := Bool(false)
}
if (p(BtbKey).nEntries > 0) {
val btb = Module(new BTB)
btb.io.req.valid := false
btb.io.req.bits.addr := s1_pc_
btb.io.btb_update := io.cpu.btb_update
btb.io.bht_update := io.cpu.bht_update
btb.io.ras_update := io.cpu.ras_update
when (!stall && !icmiss) {
btb.io.req.valid := true
s2_btb_resp_valid := btb.io.resp.valid
s2_btb_resp_bits := btb.io.resp.bits
}
when (btb.io.resp.valid && btb.io.resp.bits.taken) {
predicted_npc := btb.io.resp.bits.target.sextTo(vaddrBitsExtended)
predicted_taken := Bool(true)
}
}
io.ptw <> tlb.io.ptw
tlb.io.req.valid := !stall && !icmiss
tlb.io.req.bits.vpn := s1_pc >> pgIdxBits
tlb.io.req.bits.passthrough := Bool(false)
tlb.io.req.bits.instruction := Bool(true)
tlb.io.req.bits.store := Bool(false)
io.mem <> icache.io.mem
icache.io.req.valid := !stall && !s0_same_block
icache.io.req.bits.addr := io.cpu.npc
icache.io.invalidate := io.cpu.flush_icache
icache.io.s1_ppn := tlb.io.resp.ppn
icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || tlb.io.resp.xcpt_if || icmiss || io.cpu.flush_tlb
icache.io.s2_kill := s2_speculative && !s2_cacheable
icache.io.resp.ready := !stall && !s1_same_block
io.cpu.resp.valid := s2_valid && (icache.io.resp.valid || icache.io.s2_kill || s2_xcpt_if)
io.cpu.resp.bits.pc := s2_pc
io.cpu.npc := Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc)
require(fetchWidth * coreInstBytes <= rowBytes && isPow2(fetchWidth))
io.cpu.resp.bits.data := icache.io.resp.bits.datablock >> (s2_pc.extract(log2Ceil(rowBytes)-1,log2Ceil(fetchWidth*coreInstBytes)) << log2Ceil(fetchWidth*coreInstBits))
io.cpu.resp.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes))
io.cpu.resp.bits.xcpt_if := s2_xcpt_if
io.cpu.resp.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt_if
io.cpu.resp.bits.btb.valid := s2_btb_resp_valid
io.cpu.resp.bits.btb.bits := s2_btb_resp_bits
}

View File

@ -0,0 +1,132 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Util._
import cde.{Parameters, Field}
import junctions._
class Instruction(implicit val p: Parameters) extends ParameterizedBundle with HasCoreParameters {
val pf0 = Bool() // page fault on first half of instruction
val pf1 = Bool() // page fault on second half of instruction
val replay = Bool()
val btb_hit = Bool()
val rvc = Bool()
val inst = new ExpandedInstruction
require(coreInstBits == (if (usingCompressed) 16 else 32))
}
class IBuf(implicit p: Parameters) extends CoreModule {
val io = new Bundle {
val imem = Decoupled(new FrontendResp).flip
val kill = Bool(INPUT)
val pc = UInt(width = vaddrBitsExtended)
val btb_resp = new BTBResp().asOutput
val inst = Vec(retireWidth, Decoupled(new Instruction))
}
// This module is meant to be more general, but it's not there yet
require(decodeWidth == 1)
val n = fetchWidth - 1
val nBufValid = if (n == 0) UInt(0) else Reg(init=UInt(0, log2Ceil(fetchWidth)))
val buf = Reg(io.imem.bits)
val ibufBTBHit = Reg(Bool())
val ibufBTBResp = Reg(new BTBResp)
val pcWordMask = UInt(coreInstBytes*fetchWidth-1, vaddrBitsExtended)
val pcWordBits = io.imem.bits.pc.extract(log2Ceil(fetchWidth*coreInstBytes)-1, log2Ceil(coreInstBytes))
val nReady = Wire(init = UInt(0, log2Ceil(fetchWidth+1)))
val nIC = Mux(io.imem.bits.btb.valid && io.imem.bits.btb.bits.taken, io.imem.bits.btb.bits.bridx +& 1, UInt(fetchWidth)) - pcWordBits
val nICReady = nReady - nBufValid
val nValid = Mux(io.imem.valid, nIC, UInt(0)) + nBufValid
io.imem.ready := nReady >= nBufValid && (nICReady >= nIC || n >= nIC - nICReady)
if (n > 0) {
nBufValid := Mux(nReady >= nBufValid, UInt(0), nBufValid - nReady)
if (n > 1) when (nReady > 0 && nReady < nBufValid) {
val shiftedBuf = shiftInsnRight(buf.data(n*coreInstBits-1, coreInstBits), (nReady-1)(log2Ceil(n-1)-1,0))
buf.data := Cat(buf.data(n*coreInstBits-1, (n-1)*coreInstBits), shiftedBuf((n-1)*coreInstBits-1, 0))
buf.pc := buf.pc & ~pcWordMask | (buf.pc + (nReady << log2Ceil(coreInstBytes))) & pcWordMask
ibufBTBResp.bridx := ibufBTBResp.bridx - nReady
}
when (io.imem.valid && nReady >= nBufValid && nICReady < nIC && n >= nIC - nICReady) {
val shamt = pcWordBits + nICReady
nBufValid := nIC - nICReady
buf := io.imem.bits
buf.data := shiftInsnRight(io.imem.bits.data, shamt)(n*coreInstBits-1,0)
buf.pc := io.imem.bits.pc & ~pcWordMask | (io.imem.bits.pc + (nICReady << log2Ceil(coreInstBytes))) & pcWordMask
ibufBTBHit := io.imem.bits.btb.valid
when (io.imem.bits.btb.valid) {
ibufBTBResp := io.imem.bits.btb.bits
ibufBTBResp.bridx := io.imem.bits.btb.bits.bridx + nICReady
}
}
when (io.kill) {
nBufValid := 0
}
}
val icShiftAmt = (fetchWidth + nBufValid - pcWordBits)(log2Ceil(fetchWidth), 0)
val icData = shiftInsnLeft(Cat(io.imem.bits.data, Fill(fetchWidth, io.imem.bits.data(coreInstBits-1, 0))), icShiftAmt)
.extract(3*fetchWidth*coreInstBits-1, 2*fetchWidth*coreInstBits)
val icMask = (~UInt(0, fetchWidth*coreInstBits) << (nBufValid << log2Ceil(coreInstBits)))(fetchWidth*coreInstBits-1,0)
val inst = icData & icMask | buf.data & ~icMask
val valid = (UIntToOH(nValid) - 1)(fetchWidth-1, 0)
val bufMask = UIntToOH(nBufValid) - 1
val xcpt_if = valid & (Mux(buf.xcpt_if, bufMask, UInt(0)) | Mux(io.imem.bits.xcpt_if, ~bufMask, UInt(0)))
val ic_replay = valid & (Mux(buf.replay, bufMask, UInt(0)) | Mux(io.imem.bits.replay, ~bufMask, UInt(0)))
val ibufBTBHitMask = Mux(ibufBTBHit, UIntToOH(ibufBTBResp.bridx), UInt(0))
val icBTBHitMask = Mux(io.imem.bits.btb.valid, UIntToOH(io.imem.bits.btb.bits.bridx +& nBufValid - pcWordBits), UInt(0))
val btbHitMask = ibufBTBHitMask & bufMask | icBTBHitMask & ~bufMask
io.btb_resp := Mux((ibufBTBHitMask & bufMask).orR, ibufBTBResp, io.imem.bits.btb.bits)
io.pc := Mux(nBufValid > 0, buf.pc, io.imem.bits.pc)
expand(0, 0, inst)
def expand(i: Int, j: UInt, curInst: UInt): Unit = if (i < retireWidth) {
val exp = Module(new RVCExpander)
exp.io.in := curInst
io.inst(i).bits.inst := exp.io.out
if (usingCompressed) {
val replay = ic_replay(j) || (!exp.io.rvc && (btbHitMask(j) || ic_replay(j+1)))
io.inst(i).valid := valid(j) && (exp.io.rvc || valid(j+1) || xcpt_if(j+1) || replay)
io.inst(i).bits.pf0 := xcpt_if(j)
io.inst(i).bits.pf1 := !exp.io.rvc && xcpt_if(j+1)
io.inst(i).bits.replay := replay
io.inst(i).bits.btb_hit := btbHitMask(j) || (!exp.io.rvc && btbHitMask(j+1))
io.inst(i).bits.rvc := exp.io.rvc
when (io.inst(i).fire()) { nReady := Mux(exp.io.rvc, j+1, j+2) }
expand(i+1, Mux(exp.io.rvc, j+1, j+2), Mux(exp.io.rvc, curInst >> 16, curInst >> 32))
} else {
when (io.inst(i).ready) { nReady := i+1 }
io.inst(i).valid := valid(i)
io.inst(i).bits.pf0 := xcpt_if(i)
io.inst(i).bits.pf1 := false
io.inst(i).bits.replay := ic_replay(i)
io.inst(i).bits.rvc := false
io.inst(i).bits.btb_hit := btbHitMask(i)
expand(i+1, null, curInst >> 32)
}
}
def shiftInsnLeft(in: UInt, dist: UInt) = {
val r = in.getWidth/coreInstBits
require(in.getWidth % coreInstBits == 0)
val data = Cat(Fill((1 << (log2Ceil(r) + 1)) - r, in >> (r-1)*coreInstBits), in)
data << (dist << log2Ceil(coreInstBits))
}
def shiftInsnRight(in: UInt, dist: UInt) = {
val r = in.getWidth/coreInstBits
require(in.getWidth % coreInstBits == 0)
val data = Cat(Fill((1 << (log2Ceil(r) + 1)) - r, in >> (r-1)*coreInstBits), in)
data >> (dist << log2Ceil(coreInstBits))
}
}

View File

@ -0,0 +1,157 @@
package rocket
import Chisel._
import uncore.agents._
import uncore.tilelink._
import uncore.util._
import Util._
import cde.{Parameters, Field}
trait HasL1CacheParameters extends HasCacheParameters with HasCoreParameters {
val outerDataBeats = p(TLKey(p(TLId))).dataBeats
val outerDataBits = p(TLKey(p(TLId))).dataBitsPerBeat
val refillCyclesPerBeat = outerDataBits/rowBits
val refillCycles = refillCyclesPerBeat*outerDataBeats
}
class ICacheReq(implicit p: Parameters) extends CoreBundle()(p) with HasL1CacheParameters {
val addr = UInt(width = vaddrBits)
}
class ICacheResp(implicit p: Parameters) extends CoreBundle()(p) with HasL1CacheParameters {
val data = Bits(width = coreInstBits)
val datablock = Bits(width = rowBits)
}
class ICache(latency: Int)(implicit p: Parameters) extends CoreModule()(p) with HasL1CacheParameters {
val io = new Bundle {
val req = Valid(new ICacheReq).flip
val s1_ppn = UInt(INPUT, ppnBits) // delayed one cycle w.r.t. req
val s1_kill = Bool(INPUT) // delayed one cycle w.r.t. req
val s2_kill = Bool(INPUT) // delayed two cycles; prevents I$ miss emission
val resp = Decoupled(new ICacheResp)
val invalidate = Bool(INPUT)
val mem = new ClientUncachedTileLinkIO
}
require(isPow2(nSets) && isPow2(nWays))
require(isPow2(coreInstBytes))
require(!usingVM || pgIdxBits >= untagBits)
val s_ready :: s_request :: s_refill_wait :: s_refill :: Nil = Enum(UInt(), 4)
val state = Reg(init=s_ready)
val invalidated = Reg(Bool())
val stall = !io.resp.ready
val rdy = Wire(Bool())
val refill_addr = Reg(UInt(width = paddrBits))
val s1_any_tag_hit = Wire(Bool())
val s1_valid = Reg(init=Bool(false))
val s1_vaddr = Reg(UInt())
val s1_paddr = Cat(io.s1_ppn, s1_vaddr(pgIdxBits-1,0))
val s1_tag = s1_paddr(tagBits+untagBits-1,untagBits)
val s0_valid = io.req.valid || s1_valid && stall
val s0_vaddr = Mux(s1_valid && stall, s1_vaddr, io.req.bits.addr)
s1_valid := io.req.valid && rdy || s1_valid && stall && !io.s1_kill
when (io.req.valid && rdy) {
s1_vaddr := io.req.bits.addr
}
val out_valid = s1_valid && !io.s1_kill && state === s_ready
val s1_idx = s1_vaddr(untagBits-1,blockOffBits)
val s1_hit = out_valid && s1_any_tag_hit
val s1_miss = out_valid && !s1_any_tag_hit
rdy := state === s_ready && !s1_miss
when (s1_miss && state === s_ready) {
refill_addr := s1_paddr
}
val refill_tag = refill_addr(tagBits+untagBits-1,untagBits)
val narrow_grant = FlowThroughSerializer(io.mem.grant, refillCyclesPerBeat)
val (refill_cnt, refill_wrap) = Counter(narrow_grant.fire(), refillCycles)
val refill_done = state === s_refill && refill_wrap
narrow_grant.ready := Bool(true)
val repl_way = if (isDM) UInt(0) else LFSR16(s1_miss)(log2Up(nWays)-1,0)
val entagbits = code.width(tagBits)
val tag_array = SeqMem(nSets, Vec(nWays, Bits(width = entagbits)))
val tag_rdata = tag_array.read(s0_vaddr(untagBits-1,blockOffBits), !refill_done && s0_valid)
when (refill_done) {
val tag = code.encode(refill_tag)
tag_array.write(s1_idx, Vec.fill(nWays)(tag), Vec.tabulate(nWays)(repl_way === _))
}
val vb_array = Reg(init=Bits(0, nSets*nWays))
when (refill_done && !invalidated) {
vb_array := vb_array.bitSet(Cat(repl_way, s1_idx), Bool(true))
}
when (io.invalidate) {
vb_array := Bits(0)
invalidated := Bool(true)
}
val s1_disparity = Wire(Vec(nWays, Bool()))
for (i <- 0 until nWays)
when (s1_valid && s1_disparity(i)) { vb_array := vb_array.bitSet(Cat(UInt(i), s1_idx), Bool(false)) }
val s1_tag_match = Wire(Vec(nWays, Bool()))
val s1_tag_hit = Wire(Vec(nWays, Bool()))
val s1_dout = Wire(Vec(nWays, Bits(width = rowBits)))
for (i <- 0 until nWays) {
val s1_vb = !io.invalidate && vb_array(Cat(UInt(i), s1_vaddr(untagBits-1,blockOffBits))).toBool
val tag_out = tag_rdata(i)
val s1_tag_disparity = code.decode(tag_out).error
s1_tag_match(i) := tag_out(tagBits-1,0) === s1_tag
s1_tag_hit(i) := s1_vb && s1_tag_match(i)
s1_disparity(i) := s1_vb && (s1_tag_disparity || code.decode(s1_dout(i)).error)
}
s1_any_tag_hit := s1_tag_hit.reduceLeft(_||_) && !s1_disparity.reduceLeft(_||_)
for (i <- 0 until nWays) {
val data_array = SeqMem(nSets * refillCycles, Bits(width = code.width(rowBits)))
val wen = narrow_grant.valid && repl_way === UInt(i)
when (wen) {
val e_d = code.encode(narrow_grant.bits.data)
data_array.write((s1_idx << log2Ceil(refillCycles)) | refill_cnt, e_d)
}
val s0_raddr = s0_vaddr(untagBits-1,blockOffBits-log2Ceil(refillCycles))
s1_dout(i) := data_array.read(s0_raddr, !wen && s0_valid)
}
// output signals
latency match {
case 1 =>
io.resp.bits.datablock := Mux1H(s1_tag_hit, s1_dout)
io.resp.valid := s1_hit
case 2 =>
val s2_hit = RegEnable(s1_hit, !stall)
val s2_tag_hit = RegEnable(s1_tag_hit, !stall)
val s2_dout = RegEnable(s1_dout, !stall)
io.resp.bits.datablock := Mux1H(s2_tag_hit, s2_dout)
io.resp.valid := s2_hit
}
io.mem.acquire.valid := state === s_request && !io.s2_kill
io.mem.acquire.bits := GetBlock(addr_block = refill_addr >> blockOffBits)
// control state machine
switch (state) {
is (s_ready) {
when (s1_miss) { state := s_request }
invalidated := Bool(false)
}
is (s_request) {
when (io.mem.acquire.ready) { state := s_refill_wait }
when (io.s2_kill) { state := s_ready }
}
is (s_refill_wait) {
when (io.mem.grant.valid) { state := s_refill }
}
is (s_refill) {
when (refill_done) { state := s_ready }
}
}
}

View File

@ -0,0 +1,314 @@
// See LICENSE for license details
package rocket
import Chisel._
import Instructions._
import uncore.constants.MemoryOpConstants._
import ALU._
import cde.Parameters
import Util._
abstract trait DecodeConstants extends HasCoreParameters
{
val table: Array[(BitPat, List[BitPat])]
}
class IntCtrlSigs extends Bundle {
val legal = Bool()
val fp = Bool()
val rocc = Bool()
val branch = Bool()
val jal = Bool()
val jalr = Bool()
val rxs2 = Bool()
val rxs1 = Bool()
val sel_alu2 = Bits(width = A2_X.getWidth)
val sel_alu1 = Bits(width = A1_X.getWidth)
val sel_imm = Bits(width = IMM_X.getWidth)
val alu_dw = Bool()
val alu_fn = Bits(width = FN_X.getWidth)
val mem = Bool()
val mem_cmd = Bits(width = M_SZ)
val mem_type = Bits(width = MT_SZ)
val rfs1 = Bool()
val rfs2 = Bool()
val rfs3 = Bool()
val wfd = Bool()
val div = Bool()
val wxd = Bool()
val csr = Bits(width = CSR.SZ)
val fence_i = Bool()
val fence = Bool()
val amo = Bool()
def default: List[BitPat] =
// jal renf1 fence.i
// val | jalr | renf2 |
// | fp_val| | renx2 | | renf3 |
// | | rocc| | | renx1 s_alu1 mem_val | | | wfd |
// | | | br| | | | s_alu2 | imm dw alu | mem_cmd mem_type| | | | div |
// | | | | | | | | | | | | | | | | | | | | | wxd | fence
// | | | | | | | | | | | | | | | | | | | | | | csr | | amo
// | | | | | | | | | | | | | | | | | | | | | | | | | |
List(N,X,X,X,X,X,X,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, X,X,X,X,X,X,CSR.X,X,X,X)
def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
val decoder = DecodeLogic(inst, default, table)
val sigs = Seq(legal, fp, rocc, branch, jal, jalr, rxs2, rxs1, sel_alu2,
sel_alu1, sel_imm, alu_dw, alu_fn, mem, mem_cmd, mem_type,
rfs1, rfs2, rfs3, wfd, div, wxd, csr, fence_i, fence, amo)
sigs zip decoder map {case(s,d) => s := d}
this
}
}
class IDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
BNE-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SNE, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
BEQ-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SEQ, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
BLT-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SLT, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
BLTU-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SLTU, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
BGE-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SGE, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
BGEU-> List(Y,N,N,Y,N,N,Y,Y,A2_RS2, A1_RS1, IMM_SB,DW_X, FN_SGEU, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
JAL-> List(Y,N,N,N,Y,N,N,N,A2_SIZE,A1_PC, IMM_UJ,DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
JALR-> List(Y,N,N,N,N,Y,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
AUIPC-> List(Y,N,N,N,N,N,N,N,A2_IMM, A1_PC, IMM_U, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
LB-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_B, N,N,N,N,N,Y,CSR.N,N,N,N),
LH-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_H, N,N,N,N,N,Y,CSR.N,N,N,N),
LW-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_W, N,N,N,N,N,Y,CSR.N,N,N,N),
LBU-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_BU,N,N,N,N,N,Y,CSR.N,N,N,N),
LHU-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_HU,N,N,N,N,N,Y,CSR.N,N,N,N),
SB-> List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_B, N,N,N,N,N,N,CSR.N,N,N,N),
SH-> List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_H, N,N,N,N,N,N,CSR.N,N,N,N),
SW-> List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_W, N,N,N,N,N,N,CSR.N,N,N,N),
LUI-> List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_U, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
ADDI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLTI -> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SLT, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLTIU-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SLTU, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
ANDI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_AND, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
ORI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_OR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
XORI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_XOR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLLI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SL, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRLI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRAI-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_SRA, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
ADD-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SUB-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SUB, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLT-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SLT, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLTU-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SLTU, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
AND-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_AND, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
OR-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_OR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
XOR-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_XOR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLL-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SL, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRL-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRA-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_SRA, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
FENCE-> List(Y,N,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,Y,N),
FENCE_I-> List(Y,N,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, Y,M_FLUSH_ALL,MT_X, N,N,N,N,N,N,CSR.N,Y,N,N),
SCALL-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
SBREAK-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
MRET-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
WFI-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
CSRRW-> List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.W,N,N,N),
CSRRS-> List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.S,N,N,N),
CSRRC-> List(Y,N,N,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.C,N,N,N),
CSRRWI-> List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.W,N,N,N),
CSRRSI-> List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.S,N,N,N),
CSRRCI-> List(Y,N,N,N,N,N,N,N,A2_IMM, A1_ZERO,IMM_Z, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.C,N,N,N))
}
class SDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
SFENCE_VM-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N),
SRET-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N))
}
class DebugDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
DRET-> List(Y,N,N,N,N,N,N,X,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,N,N,N,CSR.I,N,N,N))
}
class I64Decode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
LD-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_D, N,N,N,N,N,Y,CSR.N,N,N,N),
LWU-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_WU,N,N,N,N,N,Y,CSR.N,N,N,N),
SD-> List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_D, N,N,N,N,N,N,CSR.N,N,N,N),
ADDIW-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLLIW-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SL, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRLIW-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRAIW-> List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_32,FN_SRA, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
ADDW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SUBW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SUB, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SLLW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SL, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRLW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SR, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
SRAW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32,FN_SRA, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N))
}
class MDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
MUL-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MUL, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
MULH-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULH, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
MULHU-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULHU, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
MULHSU-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_MULHSU,N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
DIV-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_DIV, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
DIVU-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_DIVU, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
REM-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_REM, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
REMU-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_XPR,FN_REMU, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N))
}
class M64Decode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
MULW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_MUL, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
DIVW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_DIV, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
DIVUW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_DIVU, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
REMW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_REM, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N),
REMUW-> List(Y,N,N,N,N,N,Y,Y,A2_RS2, A1_RS1, IMM_X, DW_32, FN_REMU, N,M_X, MT_X, N,N,N,N,Y,Y,CSR.N,N,N,N))
}
class ADecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
AMOADD_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_ADD, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOXOR_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_XOR, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOSWAP_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_SWAP, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOAND_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_AND, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOOR_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_OR, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMIN_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MIN, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMINU_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MINU, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMAX_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MAX, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMAXU_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MAXU, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
LR_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XLR, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y),
SC_W-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XSC, MT_W, N,N,N,N,N,Y,CSR.N,N,N,Y))
}
class A64Decode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
AMOADD_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_ADD, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOSWAP_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_SWAP, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOXOR_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_XOR, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOAND_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_AND, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOOR_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_OR, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMIN_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MIN, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMINU_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MINU, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMAX_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MAX, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
AMOMAXU_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XA_MAXU, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
LR_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XLR, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y),
SC_D-> List(Y,N,N,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, Y,M_XSC, MT_D, N,N,N,N,N,Y,CSR.N,N,N,Y))
}
class FDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
FCVT_S_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_D_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,Y,N,N,CSR.N,N,N,N),
FSGNJ_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSGNJ_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSGNJX_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSGNJX_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSGNJN_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSGNJN_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMIN_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMIN_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMAX_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMAX_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FADD_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FADD_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSUB_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSUB_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMUL_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMUL_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FMADD_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FMADD_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FMSUB_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FMSUB_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FNMADD_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FNMADD_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FNMSUB_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FNMSUB_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,Y,Y,N,N,CSR.N,N,N,N),
FCLASS_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCLASS_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FMV_X_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_W_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_W_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_WU_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_WU_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FEQ_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FEQ_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FLT_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FLT_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FLE_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FLE_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,N,N,Y,CSR.N,N,N,N),
FMV_S_X-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_S_W-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_D_W-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_S_WU-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_D_WU-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FLW-> List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_W, N,N,N,Y,N,N,CSR.N,N,N,N),
FLD-> List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD, Y,M_XRD, MT_D, N,N,N,Y,N,N,CSR.N,N,N,N),
FSW-> List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_W, N,Y,N,N,N,N,CSR.N,N,N,N),
FSD-> List(Y,Y,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD, Y,M_XWR, MT_D, N,Y,N,N,N,N,CSR.N,N,N,N))
}
class F64Decode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
FMV_X_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_L_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_L_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_LU_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FCVT_LU_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,N,N,N,N,Y,CSR.N,N,N,N),
FMV_D_X-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_S_L-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_D_L-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_S_LU-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FCVT_D_LU-> List(Y,Y,N,N,N,N,N,Y,A2_X, A1_RS1, IMM_X, DW_X, FN_X, N,M_X, MT_X, N,N,N,Y,N,N,CSR.N,N,N,N),
FDIV_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FDIV_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSQRT_S-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N),
FSQRT_D-> List(Y,Y,N,N,N,N,N,N,A2_X, A1_X, IMM_X, DW_X, FN_X, N,M_X, MT_X, Y,Y,N,Y,N,N,CSR.N,N,N,N))
}
class RoCCDecode(implicit val p: Parameters) extends DecodeConstants
{
val table: Array[(BitPat, List[BitPat])] = Array(
CUSTOM0-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM0_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM0_RS1_RS2-> List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM0_RD-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM0_RD_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM0_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM1-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM1_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM1_RS1_RS2-> List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM1_RD-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM1_RD_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM1_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM2-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM2_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM2_RS1_RS2-> List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM2_RD-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM2_RD_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM2_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM3-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM3_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM3_RS1_RS2-> List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,N,CSR.N,N,N,N),
CUSTOM3_RD-> List(Y,N,Y,N,N,N,N,N,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM3_RD_RS1-> List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N),
CUSTOM3_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD, N,M_X, MT_X, N,N,N,N,N,Y,CSR.N,N,N,N))
}

View File

@ -0,0 +1,383 @@
// See LICENSE for license details.
package rocket
import Chisel._
/* Automatically generated by parse-opcodes */
object Instructions {
def BEQ = BitPat("b?????????????????000?????1100011")
def BNE = BitPat("b?????????????????001?????1100011")
def BLT = BitPat("b?????????????????100?????1100011")
def BGE = BitPat("b?????????????????101?????1100011")
def BLTU = BitPat("b?????????????????110?????1100011")
def BGEU = BitPat("b?????????????????111?????1100011")
def JALR = BitPat("b?????????????????000?????1100111")
def JAL = BitPat("b?????????????????????????1101111")
def LUI = BitPat("b?????????????????????????0110111")
def AUIPC = BitPat("b?????????????????????????0010111")
def ADDI = BitPat("b?????????????????000?????0010011")
def SLLI = BitPat("b000000???????????001?????0010011")
def SLTI = BitPat("b?????????????????010?????0010011")
def SLTIU = BitPat("b?????????????????011?????0010011")
def XORI = BitPat("b?????????????????100?????0010011")
def SRLI = BitPat("b000000???????????101?????0010011")
def SRAI = BitPat("b010000???????????101?????0010011")
def ORI = BitPat("b?????????????????110?????0010011")
def ANDI = BitPat("b?????????????????111?????0010011")
def ADD = BitPat("b0000000??????????000?????0110011")
def SUB = BitPat("b0100000??????????000?????0110011")
def SLL = BitPat("b0000000??????????001?????0110011")
def SLT = BitPat("b0000000??????????010?????0110011")
def SLTU = BitPat("b0000000??????????011?????0110011")
def XOR = BitPat("b0000000??????????100?????0110011")
def SRL = BitPat("b0000000??????????101?????0110011")
def SRA = BitPat("b0100000??????????101?????0110011")
def OR = BitPat("b0000000??????????110?????0110011")
def AND = BitPat("b0000000??????????111?????0110011")
def ADDIW = BitPat("b?????????????????000?????0011011")
def SLLIW = BitPat("b0000000??????????001?????0011011")
def SRLIW = BitPat("b0000000??????????101?????0011011")
def SRAIW = BitPat("b0100000??????????101?????0011011")
def ADDW = BitPat("b0000000??????????000?????0111011")
def SUBW = BitPat("b0100000??????????000?????0111011")
def SLLW = BitPat("b0000000??????????001?????0111011")
def SRLW = BitPat("b0000000??????????101?????0111011")
def SRAW = BitPat("b0100000??????????101?????0111011")
def LB = BitPat("b?????????????????000?????0000011")
def LH = BitPat("b?????????????????001?????0000011")
def LW = BitPat("b?????????????????010?????0000011")
def LD = BitPat("b?????????????????011?????0000011")
def LBU = BitPat("b?????????????????100?????0000011")
def LHU = BitPat("b?????????????????101?????0000011")
def LWU = BitPat("b?????????????????110?????0000011")
def SB = BitPat("b?????????????????000?????0100011")
def SH = BitPat("b?????????????????001?????0100011")
def SW = BitPat("b?????????????????010?????0100011")
def SD = BitPat("b?????????????????011?????0100011")
def FENCE = BitPat("b?????????????????000?????0001111")
def FENCE_I = BitPat("b?????????????????001?????0001111")
def MUL = BitPat("b0000001??????????000?????0110011")
def MULH = BitPat("b0000001??????????001?????0110011")
def MULHSU = BitPat("b0000001??????????010?????0110011")
def MULHU = BitPat("b0000001??????????011?????0110011")
def DIV = BitPat("b0000001??????????100?????0110011")
def DIVU = BitPat("b0000001??????????101?????0110011")
def REM = BitPat("b0000001??????????110?????0110011")
def REMU = BitPat("b0000001??????????111?????0110011")
def MULW = BitPat("b0000001??????????000?????0111011")
def DIVW = BitPat("b0000001??????????100?????0111011")
def DIVUW = BitPat("b0000001??????????101?????0111011")
def REMW = BitPat("b0000001??????????110?????0111011")
def REMUW = BitPat("b0000001??????????111?????0111011")
def AMOADD_W = BitPat("b00000????????????010?????0101111")
def AMOXOR_W = BitPat("b00100????????????010?????0101111")
def AMOOR_W = BitPat("b01000????????????010?????0101111")
def AMOAND_W = BitPat("b01100????????????010?????0101111")
def AMOMIN_W = BitPat("b10000????????????010?????0101111")
def AMOMAX_W = BitPat("b10100????????????010?????0101111")
def AMOMINU_W = BitPat("b11000????????????010?????0101111")
def AMOMAXU_W = BitPat("b11100????????????010?????0101111")
def AMOSWAP_W = BitPat("b00001????????????010?????0101111")
def LR_W = BitPat("b00010??00000?????010?????0101111")
def SC_W = BitPat("b00011????????????010?????0101111")
def AMOADD_D = BitPat("b00000????????????011?????0101111")
def AMOXOR_D = BitPat("b00100????????????011?????0101111")
def AMOOR_D = BitPat("b01000????????????011?????0101111")
def AMOAND_D = BitPat("b01100????????????011?????0101111")
def AMOMIN_D = BitPat("b10000????????????011?????0101111")
def AMOMAX_D = BitPat("b10100????????????011?????0101111")
def AMOMINU_D = BitPat("b11000????????????011?????0101111")
def AMOMAXU_D = BitPat("b11100????????????011?????0101111")
def AMOSWAP_D = BitPat("b00001????????????011?????0101111")
def LR_D = BitPat("b00010??00000?????011?????0101111")
def SC_D = BitPat("b00011????????????011?????0101111")
def ECALL = BitPat("b00000000000000000000000001110011")
def EBREAK = BitPat("b00000000000100000000000001110011")
def URET = BitPat("b00000000001000000000000001110011")
def SRET = BitPat("b00010000001000000000000001110011")
def HRET = BitPat("b00100000001000000000000001110011")
def MRET = BitPat("b00110000001000000000000001110011")
def DRET = BitPat("b01111011001000000000000001110011")
def SFENCE_VM = BitPat("b000100000100?????000000001110011")
def WFI = BitPat("b00010000010100000000000001110011")
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")
def FADD_S = BitPat("b0000000??????????????????1010011")
def FSUB_S = BitPat("b0000100??????????????????1010011")
def FMUL_S = BitPat("b0001000??????????????????1010011")
def FDIV_S = BitPat("b0001100??????????????????1010011")
def FSGNJ_S = BitPat("b0010000??????????000?????1010011")
def FSGNJN_S = BitPat("b0010000??????????001?????1010011")
def FSGNJX_S = BitPat("b0010000??????????010?????1010011")
def FMIN_S = BitPat("b0010100??????????000?????1010011")
def FMAX_S = BitPat("b0010100??????????001?????1010011")
def FSQRT_S = BitPat("b010110000000?????????????1010011")
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_S = BitPat("b1010000??????????000?????1010011")
def FLT_S = BitPat("b1010000??????????001?????1010011")
def FEQ_S = BitPat("b1010000??????????010?????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_S = BitPat("b110000000000?????????????1010011")
def FCVT_WU_S = BitPat("b110000000001?????????????1010011")
def FCVT_L_S = BitPat("b110000000010?????????????1010011")
def FCVT_LU_S = BitPat("b110000000011?????????????1010011")
def FMV_X_S = BitPat("b111000000000?????000?????1010011")
def FCLASS_S = BitPat("b111000000000?????001?????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_S_W = BitPat("b110100000000?????????????1010011")
def FCVT_S_WU = BitPat("b110100000001?????????????1010011")
def FCVT_S_L = BitPat("b110100000010?????????????1010011")
def FCVT_S_LU = BitPat("b110100000011?????????????1010011")
def FMV_S_X = BitPat("b111100000000?????000?????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 FLW = BitPat("b?????????????????010?????0000111")
def FLD = BitPat("b?????????????????011?????0000111")
def FSW = BitPat("b?????????????????010?????0100111")
def FSD = BitPat("b?????????????????011?????0100111")
def FMADD_S = BitPat("b?????00??????????????????1000011")
def FMSUB_S = BitPat("b?????00??????????????????1000111")
def FNMSUB_S = BitPat("b?????00??????????????????1001011")
def FNMADD_S = BitPat("b?????00??????????????????1001111")
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")
def CUSTOM0 = BitPat("b?????????????????000?????0001011")
def CUSTOM0_RS1 = BitPat("b?????????????????010?????0001011")
def CUSTOM0_RS1_RS2 = BitPat("b?????????????????011?????0001011")
def CUSTOM0_RD = BitPat("b?????????????????100?????0001011")
def CUSTOM0_RD_RS1 = BitPat("b?????????????????110?????0001011")
def CUSTOM0_RD_RS1_RS2 = BitPat("b?????????????????111?????0001011")
def CUSTOM1 = BitPat("b?????????????????000?????0101011")
def CUSTOM1_RS1 = BitPat("b?????????????????010?????0101011")
def CUSTOM1_RS1_RS2 = BitPat("b?????????????????011?????0101011")
def CUSTOM1_RD = BitPat("b?????????????????100?????0101011")
def CUSTOM1_RD_RS1 = BitPat("b?????????????????110?????0101011")
def CUSTOM1_RD_RS1_RS2 = BitPat("b?????????????????111?????0101011")
def CUSTOM2 = BitPat("b?????????????????000?????1011011")
def CUSTOM2_RS1 = BitPat("b?????????????????010?????1011011")
def CUSTOM2_RS1_RS2 = BitPat("b?????????????????011?????1011011")
def CUSTOM2_RD = BitPat("b?????????????????100?????1011011")
def CUSTOM2_RD_RS1 = BitPat("b?????????????????110?????1011011")
def CUSTOM2_RD_RS1_RS2 = BitPat("b?????????????????111?????1011011")
def CUSTOM3 = BitPat("b?????????????????000?????1111011")
def CUSTOM3_RS1 = BitPat("b?????????????????010?????1111011")
def CUSTOM3_RS1_RS2 = BitPat("b?????????????????011?????1111011")
def CUSTOM3_RD = BitPat("b?????????????????100?????1111011")
def CUSTOM3_RD_RS1 = BitPat("b?????????????????110?????1111011")
def CUSTOM3_RD_RS1_RS2 = BitPat("b?????????????????111?????1111011")
def SLLI_RV32 = BitPat("b0000000??????????001?????0010011")
def SRLI_RV32 = BitPat("b0000000??????????101?????0010011")
def SRAI_RV32 = BitPat("b0100000??????????101?????0010011")
def FRFLAGS = BitPat("b00000000000100000010?????1110011")
def FSFLAGS = BitPat("b000000000001?????001?????1110011")
def FSFLAGSI = BitPat("b000000000001?????101?????1110011")
def FRRM = BitPat("b00000000001000000010?????1110011")
def FSRM = BitPat("b000000000010?????001?????1110011")
def FSRMI = BitPat("b000000000010?????101?????1110011")
def FSCSR = BitPat("b000000000011?????001?????1110011")
def FRCSR = BitPat("b00000000001100000010?????1110011")
def RDCYCLE = BitPat("b11000000000000000010?????1110011")
def RDTIME = BitPat("b11000000000100000010?????1110011")
def RDINSTRET = BitPat("b11000000001000000010?????1110011")
def RDCYCLEH = BitPat("b11001000000000000010?????1110011")
def RDTIMEH = BitPat("b11001000000100000010?????1110011")
def RDINSTRETH = BitPat("b11001000001000000010?????1110011")
def SCALL = BitPat("b00000000000000000000000001110011")
def SBREAK = BitPat("b00000000000100000000000001110011")
}
object Causes {
val misaligned_fetch = 0x0
val fault_fetch = 0x1
val illegal_instruction = 0x2
val breakpoint = 0x3
val misaligned_load = 0x4
val fault_load = 0x5
val misaligned_store = 0x6
val fault_store = 0x7
val user_ecall = 0x8
val supervisor_ecall = 0x9
val hypervisor_ecall = 0xa
val machine_ecall = 0xb
val all = {
val res = collection.mutable.ArrayBuffer[Int]()
res += misaligned_fetch
res += fault_fetch
res += illegal_instruction
res += breakpoint
res += misaligned_load
res += fault_load
res += misaligned_store
res += fault_store
res += user_ecall
res += supervisor_ecall
res += hypervisor_ecall
res += machine_ecall
res.toArray
}
}
object CSRs {
val fflags = 0x1
val frm = 0x2
val fcsr = 0x3
val cycle = 0xc00
val time = 0xc01
val instret = 0xc02
val sstatus = 0x100
val sie = 0x104
val stvec = 0x105
val sscratch = 0x140
val sepc = 0x141
val scause = 0x142
val sbadaddr = 0x143
val sip = 0x144
val sptbr = 0x180
val scycle = 0xd00
val stime = 0xd01
val sinstret = 0xd02
val mstatus = 0x300
val medeleg = 0x302
val mideleg = 0x303
val mie = 0x304
val mtvec = 0x305
val mscratch = 0x340
val mepc = 0x341
val mcause = 0x342
val mbadaddr = 0x343
val mip = 0x344
val mucounteren = 0x310
val mscounteren = 0x311
val mucycle_delta = 0x700
val mutime_delta = 0x701
val muinstret_delta = 0x702
val mscycle_delta = 0x704
val mstime_delta = 0x705
val msinstret_delta = 0x706
val tdrselect = 0x7a0
val tdrdata1 = 0x7a1
val tdrdata2 = 0x7a2
val tdrdata3 = 0x7a3
val dcsr = 0x7b0
val dpc = 0x7b1
val dscratch = 0x7b2
val mcycle = 0xf00
val mtime = 0xf01
val minstret = 0xf02
val misa = 0xf10
val mvendorid = 0xf11
val marchid = 0xf12
val mimpid = 0xf13
val mhartid = 0xf14
val mreset = 0x7c2
val cycleh = 0xc80
val timeh = 0xc81
val instreth = 0xc82
val mucycle_deltah = 0x780
val mutime_deltah = 0x781
val muinstret_deltah = 0x782
val mscycle_deltah = 0x784
val mstime_deltah = 0x785
val msinstret_deltah = 0x786
val mcycleh = 0xf80
val mtimeh = 0xf81
val minstreth = 0xf82
val all = {
val res = collection.mutable.ArrayBuffer[Int]()
res += fflags
res += frm
res += fcsr
res += cycle
res += time
res += instret
res += sstatus
res += sie
res += stvec
res += sscratch
res += sepc
res += scause
res += sbadaddr
res += sip
res += sptbr
res += scycle
res += stime
res += sinstret
res += mstatus
res += medeleg
res += mideleg
res += mie
res += mtvec
res += mscratch
res += mepc
res += mcause
res += mbadaddr
res += mip
res += mucounteren
res += mscounteren
res += mucycle_delta
res += mutime_delta
res += muinstret_delta
res += mscycle_delta
res += mstime_delta
res += msinstret_delta
res += tdrselect
res += tdrdata1
res += tdrdata2
res += tdrdata3
res += dcsr
res += dpc
res += dscratch
res += mcycle
res += mtime
res += minstret
res += misa
res += mvendorid
res += marchid
res += mimpid
res += mhartid
res += mreset
res.toArray
}
val all32 = {
val res = collection.mutable.ArrayBuffer(all:_*)
res += cycleh
res += timeh
res += instreth
res += mucycle_deltah
res += mutime_deltah
res += muinstret_deltah
res += mscycle_deltah
res += mstime_deltah
res += msinstret_deltah
res += mcycleh
res += mtimeh
res += minstreth
res.toArray
}
}

View File

@ -0,0 +1,154 @@
// See LICENSE for license details.
package rocket
import Chisel._
import ALU._
import Util._
class MultiplierReq(dataBits: Int, tagBits: Int) extends Bundle {
val fn = Bits(width = SZ_ALU_FN)
val dw = Bits(width = SZ_DW)
val in1 = Bits(width = dataBits)
val in2 = Bits(width = dataBits)
val tag = UInt(width = tagBits)
override def cloneType = new MultiplierReq(dataBits, tagBits).asInstanceOf[this.type]
}
class MultiplierResp(dataBits: Int, tagBits: Int) extends Bundle {
val data = Bits(width = dataBits)
val tag = UInt(width = tagBits)
override def cloneType = new MultiplierResp(dataBits, tagBits).asInstanceOf[this.type]
}
class MultiplierIO(dataBits: Int, tagBits: Int) extends Bundle {
val req = Decoupled(new MultiplierReq(dataBits, tagBits)).flip
val kill = Bool(INPUT)
val resp = Decoupled(new MultiplierResp(dataBits, tagBits))
}
case class MulDivConfig(
mulUnroll: Int = 1,
mulEarlyOut: Boolean = false,
divEarlyOut: Boolean = false
)
class MulDiv(cfg: MulDivConfig, width: Int, nXpr: Int = 32) extends Module {
val io = new MultiplierIO(width, log2Up(nXpr))
val w = io.req.bits.in1.getWidth
val mulw = (w + cfg.mulUnroll - 1) / cfg.mulUnroll * cfg.mulUnroll
val s_ready :: s_neg_inputs :: s_busy :: s_move_rem :: s_neg_output :: s_done :: Nil = Enum(UInt(), 6)
val state = Reg(init=s_ready)
val req = Reg(io.req.bits)
val count = Reg(UInt(width = log2Up(w+1)))
val neg_out = Reg(Bool())
val isMul = Reg(Bool())
val isHi = Reg(Bool())
val divisor = Reg(Bits(width = w+1)) // div only needs w bits
val remainder = Reg(Bits(width = 2*mulw+2)) // div only needs 2*w+1 bits
val cmdMul :: cmdHi :: lhsSigned :: rhsSigned :: Nil =
DecodeLogic(io.req.bits.fn, List(X, X, X, X), List(
FN_DIV -> List(N, N, Y, Y),
FN_REM -> List(N, Y, Y, Y),
FN_DIVU -> List(N, N, N, N),
FN_REMU -> List(N, Y, N, N),
FN_MUL -> List(Y, N, X, X),
FN_MULH -> List(Y, Y, Y, Y),
FN_MULHU -> List(Y, Y, N, N),
FN_MULHSU -> List(Y, Y, Y, N))).map(_ toBool)
require(w == 32 || w == 64)
def halfWidth(req: MultiplierReq) = Bool(w > 32) && req.dw === DW_32
def sext(x: Bits, halfW: Bool, signed: Bool) = {
val sign = signed && Mux(halfW, x(w/2-1), x(w-1))
val hi = Mux(halfW, Fill(w/2, sign), x(w-1,w/2))
(Cat(hi, x(w/2-1,0)), sign)
}
val (lhs_in, lhs_sign) = sext(io.req.bits.in1, halfWidth(io.req.bits), lhsSigned)
val (rhs_in, rhs_sign) = sext(io.req.bits.in2, halfWidth(io.req.bits), rhsSigned)
val subtractor = remainder(2*w,w) - divisor(w,0)
val less = subtractor(w)
val negated_remainder = -remainder(w-1,0)
when (state === s_neg_inputs) {
when (remainder(w-1) || isMul) {
remainder := negated_remainder
}
when (divisor(w-1) || isMul) {
divisor := subtractor
}
state := s_busy
}
when (state === s_neg_output) {
remainder := negated_remainder
state := s_done
}
when (state === s_move_rem) {
remainder := remainder(2*w, w+1)
state := Mux(neg_out, s_neg_output, s_done)
}
when (state === s_busy && isMul) {
val mulReg = Cat(remainder(2*mulw+1,w+1),remainder(w-1,0))
val mplier = mulReg(mulw-1,0)
val accum = mulReg(2*mulw,mulw).asSInt
val mpcand = divisor.asSInt
val prod = mplier(cfg.mulUnroll-1, 0) * mpcand + accum
val nextMulReg = Cat(prod, mplier(mulw-1, cfg.mulUnroll))
val eOutMask = (SInt(BigInt(-1) << mulw) >> (count * cfg.mulUnroll)(log2Up(mulw)-1,0))(mulw-1,0)
val eOut = Bool(cfg.mulEarlyOut) && count =/= mulw/cfg.mulUnroll-1 && count =/= 0 &&
!isHi && (mplier & ~eOutMask) === UInt(0)
val eOutRes = (mulReg >> (mulw - count * cfg.mulUnroll)(log2Up(mulw)-1,0))
val nextMulReg1 = Cat(nextMulReg(2*mulw,mulw), Mux(eOut, eOutRes, nextMulReg)(mulw-1,0))
remainder := Cat(nextMulReg1 >> w, Bool(false), nextMulReg1(w-1,0))
count := count + 1
when (eOut || count === mulw/cfg.mulUnroll-1) {
state := Mux(isHi, s_move_rem, s_done)
}
}
when (state === s_busy && !isMul) {
when (count === w) {
state := Mux(isHi, s_move_rem, Mux(neg_out, s_neg_output, s_done))
}
count := count + 1
remainder := Cat(Mux(less, remainder(2*w-1,w), subtractor(w-1,0)), remainder(w-1,0), !less)
val divisorMSB = Log2(divisor(w-1,0), w)
val dividendMSB = Log2(remainder(w-1,0), w)
val eOutPos = UInt(w-1) + divisorMSB - dividendMSB
val eOutZero = divisorMSB > dividendMSB
val eOut = count === 0 && less /* not divby0 */ && (eOutPos > 0 || eOutZero)
when (Bool(cfg.divEarlyOut) && eOut) {
val shift = Mux(eOutZero, UInt(w-1), eOutPos(log2Up(w)-1,0))
remainder := remainder(w-1,0) << shift
count := shift
}
when (count === 0 && !less /* divby0 */ && !isHi) { neg_out := false }
}
when (io.resp.fire() || io.kill) {
state := s_ready
}
when (io.req.fire()) {
state := Mux(lhs_sign || rhs_sign && !cmdMul, s_neg_inputs, s_busy)
isMul := cmdMul
isHi := cmdHi
count := 0
neg_out := !cmdMul && Mux(cmdHi, lhs_sign, lhs_sign =/= rhs_sign)
divisor := Cat(rhs_sign, rhs_in)
remainder := lhs_in
req := io.req.bits
}
io.resp.bits := req
io.resp.bits.data := Mux(halfWidth(req), Cat(Fill(w/2, remainder(w/2-1)), remainder(w/2-1,0)), remainder(w-1,0))
io.resp.valid := state === s_done
io.req.ready := state === s_ready
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
// See LICENSE for license details.
package object rocket extends
rocket.constants.ScalarOpConstants

View File

@ -0,0 +1,218 @@
// See LICENSE for license details.
package rocket
import Chisel._
import uncore.agents._
import uncore.constants._
import Util._
import uncore.util._
import cde.{Parameters, Field}
class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
val prv = Bits(width = 2)
val pum = Bool()
val mxr = Bool()
val addr = UInt(width = vpnBits)
val store = Bool()
val fetch = Bool()
}
class PTWResp(implicit p: Parameters) extends CoreBundle()(p) {
val pte = new PTE
}
class TLBPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
val req = Decoupled(new PTWReq)
val resp = Valid(new PTWResp).flip
val ptbr = new PTBR().asInput
val invalidate = Bool(INPUT)
val status = new MStatus().asInput
}
class DatapathPTWIO(implicit p: Parameters) extends CoreBundle()(p) {
val ptbr = new PTBR().asInput
val invalidate = Bool(INPUT)
val status = new MStatus().asInput
}
class PTE(implicit p: Parameters) extends CoreBundle()(p) {
val reserved_for_hardware = Bits(width = 16)
val ppn = UInt(width = 38)
val reserved_for_software = Bits(width = 2)
val d = Bool()
val a = Bool()
val g = Bool()
val u = Bool()
val x = Bool()
val w = Bool()
val r = Bool()
val v = Bool()
def table(dummy: Int = 0) = v && !r && !w && !x
def leaf(dummy: Int = 0) = v && (r || (x && !w))
def ur(dummy: Int = 0) = sr() && u
def uw(dummy: Int = 0) = sw() && u
def ux(dummy: Int = 0) = sx() && u
def sr(dummy: Int = 0) = leaf() && r
def sw(dummy: Int = 0) = leaf() && w
def sx(dummy: Int = 0) = leaf() && x
def access_ok(req: PTWReq) = {
val perm_ok = Mux(req.fetch, x, Mux(req.store, w, r || (x && req.mxr)))
val priv_ok = Mux(u, !req.pum, req.prv(0))
leaf() && priv_ok && perm_ok
}
}
class PTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) {
val io = new Bundle {
val requestor = Vec(n, new TLBPTWIO).flip
val mem = new HellaCacheIO
val dpath = new DatapathPTWIO
}
require(usingAtomics, "PTW requires atomic memory operations")
val s_ready :: s_req :: s_wait1 :: s_wait2 :: s_set_dirty :: s_wait1_dirty :: s_wait2_dirty :: s_done :: Nil = Enum(UInt(), 8)
val state = Reg(init=s_ready)
val count = Reg(UInt(width = log2Up(pgLevels)))
val s1_kill = Reg(next = Bool(false))
val r_req = Reg(new PTWReq)
val r_req_dest = Reg(Bits())
val r_pte = Reg(new PTE)
val vpn_idxs = (0 until pgLevels).map(i => (r_req.addr >> (pgLevels-i-1)*pgLevelBits)(pgLevelBits-1,0))
val vpn_idx = vpn_idxs(count)
val arb = Module(new RRArbiter(new PTWReq, n))
arb.io.in <> io.requestor.map(_.req)
arb.io.out.ready := state === s_ready
val pte = {
val tmp = new PTE().fromBits(io.mem.resp.bits.data)
val res = Wire(init = new PTE().fromBits(io.mem.resp.bits.data))
res.ppn := tmp.ppn(ppnBits-1, 0)
when ((tmp.ppn >> ppnBits) =/= 0) { res.v := false }
res
}
val pte_addr = Cat(r_pte.ppn, vpn_idx) << log2Ceil(xLen/8)
when (arb.io.out.fire()) {
r_req := arb.io.out.bits
r_req_dest := arb.io.chosen
r_pte.ppn := io.dpath.ptbr.ppn
}
val (pte_cache_hit, pte_cache_data) = {
val size = 1 << log2Up(pgLevels * 2)
val plru = new PseudoLRU(size)
val valid = Reg(init = UInt(0, size))
val tags = Reg(Vec(size, UInt(width = paddrBits)))
val data = Reg(Vec(size, UInt(width = ppnBits)))
val hits = tags.map(_ === pte_addr).asUInt & valid
val hit = hits.orR
when (io.mem.resp.valid && pte.table() && !hit) {
val r = Mux(valid.andR, plru.replace, PriorityEncoder(~valid))
valid := valid | UIntToOH(r)
tags(r) := pte_addr
data(r) := pte.ppn
}
when (hit && state === s_req) { plru.access(OHToUInt(hits)) }
when (io.dpath.invalidate) { valid := 0 }
(hit && count < pgLevels-1, Mux1H(hits, data))
}
val pte_wdata = Wire(init=new PTE().fromBits(0))
pte_wdata.a := true
pte_wdata.d := r_req.store
io.mem.req.valid := state.isOneOf(s_req, s_set_dirty)
io.mem.req.bits.phys := Bool(true)
io.mem.req.bits.cmd := Mux(state === s_set_dirty, M_XA_OR, M_XRD)
io.mem.req.bits.typ := log2Ceil(xLen/8)
io.mem.req.bits.addr := pte_addr
io.mem.s1_data := pte_wdata.asUInt
io.mem.s1_kill := s1_kill
io.mem.invalidate_lr := Bool(false)
val resp_ppns = (0 until pgLevels-1).map(i => Cat(pte_addr >> (pgIdxBits + pgLevelBits*(pgLevels-i-1)), r_req.addr(pgLevelBits*(pgLevels-i-1)-1,0))) :+ (pte_addr >> pgIdxBits)
for (i <- 0 until io.requestor.size) {
io.requestor(i).resp.valid := state === s_done && (r_req_dest === i)
io.requestor(i).resp.bits.pte := r_pte
io.requestor(i).resp.bits.pte.ppn := resp_ppns(count)
io.requestor(i).ptbr := io.dpath.ptbr
io.requestor(i).invalidate := io.dpath.invalidate
io.requestor(i).status := io.dpath.status
}
// control state machine
switch (state) {
is (s_ready) {
when (arb.io.out.valid) {
state := s_req
}
count := UInt(0)
}
is (s_req) {
when (pte_cache_hit) {
s1_kill := true
state := s_req
count := count + 1
r_pte.ppn := pte_cache_data
}.elsewhen (io.mem.req.ready) {
state := s_wait1
}
}
is (s_wait1) {
state := s_wait2
when (io.mem.xcpt.pf.ld) {
r_pte.v := false
state := s_done
}
}
is (s_wait2) {
when (io.mem.s2_nack) {
state := s_req
}
when (io.mem.resp.valid) {
state := s_done
when (pte.access_ok(r_req) && (!pte.a || (r_req.store && !pte.d))) {
state := s_set_dirty
}.otherwise {
r_pte := pte
}
when (pte.table() && count < pgLevels-1) {
state := s_req
count := count + 1
}
}
}
is (s_set_dirty) {
when (io.mem.req.ready) {
state := s_wait1_dirty
}
}
is (s_wait1_dirty) {
state := s_wait2_dirty
when (io.mem.xcpt.pf.st) {
r_pte.v := false
state := s_done
}
}
is (s_wait2_dirty) {
when (io.mem.s2_nack) {
state := s_set_dirty
}
when (io.mem.resp.valid) {
state := s_req
}
}
is (s_done) {
state := s_ready
}
}
}

View File

@ -0,0 +1,290 @@
// See LICENSE for license details.
package rocket
import Chisel._
import uncore.tilelink._
import uncore.constants._
import uncore.agents.CacheName
import Util._
import cde.{Parameters, Field}
case object RoccMaxTaggedMemXacts extends Field[Int]
case object RoccNMemChannels extends Field[Int]
case object RoccNPTWPorts extends Field[Int]
class RoCCInstruction extends Bundle
{
val funct = Bits(width = 7)
val rs2 = Bits(width = 5)
val rs1 = Bits(width = 5)
val xd = Bool()
val xs1 = Bool()
val xs2 = Bool()
val rd = Bits(width = 5)
val opcode = Bits(width = 7)
}
class RoCCCommand(implicit p: Parameters) extends CoreBundle()(p) {
val inst = new RoCCInstruction
val rs1 = Bits(width = xLen)
val rs2 = Bits(width = xLen)
val status = new MStatus
}
class RoCCResponse(implicit p: Parameters) extends CoreBundle()(p) {
val rd = Bits(width = 5)
val data = Bits(width = xLen)
}
class RoCCInterface(implicit p: Parameters) extends CoreBundle()(p) {
val cmd = Decoupled(new RoCCCommand).flip
val resp = Decoupled(new RoCCResponse)
val mem = new HellaCacheIO()(p.alterPartial({ case CacheName => "L1D" }))
val busy = Bool(OUTPUT)
val interrupt = Bool(OUTPUT)
// These should be handled differently, eventually
val autl = new ClientUncachedTileLinkIO
val utl = Vec(p(RoccNMemChannels), new ClientUncachedTileLinkIO)
val ptw = Vec(p(RoccNPTWPorts), new TLBPTWIO)
val fpu_req = Decoupled(new FPInput)
val fpu_resp = Decoupled(new FPResult).flip
val exception = Bool(INPUT)
override def cloneType = new RoCCInterface().asInstanceOf[this.type]
}
abstract class RoCC(implicit p: Parameters) extends CoreModule()(p) {
val io = new RoCCInterface
io.mem.req.bits.phys := Bool(true) // don't perform address translation
}
class AccumulatorExample(n: Int = 4)(implicit p: Parameters) extends RoCC()(p) {
val regfile = Mem(n, UInt(width = xLen))
val busy = Reg(init = Vec.fill(n){Bool(false)})
val cmd = Queue(io.cmd)
val funct = cmd.bits.inst.funct
val addr = cmd.bits.rs2(log2Up(n)-1,0)
val doWrite = funct === UInt(0)
val doRead = funct === UInt(1)
val doLoad = funct === UInt(2)
val doAccum = funct === UInt(3)
val memRespTag = io.mem.resp.bits.tag(log2Up(n)-1,0)
// datapath
val addend = cmd.bits.rs1
val accum = regfile(addr)
val wdata = Mux(doWrite, addend, accum + addend)
when (cmd.fire() && (doWrite || doAccum)) {
regfile(addr) := wdata
}
when (io.mem.resp.valid) {
regfile(memRespTag) := io.mem.resp.bits.data
busy(memRespTag) := Bool(false)
}
// control
when (io.mem.req.fire()) {
busy(addr) := Bool(true)
}
val doResp = cmd.bits.inst.xd
val stallReg = busy(addr)
val stallLoad = doLoad && !io.mem.req.ready
val stallResp = doResp && !io.resp.ready
cmd.ready := !stallReg && !stallLoad && !stallResp
// command resolved if no stalls AND not issuing a load that will need a request
// PROC RESPONSE INTERFACE
io.resp.valid := cmd.valid && doResp && !stallReg && !stallLoad
// valid response if valid command, need a response, and no stalls
io.resp.bits.rd := cmd.bits.inst.rd
// Must respond with the appropriate tag or undefined behavior
io.resp.bits.data := accum
// Semantics is to always send out prior accumulator register value
io.busy := cmd.valid || busy.reduce(_||_)
// Be busy when have pending memory requests or committed possibility of pending requests
io.interrupt := Bool(false)
// Set this true to trigger an interrupt on the processor (please refer to supervisor documentation)
// MEMORY REQUEST INTERFACE
io.mem.req.valid := cmd.valid && doLoad && !stallReg && !stallResp
io.mem.req.bits.addr := addend
io.mem.req.bits.tag := addr
io.mem.req.bits.cmd := M_XRD // perform a load (M_XWR for stores)
io.mem.req.bits.typ := MT_D // D = 8 bytes, W = 4, H = 2, B = 1
io.mem.req.bits.data := Bits(0) // we're not performing any stores...
io.mem.invalidate_lr := false
io.autl.acquire.valid := false
io.autl.grant.ready := false
}
class TranslatorExample(implicit p: Parameters) extends RoCC()(p) {
val req_addr = Reg(UInt(width = coreMaxAddrBits))
val req_rd = Reg(io.resp.bits.rd)
val req_offset = req_addr(pgIdxBits - 1, 0)
val req_vpn = req_addr(coreMaxAddrBits - 1, pgIdxBits)
val pte = Reg(new PTE)
val s_idle :: s_ptw_req :: s_ptw_resp :: s_resp :: Nil = Enum(Bits(), 4)
val state = Reg(init = s_idle)
io.cmd.ready := (state === s_idle)
when (io.cmd.fire()) {
req_rd := io.cmd.bits.inst.rd
req_addr := io.cmd.bits.rs1
state := s_ptw_req
}
private val ptw = io.ptw(0)
when (ptw.req.fire()) { state := s_ptw_resp }
when (state === s_ptw_resp && ptw.resp.valid) {
pte := ptw.resp.bits.pte
state := s_resp
}
when (io.resp.fire()) { state := s_idle }
ptw.req.valid := (state === s_ptw_req)
ptw.req.bits.addr := req_vpn
ptw.req.bits.store := Bool(false)
ptw.req.bits.fetch := Bool(false)
io.resp.valid := (state === s_resp)
io.resp.bits.rd := req_rd
io.resp.bits.data := Mux(pte.leaf(), Cat(pte.ppn, req_offset), SInt(-1, xLen).asUInt)
io.busy := (state =/= s_idle)
io.interrupt := Bool(false)
io.mem.req.valid := Bool(false)
io.mem.invalidate_lr := Bool(false)
io.autl.acquire.valid := Bool(false)
io.autl.grant.ready := Bool(false)
}
class CharacterCountExample(implicit p: Parameters) extends RoCC()(p)
with HasTileLinkParameters {
private val blockOffset = tlBeatAddrBits + tlByteAddrBits
val needle = Reg(UInt(width = 8))
val addr = Reg(UInt(width = coreMaxAddrBits))
val count = Reg(UInt(width = xLen))
val resp_rd = Reg(io.resp.bits.rd)
val addr_block = addr(coreMaxAddrBits - 1, blockOffset)
val offset = addr(blockOffset - 1, 0)
val next_addr = (addr_block + UInt(1)) << UInt(blockOffset)
val s_idle :: s_acq :: s_gnt :: s_check :: s_resp :: Nil = Enum(Bits(), 5)
val state = Reg(init = s_idle)
val gnt = io.autl.grant.bits
val recv_data = Reg(UInt(width = tlDataBits))
val recv_beat = Reg(UInt(width = tlBeatAddrBits))
val data_bytes = Vec.tabulate(tlDataBytes) { i => recv_data(8 * (i + 1) - 1, 8 * i) }
val zero_match = data_bytes.map(_ === UInt(0))
val needle_match = data_bytes.map(_ === needle)
val first_zero = PriorityEncoder(zero_match)
val chars_found = PopCount(needle_match.zipWithIndex.map {
case (matches, i) =>
val idx = Cat(recv_beat, UInt(i, tlByteAddrBits))
matches && idx >= offset && UInt(i) <= first_zero
})
val zero_found = zero_match.reduce(_ || _)
val finished = Reg(Bool())
io.cmd.ready := (state === s_idle)
io.resp.valid := (state === s_resp)
io.resp.bits.rd := resp_rd
io.resp.bits.data := count
io.autl.acquire.valid := (state === s_acq)
io.autl.acquire.bits := GetBlock(addr_block = addr_block)
io.autl.grant.ready := (state === s_gnt)
when (io.cmd.fire()) {
addr := io.cmd.bits.rs1
needle := io.cmd.bits.rs2
resp_rd := io.cmd.bits.inst.rd
count := UInt(0)
finished := Bool(false)
state := s_acq
}
when (io.autl.acquire.fire()) { state := s_gnt }
when (io.autl.grant.fire()) {
recv_beat := gnt.addr_beat
recv_data := gnt.data
state := s_check
}
when (state === s_check) {
when (!finished) {
count := count + chars_found
}
when (zero_found) { finished := Bool(true) }
when (recv_beat === UInt(tlDataBeats - 1)) {
addr := next_addr
state := Mux(zero_found || finished, s_resp, s_acq)
} .otherwise {
state := s_gnt
}
}
when (io.resp.fire()) { state := s_idle }
io.busy := (state =/= s_idle)
io.interrupt := Bool(false)
io.mem.req.valid := Bool(false)
io.mem.invalidate_lr := Bool(false)
}
class OpcodeSet(val opcodes: Seq[UInt]) {
def |(set: OpcodeSet) =
new OpcodeSet(this.opcodes ++ set.opcodes)
def matches(oc: UInt) = opcodes.map(_ === oc).reduce(_ || _)
}
object OpcodeSet {
val custom0 = new OpcodeSet(Seq(Bits("b0001011")))
val custom1 = new OpcodeSet(Seq(Bits("b0101011")))
val custom2 = new OpcodeSet(Seq(Bits("b1011011")))
val custom3 = new OpcodeSet(Seq(Bits("b1111011")))
val all = custom0 | custom1 | custom2 | custom3
}
class RoccCommandRouter(opcodes: Seq[OpcodeSet])(implicit p: Parameters)
extends CoreModule()(p) {
val io = new Bundle {
val in = Decoupled(new RoCCCommand).flip
val out = Vec(opcodes.size, Decoupled(new RoCCCommand))
val busy = Bool(OUTPUT)
}
val cmd = Queue(io.in)
val cmdReadys = io.out.zip(opcodes).map { case (out, opcode) =>
val me = opcode.matches(cmd.bits.inst.opcode)
out.valid := cmd.valid && me
out.bits := cmd.bits
out.ready && me
}
cmd.ready := cmdReadys.reduce(_ || _)
io.busy := cmd.valid
assert(PopCount(cmdReadys) <= UInt(1),
"Custom opcode matched for more than one accelerator")
}

View File

@ -0,0 +1,702 @@
// See LICENSE for license details.
package rocket
import Chisel._
import junctions._
import uncore.devices._
import uncore.agents.CacheName
import uncore.constants._
import Util._
import cde.{Parameters, Field}
case object XLen extends Field[Int]
case object FetchWidth extends Field[Int]
case object RetireWidth extends Field[Int]
case object FPUKey extends Field[Option[FPUConfig]]
case object MulDivKey extends Field[Option[MulDivConfig]]
case object UseVM extends Field[Boolean]
case object UseUser extends Field[Boolean]
case object UseDebug extends Field[Boolean]
case object UseAtomics extends Field[Boolean]
case object UseCompressed extends Field[Boolean]
case object FastLoadWord extends Field[Boolean]
case object FastLoadByte extends Field[Boolean]
case object CoreInstBits extends Field[Int]
case object NCustomMRWCSRs extends Field[Int]
case object MtvecWritable extends Field[Boolean]
case object MtvecInit extends Field[BigInt]
case object ResetVector extends Field[BigInt]
case object NBreakpoints extends Field[Int]
trait HasCoreParameters extends HasAddrMapParameters {
implicit val p: Parameters
val xLen = p(XLen)
val usingVM = p(UseVM)
val usingUser = p(UseUser) || usingVM
val usingDebug = p(UseDebug)
val usingMulDiv = p(MulDivKey).nonEmpty
val usingFPU = p(FPUKey).nonEmpty
val usingAtomics = p(UseAtomics)
val usingCompressed = p(UseCompressed)
val usingRoCC = !p(BuildRoCC).isEmpty
val fastLoadWord = p(FastLoadWord)
val fastLoadByte = p(FastLoadByte)
val retireWidth = p(RetireWidth)
val fetchWidth = p(FetchWidth)
val coreInstBits = p(CoreInstBits)
val coreInstBytes = coreInstBits/8
val coreDataBits = xLen
val coreDataBytes = coreDataBits/8
val dcacheArbPorts = 1 + (if (usingVM) 1 else 0) + p(BuildRoCC).size
val coreDCacheReqTagBits = 6
val dcacheReqTagBits = coreDCacheReqTagBits + log2Ceil(dcacheArbPorts)
def pgIdxBits = 12
def pgLevelBits = 10 - log2Ceil(xLen / 32)
def vaddrBits = pgIdxBits + pgLevels * pgLevelBits
def ppnBits = paddrBits - pgIdxBits
def vpnBits = vaddrBits - pgIdxBits
val pgLevels = p(PgLevels)
val asIdBits = p(ASIdBits)
val vpnBitsExtended = vpnBits + (vaddrBits < xLen).toInt
val vaddrBitsExtended = vpnBitsExtended + pgIdxBits
val coreMaxAddrBits = paddrBits max vaddrBitsExtended
val nCustomMrwCsrs = p(NCustomMRWCSRs)
val nCores = p(NTiles)
// fetchWidth doubled, but coreInstBytes halved, for RVC
val decodeWidth = fetchWidth / (if (usingCompressed) 2 else 1)
// Print out log of committed instructions and their writeback values.
// Requires post-processing due to out-of-order writebacks.
val enableCommitLog = false
val maxPAddrBits = xLen match {
case 32 => 34
case 64 => 50
}
require(paddrBits <= maxPAddrBits)
require(!fastLoadByte || fastLoadWord)
}
abstract class CoreModule(implicit val p: Parameters) extends Module
with HasCoreParameters
abstract class CoreBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
with HasCoreParameters
class RegFile(n: Int, w: Int, zero: Boolean = false) {
private val rf = Mem(n, UInt(width = w))
private def access(addr: UInt) = rf(~addr(log2Up(n)-1,0))
private val reads = collection.mutable.ArrayBuffer[(UInt,UInt)]()
private var canRead = true
def read(addr: UInt) = {
require(canRead)
reads += addr -> Wire(UInt())
reads.last._2 := Mux(Bool(zero) && addr === UInt(0), UInt(0), access(addr))
reads.last._2
}
def write(addr: UInt, data: UInt) = {
canRead = false
when (addr =/= UInt(0)) {
access(addr) := data
for ((raddr, rdata) <- reads)
when (addr === raddr) { rdata := data }
}
}
}
object ImmGen {
def apply(sel: UInt, inst: UInt) = {
val sign = Mux(sel === IMM_Z, SInt(0), inst(31).asSInt)
val b30_20 = Mux(sel === IMM_U, inst(30,20).asSInt, sign)
val b19_12 = Mux(sel =/= IMM_U && sel =/= IMM_UJ, sign, inst(19,12).asSInt)
val b11 = Mux(sel === IMM_U || sel === IMM_Z, SInt(0),
Mux(sel === IMM_UJ, inst(20).asSInt,
Mux(sel === IMM_SB, inst(7).asSInt, sign)))
val b10_5 = Mux(sel === IMM_U || sel === IMM_Z, Bits(0), inst(30,25))
val b4_1 = Mux(sel === IMM_U, Bits(0),
Mux(sel === IMM_S || sel === IMM_SB, inst(11,8),
Mux(sel === IMM_Z, inst(19,16), inst(24,21))))
val b0 = Mux(sel === IMM_S, inst(7),
Mux(sel === IMM_I, inst(20),
Mux(sel === IMM_Z, inst(15), Bits(0))))
Cat(sign, b30_20, b19_12, b11, b10_5, b4_1, b0).asSInt
}
}
class Rocket(implicit p: Parameters) extends CoreModule()(p) {
val io = new Bundle {
val prci = new PRCITileIO().flip
val imem = new FrontendIO()(p.alterPartial({case CacheName => "L1I" }))
val dmem = new HellaCacheIO()(p.alterPartial({ case CacheName => "L1D" }))
val ptw = new DatapathPTWIO().flip
val fpu = new FPUIO().flip
val rocc = new RoCCInterface().flip
}
val decode_table = {
(if (usingMulDiv) new MDecode +: (if (xLen > 32) Seq(new M64Decode) else Nil) else Nil) ++:
(if (usingAtomics) new ADecode +: (if (xLen > 32) Seq(new A64Decode) else Nil) else Nil) ++:
(if (usingFPU) new FDecode +: (if (xLen > 32) Seq(new F64Decode) else Nil) else Nil) ++:
(if (usingRoCC) Some(new RoCCDecode) else None) ++:
(if (xLen > 32) Some(new I64Decode) else None) ++:
(if (usingVM) Some(new SDecode) else None) ++:
(if (usingDebug) Some(new DebugDecode) else None) ++:
Seq(new IDecode)
} flatMap(_.table)
val ex_ctrl = Reg(new IntCtrlSigs)
val mem_ctrl = Reg(new IntCtrlSigs)
val wb_ctrl = Reg(new IntCtrlSigs)
val ex_reg_xcpt_interrupt = Reg(Bool())
val ex_reg_valid = Reg(Bool())
val ex_reg_rvc = Reg(Bool())
val ex_reg_btb_hit = Reg(Bool())
val ex_reg_btb_resp = Reg(new BTBResp)
val ex_reg_xcpt = Reg(Bool())
val ex_reg_flush_pipe = Reg(Bool())
val ex_reg_load_use = Reg(Bool())
val ex_reg_cause = Reg(UInt())
val ex_reg_replay = Reg(Bool())
val ex_reg_pc = Reg(UInt())
val ex_reg_inst = Reg(Bits())
val mem_reg_xcpt_interrupt = Reg(Bool())
val mem_reg_valid = Reg(Bool())
val mem_reg_rvc = Reg(Bool())
val mem_reg_btb_hit = Reg(Bool())
val mem_reg_btb_resp = Reg(new BTBResp)
val mem_reg_xcpt = Reg(Bool())
val mem_reg_replay = Reg(Bool())
val mem_reg_flush_pipe = Reg(Bool())
val mem_reg_cause = Reg(UInt())
val mem_reg_slow_bypass = Reg(Bool())
val mem_reg_load = Reg(Bool())
val mem_reg_store = Reg(Bool())
val mem_reg_pc = Reg(UInt())
val mem_reg_inst = Reg(Bits())
val mem_reg_wdata = Reg(Bits())
val mem_reg_rs2 = Reg(Bits())
val take_pc_mem = Wire(Bool())
val wb_reg_valid = Reg(Bool())
val wb_reg_xcpt = Reg(Bool())
val wb_reg_replay = Reg(Bool())
val wb_reg_cause = Reg(UInt())
val wb_reg_pc = Reg(UInt())
val wb_reg_inst = Reg(Bits())
val wb_reg_wdata = Reg(Bits())
val wb_reg_rs2 = Reg(Bits())
val take_pc_wb = Wire(Bool())
val take_pc_mem_wb = take_pc_wb || take_pc_mem
val take_pc = take_pc_mem_wb
// decode stage
val ibuf = Module(new IBuf)
val id_expanded_inst = ibuf.io.inst.map(_.bits.inst)
val id_inst = id_expanded_inst.map(_.bits)
ibuf.io.imem <> io.imem.resp
ibuf.io.kill := take_pc
require(decodeWidth == 1 /* TODO */ && retireWidth == decodeWidth)
val id_ctrl = Wire(new IntCtrlSigs()).decode(id_inst(0), decode_table)
val id_raddr3 = id_expanded_inst(0).rs3
val id_raddr2 = id_expanded_inst(0).rs2
val id_raddr1 = id_expanded_inst(0).rs1
val id_waddr = id_expanded_inst(0).rd
val id_load_use = Wire(Bool())
val id_reg_fence = Reg(init=Bool(false))
val id_ren = IndexedSeq(id_ctrl.rxs1, id_ctrl.rxs2)
val id_raddr = IndexedSeq(id_raddr1, id_raddr2)
val rf = new RegFile(31, xLen)
val id_rs = id_raddr.map(rf.read _)
val ctrl_killd = Wire(Bool())
val csr = Module(new CSRFile)
val id_csr_en = id_ctrl.csr =/= CSR.N
val id_system_insn = id_ctrl.csr === CSR.I
val id_csr_ren = (id_ctrl.csr === CSR.S || id_ctrl.csr === CSR.C) && id_raddr1 === UInt(0)
val id_csr = Mux(id_csr_ren, CSR.R, id_ctrl.csr)
val id_csr_addr = id_inst(0)(31,20)
// this is overly conservative
val safe_csrs = CSRs.sscratch :: CSRs.sepc :: CSRs.mscratch :: CSRs.mepc :: CSRs.mcause :: CSRs.mbadaddr :: Nil
val legal_csrs = collection.mutable.LinkedHashSet(CSRs.all:_*)
val id_csr_flush = id_system_insn || (id_csr_en && !id_csr_ren && !DecodeLogic(id_csr_addr, safe_csrs.map(UInt(_)), (legal_csrs -- safe_csrs).toList.map(UInt(_))))
val id_illegal_insn = !id_ctrl.legal ||
id_ctrl.fp && !csr.io.status.fs.orR ||
id_ctrl.rocc && !csr.io.status.xs.orR
// stall decode for fences (now, for AMO.aq; later, for AMO.rl and FENCE)
val id_amo_aq = id_inst(0)(26)
val id_amo_rl = id_inst(0)(25)
val id_fence_next = id_ctrl.fence || id_ctrl.amo && id_amo_rl
val id_mem_busy = !io.dmem.ordered || io.dmem.req.valid
val id_rocc_busy = Bool(usingRoCC) &&
(io.rocc.busy || ex_reg_valid && ex_ctrl.rocc ||
mem_reg_valid && mem_ctrl.rocc || wb_reg_valid && wb_ctrl.rocc)
id_reg_fence := id_fence_next || id_reg_fence && id_mem_busy
val id_do_fence = id_rocc_busy && id_ctrl.fence ||
id_mem_busy && (id_ctrl.amo && id_amo_aq || id_ctrl.fence_i || id_reg_fence && (id_ctrl.mem || id_ctrl.rocc) || id_csr_en)
val bpu = Module(new BreakpointUnit)
bpu.io.status := csr.io.status
bpu.io.bp := csr.io.bp
bpu.io.pc := ibuf.io.pc
bpu.io.ea := mem_reg_wdata
val id_xcpt_if = ibuf.io.inst(0).bits.pf0 || ibuf.io.inst(0).bits.pf1
val (id_xcpt, id_cause) = checkExceptions(List(
(csr.io.interrupt, csr.io.interrupt_cause),
(bpu.io.xcpt_if, UInt(Causes.breakpoint)),
(id_xcpt_if, UInt(Causes.fault_fetch)),
(id_illegal_insn, UInt(Causes.illegal_instruction))))
val dcache_bypass_data =
if (fastLoadByte) io.dmem.resp.bits.data
else if (fastLoadWord) io.dmem.resp.bits.data_word_bypass
else wb_reg_wdata
// detect bypass opportunities
val ex_waddr = ex_reg_inst(11,7)
val mem_waddr = mem_reg_inst(11,7)
val wb_waddr = wb_reg_inst(11,7)
val bypass_sources = IndexedSeq(
(Bool(true), UInt(0), UInt(0)), // treat reading x0 as a bypass
(ex_reg_valid && ex_ctrl.wxd, ex_waddr, mem_reg_wdata),
(mem_reg_valid && mem_ctrl.wxd && !mem_ctrl.mem, mem_waddr, wb_reg_wdata),
(mem_reg_valid && mem_ctrl.wxd, mem_waddr, dcache_bypass_data))
val id_bypass_src = id_raddr.map(raddr => bypass_sources.map(s => s._1 && s._2 === raddr))
// execute stage
val bypass_mux = Vec(bypass_sources.map(_._3))
val ex_reg_rs_bypass = Reg(Vec(id_raddr.size, Bool()))
val ex_reg_rs_lsb = Reg(Vec(id_raddr.size, UInt()))
val ex_reg_rs_msb = Reg(Vec(id_raddr.size, UInt()))
val ex_rs = for (i <- 0 until id_raddr.size)
yield Mux(ex_reg_rs_bypass(i), bypass_mux(ex_reg_rs_lsb(i)), Cat(ex_reg_rs_msb(i), ex_reg_rs_lsb(i)))
val ex_imm = ImmGen(ex_ctrl.sel_imm, ex_reg_inst)
val ex_op1 = MuxLookup(ex_ctrl.sel_alu1, SInt(0), Seq(
A1_RS1 -> ex_rs(0).asSInt,
A1_PC -> ex_reg_pc.asSInt))
val ex_op2 = MuxLookup(ex_ctrl.sel_alu2, SInt(0), Seq(
A2_RS2 -> ex_rs(1).asSInt,
A2_IMM -> ex_imm,
A2_SIZE -> Mux(ex_reg_rvc, SInt(2), SInt(4))))
val alu = Module(new ALU)
alu.io.dw := ex_ctrl.alu_dw
alu.io.fn := ex_ctrl.alu_fn
alu.io.in2 := ex_op2.asUInt
alu.io.in1 := ex_op1.asUInt
// multiplier and divider
val div = Module(new MulDiv(p(MulDivKey).getOrElse(MulDivConfig()), width = xLen))
div.io.req.valid := ex_reg_valid && ex_ctrl.div
div.io.req.bits.dw := ex_ctrl.alu_dw
div.io.req.bits.fn := ex_ctrl.alu_fn
div.io.req.bits.in1 := ex_rs(0)
div.io.req.bits.in2 := ex_rs(1)
div.io.req.bits.tag := ex_waddr
ex_reg_valid := !ctrl_killd
ex_reg_replay := !take_pc && ibuf.io.inst(0).valid && ibuf.io.inst(0).bits.replay
ex_reg_xcpt := !ctrl_killd && id_xcpt
ex_reg_xcpt_interrupt := !take_pc && ibuf.io.inst(0).valid && csr.io.interrupt
when (id_xcpt) { ex_reg_cause := id_cause }
ex_reg_btb_hit := ibuf.io.inst(0).bits.btb_hit
when (ibuf.io.inst(0).bits.btb_hit) { ex_reg_btb_resp := ibuf.io.btb_resp }
when (!ctrl_killd) {
ex_ctrl := id_ctrl
ex_reg_rvc := ibuf.io.inst(0).bits.rvc
ex_ctrl.csr := id_csr
when (id_xcpt) { // pass PC down ALU writeback pipeline for badaddr
ex_ctrl.alu_fn := ALU.FN_ADD
ex_ctrl.alu_dw := DW_XPR
ex_ctrl.sel_alu1 := A1_PC
ex_ctrl.sel_alu2 := A2_ZERO
when (!bpu.io.xcpt_if && !ibuf.io.inst(0).bits.pf0 && ibuf.io.inst(0).bits.pf1) { // PC+2
ex_ctrl.sel_alu2 := A2_SIZE
ex_reg_rvc := true
}
}
ex_reg_flush_pipe := id_ctrl.fence_i || id_csr_flush || csr.io.singleStep
ex_reg_load_use := id_load_use
when (id_ctrl.jalr && csr.io.status.debug) {
ex_reg_flush_pipe := true
ex_ctrl.fence_i := true
}
for (i <- 0 until id_raddr.size) {
val do_bypass = id_bypass_src(i).reduce(_||_)
val bypass_src = PriorityEncoder(id_bypass_src(i))
ex_reg_rs_bypass(i) := do_bypass
ex_reg_rs_lsb(i) := bypass_src
when (id_ren(i) && !do_bypass) {
ex_reg_rs_lsb(i) := id_rs(i)(bypass_src.getWidth-1,0)
ex_reg_rs_msb(i) := id_rs(i) >> bypass_src.getWidth
}
}
}
when (!ctrl_killd || csr.io.interrupt || ibuf.io.inst(0).bits.replay) {
ex_reg_inst := id_inst(0)
ex_reg_pc := ibuf.io.pc
}
// replay inst in ex stage?
val ex_pc_valid = ex_reg_valid || ex_reg_replay || ex_reg_xcpt_interrupt
val wb_dcache_miss = wb_ctrl.mem && !io.dmem.resp.valid
val replay_ex_structural = ex_ctrl.mem && !io.dmem.req.ready ||
ex_ctrl.div && !div.io.req.ready
val replay_ex_load_use = wb_dcache_miss && ex_reg_load_use
val replay_ex = ex_reg_replay || (ex_reg_valid && (replay_ex_structural || replay_ex_load_use))
val ctrl_killx = take_pc_mem_wb || replay_ex || !ex_reg_valid
// detect 2-cycle load-use delay for LB/LH/SC
val ex_slow_bypass = ex_ctrl.mem_cmd === M_XSC || Vec(MT_B, MT_BU, MT_H, MT_HU).contains(ex_ctrl.mem_type)
val (ex_xcpt, ex_cause) = checkExceptions(List(
(ex_reg_xcpt_interrupt || ex_reg_xcpt, ex_reg_cause),
(ex_ctrl.fp && io.fpu.illegal_rm, UInt(Causes.illegal_instruction))))
// memory stage
val mem_br_taken = mem_reg_wdata(0)
val mem_br_target = mem_reg_pc.asSInt +
Mux(mem_ctrl.branch && mem_br_taken, ImmGen(IMM_SB, mem_reg_inst),
Mux(mem_ctrl.jal, ImmGen(IMM_UJ, mem_reg_inst),
Mux(mem_reg_rvc, SInt(2), SInt(4))))
val mem_npc = (Mux(mem_ctrl.jalr, encodeVirtualAddress(mem_reg_wdata, mem_reg_wdata).asSInt, mem_br_target) & SInt(-2)).asUInt
val mem_wrong_npc = Mux(ex_pc_valid, mem_npc =/= ex_reg_pc, Mux(ibuf.io.inst(0).valid, mem_npc =/= ibuf.io.pc, Bool(true)))
val mem_npc_misaligned = if (usingCompressed) Bool(false) else mem_npc(1)
val mem_int_wdata = Mux(!mem_reg_xcpt && (mem_ctrl.jalr ^ mem_npc_misaligned), mem_br_target, mem_reg_wdata.asSInt).asUInt
val mem_cfi = mem_ctrl.branch || mem_ctrl.jalr || mem_ctrl.jal
val mem_cfi_taken = (mem_ctrl.branch && mem_br_taken) || mem_ctrl.jalr || mem_ctrl.jal
val mem_misprediction =
if (p(BtbKey).nEntries == 0) mem_cfi_taken
else mem_wrong_npc
take_pc_mem := mem_reg_valid && (mem_misprediction || mem_reg_flush_pipe)
mem_reg_valid := !ctrl_killx
mem_reg_replay := !take_pc_mem_wb && replay_ex
mem_reg_xcpt := !ctrl_killx && ex_xcpt
mem_reg_xcpt_interrupt := !take_pc_mem_wb && ex_reg_xcpt_interrupt
when (ex_xcpt) { mem_reg_cause := ex_cause }
when (ex_pc_valid) {
mem_ctrl := ex_ctrl
mem_reg_rvc := ex_reg_rvc
mem_reg_load := ex_ctrl.mem && isRead(ex_ctrl.mem_cmd)
mem_reg_store := ex_ctrl.mem && isWrite(ex_ctrl.mem_cmd)
mem_reg_btb_hit := ex_reg_btb_hit
when (ex_reg_btb_hit) { mem_reg_btb_resp := ex_reg_btb_resp }
mem_reg_flush_pipe := ex_reg_flush_pipe
mem_reg_slow_bypass := ex_slow_bypass
mem_reg_inst := ex_reg_inst
mem_reg_pc := ex_reg_pc
mem_reg_wdata := alu.io.out
when (ex_ctrl.rxs2 && (ex_ctrl.mem || ex_ctrl.rocc)) {
mem_reg_rs2 := ex_rs(1)
}
}
val mem_breakpoint = (mem_reg_load && bpu.io.xcpt_ld) || (mem_reg_store && bpu.io.xcpt_st)
val (mem_new_xcpt, mem_new_cause) = checkExceptions(List(
(mem_breakpoint, UInt(Causes.breakpoint)),
(mem_npc_misaligned, UInt(Causes.misaligned_fetch)),
(mem_ctrl.mem && io.dmem.xcpt.ma.st, UInt(Causes.misaligned_store)),
(mem_ctrl.mem && io.dmem.xcpt.ma.ld, UInt(Causes.misaligned_load)),
(mem_ctrl.mem && io.dmem.xcpt.pf.st, UInt(Causes.fault_store)),
(mem_ctrl.mem && io.dmem.xcpt.pf.ld, UInt(Causes.fault_load))))
val (mem_xcpt, mem_cause) = checkExceptions(List(
(mem_reg_xcpt_interrupt || mem_reg_xcpt, mem_reg_cause),
(mem_reg_valid && mem_new_xcpt, mem_new_cause)))
val dcache_kill_mem = mem_reg_valid && mem_ctrl.wxd && io.dmem.replay_next // structural hazard on writeback port
val fpu_kill_mem = mem_reg_valid && mem_ctrl.fp && io.fpu.nack_mem
val replay_mem = dcache_kill_mem || mem_reg_replay || fpu_kill_mem
val killm_common = dcache_kill_mem || take_pc_wb || mem_reg_xcpt || !mem_reg_valid
div.io.kill := killm_common && Reg(next = div.io.req.fire())
val ctrl_killm = killm_common || mem_xcpt || fpu_kill_mem
// writeback stage
wb_reg_valid := !ctrl_killm
wb_reg_replay := replay_mem && !take_pc_wb
wb_reg_xcpt := mem_xcpt && !take_pc_wb
when (mem_xcpt) { wb_reg_cause := mem_cause }
when (mem_reg_valid || mem_reg_replay || mem_reg_xcpt_interrupt) {
wb_ctrl := mem_ctrl
wb_reg_wdata := Mux(!mem_reg_xcpt && mem_ctrl.fp && mem_ctrl.wxd, io.fpu.toint_data, mem_int_wdata)
when (mem_ctrl.rocc) {
wb_reg_rs2 := mem_reg_rs2
}
wb_reg_inst := mem_reg_inst
wb_reg_pc := mem_reg_pc
}
val wb_set_sboard = wb_ctrl.div || wb_dcache_miss || wb_ctrl.rocc
val replay_wb_common = io.dmem.s2_nack || wb_reg_replay
val replay_wb_rocc = wb_reg_valid && wb_ctrl.rocc && !io.rocc.cmd.ready
val replay_wb = replay_wb_common || replay_wb_rocc
val wb_xcpt = wb_reg_xcpt || csr.io.csr_xcpt
take_pc_wb := replay_wb || wb_xcpt || csr.io.eret
// writeback arbitration
val dmem_resp_xpu = !io.dmem.resp.bits.tag(0).toBool
val dmem_resp_fpu = io.dmem.resp.bits.tag(0).toBool
val dmem_resp_waddr = io.dmem.resp.bits.tag(5, 1)
val dmem_resp_valid = io.dmem.resp.valid && io.dmem.resp.bits.has_data
val dmem_resp_replay = dmem_resp_valid && io.dmem.resp.bits.replay
div.io.resp.ready := !(wb_reg_valid && wb_ctrl.wxd)
val ll_wdata = Wire(init = div.io.resp.bits.data)
val ll_waddr = Wire(init = div.io.resp.bits.tag)
val ll_wen = Wire(init = div.io.resp.fire())
if (usingRoCC) {
io.rocc.resp.ready := !(wb_reg_valid && wb_ctrl.wxd)
when (io.rocc.resp.fire()) {
div.io.resp.ready := Bool(false)
ll_wdata := io.rocc.resp.bits.data
ll_waddr := io.rocc.resp.bits.rd
ll_wen := Bool(true)
}
}
when (dmem_resp_replay && dmem_resp_xpu) {
div.io.resp.ready := Bool(false)
if (usingRoCC)
io.rocc.resp.ready := Bool(false)
ll_waddr := dmem_resp_waddr
ll_wen := Bool(true)
}
val wb_valid = wb_reg_valid && !replay_wb && !wb_xcpt
val wb_wen = wb_valid && wb_ctrl.wxd
val rf_wen = wb_wen || ll_wen
val rf_waddr = Mux(ll_wen, ll_waddr, wb_waddr)
val rf_wdata = Mux(dmem_resp_valid && dmem_resp_xpu, io.dmem.resp.bits.data,
Mux(ll_wen, ll_wdata,
Mux(wb_ctrl.csr =/= CSR.N, csr.io.rw.rdata,
wb_reg_wdata)))
when (rf_wen) { rf.write(rf_waddr, rf_wdata) }
// hook up control/status regfile
csr.io.exception := wb_reg_xcpt
csr.io.cause := wb_reg_cause
csr.io.retire := wb_valid
csr.io.prci <> io.prci
io.fpu.fcsr_rm := csr.io.fcsr_rm
csr.io.fcsr_flags := io.fpu.fcsr_flags
csr.io.rocc.interrupt <> io.rocc.interrupt
csr.io.pc := wb_reg_pc
csr.io.badaddr := encodeVirtualAddress(wb_reg_wdata, wb_reg_wdata)
io.ptw.ptbr := csr.io.ptbr
io.ptw.invalidate := csr.io.fatc
io.ptw.status := csr.io.status
csr.io.rw.addr := wb_reg_inst(31,20)
csr.io.rw.cmd := Mux(wb_reg_valid, wb_ctrl.csr, CSR.N)
csr.io.rw.wdata := wb_reg_wdata
val hazard_targets = Seq((id_ctrl.rxs1 && id_raddr1 =/= UInt(0), id_raddr1),
(id_ctrl.rxs2 && id_raddr2 =/= UInt(0), id_raddr2),
(id_ctrl.wxd && id_waddr =/= UInt(0), id_waddr))
val fp_hazard_targets = Seq((io.fpu.dec.ren1, id_raddr1),
(io.fpu.dec.ren2, id_raddr2),
(io.fpu.dec.ren3, id_raddr3),
(io.fpu.dec.wen, id_waddr))
val sboard = new Scoreboard(32, true)
sboard.clear(ll_wen, ll_waddr)
val id_sboard_hazard = checkHazards(hazard_targets, sboard.read _)
sboard.set(wb_set_sboard && wb_wen, wb_waddr)
// stall for RAW/WAW hazards on CSRs, loads, AMOs, and mul/div in execute stage.
val ex_cannot_bypass = ex_ctrl.csr =/= CSR.N || ex_ctrl.jalr || ex_ctrl.mem || ex_ctrl.div || ex_ctrl.fp || ex_ctrl.rocc
val data_hazard_ex = ex_ctrl.wxd && checkHazards(hazard_targets, _ === ex_waddr)
val fp_data_hazard_ex = ex_ctrl.wfd && checkHazards(fp_hazard_targets, _ === ex_waddr)
val id_ex_hazard = ex_reg_valid && (data_hazard_ex && ex_cannot_bypass || fp_data_hazard_ex)
// stall for RAW/WAW hazards on CSRs, LB/LH, and mul/div in memory stage.
val mem_mem_cmd_bh =
if (fastLoadWord) Bool(!fastLoadByte) && mem_reg_slow_bypass
else Bool(true)
val mem_cannot_bypass = mem_ctrl.csr =/= CSR.N || mem_ctrl.mem && mem_mem_cmd_bh || mem_ctrl.div || mem_ctrl.fp || mem_ctrl.rocc
val data_hazard_mem = mem_ctrl.wxd && checkHazards(hazard_targets, _ === mem_waddr)
val fp_data_hazard_mem = mem_ctrl.wfd && checkHazards(fp_hazard_targets, _ === mem_waddr)
val id_mem_hazard = mem_reg_valid && (data_hazard_mem && mem_cannot_bypass || fp_data_hazard_mem)
id_load_use := mem_reg_valid && data_hazard_mem && mem_ctrl.mem
// stall for RAW/WAW hazards on load/AMO misses and mul/div in writeback.
val data_hazard_wb = wb_ctrl.wxd && checkHazards(hazard_targets, _ === wb_waddr)
val fp_data_hazard_wb = wb_ctrl.wfd && checkHazards(fp_hazard_targets, _ === wb_waddr)
val id_wb_hazard = wb_reg_valid && (data_hazard_wb && wb_set_sboard || fp_data_hazard_wb)
val id_stall_fpu = if (usingFPU) {
val fp_sboard = new Scoreboard(32)
fp_sboard.set((wb_dcache_miss && wb_ctrl.wfd || io.fpu.sboard_set) && wb_valid, wb_waddr)
fp_sboard.clear(dmem_resp_replay && dmem_resp_fpu, dmem_resp_waddr)
fp_sboard.clear(io.fpu.sboard_clr, io.fpu.sboard_clra)
id_csr_en && !io.fpu.fcsr_rdy || checkHazards(fp_hazard_targets, fp_sboard.read _)
} else Bool(false)
val dcache_blocked = Reg(Bool())
dcache_blocked := !io.dmem.req.ready && (io.dmem.req.valid || dcache_blocked)
val rocc_blocked = Reg(Bool())
rocc_blocked := !wb_reg_xcpt && !io.rocc.cmd.ready && (io.rocc.cmd.valid || rocc_blocked)
val ctrl_stalld =
id_ex_hazard || id_mem_hazard || id_wb_hazard || id_sboard_hazard ||
id_ctrl.fp && id_stall_fpu ||
id_ctrl.mem && dcache_blocked || // reduce activity during D$ misses
id_ctrl.rocc && rocc_blocked || // reduce activity while RoCC is busy
id_do_fence ||
csr.io.csr_stall
ctrl_killd := !ibuf.io.inst(0).valid || ibuf.io.inst(0).bits.replay || take_pc || ctrl_stalld || csr.io.interrupt
io.imem.req.valid := take_pc
io.imem.req.bits.speculative := !take_pc_wb
io.imem.req.bits.pc :=
Mux(wb_xcpt || csr.io.eret, csr.io.evec, // exception or [m|s]ret
Mux(replay_wb, wb_reg_pc, // replay
mem_npc)) // mispredicted branch
io.imem.flush_icache := wb_reg_valid && wb_ctrl.fence_i && !io.dmem.s2_nack
io.imem.flush_tlb := csr.io.fatc
ibuf.io.inst(0).ready := !ctrl_stalld || csr.io.interrupt
io.imem.btb_update.valid := (mem_reg_replay && mem_reg_btb_hit) || (mem_reg_valid && !take_pc_wb && (mem_cfi_taken || !mem_cfi) && mem_wrong_npc)
io.imem.btb_update.bits.isValid := !mem_reg_replay && mem_cfi
io.imem.btb_update.bits.isJump := mem_ctrl.jal || mem_ctrl.jalr
io.imem.btb_update.bits.isReturn := mem_ctrl.jalr && mem_reg_inst(19,15) === BitPat("b00??1")
io.imem.btb_update.bits.target := io.imem.req.bits.pc
io.imem.btb_update.bits.br_pc := (if (usingCompressed) mem_reg_pc + Mux(mem_reg_rvc, UInt(0), UInt(2)) else mem_reg_pc)
io.imem.btb_update.bits.pc := ~(~io.imem.btb_update.bits.br_pc | (coreInstBytes*fetchWidth-1))
io.imem.btb_update.bits.prediction.valid := mem_reg_btb_hit
io.imem.btb_update.bits.prediction.bits := mem_reg_btb_resp
io.imem.bht_update.valid := mem_reg_valid && !take_pc_wb && mem_ctrl.branch
io.imem.bht_update.bits.pc := io.imem.btb_update.bits.pc
io.imem.bht_update.bits.taken := mem_br_taken
io.imem.bht_update.bits.mispredict := mem_wrong_npc
io.imem.bht_update.bits.prediction := io.imem.btb_update.bits.prediction
io.imem.ras_update.valid := mem_reg_valid && !take_pc_wb
io.imem.ras_update.bits.returnAddr := mem_int_wdata
io.imem.ras_update.bits.isCall := io.imem.btb_update.bits.isJump && mem_waddr(0)
io.imem.ras_update.bits.isReturn := io.imem.btb_update.bits.isReturn
io.imem.ras_update.bits.prediction := io.imem.btb_update.bits.prediction
io.fpu.valid := !ctrl_killd && id_ctrl.fp
io.fpu.killx := ctrl_killx
io.fpu.killm := killm_common
io.fpu.inst := id_inst(0)
io.fpu.fromint_data := ex_rs(0)
io.fpu.dmem_resp_val := dmem_resp_valid && dmem_resp_fpu
io.fpu.dmem_resp_data := io.dmem.resp.bits.data_word_bypass
io.fpu.dmem_resp_type := io.dmem.resp.bits.typ
io.fpu.dmem_resp_tag := dmem_resp_waddr
io.dmem.req.valid := ex_reg_valid && ex_ctrl.mem
val ex_dcache_tag = Cat(ex_waddr, ex_ctrl.fp)
require(coreDCacheReqTagBits >= ex_dcache_tag.getWidth)
io.dmem.req.bits.tag := ex_dcache_tag
io.dmem.req.bits.cmd := ex_ctrl.mem_cmd
io.dmem.req.bits.typ := ex_ctrl.mem_type
io.dmem.req.bits.phys := Bool(false)
io.dmem.req.bits.addr := encodeVirtualAddress(ex_rs(0), alu.io.adder_out)
io.dmem.invalidate_lr := wb_xcpt
io.dmem.s1_data := Mux(mem_ctrl.fp, io.fpu.store_data, mem_reg_rs2)
io.dmem.s1_kill := killm_common || mem_breakpoint
when (mem_xcpt && !io.dmem.s1_kill) {
assert(io.dmem.xcpt.asUInt.orR) // make sure s1_kill is exhaustive
}
io.rocc.cmd.valid := wb_reg_valid && wb_ctrl.rocc && !replay_wb_common
io.rocc.exception := wb_xcpt && csr.io.status.xs.orR
io.rocc.cmd.bits.status := csr.io.status
io.rocc.cmd.bits.inst := new RoCCInstruction().fromBits(wb_reg_inst)
io.rocc.cmd.bits.rs1 := wb_reg_wdata
io.rocc.cmd.bits.rs2 := wb_reg_rs2
if (enableCommitLog) {
val pc = Wire(SInt(width=xLen))
pc := wb_reg_pc
val inst = wb_reg_inst
val rd = RegNext(RegNext(RegNext(id_waddr)))
val wfd = wb_ctrl.wfd
val wxd = wb_ctrl.wxd
val has_data = wb_wen && !wb_set_sboard
val priv = csr.io.status.prv
when (wb_valid) {
when (wfd) {
printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, inst, rd, rd+UInt(32))
}
.elsewhen (wxd && rd =/= UInt(0) && has_data) {
printf ("%d 0x%x (0x%x) x%d 0x%x\n", priv, pc, inst, rd, rf_wdata)
}
.elsewhen (wxd && rd =/= UInt(0) && !has_data) {
printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, inst, rd, rd)
}
.otherwise {
printf ("%d 0x%x (0x%x)\n", priv, pc, inst)
}
}
when (ll_wen && rf_waddr =/= UInt(0)) {
printf ("x%d p%d 0x%x\n", rf_waddr, rf_waddr, rf_wdata)
}
}
else {
printf("C%d: %d [%d] pc=[%x] W[r%d=%x][%d] R[r%d=%x] R[r%d=%x] inst=[%x] DASM(%x)\n",
io.prci.id, csr.io.time(31,0), wb_valid, wb_reg_pc,
Mux(rf_wen, rf_waddr, UInt(0)), rf_wdata, rf_wen,
wb_reg_inst(19,15), Reg(next=Reg(next=ex_rs(0))),
wb_reg_inst(24,20), Reg(next=Reg(next=ex_rs(1))),
wb_reg_inst, wb_reg_inst)
}
def checkExceptions(x: Seq[(Bool, UInt)]) =
(x.map(_._1).reduce(_||_), PriorityMux(x))
def checkHazards(targets: Seq[(Bool, UInt)], cond: UInt => Bool) =
targets.map(h => h._1 && cond(h._2)).reduce(_||_)
def encodeVirtualAddress(a0: UInt, ea: UInt) = if (vaddrBitsExtended == vaddrBits) ea else {
// efficient means to compress 64-bit VA into vaddrBits+1 bits
// (VA is bad if VA(vaddrBits) != VA(vaddrBits-1))
val a = a0 >> vaddrBits-1
val e = ea(vaddrBits,vaddrBits-1).asSInt
val msb =
Mux(a === UInt(0) || a === UInt(1), e =/= SInt(0),
Mux(a.asSInt === SInt(-1) || a.asSInt === SInt(-2), e === SInt(-1), e(0)))
Cat(msb, ea(vaddrBits-1,0))
}
class Scoreboard(n: Int, zero: Boolean = false)
{
def set(en: Bool, addr: UInt): Unit = update(en, _next | mask(en, addr))
def clear(en: Bool, addr: UInt): Unit = update(en, _next & ~mask(en, addr))
def read(addr: UInt): Bool = r(addr)
def readBypassed(addr: UInt): Bool = _next(addr)
private val _r = Reg(init=Bits(0, n))
private val r = if (zero) (_r >> 1 << 1) else _r
private var _next = r
private var ens = Bool(false)
private def mask(en: Bool, addr: UInt) = Mux(en, UInt(1) << addr, UInt(0))
private def update(en: Bool, update: UInt) = {
_next = update
ens = ens || en
when (ens) { _r := _next }
}
}
}

View File

@ -0,0 +1,166 @@
package rocket
import Chisel._
import Chisel.ImplicitConversions._
import Util._
import cde.Parameters
import uncore.util._
class ExpandedInstruction extends Bundle {
val bits = UInt(width = 32)
val rd = UInt(width = 5)
val rs1 = UInt(width = 5)
val rs2 = UInt(width = 5)
val rs3 = UInt(width = 5)
}
class RVCDecoder(x: UInt)(implicit p: Parameters) {
def inst(bits: UInt, rd: UInt = x(11,7), rs1: UInt = x(19,15), rs2: UInt = x(24,20), rs3: UInt = x(31,27)) = {
val res = Wire(new ExpandedInstruction)
res.bits := bits
res.rd := rd
res.rs1 := rs1
res.rs2 := rs2
res.rs3 := rs3
res
}
def rs1p = Cat(UInt(1,2), x(9,7))
def rs2p = Cat(UInt(1,2), x(4,2))
def rs2 = x(6,2)
def rd = x(11,7)
def addi4spnImm = Cat(x(10,7), x(12,11), x(5), x(6), UInt(0,2))
def lwImm = Cat(x(5), x(12,10), x(6), UInt(0,2))
def ldImm = Cat(x(6,5), x(12,10), UInt(0,3))
def lwspImm = Cat(x(3,2), x(12), x(6,4), UInt(0,2))
def ldspImm = Cat(x(4,2), x(12), x(6,5), UInt(0,3))
def swspImm = Cat(x(8,7), x(12,9), UInt(0,2))
def sdspImm = Cat(x(9,7), x(12,10), UInt(0,3))
def luiImm = Cat(Fill(15, x(12)), x(6,2), UInt(0,12))
def addi16spImm = Cat(Fill(3, x(12)), x(4,3), x(5), x(2), x(6), UInt(0,4))
def addiImm = Cat(Fill(7, x(12)), x(6,2))
def jImm = Cat(Fill(10, x(12)), x(8), x(10,9), x(6), x(7), x(2), x(11), x(5,3), UInt(0,1))
def bImm = Cat(Fill(5, x(12)), x(6,5), x(2), x(11,10), x(4,3), UInt(0,1))
def shamt = Cat(x(12), x(6,2))
def x0 = UInt(0,5)
def ra = UInt(1,5)
def sp = UInt(2,5)
def q0 = {
def addi4spn = {
val opc = Mux(x(12,5).orR, UInt(0x13,7), UInt(0x1F,7))
inst(Cat(addi4spnImm, sp, UInt(0,3), rs2p, opc), rs2p, sp, rs2p)
}
def ld = inst(Cat(ldImm, rs1p, UInt(3,3), rs2p, UInt(0x03,7)), rs2p, rs1p, rs2p)
def lw = inst(Cat(lwImm, rs1p, UInt(2,3), rs2p, UInt(0x03,7)), rs2p, rs1p, rs2p)
def fld = inst(Cat(ldImm, rs1p, UInt(3,3), rs2p, UInt(0x07,7)), rs2p, rs1p, rs2p)
def flw = {
if (p(XLen) == 32) inst(Cat(lwImm, rs1p, UInt(2,3), rs2p, UInt(0x07,7)), rs2p, rs1p, rs2p)
else ld
}
def unimp = inst(Cat(lwImm >> 5, rs2p, rs1p, UInt(2,3), lwImm(4,0), UInt(0x2F,7)), rs2p, rs1p, rs2p)
def sd = inst(Cat(ldImm >> 5, rs2p, rs1p, UInt(3,3), ldImm(4,0), UInt(0x23,7)), rs2p, rs1p, rs2p)
def sw = inst(Cat(lwImm >> 5, rs2p, rs1p, UInt(2,3), lwImm(4,0), UInt(0x23,7)), rs2p, rs1p, rs2p)
def fsd = inst(Cat(ldImm >> 5, rs2p, rs1p, UInt(3,3), ldImm(4,0), UInt(0x27,7)), rs2p, rs1p, rs2p)
def fsw = {
if (p(XLen) == 32) inst(Cat(lwImm >> 5, rs2p, rs1p, UInt(2,3), lwImm(4,0), UInt(0x27,7)), rs2p, rs1p, rs2p)
else sd
}
Seq(addi4spn, fld, lw, flw, unimp, fsd, sw, fsw)
}
def q1 = {
def addi = inst(Cat(addiImm, rd, UInt(0,3), rd, UInt(0x13,7)), rd, rd, rs2p)
def addiw = {
val opc = Mux(rd.orR, UInt(0x1B,7), UInt(0x1F,7))
inst(Cat(addiImm, rd, UInt(0,3), rd, opc), rd, rd, rs2p)
}
def jal = {
if (p(XLen) == 32) inst(Cat(jImm(20), jImm(10,1), jImm(11), jImm(19,12), ra, UInt(0x6F,7)), ra, rd, rs2p)
else addiw
}
def li = inst(Cat(addiImm, x0, UInt(0,3), rd, UInt(0x13,7)), rd, x0, rs2p)
def addi16sp = {
val opc = Mux(addiImm.orR, UInt(0x13,7), UInt(0x1F,7))
inst(Cat(addi16spImm, rd, UInt(0,3), rd, opc), rd, rd, rs2p)
}
def lui = {
val opc = Mux(addiImm.orR, UInt(0x37,7), UInt(0x3F,7))
val me = inst(Cat(luiImm(31,12), rd, opc), rd, rd, rs2p)
Mux(rd === x0 || rd === sp, addi16sp, me)
}
def j = inst(Cat(jImm(20), jImm(10,1), jImm(11), jImm(19,12), x0, UInt(0x6F,7)), x0, rs1p, rs2p)
def beqz = inst(Cat(bImm(12), bImm(10,5), x0, rs1p, UInt(0,3), bImm(4,1), bImm(11), UInt(0x63,7)), rs1p, rs1p, x0)
def bnez = inst(Cat(bImm(12), bImm(10,5), x0, rs1p, UInt(1,3), bImm(4,1), bImm(11), UInt(0x63,7)), x0, rs1p, x0)
def arith = {
def srli = Cat(shamt, rs1p, UInt(5,3), rs1p, UInt(0x13,7))
def srai = srli | UInt(1 << 30)
def andi = Cat(addiImm, rs1p, UInt(7,3), rs1p, UInt(0x13,7))
def rtype = {
val funct = Seq(0.U, 4.U, 6.U, 7.U, 0.U, 0.U, 2.U, 3.U)(Cat(x(12), x(6,5)))
val sub = Mux(x(6,5) === UInt(0), UInt(1 << 30), UInt(0))
val opc = Mux(x(12), UInt(0x3B,7), UInt(0x33,7))
Cat(rs2p, rs1p, funct, rs1p, opc) | sub
}
inst(Seq(srli, srai, andi, rtype)(x(11,10)), rs1p, rs1p, rs2p)
}
Seq(addi, jal, li, lui, arith, j, beqz, bnez)
}
def q2 = {
def slli = inst(Cat(shamt, rd, UInt(1,3), rd, UInt(0x13,7)), rd, rd, rs2)
def ldsp = inst(Cat(ldspImm, sp, UInt(3,3), rd, UInt(0x03,7)), rd, sp, rs2)
def lwsp = inst(Cat(lwspImm, sp, UInt(2,3), rd, UInt(0x03,7)), rd, sp, rs2)
def fldsp = inst(Cat(ldspImm, sp, UInt(3,3), rd, UInt(0x07,7)), rd, sp, rs2)
def flwsp = {
if (p(XLen) == 32) inst(Cat(lwspImm, sp, UInt(2,3), rd, UInt(0x07,7)), rd, sp, rs2)
else ldsp
}
def sdsp = inst(Cat(sdspImm >> 5, rs2, sp, UInt(3,3), sdspImm(4,0), UInt(0x23,7)), rd, sp, rs2)
def swsp = inst(Cat(swspImm >> 5, rs2, sp, UInt(2,3), swspImm(4,0), UInt(0x23,7)), rd, sp, rs2)
def fsdsp = inst(Cat(sdspImm >> 5, rs2, sp, UInt(3,3), sdspImm(4,0), UInt(0x27,7)), rd, sp, rs2)
def fswsp = {
if (p(XLen) == 32) inst(Cat(swspImm >> 5, rs2, sp, UInt(2,3), swspImm(4,0), UInt(0x27,7)), rd, sp, rs2)
else sdsp
}
def jalr = {
val mv = inst(Cat(rs2, x0, UInt(0,3), rd, UInt(0x33,7)), rd, x0, rs2)
val add = inst(Cat(rs2, rd, UInt(0,3), rd, UInt(0x33,7)), rd, rd, rs2)
val jr = Cat(rs2, rd, UInt(0,3), x0, UInt(0x67,7))
val reserved = Cat(jr >> 7, UInt(0x1F,7))
val jr_reserved = inst(Mux(rd.orR, jr, reserved), x0, rd, rs2)
val jr_mv = Mux(rs2.orR, mv, jr_reserved)
val jalr = Cat(rs2, rd, UInt(0,3), ra, UInt(0x67,7))
val ebreak = Cat(jr >> 7, UInt(0x73,7)) | UInt(1 << 20)
val jalr_ebreak = inst(Mux(rd.orR, jalr, ebreak), ra, rd, rs2)
val jalr_add = Mux(rs2.orR, add, jalr_ebreak)
Mux(x(12), jalr_add, jr_mv)
}
Seq(slli, fldsp, lwsp, flwsp, jalr, fsdsp, swsp, fswsp)
}
def q3 = Seq.fill(8)(passthrough)
def passthrough = inst(x)
def decode = {
val s = q0 ++ q1 ++ q2 ++ q3
s(Cat(x(1,0), x(15,13)))
}
}
class RVCExpander(implicit p: Parameters) extends Module {
val io = new Bundle {
val in = UInt(INPUT, 32)
val out = new ExpandedInstruction
val rvc = Bool(OUTPUT)
}
if (p(UseCompressed)) {
io.rvc := io.in(1,0) =/= UInt(3)
io.out := new RVCDecoder(io.in).decode
} else {
io.rvc := Bool(false)
io.out := new RVCDecoder(io.in).passthrough
}
}

View File

@ -0,0 +1,134 @@
// See LICENSE for license details.
package rocket
import Chisel._
import uncore.tilelink._
import uncore.agents._
import uncore.devices._
import Util._
import cde.{Parameters, Field}
case object BuildRoCC extends Field[Seq[RoccParameters]]
case object NCachedTileLinkPorts extends Field[Int]
case object NUncachedTileLinkPorts extends Field[Int]
case class RoccParameters(
opcodes: OpcodeSet,
generator: Parameters => RoCC,
nMemChannels: Int = 0,
nPTWPorts : Int = 0,
useFPU: Boolean = false)
abstract class Tile(clockSignal: Clock = null, resetSignal: Bool = null)
(implicit p: Parameters) extends Module(Option(clockSignal), Option(resetSignal)) {
val nCachedTileLinkPorts = p(NCachedTileLinkPorts)
val nUncachedTileLinkPorts = p(NUncachedTileLinkPorts)
val dcacheParams = p.alterPartial({ case CacheName => "L1D" })
class TileIO extends Bundle {
val cached = Vec(nCachedTileLinkPorts, new ClientTileLinkIO)
val uncached = Vec(nUncachedTileLinkPorts, new ClientUncachedTileLinkIO)
val prci = new PRCITileIO().flip
}
val io = new TileIO
}
class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
(implicit p: Parameters) extends Tile(clockSignal, resetSignal)(p) {
val buildRocc = p(BuildRoCC)
val usingRocc = !buildRocc.isEmpty
val nRocc = buildRocc.size
val nFPUPorts = buildRocc.filter(_.useFPU).size
val core = Module(new Rocket)
val icache = Module(new Frontend()(p.alterPartial({ case CacheName => "L1I" })))
val dcache = HellaCache(p(DCacheKey))(dcacheParams)
val ptwPorts = collection.mutable.ArrayBuffer(icache.io.ptw, dcache.ptw)
val dcPorts = collection.mutable.ArrayBuffer(core.io.dmem)
val uncachedArbPorts = collection.mutable.ArrayBuffer(icache.io.mem)
val uncachedPorts = collection.mutable.ArrayBuffer[ClientUncachedTileLinkIO]()
val cachedPorts = collection.mutable.ArrayBuffer(dcache.mem)
core.io.prci <> io.prci
icache.io.cpu <> core.io.imem
val fpuOpt = p(FPUKey).map(cfg => Module(new FPU(cfg)))
fpuOpt.foreach(fpu => core.io.fpu <> fpu.io)
if (usingRocc) {
val respArb = Module(new RRArbiter(new RoCCResponse, nRocc))
core.io.rocc.resp <> respArb.io.out
val roccOpcodes = buildRocc.map(_.opcodes)
val cmdRouter = Module(new RoccCommandRouter(roccOpcodes))
cmdRouter.io.in <> core.io.rocc.cmd
val roccs = buildRocc.zipWithIndex.map { case (accelParams, i) =>
val rocc = accelParams.generator(p.alterPartial({
case RoccNMemChannels => accelParams.nMemChannels
case RoccNPTWPorts => accelParams.nPTWPorts
}))
val dcIF = Module(new SimpleHellaCacheIF()(dcacheParams))
rocc.io.cmd <> cmdRouter.io.out(i)
rocc.io.exception := core.io.rocc.exception
dcIF.io.requestor <> rocc.io.mem
dcPorts += dcIF.io.cache
uncachedArbPorts += rocc.io.autl
rocc
}
if (nFPUPorts > 0) {
fpuOpt.foreach { fpu =>
val fpArb = Module(new InOrderArbiter(new FPInput, new FPResult, nFPUPorts))
val fp_roccs = roccs.zip(buildRocc)
.filter { case (_, params) => params.useFPU }
.map { case (rocc, _) => rocc.io }
fpArb.io.in_req <> fp_roccs.map(_.fpu_req)
fp_roccs.zip(fpArb.io.in_resp).foreach {
case (rocc, fpu_resp) => rocc.fpu_resp <> fpu_resp
}
fpu.io.cp_req <> fpArb.io.out_req
fpArb.io.out_resp <> fpu.io.cp_resp
}
}
core.io.rocc.busy := cmdRouter.io.busy || roccs.map(_.io.busy).reduce(_ || _)
core.io.rocc.interrupt := roccs.map(_.io.interrupt).reduce(_ || _)
respArb.io.in <> roccs.map(rocc => Queue(rocc.io.resp))
ptwPorts ++= roccs.flatMap(_.io.ptw)
uncachedPorts ++= roccs.flatMap(_.io.utl)
}
val uncachedArb = Module(new ClientUncachedTileLinkIOArbiter(uncachedArbPorts.size))
uncachedArb.io.in <> uncachedArbPorts
uncachedArb.io.out +=: uncachedPorts
// Connect the caches and RoCC to the outer memory system
io.uncached <> uncachedPorts
io.cached <> cachedPorts
// TODO remove nCached/nUncachedTileLinkPorts parameters and these assertions
require(uncachedPorts.size == nUncachedTileLinkPorts)
require(cachedPorts.size == nCachedTileLinkPorts)
if (p(UseVM)) {
val ptw = Module(new PTW(ptwPorts.size)(dcacheParams))
ptw.io.requestor <> ptwPorts
ptw.io.mem +=: dcPorts
core.io.ptw <> ptw.io.dpath
}
require(dcPorts.size == core.dcacheArbPorts)
val dcArb = Module(new HellaCacheArbiter(dcPorts.size)(dcacheParams))
dcArb.io.requestor <> dcPorts
dcache.cpu <> dcArb.io.mem
if (nFPUPorts == 0) {
fpuOpt.foreach { fpu =>
fpu.io.cp_req.valid := Bool(false)
fpu.io.cp_resp.ready := Bool(false)
}
}
}

View File

@ -0,0 +1,193 @@
// See LICENSE for license details.
package rocket
import Chisel._
import Util._
import junctions._
import scala.math._
import cde.{Parameters, Field}
import uncore.agents.PseudoLRU
import uncore.coherence._
import uncore.util._
case object PgLevels extends Field[Int]
case object ASIdBits extends Field[Int]
case object NTLBEntries extends Field[Int]
trait HasTLBParameters extends HasCoreParameters {
val entries = p(NTLBEntries)
val camAddrBits = log2Ceil(entries)
val camTagBits = asIdBits + vpnBits
}
class TLBReq(implicit p: Parameters) extends CoreBundle()(p) {
val vpn = UInt(width = vpnBitsExtended)
val passthrough = Bool()
val instruction = Bool()
val store = Bool()
}
class TLBResp(implicit p: Parameters) extends CoreBundle()(p) {
// lookup responses
val miss = Bool(OUTPUT)
val ppn = UInt(OUTPUT, ppnBits)
val xcpt_ld = Bool(OUTPUT)
val xcpt_st = Bool(OUTPUT)
val xcpt_if = Bool(OUTPUT)
val cacheable = Bool(OUTPUT)
}
class TLB(implicit val p: Parameters) extends Module with HasTLBParameters {
val io = new Bundle {
val req = Decoupled(new TLBReq).flip
val resp = new TLBResp
val ptw = new TLBPTWIO
}
val valid = Reg(init = UInt(0, entries))
val ppns = Reg(Vec(entries, UInt(width = ppnBits)))
val tags = Reg(Vec(entries, UInt(width = asIdBits + vpnBits)))
val s_ready :: s_request :: s_wait :: s_wait_invalidate :: Nil = Enum(UInt(), 4)
val state = Reg(init=s_ready)
val r_refill_tag = Reg(UInt(width = asIdBits + vpnBits))
val r_refill_waddr = Reg(UInt(width = log2Ceil(entries)))
val r_req = Reg(new TLBReq)
val do_mprv = io.ptw.status.mprv && !io.req.bits.instruction
val priv = Mux(do_mprv, io.ptw.status.mpp, io.ptw.status.prv)
val priv_s = priv === PRV.S
val priv_uses_vm = priv <= PRV.S && !io.ptw.status.debug
// share a single physical memory attribute checker (unshare if critical path)
val passthrough_ppn = io.req.bits.vpn(ppnBits-1, 0)
val refill_ppn = io.ptw.resp.bits.pte.ppn(ppnBits-1, 0)
val do_refill = Bool(usingVM) && io.ptw.resp.valid
val mpu_ppn = Mux(do_refill, refill_ppn, passthrough_ppn)
val prot = addrMap.getProt(mpu_ppn << pgIdxBits)
val cacheable = addrMap.isCacheable(mpu_ppn << pgIdxBits)
def pgaligned(r: MemRegion) = {
val pgsize = 1 << pgIdxBits
(r.start % pgsize) == 0 && (r.size % pgsize) == 0
}
require(addrMap.flatten.forall(e => pgaligned(e.region)),
"MemoryMap regions must be page-aligned")
val lookup_tag = Cat(io.ptw.ptbr.asid, io.req.bits.vpn(vpnBits-1,0))
val vm_enabled = Bool(usingVM) && io.ptw.status.vm(3) && priv_uses_vm && !io.req.bits.passthrough
val hitsVec = (0 until entries).map(i => valid(i) && vm_enabled && tags(i) === lookup_tag) :+ !vm_enabled
val hits = hitsVec.asUInt
// permission bit arrays
val pte_array = Reg(new PTE)
val u_array = Reg(UInt(width = entries)) // user permission
val sw_array = Reg(UInt(width = entries)) // write permission
val sx_array = Reg(UInt(width = entries)) // execute permission
val sr_array = Reg(UInt(width = entries)) // read permission
val xr_array = Reg(UInt(width = entries)) // read permission to executable page
val cash_array = Reg(UInt(width = entries)) // cacheable
val dirty_array = Reg(UInt(width = entries)) // PTE dirty bit
when (do_refill) {
val pte = io.ptw.resp.bits.pte
ppns(r_refill_waddr) := pte.ppn
tags(r_refill_waddr) := r_refill_tag
val mask = UIntToOH(r_refill_waddr)
valid := valid | mask
u_array := Mux(pte.u, u_array | mask, u_array & ~mask)
sw_array := Mux(pte.sw() && prot.w, sw_array | mask, sw_array & ~mask)
sx_array := Mux(pte.sx() && prot.x, sx_array | mask, sx_array & ~mask)
sr_array := Mux(pte.sr() && prot.r, sr_array | mask, sr_array & ~mask)
xr_array := Mux(pte.sx() && prot.r, xr_array | mask, xr_array & ~mask)
cash_array := Mux(cacheable, cash_array | mask, cash_array & ~mask)
dirty_array := Mux(pte.d, dirty_array | mask, dirty_array & ~mask)
}
val plru = new PseudoLRU(entries)
val repl_waddr = Mux(!valid.andR, PriorityEncoder(~valid), plru.replace)
val priv_ok = Mux(priv_s, ~Mux(io.ptw.status.pum, u_array, UInt(0)), u_array)
val w_array = Cat(prot.w, priv_ok & sw_array)
val x_array = Cat(prot.x, priv_ok & sx_array)
val r_array = Cat(prot.r, priv_ok & (sr_array | Mux(io.ptw.status.mxr, xr_array, UInt(0))))
val c_array = Cat(cacheable, cash_array)
val bad_va =
if (vpnBits == vpnBitsExtended) Bool(false)
else io.req.bits.vpn(vpnBits) =/= io.req.bits.vpn(vpnBits-1)
// it's only a store hit if the dirty bit is set
val tlb_hits = hits(entries-1, 0) & (dirty_array | ~Mux(io.req.bits.store, w_array, UInt(0)))
val tlb_hit = tlb_hits.orR
val tlb_miss = vm_enabled && !bad_va && !tlb_hit
when (io.req.valid && !tlb_miss) {
plru.access(OHToUInt(hits(entries-1, 0)))
}
io.req.ready := state === s_ready
io.resp.xcpt_ld := bad_va || (~r_array & hits).orR
io.resp.xcpt_st := bad_va || (~w_array & hits).orR
io.resp.xcpt_if := bad_va || (~x_array & hits).orR
io.resp.cacheable := (c_array & hits).orR
io.resp.miss := do_refill || tlb_miss
io.resp.ppn := Mux1H(hitsVec, ppns :+ passthrough_ppn)
io.ptw.req.valid := state === s_request
io.ptw.req.bits := io.ptw.status
io.ptw.req.bits.addr := r_refill_tag
io.ptw.req.bits.store := r_req.store
io.ptw.req.bits.fetch := r_req.instruction
if (usingVM) {
when (io.req.fire() && tlb_miss) {
state := s_request
r_refill_tag := lookup_tag
r_refill_waddr := repl_waddr
r_req := io.req.bits
}
when (state === s_request) {
when (io.ptw.invalidate) {
state := s_ready
}
when (io.ptw.req.ready) {
state := s_wait
when (io.ptw.invalidate) { state := s_wait_invalidate }
}
}
when (state === s_wait && io.ptw.invalidate) {
state := s_wait_invalidate
}
when (io.ptw.resp.valid) {
state := s_ready
}
when (io.ptw.invalidate) {
valid := 0
}
}
}
class DecoupledTLB(implicit p: Parameters) extends Module {
val io = new Bundle {
val req = Decoupled(new TLBReq).flip
val resp = Decoupled(new TLBResp)
val ptw = new TLBPTWIO
}
val reqq = Queue(io.req)
val tlb = Module(new TLB)
val resp_helper = DecoupledHelper(
reqq.valid, tlb.io.req.ready, io.resp.ready)
val tlb_miss = tlb.io.resp.miss
tlb.io.req.valid := resp_helper.fire(tlb.io.req.ready)
tlb.io.req.bits := reqq.bits
reqq.ready := resp_helper.fire(reqq.valid, !tlb_miss)
io.resp.valid := resp_helper.fire(io.resp.ready, !tlb_miss)
io.resp.bits := tlb.io.resp
io.ptw <> tlb.io.ptw
}

View File

@ -0,0 +1,159 @@
// See LICENSE for license details.
package rocket
import Chisel._
import uncore.util._
import scala.math._
import cde.{Parameters, Field}
object Util {
implicit def uintToBitPat(x: UInt): BitPat = BitPat(x)
implicit def intToUInt(x: Int): UInt = UInt(x)
implicit def bigIntToUInt(x: BigInt): UInt = UInt(x)
implicit def booleanToBool(x: Boolean): Bits = Bool(x)
implicit def intSeqToUIntSeq(x: Seq[Int]): Seq[UInt] = x.map(UInt(_))
implicit def wcToUInt(c: WideCounter): UInt = c.value
implicit class UIntToAugmentedUInt(val x: UInt) extends AnyVal {
def sextTo(n: Int): UInt =
if (x.getWidth == n) x
else Cat(Fill(n - x.getWidth, x(x.getWidth-1)), x)
def extract(hi: Int, lo: Int): UInt = {
if (hi == lo-1) UInt(0)
else x(hi, lo)
}
}
implicit def booleanToIntConv(x: Boolean) = new AnyRef {
def toInt: Int = if (x) 1 else 0
}
}
import Util._
object Str
{
def apply(s: String): UInt = {
var i = BigInt(0)
require(s.forall(validChar _))
for (c <- s)
i = (i << 8) | c
UInt(i, s.length*8)
}
def apply(x: Char): UInt = {
require(validChar(x))
UInt(x.toInt, 8)
}
def apply(x: UInt): UInt = apply(x, 10)
def apply(x: UInt, radix: Int): UInt = {
val rad = UInt(radix)
val w = x.getWidth
require(w > 0)
var q = x
var s = digit(q % rad)
for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) {
q = q / rad
s = Cat(Mux(Bool(radix == 10) && q === UInt(0), Str(' '), digit(q % rad)), s)
}
s
}
def apply(x: SInt): UInt = apply(x, 10)
def apply(x: SInt, radix: Int): UInt = {
val neg = x < SInt(0)
val abs = x.abs
if (radix != 10) {
Cat(Mux(neg, Str('-'), Str(' ')), Str(abs, radix))
} else {
val rad = UInt(radix)
val w = abs.getWidth
require(w > 0)
var q = abs
var s = digit(q % rad)
var needSign = neg
for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) {
q = q / rad
val placeSpace = q === UInt(0)
val space = Mux(needSign, Str('-'), Str(' '))
needSign = needSign && !placeSpace
s = Cat(Mux(placeSpace, space, digit(q % rad)), s)
}
Cat(Mux(needSign, Str('-'), Str(' ')), s)
}
}
private def digit(d: UInt): UInt = Mux(d < UInt(10), Str('0')+d, Str(('a'-10).toChar)+d)(7,0)
private def validChar(x: Char) = x == (x & 0xFF)
}
object Split
{
// is there a better way to do do this?
def apply(x: Bits, n0: Int) = {
val w = checkWidth(x, n0)
(x(w-1,n0), x(n0-1,0))
}
def apply(x: Bits, n1: Int, n0: Int) = {
val w = checkWidth(x, n1, n0)
(x(w-1,n1), x(n1-1,n0), x(n0-1,0))
}
def apply(x: Bits, n2: Int, n1: Int, n0: Int) = {
val w = checkWidth(x, n2, n1, n0)
(x(w-1,n2), x(n2-1,n1), x(n1-1,n0), x(n0-1,0))
}
private def checkWidth(x: Bits, n: Int*) = {
val w = x.getWidth
def decreasing(x: Seq[Int]): Boolean =
if (x.tail.isEmpty) true
else x.head >= x.tail.head && decreasing(x.tail)
require(decreasing(w :: n.toList))
w
}
}
// a counter that clock gates most of its MSBs using the LSB carry-out
case class WideCounter(width: Int, inc: UInt = UInt(1))
{
private val isWide = width > 2*inc.getWidth
private val smallWidth = if (isWide) inc.getWidth max log2Up(width) else width
private val small = Reg(init=UInt(0, smallWidth))
private val nextSmall = small +& inc
small := nextSmall
private val large = if (isWide) {
val r = Reg(init=UInt(0, width - smallWidth))
when (nextSmall(smallWidth)) { r := r + UInt(1) }
r
} else null
val value = if (isWide) Cat(large, small) else small
def := (x: UInt) = {
small := x
if (isWide) large := x >> smallWidth
}
}
object Random
{
def apply(mod: Int, random: UInt): UInt = {
if (isPow2(mod)) random(log2Up(mod)-1,0)
else PriorityEncoder(partition(apply(1 << log2Up(mod*8), random), mod))
}
def apply(mod: Int): UInt = apply(mod, randomizer)
def oneHot(mod: Int, random: UInt): UInt = {
if (isPow2(mod)) UIntToOH(random(log2Up(mod)-1,0))
else PriorityEncoderOH(partition(apply(1 << log2Up(mod*8), random), mod)).asUInt
}
def oneHot(mod: Int): UInt = oneHot(mod, randomizer)
private def randomizer = LFSR16()
private def round(x: Double): Int =
if (x.toInt.toDouble == x) x.toInt else (x.toInt + 1) & -2
private def partition(value: UInt, slices: Int) =
Seq.tabulate(slices)(i => value < round((i << value.getWidth).toDouble / slices))
}