-
Notifications
You must be signed in to change notification settings - Fork 99
Conversation
So, width is in bytes and pad is in bits? Any reason for that? |
What does |
@farcaller, I had intended for both width and pad to be in bits. |
@farcaller, |
Can you cherry-pick 7cbad1e on top of current master? I suppose that other commits are not related to |
So, |
@farcaller, I just elaborated a bit in the pull request message. |
@farcaller to summarize, field types are defined by an element type and a repeat count. The syntax for this is
|
@farcaller, I've cleaned up and updated the text and example above. Let me know what you think. The biggest syntactic issue I see is the fact that the count always appears after the type as this ends up being a bit awkward in the case of long
ioregs!(FTM,
...
CH[8]: struct Channel { ... },
ioregs!(FTM,
...
struct Channel { ... },
CH: Channel[8], Otherwise, I'm currently grappling with how to specify the memory map and use bitbanding. At the moment I'm thinking the memory map (including bitband windows) can be specified in a external file in a structured format like JSON. Bitbanding will be used in single-bit field accessors for peripheral instances covered by a bitband window. As not all peripheral instances fall in a bitband window, we may need to emit a separate type for each peripheral instance (e.g. |
So I see two things that confuse me so far:
We are not the only ones trying to come up with a meta-language for peripheral definitions, there's at least this one. I don't say we need to generate that from yaml or whatever, the more things stay in rust code, the more we push rust to the limits. |
Let's say, if you don't think about code and accessing the peripheral, how would you like to see it's definition? We can convert a definition of about any complexity down to code, but it must be simple to read. This is about the only place we cannot cover with unit tests, so there would be errors in ioregs. We need to minimise the margin for error, to the primary goal for a new ioreg is to be simple and readable. |
@farcaller, is your first point just a syntactic concern? Perhaps just dropping the I absolutely agree with your point about the repeat count (e.g. |
@farcaller, so far I've been trying to guide the syntax towards being easy to read (although that's not to say that I've succeeded). In my mind, the current syntax (up to minor changes like dropping the |
@farcaller, in the process of formalizing the semantics I've realized that this representation might not be quite sufficient. In particular, we really don't have enough information to unambiguously choose an access width. In practice this may not be a problem since even on the rather quirky K20 I haven't noticed any architectural assumptions on access width. That being said, there may very well be an architecture that does care. The problem is that currently The trouble with this is that your point regarding the inconsistent use of Here is my latest proposed syntax, moving the repeat count behind the field name and using an explicit |
Alternatively, if we really wanted to leave Rust syntax behind, we could try something like the following. It has the advantage of not requiring explicit padding, is a bit easier to read due to its tabular nature, and can be trivially read off of most datasheets. Moreover, the lowering semantics are obvious. To summarize, registers are introduced by their offset marked with a ioregs!(FTM =
@0x0 SC
0..2 PS: uint
3..4 CLKS: enum { 0x0 = NO_CLOCK, 0x1 = SYSTEM_CLOCK, 0x2 = FIXED_FREQ, 0x3 = EXTERNAL }
5 CPWMS: bool
6 TOIE: bool
7 TOF: bool
@0x4 CNT
0..15 COUNT: uint
@0x8 MOD
0..15 MOD: uint
group Channel {
@0x0 CSC "channel status and control register"
0 DMA: bool "enable DMA"
2 ELSA: bool "another docstring"
3 ELSB: bool
4 MSA: bool
5 MSB: bool
6 CHIE: bool
7 CHF: bool
@0x4 CV
0..15 VAL: uint
}
@0xc CHANNELS: Channel[8]
@0x4c CNTIN
0..15 INIT: uint
@0x50 STATUS
0..7 CHF: bool[8]
) |
I do like the last version, although white space seem a bit vague... I'd introduce some additional delimiters, e.g.: ioregs!(FTM =
@(0x0) => SC: {
<0..2> PRESCALE: uint
<3..4> CLOCKS: enum {
0x0 = NO_CLOCK,
0x1 = SYSTEM_CLOCK,
0x2 = FIXED_FREQ,
0x3 = EXTERNAL,
}
<5> CPWMS: bool
<6> TOIE: bool
<7> TOF: bool
} // end of SC
) Making |
Another though, a side from defining an |
I do very much like the doc strings, I have to say! |
I can think a bit more straight after a nap so I got you a proposal on syntax. If it looks a bit like PTs, it's just because if only thing you have is a hammer... 😉 I really tried to use the same register from k20 but I couldn't find my way through freescale docs. I re-read the chapter a dozen times but I still can't figure where do you put those 8 regs in memory. So I took lpc's uart register which is quite fun (and has different compatibility issues so we have something to compare to). Another thing to note is safety. I plan to introduce better |
@farcaller this looks better to me. The only thing I'm not quite sure about is |
I just dropped it in there for completeness, e.g. if you read-modify-write, those bits can be forced 0 in mask. |
Sorry for not contributing much recently. IMHO, any macro that requires 'pad' is a non-starter. We have the power of syntax extensions, lets have a more clever solution that counting the correct number of pad invocations. I don't mind any of the proposed syntaxes that have explicit offsets for ranges and bit number for fields. @bgamari did you want to double check your proposed syntax is as easy to map from datasheet to Rust for LPC and STM32 as it was for Kinetis? At then end of the day we want a solution that makes it quick and simple to transfer from the datasheet text to Rust, to minimise errors and make it quicker to port to new devices (and if it is modular-ish with offsets, it makes copy paste easier for similar but different platforms). |
closes/cc #56 |
So are you against |
Both the pad and cursor (so for both register definition and register location). Datasheets give the addresses/offsets explicitly, we shouldn't make ourselves have to count how many registers are padding in a spare peripheral definition. At least the error checking for specifying offset/size exactly is easier to do, to error check padding I need to calculate the padding on the datasheet and also on the definition. Also, if I am debugging the assembly, when the offset is explicit, I can see it in the asm. Otherwise I need to keep counting. |
Good morning everyone! @bharrisau, I'll admit that I didn't look as carefully at the other two platforms although checking again I don't see any issues. My second representation is literally exactly what most datasheets I've read provide. I agree that explicit offsets is better than explicit padding. It's both easier to write and validate against the datasheet. That being said, I'm not entirely sure we need the padding at all if we take this route. |
Probably not worth worrying too much about at the moment - but Rust gives us the ability to do things like
Otherwise a macro_rules! could handle this for us. |
Not sure if the Drop trait would let you have something like this (removing the need for the
If that worked it would be good. Edit: The set() could probably be dropped also.
All compile time checked, and inlined into operations on two u32 values; the val and mask. |
@bharrisau I had considered something like that as well, unfortunately I seem to recall that |
Have to check - I think for temporaries it is called much sooner. http://smallcultfollowing.com/babysteps/blog/2014/01/09/rvalue-lifetimes-in-rust/ |
@bharrisau this was my attempt at checking this, https://gist.github.com/bgamari/4d56b64d64ae743b6939. The |
What if it is without the let? I'm thinking the explicit |
@bharrisau oh, you're right! as long as you it's a temporary it seems to be dropped at the end of the statement. |
Now that we have agreement on the In terms what I want in the
Also note: we can now have an ioreg lint, to make sure people aren't using a |
@bharrisau sounds like a plan. |
So yes, we can do the units (I'm mostly concerned about register unions though) with overlapping indexes, but overlapping indexes are also a source of errors so I'd prefer if it would be explicit.
Lets not have any optional syntax, there's really no reason for having two options here. |
@farcaller the reason for the optional syntax was to allow consistency between definitions with and without blocks and it was easy to do. @bharrisau this probably belongs on the (to-be-created) API pull request, but anyways here is my implementation of the read-modify-write interface. |
Let's move this to the mailing list for now. |
The macro syntax will need flags for write-to-clear registers. Something |
What do we still need to figure out to make this happen? |
Closed is favor of new pull request so we can start discussing API considerations. |
@farcaller I just squashed together the patches. Next I intend on adding support for @bharrisau's setter interface. After that I'll add write-to-clear support. |
Thanks for all this @bgamari. Don't feel like you need to get it all in one go. |
@bharrisau how does this look? |
Not sure why you are trying to do it that way. Why do you want to do the |
@bharrisau ahh, I hadn't noticed that property of your approach until now. That is clearly the right way to do things. You unfortunately loose the ability for the accessor type to support getters, but I suppose these can be moved into a separate type which. In hindsight, it probably makes more sense for getting and setting to be distinguished in the type system. |
@bharrisau I just updated the gist. What do you think now? |
Line 88 is redundant. I get why/where the On 15 July 2014 22:11, Ben Gamari [email protected] wrote:
|
Hopefully most of this inlines away normally, otherwise it might need On 16 July 2014 07:14, Ben Harris [email protected] wrote:
|
And you can probably dump the check on line 71. On 16 July 2014 07:15, Ben Harris [email protected] wrote:
|
Ignore the bit about , was too early in the morning and I wasn't thinking. |
This is the beginning of a syntax extension to generate register definitions with type-safe bitfields and enable opportunistic use of bitbanding.
A register set is defined in a domain-specific language parsed by the
ioregs!
macro. There are three primitives in this language,the containing group, and a type. Register types include group of registers and primitive bitfield types (
reg32
,reg16
,reg8
)name and a type (either implicitly
uint
orbool
, or an syntactically explicitenum
)Register and field types can both be arrays.
For example, consider this register set. This would be translated to the proposed DSL as follows,
which should produce something like,
Lowering semantics
Lowering the DSL representation to a Rust data structure would be performed as follows,
GROUP
produce a typepub struct GROUP { ... }
where the fields are generated as follows,
REG
in the group,T
, produce a fieldpub REG: T
T[N]
, produce afield
pub REG: [T, ..N]
T
orT[N]
, produce a typepub struct GROUP_REG {_value: VolatileCell<T>}
and,T[N]
, produce a fieldpub REG: [GROUP_REG, ..N]
instruct GROUP
pub REG: GROUP_REG
instruct GROUP
To generate the accessor functions, the following lowering would be performed,
For a register group
GROUP
,REG
in the group,FIELD
of the register,T[N]
, produce accessors