-
Notifications
You must be signed in to change notification settings - Fork 615
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
Implement read-write memory accessors for SyncReadMem #3190
Conversation
Can we add this to the Memories explanations doc |
Or add a new cookbook "how to I make a 1readwrite port memory, how do I make a 1r1w port memory"? |
* val mem = Module(new MyMemWrapper) | ||
* mem.io := DontCare | ||
* | ||
* val rdata = Wire(UInt(2.W)) |
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 code would not quite compile
* val rdata = Wire(UInt(2.W)) | ||
* readData := DontCare |
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.
* val rdata = Wire(UInt(2.W)) | |
* readData := DontCare | |
* val rdata = Wire(UInt(2.W)) | |
* rdata := DontCare |
* readData := DontCare | ||
* | ||
* // Read from the memory port | ||
* when(doRead) { |
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.
what is doRead
? an Input?
* } | ||
* // Read data will show up on the next cycle | ||
* when(timeToRead) { | ||
* readData := mem.io.rdata |
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 a little confusing, the user is going to have to understand that the rddata is available the following cycle. Let's just omit this part
* | ||
* val rdata = Wire(UInt(2.W)) | ||
* readData := DontCare | ||
* |
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.
we should default mem.io.enable to false.B
scaladoc nits
This LGTM. I am not sure if there are any issues on the CIRCT side in interpreting this. Can @jackkoenig @seldridge give a review? |
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.
A long missing API. Great work!
Minor nits throughout. Good to land whenever you're ready.
val a = Wire(UInt()) | ||
a := DontCare |
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.
Using val _a
indicates better that this is a temporary. Same for port
. Basically, I would use _
for any hardware component created in a library/utility.
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.
Nits/golf:
val a = Wire(UInt()) | |
a := DontCare | |
val _a = WireDefault(chiselTypeOf(addr), DontCare) |
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.
Same comments for the masked version.
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.
Is the declaration of a
separate from the connection of addr
to it required for the enable
to infer correctly @jared-barocsi? Or why else is is split?
Also are we sure returning the port works? Such value capturing is often problematic for lexical scoping, what happens if someone uses the return value of this function? Perhaps we should be assigning the read data to a wire? The integration test is passing so that suggests the lexical scoping is okay or at least supported by firtool but I'd be curious to see what the FIRRTL actually looks like.
* } | ||
* }}} | ||
* | ||
* @note this is only allowed if the memory's element data type is a Vec |
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.
At least in FIRRTL this is allowed so long as the type of the mask is the same type as the underlying data type with the leaf types as all 1-bit UInts. I.e., this is supported on any aggregate including bundles.
This is a relatively niche feature and pretty rare. I am fine to start this as only working for Vec
(which makes sense).
@@ -188,6 +188,156 @@ private class TrueDualPortMemory(addrW: Int, dataW: Int) extends RawModule { | |||
} | |||
} | |||
|
|||
class MemReadWriteTester extends BasicTester { |
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 a huge fan of big integration tests like this. However, this is entirely consistent with the rest of this existing file.
Can you open an issue to move all refactor this to move the integration tests into the integration test area and slim these down to just checking the CHIRRTL?
I didn't notice you had auto-merge on. 😂 Any cleanup/feedback can happen post-merge. 😉 |
enable := true.B; | ||
isWrite := false.B; |
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.
Can you please remove all of the semicolons in this file?
Adds new APIs to generate explicit read-write (rdwr) ports for a SyncReadMem, and all masked or clocked variants. --------- Co-authored-by: Megan Wachs <[email protected]> (cherry picked from commit 1e6f2b4)
Adds new APIs to generate explicit read-write (rdwr) ports for a SyncReadMem, and all masked or clocked variants. --------- Co-authored-by: Megan Wachs <[email protected]> (cherry picked from commit 1e6f2b4)
Adds new APIs to generate explicit read-write (rdwr) ports for a SyncReadMem, and all masked or clocked variants. --------- Co-authored-by: Megan Wachs <[email protected]> (cherry picked from commit 1e6f2b4) Co-authored-by: Jared Barocsi <[email protected]>
)( | ||
implicit evidence: T <:< Vec[_] | ||
): T = masked_readWrite_impl(idx, writeData, mask, en, isWrite, clock, true) | ||
|
||
private def masked_readWrite_impl( | ||
addr: UInt, | ||
data: T, | ||
mask: Seq[Bool], | ||
enable: Bool, | ||
isWrite: Bool, | ||
clock: Clock, | ||
warn: Boolean | ||
)( | ||
implicit evidence: T <:< Vec[_] | ||
): T = { | ||
implicit val sourceInfo = UnlocatableSourceInfo | ||
val a = Wire(UInt()) |
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 would also be good to have a source locator here, since we're already taking an implicit argument we can just take the sourceInfo argument. Users won't be able to immediately call .apply
on the return value, but due to the existing implicit argument, they already can't.
#3213) * Implement read-write memory accessors for SyncReadMem (#3190) Adds new APIs to generate explicit read-write (rdwr) ports for a SyncReadMem, and all masked or clocked variants. --------- Co-authored-by: Megan Wachs <[email protected]> (cherry picked from commit 1e6f2b4) * Add CompileOptions to SyncReadMem.readWrite methods --------- Co-authored-by: Jared Barocsi <[email protected]> Co-authored-by: Jack Koenig <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Implements
SyncReadMem.readWrite(address, writeData, enabled, isWrite)
as a way to explicitly instantiate a readwrite port for a memory. This addresses the problem of unintentionally creating multiple read or write ports through multiple calls ofSyncReadMem.read()
and/orSyncReadMem.write()
. Additionally, implements clocked and masked versions ofreadWrite
for parity with the existingread
andwrite
functions.Compare:
which instantiates a 1R2W memory, as opposed to
which instantiates a 1RW memory.
Contributor Checklist
docs/src
?Type of Improvement
Desired Merge Strategy
squash and merge
Release Notes
SyncReadMem.readWrite(address, writeData, enabled, isWrite)
explicitly generates a read-write port that supports both read and write access to the memory.Reviewer Checklist (only modified by reviewer)
3.5.x
or3.6.x
depending on impact, API modification or big change:5.0.0
)?Enable auto-merge (squash)
, clean up the commit message, and label withPlease Merge
.Create a merge commit
.