1
\$\begingroup\$

I'm going to take a random 8-bit Microchip microcontroller: PIC16F887.

Let's have a look at how the XC8 compiler (and the HI-TECH PICC, for that matter) is defining a register (SFR) and its coresponding bits in the header file of the device (/opt/microchip/xc8/v1.31/include/pic16f887.h):

extern volatile unsigned char           PORTB               @ 0x006;

So PORTB SFR is defined as an 8-bit volatile variable with the absolute address 0x006, as per the datasheet.

I'm having problems understanding the definition of a single bit (bit 1, for example) corresponding to PORTB:

extern volatile __bit                   RB1                 @ (((unsigned) &PORTB)*8) + 1;

Why do they multiply the PORTB address by 8?

EDIT:

I also looked for an explanation in the compiler's manual and found pretty much the same answers that Spehro gave me. I should have consulted the manual before asking here:

When defining absolute bit variables (see Section 5.4.2.1 “Bit Data Types and Variables”), the address specified must be a bit address. A bit address is obtained by mul- tiplying the desired byte address by 8, then adding the bit offset within that bit.

So, for example, to place a bit variable called mode at bit position #2 at byte address 0x50, use the following: bit mode @ 0x282; If you wish to place a bit variable over an existing object (typically this will be an SFR variable or another absolute variable) then you can use the symbol of that object, as in the following example which places flag at bit position #3 in the char variable MOT_STATUS:

bit flag @ ((unsigned) &MOT_STATUS)*8 + 3;

\$\endgroup\$
  • \$\begingroup\$ In this .h, it is completely different: ecse.rpi.edu/courses/CStudio/SDCC%20Compiler/sdcc-src-2.8.0/… \$\endgroup\$ – Swanand Jul 29 '14 at 11:23
  • \$\begingroup\$ @Swanand Yeah, they use unions and structs to define the register's bits. The Microchip compilers do that as well, besides the definitions I mentioned.. \$\endgroup\$ – m.Alin Jul 29 '14 at 11:29
2
\$\begingroup\$

Bit addressing uses the lower 3 bits of the address to point to the bit within a byte.

So the bit is number (RB1 & 0x07) or 1 in your example, the byte address is (RB1 >> 3), or 0x06 in your example.

\$\endgroup\$
  • \$\begingroup\$ I don't think I understand your explanation. Take the expression from the bit definition: @ (((unsigned) &PORTB)*8) + 1; Let's evaluate this expression: &PORTB = 0x06. 0x06 * 8 = 0x30 (0b00110000). 0x30 + 1 = 0x31 (0b00110001). How is 0x31 the address of bit 1 of PORTB? \$\endgroup\$ – m.Alin Jul 29 '14 at 8:42
  • 1
    \$\begingroup\$ The compiler knows what type if object (bit) the address points to, and treats it differently from a byte address. Try looking at the emitted machine code for very simple bit set/clear statements. \$\endgroup\$ – Spehro Pefhany Jul 29 '14 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.