// See LICENSE for license details. package uncore import Chisel._ import junctions._ import cde.{Parameters, Config, Field} // ***************************************** // Constants which are interesting even // outside of this module // ***************************************** object DbRegAddrs{ 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 defaultRomContents : 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 = UInt(0x100) def SETHALTNOT = UInt(0x10C) def SERINFO = UInt(0x110) def SERBASE = UInt(0x114) // For each serial, there are // 3 registers starting here: // SERSEND0 // SERRECEIVE0 // SERSTATUS0 // ... // SERSTATUS7 def SERTX_OFFSET = UInt(0) def SERRX_OFFSET = UInt(4) def SERSTAT_OFFSET = UInt(8) } // ***************************************** // 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 match{ case Some(_) => true case None => false } if (hasDebugRom) { require (debugRomContents.size > 0) require (debugRomContents.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 op = UInt(width = DbBusConsts.dbOpSize) val data = UInt(width = DbBusConsts.dbDataSize) override def cloneType = new DebugBusReq(addrBits).asInstanceOf[this.type] } /** Structure to define the contents of a Debug Bus Response */ class DebugBusResp( ) extends Bundle { val resp = UInt(width = DbBusConsts.dbRespSize) val data = UInt(width = DbBusConsts.dbDataSize) } /** 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() } // ***************************************** // 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 Uncached Tile Link. * * 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. */ class DebugModule ()(implicit val p:cde.Parameters) extends Module with HasTileLinkParameters { val cfg = p(DMKey) //-------------------------------------------------------------- // 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) //-------------------------------------------------------------- // 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] } //-------------------------------------------------------------- // Module I/O //-------------------------------------------------------------- val io = new Bundle { val db = new DebugBusIO()(p).flip() val debugInterrupts = Vec(cfg.nComponents, Bool()).asOutput val tl = new ClientUncachedTileLinkIO().flip val ndreset = Bool(OUTPUT) val fullreset = Bool(OUTPUT) } //-------------------------------------------------------------- // 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 // Since the access size from Debug Bus and System Bus may not be consistent, // use the maximum to build the RAM, and then select as needed for the smaller // size. val dbRamDataWidth = DbBusConsts.dbRamWordBits val sbRamDataWidth = tlDataBits val dbRamAddrWidth = log2Up((cfg.nDebugRamBytes * 8) / dbRamDataWidth) val sbRamAddrWidth = log2Up((cfg.nDebugRamBytes * 8) / sbRamDataWidth) val sbRamAddrOffset = log2Up(tlDataBits/8) val ramDataWidth = dbRamDataWidth max sbRamDataWidth val ramAddrWidth = dbRamAddrWidth min sbRamAddrWidth val ramMem = Mem(1 << ramAddrWidth , UInt(width=ramDataWidth)) val ramAddr = Wire(UInt(width=ramAddrWidth)) val ramRdData = Wire(UInt(width=ramDataWidth)) val ramWrData = Wire(UInt(width=ramDataWidth)) val ramWrMask = Wire(UInt(width=ramDataWidth)) val ramWrEn = Wire(Bool()) val dbRamAddr = Wire(UInt(width=dbRamAddrWidth)) val dbRamRdData = Wire (UInt(width=dbRamDataWidth)) val dbRamWrData = Wire(UInt(width=dbRamDataWidth)) val dbRamWrEn = Wire(Bool()) val dbRamRdEn = Wire(Bool()) val sbRamAddr = Wire(UInt(width=sbRamAddrWidth)) val sbRamRdData = Wire (UInt(width=sbRamDataWidth)) val sbRamWrData = Wire(UInt(width=sbRamDataWidth)) val sbRamWrEn = Wire(Bool()) val sbRamRdEn = Wire(Bool()) val sbRomRdData = Wire(UInt(width=tlDataBits)) val sbRomAddrOffset = log2Up(tlDataBits/8) // --- 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()) // --- System Bus Access val sbAddr = Wire(UInt(width=sbAddrWidth)) val sbRdData = Wire(UInt(width=tlDataBits)) val sbWrData = Wire(UInt(width=tlDataBits)) val sbWrMask = Wire(UInt(width=tlDataBits)) val sbWrEn = Wire(Bool()) val sbRdEn = Wire(Bool()) val stallFromDb = Wire(Bool()) val stallFromSb = 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) //-------------------------------------------------------------- dbReq := io.db.req.bits // Debug Bus RAM Access // From Specification: Debug RAM is 0x00 - 0x0F // 0x40 - 0x6F Not Implemented dbRamAddr := dbReq.addr( dbRamAddrWidth-1 , 0) dbRamWrData := dbReq.data sbRamAddr := sbAddr(sbRamAddrWidth + sbRamAddrOffset - 1, sbRamAddrOffset) sbRamWrData := sbWrData require (dbRamAddrWidth >= ramAddrWidth) // SB accesses less than 32 bits Not Implemented. val dbRamWrMask = Wire(init=Vec.fill(1 << (dbRamAddrWidth - ramAddrWidth)){Fill(dbRamDataWidth, UInt(1, width=1))}) if (dbRamDataWidth < ramDataWidth){ val dbRamSel = dbRamAddr(dbRamAddrWidth - ramAddrWidth - 1 , 0) val rdDataWords = Vec.tabulate(1 << (dbRamAddrWidth - ramAddrWidth)){ ii => ramRdData((ii+1)*dbRamDataWidth - 1 , ii*dbRamDataWidth)} dbRamWrMask := Vec.fill(1 << (dbRamAddrWidth - ramAddrWidth)){UInt(0, width = dbRamDataWidth)} dbRamWrMask(dbRamSel) := Fill(dbRamDataWidth, UInt(1, width=1)) dbRamRdData := rdDataWords(dbRamSel) } else { dbRamRdData := ramRdData } sbRamRdData := ramRdData ramWrMask := Mux(sbRamWrEn, sbWrMask, dbRamWrMask.toBits()) assert (!((dbRamWrEn | dbRamRdEn) & (sbRamRdEn | sbRamWrEn)), "Stall logic should have prevented concurrent SB/DB RAM Access") // Make copies of DB RAM data before writing. val dbRamWrDataVec = Fill(1 << (dbRamAddrWidth - ramAddrWidth), dbRamWrData) ramWrData := Mux(sbRamWrEn, (ramWrMask & sbRamWrData ) | (~ramWrMask & ramRdData), (ramWrMask & dbRamWrDataVec.toBits) | (~ramWrMask & ramRdData)) ramAddr := Mux(sbRamWrEn | sbRamRdEn, sbRamAddr, dbRamAddr >> (dbRamAddrWidth - ramAddrWidth)) ramRdData := ramMem(ramAddr) when (ramWrEn) { ramMem(ramAddr) := ramWrData } ramWrEn := sbRamWrEn | dbRamWrEn //-------------------------------------------------------------- // 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) CONTROLWrEn := Bool(false) when ((dbReq.addr >> 4) === Bits(0)) { // 0x00 - 0x0F Debug RAM dbRamWrEn := 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 === SInt(-1).toBits), 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) when ((dbReq.addr >> 4) === Bits(0)) { // 0x00 - 0x0F Debug RAM dbRdData := RAMRdData.toBits() dbRamRdEn := dbRdEn }.elsewhen (dbReq.addr === DMCONTROL) { dbRdData := CONTROLRdData.toBits() }.elsewhen (dbReq.addr === DMINFO) { dbRdData := DMINFORdData.toBits() }.elsewhen (dbReq.addr === HALTSUM) { if (cfg.hasHaltSum){ dbRdData := HALTSUMRdData.toBits() } 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 := !stallFromSb && ((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 //-------------------------------------------------------------- sbRomRdData := UInt(0) if (cfg.hasDebugRom) { // Inspired by ROMSlave val romContents = cfg.debugRomContents.get val romByteWidth = tlDataBits / 8 val romRows = (romContents.size + romByteWidth - 1)/romByteWidth val romMem = Vec.tabulate(romRows) { ii => val slice = romContents.slice(ii*romByteWidth, (ii+1)*romByteWidth) UInt(slice.foldRight(BigInt(0)) { case (x,y) => ((y << 8) + (x.toInt & 0xFF))}, width = romByteWidth*8) } val sbRomRdAddr = Wire(UInt()) if (romRows == 1) { sbRomRdAddr := UInt(0) } else { sbRomRdAddr := sbAddr(log2Up(romRows) + sbRomAddrOffset - 1, sbRomAddrOffset) } sbRomRdData := romMem (sbRomRdAddr) } //-------------------------------------------------------------- // System Bus Access //-------------------------------------------------------------- // ----------------------------------------- // SB Access Write Decoder sbRamWrEn := Bool(false) SETHALTNOTWrEn := Bool(false) CLEARDEBINTWrEn := Bool(false) if (tlDataBits == 32) { SETHALTNOTWrData := sbWrData CLEARDEBINTWrData := sbWrData when (sbAddr(11, 8) === UInt(4)){ // 0x400-0x4ff is Debug RAM sbRamWrEn := sbWrEn sbRamRdEn := sbRdEn }.elsewhen (sbAddr === SETHALTNOT){ SETHALTNOTWrEn := sbWrEn }.elsewhen (sbAddr === CLEARDEBINT){ CLEARDEBINTWrEn := sbWrEn }.otherwise { //Other registers/RAM are Not Implemented. } } else { // Pick out the correct word based on the address. val sbWrDataWords = Vec.tabulate (tlDataBits / 32) {ii => sbWrData((ii+1)*32 - 1, ii*32)} val sbWrMaskWords = Vec.tabulate (tlDataBits / 32) {ii => sbWrMask ((ii+1)*32 -1, ii*32)} val sbWrSelTop = log2Up(tlDataBits/8) - 1 val sbWrSelBottom = 2 SETHALTNOTWrData := sbWrDataWords(SETHALTNOT(sbWrSelTop, sbWrSelBottom)) CLEARDEBINTWrData := sbWrDataWords(CLEARDEBINT(sbWrSelTop, sbWrSelBottom)) when (sbAddr(11,8) === UInt(4)){ //0x400-0x4ff is Debug RAM sbRamWrEn := sbWrEn sbRamRdEn := sbRdEn } SETHALTNOTWrEn := sbAddr(sbAddrWidth - 1, sbWrSelTop + 1) === SETHALTNOT(sbAddrWidth-1, sbWrSelTop + 1) && (sbWrMaskWords(SETHALTNOT(sbWrSelTop, sbWrSelBottom))).orR && sbWrEn CLEARDEBINTWrEn := sbAddr(sbAddrWidth - 1, sbWrSelTop + 1) === CLEARDEBINT(sbAddrWidth-1, sbWrSelTop + 1) && (sbWrMaskWords(CLEARDEBINT(sbWrSelTop, sbWrSelBottom))).orR && sbWrEn } // ----------------------------------------- // SB Access Read Mux sbRdData := UInt(0) sbRamRdEn := Bool(false) dbRamRdEn := Bool(false) when (sbAddr(11, 8) === UInt(4)) { //0x400-0x4FF Debug RAM sbRdData := sbRamRdData sbRamRdEn := sbRdEn }.elsewhen (sbAddr(11,8) === UInt(8) || sbAddr(11,8) === UInt(9)){ //0x800-0x9FF Debug ROM if (cfg.hasDebugRom) { sbRdData := sbRomRdData } else { sbRdData := UInt(0) } }. otherwise { // All readable registers are Not Implemented. sbRdData := UInt(0) } // ----------------------------------------- // SB Access State Machine -- based on BRAM Slave val sbAcqReg = Reg(io.tl.acquire.bits) val sbAcqValidReg = Reg(init = Bool(false)) val (sbReg_get :: sbReg_getblk :: sbReg_put :: sbReg_putblk :: Nil) = Seq( Acquire.getType, Acquire.getBlockType, Acquire.putType, Acquire.putBlockType ).map(sbAcqReg.isBuiltInType _) val sbMultibeat = sbReg_getblk & sbAcqValidReg; val sbBeatInc1 = sbAcqReg.addr_beat + UInt(1) val sbLast = (sbAcqReg.addr_beat === UInt(tlDataBeats - 1)) sbAddr := sbAcqReg.full_addr() sbRdEn := (sbAcqValidReg && (sbReg_get || sbReg_getblk)) sbWrEn := (sbAcqValidReg && (sbReg_put || sbReg_putblk)) sbWrData := sbAcqReg.data sbWrMask := sbAcqReg.full_wmask() // ----------------------------------------- // SB Access State Machine Update (Seq) when (io.tl.acquire.fire()){ sbAcqReg := io.tl.acquire.bits sbAcqValidReg := Bool(true) } .elsewhen (io.tl.grant.fire()) { when (sbMultibeat){ sbAcqReg.addr_beat := sbBeatInc1 when (sbLast) { sbAcqValidReg := Bool(false) } } . otherwise { sbAcqValidReg := Bool(false) } } io.tl.grant.valid := sbAcqValidReg io.tl.grant.bits := Grant( is_builtin_type = Bool(true), g_type = sbAcqReg.getBuiltInGrantType(), client_xact_id = sbAcqReg.client_xact_id, manager_xact_id = UInt(0), addr_beat = sbAcqReg.addr_beat, data = sbRdData ) stallFromDb := Bool(false) // SB always wins, and DB latches its read data so it is not necessary for SB to wait stallFromSb := sbRamRdEn || sbRamWrEn // pessimistically assume that DB/SB are going to conflict on the RAM, // and SB doesn't latch its read data to it is necessary for DB hold // off while SB is accessing the RAM and waiting to send its result. val sbStall = (sbMultibeat & !sbLast) || (io.tl.grant.valid && !io.tl.grant.ready) || stallFromDb io.tl.acquire.ready := !sbStall //-------------------------------------------------------------- // Misc. Outputs //-------------------------------------------------------------- io.ndreset := ndresetCtrReg.orR io.fullreset := CONTROLReg.fullreset }