Assembler Tricks & Tips

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

There are lots of clever bit banging tricks that the ASM programmer has available, but I haven't seen them all yet, cause they're still waiting to be invented.
Anyone care to share theirs ?
I'll start the ball rolling with one of my discoveries:

Here's a way to automatically add an 8bit immediate value to a 16bit value contained in a pair of any 2 registers.
This is better than 'adiw' because you're not limited to a 0-63 addition value plus you're not limited to the top 4 register pairs only. Takes 2 clock cycles also. You'll never use adiw again.

subi lowreg,-immediatevalue ; just negate the value you wish to add to the reg pair
sbci highreg,-1 ; highreg will be incremented only if lowreg clocks over to 0

Edit: That should read: highreg will be incremented only if lowreg generates a carry. ie. 0 or greater

JimK

Last Edited: Tue. Nov 8, 2005 - 03:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi JimK

seems cool.

I wonder if the

sbci highreg,-1

works properly because the SBCI constant values are from 0...255, so the "-1" is not included. But on the other hand -1 coud be the same as 255.
The assembler shows no error with "-1"?

Here an assembler hint from me:
Often i preset r2 (or any other other lower register) to "0"
It helps to clear data and helps with adding up values

; initilize r2 = zero
.def   zero = r2
ldi   zero, 0x00
; end of init
;....
;some other code
;...
; clear a SRAM address (saddr)
   sts saddr, zero 
;....
; adding up 8 bit values to a 32-bit value
   add   r20, tmp1
   adc   r21, zero
   adc   r22, zero
   adc   r23, zero

r20..r23 is the 32-bit value
tmp1 is the value to add

with this i don´t need branches and have a time-constant code.
sometimes usefull

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

Quote:
.def zero = r2
ldi zero, 0x00

I thought ldi only worked with r16 - r31
however

clr zero 

should work fine.

Laurence Boyd II

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

Why bother? The power on reset circutry automatically sets all registers to 0 in the first place, as long as your code never changes the value of R2, it would take freakish conditions to alter it.

-Curiosity may have killed the cat
-But that's why they have nine lives

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

Quote:

The power on reset circutry automatically sets all registers to 0

Not true. I/O registers have defined values. R0-R31 can have any value. I would not count on those registers having a particular value when "events" happen.

Quote:

Why bother?

Because I want my apps to >>always<< start up and run properly.

Side note: I tried the "register having 0" in a couple of '4433 apps. I ended up finding the register itself was more "valuable" than having a source of zero readily available. I think GCC keeps a zero register? Perhaps the value depends on the app. For 8-bit operations it doesn't seem to have much benefit.

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

JimK wrote:
There are lots of clever bit banging tricks that the ASM programmer has available, but I haven't seen them all yet, cause they're still waiting to be invented.
Anyone care to share theirs ?

How about swapping the contents of two registers without any additional storage?

ldi    r17,0x17
ldi    r19,0x19
...
eor    r17,r19
eor    r19,r17
eor    r17,r19

That one never fails to blow the mind of programmers who cut their teeth on C++ or some other "low level code". (I tell them it usually only works when using prime-numbered registers).

Mike

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

yeah that can be a good trick, though it's not exclusive to assembly.

A ^= B;
B ^= A;
A ^= B;

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:
ldi zero, 0x00

my mistake ...

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

Ah!!!

And then there's the tricks. If properly documented - which the tricky code rarely ever is - you might gain a byte or clock cycle, or two.

But to sacrifice program clarity for a byte or clock cycle is probably much more expensive in the end. There might be times when you need to squeeze every single last byte or clock cycle out of a function, I admit. But program readability is far more important then writing tricky, obsure, stealthy, or unmaintainable code.

What ever happened to functional, readable, maintainable and, elegant code writing?

The problem with "Trixter" code is, that the trick usually gets played back on you in the end!

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

The new mega avrs have a new instruction to toggle an output in one instruction. Should almost double the speed of the bitbanged usbs and ethernets and stuff like that

Imagecraft compiler user

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

You mean like these single clock cycle toggle instructions ?

Clr R0 ;Set up 0 in R0
Clr R1
Inc R1 ;Set up 1 in R1

Out Portb, R1 ;toggle pin 0 in 1 clk cycle
Out Portb, R0 ;toggle pin 0 in 1 clk cycle

JimK

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

no Jim.. I think he's referring to writing to the PIN register.. so it's not a new instruction, but rather a new I/O feature of the PIN register. Writing a 1 to a particular bit in the PIN register will cause it's PORT output value to toggle. (I do not know, off the top of my head, if this only works when DDR=1, or if it will also toggle the pull-up state when DDR=0)

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

Is thise feature described somewhere? Could you be so kind to give me a link to any Atmel document which describes this?

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

Quote:

