chipsalliance / chisel

Chisel: A Modern Hardware Design Language
https://www.chisel-lang.org/
Apache License 2.0
3.83k stars 578 forks source link

Hard to obtain needed context to build IR for referencing results of `FirrtlMemory` #4022

Open SpriteOvO opened 2 months ago

SpriteOvO commented 2 months ago

I'm trying to add support for #3955 in panama converter, and it's working in progress under binder-fir-mem-binding branch (code is a bit mess at the moment). We create IR firrtl.memory for FirrtlMemory, the IR returns multiple MlirValue results based on the number of ports.

So far, I seem to be successfully associating the MlirValue with the target port via SramTarget. For referencing normal bundle fields, we compute the field index (because firrtl.subfield needs index) via chisel.data.binding (code). But for referencing fields under ports of FirrtlMemory in subsequent operations, something like Slot(Slot(Node(chisel3.SramTarget),RW0),wmask) is given in the Chisel IR - only the field name is provided in the Slot.

Currently panama converter does not store types itself, but tries its best to use the context given by Chisel internal. Am I missing a clean way to compute their indexes? Reflection might work, but it's not really clean to me. Maybe we should make some changes / improvements to FirrtlMemory?

jackkoenig commented 2 months ago

This is a tricky one. The type of wmask is essentially a shadow type of the data type where every leaf element is a Bool instead of whatever the original data type has. This is pretty difficult to represent in Chisel, so we took a short cut. We left wmask off of the Chisel types representing the memory ports (https://github.com/chipsalliance/chisel/blob/03ef61f3a14831ae34caa0fa5b800291ca0299db/src/main/scala/chisel3/util/SRAM.scala#L641) and instead just manually construct the Chisel IR for accessing the wmask: https://github.com/chipsalliance/chisel/blob/03ef61f3a14831ae34caa0fa5b800291ca0299db/src/main/scala/chisel3/util/SRAM.scala#L564.

It's not super clean, but for computing the field index, wmask should have the same field indices as the regular data type would, but again with the tweak that the actual type of the leaf element field is UInt<1>. I would like to represent the wmask in pure Chisel, and I have a prototype of how to do it, but the code is nasty and I don't have time to clean it up and upstream it right now.

sequencer commented 2 months ago

I’m wondering how about going to another path to intmodule version of SRAM? w/o using firrtl.mem as intermediate representation? We also have some problem on the memory for the mbist which cannot be represented by firrtl ir.

SpriteOvO commented 2 months ago

@jackkoenig I apologize for the late update.

Let's say a val mem = SRAM(1024, UInt(8.W), 1, 1, 1), it will auto generated a

mem mem_sram :
  data-type => UInt<8>
  depth => 1024
  read-latency => 1
  write-latency => 1
  reader => R0
  writer => W0
  readwriter => RW0
  read-under-write => undefined

and auto connect them to a mem wire

connect mem_sram.R0.addr, mem.readPorts[0].address
connect mem_sram.R0.clk, clock
connect mem.readPorts[0].data, mem_sram.R0.data
connect mem_sram.R0.en, mem.readPorts[0].enable
connect mem_sram.W0.addr, mem.writePorts[0].address
connect mem_sram.W0.clk, clock
connect mem_sram.W0.data, mem.writePorts[0].data
connect mem_sram.W0.en, mem.writePorts[0].enable
connect mem_sram.W0.mask, UInt<1>(0h1)
connect mem_sram.RW0.addr, mem.readwritePorts[0].address
connect mem_sram.RW0.clk, clock
connect mem_sram.RW0.en, mem.readwritePorts[0].enable
connect mem.readwritePorts[0].readData, mem_sram.RW0.rdata
connect mem_sram.RW0.wdata, mem.readwritePorts[0].writeData
connect mem_sram.RW0.wmode, mem.readwritePorts[0].isWrite
connect mem_sram.RW0.wmask, UInt<1>(0h1)

The concrete value of loc: Arg for these connect IRs looks like Slot(Slot(Node(chisel3.SramTarget),RW0),wmask), so the only known information here is a SramTarget, a mem port name string ("RW0"), and a port field name string ("wmask").

FirrtlMemory contains 3 names, respectively for R, W, and RW

https://github.com/chipsalliance/chisel/blob/d4dd11c711e19b44b5ee5985fe45b119350eff92/core/src/main/scala/chisel3/internal/firrtl/IR.scala#L291-L299

firrtl.mem returns multiple MlirValue in order of the parameter portNames we passed. portNames is an array which should not care about the order, as long as the order of the given return types matches the names.

So the first thing is that we need a way to determine which referenced mem port (e.g. R0, R1, W0, or RW0) corresponds to which returned MlirValue.

Then, we need to know which bundle the field (e.g addr, wmask, or mask) under the mem port belongs to, so we can calculate the field index. Like the way we calculate for a normal field

https://github.com/chipsalliance/chisel/blob/d4dd11c711e19b44b5ee5985fe45b119350eff92/panamaconverter/src/PanamaCIRCTConverter.scala#L378-L381


These are the difficulties I can imagine at the moment and I'm trying to explain it clearly, but if you have any further questions please feel free to ask me.