// license:BSD-3-Clause // copyright-holders:Juergen Buchmueller /***************************************************************************** * * Xerox AltoII emulator task * *****************************************************************************/ #include "emu.h" #include "alto2cpu.h" /** @brief CTL2K_U3 address line for F2 function */ #define CTL2K_U3(f2) (f2 == f2_emu_idisp ? 0x80 : 0x00) /** * width,from,to of the 16 bit instruction register * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * ============================================================= * x - - - - - - - - - - - - - - - arithmetic operation * 0 m m - - - - - - - - - - - - - memory function * 0 0 0 - - - - - - - - - - - - - jump functions * 0 0 1 d d - - - - - - - - - - - LDA dstAC * 0 1 0 d d - - - - - - - - - - - STA dstAC * 0 1 1 - - - - - - - - - - - - - augmented functions * 1 s s - - - - - - - - - - - - - source accumulator (0-3) * 1 - - d d - - - - - - - - - - - destination accumulator (0-3) * 1 s s d d x x x - - - - - - - - accumulator function * 1 s s d d 0 0 0 - - - - - - - - COM dstAC, srcAC * 1 s s d d 0 0 1 - - - - - - - - NEG dstAC, srcAC * 1 s s d d 0 1 0 - - - - - - - - MOV dstAC, srcAC * 1 s s d d 0 1 1 - - - - - - - - INC dstAC, srcAC * 1 s s d d 1 0 0 - - - - - - - - ADC dstAC, srcAC * 1 s s d d 1 0 1 - - - - - - - - SUB dstAC, srcAC * 1 s s d d 1 1 0 - - - - - - - - ADD dstAC, srcAC * 1 s s d d 1 1 1 - - - - - - - - AND dstAC, srcAC * 1 - - - - - - - x x - - - - - - shift operation * 1 - - - - - - - 0 0 - - - - - - nothing * 1 - - - - - - - 0 1 - - - - - - rotate left through carry * 1 - - - - - - - 1 0 - - - - - - rotate right through carry * 1 - - - - - - - 1 1 - - - - - - swap byte halves * 1 - - - - - - - - - x x - - - - carry in mode * 1 - - - - - - - - - 0 0 - - - - nothing * 1 - - - - - - - - - 0 1 - - - - Z carry in is zero * 1 - - - - - - - - - 1 0 - - - - O carry in is one * 1 - - - - - - - - - 1 1 - - - - C carry in is complemented carry * 1 - - - - - - - - - - - x - - - NL * - - - - - - - - - - - - - x x x conditional execution * - - - - - - - - - - - - - 0 0 0 NVR never skip * - - - - - - - - - - - - - 0 0 1 SKP always skip * - - - - - - - - - - - - - 0 1 0 SZC skip if carry result is zero * - - - - - - - - - - - - - 0 1 1 SNC skip if carry result is non-zero * - - - - - - - - - - - - - 1 0 0 SZR skip if 16 bit result is zero * - - - - - - - - - - - - - 1 0 1 SNR skip if 16 bit result is non-zero * - - - - - - - - - - - - - 1 1 0 SEZ skip if either result is zero * - - - - - - - - - - - - - 1 1 1 SBN skip if both results are non-zero */ #define IR_ARITH(ir) X_RDBITS(ir,16, 0, 0) #define IR_SrcAC(ir) X_RDBITS(ir,16, 1, 2) #define IR_DstAC(ir) X_RDBITS(ir,16, 3, 4) #define IR_AFunc(ir) X_RDBITS(ir,16, 5, 7) #define IR_SH(ir) X_RDBITS(ir,16, 8, 9) #define IR_CY(ir) X_RDBITS(ir,16,10,11) #define IR_NL(ir) X_RDBITS(ir,16,12,12) #define IR_SK(ir) X_RDBITS(ir,16,13,15) #define IR_MFunc(ir) X_RDBITS(ir,16, 1, 2) #define IR_JFunc(ir) X_RDBITS(ir,16, 3, 4) #define IR_I(ir) X_RDBITS(ir,16, 5, 5) #define IR_X(ir) X_RDBITS(ir,16, 6, 7) #define IR_DISP(ir) X_RDBITS(ir,16, 8,15) #define IR_AUGFUNC(ir) X_RDBITS(ir,16, 3, 7) #define op_MFUNC_MASK 0060000 //!< instruction register memory function mask #define op_MFUNC_JUMP 0000000 //!< jump functions value #define op_JUMP_MASK 0014000 //!< jump functions mask #define op_JMP 0000000 //!< jump #define op_JSR 0004000 //!< jump to subroutine #define op_ISZ 0010000 //!< increment and skip if zero #define op_DSZ 0014000 //!< decrement and skip if zero #define op_LDA 0020000 //!< load accu functions value #define op_STA 0040000 //!< store accu functions value #define op_AUGMENTED 0060000 //!< store accu functions value #define op_AUGM_MASK 0077400 //!< mask covering all augmented functions #define op_AUGM_NODISP 0061000 //!< augmented functions w/o displacement #define op_AUGM_SUBFUNC 0000037 //!< mask for augmented subfunctions in DISP #define op_CYCLE 0060000 //!< cycle AC0 #define op_NODISP 0061000 //!< NODISP: opcodes without displacement #define op_DIR 0061000 //!< disable interrupts #define op_EIR 0061001 //!< enable interrupts #define op_BRI 0061002 //!< branch and return from interrupt #define op_RCLK 0061003 //!< read clock to AC0, AC1 #define op_SIO 0061004 //!< start I/O #define op_BLT 0061005 //!< block transfer #define op_BLKS 0061006 //!< block set value #define op_SIT 0061007 //!< start interval timer #define op_JMPRAM 0061010 //!< jump to microcode RAM (actually ROM, too) #define op_RDRAM 0061011 //!< read microcode RAM #define op_WRTRAM 0061012 //!< write microcode RAM #define op_DIRS 0061013 //!< disable interrupts, and skip, if already disabled #define op_VERS 0061014 //!< get microcode version in AC0 #define op_DREAD 0061015 //!< double word read (Alto II) #define op_DWRITE 0061016 //!< double word write (Alto II) #define op_DEXCH 0061017 //!< double word exchange (Alto II) #define op_MUL 0061020 //!< unsigned multiply #define op_DIV 0061021 //!< unsigned divide #define op_DIAGNOSE1 0061022 //!< write two different accus in fast succession #define op_DIAGNOSE2 0061023 //!< write Hamming code and memory #define op_BITBLT 0061024 //!< bit-aligned block transfer #define op_XMLDA 0061025 //!< load accu AC0 from extended memory (Alto II/XM) #define op_XMSTA 0061026 //!< store accu AC0 to extended memory (Alto II/XM) #define op_JSRII 0064400 //!< jump to subroutine PC relative, doubly indirect #define op_JSRIS 0065000 //!< jump to subroutine AC2 relative, doubly indirect #define op_CONVERT 0067000 //!< convert bitmapped font to bitmap #define op_ARITH_MASK 0103400 //!< mask for arithmetic functions #define op_COM 0100000 //!< one's complement #define op_NEG 0100400 //!< two's complement #define op_MOV 0101000 //!< accu transfer #define op_INC 0101400 //!< increment #define op_ADC 0102000 //!< add one's complement #define op_SUB 0102400 //!< subtract by adding two's complement #define op_ADD 0103000 //!< add #define op_AND 0103400 //!< logical and #define ea_DIRECT 0000000 //!< effective address is direct #define ea_INDIRECT 0002000 //!< effective address is indirect #define ea_MASK 0001400 //!< mask for effective address modes #define ea_PAGE0 0000000 //!< e is page 0 address #define ea_PCREL 0000400 //!< e is PC + signed displacement #define ea_AC2REL 0001000 //!< e is AC2 + signed displacement #define ea_AC3REL 0001400 //!< e is AC3 + signed displacement #define sh_MASK 0000300 //!< shift mode mask (do novel shifts) #define sh_L 0000100 //!< rotate left through carry #define sh_R 0000200 //!< rotate right through carry #define sh_S 0000300 //!< swap byte halves #define cy_MASK 0000060 //!< carry in mode mask #define cy_Z 0000020 //!< carry in is zero #define cy_O 0000040 //!< carry in is one #define cy_C 0000060 //!< carry in is complemented carry #define nl_MASK 0000010 //!< no-load mask #define nl_NONE 0000010 //!< do not load DstAC nor carry #define sk_MASK 0000007 //!< skip mask #define sk_NVR 0000000 //!< never skip #define sk_SKP 0000001 //!< always skip #define sk_SZC 0000002 //!< skip if carry result is zero #define sk_SNC 0000003 //!< skip if carry result is non-zero #define sk_SZR 0000004 //!< skip if 16-bit result is zero #define sk_SNR 0000005 //!< skip if 16-bit result is non-zero #define sk_SEZ 0000006 //!< skip if either result is zero #define sk_SBN 0000007 //!< skip if both results are non-zero /** * @brief register selection * *
* From the schematics: 08_ALU, page 6 (PDF page 4) * * EMACT emulator task active * F2[0-2]=111b <-ACSOURCE and F2_17 * F2[0-2]=101b DNS<- and ACDEST<- * * u49 (8 input NAND 74S30) * ---------------------------------------------- * F2[0] & F2[2] & F2[1]' & IR[03]' & EMACT * * F2[0-2] IR[03] EMACT output u49pin8 * -------------------------------------- * 101 0 1 0 * all others 1 * * * u59 (8 input NAND 74S30) * ---------------------------------------------- * F2[0] & F2[2] & F2[1] & IR[01]' & EMACT * * F2[0-2] IR[01] EMACT output u59pin8 * -------------------------------------- * 111 0 1 0 * all others 1 * * u70d (2 input NOR 74S02 used as inverter) * --------------------------------------------- * RSEL3 -> RSEL3' * * u79b (3 input NAND 74S10) * --------------------------------------------- * u49pin8 u59pin8 RSEL3' output 6RA3 * ------------------------------------- * 1 1 1 0 * 0 x x 1 * x 0 x 1 * x x 0 1 * * * u60 (8 input NAND 74S30) * ---------------------------------------------- * F2[0] & F2[2] & F2[1]' & IR[02]' & EMACT * * F2[0-2] IR[02] EMACT output u60pin8 * -------------------------------------- * 101 0 1 0 * all others 1 * * u50 (8 input NAND 74S30) * ---------------------------------------------- * F2[0] & F2[2] & F2[1] & IR[04]' & EMACT * * F2[0-2] IR[04] EMACT output u50pin8 * -------------------------------------- * 111 0 1 0 * all others 1 * * u70c (2 input NOR 74S02 used as inverter) * --------------------------------------------- * RSEL4 -> RSEL4' * * * u79c (3 input NAND 74S10) * --------------------------------------------- * u60pin8 u50pin8 RSEL4' output 8RA4 * ------------------------------------- * 1 1 1 0 * 0 x x 1 * x 0 x 1 * x x 0 1 * * BUG?: schematics seem to have swapped IR(04)' and IR(02)' inputs for the * RA4 decoding, because SrcAC is selected from IR[1-2]? **/ /** * @brief bs_disp early: drive bus by IR[8-15], possibly sign extended * * The high order bits of IR cannot be read directly, but the * displacement field of IR (8 low order bits) may be read with * the <-DISP bus source. If the X field of the instruction is * zero (i.e., it specifies page 0 addressing), then the DISP * field of the instruction is put on BUS[8-15] and BUS[0-7] * is zeroed. If the X field of the instruction is non-zero * (i.e. it specifies PC-relative or base-register addressing) * then the DISP field is sign-extended and put on the bus. * */ void alto2_cpu_device::bs_early_emu_disp() { uint16_t r = IR_DISP(m_emu.ir); if (IR_X(m_emu.ir)) { r = ((signed char)r) & 0177777; } LOG((this,LOG_EMU,2, " <-DISP (%06o)\n", r)); m_bus &= r; } /** * @brief f1_block early: block task * * The task request for the active task is cleared */ void alto2_cpu_device::f1_early_emu_block() { #if 0 CPU_CLR_TASK_WAKEUP(m_task); LOG((this,LOG_EMU,2, " BLOCK %02o:%s\n", m_task, task_name(m_task))); #elif 0 fatal(1, "Emulator task want's to BLOCK.\n" \ "%s-%04o: r:%02o af:%02o bs:%02o f1:%02o f2:%02o" \ " t:%o l:%o next:%05o next2:%05o cycle:%lld\n", task_name(m_task), m_mpc, m_rsel, m_daluf, m_dbs, m_df1, mdf2, m_dloadt, m_dloatl, m_next, m_next2, ntime() / CPU_MICROCYCLE_TIME); #else /* just ignore (?) */ #endif } /** * @brief f1_load_rmr late: load the reset mode register */ void alto2_cpu_device::f1_late_emu_load_rmr() { LOG((this,LOG_EMU,2," RMR<-; BUS (%#o)\n", m_bus)); m_reset_mode = m_bus; } /** * @brief f1_load_esrb late: load the extended S register bank from BUS[12-14] */ void alto2_cpu_device::f1_late_emu_load_esrb() { LOG((this,LOG_EMU,2," ESRB<-; BUS[12-14] (%#o)\n", m_bus)); m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14); } /** * @brief f1_rsnf early: drive the bus from the Ethernet node ID * * TODO: move this to the Ethernet code? It's really a emulator * specific function that is decoded by the Ethernet card. */ void alto2_cpu_device::f1_early_rsnf() { uint16_t r = 0177400 | m_ether_id; LOG((this,LOG_EMU,2," <-RSNF; (%#o)\n", r)); m_bus &= r; } /** * @brief f1_startf early: defines commands for for I/O hardware, including Ethernet *
* (SIO) Start I/O is included to facilitate I/O control, It places the contents of * AC0 on the processor bus and executes the STARTF function (F1 = 17B). By convention, * bits of AC0 must be "1" in order to signal devices. See Appendix C for a summary of * assigned bits. * Bit 0 100000B Standard Alto: Software boot feature * Bit 14 000002B Standard Alto: Ethernet * Bit 15 000001B Standard Alto: Ethernet * If bit 0 of AC0 is 1, and if an Ethernet board is plugged into the Alto, the machine * will boot, just as if the "boot button" were pressed (see sections 3.4, 8.4 and 9.2.2 * for discussions of bootstrapping). * * SIO also returns a result in AC0. If the Ethernet hardware is installed, the serial * number and/or Ethernet host address of the machine (0-377B) is loaded into AC0[8-15]. * (On Alto I, the serial number and Ethernet host address are equivalent; on Alto II, * the value loaded into AC0 is the Ethernet host address only.) If Ethernet hardware * is missing, AC0[8-15] = 377B. Microcode installed after June 1976, which this manual * describes, returns AC0[0] = 0. Microcode installed prior to June 1976 returns * AC0[0] = 1; this is a quick way to acquire the approximate vintage of a machine's * microcode. ** * TODO: move this to the Ethernet code? It's really a emulator * specific function that is decoded by the Ethernet card. */ void alto2_cpu_device::f1_early_startf() { LOG((this,LOG_EMU,2," STARTF (BUS is %06o)\n", m_bus)); /* TODO: what do we do here? reset the CPU on bit 0? */ if (X_BIT(m_bus,16,0)) { LOG((this,LOG_EMU,2,"**** Software boot feature\n")); soft_reset(); } else { LOG((this,LOG_EMU,2,"**** Ethernet start function\n")); eth_startf(); } } /** * @brief branch on odd bus */ void alto2_cpu_device::f2_late_busodd() { uint16_t r = m_bus & 1; LOG((this,LOG_EMU,2," BUSODD; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); m_next2 |= r; } /** * @brief f2_magic late: shift and use T[0] or T[15] for bit 15 or 0 */ void alto2_cpu_device::f2_late_magic() { int XC; switch (f1()) { case f1_l_lsh_1: // <-L MLSH 1 XC = (m_t >> 15) & 1; m_shifter = (m_l << 1) | XC; LOG((this,LOG_EMU,2," <-L MLSH 1 (shifer:%06o XC:%o)", m_shifter, XC)); break; case f1_l_rsh_1: // <-L MRSH 1 XC = (m_t & 1) << 15; m_shifter = (m_l >> 1) | XC; LOG((this,LOG_EMU,2," <-L MRSH 1 (shifter:%06o XC:%o)", m_shifter, XC)); break; case f1_l_lcy_8: // <-L LCY 8 m_shifter = (m_l >> 8) | (m_l << 8); break; default: // other m_shifter = m_l; break; } } /** * @brief do novel shifts: modify RESELECT with DstAC = (3 - IR[3-4]) */ void alto2_cpu_device::f2_early_load_dns() { X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); LOG((this,LOG_EMU,2," DNS<-; rsel := DstAC (%#o %s)\n", m_rsel, r_name(m_rsel))); } /** * @brief do novel shifts * *
* New emulator carry is selected by instruction register * bits CY = IR[10-11]. R register and emulator carry are * loaded only if NL = IR[12] is 0 (NL = no load). * SKIP is set according to SK = IR[13-15]. * * CARRY = !m_emu.cy * exorB = IR11 ^ IR10 * ORA = !(exorB | CARRY) * = (exorB | CARRY) ^ 1 * exorC = ORA ^ !IR11 * = ORA ^ IR11 ^ 1 * exorD = exorC ^ LALUC0 * XC = !(!(DNS & exorD) & !(MAGIC & OUTza)) * = (DNS & exorD) | (MAGIC & OUTza) * = exorD, because this is DNS * NEWCARRY = [XC, L(00), L(15), XC] for F1 = no shift, <-L RSH 1, <-L LSH 1, LCY 8 * SHZERO = shifter == 0 * DCARRY = !((!IR12 & NEWCARRY) | (IR12 & CARRY)) * = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1 * DSKIP = !((!NEWCARRY & IR14) | (SHZERO & IR13)) ^ !IR15 * = ((((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ 1) ^ (IR15 ^ 1) * = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15 **/ void alto2_cpu_device::f2_late_load_dns() { uint8_t IR10 = X_BIT(m_emu.ir,16,10); uint8_t IR11 = X_BIT(m_emu.ir,16,11); uint8_t IR12 = X_BIT(m_emu.ir,16,12); uint8_t IR13 = X_BIT(m_emu.ir,16,13); uint8_t IR14 = X_BIT(m_emu.ir,16,14); uint8_t IR15 = X_BIT(m_emu.ir,16,15); uint8_t exorB = IR11 ^ IR10; uint8_t CARRY = m_emu.cy ^ 1; uint8_t ORA = (exorB | CARRY) ^ 1; uint8_t exorC = ORA ^ (IR11 ^ 1); uint8_t exorD = exorC ^ m_laluc0; uint8_t XC = exorD; uint8_t NEWCARRY; uint8_t DCARRY; uint8_t DSKIP; uint8_t SHZERO; switch (f1()) { case f1_l_rsh_1: // <-L RSH 1 NEWCARRY = m_l & 1; m_shifter = ((m_l >> 1) | (XC << 15)) & 0177777; LOG((this,LOG_EMU,2," DNS; <-L RSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); break; case f1_l_lsh_1: // <-L LSH 1 NEWCARRY = (m_l >> 15) & 1; m_shifter = ((m_l << 1) | XC) & 0177777; LOG((this,LOG_EMU,2," DNS; <-L LSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); break; case f1_l_lcy_8: // <-L LCY 8 NEWCARRY = XC; m_shifter = (m_l >> 8) | (m_l << 8); LOG((this,LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY)); break; default: // other NEWCARRY = XC; m_shifter = m_l; LOG((this,LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY)); break; } SHZERO = (m_shifter == 0); DCARRY = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1; DSKIP = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15; m_emu.cy = DCARRY; // DCARRY is latched as new m_emu.cy m_emu.skip = DSKIP; // DSKIP is latched as new m_emu.skip /* !(IR12 & DNS) -> WR' = 0 for the register file */ if (!IR12) { m_r[m_rsel] = m_shifter; } } /** * @brief destiantion accu: modify RSELECT with DstAC = (3 - IR[3-4]) */ void alto2_cpu_device::f2_early_acdest() { X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); LOG((this,LOG_EMU,2," ACDEST<-; mux (rsel:%#o %s)\n", m_rsel, r_name(m_rsel))); } #if ALTO2_DEBUG void alto2_cpu_device::bitblt_info() { static const char *type_name[4] = {"bitmap","complement","and gray","gray"}; static const char *oper_name[4] = {"replace","paint","invert","erase"}; int bbt = m_r[rsel_ac2]; int val = debug_read_mem(bbt); LOG((this,LOG_EMU,3," BITBLT AC1:%06o AC2:%06o\n", m_r[rsel_ac1], m_r[rsel_ac2])); LOG((this,LOG_EMU,3," function : %06o\n", val)); LOG((this,LOG_EMU,3," src extRAM: %o\n", X_BIT(val,16,10))); LOG((this,LOG_EMU,3," dst extRAM: %o\n", X_BIT(val,16,11))); LOG((this,LOG_EMU,3," src type : %o (%s)\n", X_RDBITS(val,16,12,13), type_name[X_RDBITS(val,16,12,13)])); LOG((this,LOG_EMU,3," operation : %o (%s)\n", X_RDBITS(val,16,14,15), oper_name[X_RDBITS(val,16,14,15)])); val = debug_read_mem(bbt+1); LOG((this,LOG_EMU,3," unused AC2: %06o (%d)\n", val, val)); val = debug_read_mem(bbt+2); LOG((this,LOG_EMU,3," DBCA : %06o (%d)\n", val, val)); val = debug_read_mem(bbt+3); LOG((this,LOG_EMU,3," DBMR : %06o (%d words)\n", val, val)); val = debug_read_mem(bbt+4); LOG((this,LOG_EMU,3," DLX : %06o (%d bits)\n", val, val)); val = debug_read_mem(bbt+5); LOG((this,LOG_EMU,3," DTY : %06o (%d scanlines)\n", val, val)); val = debug_read_mem(bbt+6); LOG((this,LOG_EMU,3," DW : %06o (%d bits)\n", val, val)); val = debug_read_mem(bbt+7); LOG((this,LOG_EMU,3," DH : %06o (%d scanlines)\n", val, val)); val = debug_read_mem(bbt+8); LOG((this,LOG_EMU,3," SBCA : %06o (%d)\n", val, val)); val = debug_read_mem(bbt+9); LOG((this,LOG_EMU,3," SBMR : %06o (%d words)\n", val, val)); val = debug_read_mem(bbt+10); LOG((this,LOG_EMU,3," SLX : %06o (%d bits)\n", val, val)); val = debug_read_mem(bbt+11); LOG((this,LOG_EMU,3," STY : %06o (%d scanlines)\n", val, val)); LOG((this,LOG_EMU,3," GRAY0-3 : %06o %06o %06o %06o\n", debug_read_mem(bbt+12), debug_read_mem(bbt+13), debug_read_mem(bbt+14), debug_read_mem(bbt+15))); } #endif /* DEBUG */ /** * @brief load instruction register IR and branch on IR[0,5-7] * * Loading the IR clears the skip latch. */ void alto2_cpu_device::f2_late_load_ir() { uint16_t r = (X_BIT(m_bus,16,0) << 3) | X_RDBITS(m_bus,16,5,7); #if ALTO2_DEBUG /* special logging of some opcodes */ switch (m_bus) { case op_CYCLE: LOG((this,LOG_EMU,3," CYCLE AC0:#o\n", m_r[rsel_ac0])); break; case op_CYCLE + 1: case op_CYCLE + 2: case op_CYCLE + 3: case op_CYCLE + 4: case op_CYCLE + 5: case op_CYCLE + 6: case op_CYCLE + 7: case op_CYCLE + 8: case op_CYCLE + 9: case op_CYCLE +10: case op_CYCLE +11: case op_CYCLE +12: case op_CYCLE +13: case op_CYCLE +14: case op_CYCLE +15: LOG((this,LOG_EMU,3," CYCLE %#o\n", m_bus - op_CYCLE)); break; case op_BLT: LOG((this,LOG_EMU,3," BLT dst:%#o src:%#o size:%#o\n", (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, (m_r[rsel_ac0] + 1) & 017777, -m_r[rsel_ac3] & 0177777)); break; case op_BLKS: LOG((this,LOG_EMU,3," BLKS dst:%#o val:%#o size:%#o\n", (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, m_r[rsel_ac0], -m_r[rsel_ac3] & 0177777)); break; case op_DIAGNOSE1: LOG((this,LOG_EMU,3," DIAGNOSE1 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", m_r[rsel_ac0], m_r[rsel_ac1], m_r[rsel_ac2], m_r[rsel_ac3])); break; case op_DIAGNOSE2: LOG((this,LOG_EMU,3," DIAGNOSE2 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", m_r[rsel_ac0], m_r[rsel_ac1], m_r[rsel_ac2], m_r[rsel_ac3])); break; case op_BITBLT: bitblt_info(); break; case op_RDRAM: LOG((this,LOG_EMU,3," RDRAM addr:%#o\n", m_r[rsel_ac1])); break; case op_WRTRAM: LOG((this,LOG_EMU,3," WRTAM addr:%#o upper:%06o lower:%06o\n", m_r[rsel_ac1], m_r[rsel_ac0], m_r[rsel_ac3])); break; case op_JMPRAM: LOG((this,LOG_EMU,3," JMPRAM addr:%#o\n", m_r[rsel_ac1])); break; case op_XMLDA: LOG((this,LOG_EMU,3," XMLDA AC0 = [bank:%o AC1:#o]\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1])); break; case op_XMSTA: LOG((this,LOG_EMU,3," XMSTA [bank:%o AC1:#o] = AC0 (%#o)\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1], m_r[rsel_ac0])); break; } #endif m_emu.ir = m_bus; m_emu.skip = 0; m_next2 |= r; } /** * @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] */ void alto2_cpu_device::f2_late_idisp() { uint16_t r; if (IR_ARITH(m_emu.ir)) { /* 1xxxxxxxxxxxxxxx */ r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ LOG((this,LOG_EMU,2," IDISP<-; branch on SH^3 (%#o|%#o)\n", m_next2, r)); } else { //int addr = CTL2K_U3(f2_emu_idisp) + X_RDBITS(m_emu.ir,16,1,7); // The above line triggers the following warning in PVS-Studio: // V501: There are identical sub-expressions to the left and to the right of the '==' operator: f2_emu_idisp == f2_emu_idisp // This is because CTL2K_U3(f2) checks f2 == f2_emu_idisp, and so will always evaluate to true in this case. // Consider checking if this is a typo or if it is correct. int addr = 0x80 + X_RDBITS(m_emu.ir,16,1,7); /* 0???????xxxxxxxx */ r = m_ctl2k_u3[addr]; LOG((this,LOG_EMU,2," IDISP<-; IR (%#o) branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", m_emu.ir, addr, m_next2, r)); } m_next2 |= r; } /** * @brief source accu: modify RSELECT with SrcAC = (3 - IR[1-2]) */ void alto2_cpu_device::f2_early_acsource() { X_WRBITS(m_rsel, 5, 3, 4, IR_SrcAC(m_emu.ir) ^ 3); LOG((this,LOG_EMU,2," <-ACSOURCE; rsel := SrcAC (%#o %s)\n", m_rsel, r_name(m_rsel))); } /** * @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] */ void alto2_cpu_device::f2_late_acsource() { uint16_t r; if (IR_ARITH(m_emu.ir)) { /* 1xxxxxxxxxxxxxxx */ r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ LOG((this,LOG_EMU,2," <-ACSOURCE; branch on SH^3 (%#o|%#o)\n", m_next2, r)); } else { int addr = CTL2K_U3(f2_emu_acsource) + X_RDBITS(m_emu.ir,16,1,7); /* 0???????xxxxxxxx */ r = m_ctl2k_u3[addr]; LOG((this,LOG_EMU,2," <-ACSOURCE; branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", addr, m_next2, r)); } m_next2 |= r; } void alto2_cpu_device::init_emu(int task) { memset(&m_emu, 0, sizeof(m_emu)); save_item(NAME(m_emu.ir)); save_item(NAME(m_emu.skip)); save_item(NAME(m_emu.cy)); init_ram(task); } void alto2_cpu_device::exit_emu() { // nothing to do yet } void alto2_cpu_device::reset_emu() { m_emu.ir = 0; m_emu.skip = 0; m_emu.cy = 0; }