<< Click to Display Table of Contents >> Host Access of Bitfields and Bools |
The ETEC auto-defines file outputs all the necessary information for the host to be able to access bit-fields and _Bool variables. First, say the channel frame includes three _Bool variables:
static _Bool _b1, _b2, _b3;
The 'defines' auto-generated interface file would contain the following information for these variables:
// 8-bit Channel Variable address offsets
// address = ((CXCR.CPBA)<<3) + _CPBA8_Test__b1_
#define _CPBA8_Test__b1_ 0x00
#define _CPBA8_BOOLBITOFFSET__b1_ 0x07
#define _CPBA8_Test__b2_ 0x00
#define _CPBA8_BOOLBITOFFSET__b2_ 0x06
#define _CPBA8_Test__b3_ 0x00
#define _CPBA8_BOOLBITOFFSET__b3_ 0x05
_Bool variables in the channel frame get packed as bits into 8-bit locations. For each _Bool variable, there is a byte offset from the base of the channel frame, and a bit offset from the start of that byte. Host code to set and clear _Bool bits would then look something like:
char* CPBA;
// initialize CPBA...
// set _b1
*(CPBA + _CPBA8_Test__b1_) |= (0x80 >> _CPBA8_BOOLBITOFFSET__b1_);
// clear _b2
*(CPBA + _CPBA8_Test__b2_) &= ~(0x80 >> _CPBA8_BOOLBITOFFSET__b2_);
// extract _b3
int b3_val = ((*(CPBA + _CPBA8_Test__b3_) & (0x80 >> _CPBA8_BOOLBITOFFSET__b3_)) != 0)
Bit-field access is slightly more complicated. Given that bit-fields can be up to 24-bits in width, it is best to access them from the host via 32-bit accesses. For example, say on the eTPU side there is a variable declaration such as:
struct S1
{
unsigned int x : 4;
unsigned int y : 20;
};
struct S1 g_S1;
Then the 'defines' auto-generated file would contain the following information:
// defines for type struct S1
// size of a tag type
// value (sizeof) = _GLOB_TAG_TYPE_SIZE_S1_
#define _GLOB_TAG_TYPE_SIZE_S1_ 0x03
// offset of struct/union members from variable base location
// the offset of bitfields is specified in bits, otherwise it is bytes
// address = SPRAM + [variable SPRAM offset] + _GLOB_MEMBER_BITOFFSET_S1_x_
#define _GLOB_MEMBER_BITOFFSET_S1_x_ 0x14
#define _GLOB_MEMBER_BITSIZE_S1_x_ 0x04
#define _GLOB_MEMBER_BITOFFSET_S1_y_ 0x00
#define _GLOB_MEMBER_BITSIZE_S1_y_ 0x14
// Global Struct/Union Variable address
// address = SPRAM + _GLOB_STRUCT_g_S1_
#define _GLOB_STRUCT_g_S1_ 0x01
Given the above, the host can write to, and read from bit fields using code like the following:
uint32* SPRAM;
// initialize SPRAM...
#define _S1_X_WORD_OFFSET ((((_GLOB_STRUCT_g_S1_ & 3) * 8) + _GLOB_MEMBER_BITOFFSET_S1_x_) / 32) // word offset within structure
#define _S1_X_WORD_MSB_BITOFFSET ((((_GLOB_STRUCT_g_S1_ & 3) * 8) + _GLOB_MEMBER_BITOFFSET_S1_x_) - _S1_X_WORD_OFFSET*32)
#define _S1_X_WORD_LSB_BITOFFSET (32 - _S1_X_WORD_MSB_BITOFFSET - _GLOB_MEMBER_BITSIZE_S1_x_)
#define _S1_X_MASK (((1 << _GLOB_MEMBER_BITSIZE_S1_x_) ? 1) << S1_X_WORD_LSB_BITOFFSET)
// read g_S1.x
uint32 X = (*(SPRAM + (_GLOB_STRUCT_g_S1_ >> 2) + _S1_X_WORD_OFFSET) & _S1_X_MASK) >> _S1_X_WORD_LSB_BITOFFSET;
// write g_S1.x
// NOTE: this is not coherent!! Use CDC if coherency required!!
// clear bit-field first
*(SPRAM + (_GLOB_STRUCT_g_S1_ >> 2) + _S1_X_WORD_OFFSET) &= ~_S1_X_MASK;
// write in new value
*(SPRAM + (_GLOB_STRUCT_g_S1_ >> 2) + _S1_X_WORD_OFFSET) = (X << _S1_X_WORD_LSB_BITOFFSET) & _S1_X_MASK;