src/cdecl/bitfields

    Dark Mode
Search:
Group by:

Procs

proc setBitsSlice[T: SomeInteger; V](b: var T; slice: Slice[int]; x: V)

Macros

macro bitfields(name, def: untyped)
Create a new distinct integer type with accessors for bitfields that set and get bits for each field. This is more stable than C-style bitfields (see below).
The basic syntax for a bitfield declarations is:
fieldname: uint8[4..5]
- fieldName is the name of the accessors and produces both
a getter (fieldName) and setter (fieldName=)
- the range 4..5 is the target bit indexes. The ranges are
inclusive meaning 6 ... 6 is 1 bit. Ranges are sorted so you can also use 5 .. 4 to match hardware documentation.
  • The type uint8 is the type that the bits are converted to/from.

Signed types like int8 are supported and do signed shifts to

properly extend the sign. For example:
speed: int8[7..4]

The accessors generated are very simple and what you would generally produce by hand. For example:

bitfields RegConfig(uint16):
    speed: int8[4..2]
  

Generates code similar too:
type
    RegChannel = distinct uint16
  
  proc speed*(reg: RegChannel): uint8 =
      result = uint8(bitsliced(uint16(reg), 4 .. 9))
  proc speed=*(reg: var RegChannel; x: uint8) =
      setBitsSlice(uint16(reg), 4 .. 9, x)
  

This is often preferable to C-style bitfields which Nim does support. C-style bitfields are compiler and architecture dependent and prone to breaking on field alignement, endiannes, and other issues. See https://lwn.net/Articles/478657/

Example:

bitfields RegConfig(uint8):
  ## define RegConfig integer with accessors for `bitfields`
  clockEnable: bool[7..7]
  daisyIn: bool[6..6]
  speed: int8[5..1]

## Now use it to make a new register field
var regConfig: RegConfig

regConfig.clockEnable= true
regConfig.speed= -10

echo "regConfig.speed ", regConfig.speed 
assert regConfig.clockEnable == true
assert regConfig.speed == -10
## the type of `RegConfig` is just a `distinct uint8`
import typetraits
assert distinctBase(typeof(regConfig)) is uint8