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: */