// license:BSD-3-Clause // copyright-holders:Juergen Buchmueller /***************************************************************************** * * Xerox AltoII memory interface * *****************************************************************************/ #include "emu.h" #include "alto2cpu.h" #define PUT_EVEN(dword,word) X_WRBITS(dword,32, 0,15,word) #define GET_EVEN(dword) X_RDBITS(dword,32, 0,15) #define PUT_ODD(dword,word) X_WRBITS(dword,32,16,31,word) #define GET_ODD(dword) X_RDBITS(dword,32,16,31) #define GET_MESR_HAMMING(mesr) X_RDBITS(mesr,16,0,5) #define PUT_MESR_HAMMING(mesr,val) X_WRBITS(mesr,16,0,5,val) #define GET_MESR_PERR(mesr) X_RDBITS(mesr,16,6,6) #define PUT_MESR_PERR(mesr,val) X_WRBITS(mesr,16,6,6,val) #define GET_MESR_PARITY(mesr) X_RDBITS(mesr,16,7,7) #define PUT_MESR_PARITY(mesr,val) X_WRBITS(mesr,16,7,7,val) #define GET_MESR_SYNDROME(mesr) X_RDBITS(mesr,16,8,13) #define PUT_MESR_SYNDROME(mesr,val) X_WRBITS(mesr,16,8,13,val) #define GET_MESR_BANK(mesr) X_RDBITS(mesr,16,14,15) #define PUT_MESR_BANK(mesr,val) X_WRBITS(mesr,16,14,15,val) #define GET_MECR_SPARE1(mecr,val) X_RDBITS(mecr,16,0,3) #define PUT_MECR_SPARE1(mecr,val) X_WRBITS(mecr,16,0,3,val) #define GET_MECR_TEST_CODE(mecr) X_RDBITS(mecr,16,4,10) #define PUT_MECR_TEST_CODE(mecr,val) X_WRBITS(mecr,16,4,10,val) #define GET_MECR_TEST_MODE(mecr) X_RDBITS(mecr,16,11,11) #define PUT_MECR_TEST_MODE(mecr,val) X_WRBITS(mecr,16,11,11,val) #define GET_MECR_INT_SBERR(mecr) X_RDBITS(mecr,16,12,12) #define PUT_MECR_INT_SBERR(mecr,val) X_WRBITS(mecr,16,12,12,val) #define GET_MECR_INT_DBERR(mecr) X_RDBITS(mecr,16,13,13) #define PUT_MECR_INT_DBERR(mecr,val) X_WRBITS(mecr,16,13,13,val) #define GET_MECR_ERRCORR(mecr) X_RDBITS(mecr,16,14,14) #define PUT_MECR_ERRCORR(mecr,val) X_WRBITS(mecr,16,14,14,val) #define GET_MECR_SPARE2(mecr) X_RDBITS(mecr,16,15,15) #define PUT_MECR_SPARE2(mecr,val) X_WRBITS(mecr,16,15,15,val) /** *
* AltoII Memory * * Address mapping * * The mapping of addresses to memory chips can be altered by the setting of * the "memory configuration switch". This switch is located at the top of the * backplane of the AltoII. If the switch is in the alternate position, the * first and second 32K portions of memory are exchanged. * * The AltoII memory system is organized around 32-bit doublewords. Stored * along with each doubleword is 6 bits of Hamming code and a Parity bit for * a total of 39 bits: * * bits 0-15 even data word * bits 16-31 odd data word * bits 32-37 Hamming code * bit 38 Parity bit * * Things are further complicated by the fact that two types of memory chips * are used: 16K chips in machines with extended memory and 4K chips for all * others. * * The bits in a 1-word deep slice of memory are called a group. A group * contains 4K oder 16K doublewords, depending on the chip type. The bits of * a group on a single board are called a subgroup. Thus a subgroup contains * 10 of the 40 bits in a group. There are 8 subgroups on a memory board. * Subgroups are numbered from the high 3 bits of the address; for 4K chips * this means MAR[0-2]; for 16K chips (i.e., an Alto with extended memory) * this means BANK,MAR[0]: * * Subgroup Chip Positions * 7 81-90 * 6 71-80 * 5 61-70 * 4 51-60 * 3 41-50 * 2 31-40 * 1 21-30 * 0 11-20 * * The location of the bits in group 0 is: * * CARD 1 CARD2 CARD3 CARD4 * 32 24 16 08 00 33 25 17 09 01 34 26 18 10 02 35 27 19 11 03 * 36 28 20 12 04 37 29 21 13 05 38 30 22 14 06 xx 31 23 25 07 * * Chips 15, 25, 35, 45, 65, 75 and 85 on board 4 aren't used. If you are out * of replacement memory chips, you can use one of these, but then the board * with the missing chips will only work in Slot 4. * * o WORD = 16 BITS * o ACCESS -> 2 WORDS AT A TIME * o -> 32 BITS + 6 BITS EC + PARITY + SPARE = 40 BITS * o 10 BITS/MODULE 80 DRAMS/MODULE * o 4 MODULES/ALTO 320 DRAMS/ALTO * * ADDRESS A0-6, WE, CAS' * | TO ALL DEVICES * v * +-----------------------------------------+ * | ^ 8 DEVICES (32K OR 128K FOR XM) | * | | | CARD 1 * /| v <------------ DATA OUT ----------> | * / | 0 1 2 3 4 5 6 7 8 9 | * / +-----------------------------------------+ * | H4 H0 28 24 20 16 12 8 4 0 * | * | +-----------------------------------------+ * | /| | CARD 2 * | / +-----------------------------------------+ * RAS H5 H1 29 25 21 17 13 9 5 1 * 0-7 * | \ +-----------------------------------------+ * | \| | CARD 3 * | +-----------------------------------------+ * | P H2 30 26 22 18 14 10 6 2 * \ * \ +-----------------------------------------+ * \| | CARD 4 * +-----------------------------------------+ * X H3 31 27 23 19 15 11 7 3 * * [ ODD WORD ] [ EVEN WORD ] * ** * Whoa ;-) */ #define WD(x) (1ul<<(31-x)) //! Data double word mask for chip A75. #define A75 (WD( 1)|WD( 4)|WD( 8)|WD(11)|WD(15)|WD(19)|WD(23)|WD(26)|WD(30)) //! Data double word mask for chip A76. #define A76 (WD( 0)|WD( 3)|WD( 6)|WD(10)|WD(13)|WD(17)|WD(21)|WD(25)|WD(28)) //! Data double word mask for chip A86. #define A86 (WD( 2)|WD( 5)|WD( 9)|WD(12)|WD(16)|WD(20)|WD(24)|WD(27)|WD(31)) //! Data double word mask for chip A64. #define A64 (WD( 1)|WD( 2)|WD( 3)|WD( 7)|WD( 8)|WD( 9)|WD(10)|WD(14)|WD(15)) //! Data double word mask for chip A85. #define A85 (WD(16)|WD(17)|WD(22)|WD(23)|WD(24)|WD(25)|WD(29)|WD(30)|WD(31)) //! Data double word mask for chip A66. #define A66 (WD( 4)|WD( 5)|WD( 6)|WD( 7)|WD( 8)|WD( 9)|WD(10)) //! Data double word mask for chip A84. #define A84 (WD(18)|WD(19)|WD(20)|WD(21)|WD(22)|WD(23)|WD(24)|WD(25)) //! Data double word mask for chip A63. #define A63 (WD(11)|WD(12)|WD(13)|WD(14)|WD(15)|WD(16)|WD(17)) //! Data double word mask for chip A87. #define A87 (WD(26)|WD(27)|WD(28)|WD(29)|WD(30)|WD(31)) //! Data double word mask for chip A54. #define A54 (WD( 2)|WD( 3)) //! Data double word mask for chip A65. #define A65 (WD( 0)|WD( 1)|WD( 2)|WD( 4)|WD( 5)|WD( 7)|WD(10)|WD(11)|WD(12)) //! Data double word mask for chip A74. #define A74 (WD(14)|WD(17)|WD(18)|WD(21)|WD(23)|WD(24)|WD(26)|WD(27)|WD(29)) #define H0(hpb) X_BIT(hpb,8,0) //!< get Hamming code bit 0 from hpb data (really bit 32) #define H1(hpb) X_BIT(hpb,8,1) //!< get Hamming code bit 1 from hpb data (really bit 33) #define H2(hpb) X_BIT(hpb,8,2) //!< get Hamming code bit 2 from hpb data (really bit 34) #define H3(hpb) X_BIT(hpb,8,3) //!< get Hamming code bit 3 from hpb data (really bit 35) #define H4(hpb) X_BIT(hpb,8,4) //!< get Hamming code bit 4 from hpb data (really bit 36) #define H5(hpb) X_BIT(hpb,8,5) //!< get Hamming code bit 5 from hpb data (really bit 37) #define RH(hpb) X_RDBITS(hpb,8,0,5) //!< get Hamming code from hpb data (bits 32 to 37) #define RP(hpb) X_BIT(hpb,8,6) //!< get parity bit from hpb data (really bit 38) #define RU(hpb) X_BIT(hpb,8,7) //!< get unused bit from hpb data (really bit 39) [unused] /** * @brief Return even parity of a (masked) 32 bit value. * @param val 32 bits * @return 1 for even parity, 0 for odd parity */ static __inline uint8_t parity_even(uint32_t val) { val -= ((val >> 1) & 0x55555555); val = (((val >> 2) & 0x33333333) + (val & 0x33333333)); val = (((val >> 4) + val) & 0x0f0f0f0f); val += (val >> 8); val += (val >> 16); // val now has number of 1 bits return val & 1; } /** @brief Return odd parity of a (masked) 32 bit value. */ #define parity_odd(val) (parity_even(val)^1) /** * @brief Lookup table to convert a Hamming syndrome into a bit number to correct. */ static const int hamming_lut[64] = { -1, -1, -1, 0, -1, 1, 2, 3, /* A69: HR(5):0 HR(4):0 HR(3):0 */ -1, 4, 5, 6, 7, 8, 9, 10, /* A79: HR(5):0 HR(4):0 HR(3):1 */ -1, 11, 12, 13, 14, 15, 16, 17, /* A67: HR(5):0 HR(4):1 HR(3):0 */ -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ -1, 26, 27, 28, 29, 30, 31, -1, /* A68: HR(5):1 HR(4):0 HR(3):0 */ -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ 18, 19, 20, 21, 22, 23, 24, 25, /* A78: HR(5):1 HR(4):1 HR(3):0 */ -1, -1, -1, -1, -1, 1, -1, -1 /* non chip selected */ }; /** * @brief Calculate a Hamming code after reading or before writing a memory double-word. * * Hamming code generation is according to the schematics described above. * * It's certainly overkill to do this on a modern PC, but I think we'll * need it for perfect emulation anyways, e.g. Hamming code hardware checking. * * @param write true, if this is a memory write (don't check for error) * @param dw_addr the double-word address * @param dw_data the double-word data * @return dw_data, possibly with 1 bit error corrected */ uint32_t alto2_cpu_device::hamming_code(bool write, uint32_t dw_addr, uint32_t dw_data) { const uint8_t hpb = write ? 0 : m_mem.hpb[dw_addr]; /* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */ const uint8_t hc_0_a = parity_odd (dw_data & A75); /* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */ const uint8_t hc_0b1 = parity_even(dw_data & A76); /* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */ const uint8_t hc_1_a = parity_even(dw_data & A86); /* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */ const uint8_t hc_2_a = parity_odd (dw_data & A64); /* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */ const uint8_t hc_2_b = parity_even(dw_data & A85); const uint8_t hc_0 = H0(hpb) ^ hc_0_a ^ hc_0b1; const uint8_t hc_1 = H1(hpb) ^ hc_1_a ^ hc_0b1; const uint8_t hc_2 = hc_2_a ^ hc_2_b ^ H2(hpb); const uint8_t h_0_2 = H0(hpb) ^ H1(hpb) ^ H2(hpb); /* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */ const uint8_t hc_3_a = parity_odd ((dw_data & A66) ^ H3(hpb)); /* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */ const uint8_t hcpa = parity_odd (dw_data & A84); const uint8_t hc_3_4 = hcpa ^ 1; /* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */ const uint8_t hc_4_a = parity_odd ((dw_data & A63) ^ H4(hpb)); /* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */ const uint8_t hcpb = parity_odd ((dw_data & A87) ^ H5(hpb)); const uint8_t hc_3 = hc_3_a ^ hc_3_4; const uint8_t hc_4 = hc_4_a ^ hc_3_4; const uint8_t hc_5 = hcpb ^ 1; const uint8_t syndrome = 32*hc_0 + 16*hc_1 + 8*hc_2 + 4*hc_3 + 2*hc_4 + hc_5; /* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- * * Note: Here I XOR all the non dw_data inputs into bit 0, * which has the same effect as spreading them over some bits * and then counting them... I hope ;-) */ const uint8_t perr = parity_even( hc_3_a ^ hc_4_a ^ hcpa ^ hcpb ^ h_0_2 ^ X_RDBITS(dw_data,32,0,0) ^ X_RDBITS(dw_data,32,1,1) ^ (dw_data & A54) ^ RP(hpb) ^ 1); /* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */ const uint8_t pca = parity_odd (dw_data & A65); /* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */ const uint8_t pcb = parity_even(dw_data & A74); const uint8_t pc = pca ^ pcb; if (write) { /* Update the hamming code and parity bit store */ m_mem.hpb[dw_addr] = (syndrome << 2) | (pc << 1); return dw_data; } /** *
* * 32K x 10 STORAGE MODULE * * Table I * * +-------+-------+-------+---------------+-------+ * |CIRCUIT| INPUT | SIGNAL| INVERTER | | * | NO. | PINS | NAME | DEF?? ??? |RESIST.| * +-------+-------+-------+---------------+-------+ * | | 71 | RAS0 | A1 1 -> 2 | ?? R2 | * | 1 +-------+-------+---------------+-------+ * | | 110 | CS0 | A1 3 -> 4 | ?? R3 | * +-------+-------+-------+---------------+-------+ * | | 79 | RAS1 | A2 1 -> 2 | ?? R4 | * | 2 +-------+-------+---------------+-------+ * | | 110 | CS1 | A2 3 -> 4 | ?? R5 | * +-------+-------+-------+---------------+-------+ * | | 90 | RAS2 | A3 1 -> 2 | ?? R7 | * | 3 +-------+-------+---------------+-------+ * | | 110 | CS2 | A3 3 -> 4 | ?? R8 | * +-------+-------+-------+---------------+-------+ * | | 86 | RAS3 | A3 11 -> 10 | ?? R9 | * | 4 +-------+-------+---------------+-------+ * | | 110 | CS3 | A4 11 -> 10 | ?? R7 | * +-------+-------+-------+---------------+-------+ * | | 102 | RAS4 | A4 1 -> 2 | ?? R4 | * | 5 +-------+-------+---------------+-------+ * | | 110 | CS4 | A3 13 -> 12 | ?? R5 | * +-------+-------+-------+---------------+-------+ * | | 106 | RAS5 | A5 11 -> 10 | ?? R3 | * | 6 +-------+-------+---------------+-------+ * | | 110 | CS5 | A5 3 -> 4 | ?? R2 | * +-------+-------+-------+---------------+-------+ * | | 111 | RAS6 | A5 1 -> 2 | ?? R8 | * | 7 +-------+-------+---------------+-------+ * | | 110 | CS6 | A5 13 -> 12 | ?? R9 | * +-------+-------+-------+---------------+-------+ * | | 99 | RAS7 | A4 13 -> 12 | ?? R5 | * | 8 +-------+-------+---------------+-------+ * | | 110 | CS7 | A4 3 -> 4 | ?? R5 | * +-------+-------+-------+---------------+-------+ * * Table II * * MEMORY CHIP REFERENCE DESIGNATOR * * CIRCUIT NO. * ROW NO. 1 2 3 4 5 6 7 8 * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * | 1 | 15 20 | 25 30 | 35 40 | 45 50 | 55 60 | 65 70 | 75 80 | 85 90 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * | 2 | 14 19 | 24 29 | 34 39 | 44 49 | 54 59 | 64 69 | 64 79 | 84 89 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * | 3 | 13 18 | 23 28 | 33 38 | 43 48 | 53 58 | 63 68 | 73 78 | 83 88 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * | 4 | 12 17 | 22 27 | 32 37 | 42 47 | 52 57 | 62 67 | 72 77 | 82 87 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * | 5 | 11 16 | 21 26 | 31 36 | 41 46 | 52 56 | 61 66 | 71 76 | 81 86 | * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ * * * The Hamming code generator: * * WDxx is write data bit xx. * H(x) is Hammming code bit x. * HC(x) is generated Hamming code bit x. * HC(x/y) is an intermediate value. * HC(x)A and HC(x)B are also intermediate values. * * Chips used are: * 74S280 9-bit parity generator (A-I inputs, even and odd outputs) * 74S135 EX-OR/EX-NOR gates (5 inputs, 2 outputs) * 74S86 EX-OR gates (2 inputs, 1 output) * * chip A B C D E F G H I even odd * --------------------------------------------------------------------------------- * A75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A * A76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD28 HC(0B1) --- * A86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- * A64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A * A85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- * * H(0) ^ HC(0)A ^ HC(0B1) -> HC(0) * H(1) ^ HC(1)A ^ HC(0B1) -> HC(1) * HC(2)A ^ HC(2)B ^ H(2) -> HC(2) * H(0) ^ H(1) ^ H(2) -> H(0/2) * * chip A B C D E F G H I even odd * --------------------------------------------------------------------------------- * A66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A * A84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA * A63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A * A87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB * * HC(3)A ^ HC(3/4) -> HC(3) * HC(4)A ^ HC(3/4) -> HC(4) * * WD00 ^ WD01 -> XX01 * * chip A B C D E F G H I even odd * --------------------------------------------------------------------------------- * A54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 RP PERR --- * A65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA * A74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- * * PCA ^ PCB -> PC *
* A22 (74H30) 8-input NAND to check for error * input signal * ------------------------- * 1 POK = PERR' * 4 NER(08) = HC(0)' * 3 NER(09) = HC(1)' * 2 NER(10) = HC(2)' * 6 NER(11) = HC(3)' * 5 NER(12) = HC(4)' * 12 NER(13) = HC(5)' * 11 1 (VPUL3) * * output signal * ------------------------- * 8 ERROR ** * Using De Morgan this can be simplified: * ERROR is 0, whenever all of PERR and HC(0) to HC(5) are 0. * Or the other way round: any of perr or syndrome non-zero means ERROR=1. */ if (perr || syndrome) { /* latch data on the first error */ if (!m_mem.error) { m_mem.error = true; PUT_MESR_HAMMING(m_mem.mesr, RH(hpb)); PUT_MESR_PERR(m_mem.mesr, perr); PUT_MESR_PARITY(m_mem.mesr, RP(hpb)); PUT_MESR_SYNDROME(m_mem.mesr, syndrome); PUT_MESR_BANK(m_mem.mesr, (dw_addr >> 15)); /* latch memory address register */ m_mem.mear = m_mem.mar & 0177777; LOG((this,LOG_MEM,5," memory error at dword addr:%07o data:%011o check:%03o\n", dw_addr * 2, dw_data, hpb)); LOG((this,LOG_MEM,6," MEAR: %06o\n", m_mem.mear)); LOG((this,LOG_MEM,6," MESR: %06o\n", m_mem.mesr ^ 0177777)); LOG((this,LOG_MEM,7," Hamming code read : %#o\n", GET_MESR_HAMMING(m_mem.mesr))); LOG((this,LOG_MEM,7," Parity error : %o\n", GET_MESR_PERR(m_mem.mesr))); LOG((this,LOG_MEM,7," Memory parity bit : %o\n", GET_MESR_PARITY(m_mem.mesr))); LOG((this,LOG_MEM,7," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(m_mem.mesr), hamming_lut[GET_MESR_SYNDROME(m_mem.mesr)])); LOG((this,LOG_MEM,7," Memory bank : %#o\n", GET_MESR_BANK(m_mem.mesr))); LOG((this,LOG_MEM,6," MECR: %06o\n", m_mem.mecr ^ 0177777)); LOG((this,LOG_MEM,7," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr))); LOG((this,LOG_MEM,7," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,7," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,7," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,7," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on")); } if (-1 == hamming_lut[syndrome]) { /* double-bit error: wake task_part, if we're told so */ if (GET_MECR_INT_DBERR(m_mem.mecr)) m_task_wakeup |= 1 << task_part; } else { /* single-bit error: wake task_part, if we're told so */ if (GET_MECR_INT_SBERR(m_mem.mecr)) m_task_wakeup |= 1 << task_part; /* should we correct the single bit error ? */ if (0 == GET_MECR_ERRCORR(m_mem.mecr)) { LOG((this,LOG_MEM,0," correct bit #%d addr:%07o data:%011o check:%03o\n", hamming_lut[syndrome], dw_addr * 2, dw_data, hpb)); dw_data ^= 1ul << hamming_lut[syndrome]; } } } return dw_data; } /** * @brief memory error address register read * * This register is a 'shadow MAR'; it holds the address of the * first error since the error status was last reset. If no error * has occurred, MEAR reports the address of the most recent * memory access. Note that MEAR is set whenever an error of * _any kind_ (single-bit or double-bit) is detected. */ READ16_MEMBER( alto2_cpu_device::mear_r ) { int data = m_mem.error ? m_mem.mear : m_mem.mar; if (!machine().side_effects_disabled()) { LOG((this,LOG_MEM,2," MEAR read %07o\n", data)); } return data; } /** * @brief memory error status register read * * This register reports specifics of the first error that * occurred since MESR was last reset. Storing anything into * this register resets the error logic and enables it to * detect a new error. Bits are "low true", i.e. if the bit * is 0, the conidition is true. *
* MESR[0-5] Hamming code reported from error * MESR[6] Parity error * MESR[7] Memory parity bit * MESR[8-13] Syndrome bits * MESR[14-15] Bank number in which error occurred **/ READ16_MEMBER( alto2_cpu_device::mesr_r ) { uint16_t data = m_mem.mesr ^ 0177777; if (!machine().side_effects_disabled()) { LOG((this,LOG_MEM,2," MESR read %07o\n", data)); LOG((this,LOG_MEM,6," Hamming code read : %#o\n", GET_MESR_HAMMING(data))); LOG((this,LOG_MEM,6," Parity error : %o\n", GET_MESR_PERR(data))); LOG((this,LOG_MEM,6," Memory parity bit : %o\n", GET_MESR_PARITY(data))); LOG((this,LOG_MEM,6," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(data), hamming_lut[GET_MESR_SYNDROME(data)])); LOG((this,LOG_MEM,6," Memory bank : %#o\n", GET_MESR_BANK(data))); } return data; } WRITE16_MEMBER( alto2_cpu_device::mesr_w ) { if (!machine().side_effects_disabled()) { LOG((this,LOG_MEM,2," MESR write %07o (clear MESR; was %07o)\n", data, m_mem.mesr)); m_mem.mesr = 0; // set all bits to 0 m_mem.error = 0; // reset the error flag m_task_wakeup &= ~(1 << task_part); // clear the task wakeup for the parity error task } } /** * @brief memory error control register write * * Storing into this register is the means for controlling * the memory error logic. This register is set to all ones * (disable all interrupts) when the alto is bootstrapped * and when the parity error task first detects an error. * When an error has occurred, MEAR and MESR should be read * before setting MECR. Bits are "low true", i.e. a 0 bit * enables the condition. * *
* MECR[0-3] Spare * MECR[4-10] Test hamming code (used only for special diagnostics) * MECR[11] Test mode (used only for special diagnostics) * MECR[12] Cause interrupt on single-bit errors if zero * MECR[13] Cause interrupt on double-bit errors if zero * MECR[14] Do not use error correction if zero * MECR[15] Spare **/ WRITE16_MEMBER( alto2_cpu_device::mecr_w ) { m_mem.mecr = data ^ 0177777; // clear spare bits X_WRBITS(m_mem.mecr,16, 0, 3,0); X_WRBITS(m_mem.mecr,16,15,15,0); if (!machine().side_effects_disabled()) { LOG((this,LOG_MEM,2," MECR write %07o\n", data)); LOG((this,LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr))); LOG((this,LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off")); LOG((this,LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on")); } } /** * @brief memory error control register read */ READ16_MEMBER( alto2_cpu_device::mecr_r ) { uint16_t data = m_mem.mecr ^ 0177777; // all spare bits are set if (!machine().side_effects_disabled()) { LOG((this,LOG_MEM,2," MECR read %07o\n", data)); LOG((this,LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(data))); LOG((this,LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(data) ? "on" : "off")); LOG((this,LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(data) ? "on" : "off")); LOG((this,LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(data) ? "on" : "off")); LOG((this,LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(data) ? "off" : "on")); } return data; } /** * @brief Read i/o space RAM. * Note: This is for debugger access. Regular memory access is * only through load_mar, read_mem and write_mem. */ READ16_MEMBER ( alto2_cpu_device::ioram_r ) { offs_t dw_addr = offset / 2; return static_cast