1
0
rocket-chip/src/main/scala/uncore/devices/Debug.scala

872 lines
29 KiB
Scala

// See LICENSE for license details.
package uncore.devices
import Chisel._
import junctions._
import util._
import regmapper._
import uncore.tilelink2._
import cde.{Parameters, Config, Field}
// *****************************************
// 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: cde.Parameters) extends ParameterizedBundle()(p) {
val req = new DecoupledIO(new DebugBusReq(p(DMKey).nDebugBusAddrSize))
val resp = new DecoupledIO(new DebugBusResp).flip()
}
trait HasDebugModuleParameters {
val params : Parameters
implicit val p = params
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())
// --- 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 := Bool(true)
if (ramAddrWidth < 4){
dbRamAddrValid := (dbReq.addr(3, ramAddrWidth) === UInt(0))
}
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(ramDataBytes) + 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 === 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) {
// Inspired by ROMSlave
val romContents = cfg.debugRomContents.get
val romByteWidth = ramDataWidth / 8
val romRows = (romContents.size + romByteWidth - 1)/romByteWidth
List.tabulate(romRows) { ii => {
val slice = romContents.slice(ii*romByteWidth, (ii+1)*romByteWidth)
val line = UInt(slice.foldRight(BigInt(0)) { case (x,y) => ((y << 8) + (x.toInt & 0xFF))}, width = romByteWidth*8)
RegField.r(ramDataWidth, line)
}
}
} else {
Seq(RegField(ramDataWidth))
}
//--------------------------------------------------------------
// 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(beatBytes: Int) (implicit p: Parameters)
extends TLRegisterRouter(0x0, beatBytes=beatBytes)(
new TLRegBundle(p, _ ) with DebugModuleBundle)(
new TLRegModule(p, _, _) 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)
}
}