How from number to bitnumber? (ASM)

Go To Last Post
33 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How can I set a bit corresponding to the number in a register? (numbers 0 to 7)
For example.
00000101 -> 00100000
(five -> 5th bit)

RES

Last Edited: Thu. May 3, 2007 - 10:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lookup table?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or:

ldi  R17,5            ;input number
inc  R17
ldi  R16,0
sec
rol  R16
dec  R17
brne PC-2
;R16 is your output
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	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

Last Edited: Thu. May 3, 2007 - 11:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
can You suggest the best way of
reversing the given bit (n) in a number (b)?
in C?

Exclusive OR:

b ^= (1<<n);

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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   

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Just to optimize Chucks code

Very nicely done - that's great!

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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:	
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 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)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smaslan wrote:
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)

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.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

Last Edited: Fri. May 4, 2007 - 04:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike B wrote:
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.

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.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But the fastest & shortest is to use a 74138, right? 'Course you need to burn 11/12 I/O pins... ;)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I can't remember exactly where it was I read that.

Was that Steve Ciarcia of Byte and Circuit Cellar fame?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Was that Steve Ciarcia

I think it was Steve, a couple or three months ago, in Circuit Cellar.

found it -

Quote:
“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

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 :-).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

note 4 glitch:
I said that subiw (not sbiw) and addw are MACROS so it's not limited to 63B. ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
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.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

smaslan wrote:
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.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
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

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

RES

Last Edited: Sun. May 6, 2007 - 09:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have to also make sure that YH is correct (0x00)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Going BACK to the original question:

Quote:
How can I set a bit corresponding to the number in a register? (numbers 0 to 7)
the answer would be
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 :?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
set i.e. bit 5 if input value is 0x05
ooohh I see :oops: I would just use a loop but not necessarily the fastest or smallest way to do it.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.