1
0

refactor uncore files into separate packages

This commit is contained in:
Howard Mao
2016-06-28 11:21:38 -07:00
parent 97e74aec3a
commit b936aa9826
35 changed files with 1750 additions and 1667 deletions

View File

@ -0,0 +1,121 @@
package uncore.devices
import Chisel._
import cde.{Parameters, Field}
import junctions._
import uncore.tilelink._
import HastiConstants._
class BRAMSlave(depth: Int)(implicit val p: Parameters) extends Module
with HasTileLinkParameters {
val io = new ClientUncachedTileLinkIO().flip
val bram = SeqMem(depth, Vec(tlDataBytes, UInt(width = 8)))
val s_idle :: s_getblk :: s_putblk :: s_resp :: Nil = Enum(Bits(), 4)
val state = Reg(init = s_idle)
val acq = io.acquire.bits
val r_acq = Reg(new AcquireMetadata)
val (is_get :: is_getblk :: is_put :: is_putblk :: Nil) = Seq(
Acquire.getType, Acquire.getBlockType, Acquire.putType, Acquire.putBlockType
).map(acq.isBuiltInType _)
val beats = Reg(UInt(width = tlBeatAddrBits))
when (io.acquire.fire()) {
r_acq := acq
when (is_get || is_put || acq.isPrefetch()) {
state := s_resp
}
when (is_getblk) {
beats := UInt(tlDataBeats - 1)
state := s_getblk
}
/** Need to collect the rest of the beats.
* Beat 0 has already been accepted. */
when (is_putblk) {
beats := UInt(tlDataBeats - 2)
state := s_putblk
}
}
when (state === s_getblk && io.grant.ready) {
r_acq.addr_beat := r_acq.addr_beat + UInt(1)
beats := beats - UInt(1)
when (beats === UInt(0)) { state := s_idle }
}
when (state === s_putblk && io.acquire.valid) {
beats := beats - UInt(1)
when (beats === UInt(0)) { state := s_resp }
}
when (state === s_resp && io.grant.ready) { state := s_idle }
val acq_addr = Cat(acq.addr_block, acq.addr_beat)
val r_acq_addr = Cat(r_acq.addr_block, r_acq.addr_beat)
val ren = (io.acquire.fire() && (is_get || is_getblk)) ||
(state === s_getblk && io.grant.ready)
val raddr = Mux(state === s_idle, acq_addr,
Mux(io.grant.ready, r_acq_addr + UInt(1), r_acq_addr))
val rdata = bram.read(raddr, ren)
val wen = (io.acquire.fire() && (is_put || is_putblk))
val wdata = Vec.tabulate(tlDataBytes) { i => acq.data((i+1)*8-1, i*8) }
val wmask = Vec.tabulate(tlWriteMaskBits) { i => acq.wmask()(i) }
when (wen) { bram.write(acq_addr, wdata, wmask) }
io.grant.valid := (state === s_resp) || (state === s_getblk)
io.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = r_acq.getBuiltInGrantType(),
client_xact_id = r_acq.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = r_acq.addr_beat,
data = rdata.toBits)
io.acquire.ready := (state === s_idle) || (state === s_putblk)
}
class HastiRAM(depth: Int)(implicit p: Parameters) extends HastiModule()(p) {
val io = new HastiSlaveIO
val wdata = Vec.tabulate(hastiDataBytes)(i => io.hwdata(8*(i+1)-1,8*i))
val waddr = Reg(UInt(width = hastiAddrBits))
val wvalid = Reg(init = Bool(false))
val wsize = Reg(UInt(width = SZ_HSIZE))
val ram = SeqMem(depth, Vec(hastiDataBytes, Bits(width = 8)))
val max_size = log2Ceil(hastiDataBytes)
val wmask_lut = MuxLookup(wsize, SInt(-1, hastiDataBytes).asUInt,
(0 until max_size).map(sz => (UInt(sz) -> UInt((1 << (1 << sz)) - 1))))
val wmask = (wmask_lut << waddr(max_size - 1, 0))(hastiDataBytes - 1, 0)
val is_trans = io.hsel && (io.htrans === HTRANS_NONSEQ || io.htrans === HTRANS_SEQ)
val raddr = io.haddr >> UInt(max_size)
val ren = is_trans && !io.hwrite
val bypass = Reg(init = Bool(false))
when (is_trans && io.hwrite) {
waddr := io.haddr
wsize := io.hsize
wvalid := Bool(true)
} .otherwise { wvalid := Bool(false) }
when (ren) { bypass := wvalid && (waddr >> UInt(max_size)) === raddr }
when (wvalid) {
ram.write(waddr >> UInt(max_size), wdata, wmask.toBools)
}
val rdata = ram.read(raddr, ren)
io.hrdata := Cat(rdata.zip(wmask.toBools).zip(wdata).map {
case ((rbyte, wsel), wbyte) => Mux(wsel && bypass, wbyte, rbyte)
}.reverse)
io.hready := Bool(true)
io.hresp := HRESP_OKAY
}

View File

@ -0,0 +1,985 @@
// See LICENSE for license details.
package uncore.devices
import Chisel._
import uncore.tilelink._
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
}

View File

