1
0

Merge pull request #994 from freechipsproject/beu

Add L1 bus-error unit
This commit is contained in:
Andrew Waterman 2017-09-20 12:17:08 -07:00 committed by GitHub
commit f1a506476b
12 changed files with 210 additions and 24 deletions

View File

@ -84,6 +84,8 @@ trait HasRocketTiles extends HasSystemBus
lip.foreach { coreIntXbar.intnode := _ } // lip
wrapper.coreIntNode := coreIntXbar.intnode
wrapper.intOutputNode.foreach { plic.intnode := _ }
wrapper
}
}

View File

@ -0,0 +1,76 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.rocket
import Chisel._
import Chisel.ImplicitConversions._
import chisel3.util.Valid
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
trait BusErrors extends Bundle {
def toErrorList: List[Option[Valid[UInt]]]
}
class L1BusErrors(implicit p: Parameters) extends CoreBundle()(p) with BusErrors {
val icache = new ICacheErrors
val dcache = new DCacheErrors
def toErrorList =
List(None, None, icache.correctable, icache.uncorrectable,
None, Some(dcache.bus), dcache.correctable, dcache.uncorrectable)
}
case class BusErrorUnitParams(addr: BigInt, size: Int = 4096)
class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit p: Parameters) extends LazyModule {
val regWidth = 64
val device = new SimpleDevice("bus-error-unit", Seq("sifive,buserror0"))
val intNode = IntSourceNode(IntSourcePortSimple(resources = device.int))
val node = TLRegisterNode(
address = Seq(AddressSet(params.addr, params.size-1)),
device = device,
beatBytes = p(XLen)/8)
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl = node.bundleIn
val interrupt = intNode.bundleOut
val errors = t.flip
}
val sources = io.errors.toErrorList
val mask = sources.map(_.nonEmpty.B).asUInt
val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)))
val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max))
require(value.getWidth <= regWidth)
val enable = Reg(init = mask)
val interrupt = Reg(init = UInt(0, sources.size))
val accrued = Reg(init = UInt(0, sources.size))
accrued := accrued | sources.map(_.map(_.valid).getOrElse(false.B)).asUInt
for ((s, i) <- sources.zipWithIndex; if s.nonEmpty) {
when (s.get.valid && enable(i) && cause === 0) {
cause := i
value := s.get.bits
}
}
io.interrupt.head(0) := (accrued & interrupt).orR
def reg(r: UInt) = RegField(regWidth, r)
def maskedReg(r: UInt, m: UInt) = RegField(regWidth, r, RegWriteFn((v, d) => { when (v) { r := d & m }; true }))
node.regmap(
0 -> Seq(reg(cause),
reg(value),
maskedReg(enable, mask),
maskedReg(interrupt, mask),
maskedReg(accrued, mask)))
}
}

View File

