Use of CPSE Instruction

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

I'm programming in assembly using avr-as. I'm trying to understand the CPSE instruction and what it might be useful for. Basically, I was looking for a way to code a switch/case statement using something like:

cpi R16,1
brne 1f
bra case1
1: cpi R16,2
brne 2f
bra case2
2: ...

I guess I don't understand why there isn't a CPSNE instruction that skips if NOT EQUAL which would be very useful in this situation.

Is there a better way, i.e., less code, to do code switch?

What do you use the CPSE instruction for? Loop termination?

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

I measure time between packets. I want the variable TIME to rise up to 255 and to stay there, not to overflow back to zero. R0 is supposed to be zero.

lds r24,TIME
inc r24
cpse r24,r0
sts TIME,r24

So, CPSE prevents TIME from being cleared.
It took me a few years to make some profit from CPSE. Without this example, I would think CPSE is completely unuseful and lacking any sense. I always needed CPSNE instead.

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

Since you may skip a two word instruction I think you'll save a cycle (if the skip is done) with BREQ instead of CPSE. And it will not require a zero reg since the compare with zero is done by inc. And you may skip a little more than +1 instruction.

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

Quote:
Without this example, I would think CPSE is completely unuseful and lacking any sense.

For conditional branching you can use brbx. IMHO the main advantage of "cpse" over "tst+brbx SREG_Z" is the fact that cpse does not change SREG.
Useless is that "cpse Rx,Ry" and "cpse Ry,Rx" have different op-codes but same mnemonics.
h8mmc

No RSTDISBL, no fun!

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

Quote:

It took me a few years to make some profit from CPSE. Without this example, I would think CPSE is completely unuseful and lacking any sense. I always needed CPSNE instead.


Just for fun I looked at the instruction stats for an app with 80000 bytes of code/40000 words. Perhaps 30000 instructions...

ATmega1280 instruction use summary:
...
cp    : 216 cpc   : 205 cpi   :1241 cpse  :   0 dec   :  24 des   :   0 
...
Instructions used: 75 out of 117 (64.1%)

;)

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

I would have liked a cpsne as well.
One good thing about cpse is that it don't change any flags, so in very fast interrups you can do compare and exit without saving SREG

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
lpm r0, Z+
ld r1, Y+
cpse r0, r1
jmp Error

RES

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

interrupt wrote:
I was looking for a way to code a switch/case statement

        cpi     r16, 1
        brcs    case0
        breq    case1
        cpi     r16, 3
        brcs    case2
        breq    case3
        ...

Peter

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

Quote:
Is there a better way, i.e., less code, to do code switch?

The switch was heavily discussed in here and several methods could be used.
For further reading I can recommend this and that.
intcn

No RSTDISBL, no fun!

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

If you want a big switch (where max one statement is used) it's faster implemented with IJMP.

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

Isn't it aimed at things like for loop termination?

add IDX, INC
cpse IDX, END
rjmp loop

I'm not sure that I'd spend 1024 opcodes on it, but the instruction set is supposed to be designed to support C, right?

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

@westfw,

Lee has already shown that CV apparently never uses the opcode. Try grepping the .lss files for some of your avr-gcc projects. Do you see avr-gcc ever using it either? (actually I guess one could study the insn code in the compiler source to absolutely verify this).

Of course AVR was designed for C by Atmel in collaboration with IAR (not CodeVision or GCC or ImageCraft) so perhaps it's the case that the IAR compiler does use it?

EDIT: Actually I just tried:

..Atmel Studio>for /d %a in (*) do grep -i cpse %a/%a/Debug/*.lss

and it found one! It was used here:

000000d0 :
	{END, 0},
};


void delay100ms(uint8_t n) {
	while(n--) {
  d0:	0a c0       	rjmp	.+20     	; 0xe6 
	#else
		//round up by default
		__ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
	#endif

	__builtin_avr_delay_cycles(__ticks_dc);
  d2:	ef ef       	ldi	r30, 0xFF	; 255
  d4:	f3 eb       	ldi	r31, 0xB3	; 179
  d6:	31 97       	sbiw	r30, 0x01	; 1
  d8:	f1 f7       	brne	.-4      	; 0xd6 
  da:	00 c0       	rjmp	.+0      	; 0xdc 
  dc:	00 00       	nop
		_delay_ms(50);
		PORTD ^= (1 << PD7);
  de:	92 b3       	in	r25, 0x12	; 18
  e0:	90 58       	subi	r25, 0x80	; 128
  e2:	92 bb       	out	0x12, r25	; 18
  e4:	81 50       	subi	r24, 0x01	; 1
	{END, 0},
};


void delay100ms(uint8_t n) {
	while(n--) {
  e6:	81 11       	cpse	r24, r1
  e8:	f4 cf       	rjmp	.-24     	; 0xd2 
		_delay_ms(50);
		PORTD ^= (1 << PD7);
	}
}
  ea:	08 95       	ret

which comes from the source:

void delay100ms(uint8_t n) {
	while(n--) {
		_delay_ms(50);
		PORTD ^= (1 << PD7);
	}
}

So I take it back - avr-gcc *has* been known to generate it in exactly the circumstance you suggested.

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

it's used in more normal code as well :

  match=1;
  for (i=0;i<5;i++){
    if (wlaninputbuffer[i]!=wlan4[i]){
      match=0;
    }
  }

make this code that CPSE over clear match in R21

    if (wlaninputbuffer[i]!=wlan4[i]){
    127a:	f9 01       	movw	r30, r18
    127c:	e7 55       	subi	r30, 0x57	; 87
    127e:	fc 4f       	sbci	r31, 0xFC	; 252
    1280:	90 81       	ld	r25, Z
    1282:	f9 01       	movw	r30, r18
    1284:	e5 54       	subi	r30, 0x45	; 69
    1286:	fd 4f       	sbci	r31, 0xFD	; 253
    1288:	80 81       	ld	r24, Z
    128a:	98 13       	cpse	r25, r24
    128c:	50 e0       	ldi	r21, 0x00	; 0
    128e:	2f 5f       	subi	r18, 0xFF	; 255
    1290:	3f 4f       	sbci	r19, 0xFF	; 255

Not all the relevant code is here, the optimizer have rearranged it :)

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

clawson wrote:
So I take it back - avr-gcc *has* been known to generate it in exactly the circumstance you suggested.
I just looked at the app for a small project I'm working on. The binary is < 2.5kB and uses CPSE 9 times.

The source line follows the form of one of:

if (var)
if (!var)
while (var)
while (func())
var = !var;

CPSE also appears as part of __fixsfsi and __floatsisf.

These results are with -O2 or -O3.

Compiling with -Os or -O1 loses 2 of them.

Compiler version is 4.7.2.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

interrupt wrote:
What do you use the CPSE instruction for? Loop termination?

cpse can be used together with a bitmask register. (you can set a bit in a bitmask register like this 00010000, and change the bitnumber by using rotate or shift instructions)

cpse row, bitmask

while sbrs skips on steady bit numbers.