VAX, MicroVAX I & II: Revamped Qbus memory access as Qbus peripheral

This commit is contained in:
Mark Pizzolato 2019-05-12 21:52:06 -07:00
parent 05f84879ad
commit 94f5034712
11 changed files with 232 additions and 188 deletions

View file

@ -110,6 +110,10 @@ t_stat vax610_set_instruction_set (UNIT *uptr, int32 val, CONST char *cptr, void
#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ #define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */
#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ #define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
#define QVMBASE 0x3C0000 /* QVSS mem base */ #define QVMBASE 0x3C0000 /* QVSS mem base */
#define ADDR_IS_QVM(x) (vc_buf && \
(((uint32) (x)) >= QVMBASE) && \
(((uint32) (x)) < (QVMBASE + QVMSIZE)))
extern uint32 *vc_buf;
/* Memory */ /* Memory */
@ -137,8 +141,9 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */ #define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */
#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */ #define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
#define IOPAGEBASE 0x20000000 /* IO page base */ #define IOPAGEBASE 0x20000000 /* IO page base */
#define ADDR_IS_IO(x) ((((uint32) (x)) >= IOPAGEBASE) && \ #define ADDR_IS_IO(x) ((ADDR_IS_QVM (x)) || \
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE))) ((((uint32) (x)) >= IOPAGEBASE) && \
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE))))
/* Other address spaces */ /* Other address spaces */

View file

@ -35,6 +35,9 @@ int32 int_req[IPL_HLVL] = { 0 }; /* intr, IPL 14-17 */
int32 int_vec_set[IPL_HLVL][32] = { 0 }; /* bits to set in vector */ int32 int_vec_set[IPL_HLVL][32] = { 0 }; /* bits to set in vector */
int32 autcon_enb = 1; /* autoconfig enable */ int32 autcon_enb = 1; /* autoconfig enable */
extern int32 vc_mem_rd (int32 pa);
extern void vc_mem_wr (int32 pa, int32 val, int32 lnt);
int32 eval_int (void); int32 eval_int (void);
t_stat qba_reset (DEVICE *dptr); t_stat qba_reset (DEVICE *dptr);
const char *qba_description (DEVICE *dptr); const char *qba_description (DEVICE *dptr);
@ -102,6 +105,9 @@ int32 ReadQb (uint32 pa)
{ {
int32 idx, val; int32 idx, val;
if (ADDR_IS_QVM (pa))
return vc_mem_rd (pa);
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispR[idx]) { if (iodispR[idx]) {
iodispR[idx] (&val, pa, READ); iodispR[idx] (&val, pa, READ);
@ -115,6 +121,11 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
{ {
int32 idx; int32 idx;
if (ADDR_IS_QVM (pa)) {
vc_mem_wr (pa, val, mode);
return;
}
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispW[idx]) { if (iodispW[idx]) {
iodispW[idx] (val, pa, mode); iodispW[idx] (val, pa, mode);
@ -140,7 +151,8 @@ int32 iod;
iod = ReadQb (pa); /* wd from Qbus */ iod = ReadQb (pa); /* wd from Qbus */
if (lnt < L_LONG) /* bw? position */ if (lnt < L_LONG) /* bw? position */
iod = iod << ((pa & 2)? 16: 0); iod = iod << ((pa & 2)? 16: 0);
else iod = (ReadQb (pa + 2) << 16) | iod; /* lw, get 2nd wd */ else
iod = (ReadQb (pa + 2) << 16) | iod; /* lw, get 2nd wd */
SET_IRQL; SET_IRQL;
return iod; return iod;
} }
@ -182,7 +194,8 @@ int32 iod;
iod = ReadQb (pa); /* wd from Qbus */ iod = ReadQb (pa); /* wd from Qbus */
if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */ if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */
iod = iod << ((pa & 2)? 16: 0); /* one op */ iod = iod << ((pa & 2)? 16: 0); /* one op */
else iod = (ReadQb (pa + 2) << 16) | iod; /* two ops, get 2nd wd */ else
iod = (ReadQb (pa + 2) << 16) | iod; /* two ops, get 2nd wd */
SET_IRQL; SET_IRQL;
return iod; return iod;
} }

View file

@ -66,8 +66,6 @@ const char *sysd_description (DEVICE *dptr);
t_stat vax610_boot (int32 flag, CONST char *ptr); t_stat vax610_boot (int32 flag, CONST char *ptr);
t_stat vax610_boot_parse (int32 flag, const char *ptr); t_stat vax610_boot_parse (int32 flag, const char *ptr);
extern int32 vc_mem_rd (int32 pa);
extern void vc_mem_wr (int32 pa, int32 val, int32 lnt);
extern int32 iccs_rd (void); extern int32 iccs_rd (void);
extern int32 todr_rd (void); extern int32 todr_rd (void);
extern int32 rxcs_rd (void); extern int32 rxcs_rd (void);
@ -265,12 +263,11 @@ return;
struct reglink { /* register linkage */ struct reglink { /* register linkage */
uint32 low; /* low addr */ uint32 low; /* low addr */
uint32 high; /* high addr */ uint32 high; /* high addr */
int32 (*read)(int32 pa); /* read routine */ int32 (*read)(int32 pa, int32 lnt); /* read routine */
void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */ void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */
}; };
struct reglink regtable[] = { struct reglink regtable[] = {
{ QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr },
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL }
}; };
@ -289,7 +286,7 @@ struct reglink *p;
for (p = &regtable[0]; p->low != 0; p++) { for (p = &regtable[0]; p->low != 0; p++) {
if ((pa >= p->low) && (pa < p->high) && p->read) if ((pa >= p->low) && (pa < p->high) && p->read)
return p->read (pa); return p->read (pa, lnt);
} }
MACH_CHECK (MCHK_READ); MACH_CHECK (MCHK_READ);
} }

