Merge remote-tracking branch 'origin/master' into rf-after-issue
This commit is contained in:
		
						commit
						b6c99e8e08
					
				|  | @ -13,3 +13,9 @@ | |||
| [submodule "fudian"] | ||||
| 	path = fudian | ||||
| 	url = https://github.com/OpenXiangShan/fudian.git | ||||
| [submodule "utility"] | ||||
| 	path = utility | ||||
| 	url = https://github.com/OpenXiangShan/utility | ||||
| [submodule "yunsuan"] | ||||
| 	path = yunsuan | ||||
| 	url = https://github.com/OpenXiangShan/YunSuan.git | ||||
|  |  | |||
							
								
								
									
										17
									
								
								build.sc
								
								
								
								
							
							
						
						
									
										17
									
								
								build.sc
								
								
								
								
							|  | @ -114,7 +114,8 @@ object huancun extends XSModule with SbtModule { | |||
|   override def millSourcePath = os.pwd / "huancun" | ||||
| 
 | ||||
|   override def moduleDeps = super.moduleDeps ++ Seq( | ||||
|     rocketchip | ||||
|     rocketchip, | ||||
|     utility | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
|  | @ -128,6 +129,15 @@ object yunsuan extends XSModule with SbtModule { | |||
| 
 | ||||
| object fudian extends XSModule with SbtModule | ||||
| 
 | ||||
| object utility extends XSModule with SbtModule { | ||||
| 
 | ||||
|   override def millSourcePath = os.pwd / "utility" | ||||
| 
 | ||||
|   override def moduleDeps = super.moduleDeps ++ Seq( | ||||
|     rocketchip | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| // extends this trait to use XiangShan in other projects | ||||
| trait CommonXiangShan extends XSModule with SbtModule { m => | ||||
| 
 | ||||
|  | @ -137,6 +147,7 @@ trait CommonXiangShan extends XSModule with SbtModule { m => | |||
|   def huancunModule: PublishModule | ||||
|   def yunsuanModule: PublishModule | ||||
|   def fudianModule: PublishModule | ||||
|   def utilityModule: PublishModule | ||||
| 
 | ||||
|   override def millSourcePath = os.pwd | ||||
| 
 | ||||
|  | @ -149,7 +160,8 @@ trait CommonXiangShan extends XSModule with SbtModule { m => | |||
|     difftestModule, | ||||
|     huancunModule, | ||||
|     yunsuanModule, | ||||
|     fudianModule | ||||
|     fudianModule, | ||||
|     utilityModule | ||||
|   ) | ||||
| 
 | ||||
|   object test extends Tests with TestModule.ScalaTest { | ||||
|  | @ -170,4 +182,5 @@ object XiangShan extends CommonXiangShan { | |||
|   override def huancunModule = huancun | ||||
|   override def yunsuanModule = yunsuan | ||||
|   override def fudianModule = fudian | ||||
|   override def utilityModule = utility | ||||
| } | ||||
|  |  | |||
							
								
								
									
										2
									
								
								huancun
								
								
								
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								huancun
								
								
								
								
							|  | @ -1 +1 @@ | |||
| Subproject commit 57ccacbf0c5b552a3d6dda5baeef3abc8bad033c | ||||
| Subproject commit f96ac25904091ae7ab96b7f6f5bd7047d4129466 | ||||
|  | @ -21,7 +21,7 @@ import chisel3._ | |||
| import chisel3.experimental.ExtModule | ||||
| import chisel3.util._ | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| trait HasSDConst { | ||||
|   def MemorySize = 4L * 1024 * 1024 * 1024 // 4GB | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3.experimental.ExtModule | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class FlashHelper extends ExtModule with HasExtModuleInline { | ||||
|   val clk = IO(Input(Clock())) | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3.util._ | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| // we support 256 interrupt bits by default | ||||
| class IntrGenIO extends Bundle { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3.util._ | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class KeyboardIO extends Bundle { | ||||
|   val ps2Clk = Input(Bool()) | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import freechips.rocketchip.amba.axi4.{AXI4MasterNode, AXI4Parameters, AXI4SlaveNode} | ||||
| import freechips.rocketchip.diplomacy.{AddressSet, InModuleBody, LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class MemoryRWHelper extends ExtModule with HasExtModuleInline { | ||||
|   val DataBits = 64 | ||||
|  |  | |||
|  | @ -20,8 +20,8 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import chipsalliance.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import utils.MaskExpand | ||||
| import utils.{HasTLDump, XSDebug, RegMap} | ||||
| import utils.{XSDebug, HasTLDump} | ||||
| import utility.{RegMap, MaskExpand} | ||||
| 
 | ||||
| /*  base + 0x000000: Reserved (interrupt source 0 does not exist) | ||||
|     base + 0x000004: Interrupt source 1 priority | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ import chisel3.experimental.ExtModule | |||
| import chisel3.util._ | ||||
| import freechips.rocketchip.amba.axi4.AXI4SlaveNode | ||||
| import freechips.rocketchip.diplomacy.{AddressSet, LazyModule} | ||||
| import utils.MaskExpand | ||||
| import utility.MaskExpand | ||||
| 
 | ||||
| class RAMHelper(memByte: BigInt) extends ExtModule { | ||||
|   val DataBits = 64 | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ package device | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType, TransferSizes} | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.amba.axi4.{AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters} | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chisel3._ | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class TimerIO extends Bundle { | ||||
|   val mtip = Output(Bool()) | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3.util._ | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.AddressSet | ||||
| import utils._ | ||||
| import utility._ | ||||
| import difftest._ | ||||
| 
 | ||||
| class AXI4UART | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import chisel3.experimental.ExtModule | |||
| import freechips.rocketchip.amba.axi4.{AXI4AdapterNode, AXI4IdentityNode, AXI4Parameters, AXI4SlaveNode, AXI4SlaveParameters, AXI4SlavePortParameters, AXI4Xbar} | ||||
| import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType} | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| trait HasVGAConst { | ||||
|   val ScreenW = 800 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import freechips.rocketchip.regmapper.RegFieldGroup | ||||
| import freechips.rocketchip.tilelink.TLRegisterNode | ||||
| import xiangshan.backend.fu.{MMPMAMethod, PMAConst, PMPChecker, PMPReqBundle, PMPRespBundle} | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
| //import bus.axi4._ | ||||
| //import device.AXI4SlaveModule | ||||
| //import utils._ | ||||
| import utility._ | ||||
| // | ||||
| //class PixelBundle extends Bundle { | ||||
| //  val a = UInt(8.W) | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ import freechips.rocketchip.devices.tilelink.{CLINT, CLINTParams, DevNullParams, | |||
| import freechips.rocketchip.diplomacy.{AddressSet, IdRange, InModuleBody, LazyModule, LazyModuleImp, MemoryDevice, RegionType, SimpleDevice, TransferSizes} | ||||
| import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple} | ||||
| import freechips.rocketchip.regmapper.{RegField, RegFieldAccessType, RegFieldDesc, RegFieldGroup} | ||||
| import utils.{BinaryArbiter, TLEdgeBuffer} | ||||
| import utility.{BinaryArbiter, TLEdgeBuffer} | ||||
| import xiangshan.{DebugOptionsKey, HasXSParameter, XSBundle, XSCore, XSCoreParameters, XSTileKey} | ||||
| import freechips.rocketchip.amba.axi4._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import system._ | ||||
| import chipsalliance.rocketchip.config._ | ||||
| import freechips.rocketchip.tile.{BusErrorUnit, BusErrorUnitParams, XLen} | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import system._ | ||||
| import device._ | ||||
| import chisel3.stage.ChiselGeneratorAnnotation | ||||
|  |  | |||
|  | @ -1,106 +0,0 @@ | |||
| package utils | ||||
| 
 | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util.BundleField | ||||
| import huancun.XbarCircuit | ||||
| 
 | ||||
| 
 | ||||
| case class BinaryArbiterNode | ||||
| ( | ||||
|   clientFn: Seq[TLMasterPortParameters] => TLMasterPortParameters, | ||||
|   managerFn: Seq[TLSlavePortParameters] => TLSlavePortParameters | ||||
| )(implicit valName: ValName) extends TLCustomNode { | ||||
| 
 | ||||
|   override def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { | ||||
|     require(iStars == 0 && oKnown == 0 && oStars == 1) | ||||
|     if(iKnown < 4) { | ||||
|       (0, 1) | ||||
|     } else { | ||||
|       require(2 * (iKnown / 2) == iKnown) | ||||
|       (0, 2) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   override def mapParamsD(n: Int, p: Seq[TLClientPortParameters]): Seq[TLClientPortParameters] = { | ||||
|     if(n == 1){ | ||||
|       Seq(clientFn(p)) | ||||
|     } else { | ||||
|       require(n == 2) | ||||
|       p.grouped(2).toList.transpose.map(grp => clientFn(grp)) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   override def mapParamsU(n: Int, p: Seq[TLManagerPortParameters]): Seq[TLManagerPortParameters] = { | ||||
|     Seq.fill(n)(p.head) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class BinaryArbiter(policy: TLArbiter.Policy)(implicit p: Parameters) extends LazyModule { | ||||
| 
 | ||||
|   val node = BinaryArbiterNode( | ||||
|     clientFn = { seq => | ||||
|       seq.head.v1copy( | ||||
|         echoFields = BundleField.union(seq.flatMap(_.echoFields)), | ||||
|         requestFields = BundleField.union(seq.flatMap(_.requestFields)), | ||||
|         responseKeys = seq.flatMap(_.responseKeys).distinct, | ||||
|         minLatency = seq.map(_.minLatency).min, | ||||
|         clients = (TLXbar.mapInputIds(seq) zip seq) flatMap { case (range, port) => | ||||
|           port.clients map { client => | ||||
|             client.v1copy( | ||||
|               sourceId = client.sourceId.shift(range.start) | ||||
|             ) | ||||
|           } | ||||
|         } | ||||
|       ) | ||||
|     }, | ||||
|     managerFn = { seq => | ||||
|       val fifoIdFactory = TLXbar.relabeler() | ||||
|       seq.head.v1copy( | ||||
|         responseFields = BundleField.union(seq.flatMap(_.responseFields)), | ||||
|         requestKeys = seq.flatMap(_.requestKeys).distinct, | ||||
|         minLatency = seq.map(_.minLatency).min, | ||||
|         endSinkId = TLXbar.mapOutputIds(seq).map(_.end).max, | ||||
|         managers = seq.flatMap { port => | ||||
|           require(port.beatBytes == seq.head.beatBytes, | ||||
|             s"Xbar ($name with parent $parent) data widths don't match: ${port.managers.map(_.name)} has ${port.beatBytes}B vs ${seq(0).managers.map(_.name)} has ${seq(0).beatBytes}B") | ||||
|           val fifoIdMapper = fifoIdFactory() | ||||
|           port.managers map { manager => | ||||
|             manager.v1copy( | ||||
|               fifoId = manager.fifoId.map(fifoIdMapper(_)) | ||||
|             ) | ||||
|           } | ||||
|         } | ||||
|       )} | ||||
|   ) | ||||
| 
 | ||||
|   lazy val module = new LazyModuleImp(this){ | ||||
| 
 | ||||
|     if(node.out.size == 1){ | ||||
|       TLXbar.circuit(policy, node.in, node.out) | ||||
|     } else { | ||||
|       require(node.out.size == 2) | ||||
|       /* | ||||
|             0, 1, 2, 3 => (0, 2) (1, 3) | ||||
|        */ | ||||
|       val grps = node.in.grouped(2).toList.transpose | ||||
|       require(grps.size == 2) | ||||
|       for((gp, out) <- grps.zip(node.out)){ | ||||
|         val xbar = Module(new XbarCircuit(policy, gp.map(_._2), Seq(out._2))) | ||||
|         xbar.io.in.zip(gp.map(_._1)).foreach(x => x._1 <> x._2) | ||||
|         out._1 <> xbar.io.out.head | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object BinaryArbiter { | ||||
|   def apply(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parameters) = { | ||||
|     val arbiter = LazyModule(new BinaryArbiter(policy)) | ||||
|     arbiter.node | ||||
|   } | ||||
| } | ||||
|  | @ -1,349 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| import scala.math.min | ||||
| 
 | ||||
| object RegNextWithEnable { | ||||
|   def apply[T <: Data](data: Valid[T], hasInit: Boolean = true): Valid[T] = { | ||||
|     val next = Wire(data.cloneType) | ||||
|     if (hasInit) { | ||||
|       next.valid := RegNext(data.valid, false.B) | ||||
|     } | ||||
|     else { | ||||
|       next.valid := RegNext(data.valid) | ||||
|     } | ||||
|     next.bits := RegEnable(data.bits, data.valid) | ||||
|     next | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class CircularShift(data: UInt) { | ||||
|   private def helper(step: Int, isLeft: Boolean): UInt = { | ||||
|     if (step == 0) { | ||||
|       data | ||||
|     } | ||||
|     else { | ||||
|       val splitIndex = if (isLeft) { | ||||
|         data.getWidth - (step % data.getWidth) | ||||
|       } else { | ||||
|         step % data.getWidth | ||||
|       } | ||||
|       Cat(data(splitIndex - 1, 0), data(data.getWidth - 1, splitIndex)) | ||||
|     } | ||||
|   } | ||||
|   def left(step: Int): UInt = helper(step, true) | ||||
|   def right(step: Int): UInt = helper(step, false) | ||||
| } | ||||
| 
 | ||||
| object CircularShift { | ||||
|   def apply(data: UInt): CircularShift = new CircularShift(data) | ||||
| } | ||||
| 
 | ||||
| object WordShift { | ||||
|   def apply(data: UInt, wordIndex: UInt, step: Int): UInt = (data << (wordIndex * step.U)).asUInt | ||||
| } | ||||
| 
 | ||||
| object MaskExpand { | ||||
|   def apply(m: UInt, maskWidth: Int = 8): UInt = Cat(m.asBools.map(Fill(maskWidth, _)).reverse) | ||||
|   def apply(m: Seq[Bool], maskWidth: Int): Vec[UInt] = VecInit(m.map(Fill(maskWidth, _))) | ||||
| } | ||||
| 
 | ||||
| object MaskData { | ||||
|   def apply(oldData: UInt, newData: UInt, fullmask: UInt): UInt = { | ||||
|     require(oldData.getWidth <= fullmask.getWidth, s"${oldData.getWidth} < ${fullmask.getWidth}") | ||||
|     require(newData.getWidth <= fullmask.getWidth, s"${newData.getWidth} < ${fullmask.getWidth}") | ||||
|     (newData & fullmask) | (oldData & (~fullmask).asUInt) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object SignExt { | ||||
|   def apply(a: UInt, len: Int): UInt = { | ||||
|     val aLen = a.getWidth | ||||
|     val signBit = a(aLen-1) | ||||
|     if (aLen >= len) a(len-1,0) else Cat(Fill(len - aLen, signBit), a) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ZeroExt { | ||||
|   def apply(a: UInt, len: Int): UInt = { | ||||
|     val aLen = a.getWidth | ||||
|     if (aLen >= len) a(len-1,0) else Cat(0.U((len - aLen).W), a) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object Or { | ||||
|   // Fill 1s from low bits to high bits | ||||
|   def leftOR(x: UInt): UInt = leftOR(x, x.getWidth, x.getWidth) | ||||
|   def leftOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = { | ||||
|     val stop = min(width, cap) | ||||
|     def helper(s: Int, x: UInt): UInt = | ||||
|       if (s >= stop) x else helper(s+s, x | (x << s)(width-1,0)) | ||||
|     helper(1, x)(width-1, 0) | ||||
|   } | ||||
| 
 | ||||
|   // Fill 1s form high bits to low bits | ||||
|   def rightOR(x: UInt): UInt = rightOR(x, x.getWidth, x.getWidth) | ||||
|   def rightOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = { | ||||
|     val stop = min(width, cap) | ||||
|     def helper(s: Int, x: UInt): UInt = | ||||
|       if (s >= stop) x else helper(s+s, x | (x >> s).asUInt) | ||||
|     helper(1, x)(width-1, 0) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object OneHot { | ||||
|   def OH1ToOH(x: UInt): UInt = ((x << 1).asUInt | 1.U) & (~Cat(0.U(1.W), x)).asUInt | ||||
|   def OH1ToUInt(x: UInt): UInt = OHToUInt(OH1ToOH(x)) | ||||
|   def UIntToOH1(x: UInt, width: Int): UInt = (~((-1).S(width.W).asUInt << x)(width-1, 0)).asUInt | ||||
|   def UIntToOH1(x: UInt): UInt = UIntToOH1(x, (1 << x.getWidth) - 1) | ||||
|   def checkOneHot(in: Bits): Unit = assert(PopCount(in) <= 1.U) | ||||
|   def checkOneHot(in: Iterable[Bool]): Unit = assert(PopCount(in) <= 1.U) | ||||
| } | ||||
| 
 | ||||
| object LowerMask { | ||||
|   def apply(a: UInt, len: Int): UInt = { | ||||
|     ParallelOR((0 until len).map(i => (a >> i).asUInt)) | ||||
|   } | ||||
|   def apply(a: UInt): UInt = { | ||||
|     apply(a, a.getWidth) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object HigherMask { | ||||
|   def apply(a: UInt, len: Int) = { | ||||
|     Reverse(LowerMask(Reverse(a), len)) | ||||
|   } | ||||
|   def apply(a: UInt): UInt = { | ||||
|     apply(a, a.getWidth) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object LowerMaskFromLowest { | ||||
|   def apply(a: UInt) = { | ||||
|     LowerMask(PriorityEncoderOH(a)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object HigherMaskFromHighest { | ||||
|   def apply(a: UInt) = { | ||||
|     Reverse(LowerMask(PriorityEncoderOH(Reverse(a)))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object LowestBit { | ||||
|   def apply(a: UInt, len: Int) = { | ||||
|     Mux(a(0), 1.U(len.W), Reverse((ParallelOR((0 until len).map(i => Reverse(a(len - 1, 0)) >> i.U)) + 1.U) >> 1.U)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object HighestBit { | ||||
|   def apply(a: UInt, len: Int) = { | ||||
|     Reverse(LowestBit(Reverse(a), len)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object GenMask { | ||||
|   // generate w/r mask | ||||
|   def apply(high: Int, low: Int) = { | ||||
|     require(high > low) | ||||
|     (VecInit(List.fill(high+1)(true.B)).asUInt >> low << low).asUInt() | ||||
|   } | ||||
|   def apply(pos: Int) = { | ||||
|     (1.U << pos).asUInt() | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object UIntToMask { | ||||
|   def apply(ptr: UInt, length: Integer) = leftmask(ptr, length) | ||||
|   def reverseUInt(input: UInt): UInt = { | ||||
|     VecInit(input.asBools.reverse).asUInt | ||||
|   } | ||||
|   def leftmask(ptr: UInt, length: Integer) = UIntToOH(ptr)(length - 1, 0) - 1.U | ||||
|   def rightmask(ptr: UInt, length: Integer) = reverseUInt(reverseUInt(UIntToOH(ptr)(length - 1, 0)) - 1.U) | ||||
| } | ||||
| 
 | ||||
| object GetEvenBits { | ||||
|   def apply(input: UInt): UInt = { | ||||
|     VecInit((0 until input.getWidth/2).map(i => {input(2*i)})).asUInt | ||||
|   } | ||||
|   def reverse(input: UInt): UInt = { | ||||
|     VecInit((0 until input.getWidth * 2).map(i => { | ||||
|       if(i % 2 == 0) input(i/2) else false.B  | ||||
|     })).asUInt | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| object GetOddBits { | ||||
|   def apply(input: UInt): UInt = { | ||||
|     VecInit((0 until input.getWidth/2).map(i => {input(2*i+1)})).asUInt | ||||
|   } | ||||
|   def reverse(input: UInt): UInt = { | ||||
|     VecInit((0 until input.getWidth * 2).map(i => { | ||||
|       if(i % 2 == 0) false.B else input(i/2)  | ||||
|     })).asUInt | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object GetRemBits { | ||||
|   def apply(div: Int)(input: UInt): Seq[UInt] = { | ||||
|     (0 until div).map(rem => VecInit((0 until input.getWidth / div).map(i => input(div * i + rem))).asUInt) | ||||
|   } | ||||
|   def reverse(div: Int)(input: Seq[UInt]): Seq[UInt] = { | ||||
|     (0 until div).map(rem => VecInit((0 until input(rem).getWidth * div).map(i => { | ||||
|       if (i % div == rem) input(rem)(i / div) else 0.B | ||||
|     })).asUInt) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object XORFold { | ||||
|   def apply(input: UInt, resWidth: Int): UInt = { | ||||
|     require(resWidth > 0) | ||||
|     val fold_range = (input.getWidth + resWidth - 1) / resWidth | ||||
|     val value = ZeroExt(input, fold_range * resWidth) | ||||
|     ParallelXOR((0 until fold_range).map(i => value(i*resWidth+resWidth-1, i*resWidth))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object OnesMoreThan { | ||||
|   def apply(input: Seq[Bool], thres: Int): Bool = { | ||||
|     if (thres == 0) { | ||||
|       true.B | ||||
|     } | ||||
|     else if (input.length < thres) { | ||||
|       false.B | ||||
|     } | ||||
|     else if (thres == 1) { | ||||
|       VecInit(input).asUInt.orR | ||||
|     } | ||||
|     else { | ||||
|       val tail = input.drop(1) | ||||
|       input(0) && OnesMoreThan(tail, thres - 1) || OnesMoreThan(tail, thres) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| abstract class SelectOne { | ||||
|   def getNthOH(n: Int): (Bool, Vec[Bool]) | ||||
| } | ||||
| 
 | ||||
| class NaiveSelectOne(bits: Seq[Bool], max_sel: Int = -1) extends SelectOne { | ||||
|   val n_bits = bits.length | ||||
|   val n_sel = if (max_sel > 0) max_sel else n_bits | ||||
|   require(n_bits > 0 && n_sel > 0 && n_bits >= n_sel) | ||||
|   private val matrix = Wire(Vec(n_bits, Vec(n_sel, Bool()))) | ||||
|   // matrix[i][j]: first i bits has j one's | ||||
|   for (i <- 0 until n_bits) { | ||||
|     for (j <- 0 until n_sel) { | ||||
|       if (j == 0) { | ||||
|         matrix(i)(j) := (if (i == 0) true.B else !Cat(bits.take(i)).orR) | ||||
|       } | ||||
|       // it's impossible to select j-th one from i elements | ||||
|       else if (i < j) { | ||||
|         matrix(i)(j) := false.B | ||||
|       } | ||||
|       else { | ||||
|         matrix(i)(j) := bits(i - 1) && matrix(i - 1)(j - 1) || !bits(i - 1) && matrix(i - 1)(j) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   def getNthOH(n: Int): (Bool, Vec[Bool]) = { | ||||
|     require(n > 0, s"$n should be positive to select the n-th one") | ||||
|     require(n <= n_sel, s"$n should not be larger than $n_sel") | ||||
|     // bits(i) is true.B and bits(i - 1, 0) has n - 1 | ||||
|     val selValid = OnesMoreThan(bits, n) | ||||
|     val sel = VecInit(bits.zip(matrix).map{ case (b, m) => b && m(n - 1) }) | ||||
|     (selValid, sel) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class CircSelectOne(bits: Seq[Bool], max_sel: Int = -1) extends SelectOne { | ||||
|   val n_bits = bits.length | ||||
|   val n_sel = if (max_sel > 0) max_sel else n_bits | ||||
|   require(n_bits > 0 && n_sel > 0 && n_bits >= n_sel) | ||||
| 
 | ||||
|   val sel_forward = new NaiveSelectOne(bits, (n_sel + 1) / 2) | ||||
|   val sel_backward = new NaiveSelectOne(bits.reverse, n_sel / 2) | ||||
|   val moreThan = Seq(1, 2).map(i => OnesMoreThan(bits, i)) | ||||
| 
 | ||||
|   def getNthOH(n: Int): (Bool, Vec[Bool]) = { | ||||
|     val selValid = OnesMoreThan(bits, n) | ||||
|     val sel_index = (n + 1) / 2 | ||||
|     if (n % 2 == 1) { | ||||
|       (selValid, sel_forward.getNthOH(sel_index)._2) | ||||
|     } | ||||
|     else { | ||||
|       (selValid, VecInit(sel_backward.getNthOH(sel_index)._2.reverse)) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class OddEvenSelectOne(bits: Seq[Bool], max_sel: Int = -1) extends SelectOne { | ||||
|   val n_bits = bits.length | ||||
|   val n_sel = if (max_sel > 0) max_sel else n_bits | ||||
|   require(n_bits > 0 && n_sel > 0 && n_bits >= n_sel) | ||||
|   require(n_sel > 1, "Select only one entry via OddEven causes odd entries to be ignored") | ||||
| 
 | ||||
|   val n_even = (n_bits + 1) / 2 | ||||
|   val sel_even = new CircSelectOne((0 until n_even).map(i => bits(2 * i)), n_sel / 2) | ||||
|   val n_odd = n_bits / 2 | ||||
|   val sel_odd = new CircSelectOne((0 until n_odd).map(i => bits(2 * i + 1)), (n_sel + 1) / 2) | ||||
| 
 | ||||
|   def getNthOH(n: Int): (Bool, Vec[Bool]) = { | ||||
|     val sel_index = (n + 1) / 2 | ||||
|     if (n % 2 == 1) { | ||||
|       val selected = sel_even.getNthOH(sel_index) | ||||
|       val sel = VecInit((0 until n_bits).map(i => if (i % 2 == 0) selected._2(i / 2) else false.B)) | ||||
|       (selected._1, sel) | ||||
|     } | ||||
|     else { | ||||
|       val selected = sel_odd.getNthOH(sel_index) | ||||
|       val sel = VecInit((0 until n_bits).map(i => if (i % 2 == 1) selected._2(i / 2) else false.B)) | ||||
|       (selected._1, sel) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class CenterSelectOne(bits: Seq[Bool], max_sel: Int = -1) extends SelectOne { | ||||
|   require(max_sel == 2, "only 2 is supported!") | ||||
|   val n_bits = bits.length | ||||
|   val half_index = (bits.length + 1) / 2 | ||||
|   def centerReverse(data: Seq[Bool]): Seq[Bool] = data.take(half_index).reverse ++ data.drop(half_index).reverse | ||||
|   val select = new CircSelectOne(centerReverse(bits), max_sel) | ||||
| 
 | ||||
|   def getNthOH(n: Int): (Bool, Vec[Bool]) = { | ||||
|     val selected = select.getNthOH(n) | ||||
|     (selected._1, VecInit(centerReverse(selected._2))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object SelectOne { | ||||
|   def apply(policy: String, bits: Seq[Bool], max_sel: Int = -1): SelectOne = { | ||||
|     policy.toLowerCase match { | ||||
|       case "naive" => new NaiveSelectOne(bits, max_sel) | ||||
|       case "circ" => new CircSelectOne(bits, max_sel) | ||||
|       case "oddeven" => new OddEvenSelectOne(bits, max_sel) | ||||
|       case "center" => new CenterSelectOne(bits, max_sel) | ||||
|       case _ => throw new IllegalArgumentException(s"unknown select policy") | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -1,113 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class CircularQueuePtr[T <: CircularQueuePtr[T]](val entries: Int) extends Bundle { | ||||
| 
 | ||||
|   def this(f: Parameters => Int)(implicit p: Parameters) = this(f(p)) | ||||
| 
 | ||||
|   val PTR_WIDTH = log2Up(entries) | ||||
|   val flag = Bool() | ||||
|   val value = UInt(PTR_WIDTH.W) | ||||
| 
 | ||||
|   override def toPrintable: Printable = { | ||||
|     p"$flag:$value" | ||||
|   } | ||||
| 
 | ||||
|   final def +(v: UInt): T = { | ||||
|     val entries = this.entries | ||||
|     val new_ptr = Wire(this.asInstanceOf[T].cloneType) | ||||
|     if(isPow2(entries)){ | ||||
|       new_ptr := (Cat(this.flag, this.value) + v).asTypeOf(new_ptr) | ||||
|     } else { | ||||
|       val new_value = this.value +& v | ||||
|       val diff = Cat(0.U(1.W), new_value).asSInt() - Cat(0.U(1.W), entries.U.asTypeOf(new_value)).asSInt() | ||||
|       val reverse_flag = diff >= 0.S | ||||
|       new_ptr.flag := Mux(reverse_flag, !this.flag, this.flag) | ||||
|       new_ptr.value := Mux(reverse_flag, | ||||
|         diff.asUInt(), | ||||
|         new_value | ||||
|       ) | ||||
|     } | ||||
|     new_ptr | ||||
|   } | ||||
| 
 | ||||
|   final def -(v: UInt): T = { | ||||
|     val flipped_new_ptr = this + (this.entries.U - v) | ||||
|     val new_ptr = Wire(this.asInstanceOf[T].cloneType) | ||||
|     new_ptr.flag := !flipped_new_ptr.flag | ||||
|     new_ptr.value := flipped_new_ptr.value | ||||
|     new_ptr | ||||
|   } | ||||
| 
 | ||||
|   final def === (that_ptr: T): Bool = this.asUInt()===that_ptr.asUInt() | ||||
| 
 | ||||
|   final def =/= (that_ptr: T): Bool = this.asUInt()=/=that_ptr.asUInt() | ||||
| 
 | ||||
|   def toOH: UInt = UIntToOH(value, entries) | ||||
| } | ||||
| 
 | ||||
| trait HasCircularQueuePtrHelper { | ||||
| 
 | ||||
|   def isEmpty[T <: CircularQueuePtr[T]](enq_ptr: T, deq_ptr: T): Bool = { | ||||
|     enq_ptr === deq_ptr | ||||
|   } | ||||
| 
 | ||||
|   def isFull[T <: CircularQueuePtr[T]](enq_ptr: T, deq_ptr: T): Bool = { | ||||
|     (enq_ptr.flag =/= deq_ptr.flag) && (enq_ptr.value === deq_ptr.value) | ||||
|   } | ||||
| 
 | ||||
|   def distanceBetween[T <: CircularQueuePtr[T]](enq_ptr: T, deq_ptr: T): UInt = { | ||||
|     assert(enq_ptr.entries == deq_ptr.entries) | ||||
|     Mux(enq_ptr.flag === deq_ptr.flag, | ||||
|       enq_ptr.value - deq_ptr.value, | ||||
|       enq_ptr.entries.U + enq_ptr.value - deq_ptr.value) | ||||
|   } | ||||
| 
 | ||||
|   def isAfter[T <: CircularQueuePtr[T]](left: T, right: T): Bool = { | ||||
|     val differentFlag = left.flag ^ right.flag | ||||
|     val compare = left.value > right.value | ||||
|     differentFlag ^ compare | ||||
|   } | ||||
| 
 | ||||
|   def isBefore[T <: CircularQueuePtr[T]](left: T, right: T): Bool = { | ||||
|     val differentFlag = left.flag ^ right.flag | ||||
|     val compare = left.value < right.value | ||||
|     differentFlag ^ compare | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Should only be used when left and right are continuous pointers. | ||||
| class QPtrMatchMatrix[T <: CircularQueuePtr[T]](left: Seq[T], right: Seq[T]) { | ||||
|   val matrix = left.map(l => right.map(_.value === l.value)) | ||||
| 
 | ||||
|   def apply(leftIndex: Int, rightIndex: Int): Bool = { | ||||
|     require(leftIndex < left.length && rightIndex < right.length) | ||||
|     if (leftIndex == 0 || rightIndex == 0) { | ||||
|       matrix(leftIndex)(rightIndex) | ||||
|     } | ||||
|     else { | ||||
|       apply(leftIndex - 1, rightIndex - 1) | ||||
|     } | ||||
|   } | ||||
|   def apply(leftIndex: Int): Seq[Bool] = right.indices.map(i => apply(leftIndex, i)) | ||||
| } | ||||
| 
 | ||||
|  | @ -1,238 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class RawDataModuleTemplate[T <: Data]( | ||||
|   gen: T, | ||||
|   numEntries: Int, | ||||
|   numRead: Int, | ||||
|   numWrite: Int, | ||||
|   isSync: Boolean, | ||||
|   optWrite: Seq[Int] = Seq() | ||||
| ) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val rvec  = Vec(numRead,  Input(UInt(numEntries.W))) | ||||
|     val rdata = Vec(numRead,  Output(gen)) | ||||
|     val wen   = Vec(numWrite, Input(Bool())) | ||||
|     val wvec  = Vec(numWrite, Input(UInt(numEntries.W))) | ||||
|     val wdata = Vec(numWrite, Input(gen)) | ||||
|   }) | ||||
| 
 | ||||
|   val data = Reg(Vec(numEntries, gen)) | ||||
| 
 | ||||
|   val wen = io.wen.zipWithIndex.map{ case (en, i) => if (optWrite.contains(i)) RegNext(en) else en } | ||||
|   val wvec = io.wvec.zipWithIndex.map{ case (v, i) => if (optWrite.contains(i)) RegEnable(v, io.wen(i)) else v } | ||||
|   val wdata = io.wdata.zipWithIndex.map{ case (d, i) => if (optWrite.contains(i)) RegEnable(d, io.wen(i)) else d } | ||||
| 
 | ||||
|   // read ports | ||||
|   val rvec = if (isSync) RegNext(io.rvec) else io.rvec | ||||
|   for (i <- 0 until numRead) { | ||||
|     assert(PopCount(rvec(i)) <= 1.U) | ||||
|     io.rdata(i) := Mux1H(rvec(i), data) | ||||
|   } | ||||
| 
 | ||||
|   if (optWrite.nonEmpty) { | ||||
|     val data_next = WireInit(data) | ||||
|     val wbypass = io.wen.zip(io.wvec).zip(wdata).zipWithIndex.filter(x => optWrite.contains(x._2)).map(_._1) | ||||
|     for (i <- 0 until numEntries) { | ||||
|       val wbypass_en = wbypass.map(w => RegNext(w._1._1 && w._1._2(i))) | ||||
|       when (VecInit(wbypass_en).asUInt.orR) { | ||||
|         data_next(i) := Mux1H(wbypass_en, wbypass.map(_._2)) | ||||
|       } | ||||
|     } | ||||
|     for (i <- 0 until numRead) { | ||||
|       io.rdata(i) := Mux1H(rvec(i), data_next) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // write ports | ||||
|   for (i <- 0 until numEntries) { | ||||
|     val w = VecInit((0 until numWrite).map(j => wen(j) && wvec(j)(i))) | ||||
|     assert(PopCount(w) <= 1.U, s"RawDatModule multi-write index:$i") | ||||
|     when (w.asUInt.orR) { | ||||
|       data(i) := Mux1H(w, wdata) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class SyncRawDataModuleTemplate[T <: Data]( | ||||
|   gen: T, numEntries: Int, numRead: Int, numWrite: Int, optWrite: Seq[Int] = Seq() | ||||
| ) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, true, optWrite) | ||||
| class AsyncRawDataModuleTemplate[T <: Data]( | ||||
|   gen: T, numEntries: Int, numRead: Int, numWrite: Int, optWrite: Seq[Int] = Seq() | ||||
| ) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, false, optWrite) | ||||
| 
 | ||||
| class SyncDataModuleTemplate[T <: Data]( | ||||
|   gen: T, | ||||
|   numEntries: Int, | ||||
|   numRead: Int, | ||||
|   numWrite: Int, | ||||
|   parentModule: String = "", | ||||
|   concatData: Boolean = false, | ||||
|   perReadPortBypassEnable: Option[Seq[Boolean]] = None | ||||
| ) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val raddr = Vec(numRead,  Input(UInt(log2Ceil(numEntries).W))) | ||||
|     val rdata = Vec(numRead,  Output(gen)) | ||||
|     val wen   = Vec(numWrite, Input(Bool())) | ||||
|     val waddr = Vec(numWrite, Input(UInt(log2Ceil(numEntries).W))) | ||||
|     val wdata = Vec(numWrite, Input(gen)) | ||||
|   }) | ||||
| 
 | ||||
|   override def desiredName: String = s"SyncDataModuleTemplate_${parentModule}_${numEntries}entry" | ||||
|   val dataType = if (concatData) UInt(gen.getWidth.W) else gen | ||||
| 
 | ||||
|   val maxBankEntries = if (numEntries >= 2 * 64) 64 else 16 | ||||
|   val numBanks = (numEntries + maxBankEntries - 1) / maxBankEntries | ||||
|   def bankOffset(address: UInt): UInt = { | ||||
|     if (numBanks > 1) address(log2Ceil(maxBankEntries) - 1, 0) | ||||
|     else address | ||||
|   } | ||||
|   def bankIndex(address: UInt): UInt = { | ||||
|     if (numBanks > 1) address(log2Ceil(numEntries) - 1, log2Ceil(maxBankEntries)) | ||||
|     else 0.U | ||||
|   } | ||||
| 
 | ||||
|   // if use bypassEnable to control bypass of each port, | ||||
|   // then we should have a separate bit for each read port | ||||
|   perReadPortBypassEnable.map(en_vec => require(en_vec.length == numRead)) | ||||
| 
 | ||||
|   val dataBanks = Seq.tabulate(numBanks)(i => { | ||||
|     val bankEntries = if (i < numBanks - 1) maxBankEntries else numEntries - (i * maxBankEntries) | ||||
|     val dataBank = Module(new NegedgeDataModuleTemplate(dataType, bankEntries, numRead, numWrite, parentModule, perReadPortBypassEnable)) | ||||
| 
 | ||||
|     // delay one clock | ||||
|     val raddr_dup = RegNext(io.raddr) | ||||
|     val wen_dup = RegNext(io.wen) | ||||
|     val waddr_dup = io.wen.zip(io.waddr).map(w => RegEnable(w._2, w._1)) | ||||
| 
 | ||||
|     // input | ||||
|     dataBank.io.raddr := raddr_dup.map(bankOffset) | ||||
|     dataBank.io.wen := wen_dup.zip(waddr_dup).map{ case (en, addr) => en && bankIndex(addr) === i.U } | ||||
|     dataBank.io.waddr := waddr_dup.map(bankOffset) | ||||
|     if (concatData) { | ||||
|       val wdata_dup = io.wen.zip(io.wdata).map(w => RegEnable(w._2.asTypeOf(dataType), w._1)) | ||||
|       dataBank.io.wdata := wdata_dup | ||||
|     } | ||||
|     else { | ||||
|       dataBank.io.wdata := io.wen.zip(io.wdata).map(w => RegEnable(w._2, w._1)) | ||||
|     } | ||||
| 
 | ||||
|     dataBank | ||||
|   }) | ||||
| 
 | ||||
|   // output | ||||
|   val rdata = if (concatData) dataBanks.map(_.io.rdata.map(_.asTypeOf(gen))) else dataBanks.map(_.io.rdata) | ||||
|   for (j <- 0 until numRead) { | ||||
|     val raddr_dup = RegNext(io.raddr(j)) | ||||
|     val index_dec = UIntToOH(bankIndex(raddr_dup), numBanks) | ||||
|     io.rdata(j) := Mux1H(index_dec, rdata.map(_(j))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class NegedgeDataModuleTemplate[T <: Data]( | ||||
|   gen: T, | ||||
|   numEntries: Int, | ||||
|   numRead: Int, | ||||
|   numWrite: Int, | ||||
|   parentModule: String, | ||||
|   perReadPortBypassEnable: Option[Seq[Boolean]] = None | ||||
| ) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val raddr = Vec(numRead,  Input(UInt(log2Ceil(numEntries).W))) | ||||
|     val rdata = Vec(numRead,  Output(gen)) | ||||
|     val wen   = Vec(numWrite, Input(Bool())) | ||||
|     val waddr = Vec(numWrite, Input(UInt(log2Ceil(numEntries).W))) | ||||
|     val wdata = Vec(numWrite, Input(gen)) | ||||
|   }) | ||||
| 
 | ||||
|   override def desiredName: String = s"NegedgeDataModule_${parentModule}_${numEntries}entry" | ||||
|   val data = Reg(Vec(numEntries, gen)) | ||||
| 
 | ||||
|   // if use bypassEnable to control bypass of each port, | ||||
|   // then we should have a separate bit for each read port | ||||
|   perReadPortBypassEnable.map(en_vec => require(en_vec.length == numRead)) | ||||
|   // read ports | ||||
|   for (i <- 0 until numRead) { | ||||
|     val bypass_en = perReadPortBypassEnable.map(_(i)).getOrElse(true) | ||||
|     val read_by = io.wen.zip(io.waddr).map(w => w._1 && w._2 === io.raddr(i) && bypass_en.B) | ||||
|     val addr_dec = UIntToOH(io.raddr(i), numEntries) | ||||
|     when (VecInit(read_by).asUInt.orR) { | ||||
|       io.rdata(i) := Mux1H(read_by, io.wdata) | ||||
|     } .otherwise { | ||||
|       io.rdata(i) := Mux1H(addr_dec, data) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // write ports | ||||
|   val waddr_dec = io.waddr.map(a => UIntToOH(a)) | ||||
|   for (j <- 0 until numEntries) { | ||||
|     val write_wen = io.wen.zip(waddr_dec).map(w => w._1 && w._2(j)) | ||||
|     when (VecInit(write_wen).asUInt.orR) { | ||||
|       data(j) := Mux1H(write_wen, io.wdata) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class Folded1WDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, | ||||
|   isSync: Boolean, width: Int, hasResetEn: Boolean = true) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val raddr = Vec(numRead,  Input(UInt(log2Up(numEntries).W))) | ||||
|     val rdata = Vec(numRead,  Output(gen)) | ||||
|     val wen   = Input(Bool()) | ||||
|     val waddr = Input(UInt(log2Up(numEntries).W)) | ||||
|     val wdata = Input(gen) | ||||
|     val resetEn = if (hasResetEn) Some(Input(Bool())) else None | ||||
|   }) | ||||
| 
 | ||||
|   require(width > 0 && isPow2(width)) | ||||
|   require(numEntries % width == 0) | ||||
| 
 | ||||
|   val nRows = numEntries / width | ||||
| 
 | ||||
|   val data = Mem(nRows, Vec(width, gen)) | ||||
| 
 | ||||
|   val doing_reset = RegInit(true.B) | ||||
|   if (hasResetEn) { | ||||
|     io.resetEn.map(en => when (en) { doing_reset := true.B }) | ||||
|   } | ||||
|   val resetRow = RegInit(0.U(log2Ceil(nRows).W)) | ||||
|   resetRow := resetRow + doing_reset | ||||
|   when (resetRow === (nRows-1).U) { doing_reset := false.B } | ||||
| 
 | ||||
|   val raddr = if (isSync) RegNext(io.raddr) else io.raddr | ||||
| 
 | ||||
|   for (i <- 0 until numRead) { | ||||
|     val addr = raddr(i) >> log2Ceil(width) | ||||
|     val idx = raddr(i)(log2Ceil(width)-1, 0) | ||||
|     io.rdata(i) := Mux(doing_reset, 0.U.asTypeOf(gen), data(addr)(idx)) | ||||
|   } | ||||
| 
 | ||||
|   val waddr = io.waddr >> log2Ceil(width) | ||||
|   val wmask = UIntToOH(io.waddr(log2Ceil(width)-1, 0)) | ||||
|   val wdata = VecInit(Seq.fill(width)(io.wdata)) | ||||
| 
 | ||||
|   when(doing_reset) { | ||||
|     data.write(resetRow, 0.U.asTypeOf(Vec(width, gen))) | ||||
|   }.elsewhen(io.wen) { | ||||
|     data.write(waddr, wdata, wmask.asBools) | ||||
|   } | ||||
| } | ||||
|  | @ -1,230 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| // See LICENSE.Berkeley for license details. | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import chisel3.util.random.LFSR | ||||
| 
 | ||||
| abstract class Decoding | ||||
| { | ||||
|   def uncorrected: UInt | ||||
|   def corrected: UInt | ||||
|   def correctable: Bool | ||||
|   def uncorrectable: Bool // If true, correctable should be ignored | ||||
|   def error = correctable || uncorrectable | ||||
| } | ||||
| 
 | ||||
| abstract class Code | ||||
| { | ||||
|   def canDetect: Boolean | ||||
|   def canCorrect: Boolean | ||||
| 
 | ||||
|   def width(w0: Int): Int | ||||
| 
 | ||||
|   /** Encode x to a codeword suitable for decode. | ||||
|    *  If poison is true, the decoded value will report uncorrectable | ||||
|    *  error despite uncorrected == corrected == x. | ||||
|    */ | ||||
|   def encode(x: UInt, poison: Bool = false.B): UInt | ||||
|   def decode(x: UInt): Decoding | ||||
| 
 | ||||
|   /** Copy the bits in x to the right bit positions in an encoded word, | ||||
|    *  so that x === decode(swizzle(x)).uncorrected; but don't generate | ||||
|    *  the other code bits, so decode(swizzle(x)).error might be true. | ||||
|    *  For codes for which this operation is not trivial, throw an | ||||
|    *  UnsupportedOperationException.  */ | ||||
|   def swizzle(x: UInt): UInt | ||||
| } | ||||
| 
 | ||||
| class IdentityCode extends Code | ||||
| { | ||||
|   def canDetect = false | ||||
|   def canCorrect = false | ||||
| 
 | ||||
|   def width(w0: Int) = w0 | ||||
|   def encode(x: UInt, poison: Bool = false.B) = { | ||||
|     require (poison.isLit && poison.litValue == 0, "IdentityCode can not be poisoned") | ||||
|     x | ||||
|   } | ||||
|   def swizzle(x: UInt) = x | ||||
|   def decode(y: UInt) = new Decoding { | ||||
|     def uncorrected = y | ||||
|     def corrected = y | ||||
|     def correctable = false.B | ||||
|     def uncorrectable = false.B | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ParityCode extends Code | ||||
| { | ||||
|   def canDetect = true | ||||
|   def canCorrect = false | ||||
| 
 | ||||
|   def width(w0: Int) = w0+1 | ||||
|   def encode(x: UInt, poison: Bool = false.B) = Cat(x.xorR ^ poison, x) | ||||
|   def swizzle(x: UInt) = Cat(false.B, x) | ||||
|   def decode(y: UInt) = new Decoding { | ||||
|     val uncorrected = y(y.getWidth-2,0) | ||||
|     val corrected = uncorrected | ||||
|     val correctable = false.B | ||||
|     val uncorrectable = y.xorR | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SECCode extends Code | ||||
| { | ||||
|   def canDetect = true | ||||
|   def canCorrect = true | ||||
| 
 | ||||
|   // SEC codes may or may not be poisonous depending on the length | ||||
|   // If the code is perfect, every non-codeword is correctable | ||||
|   def poisonous(n: Int) = !isPow2(n+1) | ||||
| 
 | ||||
|   def width(k: Int) = { | ||||
|     val m = log2Floor(k) + 1 | ||||
|     k + m + (if((1 << m) < m+k+1) 1 else 0) | ||||
|   } | ||||
|   def swizzle(x: UInt) = { | ||||
|     val k = x.getWidth | ||||
|     val n = width(k) | ||||
|     Cat(0.U((n-k).W), x) | ||||
|   } | ||||
| 
 | ||||
|   // An (n=16, k=11) Hamming code is naturally encoded as: | ||||
|   //   PPxPxxxPxxxxxxxP where P are parity bits and x are data | ||||
|   //   Indexes typically start at 1, because then the P are on powers of two | ||||
|   // In systematic coding, you put all the data in the front: | ||||
|   //   xxxxxxxxxxxPPPPP | ||||
|   //   Indexes typically start at 0, because Computer Science | ||||
|   // For sanity when reading SRAMs, you want systematic form. | ||||
| 
 | ||||
|   private def impl(n: Int, k: Int) = { | ||||
|     require (n >= 3 && k >= 1 && !isPow2(n)) | ||||
|     val hamm2sys = IndexedSeq.tabulate(n+1) { i => | ||||
|       if (i == 0) { | ||||
|         n /* undefined */ | ||||
|       } else if (isPow2(i)) { | ||||
|         k + log2Ceil(i) | ||||
|       } else { | ||||
|         i - 1 - log2Ceil(i) | ||||
|       } | ||||
|     } | ||||
|     val sys2hamm = hamm2sys.zipWithIndex.sortBy(_._1).map(_._2).toIndexedSeq | ||||
|     def syndrome(j: Int) = { | ||||
|       val bit = 1 << j | ||||
|       ("b" + Seq.tabulate(n) { i => | ||||
|         if ((sys2hamm(i) & bit) != 0) "1" else "0" | ||||
|       }.reverse.mkString).U | ||||
|     } | ||||
|     (hamm2sys, sys2hamm, syndrome _) | ||||
|   } | ||||
| 
 | ||||
|   def encode(x: UInt, poison: Bool = false.B) = { | ||||
|     val k = x.getWidth | ||||
|     val n = width(k) | ||||
|     val (_, _, syndrome) = impl(n, k) | ||||
| 
 | ||||
|     require ((poison.isLit && poison.litValue == 0) || poisonous(n), s"SEC code of length ${n} cannot be poisoned") | ||||
| 
 | ||||
|     /* By setting the entire syndrome on poison, the corrected bit falls off the end of the code */ | ||||
|     val syndromeUInt = VecInit.tabulate(n-k) { j => (syndrome(j)(k-1, 0) & x).xorR ^ poison }.asUInt | ||||
|     Cat(syndromeUInt, x) | ||||
|   } | ||||
| 
 | ||||
|   def decode(y: UInt) = new Decoding { | ||||
|     val n = y.getWidth | ||||
|     val k = n - log2Ceil(n) | ||||
|     val (_, sys2hamm, syndrome) = impl(n, k) | ||||
| 
 | ||||
|     val syndromeUInt = VecInit.tabulate(n-k) { j => (syndrome(j) & y).xorR }.asUInt | ||||
| 
 | ||||
|     val hammBadBitOH = UIntToOH(syndromeUInt, n+1) | ||||
|     val sysBadBitOH = VecInit.tabulate(k) { i => hammBadBitOH(sys2hamm(i)) }.asUInt | ||||
| 
 | ||||
|     val uncorrected = y(k-1, 0) | ||||
|     val corrected = uncorrected ^ sysBadBitOH | ||||
|     val correctable = syndromeUInt.orR | ||||
|     val uncorrectable = if (poisonous(n)) { syndromeUInt > n.U } else { false.B } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SECDEDCode extends Code | ||||
| { | ||||
|   def canDetect = true | ||||
|   def canCorrect = true | ||||
| 
 | ||||
|   private val sec = new SECCode | ||||
|   private val par = new ParityCode | ||||
| 
 | ||||
|   def width(k: Int) = sec.width(k)+1 | ||||
|   def encode(x: UInt, poison: Bool = false.B) = { | ||||
|     // toggling two bits ensures the error is uncorrectable | ||||
|     // to ensure corrected == uncorrected, we pick one redundant | ||||
|     // bit from SEC (the highest); correcting it does not affect | ||||
|     // corrected == uncorrected. the second toggled bit is the | ||||
|     // parity bit, which also does not appear in the decoding | ||||
|     val toggle_lo = Cat(poison.asUInt, poison.asUInt) | ||||
|     val toggle_hi = toggle_lo << (sec.width(x.getWidth)-1) | ||||
|     par.encode(sec.encode(x)) ^ toggle_hi | ||||
|   } | ||||
|   def swizzle(x: UInt) = par.swizzle(sec.swizzle(x)) | ||||
|   def decode(x: UInt) = new Decoding { | ||||
|     val secdec = sec.decode(x(x.getWidth-2,0)) | ||||
|     val pardec = par.decode(x) | ||||
| 
 | ||||
|     val uncorrected = secdec.uncorrected | ||||
|     val corrected = secdec.corrected | ||||
|     val correctable = pardec.uncorrectable | ||||
|     val uncorrectable = !pardec.uncorrectable && secdec.correctable | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ErrGen | ||||
| { | ||||
|   // generate a 1-bit error with approximate probability 2^-f | ||||
|   def apply(width: Int, f: Int): UInt = { | ||||
|     require(width > 0 && f >= 0 && log2Up(width) + f <= 16) | ||||
|     UIntToOH(LFSR(16)(log2Up(width)+f-1,0))(width-1,0) | ||||
|   } | ||||
|   def apply(x: UInt, f: Int): UInt = x ^ apply(x.getWidth, f) | ||||
| } | ||||
| 
 | ||||
| trait CanHaveErrors extends Bundle { | ||||
|   val correctable: Option[ValidIO[UInt]] | ||||
|   val uncorrectable: Option[ValidIO[UInt]] | ||||
| } | ||||
| 
 | ||||
| case class ECCParams( | ||||
|   bytes: Int = 1, | ||||
|   code: Code = new IdentityCode, | ||||
|   notifyErrors: Boolean = false | ||||
| ) | ||||
| 
 | ||||
| object Code { | ||||
|   def fromString(s: Option[String]): Code = fromString(s.getOrElse("none")) | ||||
|   def fromString(s: String): Code = s.toLowerCase match { | ||||
|     case "none" => new IdentityCode | ||||
|     case "identity" => new IdentityCode | ||||
|     case "parity" => new ParityCode | ||||
|     case "sec" => new SECCode | ||||
|     case "secded" => new SECDEDCode | ||||
|     case _ => throw new IllegalArgumentException("Unknown ECC type") | ||||
|   } | ||||
| } | ||||
|  | @ -1,115 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package chisel3 | ||||
| 
 | ||||
| import chisel3.internal.NamedComponent | ||||
| import chisel3.util.experimental.BoringUtils | ||||
| import scala.collection.mutable | ||||
| 
 | ||||
| object ExcitingUtils { | ||||
| 
 | ||||
|   object ConnectionType extends Enumeration { | ||||
|     val Perf = Value("perf") | ||||
|     val Func = Value("func") | ||||
|     val Debug = Value("debug") | ||||
|   } | ||||
| 
 | ||||
|   type ConnectionType = ConnectionType.Value | ||||
|   val Perf = ConnectionType.Perf | ||||
|   val Func = ConnectionType.Func | ||||
|   val Debug = ConnectionType.Debug | ||||
| 
 | ||||
|   private def strToErrorMsg(str: String) = "\u001b[1m\u001b[;31m"+ str +"\u001b[0m" | ||||
| 
 | ||||
|   private class Connection | ||||
|   ( | ||||
|     var connType: ConnectionType, | ||||
|     var sourceModule: Option[String] = None, | ||||
|     var sinkModule: Option[String] = None, | ||||
|     var warned: Boolean = false | ||||
|   ){ | ||||
| 
 | ||||
|     override def toString: String = | ||||
|       s"type:[$connType] source location:[${sourceModule.getOrElse(strToErrorMsg("Not Found"))}]" + | ||||
|         s" sink location:[${sinkModule.getOrElse(strToErrorMsg("Not Found"))}]" | ||||
| 
 | ||||
|     def isLegalConnection: Boolean = sourceModule.nonEmpty && sinkModule.nonEmpty | ||||
|   } | ||||
| 
 | ||||
|   private val map = mutable.LinkedHashMap[String, Connection]() | ||||
| 
 | ||||
|   def addSource | ||||
|   ( | ||||
|     component: NamedComponent, | ||||
|     name: String, | ||||
|     connType: ConnectionType = Func, | ||||
|     disableDedup: Boolean = false, | ||||
|     uniqueName: Boolean = false | ||||
|   ): String = { | ||||
|     val conn = map.getOrElseUpdate(name, new Connection(connType)) | ||||
|     if (!conn.sourceModule.isEmpty && !conn.warned) { | ||||
|       println(s"[WARN] Signal |$name| has multiple sources") | ||||
|       conn.warned = true | ||||
|     } | ||||
|     require(conn.connType == connType) | ||||
|     conn.sourceModule = Some(component.parentModName) | ||||
|     BoringUtils.addSource(component, name, disableDedup, uniqueName) | ||||
|   } | ||||
| 
 | ||||
|   def addSink | ||||
|   ( | ||||
|     component: InstanceId, | ||||
|     name: String, | ||||
|     connType: ConnectionType = Func, | ||||
|     disableDedup: Boolean = false, | ||||
|     forceExists: Boolean = false | ||||
|   ): Unit = { | ||||
|     val conn = map.getOrElseUpdate(name, new Connection(connType)) | ||||
|     if (!conn.sinkModule.isEmpty && !conn.warned) { | ||||
|       println(s"[WARN] Signal |$name| has multiple sinks") | ||||
|       conn.warned = true | ||||
|     } | ||||
|     require(conn.connType == connType) | ||||
|     conn.sinkModule = Some(component.parentModName) | ||||
|     BoringUtils.addSink(component, name, disableDedup, forceExists) | ||||
|   } | ||||
| 
 | ||||
|   def fixConnections(): Unit ={ | ||||
|     val dontCare = WireInit(0.U) | ||||
|     for((name, conn) <- map){ | ||||
|       if(conn.sinkModule.isEmpty){ | ||||
|         addSink(dontCare, name, conn.connType) | ||||
|       } | ||||
|       if(conn.sourceModule.isEmpty){ | ||||
|         addSource(dontCare, name, conn.connType) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   def checkAndDisplay(): Unit = { | ||||
|     var legal = true | ||||
|     val buf = new mutable.StringBuilder() | ||||
|     for((id, conn) <- map){ | ||||
|       buf ++= s"Connection:[$id] $conn\n" | ||||
|       if(!conn.isLegalConnection) legal = false | ||||
|     } | ||||
|     print(buf) | ||||
|     require(legal, strToErrorMsg("Error: Illegal connection found!")) | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,232 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| /* | ||||
|     https://github.com/Lingrui98/scalaTage/blob/vme/src/main/scala/getVerilogModules.scala | ||||
|  */ | ||||
| 
 | ||||
| import scala.io.Source | ||||
| import java.io._ | ||||
| import scala.language.postfixOps | ||||
| import sys.process._ | ||||
| import sys._ | ||||
| 
 | ||||
| class VerilogModuleExtractor { | ||||
|   //                            name | ||||
|   val modulePattern = "module ([\\w]+)\\(".r.unanchored | ||||
|   //                       type      name | ||||
|   val subMoudlePattern = "([\\w]+) ([\\w]+) \\((?: //.*)*\\Z".r.unanchored | ||||
|   val endMoudleIOPattern = "\\);".r.unanchored | ||||
|   val endMoudlePattern = "endmodule".r.unanchored | ||||
| 
 | ||||
|   //                           (submoudle type, submoudle name) | ||||
|   type SubMoudleRecord = Tuple2[String, String] | ||||
| 
 | ||||
|   //                        (content,          submodules) | ||||
|   type ModuleRecord = Tuple2[List[String], List[SubMoudleRecord]] | ||||
|   //                   name | ||||
|   type ModuleMap = Map[String, ModuleRecord] | ||||
| 
 | ||||
|   def getLines(s: scala.io.BufferedSource): Iterator[String] = s.getLines() | ||||
| 
 | ||||
|   def makeRecord(s: Iterator[String]): ModuleMap = { | ||||
|     val m: ModuleMap = Map() | ||||
|     // called before we see the first line of a module | ||||
|     def processModule(firstLine: String, it: Iterator[String]): ModuleRecord = { | ||||
|       val content: List[String] = List(firstLine) | ||||
|       val submodules: List[SubMoudleRecord] = List() | ||||
|       def iter(cont: List[String], subm: List[SubMoudleRecord]): ModuleRecord = | ||||
|         it.next() match { | ||||
|           case l: String => l match { | ||||
|             case endMoudlePattern() => (l :: cont, subm) | ||||
|             case subMoudlePattern(ty, name) => | ||||
|               // println(s"submoudle $ty $name") | ||||
|               iter(l :: cont, (ty, name) :: subm) | ||||
|             case _ => iter(l :: cont, subm) | ||||
|           } | ||||
|           case _ => println("Should not reach here"); (cont, subm) | ||||
|         } | ||||
|       val temp = iter(content, submodules) | ||||
|       (temp._1.reverse, temp._2) | ||||
|     } | ||||
|     def traverse(m: ModuleMap, it: Iterator[String]): ModuleMap = | ||||
|       if (it.hasNext) { | ||||
|         it.next() match { | ||||
|           case l: String => | ||||
|             // println(f"traversing $l") | ||||
|             l match { | ||||
|               case modulePattern(name) => | ||||
|                 // println(f"get Module of name $name") | ||||
|                 traverse(m ++ Map(name -> processModule(l, it)), it) | ||||
|               case _ => | ||||
|                 println(f"line $l is not a module definition") | ||||
|                 traverse(m, it) | ||||
|             } | ||||
|           case _ => traverse(m, it) | ||||
|         } | ||||
|       } | ||||
|       else m | ||||
| 
 | ||||
|     traverse(m, s) | ||||
|   } | ||||
| 
 | ||||
|   def makeRecordFromFile(file: String): ModuleMap = { | ||||
|     val bufSrc = Source.fromFile(file) | ||||
|     makeRecord(bufSrc.getLines()) | ||||
|   } | ||||
| 
 | ||||
|   def writeModuleToFile(name: String, record: ModuleRecord, dir: String) = { | ||||
|     val path = dir+name+".v" | ||||
|     val writer = new PrintWriter(new File(path)) | ||||
|     println(f"Writing module $name%20s to $path") | ||||
|     record._1.foreach(r => { | ||||
|       writer.write(f"$r\n") | ||||
|     }) | ||||
|     writer.close() | ||||
|   } | ||||
| 
 | ||||
|   // get moudle definition of specified name | ||||
|   def getModule(name: String, m: ModuleMap): ModuleRecord = { | ||||
|     m(name) | ||||
|   } | ||||
| 
 | ||||
|   def showModuleRecord(r: ModuleRecord) = { | ||||
|     val (content, submodules) = r | ||||
|     submodules.foreach { | ||||
|       case (t, n) => println(f"submoudle type: $t, submodule name: $n") | ||||
|     } | ||||
|     println("\nprinting module contents...") | ||||
|     content.foreach(println(_)) | ||||
|   } | ||||
| 
 | ||||
|   // We first get records of all the modules and its submodule record | ||||
|   // Then we choose a module as the root node to traverse its submodule | ||||
|   def processFromModule(name: String, map: ModuleMap, outPath: String, doneSet: Set[String] = Set(), top: Tuple2[String, Boolean]): Unit = { | ||||
|     def printSRAMs(sub: List[SubMoudleRecord]) = { | ||||
|       sub map { | ||||
|         case (ty, subn) if (ty contains "SRAM") => println(s"top module $name, sub module type $ty, name $subn") | ||||
|         case _ => | ||||
|       } | ||||
|     } | ||||
|     val (topName, isTop) = top | ||||
|     if (!map.contains(name)) { | ||||
|       println(s"${if (isTop) "chosen top" else s"submodule of ${topName},"} module $name does not exist!") | ||||
|       return | ||||
|     } | ||||
|     if (isTop) println(s"\nProcessing top module $name") | ||||
|     val r = map(name) | ||||
|     new File(outPath).mkdirs() // ensure the path exists | ||||
|     writeModuleToFile(name, r, outPath) | ||||
|     val submodules = r._2 | ||||
|     // printSRAMs(submodules) | ||||
|     // DFS | ||||
|     val subTypesSet = submodules map (m => m._1) toSet | ||||
|     val nowMap = map - name | ||||
|     val nowSet = doneSet ++ subTypesSet | ||||
|     subTypesSet.foreach { s  => if (!doneSet.contains(s)) processFromModule(s, nowMap, outPath, nowSet, (if (isTop) name else topName, false)) } | ||||
|   } | ||||
| 
 | ||||
|   def getDate: String = { | ||||
|     val d = java.time.LocalDate.now | ||||
|     d.toString.toCharArray.filterNot(_ == '-').mkString | ||||
|   } | ||||
| 
 | ||||
|   def makePath(topModule: String, outDir: String , user: String = "glr"): String = { | ||||
|     (if (outDir.last == '/') | ||||
|       outDir | ||||
|     else | ||||
|       outDir+"/") + getDate + "-" + user + "-" + topModule + "/" | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   def extract(src: String, topModule: String, outDir: String, user: String, mapp: Option[ModuleMap]): Unit = { | ||||
|     val useMap = mapp.getOrElse(makeRecordFromFile(src)) | ||||
|     val path = makePath(topModule, outDir, user) | ||||
|     processFromModule(topModule, useMap, path, top=(topModule, true)) | ||||
|   } | ||||
| 
 | ||||
|   def extract(src: String, topModules: List[String], outDir: String, user: String): Unit = { | ||||
|     // avoid repeat | ||||
|     val mapp = makeRecordFromFile(src) | ||||
|     topModules.foreach(n => extract(src, n, outDir, user, Some(mapp))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| trait VMEArgParser { | ||||
|   type OptionMap = Map[String, Option[Any]] | ||||
| 
 | ||||
|   val usage = """ | ||||
|         Usage: sbt "run [OPTION...]" | ||||
|             -s, --source   the verilog file generated by chisel, all in one file | ||||
|                            default: $NOOP_HOME/build/XSSimTop.v | ||||
|             -h, --help     print this help info | ||||
|             -o, --output   the place you want to store your extracted verilog | ||||
|                            default: $NOOP_HOME/build/extracted | ||||
|             -u, --usr      your name, will be used to name the output folder | ||||
|                            default: current user | ||||
|             -m, --modules  the top modules you would like to extract verilog from | ||||
|                            should always be the last argument | ||||
|                            default: IFU | ||||
|       """ | ||||
| 
 | ||||
|   def parse(args: List[String]) = { | ||||
|     def nextOption(map: OptionMap, l: List[String]): OptionMap = { | ||||
|       def isSwitch(s : String)= (s(0) == '-') | ||||
|       l match { | ||||
|         case Nil => map | ||||
|         case ("--help" | "-h") :: tail => { | ||||
|           println(usage) | ||||
|           sys.exit() | ||||
|           map | ||||
|         } | ||||
|         case ("--source" | "-s") :: file :: tail => | ||||
|           nextOption(map ++ Map("source" -> Some(file)), tail) | ||||
|         case ("--output" | "-o") :: path :: tail => | ||||
|           nextOption(map ++ Map("output" -> Some(path)), tail) | ||||
|         case ("--usr" | "-u") :: name :: tail => | ||||
|           nextOption(map ++ Map("usr" -> Some(name)), tail) | ||||
|         // this should always be the last argument, since it is length variable | ||||
|         case ("--modules" | "-m") :: m :: tail => | ||||
|           map ++ Map("modules" -> Some(m :: tail)) | ||||
|         case s :: tail => { | ||||
|           if (isSwitch(s)) println(s"unexpected argument $s") | ||||
|           nextOption(map, tail) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     nextOption(Map("source" -> None, "output" -> None, "usr" -> None, "modules" -> None), args) | ||||
|   } | ||||
| 
 | ||||
|   def wrapParams(args: Array[String]): (String, List[String], String, String) = { | ||||
|     val argL = args.toList | ||||
|     val paramMap = parse(argL) | ||||
|     (paramMap("source").map(_.asInstanceOf[String]).getOrElse(env("NOOP_HOME")+"/build/XSSimTop.v"), | ||||
|       paramMap("modules").map(_.asInstanceOf[List[String]]).getOrElse(List("IFU")), | ||||
|       paramMap("output").map(_.asInstanceOf[String]).getOrElse(env("NOOP_HOME")+"/build/extracted/"), | ||||
|       paramMap("usr").map(_.asInstanceOf[String]).getOrElse("whoami".!!.init)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ExtractVerilogModules extends VMEArgParser { | ||||
|   def main(args: Array[String]): Unit = { | ||||
|     val vme = new VerilogModuleExtractor() | ||||
|     val (sourceFile, topModules, outTopDir, usr) = wrapParams(args) | ||||
|     vme.extract(sourceFile, topModules, outTopDir, usr) | ||||
|   } | ||||
| } | ||||
|  | @ -1,27 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| 
 | ||||
| object GTimer { | ||||
|   def apply() = { | ||||
|     val c = RegInit(0.U(64.W)) | ||||
|     c := c + 1.U | ||||
|     c | ||||
|   } | ||||
| } | ||||
|  | @ -1,98 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| object HoldUnless { | ||||
|   def apply[T <: Data](x: T, en: Bool): T = Mux(en, x, RegEnable(x, 0.U.asTypeOf(x), en)) | ||||
| } | ||||
| 
 | ||||
| object ReadAndHold { | ||||
|   def apply[T <: Data](x: Mem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr), en) | ||||
|   def apply[T <: Data](x: SyncReadMem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr, en), RegNext(en)) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Hold the in fire unless out fire or flush happens | ||||
|  * similar to BoolStopWatch | ||||
|  */ | ||||
| object ValidHold { | ||||
|   def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = { | ||||
|     val valid = RegInit(false.B) | ||||
|     when (outfire) { valid := false.B } | ||||
|     when (infire) { valid := true.B } | ||||
|     when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok? | ||||
|     valid | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
|  * Hold the 'fire' for only one cycle unless new fire comes in | ||||
|  */ | ||||
| object OneCycleValid { | ||||
|   def apply(fire: Bool, flush: Bool = false.B) = { | ||||
|     val valid = RegInit(false.B) | ||||
|     when (valid) { valid := false.B } | ||||
|     when (fire) { valid := true.B } | ||||
|     when (flush) { valid := false.B } | ||||
|     valid | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Hold the data when it is valid and bypass latest data | ||||
|  */ | ||||
| object DataHoldBypass { | ||||
|   def apply[T <: Data](data: T, valid: Bool): T = { | ||||
|     Mux(valid, data, RegEnable(data, valid)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * Data change or not | ||||
|  */ | ||||
| object DataChanged { | ||||
|   def apply(data: UInt): UInt = { | ||||
|     data =/= RegNext(data) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|   * Delay the data for N cycles | ||||
|   */ | ||||
| class DelayN[T <: Data](gen: T, n: Int) extends Module { | ||||
|   val io = IO(new Bundle() { | ||||
|     val in = Input(gen) | ||||
|     val out = Output(gen) | ||||
|   }) | ||||
|   var out = io.in | ||||
|   for (i <- 0 until n) { | ||||
|     out = RegNext(out) | ||||
|   } | ||||
|   io.out := out | ||||
| } | ||||
| 
 | ||||
| object DelayN { | ||||
|   def apply[T <: Data](in: T, n: Int): T = { | ||||
|     val delay = Module(new DelayN(in.cloneType, n)) | ||||
|     delay.io.in := in | ||||
|     delay.io.out | ||||
|   } | ||||
| } | ||||
|  | @ -1,25 +0,0 @@ | |||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import freechips.rocketchip.interrupts.IntAdapterNode | ||||
| 
 | ||||
| class IntBuffer(implicit p: Parameters) extends LazyModule { | ||||
| 
 | ||||
|   val node = IntAdapterNode() | ||||
| 
 | ||||
|   lazy val module = new LazyModuleImp(this){ | ||||
|     for(((in, edgeIn), (out, edgeOut)) <- node.in.zip(node.out)){ | ||||
|       out := RegNext(in, 0.U.asTypeOf(in)) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| object IntBuffer { | ||||
|   def apply()(implicit p: Parameters) = { | ||||
|     val intBuffer = LazyModule(new IntBuffer) | ||||
|     intBuffer.node | ||||
|   } | ||||
| } | ||||
|  | @ -1,32 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| object LFSR64 { | ||||
|   def apply(increment: Bool = true.B): UInt = { | ||||
|     val wide = 64 | ||||
|     val lfsr = RegInit(0x1234567887654321L.U(wide.W)) // random initial value based on simulation seed | ||||
|     val xor = lfsr(0) ^ lfsr(1) ^ lfsr(3) ^ lfsr(4) | ||||
|     when (increment) { | ||||
|       lfsr := Mux(lfsr === 0.U, 1.U, Cat(xor, lfsr(wide-1,1))) | ||||
|     } | ||||
|     lfsr | ||||
|   } | ||||
| } | ||||
|  | @ -1,41 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| // See LICENSE.Berkeley for license details. | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import Chisel._ | ||||
| 
 | ||||
| class LatencyPipe[T <: Data](typ: T, latency: Int) extends Module { | ||||
|   val io = new Bundle { | ||||
|     val in = Decoupled(typ).flip | ||||
|     val out = Decoupled(typ) | ||||
|   } | ||||
| 
 | ||||
|   def doN[T](n: Int, func: T => T, in: T): T = | ||||
|     (0 until n).foldLeft(in)((last, _) => func(last)) | ||||
| 
 | ||||
|   io.out <> doN(latency, (last: DecoupledIO[T]) => Queue(last, 1, pipe=true), io.in) | ||||
| } | ||||
| 
 | ||||
| object LatencyPipe { | ||||
|   def apply[T <: Data](in: DecoupledIO[T], latency: Int): DecoupledIO[T] = { | ||||
|     val pipe = Module(new LatencyPipe(in.bits, latency)) | ||||
|     pipe.io.in <> in | ||||
|     pipe.io.out | ||||
|   } | ||||
| } | ||||
|  | @ -20,6 +20,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import xiangshan.DebugOptionsKey | ||||
| import utils.XSLogLevel.XSLogLevel | ||||
| import utility.GTimer | ||||
| 
 | ||||
| object XSLogLevel extends Enumeration { | ||||
|   type XSLogLevel = Value | ||||
|  |  | |||
|  | @ -1,67 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| object LookupTree { | ||||
|   def apply[T <: Data](key: UInt, mapping: Iterable[(UInt, T)]): T = | ||||
|     Mux1H(mapping.map(p => (p._1 === key, p._2))) | ||||
| } | ||||
| 
 | ||||
| object LookupTreeDefault { | ||||
|   def apply[T <: Data](key: UInt, default: T, mapping: Iterable[(UInt, T)]): T = | ||||
|     MuxLookup(key, default, mapping.toSeq) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| object MuxT { | ||||
|   def apply[T <: Data, U <: Data](cond: Bool, con: (T, U), alt: (T, U)): (T, U) = | ||||
|     (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2)) | ||||
| 
 | ||||
|   def apply[T <: Data, U <: Data, W <: Data](cond: Bool, con: (T, U, W), alt: (T, U, W)): (T, U, W) = | ||||
|     (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2), Mux(cond, con._3, alt._3)) | ||||
| 
 | ||||
|   def apply[T <: Data, U <: Data, W <: Data, X <: Data](cond: Bool, con: (T, U, W, X), alt: (T, U, W, X)): (T, U, W, X) = | ||||
|     (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2), Mux(cond, con._3, alt._3), Mux(cond, con._4, alt._4)) | ||||
| } | ||||
| 
 | ||||
| /** Creates a cascade of n MuxTs to search for a key value. */ | ||||
| object MuxTLookup { | ||||
|   def apply[S <: UInt, T <: Data, U <: Data](key: S, default: (T, U), mapping: Seq[(S, (T, U))]): (T, U) = { | ||||
|     var res = default | ||||
|     for ((k, v) <- mapping.reverse) | ||||
|       res = MuxT(k === key, v, res) | ||||
|     res | ||||
|   } | ||||
| 
 | ||||
|   def apply[S <: UInt, T <: Data, U <: Data, W <: Data](key: S, default: (T, U, W), mapping: Seq[(S, (T, U, W))]): (T, U, W) = { | ||||
|     var res = default | ||||
|     for ((k, v) <- mapping.reverse) | ||||
|       res = MuxT(k === key, v, res) | ||||
|     res | ||||
|   } | ||||
| 
 | ||||
|   // in case you really need to search for a 4-tuple | ||||
|   def apply[S <: UInt, T <: Data, U <: Data, W <: Data, X <: Data](key: S, default: (T, U, W, X), mapping: Seq[(S, (T, U, W, X))]): (T, U, W, X) = { | ||||
|     var res = default | ||||
|     for ((k, v) <- mapping.reverse) | ||||
|       res = MuxT(k === key, v, res) | ||||
|     res | ||||
|   } | ||||
| } | ||||
|  | @ -1,172 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.experimental.{DataMirror, requireIsChiselType} | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class IndexableMem[T <: Data] | ||||
| ( | ||||
|   entries: Int, | ||||
|   gen: T, | ||||
|   mem: Boolean, | ||||
|   init: Option[Seq[T]] | ||||
| ){ | ||||
|   require(!(init.nonEmpty && init.get.size!=entries)) | ||||
|   val ram = Mem(entries, gen) | ||||
|   val vec = Reg(Vec(entries, gen)) | ||||
|   val initializedVec = if(init.nonEmpty) RegInit(VecInit(init.get)) else null | ||||
|   def apply(idx: UInt): T = { | ||||
|     if(mem) ram(idx) | ||||
|     else if(init.nonEmpty) initializedVec(idx) | ||||
|     else vec(idx) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object IndexableMem { | ||||
|   def apply[T <: Data] | ||||
|   ( | ||||
|     entries: Int, | ||||
|     gen: T, | ||||
|     mem: Boolean = false, | ||||
|     init: Option[Seq[T]] = None | ||||
|   ): IndexableMem[T] = { | ||||
|     new IndexableMem[T](entries, gen, mem, init) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class MIMOQueueIO[T <: Data](gen: T, entries: Int, inCnt: Int, outCnt: Int) extends Bundle | ||||
| { | ||||
|   val flush = Input(Bool()) | ||||
|   val enq = Vec(inCnt, Flipped(DecoupledIO(gen))) | ||||
|   val deq = Vec(outCnt, DecoupledIO(gen)) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class MIMOQueue[T <: Data] | ||||
| ( | ||||
|   gen: T, | ||||
|   val entries: Int, | ||||
|   val inCnt: Int, | ||||
|   val outCnt: Int, | ||||
|   mem: Boolean = false, | ||||
|   perf: Boolean = false, | ||||
|   init: Option[Seq[T]] = None | ||||
| ) extends Module { | ||||
| 
 | ||||
|   require(isPow2(entries), "MIMOQueue: entries must be a power of 2!") | ||||
|   require(!(init.nonEmpty && mem), "MIMOQueue: Mem can't be init!") | ||||
|   require(!(init.nonEmpty && init.get.size!=entries)) | ||||
| 
 | ||||
|   def ptr_width = log2Up(entries) | ||||
| 
 | ||||
|   val io = IO(new MIMOQueueIO[T](gen, entries, inCnt, outCnt)) | ||||
| 
 | ||||
|   val genType = if (compileOptions.declaredTypeMustBeUnbound) { | ||||
|     requireIsChiselType(gen) | ||||
|     gen | ||||
|   } else { | ||||
|     if (DataMirror.internal.isSynthesizable(gen)) { | ||||
|       chiselTypeOf(gen) | ||||
|     } else { | ||||
|       gen | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   val ram = IndexableMem(entries, genType, mem, init) | ||||
| 
 | ||||
|   val valids = if(perf){ | ||||
|     RegInit(VecInit((0 until entries).map(_ => if(init.nonEmpty) true.B else false.B))) | ||||
|   } else null | ||||
| 
 | ||||
|   val enqPtrInitVal = 0.U((ptr_width+1).W) | ||||
|   val deqPtrInitVal = (if(init.nonEmpty) 1<<ptr_width else 0).U((ptr_width+1).W) | ||||
| 
 | ||||
|   val enq_ptr = RegInit(enqPtrInitVal) | ||||
|   val deq_ptr = RegInit(deqPtrInitVal) | ||||
| 
 | ||||
|   def ptrToIdx(ptr: UInt): UInt = ptr.tail(1) | ||||
|   def isFull(ptr1: UInt, ptr2: UInt): Bool = (ptr1.head(1)=/=ptr2.head(1)) && (ptr1.tail(1) === ptr2.tail(1)) | ||||
|   def isEmpty(ptr1: UInt, ptr2: UInt): Bool = ptr1 === ptr2 | ||||
| 
 | ||||
| 
 | ||||
|   def genPtrs(init: UInt, vec: Vec[DecoupledIO[T]]) = { | ||||
|     if(perf){ | ||||
|       vec.indices.map(i => { | ||||
|         init + PopCount(vec.take(i).map(_.fire())) | ||||
|       }) | ||||
|     } else { | ||||
|       val ptrs = vec.map(_ => Wire(UInt((ptr_width+1).W))) | ||||
|       for(i <- vec.indices){ | ||||
|         ptrs(i) := {if(i==0) init else ptrs(i-1) + vec(i-1).fire()} | ||||
|       } | ||||
|       ptrs | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // dequeue | ||||
|   val deq_ptrs = genPtrs(deq_ptr, io.deq) | ||||
| 
 | ||||
|   for((deq, deq_ptr_wire) <- io.deq.zip(deq_ptrs)){ | ||||
|     val deq_idx = ptrToIdx(deq_ptr_wire) | ||||
|     deq.valid := { | ||||
|       if(perf) valids(deq_idx) | ||||
|       else !isEmpty(deq_ptr_wire, enq_ptr) | ||||
|     } | ||||
|     deq.bits := ram(deq_idx) | ||||
|     if(perf) when(deq.fire()){ valids(deq_idx) := false.B } | ||||
|   } | ||||
| 
 | ||||
|   deq_ptr := deq_ptrs.last + io.deq(outCnt-1).fire() | ||||
| 
 | ||||
|   // enqueue | ||||
|   val enq_ptrs = genPtrs(enq_ptr, io.enq) | ||||
| 
 | ||||
|   for((enq, enq_ptr_wire) <- io.enq.zip(enq_ptrs)){ | ||||
|     val enq_idx = ptrToIdx(enq_ptr_wire) | ||||
|     enq.ready := { | ||||
|       if(perf) !valids(enq_idx) | ||||
|       else !isFull(enq_ptr_wire, deq_ptr) | ||||
|     } | ||||
|     when(enq.fire()){ | ||||
|       ram(enq_idx) := enq.bits | ||||
|       if(perf){ | ||||
|         valids(enq_idx) := true.B | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   enq_ptr := enq_ptrs.last + io.enq(inCnt-1).fire() | ||||
| 
 | ||||
|   when(io.flush){ | ||||
|     deq_ptr := 0.U | ||||
|     enq_ptr := 0.U | ||||
|     if(perf) valids.foreach(_ := false.B) | ||||
|   } | ||||
| 
 | ||||
|   // Debug(false){ | ||||
|   //   val cnt = RegInit((if(init.nonEmpty) entries else 0).U(32.W)) | ||||
|   //   val enqCnt = PopCount(io.enq.map(_.fire())) | ||||
|   //   val deqCnt = PopCount(io.deq.map(_.fire())) | ||||
|   //   cnt := cnt + enqCnt - deqCnt | ||||
|   //   assert(cnt > deqCnt, "MIMOQueue underflow!") | ||||
|   //   assert(cnt + enqCnt < entries.U(32.W), "MIMOQueue overflow!") | ||||
|   //   printf(p"cnt: $cnt enqCnt:$enqCnt deqCnt:$deqCnt\n") | ||||
|   // } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,101 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import chisel3.util.random.LFSR | ||||
| 
 | ||||
| // This gets used everywhere, so make the smallest circuit possible ... | ||||
| // Given an address and size, create a mask of beatBytes size | ||||
| // eg: (0x3, 0, 4) => 0001, (0x3, 1, 4) => 0011, (0x3, 2, 4) => 1111 | ||||
| // groupBy applies an interleaved OR reduction; groupBy=2 take 0010 => 01 | ||||
| object MaskGen { | ||||
|   def apply(addr_lo: UInt, lgSize: UInt, beatBytes: Int, groupBy: Int = 1): UInt = { | ||||
|     require (groupBy >= 1 && beatBytes >= groupBy) | ||||
|     require (isPow2(beatBytes) && isPow2(groupBy)) | ||||
|     val lgBytes = log2Ceil(beatBytes) | ||||
|     val sizeOH = UIntToOH(lgSize | 0.U(log2Up(beatBytes).W), log2Up(beatBytes)) | (groupBy*2 - 1).U | ||||
| 
 | ||||
|     def helper(i: Int): Seq[(Bool, Bool)] = { | ||||
|       if (i == 0) { | ||||
|         Seq((lgSize >= lgBytes.U, true.B)) | ||||
|       } else { | ||||
|         val sub = helper(i-1) | ||||
|         val size = sizeOH(lgBytes - i) | ||||
|         val bit = addr_lo(lgBytes - i) | ||||
|         val nbit = !bit | ||||
|         Seq.tabulate (1 << i) { j => | ||||
|           val (sub_acc, sub_eq) = sub(j/2) | ||||
|           val eq = sub_eq && (if (j % 2 == 1) bit else nbit) | ||||
|           val acc = sub_acc || (size && eq) | ||||
|           (acc, eq) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (groupBy == beatBytes) 1.U else | ||||
|       Cat(helper(lgBytes-log2Ceil(groupBy)).map(_._1).reverse) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object Random | ||||
| { | ||||
|   def apply(mod: Int, random: UInt): UInt = { | ||||
|     if (mod == 1) 0.U | ||||
|     else if (isPow2(mod)) random(log2Ceil(mod)-1,0) | ||||
|     else PriorityEncoder(partition(apply(1 << log2Up(mod*8), random), mod)) | ||||
|   } | ||||
|   def apply(mod: Int): UInt = apply(mod, randomizer) | ||||
|   def oneHot(mod: Int, random: UInt): UInt = { | ||||
|     if (mod == 1) 1.U(1.W) | ||||
|     else if (isPow2(mod)) UIntToOH(random(log2Up(mod)-1,0)) | ||||
|     else VecInit(PriorityEncoderOH(partition(apply(1 << log2Up(mod*8), random), mod))).asUInt | ||||
|   } | ||||
|   def oneHot(mod: Int): UInt = oneHot(mod, randomizer) | ||||
| 
 | ||||
|   private def randomizer = LFSR(16) | ||||
|   private def partition(value: UInt, slices: Int) = | ||||
|     Seq.tabulate(slices)(i => value < (((i + 1) << value.getWidth) / slices).U) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Transpose a matrix of Chisel Vecs. | ||||
|  */ | ||||
| object Transpose | ||||
| { | ||||
|   def apply[T <: chisel3.Data](in: Vec[Vec[T]]) = { | ||||
|     val n = in(0).size | ||||
|     VecInit((0 until n).map(i => VecInit(in.map(row => row(i))))) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * assert when 'signal' is true for more than 'threshold' cycles | ||||
|  */ | ||||
| object TimeOutAssert { | ||||
|   def apply(signal: Bool, threshold: Int, message: String): Unit = { | ||||
|     val counter = RegInit(0.U(32.W)) | ||||
|     when (signal) { | ||||
|       counter := counter + 1.U | ||||
|     }.otherwise { | ||||
|       counter := 0.U | ||||
|     } | ||||
|     assert(counter <= threshold.U, message) | ||||
|   } | ||||
| } | ||||
|  | @ -1,145 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| object ParallelOperation { | ||||
|   def apply[T](xs: Seq[T], func: (T, T) => T): T = { | ||||
|     require(xs.nonEmpty) | ||||
|     xs match { | ||||
|       case Seq(a) => a | ||||
|       case Seq(a, b) => func(a, b) | ||||
|       case _ => | ||||
|         apply(Seq(apply(xs take xs.size/2, func), apply(xs drop xs.size/2, func)), func) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelOR { | ||||
|   def apply[T <: Data](xs: Seq[T]): T = { | ||||
|     ParallelOperation(xs, (a: T, b: T) => (a.asUInt | b.asUInt).asTypeOf(xs.head)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelORR { | ||||
|   def apply(in: Seq[Bool]): Bool = ParallelOR(in) | ||||
|   def apply(in: Bits): Bool = apply(in.asBools) | ||||
| } | ||||
| 
 | ||||
| object ParallelAND { | ||||
|   def apply[T <: Data](xs: Seq[T]): T = { | ||||
|     ParallelOperation(xs, (a: T, b:T) => (a.asUInt & b.asUInt).asTypeOf(xs.head)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelANDR { | ||||
|   def apply(in: Seq[Bool]): Bool = ParallelAND(in) | ||||
|   def apply(in: Bits): Bool = apply(in.asBools) | ||||
| } | ||||
| 
 | ||||
| object ParallelXOR { | ||||
|   def apply[T <: Data](xs: Seq[T]): T = { | ||||
|     ParallelOperation(xs, (a: T, b:T) => (a.asUInt ^ b.asUInt).asTypeOf(xs.head)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelMux { | ||||
|   def apply[T<:Data](in: Seq[(Bool, T)]): T = { | ||||
|     val xs = in map { case (cond, x) => Mux(cond, x, 0.U.asTypeOf(x.cloneType)) } | ||||
|     ParallelOR(xs) | ||||
|   } | ||||
|   def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel.zip(in)) | ||||
| } | ||||
| 
 | ||||
| object ParallelLookUp { | ||||
|   def apply[T<:Data](key: UInt, mapping:Seq[(UInt,T)]): T = { | ||||
|     ParallelMux(mapping.map(m => (m._1===key) -> m._2)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelMax { | ||||
|   def apply[T <: Data](xs: Seq[T]): T = { | ||||
|     ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt > b.asUInt,a, b).asTypeOf(xs.head)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelMin { | ||||
|   def apply[T <: Data](xs: Seq[T]): T = { | ||||
|     ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt < b.asUInt,a, b).asTypeOf(xs.head)) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object ParallelPriorityMux { | ||||
|   def apply[T <: Data](in: Seq[(Bool, T)]): T = { | ||||
|     ParallelOperation(in, (a: (Bool, T), b: (Bool, T)) => (a._1 || b._1, Mux(a._1, a._2, b._2)))._2 | ||||
|   } | ||||
|   def apply[T <: Data](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in) | ||||
|   def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in) | ||||
| } | ||||
| 
 | ||||
| object ParallelPriorityEncoder { | ||||
|   def apply(in: Seq[Bool]): UInt = ParallelPriorityMux(in, (0 until in.size).map(_.asUInt)) | ||||
|   def apply(in: Bits): UInt = apply(in.asBools) | ||||
| } | ||||
| 
 | ||||
| object ParallelSingedExpandingAdd { | ||||
|   def apply(in: Seq[SInt]): SInt = ParallelOperation(in, (a: SInt, b: SInt) => a +& b) | ||||
| } | ||||
| 
 | ||||
| class SelectTwoInterRes[T <: Data](gen: T) extends Bundle { | ||||
|   // val valid = Bool() | ||||
|   val hasOne = Bool() | ||||
|   val hasTwo = Bool() | ||||
|   val first = gen.cloneType | ||||
|   val second = gen.cloneType | ||||
| } | ||||
| 
 | ||||
| object SelectTwoInterRes { | ||||
|   def apply[T <: Data](hasOne: Bool, hasTwo: Bool, first: T, second: T): SelectTwoInterRes[T] = { | ||||
|     val res = Wire(new SelectTwoInterRes(first)) | ||||
|     res.hasOne := hasOne | ||||
|     res.hasTwo := hasTwo | ||||
|     res.first := first | ||||
|     res.second := second | ||||
|     res | ||||
|   } | ||||
|   def apply[T <: Data](valid: Bool, data: T): SelectTwoInterRes[T] = { | ||||
|     val res = apply(valid, false.B, data, data) | ||||
|     res | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| object ParallelSelectTwo { | ||||
|   def mergeSelectFirstTwo[T <: Data](a: SelectTwoInterRes[T], b: SelectTwoInterRes[T]): SelectTwoInterRes[T] = { | ||||
|     SelectTwoInterRes( | ||||
|       a.hasOne || b.hasOne, | ||||
|       a.hasTwo || b.hasTwo || a.hasOne && b.hasOne, | ||||
|       Mux(a.hasOne, a.first, b.first), | ||||
|       Mux1H(Seq( | ||||
|         (!a.hasOne, b.second), | ||||
|         (a.hasOne && !a.hasTwo, b.first), | ||||
|         (a.hasTwo, a.second)  | ||||
|       )) | ||||
|     ) | ||||
|   } | ||||
|   def apply[T <: Data](xs: Seq[SelectTwoInterRes[T]]): SelectTwoInterRes[T] = { | ||||
|     ParallelOperation(xs, mergeSelectFirstTwo[T]) | ||||
|   } | ||||
| } | ||||
|  | @ -1,196 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class PipelineConnectPipe[T <: Data](gen: T) extends Module { | ||||
|   val io = IO(new Bundle() { | ||||
|     val in = Flipped(DecoupledIO(gen.cloneType)) | ||||
|     val out = DecoupledIO(gen.cloneType) | ||||
|     val rightOutFire = Input(Bool()) | ||||
|     val isFlush = Input(Bool()) | ||||
|   }) | ||||
| 
 | ||||
|   PipelineConnect.connect(io.in, io.out, io.rightOutFire, io.isFlush, false.B) | ||||
| } | ||||
| 
 | ||||
| class PipelineConnectBuffer[T <: Data, FlushT <: Data](gen: T, flushGen: FlushT, flushFunc: (T, FlushT) => Bool) | ||||
|   extends Module { | ||||
|   val io = IO(new Bundle() { | ||||
|     val in = Flipped(DecoupledIO(gen.cloneType)) | ||||
|     val out = DecoupledIO(gen.cloneType) | ||||
|     val flush = Input(flushGen.cloneType) | ||||
|   }) | ||||
| 
 | ||||
|   val valid = RegInit(VecInit.fill(2)(false.B)) | ||||
|   val data = Reg(Vec(2, gen.cloneType)) | ||||
|   val older = RegInit(false.B) | ||||
| 
 | ||||
|   // out | ||||
|   io.out.valid := valid.asUInt.orR | ||||
|   io.out.bits := data(older) | ||||
|   when (io.out.fire) { | ||||
|     valid(older) := false.B | ||||
|     older := !older | ||||
|   } | ||||
| 
 | ||||
|   // in | ||||
|   io.in.ready := !valid.asUInt.andR | ||||
|   val updateVec = WireInit(VecInit.fill(2)(false.B)) | ||||
|   when (io.in.valid && !flushFunc(io.in.bits, io.flush)) { | ||||
|     // how to choose: this_empty && (this_older || other_older && other_not_empty) | ||||
|     when (!valid(0) && (!older || older && valid(1))) { | ||||
|       valid(0) := true.B | ||||
|       data(0) := io.in.bits | ||||
|       updateVec(0) := true.B | ||||
|     }.elsewhen (!valid(1) && (older || !older && valid(0))) { | ||||
|       valid(1) := true.B | ||||
|       data(1) := io.in.bits | ||||
|       updateVec(1) := true.B | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // flush | ||||
|   val flushVec = data.zip(valid).map{ case (d, v) => flushFunc(d, io.flush) && v } | ||||
|   flushVec.zip(valid).foreach{ case (f, v) => | ||||
|     when (f) { | ||||
|       v := false.B | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class PipelineConnectBufferWithExtraData[T <: Data, FlushT <: Data, ExtraT <: Data]( | ||||
|   gen: T, flushGen: FlushT, flushFunc: (T, FlushT) => Bool, extraGen: ExtraT, extraLatency: Int | ||||
| ) extends PipelineConnectBuffer(gen, flushGen, flushFunc) { | ||||
|   require(extraLatency > 0, "why not use PipelineConnectBuffer?") | ||||
|   require(extraLatency == 1, "only 1 is supported now") | ||||
| 
 | ||||
|   val extra = IO(new Bundle { | ||||
|     val in = Input(extraGen.cloneType) | ||||
|     val out = Output(extraGen.cloneType) | ||||
|   }) | ||||
| 
 | ||||
|   val extraData = Reg(Vec(2, extraGen.cloneType)) | ||||
|   for (i <- 0 until 2) { | ||||
|     when (RegNext(updateVec(i) && !flushVec(i))) { | ||||
|       extraData(i) := extra.in | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // after out.fire, we assert(!older === RegNext(older)) | ||||
|   extra.out := extraData(!older) | ||||
| } | ||||
| 
 | ||||
| object PipelineConnect { | ||||
|   def connect[T <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     right: DecoupledIO[T], | ||||
|     rightOutFire: Bool, | ||||
|     isFlush: Bool, | ||||
|     block: Bool | ||||
|   ): T = { | ||||
|     val valid = RegInit(false.B) | ||||
|     val leftFire = left.valid && right.ready && !block | ||||
|     when (rightOutFire) { valid := false.B } | ||||
|     when (leftFire) { valid := true.B } | ||||
|     when (isFlush) { valid := false.B } | ||||
| 
 | ||||
|     left.ready := right.ready && !block | ||||
|     val data = RegEnable(left.bits, leftFire) | ||||
|     right.bits := data | ||||
|     right.valid := valid | ||||
| 
 | ||||
|     data | ||||
|   } | ||||
| 
 | ||||
|   def apply[T <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     right: DecoupledIO[T], | ||||
|     rightOutFire: Bool, | ||||
|     isFlush: Bool, | ||||
|     block: Bool = false.B, | ||||
|     moduleName: Option[String] = None | ||||
|   ): Option[T] = { | ||||
|     if (moduleName.isDefined) { | ||||
|       val pipeline = Module(new PipelineConnectPipe(left.bits)) | ||||
|       pipeline.suggestName(moduleName.get) | ||||
|       pipeline.io.in <> left | ||||
|       pipeline.io.rightOutFire := rightOutFire | ||||
|       pipeline.io.isFlush := isFlush | ||||
|       pipeline.io.out <> right | ||||
|       pipeline.io.out.ready := right.ready && !block | ||||
|       None | ||||
|     } | ||||
|     else { | ||||
|       // do not use module here to please DCE | ||||
|       Some(connect(left, right, rightOutFire, isFlush, block)) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   def apply[T <: Data, FlushT <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     right: DecoupledIO[T], | ||||
|     flushFunc: (T, FlushT) => Bool, | ||||
|     flush: FlushT, | ||||
|     moduleName: Option[String] | ||||
|   ): Unit = { | ||||
|     val pipe_buffer = Module(new PipelineConnectBuffer(left.bits, flush, flushFunc)) | ||||
|     if(moduleName.nonEmpty) pipe_buffer.suggestName(moduleName.get) | ||||
|     pipe_buffer.io.in <> left | ||||
|     pipe_buffer.io.out <> right | ||||
|     pipe_buffer.io.flush := flush | ||||
|   } | ||||
| 
 | ||||
|   def apply[T <: Data, FlushT <: Data, ExtraT <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     right: DecoupledIO[T], | ||||
|     flushFunc: (T, FlushT) => Bool, | ||||
|     flush: FlushT, | ||||
|     extraGen: ExtraT, | ||||
|     extraLatency: Int | ||||
|   ): PipelineConnectBufferWithExtraData[T, FlushT, ExtraT] = { | ||||
|     val pipe_buffer = Module(new PipelineConnectBufferWithExtraData(left.bits, flush, flushFunc, extraGen, extraLatency)) | ||||
|     pipe_buffer.io.in <> left | ||||
|     pipe_buffer.io.out <> right | ||||
|     pipe_buffer.io.flush := flush | ||||
|     pipe_buffer | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object PipelineNext { | ||||
|   def apply[T <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     rightOutFire: Bool, | ||||
|     isFlush: Bool | ||||
|   ): DecoupledIO[T] = { | ||||
|     val right = Wire(Decoupled(left.bits.cloneType)) | ||||
|     PipelineConnect(left, right, rightOutFire, isFlush) | ||||
|     right | ||||
|   } | ||||
| 
 | ||||
|   def apply[T <: Data, FlushT <: Data]( | ||||
|     left: DecoupledIO[T], | ||||
|     flushFunc: (T, FlushT) => Bool, | ||||
|     flush: FlushT | ||||
|   ): DecoupledIO[T] = { | ||||
|     val right = Wire(Decoupled(left.bits.cloneType)) | ||||
|     PipelineConnect(left, right, flushFunc, flush, Some("buffer")) | ||||
|     right | ||||
|   } | ||||
| } | ||||
|  | @ -1,59 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| 
 | ||||
| object PriorityMuxDefault { | ||||
|   def apply[T <: Data](in: Seq[(Bool, T)], default: T): T = { | ||||
|     in.size match { | ||||
|       case 1=> | ||||
|         Mux(in.head._1, in.head._2, default) | ||||
|       case _ => | ||||
|         Mux(in.head._1, in.head._2, PriorityMuxDefault(in.tail, default)) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object PriorityEncoderDefault { | ||||
|   def apply(in: Seq[Bool], default: UInt): UInt = { | ||||
|     PriorityMuxDefault(in.zipWithIndex.map(x => x._1 -> x._2.U), default) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object PriorityMuxWithFlag { | ||||
|   def apply[T <: Data](in: Seq[(Bool, T)]): (T, Bool) = { | ||||
|     in.size match { | ||||
|       case 1 => | ||||
|         (in.head._2, in.head._1) | ||||
|       case _ => | ||||
|         val (d_tail, f_tail) = PriorityMuxWithFlag(in.tail) | ||||
|         val d_head = in.head._2 | ||||
|         val f_head = in.head._1 | ||||
|         (Mux(f_head, d_head, d_tail), f_head || f_tail) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| object PriorityEncoderWithFlag { | ||||
|   def apply(in: Seq[Bool]): (UInt, Bool) = { | ||||
|     PriorityMuxWithFlag(in.zipWithIndex.map(x => x._1 -> x._2.U)) | ||||
|   } | ||||
|   def apply(in: Bits): (UInt, Bool) = { | ||||
|     PriorityEncoderWithFlag(in.asBools()) | ||||
|   } | ||||
| } | ||||
|  | @ -1,145 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import Chisel.experimental.chiselName | ||||
| 
 | ||||
| @chiselName | ||||
| class PriorityMuxModule[T <: Data](val gen: T)(val names: Seq[String]) extends MultiIOModule { | ||||
|     class InBundle extends Bundle { | ||||
|         val sel = Bool() | ||||
|         val src = gen.cloneType | ||||
|     } | ||||
|     class OutBundle extends Bundle { | ||||
|         val res = gen.cloneType | ||||
|     } | ||||
|     val ins = names.map(s => { | ||||
|         IO(Input(new InBundle)).suggestName(s) | ||||
|     }) | ||||
|     val out = IO(Output(new OutBundle)) | ||||
|     out.res := PriorityMux(ins.map{i => (i.sel, i.src)}) | ||||
| } | ||||
| 
 | ||||
| // this could be used to handle the situation | ||||
| // in which we have mux sources at multiple | ||||
| // locations, and this is same to multiple | ||||
| // when clauses as below, but collect them | ||||
| // and put them into a ParallelPrioriyMux | ||||
| // when (sel1) { x := in1 } | ||||
| // when (sel2) { x := in2 } | ||||
| class PriorityMuxGenerator[T <: Data] { | ||||
|     var src: List[(Bool, T, String)] = List() | ||||
|     var num: Int = 0 | ||||
|     def genPortName(n: Option[String]): String = { | ||||
|         num = num + 1 | ||||
|         n match { | ||||
|             case Some(name) => name | ||||
|             case None => { | ||||
|                 "in" + num.toString() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     def register(sel: Bool, in: T, name: Option[String] = None) = { | ||||
|         src = (sel, in, genPortName(name)) :: src | ||||
|     } | ||||
|     def register(in: Seq[(Bool, T, Option[String])]) = { | ||||
|         src = in.toList.map{ case (b, t, n) => (b, t, genPortName(n)) } ::: src | ||||
|     } | ||||
|     def register(sel: Seq[Bool], in: Seq[T], name: Seq[Option[String]]) = { | ||||
|         src = (sel,in,name.map(genPortName)).zipped.toList ::: src | ||||
|     } | ||||
|     def apply(): T = { | ||||
|         val names = src.map(_._3) | ||||
|         val ins = src.map(s => (s._1, s._2)) | ||||
|         // we should use this sample data to get type and width | ||||
|         // ugly | ||||
|         val sample = ins(0)._2 | ||||
|         val ppm = Module(new PriorityMuxModule(sample)(names)) | ||||
|         (ppm.ins zip ins).foreach { | ||||
|             case (in, (b, t)) => { | ||||
|                 in.sel := b | ||||
|                 in.src := t | ||||
|             } | ||||
|         } | ||||
|         ppm.out.res | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // this module is like PhyPriorityMuxGenerator | ||||
| // but you can specify the physical priority | ||||
| // by passing in an Int, usually we give | ||||
| // the hightest priority to the condition | ||||
| // with the largest delay. | ||||
| // but their logical priority is still | ||||
| // arranged in the order specified in the code | ||||
| class PhyPriorityMuxGenerator[T <: Data] { | ||||
|     var src: List[(Bool, T, String, Int)] = List() | ||||
|     var rev_src: List[(Bool, T, String, Int)] = List() | ||||
|     var sorted_src: List[(Bool, T, String, Int)] = List() | ||||
|     var num: Int = 0 | ||||
|     def genPortName(n: Option[String]): String = { | ||||
|         num = num + 1 | ||||
|         n match { | ||||
|             case Some(name) => name | ||||
|             case None => { | ||||
|                 "in" + num.toString() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     def register(sel: Bool, in: T, name: Option[String] = None, phyPrio: Int = 0) = { | ||||
|         src = (sel, in, genPortName(name), phyPrio) :: src | ||||
|     } | ||||
|     def register(in: Seq[(Bool, T, Option[String], Int)]) = { | ||||
|         src = in.toList.map{ case (b, t, n, p) => (b, t, genPortName(n), p) } ::: src | ||||
|     } | ||||
|     def register(sel: Seq[Bool], in: Seq[T], name: Seq[Option[String]], phyPrio: Seq[Int]) = { | ||||
|         src = sel.zip(in.zip(name.map(genPortName).zip(phyPrio))).map { case (s, (i, (n, p))) => | ||||
|             (s, i, n, p) }.toList ::: src | ||||
|     } | ||||
|     def apply(): T = { | ||||
|         rev_src = src.reverse | ||||
|         for (i <- 0 until rev_src.length) { | ||||
|             // println(rev_src(i)._3) | ||||
|             sorted_src = (rev_src(i)._1 && (if (i == rev_src.length-1) true.B else (i+1 until rev_src.length).map(j => !rev_src(j)._1).reduce(_&&_)), | ||||
|                 rev_src(i)._2, rev_src(i)._3, rev_src(i)._4) :: sorted_src | ||||
|         } | ||||
|         sorted_src = sorted_src.sortBy(_._4).reverse | ||||
|         // println(sorted_src) | ||||
|         val names = sorted_src.map(_._3) | ||||
|         val ins = sorted_src.map(s => (s._1, s._2)) | ||||
|         // we should use this sample data to get type and width | ||||
|         // ugly | ||||
|         val sample = ins(0)._2 | ||||
|         // println(src) | ||||
|         // println(sorted_src) | ||||
|         // println(ins) | ||||
|         // println(names) | ||||
| 
 | ||||
|         val ppm = Module(new PriorityMuxModule(sample)(names)) | ||||
|         (ppm.ins zip ins).foreach { | ||||
|             case (in, (b, t)) => { | ||||
|                 in.sel := b | ||||
|                 in.src := t | ||||
|             } | ||||
|         } | ||||
|         ppm.out.res | ||||
|     } | ||||
| } | ||||
|  | @ -1,67 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| object RegMap { | ||||
|   def Unwritable = null | ||||
|   def apply(addr: Int, reg: UInt, wfn: UInt => UInt = (x => x)) = (addr, (reg, wfn)) | ||||
|   def generate(mapping: Map[Int, (UInt, UInt => UInt)], raddr: UInt, rdata: UInt, | ||||
|     waddr: UInt, wen: Bool, wdata: UInt, wmask: UInt):Unit = { | ||||
|     val chiselMapping = mapping.map { case (a, (r, w)) => (a.U, r, w) } | ||||
|     rdata := LookupTree(raddr, chiselMapping.map { case (a, r, w) => (a, r) }) | ||||
|     chiselMapping.map { case (a, r, w) => | ||||
|       if (w != null) when (wen && waddr === a) { r := w(MaskData(r, wdata, wmask)) } | ||||
|     } | ||||
|   } | ||||
|   def generate(mapping: Map[Int, (UInt, UInt => UInt)], addr: UInt, rdata: UInt, | ||||
|     wen: Bool, wdata: UInt, wmask: UInt):Unit = generate(mapping, addr, rdata, addr, wen, wdata, wmask) | ||||
| } | ||||
| 
 | ||||
| object MaskedRegMap { // TODO: add read mask | ||||
|   def Unwritable = null | ||||
|   def NoSideEffect: UInt => UInt = (x=>x) | ||||
|   def WritableMask = Fill(64, true.B) | ||||
|   def UnwritableMask = 0.U(64.W) | ||||
|   def apply(addr: Int, reg: UInt, | ||||
|             wmask: UInt = WritableMask, wfn: UInt => UInt = (x => x), | ||||
|             rmask: UInt = WritableMask, rfn: UInt => UInt = x=>x | ||||
|            ): (Int, (UInt, UInt, UInt => UInt, UInt, UInt => UInt)) = (addr, (reg, wmask, wfn, rmask, rfn)) | ||||
|   def generate(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt, UInt => UInt)], raddr: UInt, rdata: UInt, | ||||
|     waddr: UInt, wen: Bool, wdata: UInt):Unit = { | ||||
|     val chiselMapping = mapping.map { case (a, (r, wm, w, rm, rfn)) => (a.U, r, wm, w, rm, rfn) } | ||||
|     rdata := LookupTree(raddr, chiselMapping.map { case (a, r, _, _, rm, rfn) => (a, rfn(r & rm)) }) | ||||
|     val wdata_reg = RegEnable(wdata, wen) | ||||
|     chiselMapping.foreach { case (a, r, wm, w, _, _) => | ||||
|       if (w != null && wm != UnwritableMask) { | ||||
|         // Warning: this RegMap adds a RegNext for write to reduce fanout | ||||
|         // the w must be pure function without side effects | ||||
|         val wen_reg = RegNext(wen && waddr === a) | ||||
|         when (wen_reg) { r := w(MaskData(r, wdata_reg, wm)) } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   def isIllegalAddr(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt, UInt => UInt)], addr: UInt):Bool = { | ||||
|     val illegalAddr = Wire(Bool()) | ||||
|     illegalAddr := LookupTreeDefault(addr, true.B, mapping.toSeq.sortBy(_._1).map { case (a, _) => (a.U, false.B) }) | ||||
|     illegalAddr | ||||
|   } | ||||
|   def generate(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt, UInt => UInt)], addr: UInt, rdata: UInt, | ||||
|     wen: Bool, wdata: UInt):Unit = generate(mapping, addr, rdata, addr, wen, wdata) | ||||
| } | ||||
|  | @ -1,57 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| // See LICENSE.Berkeley for license details. | ||||
| // See LICENSE.SiFive for license details. | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import chisel3.util.random.LFSR | ||||
| import freechips.rocketchip.util._ | ||||
| import freechips.rocketchip.util.property.cover | ||||
| import xiangshan.{XSCoreParameters} | ||||
| 
 | ||||
| object ReplacementPolicy { | ||||
|   //for fully associative mapping | ||||
|   def fromString(s: Option[String],n_ways: Int): ReplacementPolicy = fromString(s.getOrElse("none"),n_ways) | ||||
|   def fromString(s: String, n_ways: Int): ReplacementPolicy = s.toLowerCase match { | ||||
|     case "random" => new RandomReplacement(n_ways) | ||||
|     case "lru"    => new TrueLRU(n_ways) | ||||
|     case "plru"   => new PseudoLRU(n_ways) | ||||
|     case t => throw new IllegalArgumentException(s"unknown Replacement Policy type $t") | ||||
|   } | ||||
|   //for set associative mapping | ||||
|   def fromString(s: Option[String], n_ways: Int, n_sets: Int): SetAssocReplacementPolicy = fromString(s.getOrElse("none"),n_ways,n_sets ) | ||||
|   def fromString(s: String, n_ways: Int, n_sets: Int): SetAssocReplacementPolicy = s.toLowerCase match { | ||||
|     case "random"    => new SetAssocRandom(n_sets, n_ways) | ||||
|     case "setlru"    => new SetAssocLRU(n_sets, n_ways, "lru") | ||||
|     case "setplru"   => new SetAssocLRU(n_sets, n_ways, "plru") | ||||
|     case t => throw new IllegalArgumentException(s"unknown Replacement Policy type $t") | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SetAssocRandom(n_sets : Int, n_ways: Int) extends SetAssocReplacementPolicy { | ||||
|   val random = new RandomReplacement(n_ways) | ||||
| 
 | ||||
|   def miss(set: UInt) =  random.miss | ||||
|   def way(set: UInt) = random.way | ||||
| 
 | ||||
|   def access(set: UInt, touch_way: UInt) = random.access(touch_way) | ||||
|   def access(sets: Seq[UInt], touch_ways: Seq[Valid[UInt]]) = random.access(touch_ways) | ||||
| 
 | ||||
| } | ||||
|  | @ -1,68 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class ResetGen extends Module { | ||||
|   val io = IO(new Bundle() { | ||||
|     val out = Output(Bool()) | ||||
|   }) | ||||
| 
 | ||||
|   io.out := RegNext(RegNext(reset.asBool)) | ||||
| } | ||||
| 
 | ||||
| trait ResetNode | ||||
| 
 | ||||
| case class ModuleNode(mod: MultiIOModule) extends ResetNode | ||||
| 
 | ||||
| case class ResetGenNode(children: Seq[ResetNode]) extends ResetNode | ||||
| 
 | ||||
| object ResetGen { | ||||
| 
 | ||||
|   def apply(resetTree: ResetNode, reset: Bool, sim: Boolean): Unit = { | ||||
|     if(!sim) { | ||||
|       resetTree match { | ||||
|         case ModuleNode(mod) => | ||||
|           mod.reset := reset | ||||
|         case ResetGenNode(children) => | ||||
|           val next_rst = Wire(Bool()) | ||||
|           withReset(reset){ | ||||
|             val resetGen = Module(new ResetGen) | ||||
|             next_rst := resetGen.io.out | ||||
|           } | ||||
|           children.foreach(child => apply(child, next_rst, sim)) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   def apply(resetChain: Seq[Seq[MultiIOModule]], reset: Bool, sim: Boolean): Seq[Bool] = { | ||||
|     val resetReg = Wire(Vec(resetChain.length + 1, Bool())) | ||||
|     resetReg.foreach(_ := reset) | ||||
|     for ((resetLevel, i) <- resetChain.zipWithIndex) { | ||||
|       if (!sim) { | ||||
|         withReset(resetReg(i)) { | ||||
|           val resetGen = Module(new ResetGen) | ||||
|           resetReg(i + 1) := resetGen.io.out | ||||
|         } | ||||
|       } | ||||
|       resetLevel.foreach(_.reset := resetReg(i + 1)) | ||||
|     } | ||||
|     resetReg.tail | ||||
|   } | ||||
| } | ||||
|  | @ -1,234 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| /************************************************************************************** | ||||
| * Copyright (c) 2020 Institute of Computing Technology, CAS | ||||
| * Copyright (c) 2020 University of Chinese Academy of Sciences | ||||
| * | ||||
| * NutShell is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *             http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER | ||||
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR | ||||
| * FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| 
 | ||||
| class SRAMBundleA(val set: Int) extends Bundle { | ||||
|   val setIdx = Output(UInt(log2Up(set).W)) | ||||
| 
 | ||||
|   def apply(setIdx: UInt) = { | ||||
|     this.setIdx := setIdx | ||||
|     this | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SRAMBundleAW[T <: Data](private val gen: T, set: Int, val way: Int = 1) extends SRAMBundleA(set) { | ||||
|   val data = Output(Vec(way, gen)) | ||||
|   val waymask = if (way > 1) Some(Output(UInt(way.W))) else None | ||||
| 
 | ||||
|   def apply(data: Vec[T], setIdx: UInt, waymask: UInt): SRAMBundleAW[T] = { | ||||
|     super.apply(setIdx) | ||||
|     this.data := data | ||||
|     this.waymask.map(_ := waymask) | ||||
|     this | ||||
|   } | ||||
|   // this could only be used when waymask is onehot or nway is 1 | ||||
|   def apply(data: T, setIdx: UInt, waymask: UInt): SRAMBundleAW[T] = { | ||||
|     apply(VecInit(Seq.fill(way)(data)), setIdx, waymask) | ||||
|     this | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SRAMBundleR[T <: Data](private val gen: T, val way: Int = 1) extends Bundle { | ||||
|   val data = Output(Vec(way, gen)) | ||||
| } | ||||
| 
 | ||||
| class SRAMReadBus[T <: Data](private val gen: T, val set: Int, val way: Int = 1) extends Bundle { | ||||
|   val req = Decoupled(new SRAMBundleA(set)) | ||||
|   val resp = Flipped(new SRAMBundleR(gen, way)) | ||||
| 
 | ||||
|   def apply(valid: Bool, setIdx: UInt) = { | ||||
|     this.req.bits.apply(setIdx) | ||||
|     this.req.valid := valid | ||||
|     this | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SRAMWriteBus[T <: Data](private val gen: T, val set: Int, val way: Int = 1) extends Bundle { | ||||
|   val req = Decoupled(new SRAMBundleAW(gen, set, way)) | ||||
| 
 | ||||
|   def apply(valid: Bool, data: Vec[T], setIdx: UInt, waymask: UInt): SRAMWriteBus[T] = { | ||||
|     this.req.bits.apply(data = data, setIdx = setIdx, waymask = waymask) | ||||
|     this.req.valid := valid | ||||
|     this | ||||
|   } | ||||
|   def apply(valid: Bool, data: T, setIdx: UInt, waymask: UInt): SRAMWriteBus[T] = { | ||||
|     apply(valid, VecInit(Seq.fill(way)(data)), setIdx, waymask) | ||||
|     this | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class SRAMTemplate[T <: Data]( | ||||
|   gen: T, set: Int, way: Int = 1, singlePort: Boolean = false, | ||||
|   shouldReset: Boolean = false, extraReset: Boolean = false, | ||||
|   holdRead: Boolean = false, bypassWrite: Boolean = false | ||||
| ) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val r = Flipped(new SRAMReadBus(gen, set, way)) | ||||
|     val w = Flipped(new SRAMWriteBus(gen, set, way)) | ||||
|   }) | ||||
|   val extra_reset = if (extraReset) Some(IO(Input(Bool()))) else None | ||||
| 
 | ||||
|   val wordType = UInt(gen.getWidth.W) | ||||
|   val array = SyncReadMem(set, Vec(way, wordType)) | ||||
|   val (resetState, resetSet) = (WireInit(false.B), WireInit(0.U)) | ||||
| 
 | ||||
|   if (shouldReset) { | ||||
|     val _resetState = RegInit(true.B) | ||||
|     val (_resetSet, resetFinish) = Counter(_resetState, set) | ||||
|     when (resetFinish) { _resetState := false.B } | ||||
|     if (extra_reset.isDefined) { | ||||
|       when (extra_reset.get) { | ||||
|         _resetState := true.B | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     resetState := _resetState | ||||
|     resetSet := _resetSet | ||||
|   } | ||||
| 
 | ||||
|   val (ren, wen) = (io.r.req.valid, io.w.req.valid || resetState) | ||||
|   val realRen = (if (singlePort) ren && !wen else ren) | ||||
| 
 | ||||
|   val setIdx = Mux(resetState, resetSet, io.w.req.bits.setIdx) | ||||
|   val wdata = VecInit(Mux(resetState, 0.U.asTypeOf(Vec(way, gen)), io.w.req.bits.data).map(_.asTypeOf(wordType))) | ||||
|   val waymask = Mux(resetState, Fill(way, "b1".U), io.w.req.bits.waymask.getOrElse("b1".U)) | ||||
|   when (wen) { array.write(setIdx, wdata, waymask.asBools) } | ||||
| 
 | ||||
|   val raw_rdata = array.read(io.r.req.bits.setIdx, realRen) | ||||
| 
 | ||||
|   // bypass for dual-port SRAMs | ||||
|   require(!bypassWrite || bypassWrite && !singlePort) | ||||
|   def need_bypass(wen: Bool, waddr: UInt, wmask: UInt, ren: Bool, raddr: UInt) : UInt = { | ||||
|     val need_check = RegNext(ren && wen) | ||||
|     val waddr_reg = RegNext(waddr) | ||||
|     val raddr_reg = RegNext(raddr) | ||||
|     require(wmask.getWidth == way) | ||||
|     val bypass = Fill(way, need_check && waddr_reg === raddr_reg) & RegNext(wmask) | ||||
|     bypass.asTypeOf(UInt(way.W)) | ||||
|   } | ||||
|   val bypass_wdata = if (bypassWrite) VecInit(RegNext(io.w.req.bits.data).map(_.asTypeOf(wordType))) | ||||
|     else VecInit((0 until way).map(_ => LFSR64().asTypeOf(wordType))) | ||||
|   val bypass_mask = need_bypass(io.w.req.valid, io.w.req.bits.setIdx, io.w.req.bits.waymask.getOrElse("b1".U), io.r.req.valid, io.r.req.bits.setIdx) | ||||
|   val mem_rdata = { | ||||
|     if (singlePort) raw_rdata | ||||
|     else VecInit(bypass_mask.asBools.zip(raw_rdata).zip(bypass_wdata).map { | ||||
|       case ((m, r), w) => Mux(m, w, r) | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   // hold read data for SRAMs | ||||
|   val rdata = (if (holdRead) HoldUnless(mem_rdata, RegNext(realRen)) | ||||
|               else mem_rdata).map(_.asTypeOf(gen)) | ||||
| 
 | ||||
|   io.r.resp.data := VecInit(rdata) | ||||
|   io.r.req.ready := !resetState && (if (singlePort) !wen else true.B) | ||||
|   io.w.req.ready := true.B | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class FoldedSRAMTemplate[T <: Data](gen: T, set: Int, width: Int = 4, way: Int = 1, | ||||
|   shouldReset: Boolean = false, extraReset: Boolean = false, | ||||
|   holdRead: Boolean = false, singlePort: Boolean = false, bypassWrite: Boolean = false) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val r = Flipped(new SRAMReadBus(gen, set, way)) | ||||
|     val w = Flipped(new SRAMWriteBus(gen, set, way)) | ||||
|   }) | ||||
|   val extra_reset = if (extraReset) Some(IO(Input(Bool()))) else None | ||||
|   //   |<----- setIdx ----->| | ||||
|   //   | ridx | width | way | | ||||
| 
 | ||||
|   require(width > 0 && isPow2(width)) | ||||
|   require(way > 0 && isPow2(way)) | ||||
|   require(set % width == 0) | ||||
| 
 | ||||
|   val nRows = set / width | ||||
| 
 | ||||
|   val array = Module(new SRAMTemplate(gen, set=nRows, way=width*way, | ||||
|     shouldReset=shouldReset, extraReset=extraReset, holdRead=holdRead, singlePort=singlePort)) | ||||
|   if (array.extra_reset.isDefined) { | ||||
|     array.extra_reset.get := extra_reset.get | ||||
|   } | ||||
| 
 | ||||
|   io.r.req.ready := array.io.r.req.ready | ||||
|   io.w.req.ready := array.io.w.req.ready | ||||
| 
 | ||||
|   val raddr = io.r.req.bits.setIdx >> log2Ceil(width) | ||||
|   val ridx = RegNext(if (width != 1) io.r.req.bits.setIdx(log2Ceil(width)-1, 0) else 0.U(1.W)) | ||||
|   val ren  = io.r.req.valid | ||||
| 
 | ||||
|   array.io.r.req.valid := ren | ||||
|   array.io.r.req.bits.setIdx := raddr | ||||
| 
 | ||||
|   val rdata = array.io.r.resp.data | ||||
|   for (w <- 0 until way) { | ||||
|     val wayData = VecInit(rdata.indices.filter(_ % way == w).map(rdata(_))) | ||||
|     val holdRidx = HoldUnless(ridx, RegNext(io.r.req.valid)) | ||||
|     val realRidx = if (holdRead) holdRidx else ridx | ||||
|     io.r.resp.data(w) := Mux1H(UIntToOH(realRidx, width), wayData) | ||||
|   } | ||||
| 
 | ||||
|   val wen = io.w.req.valid | ||||
|   val wdata = VecInit(Seq.fill(width)(io.w.req.bits.data).flatten) | ||||
|   val waddr = io.w.req.bits.setIdx >> log2Ceil(width) | ||||
|   val widthIdx = if (width != 1) io.w.req.bits.setIdx(log2Ceil(width)-1, 0) else 0.U | ||||
|   val wmask = (width, way) match { | ||||
|     case (1, 1) => 1.U(1.W) | ||||
|     case (x, 1) => UIntToOH(widthIdx) | ||||
|     case _      => VecInit(Seq.tabulate(width*way)(n => (n / way).U === widthIdx && io.w.req.bits.waymask.get(n % way))).asUInt | ||||
|   } | ||||
|   require(wmask.getWidth == way*width) | ||||
| 
 | ||||
|   array.io.w.apply(wen, wdata, waddr, wmask) | ||||
| } | ||||
| class SRAMTemplateWithArbiter[T <: Data](nRead: Int, gen: T, set: Int, way: Int = 1, | ||||
|   shouldReset: Boolean = false) extends Module { | ||||
|   val io = IO(new Bundle { | ||||
|     val r = Flipped(Vec(nRead, new SRAMReadBus(gen, set, way))) | ||||
|     val w = Flipped(new SRAMWriteBus(gen, set, way)) | ||||
|   }) | ||||
| 
 | ||||
|   val ram = Module(new SRAMTemplate(gen, set, way, shouldReset = shouldReset, holdRead = false, singlePort = true)) | ||||
|   ram.io.w <> io.w | ||||
| 
 | ||||
|   val readArb = Module(new Arbiter(chiselTypeOf(io.r(0).req.bits), nRead)) | ||||
|   readArb.io.in <> io.r.map(_.req) | ||||
|   ram.io.r.req <> readArb.io.out | ||||
| 
 | ||||
|   // latch read results | ||||
|   io.r.map{ case r => { | ||||
|     r.resp.data := HoldUnless(ram.io.r.resp.data, RegNext(r.req.fire())) | ||||
|   }} | ||||
| } | ||||
|  | @ -1,35 +0,0 @@ | |||
| /*************************************************************************************** | ||||
| * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences | ||||
| * Copyright (c) 2020-2021 Peng Cheng Laboratory | ||||
| * | ||||
| * XiangShan is licensed under Mulan PSL v2. | ||||
| * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||||
| * You may obtain a copy of Mulan PSL v2 at: | ||||
| *          http://license.coscl.org.cn/MulanPSL2 | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||||
| * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||||
| * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||||
| * | ||||
| * See the Mulan PSL v2 for more details. | ||||
| ***************************************************************************************/ | ||||
| 
 | ||||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| 
 | ||||
| object BoolStopWatch { | ||||
|   def apply(start: Bool, stop: Bool, startHighPriority: Boolean = false, bypass: Boolean = false) = { | ||||
|     val r = RegInit(false.B) | ||||
|     if (startHighPriority) { | ||||
|       when (stop) { r := false.B } | ||||
|       when (start) { r := true.B } | ||||
|     } | ||||
|     else { | ||||
|       when (start) { r := true.B } | ||||
|       when (stop) { r := false.B } | ||||
|     } | ||||
|     (if (bypass) (start || r) else r) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1,69 +0,0 @@ | |||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp} | ||||
| import freechips.rocketchip.tilelink.TLAdapterNode | ||||
| 
 | ||||
| class TLClientsMerger(debug: Boolean)(implicit p: Parameters) extends LazyModule { | ||||
| 
 | ||||
|   val node = TLAdapterNode( | ||||
|     clientFn = s => { | ||||
|       val sourceIds = s.masters.map(_.sourceId) | ||||
|       val minId = sourceIds.map(_.start).min | ||||
|       val maxId = sourceIds.map(_.end).max | ||||
|       val merged = s.v1copy( | ||||
|         clients = Seq(s.masters.head.v1copy( | ||||
|           sourceId = IdRange(minId, maxId), | ||||
|           visibility = s.masters.flatMap(_.visibility) | ||||
|         )) | ||||
|       ) | ||||
|       if(debug){ | ||||
|         println("TLClientsMerger: Merging clients:") | ||||
|         for(c <- s.masters){ | ||||
|           println(c) | ||||
|         } | ||||
|         println("Merged params:") | ||||
|         println(merged.masters) | ||||
|       } | ||||
|       for(c <- s.masters.tail){ | ||||
|         // ensure all masters have same params except `sourceId` and `visiblity` | ||||
|         val head = s.masters.head | ||||
|         for(i <- (0 until head.productArity) | ||||
|           .filterNot(x => x == 1 || x == 3)) // skip `sourceId` and `visibility` | ||||
|         { | ||||
|           require(head.productElement(i) == c.productElement(i)) | ||||
|         } | ||||
|       } | ||||
|       merged | ||||
|     } | ||||
|   ) | ||||
| 
 | ||||
|   lazy val module = new LazyModuleImp(this){ | ||||
|     require(node.in.size == 1) | ||||
|     for((in, out) <- node.in.map(_._1).zip(node.out.map(_._1))){ | ||||
|       out <> in | ||||
|     } | ||||
|     for(((in, edgeIn), (out, edgeOut)) <- node.in.zip(node.out)){ | ||||
|       out <> in | ||||
|       // handle b channel carefully | ||||
|       val banks = edgeIn.master.masters.size | ||||
|       if(banks != 1){ | ||||
|         val blockBytes = edgeIn.master.masters.head.visibility.head.alignment | ||||
|         val bankBits = log2Up(banks) | ||||
|         val bankIdx = (out.b.bits.address >> log2Up(blockBytes))(bankBits - 1, 0) | ||||
|         val startIds = VecInit(edgeIn.master.masters.map(_.sourceId.start.U)) | ||||
|         in.b.bits.source := startIds(bankIdx) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| object TLClientsMerger { | ||||
|   def apply(debug: Boolean = true)(implicit p: Parameters) = { | ||||
|     val merger = LazyModule(new TLClientsMerger(debug)) | ||||
|     merger.node | ||||
|   } | ||||
| } | ||||
|  | @ -1,98 +0,0 @@ | |||
| package utils | ||||
| 
 | ||||
| import chisel3._ | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| 
 | ||||
| 
 | ||||
| class TLEdgeBuffer | ||||
| ( | ||||
|   edgeFilter: Int => Boolean, | ||||
|   nameOpt: Option[String], | ||||
|   a: BufferParams = BufferParams.default, | ||||
|   b: BufferParams = BufferParams.default, | ||||
|   c: BufferParams = BufferParams.default, | ||||
|   d: BufferParams = BufferParams.default, | ||||
|   e: BufferParams = BufferParams.default, | ||||
| )(implicit p: Parameters) extends LazyModule { | ||||
| 
 | ||||
|   val node = new TLBufferNode(a, b, c, d, e) | ||||
| 
 | ||||
|   lazy val module = new LazyModuleImp(this){ | ||||
|     for((((in, edgeIn), (out, edgeOut)), i) <- node.in.zip(node.out).zipWithIndex){ | ||||
|       val buffer = edgeFilter(i) | ||||
|       if(buffer){ | ||||
|         out <> TLBufferModule(edgeIn, edgeOut, in, name = nameOpt.map(s => s"${s}_edge_$i")) | ||||
|       } else { | ||||
|         out <> in | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| object TLEdgeBuffer { | ||||
|   def apply | ||||
|   ( | ||||
|     edgeFilter: Int => Boolean, | ||||
|     nameOpt: Option[String] = None | ||||
|   )(implicit p: Parameters) = { | ||||
|     val buffer = LazyModule(new TLEdgeBuffer(edgeFilter, nameOpt)) | ||||
|     buffer.suggestName(nameOpt) | ||||
|     buffer.node | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class TLBufferModule | ||||
| ( | ||||
|   edge: TLEdge, | ||||
|   bce: Boolean = true, | ||||
|   a: BufferParams = BufferParams.default, | ||||
|   b: BufferParams = BufferParams.default, | ||||
|   c: BufferParams = BufferParams.default, | ||||
|   d: BufferParams = BufferParams.default, | ||||
|   e: BufferParams = BufferParams.default | ||||
| ) extends Module { | ||||
|   val io = IO(new Bundle() { | ||||
|     val in = Flipped(TLBundle(edge.bundle)) | ||||
|     val out = TLBundle(edge.bundle) | ||||
|   }) | ||||
| 
 | ||||
|   io.out.a <> a(io.in.a) | ||||
|   io.in.d <> d(io.out.d) | ||||
|   if(bce){ | ||||
|     io.out.c <> c(io.in .c) | ||||
|     io.out.e <> e(io.in .e) | ||||
|     io.in.b <> b(io.out.b) | ||||
|   } else { | ||||
|     io.in.b.valid := false.B | ||||
|     io.in.c.ready := true.B | ||||
|     io.in.e.ready := true.B | ||||
|     io.out.b.ready := true.B | ||||
|     io.out.c.valid := false.B | ||||
|     io.out.e.valid := false.B | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| object TLBufferModule { | ||||
|   def apply | ||||
|   ( | ||||
|     edgeIn: TLEdgeIn, | ||||
|     edgeOut: TLEdgeOut, | ||||
|     in: TLBundle, | ||||
|     a: BufferParams = BufferParams.default, | ||||
|     b: BufferParams = BufferParams.default, | ||||
|     c: BufferParams = BufferParams.default, | ||||
|     d: BufferParams = BufferParams.default, | ||||
|     e: BufferParams = BufferParams.default, | ||||
|     name: Option[String] = None | ||||
|   ): TLBundle = { | ||||
|     val bce = edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe | ||||
|     val mod = Module(new TLBufferModule(edgeIn, bce, a, b, c, d, e)) | ||||
|     name.map(mod.suggestName(_)) | ||||
|     mod.io.in <> in | ||||
|     mod.io.out | ||||
|   } | ||||
| } | ||||
|  | @ -32,6 +32,7 @@ import xiangshan.frontend.CGHPtr | |||
| import xiangshan.frontend.FtqRead | ||||
| import xiangshan.frontend.FtqToCtrlIO | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| import scala.math.max | ||||
| import Chisel.experimental.chiselName | ||||
|  |  | |||
|  | @ -244,7 +244,8 @@ case class XSCoreParameters | |||
|   )), | ||||
|   L2NBanks: Int = 1, | ||||
|   usePTWRepeater: Boolean = false, | ||||
|   softPTW: Boolean = false // dpi-c debug only | ||||
|   softPTW: Boolean = false, // dpi-c debug only | ||||
|   softPTWDelay: Int = 1 | ||||
| ){ | ||||
|   val allHistLens = SCHistLens ++ ITTageTableInfos.map(_._2) ++ TageTableInfos.map(_._2) :+ UbtbGHRLength | ||||
|   val HistoryLength = allHistLens.max + numBr * FtqSize + 9 // 256 for the predictor configs now | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ import freechips.rocketchip.tile.HasFPUParameters | |||
| import freechips.rocketchip.tilelink.TLBuffer | ||||
| import system.HasSoCParameter | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend._ | ||||
| import xiangshan.backend.exu.{ExuConfig, Wb2Ctrl, WbArbiterWrapper} | ||||
| import xiangshan.cache.mmu._ | ||||
|  | @ -137,10 +138,12 @@ abstract class XSCoreBase()(implicit p: config.Parameters) extends LazyModule | |||
|   // outer facing nodes | ||||
|   val frontend = LazyModule(new Frontend()) | ||||
|   val ptw = LazyModule(new L2TLBWrapper()) | ||||
|   val ptw_to_l2_buffer = LazyModule(new TLBuffer) | ||||
|   val ptw_to_l2_buffer = if (!coreParams.softPTW) LazyModule(new TLBuffer) else null | ||||
|   val csrOut = BundleBridgeSource(Some(() => new DistributedCSRIO())) | ||||
| 
 | ||||
|   if (!coreParams.softPTW) { | ||||
|     ptw_to_l2_buffer.node := ptw.node | ||||
|   } | ||||
| 
 | ||||
|   val wbArbiter = LazyModule(new WbArbiterWrapper(exuConfigs, NRIntWritePorts, NRFpWritePorts)) | ||||
|   val intWbPorts: Seq[Seq[ExuConfig]] = wbArbiter.intWbPorts | ||||
|  | @ -294,7 +297,7 @@ class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) | |||
|   val wb2Ctrl = outer.wb2Ctrl.module | ||||
|   val memBlock = outer.memBlock.module | ||||
|   val ptw = outer.ptw.module | ||||
|   val ptw_to_l2_buffer = outer.ptw_to_l2_buffer.module | ||||
|   val ptw_to_l2_buffer = if (!coreParams.softPTW) outer.ptw_to_l2_buffer.module else null | ||||
|   val exuBlocks = outer.exuBlocks.map(_.module) | ||||
| 
 | ||||
|   frontend.io.hartId  := io.hartId | ||||
|  | @ -400,7 +403,11 @@ class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) | |||
| 
 | ||||
|   ctrlBlock.perfinfo.perfEventsEu0 := exuBlocks(0).getPerf.dropRight(outer.exuBlocks(0).scheduler.numRs) | ||||
|   ctrlBlock.perfinfo.perfEventsEu1 := exuBlocks(1).getPerf.dropRight(outer.exuBlocks(1).scheduler.numRs) | ||||
|   if (!coreParams.softPTW) { | ||||
|     memBlock.io.perfEventsPTW := ptw.getPerf | ||||
|   } else { | ||||
|     memBlock.io.perfEventsPTW := DontCare | ||||
|   } | ||||
|   ctrlBlock.perfinfo.perfEventsRs  := outer.exuBlocks.flatMap(b => b.module.getPerf.takeRight(b.scheduler.numRs)) | ||||
| 
 | ||||
|   csrioIn.hartId <> io.hartId | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ import huancun.debug.TLLogger | |||
| import huancun.{HCCacheParamsKey, HuanCun} | ||||
| import system.HasSoCParameter | ||||
| import top.BusPerfMonitor | ||||
| import utils.{DelayN, ResetGen, TLClientsMerger, TLEdgeBuffer} | ||||
| import utility.{DelayN, ResetGen, TLClientsMerger, TLEdgeBuffer} | ||||
| 
 | ||||
| class L1BusErrorUnitInfo(implicit val p: Parameters) extends Bundle with HasSoCParameter { | ||||
|   val ecc_error = Valid(UInt(soc.PAddrBits.W))  | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.decode.{DecodeStage, FusionDecoder, ImmUnion} | ||||
| import xiangshan.backend.dispatch.{Dispatch, Dispatch2Rs, DispatchQueue} | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.exu._ | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.experimental.hierarchy.Instance | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.exu._ | ||||
| import xiangshan.backend.fu.CSRFileIO | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import freechips.rocketchip.tile.HasFPUParameters | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.exu.StdExeUnit | ||||
| import xiangshan.backend.fu._ | ||||
|  | @ -269,6 +270,8 @@ class MemBlockImp(outer: MemBlock) extends LazyModuleImp(outer) | |||
|     // forward | ||||
|     loadUnits(i).io.lsq.forward <> lsq.io.forward(i) | ||||
|     loadUnits(i).io.sbuffer <> sbuffer.io.forward(i) | ||||
|     loadUnits(i).io.tlDchannel := dcache.io.lsu.forward_D(i) | ||||
|     loadUnits(i).io.forward_mshr <> dcache.io.lsu.forward_mshr(i) | ||||
|     // ld-ld violation check | ||||
|     loadUnits(i).io.lsq.loadViolationQuery <> lsq.io.loadViolationQuery(i) | ||||
|     loadUnits(i).io.csrCtrl       <> csrCtrl | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import difftest.{DifftestArchFpRegState, DifftestArchIntRegState, DifftestArchVecRegState} | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.dispatch.Dispatch2Rs | ||||
| import xiangshan.backend.exu.ExuConfig | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.rename.RatReadPort | ||||
| 
 | ||||
| class DecodeStage(implicit p: Parameters) extends XSModule with HasPerfEvents { | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import freechips.rocketchip.rocket.Instructions | ||||
| import freechips.rocketchip.util.uintToBitPat | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.ExceptionNO.illegalInstr | ||||
| import xiangshan._ | ||||
| import freechips.rocketchip.rocket.Instructions._ | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import freechips.rocketchip.rocket.Instructions | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| 
 | ||||
| abstract class BaseFusionCase(pair: Seq[Valid[UInt]])(implicit p: Parameters) | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import difftest._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.ExceptionNO._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.rob.RobEnqIO | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.exu.ExuConfig | ||||
| import xiangshan.backend.rename.BusyTableReadIO | ||||
| import xiangshan.mem.LsqEnqIO | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.rob.RobPtr | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class IndexMapping(inWidth: Int, outWidth: Int, withPriority: Boolean)(implicit p: Parameters) extends XSModule { | ||||
|   val io = IO(new Bundle() { | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3._ | |||
| import chisel3.experimental.hierarchy.{Definition, instantiable, public} | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu.fpu.{FMA, FPUSubModule} | ||||
| import xiangshan.backend.fu.{CSR, FUWithRedirect, Fence, FenceToSbuffer} | ||||
|  |  | |||
|  | @ -20,7 +20,8 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.experimental.hierarchy.{IsLookupable, instantiable, public} | ||||
| import chisel3.util._ | ||||
| import utils.{XSPerfAccumulate, ZeroExt} | ||||
| import utils.XSPerfAccumulate | ||||
| import utility.ZeroExt | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu._ | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu._ | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import difftest.{DifftestFpWriteback, DifftestIntWriteback} | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.ExceptionNO._ | ||||
| import xiangshan.backend.HasExuWbHelper | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ package xiangshan.backend.fu | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils.{LookupTree, LookupTreeDefault, ParallelMux, SignExt, ZeroExt} | ||||
| import utility.{LookupTree, LookupTreeDefault, ParallelMux, SignExt, ZeroExt} | ||||
| import xiangshan._ | ||||
| 
 | ||||
| class AddModule(implicit p: Parameters) extends XSModule { | ||||
|  |  | |||
|  | @ -19,7 +19,8 @@ package xiangshan.backend.fu | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils.{LookupTreeDefault, ParallelMux, ParallelXOR, SignExt, XSDebug, XSError, ZeroExt} | ||||
| import utility.{LookupTreeDefault, ParallelMux, ParallelXOR, SignExt, ZeroExt} | ||||
| import utils.{XSDebug, XSError} | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu.util._ | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,8 +21,9 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import difftest._ | ||||
| import freechips.rocketchip.util._ | ||||
| import utils.MaskedRegMap.WritableMask | ||||
| import utility.MaskedRegMap.WritableMask | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.ExceptionNO._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu.util._ | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.ExceptionNO.illegalInstr | ||||
| 
 | ||||
| class FenceToSbuffer extends Bundle { | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.issue.AgeDetector | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend._ | ||||
| import xiangshan.backend.decode.ImmUnion | ||||
| import xiangshan.backend.decode.isa._ | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.fu.util.{C22, C32, C53} | ||||
| 
 | ||||
| class MulDivCtrl extends Bundle{ | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ package xiangshan.backend.fu | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import freechips.rocketchip.regmapper.{RegField, RegFieldDesc, RegReadFn, RegWriteFn} | ||||
| import utils.{ParallelPriorityMux, ZeroExt, ValidHold} | ||||
| import utility.{ParallelPriorityMux, ZeroExt, ValidHold} | ||||
| import xiangshan.cache.mmu.TlbCmd | ||||
| 
 | ||||
| /* Memory Mapped PMA */ | ||||
|  |  | |||
|  | @ -22,10 +22,11 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.internal.naming.chiselName | ||||
| import chisel3.util._ | ||||
| import utils.MaskedRegMap.WritableMask | ||||
| import utility.MaskedRegMap.WritableMask | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu.util.HasCSRConst | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.cache.mmu.{TlbCmd, TlbExceptionBundle} | ||||
| 
 | ||||
| trait PMPConst extends HasPMParameters { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| abstract class AbstractDivider(len: Int)(implicit p: Parameters) extends FunctionUnit(len){ | ||||
|   val ctrl = IO(Input(new MulDivCtrl)) | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.fu.util.CSA3_2 | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ package xiangshan.backend.fu | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils.SignExt | ||||
| import utility.SignExt | ||||
| import xiangshan.backend.fu.util.CSA3_2 | ||||
| 
 | ||||
| /** A Radix-4 SRT Integer Divider | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import chisel3._ | |||
| import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} | ||||
| import chisel3.util._ | ||||
| import fudian.FDIV | ||||
| import utils.MaskExpand | ||||
| import utility.MaskExpand | ||||
| 
 | ||||
| import scala.collection.mutable | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import fudian.utils.Multiplier | |||
| import fudian.{FCMA, FCMA_ADD, FCMA_ADD_s1, FCMA_ADD_s2, FMUL, FMULToFADD, FMUL_s1, FMUL_s2, FMUL_s3, RawFloat} | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| class MulToAddIO(val ftypes: Seq[FPU.FType])(implicit val p: Parameters) extends Bundle { | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ import chipsalliance.rocketchip.config.Parameters | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import fudian.FCMP | ||||
| import utils.SignExt | ||||
| import utility.SignExt | ||||
| import xiangshan._ | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ package xiangshan.backend.fu.fpu | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils.{SignExt, ZeroExt} | ||||
| import utility.{SignExt, ZeroExt} | ||||
| import xiangshan.backend.fu.HasPipelineReg | ||||
| import xiangshan.i2fCfg | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,9 +19,9 @@ package xiangshan.backend.fu.util | |||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend._ | ||||
| import utils.XSDebug | ||||
| 
 | ||||
| trait HasCSRConst { | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| class BypassInfo(numWays: Int, dataBits: Int) extends Bundle { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.decode.{ImmUnion, Imm_LUI_LOAD, Imm_U} | ||||
| import xiangshan.backend.exu.ExuConfig | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class PayloadArrayReadIO[T <: Data](gen: T, params: RSParams) extends Bundle { | ||||
|   val addr = Input(UInt(params.numEntries.W)) | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.exu.ExuConfig | ||||
| import xiangshan.backend.fu.FuConfig | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class SelectPolicy(params: RSParams)(implicit p: Parameters) extends XSModule { | ||||
|   val io = IO(new Bundle { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.rob.RobPtr | ||||
| import xiangshan.mem.{SqPtr, MemWaitUpdateReq} | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class WakeupQueue(number: Int)(implicit p: Parameters) extends XSModule { | ||||
|   val io = IO(new Bundle { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| class BusyTableReadIO(implicit p: Parameters) extends XSBundle { | ||||
|   val req = Input(UInt(PhyRegIdxWidth.W)) | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan.backend.decode.{FusionDecodeInfo, Imm_I, Imm_LUI_LOAD, Imm_U} | ||||
| import xiangshan.backend.rob.RobPtr | ||||
| import xiangshan.backend.rename.freelist._ | ||||
|  |  | |||
|  | @ -19,7 +19,8 @@ package xiangshan.backend.rename | |||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import chisel3._ | ||||
| import chisel3.util._ | ||||
| import utils.{ParallelPriorityMux, XSError} | ||||
| import utility.ParallelPriorityMux | ||||
| import utils.XSError | ||||
| import xiangshan._ | ||||
| 
 | ||||
| abstract class RegType | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| abstract class BaseFreeList(size: Int)(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| class MEFreeList(size: Int)(implicit p: Parameters) extends BaseFreeList(size) with HasPerfEvents { | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import chisel3._ | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| 
 | ||||
| 
 | ||||
| class StdFreeList(size: Int)(implicit p: Parameters) extends BaseFreeList(size) with HasPerfEvents { | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import chisel3.util._ | |||
| import difftest._ | ||||
| import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} | ||||
| import utils._ | ||||
| import utility._ | ||||
| import xiangshan._ | ||||
| import xiangshan.backend.exu.ExuConfig | ||||
| import xiangshan.frontend.FtqPtr | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import chisel3.util._ | |||
| import xiangshan._ | ||||
| import xiangshan.frontend.icache._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import chipsalliance.rocketchip.config.Parameters | ||||
| import xiangshan.backend.fu.util.HasCSRConst | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,12 +22,13 @@ import chisel3.experimental.ExtModule | |||
| import chisel3.util._ | ||||
| import xiangshan._ | ||||
| import utils._ | ||||
| import utility._ | ||||
| import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes} | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util.{BundleFieldBase, UIntToOH1} | ||||
| import device.RAMHelper | ||||
| import huancun.{AliasField, AliasKey, DirtyField, PreferCacheField, PrefetchField} | ||||
| import huancun.utils.FastArbiter | ||||
| import utility.FastArbiter | ||||
| import mem.{AddPipelineReg} | ||||
| 
 | ||||
| import scala.math.max | ||||
|  | @ -335,6 +336,7 @@ class BankedDCacheWordResp(implicit p: Parameters) extends DCacheWordResp | |||
| { | ||||
|   val bank_data = Vec(DCacheBanks, Bits(DCacheSRAMRowBits.W)) | ||||
|   val bank_oh = UInt(DCacheBanks.W) | ||||
|   val mshr_id = UInt(log2Up(cfg.nMissEntries).W) | ||||
| } | ||||
| 
 | ||||
| class DCacheWordRespWithError(implicit p: Parameters) extends BaseDCacheWordResp | ||||
|  | @ -368,6 +370,7 @@ class Refill(implicit p: Parameters) extends DCacheBundle | |||
|   def dump() = { | ||||
|     XSDebug("Refill: addr: %x data: %x\n", addr, data) | ||||
|   } | ||||
|   val id     = UInt(log2Up(cfg.nMissEntries).W) | ||||
| } | ||||
| 
 | ||||
| class Release(implicit p: Parameters) extends DCacheBundle | ||||
|  | @ -478,12 +481,128 @@ class DCacheToSbufferIO(implicit p: Parameters) extends DCacheBundle { | |||
|   def hit_resps: Seq[ValidIO[DCacheLineResp]] = Seq(main_pipe_hit_resp, refill_hit_resp) | ||||
| } | ||||
| 
 | ||||
| // forward tilelink channel D's data to ldu | ||||
| class DcacheToLduForwardIO(implicit p: Parameters) extends DCacheBundle { | ||||
|   val valid = Bool() | ||||
|   val data = UInt(l1BusDataWidth.W) | ||||
|   val mshrid = UInt(log2Up(cfg.nMissEntries).W) | ||||
|   val last = Bool() | ||||
| 
 | ||||
|   def apply(req_valid : Bool, req_data : UInt, req_mshrid : UInt, req_last : Bool) = { | ||||
|     valid := req_valid | ||||
|     data := req_data | ||||
|     mshrid := req_mshrid | ||||
|     last := req_last | ||||
|   } | ||||
| 
 | ||||
|   def dontCare() = { | ||||
|     valid := false.B | ||||
|     data := DontCare | ||||
|     mshrid := DontCare | ||||
|     last := DontCare | ||||
|   } | ||||
| 
 | ||||
|   def forward(req_valid : Bool, req_mshr_id : UInt, req_paddr : UInt) = { | ||||
|     val all_match = req_valid && valid && | ||||
|                 req_mshr_id === mshrid && | ||||
|                 req_paddr(log2Up(refillBytes)) === last | ||||
| 
 | ||||
|     val forward_D = RegInit(false.B) | ||||
|     val forwardData = RegInit(VecInit(List.fill(8)(0.U(8.W)))) | ||||
| 
 | ||||
|     val block_idx = req_paddr(log2Up(refillBytes) - 1, 3) | ||||
|     val block_data = Wire(Vec(l1BusDataWidth / 64, UInt(64.W))) | ||||
|     (0 until l1BusDataWidth / 64).map(i => { | ||||
|       block_data(i) := data(64 * i + 63, 64 * i) | ||||
|     }) | ||||
|     val selected_data = block_data(block_idx) | ||||
| 
 | ||||
|     forward_D := all_match | ||||
|     for (i <- 0 until 8) { | ||||
|       forwardData(i) := selected_data(8 * i + 7, 8 * i) | ||||
|     } | ||||
| 
 | ||||
|     (forward_D, forwardData) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class MissEntryForwardIO(implicit p: Parameters) extends DCacheBundle { | ||||
|   val inflight = Bool() | ||||
|   val paddr = UInt(PAddrBits.W) | ||||
|   val raw_data = Vec(blockBytes/beatBytes, UInt(beatBits.W)) | ||||
|   val firstbeat_valid = Bool() | ||||
|   val lastbeat_valid = Bool() | ||||
| 
 | ||||
|   def apply(mshr_valid : Bool, mshr_paddr : UInt, mshr_rawdata : Vec[UInt], mshr_first_valid : Bool, mshr_last_valid : Bool) = { | ||||
|     inflight := mshr_valid | ||||
|     paddr := mshr_paddr | ||||
|     raw_data := mshr_rawdata | ||||
|     firstbeat_valid := mshr_first_valid | ||||
|     lastbeat_valid := mshr_last_valid | ||||
|   } | ||||
| 
 | ||||
|   // check if we can forward from mshr or D channel | ||||
|   def check(req_valid : Bool, req_paddr : UInt) = { | ||||
|     RegNext(req_valid && inflight && req_paddr(PAddrBits - 1, blockOffBits) === paddr(PAddrBits - 1, blockOffBits)) | ||||
|   } | ||||
| 
 | ||||
|   def forward(req_valid : Bool, req_paddr : UInt) = { | ||||
|     val all_match = (req_paddr(log2Up(refillBytes)) === 0.U && firstbeat_valid) ||  | ||||
|                     (req_paddr(log2Up(refillBytes)) === 1.U && lastbeat_valid) | ||||
| 
 | ||||
|     val forward_mshr = RegInit(false.B) | ||||
|     val forwardData = RegInit(VecInit(List.fill(8)(0.U(8.W)))) | ||||
| 
 | ||||
|     val beat_data = raw_data(req_paddr(log2Up(refillBytes))) | ||||
|     val block_idx = req_paddr(log2Up(refillBytes) - 1, 3) | ||||
|     val block_data = Wire(Vec(l1BusDataWidth / 64, UInt(64.W))) | ||||
|     (0 until l1BusDataWidth / 64).map(i => { | ||||
|       block_data(i) := beat_data(64 * i + 63, 64 * i) | ||||
|     }) | ||||
|     val selected_data = block_data(block_idx) | ||||
| 
 | ||||
|     forward_mshr := all_match | ||||
|     for (i <- 0 until 8) { | ||||
|       forwardData(i) := selected_data(8 * i + 7, 8 * i) | ||||
|     } | ||||
| 
 | ||||
|     (forward_mshr, forwardData) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // forward mshr's data to ldu | ||||
| class LduToMissqueueForwardIO(implicit p: Parameters) extends DCacheBundle { | ||||
|   // req | ||||
|   val valid = Input(Bool()) | ||||
|   val mshrid = Input(UInt(log2Up(cfg.nMissEntries).W)) | ||||
|   val paddr = Input(UInt(PAddrBits.W)) | ||||
|   // resp | ||||
|   val forward_mshr = Output(Bool()) | ||||
|   val forwardData = Output(Vec(8, UInt(8.W))) | ||||
|   val forward_result_valid = Output(Bool()) | ||||
| 
 | ||||
|   def connect(sink: LduToMissqueueForwardIO) = { | ||||
|     sink.valid := valid | ||||
|     sink.mshrid := mshrid | ||||
|     sink.paddr := paddr | ||||
|     forward_mshr := sink.forward_mshr | ||||
|     forwardData := sink.forwardData | ||||
|     forward_result_valid := sink.forward_result_valid | ||||
|   } | ||||
| 
 | ||||
|   def forward() = { | ||||
|     (forward_result_valid, forward_mshr, forwardData) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DCacheToLsuIO(implicit p: Parameters) extends DCacheBundle { | ||||
|   val load  = Vec(LoadPipelineWidth, Flipped(new DCacheLoadIO)) // for speculative load | ||||
|   val lsq = ValidIO(new Refill)  // refill to load queue, wake up load misses | ||||
|   val store = new DCacheToSbufferIO // for sbuffer | ||||
|   val atomics  = Flipped(new AtomicWordIO)  // atomics reqs | ||||
|   val release = ValidIO(new Release) // cacheline release hint for ld-ld violation check  | ||||
|   val forward_D = Output(Vec(LoadPipelineWidth, new DcacheToLduForwardIO)) | ||||
|   val forward_mshr = Vec(LoadPipelineWidth, new LduToMissqueueForwardIO) | ||||
| } | ||||
| 
 | ||||
| class DCacheIO(implicit p: Parameters) extends DCacheBundle { | ||||
|  | @ -637,6 +756,15 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame | |||
|     ldu(i).io.banked_data_resp := bankedDataArray.io.resp | ||||
|   }) | ||||
| 
 | ||||
|   (0 until LoadPipelineWidth).map(i => { | ||||
|     val (_, _, done, _) = edge.count(bus.d) | ||||
|     when(bus.d.bits.opcode === TLMessages.GrantData) { | ||||
|       io.lsu.forward_D(i).apply(bus.d.valid, bus.d.bits.data, bus.d.bits.source, done) | ||||
|     }.otherwise { | ||||
|       io.lsu.forward_D(i).dontCare() | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   //---------------------------------------- | ||||
|   // load pipe | ||||
|   // the s1 kill signal | ||||
|  | @ -672,6 +800,8 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame | |||
|   missReqArb.io.in(MainPipeMissReqPort) <> mainPipe.io.miss_req | ||||
|   for (w <- 0 until LoadPipelineWidth) { missReqArb.io.in(w + 1) <> ldu(w).io.miss_req } | ||||
| 
 | ||||
|   for (w <- 0 until LoadPipelineWidth) { ldu(w).io.miss_resp.id := missQueue.io.resp.id } | ||||
| 
 | ||||
|   wb.io.miss_req.valid := missReqArb.io.out.valid | ||||
|   wb.io.miss_req.bits  := missReqArb.io.out.bits.addr | ||||
| 
 | ||||
|  | @ -682,6 +812,9 @@ class DCacheImp(outer: DCache) extends LazyModuleImp(outer) with HasDCacheParame | |||
|     missReqArb.io.out.ready := false.B | ||||
|   } | ||||
| 
 | ||||
|   // forward missqueue | ||||
|   (0 until LoadPipelineWidth).map(i => io.lsu.forward_mshr(i).connect(missQueue.io.forward(i))) | ||||
| 
 | ||||
|   // refill to load queue | ||||
|   io.lsu.lsq <> missQueue.io.refill_to_ldq | ||||
| 
 | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue