Bit manipulation: 'Stretching a bitmask' - Page 1
Forum section: electronics / general

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 08:22:09 am
content: One of my function needs to write to a register, split up into blocks of two bits (The ModeR register of a GPIO block on an STM32F4 Processor, see attached screenshot!)Therefor I need to create a bit mask to mask the right 2 bit wide fields. However, the method is only given a bitmask where each bitfield is 1 bit wide.In other words:0010 needs to translate to:00001100or1100 needs to translate to:11110000Any ideas on how to do this?

author: Rerouter
author_rank: Super Contributor
timestamp: November 01, 2016, 08:33:06 am
content: As you only have 15 states, i would just say use a lookup table.Something likeChar input = (whatever)Char Output = 0If(input = 0001b) {Output = 00000011b}If(input = 0010b) {Output = 00001100b}And so on for all 15 combinations, you can skip the if equal to 0, if each time you initialise to 0, and it means if you try to feed if a value greater than 4 bits, it will return 0000,

author: Phoenix
author_rank: Frequent Contributor
timestamp: November 01, 2016, 08:52:10 am
content: Another lookup table method:const uint8_t two_bit_mask = {00000000,00000011,00001100,00001111,00110000 and so onFeed in the 4 bit long mask, get out the 8 bit long mask. Just have to avoid putting in an invalid number...

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 09:04:24 am
content: I though about this, but I would like this to work not only with a single bit selectedSo0101 should be00110011

author: obiwanjacobi
author_rank: Super Contributor
timestamp: November 01, 2016, 09:26:56 am
content: Pseudo codeCode:value = b0010newValue = 0srcIndex = 0trgIndex = 0loop{newBit = (value & (0x01 << srcIndex))if (newBit)//newValue |= (newBit << trgIndex) | (newBit << trgIndex+1) => optimized to =>newValue |= 0x02 << trgIndexsrcIndex++trgIndex += 2} endloopreturn newValueDisclaimer, disclaimer...

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 09:29:57 am
content: Anyway of doing it without a loop?

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 09:32:29 am
content: Or a better name for this problem? Something I could google for?

author: obiwanjacobi
author_rank: Super Contributor
timestamp: November 01, 2016, 09:36:31 am
content: No loopsCode:value = b0010newValue = 0newValue |= (value & 0x1) ? b00000011 : 0newValue |= (value & 0x2) ? b00001100 : 0newValue |= (value & 0x4) ? b00110000 : 0newValue |= (value & 0x8) ? b11000000 : 0return newValue

author: AndyC_772
author_rank: Super Contributor
timestamp: November 01, 2016, 09:54:37 am
content: If the input is just 4 bits, I'd still just use a look-up table. It's only 16 bytes long, which is 8 THUMB instructions' worth.Code:uint8_t mask_lookup = {0b00000000, 0b00000011, 0b00001111.... }bit_mask = mask_lookup [index & 0x0f]

author: dannyf
author_rank: Super Contributor
timestamp: November 01, 2016, 10:00:48 am
content: QuoteA look-up table would be fairly simple, for a few bits.Otherwise, coding + a look-up table would do it. For example, use a 4-bit look-up table to process 4 bit at a time and then coding.Code:const uint8_t lut4[] = {0x00, 0x03, 0x0c, 0x0f, //0b0000->0b00000000, 0b0001->0b00000011, 0b0010->0b00001100, 0b0011->0b00001111...};//convert 8-bits to 16 bitsuint16_t lutb2w(uint8_t dat) {return (lut4[dat >> 4] << 8) | lut4[dat & 0x0f];}//convert 16bits to 32 bitsuint32_t lutw2dw(uint16_t dat) {return (lutb2w(dat >> 8) << 16) | lutb2w(dat & 0xffff);}....you can speed it up with pointers, unions, or struct, etc.

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 10:20:32 am
content: And for possible input width of 8 bits?Well I guess 256 values in the lookup table are not bad..Still I would have liked a logical set of operations that could do this

author: John Coloccia
author_rank: Super Contributor
timestamp: November 01, 2016, 11:21:23 am
content: Quote from: BurnedResistor on November 01, 2016, 08:22:09 amCold you explain exactly what you're doing? If you need it to look like 00001100, why do you have it kicking around as 0010 in the first place? Perhaps your core problem is that you're storing the information incorrectly in the first place. For example, if you're using 0010 to store the idea of "Turn on GPIO2", and then passing the bitmask into a function to set all your GPIO at once, it would be better to do something like:#define GPIO1 b00000011#define GPIO2 b00001100etc....and thegpio = 0 | GPIO1 | GPIO4;Or even better, looking at the documentation, something like#define GPIO1 b00000011#define INPUT b00000000#define OUTPUT b01010101#define ALTERNATE b10101010#define ANALOG b11111111and thengpio = 0 | (GPIO1&ANALOG) | (GPIO2&OUTPUT) etc etcAnyhow, just a thought.

author: Ian.M
author_rank: Super Contributor
timestamp: November 01, 2016, 12:05:20 pm
content: See if any of the ideas for interleaving bits work for you:http://graphics.stanford.edu/~seander/bithacks.html#InterleaveTableObvious

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 12:16:23 pm
content: I am trying to write a set of functions, that can manipulate the configuration of different gpio ports using the same nomenclature. For example the function:GPIO_setPins(port, pins)Could be used like this to modifiy multiple pins:GPIO_setPins(GPIOD,PIN12|PIN13|PIN14);where PIN0-15 is a predefined bit mask for that pin.That also comes with the added advantage of being able to predefine sets of GPIO given they are on the same port:GPIO_setPINS(GPIOD,ALL_PINS);This works great with setting, clearing, writing pins etc. because they use 1 bit per pin.However for speed, pullups etc, the function:GPIO_setModes(Port, Pins, Mode);Typed like this:GPIO_setModes(GPIOD,PIN0|PIN1,GPIO_MODE_OUTPUT);Function would have to create a mask from the mask given.I realize I could probably just have a second set of definitions for the pins with the correct mask, which would probably yield the fastest code, and smallest size, but that seems like it would be very prone to errors, because there is no way to check if 1100 is a mask for pins 2 and 3, or only pin 1.Any ideas?

author: newbrain
author_rank: Super Contributor
timestamp: November 01, 2016, 12:17:58 pm
content: That would be a single operation in INTERCAL, using the MINGLE operator, (¢ : cent sign):Code:PLEASE DO :0 <- .0¢.0the result is in :0 (a 32 bit variable) the original mask is in .0 (a 16 bit variable)First time that language comes handy!Edit: On a more serious note, I would go for a mixed solution: a 4bit->8bit LUT, breaking up and shifting accordingly both inputs and outputs.

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 01:56:58 pm
content: I have been rethinking it, and in the interest of program size (lookup table) and speed (bit twitteling) I will probably just have sepereate definitions for the pin masks.

author: John Coloccia
author_rank: Super Contributor
timestamp: November 01, 2016, 02:08:56 pm
content: Is size and performance a particular problem? If you're wanting to do something generic, then the way to do it is a mapping og logical ports to physiscal ones, and functions to set the proper registrrs depending on the specific hardware. You can use compiler directives to choose, or structs with function pointers, or C++, or any one of a dozen ways, but the mapping is key. Since it's just a small setup operation, clarity and flexibility should trump any performance issues, assuming you really need it to be flexible.If not, just set them simply as you can, but keep it encapsulated somewhere so it's simple to modify later if you really need the flexibility. This is one of those cases where you don't want to invent problems to solve until you need to because you'll just be guessing at what some other piece of hardwars needs, and to truly make it generic is a project all on it's own.

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 03:56:58 pm
content: Quote from: John Coloccia on November 01, 2016, 02:08:56 pmThis being one of the first larger scale projects I am working on, I think you are right. I was concerned with creating these utility functions to be as fast as possible while also being as user friendly as possible. While not complete opposites, one will have to give to get the other. Right now I will make utility functions that are easy to use and flexible. If I need a faster operation I can always implement a second function!Could you elaborate on what you mean by your explaination on how you would implement a generic one? My current appraoch is the following for the single pin functions:Code:void GPIO_setMode(GPIO_TypeDef *_P, uint32_t _N, GPIO_MODE _M ){_P->MODER = mask_replace((uint32_t)_P->MODER,(0x3)<<(_N*2),(uint32_t)_M);}void GPIO_setType(GPIO_TypeDef *_P, uint32_t _N, GPIO_TYPE _T ){periph_bit(_P->OTYPER,_N) = (uint32_t)_T;}void GPIO_setSpeed(GPIO_TypeDef *_P, uint32_t _N, GPIO_SPEED _T){_P->OSPEEDR = mask_replace((uint32_t)_P->OSPEEDR,(0x3)<<(_N*2),(uint32_t)_T);}void GPIO_setPUPDR(GPIO_TypeDef *_P, uint32_t _N, GPIO_PUPDR _V){_P->PUPDR =((uint32_t)_P->PUPDR,(0x3)<<(_N*2),(uint32_t) _V);}void GPIO_writePin(GPIO_TypeDef *_P, uint32_t _N, uint32_t _S){periph_bit(_P->ODR,_N) = _S;}void GPIO_setPin(GPIO_TypeDef *_P, uint32_t _N){periph_bit(_P->ODR,_N) = 1;}void GPIO_clearPin(GPIO_TypeDef *_P, uint32_t _N){periph_bit(_P->ODR,_N) = 0;}uint32_t GPIO_readPin(GPIO_TypeDef *_P, uint32_t _N){return periph_bit(_P->IDR,_N);}void GPIO_configPin(GPIO_TypeDef *_P, uint32_t _N, GPIO_MODE _M, GPIO_TYPE _T, GPIO_SPEED _S, GPIO_PUPDR _V){GPIO_setMode(_P,_N,_M);GPIO_setType(_P,_N,_T);GPIO_setSpeed(_P,_N,_S);GPIO_setPUPDR(_P,_N,_V);}where:Code:periph_bit(_R,_N)is a macro to return the bit banding register for the bit _N (0-31) in the peripheral register _RCode:mask_replace(_O,_M,_V)is a macro to return the original value _O, where the bits indicated by the bitmask _M have been replaced by the values in _V.I now was aiming to implement similar functions, where instead of specifying the number of a single pin (0-15) one could specify a mask for the pins one would like to address, making it very quick to say, configure a simple 8bit bus all at once, and then write two it with two single function calls.I am not the most experienced, but this seemed like a fairly flexible, easy to use, efficient approach to implement a wrapper for the STM GPIO.Like mentioned before, the writing clearing reading setting of bits is trivial due to the BSRS, ODR, and IDR simply having one bit mapped to a pin. It was with the implementation of say Mode, Speed, and pull-resistors that I struggeled with, as a single pin is mapped to 2 bits.Granted extreme speed for these functions is not neccesary as most likely they will only be used once during initialization, but I was hoping for a more elegant solution. I need to map 16 bits so A lookup table seems overkill even though it would be the fastest. The solution mentioned by obiwanjacobi is probably best, but would not seem very elegant for the 16 bits required. The loop seems excessively slow but might also be the best option.I did a bit of testing, to see if there is any clear, easy to identify mathematical relation ship, but I was not able to come up with a easy solution.My test:0 (0) -> 0 (0)1 (1) -> 3 (11)2 (10) -> 12 (1100)3 (11) -> 15 (1111)4 (100) -> 48 (110000)5 (101) -> 51 (110011)the resulting graph is attached, it makes a step like looking pattern.. not the easiest to model mathematically....hmmm....

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 04:03:40 pm
content: I did some more number fiddeling:0 (0) -> 0 (0)1 (1) -> 3 (11) +32 (10) -> 12 (1100) +93 (11) -> 15 (1111) +34 (100) -> 48 (110000) +335 (101) -> 51 (110011) +36 (110) -> 60 (111100) +97 (111) -> 63 +38 (1000) -> 192 +129There is some pattern to it,It increases by 3, then a multiple of 3Which makes sense because those are the values 0011 , 1100 , 110000 etc representAny way to model this mathematically?

author: John Coloccia
author_rank: Super Contributor
timestamp: November 01, 2016, 04:16:08 pm
content: I think the absolute simplest relationship, using just logical operations, is the one I suggested before with simple bit patterns ORd and ANDed with each other. If I have a chance, I'll try to write something up along the lines of what I suggested re: mapping logical ports to physical ones. The basic idea is you have some machine specific files, and you select what you want at compile time, possibly by passing in a command line argument or something like that. The machine specific files map (via arrays, or however is appropriate) the internal logical name of the port that you use everywhere else to a machine specific representation that's appropriate for your particular processor. In this case, the bit patterns I mentioned. On another processor, it might be a combination of values for several different registers, for example.So you select at compile time which implementation you're going to use, depending on processor, but the rest of your program doesn't have to change. You need to recompile for different machines anyway. Then in the specific implementation for your chip, you don't have to worry about writing generic, complex code that works everywhere. You can write very simple, straightforward code that simply targets your specific machine, or family of machines. There will probably be a little duplication, but that's OK!! The guidelines for avoiding duplicated code and things like that are good inasmuch as they ultimately make your life easier, and the code more robust. When it's a lot of trouble to get there, and there's no practical benefit, forget the rules and write simply instead.

author: John Coloccia
author_rank: Super Contributor
timestamp: November 01, 2016, 04:17:37 pm
content: Quote from: BurnedResistor on November 01, 2016, 04:03:40 pmI think you start running into trouble when you have multiple ports set with carries and things like that.

author: helius
author_rank: Super Contributor
timestamp: November 01, 2016, 04:26:23 pm
content: \$ f(n) = \sum_{i \in n} n_i (2 ^ {2 i+1} + 2 ^ {2 i} ) \$ where n is considered as a sequence of k bits.That can be simplified to \$ \sum_{i \in n} n_i \cdot 3(2^{2i}) \$

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 04:37:03 pm
content: WOW!umm. Let me look at that for a few minutes!

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 05:06:48 pm
content: Just to make sure I am understanding thisThe sigma effectively iterates through every bit.For each bit, the value of the two bits that would be set are calculated as 2^2i and 2^2i+1. Then they are multiplied by the bit. In other words, ignoring all the 0s. Very clever!Effectively this is the mathematical notation of the method obiwanjacobi!That is really cool!

author: BurnedResistor
author_rank: Regular Contributor
timestamp: November 01, 2016, 07:49:05 pm
content: Quote from: John Coloccia on November 01, 2016, 04:16:08 pmIf I used the following method proposed by obiwanjacobi with a constant original bitmask, would gcc be able to optimize this out?Code:newValue |= (value & 0x1) ? b00000011 : 0newValue |= (value & 0x2) ? b00001100 : 0newValue |= (value & 0x4) ? b00110000 : 0newValue |= (value & 0x8) ? b11000000 : 0If so under what conditions?If it would be able to optimize it out i think it would be the optimal solution (BADANG DISH).If it is called with a constant, gcc would optimize this constant to the actual require bitmask. If it is called with a dynamic mask, gcc would leave it. The code would function both ways, and the benefit of the lower overhead for the constant would still be there!As an extension, how could I determine if this would be optimized?

author: Someone
author_rank: Super Contributor
timestamp: November 01, 2016, 10:54:05 pm
content: It really depends on your instruction set if you want to optimise to this level, for instance with a short pipeline DSP (or AVR) processor you can use a shift through carry.Code:for length of sourcesource = source << 1result = result << carry_flagresult = result << 1loopresult = result | (result >> 1)And unroll the loop since its length is known at compile time. If branching is cheap or you can selectively apply operands or immediates, then it might be cheaper do something more like:Code:result = (result << 2) + (carry_flag) ? 3 : 0It all depends on the underlying architecture of the chip.

author: dannyf
author_rank: Super Contributor
timestamp: November 01, 2016, 11:13:27 pm
content: here is the base line:8-bit types -> 16-bit types, <9k ticks, for all 256 conversions;16-bit types -> 32-bit types, 7 million ticks, for all 64K conversions.they should be fairly easy to beat.

author: hamster_nz
author_rank: Super Contributor
timestamp: November 02, 2016, 12:48:11 am
content: I would keep is simple.Code:u8_t doubleup_bits(u8_t i) {u8_t o = 0;if(i&1) o += 3<<0;if(i&2) o += 3<<2;if(i&4) o += 3<<4;if(i&8) o += 3<<6;return o;}Or use a lookup 16 byte lookup table (which would be far more efficient:Code:static const u8_t lookup_table = {0x00, 0x03, 0x0C, 0x0F,0x30, 0x33, 0x3C, 0x3F,0xC0, 0xC3, 0xCC, 0xCF,0xF0, 0xF3, 0xFC, 0xFF},...o = 0;if(i < 16)o = lookup_table;...But that is just me... simple....

author: spongman
author_rank: Newbie
timestamp: November 02, 2016, 01:21:22 am
content: don't ask me how, butCode:uint8_t double_bits(uint8_t i) { return ((i * 0x01010101 & 0x08040201) * 0x0204081 >> 21) * 3; }does the trick.

author: westfw
author_rank: Super Contributor
timestamp: November 02, 2016, 01:32:34 am
content: Quote[size=126%]?[size=70.7%]i[size=70.7%]?[size=70.7%]nn[size=70.7%]i?3(2[size=70.7%]2[size=70.7%]i)That's very pretty, but it's a restatement of the problem rather than a solution. (1 bit-doubled is 3)Ian's post pans out, I think:QuoteHere, I've tried to prune the "magic number" algorithm down to an 8bit->16bit version:Code:unsigned int stretch(int x){x = (x | (x << 4)) & 0x0F0F;x = (x | (x << 2)) & 0x3333;x = (x | (x << 1)) & 0x5555;return x | (x<<1);}That works out to about 16 instructions (~48 bytes) on a CM3, with no looping or jumps. That seems pretty good for 8bits; a loop would use half of that in jump instructions, and the "newValue |= (value & 0x1) ? 0b00000011 : 0" version is longer even for 4bits.(the ?: version ends up being about 114 bytes. A loop-based version is actually significantly shorter (~26 bytes), but of course it loops...)QuoteLook at the assembly code produced. I tried some examples with gcc, and it did NOT succeed in optimizing the constant case for the "?:" version until I explicitly declared the function as "static inline"; OTOH, the magic number version was optimized away even with no inlining hints at all. Note that you'd have to include the function definition in a .h file to get constant-based optimization, and it's a bit long to get inlined for the non-constant cases (IMO.)Whole "test program":Code:#include <stdio.h>// Magic number versionunsigned int stretch(int x){x = (x | (x << 4)) & 0x0F0F;x = (x | (x << 2)) & 0x3333;x = (x | (x << 1)) & 0x5555;return x | (x<<1);}// ?: versionunsigned int stretch1(int value){int newValue = 0;newValue |= (value & 0x1) ? 0b00000011 : 0;newValue |= (value & 0x2) ? 0b00001100 : 0;newValue |= (value & 0x4) ? 0b00110000 : 0;newValue |= (value & 0x8) ? 0b11000000 : 0;#if 1 // 4 bits or 8bitsnewValue |= (value & 0x10) ? 0b1100000000 : 0;newValue |= (value & 0x20) ? 0b110000000000 : 0;newValue |= (value & 0x40) ? 0b11000000000000 : 0;newValue |= (value & 0x80) ? 0b1100000000000000 : 0;#endifreturn newValue;}// Loop based versionunsigned int stretch2(int value){unsigned int newValue = 0;int i;for (i=0;i < 8;i++) {newValue >>= 2;if (value & 1) { // One bit outnewValue |= 0xC000; // two bits in}value >>= 1;}return newValue;}volatile int*p = 0x20000000;int main() {int c;#ifdef __ARM__c = *p;*p = stretch(0x59);*p = stretch1(0xA);*p = stretch2(0x61);#endiffor (c=0; c <=255; c++) {volatile int s, s1, s2;s = stretch(c);s1 = stretch1(c);s2 = stretch2(c);if (s != s1 ||s != s2) {printf("\nSomething wrong %x: %x %x %x", c, s, s1, s2);}}}

author: hamster_nz
author_rank: Super Contributor
timestamp: November 02, 2016, 01:35:13 am
content: Quote from: spongman on November 02, 2016, 01:21:22 amOh, that is awesome! - use the multiply to expand the bits out, then mask them off, then push them back together again.However I like it best in VHDL:Code:for i in 0 to in_bits'highloopout_bits(2*i) <= in_bits(i);out_bits(2*i+1) <= in_bits(i);end loop;Also runs a lot quicker - less than one clock cycle

author: westfw
author_rank: Super Contributor
timestamp: November 02, 2016, 01:50:51 am
content: QuoteDidn't work for me (2--> 0x60c) (and others)I looked at some of those magic bit-reversal algorithms that use multiply/modulo, but they looked like they'd get messy fast above 4bits. (the bit reversal algorithms actually derive 2 bits from each copy, so they only make 5 copies to do 8bits, and they STILL need 64bits...)

author: John Coloccia
author_rank: Super Contributor
timestamp: November 02, 2016, 07:06:23 am
content: Where is the drive to optimize this code coming from? It's basic setup code and should be written as simply and clearly as possible. The standard way of doing stuff like this is with flags that are ORd together, like I showed.

author: Kalvin
author_rank: Super Contributor
timestamp: November 02, 2016, 08:25:53 am
content: Looks to me that a lookup-table with 16 entries containing the expanded 8-bit value is a simple to understand and possibly very efficient as it doesn't require any conditional jumps. You can expand it to 8-bit input value easily when you process the input in two 4-bit values:Code:uint16_t expand_bitmask(uint8_t bitmask){const uint8_t lookup  = {/* 0 */ b0000_0000,/* 1 */ b0000_0011,/* 2 */ b0000_1100,/* 3 */ b0000_1111,/* 4 */ b0011_0000,.../* 15 */ b1111_1111 };uint16_t expanded_bitmask = (lookup[(bitmask >> 4) & 0x0f] << 8) | (lookup[bitmask & 0x0f]);return expanded_bitmask;}

author: westfw
author_rank: Super Contributor
timestamp: November 02, 2016, 09:13:00 am
content: The 4-bit "magic number" version compiles to 20 byte, total:Code:// Magic number versionunsigned int stretch4(int x){x = (x | (x << 2)) & 0x33;x = (x | (x << 1)) & 0x55;return x | (x<<1);}

author: rob42
author_rank: Newbie
timestamp: November 02, 2016, 10:02:13 am
content: Code:// set group of bits#define _bs(bits,n,m) ((u32)(bits) << ((n) << ((m)-1)))// clear group of bits#define _nbs(bits,n,m) ((u32)~(_bs((bits),(n),(m))))// clear/set 1-bit groups#define _rm11(r,b,n) (r) = ((r) & _nbs(1,n,1)) | _bs(b,n,1)#define _rm12(r, b, n1,n2) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1))) | (_bs(b,n1,1) | _bs(b,n2,1))#define _rm13(r, b, n1,n2,n3) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1))#define _rm14(r, b, n1,n2,n3,n4) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1))#define _rm15(r, b, n1,n2,n3,n4,n5) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1) & _nbs(1,n5,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1) | _bs(b,n5,1))#define _rm16(r, b, n1,n2,n3,n4,n5,n6) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1) & _nbs(1,n5,1) & _nbs(1,n6,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1) | _bs(b,n5,1) | _bs(b,n6,1))// clear/set 2-bit groups#define _rm21(r,b,n) (r) = ((r) & _nbs(3,n,2)) | _bs(b,n,2)#define _rm22(r, b, n1,n2) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2))) | (_bs(b,n1,2) | _bs(b,n2,2))#define _rm23(r, b, n1,n2,n3) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2))#define _rm24(r, b, n1,n2,n3,n4) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2))#define _rm25(r, b, n1,n2,n3,n4,n5) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2) & _nbs(3,n5,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2) | _bs(b,n5,2))#define _rm26(r, b, n1,n2,n3,n4,n5,n6) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2) & _nbs(3,n5,2) & _nbs(3,n6,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2) | _bs(b,n5,2) | _bs(b,n6,2))// configure mode of 1..6 pinsinline void gpio_mode1(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1){ _rm21(GPIOx->MODER, mode, pin1); }inline void gpio_mode2(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->MODER, mode, pin1,pin2); }inline void gpio_mode3(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->MODER, mode, pin1,pin2,pin3); }inline void gpio_mode4(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->MODER, mode, pin1,pin2,pin3,pin4); }inline void gpio_mode5(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->MODER, mode, pin1,pin2,pin3,pin4,pin5); }inline void gpio_mode6(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->MODER, mode, pin1,pin2,pin3,pin4,pin5,pin6); }// configure output type of 1..6 pinsinline void gpio_otype1(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1){ _rm11(GPIOx->OTYPER, mode, pin1); }inline void gpio_otype2(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2){ _rm12(GPIOx->OTYPER, mode, pin1,pin2); }inline void gpio_otype3(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm13(GPIOx->OTYPER, mode, pin1,pin2,pin3); }inline void gpio_otype4(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm14(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4); }inline void gpio_otype5(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm15(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4,pin5); }inline void gpio_otype6(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm16(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4,pin5,pin6); }// configure speed of 1..6 pinsinline void gpio_ospeed1(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1){ _rm21(GPIOx->OSPEEDR, mode, pin1); }inline void gpio_ospeed2(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->OSPEEDR, mode, pin1,pin2); }inline void gpio_ospeed3(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->OSPEEDR, mode, pin1,pin2,pin3); }inline void gpio_ospeed4(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4); }inline void gpio_ospeed5(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4,pin5); }inline void gpio_ospeed6(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4,pin5,pin6); }// configure pull mode of 1..6 pinsinline void gpio_pupd1(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1){ _rm21(GPIOx->PUPDR, mode, pin1); }inline void gpio_pupd2(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->PUPDR, mode, pin1,pin2); }inline void gpio_pupd3(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->PUPDR, mode, pin1,pin2,pin3); }inline void gpio_pupd4(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4); }inline void gpio_pupd5(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4,pin5); }inline void gpio_pupd6(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4,pin5,pin6); }

author: @rt
author_rank: Super Contributor
timestamp: November 02, 2016, 01:08:42 pm
content: I can only gather I haven’t understood the problem properly.Code:byte b0 = b0000; // sourcebyte b1 = b00000000; // targetb1 = b0 * b0;b1 += b1 << 1;EDIT,, Ah I see, any of the first four bits could be set.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: November 02, 2016, 02:26:56 pm
content: Quote from: John Coloccia on November 02, 2016, 07:06:23 am+1"Premature optimization is the root of all evil."

author: spongman
author_rank: Newbie
timestamp: November 02, 2016, 09:53:47 pm
content: Quote from: obiwanjacobi on November 02, 2016, 02:26:56 pm"about 97% of the time."

author: spongman
author_rank: Newbie
timestamp: November 02, 2016, 10:01:47 pm
content: Quote from: westfw on November 02, 2016, 01:50:51 amthe uint8_t return type implies an "& 0xff" mask. if you just copied the expression and missed the mask then you'll see extra noise in the upper bytes.2 --> (0x60c & 0xff) is correct.

author: spongman
author_rank: Newbie
timestamp: November 02, 2016, 10:13:40 pm
content: Quote from: hamster_nz on November 02, 2016, 01:35:13 amfor more awesome: the ARM assembly that 'gcc -O3' generates:Code:double_bits:@ args = 0, pretend = 0, frame = 0@ frame_needed = 0, uses_anonymous_args = 0@ link register save eliminated.add r0, r0, r0, asl #8ldr r3, .L2add r0, r0, r0, asl #16and r3, r3, r0add r3, r3, r3, asl #7add r3, r3, r3, asl #14mov r0, r3, asr #21add r0, r0, r0, asl #1uxth r0, r0bx lr.L2:.word 0x8040201

author: magetoo
author_rank: Frequent Contributor
timestamp: November 02, 2016, 10:23:44 pm
content: Quote from: obiwanjacobi on November 02, 2016, 02:26:56 pm<<1Unless you are in a tight inner loop, you have no business messing with magic constants and that sort of thing. You should be able to glance at the code a year from now and instantly see what it does.If you really need a function or macro, obiwanjacobi's "no loops" suggestion works and what it does is obvious just from its structure.

author: dannyf
author_rank: Super Contributor
timestamp: November 03, 2016, 11:00:02 pm
content: Quotepros write robust and well understood code;newbies write fancy code.

author: dgtl
author_rank: Regular Contributor
timestamp: November 03, 2016, 11:47:20 pm
content: I've had the same question myself and my solution is following...1) You should not compute values in runtime that can be pre-computed compile-time2) As the gpio pin definitions in my projects have been constants for now, the register masks and values can be pre-computed3) Let the compiler do the bit manipulation work, the interface shall be left clean. As long as everything is optimized out, the actual function can be just a stupid block of copypaste. (See linux kernel source for examples of such code, ie ilog2).So I wrote my gpio accesses as macros and let the compiler optimize it to actual register read-modify-writes without any branches or shifting. The following code i'm using on F2-s (part of my gpio.h file). Of course, it would be terribly inefficient if arguments weren't constant or the optimization otherwise failed.Code:////////////////////////////////////////////////////////////////////////////// double bits: abcd -> aabbccdd#define GPIO_BITMASK2(b) (\(((b) & (1<<0)) ? (3<<0):0 ) |\(((b) & (1<<1)) ? (3<<2):0 ) |\(((b) & (1<<2)) ? (3<<4):0 ) |\(((b) & (1<<3)) ? (3<<6):0 ) |\(((b) & (1<<4)) ? (3<<8):0 ) |\(((b) & (1<<5)) ? (3<<10):0 ) |\(((b) & (1<<6)) ? (3<<12):0 ) |\(((b) & (1<<7)) ? (3<<14):0 ) |\(((b) & (1<<8)) ? (3<<16):0 ) |\(((b) & (1<<9)) ? (3<<18):0 ) |\(((b) & (1<<10)) ? (3<<20):0 ) |\(((b) & (1<<11)) ? (3<<22):0 ) |\(((b) & (1<<12)) ? (3<<24):0 ) |\(((b) & (1<<13)) ? (3<<26):0 ) |\(((b) & (1<<14)) ? (3<<28):0 ) |\(((b) & (1<<15)) ? (3<<30):0 )\)// quadruple low bits, abcd ->aaaabbbbccccdddd#define GPIO_BITMASK4L(b) (\(((b) & (1<<0)) ? (15<<0):0 ) |\(((b) & (1<<1)) ? (15<<4):0 ) |\(((b) & (1<<2)) ? (15<<8):0 ) |\(((b) & (1<<3)) ? (15<<12):0 ) |\(((b) & (1<<4)) ? (15<<16):0 ) |\(((b) & (1<<5)) ? (15<<20):0 ) |\(((b) & (1<<6)) ? (15<<24):0 ) |\(((b) & (1<<7)) ? (15<<28):0 )\)// quadruple high bits, abcd -> aaaabbbbccccdddd#define GPIO_BITMASK4H(b) (\(((b) & (1<<8)) ? (15<<0):0 ) |\(((b) & (1<<9)) ? (15<<4):0 ) |\(((b) & (1<<10)) ? (15<<8):0 ) |\(((b) & (1<<11)) ? (15<<12):0 ) |\(((b) & (1<<12)) ? (15<<16):0 ) |\(((b) & (1<<13)) ? (15<<20):0 ) |\(((b) & (1<<14)) ? (15<<24):0 ) |\(((b) & (1<<15)) ? (15<<28):0 )\)// repeat 4bit value 8 times to full int length#define GPIO_REPEAT4(b) ((b) * 0x11111111U)// repeat 2bit value 16 times to full int length#define GPIO_REPEAT2(b) ((b) * 0x55555555U)// modify certain bits in register#define GPIO_MODIFY_REG(reg, clr, set) (reg)=((((reg) & (~(clr))) | ((set)&(clr))))////////////////////////////////////////////////////////////////////////////// set gpio pins in port to peripheral mode#define GPIO_PERIPH(port, pinmask, periph) do {\GPIO_MODIFY_REG((port)->MODER, GPIO_BITMASK2(pinmask), GPIO_REPEAT2(GPIO_MODER_PERIPH));\if ((pinmask) & 0x00FF) GPIO_MODIFY_REG(port->AFR, GPIO_BITMASK4L(pinmask), GPIO_REPEAT4(periph));\if ((pinmask) & 0xFF00) GPIO_MODIFY_REG(port->AFR, GPIO_BITMASK4H(pinmask), GPIO_REPEAT4(periph));\} while(0)

author: Kalvin
author_rank: Super Contributor
timestamp: November 04, 2016, 09:15:57 am
content: If your compiler cannot optimize at the compilation time, but the mask is constant, you can precompute and cache the mask at the system boot time as a workaround:Code:#include <stdio.h>#include <stdlib.h>#include <stdint.h>uint16_t gpio_stretch_bitmask(uint8_t bits){uint16_t temp = 0;uint16_t mask = 0x03;while (bits){temp |= ((bits & 1) ? mask : 0);mask <<= 2;bits >>= 1;}return temp;}static const uint8_t GPIO_MASK = 0x55;static uint16_t GPIO_WIDE_MASK = 0; // Will be initialized in the gpio_init()static void gpio_init(){GPIO_WIDE_MASK = gpio_stretch_bitmask(GPIO_MASK);}int main(int argc, char** argv){gpio_init();printf("Mask = 0x%x, Wide Mask= 0x%x\n", GPIO_MASK, GPIO_WIDE_MASK);return (EXIT_SUCCESS);}Edit: Oops! Fixed an error.