-
Notifications
You must be signed in to change notification settings - Fork 10
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
Add RFC for an UART peripheral. #60
base: main
Are you sure you want to change the base?
Conversation
20b190d
to
c4dd011
Compare
c4dd011
to
5c324aa
Compare
Overall, this peripheral comes across as substantially under-opinionated to me. Essentially all the logic and behavior is in the PHY, so this really just specifies a schema for connecting a UART peripheral to the CSR bus, rather than being a peripheral in its own right. But it's limiting because the PHY is going to have to be closely coupled to the peripheral due to the shared interface prescribing the features. I don't think there's anything that could be added without changing this, except for DMA. I would be strongly in favor of dropping the possibilities of multiple PHYs and just dragging in (or duplicating) amaranth-stdio for the implementation. Some more specific comments:
|
The RFC is explicitly designed to be usable with anything that comes with a pair of streams. Furthermore, nothing in Amaranth SoC is supposed to duplicate or even closely couple to Amaranth stdio. I don't expect that to change. The advantage of being able to couple to anything that's a pair of streams is that the peripheral becomes truly a "basic universal asynchronous receiver/transmitter" peripheral rather than an RS-232 peripheral that most "UART"s are. I consider this a highly desirable property in its own right. It is not intended to replicate the 16550 interface in the slightest.
I came up with the packing scheme for 3 scale bits and 13 mantissa bits, and it has less than 1% error for all bauds from 9600 to 3M, and all clocks from 32k to 200M, except for these:
Unless you're really into 9600 baud this is good enough. You can also play with the script.
No, that is of no concern to the firmware author.
The entire current amaranth-stdio PHY will be removed and replaced with a new one based on an actual methodology rather than some scribbles I did five years ago. |
I personally agree with not duplicating _stdio things in _soc. I do find though that current implementation needs quite some boilerplate code for each UART instantiation. I think the divisor and the pins are what will be specific for each instance and the rest will be boilerplate. I think it would be good to have convenience function that has the boilerplate code included. |
Broadly speaking I agree but we are still at the stage where we are finding out what are the conventions and methodologies for building SoC peripherals. So I think such a function can be added at a later stage, when we have gained more understanding of what it means to build a SoC in Amaranth. (This is also how I approach the core language, so my position should not be surprising.) |
- do not enforce a divisor encoding (besides being 16 bits). - fix signature direction (the peripheral drives the interface). - do not use abbreviated names (`rdy` is renamed to `ready`, etc). - rename `Enable` to `Control` and add ResR0W0 padding bits. - clarify the behavior of `Control.enable` values (0 and 1). - reorder registers (`Status` now follows `Control`). - rename `data_bits` to `symbol_width` and `data` to `symbol`. - `symbol_width` must be a positive integer.
- do not enforce a divisor encoding (besides being 16 bits). - fix signature direction (the peripheral drives the interface). - do not use abbreviated names (`rdy` is renamed to `ready`, etc). - rename `Enable` to `Control` and add ResR0W0 padding bits. - clarify the behavior of `Control.enable` values (0 and 1). - reorder registers (`Status` now follows `Control`). - rename `data_bits` to `symbol_width` and `data` to `symbol`. - `symbol_width` must be a positive integer.
fc8181c
to
d2c1834
Compare
fd1062f
to
5638b9d
Compare
Changed to draft status, which will be removed once the UART in amaranth-stdio is |
This RFC was discussed during the 2024-03-22 SoC meeting:
|
Updated to use a The layout of the
|
I think it's worth adding a few words on the intended CDC architecture as it's a common pain point with things like UARTs. It's desirable to support a separate baud-reference clock from the bus clock, so that you don't have to reconfigure the UART when dynamically scaling the bus frequency. At the same time, you don't want to have to expose details of the CDC strategy to the user (like PL011 having the weird LCR write latching behaviour, and forbidding changing some settings whilst the UART is running). Ideally you want to avoid unstructured CDC between CSRs and internals/PHY. Conversely you don't want to just have a bus CDC going into a single-domain UART implementation running from the reference clock, because this causes severe bus stalls when the reference domain is much slower than the bus clock. One way to get around this is to split your bus into two segments:
This style of CDC architecture avoids bus stalls for the common case of FIFO + status access. You can implement it with multiple bus subordinates, or with a single subordinate and an internal bus splitter. You can also generate DMA requests from the bus-side FIFO status, which avoids having to CDC the DMA request. I'm just trying to provoke discussion as this is a tricky topic, and this design's support for multiple PHYs is quite ambitious. |
I'm on vacation until January, but I'd be interested to brainstorm this approach afterwards. |
Rendered.