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:
		| @@ -84,7 +84,3 @@ jobs: | ||||
|       script: | ||||
|         - 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 | ||||
|     - <<: *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 | ||||
|  | ||||
| MODEL ?= TestHarness | ||||
| PROJECT ?= rocketchip | ||||
| PROJECT ?= freechips.rocketchip.chip | ||||
| CFG_PROJECT ?= $(PROJECT) | ||||
| CONFIG ?= DefaultConfig | ||||
| # 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. | ||||
| 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** | ||||
| This utility package provides Scala interfaces for configuring a generator via a dynamically-scoped | ||||
| parameterization library. | ||||
| * **coreplex** | ||||
| This RTL package generates a complete coreplex by gluing together a variety of other components, | ||||
| including tiled Rocket cores, an L1-to-L2 network, L2 coherence agents, and internal devices | ||||
| such as the debug unit and interrupt handlers. | ||||
| This RTL package generates a complete coreplex by gluing together a variety of components from other packages, | ||||
| including: tiled Rocket cores, a system bus network, coherence agents, debug devices, interrupt handlers, externally-facing peripherals, | ||||
| 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** | ||||
| This utility package extends Chisel by allowing for two-phase hardware elaboration, in which certain parameters | ||||
| 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. | ||||
| 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. | ||||
| * **uncore** | ||||
| This RTL package generates a variety of uncore logic and devices, such as | ||||
| such as the L2 coherence hub and Debug modules, as well as defining their interfaces and protocols. | ||||
| Contains implementations of both TileLink and AXI4. | ||||
| * **tile** | ||||
| This RTL package contains components that can be combined with cores to construct tiles, such as FPUs and accelerators. | ||||
| * **tilelink** | ||||
| This RTL package uses diplomacy to generate bus implementations of the TileLink protocol. It also contains a variety | ||||
| of adapters and protocol converters. | ||||
| * **unittest** | ||||
| 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** | ||||
| This utility package provides a variety of common Scala and Chisel constructs that are re-used across | ||||
| multiple other packages, | ||||
|   | ||||
| @@ -42,31 +42,23 @@ $(error Set SUITE to the regression suite you want to run) | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE),RocketSuiteA) | ||||
| PROJECT=rocketchip | ||||
| PROJECT=freechips.rocketchip.chip | ||||
| CONFIGS=DefaultConfig | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE),RocketSuiteB) | ||||
| PROJECT=rocketchip | ||||
| PROJECT=freechips.rocketchip.chip | ||||
| CONFIGS=DefaultBufferlessConfig | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE),RocketSuiteC) | ||||
| PROJECT=rocketchip | ||||
| CONFIGS=DefaultL2Config TinyConfig | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE),GroundtestSuite) | ||||
| PROJECT=groundtest | ||||
| CONFIGS=MemtestConfig MemtestBufferlessConfig MemtestStatelessConfig \ | ||||
|         BroadcastRegressionTestConfig BufferlessRegressionTestConfig CacheRegressionTestConfig \ | ||||
| 	ComparatorConfig ComparatorBufferlessConfig ComparatorStatelessConfig | ||||
| # FancyMemtestConfig takes too long to compile | ||||
| PROJECT=freechips.rocketchip.chip | ||||
| CONFIGS=TinyConfig | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE),UnittestSuite) | ||||
| PROJECT=unittest | ||||
| CONFIGS=UncoreUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig | ||||
| PROJECT=freechips.rocketchip.unittest | ||||
| CONFIGS=AMBAUnitTestConfig TLSimpleUnitTestConfig TLWidthUnitTestConfig | ||||
| endif | ||||
|  | ||||
| ifeq ($(SUITE), JtagDtmSuite) | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import util.GenericParameterizedBundle | ||||
| import freechips.rocketchip.util.GenericParameterizedBundle | ||||
| 
 | ||||
| abstract class AHBBundleBase(params: AHBBundleParameters) extends GenericParameterizedBundle(params) | ||||
| 
 | ||||
| @@ -1,11 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| 
 | ||||
