mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Do MMIO registers have to be read/written as 32bit?

Fri Jan 18, 2013 9:31 pm

I noticed that all MMIO registers (like the UART) in examples are declared as 32bit and read/written through a special asm function or inline asm.

What is the reasoning behind that? Why not simply declare them as volatile uint32_t?

Also do I always have to read/write them as 32bit values? Since many contains bitfields I was thinking of declaring them as such:

Code: Select all

struct Reg1 {
    volatile uint32_t bit0:1;
    volatile uint32_t bit1:1;
    volatile uint32_t bit2:1;
    volatile uint32_t bit3:1;
}  *reg1 = 0x20200420;
But I fear that reg1->bit0 will probably not result in a 32bit access. Would that break things?

MfG
Mrvn

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: Do MMIO registers have to be read/written as 32bit?

Fri Jan 18, 2013 9:38 pm

mrvn wrote:I noticed that all MMIO registers (like the UART) in examples are declared as 32bit and read/written through a special asm function or inline asm.

What is the reasoning behind that? Why not simply declare them as volatile uint32_t?
I couldn't figure that out, either. I've always used volatile pointers; it's worked just fine.

User avatar
DavidS
Posts: 3800
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Do MMIO registers have to be read/written as 32bit?

Fri Jan 18, 2013 9:58 pm

mrvn wrote:...
Also do I always have to read/write them as 32bit values?
...
But I fear that reg1->bit0 will probably not result in a 32bit access. Would that break things?

MfG
Mrvn
You are coding for an ARMv6 CPU, all memory access is 32-bit. If you us 8it access then it still does a 32-bit memory access (in some cases with an extra read in order to keep the surrounding bits correct), and this is why when accessing HW registors you will always use a 32-bit access. And from every thing I have seen the way most C compilers (including GCC) do bitfeids is horidly ineficient.

Also so long as you avoid GAS and inline GCC/LCC assembly, ARM assembly is a lot easier to work with than C.
RPi = Way for me to have fun and save power.
100% Off Grid.
Household TTL Electricity Usage = 1.4KW/h per day.
500W Solar System, produces 2.8KW/h per day average.

dwelch67
Posts: 954
Joined: Sat May 26, 2012 5:32 pm

Re: Do MMIO registers have to be read/written as 32bit?

Fri Jan 18, 2013 10:25 pm

It depends on the vendor, the bus is likely 64 bit, but has byte enables so you can address any byte in the address space. control and status registers generally dont decode on a byte basis as it rarely makes sense. I would assume on the raspberry pi that you should use 32 bit accesses. byte accesses vs word accesses dont save you anything and can sometimes cost you more cycles, 32 bit variables and 32 bit accesses (or 64 bit) are the cheapest/fastest.

You most certainly and will find many examples that use volatile uint32_t*. My examples dont and I have here and there stated the reasons (I have many times gotten gcc (and others) to fail to properly generate the right instruction for volatile uint32_t solutions). Further, I am willing to sacrifice the extra cycles of having an abstraction layer for memory/register access for many reasons. Mostly having to do with writing a driver one time that can be used on a host talking to simulated hardware, then on the processor in the simulation, then later on silicon and also then from the host through an interface (serial, jtag, pcie, usb, etc). Never having to re-write the core application, only change the abstraction layer. Plus the benefit of accurately and correctly using the right instruction to cause the right bus cycle, rather than hoping the compiler will. And it is very easy to inline the abstraction if you want to recover the speed.

I have also watched folks have to refactor a lot of code to add an abstraction layer after the fact (for various reasons) when moving to a new platform or going through a new interface. Was painful for them every time.

No, nothing special about these compilers nor this platform, the volatile uint32_t* approach will give you the same/similar experience on this platform as on any other.

dwelch67

User avatar
DavidS
Posts: 3800
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Do MMIO registers have to be read/written as 32bit?

Fri Jan 18, 2013 10:44 pm

@dwelch67:
Ok I was not aware of any ARM that uses byte selects. I have checked quite a few, and with all the CPUs/MCUs that I have checked that are ARM based, BYTE access is done as a thirty-two bit operation (I can not check for case of the implementation in the BCM2835 as my oscilloscope is a bit slow for that, and most of the tracks are either internal to the MCU or unaccesable on the RPi).

I am sure that it is very likely a 64 or 128 bit memory bus with word (32 bit word that is) sellects, and you may have better information sbout this particular implementation of the ARM 1176, so until I figure out a way to test this with this MCU I will defer to you.
RPi = Way for me to have fun and save power.
100% Off Grid.
Household TTL Electricity Usage = 1.4KW/h per day.
500W Solar System, produces 2.8KW/h per day average.

mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Re: Do MMIO registers have to be read/written as 32bit?

Sat Jan 19, 2013 12:00 am

dwelch67 wrote:You most certainly and will find many examples that use volatile uint32_t*. My examples dont and I have here and there stated the reasons (I have many times gotten gcc (and others) to fail to properly generate the right instruction for volatile uint32_t solutions).
Can you give an example?


mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Re: Do MMIO registers have to be read/written as 32bit?

Sat Jan 19, 2013 10:44 am

I ment an example where gcc does the wrong thing. I vaguely remember something in the C standard that should prevent that and some quick tests show that access to parts/bits of an "unsigned long long" do get optimized into smaller reads but "volatile unsigned long long" sticks with reading the whole thing even if it ignores half of it. Using a 32bit type always did a 32bit read in my tests. Couldn't find an example where gcc would optimize something into a byte read.
int foo1(unsigned long long *p) { return *p >> 32; }
int foo2(volatile unsigned long long *p) { return *p >> 32; }

00000000 <foo1>:
0: e5900004 ldr r0, [r0, #4]
4: e12fff1e bx lr

00000008 <foo2>:
8: e1c020d0 ldrd r2, [r0]
c: e1a00003 mov r0, r3
10: e12fff1e bx lr
MfG
Mrvn

dwelch67
Posts: 954
Joined: Sat May 26, 2012 5:32 pm

Re: Do MMIO registers have to be read/written as 32bit?

Sat Jan 19, 2013 3:23 pm

Thats the thing, it is clearly a bug when it happens, very data dependent. One of those things that waits for just before or just after you are ready to release something. If could make it happen on demand I would and file the bug. I have been doing the PUT32 thing for well over a decade now for other reasons and have no need to go back (yep, somewhere around late 3.x early 4.x was the last time I saw it). For the msp430 I do the volatile pointer thing because of the nature of the instruction set and optimization it is just too tempting. I have not written any large apps though and check the generated code.

Most (if not all) people do the volatile pointer thing, so you might as well go with the flow if that is the style you prefer. On some chips the byte mask will be ignored so an strb *might* work against a 32 bit register (masking that you have/had a problem), and on others the bytemask is decoded and an strb vs str will give different results (so you want the compiler to get it right). So keep your eyes open...

dwelch67

Return to “Bare metal, Assembly language”