@ -0,0 +1,534 @@
package uncore.devices
import Chisel._
import cde.{Parameters, Field}
import junctions._
import junctions.NastiConstants._
import uncore.tilelink._
case object NDmaTransactors extends Field[Int]
case object NDmaXacts extends Field[Int]
case object NDmaClients extends Field[Int]
trait HasDmaParameters {
implicit val p: Parameters
val nDmaTransactors = p(NDmaTransactors)
val nDmaXacts = p(NDmaXacts)
val nDmaClients = p(NDmaClients)
val dmaXactIdBits = log2Up(nDmaXacts)
val dmaClientIdBits = log2Up(nDmaClients)
val addrBits = p(PAddrBits)
val dmaStatusBits = 2
val dmaWordSizeBits = 2
}
abstract class DmaModule(implicit val p: Parameters) extends Module with HasDmaParameters
abstract class DmaBundle(implicit val p: Parameters) extends ParameterizedBundle()(p) with HasDmaParameters
class DmaRequest(implicit p: Parameters) extends DmaBundle()(p) {
val xact_id = UInt(width = dmaXactIdBits)
val client_id = UInt(width = dmaClientIdBits)
val cmd = UInt(width = DmaRequest.DMA_CMD_SZ)
val source = UInt(width = addrBits)
val dest = UInt(width = addrBits)
val length = UInt(width = addrBits)
val size = UInt(width = dmaWordSizeBits)
}
class DmaResponse(implicit p: Parameters) extends DmaBundle()(p) {
val xact_id = UInt(width = dmaXactIdBits)
val client_id = UInt(width = dmaClientIdBits)
val status = UInt(width = dmaStatusBits)
}
object DmaRequest {
val DMA_CMD_SZ = 3
val DMA_CMD_COPY = UInt("b000")
val DMA_CMD_PFR = UInt("b010")
val DMA_CMD_PFW = UInt("b011")
val DMA_CMD_SIN = UInt("b100")
val DMA_CMD_SOUT = UInt("b101")
def apply(xact_id: UInt = UInt(0),
client_id: UInt,
cmd: UInt,
source: UInt,
dest: UInt,
length: UInt,
size: UInt = UInt(0))(implicit p: Parameters): DmaRequest = {
val req = Wire(new DmaRequest)
req.xact_id := xact_id
req.client_id := client_id
req.cmd := cmd
req.source := source
req.dest := dest
req.length := length
req.size := size
req
}
}
import DmaRequest._
class DmaIO(implicit p: Parameters) extends DmaBundle()(p) {
val req = Decoupled(new DmaRequest)
val resp = Decoupled(new DmaResponse).flip
}
class DmaTrackerIO(implicit p: Parameters) extends DmaBundle()(p) {
val dma = (new DmaIO).flip
val mem = new ClientUncachedTileLinkIO
val mmio = new NastiIO
}
class DmaManager(outstandingCSR: Int)(implicit p: Parameters)
extends DmaModule()(p)
with HasNastiParameters
with HasAddrMapParameters {
val io = new Bundle {
val ctrl = (new NastiIO).flip
val mmio = new NastiIO
val dma = new DmaIO
}
private val wordBits = 1 << log2Up(addrBits)
private val wordBytes = wordBits / 8
private val wordOff = log2Up(wordBytes)
private val wordMSB = wordOff + 2
val s_idle :: s_wdata :: s_dma_req :: s_wresp :: Nil = Enum(Bits(), 4)
val state = Reg(init = s_idle)
val nCtrlWords = (addrBits * 4) / nastiXDataBits
val ctrl_regs = Reg(Vec(nCtrlWords, UInt(width = nastiXDataBits)))
val ctrl_idx = Reg(UInt(width = log2Up(nCtrlWords)))
val ctrl_done = Reg(Bool())
val ctrl_blob = ctrl_regs.toBits
val ctrl_id = Reg(UInt(width = nastiXIdBits))
val sizeOffset = 3 * addrBits
val cmdOffset = sizeOffset + dmaWordSizeBits
val dma_req = new DmaRequest().fromBits(ctrl_blob)
val dma_busy = Reg(init = UInt(0, nDmaXacts))
val dma_xact_id = PriorityEncoder(~dma_busy)
when (io.ctrl.aw.fire()) {
ctrl_id := io.ctrl.aw.bits.id
ctrl_idx := UInt(0)
ctrl_done := Bool(false)
state := s_wdata
}
when (io.ctrl.w.fire()) {
when (!ctrl_done) {
ctrl_regs(ctrl_idx) := io.ctrl.w.bits.data
ctrl_idx := ctrl_idx + UInt(1)
}
when (ctrl_idx === UInt(nCtrlWords - 1)) { ctrl_done := Bool(true) }
when (io.ctrl.w.bits.last) { state := s_dma_req }
}
dma_busy := (dma_busy |
Mux(io.dma.req.fire(), UIntToOH(dma_xact_id), UInt(0))) &
~Mux(io.dma.resp.fire(), UIntToOH(io.dma.resp.bits.xact_id), UInt(0))
when (io.dma.req.fire()) { state := s_wresp }
when (io.ctrl.b.fire()) { state := s_idle }
io.ctrl.ar.ready := Bool(false)
io.ctrl.aw.ready := (state === s_idle)
io.ctrl.w.ready := (state === s_wdata)
io.ctrl.r.valid := Bool(false)
io.ctrl.b.valid := (state === s_wresp)
io.ctrl.b.bits := NastiWriteResponseChannel(id = ctrl_id)
io.dma.req.valid := (state === s_dma_req) && !dma_busy.andR
io.dma.req.bits := dma_req
io.dma.req.bits.xact_id := dma_xact_id
val resp_waddr_pending = Reg(init = Bool(false))
val resp_wdata_pending = Reg(init = Bool(false))
val resp_wresp_pending = Reg(init = Bool(false))
val resp_pending = resp_waddr_pending || resp_wdata_pending || resp_wresp_pending
val resp_client_id = Reg(UInt(width = dmaClientIdBits))
val resp_status = Reg(UInt(width = dmaStatusBits))
io.dma.resp.ready := !resp_pending
when (io.dma.resp.fire()) {
resp_client_id := io.dma.resp.bits.client_id
resp_status := io.dma.resp.bits.status
resp_waddr_pending := Bool(true)
resp_wdata_pending := Bool(true)
resp_wresp_pending := Bool(true)
}
val addrTable = Vec.tabulate(nDmaClients) { i =>
//UInt(addrMap(s"conf:csr$i").start + outstandingCSR * csrDataBytes)
require(false, "CSR MMIO ports no longer exist")
UInt(0)
}
io.mmio.ar.valid := Bool(false)
io.mmio.aw.valid := resp_waddr_pending
io.mmio.aw.bits := NastiWriteAddressChannel(
id = UInt(0),
addr = addrTable(resp_client_id),
size = { require(false, "CSR MMIO ports no longer exist"); UInt(0) })
io.mmio.w.valid := resp_wdata_pending
io.mmio.w.bits := NastiWriteDataChannel(data = resp_status)
io.mmio.b.ready := resp_wresp_pending
io.mmio.r.ready := Bool(false)
when (io.mmio.aw.fire()) { resp_waddr_pending := Bool(false) }
when (io.mmio.w.fire()) { resp_wdata_pending := Bool(false) }
when (io.mmio.b.fire()) { resp_wresp_pending := Bool(false) }
}
class DmaEngine(outstandingCSR: Int)(implicit p: Parameters) extends DmaModule()(p) {
val io = new Bundle {
val ctrl = (new NastiIO).flip
val mem = new ClientUncachedTileLinkIO
val mmio = new NastiIO
}
val manager = Module(new DmaManager(outstandingCSR))
val trackers = Module(new DmaTrackerFile)
manager.io.ctrl <> io.ctrl
trackers.io.dma <> manager.io.dma
val innerIOs = trackers.io.mem
val outerIOs = trackers.io.mmio :+ manager.io.mmio
val innerArb = Module(new ClientUncachedTileLinkIOArbiter(innerIOs.size))
innerArb.io.in <> innerIOs
io.mem <> innerArb.io.out
val outerArb = Module(new NastiArbiter(outerIOs.size))
outerArb.io.master <> outerIOs
io.mmio <> outerArb.io.slave
assert(!io.mmio.b.valid || io.mmio.b.bits.resp === UInt(0),
"DmaEngine: NASTI write response error")
assert(!io.mmio.r.valid || io.mmio.r.bits.resp === UInt(0),
"DmaEngine: NASTI read response error")
}
class DmaTrackerFile(implicit p: Parameters) extends DmaModule()(p) {
val io = new Bundle {
val dma = (new DmaIO).flip
val mem = Vec(nDmaTransactors, new ClientUncachedTileLinkIO)
val mmio = Vec(nDmaTransactors, new NastiIO)
}
val trackers = List.fill(nDmaTransactors) { Module(new DmaTracker) }
val reqReadys = Vec(trackers.map(_.io.dma.req.ready)).toBits
io.mem <> trackers.map(_.io.mem)
io.mmio <> trackers.map(_.io.mmio)
if (nDmaTransactors > 1) {
val resp_arb = Module(new RRArbiter(new DmaResponse, nDmaTransactors))
resp_arb.io.in <> trackers.map(_.io.dma.resp)
io.dma.resp <> resp_arb.io.out
val selection = PriorityEncoder(reqReadys)
trackers.zipWithIndex.foreach { case (tracker, i) =>
tracker.io.dma.req.valid := io.dma.req.valid && selection === UInt(i)
tracker.io.dma.req.bits := io.dma.req.bits
}
io.dma.req.ready := reqReadys.orR
} else {
io.dma <> trackers.head.io.dma
}
}
class DmaTracker(implicit p: Parameters) extends DmaModule()(p)
with HasTileLinkParameters with HasNastiParameters {
val io = new DmaTrackerIO
private val blockOffset = tlBeatAddrBits + tlByteAddrBits
private val blockBytes = tlDataBeats * tlDataBytes
val data_buffer = Reg(Vec(2 * tlDataBeats, Bits(width = tlDataBits)))
val get_inflight = Reg(UInt(2 * tlDataBeats))
val put_inflight = Reg(Bool())
val put_half = Reg(UInt(width = 1))
val get_half = Reg(UInt(width = 1))
val prefetch_put = Reg(Bool())
val get_done = !get_inflight.orR
val src_block = Reg(UInt(width = tlBlockAddrBits))
val dst_block = Reg(UInt(width = tlBlockAddrBits))
val offset = Reg(UInt(width = blockOffset))
val alignment = Reg(UInt(width = blockOffset))
val shift_dir = Reg(Bool())
val bytes_left = Reg(UInt(width = addrBits))
val streaming = Reg(Bool())
val stream_addr = Reg(UInt(width = nastiXAddrBits))
val stream_len = Reg(UInt(width = nastiXLenBits))
val stream_size = Reg(UInt(width = nastiXSizeBits))
val stream_idx = Reg(UInt(width = blockOffset))
val stream_bytesel = MuxLookup(stream_size, UInt("b11111111"), Seq(
UInt("b00") -> UInt("b00000001"),
UInt("b01") -> UInt("b00000011"),
UInt("b10") -> UInt("b00001111")))
val stream_mask = FillInterleaved(8, stream_bytesel)
val stream_last = Reg(Bool())
val stream_word_bytes = UInt(1) << stream_size
val stream_beat_idx = stream_idx(blockOffset - 1, tlByteAddrBits)
val stream_byte_idx = stream_idx(tlByteAddrBits - 1, 0)
val stream_bitshift = Cat(stream_byte_idx, UInt(0, 3))
val stream_in_beat =
(((io.mmio.r.bits.data & stream_mask) << stream_bitshift)) |
(data_buffer(stream_beat_idx) & ~(stream_mask << stream_bitshift))
val stream_out_word = data_buffer(stream_beat_idx) >> stream_bitshift
val stream_out_last = bytes_left === stream_word_bytes
val acq = io.mem.acquire.bits
val gnt = io.mem.grant.bits
val (s_idle :: s_get :: s_put :: s_prefetch ::
s_stream_read_req :: s_stream_read_resp ::
s_stream_write_req :: s_stream_write_data :: s_stream_write_resp ::
s_wait :: s_resp :: Nil) = Enum(Bits(), 11)
val state = Reg(init = s_idle)
val (put_beat, put_done) = Counter(
io.mem.acquire.fire() && acq.hasData(), tlDataBeats)
val put_mask = Vec.tabulate(tlDataBytes) { i =>
val byte_index = Cat(put_beat, UInt(i, tlByteAddrBits))
byte_index >= offset && byte_index < bytes_left
}.toBits
val prefetch_sent = io.mem.acquire.fire() && io.mem.acquire.bits.isPrefetch()
val prefetch_busy = Reg(init = UInt(0, tlMaxClientXacts))
val (prefetch_id, _) = Counter(prefetch_sent, tlMaxClientXacts)
val base_index = Cat(put_half, put_beat)
val put_data = Wire(init = Bits(0, tlDataBits))
val beat_align = alignment(blockOffset - 1, tlByteAddrBits)
val bit_align = Cat(alignment(tlByteAddrBits - 1, 0), UInt(0, 3))
val rev_align = UInt(tlDataBits) - bit_align
def getBit(value: UInt, sel: UInt): Bool =
(value >> sel)(0)
when (alignment === UInt(0)) {
put_data := data_buffer.read(base_index)
} .elsewhen (shift_dir) {
val shift_index = base_index - beat_align
when (bit_align === UInt(0)) {
put_data := data_buffer.read(shift_index)
} .otherwise {
val upper_bits = data_buffer.read(shift_index)
val lower_bits = data_buffer.read(shift_index - UInt(1))
val upper_shifted = upper_bits << bit_align
val lower_shifted = lower_bits >> rev_align
put_data := upper_shifted | lower_shifted
}
} .otherwise {
val shift_index = base_index + beat_align
when (bit_align === UInt(0)) {
put_data := data_buffer.read(shift_index)
} .otherwise {
val upper_bits = data_buffer.read(shift_index + UInt(1))
val lower_bits = data_buffer.read(shift_index)
val upper_shifted = upper_bits << rev_align
val lower_shifted = lower_bits >> bit_align
put_data := upper_shifted | lower_shifted
}
}
val put_acquire = PutBlock(
client_xact_id = UInt(2),
addr_block = dst_block,
addr_beat = put_beat,
data = put_data,
wmask = put_mask)
val get_acquire = GetBlock(
client_xact_id = get_half,
addr_block = src_block,
alloc = Bool(false))
val prefetch_acquire = Mux(prefetch_put,
PutPrefetch(client_xact_id = prefetch_id, addr_block = dst_block),
GetPrefetch(client_xact_id = prefetch_id, addr_block = dst_block))
val resp_xact_id = Reg(UInt(width = dmaXactIdBits))
val resp_client_id = Reg(UInt(width = dmaClientIdBits))
io.mem.acquire.valid := (state === s_get) ||
(state === s_put && get_done) ||
(state === s_prefetch && !prefetch_busy(prefetch_id))
io.mem.acquire.bits := MuxLookup(
state, prefetch_acquire, Seq(
s_get -> get_acquire,
s_put -> put_acquire))
io.mem.grant.ready := Bool(true)
io.dma.req.ready := state === s_idle
io.dma.resp.valid := state === s_resp
io.dma.resp.bits.xact_id := resp_xact_id
io.dma.resp.bits.client_id := resp_client_id
io.dma.resp.bits.status := UInt(0)
io.mmio.ar.valid := (state === s_stream_read_req)
io.mmio.ar.bits := NastiReadAddressChannel(
id = UInt(0),
addr = stream_addr,
size = stream_size,
len = stream_len,
burst = BURST_FIXED)
io.mmio.r.ready := (state === s_stream_read_resp)
io.mmio.aw.valid := (state === s_stream_write_req)
io.mmio.aw.bits := NastiWriteAddressChannel(
id = UInt(0),
addr = stream_addr,
size = stream_size,
len = stream_len,
burst = BURST_FIXED)
io.mmio.w.valid := (state === s_stream_write_data) && get_done
io.mmio.w.bits := NastiWriteDataChannel(
data = stream_out_word,
last = stream_out_last)
io.mmio.b.ready := (state === s_stream_write_resp)
when (io.dma.req.fire()) {
val src_off = io.dma.req.bits.source(blockOffset - 1, 0)
val dst_off = io.dma.req.bits.dest(blockOffset - 1, 0)
val direction = src_off < dst_off
resp_xact_id := io.dma.req.bits.xact_id
resp_client_id := io.dma.req.bits.client_id
src_block := io.dma.req.bits.source(addrBits - 1, blockOffset)
dst_block := io.dma.req.bits.dest(addrBits - 1, blockOffset)
alignment := Mux(direction, dst_off - src_off, src_off - dst_off)
shift_dir := direction
offset := dst_off
bytes_left := io.dma.req.bits.length + dst_off
get_inflight := UInt(0)
put_inflight := Bool(false)
get_half := UInt(0)
put_half := UInt(0)
streaming := Bool(false)
stream_len := (io.dma.req.bits.length >> io.dma.req.bits.size) - UInt(1)
stream_size := io.dma.req.bits.size
stream_last := Bool(false)
when (io.dma.req.bits.cmd === DMA_CMD_COPY) {
state := s_get
} .elsewhen (io.dma.req.bits.cmd(2, 1) === UInt("b01")) {
prefetch_put := io.dma.req.bits.cmd(0)
state := s_prefetch
} .elsewhen (io.dma.req.bits.cmd === DMA_CMD_SIN) {
stream_addr := io.dma.req.bits.source
stream_idx := dst_off
streaming := Bool(true)
alignment := UInt(0)
state := s_stream_read_req
} .elsewhen (io.dma.req.bits.cmd === DMA_CMD_SOUT) {
stream_addr := io.dma.req.bits.dest
stream_idx := src_off
streaming := Bool(true)
bytes_left := io.dma.req.bits.length
state := s_stream_write_req
}
}
when (io.mmio.ar.fire()) { state := s_stream_read_resp }
when (io.mmio.r.fire()) {
data_buffer(stream_beat_idx) := stream_in_beat
stream_idx := stream_idx + stream_word_bytes
val block_finished = stream_idx === UInt(blockBytes) - stream_word_bytes
when (block_finished || io.mmio.r.bits.last) { state := s_put }
}
when (io.mmio.aw.fire()) { state := s_get }
when (io.mmio.w.fire()) {
stream_idx := stream_idx + stream_word_bytes
bytes_left := bytes_left - stream_word_bytes
val block_finished = stream_idx === UInt(blockBytes) - stream_word_bytes
when (stream_out_last) {
state := s_stream_write_resp
} .elsewhen (block_finished) {
state := s_get
}
}
when (io.mmio.b.fire()) { state := s_resp }
when (state === s_get && io.mem.acquire.ready) {
get_inflight := get_inflight | FillInterleaved(tlDataBeats, UIntToOH(get_half))
src_block := src_block + UInt(1)
when (streaming) {
state := s_stream_write_data
} .otherwise {
val bytes_in_buffer = UInt(blockBytes) - alignment
val extra_read = alignment > UInt(0) && !shift_dir && // dst_off < src_off
get_half === UInt(0) && // this is the first block
bytes_in_buffer < bytes_left // there is still more data left to fetch
get_half := get_half + UInt(1)
when (!extra_read) { state := s_put }
}
}
when (prefetch_sent) {
prefetch_busy := prefetch_busy | UIntToOH(prefetch_id)
when (bytes_left < UInt(blockBytes)) {
bytes_left := UInt(0)
state := s_resp
} .otherwise {
bytes_left := bytes_left - UInt(blockBytes)
dst_block := dst_block + UInt(1)
}
}
when (io.mem.grant.fire()) {
when (gnt.g_type === Grant.prefetchAckType) {
prefetch_busy := prefetch_busy & ~UIntToOH(gnt.client_xact_id)
} .elsewhen (gnt.hasData()) {
val write_half = gnt.client_xact_id(0)
val write_idx = Cat(write_half, gnt.addr_beat)
get_inflight := get_inflight & ~UIntToOH(write_idx)
data_buffer.write(write_idx, gnt.data)
} .otherwise {
put_inflight := Bool(false)
}
}
when (put_done) { // state === s_put
when (!streaming) {
put_half := put_half + UInt(1)
}
offset := UInt(0)
stream_idx := UInt(0)
when (bytes_left < UInt(blockBytes)) {
bytes_left := UInt(0)
} .otherwise {
bytes_left := bytes_left - UInt(blockBytes)
}
put_inflight := Bool(true)
dst_block := dst_block + UInt(1)
state := s_wait
}
when (state === s_wait && get_done && !put_inflight) {
state := MuxCase(s_get, Seq(
(bytes_left === UInt(0)) -> s_resp,
streaming -> s_stream_read_resp))
}
when (io.dma.resp.fire()) { state := s_idle }
}

