1
0
mirror of https://github.com/simh/simh.git synced 2026-01-13 07:19:43 +00:00

SCP: Updated REG manipulation APIs and REGister sanity checks for all macros

- bounds check accesses in get_rval and put_rval for circular registers
- extend unit tests for REGister sanity checks to include all macros
- add sanity checks for new REGister macros
This commit is contained in:
Mark Pizzolato 2022-06-26 14:39:25 -07:00
parent 72196b08bb
commit bc99d6d5de
3 changed files with 160 additions and 40 deletions

Binary file not shown.

192
scp.c
View File

@ -293,7 +293,9 @@
else \
(void)0
/* Size of a DEVICE's data element */
#define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT])
/* Size of a REGister's data element */
#define SZ_R(rp) \
(size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT])
#if defined (USE_INT64)
@ -9925,11 +9927,8 @@ t_value get_rval (REG *rptr, uint32 idx)
t_value val;
void *ptr;
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_CIRC)) /* if the register is a circular queue */
idx = (idx + rptr->qptr) % rptr->depth; /* then adjust the index relative to the queue (wrapped as needed) */
ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */
@ -10042,11 +10041,8 @@ if (pc_chk && (rptr == sim_PC)) /* if the PC is changing
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_CIRC)) /* if the register is a circular queue */
idx = (idx + rptr->qptr) % rptr->depth; /* then adjust the index relative to the queue (wrapped as needed) */
ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */
@ -16142,7 +16138,7 @@ for (i = 0; (dptr = devices[i]) != NULL; i++) {
for (rptr = dptr->registers; (rptr != NULL) && (rptr->name != NULL); rptr++) {
uint32 bytes = 1;
uint32 rsz = SZ_R(rptr);
uint32 memsize = ((rptr->flags & REG_FIT) || (rptr->depth > 1)) ? rptr->depth * rsz : 4;
uint32 memsize = (rptr->depth >= 1) ? rptr->depth * rsz : rsz;
DEVICE *udptr = NULL;
t_bool Bad;
@ -16152,6 +16148,17 @@ for (i = 0; (dptr = devices[i]) != NULL; i++) {
if (rptr->depth > 1)
bytes = rptr->size;
if (rptr->macro && (strstr (rptr->macro, "URDATA") != NULL)) {
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;
@ -16162,10 +16169,11 @@ 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 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 : "");
sim_printf ("%5s:%-9.9s %s%s%s(rdx=%u, wd=%u, off=%u, dep=%u, strsz=%u, objsz=%u, elesz=%u, rsz=%u, %s%s%s membytes=%u)\n",
dptr->name, rptr->name, rptr->desc ? rptr->desc : "", rptr->desc ? "\n\t" : "", rptr->macro ? rptr->macro : "",
rptr->radix, rptr->width, rptr->offset, rptr->depth, (uint32)rptr->stride, (uint32)rptr->obj_size, (uint32)rptr->size, rsz,
(rptr->flags & REG_VMAD) ? " REG_VMAD" : "", (rptr->flags & REG_VMIO) ? " REG_VMIO" : "",
(rptr->flags & REG_DEPOSIT) ? " REG_DEPOSIT" : "", memsize);
MFlush (f);
if (rptr->depth == 1) {
@ -16184,6 +16192,49 @@ 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->size != 0) && (rptr->depth != 0) && (rptr->macro != NULL)) {
if (strstr (rptr->macro, "URDATA") != NULL) {
if (udptr == NULL) {
Bad = TRUE;
Mprintf (f, "\tthe indicated UNIT can't be found for this %u depth array\n", rptr->depth);
}
else {
UNIT *uptr;
for (uptr = udptr->units; (uint32)(uptr - udptr->units) < udptr->numunits; uptr++) {
if (((char *)rptr->loc) < (char *)(uptr + 1))
break;
}
if ((rptr->depth + (uptr - udptr->units)) > udptr->numunits) {
Bad = TRUE;
Mprintf (f, "\tthe %u depth of the UNIT array exceeds the number of units on the %s device which is %u\n", rptr->depth, 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->macro && (strstr (rptr->macro, "STRDATA") != NULL)) && (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->size)))
continue;
Bad = TRUE;
Mprintf (f, "\ttherefore EXAMINE and SAVE operations will reference %u byte%s\n", bytes, (bytes != 1) ? "s" : "");
Mprintf (f, "\tand DEPOSIT and 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;
@ -16214,28 +16265,95 @@ uint8 treg8;
uint16 treg16;
uint32 treg32;
t_value tregval;
uint16 treg16array[5];
uint16 treg16arrayx2[5][4];
static struct validation_test {
REG reg[5];
t_stat expected_result;
} validations[] = {
{ { { ORDATAD (REG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ ORDATAD (REG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ ORDATAD (REG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ ORDATAD (REGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { { ORDATAD (REG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ ORDATAD (REG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ ORDATAD (REG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ ORDATAD (REGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { {NULL} } }
};
static UNIT validate_units[3];
static struct validation_test {
REG reg[7];
t_stat expected_result;
} validations[] = {
{ { { ORDATAD (OREG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ ORDATAD (OREG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ ORDATAD (OREG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ ORDATAD (OREGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { { DRDATAD (DREG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ DRDATAD (DREG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ DRDATAD (DREG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ DRDATAD (DREGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { { HRDATAD (HREG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ HRDATAD (HREG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ HRDATAD (HREG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ HRDATAD (HREGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { { BINRDATAD (BINREG8, treg8, 8*sizeof(treg8), "8 bit register") },
{ BINRDATAD (BINREG16, treg16, 8*sizeof(treg16), "16 bit register") },
{ BINRDATAD (BINREG32, treg32, 8*sizeof(treg32), "32 bit register") },
{ BINRDATAD (BINREGVAL, tregval, 8*sizeof(tregval), "value register") },
{NULL} },
SCPE_OK},
{ { { FLDATAD (FLREG8, treg8, 0, "Flag in 0'th bit of 8 bit register") },
{ FLDATAD (FLREG8, treg8, (8*sizeof(treg8)-1), "Flag in 7'th bit of 8 bit register") },
{ FLDATAD (FLREG160, treg16, 0, "Flag in 0'th bit of 16 bit register") },
{ FLDATAD (FLREG1615,treg16, (8*sizeof(treg16)-1), "Flag in 15'th bit of 16 bit register") },
{ FLDATAD (FLREG320, treg32, 0, "Flag in 0'th bit of 32 bit register") },
{ FLDATAD (FLREG3231,treg32, (8*sizeof(treg32)-1), "Flag in 31'st bit of 32 bit register") },
{NULL} },
SCPE_OK},
{ { { GRDATAD (FLREG8, treg8, 16, (8*sizeof(treg8))/2, (8*sizeof(treg8))/4, "2 bit field starting at offset 4 in an 8 bit register") },
{ GRDATAD (FLREG16, treg16, 16, (8*sizeof(treg16))/2, (8*sizeof(treg16))/4, "4 bit field starting at offset 8 in a 16 bit register") },
{ GRDATAD (FLREG32, treg32, 16, (8*sizeof(treg32))/2, (8*sizeof(treg32))/4, "8 bit field starting at offset 16 in a 32 bit register") },
{NULL} },
SCPE_OK},
{ { { XRDATA (FLREG32, &treg32, 16, 8, 0, sizeof(treg32), 1, 1) },
{NULL} },
SCPE_OK},
{ { { BRDATAD (FLREG16, treg16array, 16, 16, 5, "array of 5 uint16's") },
{NULL} },
SCPE_OK},
{ { { CRDATAD (FLREG16, treg16arrayx2, 16, 16, 20, "array of 5x4 uint16's") },
{NULL} },
SCPE_OK},
{ { { VBRDATAD (FLREG16, treg16array, 16, 16, 5, "5 Successive scalar values") },
{NULL} },
SCPE_OK},
{ { { URDATAD (FLREG32, validate_units[0].pos, 16, 32, 0, 3, PV_LEFT, "Unit POS register array for 3 units") },
{NULL} },
SCPE_OK},
{ { { URDATAD (FLREG32, validate_units[2].pos, 16, 32, 0, 3, PV_LEFT, "Unit POS register array for 3 units out of bounds") },
{NULL} },
SCPE_IERR},
{ { { STRDATAD (STRPOS, validate_units[0].pos, 16, 32, 0, 3, sizeof(UNIT), PV_LEFT, "Structure") },
{NULL} },
SCPE_OK},
{ { { SAVEDATA (ALLUNITS, validate_units) },
{NULL} },
SCPE_OK},
{ { { FLDATAD (FLREG8, treg8, 0, "Flag in 0'th bit of 8 bit register") },
{ FLDATAD (FLREG8, treg8, (8*sizeof(treg8)-1), "Flag in 7'th bit of 8 bit register") },
{ FLDATAD (FLREG8, treg8, 8*sizeof(treg8), "Flag outside of 8 bit register") },
{NULL} },
SCPE_IERR},
{ { { FLDATAD (FLREG16, treg16, 0, "Flag in 0'th bit of 16 bit register") },
{ FLDATAD (FLREG16, treg16, (8*sizeof(treg16)-1), "Flag in 15'th bit of 16 bit register") },
{ FLDATAD (FLREG16, treg16, 8*sizeof(treg16), "Flag outside of 16 bit register") },
{NULL} },
SCPE_IERR},
{ { { FLDATAD (FLREG32, treg32, 0, "Flag in 0'th bit of 32 bit register") },
{ FLDATAD (FLREG32, treg32, (8*sizeof(treg32)-1), "Flag in 31'st bit of 32 bit register") },
{ FLDATAD (FLREG32, treg32, 8*sizeof(treg32), "Flag outside of 32 bit register") },
{NULL} },
SCPE_IERR},
{ { {NULL} } }
};
static DEVICE validate_test = {
"TEST-REG", validate_units, NULL, NULL,
3, 16, 22, 4, 16, 16};
@ -16245,17 +16363,19 @@ static t_stat test_register_validation (void)
struct validation_test *v;
DEVICE *v_devs[] = {&validate_test,
NULL};
t_stat tstat, stat = SCPE_OK;
if (sim_switches & SWMASK ('T'))
sim_messagef (SCPE_OK, "test_register_validation - starting\n");
for (v = validations; v->reg[0].name != NULL; v++) {
validate_test.registers = v->reg;
if (SCPE_OK != sim_sanity_check_register_declarations (v_devs))
break;
tstat = sim_sanity_check_register_declarations (v_devs);
if (tstat != v->expected_result)
stat = tstat;
}
if (sim_switches & SWMASK ('T'))
sim_messagef (SCPE_OK, "test_register_validation - done\n");
return SCPE_OK;
return stat;
}
typedef const char *(*parse_function)(const char *input, char *output, char end_char);

View File

@ -1026,7 +1026,7 @@ struct MEMFILE {
_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)
_RegCheck(#nm,loc,rdx,wd,off,dep,NULL,NULL,0,siz,sizeof((loc)),XRDATA)
/* Right Justified Octal Register Data */
#define ORDATA(nm,loc,wd) \
@ -1079,11 +1079,11 @@ struct MEMFILE {
_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)
_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)
_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)
_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) \