Refactor package hierarchy and remove legacy bus protocol implementations (#845)
* Refactors package hierarchy. Additionally: - Removes legacy ground tests and configs - Removes legacy bus protocol implementations - Removes NTiles - Adds devices package - Adds more functions to util package
This commit is contained in:
parent
c28c23150d
commit
4c595d175c
@ -84,7 +84,3 @@ jobs:
|
|||||||
script:
|
script:
|
||||||
- travis_wait 80 make emulator-ndebug -C regression SUITE=RocketSuiteA JVM_MEMORY=3G
|
- travis_wait 80 make emulator-ndebug -C regression SUITE=RocketSuiteA JVM_MEMORY=3G
|
||||||
- travis_wait 80 make emulator-regression-tests -C regression SUITE=RocketSuiteA JVM_MEMORY=3G
|
- travis_wait 80 make emulator-regression-tests -C regression SUITE=RocketSuiteA JVM_MEMORY=3G
|
||||||
- <<: *test
|
|
||||||
script:
|
|
||||||
- travis_wait 80 make emulator-ndebug -C regression SUITE=GroundtestSuite JVM_MEMORY=3G
|
|
||||||
- travis_wait 80 make emulator-regression-tests -C regression SUITE=GroundtestSuite JVM_MEMORY=3G
|
|
||||||
|
2
Makefrag
2
Makefrag
@ -4,7 +4,7 @@ $(error Please set environment variable RISCV. Please take a look at README)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
MODEL ?= TestHarness
|
MODEL ?= TestHarness
|
||||||
PROJECT ?= rocketchip
|
PROJECT ?= freechips.rocketchip.chip
|
||||||
CFG_PROJECT ?= $(PROJECT)
|
CFG_PROJECT ?= $(PROJECT)
|
||||||
CONFIG ?= DefaultConfig
|
CONFIG ?= DefaultConfig
|
||||||
# TODO: For now must match rocketchip.Generator
|
# TODO: For now must match rocketchip.Generator
|
||||||
|
26
README.md
26
README.md
@ -154,13 +154,20 @@ Some of these packages provide Scala utilities for generator configuration,
|
|||||||
while other contain the actual Chisel RTL generators themselves.
|
while other contain the actual Chisel RTL generators themselves.
|
||||||
Here is a brief description of what can be found in each package:
|
Here is a brief description of what can be found in each package:
|
||||||
|
|
||||||
|
* **amba**
|
||||||
|
This RTL package uses diplomacy to generate bus implementations of AMBA protocols, including AXI4, AHB-lite, and APB.
|
||||||
|
* **chip**
|
||||||
|
This top-level utility package invokes Chisel to elaborate a particular configuration of a coreplex,
|
||||||
|
along with the appropriate testing collateral.
|
||||||
* **config**
|
* **config**
|
||||||
This utility package provides Scala interfaces for configuring a generator via a dynamically-scoped
|
This utility package provides Scala interfaces for configuring a generator via a dynamically-scoped
|
||||||
parameterization library.
|
parameterization library.
|
||||||
* **coreplex**
|
* **coreplex**
|
||||||
This RTL package generates a complete coreplex by gluing together a variety of other components,
|
This RTL package generates a complete coreplex by gluing together a variety of components from other packages,
|
||||||
including tiled Rocket cores, an L1-to-L2 network, L2 coherence agents, and internal devices
|
including: tiled Rocket cores, a system bus network, coherence agents, debug devices, interrupt handlers, externally-facing peripherals,
|
||||||
such as the debug unit and interrupt handlers.
|
clock-crossers and converters from TileLink to external bus protocols (e.g. AXI or AHB).
|
||||||
|
* **devices**
|
||||||
|
This RTL package contains implementations for peripheral devices, including the Debug module and various TL slaves.
|
||||||
* **diplomacy**
|
* **diplomacy**
|
||||||
This utility package extends Chisel by allowing for two-phase hardware elaboration, in which certain parameters
|
This utility package extends Chisel by allowing for two-phase hardware elaboration, in which certain parameters
|
||||||
are dynamically negotiated between modules.
|
are dynamically negotiated between modules.
|
||||||
@ -176,16 +183,13 @@ This RTL package generates the Rocket in-order pipelined core,
|
|||||||
as well as the L1 instruction and data caches.
|
as well as the L1 instruction and data caches.
|
||||||
This library is intended to be used by a chip generator that instantiates the
|
This library is intended to be used by a chip generator that instantiates the
|
||||||
core within a memory system and connects it to the outside world.
|
core within a memory system and connects it to the outside world.
|
||||||
* **uncore**
|
* **tile**
|
||||||
This RTL package generates a variety of uncore logic and devices, such as
|
This RTL package contains components that can be combined with cores to construct tiles, such as FPUs and accelerators.
|
||||||
such as the L2 coherence hub and Debug modules, as well as defining their interfaces and protocols.
|
* **tilelink**
|
||||||
Contains implementations of both TileLink and AXI4.
|
This RTL package uses diplomacy to generate bus implementations of the TileLink protocol. It also contains a variety
|
||||||
|
of adapters and protocol converters.
|
||||||
* **unittest**
|
* **unittest**
|
||||||
This utility package contains a framework for generateing synthesizeable hardware testers of individual modules.
|
This utility package contains a framework for generateing synthesizeable hardware testers of individual modules.
|
||||||
* **rocketchip**
|
|
||||||
This top-level RTL package instantiates a coreplex and drops in any additional
|
|
||||||
externally-facing peripheral devices. It also includes clock-crossers and converters
|
|
||||||
from TileLink to external bus protocols (e.g. AXI or AHB).
|
|
||||||
* **util**
|
* **util**
|
||||||
This utility package provides a variety of common Scala and Chisel constructs that are re-used across
|
This utility package provides a variety of common Scala and Chisel constructs that are re-used across
|
||||||
multiple other packages,
|
multiple other packages,
|
||||||
|
@ -42,31 +42,23 @@ $(error Set SUITE to the regression suite you want to run)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(SUITE),RocketSuiteA)
|
ifeq ($(SUITE),RocketSuiteA)
|
||||||
PROJECT=rocketchip
|
PROJECT=freechips.rocketchip.chip
|
||||||
CONFIGS=DefaultConfig
|
CONFIGS=DefaultConfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(SUITE),RocketSuiteB)
|
ifeq ($(SUITE),RocketSuiteB)
|
||||||
PROJECT=rocketchip
|
PROJECT=freechips.rocketchip.chip
|
||||||
CONFIGS=DefaultBufferlessConfig
|
CONFIGS=DefaultBufferlessConfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(SUITE),RocketSuiteC)
|
ifeq ($(SUITE),RocketSuiteC)
|
||||||
PROJECT=rocketchip
|
PROJECT=freechips.rocketchip.chip
|
||||||
CONFIGS=DefaultL2Config TinyConfig
|
CONFIGS=TinyConfig
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(SUITE),GroundtestSuite)
|
|
||||||
PROJECT=groundtest
|
|
||||||
CONFIGS=MemtestConfig MemtestBufferlessConfig MemtestStatelessConfig \
|
|
||||||
BroadcastRegressionTestConfig BufferlessRegressionTestConfig CacheRegressionTestConfig \
|
|
||||||
ComparatorConfig ComparatorBufferlessConfig ComparatorStatelessConfig
|
|
||||||
# FancyMemtestConfig takes too long to compile
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(SUITE),UnittestSuite)
|
ifeq ($(SUITE),UnittestSuite)
|
||||||
PROJECT=unittest
|
PROJECT=freechips.rocketchip.unittest
|
||||||
CONFIGS=UncoreUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig
|
CONFIGS=AMBAUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(SUITE), JtagDtmSuite)
|
ifeq ($(SUITE), JtagDtmSuite)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import util.GenericParameterizedBundle
|
import freechips.rocketchip.util.GenericParameterizedBundle
|
||||||
|
|
||||||
abstract class AHBBundleBase(params: AHBBundleParameters) extends GenericParameterizedBundle(params)
|
abstract class AHBBundleBase(params: AHBBundleParameters) extends GenericParameterizedBundle(params)
|
||||||
|
|
@ -1,11 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.diplomacy._
|
||||||
import diplomacy._
|
|
||||||
|
|
||||||
object AHBImp extends NodeImp[AHBMasterPortParameters, AHBSlavePortParameters, AHBEdgeParameters, AHBEdgeParameters, AHBBundle]
|
object AHBImp extends NodeImp[AHBMasterPortParameters, AHBSlavePortParameters, AHBEdgeParameters, AHBEdgeParameters, AHBBundle]
|
||||||
{
|
{
|
@ -1,10 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.diplomacy._
|
||||||
import diplomacy._
|
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
case class AHBSlaveParameters(
|
case class AHBSlaveParameters(
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
@ -1,11 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||||
|
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class AHBRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
class AHBRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
||||||
@ -57,7 +59,7 @@ class AHBRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int
|
|||||||
d_taken := Bool(false)
|
d_taken := Bool(false)
|
||||||
d_read := !ahb.hwrite
|
d_read := !ahb.hwrite
|
||||||
d_index := ahb.haddr >> log2Ceil(beatBytes)
|
d_index := ahb.haddr >> log2Ceil(beatBytes)
|
||||||
d_mask := uncore.tilelink2.maskGen(ahb.haddr, ahb.hsize, beatBytes)
|
d_mask := MaskGen(ahb.haddr, ahb.hsize, beatBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
out.ready := Bool(true)
|
out.ready := Bool(true)
|
||||||
@ -77,10 +79,10 @@ object AHBRegisterNode
|
|||||||
abstract class AHBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class AHBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = AHBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = AHBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
val intnode = IntSourceNode(IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AHBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AHBBundle])(implicit val p: Parameters)
|
case class AHBRegBundleArg(interrupts: HeterogeneousBag[Vec[Bool]], in: HeterogeneousBag[AHBBundle])(implicit val p: Parameters)
|
||||||
|
|
||||||
class AHBRegBundleBase(arg: AHBRegBundleArg) extends Bundle
|
class AHBRegBundleBase(arg: AHBRegBundleArg) extends Bundle
|
||||||
{
|
{
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class AHBRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4, fuzzHreadyout: Boolean = false)(implicit p: Parameters) extends LazyModule
|
class AHBRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4, fuzzHreadyout: Boolean = false)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
@ -35,7 +35,7 @@ class AHBRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4
|
|||||||
// The mask and address during the address phase
|
// The mask and address during the address phase
|
||||||
val a_access = in.htrans === AHBParameters.TRANS_NONSEQ || in.htrans === AHBParameters.TRANS_SEQ
|
val a_access = in.htrans === AHBParameters.TRANS_NONSEQ || in.htrans === AHBParameters.TRANS_SEQ
|
||||||
val a_request = in.hready && in.hsel && a_access
|
val a_request = in.hready && in.hsel && a_access
|
||||||
val a_mask = uncore.tilelink2.maskGen(in.haddr, in.hsize, beatBytes)
|
val a_mask = MaskGen(in.haddr, in.hsize, beatBytes)
|
||||||
val a_address = Cat((mask zip (in.haddr >> log2Ceil(beatBytes)).toBools).filter(_._1).map(_._2).reverse)
|
val a_address = Cat((mask zip (in.haddr >> log2Ceil(beatBytes)).toBools).filter(_._1).map(_._2).reverse)
|
||||||
val a_write = in.hwrite
|
val a_write = in.hwrite
|
||||||
|
|
@ -1,12 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.devices.tilelink.TLTestRAM
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.diplomacy._
|
||||||
import unittest._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.unittest._
|
||||||
|
|
||||||
class RRTest0(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter(address, 0, 32, 0, 4)(
|
class RRTest0(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter(address, 0, 32, 0, 4)(
|
||||||
new AHBRegBundle((), _) with RRTest0Bundle)(
|
new AHBRegBundle((), _) with RRTest0Bundle)(
|
@ -1,12 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util.MaskGen
|
||||||
|
|
||||||
case class AHBToTLNode() extends MixedAdapterNode(AHBImp, TLImp)(
|
case class AHBToTLNode() extends MixedAdapterNode(AHBImp, TLImp)(
|
||||||
dFn = { case AHBMasterPortParameters(masters) =>
|
dFn = { case AHBMasterPortParameters(masters) =>
|
||||||
@ -108,7 +109,7 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule
|
|||||||
out.a.bits.source := UInt(0)
|
out.a.bits.source := UInt(0)
|
||||||
out.a.bits.address := d_addr
|
out.a.bits.address := d_addr
|
||||||
out.a.bits.data := in.hwdata
|
out.a.bits.data := in.hwdata
|
||||||
out.a.bits.mask := maskGen(d_addr, d_size, beatBytes)
|
out.a.bits.mask := MaskGen(d_addr, d_size, beatBytes)
|
||||||
|
|
||||||
out.d.ready := d_recv // backpressure AccessAckData arriving faster than AHB beats
|
out.d.ready := d_recv // backpressure AccessAckData arriving faster than AHB beats
|
||||||
in.hrdata := out.d.bits.data
|
in.hrdata := out.d.bits.data
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.ahb
|
package freechips.rocketchip.amba.ahb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class AHBFanout()(implicit p: Parameters) extends LazyModule {
|
class AHBFanout()(implicit p: Parameters) extends LazyModule {
|
@ -1,9 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore
|
package freechips.rocketchip.amba
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy.OutwardNodeHandle
|
||||||
|
|
||||||
package object ahb
|
package object ahb
|
||||||
{
|
{
|
@ -1,9 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import util.GenericParameterizedBundle
|
import freechips.rocketchip.util.GenericParameterizedBundle
|
||||||
|
|
||||||
abstract class APBBundleBase(params: APBBundleParameters) extends GenericParameterizedBundle(params)
|
abstract class APBBundleBase(params: APBBundleParameters) extends GenericParameterizedBundle(params)
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
|
||||||
object APBImp extends NodeImp[APBMasterPortParameters, APBSlavePortParameters, APBEdgeParameters, APBEdgeParameters, APBBundle]
|
object APBImp extends NodeImp[APBMasterPortParameters, APBSlavePortParameters, APBEdgeParameters, APBEdgeParameters, APBBundle]
|
||||||
{
|
{
|
@ -1,10 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
case class APBSlaveParameters(
|
case class APBSlaveParameters(
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
@ -1,11 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||||
|
import freechips.rocketchip.util.HeterogeneousBag
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class APBRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
class APBRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
||||||
@ -61,10 +63,10 @@ object APBRegisterNode
|
|||||||
abstract class APBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class APBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = APBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = APBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
val intnode = IntSourceNode(IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class APBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[APBBundle])(implicit val p: Parameters)
|
case class APBRegBundleArg(interrupts: HeterogeneousBag[Vec[Bool]], in: HeterogeneousBag[APBBundle])(implicit val p: Parameters)
|
||||||
|
|
||||||
class APBRegBundleBase(arg: APBRegBundleArg) extends Bundle
|
class APBRegBundleBase(arg: APBRegBundleArg) extends Bundle
|
||||||
{
|
{
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class APBRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class APBRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,12 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
import unittest._
|
import freechips.rocketchip.unittest._
|
||||||
|
|
||||||
class RRTest0(address: BigInt)(implicit p: Parameters) extends APBRegisterRouter(address, 0, 32, 0, 4)(
|
class RRTest0(address: BigInt)(implicit p: Parameters) extends APBRegisterRouter(address, 0, 32, 0, 4)(
|
||||||
new APBRegBundle((), _) with RRTest0Bundle)(
|
new APBRegBundle((), _) with RRTest0Bundle)(
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.apb
|
package freechips.rocketchip.amba.apb
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class APBFanout()(implicit p: Parameters) extends LazyModule {
|
class APBFanout()(implicit p: Parameters) extends LazyModule {
|
@ -1,9 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore
|
package freechips.rocketchip.amba
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy.OutwardNodeHandle
|
||||||
|
|
||||||
package object apb
|
package object apb
|
||||||
{
|
{
|
@ -1,12 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import chisel3.util.IrrevocableIO
|
import chisel3.util.IrrevocableIO
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
// pipe is only used if a queue has depth = 1
|
// pipe is only used if a queue has depth = 1
|
@ -1,10 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.Irrevocable
|
import chisel3.util.Irrevocable
|
||||||
import util.GenericParameterizedBundle
|
import freechips.rocketchip.util.GenericParameterizedBundle
|
||||||
|
|
||||||
abstract class AXI4BundleBase(params: AXI4BundleParameters) extends GenericParameterizedBundle(params)
|
abstract class AXI4BundleBase(params: AXI4BundleParameters) extends GenericParameterizedBundle(params)
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import chisel3.util.IrrevocableIO
|
import chisel3.util.IrrevocableIO
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.util.{leftOR, rightOR, UIntToOH1, OH1ToOH}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH}
|
|
||||||
|
|
||||||
class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyModule
|
class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,14 +1,14 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import chisel3.util.IrrevocableIO
|
import chisel3.util.IrrevocableIO
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.util.{leftOR, rightOR, UIntToOH1, OH1ToOH}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH}
|
|
||||||
|
|
||||||
class AXI4Fragmenter()(implicit p: Parameters) extends LazyModule
|
class AXI4Fragmenter()(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule
|
class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
|
||||||
object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4EdgeParameters, AXI4EdgeParameters, AXI4Bundle]
|
object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4EdgeParameters, AXI4EdgeParameters, AXI4Bundle]
|
||||||
{
|
{
|
@ -1,10 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
case class AXI4SlaveParameters(
|
case class AXI4SlaveParameters(
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{Irrevocable, IrrevocableIO}
|
import chisel3.util.{Irrevocable, IrrevocableIO}
|
@ -1,11 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||||
|
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
||||||
@ -43,7 +45,7 @@ class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int
|
|||||||
val aw_extra = Cat(Seq(aw.bits.id) ++ aw.bits.user.toList)
|
val aw_extra = Cat(Seq(aw.bits.id) ++ aw.bits.user.toList)
|
||||||
val in_extra = Mux(ar.valid, ar_extra, aw_extra)
|
val in_extra = Mux(ar.valid, ar_extra, aw_extra)
|
||||||
val addr = Mux(ar.valid, ar.bits.addr, aw.bits.addr)
|
val addr = Mux(ar.valid, ar.bits.addr, aw.bits.addr)
|
||||||
val mask = uncore.tilelink2.maskGen(ar.bits.addr, ar.bits.size, beatBytes)
|
val mask = MaskGen(ar.bits.addr, ar.bits.size, beatBytes)
|
||||||
|
|
||||||
in.bits.read := ar.valid
|
in.bits.read := ar.valid
|
||||||
in.bits.index := addr >> log2Ceil(beatBytes)
|
in.bits.index := addr >> log2Ceil(beatBytes)
|
||||||
@ -87,10 +89,10 @@ object AXI4RegisterNode
|
|||||||
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
val intnode = IntSourceNode(IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AXI4RegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AXI4Bundle])(implicit val p: Parameters)
|
case class AXI4RegBundleArg(interrupts: HeterogeneousBag[Vec[Bool]], in: HeterogeneousBag[AXI4Bundle])(implicit val p: Parameters)
|
||||||
|
|
||||||
class AXI4RegBundleBase(arg: AXI4RegBundleArg) extends Bundle
|
class AXI4RegBundleBase(arg: AXI4RegBundleArg) extends Bundle
|
||||||
{
|
{
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class AXI4RAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class AXI4RAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,12 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.devices.tilelink.TLError
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.diplomacy._
|
||||||
import unittest._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.unittest._
|
||||||
|
|
||||||
class RRTest0(address: BigInt)(implicit p: Parameters) extends AXI4RegisterRouter(address, 0, 32, 0, 4)(
|
class RRTest0(address: BigInt)(implicit p: Parameters) extends AXI4RegisterRouter(address, 0, 32, 0, 4)(
|
||||||
new AXI4RegBundle((), _) with RRTest0Bundle)(
|
new AXI4RegBundle((), _) with RRTest0Bundle)(
|
@ -1,12 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
||||||
dFn = { case AXI4MasterPortParameters(masters, userBits) =>
|
dFn = { case AXI4MasterPortParameters(masters, userBits) =>
|
@ -1,12 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.axi4
|
package freechips.rocketchip.amba.axi4
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.tilelink2.UIntToOH1
|
import freechips.rocketchip.util.UIntToOH1
|
||||||
|
|
||||||
class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) extends LazyModule
|
class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,9 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore
|
package freechips.rocketchip.amba
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy.OutwardNodeHandle
|
||||||
|
|
||||||
package object axi4
|
package object axi4
|
||||||
{
|
{
|
@ -1,24 +1,24 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import junctions._
|
|
||||||
import rocket._
|
import freechips.rocketchip.config._
|
||||||
import diplomacy._
|
import freechips.rocketchip.coreplex._
|
||||||
import uncore.agents._
|
import freechips.rocketchip.devices._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.devices._
|
import freechips.rocketchip.rocket._
|
||||||
import uncore.converters._
|
import freechips.rocketchip.tile.XLen
|
||||||
import util._
|
import freechips.rocketchip.tilelink._
|
||||||
import coreplex._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
import scala.collection.mutable.{LinkedHashSet, ListBuffer}
|
import scala.collection.mutable.{LinkedHashSet, ListBuffer}
|
||||||
import scala.collection.immutable.HashMap
|
import scala.collection.immutable.HashMap
|
||||||
|
|
||||||
import DefaultTestSuites._
|
import DefaultTestSuites._
|
||||||
import config._
|
|
||||||
import tile.XLen
|
|
||||||
|
|
||||||
class BasePlatformConfig extends Config((site, here, up) => {
|
class BasePlatformConfig extends Config((site, here, up) => {
|
||||||
// DTS descriptive parameters
|
// DTS descriptive parameters
|
||||||
@ -49,33 +49,23 @@ class BasePlatformConfig extends Config((site, here, up) => {
|
|||||||
class BaseConfig extends Config(new BaseCoreplexConfig ++ new BasePlatformConfig)
|
class BaseConfig extends Config(new BaseCoreplexConfig ++ new BasePlatformConfig)
|
||||||
class DefaultConfig extends Config(new WithNBigCores(1) ++ new BaseConfig)
|
class DefaultConfig extends Config(new WithNBigCores(1) ++ new BaseConfig)
|
||||||
|
|
||||||
class DefaultL2Config extends Config(new WithL2Cache ++ new WithNBigCores(1) ++ new BaseConfig)
|
|
||||||
class DefaultBufferlessConfig extends Config(
|
class DefaultBufferlessConfig extends Config(
|
||||||
new WithBufferlessBroadcastHub ++ new WithNBigCores(1) ++ new BaseConfig)
|
new WithBufferlessBroadcastHub ++ new WithNBigCores(1) ++ new BaseConfig)
|
||||||
|
|
||||||
class FPGAConfig extends Config(Parameters.empty)
|
class FPGAConfig extends Config(Parameters.empty)
|
||||||
class DefaultFPGAConfig extends Config(new FPGAConfig ++ new BaseConfig)
|
class DefaultFPGAConfig extends Config(new FPGAConfig ++ new BaseConfig)
|
||||||
class DefaultL2FPGAConfig extends Config(
|
|
||||||
new WithL2Capacity(64) ++ new WithL2Cache ++ new DefaultFPGAConfig)
|
|
||||||
|
|
||||||
class DefaultSmallConfig extends Config(new WithNSmallCores(1) ++ new BaseConfig)
|
class DefaultSmallConfig extends Config(new WithNSmallCores(1) ++ new BaseConfig)
|
||||||
class DefaultRV32Config extends Config(new WithRV32 ++ new DefaultConfig)
|
class DefaultRV32Config extends Config(new WithRV32 ++ new DefaultConfig)
|
||||||
|
|
||||||
class DualBankConfig extends Config(
|
class DualBankConfig extends Config(
|
||||||
new WithNBanksPerMemChannel(2) ++ new BaseConfig)
|
new WithNBanksPerMemChannel(2) ++ new BaseConfig)
|
||||||
class DualBankL2Config extends Config(
|
|
||||||
new WithNBanksPerMemChannel(2) ++ new WithL2Cache ++ new BaseConfig)
|
|
||||||
|
|
||||||
class DualChannelConfig extends Config(new WithNMemoryChannels(2) ++ new BaseConfig)
|
class DualChannelConfig extends Config(new WithNMemoryChannels(2) ++ new BaseConfig)
|
||||||
class DualChannelL2Config extends Config(
|
|
||||||
new WithNMemoryChannels(2) ++ new WithL2Cache ++ new BaseConfig)
|
|
||||||
|
|
||||||
class DualChannelDualBankConfig extends Config(
|
class DualChannelDualBankConfig extends Config(
|
||||||
new WithNMemoryChannels(2) ++
|
new WithNMemoryChannels(2) ++
|
||||||
new WithNBanksPerMemChannel(2) ++ new BaseConfig)
|
new WithNBanksPerMemChannel(2) ++ new BaseConfig)
|
||||||
class DualChannelDualBankL2Config extends Config(
|
|
||||||
new WithNMemoryChannels(2) ++ new WithNBanksPerMemChannel(2) ++
|
|
||||||
new WithL2Cache ++ new BaseConfig)
|
|
||||||
|
|
||||||
class RoccExampleConfig extends Config(new WithRoccExample ++ new DefaultConfig)
|
class RoccExampleConfig extends Config(new WithRoccExample ++ new DefaultConfig)
|
||||||
|
|
||||||
@ -84,11 +74,7 @@ class Edge128BitConfig extends Config(
|
|||||||
class Edge32BitConfig extends Config(
|
class Edge32BitConfig extends Config(
|
||||||
new WithEdgeDataBits(32) ++ new BaseConfig)
|
new WithEdgeDataBits(32) ++ new BaseConfig)
|
||||||
|
|
||||||
class SmallL2Config extends Config(
|
class SingleChannelBenchmarkConfig extends Config(new DefaultConfig)
|
||||||
new WithNMemoryChannels(2) ++ new WithNBanksPerMemChannel(4) ++
|
|
||||||
new WithL2Capacity(256) ++ new DefaultL2Config)
|
|
||||||
|
|
||||||
class SingleChannelBenchmarkConfig extends Config(new WithL2Capacity(256) ++ new DefaultL2Config)
|
|
||||||
class DualChannelBenchmarkConfig extends Config(new WithNMemoryChannels(2) ++ new SingleChannelBenchmarkConfig)
|
class DualChannelBenchmarkConfig extends Config(new WithNMemoryChannels(2) ++ new SingleChannelBenchmarkConfig)
|
||||||
class QuadChannelBenchmarkConfig extends Config(new WithNMemoryChannels(4) ++ new SingleChannelBenchmarkConfig)
|
class QuadChannelBenchmarkConfig extends Config(new WithNMemoryChannels(4) ++ new SingleChannelBenchmarkConfig)
|
||||||
class OctoChannelBenchmarkConfig extends Config(new WithNMemoryChannels(8) ++ new SingleChannelBenchmarkConfig)
|
class OctoChannelBenchmarkConfig extends Config(new WithNMemoryChannels(8) ++ new SingleChannelBenchmarkConfig)
|
||||||
@ -96,9 +82,9 @@ class OctoChannelBenchmarkConfig extends Config(new WithNMemoryChannels(8) ++ ne
|
|||||||
class EightChannelConfig extends Config(new WithNMemoryChannels(8) ++ new BaseConfig)
|
class EightChannelConfig extends Config(new WithNMemoryChannels(8) ++ new BaseConfig)
|
||||||
|
|
||||||
class DualCoreConfig extends Config(
|
class DualCoreConfig extends Config(
|
||||||
new WithNBigCores(2) ++ new WithL2Cache ++ new BaseConfig)
|
new WithNBigCores(2) ++ new BaseConfig)
|
||||||
class HeterogeneousDualCoreConfig extends Config(
|
class HeterogeneousDualCoreConfig extends Config(
|
||||||
new WithNSmallCores(1) ++ new WithNBigCores(1) ++ new WithL2Cache ++ new BaseConfig)
|
new WithNSmallCores(1) ++ new WithNBigCores(1) ++ new BaseConfig)
|
||||||
|
|
||||||
class TinyConfig extends Config(
|
class TinyConfig extends Config(
|
||||||
new WithNMemoryChannels(0) ++
|
new WithNMemoryChannels(0) ++
|
@ -1,12 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import util._
|
|
||||||
import config._
|
import freechips.rocketchip.config._
|
||||||
import jtag._
|
import freechips.rocketchip.devices.debug.{DMIConsts, DMIIO, DMIReq, DMIResp}
|
||||||
import uncore.devices.{DMIConsts, DMIIO, DMIReq, DMIResp}
|
import freechips.rocketchip.jtag._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
case object IncludeJtagDTM extends Field[Boolean]
|
case object IncludeJtagDTM extends Field[Boolean]
|
||||||
|
|
@ -1,11 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import junctions._
|
import freechips.rocketchip.config.Parameters
|
||||||
import rocketchip._
|
|
||||||
|
|
||||||
/** Example system with periphery devices (w/o coreplex) */
|
/** Example system with periphery devices (w/o coreplex) */
|
||||||
abstract class ExampleSystem(implicit p: Parameters) extends BaseSystem
|
abstract class ExampleSystem(implicit p: Parameters) extends BaseSystem
|
@ -1,14 +1,15 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import tile.XLen
|
import freechips.rocketchip.coreplex.RocketTilesKey
|
||||||
import coreplex.RocketTilesKey
|
import freechips.rocketchip.tile.XLen
|
||||||
|
import freechips.rocketchip.util.GeneratorApp
|
||||||
|
|
||||||
import scala.collection.mutable.LinkedHashSet
|
import scala.collection.mutable.LinkedHashSet
|
||||||
|
|
||||||
/** A Generator for platforms containing Rocket Coreplexes */
|
/** A Generator for platforms containing Rocket Coreplexes */
|
||||||
object Generator extends util.GeneratorApp {
|
object Generator extends GeneratorApp {
|
||||||
|
|
||||||
val rv64RegrTestNames = LinkedHashSet(
|
val rv64RegrTestNames = LinkedHashSet(
|
||||||
"rv64ud-v-fcvt",
|
"rv64ud-v-fcvt",
|
@ -1,14 +1,17 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import coreplex._
|
import freechips.rocketchip.config._
|
||||||
import diplomacy._
|
import freechips.rocketchip.coreplex._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.devices.tilelink._
|
||||||
import uncore.axi4._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.amba.axi4._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
/** Specifies the size of external memory */
|
/** Specifies the size of external memory */
|
||||||
@ -42,7 +45,7 @@ trait HasPeripheryParameters {
|
|||||||
def socBusBytes = socBusConfig.beatBytes
|
def socBusBytes = socBusConfig.beatBytes
|
||||||
def cacheBlockBytes = p(CacheBlockBytes)
|
def cacheBlockBytes = p(CacheBlockBytes)
|
||||||
def peripheryBusArithmetic = p(PeripheryBusArithmetic)
|
def peripheryBusArithmetic = p(PeripheryBusArithmetic)
|
||||||
def nMemoryChannels = p(coreplex.BankedL2Config).nMemoryChannels
|
def nMemoryChannels = p(BankedL2Config).nMemoryChannels
|
||||||
def nExtInterrupts = p(NExtTopInterrupts)
|
def nExtInterrupts = p(NExtTopInterrupts)
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,17 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import coreplex._
|
import freechips.rocketchip.config._
|
||||||
import diplomacy._
|
import freechips.rocketchip.devices.debug._
|
||||||
import jtag.JTAGIO
|
import freechips.rocketchip.devices.tilelink._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.coreplex._
|
||||||
import uncore.devices._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.jtag.JTAGIO
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
/** All the traits defined in this file assume that they are being mixed in
|
/** All the traits defined in this file assume that they are being mixed in
|
||||||
* to a system that has a standard RISCV-based coreplex platform.
|
* to a system that has a standard RISCV-based coreplex platform.
|
||||||
@ -89,7 +91,7 @@ trait HasPeripheryRTCCounter extends HasSystemNetworks with HasCoreplexRISCVPlat
|
|||||||
|
|
||||||
trait HasPeripheryRTCCounterModuleImp extends LazyMultiIOModuleImp {
|
trait HasPeripheryRTCCounterModuleImp extends LazyMultiIOModuleImp {
|
||||||
val outer: HasPeripheryRTCCounter
|
val outer: HasPeripheryRTCCounter
|
||||||
val period = p(rocketchip.RTCPeriod)
|
val period = p(RTCPeriod)
|
||||||
val rtcCounter = RegInit(UInt(0, width = log2Up(period)))
|
val rtcCounter = RegInit(UInt(0, width = log2Up(period)))
|
||||||
val rtcWrap = rtcCounter === UInt(period-1)
|
val rtcWrap = rtcCounter === UInt(period-1)
|
||||||
|
|
@ -1,10 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import coreplex.RocketPlex
|
|
||||||
import diplomacy.{LazyModule, LazyMultiIOModuleImp}
|
import freechips.rocketchip.coreplex.RocketPlex
|
||||||
|
import freechips.rocketchip.diplomacy.{LazyModule, LazyMultiIOModuleImp}
|
||||||
|
|
||||||
/** Add a RocketPlex to the system */
|
/** Add a RocketPlex to the system */
|
||||||
trait HasRocketPlexMaster extends HasSystemNetworks with HasCoreplexRISCVPlatform {
|
trait HasRocketPlexMaster extends HasSystemNetworks with HasCoreplexRISCVPlatform {
|
@ -1,9 +1,8 @@
|
|||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import scala.collection.mutable.LinkedHashSet
|
import scala.collection.mutable.LinkedHashSet
|
||||||
|
|
||||||
abstract class RocketTestSuite {
|
abstract class RocketTestSuite {
|
@ -1,11 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config.Parameters
|
|
||||||
import diplomacy._
|
import freechips.rocketchip.config.Parameters
|
||||||
import util._
|
import freechips.rocketchip.diplomacy.{LazyModule, LazyMultiIOModuleImp}
|
||||||
|
import freechips.rocketchip.util.ElaborationArtefacts
|
||||||
|
|
||||||
/** BareSystem is the root class for creating a top-level RTL module */
|
/** BareSystem is the root class for creating a top-level RTL module */
|
||||||
abstract class BareSystem(implicit p: Parameters) extends LazyModule {
|
abstract class BareSystem(implicit p: Parameters) extends LazyModule {
|
@ -1,14 +1,15 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import junctions._
|
import freechips.rocketchip.amba.axi4._
|
||||||
import diplomacy._
|
import freechips.rocketchip.config.Parameters
|
||||||
import coreplex._
|
import freechips.rocketchip.coreplex._
|
||||||
import uncore.axi4._
|
import freechips.rocketchip.devices.debug._
|
||||||
import jtag.JTAGIO
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.jtag.JTAGIO
|
||||||
|
|
||||||
class TestHarness()(implicit p: Parameters) extends Module {
|
class TestHarness()(implicit p: Parameters) extends Module {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
@ -52,11 +53,11 @@ class SimDTM(implicit p: Parameters) extends BlackBox {
|
|||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val clk = Clock(INPUT)
|
val clk = Clock(INPUT)
|
||||||
val reset = Bool(INPUT)
|
val reset = Bool(INPUT)
|
||||||
val debug = new uncore.devices.DMIIO
|
val debug = new DMIIO
|
||||||
val exit = UInt(OUTPUT, 32)
|
val exit = UInt(OUTPUT, 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.ClockedDMIIO, tbsuccess: Bool) = {
|
def connect(tbclk: Clock, tbreset: Bool, dutio: ClockedDMIIO, tbsuccess: Bool) = {
|
||||||
io.clk := tbclk
|
io.clk := tbclk
|
||||||
io.reset := tbreset
|
io.reset := tbreset
|
||||||
dutio.dmi <> io.debug
|
dutio.dmi <> io.debug
|
@ -1,18 +1,13 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package rocketchip
|
package freechips.rocketchip.chip
|
||||||
|
|
||||||
import config._
|
|
||||||
import junctions._
|
|
||||||
import diplomacy._
|
|
||||||
import uncore.devices._
|
|
||||||
import tile.XLen
|
|
||||||
import coreplex._
|
|
||||||
import uncore.tilelink2._
|
|
||||||
import util._
|
|
||||||
|
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
|
import freechips.rocketchip.diplomacy.DTB
|
||||||
|
import freechips.rocketchip.coreplex.BootROMFile
|
||||||
import java.nio.file.{Files, Paths}
|
import java.nio.file.{Files, Paths}
|
||||||
import java.nio.{ByteBuffer, ByteOrder}
|
import java.nio.{ByteBuffer, ByteOrder}
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
class RangeManager {
|
class RangeManager {
|
||||||
private var finalized = false
|
private var finalized = false
|
||||||
@ -39,7 +34,7 @@ class RangeManager {
|
|||||||
|
|
||||||
class ResourceManager[T] {
|
class ResourceManager[T] {
|
||||||
private var finalized = false
|
private var finalized = false
|
||||||
private val l = collection.mutable.ArrayBuffer[T]()
|
private val l = ArrayBuffer[T]()
|
||||||
def add(element: T) = { require(!finalized); l += element }
|
def add(element: T) = { require(!finalized); l += element }
|
||||||
def add(list: Seq[T]) = { require(!finalized); l ++= list }
|
def add(list: Seq[T]) = { require(!finalized); l ++= list }
|
||||||
def get: Seq[T] = { finalized = true; l }
|
def get: Seq[T] = { finalized = true; l }
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package config
|
package freechips.rocketchip.config
|
||||||
|
|
||||||
class Field[T]
|
class Field[T]
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import diplomacy._
|
import freechips.rocketchip.config._
|
||||||
import tile.XLen
|
import freechips.rocketchip.diplomacy._
|
||||||
import tile.TileInterrupts
|
import freechips.rocketchip.tile.{ XLen, TileInterrupts}
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
/** Widths of various points in the SoC */
|
/** Widths of various points in the SoC */
|
||||||
case class TLBusConfig(beatBytes: Int)
|
case class TLBusConfig(beatBytes: Int)
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import diplomacy._
|
import freechips.rocketchip.config._
|
||||||
import rocket._
|
import freechips.rocketchip.devices.debug._
|
||||||
import tile._
|
import freechips.rocketchip.devices.tilelink._
|
||||||
import uncore.converters._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.devices._
|
import freechips.rocketchip.rocket._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tile._
|
||||||
import uncore.util._
|
import freechips.rocketchip.tilelink._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class BaseCoreplexConfig extends Config ((site, here, up) => {
|
class BaseCoreplexConfig extends Config ((site, here, up) => {
|
||||||
case PAddrBits => 32
|
case PAddrBits => 32
|
||||||
@ -20,14 +20,13 @@ class BaseCoreplexConfig extends Config ((site, here, up) => {
|
|||||||
case ASIdBits => 0
|
case ASIdBits => 0
|
||||||
case XLen => 64 // Applies to all cores
|
case XLen => 64 // Applies to all cores
|
||||||
case ResetVectorBits => site(PAddrBits)
|
case ResetVectorBits => site(PAddrBits)
|
||||||
case MaxHartIdBits => log2Up(site(NTiles))
|
case MaxHartIdBits => log2Up(site(RocketTilesKey).size)
|
||||||
case BuildCore => (p: Parameters) => new Rocket()(p)
|
case BuildCore => (p: Parameters) => new Rocket()(p)
|
||||||
case RocketCrossing => SynchronousCrossing()
|
case RocketCrossing => SynchronousCrossing()
|
||||||
case RocketTilesKey => Nil
|
case RocketTilesKey => Nil
|
||||||
case DMKey => DefaultDebugModuleConfig(site(XLen))
|
case DMKey => DefaultDebugModuleConfig(site(XLen))
|
||||||
case PLICKey => PLICParams()
|
case PLICKey => PLICParams()
|
||||||
case ClintKey => ClintParams()
|
case ClintKey => ClintParams()
|
||||||
case NTiles => site(RocketTilesKey).size
|
|
||||||
case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8)
|
case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8)
|
||||||
case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth
|
case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth
|
||||||
case BootROMFile => "./bootrom/bootrom.img"
|
case BootROMFile => "./bootrom/bootrom.img"
|
||||||
@ -112,10 +111,6 @@ class WithCacheBlockBytes(linesize: Int) extends Config((site, here, up) => {
|
|||||||
case CacheBlockBytes => linesize
|
case CacheBlockBytes => linesize
|
||||||
})
|
})
|
||||||
|
|
||||||
class WithL2Cache extends Config(Parameters.empty) // TODO: re-add L2
|
|
||||||
class WithL2Capacity(size_kb: Int) extends Config(Parameters.empty) // TODO: re-add L2
|
|
||||||
class WithNL2Ways(n: Int) extends Config(Parameters.empty) // TODO: re-add L2
|
|
||||||
|
|
||||||
class WithBufferlessBroadcastHub extends Config((site, here, up) => {
|
class WithBufferlessBroadcastHub extends Config((site, here, up) => {
|
||||||
case BroadcastConfig => up(BroadcastConfig, site).copy(bufferless = true)
|
case BroadcastConfig => up(BroadcastConfig, site).copy(bufferless = true)
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import diplomacy._
|
import freechips.rocketchip.config._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.diplomacy._
|
||||||
import uncore.util._
|
import freechips.rocketchip.rocket.PAddrBits
|
||||||
import util._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
trait CoreplexNetwork extends HasCoreplexParameters {
|
trait CoreplexNetwork extends HasCoreplexParameters {
|
||||||
val module: CoreplexNetworkModule
|
val module: CoreplexNetworkModule
|
||||||
@ -112,7 +113,7 @@ trait CoreplexNetworkModule extends HasCoreplexParameters {
|
|||||||
val io: CoreplexNetworkBundle
|
val io: CoreplexNetworkBundle
|
||||||
|
|
||||||
println("Generated Address Map")
|
println("Generated Address Map")
|
||||||
private val aw = (outer.p(rocket.PAddrBits)-1)/4 + 1
|
private val aw = (outer.p(PAddrBits)-1)/4 + 1
|
||||||
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c %s"
|
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c %s"
|
||||||
|
|
||||||
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.diplomacy.LazyModule
|
||||||
import diplomacy._
|
import freechips.rocketchip.tilelink._
|
||||||
import rocket._
|
|
||||||
import tile._
|
|
||||||
import uncore.tilelink2._
|
|
||||||
import util._
|
|
||||||
|
|
||||||
trait HasISPPort extends CoreplexNetwork {
|
trait HasISPPort extends CoreplexNetwork {
|
||||||
val module: HasISPPortModule
|
val module: HasISPPortModule
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config.Field
|
|
||||||
import diplomacy._
|
|
||||||
import tile._
|
|
||||||
import uncore.tilelink2._
|
|
||||||
import uncore.devices._
|
|
||||||
import util._
|
|
||||||
|
|
||||||
/** Number of tiles */
|
import freechips.rocketchip.config.Field
|
||||||
case object NTiles extends Field[Int]
|
import freechips.rocketchip.devices.debug._
|
||||||
|
import freechips.rocketchip.devices.tilelink._
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.tile._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
case object PLICKey extends Field[PLICParams]
|
case object PLICKey extends Field[PLICParams]
|
||||||
case object ClintKey extends Field[ClintParams]
|
case object ClintKey extends Field[ClintParams]
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config.Parameters
|
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
|
|
||||||
class RocketPlex(implicit p: Parameters) extends BaseCoreplex
|
class RocketPlex(implicit p: Parameters) extends BaseCoreplex
|
||||||
with CoreplexRISCVPlatform
|
with CoreplexRISCVPlatform
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Field
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import rocket._
|
import freechips.rocketchip.rocket._
|
||||||
import tile._
|
import freechips.rocketchip.tile._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
import util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
sealed trait ClockCrossing
|
sealed trait CoreplexClockCrossing
|
||||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends ClockCrossing
|
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends ClockCrossing
|
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||||
case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends ClockCrossing
|
case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends CoreplexClockCrossing
|
||||||
|
|
||||||
case object RocketTilesKey extends Field[Seq[RocketTileParams]]
|
case object RocketTilesKey extends Field[Seq[RocketTileParams]]
|
||||||
case object RocketCrossing extends Field[ClockCrossing]
|
case object RocketCrossing extends Field[CoreplexClockCrossing]
|
||||||
|
|
||||||
trait HasRocketTiles extends CoreplexRISCVPlatform {
|
trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||||
val module: HasRocketTilesModule
|
val module: HasRocketTilesModule
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.devices
|
package freechips.rocketchip.devices.debug
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import junctions._
|
import freechips.rocketchip.config._
|
||||||
import util._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import tile.XLen
|
import freechips.rocketchip.rocket.Instructions
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tile.XLen
|
||||||
import config._
|
import freechips.rocketchip.tilelink._
|
||||||
import diplomacy._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
|
|
||||||
/** Constant values used by both Debug Bus Response & Request
|
/** Constant values used by both Debug Bus Response & Request
|
||||||
*/
|
*/
|
||||||
@ -756,7 +755,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
|
|||||||
|
|
||||||
val goReg = Reg(Bool())
|
val goReg = Reg(Bool())
|
||||||
val goAbstract = Wire(init = false.B)
|
val goAbstract = Wire(init = false.B)
|
||||||
val jalAbstract = Wire(init = (new GeneratedUJ()).fromBits(rocket.Instructions.JAL.value.U))
|
val jalAbstract = Wire(init = (new GeneratedUJ()).fromBits(Instructions.JAL.value.U))
|
||||||
jalAbstract.setImm(ABSTRACT(cfg) - WHERETO)
|
jalAbstract.setImm(ABSTRACT(cfg) - WHERETO)
|
||||||
|
|
||||||
when (~io.dmactive){
|
when (~io.dmactive){
|
||||||
@ -838,20 +837,20 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
|
|||||||
val abstractGeneratedS = Wire(new GeneratedS())
|
val abstractGeneratedS = Wire(new GeneratedS())
|
||||||
val nop = Wire(new GeneratedI())
|
val nop = Wire(new GeneratedI())
|
||||||
|
|
||||||
abstractGeneratedI.opcode := ((new GeneratedI()).fromBits(rocket.Instructions.LW.value.U)).opcode
|
abstractGeneratedI.opcode := ((new GeneratedI()).fromBits(Instructions.LW.value.U)).opcode
|
||||||
abstractGeneratedI.rd := (accessRegisterCommandReg.regno & 0x1F.U)
|
abstractGeneratedI.rd := (accessRegisterCommandReg.regno & 0x1F.U)
|
||||||
abstractGeneratedI.funct3 := accessRegisterCommandReg.size
|
abstractGeneratedI.funct3 := accessRegisterCommandReg.size
|
||||||
abstractGeneratedI.rs1 := 0.U
|
abstractGeneratedI.rs1 := 0.U
|
||||||
abstractGeneratedI.imm := DATA.U
|
abstractGeneratedI.imm := DATA.U
|
||||||
|
|
||||||
abstractGeneratedS.opcode := ((new GeneratedS()).fromBits(rocket.Instructions.SW.value.U)).opcode
|
abstractGeneratedS.opcode := ((new GeneratedS()).fromBits(Instructions.SW.value.U)).opcode
|
||||||
abstractGeneratedS.immlo := (DATA & 0x1F).U
|
abstractGeneratedS.immlo := (DATA & 0x1F).U
|
||||||
abstractGeneratedS.funct3 := accessRegisterCommandReg.size
|
abstractGeneratedS.funct3 := accessRegisterCommandReg.size
|
||||||
abstractGeneratedS.rs1 := 0.U
|
abstractGeneratedS.rs1 := 0.U
|
||||||
abstractGeneratedS.rs2 := (accessRegisterCommandReg.regno & 0x1F.U)
|
abstractGeneratedS.rs2 := (accessRegisterCommandReg.regno & 0x1F.U)
|
||||||
abstractGeneratedS.immhi := (DATA >> 5).U
|
abstractGeneratedS.immhi := (DATA >> 5).U
|
||||||
|
|
||||||
nop := ((new GeneratedI()).fromBits(rocket.Instructions.ADDI.value.U))
|
nop := ((new GeneratedI()).fromBits(Instructions.ADDI.value.U))
|
||||||
nop.rd := 0.U
|
nop.rd := 0.U
|
||||||
nop.rs1 := 0.U
|
nop.rs1 := 0.U
|
||||||
nop.imm := 0.U
|
nop.imm := 0.U
|
||||||
@ -867,7 +866,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
|
|||||||
)
|
)
|
||||||
abstractGeneratedMem(1) := Mux(accessRegisterCommandReg.postexec,
|
abstractGeneratedMem(1) := Mux(accessRegisterCommandReg.postexec,
|
||||||
nop.asUInt(),
|
nop.asUInt(),
|
||||||
rocket.Instructions.EBREAK.value.U)
|
Instructions.EBREAK.value.U)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
@ -1,6 +1,6 @@
|
|||||||
// This file was auto-generated by 'make publish' in debug/ directory.
|
// This file was auto-generated by 'make publish' in debug/ directory.
|
||||||
|
|
||||||
package uncore.devices
|
package freechips.rocketchip.devices.debug
|
||||||
|
|
||||||
object DebugRomContents {
|
object DebugRomContents {
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package uncore.devices
|
package freechips.rocketchip.devices.debug
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package uncore.devices
|
package freechips.rocketchip.devices.debug
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
@ -1,18 +1,15 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.devices
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import junctions._
|
import freechips.rocketchip.config.Parameters
|
||||||
import junctions.NastiConstants._
|
import freechips.rocketchip.diplomacy._
|
||||||
import regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import diplomacy._
|
import freechips.rocketchip.tile.XLen
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
import uncore.util._
|
import freechips.rocketchip.util._
|
||||||
import util._
|
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
import config._
|
|
||||||
import tile.XLen
|
|
||||||
|
|
||||||
object ClintConsts
|
object ClintConsts
|
||||||
{
|
{
|
@ -1,11 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class TLError(address: Seq[AddressSet], beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLError(address: Seq[AddressSet], beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,18 +1,16 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.devices
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import Chisel.ImplicitConversions._
|
import Chisel.ImplicitConversions._
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
import junctions._
|
import freechips.rocketchip.diplomacy._
|
||||||
import diplomacy._
|
import freechips.rocketchip.regmapper._
|
||||||
import regmapper._
|
import freechips.rocketchip.tile.XLen
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tilelink._
|
||||||
import config._
|
import freechips.rocketchip.util._
|
||||||
import scala.math.min
|
import scala.math.min
|
||||||
import tile.XLen
|
|
||||||
import util._
|
|
||||||
|
|
||||||
class GatewayPLICIO extends Bundle {
|
class GatewayPLICIO extends Bundle {
|
||||||
val valid = Bool(OUTPUT)
|
val valid = Bool(OUTPUT)
|
52
src/main/scala/devices/tilelink/Rom.scala
Normal file
52
src/main/scala/devices/tilelink/Rom.scala
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
|
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4,
|
||||||
|
resources: Seq[Resource] = new SimpleDevice("rom", Seq("sifive,rom0")).reg("mem"))(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
|
||||||
|
val node = TLManagerNode(beatBytes, TLManagerParameters (
|
||||||
|
address = List(AddressSet(base, size-1)),
|
||||||
|
resources = resources,
|
||||||
|
regionType = RegionType.UNCACHED,
|
||||||
|
executable = executable,
|
||||||
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
fifoId = Some(0)))
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
|
||||||
|
val contents = contentsDelayed
|
||||||
|
val wrapSize = 1 << log2Ceil(contents.size)
|
||||||
|
require (wrapSize <= size)
|
||||||
|
|
||||||
|
val in = io.in(0)
|
||||||
|
val edge = node.edgesIn(0)
|
||||||
|
|
||||||
|
val words = (contents ++ Seq.fill(wrapSize-contents.size)(0.toByte)).grouped(beatBytes).toSeq
|
||||||
|
val bigs = words.map(_.foldRight(BigInt(0)){ case (x,y) => (x.toInt & 0xff) | y << 8})
|
||||||
|
val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))
|
||||||
|
|
||||||
|
in.d.valid := in.a.valid
|
||||||
|
in.a.ready := in.d.ready
|
||||||
|
|
||||||
|
val index = in.a.bits.address(log2Ceil(wrapSize)-1,log2Ceil(beatBytes))
|
||||||
|
val high = if (wrapSize == size) UInt(0) else in.a.bits.address(log2Ceil(size)-1, log2Ceil(wrapSize))
|
||||||
|
in.d.bits := edge.AccessAck(in.a.bits, UInt(0), Mux(high.orR, UInt(0), rom(index)))
|
||||||
|
|
||||||
|
// Tie off unused channels
|
||||||
|
in.b.valid := Bool(false)
|
||||||
|
in.c.ready := Bool(true)
|
||||||
|
in.e.ready := Bool(true)
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import util._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
// Do not use this for synthesis! Only for simulation.
|
// Do not use this for synthesis! Only for simulation.
|
||||||
class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
@ -63,7 +64,7 @@ class TLTestRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Synthesizeable unit testing */
|
/** Synthesizeable unit testing */
|
||||||
import unittest._
|
import freechips.rocketchip.unittest._
|
||||||
|
|
||||||
class TLRAMZeroDelay(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
|
class TLRAMZeroDelay(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
val fuzz = LazyModule(new TLFuzzer(txns))
|
@ -1,10 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package freechips.rocketchip.devices.tilelink
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
|
||||||
class TLZero(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLZero(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
@ -1,8 +1,8 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel.log2Ceil
|
||||||
import scala.math.{max,min}
|
import scala.math.{max,min}
|
||||||
|
|
||||||
object AddressDecoder
|
object AddressDecoder
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import freechips.rocketchip.config.Field
|
||||||
import config._
|
|
||||||
import sys.process._
|
import sys.process._
|
||||||
import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
|
import java.io.{ByteArrayInputStream, ByteArrayOutputStream}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import scala.collection.immutable.SortedMap
|
import scala.collection.immutable.SortedMap
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import chisel3.experimental.{BaseModule, RawModule, MultiIOModule}
|
import chisel3.experimental.{BaseModule, RawModule, MultiIOModule}
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
|
|
||||||
abstract class LazyModule()(implicit val p: Parameters)
|
abstract class LazyModule()(implicit val p: Parameters)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine}
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine}
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
|
|
||||||
abstract class MonitorBase(implicit sourceInfo: SourceInfo, p: Parameters) extends LazyModule()(p) {
|
abstract class MonitorBase(implicit sourceInfo: SourceInfo, p: Parameters) extends LazyModule()(p) {
|
||||||
override val module: LazyModuleImp
|
override val module: LazyModuleImp
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import util.HeterogeneousBag
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import freechips.rocketchip.config.Parameters
|
||||||
|
import freechips.rocketchip.util.HeterogeneousBag
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
// DI = Downwards flowing Parameters received on the inner side of the node
|
// DI = Downwards flowing Parameters received on the inner side of the node
|
||||||
// UI = Upwards flowing Parameters generated by the inner side of the node
|
// UI = Upwards flowing Parameters generated by the inner side of the node
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package diplomacy
|
package freechips.rocketchip.diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel.log2Ceil
|
||||||
import config._
|
|
||||||
import scala.collection.immutable.{ListMap,SortedMap}
|
import scala.collection.immutable.{ListMap,SortedMap}
|
||||||
|
|
||||||
sealed trait ResourceValue
|
sealed trait ResourceValue
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
import Chisel._
|
package freechips.rocketchip
|
||||||
|
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
||||||
|
|
||||||
package object diplomacy
|
package object diplomacy
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
|
|
||||||
package groundtest
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import uncore.tilelink._
|
|
||||||
import uncore.agents._
|
|
||||||
import uncore.coherence.{InnerTLId, OuterTLId}
|
|
||||||
import util._
|
|
||||||
import rocketchip._
|
|
||||||
import config._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An example bus mastering devices that writes some preset data to memory.
|
|
||||||
* When it receives an MMIO put request, it starts writing out the data.
|
|
||||||
* When it receives an MMIO get request, it responds with the progress of
|
|
||||||
* the write. A grant data of 1 means it is still writing, grant data 0
|
|
||||||
* means it has finished.
|
|
||||||
*/
|
|
||||||
class ExampleBusMaster(implicit val p: Parameters) extends Module
|
|
||||||
with HasTileLinkParameters {
|
|
||||||
val mmioParams = p.alterPartial({ case TLId => p(InnerTLId) })
|
|
||||||
val memParams = p.alterPartial({ case TLId => p(OuterTLId) })
|
|
||||||
val memStart = p(ExtMem).base
|
|
||||||
val memStartBlock = memStart >> p(CacheBlockOffsetBits)
|
|
||||||
|
|
||||||
val io = new Bundle {
|
|
||||||
val mmio = new ClientUncachedTileLinkIO()(mmioParams).flip
|
|
||||||
val mem = new ClientUncachedTileLinkIO()(memParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
val s_idle :: s_put :: s_resp :: Nil = Enum(Bits(), 3)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
val send_resp = Reg(init = Bool(false))
|
|
||||||
val r_acq = Reg(new AcquireMetadata)
|
|
||||||
|
|
||||||
io.mmio.acquire.ready := !send_resp
|
|
||||||
io.mmio.grant.valid := send_resp
|
|
||||||
io.mmio.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 = Mux(state === s_idle, UInt(0), UInt(1)))
|
|
||||||
|
|
||||||
when (io.mmio.acquire.fire()) {
|
|
||||||
send_resp := Bool(true)
|
|
||||||
r_acq := io.mmio.acquire.bits
|
|
||||||
when (state === s_idle && io.mmio.acquire.bits.hasData()) { state := s_put }
|
|
||||||
}
|
|
||||||
when (io.mmio.grant.fire()) { send_resp := Bool(false) }
|
|
||||||
|
|
||||||
val (put_beat, put_done) = Counter(io.mem.acquire.fire(), tlDataBeats)
|
|
||||||
when (put_done) { state := s_resp }
|
|
||||||
when (io.mem.grant.fire()) { state := s_idle }
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state === s_put
|
|
||||||
io.mem.acquire.bits := PutBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = put_beat)
|
|
||||||
io.mem.grant.ready := state === s_resp
|
|
||||||
}
|
|
||||||
|
|
||||||
class BusMasterTest(implicit p: Parameters) extends GroundTest()(p)
|
|
||||||
with HasTileLinkParameters {
|
|
||||||
val (s_idle :: s_req_start :: s_resp_start :: s_req_poll :: s_resp_poll ::
|
|
||||||
s_req_check :: s_resp_check :: s_done :: Nil) = Enum(Bits(), 8)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val busMasterBlock = p(ExtBus).base >> p(CacheBlockOffsetBits)
|
|
||||||
val start_acq = Put(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(busMasterBlock),
|
|
||||||
addr_beat = UInt(0),
|
|
||||||
data = UInt(1))
|
|
||||||
val poll_acq = Get(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(busMasterBlock),
|
|
||||||
addr_beat = UInt(0))
|
|
||||||
val check_acq = GetBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock))
|
|
||||||
|
|
||||||
val acq = io.mem.head.acquire
|
|
||||||
val gnt = io.mem.head.grant
|
|
||||||
|
|
||||||
acq.valid := state.isOneOf(s_req_start, s_req_poll, s_req_check)
|
|
||||||
acq.bits := MuxLookup(state, check_acq, Seq(
|
|
||||||
s_req_start -> start_acq,
|
|
||||||
s_req_poll -> poll_acq))
|
|
||||||
gnt.ready := state.isOneOf(s_resp_start, s_resp_poll, s_resp_check)
|
|
||||||
|
|
||||||
val (get_beat, get_done) = Counter(
|
|
||||||
state === s_resp_check && gnt.valid, tlDataBeats)
|
|
||||||
|
|
||||||
when (state === s_idle) { state := s_req_start }
|
|
||||||
when (state === s_req_start && acq.ready) { state := s_resp_start }
|
|
||||||
when (state === s_resp_start && gnt.valid) { state := s_req_poll }
|
|
||||||
when (state === s_req_poll && acq.ready) { state := s_resp_poll }
|
|
||||||
when (state === s_resp_poll && gnt.valid) {
|
|
||||||
when (gnt.bits.data === UInt(0)) {
|
|
||||||
state := s_req_check
|
|
||||||
} .otherwise { state := s_req_poll }
|
|
||||||
}
|
|
||||||
when (state === s_req_check && acq.ready) { state := s_resp_check }
|
|
||||||
when (get_done) { state := s_done }
|
|
||||||
|
|
||||||
io.status.finished := state === s_done
|
|
||||||
|
|
||||||
assert(state =/= s_resp_check || !gnt.valid ||
|
|
||||||
gnt.bits.data === get_beat,
|
|
||||||
"BusMasterTest: data does not match")
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
|
|
||||||
package groundtest
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import coreplex.CacheBlockBytes
|
|
||||||
import uncore.tilelink._
|
|
||||||
import uncore.constants._
|
|
||||||
import uncore.util._
|
|
||||||
import util._
|
|
||||||
import config._
|
|
||||||
|
|
||||||
class CacheFillTest(implicit p: Parameters) extends GroundTest()(p)
|
|
||||||
with HasTileLinkParameters {
|
|
||||||
//val l2Config = p(CacheName("L2"))
|
|
||||||
//val capacityKb = l2Config.nSets * l2Config.nWays * l2Config.rowBits / (1024*8)
|
|
||||||
val capacityKb = 1024 // TODO
|
|
||||||
val nblocks = capacityKb * 1024 / p(CacheBlockBytes)
|
|
||||||
val s_start :: s_prefetch :: s_retrieve :: s_finished :: Nil = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_start)
|
|
||||||
|
|
||||||
val active = state.isOneOf(s_prefetch, s_retrieve)
|
|
||||||
|
|
||||||
val xact_pending = Reg(init = UInt(0, tlMaxClientXacts))
|
|
||||||
val xact_id = PriorityEncoder(~xact_pending)
|
|
||||||
|
|
||||||
val (req_block, round_done) = Counter(io.mem.head.acquire.fire(), nblocks)
|
|
||||||
|
|
||||||
io.mem.head.acquire.valid := active && !xact_pending.andR
|
|
||||||
io.mem.head.acquire.bits := Mux(state === s_prefetch,
|
|
||||||
GetPrefetch(xact_id, UInt(memStartBlock) + req_block),
|
|
||||||
GetBlock(xact_id, UInt(memStartBlock) + req_block))
|
|
||||||
io.mem.head.grant.ready := xact_pending.orR
|
|
||||||
|
|
||||||
def add_pending(acq: DecoupledIO[Acquire]): UInt =
|
|
||||||
Mux(acq.fire(), UIntToOH(acq.bits.client_xact_id), UInt(0))
|
|
||||||
|
|
||||||
def remove_pending(gnt: DecoupledIO[Grant]): UInt = {
|
|
||||||
val last_grant = !gnt.bits.hasMultibeatData() ||
|
|
||||||
gnt.bits.addr_beat === UInt(tlDataBeats - 1)
|
|
||||||
~Mux(gnt.fire() && last_grant, UIntToOH(gnt.bits.client_xact_id), UInt(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
xact_pending := (xact_pending |
|
|
||||||
add_pending(io.mem.head.acquire)) &
|
|
||||||
remove_pending(io.mem.head.grant)
|
|
||||||
|
|
||||||
when (state === s_start) { state := s_prefetch }
|
|
||||||
when (state === s_prefetch && round_done) { state := s_retrieve }
|
|
||||||
when (state === s_retrieve && round_done) { state := s_finished }
|
|
||||||
|
|
||||||
io.status.finished := (state === s_finished)
|
|
||||||
io.status.timeout.valid := Bool(false)
|
|
||||||
io.status.error.valid := Bool(false)
|
|
||||||
}
|
|
@ -1,394 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
|
|
||||||
package groundtest
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import uncore.tilelink._
|
|
||||||
import uncore.constants._
|
|
||||||
import junctions._
|
|
||||||
import rocket._
|
|
||||||
import util.Timer
|
|
||||||
import scala.util.Random
|
|
||||||
import config._
|
|
||||||
import util._
|
|
||||||
|
|
||||||
case class ComparatorParameters(
|
|
||||||
targets: Seq[Long],
|
|
||||||
width: Int,
|
|
||||||
operations: Int,
|
|
||||||
atomics: Boolean,
|
|
||||||
prefetches: Boolean)
|
|
||||||
case object ComparatorKey extends Field[ComparatorParameters]
|
|
||||||
|
|
||||||
trait HasComparatorParameters {
|
|
||||||
implicit val p: Parameters
|
|
||||||
val comparatorParams = p(ComparatorKey)
|
|
||||||
val targets = comparatorParams.targets
|
|
||||||
val nTargets = targets.size
|
|
||||||
val targetWidth = comparatorParams.width
|
|
||||||
val nOperations = comparatorParams.operations
|
|
||||||
val atomics = comparatorParams.atomics
|
|
||||||
val prefetches = comparatorParams.prefetches
|
|
||||||
}
|
|
||||||
|
|
||||||
object LFSR64
|
|
||||||
{
|
|
||||||
private var counter = 0
|
|
||||||
private def next: Int = {
|
|
||||||
counter += 1
|
|
||||||
counter
|
|
||||||
}
|
|
||||||
|
|
||||||
def apply(increment: Bool = Bool(true), seed: Int = next): UInt =
|
|
||||||
{
|
|
||||||
val wide = 64
|
|
||||||
val lfsr = RegInit(UInt((seed * 0xDEADBEEFCAFEBAB1L) >>> 1, width = wide))
|
|
||||||
val xor = lfsr(0) ^ lfsr(1) ^ lfsr(3) ^ lfsr(4)
|
|
||||||
when (increment) { lfsr := Cat(xor, lfsr(wide-1,1)) }
|
|
||||||
lfsr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object NoiseMaker
|
|
||||||
{
|
|
||||||
def apply(wide: Int, increment: Bool = Bool(true)): UInt = {
|
|
||||||
val lfsrs = Seq.fill((wide+63)/64) { LFSR64(increment) }
|
|
||||||
Cat(lfsrs)(wide-1,0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MaskMaker
|
|
||||||
{
|
|
||||||
def apply(wide: Int, bits: UInt): UInt =
|
|
||||||
Vec.tabulate(wide) {UInt(_) < bits} .asUInt
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComparatorSource(implicit val p: Parameters) extends Module
|
|
||||||
with HasComparatorParameters
|
|
||||||
with HasTileLinkParameters
|
|
||||||
{
|
|
||||||
val io = new Bundle {
|
|
||||||
val out = Decoupled(new Acquire)
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output exactly nOperations of Acquires
|
|
||||||
val finished = RegInit(Bool(false))
|
|
||||||
val valid = RegInit(Bool(false))
|
|
||||||
|
|
||||||
valid := Bool(true)
|
|
||||||
|
|
||||||
io.finished := finished
|
|
||||||
io.out.valid := !finished && valid
|
|
||||||
|
|
||||||
// Generate random operand sizes
|
|
||||||
val inc = io.out.fire()
|
|
||||||
val raw_operand_size = NoiseMaker(2, inc) | UInt(0, M_SZ)
|
|
||||||
val max_operand_size = UInt(log2Up(tlDataBytes))
|
|
||||||
val get_operand_size = Mux(raw_operand_size > max_operand_size, max_operand_size, raw_operand_size)
|
|
||||||
val atomic_operand_size = UInt(2) + NoiseMaker(1, inc) // word or dword
|
|
||||||
|
|
||||||
// Generate random, but valid addr_bytes
|
|
||||||
val raw_addr_byte = NoiseMaker(tlByteAddrBits, inc)
|
|
||||||
val get_addr_byte = raw_addr_byte & ~MaskMaker(tlByteAddrBits, get_operand_size)
|
|
||||||
val atomic_addr_byte = raw_addr_byte & ~MaskMaker(tlByteAddrBits, atomic_operand_size)
|
|
||||||
|
|
||||||
// Only allow some of the possible choices (M_XA_MAXU untested)
|
|
||||||
val atomic_opcode = MuxLookup(NoiseMaker(3, inc), M_XA_SWAP, Array(
|
|
||||||
UInt("b000") -> M_XA_ADD,
|
|
||||||
UInt("b001") -> M_XA_XOR,
|
|
||||||
UInt("b010") -> M_XA_OR,
|
|
||||||
UInt("b011") -> M_XA_AND,
|
|
||||||
UInt("b100") -> M_XA_MIN,
|
|
||||||
UInt("b101") -> M_XA_MAX,
|
|
||||||
UInt("b110") -> M_XA_MINU,
|
|
||||||
UInt("b111") -> M_XA_SWAP))
|
|
||||||
|
|
||||||
// Addr_block range
|
|
||||||
val addr_block_mask = MaskMaker(tlBlockAddrBits, UInt(targetWidth-tlBeatAddrBits-tlByteAddrBits))
|
|
||||||
|
|
||||||
// Generate some random values
|
|
||||||
val addr_block = NoiseMaker(tlBlockAddrBits, inc) & addr_block_mask
|
|
||||||
val addr_beat = NoiseMaker(tlBeatAddrBits, inc)
|
|
||||||
val wmask = NoiseMaker(tlDataBytes, inc)
|
|
||||||
val data = NoiseMaker(tlDataBits, inc)
|
|
||||||
val client_xact_id = UInt(0) // filled by Client
|
|
||||||
|
|
||||||
// Random transactions
|
|
||||||
val get = Get(client_xact_id, addr_block, addr_beat, get_addr_byte, get_operand_size, Bool(false))
|
|
||||||
val getBlock = GetBlock(client_xact_id, addr_block)
|
|
||||||
val put = Put(client_xact_id, addr_block, addr_beat, data, Some(wmask))
|
|
||||||
val putBlock = PutBlock(client_xact_id, addr_block, UInt(0), data)
|
|
||||||
val putAtomic = if (atomics)
|
|
||||||
PutAtomic(client_xact_id, addr_block, addr_beat,
|
|
||||||
atomic_addr_byte, atomic_opcode, atomic_operand_size, data)
|
|
||||||
else put
|
|
||||||
val putPrefetch = if (prefetches)
|
|
||||||
PutPrefetch(client_xact_id, addr_block)
|
|
||||||
else put
|
|
||||||
val getPrefetch = if (prefetches)
|
|
||||||
GetPrefetch(client_xact_id, addr_block)
|
|
||||||
else get
|
|
||||||
val a_type_sel = NoiseMaker(3, inc)
|
|
||||||
|
|
||||||
// We must initially putBlock all of memory to have a consistent starting state
|
|
||||||
val final_addr_block = addr_block_mask + UInt(1)
|
|
||||||
val wipe_addr_block = RegInit(UInt(0, width = tlBlockAddrBits))
|
|
||||||
val done_wipe = wipe_addr_block === final_addr_block
|
|
||||||
|
|
||||||
io.out.bits := Mux(!done_wipe,
|
|
||||||
// Override whatever else we were going to do if we are wiping
|
|
||||||
PutBlock(client_xact_id, wipe_addr_block, UInt(0), data),
|
|
||||||
// Generate a random a_type
|
|
||||||
MuxLookup(a_type_sel, get, Array(
|
|
||||||
UInt("b000") -> get,
|
|
||||||
UInt("b001") -> getBlock,
|
|
||||||
UInt("b010") -> put,
|
|
||||||
UInt("b011") -> putBlock,
|
|
||||||
UInt("b100") -> putAtomic,
|
|
||||||
UInt("b101") -> getPrefetch,
|
|
||||||
UInt("b110") -> putPrefetch)))
|
|
||||||
|
|
||||||
val idx = Reg(init = UInt(0, log2Up(nOperations)))
|
|
||||||
when (io.out.fire()) {
|
|
||||||
when (idx === UInt(nOperations - 1)) { finished := Bool(true) }
|
|
||||||
when (!done_wipe) {
|
|
||||||
printf("[acq %d]: PutBlock(addr_block = %x, data = %x)\n",
|
|
||||||
idx, wipe_addr_block, data)
|
|
||||||
wipe_addr_block := wipe_addr_block + UInt(1)
|
|
||||||
} .otherwise {
|
|
||||||
switch (a_type_sel) {
|
|
||||||
is (UInt("b000")) {
|
|
||||||
printf("[acq %d]: Get(addr_block = %x, addr_beat = %x, addr_byte = %x, op_size = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, get_addr_byte, get_operand_size)
|
|
||||||
}
|
|
||||||
is (UInt("b001")) {
|
|
||||||
printf("[acq %d]: GetBlock(addr_block = %x)\n", idx, addr_block)
|
|
||||||
}
|
|
||||||
is (UInt("b010")) {
|
|
||||||
printf("[acq %d]: Put(addr_block = %x, addr_beat = %x, data = %x, wmask = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, data, wmask)
|
|
||||||
}
|
|
||||||
is (UInt("b011")) {
|
|
||||||
printf("[acq %d]: PutBlock(addr_block = %x, data = %x)\n", idx, addr_block, data)
|
|
||||||
}
|
|
||||||
is (UInt("b100")) {
|
|
||||||
if (atomics) {
|
|
||||||
printf("[acq %d]: PutAtomic(addr_block = %x, addr_beat = %x, addr_byte = %x, " +
|
|
||||||
"opcode = %x, op_size = %x, data = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, atomic_addr_byte,
|
|
||||||
atomic_opcode, atomic_operand_size, data)
|
|
||||||
} else {
|
|
||||||
printf("[acq %d]: Put(addr_block = %x, addr_beat = %x, data = %x, wmask = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, data, wmask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is (UInt("b101")) {
|
|
||||||
if (prefetches) {
|
|
||||||
printf("[acq %d]: GetPrefetch(addr_block = %x)\n", idx, addr_block)
|
|
||||||
} else {
|
|
||||||
printf("[acq %d]: Get(addr_block = %x, addr_beat = %x, addr_byte = %x, op_size = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, get_addr_byte, get_operand_size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is (UInt("b110")) {
|
|
||||||
if (prefetches) {
|
|
||||||
printf("[acq %d]: PutPrefetch(addr_block = %x)\n", idx, addr_block)
|
|
||||||
} else {
|
|
||||||
printf("[acq %d]: Put(addr_block = %x, addr_beat = %x, data = %x, wmask = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, data, wmask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is (UInt("b111")) {
|
|
||||||
printf("[acq %d]: Get(addr_block = %x, addr_beat = %x, addr_byte = %x, op_size = %x)\n",
|
|
||||||
idx, addr_block, addr_beat, get_addr_byte, get_operand_size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idx := idx + UInt(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComparatorClient(val target: Long)(implicit val p: Parameters) extends Module
|
|
||||||
with HasComparatorParameters
|
|
||||||
with HasTileLinkParameters
|
|
||||||
{
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = Decoupled(new Acquire).flip
|
|
||||||
val tl = new ClientUncachedTileLinkIO()
|
|
||||||
val out = Decoupled(new Grant)
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
val timeout = Bool(OUTPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val xacts = tlMaxClientXacts
|
|
||||||
val offset = (UInt(target) >> UInt(tlBeatAddrBits+tlByteAddrBits))
|
|
||||||
|
|
||||||
// Track the status of inflight requests
|
|
||||||
val issued = RegInit(Vec.fill(xacts) {Bool(false)})
|
|
||||||
val ready = RegInit(Vec.fill(xacts) {Bool(false)})
|
|
||||||
val result = Reg(Vec(xacts, new Grant))
|
|
||||||
|
|
||||||
val buffer = Queue(io.in, xacts)
|
|
||||||
val queue = Module(new Queue(io.tl.acquire.bits.client_xact_id, xacts))
|
|
||||||
|
|
||||||
val isMultiOut = buffer.bits.hasMultibeatData()
|
|
||||||
val isMultiIn = io.tl.grant.bits.hasMultibeatData()
|
|
||||||
|
|
||||||
val beatOut = RegInit(UInt(0, width = tlBeatAddrBits))
|
|
||||||
val lastBeat = UInt(tlDataBeats-1)
|
|
||||||
val isFirstBeatOut= Mux(isMultiOut, beatOut === UInt(0), Bool(true))
|
|
||||||
val isLastBeatOut = Mux(isMultiOut, beatOut === lastBeat, Bool(true))
|
|
||||||
val isLastBeatIn = Mux(isMultiIn, io.tl.grant.bits.addr_beat === lastBeat, Bool(true))
|
|
||||||
|
|
||||||
// Potentially issue a request, using a free xact id
|
|
||||||
// NOTE: we may retract valid and change xact_id on a !ready (allowed by spec)
|
|
||||||
val allow_acq = NoiseMaker(1)(0) && issued.map(!_).reduce(_ || _)
|
|
||||||
val xact_id = PriorityEncoder(issued.map(!_)) holdUnless isFirstBeatOut
|
|
||||||
buffer.ready := allow_acq && io.tl.acquire.ready && isLastBeatOut
|
|
||||||
io.tl.acquire.valid := allow_acq && buffer.valid
|
|
||||||
io.tl.acquire.bits := buffer.bits
|
|
||||||
io.tl.acquire.bits.addr_block := buffer.bits.addr_block + offset
|
|
||||||
io.tl.acquire.bits.client_xact_id := xact_id
|
|
||||||
when (isMultiOut) {
|
|
||||||
val dataOut = (buffer.bits.data << beatOut) + buffer.bits.data // mix the data up a bit
|
|
||||||
io.tl.acquire.bits.addr_beat := beatOut
|
|
||||||
io.tl.acquire.bits.data := dataOut
|
|
||||||
}
|
|
||||||
|
|
||||||
when (io.tl.acquire.fire()) {
|
|
||||||
issued(xact_id) := isLastBeatOut
|
|
||||||
when (isMultiOut) { beatOut := beatOut + UInt(1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember the xact ID so we can return results in-order
|
|
||||||
queue.io.enq.valid := io.tl.acquire.fire() && isLastBeatOut
|
|
||||||
queue.io.enq.bits := xact_id
|
|
||||||
assert (queue.io.enq.ready || !queue.io.enq.valid) // should be big enough
|
|
||||||
|
|
||||||
// Capture the results from the manager
|
|
||||||
io.tl.grant.ready := NoiseMaker(1)(0)
|
|
||||||
when (io.tl.grant.fire()) {
|
|
||||||
val id = io.tl.grant.bits.client_xact_id
|
|
||||||
assert (!ready(id)) // got same xact_id twice?
|
|
||||||
ready(id) := isLastBeatIn
|
|
||||||
result(id) := io.tl.grant.bits
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bad xact_id returned if ready but not issued!
|
|
||||||
assert ((ready zip issued) map {case (r,i) => i || !r} reduce (_ && _))
|
|
||||||
|
|
||||||
// When we have the next grant result, send it to the sink
|
|
||||||
val next_id = queue.io.deq.bits
|
|
||||||
queue.io.deq.ready := io.out.ready && ready(next_id) // TODO: only compares last getBlock
|
|
||||||
io.out.valid := queue.io.deq.valid && ready(next_id)
|
|
||||||
io.out.bits := result(queue.io.deq.bits)
|
|
||||||
|
|
||||||
when (io.out.fire()) {
|
|
||||||
ready(next_id) := Bool(false)
|
|
||||||
issued(next_id) := Bool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.finished := !buffer.valid && !issued.reduce(_ || _)
|
|
||||||
|
|
||||||
val (idx, acq_done) = Counter(
|
|
||||||
io.tl.acquire.fire() && io.tl.acquire.bits.last(), nOperations)
|
|
||||||
|
|
||||||
val timer = Module(new Timer(8192, xacts))
|
|
||||||
timer.io.start.valid := io.tl.acquire.fire() && io.tl.acquire.bits.first()
|
|
||||||
timer.io.start.bits := xact_id
|
|
||||||
timer.io.stop.valid := io.tl.grant.fire() && io.tl.grant.bits.first()
|
|
||||||
timer.io.stop.bits := io.tl.grant.bits.client_xact_id
|
|
||||||
assert(!timer.io.timeout.valid, "Comparator TL client timed out")
|
|
||||||
io.timeout := timer.io.timeout.valid
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComparatorSink(implicit val p: Parameters) extends Module
|
|
||||||
with HasComparatorParameters
|
|
||||||
with HasTileLinkParameters
|
|
||||||
with HasGroundTestConstants
|
|
||||||
{
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = Vec(nTargets, Decoupled(new Grant)).flip
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
val error = Valid(UInt(width = errorCodeBits))
|
|
||||||
}
|
|
||||||
|
|
||||||
// could use a smaller Queue here, but would couple targets flow controls together
|
|
||||||
val queues = io.in.map(Queue(_, nOperations))
|
|
||||||
|
|
||||||
io.finished := queues.map(!_.valid).reduce(_ && _)
|
|
||||||
val all_valid = queues.map(_.valid).reduce(_ && _)
|
|
||||||
queues.foreach(_.ready := all_valid)
|
|
||||||
|
|
||||||
val base = queues(0).bits
|
|
||||||
val idx = Reg(init = UInt(0, log2Up(nOperations)))
|
|
||||||
|
|
||||||
def check(g: Grant) = {
|
|
||||||
when (g.hasData() && base.data =/= g.data) {
|
|
||||||
printf("%d: %x =/= %x, g_type = %x\n", idx, base.data, g.data, g.g_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
val assert_conds = Seq(
|
|
||||||
g.is_builtin_type,
|
|
||||||
base.g_type === g.g_type,
|
|
||||||
base.addr_beat === g.addr_beat || !g.hasData(),
|
|
||||||
base.data === g.data || !g.hasData())
|
|
||||||
|
|
||||||
// TL1 likes to duplicate 32-bits into both halves of a 64-bit value
|
|
||||||
// TL2 doesn't do this, so they compare differently when they are the same
|
|
||||||
def isDupd(x: UInt) = if (tlDataBytes != 8) Bool(false) else x(31, 0) === x(63, 32)
|
|
||||||
def safeCompare(x: UInt, y: UInt) =
|
|
||||||
Mux(!isDupd(x) && !isDupd(y), x === y, x(63,32) === y(63,32) || x(31,0) === y(31,0))
|
|
||||||
|
|
||||||
assert (g.is_builtin_type, "grant not builtin")
|
|
||||||
assert (base.g_type === g.g_type, "g_type mismatch")
|
|
||||||
assert (base.addr_beat === g.addr_beat || !g.hasMultibeatData(), "addr_beat mismatch")
|
|
||||||
assert (base.data === g.data || !g.hasMultibeatData(), "multibeat data mismatch")
|
|
||||||
assert (safeCompare(base.data, g.data) || !g.hasData(), "singlebeat data mismatch")
|
|
||||||
|
|
||||||
assert_conds.zipWithIndex.foreach { case (cond, i) =>
|
|
||||||
when (!cond) {
|
|
||||||
io.error.valid := Bool(true)
|
|
||||||
io.error.bits := UInt(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
when (all_valid) {
|
|
||||||
when (base.hasData()) {
|
|
||||||
printf("[gnt %d]: g_type = %x, addr_beat = %x, data = %x\n",
|
|
||||||
idx, base.g_type, base.addr_beat, base.data)
|
|
||||||
} .otherwise {
|
|
||||||
printf("[gnt %d]: g_type = %x\n", idx, base.g_type)
|
|
||||||
}
|
|
||||||
queues.drop(1).map(_.bits).foreach(check)
|
|
||||||
idx := idx + UInt(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ComparatorCore(implicit p: Parameters) extends GroundTest()(p)
|
|
||||||
with HasComparatorParameters
|
|
||||||
with HasTileLinkParameters {
|
|
||||||
|
|
||||||
require (io.mem.size == nTargets)
|
|
||||||
|
|
||||||
val source = Module(new ComparatorSource)
|
|
||||||
val sink = Module(new ComparatorSink)
|
|
||||||
val broadcast = Broadcaster(source.io.out, nTargets)
|
|
||||||
val clients = targets.zipWithIndex.map { case (target, index) =>
|
|
||||||
val client = Module(new ComparatorClient(target))
|
|
||||||
client.io.in <> broadcast(index)
|
|
||||||
io.mem(index) <> client.io.tl
|
|
||||||
sink.io.in(index) <> client.io.out
|
|
||||||
client
|
|
||||||
}
|
|
||||||
val client_timeouts = clients.map(_.io.timeout)
|
|
||||||
|
|
||||||
io.status.finished := source.io.finished && sink.io.finished && clients.map(_.io.finished).reduce(_ && _)
|
|
||||||
io.status.timeout.valid := client_timeouts.reduce(_ || _)
|
|
||||||
io.status.timeout.bits := MuxCase(UInt(0),
|
|
||||||
client_timeouts.zipWithIndex.map {
|
|
||||||
case (timeout, i) => (timeout -> UInt(i))
|
|
||||||
})
|
|
||||||
io.status.error := sink.io.error
|
|
||||||
}
|
|
@ -1,161 +1,40 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import rocket._
|
import freechips.rocketchip.chip.{BaseConfig, ExtMem}
|
||||||
import diplomacy._
|
import freechips.rocketchip.config.Config
|
||||||
import uncore.tilelink._
|
import freechips.rocketchip.coreplex.{CacheBlockBytes, L1toL2Config, WithBufferlessBroadcastHub}
|
||||||
import uncore.coherence._
|
import freechips.rocketchip.rocket.{DCacheParams, PAddrBits}
|
||||||
import uncore.agents._
|
import freechips.rocketchip.tile.{MaxHartIdBits, XLen}
|
||||||
import uncore.util._
|
|
||||||
import tile.TileKey
|
|
||||||
import junctions._
|
|
||||||
import config._
|
|
||||||
import coreplex._
|
|
||||||
import rocketchip._
|
|
||||||
|
|
||||||
/** Actual testing target Configs */
|
/** Actual testing target Configs */
|
||||||
|
|
||||||
class GroundTestConfig extends Config(new WithGroundTestTiles ++ new BaseConfig)
|
class TraceGenConfig extends Config(new WithTraceGen(List.fill(2){ DCacheParams(nSets = 16, nWays = 1) }) ++ new BaseConfig)
|
||||||
|
|
||||||
class ComparatorConfig extends Config(
|
class TraceGenBufferlessConfig extends Config(new WithBufferlessBroadcastHub ++ new TraceGenConfig)
|
||||||
new WithComparator(1) ++ new GroundTestConfig)
|
|
||||||
class ComparatorL2Config extends Config(
|
|
||||||
new WithAtomics ++ new WithPrefetches ++
|
|
||||||
new WithL2Cache ++ new ComparatorConfig)
|
|
||||||
class ComparatorBufferlessConfig extends Config(
|
|
||||||
new WithBufferlessBroadcastHub ++ new ComparatorConfig)
|
|
||||||
class ComparatorStatelessConfig extends Config(
|
|
||||||
new WithStatelessBridge ++ new ComparatorConfig)
|
|
||||||
|
|
||||||
class MemtestConfig extends Config(new WithMemtest(1) ++ new GroundTestConfig)
|
|
||||||
class MemtestL2Config extends Config(
|
|
||||||
new WithL2Cache ++ new MemtestConfig)
|
|
||||||
class MemtestBufferlessConfig extends Config(
|
|
||||||
new WithBufferlessBroadcastHub ++ new MemtestConfig)
|
|
||||||
class MemtestStatelessConfig extends Config(
|
|
||||||
new WithStatelessBridge ++ new MemtestConfig)
|
|
||||||
// Test ALL the things
|
|
||||||
class FancyMemtestConfig extends Config(
|
|
||||||
new WithMemtest(2) ++
|
|
||||||
new WithNMemoryChannels(2) ++ new WithNBanksPerMemChannel(4) ++
|
|
||||||
new WithL2Cache ++ new GroundTestConfig)
|
|
||||||
|
|
||||||
class CacheFillTestConfig extends Config(
|
|
||||||
new WithNL2Ways(4) ++ new WithL2Capacity(4) ++
|
|
||||||
new WithCacheFillTest(1) ++ new WithL2Cache ++ new GroundTestConfig)
|
|
||||||
|
|
||||||
class BroadcastRegressionTestConfig extends Config(
|
|
||||||
new WithBroadcastRegressionTest(1) ++ new GroundTestConfig)
|
|
||||||
class BufferlessRegressionTestConfig extends Config(
|
|
||||||
new WithBufferlessBroadcastHub ++ new BroadcastRegressionTestConfig)
|
|
||||||
class CacheRegressionTestConfig extends Config(
|
|
||||||
new WithCacheRegressionTest(1) ++ new WithL2Cache ++ new GroundTestConfig)
|
|
||||||
|
|
||||||
class TraceGenConfig extends Config(
|
|
||||||
new WithTraceGen(2) ++ new GroundTestConfig)
|
|
||||||
class TraceGenBufferlessConfig extends Config(
|
|
||||||
new WithBufferlessBroadcastHub ++ new TraceGenConfig)
|
|
||||||
class TraceGenL2Config extends Config(
|
|
||||||
new WithNL2Ways(1) ++ new WithL2Capacity(32 * 64 / 1024) ++
|
|
||||||
new WithL2Cache ++ new TraceGenConfig)
|
|
||||||
|
|
||||||
class Edge128BitComparatorConfig extends Config(
|
|
||||||
new WithEdgeDataBits(128) ++ new ComparatorConfig)
|
|
||||||
class Edge128BitMemtestConfig extends Config(
|
|
||||||
new WithEdgeDataBits(128) ++ new MemtestConfig)
|
|
||||||
|
|
||||||
class Edge32BitComparatorConfig extends Config(
|
|
||||||
new WithEdgeDataBits(32) ++ new ComparatorL2Config)
|
|
||||||
class Edge32BitMemtestConfig extends Config(
|
|
||||||
new WithEdgeDataBits(32) ++ new MemtestConfig)
|
|
||||||
|
|
||||||
/* Composable Configs to set individual parameters */
|
/* Composable Configs to set individual parameters */
|
||||||
|
|
||||||
class WithGroundTestTiles extends Config((site, here, up) => {
|
class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) extends Config((site, here, up) => {
|
||||||
case TileKey => site(GroundTestKey).head
|
case GroundTestTilesKey => params.map { dcp => TraceGenParams(
|
||||||
case NTiles => site(GroundTestKey).size
|
dcache = Some(dcp),
|
||||||
})
|
wordBits = site(XLen),
|
||||||
|
addrBits = site(PAddrBits),
|
||||||
class WithComparator(n: Int) extends Config((site, here, up) => {
|
addrBag = {
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(uncached = 2, dcache = None)
|
|
||||||
}
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new ComparatorCore()(p))
|
|
||||||
case ComparatorKey => ComparatorParameters(
|
|
||||||
targets = Seq(site(ExtMem).base, testRamAddr),
|
|
||||||
width = 8,
|
|
||||||
operations = 1000,
|
|
||||||
atomics = false,
|
|
||||||
prefetches = false)
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithAtomics extends Config((site, here, up) => {
|
|
||||||
case ComparatorKey => up(ComparatorKey, site).copy(atomics = true)
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithPrefetches extends Config((site, here, up) => {
|
|
||||||
case ComparatorKey => up(ComparatorKey, site).copy(prefetches = true)
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithMemtest(n: Int) extends Config((site, here, up) => {
|
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(uncached = 1)
|
|
||||||
}
|
|
||||||
case GeneratorKey => TrafficGeneratorParameters(
|
|
||||||
maxRequests = 128,
|
|
||||||
startAddress = BigInt(site(ExtMem).base))
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new GeneratorTest()(p))
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithCacheFillTest(n: Int) extends Config((site, here, up) => {
|
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(uncached = 1, dcache = None)
|
|
||||||
}
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new CacheFillTest()(p))
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithBroadcastRegressionTest(n: Int) extends Config((site, here, up) => {
|
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(uncached = 1, maxXacts = 3)
|
|
||||||
}
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new RegressionTest()(p))
|
|
||||||
case GroundTestRegressions =>
|
|
||||||
(p: Parameters) => RegressionTests.broadcastRegressions(p)
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithCacheRegressionTest(n: Int) extends Config((site, here, up) => {
|
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(uncached = 1, maxXacts = 5)
|
|
||||||
}
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new RegressionTest()(p))
|
|
||||||
case GroundTestRegressions =>
|
|
||||||
(p: Parameters) => RegressionTests.cacheRegressions(p)
|
|
||||||
})
|
|
||||||
|
|
||||||
class WithTraceGen(n: Int) extends Config((site, here, up) => {
|
|
||||||
case GroundTestKey => Seq.fill(n) {
|
|
||||||
GroundTestTileParams(dcache = Some(DCacheParams(nSets = 16, nWays = 1)))
|
|
||||||
}
|
|
||||||
case BuildGroundTest =>
|
|
||||||
(p: Parameters) => Module(new GroundTestTraceGenerator()(p))
|
|
||||||
case GeneratorKey => TrafficGeneratorParameters(
|
|
||||||
maxRequests = 8192,
|
|
||||||
startAddress = 0)
|
|
||||||
case AddressBag => {
|
|
||||||
val nSets = 2
|
val nSets = 2
|
||||||
val nWays = 1
|
val nWays = 1
|
||||||
val blockOffset = site(CacheBlockOffsetBits)
|
val blockOffset = log2Up(site(CacheBlockBytes))
|
||||||
val nBeats = site(CacheBlockBytes)/site(L1toL2Config).beatBytes
|
val nBeats = site(CacheBlockBytes)/site(L1toL2Config).beatBytes
|
||||||
List.tabulate(4 * nWays) { i =>
|
List.tabulate(4 * nWays) { i =>
|
||||||
Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) }
|
Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) }
|
||||||
}.flatten
|
}.flatten
|
||||||
|
},
|
||||||
|
maxRequests = nReqs,
|
||||||
|
memStart = site(ExtMem).base,
|
||||||
|
numGens = params.size)
|
||||||
}
|
}
|
||||||
|
case MaxHartIdBits => log2Up(params.size)
|
||||||
})
|
})
|
||||||
|
@ -1,44 +1,27 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import diplomacy._
|
import freechips.rocketchip.config.{Field, Parameters}
|
||||||
import coreplex._
|
import freechips.rocketchip.diplomacy._
|
||||||
import rocket._
|
import freechips.rocketchip.coreplex._
|
||||||
import tile._
|
import freechips.rocketchip.tilelink._
|
||||||
import uncore.agents._
|
import freechips.rocketchip.tile._
|
||||||
import uncore.coherence._
|
|
||||||
import uncore.devices._
|
|
||||||
import uncore.tilelink._
|
|
||||||
import uncore.tilelink2._
|
|
||||||
import uncore.util._
|
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
case object TileId extends Field[Int]
|
case object TileId extends Field[Int]
|
||||||
|
|
||||||
class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex {
|
class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex {
|
||||||
val tiles = List.tabulate(p(NTiles)) { i =>
|
val tileParams = p(GroundTestTilesKey)
|
||||||
LazyModule(new GroundTestTile()(p.alter { (site, here, up) => {
|
val tiles = tileParams.zipWithIndex.map { case(c, i) => LazyModule(
|
||||||
case TileId => i
|
c.build(i, p.alterPartial {
|
||||||
case CacheBlockOffsetBits => log2Up(site(CacheBlockBytes))
|
case TileKey => c
|
||||||
case AmoAluOperandBits => site(XLen)
|
|
||||||
case SharedMemoryTLEdge => tile_splitter.node.edgesIn(0)
|
case SharedMemoryTLEdge => tile_splitter.node.edgesIn(0)
|
||||||
case TLId => "L1toL2"
|
})
|
||||||
case TLKey("L1toL2") =>
|
)}
|
||||||
TileLinkParameters(
|
|
||||||
coherencePolicy = new MESICoherence(new NullRepresentation(site(NTiles))),
|
|
||||||
nManagers = site(BankedL2Config).nBanks + 1,
|
|
||||||
nCachingClients = 1,
|
|
||||||
nCachelessClients = 1,
|
|
||||||
maxClientXacts = site(GroundTestKey).map(_.maxXacts).reduce(max(_, _)),
|
|
||||||
maxClientsPerPort = site(GroundTestKey).map(_.uncached).sum,
|
|
||||||
maxManagerXacts = 8,
|
|
||||||
dataBeats = (8 * site(CacheBlockBytes)) / site(XLen),
|
|
||||||
dataBits = site(CacheBlockBytes)*8)
|
|
||||||
}}))
|
|
||||||
}
|
|
||||||
|
|
||||||
val fixer = LazyModule(new TLFIFOFixer)
|
val fixer = LazyModule(new TLFIFOFixer)
|
||||||
tile_splitter.node :=* fixer.node
|
tile_splitter.node :=* fixer.node
|
||||||
@ -55,5 +38,9 @@ class GroundTestCoreplexBundle[+L <: GroundTestCoreplex](_outer: L) extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GroundTestCoreplexModule[+L <: GroundTestCoreplex, +B <: GroundTestCoreplexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io) {
|
class GroundTestCoreplexModule[+L <: GroundTestCoreplex, +B <: GroundTestCoreplexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io) {
|
||||||
io.success := outer.tiles.map(_.module.io.success).reduce(_&&_)
|
|
||||||
|
outer.tiles.zipWithIndex.map { case(t, i) => t.module.io.hartid := UInt(i) }
|
||||||
|
|
||||||
|
val status = DebugCombiner(outer.tiles.map(_.module.io.status))
|
||||||
|
io.success := status.finished
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
|
||||||
import rocket._
|
import freechips.rocketchip.config.Parameters
|
||||||
import tile._
|
import freechips.rocketchip.rocket._
|
||||||
import util.ParameterizedBundle
|
import freechips.rocketchip.tile.CoreModule
|
||||||
|
import freechips.rocketchip.util.ParameterizedBundle
|
||||||
|
|
||||||
class DummyPTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) {
|
class DummyPTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
object Generator extends util.GeneratorApp {
|
import freechips.rocketchip.util.GeneratorApp
|
||||||
|
|
||||||
|
object Generator extends GeneratorApp {
|
||||||
val longName = names.topModuleProject + "." + names.configs
|
val longName = names.topModuleProject + "." + names.configs
|
||||||
generateFirrtl
|
generateFirrtl
|
||||||
generateTestSuiteMakefrags // TODO: Needed only for legacy make targets
|
generateTestSuiteMakefrags // TODO: Needed only for legacy make targets
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package freechips.rocketchip
|
||||||
|
|
||||||
package object groundtest {
|
package object groundtest {
|
||||||
val testRamAddr = 0x10000
|
val testRamAddr = 0x10000
|
||||||
|
val timeoutCodeBits = 4
|
||||||
|
val errorCodeBits = 4
|
||||||
}
|
}
|
||||||
|
@ -1,789 +0,0 @@
|
|||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
// See LICENSE.SiFive for license details.
|
|
||||||
|
|
||||||
package groundtest
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import uncore.tilelink._
|
|
||||||
import uncore.constants._
|
|
||||||
import uncore.util._
|
|
||||||
import util._
|
|
||||||
import rocket._
|
|
||||||
import rocketchip._
|
|
||||||
import config._
|
|
||||||
|
|
||||||
class RegressionIO(implicit val p: Parameters) extends ParameterizedBundle()(p) {
|
|
||||||
val start = Bool(INPUT)
|
|
||||||
val cache = new HellaCacheIO
|
|
||||||
val mem = new ClientUncachedTileLinkIO
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
val errored = Bool(OUTPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Regression(implicit val p: Parameters)
|
|
||||||
extends Module with HasTileLinkParameters {
|
|
||||||
val memStart = p(ExtMem).base
|
|
||||||
val memStartBlock = memStart >> p(CacheBlockOffsetBits)
|
|
||||||
val io = new RegressionIO
|
|
||||||
|
|
||||||
def disableCache() {
|
|
||||||
io.cache.req.valid := Bool(false)
|
|
||||||
io.cache.req.bits.addr := UInt(memStart)
|
|
||||||
io.cache.req.bits.typ := UInt(0)
|
|
||||||
io.cache.req.bits.cmd := M_XRD
|
|
||||||
io.cache.req.bits.tag := UInt(0)
|
|
||||||
io.cache.req.bits.data := Bits(0)
|
|
||||||
io.cache.req.bits.phys := Bool(true)
|
|
||||||
io.cache.invalidate_lr := Bool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
def disableMem() {
|
|
||||||
io.mem.acquire.valid := Bool(false)
|
|
||||||
io.mem.grant.ready := Bool(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This was a bug in which the TileLinkIONarrower logic screwed up
|
|
||||||
* when a PutBlock request and a narrow Get request are sent to it at the
|
|
||||||
* same time. Repeating this sequence enough times will cause a queue to
|
|
||||||
* get filled up and deadlock the system.
|
|
||||||
*/
|
|
||||||
class IOGetAfterPutBlockRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
val nRuns = 7
|
|
||||||
val run = Reg(init = UInt(0, log2Up(nRuns + 1)))
|
|
||||||
|
|
||||||
val (put_beat, put_done) = Counter(
|
|
||||||
io.mem.acquire.fire() && io.mem.acquire.bits.hasData(), tlDataBeats)
|
|
||||||
|
|
||||||
val started = Reg(init = Bool(false))
|
|
||||||
val put_sent = Reg(init = Bool(false))
|
|
||||||
val get_sent = Reg(init = Bool(false))
|
|
||||||
val put_acked = Reg(init = Bool(false))
|
|
||||||
val get_acked = Reg(init = Bool(false))
|
|
||||||
val both_acked = put_acked && get_acked
|
|
||||||
|
|
||||||
when (!started && io.start) { started := Bool(true) }
|
|
||||||
|
|
||||||
io.mem.acquire.valid := !put_sent && started
|
|
||||||
io.mem.acquire.bits := PutBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = UInt(0))
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
io.cache.req.valid := !get_sent && started
|
|
||||||
io.cache.req.bits.addr := UInt(testRamAddr)
|
|
||||||
io.cache.req.bits.typ := MT_WU
|
|
||||||
io.cache.req.bits.cmd := M_XRD
|
|
||||||
io.cache.req.bits.tag := UInt(0)
|
|
||||||
io.cache.invalidate_lr := Bool(false)
|
|
||||||
|
|
||||||
when (put_done) { put_sent := Bool(true) }
|
|
||||||
when (io.cache.req.fire()) { get_sent := Bool(true) }
|
|
||||||
when (io.mem.grant.fire()) { put_acked := Bool(true) }
|
|
||||||
when (io.cache.resp.valid) { get_acked := Bool(true) }
|
|
||||||
|
|
||||||
when (both_acked) {
|
|
||||||
when (run < UInt(nRuns - 1)) {
|
|
||||||
put_sent := Bool(false)
|
|
||||||
get_sent := Bool(false)
|
|
||||||
}
|
|
||||||
put_acked := Bool(false)
|
|
||||||
get_acked := Bool(false)
|
|
||||||
run := run + UInt(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.finished := (run === UInt(nRuns))
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This was a bug with merging two PutBlocks to the same address in the L2.
|
|
||||||
* The transactor would start accepting beats of the second transaction but
|
|
||||||
* acknowledge both of them when the first one finished.
|
|
||||||
* This caused the state to go funky since the next time around it would
|
|
||||||
* start the put in the middle */
|
|
||||||
class PutBlockMergeRegression(nSets: Int)(implicit p: Parameters)
|
|
||||||
extends Regression()(p) with HasTileLinkParameters {
|
|
||||||
val s_idle :: s_put :: s_wait :: s_done :: Nil = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val addr_blocks = Vec(Seq(0, 0, nSets).map(num => UInt(num + memStartBlock)))
|
|
||||||
val nSteps = addr_blocks.size
|
|
||||||
val (acq_beat, acq_done) = Counter(io.mem.acquire.fire(), tlDataBeats)
|
|
||||||
val (send_cnt, send_done) = Counter(acq_done, nSteps)
|
|
||||||
val (ack_cnt, ack_done) = Counter(io.mem.grant.fire(), nSteps)
|
|
||||||
|
|
||||||
io.mem.acquire.valid := (state === s_put)
|
|
||||||
io.mem.acquire.bits := PutBlock(
|
|
||||||
client_xact_id = send_cnt,
|
|
||||||
addr_block = addr_blocks(send_cnt),
|
|
||||||
addr_beat = acq_beat,
|
|
||||||
data = Cat(send_cnt, acq_beat))
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_put }
|
|
||||||
when (send_done) { state := s_wait }
|
|
||||||
when (ack_done) { state := s_done }
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure the L2 does "the right thing" when a put is sent no-alloc but
|
|
||||||
* the block is already in cache. It should just treat the request as a
|
|
||||||
* regular allocating put */
|
|
||||||
class NoAllocPutHitRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
val (s_idle :: s_prefetch :: s_put :: s_get ::
|
|
||||||
s_wait :: s_done :: Nil) = Enum(Bits(), 6)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val acq = io.mem.acquire.bits
|
|
||||||
val gnt = io.mem.grant.bits
|
|
||||||
|
|
||||||
val (put_beat, put_done) = Counter(io.mem.acquire.fire() && acq.hasData(), tlDataBeats)
|
|
||||||
val acked = Reg(init = UInt(0, tlDataBeats + 2))
|
|
||||||
|
|
||||||
val addr_block = UInt(memStartBlock + 2)
|
|
||||||
val test_data = UInt(0x3446)
|
|
||||||
|
|
||||||
val prefetch_acq = GetPrefetch(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = addr_block)
|
|
||||||
val put_acq = PutBlock(
|
|
||||||
client_xact_id = UInt(1),
|
|
||||||
addr_block = addr_block,
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = test_data,
|
|
||||||
alloc = Bool(false))
|
|
||||||
val get_acq = GetBlock(
|
|
||||||
client_xact_id = UInt(2),
|
|
||||||
addr_block = addr_block)
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state.isOneOf(s_prefetch, s_get, s_put)
|
|
||||||
io.mem.acquire.bits := MuxCase(get_acq, Seq(
|
|
||||||
(state === s_prefetch) -> prefetch_acq,
|
|
||||||
(state === s_put) -> put_acq))
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_prefetch }
|
|
||||||
when (state === s_prefetch && io.mem.acquire.ready) { state := s_put }
|
|
||||||
when (put_done) { state := s_get }
|
|
||||||
when (state === s_get && io.mem.acquire.ready) { state := s_wait }
|
|
||||||
when (state === s_wait && acked.andR) { state := s_done }
|
|
||||||
|
|
||||||
when (io.mem.grant.fire()) {
|
|
||||||
switch (gnt.client_xact_id) {
|
|
||||||
is (UInt(0)) { acked := acked | UInt(1 << tlDataBeats) }
|
|
||||||
is (UInt(1)) { acked := acked | UInt(1 << (tlDataBeats + 1)) }
|
|
||||||
is (UInt(2)) { acked := acked | UIntToOH(gnt.addr_beat) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val data_mismatch = io.mem.grant.fire() && gnt.hasData() && gnt.data =/= test_data
|
|
||||||
assert(!data_mismatch, "NoAllocPutHitRegression: data does not match")
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
io.errored := data_mismatch
|
|
||||||
|
|
||||||
disableCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Make sure L2 does the right thing when multiple puts are sent for the
|
|
||||||
* same block, but only the first one has the alloc bit set. */
|
|
||||||
class MixedAllocPutRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
val (s_idle :: s_pf_send :: s_pf_wait :: s_put_send :: s_put_wait ::
|
|
||||||
s_get_send :: s_get_wait :: s_done :: Nil) = Enum(Bits(), 8)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
/** We have to test two cases: one when the block is already cached
|
|
||||||
* and one when the block is not yet cached.
|
|
||||||
* We use prefetching to assure the first case. */
|
|
||||||
val test_data = Vec(
|
|
||||||
UInt("h2222222211111111"),
|
|
||||||
UInt("h3333333333333333"),
|
|
||||||
UInt("h4444444444444444"),
|
|
||||||
UInt("h5555555555555555"))
|
|
||||||
val test_alloc = Vec(Bool(false), Bool(false), Bool(true), Bool(false))
|
|
||||||
val test_block = Vec(
|
|
||||||
Seq.fill(2) { UInt(memStartBlock + 15) } ++
|
|
||||||
Seq.fill(2) { UInt(memStartBlock + 16) })
|
|
||||||
val test_beat = Vec(UInt(0), UInt(2), UInt(1), UInt(2))
|
|
||||||
|
|
||||||
val (put_acq_id, put_acq_done) = Counter(
|
|
||||||
state === s_put_send && io.mem.acquire.ready, test_data.size)
|
|
||||||
val (put_gnt_cnt, put_gnt_done) = Counter(
|
|
||||||
state === s_put_wait && io.mem.grant.valid, test_data.size)
|
|
||||||
|
|
||||||
val (get_acq_id, get_acq_done) = Counter(
|
|
||||||
state === s_get_send && io.mem.acquire.ready, test_data.size)
|
|
||||||
val (get_gnt_cnt, get_gnt_done) = Counter(
|
|
||||||
state === s_get_wait && io.mem.grant.valid, test_data.size)
|
|
||||||
|
|
||||||
val pf_acquire = PutPrefetch(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock + 15))
|
|
||||||
|
|
||||||
val put_acquire = Put(
|
|
||||||
client_xact_id = put_acq_id,
|
|
||||||
addr_block = test_block(put_acq_id),
|
|
||||||
addr_beat = test_beat(put_acq_id),
|
|
||||||
data = test_data(put_acq_id),
|
|
||||||
alloc = test_alloc(put_acq_id))
|
|
||||||
|
|
||||||
val get_acquire = Get(
|
|
||||||
client_xact_id = get_acq_id,
|
|
||||||
addr_block = test_block(get_acq_id),
|
|
||||||
addr_beat = test_beat(get_acq_id))
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state.isOneOf(s_pf_send, s_put_send, s_get_send)
|
|
||||||
io.mem.acquire.bits := MuxLookup(state, pf_acquire, Seq(
|
|
||||||
s_put_send -> put_acquire,
|
|
||||||
s_get_send -> get_acquire))
|
|
||||||
io.mem.grant.ready := state.isOneOf(s_pf_wait, s_put_wait, s_get_wait)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_pf_send }
|
|
||||||
when (state === s_pf_send && io.mem.acquire.ready) { state := s_pf_wait }
|
|
||||||
when (state === s_pf_wait && io.mem.grant.valid) { state := s_put_send }
|
|
||||||
when (put_acq_done) { state := s_put_wait }
|
|
||||||
when (put_gnt_done) { state := s_get_send }
|
|
||||||
when (get_acq_done) { state := s_get_wait }
|
|
||||||
when (get_gnt_done) { state := s_done }
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
|
|
||||||
val data_mismatch = state === s_get_wait && io.mem.grant.fire() &&
|
|
||||||
io.mem.grant.bits.data =/= test_data(io.mem.grant.bits.client_xact_id)
|
|
||||||
assert(!data_mismatch, "MixedAllocPutRegression: data mismatch")
|
|
||||||
io.errored := data_mismatch
|
|
||||||
|
|
||||||
disableCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure each no-alloc put triggers a request to outer memory.
|
|
||||||
* Unfortunately, there's no way to verify that this works except by looking
|
|
||||||
* at the waveform */
|
|
||||||
class RepeatedNoAllocPutRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val nPuts = 2
|
|
||||||
val (put_beat, put_done) = Counter(io.mem.acquire.fire(), tlDataBeats)
|
|
||||||
val (req_cnt, req_done) = Counter(put_done, nPuts)
|
|
||||||
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
val acked = Reg(init = UInt(0, nPuts))
|
|
||||||
|
|
||||||
when (!sending && io.start) { sending := Bool(true) }
|
|
||||||
when (sending && req_done) { sending := Bool(false) }
|
|
||||||
|
|
||||||
io.mem.acquire.valid := sending
|
|
||||||
io.mem.acquire.bits := PutBlock(
|
|
||||||
client_xact_id = req_cnt,
|
|
||||||
addr_block = UInt(memStartBlock + 5),
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = Cat(req_cnt, UInt(0, 8)),
|
|
||||||
alloc = Bool(false))
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
when (io.mem.grant.fire()) {
|
|
||||||
acked := acked | UIntToOH(io.mem.grant.bits.client_xact_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.finished := acked.andR
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure write masking works properly by writing a block of data
|
|
||||||
* piece by piece */
|
|
||||||
class WriteMaskedPutBlockRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val (s_idle :: s_put_send :: s_put_ack :: s_stall ::
|
|
||||||
s_get_send :: s_get_ack :: s_done :: Nil) = Enum(Bits(), 7)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
val post_stall_state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val gnt = io.mem.grant.bits
|
|
||||||
val acq = io.mem.acquire.bits
|
|
||||||
|
|
||||||
val stage = Reg(init = UInt(0, 1))
|
|
||||||
|
|
||||||
val (put_beat, put_block_done) = Counter(
|
|
||||||
io.mem.acquire.fire() && acq.hasData(), tlDataBeats)
|
|
||||||
val put_data = UInt(0x30010040, tlDataBits) + (put_beat << UInt(2))
|
|
||||||
|
|
||||||
val put_acq = PutBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock + 7),
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = Mux(put_beat(0) === stage, put_data, UInt(0)),
|
|
||||||
wmask = Some(Mux(put_beat(0) === stage, Acquire.fullWriteMask, Bits(0))))
|
|
||||||
|
|
||||||
val get_acq = GetBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock + 6) + stage)
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state.isOneOf(s_put_send, s_get_send)
|
|
||||||
io.mem.acquire.bits := Mux(state === s_get_send, get_acq, put_acq)
|
|
||||||
io.mem.grant.ready := state.isOneOf(s_put_ack, s_get_ack)
|
|
||||||
|
|
||||||
val (get_cnt, get_done) = Counter(
|
|
||||||
io.mem.grant.fire() && gnt.hasData(), tlDataBeats)
|
|
||||||
val get_data = UInt(0x30010040, tlDataBits) + (get_cnt << UInt(2))
|
|
||||||
|
|
||||||
val (stall_cnt, stall_done) = Counter(state === s_stall, 16)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_put_send }
|
|
||||||
when (put_block_done) { state := s_put_ack }
|
|
||||||
when (state === s_put_ack && io.mem.grant.valid) {
|
|
||||||
post_stall_state := s_get_send
|
|
||||||
state := s_stall
|
|
||||||
}
|
|
||||||
when (stall_done) { state := post_stall_state }
|
|
||||||
when (state === s_get_send && io.mem.acquire.ready) { state := s_get_ack }
|
|
||||||
when (get_done) {
|
|
||||||
// do a read in-between the two put-blocks to overwrite the data buffer
|
|
||||||
when (stage === UInt(0)) {
|
|
||||||
stage := stage + UInt(1)
|
|
||||||
post_stall_state := s_put_send
|
|
||||||
state := s_stall
|
|
||||||
} .otherwise { state := s_done }
|
|
||||||
}
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
|
|
||||||
val data_mismatch = io.mem.grant.fire() && io.mem.grant.bits.hasData() &&
|
|
||||||
stage =/= UInt(0) && io.mem.grant.bits.data =/= get_data
|
|
||||||
assert(!data_mismatch, "WriteMaskedPutBlockRegression: data does not match")
|
|
||||||
io.errored := data_mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure a prefetch that hits returns immediately. */
|
|
||||||
class PrefetchHitRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
val nPrefetches = 2
|
|
||||||
val (pf_cnt, pf_done) = Counter(io.mem.acquire.fire(), nPrefetches)
|
|
||||||
val acked = Reg(init = UInt(0, nPrefetches))
|
|
||||||
|
|
||||||
val acq_bits = Vec(
|
|
||||||
PutPrefetch(client_xact_id = UInt(0), addr_block = UInt(memStartBlock + 12)),
|
|
||||||
GetPrefetch(client_xact_id = UInt(1), addr_block = UInt(memStartBlock + 12)))
|
|
||||||
|
|
||||||
io.mem.acquire.valid := sending
|
|
||||||
io.mem.acquire.bits := acq_bits(pf_cnt)
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
when (io.mem.grant.fire()) {
|
|
||||||
acked := acked | UIntToOH(io.mem.grant.bits.client_xact_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
when (!sending && io.start) { sending := Bool(true) }
|
|
||||||
when (sending && pf_done) { sending := Bool(false) }
|
|
||||||
|
|
||||||
io.finished := acked.andR
|
|
||||||
io.errored := Bool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test that a writeback will occur by writing nWays + 1 blocks to the same
|
|
||||||
* set. This assumes that there is only a single cache bank. If we want to
|
|
||||||
* test multibank configurations, we'll have to think of some other way to
|
|
||||||
* determine which banks are conflicting */
|
|
||||||
class WritebackRegression(nSets: Int, nWays: Int)(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val addr_blocks = Vec.tabulate(nWays + 1) { i => UInt(memStartBlock + i * nSets) }
|
|
||||||
val data = Vec.tabulate(nWays + 1) { i => UInt((i + 1) * 1423) }
|
|
||||||
|
|
||||||
val (put_beat, put_done) = Counter(
|
|
||||||
io.mem.acquire.fire() && io.mem.acquire.bits.hasData(), tlDataBeats)
|
|
||||||
val (get_beat, get_done) = Counter(
|
|
||||||
io.mem.grant.fire() && io.mem.grant.bits.hasData(), tlDataBeats)
|
|
||||||
val (put_cnt, _) = Counter(put_done, nWays + 1)
|
|
||||||
val (get_cnt, _) = Counter(
|
|
||||||
io.mem.acquire.fire() && !io.mem.acquire.bits.hasData(), nWays + 1)
|
|
||||||
val (ack_cnt, ack_done) = Counter(
|
|
||||||
io.mem.grant.fire() && !io.mem.grant.bits.hasData() || get_done, nWays + 1)
|
|
||||||
|
|
||||||
val s_idle :: s_put :: s_get :: s_done :: Nil = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
|
|
||||||
io.mem.acquire.valid := sending
|
|
||||||
io.mem.acquire.bits := Mux(state === s_put,
|
|
||||||
PutBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = addr_blocks(put_cnt),
|
|
||||||
addr_beat = put_beat,
|
|
||||||
data = data(put_cnt)),
|
|
||||||
GetBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = addr_blocks(get_cnt)))
|
|
||||||
io.mem.grant.ready := !sending
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_put; sending := Bool(true) }
|
|
||||||
when (put_done || state === s_get && io.mem.acquire.fire()) {
|
|
||||||
sending := Bool(false)
|
|
||||||
}
|
|
||||||
when (get_done && !ack_done || state === s_put && io.mem.grant.fire()) {
|
|
||||||
sending := Bool(true)
|
|
||||||
}
|
|
||||||
when (ack_done) { state := Mux(state === s_put, s_get, s_done) }
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
|
|
||||||
val data_mismatch = io.mem.grant.fire() && io.mem.grant.bits.hasData() &&
|
|
||||||
io.mem.grant.bits.data =/= data(ack_cnt)
|
|
||||||
assert(!data_mismatch, "WritebackRegression: incorrect data")
|
|
||||||
io.errored := data_mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReleaseRegression(nSets: Int, nWays: Int)(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableMem()
|
|
||||||
|
|
||||||
val blockOffset = p(CacheBlockOffsetBits)
|
|
||||||
|
|
||||||
val startBlock = memStartBlock + 10
|
|
||||||
val addr_blocks = Vec.tabulate(nWays + 1) { i => UInt(startBlock + i * nSets) }
|
|
||||||
val data = Vec.tabulate(nWays + 1) { i => UInt((i + 1) * 1522) }
|
|
||||||
val (req_idx, req_done) = Counter(io.cache.req.fire(), nWays + 1)
|
|
||||||
val (resp_idx, resp_done) = Counter(io.cache.resp.valid, nWays + 1)
|
|
||||||
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
val s_idle :: s_write :: s_read :: s_done :: Nil = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
io.cache.req.valid := sending && state.isOneOf(s_write, s_read)
|
|
||||||
io.cache.req.bits.addr := Cat(addr_blocks(req_idx), UInt(0, blockOffset))
|
|
||||||
io.cache.req.bits.typ := MT_D
|
|
||||||
io.cache.req.bits.cmd := Mux(state === s_write, M_XWR, M_XRD)
|
|
||||||
io.cache.req.bits.tag := UInt(0)
|
|
||||||
io.cache.req.bits.data := data(req_idx)
|
|
||||||
io.cache.req.bits.phys := Bool(true)
|
|
||||||
io.cache.invalidate_lr := Bool(false)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) {
|
|
||||||
sending := Bool(true)
|
|
||||||
state := s_write
|
|
||||||
}
|
|
||||||
|
|
||||||
when (resp_done) { state := Mux(state === s_write, s_read, s_done) }
|
|
||||||
when (io.cache.req.fire()) { sending := Bool(false) }
|
|
||||||
when (io.cache.resp.valid) { sending := Bool(true) }
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
|
|
||||||
val data_mismatch = io.cache.resp.valid && io.cache.resp.bits.has_data &&
|
|
||||||
io.cache.resp.bits.data =/= data(resp_idx)
|
|
||||||
assert(!data_mismatch, "ReleaseRegression: data mismatch")
|
|
||||||
io.errored := data_mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
class PutBeforePutBlockRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
val (s_idle :: s_put :: s_putblock :: s_wait ::
|
|
||||||
s_finished :: Nil) = Enum(Bits(), 5)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val (put_block_beat, put_block_done) = Counter(
|
|
||||||
state === s_putblock && io.mem.acquire.ready, tlDataBeats)
|
|
||||||
|
|
||||||
val put_acquire = Put(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = UInt(0),
|
|
||||||
data = UInt(0),
|
|
||||||
wmask = Some(UInt((1 << 8) - 1)))
|
|
||||||
|
|
||||||
val put_block_acquire = PutBlock(
|
|
||||||
client_xact_id = UInt(1),
|
|
||||||
addr_block = UInt(memStartBlock + 1),
|
|
||||||
addr_beat = put_block_beat,
|
|
||||||
data = UInt(0))
|
|
||||||
|
|
||||||
val put_acked = Reg(init = UInt(0, 2))
|
|
||||||
|
|
||||||
val (ack_cnt, all_acked) = Counter(io.mem.grant.fire(), 2)
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state.isOneOf(s_put, s_putblock)
|
|
||||||
io.mem.acquire.bits := Mux(state === s_put, put_acquire, put_block_acquire)
|
|
||||||
io.mem.grant.ready := (state === s_wait)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_put }
|
|
||||||
when (state === s_put && io.mem.acquire.ready) { state := s_putblock }
|
|
||||||
when (put_block_done) { state := s_wait }
|
|
||||||
when (all_acked) { state := s_finished }
|
|
||||||
|
|
||||||
io.finished := (state === s_finished)
|
|
||||||
io.errored := Bool(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that multiple gets to the same line and beat are merged
|
|
||||||
* correctly, even if it is a cache miss.
|
|
||||||
*/
|
|
||||||
class MergedGetRegression(nSets: Int, nWays: Int)(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
disableCache()
|
|
||||||
|
|
||||||
val (s_idle :: s_put :: s_get :: s_done :: Nil) = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
// Write NWays + 1 different conflicting lines to force an eviction of the first line
|
|
||||||
val (put_acq_cnt, put_acq_done) = Counter(state === s_put && io.mem.acquire.fire(), nWays + 1)
|
|
||||||
val (put_gnt_cnt, put_gnt_done) = Counter(state === s_put && io.mem.grant.fire(), nWays + 1)
|
|
||||||
val put_addr = UInt(memStartBlock) + Cat(put_acq_cnt, UInt(0, log2Up(nSets)))
|
|
||||||
|
|
||||||
val (get_acq_cnt, get_acq_done) = Counter(state === s_get && io.mem.acquire.fire(), 2)
|
|
||||||
val (get_gnt_cnt, get_gnt_done) = Counter(state === s_get && io.mem.grant.fire(), 2)
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_put; sending := Bool(true) }
|
|
||||||
when (state === s_put) {
|
|
||||||
when (io.mem.acquire.fire()) { sending := Bool(false) }
|
|
||||||
when (io.mem.grant.fire()) { sending := Bool(true) }
|
|
||||||
when (put_gnt_done) { state := s_get }
|
|
||||||
}
|
|
||||||
when (state === s_get) {
|
|
||||||
when (get_acq_done) { sending := Bool(false) }
|
|
||||||
when (get_gnt_done) { state := s_done }
|
|
||||||
}
|
|
||||||
|
|
||||||
io.mem.acquire.valid := sending
|
|
||||||
io.mem.acquire.bits := Mux(state === s_put,
|
|
||||||
Put(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = put_addr,
|
|
||||||
addr_beat = UInt(3),
|
|
||||||
data = UInt("hdabb9321")),
|
|
||||||
Get(
|
|
||||||
client_xact_id = get_acq_cnt,
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = UInt(3)))
|
|
||||||
io.mem.grant.ready := !sending
|
|
||||||
|
|
||||||
val data_mismatch = io.mem.grant.valid && io.mem.grant.bits.hasData() &&
|
|
||||||
io.mem.grant.bits.data =/= UInt("hdabb9321")
|
|
||||||
assert(!data_mismatch, "RepeatedGetRegression: wrong data back")
|
|
||||||
|
|
||||||
io.finished := state === s_done
|
|
||||||
io.errored := data_mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that multiple puts to the same line and beat are merged
|
|
||||||
* correctly, even if there is a release from the L1
|
|
||||||
*/
|
|
||||||
class MergedPutRegression(implicit p: Parameters) extends Regression()(p)
|
|
||||||
with HasTileLinkParameters {
|
|
||||||
val (s_idle :: s_cache_req :: s_cache_wait ::
|
|
||||||
s_put :: s_get :: s_done :: Nil) = Enum(Bits(), 6)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
io.cache.req.valid := (state === s_cache_req)
|
|
||||||
io.cache.req.bits.cmd := M_XWR
|
|
||||||
io.cache.req.bits.typ := MT_D
|
|
||||||
io.cache.req.bits.addr := UInt(memStart)
|
|
||||||
io.cache.req.bits.data := UInt(1)
|
|
||||||
io.cache.req.bits.tag := UInt(0)
|
|
||||||
|
|
||||||
val sending = Reg(init = Bool(false))
|
|
||||||
val delaying = Reg(init = Bool(false))
|
|
||||||
val (put_cnt, put_done) = Counter(io.mem.acquire.fire(), tlMaxClientXacts)
|
|
||||||
val (delay_cnt, delay_done) = Counter(delaying, 8)
|
|
||||||
val put_acked = Reg(UInt(width = tlMaxClientXacts), init = UInt(0))
|
|
||||||
|
|
||||||
io.mem.acquire.valid := sending && !delaying
|
|
||||||
io.mem.acquire.bits := Mux(state === s_put,
|
|
||||||
Put(
|
|
||||||
client_xact_id = put_cnt,
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = UInt(0),
|
|
||||||
data = put_cnt + UInt(2)),
|
|
||||||
Get(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = UInt(0)))
|
|
||||||
io.mem.grant.ready := Bool(true)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_cache_req }
|
|
||||||
when (io.cache.req.fire()) { state := s_cache_wait }
|
|
||||||
when (io.cache.resp.valid) { state := s_put; sending := Bool(true) }
|
|
||||||
|
|
||||||
when (io.mem.acquire.fire()) {
|
|
||||||
delaying := Bool(true)
|
|
||||||
when (put_done || state === s_get) { sending := Bool(false) }
|
|
||||||
}
|
|
||||||
when (delay_done) { delaying := Bool(false) }
|
|
||||||
|
|
||||||
when (io.mem.grant.fire()) {
|
|
||||||
when (state === s_put) {
|
|
||||||
put_acked := put_acked | UIntToOH(io.mem.grant.bits.client_xact_id)
|
|
||||||
}
|
|
||||||
when (state === s_get) { state := s_done }
|
|
||||||
}
|
|
||||||
|
|
||||||
when (state === s_put && put_acked.andR) {
|
|
||||||
state := s_get
|
|
||||||
sending := Bool(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
val expected_data = UInt(2 + tlMaxClientXacts - 1)
|
|
||||||
val data_mismatch = io.mem.grant.valid && io.mem.grant.bits.hasData() &&
|
|
||||||
io.mem.grant.bits.data =/= expected_data
|
|
||||||
|
|
||||||
assert(!data_mismatch, "MergedPutRegression: data mismatch")
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
io.errored := data_mismatch
|
|
||||||
}
|
|
||||||
|
|
||||||
class PutAfterReleaseRegression(implicit p: Parameters) extends Regression()(p) {
|
|
||||||
val (s_idle :: s_cache_req :: s_cache_resp ::
|
|
||||||
s_write_first_req :: s_delay :: s_write_remaining_req :: s_write_resp ::
|
|
||||||
s_read_req :: s_read_resp :: s_finished :: Nil) = Enum(Bits(), 10)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val (delay_cnt, delay_done) = Counter(state === s_delay, 100)
|
|
||||||
val (write_cnt, write_done) = Counter(
|
|
||||||
io.mem.acquire.fire() && io.mem.acquire.bits.hasData(), tlDataBeats)
|
|
||||||
val (read_cnt, read_done) = Counter(
|
|
||||||
io.mem.grant.fire() && io.mem.grant.bits.hasData(), tlDataBeats)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_cache_req }
|
|
||||||
when (io.cache.req.fire()) { state := s_cache_resp }
|
|
||||||
when (state === s_cache_resp && io.cache.resp.valid) { state := s_write_first_req }
|
|
||||||
when (state === s_write_first_req && io.mem.acquire.ready) { state := s_delay }
|
|
||||||
when (delay_done) { state := s_write_remaining_req }
|
|
||||||
when (write_done) { state := s_write_resp }
|
|
||||||
when (state === s_write_resp && io.mem.grant.valid) { state := s_read_req }
|
|
||||||
when (state === s_read_req && io.mem.acquire.ready) { state := s_read_resp }
|
|
||||||
when (read_done) { state := s_finished }
|
|
||||||
|
|
||||||
io.finished := state === s_finished
|
|
||||||
|
|
||||||
io.cache.req.valid := state === s_cache_req
|
|
||||||
io.cache.req.bits.cmd := M_XWR
|
|
||||||
io.cache.req.bits.addr := UInt(memStart)
|
|
||||||
io.cache.req.bits.typ := MT_D
|
|
||||||
io.cache.req.bits.tag := UInt(0)
|
|
||||||
io.cache.req.bits.data := UInt(0)
|
|
||||||
|
|
||||||
io.mem.acquire.valid := state.isOneOf(s_write_first_req, s_write_remaining_req, s_read_req)
|
|
||||||
io.mem.acquire.bits := Mux(state === s_read_req,
|
|
||||||
GetBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock)),
|
|
||||||
PutBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(memStartBlock),
|
|
||||||
addr_beat = write_cnt,
|
|
||||||
data = write_cnt + UInt(1)))
|
|
||||||
io.mem.grant.ready := state.isOneOf(s_write_resp, s_read_resp)
|
|
||||||
|
|
||||||
assert(!io.mem.grant.valid || !io.mem.grant.bits.hasData() ||
|
|
||||||
io.mem.grant.bits.data === read_cnt + UInt(1),
|
|
||||||
"PutAfterReleaseRegression: data mismatch")
|
|
||||||
}
|
|
||||||
|
|
||||||
object RegressionTests {
|
|
||||||
val l1sets = 16 // TODO
|
|
||||||
val l1ways = 1 // TODO
|
|
||||||
val l2sets = 32 // TODO
|
|
||||||
val l2ways = 2 // TODO
|
|
||||||
def cacheRegressions(implicit p: Parameters) = Seq(
|
|
||||||
Module(new PutBlockMergeRegression(l2sets)),
|
|
||||||
Module(new NoAllocPutHitRegression),
|
|
||||||
Module(new RepeatedNoAllocPutRegression),
|
|
||||||
Module(new WriteMaskedPutBlockRegression),
|
|
||||||
Module(new PrefetchHitRegression),
|
|
||||||
Module(new WritebackRegression(l2sets, l2ways)),
|
|
||||||
Module(new PutBeforePutBlockRegression),
|
|
||||||
Module(new MixedAllocPutRegression),
|
|
||||||
Module(new ReleaseRegression(l1sets, l1ways)),
|
|
||||||
Module(new MergedGetRegression(l2sets, l2ways)),
|
|
||||||
Module(new MergedPutRegression))
|
|
||||||
def broadcastRegressions(implicit p: Parameters) = Seq(
|
|
||||||
Module(new IOGetAfterPutBlockRegression),
|
|
||||||
Module(new WriteMaskedPutBlockRegression),
|
|
||||||
Module(new PutBeforePutBlockRegression),
|
|
||||||
Module(new ReleaseRegression(l1sets, l1ways)),
|
|
||||||
Module(new PutAfterReleaseRegression))
|
|
||||||
}
|
|
||||||
|
|
||||||
case object GroundTestRegressions extends Field[Parameters => Seq[Regression]]
|
|
||||||
|
|
||||||
class RegressionTest(implicit p: Parameters) extends GroundTest()(p) {
|
|
||||||
val regressions = p(GroundTestRegressions)(p)
|
|
||||||
val regress_idx = Reg(init = UInt(0, log2Up(regressions.size + 1)))
|
|
||||||
val cur_finished = Wire(init = Bool(false))
|
|
||||||
val all_done = (regress_idx === UInt(regressions.size))
|
|
||||||
val start = Reg(init = Bool(true))
|
|
||||||
|
|
||||||
// Some tests randomly backpressure grant; make this safe:
|
|
||||||
val grant = Queue(io.mem.head.grant, 16)
|
|
||||||
|
|
||||||
// default output values
|
|
||||||
io.mem.head.acquire.valid := Bool(false)
|
|
||||||
io.mem.head.acquire.bits := GetBlock(
|
|
||||||
client_xact_id = UInt(0),
|
|
||||||
addr_block = UInt(0))
|
|
||||||
grant.ready := Bool(false)
|
|
||||||
io.cache.head.req.valid := Bool(false)
|
|
||||||
io.cache.head.req.bits.addr := UInt(0)
|
|
||||||
io.cache.head.req.bits.typ := UInt(log2Ceil(64 / 8))
|
|
||||||
io.cache.head.req.bits.cmd := M_XRD
|
|
||||||
io.cache.head.req.bits.tag := UInt(0)
|
|
||||||
io.cache.head.req.bits.phys := Bool(true)
|
|
||||||
io.cache.head.req.bits.data := UInt(0)
|
|
||||||
io.cache.head.invalidate_lr := Bool(false)
|
|
||||||
|
|
||||||
regressions.zipWithIndex.foreach { case (regress, i) =>
|
|
||||||
val me = regress_idx === UInt(i)
|
|
||||||
regress.io.start := me && start
|
|
||||||
regress.io.mem.acquire.ready := io.mem.head.acquire.ready && me
|
|
||||||
regress.io.mem.grant.valid := grant.valid && me
|
|
||||||
regress.io.mem.grant.bits := grant.bits
|
|
||||||
regress.io.cache.req.ready := io.cache.head.req.ready && me
|
|
||||||
regress.io.cache.resp.valid := io.cache.head.resp.valid && me
|
|
||||||
regress.io.cache.resp.bits := io.cache.head.resp.bits
|
|
||||||
|
|
||||||
when (me) {
|
|
||||||
io.mem.head.acquire.valid := regress.io.mem.acquire.valid
|
|
||||||
io.mem.head.acquire.bits := regress.io.mem.acquire.bits
|
|
||||||
grant.ready := regress.io.mem.grant.ready
|
|
||||||
io.cache.head.req.valid := regress.io.cache.req.valid
|
|
||||||
io.cache.head.req.bits := regress.io.cache.req.bits
|
|
||||||
io.cache.head.invalidate_lr := regress.io.cache.invalidate_lr
|
|
||||||
io.status.error.valid := regress.io.errored
|
|
||||||
io.status.error.bits := UInt(i)
|
|
||||||
cur_finished := regress.io.finished
|
|
||||||
}
|
|
||||||
|
|
||||||
when (regress.io.start) {
|
|
||||||
printf(s"Starting regression ${regress.getClass.getSimpleName}\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (cur_finished && !all_done) {
|
|
||||||
start := Bool(true)
|
|
||||||
regress_idx := regress_idx + UInt(1)
|
|
||||||
}
|
|
||||||
when (start) { start := Bool(false) }
|
|
||||||
|
|
||||||
val timeout = SimpleTimer(5000, start, cur_finished)
|
|
||||||
assert(!timeout, "Regression timed out")
|
|
||||||
|
|
||||||
io.status.finished := all_done
|
|
||||||
io.status.timeout.valid := timeout
|
|
||||||
io.status.timeout.bits := UInt(0)
|
|
||||||
|
|
||||||
assert(!(all_done && grant.valid),
|
|
||||||
"Getting grant after test completion")
|
|
||||||
|
|
||||||
when (all_done) {
|
|
||||||
io.status.error.valid := grant.valid
|
|
||||||
io.status.error.bits := UInt(regressions.size)
|
|
||||||
}
|
|
||||||
}
|
|
23
src/main/scala/groundtest/Status.scala
Normal file
23
src/main/scala/groundtest/Status.scala
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import freechips.rocketchip.util.ValidMux
|
||||||
|
|
||||||
|
class GroundTestStatus extends Bundle {
|
||||||
|
val finished = Bool(OUTPUT)
|
||||||
|
val timeout = Valid(UInt(width = 4))
|
||||||
|
val error = Valid(UInt(width = 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
object DebugCombiner {
|
||||||
|
def apply(debugs: Seq[GroundTestStatus]): GroundTestStatus = {
|
||||||
|
val out = Wire(new GroundTestStatus)
|
||||||
|
out.finished := debugs.map(_.finished).reduce(_ && _)
|
||||||
|
out.timeout := ValidMux(debugs.map(_.timeout))
|
||||||
|
out.error := ValidMux(debugs.map(_.error))
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,11 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import diplomacy._
|
|
||||||
import config._
|
import freechips.rocketchip.config.Parameters
|
||||||
import rocketchip._
|
import freechips.rocketchip.diplomacy.LazyModule
|
||||||
import util._
|
|
||||||
|
|
||||||
class TestHarness(implicit p: Parameters) extends Module {
|
class TestHarness(implicit p: Parameters) extends Module {
|
||||||
val io = new Bundle { val success = Bool(OUTPUT) }
|
val io = new Bundle { val success = Bool(OUTPUT) }
|
||||||
|
@ -1,123 +1,51 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
// See LICENSE.Berkeley for license details.
|
// See LICENSE.Berkeley for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config._
|
import freechips.rocketchip.config._
|
||||||
import coreplex._
|
import freechips.rocketchip.coreplex._
|
||||||
import rocket._
|
import freechips.rocketchip.diplomacy._
|
||||||
import tile._
|
import freechips.rocketchip.rocket._
|
||||||
import uncore.tilelink._
|
import freechips.rocketchip.chip._
|
||||||
import uncore.tilelink2._
|
import freechips.rocketchip.tile._
|
||||||
import rocketchip.ExtMem
|
import freechips.rocketchip.tilelink._
|
||||||
import diplomacy._
|
|
||||||
import util.ParameterizedBundle
|
|
||||||
|
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
case object BuildGroundTest extends Field[Parameters => GroundTest]
|
trait GroundTestTileParams extends TileParams {
|
||||||
|
val memStart: BigInt
|
||||||
|
val maxRequests: Int
|
||||||
|
val numGens: Int
|
||||||
|
|
||||||
|
def build(i: Int, p: Parameters): GroundTestTile
|
||||||
|
|
||||||
case class GroundTestTileParams(
|
|
||||||
uncached: Int = 0,
|
|
||||||
ptw: Int = 0,
|
|
||||||
maxXacts: Int = 1,
|
|
||||||
dcache: Option[DCacheParams] = Some(DCacheParams())) extends TileParams {
|
|
||||||
val icache = None
|
val icache = None
|
||||||
val btb = None
|
val btb = None
|
||||||
val rocc = Nil
|
val rocc = Nil
|
||||||
val core = rocket.RocketCoreParams(nPMPs = 0) //TODO remove this
|
val core = RocketCoreParams(nPMPs = 0) //TODO remove this
|
||||||
val cached = if(dcache.isDefined) 1 else 0
|
val cached = if(dcache.isDefined) 1 else 0
|
||||||
val dataScratchpadBytes = 0
|
val dataScratchpadBytes = 0
|
||||||
}
|
}
|
||||||
case object GroundTestKey extends Field[Seq[GroundTestTileParams]]
|
|
||||||
|
|
||||||
trait HasGroundTestConstants {
|
case object GroundTestTilesKey extends Field[Seq[GroundTestTileParams]]
|
||||||
val timeoutCodeBits = 4
|
|
||||||
val errorCodeBits = 4
|
abstract class GroundTestTile(params: GroundTestTileParams)(implicit p: Parameters) extends BaseTile(params)(p) {
|
||||||
|
val slave = None
|
||||||
|
val dcacheOpt = params.dcache.map { dc => HellaCache(0, dc.nMSHRs == 0) }
|
||||||
|
dcacheOpt.foreach { tileBus.node := _.node }
|
||||||
|
|
||||||
|
override lazy val module = new GroundTestTileModule(this, () => new GroundTestTileBundle(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
trait HasGroundTestParameters {
|
class GroundTestTileBundle[+L <: GroundTestTile](_outer: L) extends BaseTileBundle(_outer) {
|
||||||
implicit val p: Parameters
|
|
||||||
val tileParams = p(GroundTestKey)(p(TileId))
|
|
||||||
val nUncached = tileParams.uncached
|
|
||||||
val nCached = tileParams.cached
|
|
||||||
val nPTW = tileParams.ptw
|
|
||||||
val memStart = p(ExtMem).base
|
|
||||||
val memStartBlock = memStart >> p(CacheBlockOffsetBits)
|
|
||||||
}
|
|
||||||
|
|
||||||
class GroundTestStatus extends Bundle with HasGroundTestConstants {
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
val timeout = Valid(UInt(width = timeoutCodeBits))
|
|
||||||
val error = Valid(UInt(width = errorCodeBits))
|
|
||||||
}
|
|
||||||
|
|
||||||
class GroundTestIO(implicit val p: Parameters) extends ParameterizedBundle()(p)
|
|
||||||
with HasGroundTestParameters {
|
|
||||||
val cache = Vec(nCached, new HellaCacheIO)
|
|
||||||
val mem = Vec(nUncached, new ClientUncachedTileLinkIO)
|
|
||||||
val ptw = Vec(nPTW, new TLBPTWIO)
|
|
||||||
val status = new GroundTestStatus
|
val status = new GroundTestStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class GroundTest(implicit val p: Parameters) extends Module
|
class GroundTestTileModule[+L <: GroundTestTile, +B <: GroundTestTileBundle[L]](_outer: L, _io: () => B) extends BaseTileModule(_outer, _io) {
|
||||||
with HasGroundTestParameters {
|
|
||||||
val io = new GroundTestIO
|
|
||||||
}
|
|
||||||
|
|
||||||
class GroundTestTile(implicit p: Parameters) extends LazyModule
|
outer.dcacheOpt foreach { dcache =>
|
||||||
with HasGroundTestParameters {
|
val ptw = Module(new DummyPTW(1))
|
||||||
val slave = None
|
ptw.io.requestors.head <> dcache.module.io.ptw
|
||||||
val dcacheOpt = tileParams.dcache.map { dc => HellaCache(0, dc.nMSHRs == 0) }
|
|
||||||
val ucLegacy = LazyModule(new TLLegacy)
|
|
||||||
|
|
||||||
val masterNode = TLOutputNode()
|
|
||||||
dcacheOpt.foreach { masterNode := _.node }
|
|
||||||
masterNode := TLHintHandler()(ucLegacy.node)
|
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val out = masterNode.bundleOut
|
|
||||||
val success = Bool(OUTPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val test = p(BuildGroundTest)(p)
|
|
||||||
|
|
||||||
val ptwPorts = ListBuffer.empty ++= test.io.ptw
|
|
||||||
val uncachedArbPorts = ListBuffer.empty ++= test.io.mem
|
|
||||||
|
|
||||||
dcacheOpt foreach { dcache =>
|
|
||||||
val dcacheArb = Module(new HellaCacheArbiter(nCached))
|
|
||||||
|
|
||||||
dcacheArb.io.requestor.zip(test.io.cache).foreach {
|
|
||||||
case (requestor, cache) =>
|
|
||||||
val dcacheIF = Module(new SimpleHellaCacheIF())
|
|
||||||
dcacheIF.io.requestor <> cache
|
|
||||||
requestor <> dcacheIF.io.cache
|
|
||||||
}
|
|
||||||
dcache.module.io.cpu <> dcacheArb.io.mem
|
|
||||||
|
|
||||||
// SimpleHellaCacheIF leaves invalidate_lr dangling, so we wire it to false
|
|
||||||
dcache.module.io.cpu.invalidate_lr := Bool(false)
|
|
||||||
|
|
||||||
ptwPorts += dcache.module.io.ptw
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptwPorts.size > 0) {
|
|
||||||
val ptw = Module(new DummyPTW(ptwPorts.size))
|
|
||||||
ptw.io.requestors <> ptwPorts
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uncachedArbPorts.isEmpty) {
|
|
||||||
ucLegacy.module.io.legacy.acquire.valid := Bool(false)
|
|
||||||
ucLegacy.module.io.legacy.grant.ready := Bool(true)
|
|
||||||
} else {
|
|
||||||
val uncachedArb = Module(new ClientUncachedTileLinkIOArbiter(uncachedArbPorts.size))
|
|
||||||
uncachedArb.io.in <> uncachedArbPorts
|
|
||||||
ucLegacy.module.io.legacy <> uncachedArb.io.out
|
|
||||||
}
|
|
||||||
|
|
||||||
io.success := test.io.status.finished
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import config.Parameters
|
|
||||||
import diplomacy.LazyModule
|
import freechips.rocketchip.config.Parameters
|
||||||
import rocketchip._
|
import freechips.rocketchip.diplomacy.LazyModule
|
||||||
|
import freechips.rocketchip.chip._
|
||||||
|
|
||||||
class GroundTestTop(implicit p: Parameters) extends BaseSystem
|
class GroundTestTop(implicit p: Parameters) extends BaseSystem
|
||||||
with HasPeripheryMasterAXI4MemPort
|
with HasPeripheryMasterAXI4MemPort
|
||||||
|
@ -17,17 +17,14 @@
|
|||||||
// Mainstream Systems (REMS) project, funded by EPSRC grant
|
// Mainstream Systems (REMS) project, funded by EPSRC grant
|
||||||
// EP/K008528/1.
|
// EP/K008528/1.
|
||||||
|
|
||||||
package groundtest
|
package freechips.rocketchip.groundtest
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import uncore.tilelink._
|
import freechips.rocketchip.config.{Field, Parameters}
|
||||||
import uncore.constants._
|
import freechips.rocketchip.rocket._
|
||||||
import coreplex.NTiles
|
import freechips.rocketchip.tile._
|
||||||
import rocket._
|
import freechips.rocketchip.util._
|
||||||
import tile._
|
|
||||||
import util.{Timer, DynamicTimer}
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
import config._
|
|
||||||
|
|
||||||
// =======
|
// =======
|
||||||
// Outline
|
// Outline
|
||||||
@ -59,19 +56,29 @@ import config._
|
|||||||
// (This is a way to generate a wider range of addresses without having
|
// (This is a way to generate a wider range of addresses without having
|
||||||
// to repeatedly recompile with a different address bag.)
|
// to repeatedly recompile with a different address bag.)
|
||||||
|
|
||||||
case object AddressBag extends Field[List[BigInt]]
|
case class TraceGenParams(
|
||||||
|
dcache: Option[DCacheParams] = Some(DCacheParams()),
|
||||||
|
wordBits: Int, // p(XLen)
|
||||||
|
addrBits: Int, // p(PAddrBits)
|
||||||
|
addrBag: List[BigInt], // p(AddressBag)
|
||||||
|
maxRequests: Int,
|
||||||
|
memStart: BigInt, //p(ExtMem).base
|
||||||
|
numGens: Int) extends GroundTestTileParams {
|
||||||
|
def build(i: Int, p: Parameters): GroundTestTile = new TraceGenTile(i, this)(p)
|
||||||
|
}
|
||||||
|
|
||||||
trait HasTraceGenParams {
|
trait HasTraceGenParams {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pAddrBits = p(PAddrBits)
|
val params: TraceGenParams
|
||||||
val numGens = p(NTiles)
|
val pAddrBits = params.addrBits
|
||||||
val numBitsInId = log2Up(numGens)
|
val numGens = params.numGens
|
||||||
val numReqsPerGen = p(GeneratorKey).maxRequests
|
val numReqsPerGen = params.maxRequests
|
||||||
|
val memStart = params.memStart
|
||||||
val memRespTimeout = 8192
|
val memRespTimeout = 8192
|
||||||
val numBitsInWord = p(XLen)
|
val numBitsInWord = params.wordBits
|
||||||
val numBytesInWord = numBitsInWord / 8
|
val numBytesInWord = numBitsInWord / 8
|
||||||
val numBitsInWordOffset = log2Up(numBytesInWord)
|
val numBitsInWordOffset = log2Up(numBytesInWord)
|
||||||
val addressBag = p(AddressBag)
|
val addressBag = params.addrBag
|
||||||
val addressBagLen = addressBag.length
|
val addressBagLen = addressBag.length
|
||||||
val logAddressBagLen = log2Up(addressBagLen)
|
val logAddressBagLen = log2Up(addressBagLen)
|
||||||
val genExtraAddrs = false
|
val genExtraAddrs = false
|
||||||
@ -179,14 +186,13 @@ class TagMan(val logNumTags : Int) extends Module {
|
|||||||
// Trace generator
|
// Trace generator
|
||||||
// ===============
|
// ===============
|
||||||
|
|
||||||
class TraceGenerator(id: Int)
|
class TraceGenerator(val params: TraceGenParams)(implicit val p: Parameters) extends Module
|
||||||
(implicit val p: Parameters) extends Module
|
with HasTraceGenParams {
|
||||||
with HasTraceGenParams
|
|
||||||
with HasGroundTestParameters {
|
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val finished = Bool(OUTPUT)
|
val finished = Bool(OUTPUT)
|
||||||
val timeout = Bool(OUTPUT)
|
val timeout = Bool(OUTPUT)
|
||||||
val mem = new HellaCacheIO
|
val mem = new HellaCacheIO
|
||||||
|
val hartid = UInt(INPUT, log2Up(numGens))
|
||||||
}
|
}
|
||||||
|
|
||||||
val totalNumAddrs = addressBag.size + numExtraAddrs
|
val totalNumAddrs = addressBag.size + numExtraAddrs
|
||||||
@ -199,8 +205,6 @@ class TraceGenerator(id: Int)
|
|||||||
reqTimer.io.stop.valid := io.mem.resp.valid
|
reqTimer.io.stop.valid := io.mem.resp.valid
|
||||||
reqTimer.io.stop.bits := io.mem.resp.bits.tag
|
reqTimer.io.stop.bits := io.mem.resp.bits.tag
|
||||||
|
|
||||||
assert(!reqTimer.io.timeout.valid, s"TraceGen core ${id}: request timed out")
|
|
||||||
|
|
||||||
// Random addresses
|
// Random addresses
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
@ -327,7 +331,7 @@ class TraceGenerator(id: Int)
|
|||||||
// ------------------
|
// ------------------
|
||||||
|
|
||||||
// Hardware thread id
|
// Hardware thread id
|
||||||
val tid = UInt(id, numBitsInId)
|
val tid = io.hartid
|
||||||
|
|
||||||
// Request & response count
|
// Request & response count
|
||||||
val reqCount = Reg(init = UInt(0, 32))
|
val reqCount = Reg(init = UInt(0, 32))
|
||||||
@ -345,7 +349,7 @@ class TraceGenerator(id: Int)
|
|||||||
sendFreshReq := Bool(false)
|
sendFreshReq := Bool(false)
|
||||||
|
|
||||||
// Used to generate unique data values
|
// Used to generate unique data values
|
||||||
val nextData = Reg(init = UInt(1, numBitsInWord-numBitsInId))
|
val nextData = Reg(init = UInt(1, numBitsInWord-tid.getWidth))
|
||||||
|
|
||||||
// Registers for all the interesting parts of a request
|
// Registers for all the interesting parts of a request
|
||||||
val reqValid = Reg(init = Bool(false))
|
val reqValid = Reg(init = Bool(false))
|
||||||
@ -503,6 +507,7 @@ class TraceGenerator(id: Int)
|
|||||||
io.mem.req.bits.typ := UInt(log2Ceil(numBytesInWord))
|
io.mem.req.bits.typ := UInt(log2Ceil(numBytesInWord))
|
||||||
io.mem.req.bits.cmd := reqCmd
|
io.mem.req.bits.cmd := reqCmd
|
||||||
io.mem.req.bits.tag := reqTag
|
io.mem.req.bits.tag := reqTag
|
||||||
|
io.mem.invalidate_lr := Bool(false)
|
||||||
|
|
||||||
// On cycle when request is actually sent, print it
|
// On cycle when request is actually sent, print it
|
||||||
when (io.mem.req.fire()) {
|
when (io.mem.req.fire()) {
|
||||||
@ -569,17 +574,25 @@ class TraceGenerator(id: Int)
|
|||||||
// Trace-generator wrapper
|
// Trace-generator wrapper
|
||||||
// =======================
|
// =======================
|
||||||
|
|
||||||
class GroundTestTraceGenerator(implicit p: Parameters)
|
class TraceGenTile(val id: Int, val params: TraceGenParams)(implicit p: Parameters) extends GroundTestTile(params) {
|
||||||
extends GroundTest()(p) with HasTraceGenParams {
|
override lazy val module = new TraceGenTileModule(this)
|
||||||
|
}
|
||||||
|
|
||||||
require(io.mem.size <= 1)
|
class TraceGenTileModule(outer: TraceGenTile) extends GroundTestTileModule(outer, () => new GroundTestTileBundle(outer)) {
|
||||||
require(io.cache.size == 1)
|
|
||||||
|
|
||||||
val traceGen = Module(new TraceGenerator(p(TileId)))
|
val tracegen = Module(new TraceGenerator(outer.params))
|
||||||
io.cache.head <> traceGen.io.mem
|
tracegen.io.hartid := io.hartid
|
||||||
|
|
||||||
io.status.finished := traceGen.io.finished
|
outer.dcacheOpt foreach { dcache =>
|
||||||
io.status.timeout.valid := traceGen.io.timeout
|
val dcacheIF = Module(new SimpleHellaCacheIF())
|
||||||
|
dcacheIF.io.requestor <> tracegen.io.mem
|
||||||
|
dcache.module.io.cpu <> dcacheIF.io.cache
|
||||||
|
}
|
||||||
|
|
||||||
|
io.status.finished := tracegen.io.finished
|
||||||
|
io.status.timeout.valid := tracegen.io.timeout
|
||||||
io.status.timeout.bits := UInt(0)
|
io.status.timeout.bits := UInt(0)
|
||||||
io.status.error.valid := Bool(false)
|
io.status.error.valid := Bool(false)
|
||||||
|
|
||||||
|
assert(!tracegen.io.timeout, s"TraceGen tile ${outer.id}: request timed out")
|
||||||
}
|
}
|
||||||
|
@ -1,216 +0,0 @@
|
|||||||
// 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)
|
|
||||||
(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)
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
|
|
||||||
package groundtest
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// LCG16 module
|
|
||||||
// ============
|
|
||||||
|
|
||||||
// A 16-bit psuedo-random generator based on a linear conguential
|
|
||||||
// generator (LCG). The state is stored in an unitialised register.
|
|
||||||
// When using the C++ backend, it is straigtforward to arrange a
|
|
||||||
// random initial value for each uninitialised register, effectively
|
|
||||||
// seeding each LCG16 instance with a different seed.
|
|
||||||
|
|
||||||
class LCG16 extends Module {
|
|
||||||
val io = new Bundle {
|
|
||||||
val out = UInt(OUTPUT, 16)
|
|
||||||
val inc = Bool(INPUT)
|
|
||||||
}
|
|
||||||
val state = Reg(UInt(width = 32))
|
|
||||||
when (io.inc) {
|
|
||||||
state := state * UInt(1103515245, 32) + UInt(12345, 32)
|
|
||||||
}
|
|
||||||
io.out := state(30, 15)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========
|
|
||||||
// LCG module
|
|
||||||
// ==========
|
|
||||||
|
|
||||||
// An n-bit psuedo-random generator made from many instances of a
|
|
||||||
// 16-bit LCG. Parameter 'width' must be larger than 0.
|
|
||||||
|
|
||||||
class LCG(val w: Int) extends Module {
|
|
||||||
val io = new Bundle {
|
|
||||||
val out = UInt(OUTPUT, w)
|
|
||||||
val inc = Bool(INPUT)
|
|
||||||
}
|
|
||||||
require(w > 0)
|
|
||||||
val numLCG16s : Int = (w+15)/16
|
|
||||||
val outs = Seq.fill(numLCG16s) { LCG16(io.inc) }
|
|
||||||
io.out := Cat(outs)
|
|
||||||
}
|
|
||||||
|
|
||||||
object LCG16 {
|
|
||||||
def apply(inc: Bool = Bool(true)): UInt = {
|
|
||||||
val lcg = Module(new LCG16)
|
|
||||||
lcg.io.inc := inc
|
|
||||||
lcg.io.out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object LCG {
|
|
||||||
def apply(w: Int, inc: Bool = Bool(true)): UInt = {
|
|
||||||
val lcg = Module(new LCG(w))
|
|
||||||
lcg.io.inc := inc
|
|
||||||
lcg.io.out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================
|
|
||||||
// Frequency distribution
|
|
||||||
// ======================
|
|
||||||
|
|
||||||
// Given a list of (frequency, value) pairs, return a random value
|
|
||||||
// according to the frequency distribution. The sum of the
|
|
||||||
// frequencies in the distribution must be a power of two.
|
|
||||||
|
|
||||||
object Frequency {
|
|
||||||
def apply(dist : List[(Int, Bits)]) : Bits = {
|
|
||||||
// Distribution must be non-empty
|
|
||||||
require(dist.length > 0)
|
|
||||||
|
|
||||||
// Require that the frequencies sum to a power of two
|
|
||||||
val (freqs, vals) = dist.unzip
|
|
||||||
val total = freqs.sum
|
|
||||||
require(isPow2(total))
|
|
||||||
|
|
||||||
// First item in the distribution
|
|
||||||
val (firstFreq, firstVal) = dist.head
|
|
||||||
|
|
||||||
// Result wire
|
|
||||||
val result = Wire(Bits(width = firstVal.getWidth))
|
|
||||||
result := UInt(0)
|
|
||||||
|
|
||||||
// Random value
|
|
||||||
val randVal = LCG(log2Up(total))
|
|
||||||
|
|
||||||
// Pick return value
|
|
||||||
var count = firstFreq
|
|
||||||
var select = when (randVal < UInt(firstFreq)) { result := firstVal }
|
|
||||||
for (p <- dist.drop(1)) {
|
|
||||||
count = count + p._1
|
|
||||||
select = select.elsewhen(randVal < UInt(count)) { result := p._2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object ValidMux {
|
|
||||||
def apply[T <: Data](v1: ValidIO[T], v2: ValidIO[T]*): ValidIO[T] = {
|
|
||||||
apply(v1 +: v2.toSeq)
|
|
||||||
}
|
|
||||||
def apply[T <: Data](valids: Seq[ValidIO[T]]): ValidIO[T] = {
|
|
||||||
val out = Wire(Valid(valids.head.bits))
|
|
||||||
out.valid := valids.map(_.valid).reduce(_ || _)
|
|
||||||
out.bits := MuxCase(valids.head.bits,
|
|
||||||
valids.map(v => (v.valid -> v.bits)))
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DebugCombiner {
|
|
||||||
def apply(debugs: Seq[GroundTestStatus]): GroundTestStatus = {
|
|
||||||
val out = Wire(new GroundTestStatus)
|
|
||||||
out.finished := debugs.map(_.finished).reduce(_ && _)
|
|
||||||
out.timeout := ValidMux(debugs.map(_.timeout))
|
|
||||||
out.error := ValidMux(debugs.map(_.error))
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes in data on one decoupled interface and broadcasts it to
|
|
||||||
* N decoupled output interfaces
|
|
||||||
*/
|
|
||||||
class Broadcaster[T <: Data](typ: T, n: Int) extends Module {
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = Decoupled(typ).flip
|
|
||||||
val out = Vec(n, Decoupled(typ))
|
|
||||||
}
|
|
||||||
|
|
||||||
require (n > 0)
|
|
||||||
|
|
||||||
if (n == 1) {
|
|
||||||
io.out.head <> io.in
|
|
||||||
} else {
|
|
||||||
val idx = Reg(init = UInt(0, log2Up(n)))
|
|
||||||
val save = Reg(typ)
|
|
||||||
|
|
||||||
io.out.head.valid := idx === UInt(0) && io.in.valid
|
|
||||||
io.out.head.bits := io.in.bits
|
|
||||||
for (i <- 1 until n) {
|
|
||||||
io.out(i).valid := idx === UInt(i)
|
|
||||||
io.out(i).bits := save
|
|
||||||
}
|
|
||||||
io.in.ready := io.out.head.ready && idx === UInt(0)
|
|
||||||
|
|
||||||
when (io.in.fire()) { save := io.in.bits }
|
|
||||||
|
|
||||||
when (io.out(idx).fire()) {
|
|
||||||
when (idx === UInt(n - 1)) { idx := UInt(0) }
|
|
||||||
.otherwise { idx := idx + UInt(1) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object Broadcaster {
|
|
||||||
def apply[T <: Data](in: DecoupledIO[T], n: Int): Vec[DecoupledIO[T]] = {
|
|
||||||
val split = Module(new Broadcaster(in.bits, n))
|
|
||||||
split.io.in <> in
|
|
||||||
split.io.out
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.jtag for license details.
|
// See LICENSE.jtag for license details.
|
||||||
|
|
||||||
package jtag
|
package freechips.rocketchip.jtag
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.core.DataMirror
|
import chisel3.core.DataMirror
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// See LICENSE.jtag for license details.
|
// See LICENSE.jtag for license details.
|
||||||
|
|
||||||
package jtag
|
package freechips.rocketchip.jtag
|
||||||
|
|
||||||
import util.{AsyncResetRegVec}
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
|
import freechips.rocketchip.util.{AsyncResetRegVec}
|
||||||
|
|
||||||
object JtagState {
|
object JtagState {
|
||||||
sealed abstract class State(val id: Int) {
|
sealed abstract class State(val id: Int) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.jtag for license details.
|
// See LICENSE.jtag for license details.
|
||||||
|
|
||||||
package jtag
|
package freechips.rocketchip.jtag
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.jtag for license details.
|
// See LICENSE.jtag for license details.
|
||||||
|
|
||||||
package jtag
|
package freechips.rocketchip.jtag
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE.jtag for license details.
|
// See LICENSE.jtag for license details.
|
||||||
|
|
||||||
package jtag
|
package freechips.rocketchip.jtag
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.util._
|
import chisel3.util._
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// See LICENSE.jtag for license details
|
// See LICENSE.jtag for license details
|
||||||
|
|
||||||
|
package freechips.rocketchip
|
||||||
|
|
||||||
import scala.language.implicitConversions
|
import scala.language.implicitConversions
|
||||||
|
|
||||||
package object jtag {
|
package object jtag {
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
// See LICENSE.SiFive for license details.
|
|
||||||
|
|
||||||
package junctions
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import config._
|
|
||||||
|
|
||||||
class NastiDriver(dataWidth: Int, burstLen: Int, nBursts: Int)
|
|
||||||
(implicit p: Parameters) extends NastiModule {
|
|
||||||
val io = new Bundle {
|
|
||||||
val nasti = new NastiIO
|
|
||||||
val finished = Bool(OUTPUT)
|
|
||||||
val start = Bool(INPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val dataBytes = dataWidth / 8
|
|
||||||
val nastiDataBytes = nastiXDataBits / 8
|
|
||||||
|
|
||||||
val (write_cnt, write_done) = Counter(io.nasti.w.fire(), burstLen)
|
|
||||||
val (read_cnt, read_done) = Counter(io.nasti.r.fire(), burstLen)
|
|
||||||
val (req_cnt, reqs_done) = Counter(read_done, nBursts)
|
|
||||||
|
|
||||||
val req_addr = Cat(req_cnt, UInt(0, log2Up(burstLen * dataBytes)))
|
|
||||||
|
|
||||||
val write_data = UInt(0x10000000L, dataWidth) | Cat(req_cnt, write_cnt)
|
|
||||||
val expected_data = UInt(0x10000000L, dataWidth) | Cat(req_cnt, read_cnt)
|
|
||||||
|
|
||||||
val (s_idle :: s_write_addr :: s_write_data :: s_write_stall :: s_write_resp ::
|
|
||||||
s_read_addr :: s_read_data :: s_read_stall :: s_done :: Nil) = Enum(Bits(), 9)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val (stall_cnt, stall_done) = Counter(state === s_read_stall, 2)
|
|
||||||
|
|
||||||
io.nasti.aw.valid := (state === s_write_addr)
|
|
||||||
io.nasti.aw.bits := NastiWriteAddressChannel(
|
|
||||||
id = UInt(0),
|
|
||||||
addr = req_addr,
|
|
||||||
size = UInt(log2Up(dataBytes)),
|
|
||||||
len = UInt(burstLen - 1))
|
|
||||||
|
|
||||||
io.nasti.w.valid := (state === s_write_data)
|
|
||||||
io.nasti.w.bits := NastiWriteDataChannel(
|
|
||||||
data = Cat(write_data, write_data),
|
|
||||||
last = (write_cnt === UInt(burstLen - 1)))
|
|
||||||
|
|
||||||
io.nasti.b.ready := (state === s_write_resp)
|
|
||||||
|
|
||||||
io.nasti.ar.valid := (state === s_read_addr)
|
|
||||||
io.nasti.ar.bits := NastiReadAddressChannel(
|
|
||||||
id = UInt(0),
|
|
||||||
addr = req_addr,
|
|
||||||
size = UInt(log2Up(dataBytes)),
|
|
||||||
len = UInt(burstLen - 1))
|
|
||||||
|
|
||||||
io.nasti.r.ready := (state === s_read_data)
|
|
||||||
|
|
||||||
io.finished := (state === s_done)
|
|
||||||
|
|
||||||
when (state === s_idle && io.start) { state := s_write_addr }
|
|
||||||
when (io.nasti.aw.fire()) { state := s_write_data }
|
|
||||||
when (io.nasti.w.fire()) { state := s_write_stall }
|
|
||||||
when (state === s_write_stall) { state := s_write_data }
|
|
||||||
when (write_done) { state := s_write_resp }
|
|
||||||
when (io.nasti.b.fire()) { state := s_read_addr }
|
|
||||||
when (io.nasti.ar.fire()) { state := s_read_data }
|
|
||||||
when (io.nasti.r.fire()) { state := s_read_stall }
|
|
||||||
when (stall_done) { state := s_read_data }
|
|
||||||
when (read_done) { state := s_write_addr }
|
|
||||||
when (reqs_done) { state := s_done }
|
|
||||||
|
|
||||||
val full_addr = req_addr + (read_cnt << UInt(log2Up(dataBytes)))
|
|
||||||
val byteshift = full_addr(log2Up(nastiDataBytes) - 1, 0)
|
|
||||||
val bitshift = Cat(byteshift, UInt(0, 3))
|
|
||||||
val read_data = (io.nasti.r.bits.data >> bitshift) & Fill(dataWidth, UInt(1, 1))
|
|
||||||
|
|
||||||
assert(!io.nasti.r.valid || read_data === expected_data,
|
|
||||||
s"NastiDriver got wrong data")
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
|
|
||||||
package junctions
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import config._
|
|
||||||
import scala.collection.mutable.HashMap
|
|
||||||
|
|
||||||
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
|
||||||
|
|
||||||
sealed abstract class MemRegion {
|
|
||||||
def start: BigInt
|
|
||||||
def size: BigInt
|
|
||||||
def numSlaves: Int
|
|
||||||
def attr: MemAttr
|
|
||||||
|
|
||||||
def containsAddress(x: UInt) = UInt(start) <= x && x < UInt(start + size)
|
|
||||||
}
|
|
||||||
|
|
||||||
case class MemSize(size: BigInt, attr: MemAttr) extends MemRegion {
|
|
||||||
def start = 0
|
|
||||||
def numSlaves = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
case class MemRange(start: BigInt, size: BigInt, attr: MemAttr) extends MemRegion {
|
|
||||||
def numSlaves = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
object AddrMapProt {
|
|
||||||
val R = 0x1
|
|
||||||
val W = 0x2
|
|
||||||
val X = 0x4
|
|
||||||
val RW = R | W
|
|
||||||
val RX = R | X
|
|
||||||
val RWX = R | W | X
|
|
||||||
val SZ = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddrMapProt extends Bundle {
|
|
||||||
val x = Bool()
|
|
||||||
val w = Bool()
|
|
||||||
val r = Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
case class AddrMapEntry(name: String, region: MemRegion)
|
|
||||||
|
|
||||||
object AddrMap {
|
|
||||||
def apply(elems: AddrMapEntry*): AddrMap = new AddrMap(elems)
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddrMap(
|
|
||||||
entriesIn: Seq[AddrMapEntry],
|
|
||||||
val start: BigInt = BigInt(0),
|
|
||||||
val collapse: Boolean = false) extends MemRegion {
|
|
||||||
private val slavePorts = HashMap[String, Int]()
|
|
||||||
private val mapping = HashMap[String, MemRegion]()
|
|
||||||
|
|
||||||
def isEmpty = entries.isEmpty
|
|
||||||
def length = entries.size
|
|
||||||
def numSlaves = slavePorts.size
|
|
||||||
|
|
||||||
val (size: BigInt, entries: Seq[AddrMapEntry], attr: MemAttr) = {
|
|
||||||
var ind = 0
|
|
||||||
var base = start
|
|
||||||
var rebasedEntries = collection.mutable.ArrayBuffer[AddrMapEntry]()
|
|
||||||
var prot = 0
|
|
||||||
var cacheable = true
|
|
||||||
for (AddrMapEntry(name, r) <- entriesIn) {
|
|
||||||
require (!mapping.contains(name))
|
|
||||||
base = r.start
|
|
||||||
|
|
||||||
r match {
|
|
||||||
case r: AddrMap =>
|
|
||||||
val subMap = new AddrMap(r.entries, base, r.collapse)
|
|
||||||
rebasedEntries += AddrMapEntry(name, subMap)
|
|
||||||
mapping += name -> subMap
|
|
||||||
mapping ++= subMap.mapping.map { case (k, v) => s"$name:$k" -> v }
|
|
||||||
if (r.collapse) {
|
|
||||||
slavePorts += (name -> ind)
|
|
||||||
ind += 1
|
|
||||||
} else {
|
|
||||||
slavePorts ++= subMap.slavePorts.map {
|
|
||||||
case (k, v) => s"$name:$k" -> (ind + v)
|
|
||||||
}
|
|
||||||
ind += r.numSlaves
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
val e = MemRange(base, r.size, r.attr)
|
|
||||||
rebasedEntries += AddrMapEntry(name, e)
|
|
||||||
mapping += name -> e
|
|
||||||
slavePorts += name -> ind
|
|
||||||
ind += r.numSlaves
|
|
||||||
}
|
|
||||||
|
|
||||||
base += r.size
|
|
||||||
prot |= r.attr.prot
|
|
||||||
cacheable &&= r.attr.cacheable
|
|
||||||
}
|
|
||||||
(base - start, rebasedEntries, MemAttr(prot, cacheable))
|
|
||||||
}
|
|
||||||
|
|
||||||
val flatten: Seq[AddrMapEntry] = {
|
|
||||||
mapping.toSeq.map {
|
|
||||||
case (name, range: MemRange) => Some(AddrMapEntry(name, range))
|
|
||||||
case _ => None
|
|
||||||
}.flatten.sortBy(_.region.start)
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks to see whether any MemRange overlaps within this AddrMap
|
|
||||||
flatten.combinations(2) foreach {
|
|
||||||
case (Seq(AddrMapEntry(an, ar), AddrMapEntry(bn, br))) =>
|
|
||||||
val arEnd = ar.start + ar.size
|
|
||||||
val brEnd = br.start + br.size
|
|
||||||
val abOverlaps = ar.start < brEnd && br.start < arEnd
|
|
||||||
require(!abOverlaps,
|
|
||||||
s"region $an@0x${ar.start.toString(16)} overlaps region $bn@0x${br.start.toString(16)}")
|
|
||||||
}
|
|
||||||
|
|
||||||
def toRange: MemRange = MemRange(start, size, attr)
|
|
||||||
def apply(name: String): MemRegion = mapping(name)
|
|
||||||
def contains(name: String): Boolean = mapping.contains(name)
|
|
||||||
def port(name: String): Int = slavePorts(name)
|
|
||||||
def subMap(name: String): AddrMap = mapping(name).asInstanceOf[AddrMap]
|
|
||||||
def isInRegion(name: String, addr: UInt): Bool = mapping(name).containsAddress(addr)
|
|
||||||
|
|
||||||
def isCacheable(addr: UInt): Bool = {
|
|
||||||
flatten.filter(_.region.attr.cacheable).map(
|
|
||||||
_.region.containsAddress(addr)
|
|
||||||
).foldLeft(Bool(false))(_ || _)
|
|
||||||
}
|
|
||||||
|
|
||||||
def isValid(addr: UInt): Bool = {
|
|
||||||
flatten.map(_.region.containsAddress(addr)).foldLeft(Bool(false))(_ || _)
|
|
||||||
}
|
|
||||||
|
|
||||||
def getProt(addr: UInt): AddrMapProt = {
|
|
||||||
val protForRegion = flatten.map { entry =>
|
|
||||||
Mux(entry.region.containsAddress(addr),
|
|
||||||
UInt(entry.region.attr.prot, AddrMapProt.SZ), UInt(0))
|
|
||||||
}
|
|
||||||
new AddrMapProt().fromBits(protForRegion.reduce(_|_))
|
|
||||||
}
|
|
||||||
|
|
||||||
override def containsAddress(x: UInt) = {
|
|
||||||
flatten.map(_.region.containsAddress(x)).reduce(_||_)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,565 +0,0 @@
|
|||||||
// See LICENSE.SiFive for license details.
|
|
||||||
// See LICENSE.Berkeley for license details.
|
|
||||||
|
|
||||||
package junctions
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import config._
|
|
||||||
import unittest.UnitTest
|
|
||||||
import util._
|
|
||||||
|
|
||||||
object HastiConstants
|
|
||||||
{
|
|
||||||
// Values for htrans
|
|
||||||
val SZ_HTRANS = 2
|
|
||||||
def HTRANS_IDLE = UInt(0, SZ_HTRANS) // No transfer requested, not in a burst
|
|
||||||
def HTRANS_BUSY = UInt(1, SZ_HTRANS) // No transfer requested, in a burst
|
|
||||||
def HTRANS_NONSEQ = UInt(2, SZ_HTRANS) // First (potentially only) request in a burst
|
|
||||||
def HTRANS_SEQ = UInt(3, SZ_HTRANS) // Following requests in a burst
|
|
||||||
|
|
||||||
// Values for hburst
|
|
||||||
val SZ_HBURST = 3
|
|
||||||
def HBURST_SINGLE = UInt(0, SZ_HBURST) // Single access (no burst)
|
|
||||||
def HBURST_INCR = UInt(1, SZ_HBURST) // Incrementing burst of arbitrary length, not crossing 1KB
|
|
||||||
def HBURST_WRAP4 = UInt(2, SZ_HBURST) // 4-beat wrapping burst
|
|
||||||
def HBURST_INCR4 = UInt(3, SZ_HBURST) // 4-beat incrementing burst
|
|
||||||
def HBURST_WRAP8 = UInt(4, SZ_HBURST) // 8-beat wrapping burst
|
|
||||||
def HBURST_INCR8 = UInt(5, SZ_HBURST) // 8-beat incrementing burst
|
|
||||||
def HBURST_WRAP16 = UInt(6, SZ_HBURST) // 16-beat wrapping burst
|
|
||||||
def HBURST_INCR16 = UInt(7, SZ_HBURST) // 16-beat incrementing burst
|
|
||||||
|
|
||||||
// Values for hresp
|
|
||||||
val SZ_HRESP = 1
|
|
||||||
def HRESP_OKAY = UInt(0, SZ_HRESP)
|
|
||||||
def HRESP_ERROR = UInt(1, SZ_HRESP)
|
|
||||||
|
|
||||||
// Values for hsize are identical to TileLink MT_SZ
|
|
||||||
// ie: 8*2^SZ_HSIZE bit transfers
|
|
||||||
val SZ_HSIZE = 3
|
|
||||||
|
|
||||||
// Values for hprot (a bitmask)
|
|
||||||
val SZ_HPROT = 4
|
|
||||||
def HPROT_DATA = UInt("b0001") // Data access or Opcode fetch
|
|
||||||
def HPROT_PRIVILEGED = UInt("b0010") // Privileged or User access
|
|
||||||
def HPROT_BUFFERABLE = UInt("b0100") // Bufferable or non-bufferable
|
|
||||||
def HPROT_CACHEABLE = UInt("b1000") // Cacheable or non-cacheable
|
|
||||||
|
|
||||||
def dgate(valid: Bool, b: UInt) = Fill(b.getWidth, valid) & b
|
|
||||||
}
|
|
||||||
|
|
||||||
import HastiConstants._
|
|
||||||
|
|
||||||
case class HastiParameters(dataBits: Int, addrBits: Int)
|
|
||||||
case object HastiId extends Field[String]
|
|
||||||
case class HastiKey(id: String) extends Field[HastiParameters]
|
|
||||||
|
|
||||||
trait HasHastiParameters {
|
|
||||||
implicit val p: Parameters
|
|
||||||
val hastiParams = p(HastiKey(p(HastiId)))
|
|
||||||
val hastiAddrBits = hastiParams.addrBits
|
|
||||||
val hastiDataBits = hastiParams.dataBits
|
|
||||||
val hastiDataBytes = hastiDataBits/8
|
|
||||||
val hastiAlignment = log2Ceil(hastiDataBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class HastiModule(implicit val p: Parameters) extends Module
|
|
||||||
with HasHastiParameters
|
|
||||||
abstract class HastiBundle(implicit val p: Parameters) extends ParameterizedBundle()(p)
|
|
||||||
with HasHastiParameters
|
|
||||||
|
|
||||||
class HastiMasterIO(implicit p: Parameters) extends HastiBundle()(p) {
|
|
||||||
val htrans = UInt(OUTPUT, SZ_HTRANS)
|
|
||||||
val hmastlock = Bool(OUTPUT)
|
|
||||||
val haddr = UInt(OUTPUT, hastiAddrBits)
|
|
||||||
val hwrite = Bool(OUTPUT)
|
|
||||||
val hburst = UInt(OUTPUT, SZ_HBURST)
|
|
||||||
val hsize = UInt(OUTPUT, SZ_HSIZE)
|
|
||||||
val hprot = UInt(OUTPUT, SZ_HPROT)
|
|
||||||
|
|
||||||
val hwdata = Bits(OUTPUT, hastiDataBits)
|
|
||||||
val hrdata = Bits(INPUT, hastiDataBits)
|
|
||||||
|
|
||||||
val hready = Bool(INPUT)
|
|
||||||
val hresp = UInt(INPUT, SZ_HRESP)
|
|
||||||
|
|
||||||
def isNSeq(dummy:Int=0) = htrans === HTRANS_NONSEQ // SEQ does not start a NEW request
|
|
||||||
def isHold(dummy:Int=0) = htrans === HTRANS_BUSY || htrans === HTRANS_SEQ
|
|
||||||
def isIdle(dummy:Int=0) = htrans === HTRANS_IDLE || htrans === HTRANS_BUSY
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiSlaveIO(implicit p: Parameters) extends HastiBundle()(p) {
|
|
||||||
val htrans = UInt(INPUT, SZ_HTRANS)
|
|
||||||
val hmastlock = Bool(INPUT)
|
|
||||||
val haddr = UInt(INPUT, hastiAddrBits)
|
|
||||||
val hwrite = Bool(INPUT)
|
|
||||||
val hburst = UInt(INPUT, SZ_HBURST)
|
|
||||||
val hsize = UInt(INPUT, SZ_HSIZE)
|
|
||||||
val hprot = UInt(INPUT, SZ_HPROT)
|
|
||||||
|
|
||||||
val hwdata = Bits(INPUT, hastiDataBits)
|
|
||||||
val hrdata = Bits(OUTPUT, hastiDataBits)
|
|
||||||
|
|
||||||
val hsel = Bool(INPUT)
|
|
||||||
val hready = Bool(OUTPUT)
|
|
||||||
val hresp = UInt(OUTPUT, SZ_HRESP)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A diverted master is told hready when his address phase goes nowhere.
|
|
||||||
* In this case, we buffer his address phase request and replay it later.
|
|
||||||
* NOTE: this must optimize to nothing when divert is constantly false.
|
|
||||||
*/
|
|
||||||
class MasterDiversion(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = (new HastiMasterIO).flip
|
|
||||||
val out = (new HastiMasterIO)
|
|
||||||
val divert = Bool(INPUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val full = Reg(init = Bool(false))
|
|
||||||
val buffer = Reg(new HastiMasterIO)
|
|
||||||
|
|
||||||
when (io.out.hready) {
|
|
||||||
full := Bool(false)
|
|
||||||
}
|
|
||||||
when (io.divert) {
|
|
||||||
full := Bool(true)
|
|
||||||
buffer := io.in
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the master is diverted, he must also have been told hready
|
|
||||||
assert (!io.divert || io.in.hready,
|
|
||||||
"Diverted but not ready");
|
|
||||||
|
|
||||||
// Replay the request we diverted
|
|
||||||
io.out.htrans := Mux(full, buffer.htrans, io.in.htrans)
|
|
||||||
io.out.hmastlock := Mux(full, buffer.hmastlock, io.in.hmastlock)
|
|
||||||
io.out.haddr := Mux(full, buffer.haddr, io.in.haddr)
|
|
||||||
io.out.hwrite := Mux(full, buffer.hwrite, io.in.hwrite)
|
|
||||||
io.out.hburst := Mux(full, buffer.hburst, io.in.hburst)
|
|
||||||
io.out.hsize := Mux(full, buffer.hsize, io.in.hsize)
|
|
||||||
io.out.hprot := Mux(full, buffer.hprot, io.in.hprot)
|
|
||||||
io.out.hwdata := Mux(full, buffer.hwdata, io.in.hwdata)
|
|
||||||
|
|
||||||
// Pass slave response back
|
|
||||||
io.in.hrdata := io.out.hrdata
|
|
||||||
io.in.hresp := io.out.hresp
|
|
||||||
io.in.hready := io.out.hready && !full // Block master while we steal his address phase
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Masters with lower index have priority over higher index masters.
|
|
||||||
* However, a lower priority master will retain control of a slave when EITHER:
|
|
||||||
* 1. a burst is in progress (switching slaves mid-burst violates AHB-lite at slave)
|
|
||||||
* 2. a transfer was waited (the standard forbids changing requests in this case)
|
|
||||||
*
|
|
||||||
* If a master raises hmastlock, it will be waited until no other master has inflight
|
|
||||||
* requests; then, it acquires exclusive control of the crossbar until hmastlock is low.
|
|
||||||
*
|
|
||||||
* To implement an AHB-lite crossbar, it is important to realize that requests and
|
|
||||||
* responses are coupled. Unlike modern bus protocols where the response data has flow
|
|
||||||
* control independent of the request data, in AHB-lite, both flow at the same time at
|
|
||||||
* the sole discretion of the slave via the hready signal. The address and data are
|
|
||||||
* delivered on two back-to-back cycles, the so-called address and data phases.
|
|
||||||
*
|
|
||||||
* Masters can only be connected to a single slave at a time. If a master had two different
|
|
||||||
* slave connections on the address and data phases, there would be two independent hready
|
|
||||||
* signals. An AHB-lite slave can assume that data flows when it asserts hready. If the data
|
|
||||||
* slave deasserts hready while the address slave asserts hready, the master is put in the
|
|
||||||
* impossible position of being in data phase on two slaves at once. For this reason, when
|
|
||||||
* a master issues back-to-back accesses to distinct slaves, we inject a pipeline bubble
|
|
||||||
* between the two requests to limit the master to just a single slave at a time.
|
|
||||||
*
|
|
||||||
* Conversely, a slave CAN have two masters attached to it. This is unproblematic, because
|
|
||||||
* the only signal which governs data flow is hready. Thus, both masters can be stalled
|
|
||||||
* safely by the single slave.
|
|
||||||
*/
|
|
||||||
class HastiXbar(nMasters: Int, addressMap: Seq[UInt=>Bool])(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val masters = Vec(nMasters, new HastiMasterIO).flip
|
|
||||||
val slaves = Vec(addressMap.size, new HastiSlaveIO).flip
|
|
||||||
}
|
|
||||||
|
|
||||||
val nSlaves = addressMap.size
|
|
||||||
|
|
||||||
// Setup diversions infront of each master
|
|
||||||
val diversions = Seq.tabulate(nMasters) { m => Module(new MasterDiversion) }
|
|
||||||
(io.masters zip diversions) foreach { case (m, d) => d.io.in <> m }
|
|
||||||
|
|
||||||
// Handy short-hand
|
|
||||||
val masters = diversions map (_.io.out)
|
|
||||||
val slaves = io.slaves
|
|
||||||
|
|
||||||
// Lock status of the crossbar
|
|
||||||
val lockedM = Reg(init = Vec.fill(nMasters)(Bool(false)))
|
|
||||||
val isLocked = lockedM.reduce(_ || _)
|
|
||||||
|
|
||||||
// This matrix governs the master-slave connections in the address phase
|
|
||||||
// It is indexed by addressPhaseGrantSM(slave)(master)
|
|
||||||
// It is guaranteed to have at most one 'true' per column and per row
|
|
||||||
val addressPhaseGrantSM = Wire(Vec(nSlaves, Vec(nMasters, Bool())))
|
|
||||||
// This matrix governs the master-slave connections in the data phase
|
|
||||||
// It is guaranteed to have at most one 'true' per column and per row
|
|
||||||
val dataPhaseGrantSM = Reg (init = Vec.fill(nSlaves)(Vec.fill(nMasters)(Bool(false))))
|
|
||||||
// This matrix is the union of the address and data phases.
|
|
||||||
// It is transposed with respect to the two previous matrices.
|
|
||||||
// It is guaranteed to contain at most one 'true' per master row.
|
|
||||||
// However, two 'true's per slave column are permitted.
|
|
||||||
val unionGrantMS = Vec.tabulate(nMasters) { m => Vec.tabulate(nSlaves) { s =>
|
|
||||||
addressPhaseGrantSM(s)(m) || dataPhaseGrantSM(s)(m) } }
|
|
||||||
|
|
||||||
// Confirm the guarantees made above
|
|
||||||
def justOnce(v: Vec[Bool]) = v.fold(Bool(false)) { case (p, v) =>
|
|
||||||
assert (!p || !v)
|
|
||||||
p || v
|
|
||||||
}
|
|
||||||
addressPhaseGrantSM foreach { s => justOnce(s) }
|
|
||||||
unionGrantMS foreach { s => justOnce(s) }
|
|
||||||
|
|
||||||
// Data phase follows address phase whenever the slave is ready
|
|
||||||
(slaves zip (dataPhaseGrantSM zip addressPhaseGrantSM)) foreach { case (s, (d, a)) =>
|
|
||||||
when (s.hready) { d := a }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the grant state from the previous cycle; needed in case we hold access
|
|
||||||
val priorAddressPhaseGrantSM = RegNext(addressPhaseGrantSM)
|
|
||||||
|
|
||||||
// If a master says BUSY or SEQ, it is in the middle of a burst.
|
|
||||||
// In this case, it MUST stay attached to the same slave as before.
|
|
||||||
// Otherwise, it would violate the AHB-lite specification as seen by
|
|
||||||
// the slave, which is guaranteed a complete burst of the promised length.
|
|
||||||
// One case where this matters is preventing preemption of low-prio masters.
|
|
||||||
// NOTE: this exposes a slave to bad addresses when a master is buggy
|
|
||||||
val holdBurstM = Vec(masters map { _.isHold() })
|
|
||||||
|
|
||||||
// Transform the burst hold requirement from master indexing to slave indexing
|
|
||||||
// We use the previous cycle's binding because the master continues the prior burst
|
|
||||||
val holdBurstS = Vec(priorAddressPhaseGrantSM map { m => Mux1H(m, holdBurstM) })
|
|
||||||
|
|
||||||
// If a slave says !hready to a request, it must retain the same master next cycle.
|
|
||||||
// The AHB-lite specification requires that a waited transfer remain unchanged.
|
|
||||||
// If we preempted a waited master, the new master's request could potentially differ.
|
|
||||||
val holdBusyS = RegNext(Vec(slaves map { s => !s.hready && s.hsel }))
|
|
||||||
|
|
||||||
// Combine the above two grounds to determine if the slave retains its prior master
|
|
||||||
val holdS = Vec((holdBurstS zip holdBusyS) map ({ case (a,b) => a||b }))
|
|
||||||
|
|
||||||
// Determine which master addresses match which slaves
|
|
||||||
val matchMS = Vec(masters map { m => Vec(addressMap map { afn => afn(m.haddr) }) })
|
|
||||||
// Detect requests to nowhere; we need to allow progress in this case
|
|
||||||
val nowhereM = Vec(matchMS map { s => !s.reduce(_ || _) })
|
|
||||||
|
|
||||||
// Detect if we need to inject a pipeline bubble between the master requests.
|
|
||||||
// Divert masters already granted a data phase different from next request.
|
|
||||||
// NOTE: if only one slave, matchMS is always true => bubble always false
|
|
||||||
// => the diversion registers are optimized away as they are unread
|
|
||||||
// NOTE: bubble => dataPhase => have an hready signal
|
|
||||||
val bubbleM =
|
|
||||||
Vec.tabulate(nMasters) { m =>
|
|
||||||
Vec.tabulate(nSlaves) { s => dataPhaseGrantSM(s)(m) && !matchMS(m)(s) }
|
|
||||||
.reduce(_ || _) }
|
|
||||||
|
|
||||||
// Block any request that requires bus ownership or conflicts with isLocked
|
|
||||||
val blockedM =
|
|
||||||
Vec((lockedM zip masters) map { case(l, m) => !l && (isLocked || m.hmastlock) })
|
|
||||||
|
|
||||||
// Requested access to slaves from masters (pre-arbitration)
|
|
||||||
// NOTE: isNSeq does NOT include SEQ; thus, masters who are midburst do not
|
|
||||||
// request access to a new slave. They stay tied to the old and do not get two.
|
|
||||||
// NOTE: if a master was waited, it must repeat the same request as last cycle;
|
|
||||||
// thus, it will request the same slave and not end up with two (unless buggy).
|
|
||||||
val NSeq = masters.map(_.isNSeq())
|
|
||||||
val requestSM = Vec.tabulate(nSlaves) { s => Vec.tabulate(nMasters) { m =>
|
|
||||||
matchMS(m)(s) && NSeq(m) && !bubbleM(m) && !blockedM(m) } }
|
|
||||||
|
|
||||||
// Select at most one master request per slave (lowest index = highest priority)
|
|
||||||
val selectedRequestSM = Vec(requestSM map { m => Vec(PriorityEncoderOH(m)) })
|
|
||||||
|
|
||||||
// Calculate new crossbar interconnect state
|
|
||||||
addressPhaseGrantSM := Vec((holdS zip (priorAddressPhaseGrantSM zip selectedRequestSM))
|
|
||||||
map { case (h, (p, r)) => Mux(h, p, r) })
|
|
||||||
|
|
||||||
for (m <- 0 until nMasters) {
|
|
||||||
// If the master is connected to a slave, the slave determines hready.
|
|
||||||
// However, if no slave is connected, for progress report ready anyway, if:
|
|
||||||
// bad address (swallow request) OR idle (permit stupid masters to move FSM)
|
|
||||||
val autoready = nowhereM(m) || masters(m).isIdle()
|
|
||||||
val hready = if (nSlaves == 1)
|
|
||||||
Mux(unionGrantMS(m)(0), slaves(0).hready ^ autoready, Bool(false)) ^ autoready
|
|
||||||
else
|
|
||||||
Mux1H(unionGrantMS(m), slaves.map(_.hready ^ autoready)) ^ autoready
|
|
||||||
masters(m).hready := hready
|
|
||||||
// If we diverted a master, we need to absorb his address phase to replay later
|
|
||||||
diversions(m).io.divert := (bubbleM(m) || blockedM(m)) && NSeq(m) && hready
|
|
||||||
}
|
|
||||||
|
|
||||||
// Master muxes (address and data phase are the same)
|
|
||||||
(masters zip unionGrantMS) foreach { case (m, g) => {
|
|
||||||
m.hrdata := Mux1H(g, slaves.map(_.hrdata))
|
|
||||||
m.hresp := Mux1H(g, slaves.map(_.hresp))
|
|
||||||
} }
|
|
||||||
|
|
||||||
// Slave address phase muxes
|
|
||||||
(slaves zip addressPhaseGrantSM) foreach { case (s, g) => {
|
|
||||||
s.htrans := Mux1H(g, masters.map(_.htrans))
|
|
||||||
s.haddr := Mux1H(g, masters.map(_.haddr))
|
|
||||||
s.hmastlock := isLocked
|
|
||||||
s.hwrite := Mux1H(g, masters.map(_.hwrite))
|
|
||||||
s.hsize := Mux1H(g, masters.map(_.hsize))
|
|
||||||
s.hburst := Mux1H(g, masters.map(_.hburst))
|
|
||||||
s.hprot := Mux1H(g, masters.map(_.hprot))
|
|
||||||
s.hsel := g.reduce(_ || _)
|
|
||||||
} }
|
|
||||||
|
|
||||||
// Slave data phase muxes
|
|
||||||
(slaves zip dataPhaseGrantSM) foreach { case (s, g) => {
|
|
||||||
s.hwdata := Mux1H(g, masters.map(_.hwdata))
|
|
||||||
} }
|
|
||||||
|
|
||||||
// When no master-slave connections are active, a master can take-over the bus
|
|
||||||
val canLock = !addressPhaseGrantSM.map({ v => v.reduce(_ || _) }).reduce(_ || _)
|
|
||||||
|
|
||||||
// Lowest index highest priority for lock arbitration
|
|
||||||
val reqLock = masters.map(_.hmastlock)
|
|
||||||
val winLock = PriorityEncoderOH(reqLock)
|
|
||||||
|
|
||||||
// Lock arbitration
|
|
||||||
when (isLocked) {
|
|
||||||
lockedM := (lockedM zip reqLock) map { case (a,b) => a && b }
|
|
||||||
} .elsewhen (canLock) {
|
|
||||||
lockedM := winLock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiBus(amap: Seq[UInt=>Bool])(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val master = new HastiMasterIO().flip
|
|
||||||
val slaves = Vec(amap.size, new HastiSlaveIO).flip
|
|
||||||
}
|
|
||||||
|
|
||||||
val bar = Module(new HastiXbar(1, amap))
|
|
||||||
bar.io.masters(0) <> io.master
|
|
||||||
bar.io.slaves <> io.slaves
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiSlaveMux(n: Int)(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val ins = Vec(n, new HastiSlaveIO)
|
|
||||||
val out = new HastiSlaveIO().flip
|
|
||||||
}
|
|
||||||
|
|
||||||
val amap = Seq({ (_:UInt) => Bool(true)})
|
|
||||||
val bar = Module(new HastiXbar(n, amap))
|
|
||||||
io.ins <> bar.io.masters
|
|
||||||
io.out <> bar.io.slaves(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiSlaveToMaster(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = new HastiSlaveIO
|
|
||||||
val out = new HastiMasterIO
|
|
||||||
}
|
|
||||||
|
|
||||||
io.out.htrans := Mux(io.in.hsel, io.in.htrans, HTRANS_IDLE)
|
|
||||||
io.out.hmastlock := io.in.hmastlock
|
|
||||||
io.out.haddr := io.in.haddr
|
|
||||||
io.out.hwrite := io.in.hwrite
|
|
||||||
io.out.hburst := io.in.hburst
|
|
||||||
io.out.hsize := io.in.hsize
|
|
||||||
io.out.hprot := io.in.hprot
|
|
||||||
io.out.hwdata := io.in.hwdata
|
|
||||||
io.in.hrdata := io.out.hrdata
|
|
||||||
io.in.hready := io.out.hready
|
|
||||||
io.in.hresp := io.out.hresp
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiMasterIONastiIOConverter(implicit p: Parameters) extends HastiModule()(p)
|
|
||||||
with HasNastiParameters {
|
|
||||||
val io = new Bundle {
|
|
||||||
val nasti = new NastiIO().flip
|
|
||||||
val hasti = new HastiMasterIO
|
|
||||||
}
|
|
||||||
|
|
||||||
require(hastiAddrBits == nastiXAddrBits)
|
|
||||||
require(hastiDataBits == nastiXDataBits)
|
|
||||||
|
|
||||||
val r_queue = Module(new Queue(new NastiReadDataChannel, 2, pipe = true))
|
|
||||||
|
|
||||||
val s_idle :: s_read :: s_write :: s_write_resp :: Nil = Enum(Bits(), 4)
|
|
||||||
val state = Reg(init = s_idle)
|
|
||||||
|
|
||||||
val addr = Reg(UInt(width = hastiAddrBits))
|
|
||||||
val id = Reg(UInt(width = nastiXIdBits))
|
|
||||||
val size = Reg(UInt(width = nastiXSizeBits))
|
|
||||||
val len = Reg(UInt(width = nastiXLenBits))
|
|
||||||
val data = Reg(UInt(width = nastiXDataBits))
|
|
||||||
val first = Reg(init = Bool(false))
|
|
||||||
val is_rtrans = (state === s_read) &&
|
|
||||||
(io.hasti.htrans === HTRANS_SEQ ||
|
|
||||||
io.hasti.htrans === HTRANS_NONSEQ)
|
|
||||||
val rvalid = RegEnable(is_rtrans, Bool(false), io.hasti.hready)
|
|
||||||
|
|
||||||
io.nasti.aw.ready := (state === s_idle)
|
|
||||||
io.nasti.ar.ready := (state === s_idle) && !io.nasti.aw.valid
|
|
||||||
io.nasti.w.ready := (state === s_write) && io.hasti.hready
|
|
||||||
io.nasti.b.valid := (state === s_write_resp)
|
|
||||||
io.nasti.b.bits := NastiWriteResponseChannel(id = id)
|
|
||||||
io.nasti.r <> r_queue.io.deq
|
|
||||||
|
|
||||||
r_queue.io.enq.valid := io.hasti.hready && rvalid
|
|
||||||
r_queue.io.enq.bits := NastiReadDataChannel(
|
|
||||||
id = id,
|
|
||||||
data = io.hasti.hrdata,
|
|
||||||
last = (len === UInt(0)))
|
|
||||||
|
|
||||||
assert(!r_queue.io.enq.valid || r_queue.io.enq.ready,
|
|
||||||
"NASTI -> HASTI converter queue overflow")
|
|
||||||
|
|
||||||
// How many read requests have we not delivered a response for yet?
|
|
||||||
val pending_count = r_queue.io.count + rvalid
|
|
||||||
|
|
||||||
io.hasti.haddr := addr
|
|
||||||
io.hasti.hsize := size
|
|
||||||
io.hasti.hwrite := (state === s_write)
|
|
||||||
io.hasti.hburst := HBURST_INCR
|
|
||||||
io.hasti.hprot := UInt(0)
|
|
||||||
io.hasti.hwdata := data
|
|
||||||
io.hasti.hmastlock := Bool(false)
|
|
||||||
io.hasti.htrans := MuxLookup(state, HTRANS_IDLE, Seq(
|
|
||||||
s_write -> Mux(io.nasti.w.valid,
|
|
||||||
Mux(first, HTRANS_NONSEQ, HTRANS_SEQ),
|
|
||||||
Mux(first, HTRANS_IDLE, HTRANS_BUSY)),
|
|
||||||
s_read -> MuxCase(HTRANS_BUSY, Seq(
|
|
||||||
first -> HTRANS_NONSEQ,
|
|
||||||
(pending_count <= UInt(1)) -> HTRANS_SEQ))))
|
|
||||||
|
|
||||||
when (io.nasti.aw.fire()) {
|
|
||||||
first := Bool(true)
|
|
||||||
addr := io.nasti.aw.bits.addr
|
|
||||||
id := io.nasti.aw.bits.id
|
|
||||||
size := io.nasti.aw.bits.size
|
|
||||||
state := s_write
|
|
||||||
}
|
|
||||||
|
|
||||||
when (io.nasti.ar.fire()) {
|
|
||||||
first := Bool(true)
|
|
||||||
addr := io.nasti.ar.bits.addr
|
|
||||||
id := io.nasti.ar.bits.id
|
|
||||||
size := io.nasti.ar.bits.size
|
|
||||||
len := io.nasti.ar.bits.len
|
|
||||||
state := s_read
|
|
||||||
}
|
|
||||||
|
|
||||||
when (io.nasti.w.fire()) {
|
|
||||||
first := Bool(false)
|
|
||||||
addr := addr + (UInt(1) << size)
|
|
||||||
data := io.nasti.w.bits.data
|
|
||||||
when (io.nasti.w.bits.last) { state := s_write_resp }
|
|
||||||
}
|
|
||||||
|
|
||||||
when (io.nasti.b.fire()) { state := s_idle }
|
|
||||||
|
|
||||||
when (is_rtrans && io.hasti.hready) {
|
|
||||||
first := Bool(false)
|
|
||||||
addr := addr + (UInt(1) << size)
|
|
||||||
len := len - UInt(1)
|
|
||||||
when (len === UInt(0)) { state := s_idle }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiTestSRAM(depth: Int)(implicit p: Parameters) extends HastiModule()(p) {
|
|
||||||
val io = new HastiSlaveIO
|
|
||||||
|
|
||||||
// This is a test SRAM with random delays
|
|
||||||
val ready = LFSR16(Bool(true))(0) // Bool(true)
|
|
||||||
|
|
||||||
// Calculate the bitmask of which bytes are being accessed
|
|
||||||
val mask_decode = Vec.tabulate(hastiAlignment+1) (UInt(_) <= io.hsize)
|
|
||||||
val mask_wide = Vec.tabulate(hastiDataBytes) { i => mask_decode(log2Ceil(i+1)) }
|
|
||||||
val mask_shift = if (hastiAlignment == 0) UInt(1) else
|
|
||||||
mask_wide.asUInt() << io.haddr(hastiAlignment-1,0)
|
|
||||||
|
|
||||||
// The request had better have been aligned! (AHB-lite requires this)
|
|
||||||
if (hastiAlignment >= 1) {
|
|
||||||
assert (io.htrans === HTRANS_IDLE || io.htrans === HTRANS_BUSY ||
|
|
||||||
(io.haddr & mask_decode.asUInt()(hastiAlignment,1)) === UInt(0),
|
|
||||||
"HASTI request not aligned")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The mask and address during the address phase
|
|
||||||
val a_request = io.hsel && (io.htrans === HTRANS_NONSEQ || io.htrans === HTRANS_SEQ)
|
|
||||||
val a_mask = Wire(UInt(width = hastiDataBytes))
|
|
||||||
val a_address = io.haddr(depth-1, hastiAlignment)
|
|
||||||
val a_write = io.hwrite
|
|
||||||
|
|
||||||
// for backwards compatibility with chisel2, we needed a static width in definition
|
|
||||||
a_mask := mask_shift(hastiDataBytes-1, 0)
|
|
||||||
|
|
||||||
// The data phase signals
|
|
||||||
val d_read = RegEnable(a_request && !a_write, Bool(false), ready)
|
|
||||||
val d_mask = RegEnable(a_mask, ready && a_request)
|
|
||||||
val d_wdata = Vec.tabulate(hastiDataBytes) { i => io.hwdata(8*(i+1)-1, 8*i) }
|
|
||||||
|
|
||||||
// AHB writes must occur during the data phase; this poses a structural
|
|
||||||
// hazard with reads which must occur during the address phase. To solve
|
|
||||||
// this problem, we delay the writes until there is a free cycle.
|
|
||||||
//
|
|
||||||
// The idea is to record the address information from address phase and
|
|
||||||
// then as soon as possible flush the pending write. This cannot be done
|
|
||||||
// on a cycle when there is an address phase read, but on any other cycle
|
|
||||||
// the write will execute. In the case of reads following a write, the
|
|
||||||
// result must bypass data from the pending write into the read if they
|
|
||||||
// happen to have matching address.
|
|
||||||
|
|
||||||
// Pending write?
|
|
||||||
val p_valid = RegInit(Bool(false))
|
|
||||||
val p_address = Reg(a_address)
|
|
||||||
val p_mask = Reg(a_mask)
|
|
||||||
val p_latch_d = RegNext(ready && a_request && a_write, Bool(false))
|
|
||||||
val p_wdata = d_wdata holdUnless p_latch_d
|
|
||||||
|
|
||||||
// Use single-ported memory with byte-write enable
|
|
||||||
val mem = SeqMem(1 << (depth-hastiAlignment), Vec(hastiDataBytes, Bits(width = 8)))
|
|
||||||
|
|
||||||
// Decide is the SRAM port is used for reading or (potentially) writing
|
|
||||||
val read = ready && a_request && !a_write
|
|
||||||
// In case we are stalled, we need to hold the read data
|
|
||||||
val d_rdata = mem.readAndHold(a_address, read)
|
|
||||||
// Whenever the port is not needed for reading, execute pending writes
|
|
||||||
when (!read && p_valid) { mem.write(p_address, p_wdata, p_mask.toBools) }
|
|
||||||
when (!read) { p_valid := Bool(false) }
|
|
||||||
|
|
||||||
// Record the request for later?
|
|
||||||
when (ready && a_request && a_write) {
|
|
||||||
p_valid := Bool(true)
|
|
||||||
p_address := a_address
|
|
||||||
p_mask := a_mask
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does the read need to be muxed with the previous write?
|
|
||||||
val a_bypass = a_address === p_address && p_valid
|
|
||||||
val d_bypass = RegEnable(a_bypass, ready && a_request)
|
|
||||||
|
|
||||||
// Mux in data from the pending write
|
|
||||||
val muxdata = Vec((p_mask.toBools zip (p_wdata zip d_rdata))
|
|
||||||
map { case (m, (p, r)) => Mux(d_bypass && m, p, r) })
|
|
||||||
// Wipe out any data the master should not see (for testing)
|
|
||||||
val outdata = Vec((d_mask.toBools zip muxdata)
|
|
||||||
map { case (m, p) => Mux(d_read && ready && m, p, Bits(0)) })
|
|
||||||
|
|
||||||
// Finally, the outputs
|
|
||||||
io.hrdata := outdata.asUInt
|
|
||||||
io.hready := ready
|
|
||||||
io.hresp := HRESP_OKAY
|
|
||||||
}
|
|
||||||
|
|
||||||
class HastiTest(implicit p: Parameters) extends UnitTest {
|
|
||||||
val sram = Module(new HastiTestSRAM(8))
|
|
||||||
val bus = Module(new HastiBus(Seq(a => Bool(true))))
|
|
||||||
val conv = Module(new HastiMasterIONastiIOConverter)
|
|
||||||
val driver = Module(new NastiDriver(32, 8, 2))
|
|
||||||
|
|
||||||
bus.io.slaves(0) <> sram.io
|
|
||||||
bus.io.master <> conv.io.hasti
|
|
||||||
conv.io.nasti <> driver.io.nasti
|
|
||||||
io.finished := driver.io.finished
|
|
||||||
driver.io.start := io.start
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user