lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Broadcom chipset C code

Thu Dec 19, 2013 8:16 am

Code: Select all

// Function select
// pin is a BCM2835 GPIO pin number NOT RPi pin number
//      There are 6 control registers, each control the functions of a block
//      of 10 pins.
//      Each control register has 10 sets of 3 bits per GPIO pin:
//
//      000 = GPIO Pin X is an input
//      001 = GPIO Pin X is an output
//      100 = GPIO Pin X takes alternate function 0
//      101 = GPIO Pin X takes alternate function 1
//      110 = GPIO Pin X takes alternate function 2
//      111 = GPIO Pin X takes alternate function 3
//      011 = GPIO Pin X takes alternate function 4
//      010 = GPIO Pin X takes alternate function 5
//
// So the 3 bits for port X are:
//      X / 10 + ((X % 10) * 3)
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
{
    // Function selects are 10 pins per 32 bit word, 3 bits per pin
    
    
    //using the gpio already mapped address
    
    volatile uint32_t* paddr = gpio + BCM2835_GPFSEL0/4 + (pin/10);
    uint8_t   shift = (pin % 10) * 3;
    uint32_t  mask = BCM2835_GPIO_FSEL_MASK << shift;
    uint32_t  value = mode << shift;
    bcm2835_peri_set_bits(paddr, value, mask);
}

In bcm2835.h
#define BCM2835_GPFSEL0 0x0000 ///< GPIO Function Select 0


what's the point from above code BCM2835_GPFSEL0/4 which is 0x0000/4 =0 anyway.?

vadim
Posts: 129
Joined: Wed Sep 18, 2013 1:47 pm
Location: Nottingham

Re: Broadcom chipset C code

Thu Dec 19, 2013 10:13 am

For uniform addressing of all control registers, perhaps. There will be different shifts for other controls.

User avatar
joan
Posts: 15372
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Broadcom chipset C code

Thu Dec 19, 2013 10:25 am

To highlight that you are accessing a word at a byte address.

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: Broadcom chipset C code

Thu Dec 19, 2013 1:50 pm

joan wrote:To highlight that you are accessing a word at a byte address.

gpio is 32 bit address and adding to it is more like an offset. padder is also 32 bit address.
so why do you say it's a byte address?

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: Broadcom chipset C code

Thu Dec 19, 2013 1:52 pm

vadim wrote:For uniform addressing of all control registers, perhaps. There will be different shifts for other controls.
why divide by 4? why not 1, 2, or 8?

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Broadcom chipset C code

Thu Dec 19, 2013 1:56 pm

what's the point from above code BCM2835_GPFSEL0/4 which is 0x0000/4 =0 anyway.?
That is good code. The programmer who wrote that knew what they were doing.
  1. The whole point of using macros is that you do not then need to worry about what the value is.
  2. If you later copy and paste that code, or just change that piece, to use B2835_GPFSEL1, the new code will still be right.

User avatar
rpdom
Posts: 18140
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: Broadcom chipset C code

Thu Dec 19, 2013 3:08 pm

lilzz wrote:why divide by 4? why not 1, 2, or 8?
Presumably BCM2835_GPFSEL0 is a byte (8-bit) offset and it needs to be a word (32-bit) value.

User avatar
DougieLawson
Posts: 40810
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: Broadcom chipset C code

Thu Dec 19, 2013 3:58 pm

lilzz wrote:
vadim wrote:For uniform addressing of all control registers, perhaps. There will be different shifts for other controls.
why divide by 4? why not 1, 2, or 8?
It could be because lazy assembler programmers have been taught that divide takes fewer cycles than a shift. Which may or may not be true.

I'd always use divide for maths and shift for bits as I think it makes the code easier to read.
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

User avatar
rpdom
Posts: 18140
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: Broadcom chipset C code

Thu Dec 19, 2013 4:16 pm

DougieLawson wrote:It could be because lazy assembler programmers have been taught that divide takes fewer cycles than a shift. Which may or may not be true.

I'd always use divide for maths and shift for bits as I think it makes the code easier to read
That might be true for floating point maths, but as the ARM has no integer divide instruction a shift is just one instruction for byte or word values (and can often be combined with another instruction at the same time) and therefore much faster. If the compiler is decent it will convert part of that line to an add with shift.

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 28358
Joined: Sat Jul 30, 2011 7:41 pm

Re: Broadcom chipset C code

Thu Dec 19, 2013 5:03 pm

In fact, I think the compiler will have optimised out the CONSTANT/8 completely.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed.
I've been saying "Mucho" to my Spanish friend a lot more lately. It means a lot to him.

User avatar
jojopi
Posts: 3424
Joined: Tue Oct 11, 2011 8:38 pm

Re: Broadcom chipset C code

Thu Dec 19, 2013 9:17 pm

DougieLawson wrote:It could be because lazy assembler programmers have been taught that divide takes fewer cycles than a shift. Which may or may not be true.
I doubt that anyone would think that. It is always quite the opposite.

You are right to write code the way you think is clearest, because the compiler will not mind. I am not sure that shifting by two is clearer than dividing by four, however, and it requires extra parentheses.