@ -11,6 +11,12 @@ import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._
import TLMessages._
class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val correctable = (cacheParams.tagECC.canCorrect || cacheParams.dataECC.canCorrect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
val bus = Valid(UInt(width = paddrBits))
}
class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val eccBytes = cacheParams.dataECCBytes
val addr = Bits(width = untagBits)
@ -216,9 +222,11 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
val s2_flush_valid_pre_tag_ecc = RegNext(s1_flush_valid)
val s1_meta_decoded = s1_meta.map(tECC.decode(_))
val s1_meta_clk_en = s1_valid_not_nacked || s1_flush_valid || s1_probe
val s2_meta_errors = s1_meta_decoded.map(m => RegEnable(m.error, s1_meta_clk_en)).asUInt
val s2_meta_correctable_errors = s1_meta_decoded.map(m => RegEnable(m.correctable, s1_meta_clk_en)).asUInt
val s2_meta_uncorrectable_errors = s1_meta_decoded.map(m => RegEnable(m.uncorrectable, s1_meta_clk_en)).asUInt
val s2_meta_error_uncorrectable = s2_meta_uncorrectable_errors.orR
val s2_meta_corrected = s1_meta_decoded.map(m => RegEnable(m.corrected, s1_meta_clk_en).asTypeOf(new L1Metadata))
val s2_meta_error = s2_meta_errors.orR
val s2_meta_error = (s2_meta_uncorrectable_errors | s2_meta_correctable_errors).orR
val s2_flush_valid = s2_flush_valid_pre_tag_ecc && !s2_meta_error
val s2_data = {
val en = s1_valid || inWriteback || tl_out.d.fire()
@ -242,6 +250,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
val s2_word_idx = s2_req.addr.extract(log2Up(rowBits/8)-1, log2Up(wordBytes))
val s2_did_read = RegEnable(s1_did_read, s1_valid_not_nacked)
val s2_data_error = s2_did_read && (s2_data_decoded.map(_.error).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx)
val s2_data_error_uncorrectable = (s2_data_decoded.map(_.uncorrectable).grouped(wordBits/eccBits).map(_.reduce(_||_)).toSeq)(s2_word_idx)
val s2_data_corrected = (s2_data_decoded.map(_.corrected): Seq[UInt]).asUInt
val s2_data_uncorrected = (s2_data_decoded.map(_.uncorrected): Seq[UInt]).asUInt
val s2_valid_hit_pre_data_ecc = s2_valid_masked && s2_readwrite && !s2_meta_error && s2_hit
@ -264,9 +273,10 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
// tag updates on ECC errors
metaArb.io.in(1).valid := s2_meta_error && (s2_valid_masked || s2_flush_valid_pre_tag_ecc || s2_probe)
metaArb.io.in(1).bits.write := true
metaArb.io.in(1).bits.way_en := PriorityEncoderOH(s2_meta_errors)
metaArb.io.in(1).bits.way_en := s2_meta_uncorrectable_errors | Mux(s2_meta_error_uncorrectable, 0.U, PriorityEncoderOH(s2_meta_correctable_errors))
metaArb.io.in(1).bits.addr := Cat(io.cpu.req.bits.addr >> untagBits, Mux(s2_probe, probe_bits.address, s2_req.addr)(idxMSB, 0))
metaArb.io.in(1).bits.data := PriorityMux(s2_meta_errors, s2_meta_corrected)
metaArb.io.in(1).bits.data := PriorityMux(s2_meta_correctable_errors, s2_meta_corrected)
when (s2_meta_error_uncorrectable) { metaArb.io.in(1).bits.data.coh := ClientMetadata.onReset }
// tag updates on hit/miss
metaArb.io.in(2).valid := (s2_valid_hit && s2_update_meta) || (s2_victimize && !s2_victim_dirty)
@ -703,6 +713,30 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
io.cpu.perf.release := edge.done(tl_out_c)
io.cpu.perf.tlbMiss := io.ptw.req.fire()
// report errors
{
val (data_error, data_error_uncorrectable, data_error_addr) =
if (usingDataScratchpad) (s2_valid_data_error, s2_data_error_uncorrectable, s2_req.addr) else {
(tl_out_c.valid && edge.hasData(tl_out_c.bits) && s2_data_decoded.map(_.error).reduce(_||_),
s2_data_decoded.map(_.uncorrectable).reduce(_||_),
tl_out_c.bits.address)
}
val error_addr =
Mux(metaArb.io.in(1).valid, Cat(metaArb.io.in(1).bits.data.tag, metaArb.io.in(1).bits.addr(untagBits-1, idxLSB)),
data_error_addr >> idxLSB) << idxLSB
io.errors.uncorrectable.foreach { u =>
u.valid := metaArb.io.in(1).valid && s2_meta_error_uncorrectable || data_error && data_error_uncorrectable
u.bits := error_addr
}
io.errors.correctable.foreach { c =>
c.valid := metaArb.io.in(1).valid || data_error
c.bits := error_addr
io.errors.uncorrectable.foreach { u => when (u.valid) { c.valid := false } }
}
io.errors.bus.valid := tl_out.d.fire() && tl_out.d.bits.error
io.errors.bus.bits := Mux(grantIsCached, s2_req.addr >> idxLSB << idxLSB, 0.U)
}
def encodeData(x: UInt) = x.grouped(eccBits).map(dECC.encode(_)).asUInt
def dummyEncodeData(x: UInt) = x.grouped(eccBits).map(dECC.swizzle(_)).asUInt
def decodeData(x: UInt) = x.grouped(dECC.width(eccBits)).map(dECC.decode(_))

View File

@ -70,6 +70,7 @@ class FrontendBundle(outer: Frontend) extends CoreBundle()(outer.p)
val ptw = new TLBPTWIO()
val tl_out = outer.masterNode.bundleOut
val tl_in = outer.slaveNode.bundleIn
val errors = new ICacheErrors
}
class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
@ -286,6 +287,7 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
// performance events
io.cpu.perf := icache.io.perf
io.cpu.perf.tlbMiss := io.ptw.req.fire()
io.errors := icache.io.errors
def alignPC(pc: UInt) = ~(~pc | (coreInstBytes - 1))
}

View File

