Merge pull request #1183 from freechipsproject/regfield_descriptions
more detailed RegField descriptions
This commit is contained in:
		@@ -15,6 +15,7 @@ lazy val commonSettings = Seq(
 | 
				
			|||||||
  traceLevel   := 15,
 | 
					  traceLevel   := 15,
 | 
				
			||||||
  scalacOptions ++= Seq("-deprecation","-unchecked"),
 | 
					  scalacOptions ++= Seq("-deprecation","-unchecked"),
 | 
				
			||||||
  libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value),
 | 
					  libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value),
 | 
				
			||||||
 | 
					  libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.0"),
 | 
				
			||||||
  addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
 | 
					  addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,3 +45,4 @@ val chipSettings = Seq(
 | 
				
			|||||||
    s"make -C $makeDir  -j $jobs $target".!
 | 
					    s"make -C $makeDir  -j $jobs $target".!
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,7 +89,7 @@ import DebugModuleAccessType._
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object DebugAbstractCommandError extends scala.Enumeration {
 | 
					object DebugAbstractCommandError extends scala.Enumeration {
 | 
				
			||||||
  type DebugAbstractCommandError = Value
 | 
					  type DebugAbstractCommandError = Value
 | 
				
			||||||
  val None, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value
 | 
					  val Success, ErrBusy, ErrNotSupported, ErrException, ErrHaltResume = Value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
import DebugAbstractCommandError._
 | 
					import DebugAbstractCommandError._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -250,18 +250,18 @@ class DebugCtrlBundle (nComponents: Int)(implicit val p: Parameters) extends Par
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Local reg mapper function : Notify when written, but give the value as well.  
 | 
					// Local reg mapper function : Notify when written, but give the value as well.  
 | 
				
			||||||
object WNotifyWire {
 | 
					object WNotifyWire {
 | 
				
			||||||
  def apply(n: Int, value: UInt, set: Bool) : RegField = {
 | 
					  def apply(n: Int, value: UInt, set: Bool, name: String, desc: String) : RegField = {
 | 
				
			||||||
    RegField(n, UInt(0), RegWriteFn((valid, data) => {
 | 
					    RegField(n, UInt(0), RegWriteFn((valid, data) => {
 | 
				
			||||||
      set := valid
 | 
					      set := valid
 | 
				
			||||||
      value := data
 | 
					      value := data
 | 
				
			||||||
      Bool(true)
 | 
					      Bool(true)
 | 
				
			||||||
    }))
 | 
					    }), Some(RegFieldDesc(name = name, desc = desc, access = RegFieldAccessType.WSPECIAL)))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Local reg mapper function : Notify when accessed either as read or write.
 | 
					// Local reg mapper function : Notify when accessed either as read or write.
 | 
				
			||||||
object RWNotify {
 | 
					object RWNotify {
 | 
				
			||||||
    def apply (n: Int, rVal: UInt, wVal: UInt, rNotify: Bool, wNotify: Bool) : RegField = {
 | 
					    def apply (n: Int, rVal: UInt, wVal: UInt, rNotify: Bool, wNotify: Bool, desc: Option[RegFieldDesc] = None): RegField = {
 | 
				
			||||||
      RegField(n,
 | 
					      RegField(n,
 | 
				
			||||||
        RegReadFn ((ready)       => {rNotify := ready ; (Bool(true), rVal)}),
 | 
					        RegReadFn ((ready)       => {rNotify := ready ; (Bool(true), rVal)}),
 | 
				
			||||||
        RegWriteFn((valid, data) => {
 | 
					        RegWriteFn((valid, data) => {
 | 
				
			||||||
@@ -269,7 +269,7 @@ object RWNotify {
 | 
				
			|||||||
          when (valid) {wVal := data}
 | 
					          when (valid) {wVal := data}
 | 
				
			||||||
          Bool(true)
 | 
					          Bool(true)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ))
 | 
					        ), desc)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -344,7 +344,7 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod
 | 
				
			|||||||
    // DMCONTROL is the only register, so it's at offset 0.
 | 
					    // DMCONTROL is the only register, so it's at offset 0.
 | 
				
			||||||
    dmiNode.regmap(
 | 
					    dmiNode.regmap(
 | 
				
			||||||
      0 -> Seq(RWNotify(32, DMCONTROLRdData.asUInt(),
 | 
					      0 -> Seq(RWNotify(32, DMCONTROLRdData.asUInt(),
 | 
				
			||||||
        DMCONTROLWrDataVal, DMCONTROLRdEn, DMCONTROLWrEn))
 | 
					        DMCONTROLWrDataVal, DMCONTROLRdEn, DMCONTROLWrEn, Some(RegFieldDesc("dmi_dmcontrol", "", reset=Some(0)))))
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //--------------------------------------------------------------
 | 
					    //--------------------------------------------------------------
 | 
				
			||||||
@@ -726,20 +726,25 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
 | 
				
			|||||||
    // Program Buffer Access (DMI ... System Bus can override)
 | 
					    // Program Buffer Access (DMI ... System Bus can override)
 | 
				
			||||||
    //--------------------------------------------------------------
 | 
					    //--------------------------------------------------------------
 | 
				
			||||||
    dmiNode.regmap(
 | 
					    dmiNode.regmap(
 | 
				
			||||||
      (DMI_DMSTATUS    << 2) -> Seq(RegField.r(32, DMSTATUSRdData.asUInt())),
 | 
					      (DMI_DMSTATUS    << 2) -> Seq(RegField.r(32, DMSTATUSRdData.asUInt(), RegFieldDesc("dmi_dmstatus", ""))),
 | 
				
			||||||
      //TODO (DMI_CFGSTRADDR0 << 2) -> cfgStrAddrFields,
 | 
					      //TODO (DMI_CFGSTRADDR0 << 2) -> cfgStrAddrFields,
 | 
				
			||||||
      (DMI_HARTINFO    << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt())),
 | 
					      (DMI_HARTINFO    << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt(), RegFieldDesc("dmi_hartinfo", "" /*, reset=Some(HARTINFORdData.litValue)*/))),
 | 
				
			||||||
      (DMI_HALTSUM     << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt())),
 | 
					      (DMI_HALTSUM     << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt(), RegFieldDesc("dmi_haltsum", ""))),
 | 
				
			||||||
      (DMI_ABSTRACTCS  << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe)),
 | 
					      (DMI_ABSTRACTCS  << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe,
 | 
				
			||||||
      (DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe)),
 | 
					        Some(RegFieldDesc("dmi_abstractcs", "" /*, reset=Some(ABSTRACTCSReset.litValue)*/)))),
 | 
				
			||||||
      (DMI_COMMAND     << 2) -> Seq(RWNotify(32, COMMANDRdData.asUInt(), COMMANDWrDataVal, COMMANDRdEn, COMMANDWrEnMaybe)),
 | 
					      (DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe,
 | 
				
			||||||
      (DMI_DATA0       << 2) -> abstractDataMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, abstractDataNxt(i),
 | 
					        Some(RegFieldDesc("dmi_abstractauto", "", reset=Some(0))))),
 | 
				
			||||||
 | 
					      (DMI_COMMAND     << 2) -> Seq(RWNotify(32, COMMANDRdData.asUInt(), COMMANDWrDataVal, COMMANDRdEn, COMMANDWrEnMaybe,
 | 
				
			||||||
 | 
					        Some(RegFieldDesc("dmi_command", "", reset=Some(0))))),
 | 
				
			||||||
 | 
					      (DMI_DATA0       << 2) -> RegFieldGroup("dmi_data", None, abstractDataMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, abstractDataNxt(i),
 | 
				
			||||||
        dmiAbstractDataRdEn(i),
 | 
					        dmiAbstractDataRdEn(i),
 | 
				
			||||||
        dmiAbstractDataWrEnMaybe(i))},
 | 
					        dmiAbstractDataWrEnMaybe(i),
 | 
				
			||||||
      (DMI_PROGBUF0    << 2) -> programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(i),
 | 
					        Some(RegFieldDesc(s"dmi_data_$i", "", reset = Some(0))))}),
 | 
				
			||||||
 | 
					      (DMI_PROGBUF0    << 2) -> RegFieldGroup("dmi_progbuf", None, programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(i),
 | 
				
			||||||
        dmiProgramBufferRdEn(i),
 | 
					        dmiProgramBufferRdEn(i),
 | 
				
			||||||
        dmiProgramBufferWrEnMaybe(i))},
 | 
					        dmiProgramBufferWrEnMaybe(i),
 | 
				
			||||||
      (DMIConsts.dmi_haltStatusAddr << 2) -> haltedStatus.map(x => RegField.r(32, x))
 | 
					        Some(RegFieldDesc(s"dmi_progbuf_$i", "", reset = Some(0))))}),
 | 
				
			||||||
 | 
					      (DMIConsts.dmi_haltStatusAddr << 2) -> RegFieldGroup("dmi_halt_status", None, haltedStatus.zipWithIndex.map{case (x, i) => RegField.r(32, x, RegFieldDesc(s"halt_status_$i", ""))})
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    abstractDataMem.zipWithIndex.foreach { case (x, i) =>
 | 
					    abstractDataMem.zipWithIndex.foreach { case (x, i) =>
 | 
				
			||||||
@@ -880,20 +885,28 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int)(implicit p:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tlNode.regmap(
 | 
					    tlNode.regmap(
 | 
				
			||||||
      // This memory is writable.
 | 
					      // This memory is writable.
 | 
				
			||||||
      HALTED      -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn)),
 | 
					      HALTED      -> Seq(WNotifyWire(sbIdWidth, hartHaltedId, hartHaltedWrEn,
 | 
				
			||||||
      GOING       -> Seq(WNotifyWire(sbIdWidth, hartGoingId,  hartGoingWrEn)),
 | 
					        "debug_hart_halted", "Debug ROM Causes hart to write its hartID here when it is in Debug Mode.")),
 | 
				
			||||||
      RESUMING    -> Seq(WNotifyWire(sbIdWidth, hartResumingId,  hartResumingWrEn)),
 | 
					      GOING       -> Seq(WNotifyWire(sbIdWidth, hartGoingId,  hartGoingWrEn,
 | 
				
			||||||
      EXCEPTION   -> Seq(WNotifyWire(sbIdWidth, hartExceptionId,  hartExceptionWrEn)),
 | 
					        "debug_hart_going", "Debug ROM causes hart to write 0 here when it begins executing Debug Mode instructions.")),
 | 
				
			||||||
      DATA        -> abstractDataMem.map(x => RegField(8, x)),
 | 
					      RESUMING    -> Seq(WNotifyWire(sbIdWidth, hartResumingId,  hartResumingWrEn,
 | 
				
			||||||
      PROGBUF(cfg)-> programBufferMem.map(x => RegField(8, x)),
 | 
					        "debug_hart_resuming", "Debug ROM causes hart to write 0 here when it leaves Debug Mode.")),
 | 
				
			||||||
 | 
					      EXCEPTION   -> Seq(WNotifyWire(sbIdWidth, hartExceptionId,  hartExceptionWrEn,
 | 
				
			||||||
 | 
					        "debug_hart_exception", "Debug ROM causes hart to write 0 here if it gets an exception in Debug Mode.")),
 | 
				
			||||||
 | 
					      DATA        -> RegFieldGroup("debug_data", Some("Data used to communicate with Debug Module"),
 | 
				
			||||||
 | 
					        abstractDataMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_data_$i", ""))}),
 | 
				
			||||||
 | 
					      PROGBUF(cfg)-> RegFieldGroup("debug_progbuf", Some("Program buffer used to communicate with Debug Module"),
 | 
				
			||||||
 | 
					        programBufferMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_progbuf_$i", ""))}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // These sections are read-only.
 | 
					      // These sections are read-only.
 | 
				
			||||||
      IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32,  Instructions.EBREAK.value.U)) else Nil},
 | 
					      IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32,  Instructions.EBREAK.value.U, RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK"))) else Nil},
 | 
				
			||||||
      WHERETO       -> Seq(RegField.r(32, jalAbstract.asUInt)),
 | 
					      WHERETO       -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
 | 
				
			||||||
      ABSTRACT(cfg) -> abstractGeneratedMem.map{x => RegField.r(32, x)},
 | 
					      ABSTRACT(cfg) -> RegFieldGroup("debug_abstract", Some("Instructions generated by Debug Module"),
 | 
				
			||||||
      FLAGS         -> flags.map{x => RegField.r(8, x.asUInt())},
 | 
					        abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", ""))}),
 | 
				
			||||||
      ROMBASE       -> DebugRomContents().map(x => RegField.r(8, (x & 0xFF).U(8.W)))
 | 
					      FLAGS         -> RegFieldGroup("debug_flags", Some("Memory region used to control hart going/resuming in Debug Mode"),
 | 
				
			||||||
 | 
					        flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_$i", ""))}),
 | 
				
			||||||
 | 
					      ROMBASE       -> RegFieldGroup("debug_rom", Some("Debug ROM"),
 | 
				
			||||||
 | 
					        DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))})
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Override System Bus accesses with dmactive reset.
 | 
					    // Override System Bus accesses with dmactive reset.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,9 +83,11 @@ class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) exte
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    node.regmap(
 | 
					    node.regmap(
 | 
				
			||||||
      0                -> ipi.map(r => RegField(ipiWidth, r)),
 | 
					      0                -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) => RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", s"MSIP bit for Hart $i", reset=Some(0)))}),
 | 
				
			||||||
      timecmpOffset(0) -> timecmp.flatMap(RegField.bytes(_)),
 | 
					      timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) =>
 | 
				
			||||||
      timeOffset       -> RegField.bytes(time))
 | 
					        RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"), RegField.bytes(t, Some(RegFieldDesc(s"mtimecmp_$i", "", reset=None))))},
 | 
				
			||||||
 | 
					      timeOffset       -> RegFieldGroup("mtime", Some("Timer Register"), RegField.bytes(time, Some(RegFieldDesc("mtime", "", reset=Some(0)))))
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,12 +169,18 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
 | 
				
			|||||||
      harts(hart) := ShiftRegister(Reg(next = maxPri) > Cat(UInt(1), threshold(hart)), params.intStages)
 | 
					      harts(hart) := ShiftRegister(Reg(next = maxPri) > Cat(UInt(1), threshold(hart)), params.intStages)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def priorityRegField(x: UInt) = if (nPriorities > 0) RegField(32, x) else RegField.r(32, x)
 | 
					    def priorityRegDesc(i: Int) = RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i", reset=if (nPriorities > 0) None else Some(1)) 
 | 
				
			||||||
    val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p)))
 | 
					    def pendingRegDesc(i: Int) = RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.") 
 | 
				
			||||||
    val pendingRegFields = Seq(PLICConsts.pendingBase  -> pending .map(b => RegField.r(1, b)))
 | 
					    def priorityRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, priorityRegDesc(i)) else RegField.r(32, x, priorityRegDesc(i))
 | 
				
			||||||
 | 
					    val priorityRegFields = Seq(PLICConsts.priorityBase -> RegFieldGroup("priority", Some("Acting priorities of each interrupt source. 32 bits for each interrupt source."),
 | 
				
			||||||
 | 
					      priority.zipWithIndex.map{case (p, i) => priorityRegField(p, i)}))
 | 
				
			||||||
 | 
					    val pendingRegFields = Seq(PLICConsts.pendingBase  -> RegFieldGroup("pending", Some("Pending Bit Array. 1 Bit for each interrupt source."),
 | 
				
			||||||
 | 
					      pending.zipWithIndex.map{case (b, i) => RegField.r(1, b, pendingRegDesc(i))}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
 | 
					    val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
 | 
				
			||||||
      PLICConsts.enableBase(i) -> e.map(b => RegField(1, b))
 | 
					      PLICConsts.enableBase(i) -> RegFieldGroup(s"enables_${i}", Some(s"Enable bits for each interrupt source for target $i. 1 bit for each interrupt source."),
 | 
				
			||||||
 | 
					        e.zipWithIndex.map{case (b, j) => RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))})
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // When a hart reads a claim/complete register, then the
 | 
					    // When a hart reads a claim/complete register, then the
 | 
				
			||||||