View File

@ -0,0 +1,187 @@
// See LICENSE for license details.
package uncore.devices
import Chisel._
import Chisel.ImplicitConversions._
import junctions._
import uncore.tilelink._
import cde.Parameters
class GatewayPLICIO extends Bundle {
val valid = Bool(OUTPUT)
val ready = Bool(INPUT)
val complete = Bool(INPUT)
}
class LevelGateway extends Module {
val io = new Bundle {
val interrupt = Bool(INPUT)
val plic = new GatewayPLICIO
}
val inFlight = Reg(init=Bool(false))
when (io.interrupt && io.plic.ready) { inFlight := true }
when (io.plic.complete) { inFlight := false }
io.plic.valid := io.interrupt && !inFlight
}
case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriorities: Int) {
def contextsPerHart = if (supervisor) 2 else 1
def nHarts = contextsPerHart * nHartsIn
def context(i: Int, mode: Char) = mode match {
case 'M' => i * contextsPerHart
case 'S' => require(supervisor); i * contextsPerHart + 1
}
def claimAddr(i: Int, mode: Char) = hartBase + hartOffset(context(i, mode)) + claimOffset
def threshAddr(i: Int, mode: Char) = hartBase + hartOffset(context(i, mode))
def enableAddr(i: Int, mode: Char) = enableBase + enableOffset(context(i, mode))
def size = hartBase + hartOffset(maxHarts)
def maxDevices = 1023
def maxHarts = 15872
def pendingBase = 0x1000
def enableBase = 0x2000
def hartBase = 0x200000
require(hartBase >= enableBase + enableOffset(maxHarts))
def enableOffset(i: Int) = i * ((maxDevices+7)/8)
def hartOffset(i: Int) = i * 0x1000
def claimOffset = 4
def priorityBytes = 4
require(nDevices > 0 && nDevices <= maxDevices)
require(nHarts > 0 && nHarts <= maxHarts)
require(nPriorities >= 0 && nPriorities <= nDevices)
}
/** Platform-Level Interrupt Controller */
class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
with HasTileLinkParameters
with HasAddrMapParameters {
val io = new Bundle {
val devices = Vec(cfg.nDevices, new GatewayPLICIO).flip
val harts = Vec(cfg.nHarts, Bool()).asOutput
val tl = new ClientUncachedTileLinkIO().flip
}
val priority =
if (cfg.nPriorities > 0) Reg(Vec(cfg.nDevices+1, UInt(width=log2Up(cfg.nPriorities+1))))
else Wire(init=Vec.fill(cfg.nDevices+1)(UInt(1)))
val threshold =
if (cfg.nPriorities > 0) Reg(Vec(cfg.nHarts, UInt(width = log2Up(cfg.nPriorities+1))))
else Wire(init=Vec.fill(cfg.nHarts)(UInt(0)))
val pending = Reg(init=Vec.fill(cfg.nDevices+1){Bool(false)})
val enables = Reg(Vec(cfg.nHarts, Vec(cfg.nDevices+1, Bool())))
for ((p, g) <- pending.tail zip io.devices) {
g.ready := !p
g.complete := false
when (g.valid) { p := true }
}
def findMax(x: Seq[UInt]): (UInt, UInt) = {
if (x.length > 1) {
val half = 1 << (log2Ceil(x.length) - 1)
val lMax = findMax(x take half)
val rMax = findMax(x drop half)
val useLeft = lMax._1 >= rMax._1
(Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) + rMax._2))
} else (x.head, UInt(0))
}
val maxDevs = Wire(Vec(cfg.nHarts, UInt(width = log2Up(pending.size))))
for (hart <- 0 until cfg.nHarts) {
val effectivePriority =
for (((p, en), pri) <- (pending zip enables(hart) zip priority).tail)
yield Cat(p && en, pri)
val (maxPri, maxDev) = findMax((UInt(1) << priority(0).getWidth) +: effectivePriority)
maxDevs(hart) := Reg(next = maxDev)
io.harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
}
val acq = Queue(io.tl.acquire, 1)
val read = acq.fire() && acq.bits.isBuiltInType(Acquire.getType)
val write = acq.fire() && acq.bits.isBuiltInType(Acquire.putType)
assert(!acq.fire() || read || write, "unsupported PLIC operation")
val addr = acq.bits.full_addr()(log2Up(cfg.size)-1,0)
val claimant =
if (cfg.nHarts == 1) UInt(0)
else (addr - cfg.hartBase)(log2Up(cfg.hartOffset(cfg.nHarts))-1,log2Up(cfg.hartOffset(1)))
val hart = Wire(init = claimant)
val myMaxDev = maxDevs(claimant) + UInt(0) // XXX FIRRTL bug w/o the + UInt(0)
val myEnables = enables(hart)
val rdata = Wire(init = UInt(0, tlDataBits))
val masked_wdata = (acq.bits.data & acq.bits.full_wmask()) | (rdata & ~acq.bits.full_wmask())
when (addr >= cfg.hartBase) {
val word =
if (tlDataBytes > cfg.claimOffset) UInt(0)
else addr(log2Up(cfg.claimOffset),log2Up(tlDataBytes))
rdata := Cat(myMaxDev, UInt(0, 8*cfg.priorityBytes-threshold(0).getWidth), threshold(claimant)) >> (word * tlDataBits)
when (read && addr(log2Ceil(cfg.claimOffset))) {
pending(myMaxDev) := false
}
when (write) {
when (if (tlDataBytes > cfg.claimOffset) acq.bits.wmask()(cfg.claimOffset) else addr(log2Ceil(cfg.claimOffset))) {
val dev = (acq.bits.data >> ((8 * cfg.claimOffset) % tlDataBits))(log2Up(pending.size)-1,0)
when (myEnables(dev)) { io.devices(dev-1).complete := true }
}.otherwise {
if (cfg.nPriorities > 0) threshold(claimant) := acq.bits.data
}
}
}.elsewhen (addr >= cfg.enableBase) {
val enableHart =
if (cfg.nHarts > 1) (addr - cfg.enableBase)(log2Up(cfg.enableOffset(cfg.nHarts))-1,log2Up(cfg.enableOffset(1)))
else UInt(0)
hart := enableHart
val word =
if (tlDataBits >= cfg.nHarts) UInt(0)
else addr(log2Up((cfg.nHarts+7)/8)-1,log2Up(tlDataBytes))
for (i <- 0 until cfg.nHarts by tlDataBits) {
when (word === i/tlDataBits) {
rdata := Cat(myEnables.slice(i, i + tlDataBits).reverse)
for (j <- 0 until (tlDataBits min (myEnables.size - i))) {
when (write) { enables(enableHart)(i+j) := masked_wdata(j) }
}
}
}
}.elsewhen (addr >= cfg.pendingBase) {
val word =
if (tlDataBytes >= pending.size) UInt(0)
else addr(log2Up(pending.size)-1,log2Up(tlDataBytes))
rdata := pending.toBits >> (word * tlDataBits)
}.otherwise {
val regsPerBeat = tlDataBytes >> log2Up(cfg.priorityBytes)
val word =
if (regsPerBeat >= priority.size) UInt(0)
else addr(log2Up(priority.size*cfg.priorityBytes)-1,log2Up(tlDataBytes))
for (i <- 0 until priority.size by regsPerBeat) {
when (word === i/regsPerBeat) {
rdata := Cat(priority.slice(i, i + regsPerBeat).map(p => Cat(UInt(0, 8*cfg.priorityBytes-p.getWidth), p)).reverse)
for (j <- 0 until (regsPerBeat min (priority.size - i))) {
if (cfg.nPriorities > 0) when (write) { priority(i+j) := masked_wdata >> (j * 8 * cfg.priorityBytes) }
}
}
}
}
priority(0) := 0
pending(0) := false
for (e <- enables)
e(0) := false
io.tl.grant.valid := acq.valid
acq.ready := io.tl.grant.ready
io.tl.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = acq.bits.getBuiltInGrantType(),
client_xact_id = acq.bits.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = UInt(0),
data = rdata)
}

