1
0

Merge branch 'master' into name-rams

This commit is contained in:
Henry Cook 2017-03-30 17:36:01 -07:00 committed by GitHub
commit b9550e8523
25 changed files with 2616 additions and 1399 deletions

View File

@ -55,7 +55,7 @@ before_install:
script: script:
- make emulator-ndebug -C regression SUITE=$SUITE - make emulator-ndebug -C regression SUITE=$SUITE
- travis_wait make emulator-regression-tests -C regression SUITE=$SUITE - travis_wait 30 make emulator-regression-tests -C regression SUITE=$SUITE
before_cache: before_cache:
- ls -t regression/install | tail -n+2 | sed s@^@regression/install/@ | xargs rm -rf - ls -t regression/install | tail -n+2 | sed s@^@regression/install/@ | xargs rm -rf

View File

@ -33,11 +33,11 @@ extern "C" int debug_tick
unsigned char debug_req_ready, unsigned char debug_req_ready,
int* debug_req_bits_addr, int* debug_req_bits_addr,
int* debug_req_bits_op, int* debug_req_bits_op,
long long* debug_req_bits_data, int* debug_req_bits_data,
unsigned char debug_resp_valid, unsigned char debug_resp_valid,
unsigned char* debug_resp_ready, unsigned char* debug_resp_ready,
int debug_resp_bits_resp, int debug_resp_bits_resp,
long long debug_resp_bits_data int debug_resp_bits_data
) )
{ {
if (!dtm) { if (!dtm) {

@ -1 +1 @@
Subproject commit decf42b0f357220adb6722ddba362c6884321477 Subproject commit 6e32ffa7a4e03254f934623f083078f82a721be7

View File

@ -0,0 +1,31 @@
# See LICENSE.SiFive for license details
# Recursive make is bad, but in this case we're cross compiling which is a
# pretty unusual use case.
CC = $(RISCV)/bin/riscv64-unknown-elf-gcc
OBJCOPY = $(RISCV)/bin/riscv64-unknown-elf-objcopy
COMPILE = $(CC) -nostdlib -nostartfiles -I$(RISCV)/include/ -Tlink.ld
ELFS = debug_rom
DEPS = debug_rom.S link.ld
all: $(patsubst %,%.h,$(ELFS))
publish: debug_rom.scala
mv $< ../../src/main/scala/uncore/devices/debug/DebugRomContents.scala
%.scala: %.raw
xxd -i $^ | sed -e "s/^unsigned char debug_rom_raw\[\] = {/\/\/ This file was auto-generated by 'make publish' in debug\/ directory.\n\npackage uncore.devices\n\nobject DebugRomContents {\n\n def apply() : Array[Byte] = { Array (/" \
-e "s/};/ ).map(_.toByte) }\n\n}/" \
-e "s/^unsigned int debug_rom_raw_len.*//" > $@
%.raw: %
$(OBJCOPY) -O binary --only-section .text $^ $@
debug_rom: $(DEPS)
$(COMPILE) -o $@ $^
clean:
rm -f $(ELFS) debug_rom*.raw debug_rom*.h

76
scripts/debug_rom/debug_rom.S Executable file
View File

@ -0,0 +1,76 @@
// See LICENSE.SiFive for license details.
#include "spike/encoding.h"
// These are implementation-specific addresses in the Debug Module
#define HALTED 0x100
#define GOING 0x104
#define RESUMING 0x108
#define EXCEPTION 0x10C
// Region of memory where each hart has 1
// byte to read.
#define OK_GO 0x400
.option norvc
.global entry
.global exception
// Entry location on ebreak, Halt, or Breakpoint
// It is the same for all harts. They branch when
// their specific OK_GO bit is set.
entry:
jal zero, _entry
resume:
jal zero, _resume
exception:
jal zero, _exception
_entry:
// This fence is required because the execution may have written something
// into the Abstract Data or Program Buffer registers.
fence
csrw CSR_DSCRATCH, s0 // Save s0 to allow signaling MHARTID
// We continue to let the hart know that we are halted in order that
// a DM which was reset is still made aware that a hart is halted.
// We keep checking both whether there is something the debugger wants
// us to do, or whether we should not be halted anymore.
entry_loop:
csrr s0, CSR_MHARTID
sw s0, HALTED(zero)
lb s0, OK_GO(s0) // 1 byte flag per hart. Only one hart advances here.
bne zero, s0, going
jal zero, entry_loop
_exception:
sw zero, EXCEPTION(zero) // Let debug module know you got an exception.
ebreak
going:
csrr s0, CSR_DSCRATCH // Restore s0 here
sw zero, GOING(zero) // When debug module sees this write, the OK_GO flag is reset.
jalr zero, zero, %lo(whereto) // Rocket-Chip has a specific hack which is that jalr in
// Debug Mode will flush the I-Cache. We need that so that the
// remainder of the variable instructions will be what Debug Module
// intends.
_resume:
csrw CSR_DSCRATCH, s0 // Save s0 to allow signaling MHARTID
csrr s0, CSR_MHARTID
sw s0, RESUMING(zero) // Let the Debug Module know you're not halted anymore.
csrr s0, CSR_DSCRATCH // Restore s0
dret
// END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT.
.section .whereto
whereto:
nop
// Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer,
// or jal x0 resume, as desired.
// Debug Module state machine tracks what is 'desired'.
// We don't need/want to use jalr here because all of the
// Variable ROM contents are set by
// Debug Module before setting the OK_GO byte.

16
scripts/debug_rom/link.ld Normal file
View File

@ -0,0 +1,16 @@
/* See LICENSE.SiFive for license details. */
OUTPUT_ARCH( "riscv" )
ENTRY( entry )
SECTIONS
{
.whereto 0x300 :
{
*(.whereto)
}
. = 0x800;
.text :
{
*(.text)
}
_end = .;
}

View File

@ -22,7 +22,7 @@ class BaseCoreplexConfig extends Config ((site, here, up) => {
case BuildCore => (p: Parameters) => new Rocket()(p) case BuildCore => (p: Parameters) => new Rocket()(p)
case RocketCrossing => Synchronous case RocketCrossing => Synchronous
case RocketTilesKey => Nil case RocketTilesKey => Nil
case DMKey => new DefaultDebugModuleConfig(site(NTiles), site(XLen)) case DMKey => new DefaultDebugModuleConfig(site(XLen))
case NTiles => site(RocketTilesKey).size case NTiles => site(RocketTilesKey).size
case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8) case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8)
case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth

View File

@ -15,10 +15,12 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork {
val module: CoreplexRISCVPlatformModule val module: CoreplexRISCVPlatformModule
val debug = LazyModule(new TLDebugModule()) val debug = LazyModule(new TLDebugModule())
val debug_rom = LazyModule(new TLDebugModuleROM())
val plic = LazyModule(new TLPLIC(maxPriorities = 7)) val plic = LazyModule(new TLPLIC(maxPriorities = 7))
val clint = LazyModule(new CoreplexLocalInterrupter) val clint = LazyModule(new CoreplexLocalInterrupter)
debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
debug_rom.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
plic.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) plic.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
clint.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) clint.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
@ -32,7 +34,7 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork {
trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle { trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle {
val outer: CoreplexRISCVPlatform val outer: CoreplexRISCVPlatform
val debug = new AsyncDebugBusIO().flip val debug = new ClockedDMIIO().flip
val rtcToggle = Bool(INPUT) val rtcToggle = Bool(INPUT)
val resetVector = UInt(INPUT, p(XLen)) val resetVector = UInt(INPUT, p(XLen))
} }
@ -41,8 +43,14 @@ trait CoreplexRISCVPlatformModule extends CoreplexNetworkModule {
val outer: CoreplexRISCVPlatform val outer: CoreplexRISCVPlatform
val io: CoreplexRISCVPlatformBundle val io: CoreplexRISCVPlatformBundle
// Synchronize the debug bus into the coreplex outer.debug.module.io.dmi <> io.debug
outer.debug.module.io.db <> FromAsyncDebugBus(io.debug) // TODO in inheriting traits: Set this to something meaningful, e.g. "component is in reset or powered down"
val nDebugComponents = outer.debug.intnode.bundleOut.size
outer.debug.module.io.ctrl.debugUnavail := Vec.fill(nDebugComponents){Bool(false)}
// TODO in inheriting traits: Use these values in your power and reset controls.
// TODO Or move these signals to Coreplex Top Level
// ... := outer.debug.module.io.ctrl.dmactive
// ... := outer.debug.module.io.ctrl.ndreset
// Synchronize the rtc into the coreplex // Synchronize the rtc into the coreplex
val rtcSync = ShiftRegister(io.rtcToggle, 3) val rtcSync = ShiftRegister(io.rtcToggle, 3)

View File

@ -39,11 +39,8 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
case SharedMemoryTLEdge => l1tol2.node.edgesIn(0) case SharedMemoryTLEdge => l1tol2.node.edgesIn(0)
} }
// Hack debug interrupt into a node (future debug module should use diplomacy)
val debugNode = IntInternalInputNode(IntSourcePortSimple())
val intBar = LazyModule(new IntXbar) val intBar = LazyModule(new IntXbar)
intBar.intnode := debugNode // debug intBar.intnode := debug.intnode // debug
intBar.intnode := clint.intnode // msip+mtip intBar.intnode := clint.intnode // msip+mtip
intBar.intnode := plic.intnode // meip intBar.intnode := plic.intnode // meip
if (c.core.useVM) intBar.intnode := plic.intnode // seip if (c.core.useVM) intBar.intnode := plic.intnode // seip
@ -63,7 +60,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
// leave clock as default (simpler for hierarchical PnR) // leave clock as default (simpler for hierarchical PnR)
wrapper.module.io.hartid := UInt(i) wrapper.module.io.hartid := UInt(i)
wrapper.module.io.resetVector := io.resetVector wrapper.module.io.resetVector := io.resetVector
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
} }
} }
case Asynchronous(depth, sync) => { case Asynchronous(depth, sync) => {
@ -82,7 +78,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
wrapper.module.reset := io.tcrs(i).reset wrapper.module.reset := io.tcrs(i).reset
wrapper.module.io.hartid := UInt(i) wrapper.module.io.hartid := UInt(i)
wrapper.module.io.resetVector := io.resetVector wrapper.module.io.resetVector := io.resetVector
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
} }
} }
case Rational => { case Rational => {
@ -101,7 +96,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
wrapper.module.reset := io.tcrs(i).reset wrapper.module.reset := io.tcrs(i).reset
wrapper.module.io.hartid := UInt(i) wrapper.module.io.hartid := UInt(i)
wrapper.module.io.resetVector := io.resetVector wrapper.module.io.resetVector := io.resetVector
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
} }
} }
} }

View File

@ -1,16 +0,0 @@
// See LICENSE.SiFive for license details.
package junctions
import Chisel._
import config._
class JTAGIO(drvTdo: Boolean = false) extends Bundle {
val TCK = Clock(OUTPUT)
val TMS = Bool(OUTPUT)
val TDI = Bool(OUTPUT)
val TDO = Bool(INPUT)
val TRST = Bool(OUTPUT)
val DRV_TDO = if (drvTdo) Some(Bool(INPUT)) else None
override def cloneType = new JTAGIO(drvTdo).asInstanceOf[this.type]
}

View File

