Question about disassembled code

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

Hi all, 

 

I was just looking through the disassembly of some code I am working on and I have a bit of a conceptual question as to why the compiler generates the code the way it does.  The first two lines of my code are pretty standard, I set DDRA because it's all outputs and then I clear port A to make sure they all start off low.  This generates the following instructions:

DDRA |= 0xff;
0000002B  IN R24,0x1A		In from I/O location 
0000002C  SER R24		Set Register 
0000002D  OUT 0x1A,R24		Out to I/O location 
	PORTA &= 0x00;
0000002E  IN R24,0x1B		In from I/O location 
0000002F  OUT 0x1B,R1		Out to I/O location 

Looking at this I see a standard read, modify, write operation for the Data direction register.  For the PORTA register though I'm confused as to the purpose of the read instruction at 0x2E.  It's reading in the contents of PORTA register but then it is writing 0 out to it directly.  Wouldn't the same results be achieved by eliminating the instruction at 0x2E?  For grins I recompiled the code using the size optimization and wound up with the same (seemingly) wasted instruction.  This has piqued my curiosity and I was just wondering if anyone could shed some light on this behavior.  Thanks.

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

Rather than using "|=" and "&=" for these two cases, why not just use "="?

"|=" and "&=" are suggesting you want a read/modify/write, when actually you just want a write.

David

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

Sometimes, reading an I/O address can cause some kind of hardware specific effect, like changing some flag. Maybe for this reason the compiler decides to not optimize out the read, even if it seems it doesn't do anything.

 

In fact, I have seen devices where a read only register and a different write only register are mapped to the same I/O address. In this case, a read and write to the same address actually access different device registers.

 

So, the compiler can't take any chances and does what the programmer said: read/write operation.

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

AVR Mega/Tiny UART data register is an example of read and write at one address operating on two different registers.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Valueduser wrote:
Wouldn't the same results be achieved by eliminating the instruction at 0x2E?

You need to learn more about what "volatile" means and what a read-modify-write is.

 

It would be a bug in the compiler if the instruction at 0x002E was not there. Your source code asks for a read-modify-write. The target is volatile. So both the read and the write MUST be done. The instruction at 0x002E is the read part of that equation.

 

Of course anything &0 is 0 so the result was always going to be 0 and the compiler always keeps 0x00 in R1. So for the write back it's bound to write the 0x00 in R1 to the target.

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

That makes sense.  Sure enough after changing those statements to just "=" the code changes to what I would have expected.  Thanks.

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

Clawson,

I'm not seeing what makes the target volatile.  Since the entire port is set to be an output there is no way for the port values to change without explicit instructions from the code.  Could you please explain?

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

Can I guess from the use of 0x00 in R1 that we ARE talking about the avr-gcc compiler here?

 

If so then you will find that PORTA is defined as follows:

(*(volatile uint8_t *)((0x1B) + 0x20))

In fact the line:

PORTA &= 0x00;

is passed to the compiler (after preprocessing) as:

int main(void) {
    (*(volatile uint8_t *)((0x1B) + 0x20)) &= 0x00;
    while(1);

The key thing in that is:

(*(volatile uint8_t *)((0x1B) + 0x20))

Of course something like PORTA has to be a pointer to volatile. Otherwise if you wrote:

a = PORTA;
b = PORTA;

the compiler would be quite at liberty (indeed it would if it's any good at optimizing!) to only make a single read of PORTA and then assign the same value to both 'a' and 'b'. Nothing in that says that between the two lines the value held at PORTA might actually have changed. That is exactly what the word "volatile" means. Effectively "every time you see this you MUST go and read it even if you think the answer will be the same - what you can't see but I know is that this is a "port" and the value there could change at any moment.

 

(actually this is a bad example - the one that might change at a moment's notice is PINA not PORTA! However if you were doing writes you wouldn't want the compiler to skip a second write either because it "thinks" it's already done it)

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

Thanks for the help, I appreciate it.