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