| object AHBImp extends NodeImp[AHBMasterPortParameters, AHBSlavePortParameters, AHBEdgeParameters, AHBEdgeParameters, AHBBundle] | ||||
| { | ||||
| @@ -1,10 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import scala.math.max | ||||
| 
 | ||||
| case class AHBSlaveParameters( | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| 
 | ||||
| @@ -1,11 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple} | ||||
| import freechips.rocketchip.util.{HeterogeneousBag, MaskGen} | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| 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_read  := !ahb.hwrite | ||||
|       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) | ||||
| @@ -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 | ||||
| { | ||||
|   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 | ||||
| { | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| 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 | ||||
|     val a_access    = in.htrans === AHBParameters.TRANS_NONSEQ || in.htrans === AHBParameters.TRANS_SEQ | ||||
|     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_write     = in.hwrite | ||||
| 
 | ||||
| @@ -1,12 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import unittest._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.devices.tilelink.TLTestRAM | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.unittest._ | ||||
| 
 | ||||
| class RRTest0(address: BigInt)(implicit p: Parameters) extends AHBRegisterRouter(address, 0, 32, 0, 4)( | ||||
|   new AHBRegBundle((), _)    with RRTest0Bundle)( | ||||
| @@ -1,12 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util.MaskGen | ||||
| 
 | ||||
| case class AHBToTLNode() extends MixedAdapterNode(AHBImp, TLImp)( | ||||
|   dFn = { case AHBMasterPortParameters(masters) => | ||||
| @@ -108,7 +109,7 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule | ||||
|       out.a.bits.source  := UInt(0) | ||||
|       out.a.bits.address := d_addr | ||||
|       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 | ||||
|       in.hrdata    := out.d.bits.data | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.ahb | ||||
| package freechips.rocketchip.amba.ahb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| class AHBFanout()(implicit p: Parameters) extends LazyModule { | ||||
| @@ -1,9 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore | ||||
| package freechips.rocketchip.amba | ||||
| 
 | ||||
| import Chisel._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.diplomacy.OutwardNodeHandle | ||||
| 
 | ||||
| package object ahb | ||||
| { | ||||
| @@ -1,9 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import util.GenericParameterizedBundle | ||||
| import freechips.rocketchip.util.GenericParameterizedBundle | ||||
| 
 | ||||
| abstract class APBBundleBase(params: APBBundleParameters) extends GenericParameterizedBundle(params) | ||||
| 
 | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| 
 | ||||
| object APBImp extends NodeImp[APBMasterPortParameters, APBSlavePortParameters, APBEdgeParameters, APBEdgeParameters, APBBundle] | ||||
| { | ||||
| @@ -1,10 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import scala.math.max | ||||
| 
 | ||||
| case class APBSlaveParameters( | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| 
 | ||||
| @@ -1,11 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple} | ||||
| import freechips.rocketchip.util.HeterogeneousBag | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
|   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 | ||||
| { | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import unittest._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.unittest._ | ||||
| 
 | ||||
| class RRTest0(address: BigInt)(implicit p: Parameters) extends APBRegisterRouter(address, 0, 32, 0, 4)( | ||||
|   new APBRegBundle((), _)    with RRTest0Bundle)( | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.apb | ||||
| package freechips.rocketchip.amba.apb | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| class APBFanout()(implicit p: Parameters) extends LazyModule { | ||||
| @@ -1,9 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore | ||||
| package freechips.rocketchip.amba | ||||
| 
 | ||||
| import Chisel._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.diplomacy.OutwardNodeHandle | ||||
| 
 | ||||
| package object apb | ||||
| { | ||||
| @@ -1,12 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import chisel3.util.IrrevocableIO | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| // pipe is only used if a queue has depth = 1 | ||||
| @@ -1,10 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.util.Irrevocable | ||||
| import util.GenericParameterizedBundle | ||||
| import freechips.rocketchip.util.GenericParameterizedBundle | ||||
| 
 | ||||
| abstract class AXI4BundleBase(params: AXI4BundleParameters) extends GenericParameterizedBundle(params) | ||||
| 
 | ||||
| @@ -1,14 +1,14 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import chisel3.util.IrrevocableIO | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util.{leftOR, rightOR, UIntToOH1, OH1ToOH} | ||||
| import scala.math.{min,max} | ||||
| import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH} | ||||
| 
 | ||||
| class AXI4Deinterleaver(maxReadBytes: Int)(implicit p: Parameters) extends LazyModule | ||||
| { | ||||
| @@ -1,14 +1,14 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import chisel3.util.IrrevocableIO | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util.{leftOR, rightOR, UIntToOH1, OH1ToOH} | ||||
| import scala.math.{min,max} | ||||
| import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH} | ||||
| 
 | ||||
| class AXI4Fragmenter()(implicit p: Parameters) extends LazyModule | ||||
| { | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| class AXI4IdIndexer(idBits: Int)(implicit p: Parameters) extends LazyModule | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| 
 | ||||
| object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4EdgeParameters, AXI4EdgeParameters, AXI4Bundle] | ||||
| { | ||||
| @@ -1,10 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import scala.math.max | ||||
| 
 | ||||
| case class AXI4SlaveParameters( | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.util.{Irrevocable, IrrevocableIO} | ||||
| @@ -1,11 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple} | ||||
| import freechips.rocketchip.util.{HeterogeneousBag, MaskGen} | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| 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 in_extra = Mux(ar.valid, ar_extra, aw_extra) | ||||
|     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.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 | ||||
| { | ||||
|   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 | ||||
| { | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import unittest._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.devices.tilelink.TLError | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.unittest._ | ||||
| 
 | ||||
| class RRTest0(address: BigInt)(implicit p: Parameters) extends AXI4RegisterRouter(address, 0, 32, 0, 4)( | ||||
|   new AXI4RegBundle((), _)    with RRTest0Bundle)( | ||||
| @@ -1,12 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)( | ||||
|   dFn = { case AXI4MasterPortParameters(masters, userBits) => | ||||
| @@ -1,12 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.axi4 | ||||
| package freechips.rocketchip.amba.axi4 | ||||
| 
 | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2.UIntToOH1 | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.util.UIntToOH1 | ||||
| 
 | ||||
| class AXI4UserYanker(capMaxFlight: Option[Int] = None)(implicit p: Parameters) extends LazyModule | ||||
| { | ||||
| @@ -1,9 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore | ||||
| package freechips.rocketchip.amba | ||||
| 
 | ||||
| import Chisel._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.diplomacy.OutwardNodeHandle | ||||
| 
 | ||||
| package object axi4 | ||||
| { | ||||
| @@ -1,24 +1,24 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| // See LICENSE.Berkeley for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import junctions._ | ||||
| import rocket._ | ||||
| import diplomacy._ | ||||
| import uncore.agents._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.devices._ | ||||
| import uncore.converters._ | ||||
| import util._ | ||||
| import coreplex._ | ||||
| 
 | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.devices._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile.XLen | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| import scala.math.max | ||||
| import scala.collection.mutable.{LinkedHashSet, ListBuffer} | ||||
| import scala.collection.immutable.HashMap | ||||
| 
 | ||||
| import DefaultTestSuites._ | ||||
| import config._ | ||||
| import tile.XLen | ||||
| 
 | ||||
| class BasePlatformConfig extends Config((site, here, up) => { | ||||
|   // DTS descriptive parameters | ||||
| @@ -49,33 +49,23 @@ class BasePlatformConfig extends Config((site, here, up) => { | ||||
| class BaseConfig extends Config(new BaseCoreplexConfig ++ new BasePlatformConfig) | ||||
| class DefaultConfig extends Config(new WithNBigCores(1) ++ new BaseConfig) | ||||
| 
 | ||||
| class DefaultL2Config extends Config(new WithL2Cache ++ new WithNBigCores(1) ++ new BaseConfig) | ||||
| class DefaultBufferlessConfig extends Config( | ||||
|   new WithBufferlessBroadcastHub ++ new WithNBigCores(1) ++ new BaseConfig) | ||||
| 
 | ||||
| class FPGAConfig extends Config(Parameters.empty) | ||||
| 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 DefaultRV32Config extends Config(new WithRV32 ++ new DefaultConfig) | ||||
| 
 | ||||
| class DualBankConfig extends Config( | ||||
|   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 DualChannelL2Config extends Config( | ||||
|   new WithNMemoryChannels(2) ++ new WithL2Cache ++ new BaseConfig) | ||||
| 
 | ||||
| class DualChannelDualBankConfig extends Config( | ||||
|   new WithNMemoryChannels(2) ++ | ||||
|   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) | ||||
| 
 | ||||
| @@ -84,11 +74,7 @@ class Edge128BitConfig extends Config( | ||||
| class Edge32BitConfig extends Config( | ||||
|   new WithEdgeDataBits(32) ++ new BaseConfig) | ||||
| 
 | ||||
| class SmallL2Config extends Config( | ||||
|   new WithNMemoryChannels(2) ++ new WithNBanksPerMemChannel(4) ++ | ||||
|   new WithL2Capacity(256) ++ new DefaultL2Config) | ||||
| 
 | ||||
| class SingleChannelBenchmarkConfig extends Config(new WithL2Capacity(256) ++ new DefaultL2Config) | ||||
| class SingleChannelBenchmarkConfig extends Config(new DefaultConfig) | ||||
| class DualChannelBenchmarkConfig extends Config(new WithNMemoryChannels(2) ++ new SingleChannelBenchmarkConfig) | ||||
| class QuadChannelBenchmarkConfig extends Config(new WithNMemoryChannels(4) ++ 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 DualCoreConfig extends Config( | ||||
|   new WithNBigCores(2) ++ new WithL2Cache ++ new BaseConfig) | ||||
|   new WithNBigCores(2) ++ new BaseConfig) | ||||
| 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( | ||||
|   new WithNMemoryChannels(0) ++ | ||||
| @@ -1,12 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import util._ | ||||
| import config._ | ||||
| import jtag._ | ||||
| import uncore.devices.{DMIConsts, DMIIO, DMIReq, DMIResp} | ||||
| 
 | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.devices.debug.{DMIConsts, DMIIO, DMIReq, DMIResp} | ||||
| import freechips.rocketchip.jtag._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| case object IncludeJtagDTM extends Field[Boolean] | ||||
| 
 | ||||
| @@ -1,11 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import junctions._ | ||||
| import rocketchip._ | ||||
| 
 | ||||
| import freechips.rocketchip.config.Parameters | ||||
| 
 | ||||
| /** Example system with periphery devices (w/o coreplex) */ | ||||
| abstract class ExampleSystem(implicit p: Parameters) extends BaseSystem | ||||
| @@ -1,14 +1,15 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import tile.XLen | ||||
| import coreplex.RocketTilesKey | ||||
| import freechips.rocketchip.coreplex.RocketTilesKey | ||||
| import freechips.rocketchip.tile.XLen | ||||
| import freechips.rocketchip.util.GeneratorApp | ||||
| 
 | ||||
| import scala.collection.mutable.LinkedHashSet | ||||
| 
 | ||||
| /** A Generator for platforms containing Rocket Coreplexes */ | ||||
| object Generator extends util.GeneratorApp { | ||||
| object Generator extends GeneratorApp { | ||||
| 
 | ||||
|   val rv64RegrTestNames = LinkedHashSet( | ||||
|         "rv64ud-v-fcvt", | ||||
| @@ -1,14 +1,17 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import coreplex._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.axi4._ | ||||
| import util._ | ||||
| 
 | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.amba.axi4._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| import scala.math.{min,max} | ||||
| 
 | ||||
| /** Specifies the size of external memory */ | ||||
| @@ -42,7 +45,7 @@ trait HasPeripheryParameters { | ||||
|   def socBusBytes = socBusConfig.beatBytes | ||||
|   def cacheBlockBytes = p(CacheBlockBytes) | ||||
|   def peripheryBusArithmetic = p(PeripheryBusArithmetic) | ||||
|   def nMemoryChannels = p(coreplex.BankedL2Config).nMemoryChannels | ||||
|   def nMemoryChannels = p(BankedL2Config).nMemoryChannels | ||||
|   def nExtInterrupts = p(NExtTopInterrupts) | ||||
| } | ||||
| 
 | ||||
| @@ -1,15 +1,17 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import coreplex._ | ||||
| import diplomacy._ | ||||
| import jtag.JTAGIO | ||||
| import uncore.tilelink2._ | ||||
| import uncore.devices._ | ||||
| import util._ | ||||
| 
 | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.devices.debug._ | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| 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 | ||||
|   * 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 { | ||||
|   val outer: HasPeripheryRTCCounter | ||||
|   val period = p(rocketchip.RTCPeriod) | ||||
|   val period = p(RTCPeriod) | ||||
|   val rtcCounter = RegInit(UInt(0, width = log2Up(period))) | ||||
|   val rtcWrap = rtcCounter === UInt(period-1) | ||||
| 
 | ||||
| @@ -1,10 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| 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 */ | ||||
| trait HasRocketPlexMaster extends HasSystemNetworks with HasCoreplexRISCVPlatform { | ||||
| @@ -1,9 +1,8 @@ | ||||
| // See LICENSE.Berkeley for license details. | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import scala.collection.mutable.LinkedHashSet | ||||
| 
 | ||||
| abstract class RocketTestSuite { | ||||
| @@ -1,11 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config.Parameters | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| 
 | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyMultiIOModuleImp} | ||||
| import freechips.rocketchip.util.ElaborationArtefacts | ||||
| 
 | ||||
| /** BareSystem is the root class for creating a top-level RTL module */ | ||||
| abstract class BareSystem(implicit p: Parameters) extends LazyModule { | ||||
| @@ -1,14 +1,15 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import junctions._ | ||||
| import diplomacy._ | ||||
| import coreplex._ | ||||
| import uncore.axi4._ | ||||
| import jtag.JTAGIO | ||||
| 
 | ||||
| import freechips.rocketchip.amba.axi4._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.devices.debug._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.jtag.JTAGIO | ||||
| 
 | ||||
| class TestHarness()(implicit p: Parameters) extends Module { | ||||
|   val io = new Bundle { | ||||
| @@ -52,11 +53,11 @@ class SimDTM(implicit p: Parameters) extends BlackBox { | ||||
|   val io = new Bundle { | ||||
|     val clk = Clock(INPUT) | ||||
|     val reset = Bool(INPUT) | ||||
|     val debug = new uncore.devices.DMIIO | ||||
|     val debug = new DMIIO | ||||
|     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.reset := tbreset | ||||
|     dutio.dmi <> io.debug | ||||
| @@ -1,18 +1,13 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package rocketchip | ||||
| 
 | ||||
| import config._ | ||||
| import junctions._ | ||||
| import diplomacy._ | ||||
| import uncore.devices._ | ||||
| import tile.XLen | ||||
| import coreplex._ | ||||
| import uncore.tilelink2._ | ||||
| import util._ | ||||
| package freechips.rocketchip.chip | ||||
| 
 | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.DTB | ||||
| import freechips.rocketchip.coreplex.BootROMFile | ||||
| import java.nio.file.{Files, Paths} | ||||
| import java.nio.{ByteBuffer, ByteOrder} | ||||
| import scala.collection.mutable.ArrayBuffer | ||||
| 
 | ||||
| class RangeManager { | ||||
|   private var finalized = false | ||||
| @@ -39,7 +34,7 @@ class RangeManager { | ||||
| 
 | ||||
| class ResourceManager[T] { | ||||
|   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(list: Seq[T]) = { require(!finalized); l ++= list } | ||||
|   def get: Seq[T] = { finalized = true; l } | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package config | ||||
| package freechips.rocketchip.config | ||||
|  | ||||
| class Field[T] | ||||
|  | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import tile.XLen | ||||
| import tile.TileInterrupts | ||||
| import uncore.tilelink2._ | ||||
| import util._ | ||||
|  | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tile.{ XLen, TileInterrupts} | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| /** Widths of various points in the SoC */ | ||||
| case class TLBusConfig(beatBytes: Int) | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| // See LICENSE.Berkeley for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import uncore.converters._ | ||||
| import uncore.devices._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.util._ | ||||
| import util._ | ||||
|  | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.devices.debug._ | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| class BaseCoreplexConfig extends Config ((site, here, up) => { | ||||
|   case PAddrBits => 32 | ||||
| @@ -20,14 +20,13 @@ class BaseCoreplexConfig extends Config ((site, here, up) => { | ||||
|   case ASIdBits => 0 | ||||
|   case XLen => 64 // Applies to all cores | ||||
|   case ResetVectorBits => site(PAddrBits) | ||||
|   case MaxHartIdBits => log2Up(site(NTiles)) | ||||
|   case MaxHartIdBits => log2Up(site(RocketTilesKey).size) | ||||
|   case BuildCore => (p: Parameters) => new Rocket()(p) | ||||
|   case RocketCrossing => SynchronousCrossing() | ||||
|   case RocketTilesKey =>  Nil | ||||
|   case DMKey => DefaultDebugModuleConfig(site(XLen)) | ||||
|   case PLICKey => PLICParams() | ||||
|   case ClintKey => ClintParams() | ||||
|   case NTiles => site(RocketTilesKey).size | ||||
|   case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8) | ||||
|   case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth | ||||
|   case BootROMFile => "./bootrom/bootrom.img" | ||||
| @@ -112,10 +111,6 @@ class WithCacheBlockBytes(linesize: Int) extends Config((site, here, up) => { | ||||
|   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) => { | ||||
|   case BroadcastConfig => up(BroadcastConfig, site).copy(bufferless = true) | ||||
| }) | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.util._ | ||||
| import util._ | ||||
|  | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket.PAddrBits | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| trait CoreplexNetwork extends HasCoreplexParameters { | ||||
|   val module: CoreplexNetworkModule | ||||
| @@ -112,7 +113,7 @@ trait CoreplexNetworkModule extends HasCoreplexParameters { | ||||
|   val io: CoreplexNetworkBundle | ||||
|  | ||||
|   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 def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = { | ||||
|   | ||||
| @@ -1,14 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import uncore.tilelink2._ | ||||
| import util._ | ||||
| import freechips.rocketchip.diplomacy.LazyModule | ||||
| import freechips.rocketchip.tilelink._ | ||||
|  | ||||
| trait HasISPPort extends CoreplexNetwork { | ||||
|   val module: HasISPPortModule | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config.Field | ||||
| import diplomacy._ | ||||
| import tile._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.devices._ | ||||
| import util._ | ||||
|  | ||||
| /** Number of tiles */ | ||||
| case object NTiles extends Field[Int] | ||||
| import freechips.rocketchip.config.Field | ||||
| 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 ClintKey extends Field[ClintParams] | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config.Parameters | ||||
|  | ||||
| import freechips.rocketchip.config.Parameters | ||||
|  | ||||
| class RocketPlex(implicit p: Parameters) extends BaseCoreplex | ||||
|     with CoreplexRISCVPlatform | ||||
|   | ||||
| @@ -1,22 +1,22 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package coreplex | ||||
| package freechips.rocketchip.coreplex | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import uncore.tilelink2._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Field | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| sealed trait ClockCrossing | ||||
| case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends ClockCrossing | ||||
| case class RationalCrossing(direction: RationalDirection = FastToSlow) extends ClockCrossing | ||||
| case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends ClockCrossing | ||||
| sealed trait CoreplexClockCrossing | ||||
| case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing | ||||
| case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing | ||||
| case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends CoreplexClockCrossing | ||||
|  | ||||
| case object RocketTilesKey extends Field[Seq[RocketTileParams]] | ||||
| case object RocketCrossing extends Field[ClockCrossing] | ||||
| case object RocketCrossing extends Field[CoreplexClockCrossing] | ||||
|  | ||||
| trait HasRocketTiles extends CoreplexRISCVPlatform { | ||||
|   val module: HasRocketTilesModule | ||||
|   | ||||
| @@ -1,16 +1,15 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.debug | ||||
| 
 | ||||
| import Chisel._ | ||||
| import junctions._ | ||||
| import util._ | ||||
| import regmapper._ | ||||
| import tile.XLen | ||||
| import uncore.tilelink2._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| 
 | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.rocket.Instructions | ||||
| import freechips.rocketchip.tile.XLen | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| /** 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 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) | ||||
| 
 | ||||
|     when (~io.dmactive){ | ||||
| @@ -838,20 +837,20 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p: | ||||
|     val abstractGeneratedS = Wire(new GeneratedS()) | ||||
|     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.funct3 := accessRegisterCommandReg.size | ||||
|     abstractGeneratedI.rs1    := 0.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.funct3 := accessRegisterCommandReg.size | ||||
|     abstractGeneratedS.rs1    := 0.U | ||||
|     abstractGeneratedS.rs2    := (accessRegisterCommandReg.regno & 0x1F.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.rs1  := 0.U | ||||
|     nop.imm  := 0.U | ||||
| @@ -867,7 +866,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p: | ||||
|       ) | ||||
|       abstractGeneratedMem(1) := Mux(accessRegisterCommandReg.postexec, | ||||
|         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. | ||||
| 
 | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.debug | ||||
| 
 | ||||
| object DebugRomContents { | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.debug | ||||
| 
 | ||||
| import Chisel._ | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.debug | ||||
| 
 | ||||
| import Chisel._ | ||||
| 
 | ||||
| @@ -1,18 +1,15 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.tilelink | ||||
| 
 | ||||
| import Chisel._ | ||||
| import junctions._ | ||||
| import junctions.NastiConstants._ | ||||
| import regmapper._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.util._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.tile.XLen | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| import scala.math.{min,max} | ||||
| import config._ | ||||
| import tile.XLen | ||||
| 
 | ||||
| object ClintConsts | ||||
| { | ||||
| @@ -1,11 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.tilelink2 | ||||
| package freechips.rocketchip.devices.tilelink | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| class TLError(address: Seq[AddressSet], beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule | ||||
| { | ||||
| @@ -1,18 +1,16 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.devices | ||||
| package freechips.rocketchip.devices.tilelink | ||||
| 
 | ||||
| import Chisel._ | ||||
| import Chisel.ImplicitConversions._ | ||||
| 
 | ||||
| import junctions._ | ||||
| import diplomacy._ | ||||
| import regmapper._ | ||||
| import uncore.tilelink2._ | ||||
| import config._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.regmapper._ | ||||
| import freechips.rocketchip.tile.XLen | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| import scala.math.min | ||||
| import tile.XLen | ||||
| import util._ | ||||
| 
 | ||||
| class GatewayPLICIO extends Bundle { | ||||
|   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. | ||||
| 
 | ||||
| package uncore.tilelink2 | ||||
| package freechips.rocketchip.devices.tilelink | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import util._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
| 
 | ||||
| // Do not use this for synthesis! Only for simulation. | ||||
| 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 */ | ||||
| import unittest._ | ||||
| import freechips.rocketchip.unittest._ | ||||
| 
 | ||||
| class TLRAMZeroDelay(ramBeatBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule { | ||||
|   val fuzz = LazyModule(new TLFuzzer(txns)) | ||||
| @@ -1,10 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package uncore.tilelink2 | ||||
| package freechips.rocketchip.devices.tilelink | ||||
| 
 | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| 
 | ||||
| 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. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import Chisel.log2Ceil | ||||
| import scala.math.{max,min} | ||||
|  | ||||
| object AddressDecoder | ||||
|   | ||||
| @@ -1,9 +1,8 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import freechips.rocketchip.config.Field | ||||
| import sys.process._ | ||||
| import java.io.{ByteArrayInputStream, ByteArrayOutputStream} | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import scala.collection.immutable.SortedMap | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import chisel3.experimental.{BaseModule, RawModule, MultiIOModule} | ||||
| import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo} | ||||
| import freechips.rocketchip.config.Parameters | ||||
|  | ||||
| abstract class LazyModule()(implicit val p: Parameters) | ||||
| { | ||||
|   | ||||
| @@ -1,10 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.{SourceInfo, SourceLine} | ||||
| import config._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
|  | ||||
| abstract class MonitorBase(implicit sourceInfo: SourceInfo, p: Parameters) extends LazyModule()(p) { | ||||
|   override val module: LazyModuleImp | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import util.HeterogeneousBag | ||||
| import scala.collection.mutable.ListBuffer | ||||
| 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 | ||||
| // UI = Upwards   flowing Parameters generated by the inner side of the node | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,8 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package diplomacy | ||||
| package freechips.rocketchip.diplomacy | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import Chisel.log2Ceil | ||||
| import scala.collection.immutable.{ListMap,SortedMap} | ||||
|  | ||||
| sealed trait ResourceValue | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| import Chisel._ | ||||
| package freechips.rocketchip | ||||
|  | ||||
| import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo} | ||||
|  | ||||
| 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.Berkeley for license details. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import rocket._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink._ | ||||
| import uncore.coherence._ | ||||
| import uncore.agents._ | ||||
| import uncore.util._ | ||||
| import tile.TileKey | ||||
| import junctions._ | ||||
| import config._ | ||||
| import coreplex._ | ||||
| import rocketchip._ | ||||
| import freechips.rocketchip.chip.{BaseConfig, ExtMem} | ||||
| import freechips.rocketchip.config.Config | ||||
| import freechips.rocketchip.coreplex.{CacheBlockBytes, L1toL2Config, WithBufferlessBroadcastHub} | ||||
| import freechips.rocketchip.rocket.{DCacheParams, PAddrBits} | ||||
| import freechips.rocketchip.tile.{MaxHartIdBits, XLen} | ||||
|  | ||||
| /** 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( | ||||
|   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) | ||||
| class TraceGenBufferlessConfig extends Config(new WithBufferlessBroadcastHub ++ new TraceGenConfig) | ||||
|  | ||||
| /* Composable Configs to set individual parameters */ | ||||
|  | ||||
| class WithGroundTestTiles extends Config((site, here, up) => { | ||||
|   case TileKey => site(GroundTestKey).head | ||||
|   case NTiles => site(GroundTestKey).size | ||||
| }) | ||||
|  | ||||
| class WithComparator(n: Int) extends Config((site, here, up) => { | ||||
|   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 nWays = 1 | ||||
|     val blockOffset = site(CacheBlockOffsetBits) | ||||
|     val nBeats = site(CacheBlockBytes)/site(L1toL2Config).beatBytes | ||||
|     List.tabulate(4 * nWays) { i => | ||||
|       Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) } | ||||
|     }.flatten | ||||
|   } | ||||
| class WithTraceGen(params: Seq[DCacheParams], nReqs: Int = 8192) extends Config((site, here, up) => { | ||||
|   case GroundTestTilesKey => params.map { dcp => TraceGenParams( | ||||
|     dcache = Some(dcp), | ||||
|     wordBits = site(XLen), | ||||
|     addrBits = site(PAddrBits), | ||||
|     addrBag = { | ||||
|       val nSets = 2 | ||||
|       val nWays = 1 | ||||
|       val blockOffset = log2Up(site(CacheBlockBytes)) | ||||
|       val nBeats = site(CacheBlockBytes)/site(L1toL2Config).beatBytes | ||||
|       List.tabulate(4 * nWays) { i => | ||||
|         Seq.tabulate(nBeats) { j => BigInt((j * 8) + ((i * nSets) << blockOffset)) } | ||||
|       }.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. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import diplomacy._ | ||||
| import coreplex._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import uncore.agents._ | ||||
| import uncore.coherence._ | ||||
| import uncore.devices._ | ||||
| import uncore.tilelink._ | ||||
| import uncore.tilelink2._ | ||||
| import uncore.util._ | ||||
|  | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.tile._ | ||||
|  | ||||
| import scala.math.max | ||||
|  | ||||
| case object TileId extends Field[Int] | ||||
|  | ||||
| class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex { | ||||
|   val tiles = List.tabulate(p(NTiles)) { i => | ||||
|     LazyModule(new GroundTestTile()(p.alter { (site, here, up) => { | ||||
|       case TileId => i | ||||
|       case CacheBlockOffsetBits => log2Up(site(CacheBlockBytes)) | ||||
|       case AmoAluOperandBits => site(XLen) | ||||
|   val tileParams = p(GroundTestTilesKey) | ||||
|   val tiles = tileParams.zipWithIndex.map { case(c, i) => LazyModule( | ||||
|     c.build(i, p.alterPartial { | ||||
|       case TileKey => c | ||||
|       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) | ||||
|   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) { | ||||
|   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.Berkeley for license details. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import util.ParameterizedBundle | ||||
|  | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile.CoreModule | ||||
| import freechips.rocketchip.util.ParameterizedBundle | ||||
|  | ||||
| class DummyPTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) { | ||||
|   val io = new Bundle { | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| // 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 | ||||
|   generateFirrtl | ||||
|   generateTestSuiteMakefrags // TODO: Needed only for legacy make targets | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip | ||||
|  | ||||
| package object groundtest { | ||||
|   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. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import diplomacy._ | ||||
| import config._ | ||||
| import rocketchip._ | ||||
| import util._ | ||||
|  | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.LazyModule | ||||
|  | ||||
| class TestHarness(implicit p: Parameters) extends Module { | ||||
|   val io = new Bundle { val success = Bool(OUTPUT) } | ||||
|   | ||||
| @@ -1,123 +1,51 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| // See LICENSE.Berkeley for license details. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import config._ | ||||
| import coreplex._ | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import uncore.tilelink._ | ||||
| import uncore.tilelink2._ | ||||
| import rocketchip.ExtMem | ||||
| import diplomacy._ | ||||
| import util.ParameterizedBundle | ||||
|  | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.coreplex._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.chip._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| 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 | ||||
|  | ||||
| case class GroundTestTileParams( | ||||
|     uncached: Int = 0, | ||||
|     ptw: Int = 0, | ||||
|     maxXacts: Int = 1, | ||||
|     dcache: Option[DCacheParams] = Some(DCacheParams())) extends TileParams { | ||||
|   def build(i: Int, p: Parameters): GroundTestTile | ||||
|    | ||||
|   val icache = None | ||||
|   val btb = None | ||||
|   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 dataScratchpadBytes = 0 | ||||
| } | ||||
| case object GroundTestKey extends Field[Seq[GroundTestTileParams]] | ||||
|  | ||||
| trait HasGroundTestConstants { | ||||
|   val timeoutCodeBits = 4 | ||||
|   val errorCodeBits = 4 | ||||
| case object GroundTestTilesKey extends Field[Seq[GroundTestTileParams]] | ||||
|  | ||||
| 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 { | ||||
|   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) | ||||
| class GroundTestTileBundle[+L <: GroundTestTile](_outer: L) extends BaseTileBundle(_outer) { | ||||
|   val status = new GroundTestStatus | ||||
| } | ||||
|  | ||||
| abstract class GroundTest(implicit val p: Parameters) extends Module | ||||
|     with HasGroundTestParameters { | ||||
|   val io = new GroundTestIO | ||||
| } | ||||
| class GroundTestTileModule[+L <: GroundTestTile, +B <: GroundTestTileBundle[L]](_outer: L, _io: () => B) extends BaseTileModule(_outer, _io) { | ||||
|  | ||||
| class GroundTestTile(implicit p: Parameters) extends LazyModule | ||||
|     with HasGroundTestParameters { | ||||
|   val slave = None | ||||
|   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 | ||||
|   outer.dcacheOpt foreach { dcache => | ||||
|     val ptw = Module(new DummyPTW(1)) | ||||
|     ptw.io.requestors.head <> dcache.module.io.ptw | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|  | ||||
| import Chisel._ | ||||
| import config.Parameters | ||||
| import diplomacy.LazyModule | ||||
| import rocketchip._ | ||||
|  | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.LazyModule | ||||
| import freechips.rocketchip.chip._ | ||||
|  | ||||
| class GroundTestTop(implicit p: Parameters) extends BaseSystem | ||||
|     with HasPeripheryMasterAXI4MemPort | ||||
|   | ||||
| @@ -17,17 +17,14 @@ | ||||
| // Mainstream Systems (REMS) project, funded by EPSRC grant | ||||
| // EP/K008528/1. | ||||
|  | ||||
| package groundtest | ||||
| package freechips.rocketchip.groundtest | ||||
|   | ||||
| import Chisel._ | ||||
| import uncore.tilelink._ | ||||
| import uncore.constants._ | ||||
| import coreplex.NTiles | ||||
| import rocket._ | ||||
| import tile._ | ||||
| import util.{Timer, DynamicTimer} | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.util._ | ||||
| import scala.util.Random | ||||
| import config._ | ||||
|  | ||||
| // ======= | ||||
| // Outline | ||||
| @@ -59,19 +56,29 @@ import config._ | ||||
| //     (This is a way to generate a wider range of addresses without having | ||||
| //     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 { | ||||
|   implicit val p: Parameters | ||||
|   val pAddrBits           = p(PAddrBits) | ||||
|   val numGens             = p(NTiles) | ||||
|   val numBitsInId         = log2Up(numGens) | ||||
|   val numReqsPerGen       = p(GeneratorKey).maxRequests | ||||
|   val params: TraceGenParams | ||||
|   val pAddrBits           = params.addrBits | ||||
|   val numGens             = params.numGens | ||||
|   val numReqsPerGen       = params.maxRequests | ||||
|   val memStart            = params.memStart | ||||
|   val memRespTimeout      = 8192 | ||||
|   val numBitsInWord       = p(XLen) | ||||
|   val numBitsInWord       = params.wordBits | ||||
|   val numBytesInWord      = numBitsInWord / 8 | ||||
|   val numBitsInWordOffset = log2Up(numBytesInWord) | ||||
|   val addressBag          = p(AddressBag) | ||||
|   val addressBag          = params.addrBag | ||||
|   val addressBagLen       = addressBag.length | ||||
|   val logAddressBagLen    = log2Up(addressBagLen) | ||||
|   val genExtraAddrs       = false | ||||
| @@ -179,14 +186,13 @@ class TagMan(val logNumTags : Int) extends Module { | ||||
| // Trace generator | ||||
| // =============== | ||||
|  | ||||
| class TraceGenerator(id: Int) | ||||
|     (implicit val p: Parameters) extends Module | ||||
|                                 with HasTraceGenParams | ||||
|                                 with HasGroundTestParameters { | ||||
| class TraceGenerator(val params: TraceGenParams)(implicit val p: Parameters) extends Module | ||||
|     with HasTraceGenParams { | ||||
|   val io = new Bundle { | ||||
|     val finished = Bool(OUTPUT) | ||||
|     val timeout = Bool(OUTPUT) | ||||
|     val mem = new HellaCacheIO | ||||
|     val hartid = UInt(INPUT, log2Up(numGens)) | ||||
|   } | ||||
|  | ||||
|   val totalNumAddrs = addressBag.size + numExtraAddrs | ||||
| @@ -199,8 +205,6 @@ class TraceGenerator(id: Int) | ||||
|   reqTimer.io.stop.valid := io.mem.resp.valid | ||||
|   reqTimer.io.stop.bits := io.mem.resp.bits.tag | ||||
|  | ||||
|   assert(!reqTimer.io.timeout.valid, s"TraceGen core ${id}: request timed out") | ||||
|  | ||||
|   // Random addresses | ||||
|   // ---------------- | ||||
|    | ||||
| @@ -327,7 +331,7 @@ class TraceGenerator(id: Int) | ||||
|   // ------------------ | ||||
|  | ||||
|   // Hardware thread id | ||||
|   val tid = UInt(id, numBitsInId) | ||||
|   val tid = io.hartid | ||||
|  | ||||
|   // Request & response count | ||||
|   val reqCount  = Reg(init = UInt(0, 32)) | ||||
| @@ -345,7 +349,7 @@ class TraceGenerator(id: Int) | ||||
|   sendFreshReq := Bool(false) | ||||
|  | ||||
|   // 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 | ||||
|   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.cmd  := reqCmd | ||||
|   io.mem.req.bits.tag  := reqTag | ||||
|   io.mem.invalidate_lr := Bool(false) | ||||
|  | ||||
|   // On cycle when request is actually sent, print it | ||||
|   when (io.mem.req.fire()) { | ||||
| @@ -569,17 +574,25 @@ class TraceGenerator(id: Int) | ||||
| // Trace-generator wrapper | ||||
| // ======================= | ||||
|  | ||||
| class GroundTestTraceGenerator(implicit p: Parameters) | ||||
|     extends GroundTest()(p) with HasTraceGenParams { | ||||
| class TraceGenTile(val id: Int, val params: TraceGenParams)(implicit p: Parameters) extends GroundTestTile(params) { | ||||
|   override lazy val module = new TraceGenTileModule(this) | ||||
| } | ||||
|  | ||||
|   require(io.mem.size <= 1) | ||||
|   require(io.cache.size == 1) | ||||
| class TraceGenTileModule(outer: TraceGenTile) extends GroundTestTileModule(outer, () => new GroundTestTileBundle(outer)) { | ||||
|  | ||||
|   val traceGen = Module(new TraceGenerator(p(TileId))) | ||||
|   io.cache.head <> traceGen.io.mem | ||||
|   val tracegen = Module(new TraceGenerator(outer.params)) | ||||
|   tracegen.io.hartid := io.hartid | ||||
|  | ||||
|   io.status.finished := traceGen.io.finished | ||||
|   io.status.timeout.valid := traceGen.io.timeout | ||||
|   outer.dcacheOpt foreach { dcache => | ||||
|     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.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. | ||||
|  | ||||
| package jtag | ||||
| package freechips.rocketchip.jtag | ||||
|  | ||||
| import chisel3._ | ||||
| import chisel3.core.DataMirror | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| // See LICENSE.jtag for license details. | ||||
|  | ||||
| package jtag | ||||
| package freechips.rocketchip.jtag | ||||
|  | ||||
| import util.{AsyncResetRegVec} | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import freechips.rocketchip.util.{AsyncResetRegVec} | ||||
|  | ||||
| object JtagState { | ||||
|   sealed abstract class State(val id: Int) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.jtag for license details. | ||||
|  | ||||
| package jtag | ||||
| package freechips.rocketchip.jtag | ||||
|  | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.jtag for license details. | ||||
|  | ||||
| package jtag | ||||
| package freechips.rocketchip.jtag | ||||
|  | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // See LICENSE.jtag for license details. | ||||
|  | ||||
| package jtag | ||||
| package freechips.rocketchip.jtag | ||||
|  | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| // See LICENSE.jtag for license details | ||||
|  | ||||
| package freechips.rocketchip | ||||
|  | ||||
| import scala.language.implicitConversions | ||||
|  | ||||
| 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
		Reference in New Issue
	
	Block a user