@@ -208,9 +214,12 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
 | 
				
			|||||||
       g.complete := c
 | 
					       g.complete := c
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i", reset=if (nPriorities > 0) None else Some(1))
 | 
				
			||||||
 | 
					    def thresholdRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, thresholdRegDesc(i)) else RegField.r(32, x, thresholdRegDesc(i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val hartRegFields = Seq.tabulate(nHarts) { i =>
 | 
					    val hartRegFields = Seq.tabulate(nHarts) { i =>
 | 
				
			||||||
      PLICConsts.hartBase(i) -> Seq(
 | 
					      PLICConsts.hartBase(i) -> Seq(
 | 
				
			||||||
        priorityRegField(threshold(i)),
 | 
					        thresholdRegField(threshold(i), i),
 | 
				
			||||||
        RegField(32,
 | 
					        RegField(32,
 | 
				
			||||||
          RegReadFn { valid =>
 | 
					          RegReadFn { valid =>
 | 
				
			||||||
            claimer(i) := valid
 | 
					            claimer(i) := valid
 | 
				
			||||||
@@ -222,7 +231,12 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule
 | 
				
			|||||||
            completerDev := data.extract(log2Ceil(nDevices+1)-1, 0)
 | 
					            completerDev := data.extract(log2Ceil(nDevices+1)-1, 0)
 | 
				
			||||||
            completer(i) := valid && enables(i)(completerDev)
 | 
					            completer(i) := valid && enables(i)(completerDev)
 | 
				
			||||||
            Bool(true)
 | 
					            Bool(true)
 | 
				
			||||||
          }
 | 
					          },
 | 
				
			||||||
 | 
					          Some(RegFieldDesc(s"claim_complete_$i",
 | 
				
			||||||
 | 
					            s"Claim/Complete register for Target $i. Reading this register returns the claimed interrupt number and makes it no longer pending." +
 | 
				
			||||||
 | 
					            s"Writing the interrupt number back completes the interrupt.",
 | 
				
			||||||
 | 
					            reset = None,
 | 
				
			||||||
 | 
					            access = RegFieldAccessType.RWSPECIAL))
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    } 
 | 
					    } 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,46 @@ import chisel3.util.{ReadyValidIO}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import freechips.rocketchip.util.{SimpleRegIO}
 | 
					import freechips.rocketchip.util.{SimpleRegIO}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This information is not used internally by the regmap(...) function.
 | 
				
			||||||
 | 
					// However, the author of a RegField may be the best person to provide this
 | 
				
			||||||
 | 
					// information which is likely to be needed by downstream SW and Documentation
 | 
				
			||||||
 | 
					// tools.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object RegFieldAccessType extends scala.Enumeration {
 | 
				
			||||||
 | 
					  type RegFieldAccessType = Value
 | 
				
			||||||
 | 
					  val R, W, RW, RSPECIAL, WSPECIAL, RWSPECIAL, OTHER = Value
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					import RegFieldAccessType._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case class RegFieldDesc (
 | 
				
			||||||
 | 
					  name: String,
 | 
				
			||||||
 | 
					  desc: String,
 | 
				
			||||||
 | 
					  group: Option[String] = None,
 | 
				
			||||||
 | 
					  groupDesc: Option[String] = None,
 | 
				
			||||||
 | 
					  access: RegFieldAccessType = RegFieldAccessType.RW,
 | 
				
			||||||
 | 
					  reset: Option[BigInt] = None,
 | 
				
			||||||
 | 
					  enumerations: Map[String, BigInt] = Map()
 | 
				
			||||||
 | 
					){
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Our descriptions are in terms of RegFields only, which is somewhat unusual for
 | 
				
			||||||
 | 
					// developers who are used to things being defined as bitfields within registers.
 | 
				
			||||||
 | 
					// The "Group" allows a string & (optional) description to be added which describes the conceptual "Group"
 | 
				
			||||||
 | 
					// the RegField belongs to. This can be used by downstream flows as they see fit to
 | 
				
			||||||
 | 
					// present the information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object RegFieldGroup {
 | 
				
			||||||
 | 
					  def apply (name: String, desc: Option[String], regs: Seq[RegField], descFirstOnly: Boolean = true): Seq[RegField] = {
 | 
				
			||||||
 | 
					    regs.zipWithIndex.map {case (r, i) =>
 | 
				
			||||||
 | 
					      val gDesc = if ((i > 0) & descFirstOnly) None else desc
 | 
				
			||||||
 | 
					      r.desc.map { d =>
 | 
				
			||||||
 | 
					        r.copy(desc = Some(d.copy(group = Some(name), groupDesc = gDesc)) )
 | 
				
			||||||
 | 
					      }.getOrElse(r)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
 | 
					case class RegReadFn private(combinational: Boolean, fn: (Bool, Bool) => (Bool, Bool, UInt))
 | 
				
			||||||
object RegReadFn
 | 
					object RegReadFn
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -73,11 +113,11 @@ object RegWriteFn
 | 
				
			|||||||
  implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) })
 | 
					  implicit def apply(x: Unit): RegWriteFn = RegWriteFn((valid, data) => { Bool(true) })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, name: String, description: String)
 | 
					case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, desc: Option[RegFieldDesc])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  require (width > 0, s"RegField width must be > 0, not $width")
 | 
					  require (width > 0, s"RegField width must be > 0, not $width")
 | 
				
			||||||
  def pipelined = !read.combinational || !write.combinational
 | 
					  def pipelined = !read.combinational || !write.combinational
 | 
				
			||||||
  def readOnly = this.copy(write = ())
 | 
					  def readOnly = this.copy(write = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object RegField
 | 
					object RegField
 | 
				
			||||||
@@ -85,51 +125,62 @@ object RegField
 | 
				
			|||||||
  // Byte address => sequence of bitfields, lowest index => lowest address
 | 
					  // Byte address => sequence of bitfields, lowest index => lowest address
 | 
				
			||||||
  type Map = (Int, Seq[RegField])
 | 
					  type Map = (Int, Seq[RegField])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def apply(n: Int)                                                         : RegField = apply(n, (), (), "", "")
 | 
					  def apply(n: Int)                                                             : RegField = apply(n, (), (),
 | 
				
			||||||
  def apply(n: Int, r: RegReadFn, w: RegWriteFn)                            : RegField = apply(n, r, w,   "", "")
 | 
					    Some(RegFieldDesc("reserved", "", access = RegFieldAccessType.R, reset = Some(0))))
 | 
				
			||||||
  def apply(n: Int, rw: UInt)                                               : RegField = apply(n, rw, rw, "", "")
 | 
					
 | 
				
			||||||
  def apply(n: Int, rw: UInt, name: String, description: String)            : RegField = apply(n, rw, rw, name, description)
 | 
					  def apply(n: Int, r: RegReadFn, w: RegWriteFn)                                : RegField = apply(n, r,  w,  None)
 | 
				
			||||||
  def r(n: Int, r: RegReadFn,  name: String = "", description: String = "") : RegField = apply(n, r,  (), name, description)
 | 
					  def apply(n: Int, r: RegReadFn, w: RegWriteFn, desc: RegFieldDesc)            : RegField = apply(n, r,  w,  Some(desc))
 | 
				
			||||||
  def w(n: Int, w: RegWriteFn, name: String = "", description: String = "") : RegField = apply(n, (), w,  name, description)
 | 
					  def apply(n: Int, rw: UInt)                                                   : RegField = apply(n, rw, rw, None)
 | 
				
			||||||
 | 
					  def apply(n: Int, rw: UInt, desc: RegFieldDesc)                               : RegField = apply(n, rw, rw, Some(desc))
 | 
				
			||||||
 | 
					  def r(n: Int, r: RegReadFn)                                                   : RegField = apply(n, r,  (), None)
 | 
				
			||||||
 | 
					  def r(n: Int, r: RegReadFn,  desc: RegFieldDesc)                              : RegField = apply(n, r,  (), Some(desc.copy(access = RegFieldAccessType.R)))
 | 
				
			||||||
 | 
					  def w(n: Int, w: RegWriteFn)                                                  : RegField = apply(n, (), w,  None)
 | 
				
			||||||
 | 
					  def w(n: Int, w: RegWriteFn, desc: RegFieldDesc)                              : RegField = apply(n, (), w,  Some(desc.copy(access = RegFieldAccessType.W)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This RegField allows 'set' to set bits in 'reg'.
 | 
					  // This RegField allows 'set' to set bits in 'reg'.
 | 
				
			||||||
  // and to clear bits when the bus writes bits of value 1.
 | 
					  // and to clear bits when the bus writes bits of value 1.
 | 
				
			||||||
  // Setting takes priority over clearing.
 | 
					  // Setting takes priority over clearing.
 | 
				
			||||||
  def w1ToClear(n: Int, reg: UInt, set: UInt): RegField =
 | 
					  def w1ToClear(n: Int, reg: UInt, set: UInt, desc: Option[RegFieldDesc] = None): RegField =
 | 
				
			||||||
    RegField(n, reg, RegWriteFn((valid, data) => { reg := ~(~reg | Mux(valid, data, UInt(0))) | set; Bool(true) }))
 | 
					    RegField(n, reg, RegWriteFn((valid, data) => { reg := ~(~reg | Mux(valid, data, UInt(0))) | set; Bool(true) }),
 | 
				
			||||||
 | 
					      desc.map{_.copy(access = RegFieldAccessType.RWSPECIAL)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This RegField wraps an explicit register
 | 
					  // This RegField wraps an explicit register
 | 
				
			||||||
  // (e.g. Black-Boxed Register) to create a R/W register.
 | 
					  // (e.g. Black-Boxed Register) to create a R/W register.
 | 
				
			||||||
  def rwReg(n: Int, bb: SimpleRegIO, name: String = "", description: String = "") : RegField =
 | 
					  def rwReg(n: Int, bb: SimpleRegIO, desc: Option[RegFieldDesc] = None) : RegField =
 | 
				
			||||||
    RegField(n, bb.q, RegWriteFn((valid, data) => {
 | 
					    RegField(n, bb.q, RegWriteFn((valid, data) => {
 | 
				
			||||||
      bb.en := valid
 | 
					      bb.en := valid
 | 
				
			||||||
      bb.d := data
 | 
					      bb.d := data
 | 
				
			||||||
      Bool(true)
 | 
					      Bool(true)
 | 
				
			||||||
    }), name, description)
 | 
					    }), desc.map{_.copy(access = RegFieldAccessType.RW)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create byte-sized read-write RegFields out of a large UInt register.
 | 
					  // Create byte-sized read-write RegFields out of a large UInt register.
 | 
				
			||||||
  // It is updated when any of the bytes are written. Because the RegFields
 | 
					  // It is updated when any of the bytes are written. Because the RegFields
 | 
				
			||||||
  // are all byte-sized, this is also suitable when a register is larger
 | 
					  // are all byte-sized, this is also suitable when a register is larger
 | 
				
			||||||
  // than the intended bus width of the device (atomic updates are impossible). 
 | 
					  // than the intended bus width of the device (atomic updates are impossible). 
 | 
				
			||||||
  def bytes(reg: UInt, numBytes: Int): Seq[RegField] = {
 | 
					  def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
 | 
				
			||||||
    val pad = reg | UInt(0, width = 8*numBytes)
 | 
					   val pad = reg | UInt(0, width = 8*numBytes)
 | 
				
			||||||
    val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
 | 
					    val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
 | 
				
			||||||
    val newBytes = Wire(init = oldBytes)
 | 
					    val newBytes = Wire(init = oldBytes)
 | 
				
			||||||
    val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
 | 
					    val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
 | 
				
			||||||
    when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
 | 
					    when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
 | 
				
			||||||
    Seq.tabulate(numBytes) { i =>
 | 
					    Seq.tabulate(numBytes) { i =>
 | 
				
			||||||
 | 
					      val newDesc = desc.map {d => d.copy(name = d.name + s"[${(i+1)*8-1}:${i*8}]")}
 | 
				
			||||||
      RegField(8, oldBytes(i),
 | 
					      RegField(8, oldBytes(i),
 | 
				
			||||||
        RegWriteFn((valid, data) => {
 | 
					        RegWriteFn((valid, data) => {
 | 
				
			||||||
        valids(i) := valid
 | 
					        valids(i) := valid
 | 
				
			||||||
        when (valid) { newBytes(i) := data }
 | 
					        when (valid) { newBytes(i) := data }
 | 
				
			||||||
        Bool(true)
 | 
					        Bool(true)
 | 
				
			||||||
      }))}}
 | 
					      }), newDesc)}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def bytes(reg: UInt): Seq[RegField] = {
 | 
					  def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
 | 
				
			||||||
    val width = reg.getWidth
 | 
					    val width = reg.getWidth
 | 
				
			||||||
    require (width % 8 == 0, s"RegField.bytes must be called on byte-sized reg, not ${width} bits")
 | 
					    require (width % 8 == 0, s"RegField.bytes must be called on byte-sized reg, not ${width} bits")
 | 
				
			||||||
    bytes(reg, width/8)
 | 
					    bytes(reg, width/8, desc)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def bytes(reg: UInt, numBytes: Int): Seq[RegField] = bytes(reg, numBytes, None)
 | 
				
			||||||
 | 
					  def bytes(reg: UInt): Seq[RegField] = bytes(reg, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait HasRegMap
 | 
					trait HasRegMap
 | 
				
			||||||
@@ -138,4 +189,4 @@ trait HasRegMap
 | 
				
			|||||||
  val interrupts: Vec[Bool]
 | 
					  val interrupts: Vec[Bool]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// See GPIO.scala for an example of how to use regmap
 | 
					// See Example.scala for an example of how to use regmap
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -144,10 +144,13 @@ object RegMapper
 | 
				
			|||||||
      val (f_wiready, f_wovalid) = field.write.fn(f_wivalid, f_woready, data(high, low))
 | 
					      val (f_wiready, f_wovalid) = field.write.fn(f_wivalid, f_woready, data(high, low))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // cover reads and writes to register
 | 
					      // cover reads and writes to register
 | 
				
			||||||
      cover(f_rivalid && f_riready, field.name + "_Reg_read_start", field.description + " RegField Read Request Initiate")
 | 
					      val fname = field.desc.map{_.name}.getOrElse("")
 | 
				
			||||||
      cover(f_rovalid && f_roready, field.name + "_Reg_read_out", field.description + " RegField Read Request Complete")
 | 
					      val fdesc = field.desc.map{_.desc + ":"}.getOrElse("")
 | 
				
			||||||
      cover(f_wivalid && f_wiready, field.name + "_Reg_write_start", field.description + " RegField Write Request Initiate")
 | 
					
 | 
				
			||||||
      cover(f_wovalid && f_woready, field.name + "_Reg_write_out", field.description + " RegField Write Request Complete")
 | 
					      cover(f_rivalid && f_riready, fname + "_Reg_read_start",  fdesc + " RegField Read Request Initiate")
 | 
				
			||||||
 | 
					      cover(f_rovalid && f_roready, fname + "_Reg_read_out",    fdesc + " RegField Read Request Complete")
 | 
				
			||||||
 | 
					      cover(f_wivalid && f_wiready, fname + "_Reg_write_start", fdesc + " RegField Write Request Initiate")
 | 
				
			||||||
 | 
					      cover(f_wovalid && f_woready, fname + "_Reg_write_out",   fdesc + " RegField Write Request Complete")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def litOR(x: Bool, y: Bool) = if (x.isLit && x.litValue == 1) Bool(true) else x || y
 | 
					      def litOR(x: Bool, y: Bool) = if (x.isLit && x.litValue == 1) Bool(true) else x || y
 | 
				
			||||||
      // Add this field to the ready-valid signals for the register
 | 
					      // Add this field to the ready-valid signals for the register
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ trait ExampleModule extends HasRegMap
 | 
				
			|||||||
  val io: ExampleBundle
 | 
					  val io: ExampleBundle
 | 
				
			||||||
  val interrupts: Vec[Bool]
 | 
					  val interrupts: Vec[Bool]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val state = RegInit(UInt(0))
 | 
					  val state = RegInit(UInt(0, width = params.num))
 | 
				
			||||||
  val pending = RegInit(UInt(0xf, width = 4))
 | 
					  val pending = RegInit(UInt(0xf, width = 4))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  io.gpio := state
 | 
					  io.gpio := state
 | 
				
			||||||
@@ -28,9 +28,15 @@ trait ExampleModule extends HasRegMap
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  regmap(
 | 
					  regmap(
 | 
				
			||||||
    0 -> Seq(
 | 
					    0 -> Seq(
 | 
				
			||||||
      RegField(params.num, state)),
 | 
					      RegField(params.num, state,
 | 
				
			||||||
 | 
					        RegFieldDesc("state", "State: Example of a R/W Register with description.", reset = Some(0)))),
 | 
				
			||||||
    4 -> Seq(
 | 
					    4 -> Seq(
 | 
				
			||||||
      RegField.w1ToClear(4, pending, state)))
 | 
					      RegField.w1ToClear(4, pending, state,
 | 
				
			||||||
 | 
					        Some(RegFieldDesc("pending", "Pending: Example of a special (W1ToC) Register. " +
 | 
				
			||||||
 | 
					          "Writing a bit here causes it to be reset to 0. " +
 | 
				
			||||||
 | 
					          "The bits are set when the corresponding bit in 'state' is high.",
 | 
				
			||||||
 | 
					          reset=Some(0xF)))))
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create a concrete TL2 version of the abstract Example slave
 | 
					// Create a concrete TL2 version of the abstract Example slave
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,9 +7,12 @@ import freechips.rocketchip.config.Parameters
 | 
				
			|||||||
import freechips.rocketchip.diplomacy._
 | 
					import freechips.rocketchip.diplomacy._
 | 
				
			||||||
import freechips.rocketchip.regmapper._
 | 
					import freechips.rocketchip.regmapper._
 | 
				
			||||||
import freechips.rocketchip.interrupts._
 | 
					import freechips.rocketchip.interrupts._
 | 
				
			||||||
import freechips.rocketchip.util.HeterogeneousBag
 | 
					import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
 | 
				
			||||||
import scala.math.{min,max}
 | 
					import scala.math.{min,max}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.json4s.JsonDSL._
 | 
				
			||||||
 | 
					import org.json4s.jackson.JsonMethods.{pretty, render}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
case class TLRegisterNode(
 | 
					case class TLRegisterNode(
 | 
				
			||||||
    address:     Seq[AddressSet],
 | 
					    address:     Seq[AddressSet],
 | 
				
			||||||
    device:      Device,
 | 
					    device:      Device,
 | 
				
			||||||
@@ -80,6 +83,35 @@ case class TLRegisterNode(
 | 
				
			|||||||
    bundleIn.b.valid := Bool(false)
 | 
					    bundleIn.b.valid := Bool(false)
 | 
				
			||||||
    bundleIn.c.ready := Bool(true)
 | 
					    bundleIn.c.ready := Bool(true)
 | 
				
			||||||
    bundleIn.e.ready := Bool(true)
 | 
					    bundleIn.e.ready := Bool(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Dump out the register map for documentation purposes.
 | 
				
			||||||
 | 
					    val regDescs = mapping.flatMap { case (offset, seq) =>
 | 
				
			||||||
 | 
					      var currentBitOffset = 0      
 | 
				
			||||||
 | 
					      seq.zipWithIndex.map { case (f, i) => {
 | 
				
			||||||
 | 
					        val tmp = (f.desc.map{ _.name}.getOrElse(s"unnamedRegField${i}") -> (
 | 
				
			||||||
 | 
					            ("byteOffset"  -> s"0x${offset.toHexString}") ~
 | 
				
			||||||
 | 
					            ("bitOffset"   -> currentBitOffset) ~
 | 
				
			||||||
 | 
					            ("bitWidth"    -> f.width) ~
 | 
				
			||||||
 | 
					            ("name" -> f.desc.map(_.name)) ~
 | 
				
			||||||
 | 
					            ("description" -> f.desc.map{ d=> if (d.desc == "") None else Some(d.desc)}) ~
 | 
				
			||||||
 | 
					            ("resetValue"  -> f.desc.map{_.reset}) ~
 | 
				
			||||||
 | 
					            ("group"       -> f.desc.map{_.group}) ~
 | 
				
			||||||
 | 
					            ("groupDesc"   -> f.desc.map{_.groupDesc}) ~
 | 
				
			||||||
 | 
					            ("accessType"  -> f.desc.map {d => d.access.toString})
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					        currentBitOffset = currentBitOffset + f.width
 | 
				
			||||||
 | 
					        tmp
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: It would be better to name this other than "Device at ...."
 | 
				
			||||||
 | 
					    val base = s"0x${address.head.base.toInt.toHexString}"
 | 
				
			||||||
 | 
					    val json = ("peripheral" -> (
 | 
				
			||||||
 | 
					      ("displayName" -> s"deviceAt${base}") ~
 | 
				
			||||||
 | 
					      ("baseAddress" -> base) ~
 | 
				
			||||||
 | 
					      ("regfields" -> regDescs)
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					    ElaborationArtefacts.add(s"${base}.regmap.json", pretty(render(json)))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user