Skip to content

Commit

Permalink
Merge pull request #354 from riscv-boom/breakpoints
Browse files Browse the repository at this point in the history
[core] Support breakpoints
  • Loading branch information
jerryz123 committed Aug 5, 2019
2 parents 9661641 + a84a35d commit 4e9d496
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 181 deletions.
4 changes: 3 additions & 1 deletion src/main/scala/common/micro-op.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,13 @@ class MicroOp(implicit p: Parameters) extends BoomBundle
// If it's non-ld/st it will write back exception bits to the fcsr.
val fp_single = Bool() // single-precision floating point instruction (F-extension)

// exception information
// frontend exception information
val xcpt_pf_if = Bool() // I-TLB page fault.
val xcpt_ae_if = Bool() // I$ access exception.
val replay_if = Bool() // I$ wants us to replay our ifetch request
val xcpt_ma_if = Bool() // Misaligned fetch (jal/brjumping to misaligned addr).
val bp_debug_if = Bool() // Breakpoint
val bp_xcpt_if = Bool() // Breakpoint

// purely debug information
val debug_wdata = UInt(xLen.W)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/common/parameters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ case class BoomCoreParams(
mtvecWritable: Boolean = true,
haveCFlush: Boolean = false,
mulDiv: Option[freechips.rocketchip.rocket.MulDivParams] = Some(MulDivParams(divEarlyOut=true)),
nBreakpoints: Int = 1,
nBreakpoints: Int = 0, // TODO Fix with better frontend breakpoint unit
nL2TLBEntries: Int = 512,
nLocalInterrupts: Int = 0,
useAtomics: Boolean = true,
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/exu/core.scala
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ class BoomCore(implicit p: Parameters, edge: freechips.rocketchip.tilelink.TLEdg
io.ifu.br_unit := br_unit
io.ifu.tsc_reg := debug_tsc_reg

// Breakpoint info
io.ifu.status := csr.io.status
io.ifu.bp := csr.io.bp

// SFence needs access to the PC to inject an address into the TLB's CAM port. The ROB
// will have to later redirect the PC back to the regularly scheduled program.
io.ifu.sfence_take_pc := lsu.io.exe_resp.bits.sfence.valid
Expand Down Expand Up @@ -1063,6 +1067,10 @@ class BoomCore(implicit p: Parameters, edge: freechips.rocketchip.tilelink.TLEdg

exe_units(brunit_idx).io.status := csr.io.status

// Connect breakpoint info to memaddrcalcunit
exe_units.memory_unit.io.status := csr.io.status
exe_units.memory_unit.io.bp := csr.io.bp

// LSU <> ROB
rob.io.lsu_clr_bsy_valid := lsu.io.clr_bsy_valid
rob.io.lsu_clr_bsy_rob_idx := lsu.io.clr_bsy_rob_idx
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/exu/decode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ class DecodeUnit(implicit p: Parameters) extends BoomModule

val (xcpt_valid, xcpt_cause) = checkExceptions(List(
(io.interrupt, io.interrupt_cause),
(uop.bp_debug_if, (CSR.debugTriggerCause).U),
(uop.bp_xcpt_if, (Causes.breakpoint).U),
(uop.replay_if, MINI_EXCEPTION_REPLAY),
(uop.xcpt_pf_if, (Causes.fetch_page_fault).U),
(uop.xcpt_ae_if, (Causes.fetch_access).U),
Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/exu/execution-units/execution-unit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import chisel3._
import chisel3.util._

import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.rocket.{BP}
import freechips.rocketchip.tile.{XLen, RoCCCoreIO}
import freechips.rocketchip.tile

Expand Down Expand Up @@ -97,14 +98,16 @@ class ExecutionUnitIO(
// only used by the branch unit
val br_unit = if (hasBrUnit) Output(new BranchUnitResp()) else null
val get_ftq_pc = if (hasBrUnit) Flipped(new GetPCFromFtqIO()) else null
val status = if (hasBrUnit || hasRocc) Input(new freechips.rocketchip.rocket.MStatus()) else null
val status = if (hasBrUnit || hasRocc || hasMem) Input(new freechips.rocketchip.rocket.MStatus()) else null

// only used by the fpu unit
val fcsr_rm = if (hasFcsr) Input(Bits(tile.FPConstants.RM_SZ.W)) else null

// only used by the mem unit
val lsu_io = if (hasMem) Flipped(new boom.lsu.LoadStoreUnitIO(coreWidth)) else null
val dmem = if (hasMem) new boom.lsu.DCMemPortIO() else null
val bp = if (hasMem) Input(Vec(nBreakpoints, new BP)) else null

// TODO move this out of ExecutionUnit
val com_exception = if (hasMem || hasRocc) Input(Bool()) else null
}
Expand Down Expand Up @@ -388,6 +391,8 @@ class ALUExeUnit(
maddrcalc.io.req <> io.req
maddrcalc.io.req.valid := io.req.valid && io.req.bits.uop.fu_code_is(FU_MEM)
maddrcalc.io.brinfo <> io.brinfo
maddrcalc.io.status := io.status
maddrcalc.io.bp := io.bp
maddrcalc.io.resp.ready := DontCare
io.bypass <> maddrcalc.io.bypass // TODO this is not where the bypassing should
// occur from, is there any bypassing happening?!
Expand Down
45 changes: 35 additions & 10 deletions src/main/scala/exu/execution-units/functional-unit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import freechips.rocketchip.config.Parameters
import freechips.rocketchip.rocket.ALU._
import freechips.rocketchip.util._
import freechips.rocketchip.tile
import freechips.rocketchip.rocket.PipelinedMultiplier
import freechips.rocketchip.rocket.{PipelinedMultiplier,BP,BreakpointUnit,Causes,CSR}

import boom.bpu.{BpredType, BranchPredInfo, BoomBTBUpdate}
import boom.common._
Expand Down Expand Up @@ -93,6 +93,7 @@ class FunctionalUnitIo(
val numBypassStages: Int,
val dataWidth: Int,
val isBrUnit: Boolean,
val isMemAddrCalcUnit: Boolean,
val needsFcsr: Boolean
)(implicit p: Parameters) extends BoomBundle
{
Expand All @@ -109,7 +110,10 @@ class FunctionalUnitIo(
// only used by branch unit
val br_unit = if (isBrUnit) Output(new BranchUnitResp()) else null
val get_ftq_pc = if (isBrUnit) Flipped(new GetPCFromFtqIO()) else null
val status = if (isBrUnit) Input(new freechips.rocketchip.rocket.MStatus()) else null
val status = if (isBrUnit || isMemAddrCalcUnit) Input(new freechips.rocketchip.rocket.MStatus()) else null

// only used by memaddr calc unit
val bp = if (isMemAddrCalcUnit) Input(Vec(nBreakpoints, new BP)) else null
}

/**
Expand Down Expand Up @@ -228,11 +232,12 @@ abstract class FunctionalUnit(
val numBypassStages: Int,
val dataWidth: Int,
val isBranchUnit: Boolean = false,
val isMemAddrCalcUnit: Boolean = false,
val needsFcsr: Boolean = false)
(implicit p: Parameters) extends BoomModule
{
val io = IO(new FunctionalUnitIo(numStages, numBypassStages, dataWidth,
isBranchUnit, needsFcsr))
isBranchUnit, isMemAddrCalcUnit, needsFcsr))
}

/**
Expand All @@ -253,13 +258,15 @@ abstract class PipelinedFunctionalUnit(
earliestBypassStage: Int,
dataWidth: Int,
isBranchUnit: Boolean = false,
isMemAddrCalcUnit: Boolean = false,
needsFcsr: Boolean = false
)(implicit p: Parameters) extends FunctionalUnit(
isPipelined = true,
numStages = numStages,
numBypassStages = numBypassStages,
dataWidth = dataWidth,
isBranchUnit = isBranchUnit,
isMemAddrCalcUnit = isMemAddrCalcUnit,
needsFcsr = needsFcsr)
{
// Pipelined functional unit is always ready.
Expand Down Expand Up @@ -650,7 +657,8 @@ class MemAddrCalcUnit(implicit p: Parameters)
numBypassStages = 0,
earliestBypassStage = 0,
dataWidth = 65, // TODO enable this only if FP is enabled?
isBranchUnit = false)
isBranchUnit = false,
isMemAddrCalcUnit = true)
with freechips.rocketchip.rocket.constants.MemoryOpConstants
with freechips.rocketchip.rocket.constants.ScalarOpConstants
{
Expand Down Expand Up @@ -684,12 +692,29 @@ class MemAddrCalcUnit(implicit p: Parameters)
(size === 2.U && (effective_address(1,0) =/= 0.U)) ||
(size === 3.U && (effective_address(2,0) =/= 0.U))

val ma_ld = io.req.valid && io.req.bits.uop.uopc === uopLD && misaligned
val ma_st = io.req.valid && (io.req.bits.uop.uopc === uopSTA || io.req.bits.uop.uopc === uopAMO_AG) && misaligned

io.resp.bits.mxcpt.valid := ma_ld || ma_st
io.resp.bits.mxcpt.bits := Mux(ma_ld, freechips.rocketchip.rocket.Causes.misaligned_load.U,
freechips.rocketchip.rocket.Causes.misaligned_store.U)
val bkptu = Module(new BreakpointUnit(nBreakpoints))
bkptu.io.status := io.status
bkptu.io.bp := io.bp
bkptu.io.pc := DontCare
bkptu.io.ea := effective_address

val ma_ld = io.req.valid && io.req.bits.uop.uopc === uopLD && misaligned
val ma_st = io.req.valid && (io.req.bits.uop.uopc === uopSTA || io.req.bits.uop.uopc === uopAMO_AG) && misaligned
val dbg_bp = io.req.valid && ((io.req.bits.uop.uopc === uopLD && bkptu.io.debug_ld) ||
(io.req.bits.uop.uopc === uopSTA && bkptu.io.debug_st))
val bp = io.req.valid && ((io.req.bits.uop.uopc === uopLD && bkptu.io.xcpt_ld) ||
(io.req.bits.uop.uopc === uopSTA && bkptu.io.xcpt_st))

def checkExceptions(x: Seq[(Bool, UInt)]) =
(x.map(_._1).reduce(_||_), PriorityMux(x))
val (xcpt_val, xcpt_cause) = checkExceptions(List(
(ma_ld, (Causes.misaligned_load).U),
(ma_st, (Causes.misaligned_store).U),
(dbg_bp, (CSR.debugTriggerCause).U),
(bp, (Causes.breakpoint).U)))

io.resp.bits.mxcpt.valid := xcpt_val
io.resp.bits.mxcpt.bits := xcpt_cause
assert (!(ma_ld && ma_st), "Mutually-exclusive exceptions are firing.")

io.resp.bits.sfence.valid := io.req.valid && io.req.bits.uop.mem_cmd === M_SFENCE
Expand Down
21 changes: 18 additions & 3 deletions src/main/scala/ifu/fetch-buffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import chisel3.experimental.{dontTouch}
import chisel3.core.{DontCare}

import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.rocket.{MStatus, BP, BreakpointUnit}

import boom.common._
import boom.util.{BoolToChar, MaskUpper}
Expand Down Expand Up @@ -50,6 +51,10 @@ class FetchBuffer(numEntries: Int)(implicit p: Parameters) extends BoomModule

// Was the pipeline redirected? Clear/reset the fetchbuffer.
val clear = Input(Bool())

// Breakpoint info
val status = Input(new MStatus)
val bp = Input(Vec(nBreakpoints, new BP))
})

require (numEntries > fetchWidth)
Expand Down Expand Up @@ -91,12 +96,18 @@ class FetchBuffer(numEntries: Int)(implicit p: Parameters) extends BoomModule

// Step 1: Convert FetchPacket into a vector of MicroOps.
for (i <- 0 until fetchWidth) {
val pc = (alignToFetchBoundary(io.enq.bits.pc) + (i << log2Ceil(coreInstBytes)).U)
val bkptu = Module(new BreakpointUnit(nBreakpoints))
bkptu.io.status := io.status
bkptu.io.bp := io.bp
bkptu.io.pc := pc
bkptu.io.ea := DontCare

in_uops(i) := DontCare
in_mask(i) := io.enq.valid && io.enq.bits.mask(i)
in_uops(i).edge_inst := false.B
in_uops(i).debug_pc := (alignToFetchBoundary(io.enq.bits.pc)
+ (i << log2Ceil(coreInstBytes)).U)
in_uops(i).pc_lob := in_uops(i).debug_pc // LHS width will cut off high-order bits.
in_uops(i).debug_pc := pc
in_uops(i).pc_lob := pc // LHS width will cut off high-order bits.
in_uops(i).cfi_idx := i.U
if (i == 0) {
when (io.enq.bits.edge_inst) {
Expand All @@ -110,10 +121,14 @@ class FetchBuffer(numEntries: Int)(implicit p: Parameters) extends BoomModule
in_uops(i).inst := io.enq.bits.exp_insts(i)
in_uops(i).debug_inst := io.enq.bits.insts(i)
in_uops(i).is_rvc := io.enq.bits.insts(i)(1,0) =/= 3.U && usingCompressed.B

in_uops(i).xcpt_pf_if := io.enq.bits.xcpt_pf_if
in_uops(i).xcpt_ae_if := io.enq.bits.xcpt_ae_if
in_uops(i).replay_if := io.enq.bits.replay_if
in_uops(i).xcpt_ma_if := io.enq.bits.xcpt_ma_if_oh(i)
in_uops(i).bp_debug_if := bkptu.io.debug_if
in_uops(i).bp_xcpt_if := bkptu.io.xcpt_if

in_uops(i).br_prediction := io.enq.bits.bpu_info(i)
in_uops(i).debug_events := io.enq.bits.debug_events(i)
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/scala/ifu/fetch-control-unit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import chisel3.util._
import chisel3.core.{withReset, DontCare}
import chisel3.experimental.{dontTouch}

import freechips.rocketchip.rocket.{MStatus, BP}
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.util._

Expand Down Expand Up @@ -94,6 +95,10 @@ class FetchControlUnit(implicit p: Parameters) extends BoomModule
val br_unit = Input(new BranchUnitResp())
val get_pc = new GetPCFromFtqIO()

// Breakpoint info
val status = Input(new MStatus)
val bp = Input(Vec(nBreakpoints, new BP))

val tsc_reg = Input(UInt(xLen.W))

val clear_fetchbuffer = Input(Bool())
Expand Down Expand Up @@ -520,6 +525,9 @@ class FetchControlUnit(implicit p: Parameters) extends BoomModule
fb.io.enq.bits := r_f4_fetch_bundle
fb.io.clear := io.clear_fetchbuffer

fb.io.status := io.status
fb.io.bp := io.bp

for (i <- 0 until fetchWidth) {
if (i == 0) {
fb.io.enq.bits.debug_events(i).fetch_seq := fseq_reg
Expand Down
7 changes: 7 additions & 0 deletions src/main/scala/ifu/frontend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class BoomFrontendIO(implicit p: Parameters) extends BoomBundle
val status_prv = Output(UInt(freechips.rocketchip.rocket.PRV.SZ.W))
val status_debug = Output(Bool())

// Breakpoint info
val status = Output(new MStatus)
val bp = Output(Vec(nBreakpoints, new BP))

val perf = Input(new FrontendPerfEvents())
val tsc_reg = Output(UInt(xLen.W))
}
Expand Down Expand Up @@ -255,6 +259,9 @@ class BoomFrontendModule(outer: BoomFrontend) extends LazyModuleImp(outer)
fetch_controller.io.br_unit := io.cpu.br_unit
fetch_controller.io.tsc_reg := io.cpu.tsc_reg

fetch_controller.io.status := io.cpu.status
fetch_controller.io.bp := io.cpu.bp

fetch_controller.io.f2_btb_resp := bpdpipeline.io.f2_btb_resp
fetch_controller.io.f3_bpd_resp := bpdpipeline.io.f3_bpd_resp
fetch_controller.io.f2_bpd_resp := DontCare
Expand Down

0 comments on commit 4e9d496

Please sign in to comment.