ARM: Using bit-banded memory from C or C++ - c

ARM Cortex supports bit-banded memory, where individual bits are mapped to "bytes" in certain regions. I believe that only certain parts of RAM are bit-banded. I'd like to use bit-banding from C and C++.
How do I this? It seems I'd need to:
Tell the compiler to place certain variables in bit-banded regions. How? What if the variables are elements of a struct?
Tell the compiler, when I want to access a bit, to turn if (flags & 0x4) into if (flags_bb_04). Ideally, I'd like this to be automatic, and to fall back to the former if bit banding isn't available.

The simplest solution is to use regular variables and access them through thier bit-band address. For that you do not need to "tell the compiler" anything. For example, given:
extern "C" volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
volatile uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000;
uint32_t bit_band_base = word_band_base | 0x02000000;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<volatile uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
you could create a 32bit "array" thus:
uint32_t word = 0 ;
uint32_t* bits = getBitbandAddress( word, 0 ) ;
bits[5] = 1 ; // word now == 32 (bit 5 set).
Now if you have a part with external or CCM memory for example that is not bitbandable, you do need to ensure that the linker ( not the compiler) places the normal memory object in bitbandable memory. How that is done is toolchain specific but in gnu for example you might have:
uint32_t word __attribute__ ((section ("ISRAM1"))) = 0 ;
Bitbanding is perhaps most useful for atomically accessing individual bits in peripheral registers. For fast and thread-safe access.
Some compilers are bitband aware and may automatically optimise single bit bitfield access using bitbanding. So for example;
struct
{
bit1 : 1 ;
bit2 : 1 ;
} bits __attribute__ ((section ("BITBANDABLE")));
The compiler (at least armcc v5) may optimise this to utilise the bitband access to bits.bit1 and bits.bit2. YMMV.

Related

Access data on sfr P1 using raw pointer

My Environment
IDE : Keil
Processor : AT89C4051 (Simulation Mode)
I'm trying to work with P1 register (address 0x90 specified by datasheet) by setting its value to all 0 (RESET state) and setting some specific pin to be 1 (SET state). I try this code
int main() {
*((unsigned char*)0x90) = 0;
while(1) {
*((unsigned char*)0x90) = 0xE0;
}
}
But nothing change.
When I use this example every work flawlessly
sfr P1 = 0x90;
int main()
{
P1 = 0;
P1 = 0xE0;
while(1);
}
My question is, what make the different between these code since it's all pointing at address 0x90 using sfr and unsigned char pointer.
You can't access SFRs of the 8051 series microcontroller by indirect accesses.
On devices with more than 128 bytes internal RAM, the I/O addresses 0x80 to 0xFF are used for both the SFRs and the upper half of the internal RAM:
SFRs are accessed by direct addressing only.
The internal RAM is accessed by indirect addressing only.
EDIT:
Source: Right on the product summary page there is the 8051 instruction set that documents this on the very first page.

TSS entries for stack switching