View file

@ -135,7 +135,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */ #define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */
#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */ #define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
#define IOPAGEBASE 0x20000000 /* IO page base */ #define IOPAGEBASE 0x20000000 /* IO page base */
#define ADDR_IS_IO(x) ((((uint32) (x)) >= IOPAGEBASE) && \ #define ADDR_IS_IOP(x) ((((uint32) (x)) >= IOPAGEBASE) && \
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE))) (((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE)))
/* Read only memory - appears twice */ /* Read only memory - appears twice */
@ -186,12 +186,20 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define ADDR_IS_QBM(x) ((((uint32) (x)) >= QBMBASE) && \ #define ADDR_IS_QBM(x) ((((uint32) (x)) >= QBMBASE) && \
(((uint32) (x)) < (QBMBASE + QBMSIZE))) (((uint32) (x)) < (QBMBASE + QBMSIZE)))
/* Reflect to IO on either IO space or Qbus memory */
#define ADDR_IS_IO(x) (ADDR_IS_IOP(x) || ADDR_IS_QBM(x))
/* QVSS memory space */ /* QVSS memory space */
#define QVMAWIDTH 18 /* QVSS mem addr width */ #define QVMAWIDTH 18 /* QVSS mem addr width */
#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ #define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */
#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ #define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
#define QVMBASE 0x303C0000 /* QVSS mem base */ #define QVMBASE 0x303C0000 /* QVSS mem base */
#define ADDR_IS_QVM(x) (vc_buf && \
(((uint32) (x)) >= QVMBASE) && \
(((uint32) (x)) < (QVMBASE + QVMSIZE)))
extern uint32 *vc_buf;
/* QDSS memory space */ /* QDSS memory space */
@ -199,6 +207,10 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define QDMSIZE (1u << QDMAWIDTH) /* QDSS mem length */ #define QDMSIZE (1u << QDMAWIDTH) /* QDSS mem length */
#define QDMAMASK (QDMSIZE - 1) /* QDSS mem addr mask */ #define QDMAMASK (QDMSIZE - 1) /* QDSS mem addr mask */
#define QDMBASE ((uint32)(0x30000000 + va_addr))/* QDSS mem base */ #define QDMBASE ((uint32)(0x30000000 + va_addr))/* QDSS mem base */
#define ADDR_IS_QDM(x) (va_buf && \
(((uint32) (x)) >= QDMBASE) && \
(((uint32) (x)) < (QDMBASE + QDMSIZE)))
extern uint32 *va_buf;
extern uint32 va_addr; /* QDSS memory offset */ extern uint32 va_addr; /* QDSS memory offset */
/* Other address spaces */ /* Other address spaces */

View file