Is thise feature described somewhere? Could you be so kind to give me a link to any Atmel document which describes this?

This is from the Mega48 data sheet:

Quote:

Toggling the Pin - Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.

Thanks Bob I had not picked up on that new feature.

RC

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

glitch wrote:
no Jim.. I think he's referring to writing to the PIN register..

The point I was making was that you can already toggle an I/O pin in one clock cycle. ie. with 16Mhz crystal you can output an 8Mhz square wave.

JimK

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

C. H.
-------------------------------------------------------------------
It's only waste if you don't use it!

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

microcarl wrote:
Ah!!!

And then there's the tricks. If properly documented - which the tricky code rarely ever is - you might gain a byte or clock cycle, or two.

But to sacrifice program clarity for a byte or clock cycle is probably much more expensive in the end. There might be times when you need to squeeze every single last byte or clock cycle out of a function, I admit. But program readability is far more important then writing tricky, obsure, stealthy, or unmaintainable code.

What ever happened to functional, readable, maintainable and, elegant code writing?

The problem with "Trixter" code is, that the trick usually gets played back on you in the end!

Hi Carl,

You're gonna have to stop following me around.
Now ... "elegant" is how I like my women. This adjective has no place in engineering. A pretty piece of 'C' code might look very nice and readable.
Maybe we could frame it and hang it up on the wall for all to admire.
What a buzz I'd get hearing admirers comment, "Oh ... that looks so maintainable Jim"
Tongue in cheek comments aside:
Bit bashing in ASM has enabled me to build machines that would be next to impossible to build in basic or C. Like an 8Mbit/sec IR laser comms link using a 16Mhz AVR or encoding/decoding 9 channels of radio control pulse code modulated signal without the use of a single AVR timer.
The power and control is what I love about it. I can forgoe "readable, maintainable and, elegant" if the difference is, that my AVR guided missile will hit the target, rather than not.

JimK

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

JimK wrote:
glitch wrote:
no Jim.. I think he's referring to writing to the PIN register..

The point I was making was that you can already toggle an I/O pin in one clock cycle. ie. with 16Mhz crystal you can output an 8Mhz square wave.

JimK

only if not in a loop. which pretty much makes it useless. except for very short runs of pulses. The overhead of the loop would cut that rate in half at a minimum.

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:

The point I was making was that you can already toggle an I/O pin in one clock cycle. ie. with 16Mhz crystal you can output an 8Mhz square wave.

Sorry, Jim, I can only agree with you if your app ONLY uses just that one pin on the entire port.

Toggling a pin on an AVR output port is a relatively painful process. An extensive thread a few years back went through the alternatives. IIRC, the straightforward "test the pin and set it to the opposite value" with a couple of jumps is nearly the best that can be done. In the new AVR models, the chip designers have given us another tool for the toolbox.

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

You can use the USI to toggle the SCK pin in 1 instruction on older avrs. Furthermore, you can toggle the clock, and set the data bit, and rotate the data in 2 instruction. Love the USI.

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

Giorgos_K wrote:
This feature is processor specific, and you can read all about it in the data sheets of every AVR supporting it.

Refering to the image of the General Digital I/O circuit diagram, a write of 1 to a port pin (WPx active) generates a clock on the PORTxn D Flip-Flop via the NOR gate just after the output of the WPx NAND gate switches the MUX to select the Q output of the PORTxn Flip-Flop as its D input. Sweet!

There's a book by Henry S. Warren, Jr. (40 year career with IBM) titled Hacker's Delight (not what you think) that contains a wealth of logic and arithmetic programming tricks. A must read!

-Tom

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

Correction, should read: "[i]switches the MUX to select the inverted Q output

Quote:
"
After all, we are looking for a toggle here.

-Tom

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

Correction, should read: "switches the MUX to select the inverted Q output"
After all, we are looking for a toggle here. And yes, I really do have a life :-)

-Tom

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

Quote:

Bit bashing in ASM has enabled me to build machines that would be next to impossible to build in basic or C.

Ignoring the challenge here :) the fact remains that the new pin-toggle feature can toggle any port pin that can be reached in I/O space in one cycle and one instruction--this was at least a several cycle-several instruction sequence before. Regardless of your facility in bit-bashing. ;) In practice, I've only used it on indicator-type signals like LEDs. But in a tight Mega48-class app with a few of these desired, 10 words is 10 words regardless of the preferred programming language.

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:
But in a tight Mega48-class app with a few of these desired, 10 words is 10 words regardless of the preferred programming language.

And I'm sure that the C compiler writers will incorporate their use whereever they possibly can, further nullifying the concept that assembly is magnitudes better then C!!!

Trying to write that cos(x) trig function as is being discussed in the DukerX thread, is down right unreasonable in assembly language...

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston