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