@ -79,6 +79,8 @@ extern uint32 va_addr; /* QDSS (VCB02) Qbus Mem
t_stat dbl_rd (int32 *data, int32 addr, int32 access); t_stat dbl_rd (int32 *data, int32 addr, int32 access);
t_stat dbl_wr (int32 data, int32 addr, int32 access); t_stat dbl_wr (int32 data, int32 addr, int32 access);
t_stat qbmem_rd (int32 *dat, int32 pa, int32 md);
t_stat qbmem_wr (int32 dat, int32 pa, int32 md);
int32 eval_int (void); int32 eval_int (void);
t_stat qba_reset (DEVICE *dptr); t_stat qba_reset (DEVICE *dptr);
t_stat qba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); t_stat qba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
@ -168,7 +170,7 @@ int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */
int32 int_vec[IPL_HLVL][32]; /* int req to vector */ int32 int_vec[IPL_HLVL][32]; /* int req to vector */
/* The KA620/KA630 handles errors in I/O space as follows /* The KA620/KA630 handles errors on the Qbus or I/O space as follows
- read: machine check - read: machine check
- write: machine check (?) - write: machine check (?)
@ -178,6 +180,10 @@ int32 ReadQb (uint32 pa)
{ {
int32 idx, val; int32 idx, val;
if (ADDR_IS_QBM (pa)) { /* Qbus memory? */
qbmem_rd (&val, pa, READ);
return val;
}
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispR[idx]) { if (iodispR[idx]) {
iodispR[idx] (&val, pa, READ); iodispR[idx] (&val, pa, READ);
@ -191,6 +197,10 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
{ {
int32 idx; int32 idx;
if (ADDR_IS_QBM (pa)) { /* Qbus memory? */
qbmem_wr (val, pa, mode);
return;
}
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispW[idx]) { if (iodispW[idx]) {
iodispW[idx] (val, pa, mode); iodispW[idx] (val, pa, mode);
@ -432,7 +442,7 @@ return SCPE_OK;
Write error: machine check? Write error: machine check?
*/ */
int32 qbmap_rd (int32 pa) int32 qbmap_rd (int32 pa, int32 lnt)
{ {
int32 idx = ((pa - QBMAPBASE) >> 2); int32 idx = ((pa - QBMAPBASE) >> 2);
@ -459,59 +469,84 @@ return;
/* Qbus memory read and write (reflects to main memory) /* Qbus memory read and write (reflects to main memory)
May give master or slave error, depending on where the failure occurs Qbus memory is modeled like any other Qbus peripheral.
On read, it returns 16b, right justified.
On write, it handles either 16b or 8b writes.
Qbus memory may reflect to main memory or may be locally
implemented for graphics cards. If reflected to main memory,
the normal ReadW, WriteB, and WriteW routines cannot be used,
as that could create a recursive loop.
*/ */
int32 qbmem_rd (int32 pa) t_stat qbmem_rd (int32 *dat, int32 pa, int32 md)
{ {
int32 qa = pa & QBMAMASK; /* Qbus addr */ int32 qa = pa & QBMAMASK; /* Qbus addr */
uint32 ma; uint32 ma;
if (qba_map_addr (qa, &ma)) { /* in map? */
if (ADDR_IS_MEM (ma)) { /* real memory? */
*dat = (M[ma >> 2] >> ((pa & 2) ? 16 : 0)) & WMASK;
return SCPE_OK; /* return word */
} /* end if mem */
MACH_CHECK (MCHK_READ); /* mcheck */
}
#if !defined(VAX_620) #if !defined(VAX_620)
if (sys_model == 1) { /* VAXstation II? */ if (sys_model == 1) { /* VAXstation II? */
if (((uint32)pa >= QVMBASE) && ((uint32)pa < QVMBASE+QVMSIZE)) if (ADDR_IS_QVM (pa)) { /* QVSS memory? */
return vc_mem_rd (pa); /* read QVSS */ *dat = vc_mem_rd (pa);
return SCPE_OK;
}
} }
else if (sys_model == 2) { /* VAXstation II/GPX? */ else if (sys_model == 2) { /* VAXstation II/GPX? */
if (((uint32)pa >= QDMBASE) && ((uint32)pa < QDMBASE+QDMSIZE)) if (ADDR_IS_QDM (pa)) { /* QDSS memory? */
return va_mem_rd (pa); /* read QDSS */ *dat = va_mem_rd (pa);
return SCPE_OK;
}
} }
#endif #endif
if (qba_map_addr (qa, &ma)) { /* map addr */
return ReadW (ma);
}
MACH_CHECK (MCHK_READ); /* err? mcheck */ MACH_CHECK (MCHK_READ); /* err? mcheck */
return 0; return 0;
} }
void qbmem_wr (int32 pa, int32 val, int32 lnt) t_stat qbmem_wr (int32 dat, int32 pa, int32 md)
{ {
int32 qa = pa & QBMAMASK; /* Qbus addr */ int32 qa = pa & QBMAMASK; /* Qbus addr */
uint32 ma; uint32 ma;
if (qba_map_addr (qa, &ma)) { /* in map? */
if (ADDR_IS_MEM (ma)) { /* real memory? */
if (md == WRITE) { /* word access? */
int32 sc = (ma & 2) << 3; /* aligned only */
M[ma >> 2] = (M[ma >> 2] & ~(WMASK << sc)) |
((dat & WMASK) << sc);
}
else { /* byte access */
int32 sc = (ma & 3) << 3;
M[ma >> 2] = (M[ma >> 2] & ~(BMASK << sc)) |
((dat & BMASK) << sc);
}
} /* end if mem */
else
mem_err = 1;
return SCPE_OK;
} /* end if mapped */
#if !defined(VAX_620) #if !defined(VAX_620)
if (sys_model == 1) { /* VAXstation II? */ if (sys_model == 1) { /* VAXstation II? */
if (((uint32)pa >= QVMBASE) && ((uint32)pa < QVMBASE+QVMSIZE)) if (ADDR_IS_QVM (pa)) { /* QVSS memory? */
vc_mem_wr (pa, val, lnt); /* write QVSS */ vc_mem_wr (pa, dat, md);
return; return SCPE_OK;
}
} }
else if (sys_model == 2) { /* VAXstation II/GPX? */ else if (sys_model == 2) { /* VAXstation II/GPX? */
if (((uint32)pa >= QDMBASE) && ((uint32)pa < QDMBASE+QDMSIZE)) if (ADDR_IS_QDM (pa)) { /* QDSS memory? */
va_mem_wr (pa, val, lnt); /* write QDSS */ va_mem_wr (pa, dat, md);
return; return SCPE_OK;
}
} }
#endif #endif
if (qba_map_addr (qa, &ma)) { /* map addr */ mem_err = 1;
if (lnt < L_LONG) { return SCPE_OK;
int32 sc = (pa & 3) << 3;
int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
int32 t = M[ma >> 2];
val = ((val & mask) << sc) | (t & ~(mask << sc));
}
WriteW (ma, val);
}
else mem_err = 1;
return;
} }
/* Map an address via the translation map */ /* Map an address via the translation map */

View file

@ -152,17 +152,17 @@ t_stat sysd_reset (DEVICE *dptr);
t_stat sysd_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); t_stat sysd_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *sysd_description (DEVICE *dptr); const char *sysd_description (DEVICE *dptr);
int32 rom_rd (int32 pa); int32 rom_rd (int32 pa, int32 lnt);
int32 nvr_rd (int32 pa); int32 nvr_rd (int32 pa, int32 lnt);
void nvr_wr (int32 pa, int32 val, int32 lnt); void nvr_wr (int32 pa, int32 val, int32 lnt);
int32 ka_rd (int32 pa); int32 ka_rd (int32 pa, int32 lnt);
void ka_wr (int32 pa, int32 val, int32 lnt); void ka_wr (int32 pa, int32 val, int32 lnt);
t_stat sysd_powerup (void); t_stat sysd_powerup (void);
int32 con_halt (int32 code, int32 cc); int32 con_halt (int32 code, int32 cc);
extern int32 qbmap_rd (int32 pa); extern int32 qbmap_rd (int32 pa, int32 lnt);
extern void qbmap_wr (int32 pa, int32 val, int32 lnt); extern void qbmap_wr (int32 pa, int32 val, int32 lnt);
extern int32 qbmem_rd (int32 pa); extern int32 qbmem_rd (int32 pa, int32 lnt);
extern void qbmem_wr (int32 pa, int32 val, int32 lnt); extern void qbmem_wr (int32 pa, int32 val, int32 lnt);
extern int32 iccs_rd (void); extern int32 iccs_rd (void);
extern int32 todr_rd (void); extern int32 todr_rd (void);
@ -290,7 +290,7 @@ DEVICE sysd_dev = {
issues with the embedded timing loops. issues with the embedded timing loops.
*/ */
int32 rom_rd (int32 pa) int32 rom_rd (int32 pa, int32 lnt)
{ {
int32 rg = ((pa - ROMBASE) & ROMAMASK) >> 2; int32 rg = ((pa - ROMBASE) & ROMAMASK) >> 2;
int32 val = rom[rg]; int32 val = rom[rg];
@ -380,7 +380,7 @@ return "read-only memory";
/* NVR: non-volatile RAM - stored in a buffered file */ /* NVR: non-volatile RAM - stored in a buffered file */
int32 nvr_rd (int32 pa) int32 nvr_rd (int32 pa, int32 lnt)
{ {
int32 rg = (pa + 1 - NVRBASE) >> 1; int32 rg = (pa + 1 - NVRBASE) >> 1;
int32 result; int32 result;
@ -690,17 +690,15 @@ return;
struct reglink { /* register linkage */ struct reglink { /* register linkage */
uint32 low; /* low addr */ uint32 low; /* low addr */
uint32 high; /* high addr */ uint32 high; /* high addr */
int32 (*read)(int32 pa); /* read routine */ int32 (*read)(int32 pa, int32 lnt); /* read routine */
void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */ void (*write)(int32 pa, int32 val, int32 lnt);/* write routine */
int32 width; /* data path width */
}; };
struct reglink regtable[] = { struct reglink regtable[] = {
{ QBMAPBASE, QBMAPBASE+QBMAPSIZE, &qbmap_rd, &qbmap_wr, L_LONG }, { QBMAPBASE, QBMAPBASE+QBMAPSIZE, &qbmap_rd, &qbmap_wr },
{ ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL, L_LONG }, { ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL },
{ NVRBASE, NVRBASE+NVRASIZE, &nvr_rd, &nvr_wr, L_LONG }, { NVRBASE, NVRBASE+NVRASIZE, &nvr_rd, &nvr_wr },
{ KABASE, KABASE+KASIZE, &ka_rd, &ka_wr, L_LONG }, { KABASE, KABASE+KASIZE, &ka_rd, &ka_wr },
{ QBMBASE, QBMBASE+QBMSIZE, &qbmem_rd, &qbmem_wr, L_WORD },
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL }
}; };
@ -716,18 +714,10 @@ struct reglink regtable[] = {
int32 ReadReg (uint32 pa, int32 lnt) int32 ReadReg (uint32 pa, int32 lnt)
{ {
struct reglink *p; struct reglink *p;
int32 val;
for (p = &regtable[0]; p->low != 0; p++) { for (p = &regtable[0]; p->low != 0; p++) {
if ((pa >= p->low) && (pa < p->high) && p->read) { if ((pa >= p->low) && (pa < p->high) && p->read)
val = p->read (pa); return p->read (pa, lnt);
if (p->width < L_LONG) {
if (lnt < L_LONG)
val = val << ((pa & 2)? 16: 0);
else val = (p->read (pa + 2) << 16) | val;
}
return val;
}
} }
MACH_CHECK (MCHK_READ); MACH_CHECK (MCHK_READ);
@ -749,17 +739,10 @@ int32 val;
for (p = &regtable[0]; p->low != 0; p++) { for (p = &regtable[0]; p->low != 0; p++) {
if ((pa >= p->low) && (pa < p->high) && p->read) { if ((pa >= p->low) && (pa < p->high) && p->read) {
if (p->width < L_LONG) { if (lnt == L_BYTE)
val = p->read (pa); val = p->read (pa & ~03, L_LONG);
if ((lnt + (pa & 1)) <= 2) else
val = val << ((pa & 2)? 16: 0); val = (p->read (pa & ~03, L_LONG) & WMASK) | (p->read ((pa & ~03) + 2, L_LONG) & (WMASK << 16));
else val = (p->read (pa + 2) << 16) | val;
}
else {
if (lnt == L_BYTE)
val = p->read (pa & ~03);
else val = (p->read (pa & ~03) & WMASK) | (p->read ((pa & ~03) + 2) & (WMASK << 16));
}
return val; return val;
} }
} }
@ -783,11 +766,7 @@ struct reglink *p;
for (p = &regtable[0]; p->low != 0; p++) { for (p = &regtable[0]; p->low != 0; p++) {
if ((pa >= p->low) && (pa < p->high) && p->write) { if ((pa >= p->low) && (pa < p->high) && p->write) {
if (lnt > p->width) { p->write (pa, val, lnt);
p->write (pa, val & WMASK, L_WORD);
p->write (pa + 2, (val >> 16) & WMASK, L_WORD);
}
else p->write (pa, val, lnt);
return; return;
} }
} }
@ -807,53 +786,16 @@ MACH_CHECK (MCHK_WRITE);
void WriteRegU (uint32 pa, int32 val, int32 lnt) void WriteRegU (uint32 pa, int32 val, int32 lnt)
{ {
struct reglink *p; int32 sc = (pa & 03) << 3;
int32 dat = ReadReg (pa & ~03, L_LONG);
for (p = &regtable[0]; p->low != 0; p++) { dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc);
if ((pa >= p->low) && (pa < p->high) && p->write) { WriteReg (pa & ~03, dat, L_LONG);
if (p->width < L_LONG) {
switch (lnt) {
case L_BYTE: /* byte */
p->write (pa, val & BMASK, L_BYTE);
break;
case L_WORD: /* word */
if (pa & 1) { /* odd addr? */
p->write (pa, val & BMASK, L_BYTE);
p->write (pa + 1, (val >> 8) & BMASK, L_BYTE);
}
else p->write (pa, val & WMASK, L_WORD);
break;
case 3: /* tribyte */
if (pa & 1) { /* odd addr? */
p->write (pa, val & BMASK, L_BYTE); /* byte then word */
p->write (pa + 1, (val >> 8) & WMASK, L_WORD);
}
else { /* even */
p->write (pa, val & WMASK, WRITE); /* word then byte */
p->write (pa + 2, (val >> 16) & BMASK, L_BYTE);
}
break;
}
}
else if (p->read) {
int32 sc = (pa & 03) << 3;
int32 dat = p->read (pa & ~03);
dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc);
p->write (pa & ~03, dat, L_LONG);
}
return;
}
}
MACH_CHECK (MCHK_WRITE);
} }
/* KA630 registers */ /* KA630 registers */
int32 ka_rd (int32 pa) int32 ka_rd (int32 pa, int32 lnt)
{ {
int32 rg = (pa - KABASE) >> 2; int32 rg = (pa - KABASE) >> 2;

View file

@ -1,6 +1,6 @@
/* vax_io.c: VAX 3900 Qbus IO simulator /* vax_io.c: VAX 3900 Qbus IO simulator
Copyright (c) 1998-2013, Robert M Supnik Copyright (c) 1998-2019, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
qba Qbus adapter qba Qbus adapter
05-May-19 RMS Revamped Qbus memory as Qbus peripheral
20-Dec-13 RMS Added unaligned access routines 20-Dec-13 RMS Added unaligned access routines
25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata) 25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata)
28-May-08 RMS Inlined physical memory routines 28-May-08 RMS Inlined physical memory routines
@ -117,11 +118,12 @@ int32 autcon_enb = 1; /* autoconfig enable */
extern int32 ssc_bto; extern int32 ssc_bto;
extern int32 vc_mem_rd (int32 pa); extern int32 vc_mem_rd (int32 pa);
extern void vc_mem_wr (int32 pa, int32 val, int32 lnt); extern void vc_mem_wr (int32 pa, int32 val, int32 mode);
extern uint32 *vc_buf;
t_stat dbl_rd (int32 *data, int32 addr, int32 access); t_stat dbl_rd (int32 *data, int32 addr, int32 access);
t_stat dbl_wr (int32 data, int32 addr, int32 access); t_stat dbl_wr (int32 data, int32 addr, int32 access);
t_stat cqm_rd(int32 *dat, int32 ad, int32 md);
t_stat cqm_wr(int32 dat, int32 ad, int32 md);
int32 eval_int (void); int32 eval_int (void);
void cq_merr (int32 pa); void cq_merr (int32 pa);
void cq_serr (int32 pa); void cq_serr (int32 pa);
@ -210,6 +212,10 @@ int32 ReadQb (uint32 pa)
{ {
int32 idx, val; int32 idx, val;
if (ADDR_IS_CQM (pa)) { /* Qbus memory? */
cqm_rd (&val, pa, READ);
return val;
}
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispR[idx]) { if (iodispR[idx]) {
iodispR[idx] (&val, pa, READ); iodispR[idx] (&val, pa, READ);
@ -224,6 +230,10 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
{ {
int32 idx; int32 idx;
if (ADDR_IS_CQM (pa)) { /* Qbus memory? */
cqm_wr (val, pa, mode);
return;
}
idx = (pa & IOPAGEMASK) >> 1; idx = (pa & IOPAGEMASK) >> 1;
if (iodispW[idx]) { if (iodispW[idx]) {
iodispW[idx] (val, pa, mode); iodispW[idx] (val, pa, mode);
@ -588,44 +598,64 @@ return;
/* CQBIC Qbus memory read and write (reflects to main memory) /* CQBIC Qbus memory read and write (reflects to main memory)
May give master or slave error, depending on where the failure occurs Qbus memory is modeled like any other Qbus peripheral.
On read, it returns 16b, right justified.
On write, it handles either 16b or 8b writes.
Qbus memory may reflect to main memory or may be locally
implemented for graphics cards. If reflected to main memory,
the normal ReadW, WriteB, and WriteW routines cannot be used,
as that could create a recursive loop.
*/ */
t_stat cqm_rd (int32 *dat, int32 pa, int32 md)
int32 cqmem_rd (int32 pa)
{ {
int32 qa = pa & CQMAMASK; /* Qbus addr */ int32 qa = pa & CQMAMASK; /* Qbus addr */
uint32 ma; uint32 ma;
if (qba_map_addr (qa, &ma)) /* map addr */ if (qba_map_addr (qa, &ma)) { /* in map? */
return M[ma >> 2]; if (ADDR_IS_MEM (ma)) { /* real memory? */
if (ADDR_IS_QVM(pa) && vc_buf) /* QVSS memory? */ *dat = (M[ma >> 2] >> ((pa & 2) ? 16 : 0)) & WMASK;
return vc_mem_rd (pa); return SCPE_OK; /* return word */
} /* end if mem */
cq_serr (ma);
MACH_CHECK (MCHK_READ); /* mcheck */
} /* end if mapped */
if (ADDR_IS_QVM(pa)) { /* QVSS memory? */
*dat = vc_mem_rd (pa);
return SCPE_OK;
}
MACH_CHECK (MCHK_READ); /* err? mcheck */ MACH_CHECK (MCHK_READ); /* err? mcheck */
return 0; return SCPE_OK;
} }
void cqmem_wr (int32 pa, int32 val, int32 lnt) t_stat cqm_wr (int32 dat, int32 pa, int32 md)
{ {
int32 qa = pa & CQMAMASK; /* Qbus addr */ int32 qa = pa & CQMAMASK; /* Qbus addr */
uint32 ma; uint32 ma;
if (qba_map_addr (qa, &ma)) { /* map addr */ if (qba_map_addr (qa, &ma)) { /* in map? */
if (lnt < L_LONG) { if (ADDR_IS_MEM (ma)) { /* real memory? */
int32 sc = (pa & 3) << 3; if (md == WRITE) { /* word access? */
int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; int32 sc = (ma & 2) << 3; /* aligned only */
int32 t = M[ma >> 2]; M[ma >> 2] = (M[ma >> 2] & ~(WMASK << sc)) |
val = ((val & mask) << sc) | (t & ~(mask << sc)); ((dat & WMASK) << sc);
} }
M[ma >> 2] = val; else { /* byte access */
} int32 sc = (ma & 3) << 3;
else { M[ma >> 2] = (M[ma >> 2] & ~(BMASK << sc)) |
if (ADDR_IS_QVM(pa) && vc_buf) /* QVSS Memory */ ((dat & BMASK) << sc);
vc_mem_wr (pa, val, lnt); }
} /* end if mem */
else else
mem_err = 1; mem_err = 1;
} return SCPE_OK;
return; } /* end if mapped */
if (ADDR_IS_QVM(pa)) /* QVSS Memory */
vc_mem_wr (pa, dat, md);
else
mem_err = 1;
return SCPE_OK;
} }
/* Map an address via the translation map */ /* Map an address via the translation map */

View file

@ -153,7 +153,8 @@ if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */
xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */ xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */
pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03;
} }
else pa1 = ((pa + 4) & PAMASK) & ~03; /* not cross page */ else
pa1 = ((pa + 4) & PAMASK) & ~03; /* not cross page */
bo = pa & 3; bo = pa & 3;
if (lnt >= L_LONG) { /* lw unaligned? */ if (lnt >= L_LONG) { /* lw unaligned? */
sc = bo << 3; sc = bo << 3;
@ -205,9 +206,12 @@ else {
if ((pa & (lnt - 1)) == 0) { /* aligned? */ if ((pa & (lnt - 1)) == 0) { /* aligned? */
if (lnt >= L_LONG) /* long, quad? */ if (lnt >= L_LONG) /* long, quad? */
WriteL (pa, val); WriteL (pa, val);
else if (lnt == L_WORD) /* word? */ else {
WriteW (pa, val); if (lnt == L_WORD) /* word? */
else WriteB (pa, val); /* byte */ WriteW (pa, val);
else
WriteB (pa, val); /* byte */
}
return; return;
} }
if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) {
@ -219,7 +223,8 @@ if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) {
xpte = fill (va + lnt, lnt, acc, NULL); xpte = fill (va + lnt, lnt, acc, NULL);
pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03; pa1 = ((xpte.pte & TLB_PFN) | VA_GETOFF (va + 4)) & ~03;
} }
else pa1 = ((pa + 4) & PAMASK) & ~03; else
pa1 = ((pa + 4) & PAMASK) & ~03;
bo = pa & 3; bo = pa & 3;
if (lnt >= L_LONG) { if (lnt >= L_LONG) {
sc = bo << 3; sc = bo << 3;
@ -253,7 +258,8 @@ if (mapen) { /* mapping on? */
xpte = fill (va, L_BYTE, acc, status); /* fill TB */ xpte = fill (va, L_BYTE, acc, status); /* fill TB */
if (*status == PR_OK) if (*status == PR_OK)
return (xpte.pte & TLB_PFN) | off; return (xpte.pte & TLB_PFN) | off;
else return -1; else
return -1;
} }
return va & PAMASK; /* ret phys addr */ return va & PAMASK; /* ret phys addr */
} }
@ -276,7 +282,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
dat = ReadIO (pa, L_BYTE); dat = ReadIO (pa, L_BYTE);
else dat = ReadReg (pa, L_BYTE); else
dat = ReadReg (pa, L_BYTE);
} }
return ((dat >> ((pa & 3) << 3)) & BMASK); return ((dat >> ((pa & 3) << 3)) & BMASK);
} }
@ -291,7 +298,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
dat = ReadIO (pa, L_WORD); dat = ReadIO (pa, L_WORD);
else dat = ReadReg (pa, L_WORD); else
dat = ReadReg (pa, L_WORD);
} }
return ((dat >> ((pa & 2)? 16: 0)) & WMASK); return ((dat >> ((pa & 2)? 16: 0)) & WMASK);
} }
@ -336,7 +344,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
dat = ReadIOU (pa, lnt); dat = ReadIOU (pa, lnt);
else dat = ReadRegU (pa, lnt); else
dat = ReadRegU (pa, lnt);
} }
return ((dat >> sc) & insert[lnt]); return ((dat >> sc) & insert[lnt]);
} }
@ -362,7 +371,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
WriteIO (pa, val, L_BYTE); WriteIO (pa, val, L_BYTE);
else WriteReg (pa, val, L_BYTE); else
WriteReg (pa, val, L_BYTE);
} }
return; return;
} }
@ -378,7 +388,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
WriteIO (pa, val, L_WORD); WriteIO (pa, val, L_WORD);
else WriteReg (pa, val, L_WORD); else
WriteReg (pa, val, L_WORD);
} }
return; return;
} }
@ -391,7 +402,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
WriteIO (pa, val, L_LONG); WriteIO (pa, val, L_LONG);
else WriteReg (pa, val, L_LONG); else
WriteReg (pa, val, L_LONG);
} }
return; return;
} }
@ -405,7 +417,8 @@ else {
mchk_ref = REF_P; mchk_ref = REF_P;
if (ADDR_IS_IO (pa)) if (ADDR_IS_IO (pa))
WriteIO (pa, val, L_LONG); WriteIO (pa, val, L_LONG);
else WriteReg (pa, val, L_LONG); else
WriteReg (pa, val, L_LONG);
} }
return; return;
} }
@ -431,7 +444,8 @@ else {
mchk_ref = REF_V; mchk_ref = REF_V;
if ADDR_IS_IO (pa) if ADDR_IS_IO (pa)
WriteIOU (pa, val, lnt); WriteIOU (pa, val, lnt);
else WriteRegU (pa, val, lnt); else
WriteRegU (pa, val, lnt);
} }
return; return;
} }