I have read that the TSS contains information about registers, etc. Right now, I am trying to implement the switch from kernel to user mode and back. I have read the the Intel 80386 manual, and was looking at this resource: http://www.brokenthorn.com/Resources/OSDev23.html for a general workflow. They do this:
void install_tss (uint32_t idx, uint16_t kernelSS, uint16_t kernelESP) {
//! install TSS descriptor
uint32_t base = (uint32_t) &TSS;
gdt_set_descriptor (idx, base, base + sizeof (tss_entry),
I86_GDT_DESC_ACCESS|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_DPL|I86_GDT_DESC_MEMORY,
0);
//! initialize TSS
memset ((void*) &TSS, 0, sizeof (tss_entry));
TSS.ss0 = kernelSS;
TSS.esp0 = kernelESP;
TSS.cs=0x0b;
TSS.ss = 0x13;
TSS.es = 0x13;
TSS.ds = 0x13;
TSS.fs = 0x13;
TSS.gs = 0x13;
//! flush tss
flush_tss (idx * sizeof (gdt_descriptor));
}
I am confused as to why RPL = 3
In my case, when I am in user mode and I want to use a trap gate to get to kernel mode, the cs segment in the trap gate would have RPL 0 (the last 2 bits of the 16 bit segment) and the GDT entry corresponding to the cs segment would also have DPL 0. And I've read that an inter-level privilege switch switches stacks (only??) looking at the TSS. I'm guessing that the above piece of code must have a TSS.ss = 0x10.
Note: We're assuming the classic 0x08 = Kernel code, 0x10 = Kernel data, .... GDT structure here
The TSS structure has a lot of fields that are used for hardware task switching (e.g. TSS.ss, which is where the ss register's contents would be saved/loaded if a hardware task switch happened), plus a few fields that are used for switching the task to a higher privilege level ((e.g. (e.g.TSS.ss0` for switching to CPL=0).
You're looking at fields that are used for hardware task switching (which typically aren't worth bothering with because it's faster to do software task switching instead); and I'd guess someone shoved some "hardware task switch compatible" values in there (even though they're not used) to avoid uninitialized values.
Instead, you want to look at the TSS.esp0 and TSS.ss0 fields of the TSS, which are the only 2 fields of the TSS that matter for switching to CPL=0 (and might be the only 2 fields of the TSS you ever use).

How to create bitfield out of existing variables in C

I am working on a Motorola HCS08 µCU in CodeWarrior V10.6, I am trying to create an extern bitfield which has bits from existing registers. The way the bitfields are created in the µCU header is like
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 :1;
byte PTAD1 :1;
byte PTAD2 :1;
byte PTAD3 :1;
byte PTAD4 :1;
byte PTAD5 :1;
byte PTAD6 :1;
byte PTAD7 :1;
} Bits;
} PTADSTR;
extern volatile PTADSTR _PTAD #0x00000000;
#define PTAD _PTAD.Byte
#define PTAD_PTAD0 _PTAD.Bits.PTAD0
#define PTAD_PTAD1 _PTAD.Bits.PTAD1
#define PTAD_PTAD2 _PTAD.Bits.PTAD2
#define PTAD_PTAD3 _PTAD.Bits.PTAD3
#define PTAD_PTAD4 _PTAD.Bits.PTAD4
#define PTAD_PTAD5 _PTAD.Bits.PTAD5
#define PTAD_PTAD6 _PTAD.Bits.PTAD6
#define PTAD_PTAD7 _PTAD.Bits.PTAD7
Which will let the register value be changed either by PTAD = 0x01, or PTAD_PTAD0 = 1, for example. This definition is basically the same for PTAD, PTBD, PTCD, ... PTGD, the only thing changing is the address.
My attemp to create a custom bitfield out of the previous existing variables is
typedef union {
byte Byte;
struct {
byte *DB0;
byte *DB1;
byte *DB2;
byte *DB3;
byte *DB4;
byte *DB5;
byte *DB6;
byte *DB7;
} Bits;
} LCDDSTR;
I would create and initialize the bitfield as LCDDSTR lcd = {{&PTGD_PTGD6, &PTBD_PTBD5, ...}}, because by some reason, the initialization like LCDSTR lcd = {*.Bits.DB0 = &PTGD_PTGD6, *.Bits.DB1 = &PTBD_PTBD5, ...} (treating it as a struct, please correct me again) advice in How to initialize a struct in accordance with C programming language standards does not work with this compiler (it does work on an online compiler).
However, as you may see I am sort of grouping the bits, and (if it would work) I would be able to change the values of the actual register by doing *lcd.Bits.DB0 = 1, or something like that, but if I do lcd.Byte = 0x00, I would be changing the last (I think) byte of the memory address contained in lcd.Bits.DB0, you know, because the struct doesn't actually contains the data, but the pointers instead.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other, which I guess would make it easier). Is it even possible? I hope it is.
How would I go on achieving a struct that is able to contain and modify bits from several registers? (I guess the problem here is that in memory the bits are not one next to the other..
I don't think you can do it with a struct. That is because bitfields by definition have to occupy the same or contiguous addresses.
However macros may be useful here
#define DB0 PTGD_PTGD6
#define DB1 PTBD_PTBD5
....
And to clear the bits to all 0's or set to all 1's you can use a multiline macro
#define SET_DB(x) do { \
PTGD_PTGD6 = x; \
PTBD_PTBD5 = x; \
...... \
} while(0)
How would I go on achieving a struct that is able to contain and modify bits from several registers?
You can't.
A structure must represent a single, continuous block of memory -- otherwise, operations like taking the sizeof the structure, or performing operations on a pointer to one would make no sense.
If you want to permute the bits of a value, you will need to find some way of doing so explicitly. If the order of your bits is relatively simple, this may be possible with a few bitwise operations; if it's weirder, you may need to use a lookup table.
Beyond that: bitfields in C are pretty limited. The language does not make a lot of guarantees about how a structure containing bitfields will end up laid out in memory; they are generally best avoided for portable code. (Which doesn't apply here, as you're writing code for a specific compiler/microcontroller combination, but it's worth keeping in mind in general.)
Your union does unfortunately not make any sense, because it forms a union of one byte and 8 byte*. Since a pointer is 16 bit on HCS08, this ends up as 8*2 = 16 bytes of data, which can't be used in any meaningful way.
Please note that the C structure called bit-fields is very poorly specified by the standard and therefore should be avoided in any program. See this.
Please note that the Codewarrior register maps aren't remotely close to following the C standard (nor MISRA-C).
Please note that structs in general are problematic for hardware register mapping, since structs can contain padding. You don't have that problem on HCS08 specifically, since it doesn't require alignment of data. But most MCUs do require that.
It is therefore better to roll out your own register map in standard C if you have that option. The port A data register could simply be defined like this:
#define PTAD (*(volatile uint8_t*)0x0000U)
#define PTAD7 (1U << 7)
#define PTAD6 (1U << 6)
#define PTAD5 (1U << 5)
#define PTAD4 (1U << 4)
#define PTAD3 (1U << 3)
#define PTAD2 (1U << 2)
#define PTAD1 (1U << 1)
#define PTAD0 (1U << 0)
As we can tell, defining the bit masks is mostly superfluous anyway, as PTAD |= 1 << 7; is equally readable to PTAD |= PTAD7;. This is because this was a pure I/O port. Defining textual bit masks for status and control registers on the other hand, increases the readability of the code significantly.
If you want to modify bits from several registers, you'd do something like the following:
Assume we have a RGB (red-green-blue) LED, common cathode, with 3 colors connected to 3 different pins on 3 different ports. Instead of beating up the PCB designer, you could do this:
#define RGB_RED_PTD PTAD
#define RGB_RED_PTDD PTADD
...
#define RGB_BLUE_PTD PTBD
#define RGB_BLUE_PTDD PTBDD
...
#define RGB_GREEN_PTD PTDD
#define RGB_GREEN PTDD PTDDD
#define RGB_RED_PIN 1
#define RGB_BLUE_PIN 5
#define RGB_GREEN_PIN 3
You can now set these independently of where they happen to be located on the hardware:
void rgb_init (void)
{
RGB_RED_PTDD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTDD |= (1 << RGB_BLUE_PIN);
RGB_GREEN_PTDD |= (1 << RGB_GREEN_PIN);
}
void rgb_yellow (void)
{
RGB_RED_PTD |= (1 << RGB_RED_PIN);
RGB_BLUE_PTD &= ~(1 << RGB_BLUE_PIN);
RGB_GREEN_PTD |= (1 << RGB_GREEN_PIN);
}
And so on. Examples were for HCS08 but the same can of course be used universally on any MCU with direct port I/O.
It sounds like an approach such as the following is along the lines of where you would like to go with a solution.
I have not tested this as I do not have the hardware however this should provide an alternative to look at.
This assumes that you want to turn on particular pins or turn off particular pins but there will not be a case where you will want to turn on some pins and turn off other pins for a particular device in a single operation. If that should be the case I would consider making the type of RegPinNo be an unsigned short to include an op code for each register/pin number combination.
This also assumes that timing of operations is not a critical constraint and that the hardware has sufficient horsepower such that small loops are not much of a burden on throughput and hogging CPU time needed for other things. So this code may need changes to improve optimization if that is a consideration.
I assume that you want some kind of a easily readable way of expressing a command that will turn on and off a series of bits scattered across several areas of memory.
The first thing is to come up with a representation of what such a command would look like and it seems to me that borrowing from a char array to represent a string would suffice.
typedef byte RegPinNo; // upper nibble indicates register number 0 - 7, lower nibble indicates pin number 0 - 7
const byte REGPINNOEOS = 0xff; // the end of string for a RegPinNo array.
And these would be used to define an array of register/pin numbers as in the following.
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
So at this point we have a way to describe that a particular device, an LED in this case, is addressed through a series of register/pin number items.
Next lets create a small library of functions that will use this representation to actually modify the specific pins in specific registers by traversing this array of register/pin numbers and performing an operation on it such as setting the bit in the register or clearing the bit in the register.
typedef unsigned char byte;
typedef union {
byte Byte;
struct {
byte PTAD0 : 1;
byte PTAD1 : 1;
byte PTAD2 : 1;
byte PTAD3 : 1;
byte PTAD4 : 1;
byte PTAD5 : 1;
byte PTAD6 : 1;
byte PTAD7 : 1;
} Bits;
} PTADSTR;
// Define a pointer to the beginning of the register area. This area is composed of
// 8 different registers each of which is one byte in size.
// We will address these registers as Register 0, Register 1, ... Register 7 which just happens
// to be how C does its zero based indexing.
// The bits representing pins on the PCB we will address as Pin 0, Pin 1, ... Pin 7.
extern volatile PTADSTR (* const _PTAD) = 0x00000000;
void SetRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte |= pins[bPinNo];
}
}
void ClearRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte &= ~pins[bPinNo];
}
}
void ToggleRegPins(RegPinNo *x)
{
byte pins[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 4) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0x07; // get the pin number, 0 - 7
_PTAD[bRegNo].Byte ^= pins[bPinNo];
}
}
You would use the above something like the following. Not sure what a time delay function would look like in your environment so I am using a function Sleep() which takes an argument as to the number of milliseconds to delay or sleep.
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x01, 0x12, REGPINNOEOS }; // LED is addressed through Register 0, Pin 0 and Register 1, Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}
Edit - A Refinement
A more efficient implementation that would allow multiple pins to be set in a particular register at the same time would be to define the use of RegPinNo as being an unsigned short` with the upper byte being the register number and the lower byte being the pins to manipulate as a bit mask for the byte.
With this approach you would have a SetRegPins() function that would look like the following. A similar change would be needed for the other functions.
void SetRegPins(RegPinNo *x)
{
int i;
for (i = 0; x[i] != REGPINNOEOS; i++) {
byte bRegNo = (x[i] >> 8) & 0x07; // get the register number, 0 - 7
byte bPinNo = x[i] & 0xFF; // get the pin mask
_PTAD[bRegNo].Byte |= bPinNo;
}
}
And the typedefs would look like:
typedef unsigned short RegPinNo; // upper byte indicates register number 0 - 7, lower byte provides pin mask
const byte REGPINNOEOS = 0xffff; // the end of string for a RegPinNo array.
And these elements would be used like:
void LightLed (int nMilliSeconds)
{
RegPinNo myLed[] = { 0x0002, 0x0103, REGPINNOEOS }; // LED is addressed through Register 0, Pin 1 and Register 1, Pin 0 and Pin 1 (zero based)
SetRegPins(myLed); // turn on the LED
Sleep(nMilliSeconds); // delay for a time with the LED lit
ClearRegPins(myLed); // turn the LED back off
}

Addressing registers in microcontrollers

Usually we address registers in microcontrollers in form of
#define REG_1 *((uword volatile far *)(0xBEEFFF))
REG_1 = 0x12345678;
I have four similar channels (e.g. UART channels) with equal sets of registers, but they all have different addresses.
I would like to be able to find address of any register of any channel in a compact way.
Question: is it possible to apply something like this:
#define CHANNEL_0_offset 0xBEEF00
#define CHANNEL_1_offset 0xFACE00
#define REG_1 0x0000AB
*((uword volatile far *)(CHANNEL_0_offset+REG_1)) = 0x12345678;
*((uword volatile far *)(CHANNEL_1_offset+REG_1)) = 0x87654321;
?????
Thank you

Embedded C: Registers Access

Suppose we want to write at address say 0xc000, we can define a macro in C as:
#define LCDCW1_ADDR 0xc000
#define READ_LCDCW1() (*(volatile uint32_t *)LCDCW1_ADDR)
#define WRITE_LCDCW1(val) ((*(volatile uint32_t *)LCDCW1_ADDR) = (val))
My question is that when using any micro-controller, consider an example MSP430, P1OUT register address is 0x0021.
But when we use P1OUT=0xFFFF; // it assigns P1OUT a value 0xFFFF.
My question is how does it write to that address e.g. in this case 0x0021.
The IDE is IAR. I found in header msp430g2553.h below definition:
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
I suppose it is defining the address, but where are the other macros to write or read.
Could anyone please explain the flow that how P1OUT writes at that particular address location? Also do let me know what does u mean in 0x0021u ?
Thanks
So far the details I have found are :
in msp430g2553.h
#ifdef __IAR_SYSTEMS_ICC__
#include "in430.h"
#pragma language=extended
#define DEFC(name, address) __no_init volatile unsigned char name # address;
#define DEFW(name, address) __no_init volatile unsigned short name # address;
#define DEFXC volatile unsigned char
#define DEFXW volatile unsigned short
#endif /* __IAR_SYSTEMS_ICC__ */
#ifdef __IAR_SYSTEMS_ASM__
#define DEFC(name, address) sfrb name = address;
#define DEFW(name, address) sfrw name = address;
#endif /* __IAR_SYSTEMS_ASM__*/
#define P1OUT_ (0x0021u) /* Port 1 Output */
DEFC( P1OUT , P1OUT_)
The io430g2553.h says
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
Can some one explain what the above definition does? The details I found in MSP430 IAR C/C++ Compiler:
Example of using __write and __read
The code in the following examples use memory-mapped I/O to write to an LCD
display:
__no_init volatile unsigned char LCD_IO # address;
size_t __write(int Handle, const unsigned char * Buf,
size_t Bufsize)
{
size_t nChars = 0;
/* Check for stdout and stderr
(only necessary if file descriptors are enabled.) */
if (Handle != 1 && Handle != 2)
{
return -1;
}
for (/*Empty */; Bufsize > 0; --Bufsize)
{
LCD_IO = * Buf++;
++nChars;
}
return nChars;
}
The code in the following example uses memory-mapped I/O to read from a keyboard:
__no_init volatile unsigned char KB_IO # 0xD2;
size_t __read(int Handle, unsigned char *Buf, size_t BufSize)
{
size_t nChars = 0;
/* Check for stdin
(only necessary if FILE descriptors are enabled) */
if (Handle != 0)
{
return -1;
}
for (/*Empty*/; BufSize > 0; --BufSize)
{
unsigned char c = KB_IO;
if (c == 0)
break;
*Buf++ = c;
++nChars;
}
return nChars;
}
Does any one know?
This is "how does the compiler generate the code from what I've written", and only the compiler writers will actually be able to answer that for you.
Clearly, there are several non standard C components in the code above __no_init, the use of #, etc. In my reading of this, it tells the compiler that "this is a HW port, that provides an unsigned char, and it's address is 0xd2". The compiler will produce the right kind of instructions to read and write such a port - exactly how that works depends on the compiler, the processor that the compiler is producing code for, etc.
The P10out structure defines bitfields, which is part of the C standard. Google is your friend here.
Indirection operator (unary *) returns l-value equivalent to the value at pointer address.
#define LCDCW1_ADDR 0xc000
void f()
{
uint32_t a = *(volatile uint32_t *)LCDCW1_ADDR; //reading from LCDCW1_ADDR
*(volatile uint32_t *)LCDCW1_ADDR = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
Basically, compiler is smart enough to see, that a = *addr; expression means "read value from addr address and put it to a. At the same time *addr = 0xffff will be interpreted like "put 0xffff to addr address"
In your case you can use your READ_LCDCW1() macro both on left and right hand side of assignment operator. There is no need for separate WRITE_LCDCW1(val) macro. We can rewrite the previous code as:
#define LCDCW1_ADDR 0xc000
#define LCDCW1 (*(volatile uint32_t *)LCDCW1_ADDR)
void g()
{
uint32_t a = LCDCW1; //reading from LCDCW1_ADDR
LCDCW1 = 0xffff; //writing to LCDCW1_ADDR
/*...*/
}
P1OUT macro from IAR is most probably defined the same way as LCDCW1 above (if you follow the DEFC() definition you will eventually find something like it).
My question is that when using any micro-controller, consider an
example MSP430
You're not using any micro-controller, you are using an MSP430. It has memory-mapped IO (which is really nice to use for us programmers). The memory mapping will vary based on device. The answers to any of the address related questions lie within your specific device's User's Guide. TI makes very good User Guide's. Find the one for your specific device and read it thoroughly.
My question is how does it write to that address e.g. in this case
0x0021. The IDE is IAR.
Compiler glue code. Your compiler vendor will supply you with the necessary headers, macros and functions to write to your device addresses. Use the compiler vendor's code unless you can absolutely prove that it is not working for your case (with IAR I would assume that 99.9% it works, you get what you pay for. Possibly with a brand new device there are bugs in the implementation, but probably not unless you can prove it).
Also do let me know what does u mean in 0x0021u ?
From what you've posted, that is the base address for port 1. It looks like you have 8 pins on port 1 you can control.
#pragma language=extended
From this point on you must assume that there are all sorts of "magical" (aka non-standard C) things that will be happening. You can infer what you think the compiler is doing (and for the most part it is reasonably clear), however this is implementation defined, meaning only IAR compiler supports what will happen next. Look at the compiler docs for specific commands and meanings. Most notably the __no_init and the # symbol are non-standard. The __no_init will not initialize the variable at C startup (i.e. before main() runs). The # looks like an absolute address instruction that will be given to the linker (I may be wrong here).
__no_init volatile union
{
unsigned char P1OUT; /* Port 1 Output */
struct
{
unsigned char P0 : 1; /* */
unsigned char P1 : 1; /* */
unsigned char P2 : 1; /* */
unsigned char P3 : 1; /* */
unsigned char P4 : 1; /* */
unsigned char P5 : 1; /* */
unsigned char P6 : 1; /* */
unsigned char P7 : 1; /* */
}P1OUT_bit;
} #0x0021;
This defines a way to get at specific bits of the byte for port 1. This lets you manipulate the IO pins. Some would say OMG bitfields are portable, the are implementation defined! Yes, they are right, but IAR is the implementor, so in this case just trust them to do the right thing.
Final note, you probably just want to use the IAR macros as defined. You paid a lot of money for them (unless you are using the free kickstart edition). You can concentrate on writing your app and not manipulating bits this way. IAR does do a good job of standardizing their names, so you can also use the same code (or very similar) on related parts. If you switch to a different compiler all this goes out the window and you'll have to do it the way of the new compiler. Good and bad points to this approach, probably no "right" answer.

Resources