Skip to content

Commit 992ce71

Browse files
authored
feat(Sram): add SRAM_CTL interface (#108)
* add SRAM CTL interface, include: * **MCR** * **MCW** * **RTSEL** * **WTSEL** * **RCT** * **WCT** * **KP**
1 parent 2bf294f commit 992ce71

File tree

5 files changed

+82
-30
lines changed

5 files changed

+82
-30
lines changed

src/main/scala/utility/mbist/MbistClockGateCell.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ class CgDftBundle extends Bundle {
2525
val ram_aux_ckbp = Input(Bool())
2626
val cgen = Input(Bool())
2727
def fromBroadcast(brc: SramBroadcastBundle): Unit = {
28-
ram_aux_clk := brc.ram_aux_clk
29-
ram_aux_ckbp := brc.ram_aux_ckbp
30-
ram_mcp_hold := brc.ram_mcp_hold
31-
cgen := brc.cgen
28+
ram_aux_clk := brc.mbist.ram_aux_clk
29+
ram_aux_ckbp := brc.mbist.ram_aux_ckbp
30+
ram_mcp_hold := brc.mbist.ram_mcp_hold
31+
cgen := brc.mbist.cgen
3232
}
3333
}
3434

src/main/scala/utility/sram/SRAMTemplate.scala

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class SRAMWriteBus[T <: Data](
139139
* @param latency output setup multicycle, witch means how many cycles the data is ready for capture after read sampling clock edge.
140140
* @param extraHold enable a extra input hold cycle. User should keep all input for one cycle if this option is enabled.
141141
* @param extClockGate expose clock control signals to IOs to support using external clock gate when doing MBIST.
142+
* @param hasSramCtl enable sram ctl support.
142143
* @param suffix add suffix in the name of SRAM wrapper
143144
*/
144145

@@ -149,7 +150,8 @@ class SRAMTemplate[T <: Data](
149150
useBitmask: Boolean = false, withClockGate: Boolean = false,
150151
separateGateClock: Boolean = false,
151152
hasMbist: Boolean = false, latency: Int = 1, extraHold:Boolean = false,
152-
extClockGate: Boolean = false, suffix: Option[String] = None
153+
extClockGate: Boolean = false, hasSramCtl: Boolean = false,
154+
suffix: Option[String] = None
153155
)(implicit valName: sourcecode.FullName) extends Module {
154156
val io = IO(new Bundle {
155157
val r = Flipped(new SRAMReadBus(gen, set, way))
@@ -191,6 +193,7 @@ class SRAMTemplate[T <: Data](
191193
latency = latency,
192194
bist = hasMbist,
193195
broadcast = io.broadcast,
196+
hasSramCtl = hasSramCtl,
194197
rclk,
195198
Some(wclk),
196199
suffix = suffix.getOrElse(SramHelper.getSramSuffix(valName.value)),
@@ -264,7 +267,7 @@ class SRAMTemplate[T <: Data](
264267
}
265268

266269
private val ramRdata = SramProto.read(array, singlePort, ramRaddr, ramRen)
267-
when(ramWen && !brcBd.ram_hold) {
270+
when(ramWen && !brcBd.mbist.ram_hold) {
268271
SramProto.write(array, singlePort, ramWaddr, ramWdata, ramWmask)
269272
}
270273

@@ -338,7 +341,7 @@ class SRAMTemplate[T <: Data](
338341

339342
/**
340343
* Split large SRAM into smaller ones. This class draws inspiration from coupledL2-SplittedSRAM
341-
* Since the SplittedSRAM class cannot be fully compatible with the parameters of the
344+
* Since the SplittedSRAM class cannot be fully compatible with the parameters of the
342345
* FoldedSRAMTemplate class, the SplittedSRAMTemplate class is therefore defined.
343346
*/
344347
class SplittedSRAMTemplate[T <: Data]
@@ -351,7 +354,8 @@ class SplittedSRAMTemplate[T <: Data]
351354
useBitmask: Boolean = false, withClockGate: Boolean = false,
352355
separateGateClock: Boolean = false,
353356
hasMbist: Boolean = false, latency: Int = 1, extraHold:Boolean = false,
354-
extClockGate: Boolean = false, suffix: Option[String] = None
357+
extClockGate: Boolean = false, hasSramCtl: Boolean = false,
358+
suffix: Option[String] = None
355359
)(implicit valName: sourcecode.FullName) extends Module {
356360
val io = IO(new Bundle() {
357361
val r = Flipped(new SRAMReadBus(gen, set, way))
@@ -381,7 +385,8 @@ class SplittedSRAMTemplate[T <: Data]
381385
holdRead, bypassWrite,
382386
useBitmask,withClockGate,
383387
separateGateClock, hasMbist, latency, extraHold,
384-
extClockGate, Some(suffix.getOrElse(SramHelper.getSramSuffix(valName.value)))
388+
extClockGate, hasSramCtl,
389+
Some(suffix.getOrElse(SramHelper.getSramSuffix(valName.value)))
385390
))
386391
)))
387392

@@ -399,7 +404,6 @@ class SplittedSRAMTemplate[T <: Data]
399404
if (array(i)(j)(k).extra_reset.isDefined) {
400405
array(i)(j)(k).extra_reset.get := extra_reset.get
401406
}
402-
403407
array(i)(j)(k).io.r.req.bits.apply(r_setIdx)
404408
array(i)(j)(k).io.r.req.valid := io.r.req.valid && ren
405409
array(i)(j)(k).io.w.req.valid := io.w.req.valid && wen // && needWrite
@@ -412,7 +416,7 @@ class SplittedSRAMTemplate[T <: Data]
412416
array(i)(j)(k).io.w.req.bits.apply(
413417
VecInit(io.w.req.bits.data.slice(innerWays * j, innerWays * (j+1)).map(_.asUInt(innerWidth * (k+1) - 1, innerWidth * k))),
414418
w_setIdx, waymask
415-
)
419+
)
416420
}
417421

418422
}
@@ -470,7 +474,8 @@ class FoldedSRAMTemplate[T <: Data](
470474
bypassWrite: Boolean = false, useBitmask: Boolean = false,
471475
withClockGate: Boolean = false, avoidSameAddr: Boolean = false,
472476
separateGateClock: Boolean = false, // no effect, only supports independent RW cg, only for API compatibility
473-
hasMbist: Boolean = false, latency: Int = 1, suffix: Option[String] = None
477+
hasMbist: Boolean = false, latency: Int = 1,
478+
hasSramCtl: Boolean = false, suffix: Option[String] = None
474479
)(implicit valName: sourcecode.FullName) extends Module {
475480
val io = IO(new Bundle {
476481
val r = Flipped(new SRAMReadBus(gen, set, way))
@@ -491,7 +496,7 @@ class FoldedSRAMTemplate[T <: Data](
491496
shouldReset=shouldReset, extraReset=extraReset, holdRead=holdRead,
492497
singlePort=singlePort, bypassWrite=bypassWrite, useBitmask=useBitmask,
493498
withClockGate=withClockGate, separateGateClock=separateGateClock,
494-
hasMbist=hasMbist, latency=latency, extraHold = false,
499+
hasMbist=hasMbist, latency=latency, extraHold = false, hasSramCtl = hasSramCtl,
495500
suffix = Some(suffix.getOrElse(SramHelper.getSramSuffix(valName.value)))))
496501
if (array.extra_reset.isDefined) {
497502
array.extra_reset.get := extra_reset.get
@@ -580,14 +585,15 @@ class FoldedSRAMTemplate[T <: Data](
580585
}
581586
}
582587
class SRAMTemplateWithArbiter[T <: Data](nRead: Int, gen: T, set: Int, way: Int = 1,
583-
shouldReset: Boolean = false, hasMbist:Boolean = false, latency:Int = 1) extends Module {
588+
shouldReset: Boolean = false, hasMbist:Boolean = false, latency:Int = 1,
589+
hasSramCtl: Boolean = false) extends Module {
584590
val io = IO(new Bundle {
585591
val r = Flipped(Vec(nRead, new SRAMReadBus(gen, set, way)))
586592
val w = Flipped(new SRAMWriteBus(gen, set, way))
587593
})
588594

589595
val ram = Module(new SRAMTemplate(gen, set, way, shouldReset = shouldReset, holdRead = false, singlePort = true,
590-
hasMbist = hasMbist, latency = latency))
596+
hasMbist = hasMbist, latency = latency, hasSramCtl = hasSramCtl))
591597
ram.io.w <> io.w
592598

593599
val readArb = Module(new Arbiter(chiselTypeOf(io.r(0).req.bits), nRead))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**************************************************************************************
2+
* Copyright (c) 2025 Institute of Computing Technology, CAS
3+
* Copyright (c) 2025 University of Chinese Academy of Sciences
4+
*
5+
* NutShell is licensed under Mulan PSL v2.
6+
* You can use this software according to the terms and conditions of the Mulan PSL v2.
7+
* You may obtain a copy of Mulan PSL v2 at:
8+
* http://license.coscl.org.cn/MulanPSL2
9+
*
10+
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
11+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
12+
* FIT FOR A PARTICULAR PURPOSE.
13+
*
14+
* See the Mulan PSL v2 for more details.
15+
***************************************************************************************/
16+
17+
package utility.sram
18+
19+
import chisel3._
20+
import chisel3.util._
21+
import chisel3.experimental.hierarchy.core.Instance
22+
23+
class SramCtlBundle extends Bundle {
24+
val MCR = UInt(2.W)
25+
val MCW = UInt(2.W)
26+
val RTSEL = UInt(2.W)
27+
val WTSEL = UInt(2.W)
28+
val RCT = UInt(2.W)
29+
val WCT = UInt(2.W)
30+
val KP = UInt(3.W)
31+
}

src/main/scala/utility/sram/SramHelper.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ object SramHelper {
134134
latency: Int,
135135
bist: Boolean,
136136
broadcast: Option[SramBroadcastBundle],
137+
hasSramCtl: Boolean,
137138
rclk: Clock,
138139
wclk: Option[Clock],
139140
suffix: String,
@@ -142,7 +143,7 @@ object SramHelper {
142143
template: RawModule
143144
): (Ram2Mbist, Instance[SramArray], String) = {
144145

145-
val (array, vname) = SramProto(rclk, !dp, set, sp.sramDataBits, sp.sramMaskBits, setup, hold, latency, wclk, bist || broadcast.isDefined, suffix)
146+
val (array, vname) = SramProto(rclk, !dp, set, sp.sramDataBits, sp.sramMaskBits, setup, hold, latency, wclk, bist || broadcast.isDefined, hasSramCtl || broadcast.isDefined, suffix)
146147
val bdParam = Ram2MbistParams(
147148
sp,
148149
set,
@@ -164,8 +165,11 @@ object SramHelper {
164165
mbist.re := false.B
165166
mbist.wmask := Fill(sp.mbistMaskWidth, true.B)
166167
if(broadcast.isDefined || bist) {
167-
array.mbist.get.dft_ram_bp_clken := broadcast.get.ram_bp_clken
168-
array.mbist.get.dft_ram_bypass := broadcast.get.ram_bypass
168+
array.mbist.get.dft_ram_bp_clken := broadcast.get.mbist.ram_bp_clken
169+
array.mbist.get.dft_ram_bypass := broadcast.get.mbist.ram_bypass
170+
}
171+
if(broadcast.isDefined || hasSramCtl) {
172+
array.sramCtl.get := broadcast.get.sramCtl
169173
}
170174
if(bist) {
171175
dontTouch(mbist)

src/main/scala/utility/sram/SramProto.scala

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,19 @@ class SramMbistIO extends Bundle {
2828
val dft_ram_bp_clken = Input(Bool())
2929
}
3030

31+
class SramMbistBundle extends Bundle {
32+
val ram_hold = Bool()
33+
val ram_bypass = Bool()
34+
val ram_bp_clken = Bool()
35+
val ram_aux_clk = Bool()
36+
val ram_aux_ckbp = Bool()
37+
val ram_mcp_hold = Bool()
38+
val cgen = Bool()
39+
}
40+
3141
class SramBroadcastBundle extends Bundle {
32-
val ram_hold = Input(Bool())
33-
val ram_bypass = Input(Bool())
34-
val ram_bp_clken = Input(Bool())
35-
val ram_aux_clk = Input(Bool())
36-
val ram_aux_ckbp = Input(Bool())
37-
val ram_mcp_hold = Input(Bool())
38-
val cgen = Input(Bool())
42+
val mbist = Input(new SramMbistBundle)
43+
val sramCtl = Input(new SramCtlBundle)
3944
}
4045

4146
@instantiable
@@ -44,13 +49,16 @@ abstract class SramArray(
4449
width: Int,
4550
maskSegments: Int,
4651
hasMbist: Boolean,
52+
hasSramCtl: Boolean,
4753
sramName: Option[String] = None,
4854
singlePort: Boolean
4955
)
5056
extends RawModule {
5157
require(width % maskSegments == 0)
5258
@public val mbist = if(hasMbist) Some(IO(new SramMbistIO)) else None
5359
mbist.foreach(dontTouch(_))
60+
@public val sramCtl = Option.when(hasSramCtl)(IO(Input(new SramCtlBundle)))
61+
sramCtl.foreach(dontTouch(_))
5462

5563
@public val RW0 = if(singlePort) {
5664
Some(IO(new Bundle() {
@@ -98,8 +106,9 @@ class SramArray1P(
98106
width: Int,
99107
maskSegments: Int,
100108
hasMbist: Boolean,
109+
hasSramCtl: Boolean,
101110
sramName: Option[String] = None,
102-
) extends SramArray(depth, width, maskSegments, hasMbist, sramName, true) {
111+
) extends SramArray(depth, width, maskSegments, hasMbist, hasSramCtl, sramName, true) {
103112
if(maskSegments > 1) {
104113
val dataType = Vec(maskSegments, UInt((width / maskSegments).W))
105114
val array = SyncReadMem(depth, dataType)
@@ -129,8 +138,9 @@ class SramArray2P(
129138
width: Int,
130139
maskSegments: Int,
131140
hasMbist: Boolean,
141+
hasSramCtl: Boolean,
132142
sramName: Option[String] = None
133-
) extends SramArray(depth, width, maskSegments, hasMbist, sramName, false) {
143+
) extends SramArray(depth, width, maskSegments, hasMbist, hasSramCtl, sramName, false) {
134144

135145
if(maskSegments > 1) {
136146
val dataType = Vec(maskSegments, UInt((width / maskSegments).W))
@@ -208,6 +218,7 @@ object SramProto {
208218
latency: Int,
209219
writeClock: Option[Clock] = None,
210220
hasMbist: Boolean,
221+
hasSramCtl: Boolean,
211222
suffix: String = ""
212223
): (Instance[SramArray], String) = {
213224
val mcpStr = s"s${setup}h${hold}l${latency}"
@@ -217,14 +228,14 @@ object SramProto {
217228
val sramName = Some(s"sram_array_${numPort}p${depth}x${width}m$maskWidth$mcpStr${mbist}_$suffix")
218229
if(!defMap.contains(sramName.get)) {
219230
val sramDef = if(singlePort) {
220-
Definition(new SramArray1P(depth, width, maskSegments, hasMbist, sramName))
231+
Definition(new SramArray1P(depth, width, maskSegments, hasMbist, hasSramCtl, sramName))
221232
} else {
222-
Definition(new SramArray2P(depth, width, maskSegments, hasMbist, sramName))
233+
Definition(new SramArray2P(depth, width, maskSegments, hasMbist, hasSramCtl, sramName))
223234
}
224235
defMap(sramName.get) = sramDef
225236
}
226237
val array = Instance(defMap(sramName.get))
227238
SramProto.init(array, singlePort, clock, writeClock)
228239
(array, sramName.get)
229240
}
230-
}
241+
}

0 commit comments

Comments
 (0)