View File

@ -0,0 +1,127 @@
// See LICENSE for license details.
package uncore.devices
import Chisel._
import Chisel.ImplicitConversions._
import junctions._
import junctions.NastiConstants._
import uncore.tilelink._
import cde.{Parameters, Field}
/** Number of tiles */
case object NTiles extends Field[Int]
class PRCIInterrupts extends Bundle {
val meip = Bool()
val seip = Bool()
val debug = Bool()
}
class PRCITileIO(implicit p: Parameters) extends Bundle {
val reset = Bool(OUTPUT)
val id = UInt(OUTPUT, log2Up(p(NTiles)))
val interrupts = new PRCIInterrupts {
val mtip = Bool()
val msip = Bool()
}.asOutput
override def cloneType: this.type = new PRCITileIO().asInstanceOf[this.type]
}
object PRCI {
def msip(hart: Int) = hart * msipBytes
def timecmp(hart: Int) = 0x4000 + hart * timecmpBytes
def time = 0xbff8
def msipBytes = 4
def timecmpBytes = 8
def size = 0xc000
}
/** Power, Reset, Clock, Interrupt */
class PRCI(implicit val p: Parameters) extends Module
with HasTileLinkParameters
with HasAddrMapParameters {
val io = new Bundle {
val interrupts = Vec(p(NTiles), new PRCIInterrupts).asInput
val tl = new ClientUncachedTileLinkIO().flip
val tiles = Vec(p(NTiles), new PRCITileIO)
val rtcTick = Bool(INPUT)
}
val timeWidth = 64
val timecmp = Reg(Vec(p(NTiles), UInt(width = timeWidth)))
val time = Reg(init=UInt(0, timeWidth))
when (io.rtcTick) { time := time + UInt(1) }
val ipi = Reg(init=Vec.fill(p(NTiles))(UInt(0, 32)))
val acq = Queue(io.tl.acquire, 1)
val addr = acq.bits.full_addr()(log2Ceil(PRCI.size)-1,0)
val read = acq.bits.isBuiltInType(Acquire.getType)
val rdata = Wire(init=UInt(0))
io.tl.grant.valid := acq.valid
acq.ready := io.tl.grant.ready
io.tl.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = acq.bits.getBuiltInGrantType(),
client_xact_id = acq.bits.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = UInt(0),
data = rdata)
when (addr(log2Floor(PRCI.time))) {
require(log2Floor(PRCI.timecmp(p(NTiles)-1)) < log2Floor(PRCI.time))
rdata := load(Vec(time + UInt(0)), acq.bits)
}.elsewhen (addr >= PRCI.timecmp(0)) {
rdata := store(timecmp, acq.bits)
}.otherwise {
rdata := store(ipi, acq.bits) & Fill(tlDataBits/32, UInt(1, 32))
}
for ((tile, i) <- io.tiles zipWithIndex) {
tile.interrupts := io.interrupts(i)
tile.interrupts.msip := ipi(i)(0)
tile.interrupts.mtip := time >= timecmp(i)
tile.id := UInt(i)
}
// TODO generalize these to help other TL slaves
def load(v: Vec[UInt], acq: Acquire): UInt = {
val w = v.head.getWidth
val a = acq.full_addr()
require(isPow2(w) && w >= 8)
if (w > tlDataBits) {
(v(a(log2Up(w/8*v.size)-1,log2Up(w/8))) >> a(log2Up(w/8)-1,log2Up(tlDataBytes)))(tlDataBits-1,0)
} else {
val row = for (i <- 0 until v.size by tlDataBits/w)
yield Cat(v.slice(i, i + tlDataBits/w).reverse)
if (row.size == 1) row.head
else Vec(row)(a(log2Up(w/8*v.size)-1,log2Up(tlDataBytes)))
}
}
def store(v: Vec[UInt], acq: Acquire): UInt = {
val w = v.head.getWidth
require(isPow2(w) && w >= 8)
val a = acq.full_addr()
val rdata = load(v, acq)
val wdata = (acq.data & acq.full_wmask()) | (rdata & ~acq.full_wmask())
if (w <= tlDataBits) {
val word =
if (tlDataBits/w >= v.size) UInt(0)
else a(log2Up(w/8*v.size)-1,log2Up(tlDataBytes))
for (i <- 0 until v.size) {
when (acq.isBuiltInType(Acquire.putType) && word === i/(tlDataBits/w)) {
val base = i % (tlDataBits/w)
v(i) := wdata >> (w * (i % (tlDataBits/w)))
}
}
} else {
val i = a(log2Up(w/8*v.size)-1,log2Up(w/8))
val mask = FillInterleaved(tlDataBits, UIntToOH(a(log2Up(w/8)-1,log2Up(tlDataBytes))))
v(i) := (wdata & mask) | (v(i) & ~mask)
}
rdata
}
}

