1
votes

I am working with a DSL (Chisel) in which one particular part of the library requires me to define a Seq of items. I have several companion objects to create some intermediate logic and return one of these items. I have a situation where I want to actually return two of these items, but I'm having a hard time figuring out how to do that.

Let's say the "items" here are Person. (What Person is here is not important)

The DSL wants you to describe all your Persons through a Seq.

val p1 = new Person(1)
val p2 = new Person(2)

Seq(p1,p2)

I have a case where I want to link two people together. For example, I know some people have friends that they drag everywhere, so if they are showing up so is their friend (even if I don't like them). So I want to be able to do something similar to the following.

object Group {
  def apply(): Person, Person = {  //return two of these
    val pA  = new Person(10)
    val pAA = new Person(10+1)
  }
}

this way, I can easily just do the following

Seq(p1, p2, Group)

//The Seq should have p1, p2, and the pA, pAA 

Since this is a DSL, I do not have access to change the internals. I could create each piece of the Seq, then combine them all together, however this isn't ideal as this is something I'll do often enough that a good solution is desirable. I can't send back a tuple for the same reason.

I tried to see if the variable args would work on the return, but that did not seem to work.

Any help would be appreciated. Thanks


Update for our lord and savior Jack Koenig

This is utilizing the RocketChip RegisterRotuer node to describe the RegFields

It is often in my designs where I have a signal coming from some logic and I want software to have the ability to block the upstream logic and drive a signal manually (think about some enable you want software to be able to drive). To do this I build a SW register that represents the driven value, and a "mux" SW register that handles the control. What I've currently done is this (currently returning a Seq[RegField] but hopefully you see where I wanted this to be two RegField types

/**
  *   Creates a muxed override register. This allows software to take control of a particular signal by setting the "_mux" register
  *   high. Once in this mode, the value of the signal is based on the software register defined here.
  *
  *   This method makes the assumption that you want the two bitfields to be next to each other (reg then mux). If you do not want this
  *   or can't do this (because the signal you want to control is >=32bits) you will have to create two separate RWReg. One for the mux
  *   and one for the SW control value
  *
  *
  *   val rx_reset_reg    = Wire(Bool())
  *   val rx_reset_mux    = Wire(Bool())
  *   val rx_reset        = WavClockMux (rx_reset_mux,  rx_reset_reg,   io.core.rx_reset)
  *   WavD2DRxRegs.CoreOverride   -> Seq(WavRWReg(rx_reset_reg,0.U,      "rx_reset",       "RX Reset"),
  *                                      WavRWReg(rx_reset_mux,0.U,      "rx_reset_mux",   "Mux override for rx_reset")),
  *
  *
  *   This method also has the nuance that it returns a Seq[RegField]. So you must concatenate this companion object with the higher leve
  *   Seq[RegField] that we normally use for register generation
  *   
  *   WavRWMuxReg(in=io.core.tx_en,     muxed=io.ana.tx_en,    reg_reset=false.B, mux_reset=false.B, "tx_en",    "Main TX enable") ++ Seq(<other regFields>)
  */
object WavRWMuxReg{
  
  def apply[T <: Data](in: T, muxed : T, reg_reset: T, mux_reset: Bool, name: String, desc: String)(implicit p: Parameters): Seq[RegField] = {
    //val reg = RegInit(reset)
    val reg = RegInit(muxed.cloneType, reg_reset)
    reg.suggestName("swi_" + name)
    
    val mux = RegInit(mux_reset)
    mux.suggestName("swi_" + name + "_mux")
    
    muxed := Mux(mux, reg, in)
    
    //litValue returns the Bigint value
    val rf_reg = RegField(reg.getWidth, reg.asUInt, RegFieldDesc(name,        desc, access=RegFieldAccessType.RW , reset=Some(reg_reset.litValue)))
    val rf_mux = RegField(1           , mux.asUInt, RegFieldDesc(name+"_mux", "Mux control for corresponding register", access=RegFieldAccessType.RW , reset=Some(mux_reset.litValue)))
    Seq(rf_reg, rf_mux)
  }
}

  • in is the input logic
  • muxed will be the post muxed signal (can be assigned to something like a Bundle signal)
  • *_reset are the reset value for the auto generated value/mux SW registers

So ideally I would use this to create both and would be able to just say

node.regmap(
  0x0 -> Seq(WavRWReg(/*custom method that returns RegField*/),
             WavRWMuxReg(/*returns two RegFields*/))
)
1
Can you provide an example using the actual Chisel APIs? This sounds to me a bit like the "HardwareTuple" idea (see github.com/chipsalliance/chisel3/issues/864). While that issue is a bit old, I have an idea (DataView) that I'm hoping to implement in Chisel 3.5 that may do what you want (gist.github.com/jackkoenig/20bffc2e9270386044aba9f00bc82fd5).Jack Koenig
Hey @JackKoenig, I've updated with the Chisel/RocketChip specifics. It seems like more of a Scala limitation. The workaround proposed by Dima isn't bad, it's just a little funky and looks a little ugly when you have to do several of them. I don't think it's worth expanding Chisel/RC to compensate for this. But happy to hear your thoughts. Thanksl Steveo l
Hey there Steveo, yeah I think Dima's solution is best here. You could also use the Seq and do a .flatten if that looks better for you, but unless rocket-chip were to supply a RegFields(...) sort of construct, you're sort of stuck with the slightly ugly stuff.Jack Koenig
Cool, I will stick with Dima's solution.l Steveo l

1 Answers

2
votes

Return a Seq and concatenate?

    object PlusN {
       def apply(m, n): Seq[Person] = (m to m+n).map(Person)
    }
    
   val people = Seq(p1, p2) ++ PlusN(10, 1)