| /* vax780_mem.c: VAX 11/780 memory controllers | |
| Copyright (c) 2004-2008, 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"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Robert M Supnik shall not be | |
| used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Robert M Supnik. | |
| This module contains the VAX 11/780 system-specific registers and devices. | |
| mctl0, mctl1 MS780C/E memory controllers | |
| */ | |
| #include "vax_defs.h" | |
| /* Memory controller register A */ | |
| #define MCRA_OF 0x0 | |
| #define MCRA_SUMM 0x00100000 /* err summ (MS780E) */ | |
| #define MCRA_C_SIZE 0x00007E00 /* array size - fixed */ | |
| #define MCRA_V_SIZE 9 | |
| #define MCRA_ILVE 0x00000100 /* interleave wr enab */ | |
| #define MCRA_TYPE 0x000000F8 /* type */ | |
| #define MCRA_C_TYPE 0x00000010 /* 16k uninterleaved */ | |
| #define MCRA_E_TYPE 0x0000006A /* 256k upper + lower */ | |
| #define MCRA_ILV 0x00000007 /* interleave */ | |
| #define MCRA_RD (0x00107FFF|SBI_FAULTS) | |
| #define MCRA_WR 0x00000100 | |
| /* Memory controller register B */ | |
| #define MCRB_OF 0x1 | |
| #define MCRB_FP 0xF0000000 /* file pointers */ | |
| #define MCRB_V_SA 15 /* start addr */ | |
| #define MCRB_M_SA 0x1FFF | |
| #define MCRB_SA (MCRB_M_SA << MCRB_V_SA) | |
| #define MCRB_SAE 0x00004000 /* start addr wr enab */ | |
| #define MCRB_INIT 0x00003000 /* init state */ | |
| #define MCRB_REF 0x00000400 /* refresh */ | |
| #define MCRB_ECC 0x000003FF /* ECC for diags */ | |
| #define MCRB_RD 0xFFFFF7FF | |
| #define MCRB_WR 0x000043FF | |
| /* Memory controller register C,D */ | |
| #define MCRC_OF 0x2 | |
| #define MCRD_OF 0x3 | |
| #define MCRC_DCRD 0x40000000 /* disable CRD */ | |
| #define MCRC_HER 0x20000000 /* high error rate */ | |
| #define MCRC_ERL 0x10000000 /* log error */ | |
| #define MCRC_C_ER 0x0FFFFFFF /* MS780C error */ | |
| #define MCRC_E_PE1 0x00080000 /* MS780E par ctl 1 */ | |
| #define MCRC_E_PE0 0x00040000 /* MS780E par ctl 0 */ | |
| #define MCRC_E_CRD 0x00000200 /* MS780E CRD */ | |
| #define MCRC_E_PEW 0x00000100 /* MS780E par err wr */ | |
| #define MCRC_E_USEQ 0x00000080 /* MS780E seq err */ | |
| #define MCRC_C_RD 0x7FFFFFFF | |
| #define MCRC_E_RD 0x700C0380 | |
| #define MCRC_WR 0x40000000 | |
| #define MCRC_C_W1C 0x30000000 | |
| #define MCRC_E_W1C 0x300C0380 | |
| #define MCRROM_OF 0x400 | |
| uint32 mcr_a[MCTL_NUM]; | |
| uint32 mcr_b[MCTL_NUM]; | |
| uint32 mcr_c[MCTL_NUM]; | |
| uint32 mcr_d[MCTL_NUM]; | |
| uint32 rom_lw[MCTL_NUM][ROMSIZE >> 2]; | |
| extern UNIT cpu_unit; | |
| t_stat mctl_reset (DEVICE *dptr); | |
| t_stat mctl_rdreg (int32 *val, int32 pa, int32 mode); | |
| t_stat mctl_wrreg (int32 val, int32 pa, int32 mode); | |
| /* MCTLx data structures | |
| mctlx_dev MCTLx device descriptor | |
| mctlx_unit MCTLx unit | |
| mctlx_reg MCTLx register list | |
| */ | |
| DIB mctl0_dib[] = { TR_MCTL0, 0, &mctl_rdreg, &mctl_wrreg, 0 }; | |
| UNIT mctl0_unit = { UDATA (NULL, 0, 0) }; | |
| REG mctl0_reg[] = { | |
| { HRDATA (CRA, mcr_a[0], 32) }, | |
| { HRDATA (CRB, mcr_b[0], 32) }, | |
| { HRDATA (CRC, mcr_c[0], 32) }, | |
| { HRDATA (CRD, mcr_d[0], 32) }, | |
| { BRDATA (ROM, rom_lw[0], 16, 32, ROMSIZE >> 2) }, | |
| { NULL } | |
| }; | |
| MTAB mctl0_mod[] = { | |
| { MTAB_XTD|MTAB_VDV, TR_MCTL0, "NEXUS", NULL, | |
| NULL, &show_nexus }, | |
| { 0 } | |
| }; | |
| DIB mctl1_dib[] = { TR_MCTL1, 0, &mctl_rdreg, &mctl_wrreg, 0 }; | |
| UNIT mctl1_unit = { UDATA (NULL, 0, 0) }; | |
| MTAB mctl1_mod[] = { | |
| { MTAB_XTD|MTAB_VDV, TR_MCTL1, "NEXUS", NULL, | |
| NULL, &show_nexus }, | |
| { 0 } }; | |
| REG mctl1_reg[] = { | |
| { HRDATA (CRA, mcr_a[1], 32) }, | |
| { HRDATA (CRB, mcr_b[1], 32) }, | |
| { HRDATA (CRC, mcr_c[1], 32) }, | |
| { HRDATA (CRD, mcr_d[1], 32) }, | |
| { BRDATA (ROM, rom_lw[1], 16, 32, ROMSIZE >> 2) }, | |
| { NULL } | |
| }; | |
| DEVICE mctl_dev[] = { | |
| { | |
| "MCTL0", &mctl0_unit, mctl0_reg, mctl0_mod, | |
| 1, 16, 16, 1, 16, 8, | |
| NULL, NULL, &mctl_reset, | |
| NULL, NULL, NULL, | |
| &mctl0_dib, DEV_NEXUS | |
| }, | |
| { | |
| "MCTL1", &mctl1_unit, mctl1_reg, mctl1_mod, | |
| 1, 16, 16, 1, 16, 8, | |
| NULL, NULL, &mctl_reset, | |
| NULL, NULL, NULL, | |
| &mctl1_dib, DEV_NEXUS | |
| } | |
| }; | |
| /* Memory controller register read */ | |
| t_stat mctl_rdreg (int32 *val, int32 pa, int32 lnt) | |
| { | |
| int32 mctl, ofs; | |
| t_bool extmem = MEMSIZE > MAXMEMSIZE; | |
| if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ | |
| printf (">>MCTL: invalid adapter read mask, pa = %X, lnt = %d\r\n", pa, lnt); | |
| sbi_set_errcnf (); /* err confirmation */ | |
| return SCPE_OK; | |
| } | |
| mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */ | |
| ofs = NEXUS_GETOFS (pa); /* get offset */ | |
| if (ofs >= MCRROM_OF) { /* ROM? */ | |
| *val = rom_lw[mctl][ofs - MCRROM_OF]; /* get lw */ | |
| return SCPE_OK; | |
| } | |
| switch (ofs) { | |
| case MCRA_OF: /* CR A */ | |
| *val = mcr_a[mctl] & MCRA_RD; | |
| break; | |
| case MCRB_OF: /* CR B */ | |
| *val = (mcr_b[mctl] & MCRB_RD) | MCRB_INIT; | |
| break; | |
| case MCRC_OF: /* CR C */ | |
| *val = mcr_c[mctl] & (extmem? MCRC_E_RD: MCRC_C_RD); | |
| break; | |
| case MCRD_OF: /* CR D */ | |
| if (!extmem) /* MS780E only */ | |
| return SCPE_NXM; | |
| *val = mcr_d[mctl] & MCRC_E_RD; | |
| break; | |
| default: | |
| return SCPE_NXM; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Memory controller register write */ | |
| t_stat mctl_wrreg (int32 val, int32 pa, int32 lnt) | |
| { | |
| int32 mctl, ofs, mask; | |
| t_bool extmem = MEMSIZE > MAXMEMSIZE; | |
| if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ | |
| printf (">>MCTL: invalid adapter write mask, pa = %X, lnt = %d\r\n", pa, lnt); | |
| sbi_set_errcnf (); /* err confirmation */ | |
| return SCPE_OK; | |
| } | |
| mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */ | |
| ofs = NEXUS_GETOFS (pa); /* get offset */ | |
| switch (ofs) { | |
| case MCRA_OF: /* CR A */ | |
| mask = MCRA_WR | ((val & MCRA_ILVE)? MCRA_ILV: 0); | |
| mcr_a[mctl] = (mcr_a[mctl] & ~mask) | (val & mask); | |
| break; | |
| case MCRB_OF: /* CR B */ | |
| mask = MCRB_WR | ((val & MCRB_SAE)? MCRB_SA: 0); | |
| mcr_b[mctl] = (mcr_b[mctl] & ~mask) | (val & mask); | |
| break; | |
| case MCRC_OF: /* CR C */ | |
| mcr_c[mctl] = ((mcr_c[mctl] & ~MCRC_WR) | (val & MCRC_WR)) & | |
| ~(val & (extmem? MCRC_E_W1C: MCRC_C_W1C)); | |
| break; | |
| case MCRD_OF: /* CR D */ | |
| if (!extmem) /* MS780E only */ | |
| return SCPE_NXM; | |
| mcr_d[mctl] = ((mcr_d[mctl] & ~MCRC_WR) | (val & MCRC_WR)) & | |
| ~(val & MCRC_E_W1C); | |
| break; | |
| default: | |
| return SCPE_NXM; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Used by CPU and loader */ | |
| void rom_wr_B (int32 pa, int32 val) | |
| { | |
| uint32 mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */ | |
| uint32 ofs = NEXUS_GETOFS (pa) - MCRROM_OF; /* get offset */ | |
| int32 sc = (pa & 3) << 3; | |
| rom_lw[mctl][ofs] = ((val & 0xFF) << sc) | (rom_lw[mctl][ofs] & ~(0xFF << sc)); | |
| return; | |
| } | |
| /* MEMCTL reset */ | |
| t_stat mctl_reset (DEVICE *dptr) | |
| { | |
| int32 i, amb; | |
| t_bool extmem = MEMSIZE > MAXMEMSIZE; | |
| amb = (int32) (MEMSIZE / 2) >> 20; /* array size MB */ | |
| for (i = 0; i < MCTL_NUM; i++) { /* init for MS780C */ | |
| if (extmem) { /* extended memory? */ | |
| mcr_a[i] = ((amb - 1) << MCRA_V_SIZE) | MCRA_E_TYPE; | |
| mcr_b[i] = MCRB_INIT | ((i * amb) << (MCRB_V_SA + 4)); | |
| } | |
| else { | |
| mcr_a[i] = MCRA_C_SIZE | MCRA_C_TYPE; | |
| mcr_b[i] = MCRB_INIT | (i << 21); | |
| } | |
| mcr_c[i] = 0; | |
| mcr_d[i] = 0; | |
| } | |
| return SCPE_OK; | |
| } |