View File

@ -0,0 +1,67 @@
package uncore.devices
import Chisel._
import junctions._
import uncore.tilelink._
import uncore.util._
import cde.{Parameters, Field}
class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module
with HasTileLinkParameters
with HasAddrMapParameters {
val io = new ClientUncachedTileLinkIO().flip
val acq = Queue(io.acquire, 1)
val single_beat = acq.bits.isBuiltInType(Acquire.getType)
val multi_beat = acq.bits.isBuiltInType(Acquire.getBlockType)
assert(!acq.valid || single_beat || multi_beat, "unsupported ROMSlave operation")
val addr_beat = Reg(UInt())
when (io.grant.fire()) { addr_beat := addr_beat + UInt(1) }
when (io.acquire.fire()) { addr_beat := io.acquire.bits.addr_beat }
val byteWidth = tlDataBits / 8
val rows = (contents.size + byteWidth - 1)/byteWidth
val rom = Vec.tabulate(rows) { i =>
val slice = contents.slice(i*byteWidth, (i+1)*byteWidth)
UInt(slice.foldRight(BigInt(0)) { case (x,y) => (y << 8) + (x.toInt & 0xFF) }, byteWidth*8)
}
val raddr = Cat(acq.bits.addr_block, addr_beat)
val rdata = rom(if (rows == 1) UInt(0) else raddr(log2Up(rom.size)-1,0))
val last = !multi_beat || addr_beat === UInt(tlDataBeats-1)
io.grant.valid := acq.valid
acq.ready := io.grant.ready && last
io.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = acq.bits.getBuiltInGrantType(),
client_xact_id = acq.bits.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = addr_beat,
data = rdata)
}
class NastiROM(contents: Seq[Byte])(implicit p: Parameters) extends Module {
val io = new NastiIO().flip
val ar = Queue(io.ar, 1)
// This assumes ROMs are in read-only parts of the address map.
// Reuse b_queue code from NastiErrorSlave if this assumption is bad.
when (ar.valid) { assert(ar.bits.len === UInt(0), "Can't burst-read from NastiROM") }
assert(!(io.aw.valid || io.w.valid), "Can't write to NastiROM")
io.aw.ready := Bool(false)
io.w.ready := Bool(false)
io.b.valid := Bool(false)
val byteWidth = io.r.bits.nastiXDataBits / 8
val rows = (contents.size + byteWidth - 1)/byteWidth
val rom = Vec.tabulate(rows) { i =>
val slice = contents.slice(i*byteWidth, (i+1)*byteWidth)
UInt(slice.foldRight(BigInt(0)) { case (x,y) => (y << 8) + (x.toInt & 0xFF) }, byteWidth*8)
}
val rdata_word = rom(if (rows == 1) UInt(0) else ar.bits.addr(log2Up(contents.size)-1,log2Up(byteWidth)))
val rdata = new LoadGen(Cat(UInt(1), ar.bits.size), ar.bits.addr, rdata_word, Bool(false), byteWidth).data
io.r <> ar
io.r.bits := NastiReadDataChannel(ar.bits.id, rdata)
}