Merge branch 'master' into name-rams
This commit is contained in:
commit
b9550e8523
@ -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
|
||||||
|
@ -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
|
31
scripts/debug_rom/Makefile
Normal file
31
scripts/debug_rom/Makefile
Normal 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
76
scripts/debug_rom/debug_rom.S
Executable 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
16
scripts/debug_rom/link.ld
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* See LICENSE.SiFive for license details. */
|
||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
ENTRY( entry )
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.whereto 0x300 :
|
||||||
|
{
|
||||||
|
*(.whereto)
|
||||||
|
}
|
||||||
|
. = 0x800;
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
_end = .;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
1177
src/main/scala/uncore/devices/debug/Debug.scala
Normal file
1177
src/main/scala/uncore/devices/debug/Debug.scala
Normal file
File diff suppressed because it is too large
Load Diff
18
src/main/scala/uncore/devices/debug/DebugRomContents.scala
Normal file
18
src/main/scala/uncore/devices/debug/DebugRomContents.scala
Normal 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) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
72
src/main/scala/uncore/devices/debug/abstract_commands.scala
Normal file
72
src/main/scala/uncore/devices/debug/abstract_commands.scala
Normal 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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
899
src/main/scala/uncore/devices/debug/dm1_registers.scala
Normal file
899
src/main/scala/uncore/devices/debug/dm1_registers.scala
Normal 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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
@ -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 \
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user