1: // A class for bit-field access to ASIC registers. 3: /************************************************************************* 4: * 5: * FILE: bitfld.h 6: * 7: * AUTHORS: R. J. Brown <rj3@gvmail.ih.lucent.com> <rj@eli.wariat.org> 8: * 9: * CONTENTS: bitfld.h defines a class to specify bit-field accesses 10: * to registers in an ASIC. 11: * 12: * CONSTRAINTS: none 13: * 14: * REFERENCES: none 15: * 16: ************************************************************************* 17: */ 19: #ifndef BITFLD__H // guard against multiple includes... 20: #define BITFLD__H 22: #include "fwtypes.h" // common definitions 23: #include "assert.h" // for assert() macro 25: #include "memreadwrite.h" // memory access routines 29: /* 30: ================================================================ 32: THIS IS THE DECLARATION OF THE BITFLD CLASS. 34: Instances of this template class represent bitfields in memory mapped 35: I/O device registers. Each field is governed by 3 parameters: a byte 36: offset from the beginning of ASIC's memory mapped address space, a mask 37: to identify the bits in the register that belong to this bitfield, and a 38: shift count that is used to normalize the field. 40: The bitfields defined by this class may be used just like ordinary 41: variables. When used in an expression, the name of the field fetches 42: the normalized value of the field. When used as the target of an 43: assignment, the RHS is denormalized and stored in the field. 45: Subscripting is suported by creating a reference to a temporary object 46: with a modified offset so that an array of identical ASIC registers only 47: requires a permanent object for the first element in the array. 49: ---------------------------------------------------------------- 50: */ 52: template <class WIDTH> class BITFLD { 55: public: // -- M E M B E R F U N C T I O N S -- 58: BITFLD(); // default CONSTRUCTOR 61: // initializing CONSTRUCTOR 62: BITFLD(volatile WIDTH* addr, // address of register 63: WIDTH mask, // bitmask of field 64: char count); // normalizing shift count for field 67: // NOTE: There is no COPY CONSTRUCTOR! 69: /* Because assignment of a BITFLD object to another BITFLD object is 70: intended to copy the value of the bit field in one ASIC register to 71: another bit field in another ASIC register, a copy constructor is 72: explicitly not provided. If a copy constructor were to be provided, 73: then such a BITFLD to BITFLD assignment would copy the BITFLD object 74: instead of the bits of data in the ASIC register. */ 77: ~BITFLD(); // DESTRUCTOR 80: void // CONFIGURATOR 81: configure(volatile WIDTH* addr, // address of register 82: WIDTH mask, // bitmask of field 83: char count); // normalizing shift count for field 86: void 87: unconfigure(void); // UN-CONFIGURATOR 90: operator WIDTH(); // CONVERSION to WIDTH 93: BITFLD<WIDTH>& 94: operator=(volatile WIDTH src); // ASSIGNMENT operator 97: BITFLD<WIDTH> 98: operator[](int subscript); // SUBSCRIPT operator 100: void // clear bits in field 101: clear_bits(WIDTH bits); // by writing ones as specified 104: // ---------------------------------------------------------------- 107: private: // -- I N S T A N C E V A R I A B L E S -- 110: volatile WIDTH* reg_addr; // address of ASIC register 111: WIDTH field_mask; // mask to extract field 112: signed char shift_count; // to normalize the field 114: enum { 115: INVALID = -1 // invalid indicator 116: }; 119: }; 122: /* 123: ================================================================ 125: THESE ARE THE BODIES FOR THE MEMBER FUNCTIONS DECLARED ABOVE. 127: NOTE: 129: This code needed to be modified for use with the Eagle CPU simulation 130: system. The problem is that memory accesses are variable width, 131: depending on the template parameter WIDTH. This complicates the use 132: of the Eagle system because it requires that each memory read or write 133: be identified by the width of the access. The solution is to use the 134: new subroutines: 136: void memread(char* value, 137: volatile char* address, 138: size_t width); 140: and 142: void memwrite(char* value, 143: volatile char* address, 144: size_t width); 146: These routines exist in 2 versions: a real platform targetable 147: version, and an Eagle CPU simulator targetable. The real platform 148: targetable version will actually do memory operations to or from the 149: specified addresses. The Eagle version will make the correct Eagle 150: simulator memory access calls. Which version you get is determined by 151: whether the compiler time symbol EAGLE is defined or not. 153: ---------------------------------------------------------------- */ 155: // Shift count must be non-negative and less than register size. 156: #define valid_shift_count(n) (((n) >= 0) && ((n) < sizeof(WIDTH)*8)) 158: // Address must be properly aligned. 159: #define valid_reg_addr(a) (((sizeof(WIDTH) - 1) & (LWORD)(a)) == 0) 162: /************************************************************************* 163: * 164: * FUNCTION: BITFLD 165: * 166: * DESCRIPTION: default CONSTRUCTOR 167: * 168: * ENTRY: void 169: * 170: * EXIT: void 171: * 172: * SIDE EFFECTS: A BITFLD object is constructed initialized to INVALID 173: * 174: * CONSTRAINTS: An exception occurs if sufficient memory is not available 175: * to construct the object. 176: * 177: ************************************************************************* 178: */ 179: template <class WIDTH> inline 180: BITFLD<WIDTH>::BITFLD() 181: : reg_addr((WIDTH*)NULL), // initialize as INVALID 182: field_mask((WIDTH)0), 183: shift_count(INVALID) { 184: 185: /* do nothing */ 186: } 189: /************************************************************************* 190: * 191: * FUNCTION: BITFLD 192: * 193: * DESCRIPTION: initializing CONSTRUCTOR 194: * 195: * ENTRY: initial values for addr, mask, and count 196: * 197: * EXIT: void 198: * 199: * SIDE EFFECTS: A BITFLD object is constructed initialized as requested 200: * 201: * CONSTRAINTS: An exception occurs if sufficient memory is not available 202: * to construct the object. 203: * 204: ************************************************************************* 205: */ 206: template <class WIDTH> inline 207: BITFLD<WIDTH>::BITFLD(volatile WIDTH* addr, // address of register 208: WIDTH mask, // bitmask of field 209: char count) { // normalizing shift count for field 211: assert(valid_shift_count(count)); // shift count OK? 212: assert(valid_reg_addr(addr)); // register address OK? 214: reg_addr = addr; // establish field access parameters 215: field_mask = mask; 216: shift_count = count; 218: } 221: /************************************************************************* 222: * 223: * FUNCTION: ~BITFLD 224: * 225: * DESCRIPTION: default DESTRUCTOR 226: * 227: * ENTRY: void 228: * 229: * EXIT: void 230: * 231: * SIDE EFFECTS: The requested BITFLD object is destroyed. 232: * 233: * CONSTRAINTS: none 234: * 235: ************************************************************************* 236: */ 237: template <class WIDTH> inline // default DESTRUCTOR 238: BITFLD<WIDTH>::~BITFLD() { 240: /* do nothing */ 242: } 245: /************************************************************************* 246: * 247: * FUNCTION: configure 248: * 249: * DESCRIPTION: Configures a BITFLD object by initializing its member 250: * variables as requested 251: * 252: * ENTRY: initial values for addr, mask, and count 253: * 254: * EXIT: void 255: * 256: * SIDE EFFECTS: the BITFLD object's local state is altered 257: * 258: * CONSTRAINTS: none 259: * 260: ************************************************************************* 261: */ 262: template <class WIDTH> inline void // CONFIGURATOR 263: BITFLD<WIDTH>::configure(volatile WIDTH* addr, // address of register 264: WIDTH mask, // bitmask of field 265: char count) { // normalizing shift count for field 267: assert(valid_shift_count(count)); // shift count OK? 268: assert(valid_reg_addr(addr)); // register address OK? 270: reg_addr = addr; // establish field access parameters 271: field_mask = mask; 272: shift_count = count; 273: } 276: /************************************************************************* 277: * 278: * FUNCTION: unconfigure 279: * 280: * DESCRIPTION: Configures a BITFLD object by initializing its member 281: * variables to INVALID 282: * 283: * ENTRY: void 284: * 285: * EXIT: void 286: * 287: * SIDE EFFECTS: the BITFLD object's local state is altered 288: * 289: * CONSTRAINTS: none 290: * 291: ************************************************************************* 292: */ 293: template <class WIDTH> inline void 294: BITFLD<WIDTH>::unconfigure(void) { 295: 296: reg_addr = (WIDTH*)NULL; // initialize as INVALID 297: field_mask = (WIDTH)0; 298: shift_count = INVALID; 299: } 302: /************************************************************************* 303: * 304: * FUNCTION: operator WIDTH 305: * 306: * DESCRIPTION: permits conversion from BITFLD<WIDTH> to WIDTH 307: * 308: * ENTRY: implicit 309: * 310: * EXIT: implicit 311: * 312: * SIDE EFFECTS: none 313: * 314: * CONSTRAINTS: called implicitly by the compiled code to handle type 315: * conversions implied by refering to a BITFLD object as 316: * though it were of type WIDTH, which maybe any of the 317: * types BYTE, WORD, or LWORD. This function permits 318: * a BITFLD object to be referred to in an expression and 319: * have it return the value of the contents of the 320: * bit field described by the addr, mask, and count 321: * member variables of the BITFLD object. An assertion is 322: * raised if the BITFLD object is configured as INVALID. 323: * 324: ************************************************************************* 325: */ 326: template <class WIDTH> inline 327: BITFLD<WIDTH>::operator WIDTH() { 328: WIDTH value; 329: 330: assert(shift_count != INVALID); // insure validity 331: 332: memread((char*)&value, 333: (char*)reg_addr, 334: sizeof(WIDTH)); 335: 336: return ((value & field_mask) 337: >> shift_count); // extract field value 338: } 341: /************************************************************************* 342: * 343: * FUNCTION: operator= 344: * 345: * DESCRIPTION: ASSIGNMENT operator 346: * 347: * ENTRY: implicit 348: * 349: * EXIT: implicit 350: * 351: * SIDE EFFECTS: the lvalue of the assignment is modified 352: * 353: * CONSTRAINTS: called implicitly by the compiled code to handle 354: * assignment to a BITFLD object. This function permits 355: * assignment of integer types to be made to BITFLD 356: * objects to result in the bit field described by the 357: * addr, mask, and count member variables of the BITFLD 358: * object being modified. An assertion is raised if the 359: * BITFLD object is configured as INVALID. 360: * 361: ************************************************************************* 362: */ 363: template <class WIDTH> inline BITFLD<WIDTH>& 364: BITFLD<WIDTH>::operator=(volatile WIDTH src) { 365: WIDTH value; 366: 367: assert(shift_count != INVALID); // insure validity 368: 369: memread((char*)&value, 370: (volatile char*)reg_addr, 371: sizeof(WIDTH)); // value in that reg 372: 373: value &= ~field_mask; // clear out the target field bits 374: value |= ((src << shift_count) 375: & field_mask); // merge in the new bits 376: 377: memwrite((char*)&value, 378: (volatile char*)reg_addr, 379: sizeof(WIDTH)); // put the result back 380: 381: return *this; // return lvalue of operator= 382: } 385: /************************************************************************* 386: * 387: * FUNCTION: operator[] 388: * 389: * DESCRIPTION: SUBSCRIPT operator 390: * 391: * ENTRY: implicit 392: * 393: * EXIT: implicit 394: * 395: * SIDE EFFECTS: a temporary BITFLD object is constructed 396: * 397: * CONSTRAINTS: called implicitly by the compiled code to handle 398: * subscripting of a BITFLD object. This function permits 399: * an implementation of arrays of registers containing 400: * BITFLD objects that do not require the replication of 401: * the addr, mask, and count member variables in every 402: * element of the array. This can result in enormous 403: * memory savings over the more straightforward 404: * implementation of making an array of BITFLD objects 405: * directly. 406: * 407: * Since this function creates a temporary BITFLD object, 408: * an exception is raised if sufficient memory does not 409: * exist to hold the new object. The normal C++ rules 410: * for the lifetime of temporary objects hold for the 411: * returned BITFLD object; therefore, it should normally 412: * only be used within the expression that invoked this 413: * function. 414: * 415: ************************************************************************* 416: */ 417: template <class WIDTH> inline BITFLD<WIDTH> 418: BITFLD<WIDTH>::operator[](int subscript) { 419: volatile WIDTH* new_addr = 420: (WIDTH*)((char*)reg_addr 421: + subscript*sizeof(WIDTH)); // new address 422: 423: return BITFLD<WIDTH>(new_addr, // return modified clone of object 424: field_mask, 425: shift_count); 426: } 429: /************************************************************************* 430: * 431: * FUNCTION: clear_bits(WIDTH) 432: * 433: * DESCRIPTION: clear specified bits in field by writing ones 434: * 435: * ENTRY: WIDTH bits -- the bits to clear, specified as ones 436: * 437: * EXIT: void 438: * 439: * SIDE EFFECTS: The specified bits in the field are cleared by 440: * writing ones to them. 441: * 442: * CONSTRAINTS: none 443: * 444: ************************************************************************* 445: */ 446: template <class WIDTH> inline void 447: clear_bits(WIDTH bits) { 448: WIDTH value; 450: printf("Shift_count=%d\n", shift_count); // OC12 tst 451: 452: assert(shift_count != INVALID); // insure validity 454: value = ((bits << shift_count) 455: & field_mask); // only clear bits in this field 457: memwrite((char*)&value, 458: (char*)reg_addr, 459: sizeof(WIDTH)); // write the one-bits to clear them 460: } 463: #endif /* BITFLD__H */ 465: /* (for emacs) 466: ;;; Local Variables: *** 467: ;;; mode: C++ *** 468: ;;; fill-column: 75 *** 469: ;;; comment-column: 40 *** 470: */