@ -177,6 +177,7 @@ class HellaCacheBundle(outer: HellaCache)(implicit p: Parameters) extends CoreBu
val cpu = (new HellaCacheIO).flip
val ptw = new TLBPTWIO()
val mem = outer.node.bundleOut
val errors = new DCacheErrors
}
class HellaCacheModule(outer: HellaCache) extends LazyModuleImp(outer)

View File

@ -36,6 +36,11 @@ class ICacheReq(implicit p: Parameters) extends CoreBundle()(p) with HasL1ICache
val addr = UInt(width = vaddrBits)
}
class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p) with HasL1ICacheParameters {
val correctable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.itimAddr.nonEmpty && cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
}
class ICache(val icacheParams: ICacheParams, val hartid: Int)(implicit p: Parameters) extends LazyModule {
lazy val module = new ICacheModule(this)
val masterNode = TLClientNode(TLClientParameters(
@ -87,6 +92,7 @@ class ICacheBundle(outer: ICache) extends CoreBundle()(outer.p) {
val tl_out = outer.masterNode.bundleOut
val tl_in = outer.slaveNode.map(_.bundleIn)
val errors = new ICacheErrors
val perf = new ICachePerfEvents().asOutput
}
@ -116,10 +122,10 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
val scratchpadOn = RegInit(false.B)
val scratchpadMax = tl_in.map(tl => Reg(UInt(width = log2Ceil(nSets * (nWays - 1)))))
def lineInScratchpad(line: UInt) = scratchpadMax.map(scratchpadOn && line <= _).getOrElse(false.B)
def addrMaybeInScratchpad(addr: UInt) = if (outer.icacheParams.itimAddr.isEmpty) false.B else {
val base = GetPropertyByHartId(p(RocketTilesKey), _.icache.flatMap(_.itimAddr.map(_.U)), io.hartid)
addr >= base && addr < base + outer.size
val scratchpadBase = outer.icacheParams.itimAddr.map { dummy =>
GetPropertyByHartId(p(RocketTilesKey), _.icache.flatMap(_.itimAddr.map(_.U)), io.hartid)
}
def addrMaybeInScratchpad(addr: UInt) = scratchpadBase.map(base => addr >= base && addr < base + outer.size).getOrElse(false.B)
def addrInScratchpad(addr: UInt) = addrMaybeInScratchpad(addr) && lineInScratchpad(addr(untagBits+log2Ceil(nWays)-1, blockOffBits))
def scratchpadWay(addr: UInt) = addr.extract(untagBits+log2Ceil(nWays)-1, untagBits)
def scratchpadWayValid(way: UInt) = way < nWays - 1
@ -248,12 +254,15 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
io.resp.valid := s1_valid && s1_hit
case 2 =>
val s2_tag_hit = RegEnable(s1_tag_hit, s1_valid || s1_slaveValid)
val s2_dout = RegEnable(s1_dout, s1_valid || s1_slaveValid)
val s1_clk_en = s1_valid || s1_slaveValid
val s2_tag_hit = RegEnable(s1_tag_hit, s1_clk_en)
val s2_hit_way = OHToUInt(s2_tag_hit)
val s2_scratchpad_word_addr = Cat(s2_hit_way, io.s2_vaddr(untagBits-1, log2Ceil(wordBits/8)), UInt(0, log2Ceil(wordBits/8)))
val s2_dout = RegEnable(s1_dout, s1_clk_en)
val s2_way_mux = Mux1H(s2_tag_hit, s2_dout)
val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_valid || s1_slaveValid).asUInt.orR
val s2_tl_error = RegEnable(s1_tl_error.asUInt.orR, s1_valid || s1_slaveValid)
val s2_tag_disparity = RegEnable(s1_tag_disparity, s1_clk_en).asUInt.orR
val s2_tl_error = RegEnable(s1_tl_error.asUInt.orR, s1_clk_en)
val s2_data_decoded = dECC.decode(s2_way_mux)
val s2_disparity = s2_tag_disparity || s2_data_decoded.error
when (s2_valid && s2_disparity) { invalidate := true }
@ -263,6 +272,17 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
io.resp.bits.replay := s2_disparity
io.resp.valid := s2_valid && s2_hit
val s1_scratchpad_hit = Mux(s1_slaveValid, lineInScratchpad(scratchpadLine(s1s3_slaveAddr)), addrInScratchpad(io.s1_paddr))
val s2_scratchpad_hit = RegEnable(s1_scratchpad_hit, s1_clk_en)
io.errors.correctable.foreach { c =>
c.valid := s2_valid && Mux(s2_scratchpad_hit, s2_data_decoded.correctable, s2_disparity)
c.bits := 0.U
}
io.errors.uncorrectable.foreach { u =>
u.valid := s2_valid && s2_scratchpad_hit && s2_data_decoded.uncorrectable
u.bits := scratchpadBase.get + s2_scratchpad_word_addr
}
tl_in.map { tl =>
val respValid = RegInit(false.B)
tl.a.ready := !(tl_out.d.valid || s1_slaveValid || s2_slaveValid || s3_slaveValid || respValid)
@ -290,7 +310,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// a structural hazard on s1s3_slaveData/s1s3_slaveAddress).
s3_slaveValid := true
s1s3_slaveData := s2_data_decoded.corrected
s1s3_slaveAddr := Cat(OHToUInt(s2_tag_hit), io.s2_vaddr(untagBits-1, log2Ceil(wordBits/8)), s1s3_slaveAddr(log2Ceil(wordBits/8)-1, 0))
s1s3_slaveAddr := s2_scratchpad_word_addr | s1s3_slaveAddr(log2Ceil(wordBits/8)-1, 0)
}
respValid := s2_slaveValid || (respValid && !tl.d.ready)

View File

@ -30,6 +30,7 @@ case class RocketCoreParams(
fastLoadWord: Boolean = true,
fastLoadByte: Boolean = false,
jumpInFrontend: Boolean = true,
tileControlAddr: Option[BigInt] = None,
mulDiv: Option[MulDivParams] = Some(MulDivParams()),
fpu: Option[FPUParams] = Some(FPUParams())
) extends CoreParams {

View File

@ -100,21 +100,32 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend {
val module: CanHaveScratchpadModule
val cacheBlockBytes = p(CacheBlockBytes)
val slaveNode = TLInputNode() // Up to two uses for this input node:
// 1) Frontend always exists, but may or may not have a scratchpad node
// 2) ScratchpadSlavePort always has a node, but only exists when the HellaCache has a scratchpad
val fg = LazyModule(new TLFragmenter(tileParams.core.fetchBytes, cacheBlockBytes, earlyAck=true))
val ww = LazyModule(new TLWidthWidget(xBytes))
val scratch = tileParams.dcache.flatMap { d => d.scratch.map(s =>
LazyModule(new ScratchpadSlavePort(AddressSet(s, d.dataScratchpadBytes-1), xBytes, tileParams.core.useAtomics)))
}
val intOutputNode = tileParams.core.tileControlAddr.map(dummy => IntOutputNode())
val busErrorUnit = tileParams.core.tileControlAddr map { a =>
val beu = LazyModule(new BusErrorUnit(new L1BusErrors, BusErrorUnitParams(a)))
intOutputNode.get := beu.intNode
beu
}
// connect any combination of ITIM, DTIM, and BusErrorUnit
val slaveNode = TLInputNode()
DisableMonitors { implicit p =>
frontend.slaveNode :*= fg.node
fg.node :*= ww.node
ww.node :*= slaveNode
scratch foreach { lm => lm.node := TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode) }
val xbarPorts =
scratch.map(lm => (lm.node, xBytes)) ++
busErrorUnit.map(lm => (lm.node, xBytes)) ++
tileParams.icache.flatMap(icache => icache.itimAddr.map(a => (frontend.slaveNode, tileParams.core.fetchBytes)))
if (xbarPorts.nonEmpty) {
val xbar = LazyModule(new TLXbar)
xbar.node := TLFIFOFixer()(TLFragmenter(xBytes, cacheBlockBytes, earlyAck=true)(slaveNode))
xbarPorts.foreach { case (port, bytes) =>
port := (if (bytes == xBytes) xbar.node else TLFragmenter(bytes, xBytes, earlyAck=true)(TLWidthWidget(xBytes)(xbar.node)))
}
}
}
def findScratchpadFromICache: Option[AddressSet] = scratch.map { s =>
@ -130,6 +141,7 @@ trait CanHaveScratchpad extends HasHellaCache with HasICacheFrontend {
trait CanHaveScratchpadBundle extends HasHellaCacheBundle with HasICacheFrontendBundle {
val outer: CanHaveScratchpad
val slave = outer.slaveNode.bundleIn
val intOutput = outer.intOutputNode.map(_.bundleOut)
}
trait CanHaveScratchpadModule extends HasHellaCacheModule with HasICacheFrontendModule {
@ -137,4 +149,8 @@ trait CanHaveScratchpadModule extends HasHellaCacheModule with HasICacheFrontend
val io: CanHaveScratchpadBundle
outer.scratch.foreach { lm => dcachePorts += lm.module.io.dmem }
outer.busErrorUnit.foreach { lm =>
lm.module.io.errors.dcache := outer.dcache.module.io.errors
lm.module.io.errors.icache := outer.frontend.module.io.errors
}
}

View File

@ -27,6 +27,7 @@ trait CoreParams {
val nLocalInterrupts: Int
val nL2TLBEntries: Int
val jumpInFrontend: Boolean
val tileControlAddr: Option[BigInt]
def instBytes: Int = instBits / 8
def fetchBytes: Int = fetchWidth * instBytes

View File

@ -170,6 +170,7 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p:
val rocket = LazyModule(new RocketTile(rtp, hartid))
val masterNode: OutputNode[_,_,_,_,_]
val slaveNode: InputNode[_,_,_,_,_]
val intOutputNode = rocket.intOutputNode.map(dummy => IntOutputNode())
val asyncIntNode = IntInputNode()
val periphIntNode = IntInputNode()
val coreIntNode = IntInputNode()
@ -197,10 +198,19 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p:
}
}
def outputInterruptXingLatency: Int
rocket.intOutputNode.foreach { rocketIntOutputNode =>
val outXing = LazyModule(new IntXing(outputInterruptXingLatency))
intOutputNode.get := outXing.intnode
outXing.intnode := rocketIntOutputNode
}
lazy val module = new LazyModuleImp(this) {
val io = new CoreBundle with HasExternallyDrivenTileConstants with CanHaveInstructionTracePort {
val master = masterNode.bundleOut
val slave = slaveNode.bundleIn
val outputInterrupts = intOutputNode.map(_.bundleOut)
val asyncInterrupts = asyncIntNode.bundleIn
val periphInterrupts = periphIntNode.bundleIn
val coreInterrupts = coreIntNode.bundleIn
@ -227,6 +237,8 @@ class SyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters)
intXbar.intnode := xing.intnode
intXbar.intnode := periphIntNode
intXbar.intnode := coreIntNode
def outputInterruptXingLatency = 0
}
class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends RocketTileWrapper(rtp, hartid) {
@ -254,6 +266,8 @@ class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters
intXbar.intnode := asyncXing.intnode
intXbar.intnode := periphXing.intnode
intXbar.intnode := coreIntNode
def outputInterruptXingLatency = 3
}
class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends RocketTileWrapper(rtp, hartid) {
@ -282,4 +296,6 @@ class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Paramet
intXbar.intnode := asyncXing.intnode
intXbar.intnode := periphXing.intnode
intXbar.intnode := coreIntNode
def outputInterruptXingLatency = 1
}

View File

@ -15,6 +15,9 @@ abstract class Decoding
abstract class Code
{
def canDetect: Boolean
def canCorrect: Boolean
def width(w0: Int): Int
def encode(x: UInt): UInt
def decode(x: UInt): Decoding
@ -29,6 +32,9 @@ abstract class Code
class IdentityCode extends Code
{
def canDetect = false
def canCorrect = false
def width(w0: Int) = w0
def encode(x: UInt) = x
def swizzle(x: UInt) = x
@ -42,6 +48,9 @@ class IdentityCode extends Code
class ParityCode extends Code
{
def canDetect = true
def canCorrect = false
def width(w0: Int) = w0+1
def encode(x: UInt) = Cat(x.xorR, x)
def swizzle(x: UInt) = Cat(false.B, x)
@ -55,6 +64,9 @@ class ParityCode extends Code
class SECCode extends Code
{
def canDetect = true
def canCorrect = true
def width(k: Int) = {
val m = log2Floor(k) + 1
k + m + (if((1 << m) < m+k+1) 1 else 0)
@ -101,6 +113,9 @@ class SECCode extends Code
class SECDEDCode extends Code
{
def canDetect = true
def canCorrect = true
private val sec = new SECCode
private val par = new ParityCode

View File

@ -125,8 +125,10 @@ class SynchronizerShiftReg(w: Int = 1, sync: Int = 3) extends AbstractPipelineRe
object SynchronizerShiftReg {
def apply [T <: Chisel.Data](in: T, sync: Int = 3, name: Option[String] = None): T =
AbstractPipelineReg(new SynchronizerShiftReg(in.getWidth, sync), in, name)
def apply [T <: Chisel.Data](in: T, sync: Int = 3, name: Option[String] = None): T = {
if (sync == 0) in
else AbstractPipelineReg(new SynchronizerShiftReg(in.getWidth, sync), in, name)
}
}
class SyncResetSynchronizerShiftReg(w: Int = 1, sync: Int = 3, init: Int = 0) extends AbstractPipelineReg(w) {