From 1e3339e97c4fdb92b39941dd3297962233e28a9b Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 25 Aug 2016 23:07:34 -0700 Subject: [PATCH] Update breakpoints to match @timsifive's debug spec --- src/main/scala/rocket/breakpoint.scala | 81 +++++++++--------- src/main/scala/rocket/csr.scala | 104 +++++++++++++---------- src/main/scala/rocket/instructions.scala | 16 ++-- src/main/scala/rocket/rocket.scala | 6 +- 4 files changed, 113 insertions(+), 94 deletions(-) diff --git a/src/main/scala/rocket/breakpoint.scala b/src/main/scala/rocket/breakpoint.scala index ee484c28..ed0d267f 100644 --- a/src/main/scala/rocket/breakpoint.scala +++ b/src/main/scala/rocket/breakpoint.scala @@ -4,79 +4,80 @@ package rocket import Chisel._ import Util._ +import uncore.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 ttype = UInt(width = 4) + val dmode = Bool() + val maskmax = UInt(width = 6) + val reserved = UInt(width = xLen-24) + val action = Bool() + val chain = Bool() + val zero = UInt(width = 2) + val tmatch = UInt(width = 2) val m = Bool() val h = Bool() val s = Bool() val u = Bool() - val r = Bool() - val w = Bool() val x = Bool() + val w = Bool() + val r = Bool() - def tdrType = 1 - def bpaMaskMax = 4 - def enabled(mstatus: MStatus) = Cat(m, h, s, u)(mstatus.prv) + def tType = 2 + def maskMax = 4 + def enabled(mstatus: MStatus) = !mstatus.debug && 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 mask(dummy: Int = 0) = + (0 until control.maskMax-1).scanLeft(control.tmatch(0))((m, i) => m && address(i)).asUInt def pow2AddressMatch(x: UInt) = (~x | mask()) === (~address | mask()) + + def rangeAddressMatch(x: UInt) = + (x >= address) ^ control.tmatch(0) + + def addressMatch(x: UInt) = + Mux(control.tmatch(1), rangeAddressMatch(x), pow2AddressMatch(x)) } -class BreakpointUnit(implicit p: Parameters) extends CoreModule()(p) { +class BreakpointUnit(n: Int)(implicit p: Parameters) extends CoreModule()(p) { val io = new Bundle { val status = new MStatus().asInput - val bp = Vec(p(NBreakpoints), new BP).asInput + val bp = Vec(n, 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) + val debug_if = Bool(OUTPUT) + val debug_ld = Bool(OUTPUT) + val debug_st = Bool(OUTPUT) } io.xcpt_if := false io.xcpt_ld := false io.xcpt_st := false + io.debug_if := false + io.debug_ld := false + io.debug_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 } - } - } + io.bp.foldLeft((Bool(true), Bool(true), Bool(true))) { case ((ri, wi, xi), bp) => + val en = bp.control.enabled(io.status) + val r = en && ri && bp.control.r && bp.addressMatch(io.ea) + val w = en && wi && bp.control.w && bp.addressMatch(io.ea) + val x = en && xi && bp.control.x && bp.addressMatch(io.pc) + val end = !bp.control.chain - 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 } - } + when (end && r) { io.xcpt_ld := !bp.control.action; io.debug_ld := bp.control.action } + when (end && w) { io.xcpt_st := !bp.control.action; io.debug_st := bp.control.action } + when (end && x) { io.xcpt_if := !bp.control.action; io.debug_if := bp.control.action } + + (end || r, end || w, end || x) } } diff --git a/src/main/scala/rocket/csr.scala b/src/main/scala/rocket/csr.scala index f51a121e..9ace9d0b 100644 --- a/src/main/scala/rocket/csr.scala +++ b/src/main/scala/rocket/csr.scala @@ -41,7 +41,7 @@ class DCSR extends Bundle { val xdebugver = UInt(width = 2) val ndreset = Bool() val fullreset = Bool() - val hwbpcount = UInt(width = 12) + val zero3 = UInt(width = 12) val ebreakm = Bool() val ebreakh = Bool() val ebreaks = Bool() @@ -101,6 +101,11 @@ object CSR val R = UInt(5,SZ) val ADDRSZ = 12 + val debugIntCause = new MIP().getWidth + val debugTriggerCause = { + require(debugIntCause >= Causes.all.max) + debugIntCause + } } class CSRFileIO(implicit p: Parameters) extends CoreBundle { @@ -133,7 +138,7 @@ class CSRFileIO(implicit p: Parameters) extends CoreBundle { val rocc = new RoCCInterface().flip val interrupt = Bool(OUTPUT) val interrupt_cause = UInt(OUTPUT, xLen) - val bp = Vec(p(NBreakpoints), new BP).asOutput + val bp = Vec(nBreakpoints, new BP).asOutput } class CSRFile(implicit p: Parameters) extends CoreModule()(p) @@ -155,12 +160,12 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) val (supported_interrupts, delegable_interrupts) = { val sup = Wire(init=new MIP().fromBits(0)) - sup.ssip := Bool(p(UseVM)) + sup.ssip := Bool(usingVM) sup.msip := true - sup.stip := Bool(p(UseVM)) + sup.stip := Bool(usingVM) sup.mtip := true sup.meip := true - sup.seip := Bool(p(UseVM)) + sup.seip := Bool(usingVM) sup.rocc := usingRoCC val del = Wire(init=sup) @@ -189,8 +194,8 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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_tselect = Reg(UInt(width = log2Up(nBreakpoints))) + val reg_bp = Reg(Vec(1 << log2Up(nBreakpoints), new BP)) val reg_mie = Reg(init=UInt(0, xLen)) val reg_mideleg = Reg(init=UInt(0, xLen)) @@ -228,13 +233,12 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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) + io.bp := reg_bp take 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 + io.interrupt_cause := interruptMSB + CSR.debugIntCause } val system_insn = io.rw.cmd === CSR.I @@ -251,9 +255,9 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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.tselect -> reg_tselect, + CSRs.tdata1 -> reg_bp(reg_tselect).control.asUInt, + CSRs.tdata2 -> reg_bp(reg_tselect).address.sextTo(xLen), CSRs.mimpid -> UInt(0), CSRs.marchid -> UInt(0), CSRs.mvendorid -> UInt(0), @@ -276,11 +280,14 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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 - } + val debug_csrs = collection.mutable.LinkedHashMap[Int,Bits]( + CSRs.dcsr -> reg_dcsr.asUInt, + CSRs.dpc -> reg_dpc.asUInt, + CSRs.dscratch -> reg_dscratch.asUInt + ) + + if (usingDebug) + read_mapping ++= debug_csrs if (usingFPU) { read_mapping += CSRs.fflags -> reg_fflags @@ -337,14 +344,17 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) } 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 csr_addr_priv = io.rw.addr(9,8) + + val debug_csr_mask = 0x090 // only debug CSRs have address bits 7 and 4 set + require((read_mapping -- debug_csrs.keys).keys.forall(x => (x & debug_csr_mask) != debug_csr_mask)) + require(debug_csrs.keys.forall(x => (x & debug_csr_mask) == debug_csr_mask)) + val csr_debug = Bool(usingDebug) && (io.rw.addr & debug_csr_mask) === debug_csr_mask + val priv_sufficient = reg_debug || (!csr_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 @@ -374,13 +384,14 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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 causeIsDebugInt = cause(xLen-1) && cause_lsbs === CSR.debugIntCause + val causeIsDebugTrigger = !cause(xLen-1) && cause_lsbs === CSR.debugTriggerCause + val causeIsDebugBreak = !cause(xLen-1) && insn_break && Cat(reg_dcsr.ebreakm, reg_dcsr.ebreakh, reg_dcsr.ebreaks, reg_dcsr.ebreaku)(reg_mstatus.prv) + val trapToDebug = Bool(usingDebug) && (reg_singleStepped || causeIsDebugInt || causeIsDebugTrigger || causeIsDebugBreak || reg_debug) + val delegate = Bool(usingVM) && 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)) + val epc = Mux(csr_debug, reg_dpc, Mux(Bool(usingVM) && !csr_addr_priv(1), reg_sepc, reg_mepc)) io.fatc := insn_sfence_vm io.evec := Mux(exception, tvec, epc) io.ptbr := reg_sptbr @@ -403,7 +414,7 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) when (trapToDebug) { reg_debug := true reg_dpc := epc - reg_dcsr.cause := Mux(reg_singleStepped, UInt(4), Mux(causeIsDebugInt, UInt(3), UInt(1))) + reg_dcsr.cause := Mux(reg_singleStepped, 4, Mux(causeIsDebugInt, 3, Mux[UInt](causeIsDebugTrigger, 2, 1))) reg_dcsr.prv := trimPrivilege(reg_mstatus.prv) }.elsewhen (delegate) { reg_sepc := epc @@ -425,7 +436,7 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) } when (insn_ret) { - when (Bool(p(UseVM)) && !csr_addr_priv(1)) { + when (Bool(usingVM) && !csr_addr_priv(1)) { when (reg_mstatus.spp.toBool) { reg_mstatus.sie := reg_mstatus.spie } reg_mstatus.spie := false reg_mstatus.spp := PRV.U @@ -537,45 +548,48 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p) 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 } + if (nBreakpoints > 0) { + when (decoded_addr(CSRs.tselect)) { reg_tselect := wdata } - when (reg_tdrselect.tdrmode || reg_debug) { - when (decoded_addr(CSRs.tdrdata1)) { + val bp = reg_bp(reg_tselect) + when (!bp.control.dmode || reg_debug) { + when (decoded_addr(CSRs.tdata1)) { 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 */ + val dMode = newBPC.dmode && reg_debug + bp.control := newBPC + bp.control.dmode := dMode + bp.control.action := dMode && newBPC.action } - when (decoded_addr(CSRs.tdrdata2)) { reg_bp(reg_tdrselect.tdrindex).address := wdata } + when (decoded_addr(CSRs.tdata2)) { bp.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 + if (nBreakpoints <= 1) reg_tselect := 0 + if (nBreakpoints >= 1) + reg_bp(nBreakpoints-1).control.chain := false for (bpc <- reg_bp map {_.control}) { - bpc.tdrtype := bpc.tdrType - bpc.bpamaskmax := bpc.bpaMaskMax + bpc.ttype := bpc.tType + bpc.maskmax := bpc.maskMax bpc.reserved := 0 - bpc.bpaction := 0 + bpc.zero := 0 bpc.h := false if (!usingVM) bpc.s := false if (!usingUser) bpc.u := false if (!usingVM && !usingUser) bpc.m := true when (reset) { + bpc.action := false + bpc.dmode := false bpc.r := false bpc.w := false bpc.x := false } } - for (bp <- reg_bp drop p(NBreakpoints)) + for (bp <- reg_bp drop nBreakpoints) bp := new BP().fromBits(0) def legalizePrivilege(priv: UInt): UInt = diff --git a/src/main/scala/rocket/instructions.scala b/src/main/scala/rocket/instructions.scala index 339ac42f..677a6831 100644 --- a/src/main/scala/rocket/instructions.scala +++ b/src/main/scala/rocket/instructions.scala @@ -280,10 +280,10 @@ object CSRs { 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 tselect = 0x7a0 + val tdata1 = 0x7a1 + val tdata2 = 0x7a2 + val tdata3 = 0x7a3 val dcsr = 0x7b0 val dpc = 0x7b1 val dscratch = 0x7b2 @@ -346,10 +346,10 @@ object CSRs { res += mscycle_delta res += mstime_delta res += msinstret_delta - res += tdrselect - res += tdrdata1 - res += tdrdata2 - res += tdrdata3 + res += tselect + res += tdata1 + res += tdata2 + res += tdata3 res += dcsr res += dpc res += dscratch diff --git a/src/main/scala/rocket/rocket.scala b/src/main/scala/rocket/rocket.scala index bf59ad14..bb2237eb 100644 --- a/src/main/scala/rocket/rocket.scala +++ b/src/main/scala/rocket/rocket.scala @@ -43,6 +43,7 @@ trait HasCoreParameters extends HasAddrMapParameters { val usingRoCC = !p(BuildRoCC).isEmpty val fastLoadWord = p(FastLoadWord) val fastLoadByte = p(FastLoadByte) + val nBreakpoints = p(NBreakpoints) val retireWidth = p(RetireWidth) val fetchWidth = p(FetchWidth) @@ -245,7 +246,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) { 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) + val bpu = Module(new BreakpointUnit(nBreakpoints)) bpu.io.status := csr.io.status bpu.io.bp := csr.io.bp bpu.io.pc := ibuf.io.pc @@ -254,6 +255,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) { 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.debug_if, UInt(CSR.debugTriggerCause)), (bpu.io.xcpt_if, UInt(Causes.breakpoint)), (id_xcpt_if, UInt(Causes.fault_fetch)), (id_illegal_insn, UInt(Causes.illegal_instruction)))) @@ -408,7 +410,9 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) { } val mem_breakpoint = (mem_reg_load && bpu.io.xcpt_ld) || (mem_reg_store && bpu.io.xcpt_st) + val mem_debug_breakpoint = (mem_reg_load && bpu.io.debug_ld) || (mem_reg_store && bpu.io.debug_st) val (mem_new_xcpt, mem_new_cause) = checkExceptions(List( + (mem_debug_breakpoint, UInt(CSR.debugTriggerCause)), (mem_breakpoint, UInt(Causes.breakpoint)), (mem_npc_misaligned, UInt(Causes.misaligned_fetch)), (mem_ctrl.mem && io.dmem.xcpt.ma.st, UInt(Causes.misaligned_store)),