SCP: Updated REG macros and manipulation APIs

- Rewrote get_rval, put_rval to support fields within arrays of structures
- REG "size" field now determines access size
- REG "maxval" field now determines maximum allowed value

Merge from v3.12
This commit is contained in:
J. David Bryan 2022-06-24 15:39:45 -07:00 committed by Mark Pizzolato
parent 8bbec61483
commit 4dde5a69a4
2 changed files with 262 additions and 291 deletions

260
scp.c
View file

@ -24,6 +24,9 @@
in this Software without prior written authorization from Robert M Supnik.
21-Oct-21 RMS Fixed bug in byte deposits if aincr > 1
16-Feb-21 JDB Rewrote get_rval, put_rval to support arrays of structures
25-Jan-21 JDB REG "size" field now determines access size
REG "maxval" field now determines maximum allowed value
08-Mar-16 RMS Added shutdown flag for detach_all
20-Mar-12 MP Fixes to "SHOW <x> SHOW" commands
06-Jan-12 JDB Fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan)
@ -8710,7 +8713,7 @@ void *mbuf = NULL;
int32 j, blkcnt, limit, unitno, time, flg;
uint32 us, depth;
t_addr k, high, old_capac;
t_value val, mask;
t_value val, max;
t_stat r;
size_t sz;
t_bool v40, v35, v32;
@ -8979,10 +8982,13 @@ for ( ;; ) { /* device loop */
if (depth > rptr->depth)
depth = rptr->depth;
}
mask = width_mask[rptr->width]; /* get mask */
if (rptr->maxval > 0) /* if a maximum value is defined */
max = rptr->maxval; /* then use it */
else /* otherwise */
max = width_mask[rptr->width]; /* the mask defines the maximum value */
for (us = 0; us < depth; us++) { /* loop thru values */
READ_I (val); /* read value */
if (val > mask) { /* value ok? */
if (val > max) { /* value ok? */
sim_printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf);
}
else {
@ -9133,7 +9139,9 @@ if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */
else
new_pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */
if ((tptr == gbuf) || (*tptr != 0) || /* error? */
(new_pcv > width_mask[sim_PC->width]))
(new_pcv > ((sim_PC->maxval > 0)
? sim_PC->maxval
: (width_mask[sim_PC->width]))))
return SCPE_ARG;
new_pc = TRUE;
}
@ -9822,53 +9830,50 @@ return SCPE_OK;
idx = index
Outputs:
return = register value
Implementation notes:
1. The stride is the size of the element spacing for arrays, which is
equivalent to the addressing increment for array subscripting. For
scalar registers, the stride will be zero (as will the idx value), so the
access pointer is same as the specified location pointer.
2. The size of the t_value type is determined by the USE_INT64 symbol and
will be either a 32-bit or a 64-bit type. It represents the largest
value that can be returned and so is the default if one of the smaller
sizes is not indicated. If USE_INT64 is not defined, t_value will be
identical to uint32. In this case, compilers are generally smart enough
to eliminate the 32-bit size test and combine the two assignments into a
single default assignment.
*/
t_value get_rval (REG *rptr, uint32 idx)
{
size_t sz;
t_value val;
uint32 *ptr;
void *ptr;
sz = SZ_R (rptr);
if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
idx = idx + rptr->qptr;
if (idx >= rptr->depth) idx = idx - rptr->depth;
if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { /* if the register is a circular queue */
idx = idx + rptr->qptr; /* then adjust the index relative to the queue */
if (idx >= rptr->depth) /* if the index is beyond the end of the array */
idx = idx - rptr->depth; /* then wrap it around */
}
if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
#if defined (USE_INT64)
if (sz <= sizeof (uint32))
val = *ptr;
else val = *((t_uint64 *) ptr);
#else
val = *ptr;
#endif
}
else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
ptr = (uint32 *)(((size_t) rptr->loc) + (idx * rptr->str_size));
#if defined (USE_INT64)
if (sz <= sizeof (uint32))
val = *ptr;
else val = *((t_uint64 *) ptr);
#else
val = *ptr;
#endif
}
else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
(sz == sizeof (uint8)))
val = *(((uint8 *) rptr->loc) + idx);
else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
(sz == sizeof (uint16)))
val = *(((uint16 *) rptr->loc) + idx);
#if defined (USE_INT64)
else if (sz <= sizeof (uint32))
val = *(((uint32 *) rptr->loc) + idx);
else val = *(((t_uint64 *) rptr->loc) + idx);
#else
else val = *(((uint32 *) rptr->loc) + idx);
#endif
val = (val >> rptr->offset) & width_mask[rptr->width];
ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */
if (rptr->size == sizeof (uint8)) /* get the value */
val = *((uint8 *) ptr); /* using a size */
/* appropriate to */
else if (rptr->size == sizeof (uint16)) /* the size of */
val = *((uint16 *) ptr); /* the underlying type */
else if (rptr->size == sizeof (uint32))
val = *((uint32 *) ptr);
else /* if the element size is non-standard */
val = *((t_value *) ptr); /* then access using the largest size permitted */
val = (val >> rptr->offset) & width_mask[rptr->width]; /* shift and mask to obtain the final value */
return val;
}
@ -9886,7 +9891,7 @@ return val;
t_stat dep_reg (int32 flag, CONST char *cptr, REG *rptr, uint32 idx)
{
t_stat r;
t_value val, mask;
t_value val, max;
int32 rdx;
CONST char *tptr;
char gbuf[CBUFSIZE];
@ -9898,24 +9903,27 @@ if (rptr->flags & REG_RO)
if (flag & EX_I) {
cptr = read_line (gbuf, sizeof(gbuf), stdin);
if (sim_log)
fprintf (sim_log, "%s\n", cptr? cptr: "");
fprintf (sim_log, "%s\n", cptr? cptr: ""); /* fix clang error */
if (cptr == NULL) /* force exit */
return 1;
if (*cptr == 0) /* success */
return SCPE_OK;
}
mask = width_mask[rptr->width];
if (rptr->maxval > 0) /* if a maximum value is defined */
max = rptr->maxval; /* then use it */
else /* otherwise */
max = width_mask[rptr->width]; /* the mask defines the maximum value */
GET_RADIX (rdx, rptr->radix);
if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr) { /* address form? */
val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr);
if ((tptr == cptr) || (*tptr != 0) || (val > mask))
if ((tptr == cptr) || (*tptr != 0) || (val > max))
return SCPE_ARG;
}
else
if (!(rptr->flags & REG_VMFLAGS) || /* dont use sym? */
(parse_sym ((CONST char *)cptr, (rptr->flags & REG_UFMASK) | rdx, NULL,
&val, sim_switches | SIM_SW_REG) > SCPE_OK)) {
val = get_uint (cptr, rdx, mask, &r);
val = get_uint (cptr, rdx, max, &r);
if (r != SCPE_OK)
return SCPE_ARG;
}
@ -9934,76 +9942,59 @@ return SCPE_OK;
mask = mask
Outputs:
none
Implementation notes:
1. mask and val are of type t_value, so an explicit cast is not needed for
that type of assignment.
2. See the notes for the get_rval routine for additional information
regarding the stride calculation and the t_value default assignment,
*/
void put_rval_pcchk (REG *rptr, uint32 idx, t_value val, t_bool pc_chk)
{
size_t sz;
t_value mask;
uint32 *ptr;
void *ptr;
t_value prev_val = 0;
if ((!(sim_switches & SWMASK ('Z'))) &&
(rptr->flags & REG_DEPOSIT) && sim_vm_reg_update)
prev_val = get_rval (rptr, idx);
#define PUT_RVAL(sz,rp,id,v,m) \
*(((sz *) rp->loc) + id) = \
(sz)((*(((sz *) rp->loc) + id) & \
~((m) << (rp)->offset)) | ((v) << (rp)->offset))
if (pc_chk && (rptr == sim_PC)) /* if the PC is changing */
sim_brk_npc (0); /* then notify the breakpoint package */
if (pc_chk && (rptr == sim_PC))
sim_brk_npc (0);
sz = SZ_R (rptr);
mask = width_mask[rptr->width];
if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) {
idx = idx + rptr->qptr;
if (idx >= rptr->depth)
idx = idx - rptr->depth;
mask = ~(width_mask [rptr->width] << rptr->offset); /* set up a mask to produce a hole in the element */
val = val << rptr->offset; /* and position the new value to fit the hole */
if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { /* if the register is a circular queue */
idx = idx + rptr->qptr; /* then adjust the index relative to the queue */
if (idx >= rptr->depth) /* if the index is beyond the end of the array */
idx = idx - rptr->depth; /* then wrap it around */
}
if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) {
ptr = (uint32 *)(((UNIT *) rptr->loc) + idx);
#if defined (USE_INT64)
if (sz <= sizeof (uint32))
*ptr = (*ptr &
~(((uint32) mask) << rptr->offset)) |
(((uint32) val) << rptr->offset);
else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
& ~(mask << rptr->offset)) | (val << rptr->offset);
#else
*ptr = (*ptr &
~(((uint32) mask) << rptr->offset)) |
(((uint32) val) << rptr->offset);
#endif
}
else if ((rptr->depth > 1) && (rptr->flags & REG_STRUCT)) {
ptr = (uint32 *)(((size_t)rptr->loc) + (idx * rptr->str_size));
#if defined (USE_INT64)
if (sz <= sizeof (uint32))
*((uint32 *) ptr) = (*((uint32 *) ptr) &
~(((uint32) mask) << rptr->offset)) |
(((uint32) val) << rptr->offset);
else *((t_uint64 *) ptr) = (*((t_uint64 *) ptr)
& ~(mask << rptr->offset)) | (val << rptr->offset);
#else
*ptr = (*ptr &
~(((uint32) mask) << rptr->offset)) |
(((uint32) val) << rptr->offset);
#endif
}
else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
(sz == sizeof (uint8)))
PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask);
else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) &&
(sz == sizeof (uint16)))
PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask);
#if defined (USE_INT64)
else if (sz <= sizeof (uint32))
PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask);
else PUT_RVAL (t_uint64, rptr, idx, val, mask);
#else
else PUT_RVAL (uint32, rptr, idx, val, mask);
#endif
ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */
if (rptr->size == sizeof (uint8)) /* store the value */
*((uint8 *) ptr) = /* using a size */
(uint8) (*((uint8 *) ptr) & mask | val); /* appropriate to */
/* the size of */
else
if (rptr->size == sizeof (uint16)) /* the underlying type */
*((uint16 *) ptr) =
(uint16) (*((uint16 *) ptr) & mask | val);
else
if (rptr->size == sizeof (uint32))
*((uint32 *) ptr) =
(uint32) (*((uint32 *) ptr) & mask | val);
else /* if the element size is non-standard */
*((t_value *) ptr) = /* then access using the largest size permitted */
*((t_value *) ptr) & mask | val;
if ((!(sim_switches & SWMASK ('Z'))) &&
(rptr->flags & REG_DEPOSIT) && sim_vm_reg_update)
sim_vm_reg_update (rptr, idx, prev_val, val);
@ -16084,19 +16075,8 @@ for (i = 0; (dptr = devices[i]) != NULL; i++) {
bytes <<= 1;
if (rptr->depth > 1)
bytes = rptr->ele_size;
bytes = rptr->size;
if (rptr->flags & REG_UNIT) {
DEVICE **d;
for (d = devices; *d != NULL; d++) {
if (((UNIT *)rptr->loc >= (*d)->units) &&
((UNIT *)rptr->loc < (*d)->units + (*d)->numunits)) {
udptr = *d;
break;
}
}
}
if (((rptr->width + rptr->offset + CHAR_BIT - 1) / CHAR_BIT) >= sizeof(size_map) / sizeof(size_map[0])) {
Bad = TRUE;
rsz = 0;
@ -16107,10 +16087,10 @@ for (i = 0; (dptr = devices[i]) != NULL; i++) {
}
if (sim_switches & SWMASK ('R')) /* Debug output */
sim_printf ("%5s:%-9.9s %s(rdx=%u, wd=%u, off=%u, dep=%u, strsz=%u, objsz=%u, elesz=%u, rsz=%u, %s %s%s%s membytes=%u)\n", dptr->name, rptr->name, rptr->macro,
rptr->radix, rptr->width, rptr->offset, rptr->depth, (uint32)rptr->str_size, (uint32)rptr->obj_size, (uint32)rptr->ele_size, rsz, rptr->desc ? rptr->desc : "",
(rptr->flags & REG_FIT) ? "REG_FIT" : "", (rptr->flags & REG_VMIO) ? " REG_VMIO" : "", (rptr->flags & REG_STRUCT) ? " REG_STRUCT" : "",
memsize);
sim_printf ("%5s:%-9.9s %s(rdx=%u, wd=%u, off=%u, dep=%u, strsz=%u, objsz=%u, elesz=%u, rsz=%u, %s %s%s membytes=%u, macro=%s)\n", dptr->name, rptr->name, rptr->macro,
rptr->radix, rptr->width, rptr->offset, rptr->depth, (uint32)rptr->stride, (uint32)rptr->obj_size, (uint32)rptr->size, rsz, rptr->desc ? rptr->desc : "",
(rptr->flags & REG_FIT) ? "REG_FIT" : "", (rptr->flags & REG_VMIO) ? " REG_VMIO" : "",
memsize, rptr->macro ? rptr->macro : "");
MFlush (f);
if (rptr->depth == 1) {
@ -16129,42 +16109,6 @@ for (i = 0; (dptr = devices[i]) != NULL; i++) {
Bad = TRUE;
Mprintf (f, "a 0 bit wide register is meaningless\n");
}
if ((rptr->obj_size != 0) && (rptr->ele_size != 0) && (rptr->depth != 0) && (rptr->macro != NULL)) {
if (rptr->flags & REG_UNIT) {
if (udptr == NULL) {
Bad = TRUE;
Mprintf (f, "\tthe indicated UNIT can't be found for this %u depth array\n", rptr->depth);
}
else {
if (rptr->depth > udptr->numunits) {
Bad = TRUE;
Mprintf (f, "\tthe depth of the UNIT array exceeds the number of units on the %s device which is %u\n", dptr->name, udptr->numunits);
}
if (rptr->obj_size > sizeof (t_value)) {
Bad = TRUE;
Mprintf (f, "\t%u is larger than the size of the t_value type (%u)\n", (uint32)rptr->obj_size, (uint32)sizeof (t_value));
}
}
}
else {
bytes *= rptr->depth;
if (!Bad)
if ((rsz * rptr->depth == rptr->obj_size) ||
((rptr->flags & REG_STRUCT) && (rsz <= rptr->obj_size)) ||
((rptr->depth == 1) &&
((rptr->obj_size == sizeof (t_value)) || (rsz < rptr->obj_size))) ||
((rptr->depth != 1) && (bytes == rptr->obj_size)) ||
((rptr->depth != 1) && (rptr->offset == 0) && (rptr->width == 8) &&
((rptr->depth == rptr->obj_size) || (rptr->depth == rptr->obj_size - 1))) ||
((rptr->depth != 1) && (rptr->offset == 0) && (rptr->obj_size == rptr->ele_size)))
continue;
Bad = TRUE;
Mprintf (f, "\ttherefore SAVE/RESTORE operations will affect %u byte%s of memory\n", bytes, (bytes != 1) ? "s" : "");
Mprintf (f, "\twhile the variable lives in %u bytes of memory\n", (uint32)rptr->obj_size);
}
}
else
Mprintf (f, "\tthis register entry is not properly initialized\n");
if (Bad) {
FMwrite (stdout, f);
stat = SCPE_IERR;

View file

@ -694,9 +694,9 @@ struct REG {
const char *desc; /* description */
BITFIELD *fields; /* bit fields */
uint32 qptr; /* circ q ptr */
size_t str_size; /* structure size */
size_t stride; /* structure/object size (for indexing) */
size_t obj_size; /* sizeof(*loc) */
size_t ele_size; /* sizeof(**loc) or sizeof(*loc) if depth == 1 */
size_t size; /* sizeof(**loc) or sizeof(*loc) if depth == 1 */
const char *macro; /* Initializer Macro Name */
/* NOTE: Flags and maxval MUST always be last since they are initialized outside of macro definitions */
uint32 flags; /* flags */
@ -709,12 +709,10 @@ struct REG {
#define REG_RO 00004 /* read only */
#define REG_HIDDEN 00010 /* hidden */
#define REG_NZ 00020 /* must be non-zero */
#define REG_UNIT 00040 /* in unit struct */
#define REG_STRUCT 00100 /* in structure array */
#define REG_CIRC 00200 /* circular array */
#define REG_VMIO 00400 /* use VM data print/parse */
#define REG_VMAD 01000 /* use VM addr print/parse */
#define REG_FIT 02000 /* fit access to size */
#define REG_FIT 00000 /* fit access to size (obsolete) */
#define REG_DEPOSIT 04000 /* call VM routine after update */
#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */
@ -893,6 +891,7 @@ struct MEMFILE {
size_t size; /* size */
size_t pos; /* data used */
};
/*
The following macros exist to help populate structure contents
@ -903,91 +902,208 @@ struct MEMFILE {
#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,NULL,0,0,(fl),0,(cap),0,NULL,0,0
/* Register initialization macros.
The following macros should be used to initialize the elements of a
simulator's register array. The macros provide simplified initialization,
ensure that unspecified fields are set appropriately, and insulate the
simulator writer from changes in the underlying REG structure.
The macros take varying numbers of parameters with the following meanings:
Param Meaning
----- ------------------------------------------
nm Register symbolic name
loc Location of the associated variable
aloc Location of the associated array
floc Location of the associated structure field
rdx Display and entry radix
wd Field width in bits
off Field offset in bits from LSB
dep Number of array elements
siz Element size in bytes
str Array element spacing in bytes
The macros have the following uses:
Macro Use with
-------- ---------------------------------------------------------------
ORDATA Scalar with octal display/entry
DRDATA Scalar with decimal display/entry
HRDATA Scalar with hexadecimal display/entry
BINRDATA Scalar with binary display/entry
FLDATA Scalar with single bit display/entry
GRDATA Scalar with with specification of radix/width/offset parameters
BRDATA Singly-subscripted array
CRDATA Doubly-subscripted array
SRDATA Singly-subscripted array of general structure fields
URDATA Singly-subscripted array of UNIT structure fields
XRDATA Generic type with specification of all parameters
SAVEDATA Generic type used only for persistence across SAVE/RESTORE
Normally, scalar and array locations specify the variable name; the names are
converted internally to pointers as needed. However, the starting point of
a partial array may be specified by passing a pointer to the desired element.
For example:
BRDATA (SYM, array, ...)
...specifies a register starting with array element zero, while:
BRDATA (SYM, &array[3], ...)
...specifies a register starting with array element three.
For arrays of general structures, the names of the array and selected field
are given:
SRDATA (SYM, array, field, ...)
This specifies a arrayed register whose elements are array[0].field,
array[1].field, etc.
All above macro names from ORDATA through XRDATA have two additional
precisely related macros. The first it the above name with D appended and
has an additional parameter which is a quoted string describing the purpose
of the register which is visible when displaying HELP about a device's
registers. The second related macro has the above name with DF appended
and has two additional parameters. The first parameter is the register
description, and the second is the name of a BITFIELD array which describes
the fields in the register's contents. This info is used to display the
register contents (via EXAMINE) along with the detailed bitfield data.
For example:
{ HRDATA (KSP, KSP, 32) },
{ HRDATAD (KSP, KSP, 32, "kernel stack pointer") },
{ HRDATADF(PSL, PSL, 32, "processor status longword", cpu_psl_bits) },
or
{ ORDATA (PSW, PSW, 16) },
{ ORDATAD (PSW, PSW, 16, "Processor Status Word") },
{ ORDATADF(PSW, PSW, 16, "Processor Status Word", psw_bits) },
Implementation notes:
1. The "_RegCheck" macro is used to ensure that each of the user macros has
the correct number of parameters. This improves maintenance reliability,
as changes to the REG structure need to be reflected only in the
"_RegCheck" macro.
2. "Stringization" must occur at the first macro call level to support
register names that are themselves macros. Otherwise, macro expansion
will occur before stringization, resulting in the wrong register name.
3. Additional REG initialization values may be supplied after a macro
invocation. If present, these begin with the "flags" field which is,
for the most part, not specified as a macro parameter.
4. The URDATA macro is obsolescent and present for backward-compatibility.
It is a special case of the generic SRDATA macro, which provides the same
functionality. Note also that URDATA requires a "flags" parameter value,
which is optional for all other macros.
5. The SAVEDATA macro is useful to indicate global variables whose values
must persist across a SAVE and RESTORE. Such data is hidden from the
register user interface.
*/
/* Internal use ONLY (see below) Generic Register declaration for all fields */
#define _REGDATANF(nm,loc,rdx,wd,off,dep,desc,flds,qptr,siz,elesiz,macro) \
#define _RegCheck(nm,loc,rdx,wd,off,dep,desc,flds,qptr,siz,elesiz,macro) \
nm, (loc), (rdx), (wd), (off), (dep), (desc), (flds), (qptr), (siz), sizeof(*(loc)), (elesiz), #macro
#if defined (__STDC__) || defined (_WIN32) /* Variants which depend on how macro arguments are convered to strings */
/* Generic Register declaration for all fields.
If the register structure is extended, this macro will be retained and a
new internal macro will be provided that populates the new register structure */
#define REGDATA(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,qptr,siz,sizeof((loc)),REGDATA),(fl)
#define REGDATAC(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,qptr,siz,sizeof((loc)),REGDATAC),(fl)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,desc,flds,qptr,siz,sizeof((loc)),REGDATA),(fl)
/* v3 compatible macro */
#define XRDATA(nm,loc,rdx,wd,off,dep,siz,str) \
_RegCheck(#nm,loc,rdx,wd,off,dep,NULL,NULL,0,siz,sizeof((loc)),XRDATA),(fl)
/* Right Justified Octal Register Data */
#define ORDATA(nm,loc,wd) \
_REGDATANF(#nm,&(loc),8,wd,0,1,NULL,NULL,0,0,sizeof((loc)),ORDATA)
_RegCheck(#nm,&(loc),8,wd,0,1,NULL,NULL,0,0,sizeof((loc)),ORDATA)
#define ORDATAD(nm,loc,wd,desc) \
_REGDATANF(#nm,&(loc),8,wd,0,1,desc,NULL,0,0,sizeof((loc)),ORDATAD)
_RegCheck(#nm,&(loc),8,wd,0,1,desc,NULL,0,0,sizeof((loc)),ORDATAD)
#define ORDATADF(nm,loc,wd,desc,flds) \
_REGDATANF(#nm,&(loc),8,wd,0,1,desc,flds,0,0,sizeof((loc)),ORDATADF)
_RegCheck(#nm,&(loc),8,wd,0,1,desc,flds,0,0,sizeof((loc)),ORDATADF)
/* Right Justified Decimal Register Data */
#define DRDATA(nm,loc,wd) \
_REGDATANF(#nm,&(loc),10,wd,0,1,NULL,NULL,0,0,sizeof((loc)),DRDATA)
_RegCheck(#nm,&(loc),10,wd,0,1,NULL,NULL,0,0,sizeof((loc)),DRDATA)
#define DRDATAD(nm,loc,wd,desc) \
_REGDATANF(#nm,&(loc),10,wd,0,1,desc,NULL,0,0,sizeof((loc)),DRDATAD)
_RegCheck(#nm,&(loc),10,wd,0,1,desc,NULL,0,0,sizeof((loc)),DRDATAD)
#define DRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF(#nm,&(loc),10,wd,0,1,desc,flds,0,0,sizeof((loc)),DRDATADF)
_RegCheck(#nm,&(loc),10,wd,0,1,desc,flds,0,0,sizeof((loc)),DRDATADF)
/* Right Justified Hexadecimal Register Data */
#define HRDATA(nm,loc,wd) \
_REGDATANF(#nm,&(loc),16,wd,0,1,NULL,NULL,0,0,sizeof((loc)),HRDATA)
_RegCheck(#nm,&(loc),16,wd,0,1,NULL,NULL,0,0,sizeof((loc)),HRDATA)
#define HRDATAD(nm,loc,wd,desc) \
_REGDATANF(#nm,&(loc),16,wd,0,1,desc,NULL,0,0,sizeof((loc)),HRDATAD)
_RegCheck(#nm,&(loc),16,wd,0,1,desc,NULL,0,0,sizeof((loc)),HRDATAD)
#define HRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF(#nm,&(loc),16,wd,0,1,desc,flds,0,0,sizeof((loc)),HRDATADF)
_RegCheck(#nm,&(loc),16,wd,0,1,desc,flds,0,0,sizeof((loc)),HRDATADF)
/* Right Justified Binary Register Data */
#define BINRDATA(nm,loc,wd) \
_REGDATANF(#nm,&(loc),2,wd,0,1,NULL,NULL,0,0,sizeof((loc)),BINRDATA)
_RegCheck(#nm,&(loc),2,wd,0,1,NULL,NULL,0,0,sizeof((loc)),BINRDATA)
#define BINRDATAD(nm,loc,wd,desc) \
_REGDATANF(#nm,&(loc),2,wd,0,1,desc,NULL,0,0,sizeof((loc)),BINRDATAD)
_RegCheck(#nm,&(loc),2,wd,0,1,desc,NULL,0,0,sizeof((loc)),BINRDATAD)
#define BINRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF(#nm,&(loc),2,wd,0,1,desc,flds,0,0,sizeof((loc)),BINRDATADF)
_RegCheck(#nm,&(loc),2,wd,0,1,desc,flds,0,0,sizeof((loc)),BINRDATADF)
/* One-bit binary flag at an arbitrary offset in a 32-bit word Register */
#define FLDATA(nm,loc,pos) \
_REGDATANF(#nm,&(loc),2,1,pos,1,NULL,NULL,0,0,sizeof((loc)),FLDATA)
_RegCheck(#nm,&(loc),2,1,pos,1,NULL,NULL,0,0,sizeof((loc)),FLDATA)
#define FLDATAD(nm,loc,pos,desc) \
_REGDATANF(#nm,&(loc),2,1,pos,1,desc,NULL,0,0,sizeof((loc)),FLDATAD)
_RegCheck(#nm,&(loc),2,1,pos,1,desc,NULL,0,0,sizeof((loc)),FLDATAD)
#define FLDATADF(nm,loc,pos,desc,flds) \
_REGDATANF(#nm,&(loc),2,1,pos,1,desc,flds,0,0,sizeof((loc)),FLDATADF)
_RegCheck(#nm,&(loc),2,1,pos,1,desc,flds,0,0,sizeof((loc)),FLDATADF)
/* Arbitrary location and Radix Register */
#define GRDATA(nm,loc,rdx,wd,pos) \
_REGDATANF(#nm,&(loc),rdx,wd,pos,1,NULL,NULL,0,0,sizeof((loc)),GRDATA)
_RegCheck(#nm,&(loc),rdx,wd,pos,1,NULL,NULL,0,0,sizeof((loc)),GRDATA)
#define GRDATAD(nm,loc,rdx,wd,pos,desc) \
_REGDATANF(#nm,&(loc),rdx,wd,pos,1,desc,NULL,0,0,sizeof((loc)),GRDATAD)
_RegCheck(#nm,&(loc),rdx,wd,pos,1,desc,NULL,0,0,sizeof((loc)),GRDATAD)
#define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) \
_REGDATANF(#nm,&(loc),rdx,wd,pos,1,desc,flds,0,0,sizeof((loc)),GRDATADF)
_RegCheck(#nm,&(loc),rdx,wd,pos,1,desc,flds,0,0,sizeof((loc)),GRDATADF)
/* Arrayed register whose data is kept in a standard C array Register */
#define BRDATA(nm,loc,rdx,wd,dep) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,NULL,NULL,0,0,sizeof(*(loc)),BRDATA)
#define BRDATAD(nm,loc,rdx,wd,dep,desc) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,desc,NULL,0,0,sizeof(*(loc)),BRDATAD)
#define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,desc,flds,0,0,sizeof(*(loc)),BRDATADF)
#define BRDATA(nm,aloc,rdx,wd,dep) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,NULL,NULL,0,0,sizeof(*(aloc)),BRDATA)
#define BRDATAD(nm,aloc,rdx,wd,dep,desc) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,desc,NULL,0,0,sizeof(*(aloc)),BRDATAD)
#define BRDATADF(nm,aloc,rdx,wd,dep,desc,flds) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,desc,flds,0,0,sizeof(*(aloc)),BRDATADF)
/* Arrayed register whose data is kept in a standard C array Register */
#define CRDATA(nm,aloc,rdx,wd,dep) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,NULL,NULL,0,0,sizeof(**(aloc)),CRDATA)
#define CRDATAD(nm,aloc,rdx,wd,dep,desc) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,desc,NULL,0,0,sizeof(**(aloc)),CRDATAD)
#define CRDATADF(nm,aloc,rdx,wd,dep,desc,flds) \
_RegCheck(#nm,aloc,rdx,wd,0,dep,desc,flds,0,0,sizeof(**(aloc)),CRDATADF)
/* Range of memory whose data is successive scalar values accessed like an array Register */
#define VBRDATA(nm,loc,rdx,wd,dep) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,NULL,NULL,0,0,sizeof(loc),VBRDATA)
_RegCheck(#nm,&(loc),rdx,wd,0,dep,NULL,NULL,0,0,sizeof(loc),VBRDATA)
#define VBRDATAD(nm,loc,rdx,wd,dep,desc) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,desc,NULL,0,0,sizeof(loc),VBRDATAD)
_RegCheck(#nm,&(loc),rdx,wd,0,dep,desc,NULL,0,0,sizeof(loc),VBRDATAD)
#define VBRDATADF(nm,loc,rdx,wd,dep,desc,flds) \
_REGDATANF(#nm,&(loc),rdx,wd,0,dep,desc,flds,0,0,sizeof(loc),VBRDATADF)
_RegCheck(#nm,&(loc),rdx,wd,0,dep,desc,flds,0,0,sizeof(loc),VBRDATADF)
/* Arrayed register whose data is part of the UNIT structure */
#define URDATA(nm,loc,rdx,wd,off,dep,fl) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,0,sizeof((loc)),URDATA),((fl) | REG_UNIT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,sizeof(UNIT),sizeof((loc)),URDATA),(fl)
#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,0,sizeof((loc)),URDATAD),((fl) | REG_UNIT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,sizeof(UNIT),sizeof((loc)),URDATAD),(fl)
#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,0,sizeof((loc)),URDATADF),((fl) | REG_UNIT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,sizeof(UNIT),sizeof((loc)),URDATADF),(fl)
/* Arrayed register whose data is part of an arbitrary structure */
#define STRDATA(nm,loc,rdx,wd,off,dep,siz,fl) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,siz,sizeof((loc)),STRDATA),((fl) | REG_STRUCT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,siz,sizeof((loc)),STRDATA),(fl)
#define STRDATAD(nm,loc,rdx,wd,off,dep,siz,fl,desc) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,siz,sizeof((loc)),STRDATAD),((fl) | REG_STRUCT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,siz,sizeof((loc)),STRDATAD),(fl)
#define STRDATADF(nm,loc,rdx,wd,off,dep,siz,fl,desc,flds) \
_REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,siz,sizeof((loc)),STRDATADF),((fl) | REG_STRUCT)
_RegCheck(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,siz,sizeof((loc)),STRDATADF),(fl)
/* Hidden Blob of Data - Only used for SAVE/RESTORE */
#define SAVEDATA(nm,loc) \
_REGDATANF(#nm,&(loc),0,8,0,1,NULL,NULL,0,sizeof(loc),sizeof(loc),SAVEDATA),(REG_HRO)
_RegCheck(#nm,&(loc),0,8,0,1,NULL,NULL,0,sizeof(loc),sizeof(loc),SAVEDATA),(REG_HRO)
#define STARTBIT {"", 0x00000000, 0, NULL, NULL} /* Start at beginning bit */
#define BIT(nm) {#nm, 0xffffffff, 1, NULL, NULL} /* Single Bit definition */
#define BITNC {"", 0xffffffff, 1, NULL, NULL} /* Don't care Bit definition */
@ -995,95 +1111,6 @@ struct MEMFILE {
#define BITNCF(sz) {"", 0xffffffff, sz, NULL, NULL} /* Don't care Bit Field definition */
#define BITFFMT(nm,sz,fmt) {#nm, 0xffffffff, sz, NULL, #fmt} /* Bit Field definition with Output format */
#define BITFNAM(nm,sz,names) {#nm, 0xffffffff, sz, names,NULL} /* Bit Field definition with value->name map */
#else /* For non-STD-C compiler which can't stringify macro arguments with # */
/* Generic Register declaration for all fields.
If the register structure is extended, this macro will be retained and a
new macro will be provided that populates the new register structure */
#define REGDATA(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,qptr,siz,sizeof((loc)),REGDATA),(fl)
#define REGDATAC(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,qptr,siz,sizeof((loc)),REGDATAC),(fl)
/* Right Justified Octal Register Data */
#define ORDATA(nm,loc,wd) \
_REGDATANF("nm",&(loc),8,wd,0,1,NULL,NULL,0,0,sizeof((loc)),ORDATA)
#define ORDATAD(nm,loc,wd,desc) \
_REGDATANF("nm",&(loc),8,wd,0,1,desc,NULL,0,0,sizeof((loc)),ORDATAD)
#define ORDATADF(nm,loc,wd,desc,flds) \
_REGDATANF("nm",&(loc),8,wd,0,1,desc,flds,0,0,sizeof((loc)),ORDATADF)
/* Right Justified Decimal Register Data */
#define DRDATA(nm,loc,wd) \
_REGDATANF("nm",&(loc),10,wd,0,1,NULL,NULL,0,0,sizeof((loc)),DRDATA)
#define DRDATAD(nm,loc,wd,desc) \
_REGDATANF("nm",&(loc),10,wd,0,1,desc,NULL,0,0,sizeof((loc)),DRDATAD)
#define DRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF("nm",&(loc),10,wd,0,1,desc,flds,0,0,sizeof((loc)),DRDATADF)
/* Right Justified Hexadecimal Register Data */
#define HRDATA(nm,loc,wd) \
_REGDATANF("nm",&(loc),16,wd,0,1,NULL,NULL,0,0,sizeof((loc)),HRDATA)
#define HRDATAD(nm,loc,wd,desc) \
_REGDATANF("nm",&(loc),16,wd,0,1,desc,NULL,0,0,sizeof((loc)),HRDATAD)
#define HRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF("nm",&(loc),16,wd,0,1,desc,flds,0,0,sizeof((loc)),HRDATADF)
/* Right Justified Binary Register Data */
#define BINRDATA(nm,loc,wd) \
_REGDATANF("nm",&(loc),2,wd,0,1,NULL,NULL,0,0,sizeof((loc)),BINRDATA)
#define BINRDATAD(nm,loc,wd,desc) \
_REGDATANF("nm",&(loc),2,wd,0,1,desc,NULL,0,0,sizeof((loc)),BINRDATAD)
#define BINRDATADF(nm,loc,wd,desc,flds) \
_REGDATANF("nm",&(loc),2,wd,0,1,desc,flds,0,0,sizeof((loc)),BINRDATADF)
/* One-bit binary flag at an arbitrary offset in a 32-bit word Register */
#define FLDATA(nm,loc,pos) \
_REGDATANF("nm",&(loc),2,1,pos,1,NULL,NULL,0,0,sizeof((loc)),FLDATA)
#define FLDATAD(nm,loc,pos,desc) \
_REGDATANF("nm",&(loc),2,1,pos,1,desc,NULL,0,0,sizeof((loc)),FLDATAD)
#define FLDATADF(nm,loc,pos,desc,flds) \
_REGDATANF("nm",&(loc),2,1,pos,1,desc,flds,0,0,sizeof((loc)),FLDATADF)
/* Arbitrary location and Radix Register */
#define GRDATA(nm,loc,rdx,wd,pos) \
_REGDATANF("nm",&(loc),rdx,wd,pos,1,NULL,NULL,0,0,sizeof((loc)),GRDATA)
#define GRDATAD(nm,loc,rdx,wd,pos,desc) \
_REGDATANF("nm",&(loc),rdx,wd,pos,1,desc,NULL,0,0,sizeof((loc)),GRDATAD)
#define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) \
_REGDATANF("nm",&(loc),rdx,wd,pos,1,desc,flds,0,0,sizeof((loc)),GRDATADF)
/* Arrayed register whose data is kept in a standard C array Register */
#define BRDATA(nm,loc,rdx,wd,dep) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,NULL,NULL,0,0,sizeof(*(loc)),BRDATA)
#define BRDATAD(nm,loc,rdx,wd,dep,desc) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,desc,NULL,0,0,sizeof(*(loc)),BRDATAD)
#define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,desc,flds,0,0,sizeof(*(loc)),BRDATADF)
/* Range of memory whose data is successive scalar values accessed like an array Register */
#define VBRDATA(nm,loc,rdx,wd,dep) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,NULL,NULL,0,0,sizeof(loc),VBRDATA)
#define VBRDATAD(nm,loc,rdx,wd,dep,desc) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,desc,NULL,0,0,sizeof(loc),VBRDATAD)
#define VBRDATADF(nm,loc,rdx,wd,dep,desc,flds) \
_REGDATANF("nm",&(loc),rdx,wd,0,dep,desc,flds,0,0,sizeof(loc),VBRDATADF)
/* Arrayed register whose data is part of the UNIT structure */
#define URDATA(nm,loc,rdx,wd,off,dep,fl) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,NULL,NULL,0,0,sizeof((loc)),URDATA),((fl) | REG_UNIT)
#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,NULL,0,0,sizeof((loc)),URDATAD),((fl) | REG_UNIT)
#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,0,0,sizeof((loc)),URDATADF),((fl) | REG_UNIT)
/* Arrayed register whose data is part of an arbitrary structure */
#define STRDATA(nm,loc,rdx,wd,off,dep,siz,fl) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,NULL,NULL,0,siz,sizeof((loc)),STRDATA),((fl) | REG_STRUCT)
#define STRDATAD(nm,loc,rdx,wd,off,dep,siz,fl,desc) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,NULL,0,siz,sizeof((loc)),STRDATAD),((fl) | REG_STRUCT)
#define STRDATADF(nm,loc,rdx,wd,off,dep,siz,fl,desc,flds) \
_REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,0,siz,sizeof((loc)),STRDATADF),((fl) | REG_STRUCT)
/* Hidden Blob of Data - Only used for SAVE/RESTORE */
#define SAVEDATA(nm,loc) \
_REGDATANF("nm",&(loc),0,8,0,1,NULL,NULL,0,sizeof(loc),sizeof(loc)),SAVEDATA),(REG_HRO)
#define STARTBIT {"", 0x00000000, 0, NULL, NULL} /* Start at beginning bit */
#define BIT(nm) {"nm", 0xffffffff, 1, NULL, NULL} /* Single Bit definition */
#define BITNC {"", 0xffffffff, 1, NULL, NULL} /* Don't care Bit definition */
#define BITF(nm,sz) {"nm", 0xffffffff, sz, NULL, NULL} /* Bit Field definition */
#define BITNCF(sz) {"", 0xffffffff, sz, NULL, NULL} /* Don't care Bit Field definition */
#define BITFFMT(nm,sz,fmt) {"nm", 0xffffffff, sz, NULL, "fmt"}/* Bit Field definition with Output format */
#define BITFNAM(nm,sz,names) {"nm", 0xffffffff, sz, names,NULL} /* Bit Field definition with value->name map */
#endif
#define ENDBITS {NULL} /* end of bitfield list */