Incidentally, right shift is not necessarily equivalent to division, for negative values. In that case the shift is implementation-defined, which in practice on a two's-complement machine means it rounds towards negative, whereas division rounds towards zero. (Except in Python, where integer division rounds towards negative!)

User avatar
DougieLawson
Posts: 40810
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: Broadcom chipset C code

Thu Dec 19, 2013 11:06 pm

Compiler NO! Assembler YES.

I'm not used to these funny RISC machines. The machines (S/360, S/370, S/390, zSeries) that I write most assembler code for now has nearly a thousand instructions and four different flavours of maths (64-bit integer, float, packed decimal & IEEE).

I've still got to do the 700 page reading assignment for the RPi's ARM processor and it's instruction set.

I've also got to stop thinking in EBCDIC and try to get used to this new-fangled ASCII thing.
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Broadcom chipset C code

Fri Dec 20, 2013 12:03 am

lilzz wrote:
vadim wrote:For uniform addressing of all control registers, perhaps. There will be different shifts for other controls.
why divide by 4? why not 1, 2, or 8?
paddr is a pointer to a 32-bit integer. In C when you add one to a pointer you get the next object of the same size. However BCM2835_GPFSEL0 is a byte offset, so it needs to be divided by 4 to make it into a 32-bit offset (32bits/4 = 8bits).

Let's assume we have a pointer to an 32-bit integer called x, and it's value happens to be 100.
So the integer pointed to by x will be at (byte) addresses 100, 101, 102 and 103.
If we add 1 to x the compiler will multiply that by 4 and give us 104, which is the address of the next integer.
Similarly, if we have a byte offset from x, say 8, we will have to divide that by 4 so that when the compiler multiplies it by 4 it will be right.
x = x + 8/4
Now x is 108.

The whole thing will be optimised out by the compiler anyway.

User avatar
jojopi
Posts: 3424
Joined: Tue Oct 11, 2011 8:38 pm

Re: Broadcom chipset C code

Fri Dec 20, 2013 3:19 am

DougieLawson wrote:I'm not used to these funny RISC machines. The machines (S/360, S/370, S/390, zSeries) that I write most assembler code for now has nearly a thousand instructions and four different flavours of maths (64-bit integer, float, packed decimal & IEEE).
Those architectures certainly support some complex old instruction sets. The integer representation is 32/64bit two's-complement, however, just like the most modern machines. There is no excuse on any binary platform for a shift to be slower than a divide; it should always be the reverse.

The only timing information I can find is for the ancient S/360 Model 40, where if I read the Functional Characteristics correctly the slowest shift is 23.13µs, and the fastest divide 136.30µs. Presumably on current implementations these kinds of figures, and the whole concept of cycle times, are meaningless due to pipelining.

GCC does not seem to think that divide should be faster than shift. It compiles a divide by four as SRA ,2 on all supported S/390 and zSeries CPU types. (On the 64bit CPUs it converts a divide by ten to a multiply by 7378697629483820647 as well.)

lilzz
Posts: 411
Joined: Sat Nov 30, 2013 5:27 pm

Re: Broadcom chipset C code

Sat Dec 21, 2013 7:36 am

rurwin wrote: paddr is a pointer to a 32-bit integer. In C when you add one to a pointer you get the next object of the same size. However BCM2835_GPFSEL0 is a byte offset, so it needs to be divided by 4 to make it into a 32-bit offset (32bits/4 = 8bits).

Let's assume we have a pointer to an 32-bit integer called x, and it's value happens to be 100.
So the integer pointed to by x will be at (byte) addresses 100, 101, 102 and 103.
If we add 1 to x the compiler will multiply that by 4 and give us 104, which is the address of the next integer.
Similarly, if we have a byte offset from x, say 8, we will have to divide that by 4 so that when the compiler multiplies it by 4 it will be right.
x = x + 8/4
Now x is 108.

The whole thing will be optimised out by the compiler anyway.
BCM2835_GPFSEL0 is 32 bit offset (not 8 bit offset) as defined in .h

#define BCM2835_GPFSEL0 0x0000

#define BCM2835_GPFSEL1 0x0004 ///< GPIO Function Select 1

those are 32 bits offset.

User avatar
joan
Posts: 15372
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Broadcom chipset C code

Sat Dec 21, 2013 9:02 am

The code is using a pointer to a 32 bit object to access a byte address. The code is highlighting that you need to divide byte addresses by 4 when accessing them through a 32 bit object. It's highlighting C's pointer arithmetic.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Broadcom chipset C code

Sat Dec 21, 2013 11:14 am

lilzz wrote: BCM2835_GPFSEL0 is 32 bit offset (not 8 bit offset) as defined in .h

#define BCM2835_GPFSEL0 0x0000

#define BCM2835_GPFSEL1 0x0004 ///< GPIO Function Select 1

those are 32 bits offset.
It's an offset of 32-bits, yes, but that's not what I meant.
It's an offset that is counted in bytes, groups of 8-bits. The second #define indicates that GPFSEL1 is 4 bytes beyond GPFSEL0.
Because paddr and gpio are uint32_t pointers they need an offset that is counted in uint32_t's, groups of 32-bits. GPFSEL1 is 1 uint32_t beyond GPFSEL0.

That's a feature of the C language.

Return to “Advanced users”