We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I would like to to use the bit addressable memory range (bdata) with an index variable as in the following example:
#define SETBIT(I) WAIT_4_MUTEX; flags^I=1; FREE_MUTEX; unsigned char bdata flags; func () { unsigned char i; for (i=0; i < MAX_CELL; i++) { // do interesting stuff SETBIT(i); } }
This construction of coarse gives a lval error on the use of the SETBIT macro.
My current fall back are the macro's:
#define SETBIT(I) base |= ((unsigned char) (1 << I)) #define CLEARBIT(I) base &= ~((unsigned char) (1 << I))
But still have the feeling that I am wasting cycles on the shift operators in these two macro's and because this is within a mutex region the timing might become an issue.
Is there a better way to set/reset the i-th bit of a bit addressable variable ?
Unfortunately, Bits are not indirectly addressable in the 8051 architecture.
"Unfortunately, Bits are not indirectly addressable in the 8051 architecture."
Map CODE and XDATA space together and I guess you could consider using good old self modifying code :)
dunno that it'd save any cycles, though...?
;-)
set_bit (SFR, mask) clr_bit (SFR, mask)
Erik
How does that in any way satisfy his request?
The request is impossible to safisfy - the architecture just doesn't support it.
But still have the feeling that I am wasting cycles on the shift operators in these two macro's
Why would you worry about feelings, when you can so easily replace them by certainty? Check the generated code! List files exist for a reason.
If "I" is constant, probably not. It'll optimize to two simple operations, as in
mov a, #mask ; computed from (1 << I) orl base, a
For variable arguments, a table look-up instead of the shift would probably be better --- the 8051's shift opcodes are really rather limited, so a run-time computed shift-by-(n) is quite inefficient.
And of course, if all else fails, there's always Duff's Device. If you haven't heard of that before, let me put like this: you want to have seen it. And once you have, you may wish you hadn't... ;-)
Well, there is a suggestion, here is the listing for setting the second bit of the Hs_st1 bitfield:
C:0x2D4F 122FB9 LCALL OS_WAIT(C:2FB9) C:0x2D52 432202 ORL Hs_st1(0x22),#0x02 C:0x2D55 7F09 MOV R7,#0x09 C:0x2D57 123A72 LCALL OS_SEND_TOKEN(C:3A72)
The shifts apparently have been taken care of outside the critical region, probably even in the preproc's macro expansion. Although for that, in hindsight slightly embarrassing reason, this is what I wanted.
Thanks everybody for the contributions,
"In peace my mind withdraws"
Using a switch/case structure would avoid the shift by a variable.
void set_bit(unsigned char idx) { switch(idx) { case 0: bit_0 = 1; break; case 1: bit_1 = 1; break; case 2: bit_2 = 1; break; [...] } }
Using a switch/case structure would avoid the shift by a variable. but be excruciatingly slow.
the only approaches that have any reasonable throughput is the "mask in the call" and the lookup table.
The switch statement can be fast for some processors, that have efficient methods to call a jump table. But such processors normally also have a barrel shifter in which case they can shift n steps in constant time.
Easiest is if the caller can supply a constant value to or in, or the mask for clearing.
The switch statement can be fast for some processors, that have efficient methods to call a jump table.
JMP @A+DPTR ?
And if the compiler isn't clever enough to translate the switch/case structure this way, there is still the option of writing an assembly function.
This approach also works for more than 8 bits without any further effort, while the lookup table approach will need additional decision steps in such cases.
Not necessarily.
I think C51 can do it quite well with a jump table...
Only a very bad C compiler would not consider converting a switch() into a jump table if the case statements forms a suitably compact group.
One problem here is how much setup code that will be needed, where the compiler first validates if the shift value is within the range covered by the individual case statements. If the shift count is signed, the compiler will have to test if the value is < 0 or > 7 before knowing of the jump table can be used. In this special case, you may possibly be able to help the compiler with a switch (n&7) to force the count within the processed range of the switch statement.
For a processor with barrel shifter, the compiler vendor can make it easy on themselves by not testing the range of n before performing the shift, and just document that the shift operation is undefined if n is outside range. Such optimization is never allowed when the compiler generates code for a jump table, since and out-of-bounds value would result into a random jump.
in that case Keil is "a very bad C compiler" if you want to debug (no code overlay optimization) and a decent one if you do not care about using your ICE.
I have a strong suspicion that Keil has located some things in the optimizer that should be in the compiler, just to make the optimizer more impressive.