9804bdc34e
When we first implemented TL, we thought this was helpful, because it made WidthWidgets stateless in all cases. However, it put too much burden on all other masters and slaves, none of which benefitted from this signal. Furthermore, even with addr_lo, WidthWidgets were information lossy because when they widen, they have no information about what to fill in the new high bits of addr_lo.
112 lines
4.0 KiB
Scala
112 lines
4.0 KiB
Scala
// See LICENSE.SiFive for license details.
|
|
|
|
package freechips.rocketchip.tilelink
|
|
|
|
import Chisel._
|
|
import chisel3.experimental.chiselName
|
|
import freechips.rocketchip.config.Parameters
|
|
import freechips.rocketchip.diplomacy._
|
|
import freechips.rocketchip.util._
|
|
|
|
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4, name: Option[String] = None, errors: Seq[AddressSet] = Nil)(implicit p: Parameters) extends LazyModule
|
|
{
|
|
private val resources =
|
|
name.map(new SimpleDevice(_, Seq("sifive,sram0")).reg("mem")).getOrElse(new MemoryDevice().reg)
|
|
|
|
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
|
Seq(TLManagerParameters(
|
|
address = List(address) ++ errors,
|
|
resources = resources,
|
|
regionType = RegionType.UNCACHED,
|
|
executable = executable,
|
|
supportsGet = TransferSizes(1, beatBytes),
|
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
|
supportsPutFull = TransferSizes(1, beatBytes),
|
|
fifoId = Some(0))), // requests are handled in order
|
|
beatBytes = beatBytes,
|
|
minLatency = 1))) // no bypass needed for this device
|
|
|
|
// We require the address range to include an entire beat (for the write mask)
|
|
require ((address.mask & (beatBytes-1)) == beatBytes-1)
|
|
|
|
lazy val module = new Implementation
|
|
@chiselName class Implementation extends LazyModuleImp(this) {
|
|
val io = new Bundle {
|
|
val in = node.bundleIn
|
|
}
|
|
|
|
def bigBits(x: BigInt, tail: List[Boolean] = List.empty[Boolean]): List[Boolean] =
|
|
if (x == 0) tail.reverse else bigBits(x >> 1, ((x & 1) == 1) :: tail)
|
|
val mask = bigBits(address.mask >> log2Ceil(beatBytes))
|
|
|
|
val in = io.in(0)
|
|
val edge = node.edgesIn(0)
|
|
|
|
val addrBits = (mask zip edge.addr_hi(in.a.bits).toBools).filter(_._1).map(_._2)
|
|
val a_legal = address.contains(in.a.bits.address)
|
|
val memAddress = Cat(addrBits.reverse)
|
|
val mem = SeqMem(1 << addrBits.size, Vec(beatBytes, Bits(width = 8)))
|
|
|
|
val d_full = RegInit(Bool(false))
|
|
val d_read = Reg(Bool())
|
|
val d_size = Reg(UInt())
|
|
val d_source = Reg(UInt())
|
|
val d_data = Wire(UInt())
|
|
val d_legal = Reg(Bool())
|
|
|
|
// Flow control
|
|
when (in.d.fire()) { d_full := Bool(false) }
|
|
when (in.a.fire()) { d_full := Bool(true) }
|
|
in.d.valid := d_full
|
|
in.a.ready := in.d.ready || !d_full
|
|
|
|
in.d.bits := edge.AccessAck(d_source, d_size, !d_legal)
|
|
// avoid data-bus Mux
|
|
in.d.bits.data := d_data
|
|
in.d.bits.opcode := Mux(d_read, TLMessages.AccessAckData, TLMessages.AccessAck)
|
|
|
|
val read = in.a.bits.opcode === TLMessages.Get
|
|
val rdata = Wire(Vec(beatBytes, Bits(width = 8)))
|
|
val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) }
|
|
d_data := Cat(rdata.reverse)
|
|
when (in.a.fire()) {
|
|
d_read := read
|
|
d_size := in.a.bits.size
|
|
d_source := in.a.bits.source
|
|
d_legal := a_legal
|
|
}
|
|
|
|
// exactly this pattern is required to get a RWM memory
|
|
when (in.a.fire() && !read && a_legal) {
|
|
mem.write(memAddress, wdata, in.a.bits.mask.toBools)
|
|
}
|
|
val ren = in.a.fire() && read
|
|
rdata := mem.readAndHold(memAddress, ren)
|
|
|
|
// Tie off unused channels
|
|
in.b.valid := Bool(false)
|
|
in.c.ready := Bool(true)
|
|
in.e.ready := Bool(true)
|
|
}
|
|
}
|
|
|
|
/** Synthesizeable unit testing */
|
|
import freechips.rocketchip.unittest._
|
|
|
|
class TLRAMSimple(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
|
|
val fuzz = LazyModule(new TLFuzzer(txns))
|
|
val model = LazyModule(new TLRAMModel("SRAMSimple"))
|
|
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes))
|
|
|
|
model.node := fuzz.node
|
|
ram.node := TLDelayer(0.25)(model.node)
|
|
|
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
|
io.finished := fuzz.module.io.finished
|
|
}
|
|
}
|
|
|
|
class TLRAMSimpleTest(ramBeatBytes: Int, txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
|
|
io.finished := Module(LazyModule(new TLRAMSimple(ramBeatBytes, txns)).module).io.finished
|
|
}
|