From 94f5034712110574fdc714531c524187a0740753 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sun, 12 May 2019 21:52:06 -0700 Subject: [PATCH] VAX, MicroVAX I & II: Revamped Qbus memory access as Qbus peripheral --- VAX/vax610_defs.h | 9 +++- VAX/vax610_io.c | 17 ++++++- VAX/vax610_sysdev.c | 7 +-- VAX/vax630_defs.h | 14 +++++- VAX/vax630_io.c | 93 ++++++++++++++++++++++++++------------ VAX/vax630_sysdev.c | 108 ++++++++++---------------------------------- VAX/vax_io.c | 82 ++++++++++++++++++++++----------- VAX/vax_mmu.h | 42 +++++++++++------ VAX/vax_sysdev.c | 8 ++-- VAX/vax_vc.c | 25 ++++------ VAX/vaxmod_defs.h | 15 ++++-- 11 files changed, 232 insertions(+), 188 deletions(-) diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index fe59ec6e..388e42b5 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -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 */ diff --git a/VAX/vax610_io.c b/VAX/vax610_io.c index 24b71a72..16ec3e09 100644 --- a/VAX/vax610_io.c +++ b/VAX/vax610_io.c @@ -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; } diff --git a/VAX/vax610_sysdev.c b/VAX/vax610_sysdev.c index 9f203b36..701b137d 100644 --- a/VAX/vax610_sysdev.c +++ b/VAX/vax610_sysdev.c @@ -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); } diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 88788f81..b55d8ef8 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -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 */ diff --git a/VAX/vax630_io.c b/VAX/vax630_io.c index 7f948002..dd7d8d6f 100644 --- a/VAX/vax630_io.c +++ b/VAX/vax630_io.c @@ -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 */ diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index 1d180289..e2c09620 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -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; diff --git a/VAX/vax_io.c b/VAX/vax_io.c index 9c01b242..3e7c6535 100644 --- a/VAX/vax_io.c +++ b/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 */ diff --git a/VAX/vax_mmu.h b/VAX/vax_mmu.h index 1ebc7a77..809bb66b 100644 --- a/VAX/vax_mmu.h +++ b/VAX/vax_mmu.h @@ -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; } diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index e02c2c47..b7c94b0c 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -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) { diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c index 06d2366e..4c577879 100644 --- a/VAX/vax_vc.c +++ b/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 */ diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 158a0353..5ce0f5f8 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -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) */