PORTx.OUTSET vs PORTx_OUTSET

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

I would have expected these to produce the same code, but having just changed a few PORTx.OUTSETs to PORTX_OUTSETs I seem to have saved memory.   New to Atmel Studio so not sure how to look at the compiled code yet, but have others seen this effect ?

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

Post real code. There are no official macros called PORTx or PORTx_OUTSET
Defining PORTx as a specific SFR e.g. PORTA can make your code easier to maintain.
.
I like using MACROs when appropriate. You must write them VERY carefully. They are a case of Write Once Use Many times.
Cliff Lawson does not like them. There is always a risk of obfuscating your code.
.
After all. PORTA.OUTSET = value is clearer than PORTx.OUTSET = value
.
David.

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

david.prentice wrote:

Post real code.

 

They weren't macros, I was just highlighting it as a generic issue.  The code has four instances of

 

PORTB_OUTSET = PIN1_bm;

 

This is reported by Atmel Studio as using 12 less bytes than

 

PORTB.OUTSET = PIN1_bm;

 

which seems both excessive and very odd.

 

I'm obviously not going to publish the whole program as it's both irrelevant and commercially confidential.

 

 

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

In which case you should explain what you meant.
.
Both of your statements do exactly the same thing. I would expect an optimising Compiler to generate similar ASM code.
Examine the LSS file. Compare the operation in the AS7 Simulator.
.
Yes, the first statement gives more clues to the Compiler. You can alter the -O arguments to see which end up with identical output from the second statement.
.
Personally, I would advise you to use the style that you feel most comfortable.
If speed and efficiency is important, VPORTs offer dramatic performance.
.
David.

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

Yes I would have expected the compiler to produce identical code as well.  I'll play with the -O arguments as you suggest.   And I only found this problem as I'd ran out of VPORTs.

 

Mike

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

You can change VPORT on the fly. A maiintenance nightmare unless you document it carefully.
.
Are you running out of Flash?
There are probably better ways to save Flash than changing all your PORT code.
.
It is well worth spending time and effort on the 1% of code that affects the execution time by 50%.
Wasting effort on saving Flash when you have several kilobytes spare is pointless.
.
David.

Last Edited: Mon. Jan 14, 2019 - 09:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The reason for GROUP.REG and GROUP_REG is that the former uses C structs while the latter is a direct definition. For writing Asm code the assembler does not understand structs which is why the GROUP_REG version has to exist. In C:

POTRB.OUTSET = 0x55;
PORTB_OUTSET = 0x55;

will ultimately have the same result. In Asm you would have no choice:

ldi R16, 0x55
sts PORTB_OUTSET, r16

david.prentice wrote:
Personally, I would advise you to use the style that you feel most comfortable.
+1

 

Having said that you would need to take a look at the generated code but if you were to write:

PORTB.DIR = 0xF0;
PORTB.OUTSET = 0xC0;
if (PORTB.IN & 0x0F != 0) {
    PORTB.OUTSET = 0x30;
}

then because C knows this is a struct and that all these registers are "close" the way it's likely to access this is to load an index register with the base address of "PORTB" and then use indexed offsets to do the writes. If you had written this with the "_" define macro form then it's more likely to treat each location as completely independent and may use STS rather than ST access, having to specify full addresses every time (ie larger/slower code). So there *might* be an advantage to using the struct style access.

 

This is the version using C style struct:

		PORTB.DIR = 0xF0;
 220:	e0 e2       	ldi	r30, 0x20	; 32
 222:	f6 e0       	ldi	r31, 0x06	; 6
 224:	20 ef       	ldi	r18, 0xF0	; 240
		PORTB.OUTSET = 0xC0;
 226:	90 ec       	ldi	r25, 0xC0	; 192
		if (PORTB.IN & 0x0F != 0) {
			PORTB.OUTSET = 0x30;
 228:	30 e3       	ldi	r19, 0x30	; 48

int main(void)
{
	while (1)
	{
		PORTB.DIR = 0xF0;
 22a:	20 83       	st	Z, r18
		PORTB.OUTSET = 0xC0;
 22c:	95 83       	std	Z+5, r25	; 0x05
		if (PORTB.IN & 0x0F != 0) {
 22e:	80 85       	ldd	r24, Z+8	; 0x08
 230:	80 ff       	sbrs	r24, 0
 232:	fb cf       	rjmp	.-10     	; 0x22a <main+0xa>
			PORTB.OUTSET = 0x30;
 234:	35 83       	std	Z+5, r19	; 0x05

It has put the base in Z then uses things like ST Z, ST Z+5, ST Z+8

 

This is the version using the Asm macros:

		PORTB_DIR = 0xF0;
 220:	c0 e2       	ldi	r28, 0x20	; 32
 222:	d6 e0       	ldi	r29, 0x06	; 6
		PORTB_OUTSET = 0xC0;
 224:	e5 e2       	ldi	r30, 0x25	; 37
 226:	f6 e0       	ldi	r31, 0x06	; 6
		if (PORTB_IN & 0x0F != 0) {
 228:	a8 e2       	ldi	r26, 0x28	; 40
 22a:	b6 e0       	ldi	r27, 0x06	; 6

int main(void)
{
	while (1)
	{
		PORTB_DIR = 0xF0;
 22c:	20 ef       	ldi	r18, 0xF0	; 240
		PORTB_OUTSET = 0xC0;
 22e:	90 ec       	ldi	r25, 0xC0	; 192
		if (PORTB_IN & 0x0F != 0) {
			PORTB_OUTSET = 0x30;
 230:	30 e3       	ldi	r19, 0x30	; 48

int main(void)
{
	while (1)
	{
		PORTB_DIR = 0xF0;
 232:	28 83       	st	Y, r18
		PORTB_OUTSET = 0xC0;
 234:	90 83       	st	Z, r25
		if (PORTB_IN & 0x0F != 0) {
 236:	8c 91       	ld	r24, X
 238:	80 ff       	sbrs	r24, 0
 23a:	fb cf       	rjmp	.-10     	; 0x232 <main+0x12>
			PORTB_OUTSET = 0x30;
 23c:	30 83       	st	Z, r19

It's slightly longer in that for the three locations it has put their addresses separately in X, Y and Z rather than doing everything as an offset from the single Z.

 

I guess to see this in action I really need an example involving more than 3 registers because in the latter case it will shortly run out of X/Y/Z

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

I would expect an orphan PORTB_OUTSET statement to use STS

And a sequence of PORTB_xxx accesses to possibly calculate address and use STD

An orphan PORTB.OUTSET would probably load PORTB address into Z 

 

Pure speculation on my part.    The Optimiser will be making cost-benefit analyses at every stage.    The end results may vary for different apps and even for the same app.

 

Hey-ho.    Compiler writers are pretty clever.    I really do not care how they do it.    Just as long as they obey my statements.

Ok,   I would if these statements lie in the 1% of code that ruins the application's performance.

 

Otherwise,   I attempt to write straightforward code in a HLL and never worry about the binary.

 

David.

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

Personally I'd choose the C struct style definitions anyway as it is simply more "C like" cheeky

 

Grouping registers in structs is probably the first step towards object oriented code ;-)