-
Notifications
You must be signed in to change notification settings - Fork 404
[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
Conversation
| 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.
| 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())),
| ; 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. |
seldridge
left a comment
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.
| } | ||
| 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
| 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.
| ; 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: |
prithayan
left a comment
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.
| ; 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.
| } | ||
| 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
454f29a to
0f584d4
Compare
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_behaviorthat can take one of the following values :Undefined,New,Old.Undefinedbehavior is elided to keep the format unchanged for the common case. Otherwiseruw Neworruw Oldis appended to the memory's line.MemorySchemaas 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
ruwattribute toFMemModuleOp. Previously, this attribute was just anI32EnumAttr. When adding it to theFMemModuleOp's attribute dictionary this would become a generici32typed attribute, which did not seem desirable to me. So I replaced theRUWAttrwith aRUWBehaviorAttrdialect 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.