2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.Berkeley for license details.
|
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
2015-10-06 06:48:05 +02:00
|
|
|
package rocket
|
|
|
|
|
|
|
|
import Chisel._
|
2017-02-09 22:59:09 +01:00
|
|
|
import Chisel.ImplicitConversions._
|
2017-04-20 01:51:39 +02:00
|
|
|
import chisel3.core.withReset
|
2016-12-13 02:38:55 +01:00
|
|
|
import config._
|
2017-01-17 03:24:08 +01:00
|
|
|
import coreplex._
|
2016-12-13 02:38:55 +01:00
|
|
|
import diplomacy._
|
|
|
|
import uncore.tilelink2._
|
2017-02-09 22:59:09 +01:00
|
|
|
import tile._
|
2016-09-28 06:27:07 +02:00
|
|
|
import util._
|
2015-10-06 06:48:05 +02:00
|
|
|
|
|
|
|
class FrontendReq(implicit p: Parameters) extends CoreBundle()(p) {
|
|
|
|
val pc = UInt(width = vaddrBitsExtended)
|
2016-07-09 10:08:52 +02:00
|
|
|
val speculative = Bool()
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class FrontendResp(implicit p: Parameters) extends CoreBundle()(p) {
|
2016-07-30 01:36:07 +02:00
|
|
|
val btb = Valid(new BTBResp)
|
2015-10-06 06:48:05 +02:00
|
|
|
val pc = UInt(width = vaddrBitsExtended) // ID stage PC
|
2016-07-30 01:36:07 +02:00
|
|
|
val data = UInt(width = fetchWidth * coreInstBits)
|
2015-10-06 06:48:05 +02:00
|
|
|
val mask = Bits(width = fetchWidth)
|
2017-03-27 03:18:35 +02:00
|
|
|
val pf = Bool()
|
|
|
|
val ae = Bool()
|
2016-07-09 10:08:52 +02:00
|
|
|
val replay = Bool()
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class FrontendIO(implicit p: Parameters) extends CoreBundle()(p) {
|
|
|
|
val req = Valid(new FrontendReq)
|
2017-03-14 21:54:49 +01:00
|
|
|
val sfence = Valid(new SFenceReq)
|
2015-10-06 06:48:05 +02:00
|
|
|
val resp = Decoupled(new FrontendResp).flip
|
|
|
|
val btb_update = Valid(new BTBUpdate)
|
|
|
|
val bht_update = Valid(new BHTUpdate)
|
|
|
|
val ras_update = Valid(new RASUpdate)
|
2016-04-23 00:20:17 +02:00
|
|
|
val flush_icache = Bool(OUTPUT)
|
2015-10-06 06:48:05 +02:00
|
|
|
val npc = UInt(INPUT, width = vaddrBitsExtended)
|
2017-03-09 09:28:19 +01:00
|
|
|
|
|
|
|
// performance events
|
|
|
|
val acquire = Bool(INPUT)
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
|
|
|
|
2017-04-25 02:14:23 +02:00
|
|
|
class Frontend(hartid: Int)(implicit p: Parameters) extends LazyModule {
|
2016-12-13 02:38:55 +01:00
|
|
|
lazy val module = new FrontendModule(this)
|
2017-04-25 02:14:23 +02:00
|
|
|
val icache = LazyModule(new ICache(latency = 2, hartid))
|
2017-04-27 23:02:05 +02:00
|
|
|
val masterNode = TLOutputNode()
|
|
|
|
val slaveNode = TLInputNode()
|
2016-12-13 02:38:55 +01:00
|
|
|
|
2017-04-27 23:02:05 +02:00
|
|
|
icache.slaveNode.map { _ := slaveNode }
|
|
|
|
masterNode := icache.masterNode
|
2016-12-13 02:38:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class FrontendBundle(outer: Frontend) extends CoreBundle()(outer.p) {
|
|
|
|
val cpu = new FrontendIO().flip
|
|
|
|
val ptw = new TLBPTWIO()
|
2017-04-27 23:02:05 +02:00
|
|
|
val tl_out = outer.masterNode.bundleOut
|
|
|
|
val tl_in = outer.slaveNode.bundleIn
|
2016-12-13 02:38:55 +01:00
|
|
|
val resetVector = UInt(INPUT, vaddrBitsExtended)
|
2017-04-27 05:11:43 +02:00
|
|
|
val hartid = UInt(INPUT, hartIdLen)
|
2016-12-13 02:38:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
|
|
|
|
with HasCoreParameters
|
2017-02-09 22:59:09 +01:00
|
|
|
with HasL1ICacheParameters {
|
2016-12-13 02:38:55 +01:00
|
|
|
val io = new FrontendBundle(outer)
|
2017-04-27 23:02:05 +02:00
|
|
|
implicit val edge = outer.masterNode.edgesOut.head
|
2016-12-13 02:38:55 +01:00
|
|
|
val icache = outer.icache.module
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-03-15 23:18:56 +01:00
|
|
|
val tlb = Module(new TLB(log2Ceil(coreInstBytes*fetchWidth), nTLBEntries))
|
2017-04-22 03:01:09 +02:00
|
|
|
val fq = withReset(reset || io.cpu.req.valid) { Module(new ShiftQueue(new FrontendResp, 3, flow = true)) }
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-04-20 01:51:39 +02:00
|
|
|
val s0_valid = io.cpu.req.valid || fq.io.enq.ready
|
2017-04-25 02:14:23 +02:00
|
|
|
val s1_pc = Reg(UInt(width=vaddrBitsExtended))
|
2016-07-09 10:08:52 +02:00
|
|
|
val s1_speculative = Reg(Bool())
|
2015-10-06 06:48:05 +02:00
|
|
|
val s2_valid = Reg(init=Bool(true))
|
Allow reset vector to be set dynamically
A chip's power-up sequence, or awake-from-sleep sequence, may wish to
set the reset PC based upon dynamic properties, e.g., the settings of
external pins. Support this by passing the reset vector to the Coreplex.
ExampleTop simply hard-wires the reset vector, as was the case before.
Additionally, allow MTVEC to *not* be reset. In most cases, including
riscv-tests, pk, and bbl, overriding MTVEC is one of the first things
that the boot sequence does. So the reset value is superfluous.
2016-09-20 01:45:57 +02:00
|
|
|
val s2_pc = Reg(init=io.resetVector)
|
2015-10-06 06:48:05 +02:00
|
|
|
val s2_btb_resp_valid = Reg(init=Bool(false))
|
2016-04-02 00:14:45 +02:00
|
|
|
val s2_btb_resp_bits = Reg(new BTBResp)
|
2017-03-27 03:18:35 +02:00
|
|
|
val s2_maybe_pf = Reg(init=Bool(false))
|
|
|
|
val s2_maybe_ae = Reg(init=Bool(false))
|
2017-03-16 02:00:32 +01:00
|
|
|
val s2_tlb_miss = Reg(Bool())
|
2017-03-27 03:18:35 +02:00
|
|
|
val s2_pf = s2_maybe_pf && !s2_tlb_miss
|
|
|
|
val s2_ae = s2_maybe_ae && !s2_tlb_miss
|
|
|
|
val s2_xcpt = s2_pf || s2_ae
|
2016-07-09 10:08:52 +02:00
|
|
|
val s2_speculative = Reg(init=Bool(false))
|
2016-07-30 01:36:07 +02:00
|
|
|
val s2_cacheable = Reg(init=Bool(false))
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-04-23 06:35:19 +02:00
|
|
|
val fetchBytes = coreInstBytes * fetchWidth
|
|
|
|
val s1_base_pc = ~(~s1_pc | (fetchBytes - 1))
|
|
|
|
val ntpc = s1_base_pc + fetchBytes.U
|
2016-04-02 00:14:45 +02:00
|
|
|
val predicted_npc = Wire(init = ntpc)
|
2016-07-30 01:36:07 +02:00
|
|
|
val predicted_taken = Wire(init = Bool(false))
|
2017-04-20 01:51:39 +02:00
|
|
|
|
|
|
|
val s2_replay = Wire(Bool())
|
2017-04-25 04:12:37 +02:00
|
|
|
s2_replay := (s2_valid && !fq.io.enq.fire()) || RegNext(s2_replay && !s0_valid)
|
2017-04-20 01:51:39 +02:00
|
|
|
val npc = Mux(s2_replay, s2_pc, predicted_npc)
|
|
|
|
|
2017-04-25 02:14:23 +02:00
|
|
|
s1_pc := io.cpu.npc
|
2017-04-20 01:51:39 +02:00
|
|
|
// 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(io.cpu.req.valid, io.cpu.req.bits.speculative, Mux(s2_replay, s2_speculative, s0_speculative))
|
|
|
|
|
|
|
|
s2_valid := false
|
|
|
|
when (!s2_replay && !io.cpu.req.valid) {
|
|
|
|
s2_valid := true
|
|
|
|
s2_pc := s1_pc
|
|
|
|
s2_speculative := s1_speculative
|
|
|
|
s2_cacheable := tlb.io.resp.cacheable
|
|
|
|
s2_maybe_pf := tlb.io.resp.pf.inst
|
|
|
|
s2_maybe_ae := tlb.io.resp.ae.inst
|
|
|
|
s2_tlb_miss := tlb.io.resp.miss
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
|
|
|
|
2017-02-09 22:59:09 +01:00
|
|
|
if (usingBTB) {
|
2016-04-02 00:14:45 +02:00
|
|
|
val btb = Module(new BTB)
|
|
|
|
btb.io.req.valid := false
|
2017-04-25 02:14:23 +02:00
|
|
|
btb.io.req.bits.addr := s1_pc
|
2016-04-02 00:14:45 +02:00
|
|
|
btb.io.btb_update := io.cpu.btb_update
|
|
|
|
btb.io.bht_update := io.cpu.bht_update
|
|
|
|
btb.io.ras_update := io.cpu.ras_update
|
2017-04-20 01:51:39 +02:00
|
|
|
when (!s2_replay) {
|
2016-04-02 00:14:45 +02:00
|
|
|
btb.io.req.valid := true
|
|
|
|
s2_btb_resp_valid := btb.io.resp.valid
|
|
|
|
s2_btb_resp_bits := btb.io.resp.bits
|
|
|
|
}
|
2016-07-30 01:36:07 +02:00
|
|
|
when (btb.io.resp.valid && btb.io.resp.bits.taken) {
|
2016-04-02 00:14:45 +02:00
|
|
|
predicted_npc := btb.io.resp.bits.target.sextTo(vaddrBitsExtended)
|
2016-07-30 01:36:07 +02:00
|
|
|
predicted_taken := Bool(true)
|
2016-04-02 00:14:45 +02:00
|
|
|
}
|
2017-04-23 06:35:19 +02:00
|
|
|
|
|
|
|
// push RAS speculatively
|
|
|
|
btb.io.ras_update.valid := btb.io.req.valid && btb.io.resp.valid && btb.io.resp.bits.cfiType.isOneOf(CFIType.call, CFIType.ret)
|
|
|
|
val returnAddrLSBs = btb.io.resp.bits.bridx +& 1
|
|
|
|
btb.io.ras_update.bits.returnAddr :=
|
|
|
|
Mux(returnAddrLSBs(log2Ceil(fetchWidth)), ntpc, s1_base_pc | ((returnAddrLSBs << log2Ceil(coreInstBytes)) & (fetchBytes - 1)))
|
|
|
|
btb.io.ras_update.bits.cfiType := btb.io.resp.bits.cfiType
|
|
|
|
btb.io.ras_update.bits.prediction.valid := true
|
2016-04-02 00:14:45 +02:00
|
|
|
}
|
2015-10-06 06:48:05 +02:00
|
|
|
|
|
|
|
io.ptw <> tlb.io.ptw
|
2017-04-20 01:51:39 +02:00
|
|
|
tlb.io.req.valid := !s2_replay
|
2017-03-13 04:42:51 +01:00
|
|
|
tlb.io.req.bits.vaddr := s1_pc
|
2015-10-06 06:48:05 +02:00
|
|
|
tlb.io.req.bits.passthrough := Bool(false)
|
|
|
|
tlb.io.req.bits.instruction := Bool(true)
|
|
|
|
tlb.io.req.bits.store := Bool(false)
|
2017-03-14 21:54:49 +01:00
|
|
|
tlb.io.req.bits.sfence := io.cpu.sfence
|
2017-03-15 23:18:56 +01:00
|
|
|
tlb.io.req.bits.size := log2Ceil(coreInstBytes*fetchWidth)
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-04-25 02:14:23 +02:00
|
|
|
icache.io.hartid := io.hartid
|
2017-04-20 01:51:39 +02:00
|
|
|
icache.io.req.valid := s0_valid
|
2016-05-24 02:51:08 +02:00
|
|
|
icache.io.req.bits.addr := io.cpu.npc
|
2016-04-23 00:20:17 +02:00
|
|
|
icache.io.invalidate := io.cpu.flush_icache
|
2017-03-13 04:42:51 +01:00
|
|
|
icache.io.s1_paddr := tlb.io.resp.paddr
|
2017-04-25 02:14:23 +02:00
|
|
|
icache.io.s2_vaddr := s2_pc
|
2017-04-25 04:12:37 +02:00
|
|
|
icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || s2_replay
|
|
|
|
icache.io.s2_kill := s2_speculative && !s2_cacheable || s2_xcpt
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-04-25 04:12:37 +02:00
|
|
|
fq.io.enq.valid := s2_valid && (icache.io.resp.valid || icache.io.s2_kill)
|
2017-04-20 01:51:39 +02:00
|
|
|
fq.io.enq.bits.pc := s2_pc
|
2017-04-25 02:14:23 +02:00
|
|
|
io.cpu.npc := ~(~Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc) | (coreInstBytes-1)) // discard LSB(s)
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2017-04-20 01:51:39 +02:00
|
|
|
fq.io.enq.bits.data := icache.io.resp.bits
|
|
|
|
fq.io.enq.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes))
|
|
|
|
fq.io.enq.bits.pf := s2_pf
|
|
|
|
fq.io.enq.bits.ae := s2_ae
|
2017-04-25 04:12:37 +02:00
|
|
|
fq.io.enq.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt
|
2017-04-20 01:51:39 +02:00
|
|
|
fq.io.enq.bits.btb.valid := s2_btb_resp_valid
|
|
|
|
fq.io.enq.bits.btb.bits := s2_btb_resp_bits
|
|
|
|
|
|
|
|
io.cpu.resp <> fq.io.deq
|
2017-03-09 09:28:19 +01:00
|
|
|
|
|
|
|
// performance events
|
2017-04-25 02:14:23 +02:00
|
|
|
io.cpu.acquire := edge.done(icache.io.tl_out(0).a)
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
2017-01-17 03:24:08 +01:00
|
|
|
|
|
|
|
/** Mix-ins for constructing tiles that have an ICache-based pipeline frontend */
|
2017-02-09 22:59:09 +01:00
|
|
|
trait HasICacheFrontend extends CanHavePTW with HasTileLinkMasterPort {
|
2017-01-17 03:24:08 +01:00
|
|
|
val module: HasICacheFrontendModule
|
2017-04-25 02:14:23 +02:00
|
|
|
val frontend = LazyModule(new Frontend(hartid: Int))
|
|
|
|
val hartid: Int
|
2017-04-27 23:02:05 +02:00
|
|
|
masterNode := frontend.masterNode
|
2017-01-17 03:24:08 +01:00
|
|
|
nPTWPorts += 1
|
|
|
|
}
|
|
|
|
|
2017-02-09 22:59:09 +01:00
|
|
|
trait HasICacheFrontendBundle extends HasTileLinkMasterPortBundle {
|
2017-01-17 03:24:08 +01:00
|
|
|
val outer: HasICacheFrontend
|
|
|
|
}
|
|
|
|
|
2017-02-09 22:59:09 +01:00
|
|
|
trait HasICacheFrontendModule extends CanHavePTWModule with HasTileLinkMasterPortModule {
|
2017-01-17 03:24:08 +01:00
|
|
|
val outer: HasICacheFrontend
|
|
|
|
ptwPorts += outer.frontend.module.io.ptw
|
|
|
|
}
|