Author Topic: BitOffsets  (Read 8988 times)

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
BitOffsets
« on: December 04, 2014, 08:11:44 PM »
Hi,

I've just pushed a new feature called BitOffsets. This allows easy copying of certain bit-ranges, like often
done in drivers. So if your chip's reference guide says:   Counter Bit 14-10, you used to do (in Plain-Old-C)

Code: [Select]
int counter = ((value >> 10) & 0x1F);
Which is not too readable. Off course you could use a fancy macro like REG_BITS(value, 10, 0x1F),
but that's not really nice either.

Because C2 targets kernels, bootloaders and other low-level programs, accessing register values should
be easy. Enters BitOffsets:

Code: [Select]
int counter = value[14:10];
Which does the same as the example above. Additionally it can check possible overflows (like assigned a 8+ width
value to a char etc)

Currently BitOffsets can only be used in RHS (Right-hand side) expressions. I'm still debating whether
to also allow this on LHS expressions.

kyle

  • Newbie
  • *
  • Posts: 48
    • View Profile
Re: BitOffsets
« Reply #1 on: December 10, 2014, 05:32:02 PM »
I like that!

In C, I use bit fields for the same purpose, but that requires making a struct.

I end up with a lot of:

struct {
    uint32_t cntrl_field:6;
    uint32_t data_field:4;
    ...
} my_mapped_control;

Then you have to cast or create a union etc.  It is a pain.  I think having supported bit fields inline like you did is very nice!

Best,
Kyle

chqrlie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: BitOffsets
« Reply #2 on: August 30, 2015, 11:40:55 PM »
Your proposal for bitfield manipulation operators is very interesting, but I find the syntax confusing, because it is somewhat inconsistent with the C conventions.

In your example:

    int counter = value[14:10];

the width of the bitfield is not obvious.  As a matter of fact, people unfamiliar with the construct may expect the width to be 4 bits or perhaps 10 bits.  It is inconsistent with both the C indexing paradigm and the standard bitfield syntax where the number of bits appears after the colon.  I would favor this alternative for the same bitfield:

    int counter = value[10:5];  /* extract 5 bits at bit offset 10 from the integer value */

This syntax is more consistent, as you can see in this classic example:

   int red    = rgb[0:5];
   int green = rgb[5:6];
   int blue   = rgb[11:5];

This syntax is the same for storing values as well or even updating them:

    value[10:5] = 43;  /* should produce a diagnostic: 43 does not fit in 5 bits */
    value[10:5] += 1;  /* much more concise than the C alternative, and better code generated too! */

Both the offset and the width could be unsigned integer expressions with some limitations.  We probably do not want to integrate this construct generically into the type system and create pointers or references to bitfields, fixed or variable, but the above constructs can be implemented simply and do simplify the programmer's life.

Finally, I have written a lot of database code dealing with bitmaps and wished for a good syntax for arrays of 1, 2 or 4 bit values.  The same syntax could be used for this purpose on integer pointer types.  For non trivial bit widths, it is very cumbersome to write the code by hand and even more complicated to use the best underlying type to take advantage of target specific opcodes.  Definitely something you want the compiler to take care of.
« Last Edit: September 08, 2015, 05:41:31 PM by chqrlie »

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Re: BitOffsets
« Reply #3 on: September 08, 2015, 09:41:10 PM »
Any embedded programmer is reading a lot of hardware specifications. In those documents, register fields are often specified in the form of [18:16]. I tried to copy this exactly into C2.

I think the syntax just takes some getting used to. The width is (high - low + 1). When reading the hardware specs, developers are used to the same thing right? My preference would be to use the high:low instead of low:width proposal, also since both value are then offsets instead of an offset and a width. Does this make sense?

What I haven't fleshed out is that code often use macros to define field offsets and widths. Is the bitterest syntax this would look like for some field called counter

Code: [Select]
uint32 value = reg[COUNTER_HIGH: COUNTER_LOW];


Ideally this would be caught into a single thing. This would require different syntax options like specifying register sub-fields or something..

chqrlie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: BitOffsets
« Reply #4 on: September 08, 2015, 11:37:51 PM »
I see the rationale.  I guess it is logical to follow usage from the hardware community.  The ARM specs indeed use this convention, whereas the Intel docs use a mixture of reg[HIGH-LOW] and reg[HIGH .. LOW].

It bothers me that this convention is still inconsistent with the spirit of C where arrays always use offsets and sizes, not minimum and maximum indices.

We discussed case ranges in the form LOW .. HIGH, e.g.:
Code: [Select]
    switch (c) {
      case 'A'..'Z':  upper++; break;
      case 'a'..'z':   lower++; break;
    }
Do you intend to introduce a syntax for array slices similar to case ranges?  It would be very concise for initializing and copying, but the same issue arises: should we use offset:size or min..max (inclusive) or even start...stop (start included, stop excluded) ?  All 3 syntaxes, borrowed from other languages, could coexist but consistency is needed for similar but separate semantics.

The syntax for bit slices HIGH .. LOW would then be consistent as a variation of LOW .. HIGH.