-
Notifications
You must be signed in to change notification settings - Fork 354
[FIRRTL][CreateSiFiveMetadata] Add memory read-under-write behavior to emitted metadata #8604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@@ -292,7 +292,7 @@ MLIR_CAPI_EXPORTED MlirAttribute firrtlAttrGetParamDecl(MlirContext ctx, | |||
MLIR_CAPI_EXPORTED MlirAttribute firrtlAttrGetNameKind(MlirContext ctx, | |||
FIRRTLNameKind nameKind); | |||
|
|||
/// Creates a RUWAttr with the specified Read-Under-Write Behaviour. | |||
/// Creates a RUWBehaviorAttr with the specified Read-Under-Write Behavior. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologise to the British, but since the FIRRTL spec is written in AE I chose 'behavior'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's usually the Canadians you have to watch out for...
DenseBoolArrayAttr:$portDirections, ArrayRefAttr:$portLocations, | ||
ArrayRefAttr:$portAnnotations, ArrayRefAttr:$portSymbols, | ||
ArrayRefAttr:$portNames, ArrayRefAttr:$portTypes, | ||
DefaultValuedAttr<RUWBehaviorAttr, "firrtl::RUWBehavior::Undefined">:$ruw, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making RUWBehavior::Undefined
the default reduces the impact of this change but might increase the chances of accidentally dropping specified behavior.
seqMemConfStr = (StringRef(seqMemConfStr) + "name {{" + Twine(symId) + | ||
"}} depth " + Twine(mem.getDepth()) + " width " + | ||
Twine(width) + " ports " + portStr + maskGranStr + "\n") | ||
Twine(width) + " ports " + portStr + maskGranStr + | ||
(mem.getRuw() == RUWBehavior::Undefined | ||
? "" | ||
: " ruw " + stringifyRUWBehavior(mem.getRuw())) + | ||
"\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting a bit out of hand. When I'll also add the MemoryInitAttr
to the metadata, I'll probably just append the string instead of concatenating twines.
@@ -206,7 +206,8 @@ LowerMemoryPass::emitMemoryModule(MemOp op, const FirMemory &mem, | |||
auto moduleOp = b.create<FMemModuleOp>( | |||
mem.loc, moduleName, ports, mem.numReadPorts, mem.numWritePorts, | |||
mem.numReadWritePorts, mem.dataWidth, mem.maskBits, mem.readLatency, | |||
mem.writeLatency, mem.depth); | |||
mem.writeLatency, mem.depth, | |||
*symbolizeRUWBehavior(uint32_t(mem.readUnderWrite))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a huge fan of this myself, but it is just the inverse of line 92: *seq::symbolizeRUW(unsigned(op.getRuw())),
@@ -116,13 +116,13 @@ circuit test: | |||
; CHECK: FILE "metadata/tb_seq_mems.json" | |||
; CHECK: [{"module_name":"memory","depth":16,"width":8,"masked":"true", | |||
; CHECK-SAME: "read":"true","write":"true","readwrite":"false", | |||
; CHECK-SAME: "mask_granularity":8,"extra_ports":[], | |||
; CHECK-SAME: "ruw_behavior": "Undefined","mask_granularity":8,"extra_ports":[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really sure what this test is supposed to do. Does it just check that the metatdata is not emitted without the --repl-seq-mem option?
At the moment it should always expectedly fail as the formatting has not been updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure... @prithayan do you have any idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I've no recollection of why this was added. I'll get rid of it in another PR.
Thanks @fzi-hielscher for the PR, I'm also taking a look at it, will have the review by Monday. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I'll try to get a head start to figure out if this is going to break anything internally due to the format changes of some of these files. However, that is my problem.
@@ -314,7 +315,7 @@ struct ObjectModelIR { | |||
extraPortsList.push_back(extraPortsObj); | |||
} | |||
auto extraPorts = builderOM.create<ListCreateOp>( | |||
memorySchemaClass.getPortType(22), extraPortsList); | |||
memorySchemaClass.getPortType(24), extraPortsList); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this bump by +2 when others only bumped by +1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it crashed after I initially just increased it by one. 😉
The builder for the ClassOp
creates both an input and an output port for each field. So the extraPorts
port is shifted by two positions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, FIRRTL class, doesn't have the fields
representation. It uses input and output ports to represent fields, hence the +2
@@ -206,7 +206,8 @@ LowerMemoryPass::emitMemoryModule(MemOp op, const FirMemory &mem, | |||
auto moduleOp = b.create<FMemModuleOp>( | |||
mem.loc, moduleName, ports, mem.numReadPorts, mem.numWritePorts, | |||
mem.numReadWritePorts, mem.dataWidth, mem.maskBits, mem.readLatency, | |||
mem.writeLatency, mem.depth); | |||
mem.writeLatency, mem.depth, | |||
*symbolizeRUWBehavior(uint32_t(mem.readUnderWrite))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit?
*symbolizeRUWBehavior(uint32_t(mem.readUnderWrite))); | |
*symbolizeRUWBehavior(static_cast(mem.readUnderWrite))); |
; MLIR_OUT: om.class @MemorySchema(%basepath: !om.basepath, %name_in: !om.string, %depth_in: !om.integer, %width_in: !om.integer, %maskBits_in: !om.integer, %readPorts_in: !om.integer, %writePorts_in: !om.integer, %readwritePorts_in: !om.integer, %writeLatency_in: !om.integer, %readLatency_in: !om.integer, %hierarchy_in: !om.list<!om.path>, %inDut_in: i1, %extraPorts_in: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, %preExtInstName_in: !om.list<!om.string>) -> (name: !om.string, depth: !om.integer, width: !om.integer, maskBits: !om.integer, readPorts: !om.integer, writePorts: !om.integer, readwritePorts: !om.integer, writeLatency: !om.integer, readLatency: !om.integer, hierarchy: !om.list<!om.path>, inDut: i1, extraPorts: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, preExtInstName: !om.list<!om.string>) | ||
; MLIR_OUT: om.class.fields %name_in, %depth_in, %width_in, %maskBits_in, %readPorts_in, %writePorts_in, %readwritePorts_in, %writeLatency_in, %readLatency_in, %hierarchy_in, %inDut_in, %extraPorts_in, %preExtInstName_in : !om.string, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.list<!om.path>, i1, !om.list<!om.class.type<@ExtraPortsMemorySchema>>, !om.list<!om.string> | ||
; MLIR_OUT: om.class @MemoryMetadata(%basepath: !om.basepath) -> (foo_m_ext_field: !om.class.type<@MemorySchema>, bar_m_ext_field: !om.class.type<@MemorySchema>, baz_m_ext_field: !om.class.type<@MemorySchema>) | ||
; MLIR_OUT: om.class @MemorySchema(%basepath: !om.basepath, %name_in: !om.string, %depth_in: !om.integer, %width_in: !om.integer, %maskBits_in: !om.integer, %readPorts_in: !om.integer, %writePorts_in: !om.integer, %readwritePorts_in: !om.integer, %writeLatency_in: !om.integer, %readLatency_in: !om.integer, %ruwBehavior_in: !om.string, %hierarchy_in: !om.list<!om.path>, %inDut_in: i1, %extraPorts_in: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, %preExtInstName_in: !om.list<!om.string>) -> (name: !om.string, depth: !om.integer, width: !om.integer, maskBits: !om.integer, readPorts: !om.integer, writePorts: !om.integer, readwritePorts: !om.integer, writeLatency: !om.integer, readLatency: !om.integer, ruwBehavior: !om.string, hierarchy: !om.list<!om.path>, inDut: i1, extraPorts: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, preExtInstName: !om.list<!om.string>) | ||
; MLIR_OUT: om.class.fields %name_in, %depth_in, %width_in, %maskBits_in, %readPorts_in, %writePorts_in, %readwritePorts_in, %writeLatency_in, %readLatency_in, %ruwBehavior_in, %hierarchy_in, %inDut_in, %extraPorts_in, %preExtInstName_in : !om.string, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.string, !om.list<!om.path>, i1, !om.list<!om.class.type<@ExtraPortsMemorySchema>>, !om.list<!om.string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh... this is not great to work with. Somebody (not you, likely me) needs to go in and convert all of this to *-SAME
checks to make this more manageable.
//------------------------------------------------------------------ (1) OM Info | ||
// CHECK-LABEL: firrtl.class @MemoryMetadata({{.*$}} | ||
// CHECK: %[[memoryObject:.+]] = firrtl.object @MemorySchema | ||
// CHECK: %[[#a:]] = firrtl.string "Old" | ||
// CHECK-NEXT: %[[#ruw:]] = firrtl.object.subfield %[[memoryObject]][ruwBehavior_in] | ||
// CHECK-NEXT: firrtl.propassign %[[#ruw]], %[[#a]] | ||
|
||
//-------------------------------------------------------------- (2) Memory JSON | ||
// CHECK-LABEL: emit.file "metadata{{/|\\\\}}seq_mems.json" | ||
// CHECK-NEXT: sv.verbatim "[ | ||
// CHECK: \22ruw_behavior\22: \22Old\22 | ||
|
||
//------------------------------------------------------- (3) Configuration File | ||
// CHECK-LABEL: emit.file "mems.conf" | ||
// CHECK-NEXT: sv.verbatim | ||
// CHECK-SAME: ruw Old |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice test organization. 💯
test/firtool/memoryLowering.fir
Outdated
{ | ||
"class":"sifive.enterprise.firrtl.MarkDUTAnnotation", | ||
"target": "test.test" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: is the MarkDUTAnnotation
necessary?
Ditto for the second split test in this file.
@@ -116,13 +116,13 @@ circuit test: | |||
; CHECK: FILE "metadata/tb_seq_mems.json" | |||
; CHECK: [{"module_name":"memory","depth":16,"width":8,"masked":"true", | |||
; CHECK-SAME: "read":"true","write":"true","readwrite":"false", | |||
; CHECK-SAME: "mask_granularity":8,"extra_ports":[], | |||
; CHECK-SAME: "ruw_behavior": "Undefined","mask_granularity":8,"extra_ports":[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure... @prithayan do you have any idea?
Thanks, @seldridge. It's not a problem for me to delay this a bit more to make sure all known users are prepared. I've also lined up the PR for The script we are using internally has been forked many years ago from the rocket-chip repo: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Hopefully will "just work" with outer internal flow. :)
; MLIR_OUT: om.class.fields %name_in, %depth_in, %width_in, %maskBits_in, %readPorts_in, %writePorts_in, %readwritePorts_in, %writeLatency_in, %readLatency_in, %hierarchy_in, %inDut_in, %extraPorts_in, %preExtInstName_in : !om.string, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.list<!om.path>, i1, !om.list<!om.class.type<@ExtraPortsMemorySchema>>, !om.list<!om.string> | ||
; MLIR_OUT: om.class @MemoryMetadata(%basepath: !om.basepath) -> (foo_m_ext_field: !om.class.type<@MemorySchema>, bar_m_ext_field: !om.class.type<@MemorySchema>, baz_m_ext_field: !om.class.type<@MemorySchema>) | ||
; MLIR_OUT: om.class @MemorySchema(%basepath: !om.basepath, %name_in: !om.string, %depth_in: !om.integer, %width_in: !om.integer, %maskBits_in: !om.integer, %readPorts_in: !om.integer, %writePorts_in: !om.integer, %readwritePorts_in: !om.integer, %writeLatency_in: !om.integer, %readLatency_in: !om.integer, %ruwBehavior_in: !om.string, %hierarchy_in: !om.list<!om.path>, %inDut_in: i1, %extraPorts_in: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, %preExtInstName_in: !om.list<!om.string>) -> (name: !om.string, depth: !om.integer, width: !om.integer, maskBits: !om.integer, readPorts: !om.integer, writePorts: !om.integer, readwritePorts: !om.integer, writeLatency: !om.integer, readLatency: !om.integer, ruwBehavior: !om.string, hierarchy: !om.list<!om.path>, inDut: i1, extraPorts: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, preExtInstName: !om.list<!om.string>) | ||
; MLIR_OUT: om.class.fields %name_in, %depth_in, %width_in, %maskBits_in, %readPorts_in, %writePorts_in, %readwritePorts_in, %writeLatency_in, %readLatency_in, %ruwBehavior_in, %hierarchy_in, %inDut_in, %extraPorts_in, %preExtInstName_in : !om.string, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.string, !om.list<!om.path>, i1, !om.list<!om.class.type<@ExtraPortsMemorySchema>>, !om.list<!om.string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most likely I'm the culprit, I'll format this properly in another PR.
@@ -116,13 +116,13 @@ circuit test: | |||
; CHECK: FILE "metadata/tb_seq_mems.json" | |||
; CHECK: [{"module_name":"memory","depth":16,"width":8,"masked":"true", | |||
; CHECK-SAME: "read":"true","write":"true","readwrite":"false", | |||
; CHECK-SAME: "mask_granularity":8,"extra_ports":[], | |||
; CHECK-SAME: "ruw_behavior": "Undefined","mask_granularity":8,"extra_ports":[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I've no recollection of why this was added. I'll get rid of it in another PR.
@@ -314,7 +315,7 @@ struct ObjectModelIR { | |||
extraPortsList.push_back(extraPortsObj); | |||
} | |||
auto extraPorts = builderOM.create<ListCreateOp>( | |||
memorySchemaClass.getPortType(22), extraPortsList); | |||
memorySchemaClass.getPortType(24), extraPortsList); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, FIRRTL class, doesn't have the fields
representation. It uses input and output ports to represent fields, hence the +2
This PR adds information on the read under write behavior of memories, as specified by the FIRRTL/CHIRRTL IR, to the emitted memory metadata records. This includes the textual
repl-seq-mem-file
, theseq_mem.json
, and the object model IR. It should allow external tools to generate memories with the appropriate behavior.ruw_behavior
that can take one of the following values :Undefined
,New
,Old
.Undefined
behavior is elided to keep the format unchanged for the common case. Otherwiseruw New
orruw Old
is appended to the memory's line.MemorySchema
as a string-typed subfield calledruwBehavior
. I've never dealt with the object model before and I don't really know how enums should be handled here. So, please tell me if I should change my approach.To make this information available at the point of metadata emission, I had to add the
ruw
attribute toFMemModuleOp
. Previously, this attribute was just anI32EnumAttr
. When adding it to theFMemModuleOp
's attribute dictionary this would become a generici32
typed attribute, which did not seem desirable to me. So I replaced theRUWAttr
with aRUWBehaviorAttr
dialect attribute to give it an enum specific serialization (ruw = #firrtl<ruwbehavior Undefined>
). Unfortunately, this creates a fair amount of change noise. I can break it out as a separate PR if desired.