I've been doing a lot of hardware IO work lately, which involves lots of talking to hardware devices, where there are byte-wide registers that store little bitfields, sometimes of individual and unrelated bits packed together. To make this easier I tend to write myself lots of pairs of functions to pack/unpack the fields in one of these bytes; for instance:
use constant { MASK_RX_RD => 1<<6, MASK_TX_DS => 1<<5, MASK_MAX_RT => 1<<4, EN_CRC => 1<<3, CRCO => 1<<2, PWR_UP => 1<<1, PRIM_RX => 1<<0, }; sub unpack_CONFIG { my ( $config ) = @_; return MASK_RX_RD => !!( $config & MASK_RX_RD ), MASK_TX_DS => !!( $config & MASK_TX_DS ), MASK_MAX_RT => !!( $config & MASK_MAX_RT ), EN_CRC => !!( $config & EN_CRC ), CRCO => $CRCOs[!!( $config & CRCO )], PWR_UP => !!( $config & PWR_UP ), PRIM_RX => !!( $config & PRIM_RX ); } sub pack_CONFIG { my %config = @_; return ( $config{MASK_RX_RD} ? MASK_RX_RD : 0 ) | ( $config{MASK_TX_DS} ? MASK_TX_DS : 0 ) | ( $config{MASK_MAX_RT} ? MASK_MAX_RT : 0 ) | ( $config{EN_CRC} ? EN_CRC : 0 ) | ( ( _idx_of $config{CRCO}, @CRCOs ) // croak "Unsupported 'CRCO'" ) * CRCO | ( $config{PWR_UP} ? PWR_UP : 0 ) | ( $config{PRIM_RX} ? PRIM_RX : 0 ) ); }
This convenient pair of functions bidirectionally converts bytes into key/value lists. As well as containing 6 simple boolean values, there's also an enumerated field, represented by the values in the array @CRCOs. These functions convert those too.
I'm getting tired of writing these pairs of functions. Hey, this is Perl right? :) I should get Perl to write them for me.
TL;DR - I propose the followingI'd like instead to write something like:
use bitfield; bitfield CONFIG => MASK_RX_DS => boolfield(6), MASK_TX_DS => boolfield(5), MASK_MAX_RT => boolfield(4), EN_CRC => boolfield(3), CRCO => enumfield(2, qw( values here )), PWR_UP => boolfield(1), PRIM_RX => boolfield(0);
The operation here is that 'bitfield' is automatically exporting a function called bitfield, along with the various *field() functions that create field definitions. boolfield() declares a single true/false boolean bit position, enumfield() declares a range of bits that give an enumeration. I guess also would be required intfield() to use a range of bits as an integer, and finally most likely customfield() taking a pair of conversion CODE refs or somesuch.
What does anyone think to that?
Sounds sane!
ReplyDeleteI had to deal with bitlogic for doing IPv4 and IPv6 address in network lookups and had a hard time finding a good solution.
See my Net::Works fork on github which I hadn't time to finish so far.