views:

179

answers:

3

This is a snippet of disassembled avr code from a C project I'm working on. I noticed this curious code being generated and I can't understand how it works. I'm assuming it's some sort of ridiculous optimization...

Can anyone explain?

92:         ticks++;
+0000009F:   91900104    LDS       R25,0x0104     Load direct from data space
+000000A1:   5F9F        SUBI      R25,0xFF       Subtract immediate
+000000A2:   93900104    STS       0x0104,R25     Store direct to data space
95:         if (ticks == 0) {
+000000A4:   2399        TST       R25            Test for Zero or Minus
+000000A5:   F009        BREQ      PC+0x02        Branch if equal
+000000A6:   C067        RJMP      PC+0x0068      Relative jump
+1  A: 

The SUBI instruction will set the processor flags for use in subsequent instructions. Is it possible that the flags are used in the next few instructions?

Greg Hewgill
I included the next few instructions... does that help narrow things down? I still don't get the point of "SUBI R25,0xFF" vs. "INC R25", both are 1 clock. And if R25 rolls over from 255 to 0, the the TST R25 instruction would work just fine.
Mark Renouf
Ok. I thought this through a bit and realized that in unsigned math, subtracting 0xFF is the same as adding 0x01. Wierd, but why do it this way? Does INC not set flags for the branch?
Mark Renouf
It looks like INC sets the V,N,S,Z flags, but SUBI sets H,V,N,S,Z,C. Since the compiler generated a TST instruction next, it appears not to be using the flags from the SUBI anyway. Also, using a SUBI seems odd because an ADDI with 0x01 would be equivalent again. It's sort of a mystery really.
Greg Hewgill
I just noticed there is no ADDI instruction. Perhaps that explains part of it.
Greg Hewgill
A: 

Why not increment? Well if R25 contains 0xFF, then subtracting 0xFF gives 0, but adding 1 gives 0x100, which isn't zero, so the TST R25 instruction would not work.

Mike Dunlavey
The AVR is an 8-bit CPU.
Greg Hewgill
OK, so much for that idea.
Mike Dunlavey
... but is the compiler more generic than that?
Mike Dunlavey
+4  A: 

The SUBI instruction can be used to add/subtract any 8 bit constant to/from an 8 bit value. It has the same cost as INC, i.e. instruction size and execution time. So SUBI is preferred by the compiler because it is more general. There is no corresponding ADDI instruction, probably because it would be redundant.

starblue