@ -47,8 +47,7 @@ class MStatus extends Bundle {
class DCSR extends Bundle { class DCSR extends Bundle {
val xdebugver = UInt(width = 2) val xdebugver = UInt(width = 2)
val ndreset = Bool() val zero4 = UInt(width=2)
val fullreset = Bool()
val zero3 = UInt(width = 12) val zero3 = UInt(width = 12)
val ebreakm = Bool() val ebreakm = Bool()
val ebreakh = Bool() val ebreakh = Bool()
@ -58,9 +57,9 @@ class DCSR extends Bundle {
val stopcycle = Bool() val stopcycle = Bool()
val stoptime = Bool() val stoptime = Bool()
val cause = UInt(width = 3) val cause = UInt(width = 3)
// TODO: debugint is not in the Debug Spec v13
val debugint = Bool() val debugint = Bool()
val zero1 = Bool() val zero1 = UInt(width=2)
val halt = Bool()
val step = Bool() val step = Bool()
val prv = UInt(width = PRV.SZ) val prv = UInt(width = PRV.SZ)
} }
@ -474,8 +473,8 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
val causeIsDebugTrigger = !cause(xLen-1) && cause_lsbs === CSR.debugTriggerCause 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 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 trapToDebug = Bool(usingDebug) && (reg_singleStepped || causeIsDebugInt || causeIsDebugTrigger || causeIsDebugBreak || reg_debug)
val debugTVec = Mux(reg_debug, Mux(insn_break, UInt(0x800), UInt(0x808)), UInt(0x800))
val delegate = Bool(usingVM) && reg_mstatus.prv <= PRV.S && Mux(cause(xLen-1), reg_mideleg(cause_lsbs), reg_medeleg(cause_lsbs)) val delegate = Bool(usingVM) && reg_mstatus.prv <= PRV.S && 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 tvec = Mux(trapToDebug, debugTVec, Mux(delegate, reg_stvec.sextTo(vaddrBitsExtended), reg_mtvec))
io.evec := tvec io.evec := tvec
io.ptbr := reg_sptbr io.ptbr := reg_sptbr
@ -510,11 +509,13 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault) Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault)
when (trapToDebug) { when (trapToDebug) {
when (!reg_debug) {
reg_debug := true reg_debug := true
reg_dpc := epc reg_dpc := epc
reg_dcsr.cause := Mux(reg_singleStepped, 4, Mux(causeIsDebugInt, 3, Mux[UInt](causeIsDebugTrigger, 2, 1))) reg_dcsr.cause := Mux(reg_singleStepped, 4, Mux(causeIsDebugInt, 3, Mux[UInt](causeIsDebugTrigger, 2, 1)))
reg_dcsr.prv := trimPrivilege(reg_mstatus.prv) reg_dcsr.prv := trimPrivilege(reg_mstatus.prv)
new_prv := PRV.M new_prv := PRV.M
}
}.elsewhen (delegate) { }.elsewhen (delegate) {
reg_sepc := formEPC(epc) reg_sepc := formEPC(epc)
reg_scause := cause reg_scause := cause
@ -628,7 +629,6 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
if (usingDebug) { if (usingDebug) {
when (decoded_addr(CSRs.dcsr)) { when (decoded_addr(CSRs.dcsr)) {
val new_dcsr = new DCSR().fromBits(wdata) val new_dcsr = new DCSR().fromBits(wdata)
reg_dcsr.halt := new_dcsr.halt
reg_dcsr.step := new_dcsr.step reg_dcsr.step := new_dcsr.step
reg_dcsr.ebreakm := new_dcsr.ebreakm reg_dcsr.ebreakm := new_dcsr.ebreakm
if (usingVM) reg_dcsr.ebreaks := new_dcsr.ebreaks if (usingVM) reg_dcsr.ebreaks := new_dcsr.ebreaks

View File

@ -37,6 +37,7 @@ class BasePlatformConfig extends Config((site, here, up) => {
case PeripheryBusArithmetic => true case PeripheryBusArithmetic => true
// Note that PLIC asserts that this is > 0. // Note that PLIC asserts that this is > 0.
case IncludeJtagDTM => false case IncludeJtagDTM => false
case JtagDTMKey => new JtagDTMKeyDefault()
case ZeroConfig => ZeroConfig(base=0xa000000L, size=0x2000000L, beatBytes=8) case ZeroConfig => ZeroConfig(base=0xa000000L, size=0x2000000L, beatBytes=8)
case ExtMem => MasterConfig(base=0x80000000L, size=0x10000000L, beatBytes=8, idBits=4) case ExtMem => MasterConfig(base=0x80000000L, size=0x10000000L, beatBytes=8, idBits=4)
case ExtBus => MasterConfig(base=0x60000000L, size=0x20000000L, beatBytes=8, idBits=4) case ExtBus => MasterConfig(base=0x60000000L, size=0x20000000L, beatBytes=8, idBits=4)

View File

@ -3,78 +3,227 @@
package rocketchip package rocketchip
import Chisel._ import Chisel._
import uncore.devices._
import junctions._
import util._ import util._
import config._ import config._
import jtag._
import uncore.devices.{DMIConsts, DMIIO, DMIReq, DMIResp}
case object IncludeJtagDTM extends Field[Boolean] case object IncludeJtagDTM extends Field[Boolean]
/* JTAG-based Debug Transport Module case class JtagDTMConfig (
* and synchronization logic. idcodeVersion : Int, // chosen by manuf.
* idcodePartNum : Int, // Chosen by manuf.
* This implements JTAG interface described idcodeManufId : Int, // Assigned by JEDEC
* in the RISC-V Debug Specification debugIdleCycles : Int)
*
* This Module is currently a
* wrapper around a JTAG implementation
* of the Debug Transport Module.
* This is black-boxed because
* Chisel doesn't currently support:
* - Negative Edge Clocking
* - Asynchronous Resets
* (The tristate requirements of JTAG are exported from the
* Chisel domain with the DRV_TDO signal).
*
* The 'TRST' input is used to asynchronously
* reset the Debug Transport Module and the
* DTM side of the synchronizer.
* This design requires that TRST be
* synchronized to TCK (for de-assert) outside
* of this module. Your top level code should ensure
* that TRST is asserted before the rocket-chip core
* comes out of reset.
* Note that TRST is an optional
* part of the JTAG protocol, but it is not
* optional for interfacing with this logic.
*
*/
class JtagDTMWithSync(implicit val p: Parameters) extends Module { case object JtagDTMKey extends Field[JtagDTMConfig]
// io.DebugBusIO <-> Sync <-> DebugBusIO <-> UInt <-> DTM Black Box
class JtagDTMKeyDefault extends JtagDTMConfig(
idcodeVersion = 0,
idcodePartNum = 0,
idcodeManufId = 0,
debugIdleCycles = 5) // Reasonable guess for synchronization.
object dtmJTAGAddrs {
def IDCODE = 0x1
def DTM_INFO = 0x10
def DMI_ACCESS = 0x11
}
class DMIAccessUpdate(addrBits: Int) extends Bundle {
val addr = UInt(width = addrBits)
val data = UInt(width = DMIConsts.dmiDataSize)
val op = UInt(width = DMIConsts.dmiOpSize)
override def cloneType = new DMIAccessUpdate(addrBits).asInstanceOf[this.type]
}
class DMIAccessCapture(addrBits: Int) extends Bundle {
val addr = UInt(width = addrBits)
val data = UInt(width = DMIConsts.dmiDataSize)
val resp = UInt(width = DMIConsts.dmiRespSize)
override def cloneType = new DMIAccessCapture(addrBits).asInstanceOf[this.type]
}
class DTMInfo extends Bundle {
val reserved1 = UInt(15.W)
val dmireset = Bool()
val reserved0 = UInt(1.W)
val dmiIdleCycles = UInt(3.W)
val dmiStatus = UInt(2.W)
val debugAddrBits = UInt(6.W)
val debugVersion = UInt(4.W)
}
class DebugTransportModuleJTAG(debugAddrBits: Int, c: JtagDTMConfig)
(implicit val p: Parameters) extends Module {
val io = new Bundle { val io = new Bundle {
val jtag = new JTAGIO(true).flip val dmi = new DMIIO()(p)
val debug = new AsyncDebugBusIO val jtag = Flipped(new JTAGIO(hasTRSTn = false))
val jtag_reset = Bool(INPUT)
val fsmReset = Bool(OUTPUT)
} }
val req_width = io.debug.req.mem(0).getWidth //--------------------------------------------------------
val resp_width = io.debug.resp.mem(0).getWidth // Reg and Wire Declarations
val jtag_dtm = Module(new DebugTransportModuleJtag(req_width, resp_width)) val dtmInfo = Wire(new DTMInfo)
jtag_dtm.io.jtag <> io.jtag
val io_debug_bus = Wire (new DebugBusIO) val busyReg = RegInit(Bool(false))
io.debug <> ToAsyncDebugBus(io_debug_bus) val stickyBusyReg = RegInit(Bool(false))
val stickyNonzeroRespReg = RegInit(Bool(false))
val dtm_req = jtag_dtm.io.dtm_req val skipOpReg = Reg(init = Bool(false)) // Skip op because we're busy
val dtm_resp = jtag_dtm.io.dtm_resp val downgradeOpReg = Reg(init = Bool(false)) // downgrade op because prev. failed.
// Translate from straight 'bits' interface of the blackboxes val busy = Wire(Bool())
// into the Resp/Req data structures. val nonzeroResp = Wire(Bool())
io_debug_bus.req.valid := dtm_req.valid
io_debug_bus.req.bits := new DebugBusReq(p(DMKey).nDebugBusAddrSize).fromBits(dtm_req.bits)
dtm_req.ready := io_debug_bus.req.ready
dtm_resp.valid := io_debug_bus.resp.valid val busyResp = Wire(new DMIAccessCapture(debugAddrBits))
dtm_resp.bits := io_debug_bus.resp.bits.asUInt val nonbusyResp = Wire(new DMIAccessCapture(debugAddrBits))
io_debug_bus.resp.ready := dtm_resp.ready
val dmiReqReg = Reg(new DMIReq(debugAddrBits))
val dmiReqValidReg = Reg(init = Bool(false));
val dmiStatus = Wire(UInt(width = 2))
//--------------------------------------------------------
// DTM Info Chain Declaration
dmiStatus := Cat(stickyNonzeroRespReg, stickyNonzeroRespReg | stickyBusyReg)
dtmInfo.debugVersion := 1.U // This implements version 1 of the spec.
dtmInfo.debugAddrBits := UInt(debugAddrBits)
dtmInfo.dmiStatus := dmiStatus
dtmInfo.dmiIdleCycles := UInt(c.debugIdleCycles)
dtmInfo.reserved0 := 0.U
dtmInfo.dmireset := false.B // This is write-only
dtmInfo.reserved1 := 0.U
val dtmInfoChain = Module (CaptureUpdateChain(gen = new DTMInfo()))
dtmInfoChain.io.capture.bits := dtmInfo
//--------------------------------------------------------
// Debug Access Chain Declaration
val dmiAccessChain = Module(CaptureUpdateChain(genCapture = new DMIAccessCapture(debugAddrBits),
genUpdate = new DMIAccessUpdate(debugAddrBits)))
//--------------------------------------------------------
// Debug Access Support
// Busy Register. We become busy when we first try to send a request.
// We stop being busy when we accept a response.
when (io.dmi.req.valid) {
busyReg := Bool(true)
}
when (io.dmi.resp.fire()) {
busyReg := Bool(false)
} }
class DebugTransportModuleJtag(reqSize : Int, respSize : Int)(implicit val p: Parameters) extends BlackBox { // We are busy during a given CAPTURE
val io = new Bundle { // if we haven't received a valid response yet or if we
val jtag = new JTAGIO(true).flip() // were busy last time without a reset.
val dtm_req = new DecoupledIO(UInt(width = reqSize)) // busyReg will still be set when we check it,
val dtm_resp = new DecoupledIO(UInt(width = respSize)).flip() // so the logic for checking busy looks ahead.
busy := (busyReg & !io.dmi.resp.valid) | stickyBusyReg;
// Downgrade/Skip. We make the decision to downgrade or skip
// during every CAPTURE_DR, and use the result in UPDATE_DR.
// The sticky versions are reset by write to dmiReset in DTM_INFO.
when (dmiAccessChain.io.update.valid) {
skipOpReg := Bool(false)
downgradeOpReg := Bool(false)
}
when (dmiAccessChain.io.capture.capture) {
skipOpReg := busy
downgradeOpReg := (!busy & nonzeroResp)
stickyBusyReg := busy
stickyNonzeroRespReg := nonzeroResp
}
when (dtmInfoChain.io.update.valid) {
when (dtmInfoChain.io.update.bits.dmireset) {
stickyNonzeroRespReg := Bool(false)
stickyBusyReg := Bool(false)
} }
} }
// Especially for the first request, we must consider dtmResp.valid,
// so that we don't consider junk in the FIFO to be an error response.
// The current specification says that any non-zero response is an error.
nonzeroResp := stickyNonzeroRespReg | (io.dmi.resp.valid & (io.dmi.resp.bits.resp != UInt(0)))
busyResp.addr := UInt(0)
busyResp.resp := UInt(0)
busyResp.data := UInt(0)
nonbusyResp.addr := dmiReqReg.addr
nonbusyResp.resp := io.dmi.resp.bits.resp
nonbusyResp.data := io.dmi.resp.bits.data
//--------------------------------------------------------
// Debug Access Chain Implementation
dmiAccessChain.io.capture.bits := Mux(busy, busyResp, nonbusyResp)
when (dmiAccessChain.io.update.valid) {
skipOpReg := Bool(false)
downgradeOpReg := Bool(false)
}
when (dmiAccessChain.io.capture.capture) {
skipOpReg := busy
downgradeOpReg := (!busy & nonzeroResp)
stickyBusyReg := busy
stickyNonzeroRespReg := nonzeroResp
}
//--------------------------------------------------------
// Drive Ready Valid Interface
when (dmiAccessChain.io.update.valid) {
when (skipOpReg) {
// Do Nothing
}.otherwise {
when (downgradeOpReg) {
dmiReqReg.addr := UInt(0)
dmiReqReg.data := UInt(0)
dmiReqReg.op := UInt(0)
}.otherwise {
dmiReqReg := dmiAccessChain.io.update.bits
}
dmiReqValidReg := Bool(true)
}
}.otherwise {
when (io.dmi.req.ready) {
dmiReqValidReg := Bool(false)
}
}
io.dmi.resp.ready := dmiAccessChain.io.capture.capture
io.dmi.req.valid := dmiReqValidReg
// This is a name-based, not type-based assignment. Do these still work?
io.dmi.req.bits := dmiReqReg
//--------------------------------------------------------
// Actual JTAG TAP
val tapIO = JtagTapGenerator(irLength = 5,
instructions = Map(dtmJTAGAddrs.DMI_ACCESS -> dmiAccessChain,
dtmJTAGAddrs.DTM_INFO -> dtmInfoChain),
idcode = Some((dtmJTAGAddrs.IDCODE, JtagIdcode(c.idcodeVersion, c.idcodePartNum, c.idcodeManufId))))
tapIO.jtag <> io.jtag
tapIO.control.jtag_reset := io.jtag_reset
//--------------------------------------------------------
// Reset Generation (this is fed back to us by the instantiating module,
// and is used to reset the debug registers).
io.fsmReset := tapIO.output.reset
}

View File

@ -8,55 +8,64 @@ import diplomacy._
import uncore.tilelink2._ import uncore.tilelink2._
import uncore.devices._ import uncore.devices._
import util._ import util._
import junctions.JTAGIO import jtag.JTAGIO
import coreplex._ import coreplex._
/// Core with JTAG for debug only // System with JTAG DTM Instantiated inside. JTAG interface is
// exported outside.
trait PeripheryJTAG extends HasTopLevelNetworks { trait PeripheryJTAGDTM extends HasTopLevelNetworks {
val module: PeripheryJTAGModule val module: PeripheryJTAGDTMModule
val coreplex: CoreplexRISCVPlatform val coreplex: CoreplexRISCVPlatform
} }
trait PeripheryJTAGBundle extends HasTopLevelNetworksBundle { trait PeripheryJTAGDTMBundle extends HasTopLevelNetworksBundle {
val outer: PeripheryJTAG val outer: PeripheryJTAGDTM
val jtag = new JTAGIO(hasTRSTn = false).flip
val jtag_reset = Bool(INPUT)
val jtag = new JTAGIO(true).flip
} }
trait PeripheryJTAGModule extends HasTopLevelNetworksModule { trait PeripheryJTAGDTMModule extends HasTopLevelNetworksModule {
val outer: PeripheryJTAG val outer: PeripheryJTAGDTM
val io: PeripheryJTAGBundle val io: PeripheryJTAGDTMBundle
val dtm = Module (new JtagDTMWithSync) val dtm = Module (new DebugTransportModuleJTAG(p(DMKey).nDMIAddrSize, p(JtagDTMKey)))
dtm.io.jtag <> io.jtag dtm.io.jtag <> io.jtag
outer.coreplex.module.io.debug <> dtm.io.debug
dtm.clock := io.jtag.TCK dtm.clock := io.jtag.TCK
dtm.reset := io.jtag.TRST dtm.io.jtag_reset := io.jtag_reset
dtm.reset := dtm.io.fsmReset
outer.coreplex.module.io.debug.dmi <> dtm.io.dmi
outer.coreplex.module.io.debug.dmiClock := io.jtag.TCK
outer.coreplex.module.io.debug.dmiReset := ResetCatchAndSync(io.jtag.TCK, io.jtag_reset, "dmiResetCatch")
} }
/// Core with DTM for debug only // System with Debug Module Interface Only. Any sort of DTM
// can be connected outside. DMI Clock and Reset must be provided.
trait PeripheryDTM extends HasTopLevelNetworks { trait PeripheryDMI extends HasTopLevelNetworks {
val module: PeripheryDTMModule val module: PeripheryDMIModule
val coreplex: CoreplexRISCVPlatform val coreplex: CoreplexRISCVPlatform
} }
trait PeripheryDTMBundle extends HasTopLevelNetworksBundle { trait PeripheryDMIBundle extends HasTopLevelNetworksBundle {
val outer: PeripheryDTM val outer: PeripheryDMI
val debug = new DebugBusIO().flip val debug = new ClockedDMIIO().flip
} }
trait PeripheryDTMModule extends HasTopLevelNetworksModule { trait PeripheryDMIModule extends HasTopLevelNetworksModule {
val outer: PeripheryDTM val outer: PeripheryDMI
val io: PeripheryDTMBundle val io: PeripheryDMIBundle
outer.coreplex.module.io.debug <> ToAsyncDebugBus(io.debug) outer.coreplex.module.io.debug <> io.debug
} }
/// Core with DTM or JTAG based on a parameter // System with DMI or JTAG interface based on a parameter
trait PeripheryDebug extends HasTopLevelNetworks { trait PeripheryDebug extends HasTopLevelNetworks {
val module: PeripheryDebugModule val module: PeripheryDebugModule
@ -66,21 +75,30 @@ trait PeripheryDebug extends HasTopLevelNetworks {
trait PeripheryDebugBundle extends HasTopLevelNetworksBundle { trait PeripheryDebugBundle extends HasTopLevelNetworksBundle {
val outer: PeripheryDebug val outer: PeripheryDebug
val debug = (!p(IncludeJtagDTM)).option(new DebugBusIO().flip) val debug = (!p(IncludeJtagDTM)).option(new ClockedDMIIO().flip)
val jtag = (p(IncludeJtagDTM)).option(new JTAGIO(true).flip)
val jtag = (p(IncludeJtagDTM)).option(new JTAGIO(hasTRSTn = false).flip)
val jtag_reset = (p(IncludeJtagDTM)).option(Bool(INPUT))
} }
trait PeripheryDebugModule extends HasTopLevelNetworksModule { trait PeripheryDebugModule extends HasTopLevelNetworksModule {
val outer: PeripheryDebug val outer: PeripheryDebug
val io: PeripheryDebugBundle val io: PeripheryDebugBundle
io.debug.foreach { dbg => outer.coreplex.module.io.debug <> ToAsyncDebugBus(dbg) } io.debug.foreach { dbg => outer.coreplex.module.io.debug <> dbg }
io.jtag.foreach { jtag =>
val dtm = Module (new JtagDTMWithSync) val dtm = if (io.jtag.isDefined) Some[DebugTransportModuleJTAG](Module (new DebugTransportModuleJTAG(p(DMKey).nDMIAddrSize, p(JtagDTMKey)))) else None
dtm.clock := jtag.TCK dtm.foreach { dtm =>
dtm.reset := jtag.TRST dtm.io.jtag <> io.jtag.get
dtm.io.jtag <> jtag
outer.coreplex.module.io.debug <> dtm.io.debug dtm.clock := io.jtag.get.TCK
dtm.io.jtag_reset := io.jtag_reset.get
dtm.reset := dtm.io.fsmReset
outer.coreplex.module.io.debug.dmi <> dtm.io.dmi
outer.coreplex.module.io.debug.dmiClock := io.jtag.get.TCK
outer.coreplex.module.io.debug.dmiReset := ResetCatchAndSync(io.jtag.get.TCK, io.jtag_reset.get, "dmiResetCatch")
} }
} }

View File

@ -8,6 +8,7 @@ import junctions._
import diplomacy._ import diplomacy._
import coreplex._ import coreplex._
import uncore.axi4._ import uncore.axi4._
import jtag.JTAGIO
class TestHarness()(implicit p: Parameters) extends Module { class TestHarness()(implicit p: Parameters) extends Module {
val io = new Bundle { val io = new Bundle {
@ -23,7 +24,7 @@ class TestHarness()(implicit p: Parameters) extends Module {
if (!p(IncludeJtagDTM)) { if (!p(IncludeJtagDTM)) {
val dtm = Module(new SimDTM).connect(clock, reset, dut.io.debug.get, io.success) val dtm = Module(new SimDTM).connect(clock, reset, dut.io.debug.get, io.success)
} else { } else {
val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, reset, io.success) val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, dut.io.jtag_reset.get, reset, io.success)
} }
val mmio_sim = Module(LazyModule(new SimAXIMem(1, 4096)).module) val mmio_sim = Module(LazyModule(new SimAXIMem(1, 4096)).module)
@ -62,14 +63,16 @@ class SimDTM(implicit p: Parameters) extends BlackBox {
val io = new Bundle { val io = new Bundle {
val clk = Clock(INPUT) val clk = Clock(INPUT)
val reset = Bool(INPUT) val reset = Bool(INPUT)
val debug = new uncore.devices.DebugBusIO val debug = new uncore.devices.DMIIO
val exit = UInt(OUTPUT, 32) val exit = UInt(OUTPUT, 32)
} }
def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.DebugBusIO, tbsuccess: Bool) = { def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.ClockedDMIIO, tbsuccess: Bool) = {
io.clk := tbclk io.clk := tbclk
io.reset := tbreset io.reset := tbreset
dutio <> io.debug dutio.dmi <> io.debug
dutio.dmiClock := tbclk
dutio.dmiReset := tbreset
tbsuccess := io.exit === UInt(1) tbsuccess := io.exit === UInt(1)
when (io.exit >= UInt(2)) { when (io.exit >= UInt(2)) {
@ -81,22 +84,17 @@ class SimDTM(implicit p: Parameters) extends BlackBox {
class JTAGVPI(implicit val p: Parameters) extends BlackBox { class JTAGVPI(implicit val p: Parameters) extends BlackBox {
val io = new Bundle { val io = new Bundle {
val jtag = new JTAGIO(false) val jtag = new JTAGIO(hasTRSTn = false)
val enable = Bool(INPUT) val enable = Bool(INPUT)
val init_done = Bool(INPUT) val init_done = Bool(INPUT)
} }
def connect(dutio: JTAGIO, tbreset: Bool, tbsuccess: Bool) = { def connect(dutio: JTAGIO, jtag_reset: Bool, tbreset: Bool, tbsuccess: Bool) = {
dutio <> io.jtag dutio <> io.jtag
// To be proper, dutio.TRSTn.foreach{ _:= false.B}
// TRST should really be synchronized jtag_reset := tbreset
// with TCK. But this is a fairly
// accurate representation of how
// HW may drive this signal.
// Neither OpenOCD nor JtagVPI drive TRST.
dutio.TRST := tbreset
io.enable := ~tbreset io.enable := ~tbreset
io.init_done := ~tbreset io.init_done := ~tbreset

View File

@ -1,887 +0,0 @@
// See LICENSE.SiFive for license details.
package uncore.devices
import Chisel._
import junctions._
import util._
import regmapper._
import tile.XLen
import uncore.tilelink2._
import config._
// *****************************************
// Constants which are interesting even
// outside of this module
// *****************************************
object DbRegAddrs{
def DMRAMBASE = UInt(0x0)
def DMCONTROL = UInt(0x10)
def DMINFO = UInt(0x11)
def AUTHDATA0 = UInt(0x12)
def AUTHDATA1 = UInt(0x13)
def SERDATA = UInt(0x14)
def SERSTATUS = UInt(0x15)
def SBUSADDRESS0 = UInt(0x16)
def SBUSADDRESS1 = UInt(0x17)
def SBDATA0 = UInt(0x18)
def SBDATA1 = UInt(0x19)
//1a
def HALTSUM = UInt(0x1B)
//1c - 3b are the halt notification registers.
def SBADDRESS2 = UInt(0x3d)
// 3c
def SBDATA2 = UInt(0x3e)
def SBDATA3 = UInt(0x3f)
}
/** Constant values used by both Debug Bus Response & Request
*/
object DbBusConsts{
def dbDataSize = 34
def dbRamWordBits = 32
def dbOpSize = 2
def db_OP_NONE = UInt("b00")
def db_OP_READ = UInt("b01")
def db_OP_READ_WRITE = UInt("b10")
def db_OP_READ_COND_WRITE = UInt("b11")
def dbRespSize = 2
def db_RESP_SUCCESS = UInt("b00")
def db_RESP_FAILURE = UInt("b01")
def db_RESP_HW_FAILURE = UInt("b10")
// This is used outside this block
// to indicate 'busy'.
def db_RESP_RESERVED = UInt("b11")
}
object DsbBusConsts {
def sbAddrWidth = 12
def sbIdWidth = 10
//These are the default ROM contents, which support RV32 and RV64.
// See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S
// The code assumes 64 bytes of Debug RAM.
def xlenAnyRomContents : Array[Byte] = Array(
0x6f, 0x00, 0xc0, 0x04, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff,
0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f,
0xf3, 0x24, 0x00, 0xf1, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0x43,
0x6f, 0x00, 0x80, 0x00, 0x83, 0x34, 0x80, 0x43, 0x23, 0x2e, 0x80, 0x42,
0x73, 0x24, 0x40, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b,
0x13, 0x74, 0x84, 0x00, 0x63, 0x12, 0x04, 0x04, 0x73, 0x24, 0x20, 0x7b,
0x73, 0x00, 0x20, 0x7b, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b,
0x13, 0x74, 0x04, 0x1c, 0x13, 0x04, 0x04, 0xf4, 0x63, 0x1e, 0x04, 0x00,
0x73, 0x24, 0x00, 0xf1, 0x63, 0x46, 0x04, 0x00, 0x23, 0x2e, 0x90, 0x42,
0x67, 0x00, 0x00, 0x40, 0x23, 0x3c, 0x90, 0x42, 0x67, 0x00, 0x00, 0x40,
0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10, 0x73, 0x60, 0x04, 0x7b,
0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02, 0xe3, 0x0c, 0x04, 0xfe,
0x6f, 0xf0, 0x1f, 0xfd).map(_.toByte)
// These ROM contents support only RV32
// See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S
// The code assumes only 28 bytes of Debug RAM.
def xlen32OnlyRomContents : Array[Byte] = Array(
0x6f, 0x00, 0xc0, 0x03, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff,
0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f,
0x83, 0x24, 0x80, 0x41, 0x23, 0x2c, 0x80, 0x40, 0x73, 0x24, 0x40, 0xf1,
0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x84, 0x00,
0x63, 0x1a, 0x04, 0x02, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b,
0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x1c,
0x13, 0x04, 0x04, 0xf4, 0x63, 0x16, 0x04, 0x00, 0x23, 0x2c, 0x90, 0x40,
0x67, 0x00, 0x00, 0x40, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10,
0x73, 0x60, 0x04, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02,
0xe3, 0x0c, 0x04, 0xfe, 0x6f, 0xf0, 0x1f, 0xfe).map(_.toByte)
// These ROM contents support only RV64
// See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S
// The code assumes 64 bytes of Debug RAM.
def xlen64OnlyRomContents : Array[Byte] = Array(
0x6f, 0x00, 0xc0, 0x03, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff,
0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f,
0x83, 0x34, 0x80, 0x43, 0x23, 0x2e, 0x80, 0x42, 0x73, 0x24, 0x40, 0xf1,
0x23, 0x20, 0x80, 0x10, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x84, 0x00,
0x63, 0x1a, 0x04, 0x02, 0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b,
0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x1c,
0x13, 0x04, 0x04, 0xf4, 0x63, 0x16, 0x04, 0x00, 0x23, 0x3c, 0x90, 0x42,
0x67, 0x00, 0x00, 0x40, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x26, 0x80, 0x10,
0x73, 0x60, 0x04, 0x7b, 0x73, 0x24, 0x00, 0x7b, 0x13, 0x74, 0x04, 0x02,
0xe3, 0x0c, 0x04, 0xfe, 0x6f, 0xf0, 0x1f, 0xfe).map(_.toByte)
}
object DsbRegAddrs{
def CLEARDEBINT = 0x100
def SETHALTNOT = 0x10C
def SERINFO = 0x110
def SERBASE = 0x114
// For each serial, there are
// 3 registers starting here:
// SERSEND0
// SERRECEIVE0
// SERSTATUS0
// ...
// SERSTATUS7
def SERTX_OFFSET = 0
def SERRX_OFFSET = 4
def SERSTAT_OFFSET = 8
def RAMBASE = 0x400
def ROMBASE = 0x800
}
// *****************************************
// Configuration & Parameters for this Module
//
// *****************************************
/** Enumerations used both in the hardware
* and in the configuration specification.
*/
object DebugModuleAuthType extends scala.Enumeration {
type DebugModuleAuthType = Value
val None, Password, ChallengeResponse, Reserved = Value
}
import DebugModuleAuthType._
object DebugModuleAccessType extends scala.Enumeration {
type DebugModuleAccessType = Value
val Access8Bit, Access16Bit, Access32Bit, Access64Bit, Access128Bit = Value
}
import DebugModuleAccessType._
/** Parameters exposed to the top-level design, set based on
* external requirements, etc.
*
* This object checks that the parameters conform to the
* full specification. The implementation which receives this
* object can perform more checks on what that implementation
* actually supports.
* nComponents : The number of components to support debugging.
* nDebugBusAddrSize : Size of the Debug Bus Address
* nDebugRam Bytes: Size of the Debug RAM (depends on the XLEN of the machine).
* debugRomContents: Optional Sequence of bytes which form the Debug ROM contents.
* hasBusMaster: Whether or not a bus master should be included
* The size of the accesses supported by the Bus Master.
* nSerialPorts : Number of serial ports to instantiate
* authType : The Authorization Type
* Number of cycles to assert ndreset when pulsed.
**/
case class DebugModuleConfig (
nComponents : Int,
nDebugBusAddrSize : Int,
nDebugRamBytes : Int,
debugRomContents : Option[Seq[Byte]],
hasBusMaster : Boolean,
hasAccess128 : Boolean,
hasAccess64 : Boolean,
hasAccess32 : Boolean,
hasAccess16 : Boolean,
hasAccess8 : Boolean,
nSerialPorts : Int,
authType : DebugModuleAuthType,
nNDResetCycles : Int
) {
if (hasBusMaster == false){
require (hasAccess128 == false)
require (hasAccess64 == false)
require (hasAccess32 == false)
require (hasAccess16 == false)
require (hasAccess8 == false)
}
require (nSerialPorts <= 8)
require ((nDebugBusAddrSize >= 5) && (nDebugBusAddrSize <= 7))
private val maxComponents = nDebugBusAddrSize match {
case 5 => (32*4)
case 6 => (32*32)
case 7 => (32*32)
}
require (nComponents > 0 && nComponents <= maxComponents)
private val maxRam = nDebugBusAddrSize match {
case 5 => (4 * 16)
case 6 => (4 * 16)
case 7 => (4 * 64)
}
require (nDebugRamBytes > 0 && nDebugRamBytes <= maxRam)
val hasHaltSum = (nComponents > 64) || (nSerialPorts > 0)
val hasDebugRom = debugRomContents.nonEmpty
if (hasDebugRom) {
require (debugRomContents.get.size > 0)
require (debugRomContents.get.size <= 512)
}
require (nNDResetCycles > 0)
}
class DefaultDebugModuleConfig (val ncomponents : Int, val xlen:Int)
extends DebugModuleConfig(
nComponents = ncomponents,
nDebugBusAddrSize = 5,
// While smaller numbers are theoretically
// possible as noted in the Spec,
// the ROM image would need to be
// adjusted accordingly.
nDebugRamBytes = xlen match{
case 32 => 28
case 64 => 64
case 128 => 64
},
debugRomContents = xlen match {
case 32 => Some(DsbBusConsts.xlen32OnlyRomContents)
case 64 => Some(DsbBusConsts.xlen64OnlyRomContents)
},
hasBusMaster = false,
hasAccess128 = false,
hasAccess64 = false,
hasAccess32 = false,
hasAccess16 = false,
hasAccess8 = false,
nSerialPorts = 0,
authType = DebugModuleAuthType.None,
nNDResetCycles = 1)
case object DMKey extends Field[DebugModuleConfig]
// *****************************************
// Module Interfaces
//
// *****************************************
/** Structure to define the contents of a Debug Bus Request
*/
class DebugBusReq(addrBits : Int) extends Bundle {
val addr = UInt(width = addrBits)
val data = UInt(width = DbBusConsts.dbDataSize)
val op = UInt(width = DbBusConsts.dbOpSize)
override def cloneType = new DebugBusReq(addrBits).asInstanceOf[this.type]
}
/** Structure to define the contents of a Debug Bus Response
*/
class DebugBusResp( ) extends Bundle {
val data = UInt(width = DbBusConsts.dbDataSize)
val resp = UInt(width = DbBusConsts.dbRespSize)
}
/** Structure to define the top-level DebugBus interface
* of DebugModule.
* DebugModule is the consumer of this interface.
* Therefore it has the 'flipped' version of this.
*/
class DebugBusIO(implicit val p: Parameters) extends ParameterizedBundle()(p) {
val req = new DecoupledIO(new DebugBusReq(p(DMKey).nDebugBusAddrSize))
val resp = new DecoupledIO(new DebugBusResp).flip()
}
class AsyncDebugBusIO(implicit val p: Parameters) extends ParameterizedBundle()(p) {
val req = new AsyncBundle(1, new DebugBusReq(p(DMKey).nDebugBusAddrSize))
val resp = new AsyncBundle(1, new DebugBusResp).flip
}
object FromAsyncDebugBus
{
def apply(x: AsyncDebugBusIO) = {
val out = Wire(new DebugBusIO()(x.p))
out.req <> FromAsyncBundle(x.req)
x.resp <> ToAsyncBundle(out.resp, 1)
out
}
}
object ToAsyncDebugBus
{
def apply(x: DebugBusIO) = {
val out = Wire(new AsyncDebugBusIO()(x.p))
out.req <> ToAsyncBundle(x.req, 1)
x.resp <> FromAsyncBundle(out.resp)
out
}
}
trait HasDebugModuleParameters {
implicit val p: Parameters
val cfg = p(DMKey)
}
/** Debug Module I/O, with the exclusion of the RegisterRouter
* Access interface.
*/
trait DebugModuleBundle extends Bundle with HasDebugModuleParameters {
val db = new DebugBusIO()(p).flip()
val debugInterrupts = Vec(cfg.nComponents, Bool()).asOutput
val ndreset = Bool(OUTPUT)
val fullreset = Bool(OUTPUT)
}
// *****************************************
// The Module
//
// *****************************************
/** Parameterized version of the Debug Module defined in the
* RISC-V Debug Specification
*
* DebugModule is a slave to two masters:
* The Debug Bus -- implemented as a generic Decoupled IO with request
* and response channels
* The System Bus -- implemented as generic RegisterRouter
*
* DebugModule is responsible for holding registers, RAM, and ROM
* to support debug interactions, as well as driving interrupts
* to a configurable number of components in the system.
* It is also responsible for some reset lines.
*/
trait DebugModule extends Module with HasDebugModuleParameters with HasRegMap {
val io: DebugModuleBundle
//--------------------------------------------------------------
// Import constants for shorter variable names
//--------------------------------------------------------------
import DbRegAddrs._
import DsbRegAddrs._
import DsbBusConsts._
import DbBusConsts._
//--------------------------------------------------------------
// Sanity Check Configuration For this implementation.
//--------------------------------------------------------------
require (cfg.nComponents <= 128)
require (cfg.nSerialPorts == 0)
require (cfg.hasBusMaster == false)
require (cfg.nDebugRamBytes <= 64)
require (cfg.authType == DebugModuleAuthType.None)
require((DbBusConsts.dbRamWordBits % 8) == 0)
//--------------------------------------------------------------
// Private Classes (Register Fields)
//--------------------------------------------------------------
class RAMFields() extends Bundle {
val interrupt = Bool()
val haltnot = Bool()
val data = Bits(width = 32)
override def cloneType = new RAMFields().asInstanceOf[this.type]
}
class CONTROLFields() extends Bundle {
val interrupt = Bool()
val haltnot = Bool()
val reserved0 = Bits(width = 31-22 + 1)
val buserror = Bits(width = 3)
val serial = Bits(width = 3)
val autoincrement = Bool()
val access = UInt(width = 3)
val hartid = Bits(width = 10)
val ndreset = Bool()
val fullreset = Bool()
override def cloneType = new CONTROLFields().asInstanceOf[this.type]
}
class DMINFOFields() extends Bundle {
val reserved0 = Bits(width = 2)
val abussize = UInt(width = 7)
val serialcount = UInt(width = 4)
val access128 = Bool()
val access64 = Bool()
val access32 = Bool()
val access16 = Bool()
val accesss8 = Bool()
val dramsize = UInt(width = 6)
val haltsum = Bool()
val reserved1 = Bits(width = 3)
val authenticated = Bool()
val authbusy = Bool()
val authtype = UInt(width = 2)
val version = UInt(width = 2)
override def cloneType = new DMINFOFields().asInstanceOf[this.type]
}
class HALTSUMFields() extends Bundle {
val serialfull = Bool()
val serialvalid = Bool()
val acks = Bits(width = 32)
override def cloneType = new HALTSUMFields().asInstanceOf[this.type]
}
//--------------------------------------------------------------
// Register & Wire Declarations
//--------------------------------------------------------------
// --- Debug Bus Registers
val CONTROLReset = Wire(new CONTROLFields())
val CONTROLWrEn = Wire(Bool())
val CONTROLReg = Reg(new CONTROLFields())
val CONTROLWrData = Wire (new CONTROLFields())
val CONTROLRdData = Wire (new CONTROLFields())
val ndresetCtrReg = Reg(UInt(cfg.nNDResetCycles))
val DMINFORdData = Wire (new DMINFOFields())
val HALTSUMRdData = Wire (new HALTSUMFields())
val RAMWrData = Wire (new RAMFields())
val RAMRdData = Wire (new RAMFields())
// --- System Bus Registers
val SETHALTNOTWrEn = Wire(Bool())
val SETHALTNOTWrData = Wire(UInt(width = sbIdWidth))
val CLEARDEBINTWrEn = Wire(Bool())
val CLEARDEBINTWrData = Wire(UInt(width = sbIdWidth))
// --- Interrupt & Halt Notification Registers
val interruptRegs = Reg(init=Vec.fill(cfg.nComponents){Bool(false)})
val haltnotRegs = Reg(init=Vec.fill(cfg.nComponents){Bool(false)})
val numHaltnotStatus = ((cfg.nComponents - 1) / 32) + 1
val haltnotStatus = Wire(Vec(numHaltnotStatus, Bits(width = 32)))
val rdHaltnotStatus = Wire(Bits(width = 32))
val haltnotSummary = Cat(haltnotStatus.map(_.orR).reverse)
// --- Debug RAM
val ramDataWidth = DbBusConsts.dbRamWordBits
val ramDataBytes = ramDataWidth / 8;
val ramAddrWidth = log2Up(cfg.nDebugRamBytes / ramDataBytes)
val ramMem = Reg(init = Vec.fill(cfg.nDebugRamBytes){UInt(0, width = 8)})
val dbRamAddr = Wire(UInt(width=ramAddrWidth))
val dbRamAddrValid = Wire(Bool())
val dbRamRdData = Wire (UInt(width=ramDataWidth))
val dbRamWrData = Wire(UInt(width=ramDataWidth))
val dbRamWrEn = Wire(Bool())
val dbRamRdEn = Wire(Bool())
val dbRamWrEnFinal = Wire(Bool())
val dbRamRdEnFinal = Wire(Bool())
require((cfg.nDebugRamBytes % ramDataBytes) == 0)
val dbRamDataOffset = log2Up(ramDataBytes)
// --- Debug Bus Accesses
val dbRdEn = Wire(Bool())
val dbWrEn = Wire(Bool())
val dbRdData = Wire(UInt(width = DbBusConsts.dbDataSize))
val s_DB_READY :: s_DB_RESP :: Nil = Enum(Bits(), 2)
val dbStateReg = Reg(init = s_DB_READY)
val dbResult = Wire(io.db.resp.bits)
val dbReq = Wire(io.db.req.bits)
val dbRespReg = Reg(io.db.resp.bits)
val rdCondWrFailure = Wire(Bool())
val dbWrNeeded = Wire(Bool())
//--------------------------------------------------------------
// Interrupt Registers
//--------------------------------------------------------------
for (component <- 0 until cfg.nComponents) {
io.debugInterrupts(component) := interruptRegs(component)
}
// Interrupt Registers are written by write to CONTROL or debugRAM addresses
// for Debug Bus, and cleared by writes to CLEARDEBINT by System Bus.
// It is "unspecified" what should happen if both
// SET and CLEAR happen at the same time. In this
// implementation, the SET wins.
for (component <- 0 until cfg.nComponents) {
when (CONTROLWrEn) {
when (CONTROLWrData.hartid === UInt(component)) {
interruptRegs(component) := interruptRegs(component) | CONTROLWrData.interrupt
}
}.elsewhen (dbRamWrEn) {
when (CONTROLReg.hartid === UInt(component)){
interruptRegs(component) := interruptRegs(component) | RAMWrData.interrupt
}
}.elsewhen (CLEARDEBINTWrEn){
when (CLEARDEBINTWrData === UInt(component, width = sbIdWidth)) {
interruptRegs(component) := Bool(false)
}
}
}
//--------------------------------------------------------------
// Halt Notification Registers
//--------------------------------------------------------------
// Halt Notifications Registers are cleared by zero write to CONTROL or debugRAM addresses
// for Debug Bus, and set by write to SETHALTNOT by System Bus.
// It is "unspecified" what should happen if both
// SET and CLEAR happen at the same time. In this
// implementation, the SET wins.
for (component <- 0 until cfg.nComponents) {
when (SETHALTNOTWrEn){
when (SETHALTNOTWrData === UInt(component, width = sbIdWidth)) {
haltnotRegs(component) := Bool(true)
}
} .elsewhen (CONTROLWrEn) {
when (CONTROLWrData.hartid === UInt(component)) {
haltnotRegs(component) := haltnotRegs(component) & CONTROLWrData.haltnot
}
}.elsewhen (dbRamWrEn) {
when (CONTROLReg.hartid === UInt(component)){
haltnotRegs(component) := haltnotRegs(component) & RAMWrData.haltnot
}
}
}
for (ii <- 0 until numHaltnotStatus) {
haltnotStatus(ii) := Cat(haltnotRegs.slice(ii * 32, (ii + 1) * 32).reverse)
}
//--------------------------------------------------------------
// Other Registers
//--------------------------------------------------------------
CONTROLReset.interrupt := Bool(false)
CONTROLReset.haltnot := Bool(false)
CONTROLReset.reserved0 := Bits(0)
CONTROLReset.buserror := Bits(0)
CONTROLReset.serial := Bits(0)
CONTROLReset.autoincrement := Bool(false)
CONTROLReset.access := UInt(DebugModuleAccessType.Access32Bit.id)
CONTROLReset.hartid := Bits(0)
CONTROLReset.ndreset := Bool(false)
CONTROLReset.fullreset := Bool(false)
// Because this version of DebugModule doesn't
// support authentication, this entire register is
// Read-Only constant wires.
DMINFORdData.reserved0 := Bits(0)
DMINFORdData.abussize := UInt(0) // Not Implemented.
DMINFORdData.serialcount := UInt(cfg.nSerialPorts)
DMINFORdData.access128 := Bool(cfg.hasAccess128)
DMINFORdData.access64 := Bool(cfg.hasAccess64)
DMINFORdData.access32 := Bool(cfg.hasAccess32)
DMINFORdData.access16 := Bool(cfg.hasAccess16)
DMINFORdData.accesss8 := Bool(cfg.hasAccess8)
DMINFORdData.dramsize := Bits((cfg.nDebugRamBytes >> 2) - 1) // Size in 32-bit words minus 1.
DMINFORdData.haltsum := Bool(cfg.hasHaltSum)
DMINFORdData.reserved1 := Bits(0)
DMINFORdData.authenticated := Bool(true) // Not Implemented.
DMINFORdData.authbusy := Bool(false) // Not Implemented.
DMINFORdData.authtype := UInt(cfg.authType.id)
DMINFORdData.version := UInt(1) // Conforms to RISC-V Debug Spec
HALTSUMRdData.serialfull := Bool(false) // Not Implemented
HALTSUMRdData.serialvalid := Bool(false) // Not Implemented
HALTSUMRdData.acks := haltnotSummary
//--------------------------------------------------------------
// Debug RAM Access (Debug Bus ... System Bus can override)
//--------------------------------------------------------------
dbReq := io.db.req.bits
// Debug Bus RAM Access
// From Specification: Debug RAM is 0x00 - 0x0F
// 0x40 - 0x6F Not Implemented
dbRamAddr := dbReq.addr( ramAddrWidth-1 , 0)
dbRamWrData := dbReq.data
dbRamAddrValid := (dbReq.addr(3,0) <= UInt((cfg.nDebugRamBytes/ramDataBytes)))
val dbRamRdDataFields = List.tabulate(cfg.nDebugRamBytes / ramDataBytes) { ii =>
val slice = ramMem.slice(ii * ramDataBytes, (ii+1)*ramDataBytes)
slice.reduce[UInt]{ case (x: UInt, y: UInt) => Cat(y, x)}
}
dbRamRdData := dbRamRdDataFields(dbRamAddr)
when (dbRamWrEnFinal) {
for (ii <- 0 until ramDataBytes) {
ramMem((dbRamAddr << UInt(dbRamDataOffset)) + UInt(ii)) := dbRamWrData((8*(ii+1)-1), (8*ii))
}
}
//--------------------------------------------------------------
// Debug Bus Access
//--------------------------------------------------------------
// 0x00 - 0x0F Debug RAM
// 0x10 - 0x1B Registers
// 0x1C - 0x3B Halt Notification Registers
// 0x3C - 0x3F Registers
// 0x40 - 0x6F Debug RAM
// -----------------------------------------
// DB Access Write Decoder
CONTROLWrData := new CONTROLFields().fromBits(dbReq.data)
RAMWrData := new RAMFields().fromBits(dbReq.data)
dbRamWrEn := Bool(false)
dbRamWrEnFinal := Bool(false)
CONTROLWrEn := Bool(false)
when ((dbReq.addr >> 4) === Bits(0)) { // 0x00 - 0x0F Debug RAM
dbRamWrEn := dbWrEn
when (dbRamAddrValid) {
dbRamWrEnFinal := dbWrEn
}
}.elsewhen (dbReq.addr === DMCONTROL) {
CONTROLWrEn := dbWrEn
}.otherwise {
//Other registers/RAM are Not Implemented.
}
when (reset) {
CONTROLReg := CONTROLReset
ndresetCtrReg := UInt(0)
}.elsewhen (CONTROLWrEn) {
// interrupt handled in other logic
// haltnot handled in other logic
if (cfg.hasBusMaster){
// buserror is set 'until 0 is written to any bit in this field'.
CONTROLReg.buserror := Mux(CONTROLWrData.buserror.andR, CONTROLReg.buserror, UInt(0))
CONTROLReg.autoincrement := CONTROLWrData.autoincrement
CONTROLReg.access := CONTROLWrData.access
}
if (cfg.nSerialPorts > 0){
CONTROLReg.serial := CONTROLWrData.serial
}
CONTROLReg.hartid := CONTROLWrData.hartid
CONTROLReg.fullreset := CONTROLReg.fullreset | CONTROLWrData.fullreset
when (CONTROLWrData.ndreset){
ndresetCtrReg := UInt(cfg.nNDResetCycles)
}.otherwise {
ndresetCtrReg := Mux(ndresetCtrReg === UInt(0) , UInt(0), ndresetCtrReg - UInt(1))
}
}.otherwise {
ndresetCtrReg := Mux(ndresetCtrReg === UInt(0) , UInt(0), ndresetCtrReg - UInt(1))
}
// -----------------------------------------
// DB Access Read Mux
CONTROLRdData := CONTROLReg;
CONTROLRdData.interrupt := interruptRegs(CONTROLReg.hartid)
CONTROLRdData.haltnot := haltnotRegs(CONTROLReg.hartid)
CONTROLRdData.ndreset := ndresetCtrReg.orR
RAMRdData.interrupt := interruptRegs(CONTROLReg.hartid)
RAMRdData.haltnot := haltnotRegs(CONTROLReg.hartid)
RAMRdData.data := dbRamRdData
dbRdData := UInt(0)
// Higher numbers of numHaltnotStatus Not Implemented.
// This logic assumes only up to 128 components.
rdHaltnotStatus := Bits(0)
for (ii <- 0 until numHaltnotStatus) {
when (dbReq.addr(1, 0) === UInt(ii)) {
rdHaltnotStatus := haltnotStatus(ii)
}
}
dbRamRdEn := Bool(false)
dbRamRdEnFinal := Bool(false)
when ((dbReq.addr >> 4) === Bits(0)) { // 0x00 - 0x0F Debug RAM
dbRamRdEn := dbRdEn
when (dbRamAddrValid) {
dbRdData := RAMRdData.asUInt
dbRamRdEnFinal := dbRdEn
}
}.elsewhen (dbReq.addr === DMCONTROL) {
dbRdData := CONTROLRdData.asUInt
}.elsewhen (dbReq.addr === DMINFO) {
dbRdData := DMINFORdData.asUInt
}.elsewhen (dbReq.addr === HALTSUM) {
if (cfg.hasHaltSum){
dbRdData := HALTSUMRdData.asUInt
} else {
dbRdData := UInt(0)
}
}.elsewhen ((dbReq.addr >> 2) === UInt(7)) { // 0x1C - 0x1F Haltnot
dbRdData := rdHaltnotStatus
} .otherwise {
//These Registers are not implemented in this version of DebugModule:
// AUTHDATA0
// AUTHDATA1
// SERDATA
// SERSTATUS
// SBUSADDRESS0
// SBUSADDRESS1
// SBDATA0
// SBDATA1
// SBADDRESS2
// SBDATA2
// SBDATA3
// 0x20 - 0x3B haltnot
// Upper bytes of Debug RAM.
dbRdData := UInt(0)
}
// Conditional write fails if MSB is set of the read data.
rdCondWrFailure := dbRdData(dbDataSize - 1 ) &&
(dbReq.op === db_OP_READ_COND_WRITE)
dbWrNeeded := (dbReq.op === db_OP_READ_WRITE) ||
((dbReq.op === db_OP_READ_COND_WRITE) && ~rdCondWrFailure)
// This is only relevant at end of s_DB_READ.
dbResult.resp := Mux(rdCondWrFailure,
db_RESP_FAILURE,
db_RESP_SUCCESS)
dbResult.data := dbRdData
// -----------------------------------------
// DB Access State Machine Decode (Combo)
io.db.req.ready := (dbStateReg === s_DB_READY) ||
(dbStateReg === s_DB_RESP && io.db.resp.fire())
io.db.resp.valid := (dbStateReg === s_DB_RESP)
io.db.resp.bits := dbRespReg
dbRdEn := io.db.req.fire()
dbWrEn := dbWrNeeded && io.db.req.fire()
// -----------------------------------------
// DB Access State Machine Update (Seq)
when (dbStateReg === s_DB_READY){
when (io.db.req.fire()){
dbStateReg := s_DB_RESP
dbRespReg := dbResult
}
} .elsewhen (dbStateReg === s_DB_RESP){
when (io.db.req.fire()){
dbStateReg := s_DB_RESP
dbRespReg := dbResult
}.elsewhen (io.db.resp.fire()){
dbStateReg := s_DB_READY
}
}
//--------------------------------------------------------------
// Debug ROM
//--------------------------------------------------------------
val romRegFields = if (cfg.hasDebugRom) {
cfg.debugRomContents.get.map( x => RegField.r(8, UInt(x.toInt & 0xFF)))
} else {
Seq(RegField(8))
}
//--------------------------------------------------------------
// System Bus Access
//--------------------------------------------------------------
// Local reg mapper function : Notify when written, but give the value.
def wValue (n: Int, value: UInt, set: Bool) : RegField = {
RegField(n, value, RegWriteFn((valid, data) => {set := valid ; value := data; Bool(true)}))
}
regmap(
CLEARDEBINT -> Seq(wValue(sbIdWidth, CLEARDEBINTWrData, CLEARDEBINTWrEn)),
SETHALTNOT -> Seq(wValue(sbIdWidth, SETHALTNOTWrData, SETHALTNOTWrEn)),
RAMBASE -> ramMem.map(x => RegField(8, x)),
ROMBASE -> romRegFields
)
//--------------------------------------------------------------
// Misc. Outputs
//--------------------------------------------------------------
io.ndreset := ndresetCtrReg.orR
io.fullreset := CONTROLReg.fullreset
}
/** Create a concrete TL2 Slave for the DebugModule RegMapper interface.
*
*/
class TLDebugModule(address: BigInt = 0)(implicit p: Parameters)
extends TLRegisterRouter(address, "debug", Nil, beatBytes=p(XLen)/8, executable=true)(
new TLRegBundle((), _ ) with DebugModuleBundle)(
new TLRegModule((), _, _) with DebugModule)
/** Synchronizers for DebugBus
*
*/
object AsyncDebugBusCrossing {
// takes from_source from the 'from' clock domain to the 'to' clock domain
def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, to_clock: Clock, to_reset: Bool, depth: Int = 1, sync: Int = 3) = {
val to_sink = Wire(new DebugBusIO()(from_source.p))
to_sink.req <> AsyncDecoupledCrossing(from_clock, from_reset, from_source.req, to_clock, to_reset, depth, sync)
from_source.resp <> AsyncDecoupledCrossing(to_clock, to_reset, to_sink.resp, from_clock, from_reset, depth, sync)
to_sink // is now to_source
}
}
object AsyncDebugBusFrom { // OutsideClockDomain
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, depth: Int = 1, sync: Int = 3): DebugBusIO = {
val scope = AsyncScope()
AsyncDebugBusCrossing(from_clock, from_reset, from_source, scope.clock, scope.reset, depth, sync)
}
}
object AsyncDebugBusTo { // OutsideClockDomain
// takes source from your clock domain and puts it into the 'to' clock domain
def apply(to_clock: Clock, to_reset: Bool, source: DebugBusIO, depth: Int = 1, sync: Int = 3): DebugBusIO = {
val scope = AsyncScope()
AsyncDebugBusCrossing(scope.clock, scope.reset, source, to_clock, to_reset, depth, sync)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
// This file was auto-generated by 'make publish' in debug/ directory.
package uncore.devices
object DebugRomContents {
def apply() : Array[Byte] = { Array (
0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x80, 0x03, 0x6f, 0x00, 0x00, 0x02,
0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1,
0x23, 0x20, 0x80, 0x10, 0x03, 0x04, 0x04, 0x40, 0x63, 0x18, 0x80, 0x00,
0x6f, 0xf0, 0x1f, 0xff, 0x23, 0x26, 0x00, 0x10, 0x73, 0x00, 0x10, 0x00,
0x73, 0x24, 0x20, 0x7b, 0x23, 0x22, 0x00, 0x10, 0x67, 0x00, 0x00, 0x30,
0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10,
0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b
).map(_.toByte) }
}

View File

@ -0,0 +1,72 @@
package uncore.devices
import Chisel._
// This file was auto-generated from the repository at https://github.com/sifive/riscv-debug-spec.git,
// 'make chisel'
object AC_RegAddrs {
}
class ACCESS_REGISTERFields extends Bundle {
/* This is 0 to indicate Access Register Command.
*/
val cmdtype = UInt(8.W)
val reserved0 = UInt(1.W)
/* 2: Access the lowest 32 bits of the register.
3: Access the lowest 64 bits of the register.
4: Access the lowest 128 bits of the register.
If \Fsize specifies a size larger than the register's actual size,
then the access must fail. If a register is accessible, then reads of \Fsize
less than or equal to the register's actual size must be supported.
*/
val size = UInt(3.W)
/* When 1, execute the program in the Program Buffer exactly once
before performing the transfer.
\textbf{WARNING: preexec is considered for removal.}
*/
val preexec = Bool()
/* When 1, execute the program in the Program Buffer exactly once
after performing the transfer, if any.
*/
val postexec = Bool()
/* 0: Don't do the operation specified by \Fwrite.
1: Do the operation specified by \Fwrite.
*/
val transfer = Bool()
/* When \Ftransfer is set:
0: Copy data from the specified register into {\tt arg0} portion
of {\tt data}.
1: Copy data from {\tt arg0} portion of {\tt data} into the
specified register.
*/
val write = Bool()
/* Number of the register to access, as described in Table~\ref{tab:regno}.
*/
val regno = UInt(16.W)
}
class QUICK_ACCESSFields extends Bundle {
/* This is 1 to indicate Quick Access command.
*/
val cmdtype = UInt(8.W)
val reserved0 = UInt(24.W)
}

View File

@ -0,0 +1,899 @@
package uncore.devices
import Chisel._
// This file was auto-generated from the repository at https://github.com/sifive/riscv-debug-spec.git,
// 'make chisel'
object DMI_RegAddrs {
/* The address of this register will not change in the future, because it
contains \Fversion. It has changed from version 0.11 of this spec.
This register reports status for the overall debug module
as well as the currently selected harts, as defined in \Fhasel.
*/
def DMI_DMSTATUS = 0x11
/* This register controls the overall debug module
as well as the currently selected harts, as defined in \Fhasel.
*/
def DMI_DMCONTROL = 0x10
/* This register gives information about the hart currently
selected by \Fhartsel.
This register is optional. If it is not present it should
read all-zero.
If this register is included, the debugger can do more with
the Program Buffer by writing programs which
explicitly access the {\tt data} and/or {\tt dscratch}
registers.
*/
def DMI_HARTINFO = 0x12
/* This register contains a summary of which harts are halted.
Each bit contains the logical OR of 32 halt bits. When there are a
large number of harts in the system, the debugger can first read this
register, and then read from the halt region (0x40--0x5f) to determine
which hart is the one that is halted.
*/
def DMI_HALTSUM = 0x13
/* This register selects which of the 32-bit portion of the hart array mask register
is accessible in \Rhawindow.
The hart array mask register provides a mask of all harts controlled by
the debug module. A hart is part of the currently selected harts if
the corresponding bit is set in the hart array mask register and
\Fhasel in \Rdmcontrol is 1, or if the hart is selected by \Fhartsel.
*/
def DMI_HAWINDOWSEL = 0x14
/* This register provides R/W access to a 32-bit portion of the
hart array mask register. The position of the window is determined by
\Rhawindowsel.
*/
def DMI_HAWINDOW = 0x15
def DMI_ABSTRACTCS = 0x16
/* Writes to this register cause the corresponding abstract command to be
executed.
Writing while an abstract command is executing causes \Fcmderr to be set.
If \Fcmderr is non-zero, writes to this register are ignored.
\begin{commentary}
\Fcmderr inhibits starting a new command to accommodate debuggers
that, for performance reasons, send several commands to be executed
in a row without checking \Fcmderr in between. They can safely do
so and check \Fcmderr at the end without worrying that one command
failed but then a later command (which might have depended on the
previous one succeeding) passed.
\end{commentary}
*/
def DMI_COMMAND = 0x17
/* This register is optional. Including it allows more efficient burst accesses.
Debugger can attempt to set bits and read them back to determine if the functionality is supported.
*/
def DMI_ABSTRACTAUTO = 0x18
/* The Configuration String is described in the RISC-V Priviledged Specification.
When {\tt cfgstrvalid} is set, reading this register returns bits 31:0 of the configuration
string address. Reading the other {\tt cfgstraddr} registers returns the upper bits of the
address.
When system bus mastering is implemented, this should be the
address that should be used with the System Bus Access module. Otherwise,
this should be the address that should be used to access the
config string when \Fhartsel=0.
If {\tt cfgstrvalid} is 0, then the {\tt cfgstraddr} registers
hold identifier information which is not
further specified in this document.
*/
def DMI_CFGSTRADDR0 = 0x19
def DMI_CFGSTRADDR1 = 0x1a
def DMI_CFGSTRADDR2 = 0x1b
def DMI_CFGSTRADDR3 = 0x1c
/* Basic read/write registers that may be read or changed by abstract
commands.
Accessing them while an abstract command is executing causes \Fcmderr
to be set.
The values in these registers may not be preserved after an abstract
command is executed. The only guarantees on their contents are the ones
offered by the command in question. If the command fails, no
assumptions can be made about the contents of these registers.
*/
def DMI_DATA0 = 0x04
def DMI_DATA1 = 0x05
def DMI_DATA2 = 0x06
def DMI_DATA3 = 0x07
def DMI_DATA4 = 0x08
def DMI_DATA5 = 0x09
def DMI_DATA6 = 0x0a
def DMI_DATA7 = 0x0b
def DMI_DATA8 = 0x0c
def DMI_DATA9 = 0x0d
def DMI_DATA10 = 0x0e
def DMI_DATA11 = 0x0f
/* The {\tt progbuf} registers provide read/write access to the optional
program buffer.
*/
def DMI_PROGBUF0 = 0x20
def DMI_PROGBUF1 = 0x21
def DMI_PROGBUF2 = 0x22
def DMI_PROGBUF3 = 0x23
def DMI_PROGBUF4 = 0x24
def DMI_PROGBUF5 = 0x25
def DMI_PROGBUF6 = 0x26
def DMI_PROGBUF7 = 0x27
def DMI_PROGBUF8 = 0x28
def DMI_PROGBUF9 = 0x29
def DMI_PROGBUF10 = 0x2a
def DMI_PROGBUF11 = 0x2b
def DMI_PROGBUF12 = 0x2c
def DMI_PROGBUF13 = 0x2d
def DMI_PROGBUF14 = 0x2e
def DMI_PROGBUF15 = 0x2f
/* This register serves as a 32-bit serial port to the authentication
module.
When \Fauthbusy is clear, the debugger can communicate with the
authentication module by reading or writing this register. There is no
separate mechanism to signal overflow/underflow.
*/
def DMI_AUTHDATA = 0x30
/* If \Fserialcount is 0, this register is not present.
*/
def DMI_SERCS = 0x34
/* If \Fserialcount is 0, this register is not present.
This register provides access to the write data queue of the serial port
selected by \Fserial in \Rsercs.
If the {\tt error} bit is not set and the queue is not full, a write to this register
adds the written data to the core-to-debugger queue.
Otherwise the {\tt error} bit is set and the write returns error.
A read to this register returns the last data written.
*/
def DMI_SERTX = 0x35
/* If \Fserialcount is 0, this register is not present.
This register provides access to the read data queues of the serial port
selected by \Fserial in \Rsercs.
If the {\tt error} bit is not set and the queue is not empty, a read from this register reads the
oldest entry in the debugger-to-core queue, and removes that entry from the queue.
Otherwise the {\tt error} bit is set and the read returns error.
*/
def DMI_SERRX = 0x36
def DMI_SBCS = 0x38
/* If \Fsbasize is 0, then this register is not present.
When the system bus master is busy,
writes to this register will return error
and \Fsberror is set.
If \Fsberror is 0 and \Fsbautoread is set then the system bus
master will start
to read after updating the address from \Faddress. The access size is
controlled by \Fsbaccess in \Rsbcs.
If \Fsbsingleread is set, the bit is cleared.
*/
def DMI_SBADDRESS0 = 0x39
def DMI_SBADDRESS1 = 0x3a
/* If \Fsbasize is less than 65, then this register is not present.
*/
def DMI_SBADDRESS2 = 0x3b
/* If all of the {\tt sbaccess} bits in \Rsbcs are 0, then this register
is not present.
If \Fsberror isn't 0 then accesses return error, and don't do anything
else.
Writes to this register:
1. If the bus master is busy then accesses set \Fsberror, return error,
and don't do anything else.
2. Update internal data.
3. Start a bus write of the internal data to the internal address.
4. If \Fsbautoincrement is set, increment the internal address.
Reads to this register:
1. If bits 31:0 of the internal data register haven't been updated
since the last time this register was read, then set \Fsberror, return
error, and don't do anything else.
2. ``Return'' the data.
3. If \Fsbautoincrement is set, increment the internal address.
4. If \Fsbautoread is set, start another system bus read.
*/
def DMI_SBDATA0 = 0x3c
/* If \Fsbaccesssixtyfour and \Fsbaccessonetwentyeight are 0, then this
register is not present.
*/
def DMI_SBDATA1 = 0x3d
/* This register only exists if \Fsbaccessonetwentyeight is 1.
*/
def DMI_SBDATA2 = 0x3e
/* This register only exists if \Fsbaccessonetwentyeight is 1.
*/
def DMI_SBDATA3 = 0x3f
}
class DMSTATUSFields extends Bundle {
val reserved0 = UInt(16.W)
/* This field is 1 when all currently selected harts do not exist in this system.
*/
val allnonexistent = Bool()
/* This field is 1 when any currently selected hart does not exist in this system.
*/
val anynonexistent = Bool()
/* This field is 1 when all currently selected harts are unavailable.
*/
val allunavail = Bool()
/* This field is 1 when any currently selected hart is unavailable.
*/
val anyunavail = Bool()
/* This field is 1 when all currently selected harts are running.
*/
val allrunning = Bool()
/* This field is 1 when any currently selected hart is running.
*/
val anyrunning = Bool()
/* This field is 1 when all currently selected harts are halted.
*/
val allhalted = Bool()
/* This field is 1 when any currently selected hart is halted.
*/
val anyhalted = Bool()
/* 0 when authentication is required before using the DM. 1 when the
authentication check has passed. On components that don't implement
authentication, this bit must be preset as 1.
*/
val authenticated = Bool()
/* 0: The authentication module is ready to process the next
read/write to \Rauthdata.
1: The authentication module is busy. Accessing \Rauthdata results
in unspecified behavior.
\Fauthbusy only becomes set in immediate response to an access to
\Rauthdata.
*/
val authbusy = Bool()
val reserved1 = UInt(1.W)
val cfgstrvalid = Bool()
/* Reserved for future use. Reads as 0.
*/
val versionhi = UInt(2.W)
/* 00: There is no Debug Module present.
01: There is a Debug Module and it conforms to version 0.11 of this
specification.
10: There is a Debug Module and it conforms to version 0.13 of this
specification.
11: Reserved for future use.
*/
val versionlo = UInt(2.W)
}
class DMCONTROLFields extends Bundle {
/* Halt request signal for all currently selected harts. When 1, the
hart will halt if it is not currently halted.
Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val haltreq = Bool()
/* Resume request signal for all currently selected harts. When 1,
the hart will resume if it is currently halted.
Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val resumereq = Bool()
/* This optional bit controls reset to all the currently selected harts.
To perform a reset the debugger writes 1, and then writes 0 to
deassert the reset signal.
If this feature is not implemented, the bit always stays 0, so
after writing 1 the debugger can read the register back to see if
the feature is supported.
Writes apply to the new value of \Fhartsel and \Fhasel.
*/
val hartreset = Bool()
val reserved0 = UInt(2.W)
/* Selects the definition of currently selected harts.
0: There is a single currently selected hart, that selected by \Fhartsel.
1: There may be multiple currently selected harts -- that selected by \Fhartsel,
plus those selected by the hart array mask register.
An implementation which does not implement the hart array mask register
should tie this field to 0. A debugger which wishes to use the hart array
mask register feature should set this bit and read back to see if the functionality
is supported.
*/
val hasel = Bool()
/* The DM-specific index of the hart to select. This hart is always part of the
currently selected harts.
*/
val hartsel = UInt(10.W)
val reserved1 = UInt(14.W)
/* This bit controls the reset signal from the DM to the rest of the
system. To perform a reset the debugger writes 1, and then writes 0
to deassert the reset.
*/
val ndmreset = Bool()
/* This bit serves as a reset signal for the Debug Module itself.
0: The module's state, including authentication mechanism,
takes its reset values (the \Fdmactive bit is the only bit which can
be written to something other than its reset value).
1: The module functions normally.
No other mechanism should exist that may result in resetting the
Debug Module after power up, including the platform's system reset
or Debug Transport reset signals.
A debugger should pulse this bit low to ensure that the Debug
Module is fully reset and ready to use.
Implementations may use this bit to aid debugging, for example by
preventing the Debug Module from being power gated while debugging
is active.
*/
val dmactive = Bool()
}
class HARTINFOFields extends Bundle {
val reserved0 = UInt(8.W)
/* Number of {\tt dscratch} registers available for the debugger
to use during program buffer execution, starting from \Rdscratchzero.
The debugger can make no assumptions about the contents of these
registers between commands.
*/
val nscratch = UInt(4.W)
val reserved1 = UInt(3.W)
/* 0: The {\tt data} registers are shadowed in the hart by CSR
registers. Each CSR register is XLEN bits in size, and corresponds
to a single argument, per Table~\ref{tab:datareg}.
1: The {\tt data} registers are shadowed in the hart's memory map.
Each register takes up 4 bytes in the memory map.
*/
val dataaccess = Bool()
/* If \Fdataaccess is 0: Number of CSR registers dedicated to
shadowing the {\tt data} registers.
If \Fdataaccess is 1: Number of 32-bit words in the memory map
dedicated to shadowing the {\tt data} registers.
*/
val datasize = UInt(4.W)
/* If \Fdataaccess is 0: The number of the first CSR dedicated to
shadowing the {\tt data} registers.
If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
registers are shadowed.
*/
val dataaddr = UInt(12.W)
}
class HALTSUMFields extends Bundle {
val halt1023_992 = Bool()
val halt991_960 = Bool()
val halt959_928 = Bool()
val halt927_896 = Bool()
val halt895_864 = Bool()
val halt863_832 = Bool()
val halt831_800 = Bool()
val halt799_768 = Bool()
val halt767_736 = Bool()
val halt735_704 = Bool()
val halt703_672 = Bool()
val halt671_640 = Bool()
val halt639_608 = Bool()
val halt607_576 = Bool()
val halt575_544 = Bool()
val halt543_512 = Bool()
val halt511_480 = Bool()
val halt479_448 = Bool()
val halt447_416 = Bool()
val halt415_384 = Bool()
val halt383_352 = Bool()
val halt351_320 = Bool()
val halt319_288 = Bool()
val halt287_256 = Bool()
val halt255_224 = Bool()
val halt223_192 = Bool()
val halt191_160 = Bool()
val halt159_128 = Bool()
val halt127_96 = Bool()
val halt95_64 = Bool()
val halt63_32 = Bool()
val halt31_0 = Bool()
}
class HAWINDOWSELFields extends Bundle {
val reserved0 = UInt(27.W)
val hawindowsel = UInt(5.W)
}
class HAWINDOWFields extends Bundle {
val maskdata = UInt(32.W)
}
class ABSTRACTCSFields extends Bundle {
val reserved0 = UInt(3.W)
/* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
TODO: Explain what can be done with each size of the buffer, to suggest
why you would want more or less words.
*/
val progsize = UInt(5.W)
val reserved1 = UInt(11.W)
/* 1: An abstract command is currently being executed.
This bit is set as soon as \Rcommand is written, and is
not cleared until that command has completed.
*/
val busy = Bool()
val reserved2 = UInt(1.W)
/* Gets set if an abstract command fails. The bits in this field remain set until
they are cleared by writing 1 to them. No abstract command is
started until the value is reset to 0.
0 (none): No error.
1 (busy): An abstract command was executing while \Rcommand or one
of the {\tt data} registers was accessed.
2 (not supported): The requested command is not supported. A
command that is not supported while the hart is running may be
supported when it is halted.
3 (exception): An exception occurred while executing the command
(eg. while executing the Program Buffer).
4 (halt/resume): An abstract command couldn't execute because the
hart wasn't in the expected state (running/halted).
7 (other): The command failed for another reason.
*/
val cmderr = UInt(3.W)
val reserved3 = UInt(3.W)
/* Number of {\tt data} registers that are implemented as part of the
abstract command interface. Valid sizes are 0 - 8.
*/
val datacount = UInt(5.W)
}
class COMMANDFields extends Bundle {
/* The type determines the overall functionality of this
abstract command.
*/
val cmdtype = UInt(8.W)
/* This field is interpreted in a command-specific manner,
described for each abstract command.
*/
val control = UInt(24.W)
}
class ABSTRACTAUTOFields extends Bundle {
/* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word
cause the command in \Rcommand to be executed again.
*/
val autoexecprogbuf = UInt(16.W)
val reserved0 = UInt(4.W)
/* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word
cause the command in \Rcommand to be executed again.
*/
val autoexecdata = UInt(12.W)
}
class CFGSTRADDR0Fields extends Bundle {
val addr = UInt(32.W)
}
class DATA0Fields extends Bundle {
val data = UInt(32.W)
}
class PROGBUF0Fields extends Bundle {
val data = UInt(32.W)
}
class AUTHDATAFields extends Bundle {
val data = UInt(32.W)
}
class SERCSFields extends Bundle {
/* Number of supported serial ports.
*/
val serialcount = UInt(4.W)
val reserved0 = UInt(1.W)
/* Select which serial port is accessed by \Rserrx and \Rsertx.
*/
val serial = UInt(3.W)
val error7 = Bool()
val valid7 = Bool()
val full7 = Bool()
val error6 = Bool()
val valid6 = Bool()
val full6 = Bool()
val error5 = Bool()
val valid5 = Bool()
val full5 = Bool()
val error4 = Bool()
val valid4 = Bool()
val full4 = Bool()
val error3 = Bool()
val valid3 = Bool()
val full3 = Bool()
val error2 = Bool()
val valid2 = Bool()
val full2 = Bool()
val error1 = Bool()
val valid1 = Bool()
val full1 = Bool()
/* 1 when the debugger-to-core queue for serial port 0 has
over or underflowed. This bit will remain set until it is reset by
writing 1 to this bit.
*/
val error0 = Bool()
/* 1 when the core-to-debugger queue for serial port 0 is not empty.
*/
val valid0 = Bool()
/* 1 when the debugger-to-core queue for serial port 0 is full.
*/
val full0 = Bool()
}
class SERTXFields extends Bundle {
val data = UInt(32.W)
}
class SERRXFields extends Bundle {
val data = UInt(32.W)
}
class SBCSFields extends Bundle {
val reserved0 = UInt(11.W)
/* When a 1 is written here, triggers a read at the address in {\tt
sbaddress} using the access size set by \Fsbaccess.
*/
val sbsingleread = Bool()
/* Select the access size to use for system bus accesses triggered by
writes to the {\tt sbaddress} registers or \Rsbdatazero.
0: 8-bit
1: 16-bit
2: 32-bit
3: 64-bit
4: 128-bit
If an unsupported system bus access size is written here,
the DM may not perform the access, or may perform the access
with any access size.
*/
val sbaccess = UInt(3.W)
/* When 1, the internal address value (used by the system bus master)
is incremented by the access size (in bytes) selected in \Fsbaccess
after every system bus access.
*/
val sbautoincrement = Bool()
/* When 1, every read from \Rsbdatazero automatically triggers a system
bus read at the new address.
*/
val sbautoread = Bool()
/* When the debug module's system bus
master causes a bus error, this field gets set. The bits in this
field remain set until they are cleared by writing 1 to them.
While this field is non-zero, no more system bus accesses can be
initiated by the debug module.
0: There was no bus error.
1: There was a timeout.
2: A bad address was accessed.
3: There was some other error (eg. alignment).
4: The system bus master was busy when a one of the
{\tt sbaddress} or {\tt sbdata} registers was written,
or the {\tt sbdata} register was read when it had
stale data.
*/
val sberror = UInt(3.W)
/* Width of system bus addresses in bits. (0 indicates there is no bus
access support.)
*/
val sbasize = UInt(7.W)
/* 1 when 128-bit system bus accesses are supported.
*/
val sbaccess128 = Bool()
/* 1 when 64-bit system bus accesses are supported.
*/
val sbaccess64 = Bool()
/* 1 when 32-bit system bus accesses are supported.
*/
val sbaccess32 = Bool()
/* 1 when 16-bit system bus accesses are supported.
*/
val sbaccess16 = Bool()
/* 1 when 8-bit system bus accesses are supported.
*/
val sbaccess8 = Bool()
}
class SBADDRESS0Fields extends Bundle {
/* Accesses bits 31:0 of the internal address.
*/
val address = UInt(32.W)
}
class SBADDRESS1Fields extends Bundle {
/* Accesses bits 63:32 of the internal address (if the system address
bus is that wide).
*/
val address = UInt(32.W)
}
class SBADDRESS2Fields extends Bundle {
/* Accesses bits 95:64 of the internal address (if the system address
bus is that wide).
*/
val address = UInt(32.W)
}
class SBDATA0Fields extends Bundle {
/* Accesses bits 31:0 of the internal data.
*/
val data = UInt(32.W)
}
class SBDATA1Fields extends Bundle {
/* Accesses bits 63:32 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}
class SBDATA2Fields extends Bundle {
/* Accesses bits 95:64 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}
class SBDATA3Fields extends Bundle {
/* Accesses bits 127:96 of the internal data (if the system bus is
that wide).
*/
val data = UInt(32.W)
}

View File

@ -56,7 +56,7 @@ case class TLManagerParameters(
// The device had better not support a transfer larger than it's alignment // The device had better not support a transfer larger than it's alignment
val minAlignment = address.map(_.alignment).min val minAlignment = address.map(_.alignment).min
require (minAlignment >= maxTransfer) require (minAlignment >= maxTransfer, "minAlignment (" + minAlignment + ") must be >= maxTransfer (" + maxTransfer + ")")
def toResource: ResourceAddress = { def toResource: ResourceAddress = {
ResourceAddress(address, ResourceAddress(address,

View File

@ -4,7 +4,7 @@
# Verilog sources # Verilog sources
bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \ bb_vsrcs = \
$(base_dir)/vsrc/jtag_vpi.v \ $(base_dir)/vsrc/jtag_vpi.v \
$(base_dir)/vsrc/ClockDivider2.v \ $(base_dir)/vsrc/ClockDivider2.v \
$(base_dir)/vsrc/AsyncResetReg.v \ $(base_dir)/vsrc/AsyncResetReg.v \

View File

@ -1,337 +0,0 @@
// See LICENSE.SiFive for license details.
module DebugTransportModuleJtag (
//JTAG Interface
jtag_TDI,
jtag_TDO,
jtag_TCK,
jtag_TMS,
jtag_TRST,
jtag_DRV_TDO,
dtm_req_valid,
dtm_req_ready,
dtm_req_bits,
dtm_resp_valid,
dtm_resp_ready,
dtm_resp_bits
);
//--------------------------------------------------------
// Parameter Declarations
parameter DEBUG_DATA_BITS = 34;
parameter DEBUG_ADDR_BITS = 5; // Spec allows values are 5-7
parameter DEBUG_OP_BITS = 2; // OP and RESP are the same size.
parameter JTAG_VERSION = 4'h1;
parameter JTAG_PART_NUM = 16'h0E31; // E31
parameter JTAG_MANUF_ID = 11'h489; // As Assigned by JEDEC
// Number of cycles which must remain in IDLE
// The software should handle even if the
// answer is actually higher than this, or
// the software may choose to ignore it entirely
// and just check for busy.
parameter DBUS_IDLE_CYCLES = 3'h5;
localparam IR_BITS = 5;
localparam DEBUG_VERSION = 0;
// JTAG State Machine
localparam TEST_LOGIC_RESET = 4'h0;
localparam RUN_TEST_IDLE = 4'h1;
localparam SELECT_DR = 4'h2;
localparam CAPTURE_DR = 4'h3;
localparam SHIFT_DR = 4'h4;
localparam EXIT1_DR = 4'h5;
localparam PAUSE_DR = 4'h6;
localparam EXIT2_DR = 4'h7;
localparam UPDATE_DR = 4'h8;
localparam SELECT_IR = 4'h9;
localparam CAPTURE_IR = 4'hA;
localparam SHIFT_IR = 4'hB;
localparam EXIT1_IR = 4'hC;
localparam PAUSE_IR = 4'hD;
localparam EXIT2_IR = 4'hE;
localparam UPDATE_IR = 4'hF;
//RISCV DTM Registers (see RISC-V Debug Specification)
// All others are treated as 'BYPASS'.
localparam REG_BYPASS = 5'b11111;
localparam REG_IDCODE = 5'b00001;
localparam REG_DEBUG_ACCESS = 5'b10001;
localparam REG_DTM_INFO = 5'b10000;
localparam DBUS_REG_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS;
localparam DBUS_REQ_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS;
localparam DBUS_RESP_BITS = DEBUG_OP_BITS + DEBUG_DATA_BITS;
localparam SHIFT_REG_BITS = DBUS_REG_BITS;
//--------------------------------------------------------
// I/O Declarations
//JTAG SIDE
input jtag_TDI;
output reg jtag_TDO;
input jtag_TCK;
input jtag_TMS;
input jtag_TRST;
// To allow tri-state outside of this block.
output reg jtag_DRV_TDO;
// RISC-V Core Side
output dtm_req_valid;
input dtm_req_ready;
output [DBUS_REQ_BITS - 1 :0] dtm_req_bits;
input dtm_resp_valid;
output dtm_resp_ready;
input [DBUS_RESP_BITS - 1 : 0] dtm_resp_bits;
//--------------------------------------------------------
// Reg and Wire Declarations
reg [IR_BITS -1 : 0 ] irReg;
wire [31:0] idcode;
wire [31:0] dtminfo;
reg [DBUS_REG_BITS - 1 : 0] dbusReg;
reg dbusValidReg;
reg [3:0] jtagStateReg;
reg [SHIFT_REG_BITS -1 : 0] shiftReg;
reg doDbusWriteReg;
reg doDbusReadReg;
reg busyReg;
reg stickyBusyReg;
reg stickyNonzeroRespReg;
reg skipOpReg; // Skip op because we're busy.
reg downgradeOpReg; // Downgrade op because prev. op failed.
wire busy;
wire nonzeroResp;
wire [SHIFT_REG_BITS -1 : 0] busyResponse;
wire [SHIFT_REG_BITS -1 : 0] nonbusyResponse;
//--------------------------------------------------------
// Combo Logic
assign idcode = {JTAG_VERSION, JTAG_PART_NUM, JTAG_MANUF_ID, 1'h1};
wire [3:0] debugAddrBits = DEBUG_ADDR_BITS[3:0];
wire [3:0] debugVersion = DEBUG_VERSION[3:0];
wire [1:0] dbusStatus;
wire [2:0] dbusIdleCycles;
wire dbusReset;
assign dbusIdleCycles = DBUS_IDLE_CYCLES;
assign dbusStatus = {stickyNonzeroRespReg, stickyNonzeroRespReg | stickyBusyReg};
assign dbusReset = shiftReg[16];
assign dtminfo = {15'b0,
1'b0, // dbusreset goes here but is write-only
3'b0,
dbusIdleCycles,
dbusStatus,
debugAddrBits,
debugVersion};
//busy, dtm_resp* is only valid during CAPTURE_DR,
// so these signals should only be used at that time.
// This assumes there is only one transaction in flight at a time.
assign busy = (busyReg & ~dtm_resp_valid) | stickyBusyReg;
// This is needed especially for the first request.
assign nonzeroResp = (dtm_resp_valid ? | {dtm_resp_bits[DEBUG_OP_BITS-1:0]} : 1'b0) | stickyNonzeroRespReg;
// Interface to DM.
// Note that this means dtm_resp_bits must only be used during CAPTURE_DR.
assign dtm_resp_ready = (jtagStateReg == CAPTURE_DR) &&
(irReg == REG_DEBUG_ACCESS) &&
dtm_resp_valid;
assign dtm_req_valid = dbusValidReg;
assign dtm_req_bits = dbusReg;
assign busyResponse = {{(DEBUG_ADDR_BITS + DEBUG_DATA_BITS){1'b0}},
{(DEBUG_OP_BITS){1'b1}}}; // Generalizing 'busy' to 'all-1'
assign nonbusyResponse = {dbusReg[(DEBUG_DATA_BITS + DEBUG_OP_BITS) +: DEBUG_ADDR_BITS] , // retain address bits from Req.
dtm_resp_bits[DEBUG_OP_BITS +: DEBUG_DATA_BITS] , // data
dtm_resp_bits[0 +: DEBUG_OP_BITS] // response
};
//--------------------------------------------------------
// Sequential Logic
// JTAG STATE MACHINE
always @(posedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
jtagStateReg <= TEST_LOGIC_RESET;
end else begin
case (jtagStateReg)
TEST_LOGIC_RESET : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
RUN_TEST_IDLE : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_DR : jtagStateReg <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
CAPTURE_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
SHIFT_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
EXIT1_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
PAUSE_DR : jtagStateReg <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
EXIT2_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
UPDATE_DR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
SELECT_IR : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
CAPTURE_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
SHIFT_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
EXIT1_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
PAUSE_IR : jtagStateReg <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
EXIT2_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
UPDATE_IR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
endcase // case (jtagStateReg)
end // else: !if(jtag_TRST)
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
// SHIFT REG
always @(posedge jtag_TCK) begin
case (jtagStateReg)
CAPTURE_IR : shiftReg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec only says must end with 'b01.
SHIFT_IR : shiftReg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_TDI, shiftReg[IR_BITS-1 : 1]};
CAPTURE_DR : case (irReg)
REG_BYPASS : shiftReg <= {(SHIFT_REG_BITS){1'b0}};
REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, idcode};
REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, dtminfo};
REG_DEBUG_ACCESS : shiftReg <= busy ? busyResponse : nonbusyResponse;
default : //BYPASS
shiftReg <= {(SHIFT_REG_BITS){1'b0}};
endcase
SHIFT_DR : case (irReg)
REG_BYPASS : shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}}, jtag_TDI};
REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]};
REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]};
REG_DEBUG_ACCESS : shiftReg <= {jtag_TDI, shiftReg[SHIFT_REG_BITS -1 : 1 ]};
default: // BYPASS
shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}} , jtag_TDI};
endcase // case (irReg)
endcase // case (jtagStateReg)
end
// IR
always @(negedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
irReg <= REG_IDCODE;
end else if (jtagStateReg == TEST_LOGIC_RESET) begin
irReg <= REG_IDCODE;
end else if (jtagStateReg == UPDATE_IR) begin
irReg <= shiftReg[IR_BITS-1:0];
end
end
// Busy. We become busy when we first try to send a request.
// We stop being busy when we accept a response.
// This means that busyReg will still be set when we check it,
// so the logic for checking busy looks ahead.
always @(posedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
busyReg <= 1'b0;
end else if (dtm_req_valid) begin //UPDATE_DR onwards
busyReg <= 1'b1;
end else if (dtm_resp_valid & dtm_resp_ready) begin //only in CAPTURE_DR
busyReg <= 1'b0;
end
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
// Downgrade/Skip. We make the decision to downgrade or skip
// during every CAPTURE_DR, and use the result in UPDATE_DR.
always @(posedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
skipOpReg <= 1'b0;
downgradeOpReg <= 1'b0;
stickyBusyReg <= 1'b0;
stickyNonzeroRespReg <= 1'b0;
end else if (irReg == REG_DEBUG_ACCESS) begin
case(jtagStateReg)
CAPTURE_DR: begin
skipOpReg <= busy;
downgradeOpReg <= (~busy & nonzeroResp);
stickyBusyReg <= busy;
stickyNonzeroRespReg <= nonzeroResp;
end
UPDATE_DR: begin
skipOpReg <= 1'b0;
downgradeOpReg <= 1'b0;
end
endcase // case (jtagStateReg)
end else if (irReg == REG_DTM_INFO) begin
case(jtagStateReg)
UPDATE_DR: begin
if (dbusReset) begin
stickyNonzeroRespReg <= 1'b0;
stickyBusyReg <= 1'b0;
end
end
endcase // case (jtagStateReg)
end
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
//dbusReg, dbusValidReg.
always @(posedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
dbusReg <= {(DBUS_REG_BITS) {1'b0}};
dbusValidReg <= 1'b0;
end else if (jtagStateReg == UPDATE_DR) begin
if (irReg == REG_DEBUG_ACCESS) begin
if (skipOpReg) begin
// do nothing.
end else if (downgradeOpReg) begin
dbusReg <= {(DBUS_REG_BITS){1'b0}}; // NOP has encoding 2'b00.
dbusValidReg <= 1'b1;
end else begin
dbusReg <= shiftReg[DBUS_REG_BITS-1:0];
dbusValidReg <= 1'b1;
end
end
end else if (dtm_req_ready) begin
dbusValidReg <= 1'b0;
end
end // always @ (negedge jtag_TCK or posedge jtag_TRST)
//TDO
always @(negedge jtag_TCK or posedge jtag_TRST) begin
if (jtag_TRST) begin
jtag_TDO <= 1'b0;
jtag_DRV_TDO <= 1'b0;
end else if (jtagStateReg == SHIFT_IR) begin
jtag_TDO <= shiftReg[0];
jtag_DRV_TDO <= 1'b1;
end else if (jtagStateReg == SHIFT_DR) begin
jtag_TDO <= shiftReg[0];
jtag_DRV_TDO <= 1'b1;
end else begin
jtag_TDO <= 1'b0;
jtag_DRV_TDO <= 1'b0;
end
end // always @ (negedge jtag_TCK or posedge jtag_TRST)
endmodule

View File

@ -6,12 +6,12 @@ import "DPI-C" function int debug_tick
input bit debug_req_ready, input bit debug_req_ready,
output int debug_req_bits_addr, output int debug_req_bits_addr,
output int debug_req_bits_op, output int debug_req_bits_op,
output longint debug_req_bits_data, output int debug_req_bits_data,
input bit debug_resp_valid, input bit debug_resp_valid,
output bit debug_resp_ready, output bit debug_resp_ready,
input int debug_resp_bits_resp, input int debug_resp_bits_resp,
input longint debug_resp_bits_data input int debug_resp_bits_data
); );
module SimDTM( module SimDTM(
@ -20,14 +20,14 @@ module SimDTM(
output debug_req_valid, output debug_req_valid,
input debug_req_ready, input debug_req_ready,
output [ 4:0] debug_req_bits_addr, output [ 6:0] debug_req_bits_addr,
output [ 1:0] debug_req_bits_op, output [ 1:0] debug_req_bits_op,
output [33:0] debug_req_bits_data, output [31:0] debug_req_bits_data,
input debug_resp_valid, input debug_resp_valid,
output debug_resp_ready, output debug_resp_ready,
input [ 1:0] debug_resp_bits_resp, input [ 1:0] debug_resp_bits_resp,
input [33:0] debug_resp_bits_data, input [31:0] debug_resp_bits_data,
output [31:0] exit output [31:0] exit
); );
@ -37,19 +37,19 @@ module SimDTM(
wire #0.1 __debug_req_ready = debug_req_ready; wire #0.1 __debug_req_ready = debug_req_ready;
wire #0.1 __debug_resp_valid = debug_resp_valid; wire #0.1 __debug_resp_valid = debug_resp_valid;
wire [31:0] #0.1 __debug_resp_bits_resp = {30'b0, debug_resp_bits_resp}; wire [31:0] #0.1 __debug_resp_bits_resp = {30'b0, debug_resp_bits_resp};
wire [63:0] #0.1 __debug_resp_bits_data = {30'b0, debug_resp_bits_data}; wire [31:0] #0.1 __debug_resp_bits_data = debug_resp_bits_data;
bit __debug_req_valid; bit __debug_req_valid;
int __debug_req_bits_addr; int __debug_req_bits_addr;
int __debug_req_bits_op; int __debug_req_bits_op;
longint __debug_req_bits_data; int __debug_req_bits_data;
bit __debug_resp_ready; bit __debug_resp_ready;
int __exit; int __exit;
assign #0.1 debug_req_valid = __debug_req_valid; assign #0.1 debug_req_valid = __debug_req_valid;
assign #0.1 debug_req_bits_addr = __debug_req_bits_addr[4:0]; assign #0.1 debug_req_bits_addr = __debug_req_bits_addr[6:0];
assign #0.1 debug_req_bits_op = __debug_req_bits_op[1:0]; assign #0.1 debug_req_bits_op = __debug_req_bits_op[1:0];
assign #0.1 debug_req_bits_data = __debug_req_bits_data[33:0]; assign #0.1 debug_req_bits_data = __debug_req_bits_data[31:0];
assign #0.1 debug_resp_ready = __debug_resp_ready; assign #0.1 debug_resp_ready = __debug_resp_ready;
assign #0.1 exit = __exit; assign #0.1 exit = __exit;

View File

@ -48,8 +48,9 @@ module JTAGVPI
output jtag_TMS, output jtag_TMS,
output jtag_TCK, output jtag_TCK,
output jtag_TDI, output jtag_TDI,
input jtag_TDO, input jtag_TDO_data,
input jtag_TRST, // unused input jtag_TDO_driven,
input enable, input enable,
input init_done); input init_done);
@ -61,8 +62,7 @@ module JTAGVPI
assign jtag_TMS = tms; assign jtag_TMS = tms;
assign jtag_TCK = tck; assign jtag_TCK = tck;
assign jtag_TDI = tdi; assign jtag_TDI = tdi;
assign tdo = jtag_TDO; assign tdo = jtag_TDO_driven ? jtag_TDO_data : 1'bz;
integer cmd; integer cmd;
integer length; integer length;