VAX, MicroVAX I & II: Revamped Qbus memory access as Qbus peripheral
This commit is contained in:
parent
05f84879ad
commit
94f5034712
11 changed files with 232 additions and 188 deletions
|
@ -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 QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
|
||||
#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 */
|
||||
|
||||
|
@ -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 IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
|
||||
#define IOPAGEBASE 0x20000000 /* IO page base */
|
||||
#define ADDR_IS_IO(x) ((((uint32) (x)) >= IOPAGEBASE) && \
|
||||
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE)))
|
||||
#define ADDR_IS_IO(x) ((ADDR_IS_QVM (x)) || \
|
||||
((((uint32) (x)) >= IOPAGEBASE) && \
|
||||
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE))))
|
||||
|
||||
/* Other address spaces */
|
||||
|
||||
|
|
|
@ -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 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);
|
||||
t_stat qba_reset (DEVICE *dptr);
|
||||
const char *qba_description (DEVICE *dptr);
|
||||
|
@ -102,6 +105,9 @@ int32 ReadQb (uint32 pa)
|
|||
{
|
||||
int32 idx, val;
|
||||
|
||||
if (ADDR_IS_QVM (pa))
|
||||
return vc_mem_rd (pa);
|
||||
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispR[idx]) {
|
||||
iodispR[idx] (&val, pa, READ);
|
||||
|
@ -115,6 +121,11 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
|
|||
{
|
||||
int32 idx;
|
||||
|
||||
if (ADDR_IS_QVM (pa)) {
|
||||
vc_mem_wr (pa, val, mode);
|
||||
return;
|
||||
}
|
||||
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispW[idx]) {
|
||||
iodispW[idx] (val, pa, mode);
|
||||
|
@ -140,7 +151,8 @@ int32 iod;
|
|||
iod = ReadQb (pa); /* wd from Qbus */
|
||||
if (lnt < L_LONG) /* bw? position */
|
||||
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;
|
||||
return iod;
|
||||
}
|
||||
|
@ -182,7 +194,8 @@ int32 iod;
|
|||
iod = ReadQb (pa); /* wd from Qbus */
|
||||
if ((lnt + (pa & 1)) <= 2) /* byte or (word & even) */
|
||||
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;
|
||||
return iod;
|
||||
}
|
||||
|
|
|
@ -66,8 +66,6 @@ const char *sysd_description (DEVICE *dptr);
|
|||
t_stat vax610_boot (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 todr_rd (void);
|
||||
extern int32 rxcs_rd (void);
|
||||
|
@ -265,12 +263,11 @@ return;
|
|||
struct reglink { /* register linkage */
|
||||
uint32 low; /* low 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 */
|
||||
};
|
||||
|
||||
struct reglink regtable[] = {
|
||||
{ QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -289,7 +286,7 @@ struct reglink *p;
|
|||
|
||||
for (p = ®table[0]; p->low != 0; p++) {
|
||||
if ((pa >= p->low) && (pa < p->high) && p->read)
|
||||
return p->read (pa);
|
||||
return p->read (pa, lnt);
|
||||
}
|
||||
MACH_CHECK (MCHK_READ);
|
||||
}
|
||||
|
|
|
@ -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 IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
|
||||
#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)))
|
||||
|
||||
/* 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) && \
|
||||
(((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 */
|
||||
|
||||
#define QVMAWIDTH 18 /* QVSS mem addr width */
|
||||
#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */
|
||||
#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
|
||||
#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 */
|
||||
|
||||
|
@ -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 QDMAMASK (QDMSIZE - 1) /* QDSS mem addr mask */
|
||||
#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 */
|
||||
|
||||
/* Other address spaces */
|
||||
|
|
|
@ -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_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);
|
||||
t_stat qba_reset (DEVICE *dptr);
|
||||
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 */
|
||||
|
||||
/* 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
|
||||
- write: machine check (?)
|
||||
|
@ -178,6 +180,10 @@ int32 ReadQb (uint32 pa)
|
|||
{
|
||||
int32 idx, val;
|
||||
|
||||
if (ADDR_IS_QBM (pa)) { /* Qbus memory? */
|
||||
qbmem_rd (&val, pa, READ);
|
||||
return val;
|
||||
}
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispR[idx]) {
|
||||
iodispR[idx] (&val, pa, READ);
|
||||
|
@ -191,6 +197,10 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
|
|||
{
|
||||
int32 idx;
|
||||
|
||||
if (ADDR_IS_QBM (pa)) { /* Qbus memory? */
|
||||
qbmem_wr (val, pa, mode);
|
||||
return;
|
||||
}
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispW[idx]) {
|
||||
iodispW[idx] (val, pa, mode);
|
||||
|
@ -432,7 +442,7 @@ return SCPE_OK;
|
|||
Write error: machine check?
|
||||
*/
|
||||
|
||||
int32 qbmap_rd (int32 pa)
|
||||
int32 qbmap_rd (int32 pa, int32 lnt)
|
||||
{
|
||||
int32 idx = ((pa - QBMAPBASE) >> 2);
|
||||
|
||||
|
@ -459,59 +469,84 @@ return;
|
|||
|
||||
/* 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 */
|
||||
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 (sys_model == 1) { /* VAXstation II? */
|
||||
if (((uint32)pa >= QVMBASE) && ((uint32)pa < QVMBASE+QVMSIZE))
|
||||
return vc_mem_rd (pa); /* read QVSS */
|
||||
if (ADDR_IS_QVM (pa)) { /* QVSS memory? */
|
||||
*dat = vc_mem_rd (pa);
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
else if (sys_model == 2) { /* VAXstation II/GPX? */
|
||||
if (((uint32)pa >= QDMBASE) && ((uint32)pa < QDMBASE+QDMSIZE))
|
||||
return va_mem_rd (pa); /* read QDSS */
|
||||
if (ADDR_IS_QDM (pa)) { /* QDSS memory? */
|
||||
*dat = va_mem_rd (pa);
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (qba_map_addr (qa, &ma)) { /* map addr */
|
||||
return ReadW (ma);
|
||||
}
|
||||
MACH_CHECK (MCHK_READ); /* err? mcheck */
|
||||
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 */
|
||||
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 (sys_model == 1) { /* VAXstation II? */
|
||||
if (((uint32)pa >= QVMBASE) && ((uint32)pa < QVMBASE+QVMSIZE))
|
||||
vc_mem_wr (pa, val, lnt); /* write QVSS */
|
||||
return;
|
||||
if (ADDR_IS_QVM (pa)) { /* QVSS memory? */
|
||||
vc_mem_wr (pa, dat, md);
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
else if (sys_model == 2) { /* VAXstation II/GPX? */
|
||||
if (((uint32)pa >= QDMBASE) && ((uint32)pa < QDMBASE+QDMSIZE))
|
||||
va_mem_wr (pa, val, lnt); /* write QDSS */
|
||||
return;
|
||||
if (ADDR_IS_QDM (pa)) { /* QDSS memory? */
|
||||
va_mem_wr (pa, dat, md);
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (qba_map_addr (qa, &ma)) { /* map addr */
|
||||
if (lnt < L_LONG) {
|
||||
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;
|
||||
mem_err = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Map an address via the translation map */
|
||||
|
|
|
@ -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);
|
||||
const char *sysd_description (DEVICE *dptr);
|
||||
|
||||
int32 rom_rd (int32 pa);
|
||||
int32 nvr_rd (int32 pa);
|
||||
int32 rom_rd (int32 pa, int32 lnt);
|
||||
int32 nvr_rd (int32 pa, 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);
|
||||
t_stat sysd_powerup (void);
|
||||
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 int32 qbmem_rd (int32 pa);
|
||||
extern int32 qbmem_rd (int32 pa, int32 lnt);
|
||||
extern void qbmem_wr (int32 pa, int32 val, int32 lnt);
|
||||
extern int32 iccs_rd (void);
|
||||
extern int32 todr_rd (void);
|
||||
|
@ -290,7 +290,7 @@ DEVICE sysd_dev = {
|
|||
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 val = rom[rg];
|
||||
|
@ -380,7 +380,7 @@ return "read-only memory";
|
|||
|
||||
/* 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 result;
|
||||
|
@ -690,17 +690,15 @@ return;
|
|||
struct reglink { /* register linkage */
|
||||
uint32 low; /* low addr */
|
||||
uint32 high; /* high addr */
|
||||
int32 (*read)(int32 pa); /* read routine */
|
||||
void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */
|
||||
int32 width; /* data path width */
|
||||
int32 (*read)(int32 pa, int32 lnt); /* read routine */
|
||||
void (*write)(int32 pa, int32 val, int32 lnt);/* write routine */
|
||||
};
|
||||
|
||||
struct reglink regtable[] = {
|
||||
{ QBMAPBASE, QBMAPBASE+QBMAPSIZE, &qbmap_rd, &qbmap_wr, L_LONG },
|
||||
{ ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL, L_LONG },
|
||||
{ NVRBASE, NVRBASE+NVRASIZE, &nvr_rd, &nvr_wr, L_LONG },
|
||||
{ KABASE, KABASE+KASIZE, &ka_rd, &ka_wr, L_LONG },
|
||||
{ QBMBASE, QBMBASE+QBMSIZE, &qbmem_rd, &qbmem_wr, L_WORD },
|
||||
{ QBMAPBASE, QBMAPBASE+QBMAPSIZE, &qbmap_rd, &qbmap_wr },
|
||||
{ ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL },
|
||||
{ NVRBASE, NVRBASE+NVRASIZE, &nvr_rd, &nvr_wr },
|
||||
{ KABASE, KABASE+KASIZE, &ka_rd, &ka_wr },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -716,18 +714,10 @@ struct reglink regtable[] = {
|
|||
int32 ReadReg (uint32 pa, int32 lnt)
|
||||
{
|
||||
struct reglink *p;
|
||||
int32 val;
|
||||
|
||||
for (p = ®table[0]; p->low != 0; p++) {
|
||||
if ((pa >= p->low) && (pa < p->high) && p->read) {
|
||||
val = p->read (pa);
|
||||
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;
|
||||
}
|
||||
if ((pa >= p->low) && (pa < p->high) && p->read)
|
||||
return p->read (pa, lnt);
|
||||
}
|
||||
|
||||
MACH_CHECK (MCHK_READ);
|
||||
|
@ -749,17 +739,10 @@ int32 val;
|
|||
|
||||
for (p = ®table[0]; p->low != 0; p++) {
|
||||
if ((pa >= p->low) && (pa < p->high) && p->read) {
|
||||
if (p->width < L_LONG) {
|
||||
val = p->read (pa);
|
||||
if ((lnt + (pa & 1)) <= 2)
|
||||
val = val << ((pa & 2)? 16: 0);
|
||||
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));
|
||||
}
|
||||
if (lnt == L_BYTE)
|
||||
val = p->read (pa & ~03, L_LONG);
|
||||
else
|
||||
val = (p->read (pa & ~03, L_LONG) & WMASK) | (p->read ((pa & ~03) + 2, L_LONG) & (WMASK << 16));
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
@ -783,11 +766,7 @@ struct reglink *p;
|
|||
|
||||
for (p = ®table[0]; p->low != 0; p++) {
|
||||
if ((pa >= p->low) && (pa < p->high) && p->write) {
|
||||
if (lnt > p->width) {
|
||||
p->write (pa, val & WMASK, L_WORD);
|
||||
p->write (pa + 2, (val >> 16) & WMASK, L_WORD);
|
||||
}
|
||||
else p->write (pa, val, lnt);
|
||||
p->write (pa, val, lnt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -807,53 +786,16 @@ MACH_CHECK (MCHK_WRITE);
|
|||
|
||||
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 = ®table[0]; p->low != 0; p++) {
|
||||
if ((pa >= p->low) && (pa < p->high) && p->write) {
|
||||
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);
|
||||
dat = (dat & ~(insert[lnt] << sc)) | ((val & insert[lnt]) << sc);
|
||||
WriteReg (pa & ~03, dat, L_LONG);
|
||||
}
|
||||
|
||||
/* KA630 registers */
|
||||
|
||||
int32 ka_rd (int32 pa)
|
||||
int32 ka_rd (int32 pa, int32 lnt)
|
||||
{
|
||||
int32 rg = (pa - KABASE) >> 2;
|
||||
|
||||
|
|
82
VAX/vax_io.c
82
VAX/vax_io.c
|
@ -1,6 +1,6 @@
|
|||
/* 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
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -25,6 +25,7 @@
|
|||
|
||||
qba Qbus adapter
|
||||
|
||||
05-May-19 RMS Revamped Qbus memory as Qbus peripheral
|
||||
20-Dec-13 RMS Added unaligned access routines
|
||||
25-Mar-12 RMS Added parameter to int_ack prototype (Mark Pizzolata)
|
||||
28-May-08 RMS Inlined physical memory routines
|
||||
|
@ -117,11 +118,12 @@ int32 autcon_enb = 1; /* autoconfig enable */
|
|||
|
||||
extern int32 ssc_bto;
|
||||
extern int32 vc_mem_rd (int32 pa);
|
||||
extern void vc_mem_wr (int32 pa, int32 val, int32 lnt);
|
||||
extern uint32 *vc_buf;
|
||||
extern void vc_mem_wr (int32 pa, int32 val, int32 mode);
|
||||
|
||||
t_stat dbl_rd (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);
|
||||
void cq_merr (int32 pa);
|
||||
void cq_serr (int32 pa);
|
||||
|
@ -210,6 +212,10 @@ int32 ReadQb (uint32 pa)
|
|||
{
|
||||
int32 idx, val;
|
||||
|
||||
if (ADDR_IS_CQM (pa)) { /* Qbus memory? */
|
||||
cqm_rd (&val, pa, READ);
|
||||
return val;
|
||||
}
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispR[idx]) {
|
||||
iodispR[idx] (&val, pa, READ);
|
||||
|
@ -224,6 +230,10 @@ void WriteQb (uint32 pa, int32 val, int32 mode)
|
|||
{
|
||||
int32 idx;
|
||||
|
||||
if (ADDR_IS_CQM (pa)) { /* Qbus memory? */
|
||||
cqm_wr (val, pa, mode);
|
||||
return;
|
||||
}
|
||||
idx = (pa & IOPAGEMASK) >> 1;
|
||||
if (iodispW[idx]) {
|
||||
iodispW[idx] (val, pa, mode);
|
||||
|
@ -588,44 +598,64 @@ return;
|
|||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
int32 cqmem_rd (int32 pa)
|
||||
t_stat cqm_rd (int32 *dat, int32 pa, int32 md)
|
||||
{
|
||||
int32 qa = pa & CQMAMASK; /* Qbus addr */
|
||||
uint32 ma;
|
||||
|
||||
if (qba_map_addr (qa, &ma)) /* map addr */
|
||||
return M[ma >> 2];
|
||||
if (ADDR_IS_QVM(pa) && vc_buf) /* QVSS memory? */
|
||||
return vc_mem_rd (pa);
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
uint32 ma;
|
||||
|
||||
if (qba_map_addr (qa, &ma)) { /* map addr */
|
||||
if (lnt < L_LONG) {
|
||||
int32 sc = (pa & 3) << 3;
|
||||
int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
|
||||
int32 t = M[ma >> 2];
|
||||
val = ((val & mask) << sc) | (t & ~(mask << sc));
|
||||
}
|
||||
M[ma >> 2] = val;
|
||||
}
|
||||
else {
|
||||
if (ADDR_IS_QVM(pa) && vc_buf) /* QVSS Memory */
|
||||
vc_mem_wr (pa, val, lnt);
|
||||
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;
|
||||
return SCPE_OK;
|
||||
} /* 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 */
|
||||
|
|
|
@ -153,7 +153,8 @@ if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */
|
|||
xpte = fill (va + lnt, lnt, acc, NULL); /* fill if needed */
|
||||
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;
|
||||
if (lnt >= L_LONG) { /* lw unaligned? */
|
||||
sc = bo << 3;
|
||||
|
@ -205,9 +206,12 @@ else {
|
|||
if ((pa & (lnt - 1)) == 0) { /* aligned? */
|
||||
if (lnt >= L_LONG) /* long, quad? */
|
||||
WriteL (pa, val);
|
||||
else if (lnt == L_WORD) /* word? */
|
||||
WriteW (pa, val);
|
||||
else WriteB (pa, val); /* byte */
|
||||
else {
|
||||
if (lnt == L_WORD) /* word? */
|
||||
WriteW (pa, val);
|
||||
else
|
||||
WriteB (pa, val); /* byte */
|
||||
}
|
||||
return;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
if (lnt >= L_LONG) {
|
||||
sc = bo << 3;
|
||||
|
@ -253,7 +258,8 @@ if (mapen) { /* mapping on? */
|
|||
xpte = fill (va, L_BYTE, acc, status); /* fill TB */
|
||||
if (*status == PR_OK)
|
||||
return (xpte.pte & TLB_PFN) | off;
|
||||
else return -1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
return va & PAMASK; /* ret phys addr */
|
||||
}
|
||||
|
@ -276,7 +282,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
dat = ReadIO (pa, L_BYTE);
|
||||
else dat = ReadReg (pa, L_BYTE);
|
||||
else
|
||||
dat = ReadReg (pa, L_BYTE);
|
||||
}
|
||||
return ((dat >> ((pa & 3) << 3)) & BMASK);
|
||||
}
|
||||
|
@ -291,7 +298,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
dat = ReadIO (pa, L_WORD);
|
||||
else dat = ReadReg (pa, L_WORD);
|
||||
else
|
||||
dat = ReadReg (pa, L_WORD);
|
||||
}
|
||||
return ((dat >> ((pa & 2)? 16: 0)) & WMASK);
|
||||
}
|
||||
|
@ -336,7 +344,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
dat = ReadIOU (pa, lnt);
|
||||
else dat = ReadRegU (pa, lnt);
|
||||
else
|
||||
dat = ReadRegU (pa, lnt);
|
||||
}
|
||||
return ((dat >> sc) & insert[lnt]);
|
||||
}
|
||||
|
@ -362,7 +371,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
WriteIO (pa, val, L_BYTE);
|
||||
else WriteReg (pa, val, L_BYTE);
|
||||
else
|
||||
WriteReg (pa, val, L_BYTE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -378,7 +388,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
WriteIO (pa, val, L_WORD);
|
||||
else WriteReg (pa, val, L_WORD);
|
||||
else
|
||||
WriteReg (pa, val, L_WORD);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -391,7 +402,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if (ADDR_IS_IO (pa))
|
||||
WriteIO (pa, val, L_LONG);
|
||||
else WriteReg (pa, val, L_LONG);
|
||||
else
|
||||
WriteReg (pa, val, L_LONG);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -405,7 +417,8 @@ else {
|
|||
mchk_ref = REF_P;
|
||||
if (ADDR_IS_IO (pa))
|
||||
WriteIO (pa, val, L_LONG);
|
||||
else WriteReg (pa, val, L_LONG);
|
||||
else
|
||||
WriteReg (pa, val, L_LONG);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -431,7 +444,8 @@ else {
|
|||
mchk_ref = REF_V;
|
||||
if ADDR_IS_IO (pa)
|
||||
WriteIOU (pa, val, lnt);
|
||||
else WriteRegU (pa, val, lnt);
|
||||
else
|
||||
WriteRegU (pa, val, lnt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -33,6 +33,7 @@
|
|||
cmctl memory controller
|
||||
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
|
||||
23-Dec-10 RMS Added power clear call to boot routine (Mark Pizzolato)
|
||||
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 int32 cqbic_rd (int32 pa);
|
||||
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 todr_rd (void);
|
||||
extern int32 rxcs_rd (void);
|
||||
|
@ -1010,7 +1009,6 @@ struct reglink regtable[] = {
|
|||
{ KABASE, KABASE+KASIZE, &ka_rd, &ka_wr },
|
||||
{ CQBICBASE, CQBICBASE+CQBICSIZE, &cqbic_rd, &cqbic_wr },
|
||||
{ CQIPCBASE, CQIPCBASE+CQIPCSIZE, &cqipc_rd, &cqipc_wr },
|
||||
{ CQMBASE, CQMBASE+CQMSIZE, &cqmem_rd, &cqmem_wr },
|
||||
{ CDGBASE, CDGBASE+CDGSIZE, &cdg_rd, &cdg_wr },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
@ -1263,7 +1261,7 @@ for ( ; val != 0; val = val >> 1) {
|
|||
return odd;
|
||||
}
|
||||
|
||||
/* SSC registers - byte/word merges done in WriteReg */
|
||||
/* SSC registers - byte/word merges done in ssc_wr */
|
||||
|
||||
int32 ssc_rd (int32 pa)
|
||||
{
|
||||
|
|
25
VAX/vax_vc.c
25
VAX/vax_vc.c
|
@ -672,31 +672,22 @@ int32 vc_mem_rd (int32 pa)
|
|||
{
|
||||
uint32 rg = (pa >> 2) & 0xFFFF;
|
||||
|
||||
if (!vc_buf) /* QVSS disabled? */
|
||||
MACH_CHECK (MCHK_READ); /* Invalid memory reference */
|
||||
|
||||
return (pa & 0x2) ? (vc_buf[rg] >> 16) : vc_buf[rg] & 0xFFFF;
|
||||
return (pa & 0x2) ? (vc_buf[rg] >> 16) : vc_buf[rg] & WMASK;
|
||||
}
|
||||
|
||||
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 nval;
|
||||
uint32 nval, t;
|
||||
int32 lnt = (mode == WRITE) ? 2 : 1;
|
||||
int32 i;
|
||||
int32 sc;
|
||||
int32 sc = (pa & 3) << 3;
|
||||
uint32 scrln, bufln;
|
||||
uint32 idx;
|
||||
uint32 mask = (mode == WRITE)? WMASK : BMASK;
|
||||
|
||||
if (!vc_buf) /* QVSS disabled? */
|
||||
MACH_CHECK (MCHK_WRITE); /* Invalid memory reference */
|
||||
|
||||
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;
|
||||
t = vc_buf[rg];
|
||||
nval = ((val & mask) << sc) | (t & ~(mask << sc));
|
||||
|
||||
if (rg >= 0xFFF8) { /* cursor image */
|
||||
idx = (pa << 3) & 0xFF; /* get byte index */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -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 IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
|
||||
#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)))
|
||||
|
||||
/* 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) && \
|
||||
(((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 */
|
||||
|
||||
#define QVMAWIDTH 18 /* QVSS mem addr width */
|
||||
#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */
|
||||
#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */
|
||||
#define QVMBASE (CQMBASE + CQMSIZE - QVMSIZE) /* QVSS mem base - end of Qbus memory space */
|
||||
#define ADDR_IS_QVM(x) ((((uint32) (x)) >= QVMBASE) && \
|
||||
(((uint32) (x)) < (QVMBASE + QVMSIZE)))
|
||||
#define ADDR_IS_QVM(x) (vc_buf && \
|
||||
(((uint32) (x)) >= QVMBASE) && \
|
||||
(((uint32) (x)) < (QVMBASE + QVMSIZE)))
|
||||
extern uint32 *vc_buf;
|
||||
|
||||
/* Machine specific reserved operand tests (mostly NOPs) */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue