1
0
rocket-chip/src/main/scala/groundtest/TrafficGenerator.scala

217 lines
6.6 KiB
Scala
Raw Normal View History

// See LICENSE.Berkeley for license details.
// See LICENSE.SiFive for license details.
package groundtest
import Chisel._
import uncore.tilelink._
import coreplex.NTiles
import uncore.constants._
import junctions._
import rocket._
import util.SimpleTimer
import scala.util.Random
import config._
case class TrafficGeneratorParameters(
maxRequests: Int,
startAddress: BigInt)
case object GeneratorKey extends Field[TrafficGeneratorParameters]
trait HasTrafficGeneratorParameters extends HasGroundTestParameters {
implicit val p: Parameters
val genParams = p(GeneratorKey)
val nGens = p(GroundTestKey).map(
cs => cs.uncached + cs.cached).reduce(_ + _)
val genTimeout = 8192
val maxRequests = genParams.maxRequests
val startAddress = genParams.startAddress
val genWordBits = 32
val genWordBytes = genWordBits / 8
val wordOffset = log2Ceil(genWordBytes)
val wordSize = UInt(log2Ceil(genWordBytes))
require(startAddress % BigInt(genWordBytes) == 0)
}
class UncachedTileLinkGenerator(id: Int)
(implicit p: Parameters) extends TLModule()(p) with HasTrafficGeneratorParameters {
private val tlBlockOffset = tlBeatAddrBits + tlByteAddrBits
val io = new Bundle {
val mem = new ClientUncachedTileLinkIO
val status = new GroundTestStatus
}
val (s_start :: s_put :: s_get :: s_finished :: Nil) = Enum(Bits(), 4)
val state = Reg(init = s_start)
val (req_cnt, req_wrap) = Counter(io.mem.grant.fire(), maxRequests)
val sending = Reg(init = Bool(false))
when (state === s_start) {
sending := Bool(true)
state := s_put
}
when (io.mem.acquire.fire()) { sending := Bool(false) }
when (io.mem.grant.fire()) { sending := Bool(true) }
when (req_wrap) { state := Mux(state === s_put, s_get, s_finished) }
val timeout = SimpleTimer(genTimeout, io.mem.acquire.fire(), io.mem.grant.fire())
assert(!timeout, s"Uncached generator ${id} timed out waiting for grant")
io.status.finished := (state === s_finished)
io.status.timeout.valid := timeout
io.status.timeout.bits := UInt(id)
val part_of_full_addr =
if (log2Ceil(nGens) > 0) {
Cat(UInt(id, log2Ceil(nGens)),
UInt(0, wordOffset))
} else {
UInt(0, wordOffset)
}
val full_addr = UInt(startAddress) + Cat(req_cnt, part_of_full_addr)
val addr_block = full_addr >> UInt(tlBlockOffset)
val addr_beat = full_addr(tlBlockOffset - 1, tlByteAddrBits)
val addr_byte = full_addr(tlByteAddrBits - 1, 0)
val data_prefix = Cat(UInt(id, log2Up(nGens)), req_cnt)
val word_data = Wire(UInt(width = genWordBits))
word_data := Cat(data_prefix, part_of_full_addr)
val beat_data = Fill(tlDataBits / genWordBits, word_data)
val wshift = Cat(beatOffset(full_addr), UInt(0, wordOffset))
val wmask = Fill(genWordBits / 8, Bits(1, 1)) << wshift
val put_acquire = Put(
client_xact_id = UInt(0),
addr_block = addr_block,
addr_beat = addr_beat,
data = beat_data,
wmask = Some(wmask),
alloc = Bool(false))
val get_acquire = Get(
client_xact_id = UInt(0),
addr_block = addr_block,
addr_beat = addr_beat,
addr_byte = addr_byte,
operand_size = wordSize,
alloc = Bool(false))
io.mem.acquire.valid := sending && !io.status.finished
io.mem.acquire.bits := Mux(state === s_put, put_acquire, get_acquire)
io.mem.grant.ready := !sending && !io.status.finished
def wordFromBeat(addr: UInt, dat: UInt) = {
val shift = Cat(beatOffset(addr), UInt(0, wordOffset + 3))
(dat >> shift)(genWordBits - 1, 0)
}
val data_mismatch = io.mem.grant.fire() && state === s_get &&
wordFromBeat(full_addr, io.mem.grant.bits.data) =/= word_data
io.status.error.valid := data_mismatch
io.status.error.bits := UInt(id)
assert(!data_mismatch,
s"Get received incorrect data in uncached generator ${id}")
def beatOffset(addr: UInt) = // TODO zero-width
if (tlByteAddrBits > wordOffset) addr(tlByteAddrBits - 1, wordOffset)
else UInt(0)
}
class HellaCacheGenerator(id: Int)
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
(implicit val p: Parameters) extends Module with HasTrafficGeneratorParameters {
val io = new Bundle {
val mem = new HellaCacheIO
val status = new GroundTestStatus
}
val timeout = SimpleTimer(genTimeout, io.mem.req.fire(), io.mem.resp.valid)
assert(!timeout, s"Cached generator ${id} timed out waiting for response")
io.status.timeout.valid := timeout
io.status.timeout.bits := UInt(id)
val (s_start :: s_write :: s_read :: s_finished :: Nil) = Enum(Bits(), 4)
val state = Reg(init = s_start)
val sending = Reg(init = Bool(false))
val (req_cnt, req_wrap) = Counter(io.mem.resp.valid, maxRequests)
val part_of_req_addr =
if (log2Ceil(nGens) > 0) {
Cat(UInt(id, log2Ceil(nGens)),
UInt(0, wordOffset))
} else {
UInt(0, wordOffset)
}
val req_addr = UInt(startAddress) + Cat(req_cnt, part_of_req_addr)
val req_data = Cat(UInt(id, log2Up(nGens)), req_cnt, part_of_req_addr)
io.mem.req.valid := sending && !io.status.finished
io.mem.req.bits.addr := req_addr
io.mem.req.bits.data := req_data
io.mem.req.bits.typ := wordSize
io.mem.req.bits.cmd := Mux(state === s_write, M_XWR, M_XRD)
io.mem.req.bits.tag := UInt(0)
when (state === s_start) { sending := Bool(true); state := s_write }
when (io.mem.req.fire()) { sending := Bool(false) }
when (io.mem.resp.valid) { sending := Bool(true) }
when (req_wrap) { state := Mux(state === s_write, s_read, s_finished) }
io.status.finished := (state === s_finished)
def data_match(recv: Bits, expected: Bits): Bool = {
val recv_resized = Wire(Bits(width = genWordBits))
val exp_resized = Wire(Bits(width = genWordBits))
recv_resized := recv
exp_resized := expected
recv_resized === exp_resized
}
val data_mismatch = io.mem.resp.valid && io.mem.resp.bits.has_data &&
!data_match(io.mem.resp.bits.data, req_data)
io.status.error.valid := data_mismatch
io.status.error.bits := UInt(id)
assert(!data_mismatch,
s"Received incorrect data in cached generator ${id}")
}
class GeneratorTest(implicit p: Parameters)
extends GroundTest()(p) with HasTrafficGeneratorParameters {
val idStart = p(GroundTestKey).take(p(TileId))
.map(settings => settings.cached + settings.uncached)
.foldLeft(0)(_ + _)
val cached = List.tabulate(nCached) { i =>
val realId = idStart + i
Module(new HellaCacheGenerator(realId))
}
val uncached = List.tabulate(nUncached) { i =>
val realId = idStart + nCached + i
Module(new UncachedTileLinkGenerator(realId))
}
io.cache <> cached.map(_.io.mem)
io.mem <> uncached.map(_.io.mem)
val gen_debug = cached.map(_.io.status) ++ uncached.map(_.io.status)
io.status := DebugCombiner(gen_debug)
}