A Better Way to Implement Bit Fields
andrewkelley.me
andrewkelley.me
Also, this needs a (2017) tag.
How is "Avalid" any more meaningful though?
"The AValid signal is used to indicate if the session for an A-peripheral is valid. This signal is 1b when Vbus is above 2V"
They could use some better naming.
> By the way it's nice to know that the USB protocol has a bit to indicate "a valid oven". I wonder when that is used.
The bit fields he uses as an example related to USB protocol implementation.
You can also set the endianness (bit and byte order) : https://www.adacore.com/gems/gem-140-bridging-the-endianness... (I think it was added in a recent language revision).
Add to that the 'Component_Size attribute and the ability to specialize representation information easily : https://www.adacore.com/gems/gem-27 and https://www.adacore.com/gems/gem-28) and also the ability to recursively bound-check record structures (see https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/i... and https://dwheeler.com/lovelace/s17s4.htm for some background on 'valid and specific Ada safety extensions) you get a pretty elegant and powerful way to interact with low-level constructs.
Now you got me thinking about Ada again.
The whole interactive book deserves a look. You can then jump to the Spark book :-D https://learn.adacore.com/courses/intro-to-spark/index.html that sadly doesn't seem to talk about tasking but Spark supports part of it.
I'm actually looking forward the next few years, as AdaCore seems to be working on memory ownership-based guarantees a la rust (at least partially) and this might make Ada (or Spark in a first pass) a good candidate for truly fearless concurrency :-D.
[1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p070...
If a field greater than 8 bits is byte-aligned, it is represented in memory with the endianness of the host. If the field is not byte-aligned, it is represented in memory in big-endian.
So is a 12 bit fild is byte-aligned if it starts at the "first" bit of a byte (whatever that is)? Is there a way to manually specify the endianness of a field? There are certainly cases where a byte-aligned big-endian field is needed on a little-endian host.
I also don't like that keeping track of the fields' address happens in comments. It would be great if there were a language element that would specify the address of a field inside a packed struct, so the compiler could verify its correctness.
Embedded stuff typically means kernels and drivers. For that, the bitfields are in hardware registers. This is troublesome because the hardware might not act like normal RAM. Issues you will encounter:
1. The hardware demands a particular access size. For example, a nice big array of 4-bit values may need to be accessed only by 16-bit operations because it is on a 16-bit data bus that lacks byte enable lines. Another example is that different access sizes may go to different registers.
2. The hardware takes an abnormal action when accessed. Reading and writing might go to separate registers. Reading could fetch a byte from a FIFO, so the language/compiler is not free to do speculative or repeated reads. Writing could output to a FIFO. Reading or writing could clear bits, possibly in a different register, or initiate a coprocessor action.
3. The bus might allow reordering that can affect the device. For example, the bus might cancel operations that seem to be superseded by later operations (write after write, or read after read) but enforce ordering in other cases. The compiler must respect this in some way, possibly by suppressing optimization or by generating a compile error when the constraints appear to be violated.
You also get ugly layout issues like split fields, but that hits emulators and file formats too.
Furthermore IIRC an Erlang pattern can be either matching or creation, you can't "abstract" a pattern to do both, so if you need to both parse and generate your binary thing will need to be written twice (at least).
This may or may not be an issue, but at the end of the day it's not quite equivalent to C's bitfields. It's very convenient though.
IIRC in Erlang it's something along the lines of
<<V:3/signed, F1:1, F2:1, L:3, D:L/binary, I:16/signed-little>>That Erlang syntax reminds of the python 'struct' [0], except it's generating the unpacking logic at compile time, am I right? Yes that is indeed very cool - it doesn't even seem that hard to do I'd wonder why other languages don't have a similar facility!
Kinda, however there are a few superior items to the bit syntax:
* In Erlang, the bindings are in the expression itself (whether packing or unpacking) which makes the correspondance easier.
* Because the bindings are embedded and set left to right, it becomes possible to use one binding as parameter to the next pattern e.g. `L:3, D:L/binary` will first parse 3 bits as an unsigned integer L, then extract the next L bytes as a binary substring.
* Also Erlang's bit syntax can do sub-byte matching, I don't think python's struct can.
* And Erlang's bit syntax is much clearer and orthogonal (modulo knowing the — convenient — defaults) e.g. where extracting a little-endian 32-bit signed integer with struct is "<i" with Erlang it's :32/integer-signed-little (32 units, integer, signed, little-endian; the default unit size for integers is the bit). More verbose, but also completely explicit and more flexible, and very easy to change.
[1] https://rwmj.wordpress.com/2010/02/03/on-the-awesomeness-of-...
Actually this is the kind of thing lex/yacc/Bison, javacc etc. do ... except I think only for text ...
I'd say "packing" is ambiguous and could refer to either bit-aligned or byte-aligned data. But if your fields are less than 8 bits wide, I would assume "packing" means bit-packing.