2015-10-06 06:48:05 +02:00
|
|
|
package rocket
|
|
|
|
|
|
|
|
import Chisel._
|
2016-06-28 22:15:39 +02:00
|
|
|
import uncore.tilelink._
|
2016-09-28 06:27:07 +02:00
|
|
|
import util._
|
2015-10-22 03:18:32 +02:00
|
|
|
import cde.{Parameters, Field}
|
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)
|
|
|
|
val xcpt_if = 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)
|
|
|
|
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)
|
|
|
|
val flush_tlb = Bool(OUTPUT)
|
2015-10-06 06:48:05 +02:00
|
|
|
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
|
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 resetVector = UInt(INPUT, vaddrBitsExtended)
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|
|
|
|
|
2016-07-14 21:38:54 +02:00
|
|
|
val icache = Module(new ICache(latency = 2))
|
2015-10-06 06:48:05 +02:00
|
|
|
val tlb = Module(new TLB)
|
|
|
|
|
2016-04-02 02:28:42 +02:00
|
|
|
val s1_pc_ = Reg(UInt(width=vaddrBitsExtended))
|
2015-10-06 06:48:05 +02:00
|
|
|
val s1_pc = ~(~s1_pc_ | (coreInstBytes-1)) // discard PC LSBS (this propagates down the pipeline)
|
2016-07-09 10:08:52 +02:00
|
|
|
val s1_speculative = Reg(Bool())
|
2015-10-06 06:48:05 +02:00
|
|
|
val s1_same_block = Reg(Bool())
|
|
|
|
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)
|
2015-10-06 06:48:05 +02:00
|
|
|
val s2_xcpt_if = Reg(init=Bool(false))
|
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
|
|
|
|
2016-07-14 21:05:09 +02:00
|
|
|
val ntpc = ~(~s1_pc | (coreInstBytes*fetchWidth-1)) + UInt(coreInstBytes*fetchWidth)
|
2016-07-30 01:36:07 +02:00
|
|
|
val ntpc_same_block = (ntpc & rowBytes) === (s1_pc & rowBytes)
|
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))
|
2016-07-14 21:38:54 +02:00
|
|
|
val icmiss = s2_valid && !icache.io.resp.valid
|
2016-08-01 02:13:52 +02:00
|
|
|
val npc = Mux(icmiss, s2_pc, predicted_npc)
|
2016-07-30 01:36:07 +02:00
|
|
|
val s0_same_block = !predicted_taken && !icmiss && !io.cpu.req.valid && ntpc_same_block
|
2015-10-06 06:48:05 +02:00
|
|
|
|
|
|
|
val stall = io.cpu.resp.valid && !io.cpu.resp.ready
|
|
|
|
when (!stall) {
|
|
|
|
s1_same_block := s0_same_block && !tlb.io.resp.miss
|
2016-07-30 01:36:07 +02:00
|
|
|
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)
|
2015-10-06 06:48:05 +02:00
|
|
|
s2_valid := !icmiss
|
|
|
|
when (!icmiss) {
|
|
|
|
s2_pc := s1_pc
|
2016-07-30 01:36:07 +02:00
|
|
|
s2_speculative := s1_speculative
|
|
|
|
s2_cacheable := tlb.io.resp.cacheable
|
2015-10-06 06:48:05 +02:00
|
|
|
s2_xcpt_if := tlb.io.resp.xcpt_if
|
|
|
|
}
|
|
|
|
}
|
|
|
|
when (io.cpu.req.valid) {
|
|
|
|
s1_same_block := Bool(false)
|
2016-07-30 01:36:07 +02:00
|
|
|
s1_pc_ := io.cpu.npc
|
2016-07-09 10:08:52 +02:00
|
|
|
s1_speculative := io.cpu.req.bits.speculative
|
2015-10-06 06:48:05 +02:00
|
|
|
s2_valid := Bool(false)
|
|
|
|
}
|
|
|
|
|
2016-04-02 00:14:45 +02:00
|
|
|
if (p(BtbKey).nEntries > 0) {
|
|
|
|
val btb = Module(new BTB)
|
|
|
|
btb.io.req.valid := false
|
2016-07-30 01:36:07 +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
|
|
|
|
when (!stall && !icmiss) {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2015-10-06 06:48:05 +02:00
|
|
|
|
|
|
|
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
|
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
|
2016-04-02 04:30:39 +02:00
|
|
|
icache.io.s1_ppn := tlb.io.resp.ppn
|
2016-04-23 00:41:31 +02:00
|
|
|
icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || tlb.io.resp.xcpt_if || icmiss || io.cpu.flush_tlb
|
2016-07-30 01:36:07 +02:00
|
|
|
icache.io.s2_kill := s2_speculative && !s2_cacheable
|
2016-07-14 21:38:54 +02:00
|
|
|
icache.io.resp.ready := !stall && !s1_same_block
|
2015-10-06 06:48:05 +02:00
|
|
|
|
2016-07-30 01:36:07 +02:00
|
|
|
io.cpu.resp.valid := s2_valid && (icache.io.resp.valid || icache.io.s2_kill || s2_xcpt_if)
|
2015-10-06 06:48:05 +02:00
|
|
|
io.cpu.resp.bits.pc := s2_pc
|
|
|
|
io.cpu.npc := Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc)
|
|
|
|
|
2016-07-30 01:36:07 +02:00
|
|
|
require(fetchWidth * coreInstBytes <= rowBytes && isPow2(fetchWidth))
|
2016-08-01 00:21:17 +02:00
|
|
|
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))
|
2015-10-06 06:48:05 +02:00
|
|
|
io.cpu.resp.bits.xcpt_if := s2_xcpt_if
|
2016-07-30 01:36:07 +02:00
|
|
|
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
|
2015-10-06 06:48:05 +02:00
|
|
|
}
|