View file

@ -1,6 +1,6 @@
/* vax_sysdev.c: VAX 3900 system-specific logic /* vax_sysdev.c: VAX 3900 system-specific logic
Copyright (c) 1998-2013, Robert M Supnik Copyright (c) 1998-2019, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -33,6 +33,7 @@
cmctl memory controller cmctl memory controller
sysd system devices (SSC miscellany) sysd system devices (SSC miscellany)
05-May-19 RMS Removed Qbus memory space from register space
20-Dec-13 RMS Added unaligned register space access routines 20-Dec-13 RMS Added unaligned register space access routines
23-Dec-10 RMS Added power clear call to boot routine (Mark Pizzolato) 23-Dec-10 RMS Added power clear call to boot routine (Mark Pizzolato)
25-Oct-05 RMS Automated CMCTL extended memory 25-Oct-05 RMS Automated CMCTL extended memory
@ -309,8 +310,6 @@ extern int32 cqipc_rd (int32 pa);
extern void cqipc_wr (int32 pa, int32 val, int32 lnt); extern void cqipc_wr (int32 pa, int32 val, int32 lnt);
extern int32 cqbic_rd (int32 pa); extern int32 cqbic_rd (int32 pa);
extern void cqbic_wr (int32 pa, int32 val, int32 lnt); extern void cqbic_wr (int32 pa, int32 val, int32 lnt);
extern int32 cqmem_rd (int32 pa);
extern void cqmem_wr (int32 pa, int32 val, int32 lnt);
extern int32 iccs_rd (void); extern int32 iccs_rd (void);
extern int32 todr_rd (void); extern int32 todr_rd (void);
extern int32 rxcs_rd (void); extern int32 rxcs_rd (void);
@ -1010,7 +1009,6 @@ struct reglink regtable[] = {
{ KABASE, KABASE+KASIZE, &ka_rd, &ka_wr }, { KABASE, KABASE+KASIZE, &ka_rd, &ka_wr },
{ CQBICBASE, CQBICBASE+CQBICSIZE, &cqbic_rd, &cqbic_wr }, { CQBICBASE, CQBICBASE+CQBICSIZE, &cqbic_rd, &cqbic_wr },
{ CQIPCBASE, CQIPCBASE+CQIPCSIZE, &cqipc_rd, &cqipc_wr }, { CQIPCBASE, CQIPCBASE+CQIPCSIZE, &cqipc_rd, &cqipc_wr },
{ CQMBASE, CQMBASE+CQMSIZE, &cqmem_rd, &cqmem_wr },
{ CDGBASE, CDGBASE+CDGSIZE, &cdg_rd, &cdg_wr }, { CDGBASE, CDGBASE+CDGSIZE, &cdg_rd, &cdg_wr },
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL }
}; };
@ -1263,7 +1261,7 @@ for ( ; val != 0; val = val >> 1) {
return odd; return odd;
} }
/* SSC registers - byte/word merges done in WriteReg */ /* SSC registers - byte/word merges done in ssc_wr */
int32 ssc_rd (int32 pa) int32 ssc_rd (int32 pa)
{ {

View file

@ -672,31 +672,22 @@ int32 vc_mem_rd (int32 pa)
{ {
uint32 rg = (pa >> 2) & 0xFFFF; uint32 rg = (pa >> 2) & 0xFFFF;
if (!vc_buf) /* QVSS disabled? */ return (pa & 0x2) ? (vc_buf[rg] >> 16) : vc_buf[rg] & WMASK;
MACH_CHECK (MCHK_READ); /* Invalid memory reference */
return (pa & 0x2) ? (vc_buf[rg] >> 16) : vc_buf[rg] & 0xFFFF;
} }
void vc_mem_wr (int32 pa, int32 val, int32 lnt) void vc_mem_wr (int32 pa, int32 val, int32 mode)
{ {
uint32 rg = (pa >> 2) & 0xFFFF; uint32 rg = (pa >> 2) & 0xFFFF;
uint32 nval; uint32 nval, t;
int32 lnt = (mode == WRITE) ? 2 : 1;
int32 i; int32 i;
int32 sc; int32 sc = (pa & 3) << 3;
uint32 scrln, bufln; uint32 scrln, bufln;
uint32 idx; uint32 idx;
uint32 mask = (mode == WRITE)? WMASK : BMASK;
if (!vc_buf) /* QVSS disabled? */ t = vc_buf[rg];
MACH_CHECK (MCHK_WRITE); /* Invalid memory reference */ nval = ((val & mask) << sc) | (t & ~(mask << sc));
if (lnt < L_LONG) {
uint32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
uint32 t = vc_buf[rg];
sc = (pa & 3) << 3;
nval = ((val & mask) << sc) | (t & ~(mask << sc));
}
else nval = (uint32)val;
if (rg >= 0xFFF8) { /* cursor image */ if (rg >= 0xFFF8) { /* cursor image */
idx = (pa << 3) & 0xFF; /* get byte index */ idx = (pa << 3) & 0xFF; /* get byte index */

View file

@ -1,6 +1,6 @@
/* vaxmod_defs.h: VAX model-specific definitions file /* vaxmod_defs.h: VAX model-specific definitions file
Copyright (c) 1998-2017, Robert M Supnik Copyright (c) 1998-2019, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
05-May-19 RMS Added Qbus memory space to ADDR_IS_IO test
18-May-17 RMS Added model-specific AST validation test 18-May-17 RMS Added model-specific AST validation test
20-Dec-13 RMS Added prototypes for unaligned IO and register handling 20-Dec-13 RMS Added prototypes for unaligned IO and register handling
11-Dec-11 RMS Moved all Qbus devices to BR4; deleted RP definitions 11-Dec-11 RMS Moved all Qbus devices to BR4; deleted RP definitions
@ -164,7 +165,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */ #define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */
#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */ #define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
#define IOPAGEBASE 0x20000000 /* IO page base */ #define IOPAGEBASE 0x20000000 /* IO page base */
#define ADDR_IS_IO(x) ((((uint32) (x)) >= IOPAGEBASE) && \ #define ADDR_IS_IOP(x) ((((uint32) (x)) >= IOPAGEBASE) && \
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE))) (((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE)))
/* Read only memory - appears twice */ /* Read only memory - appears twice */
@ -228,14 +229,20 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, CONST void* desc
#define ADDR_IS_CQM(x) ((((uint32) (x)) >= CQMBASE) && \ #define ADDR_IS_CQM(x) ((((uint32) (x)) >= CQMBASE) && \
(((uint32) (x)) < (CQMBASE + CQMSIZE))) (((uint32) (x)) < (CQMBASE + CQMSIZE)))
/* Reflect to IO on either IO space or Qbus memory */
#define ADDR_IS_IO(x) (ADDR_IS_IOP(x) || ADDR_IS_CQM(x))
/* QVSS memory space */ /* QVSS memory space */
#define QVMAWIDTH 18 /* QVSS mem addr width */ #define QVMAWIDTH 18 /* QVSS mem addr width */
#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ #define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */
#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ #define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
#define QVMBASE (CQMBASE + CQMSIZE - QVMSIZE) /* QVSS mem base - end of Qbus memory space */ #define QVMBASE (CQMBASE + CQMSIZE - QVMSIZE) /* QVSS mem base - end of Qbus memory space */
#define ADDR_IS_QVM(x) ((((uint32) (x)) >= QVMBASE) && \ #define ADDR_IS_QVM(x) (vc_buf && \
(((uint32) (x)) < (QVMBASE + QVMSIZE))) (((uint32) (x)) >= QVMBASE) && \
(((uint32) (x)) < (QVMBASE + QVMSIZE)))
extern uint32 *vc_buf;
/* Machine specific reserved operand tests (mostly NOPs) */ /* Machine specific reserved operand tests (mostly NOPs) */