How can I set a bit corresponding to the number in a register? (numbers 0 to 7)
For example.
00000101 -> 00100000
(five -> 5th bit)
How from number to bitnumber? (ASM)
Lookup table?
Or:
ldi R17,5 ;input number inc R17 ldi R16,0 sec rol R16 dec R17 brne PC-2 ;R16 is your output
ldi data,0x00 cpi temp,1 brne bit_1 sbr data,0x01 rjmp done bit_1: cpi temp,2 brne bit_2 sbr data,0x02 rjmp done bit_2: cpi temp,3 brne bit_3 sbr data,0x04 rjmp done bit_3: cpi temp,4 brne bit_4 sbr data,0x08 rjmp done
This will only set one bit in a byte.
I have a ledbar which set several bits depending on if ADC input is beyond a certain value
do_bar: in temp,adch ;fetch ADC result ldi data,0x00 ;reset LedBar cpi temp,0x20 ;if Adc below 0x20 brlo ledbar_send ;quit test sbr data,0x01 ;else set bit 0 cpi temp,0x40 ;if Adc below 0x40 brlo ledbar_send ;quit test sbr data,0x02 ;else set bit 1 cpi temp,0x60 ;if Adc below 0x60 brlo ledbar_send ;quit test sbr data,0x04 ;else set bit 2 cpi temp,0x80 ;if Adc below 0x80 brlo ledbar_send ;quit test sbr data,0x08 ;else set bit 3 cpi temp,0xa0 ;if Adc below 0xa0 brlo ledbar_send ;quit test sbr data,0x10 ;else set bit 4 cpi temp,0xc0 ;if Adc below 0xc0 brlo ledbar_send ;quit test sbr data,0x20 ;else set bit 5 cpi temp,0xe0 ;if Adc below 0xe0 brlo ledbar_send ;quit test sbr data,0x40 ;else set bit 6 cpi temp,0xf8 ;if Adc below 0xf8 brlo ledbar_send ;quit test sbr data,0x80 ;else set bit 7
Don't know if any of this is similar to what you wan't to achieve.
edited first code :D
What about
for example n=5; b|=1<<n; //set the bit b&=~(1<<n);// clear
?
May I join the thread with question, please,
can You suggest the best way of
reversing the given bit (n) in a number (b)?
in C?
I think that this is way too complicate:
if (b& (1<<n)) b&=~(1<<n); else b|= 1<<n;
can You suggest the best way of
reversing the given bit (n) in a number (b)?
in C?
Exclusive OR:
b ^= (1<<n);
lookup table would probably be the fastest.
however here is an algorithmic approach.
; input r16 contains a number 0-7 ldi r17, 0xaa sbrs r16, 0 com r17 ldi r18, 0xcc sbrs r16, 1 com r18 and r17, r18 ldi r18, 0xf0 sbrs r16, 2 com r18 and r17, r18 ; r17 now contains the single bit, referenced by r16
And another, in pseudo code:
set carry clear target skip if bit 1 in orig clear rotate target left skip if bit 1 in orig clear rotate target left skip if bit 0 in orig clear rotate target left rotate target left skip if bit 2 in orig clear swap target
Just to optimize Chucks code a bit (it got me thinking).
ldi r17, 0x01 sbrc r16, 1 ldi r17, 0x04 sbrc r16, 0 shl r17 sbrc r16, 2 swap r17
It's a near 50% improvement over my initial code. This one would give a table lookup a good run for the money.
Just to optimize Chucks code
Very nicely done - that's great!
Another approach, not as short and not as fast, but not too bad on the average:
; R16 -- input, 0-7 ; R17 -- output clr r17 ldi zl, low(lbljmp) ldi zh, high(lbljmp) add zl, r16 adc zh, r17 sec ijmp lbljmp: ror r17 ror r17 ror r17 ror r17 ror r17 ror r17 ror r17 ror r17
Lee
Now you got me thinking :D
ldi data,5 ldi result,1 clr ctr test: cp data,ctr breq done lsl result inc ctr rjmp test done:
Gltich,
Excellent work. You did more than give a table lookup a run for the money. Given that your skip on bit value jumps, all skip over single word, single cycle instructions, it is 2 execution cycles if you do skip and 2 execution cycles if you do not skip. So, you simply count the instructions in your routine as one execution cycle each.
ldi r17, 0x01 sbrc r16, 1 ldi r17, 0x04 sbrc r16, 0 lsl r17 sbrc r16, 2 swap r17
Which is 7 execution cycles total. The smallest and fastest safe “conventional” lookup from SRAM is 8 cycles:
clr r17 andi r16, 0x7 ldi zl, low(table) ldi zh, high(table) add zl, r16 adc zh, r17 ld r17, z
LD from SRAM takes 2 cycles and LPM from FLASH takes 3 cycles to read, but SRAM requires the overhead of a setup routine which is not shown here. If you are willing force the table to never cross a 256 byte boundary and accept gross errors (as in more than 1 bit set in r17) if r16 is larger than 0x7, it can only go down to 5 cycles total for SRAM and 6 cycles total for FLASH.
ldi zl, low(table) ldi zh, high(table) add zl, r16 ld r17, z
Your code does not require setup overhead, modify the original value or give garbage results for values larger than 7 which makes it very robust. All that can be saved is one or two instruction cycles by using fragile table lookup code that must meet assumptions to work correctly (i.e. is not robust). I would score this as Glitch 1, lookup tables 0.
Hi,
I'm allways surprised when somebody using ldiw and addw for add 8 bit offset to the pointer like:
ldi R16,5 ;input clr R17 ldiw R30,Table*2 addw R30,R16 lpm R16,Z
instead of:
ldi R30,5 ;input clr R31 subiw R30,-(Table*2) lpm R16,Z
It's 2 clock faster. :-)
(addw, subiw are macros)
Hi,
I'm allways surprised when somebody using ldiw and addw for add 8 bit offset to the pointer like:ldi R16,5 ;input clr R17 ldiw R30,Table*2 addw R30,R16 lpm R16,Zinstead of:
ldi R30,5 ;input clr R31 subiw R30,-(Table*2) lpm R16,ZIt's 2 clock faster. :-)
(addw, subiw are macros)
That would be because the constant part of ADDIW, and SUBIW is limited to the range of 0-63... unless your putting your table in the first 64 bytes of RAM, or Flash, that method will not work.
the only thing you can do is save one cycle, using a subi/sbci pair (it also saves register usage) You can save a second cycle if the offset is passed in zl.
clr zh mov zl, r16 andi zl, 0x7 subi zl, low(-table) sbci zh, high(-table) ld r17, z
Of course this does not count the cost of loading the table into RAM (this is likely done once, so the cost is minimal), or the cost of possibly saving/restoring Z (this could be expensive, depending on the overall application). This is why it's often pointless to look at such a small segment of code, and optimize it... because while yes those 5 or 6 lines might be optimal, teh side effect tehy have on the rest of your program could be worse than having left the code alone in the first place. Now if the code has no side effects (as my optimized version of Chucks code), then you can indeed look at just that small segment.
Gltich,Excellent work. You did more than give a table lookup a run for the money. Given that your skip on bit value jumps, all skip over single word, single cycle instructions, it is 2 execution cycles if you do skip and 2 execution cycles if you do not skip. So, you simply count the instructions in your routine as one execution cycle each.
ldi r17, 0x01 sbrc r16, 1 ldi r17, 0x04 sbrc r16, 0 lsl r17 sbrc r16, 2 swap r17Which is 7 execution cycles total. The smallest and fastest safe “conventional” lookup from SRAM is 8 cycles:
clr r17 andi r16, 0x7 ldi zl, low(table) ldi zh, high(table) add zl, r16 adc zh, r17 ld r17, zLD from SRAM takes 2 cycles and LPM from FLASH takes 3 cycles to read, but SRAM requires the overhead of a setup routine which is not shown here. If you are willing force the table to never cross a 256 byte boundary and accept gross errors (as in more than 1 bit set in r17) if r16 is larger than 0x7, it can only go down to 5 cycles total for SRAM and 6 cycles total for FLASH.
ldi zl, low(table) ldi zh, high(table) add zl, r16 ld r17, zYour code does not require setup overhead, modify the original value or give garbage results for values larger than 7 which makes it very robust. All that can be saved is one or two instruction cycles by using fragile table lookup code that must meet assumptions to work correctly (i.e. is not robust). I would score this as Glitch 1, lookup tables 0.
hehe thanks.. The credit really goes to Chuck... all I did we optimize by pre-calculating certain results (mainly the start points). (My uninspiring first example, was jsut that, code to demonstrate, without much thought into it) But yes, those skip instructions do make cycle counting easier. They're great for when you need a constant execution time through a strip of code.
But the fastest & shortest is to use a 74138, right? 'Course you need to burn 11/12 I/O pins... ;)
Lee
Lee is correct. That reminds me about reading somewhere that a soldering iron was a favorite programming tool :). I can't remember exactly where it was I read that.
I can't remember exactly where it was I read that.
Was that Steve Ciarcia of Byte and Circuit Cellar fame?
I've been trying to think of the application of the exercise. The best I could come up with is where we in fact apply the '138--"chip selecting" a digit of a 7-segment display.
Lee
Was that Steve Ciarcia
I think it was Steve, a couple or three months ago, in Circuit Cellar.
“Inside the Box Still Counts” — This was the title of my very first Circuit Cellar INK editorial 19 years ago. Two hundred issues later I still believe it. Like solder being my favorite programming language, I still believe that however appliance-like embedded control and personal computing implementations become, we can’t forget that the process of achieving that goal isn’t instant. In order to create the sophisticated devices and technologies regarded as off-the-shelf, many people still have to maintain real expertise in rudimentary design skills. Basically, somebody always has to know what’s inside the box.
—Steve Ciarcia, “Inside the Box Still Counts,” Circuit Cellar 200, 2007
Not to be argumentative...just curious for some reason, I am thinking he actually said that back in his "Byte" magazine days? I guess I am committing a sin now and going off topic :-).
From that current quote it would be easy to believe he not only said it in Byte but also many times since. It looks like a favorite saying of his. And you could always write him and ask - he's very good about answering email.
At this point I'd say the topic is well covered, so there isn't much harm in wandering.
note 4 glitch:
I said that subiw (not sbiw) and addw are MACROS so it's not limited to 63B. ;-)
I said that subiw (not sbiw) and addw are MACROS so it's not limited to 63B
But you're using the macros in a code segment, and then claiming the code is more efficient. We need to see the macro definition/expansion to appreciate the efficiency.
note 4 glitch:
I said that subiw (not sbiw) and addw are MACROS so it's not limited to 63B. ;-)
You are correct, sorry... being so similar to the actual avr instruction nemonic I didn't catch that. But as Chuck said, we would need to see the macro definition to see that it actually was more efficient.
we would need to see the macro definition to see that it actually was more efficient
The same code without the use of undefined macros:
ldi r16, 5 clr r17 ldi r30, low(Table * 2) ldi r31, high(Table * 20 add r30, r16 adc r31, r17 ;6 clocks ldi r30, 5 clr r31 subi r30, low(-Table * 2) sbic r31, high(-Table * 2) ;4 clocks
Can be done shorter? when I put the lookup table at init at begin of SRAM. (0x60) because the stack begins at RAMEND up. And the lookuptable can be generated with sec/rol.
RAMBEGIN:
00000001 0x60
00000010
00000100
00000100
00001000
00010000
00100000
01000000
10000000
andi Yp, 0x07 ;Yp - 8 until Yp < 8 mov YL, Yp subi YL, -0x60 ld data, Y
Above code only takes 5 cycles. (or 4 when you use YL for Yp)
..one day later: I've tested this, and works fine.
You have to also make sure that YH is correct (0x00)
Going BACK to the original question:
How can I set a bit corresponding to the number in a register? (numbers 0 to 7)
sbr my_register,1<<0 (or whatever bit number and the register being r16-r31)
If you need to set more than 1 bit then it would be
sbr my_register,(1<<0|1<<5|1<<n)
so someone will tell me that I misundertood the question being asked :?
so someone will tell me that I misundertood the question being asked
Actually, yes :D
How do you figure out to set i.e. bit 5 if input value is 0x05
set i.e. bit 5 if input value is 0x05
JS, go back and read the whole thread... a novel method came out, that is nearly as fast as a table lookup. (1 cycle more vs a ram lookup, and ties a flash lookup for speed... beats both for space)