diff --git a/src/main/scala/vexiiriscv/misc/PrivilegedPlugin.scala b/src/main/scala/vexiiriscv/misc/PrivilegedPlugin.scala index 3d6ed47..ffad8c3 100644 --- a/src/main/scala/vexiiriscv/misc/PrivilegedPlugin.scala +++ b/src/main/scala/vexiiriscv/misc/PrivilegedPlugin.scala @@ -173,19 +173,20 @@ class PrivilegedPlugin(val p : PrivilegedParam, val hartIds : Seq[Int]) extends val withMachinePrivilege = privilege >= U"11" val withSupervisorPrivilege = privilege >= U"01" + val hartRunning = RegInit(True).allowUnsetRegToAvoidLatch() + val debugMode = !hartRunning val debug = p.withDebug generate new Area{ val injector = p.withDebug generate injs.injectPort() val bus = slave(DebugHartBus()) - val running = RegInit(True) - val debugMode = !running + val fetchHold = pcs.newHoldPort(hartId) - fetchHold := !running + fetchHold := !hartRunning bus.resume.rsp.valid := False - bus.running := running - bus.halted := !running + bus.running := hartRunning + bus.halted := !hartRunning bus.unavailable := BufferCC(ClockDomain.current.isResetActive) when(debugMode) { @@ -195,7 +196,7 @@ class PrivilegedPlugin(val p : PrivilegedParam, val hartIds : Seq[Int]) extends val reseting = RegNext(False) init (True) bus.haveReset := RegInit(False) setWhen (reseting) clearWhen (bus.ackReset) - val enterHalt = running.getAheadValue().fall(False) + val enterHalt = hartRunning.getAheadValue().fall(False) val doHalt = RegInit(False) setWhen (bus.haltReq && bus.running && !debugMode) clearWhen (enterHalt) val forceResume = False val doResume = forceResume || bus.resume.isPending(1) @@ -319,178 +320,180 @@ class PrivilegedPlugin(val p : PrivilegedParam, val hartIds : Seq[Int]) extends } } val stoptime = out(RegNext(debugMode && dcsr.stoptime) init(False)) + } - val noTrigger = (p.debugTriggers == 0) generate new Area { - cap.allowCsr(CSR.TSELECT) - } - val trigger = (p.debugTriggers > 0) generate new Area { - val tselect = new Area { - val index = Reg(UInt(log2Up(p.debugTriggers) bits)) init(0) - api.readWrite(index, CSR.TSELECT) + val noTrigger = (p.debugTriggers == 0) generate new Area { + cap.allowCsr(CSR.TSELECT) + } + val trigger = (p.debugTriggers > 0) generate new Area { + val tselect = new Area { + val index = Reg(UInt(log2Up(p.debugTriggers) bits)) init(0) + api.readWrite(index, CSR.TSELECT) - val outOfRange = if (isPow2(p.debugTriggers)) False else index < p.debugTriggers - } + val outOfRange = if (isPow2(p.debugTriggers)) False else index < p.debugTriggers + } - //TODO may remove tinfo, as it is optional - val tinfo = new Area { - api.read(CSR.TINFO, 0 -> tselect.outOfRange, 2 -> !tselect.outOfRange) - } + //TODO may remove tinfo, as it is optional + val tinfo = new Area { + api.read(CSR.TINFO, 0 -> tselect.outOfRange, 2 -> !tselect.outOfRange) + } - val pcBreakMatchAt = 0 - val pcBreakTrapAt = 1 + val pcBreakMatchAt = 0 + val pcBreakTrapAt = 1 - val pcBreaks = for(laneId <- 0 until Decode.LANES) yield new dpp.LaneArea(pcBreakTrapAt, laneId) { - val doIt = isValid && PC_TRIGGER_HITS.orR && !(0 until laneId).map(dpp.ctrl(pcBreakTrapAt).lane).map(lane => lane.isValid && lane.up(TRAP)).orR - when(doIt) { - bypass(Global.TRAP) := True - } - - val trapPort = tp.newTrap(dpp.getAge(pcBreakTrapAt), Decode.LANES, subAge = 1) - trapPort.valid := doIt - trapPort.exception := False - trapPort.tval := B(OHToUInt(PC_TRIGGER_HITS)).resized - trapPort.code := TrapReason.DEBUG_TRIGGER - trapPort.arg := 0 - trapPort.laneAge := laneId - trapPort.hartId := HART_ID - - val flushPort = ss.newFlushPort(dpp.getAge(pcBreakTrapAt), log2Up(Decode.LANES), true) - flushPort.valid := doIt - flushPort.hartId := Global.HART_ID - flushPort.uopId := Decode.UOP_ID - flushPort.laneAge := laneId - flushPort.self := False + val pcBreaks = for(laneId <- 0 until Decode.LANES) yield new dpp.LaneArea(pcBreakTrapAt, laneId) { + val doIt = isValid && PC_TRIGGER_HITS.orR && !(0 until laneId).map(dpp.ctrl(pcBreakTrapAt).lane).map(lane => lane.isValid && lane.up(TRAP)).orR + when(doIt) { + bypass(Global.TRAP) := True } - val slots = for (slotId <- 0 until p.debugTriggers) yield new Area { - val selected = tselect.index === slotId + val trapPort = tp.newTrap(dpp.getAge(pcBreakTrapAt), Decode.LANES, subAge = 1) + trapPort.valid := doIt + trapPort.exception := False + trapPort.tval := B(OHToUInt(PC_TRIGGER_HITS)).resized + trapPort.code := TrapReason.DEBUG_TRIGGER + trapPort.arg := 0 + trapPort.laneAge := laneId + trapPort.hartId := HART_ID + + val flushPort = ss.newFlushPort(dpp.getAge(pcBreakTrapAt), log2Up(Decode.LANES), true) + flushPort.valid := doIt + flushPort.hartId := Global.HART_ID + flushPort.uopId := Decode.UOP_ID + flushPort.laneAge := laneId + flushPort.self := False + } - def csrw(csrId: Int, thats: (Int, Data)*): Unit = { - api.onWrite(csrId, false) { - when(selected) { - for ((offset, data) <- thats) { - data.assignFromBits(cap.bus.write.bits(offset, widthOf(data) bits)) - } - } - } - } + val slots = for (slotId <- 0 until p.debugTriggers) yield new Area { + val selected = tselect.index === slotId - def csrr(csrId: Int, read: Bits, thats: (Int, Data)*): Unit = { + def csrw(csrId: Int, thats: (Int, Data)*): Unit = { + api.onWrite(csrId, false) { when(selected) { for ((offset, data) <- thats) { - read(offset, widthOf(data) bits) := data.asBits + data.assignFromBits(cap.bus.write.bits(offset, widthOf(data) bits)) } } } + } - def csrrw(csrId: Int, read: Bits, thats: (Int, Data)*): Unit = { - csrw(csrId, thats: _*) - csrr(csrId, read, thats: _*) + def csrr(csrId: Int, read: Bits, thats: (Int, Data)*): Unit = { + when(selected) { + for ((offset, data) <- thats) { + read(offset, widthOf(data) bits) := data.asBits + } } + } - val tdata1 = new Area { - val read = B(0, XLEN bits) - val tpe = U(2, 4 bits) - val dmode = Reg(Bool()) init (False) //TODO - - val execute = RegInit(False) - val m, s, u = RegInit(False) - val action = RegInit(U"0000") - val privilegeHit = !debugMode && privilege.mux( - 0 -> u, - 1 -> s, - 3 -> m, - default -> False - ) - val hit = RegInit(False) - val size = Reg(UInt((XLEN.get == 32).mux(2, 4) bits)) init (0) - - csrrw(CSR.TDATA1, read, 2 -> execute, 3 -> u, 4 -> s, 6 -> m, XLEN - 5 -> dmode, 12 -> action, 20 -> hit, 16 -> size(1 downto 0)) - if(size.getWidth > 2) csrrw(CSR.TDATA1, read, 21 -> size(3 downto 2)) - csrr(CSR.TDATA1, read, XLEN - 4 -> tpe) - csrr(CSR.TDATA1, read, 21 -> B(12)) - - val load, store = RegInit(False) - val chain = RegInit(False).allowUnsetRegToAvoidLatch - val select = False - val matcher = Reg(Bits(4 bits)) init (0) - if (p.debugTriggersLsu) { - csrrw(CSR.TDATA1, read, 11 -> chain, 0 -> load, 1 -> store, 7 -> matcher) - csrr(CSR.TDATA1, read, 18 -> (load && select)) - } + def csrrw(csrId: Int, read: Bits, thats: (Int, Data)*): Unit = { + csrw(csrId, thats: _*) + csrr(csrId, read, thats: _*) + } + + val tdata1 = new Area { + val read = B(0, XLEN bits) + val tpe = U(2, 4 bits) + val dmode = Reg(Bool()) init (False) //TODO + + val execute = RegInit(False) + val m, s, u = RegInit(False) + val action = RegInit(U(0, p.withDebug.toInt bits)) + val privilegeHit = !debugMode && privilege.mux( + 0 -> u, + 1 -> s, + 3 -> m, + default -> False + ) + val hit = RegInit(False) + val size = Reg(UInt((XLEN.get == 32).mux(2, 4) bits)) init (0) + val doEbreak = action === 0 + + csrrw(CSR.TDATA1, read, 2 -> execute, 3 -> u, 4 -> s, 6 -> m, XLEN - 5 -> dmode, 12 -> action, 20 -> hit, 16 -> size(1 downto 0)) + if(size.getWidth > 2) csrrw(CSR.TDATA1, read, 21 -> size(3 downto 2)) + csrr(CSR.TDATA1, read, XLEN - 4 -> tpe) + csrr(CSR.TDATA1, read, 21 -> B(12)) + + val load, store = RegInit(False) + val chain = RegInit(False).allowUnsetRegToAvoidLatch + val select = False + val matcher = Reg(Bits(4 bits)) init (0) + if (p.debugTriggersLsu) { + csrrw(CSR.TDATA1, read, 11 -> chain, 0 -> load, 1 -> store, 7 -> matcher) + csrr(CSR.TDATA1, read, 18 -> (load && select)) } + } + + val chainBroken = Bool() + val tdata2 = new Area { + val value = Reg(Bits(Global.MIXED_WIDTH bits)) + csrw(CSR.TDATA2, 0 -> value) + val enabled = !debugMode && tdata1.privilegeHit// && !chainBroken - val chainBroken = Bool() - val tdata2 = new Area { - val value = Reg(Bits(Global.MIXED_WIDTH bits)) - csrw(CSR.TDATA2, 0 -> value) - val enabled = !debugMode && tdata1.action === 1 && tdata1.privilegeHit// && !chainBroken + val execute = for (laneId <- 0 until Decode.LANES) yield new dpp.LaneArea(pcBreakMatchAt, laneId) { + PC_TRIGGER_HITS(slotId) := enabled && tdata1.execute && U(value) === Global.PC + } - val execute = for (laneId <- 0 until Decode.LANES) yield new dpp.LaneArea(pcBreakMatchAt, laneId) { - PC_TRIGGER_HITS(slotId) := enabled && tdata1.execute && U(value) === Global.PC + val lsu = p.debugTriggersLsu generate new Area { + val lsuTrigger = getLsuTriggerBus() + val sizeSpec = ArrayBuffer[(Any, Bool)]( + 0 -> True, + 1 -> (lsuTrigger.size === 0), + 2 -> (lsuTrigger.size === 1), + 3 -> (lsuTrigger.size === 2) + ) + if(XLEN.get >= 64) { + sizeSpec += 5 -> (lsuTrigger.size === 3) + sizeSpec += (default -> False) } - val lsu = p.debugTriggersLsu generate new Area { - val lsuTrigger = getLsuTriggerBus() - val sizeSpec = ArrayBuffer[(Any, Bool)]( - 0 -> True, - 1 -> (lsuTrigger.size === 0), - 2 -> (lsuTrigger.size === 1), - 3 -> (lsuTrigger.size === 2) + val sizeOk = tdata1.size.muxList(sizeSpec) + val matcher = new Area { + val cpu = B(lsuTrigger.virtual) + val cmp = U(cpu) < U(value) + + val mask = B(Global.MIXED_WIDTH - 12 bits, default -> true) ## Napot(value(12 - 2 downto 0)).orMask(tdata1.matcher =/= 1) + val cpuMasked = CombInit(cpu) + // when(tdata1.matcher === 4 || tdata1.matcher === 5) { + // cpuMasked(15 downto 0) := cpu.subdivideIn(2 slices)(U(tdata1.matcher.lsb)) & value(31 downto 16) + // } + val maskHit = (~((B(cpuMasked) & mask) ^ (value & mask))).andR + + val ok = tdata1.matcher.mux( + 0 -> maskHit, + 1 -> maskHit, + 2 -> !cmp, + 3 -> cmp, + // 4 -> maskHits(0), + // 5 -> maskHits(0), + default -> False ) - if(XLEN.get >= 64) { - sizeSpec += 5 -> (lsuTrigger.size === 3) - sizeSpec += (default -> False) - } - - val sizeOk = tdata1.size.muxList(sizeSpec) - val matcher = new Area { - val cpu = B(lsuTrigger.virtual) - val cmp = U(cpu) < U(value) - - val mask = B(Global.MIXED_WIDTH - 12 bits, default -> true) ## Napot(value(12 - 2 downto 0)).orMask(tdata1.matcher =/= 1) - val cpuMasked = CombInit(cpu) -// when(tdata1.matcher === 4 || tdata1.matcher === 5) { -// cpuMasked(15 downto 0) := cpu.subdivideIn(2 slices)(U(tdata1.matcher.lsb)) & value(31 downto 16) -// } - val maskHit = (~((B(cpuMasked) & mask) ^ (value & mask))).andR - - val ok = tdata1.matcher.mux( - 0 -> maskHit, - 1 -> maskHit, - 2 -> !cmp, - 3 -> cmp, -// 4 -> maskHits(0), -// 5 -> maskHits(0), - default -> False - ) - } - val virtualTrigger = (tdata1.store && lsuTrigger.store || tdata1.load && lsuTrigger.load) - val hitNoChain = enabled && !chainBroken && sizeOk && matcher.ok && virtualTrigger - val hit = hitNoChain && !tdata1.chain } + val virtualTrigger = (tdata1.store && lsuTrigger.store || tdata1.load && lsuTrigger.load) + val hitNoChain = enabled && !chainBroken && sizeOk && matcher.ok && virtualTrigger + val hit = hitNoChain && !tdata1.chain } } + } - for (slotId <- slots.indices) { - val slot = slots(slotId) - slotId match { - case 0 => slot.chainBroken := False - case _ => { - val prev = slots(slotId - 1) - slot.chainBroken := prev.tdata1.chain && (prev.chainBroken || p.debugTriggersLsu.mux(!prev.tdata2.lsu.hitNoChain, False)) - } + for (slotId <- slots.indices) { + val slot = slots(slotId) + slotId match { + case 0 => slot.chainBroken := False + case _ => { + val prev = slots(slotId - 1) + slot.chainBroken := prev.tdata1.chain && (prev.chainBroken || p.debugTriggersLsu.mux(!prev.tdata2.lsu.hitNoChain, False)) } - - val lsuTrigger = getLsuTriggerBus() - lsuTrigger.hits(slotId) := p.debugTriggersLsu.mux(slot.tdata2.lsu.hit, False) } - api.read(CSR.TDATA1, 0 -> slots.map(_.tdata1.read).read(tselect.index)) - api.read(CSR.TDATA2, 0 -> S(slots.map(_.tdata2.value).read(tselect.index)).resize(XLEN)) + val lsuTrigger = getLsuTriggerBus() + lsuTrigger.hits(slotId) := p.debugTriggersLsu.mux(slot.tdata2.lsu.hit, False) } + + api.read(CSR.TDATA1, 0 -> slots.map(_.tdata1.read).read(tselect.index)) + api.read(CSR.TDATA2, 0 -> S(slots.map(_.tdata2.value).read(tselect.index)).resize(XLEN)) } + val m = new Area { api.read(U(p.vendorId), CSR.MVENDORID) // MRO Vendor ID. api.read(U(p.archId), CSR.MARCHID) // MRO Architecture ID. diff --git a/src/main/scala/vexiiriscv/misc/TrapPlugin.scala b/src/main/scala/vexiiriscv/misc/TrapPlugin.scala index d0cf57a..d6f7d6d 100644 --- a/src/main/scala/vexiiriscv/misc/TrapPlugin.scala +++ b/src/main/scala/vexiiriscv/misc/TrapPlugin.scala @@ -78,13 +78,13 @@ case class TrapPending() extends Bundle{ object TrapReason{ val INTERRUPT = 0 val PRIV_RET = 1 - val REDO = 2 - val NEXT = 3 - val FENCE_I = 4 - val SFENCE_VMA = 5 - val MMU_REFILL = 6 - val WFI = 7 - val DEBUG_TRIGGER = 8 + val FENCE_I = 2 + val DEBUG_TRIGGER = CSR.MCAUSE_ENUM.BREAKPOINT // Need to match to reduce hardware + val REDO = 4 + val NEXT = 5 + val SFENCE_VMA = 6 + val MMU_REFILL = 7 + val WFI = 8 } object TrapArg{ @@ -355,7 +355,7 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { buffer.sampleIt := True goto(PROCESS) } - if (priv.p.withDebug) when(!csr.debug.running && csr.debug.doResume) { + if (priv.p.withDebug) when(!csr.hartRunning && csr.debug.doResume) { goto(DPC_READ) } } @@ -375,15 +375,27 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { if (fl1p.nonEmpty) fetchL1Invalidate(hartId).cmd.valid := False if (lsu.nonEmpty) lsuL1Invalidate(hartId).cmd.valid := False val trapEnterDebug = RegInit(False) + val triggerEbreak = (priv.p.debugTriggers == 0).mux(False, !pending.state.exception && pending.state.code === TrapReason.DEBUG_TRIGGER && csr.trigger.slots.reader(pending.state.tval.asUInt.resized)(_.tdata1.doEbreak)) + val triggerEbreakReg = Reg(Bool()) PROCESS.whenIsActive{ + triggerEbreakReg := triggerEbreak + if(priv.p.debugTriggers > 0 ) { + pending.state.exception setWhen(triggerEbreak) //Patch to reduce logic in next stages + when(!pending.state.exception && pending.state.code === TrapReason.DEBUG_TRIGGER) { + csr.trigger.slots.onSel(U(pending.state.tval).resized) { slot => + slot.tdata1.hit := True + } + } + } + trapEnterDebug := False if(hp.nonEmpty) historyPort.valid := True - when(pending.state.exception || buffer.trap.interrupt) { + when(pending.state.exception || triggerEbreak || buffer.trap.interrupt) { goto(TRAP_TVAL) if(priv.p.withDebug){ - when(!csr.debug.debugMode) { + when(!csr.debugMode) { val doIt = False - when(pending.state.exception && exception.code === CSR.MCAUSE_ENUM.BREAKPOINT) { + when(pending.state.exception && exception.code === CSR.MCAUSE_ENUM.BREAKPOINT || triggerEbreak) { doIt setWhen(csr.privilege === 3 && csr.debug.dcsr.ebreakm) if (priv.p.withUser) doIt setWhen (csr.privilege === 0 && csr.debug.dcsr.ebreaku) if (priv.p.withSupervisor) doIt setWhen (csr.privilege === 1 && csr.debug.dcsr.ebreaks) @@ -447,9 +459,6 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { } } if(priv.p.debugTriggers > 0 ) is(TrapReason.DEBUG_TRIGGER) { - csr.debug.trigger.slots.onSel(U(pending.state.tval).resized){slot => - slot.tdata1.hit := True - } trapEnterDebug := True goto(TRAP_EPC) } @@ -503,6 +512,9 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { csr.s.tval.getAddress() ) crsPorts.write.data := Global.expendPc(buffer.trap.tval.asUInt, XLEN).asBits + when(triggerEbreakReg){ + crsPorts.write.data := Global.expendPc(pending.pc, XLEN).asBits + } when(crsPorts.write.ready) { goto(TRAP_EPC) } @@ -572,8 +584,8 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { csr.debug.bus.exception := False csr.debug.bus.ebreak := False ENTER_DEBUG.whenIsActive{ - csr.debug.running := False - when(!csr.debug.debugMode) { + csr.hartRunning := False + when(!csr.debugMode) { csr.debug.dcsr.cause := 0 when(csr.debug.dcsr.step){ csr.debug.dcsr.cause := 4 } when(csr.debug.bus.haltReq) { csr.debug.dcsr.cause := 3 } @@ -599,7 +611,7 @@ class TrapPlugin(val trapAt : Int) extends FiberPlugin with TrapService { pcPort.valid := True pcPort.pc := U(readed).resized //PC RESIZED csr.privilege := csr.debug.dcsr.prv - csr.debug.running := True + csr.hartRunning := True csr.debug.bus.resume.rsp.valid := True goto(RUNNING) }