branches/alto2/src/emu/cpu/alto2/alto2cpu.c
r26355 | r26356 | |
1120 | 1120 | *reinterpret_cast<UINT32 *>(m_ucode_cram + offset * 4) = data; |
1121 | 1121 | } |
1122 | 1122 | |
1123 | | //! direct read access to the microcode CROM |
1124 | | #define RD_CROM(addr) (addr < ALTO2_UCODE_RAM_BASE ? \ |
1125 | | *reinterpret_cast<UINT32 *>(m_ucode_crom + addr * 4) : \ |
1126 | | *reinterpret_cast<UINT32 *>(m_ucode_cram + (addr - ALTO2_UCODE_RAM_BASE) * 4)) |
1127 | | |
1128 | | |
1129 | 1123 | //! read constants PROM |
1130 | 1124 | READ16_MEMBER ( alto2_cpu_device::const_r ) |
1131 | 1125 | { |
1132 | 1126 | return *reinterpret_cast<UINT16 *>(m_const_data + offset * 2); |
1133 | 1127 | } |
1134 | 1128 | |
1135 | | #define PUT_EVEN(dword,word) X_WRBITS(dword,32, 0,15,word) |
1136 | | #define GET_EVEN(dword) X_RDBITS(dword,32, 0,15) |
1137 | | #define PUT_ODD(dword,word) X_WRBITS(dword,32,16,31,word) |
1138 | | #define GET_ODD(dword) X_RDBITS(dword,32,16,31) |
| 1129 | //! direct read access to the microcode CROM or CRAM |
| 1130 | #define RD_UCODE(addr) (addr < ALTO2_UCODE_RAM_BASE ? \ |
| 1131 | *reinterpret_cast<UINT32 *>(m_ucode_crom + addr * 4) : \ |
| 1132 | *reinterpret_cast<UINT32 *>(m_ucode_cram + (addr - ALTO2_UCODE_RAM_BASE) * 4)) |
1139 | 1133 | |
1140 | | //! read i/o space RAM |
1141 | | READ16_MEMBER ( alto2_cpu_device::ioram_r ) |
1142 | | { |
1143 | | offs_t dword_addr = offset / 2; |
1144 | | return static_cast<UINT16>(offset & 1 ? GET_ODD(m_mem.ram[dword_addr]) : GET_EVEN(m_mem.ram[dword_addr])); |
1145 | | } |
1146 | | |
1147 | | //! write i/o space RAM |
1148 | | WRITE16_MEMBER( alto2_cpu_device::ioram_w ) |
1149 | | { |
1150 | | offs_t dword_addr = offset / 2; |
1151 | | if (offset & 1) |
1152 | | PUT_ODD(m_mem.ram[dword_addr], data); |
1153 | | else |
1154 | | PUT_EVEN(m_mem.ram[dword_addr], data); |
1155 | | } |
1156 | | |
1157 | 1134 | //------------------------------------------------- |
1158 | 1135 | // device_reset - device-specific reset |
1159 | 1136 | //------------------------------------------------- |
r26355 | r26356 | |
1161 | 1138 | void alto2_cpu_device::device_reset() |
1162 | 1139 | { |
1163 | 1140 | soft_reset(); |
1164 | | } |
| 1141 | // call all sub-devices' reset_... |
| 1142 | reset_memory(); |
| 1143 | reset_disk(); |
| 1144 | reset_disp(); |
| 1145 | reset_kbd(); |
| 1146 | reset_mouse(); |
| 1147 | reset_hw(); |
1165 | 1148 | |
| 1149 | reset_emu(); |
| 1150 | reset_ksec(); |
| 1151 | reset_ether(); |
| 1152 | reset_mrt(); |
| 1153 | reset_dwt(); |
| 1154 | reset_curt(); |
| 1155 | reset_dht(); |
| 1156 | reset_dvt(); |
| 1157 | reset_part(); |
| 1158 | reset_kwd();} |
| 1159 | |
1166 | 1160 | /** |
1167 | 1161 | * @brief callback is called by the drive timer whenever a new sector starts |
1168 | 1162 | * |
r26355 | r26356 | |
2330 | 2324 | do { |
2331 | 2325 | int do_bs, flags; |
2332 | 2326 | |
2333 | | m_cycle++; |
2334 | | /* nano seconds per cycle */ |
2335 | | m_pico_time[m_task] += ALTO2_UCYCLE; |
| 2327 | m_mpc = m_next; // next instruction's micro program counter |
| 2328 | m_mir = RD_UCODE(m_mpc); // fetch the micro code |
2336 | 2329 | |
2337 | | /* next instruction's mpc */ |
2338 | | m_mpc = m_next; |
2339 | | m_mir = RD_CROM(m_mpc); |
2340 | | |
| 2330 | // extract the bit fields |
2341 | 2331 | m_d_rsel = m_rsel = X_RDBITS(m_mir, 32, DRSEL0, DRSEL4); |
2342 | 2332 | m_d_aluf = X_RDBITS(m_mir, 32, DALUF0, DALUF3); |
2343 | 2333 | m_d_bs = X_RDBITS(m_mir, 32, DBS0, DBS2); |
r26355 | r26356 | |
2345 | 2335 | m_d_f2 = X_RDBITS(m_mir, 32, DF2_0, DF2_3); |
2346 | 2336 | m_d_loadt = X_BIT(m_mir, 32, DLOADT); |
2347 | 2337 | m_d_loadl = X_BIT(m_mir, 32, DLOADL); |
2348 | | m_next = X_RDBITS(m_mir, 32, NEXT0, NEXT9) | m_next2; |
2349 | | m_next2 = X_RDBITS(RD_CROM(m_next), 32, NEXT0, NEXT9) | (m_next2 & ~ALTO2_UCODE_PAGE_MASK); |
2350 | | LOG((LOG_CPU,2,"%s-%04o: %011o r:%02o aluf:%02o bs:%02o f1:%02o f2:%02o t:%o l:%o next:%05o next2:%05o\n", |
2351 | | task_name(m_task), m_mpc, m_mir, m_rsel, m_d_aluf, m_d_bs, m_d_f1, m_d_f2, m_d_loadt, m_d_loadl, m_next, m_next2)); |
| 2338 | |
2352 | 2339 | debugger_instruction_hook(this, m_mpc); |
2353 | 2340 | |
| 2341 | m_cycle++; |
| 2342 | m_pico_time[m_task] += ALTO2_UCYCLE; // add per task pico seconds per cycle |
| 2343 | |
2354 | 2344 | /* |
2355 | | * This bus source decoding is not performed if f1 = 7 or f2 = 7. |
2356 | | * These functions use the BS field to provide part of the address |
2357 | | * to the constant ROM |
| 2345 | * This bus source decoding is not performed if f1 == f1_const |
| 2346 | * or f2 == f2_const. These functions use the MIR BS field to |
| 2347 | * provide a part of the address to the constant ROM instead. |
2358 | 2348 | */ |
2359 | 2349 | do_bs = !(m_d_f1 == f1_const || m_d_f2 == f2_const); |
2360 | 2350 | |
2361 | | if (m_d_f1 == f1_load_mar) { |
2362 | | if (check_mem_load_mar_stall(m_rsel)) { |
2363 | | LOG((LOG_CPU,3, " MAR← stall\n")); |
2364 | | m_next2 = m_next; |
2365 | | m_next = m_mpc; |
2366 | | continue; |
2367 | | } |
2368 | | } else if (m_d_f2 == f2_load_md) { |
2369 | | if (check_mem_write_stall()) { |
2370 | | LOG((LOG_CPU,3, " MD← stall\n")); |
2371 | | m_next2 = m_next; |
2372 | | m_next = m_mpc; |
2373 | | continue; |
2374 | | } |
| 2351 | if (m_d_f1 == f1_load_mar && check_mem_load_mar_stall(m_rsel)) { |
| 2352 | LOG((LOG_CPU,3, " MAR← stall\n")); |
| 2353 | continue; |
2375 | 2354 | } |
2376 | | if (do_bs && m_d_bs == bs_read_md) { |
2377 | | if (check_mem_read_stall()) { |
2378 | | LOG((LOG_CPU,3, " ←MD stall\n")); |
2379 | | m_next2 = m_next; |
2380 | | m_next = m_mpc; |
2381 | | continue; |
2382 | | } |
| 2355 | if (m_d_f2 == f2_load_md && check_mem_write_stall()) { |
| 2356 | LOG((LOG_CPU,3, " MD← stall\n")); |
| 2357 | continue; |
2383 | 2358 | } |
| 2359 | if (do_bs && m_d_bs == bs_read_md && check_mem_read_stall()) { |
| 2360 | LOG((LOG_CPU,3, " ←MD stall\n")); |
| 2361 | continue; |
| 2362 | } |
| 2363 | // now read the next instruction field from the MIR and modify it |
| 2364 | m_next = X_RDBITS(m_mir, 32, NEXT0, NEXT9) | m_next2; |
| 2365 | // prefetch the next instruction's next field as next2 |
| 2366 | m_next2 = X_RDBITS(RD_UCODE(m_next), 32, NEXT0, NEXT9) | (m_next2 & ~ALTO2_UCODE_PAGE_MASK); |
| 2367 | LOG((LOG_CPU,2,"%s-%04o: %011o r:%02o aluf:%02o bs:%02o f1:%02o f2:%02o t:%o l:%o next:%05o next2:%05o\n", |
| 2368 | task_name(m_task), m_mpc, m_mir, m_rsel, m_d_aluf, m_d_bs, m_d_f1, m_d_f2, m_d_loadt, m_d_loadl, m_next, m_next2)); |
2384 | 2369 | |
| 2370 | // BUS is all ones at the start of each cycle |
2385 | 2371 | m_bus = 0177777; |
2386 | 2372 | |
2387 | 2373 | if (m_rdram_flag) |
2388 | 2374 | rdram(); |
2389 | 2375 | |
2390 | | /* |
2391 | | * The constant memory is gated to the bus by F1 == f1_const, F2 == f2_const, or BS >= 4 |
2392 | | */ |
| 2376 | // The constant memory is gated to the bus by F1 == f1_const, F2 == f2_const, or BS >= 4 |
2393 | 2377 | if (!do_bs || m_d_bs >= bs_task_4) { |
2394 | | int addr = 8 * m_rsel + m_d_bs; |
2395 | | UINT16 data = m_const_data[2*addr+0] | (m_const_data[2*addr+1] << 8); |
| 2378 | UINT32 addr = 8 * m_rsel + m_d_bs; |
| 2379 | // FIXME: is the format of m_const_data endian safe? |
| 2380 | UINT16 data = m_const_data[2*addr] | (m_const_data[2*addr+1] << 8); |
2396 | 2381 | m_bus &= data; |
2397 | 2382 | LOG((LOG_CPU,2," %#o; BUS &= %#o CONST[%03o]\n", m_bus, data, addr)); |
2398 | 2383 | } |
2399 | 2384 | |
2400 | 2385 | /* |
2401 | | * early f2 has to be done before early bs, because the |
2402 | | * emulator f2 acsource or acdest may change m_rsel |
| 2386 | * early F2 function has to be called before early BS, |
| 2387 | * because the emulator task F2 acsource or acdest may |
| 2388 | * change the m_rsel |
2403 | 2389 | */ |
2404 | 2390 | ((*this).*m_f2[0][m_task][m_d_f2])(); |
2405 | 2391 | |
2406 | | /* |
2407 | | * early bs can be done now |
2408 | | */ |
| 2392 | // early BS function can be done now |
2409 | 2393 | if (do_bs) |
2410 | 2394 | ((*this).*m_bs[0][m_task][m_d_bs])(); |
2411 | 2395 | |
2412 | | /* |
2413 | | * early f1 |
2414 | | */ |
| 2396 | // early F1 function |
2415 | 2397 | ((*this).*m_f1[0][m_task][m_d_f1])(); |
2416 | 2398 | |
2417 | 2399 | #if USE_ALU_74181 |
2418 | | // The ALU a10 PROM address lines are |
2419 | | // A4:SKIP A3:ALUF0 A2:ALUF1 A1:ALUF2 A0:ALUF3 |
2420 | | // The PROM output lines are |
2421 | | // B0: unused B1: TSELECT B2: ALUCI' B3: ALUM' |
2422 | | // B4: ALUS0' B5: ALUS1' B6: ALUS2' B7: ALUS3' |
2423 | | // B1 and B3-B7 are inverted on loading the PROM |
| 2400 | /** |
| 2401 | * The ALU a10 PROM address lines are |
| 2402 | * A4:SKIP A3:ALUF0 A2:ALUF1 A1:ALUF2 A0:ALUF3 |
| 2403 | * The PROM output lines are |
| 2404 | * B0: unused B1: TSELECT B2: ALUCI' B3: ALUM' |
| 2405 | * B4: ALUS0' B5: ALUS1' B6: ALUS2' B7: ALUS3' |
| 2406 | * |
| 2407 | * B1 and B3-B7 are inverted on loading the PROM |
| 2408 | */ |
2424 | 2409 | UINT8 a10 = m_alu_a10[(m_emu.skip << 4) | m_d_aluf]; |
2425 | 2410 | UINT32 alu = alu_74181(m_bus, m_t, a10); |
2426 | 2411 | m_aluc0 = (alu >> 16) & 1; |
r26355 | r26356 | |
2641 | 2626 | m_alu = static_cast<UINT16>(alu); |
2642 | 2627 | #endif |
2643 | 2628 | |
2644 | | /* WRTRAM now, before L is changed */ |
| 2629 | // WRTRAM must happen now before L is changed |
2645 | 2630 | if (m_wrtram_flag) |
2646 | 2631 | wrtram(); |
2647 | 2632 | |
2648 | 2633 | // shifter passes L, if F1 is not one of L LSH 1, L RSH 1 or L LCY 8 |
2649 | 2634 | m_shifter = m_l; |
2650 | 2635 | |
2651 | | /* late F1 is done now */ |
| 2636 | // late F1 function call now |
2652 | 2637 | ((*this).*m_f1[1][m_task][m_d_f1])(); |
2653 | 2638 | |
2654 | | /* late F2 is done now */ |
| 2639 | // late F2 function call now |
2655 | 2640 | ((*this).*m_f2[1][m_task][m_d_f2])(); |
2656 | 2641 | |
2657 | | /* late BS is done now, if no constant was put on the bus */ |
| 2642 | // late BS function call now, if no constant was put on the bus |
2658 | 2643 | if (do_bs) |
2659 | 2644 | ((*this).*m_bs[1][m_task][m_d_bs])(); |
2660 | 2645 | |
r26355 | r26356 | |
2670 | 2655 | } |
2671 | 2656 | } |
2672 | 2657 | |
2673 | | // update L register and LALUC0 |
| 2658 | // update L register and LALUC0 if LOADL is set |
2674 | 2659 | if (m_d_loadl) { |
2675 | 2660 | m_l = m_alu; // load L from ALU |
2676 | 2661 | if (flags & ALUM) { |
2677 | | m_laluc0 = 0; // logic operation - latch 0 |
| 2662 | m_laluc0 = 0; // logic operation - put 0 into latched carry |
2678 | 2663 | LOG((LOG_CPU,2, " L← ALU (%#o); LALUC0← %o\n", m_alu, 0)); |
2679 | 2664 | } else { |
2680 | | m_laluc0 = m_aluc0; // arithmethic operation - latch carry |
| 2665 | m_laluc0 = m_aluc0; // arithmethic operation - put ALU carry into latched carry |
2681 | 2666 | LOG((LOG_CPU,2, " L← ALU (%#o); LALUC0← ALUC0 (%o)\n", m_alu, m_aluc0)); |
2682 | 2667 | } |
2683 | 2668 | // update M (MYL) register, if a RAM related task is active |
r26355 | r26356 | |
2690 | 2675 | |
2691 | 2676 | // handle task switching |
2692 | 2677 | if (m_task != m_next2_task) { |
2693 | | /* switch now? */ |
| 2678 | // switch now? |
2694 | 2679 | if (m_task == m_next_task) { |
2695 | | /* one more microinstruction */ |
| 2680 | // one more microinstruction |
2696 | 2681 | m_next_task = m_next2_task; |
2697 | 2682 | } else { |
2698 | | /* save this task's mpc and next2 */ |
| 2683 | // save this task's next and next2 |
2699 | 2684 | m_task_mpc[m_task] = m_next; |
2700 | 2685 | m_task_next2[m_task] = m_next2; |
2701 | 2686 | m_task = m_next_task; |
r26355 | r26356 | |
2708 | 2693 | } |
2709 | 2694 | } |
2710 | 2695 | |
2711 | | /* |
| 2696 | /** |
2712 | 2697 | * Subtract the microcycle time from the display time accu. |
2713 | 2698 | * If it underflows, call the display state machine and add |
2714 | | * the time for 24 pixel clocks to the accu. |
2715 | | * This is very close to every seventh CPU cycle. |
| 2699 | * the time for 32(!) pixel clocks to the accu. |
| 2700 | * This is very close to every seventh CPU cycle (really?) |
2716 | 2701 | */ |
2717 | | m_dsp_time -= ALTO2_UCYCLE; |
2718 | | if (m_dsp_time < 0) { |
2719 | | display_state_machine(); |
2720 | | m_dsp_time += ALTO2_DISPLAY_BITTIME(24); |
| 2702 | if (m_dsp_time >= 0) { |
| 2703 | m_dsp_time -= ALTO2_UCYCLE; |
| 2704 | if (m_dsp_time < 0) |
| 2705 | display_state_machine(); |
2721 | 2706 | } |
2722 | 2707 | if (m_unload_time >= 0) { |
2723 | | /* |
| 2708 | /** |
2724 | 2709 | * Subtract the microcycle time from the unload time accu. |
2725 | 2710 | * If it underflows, call the unload word function which adds |
2726 | 2711 | * the time for 16 or 32 pixel clocks to the accu, or ends |
r26355 | r26356 | |
2853 | 2838 | #if (USE_BITCLK_TIMER == 0) |
2854 | 2839 | m_bitclk_time = 0; // reset the bitclk timing accu |
2855 | 2840 | #endif |
2856 | | |
2857 | | // call all sub-devices' reset_... |
2858 | | reset_memory(); |
2859 | | reset_disk(); |
2860 | | reset_disp(); |
2861 | | reset_kbd(); |
2862 | | reset_mouse(); |
2863 | | reset_hw(); |
2864 | | |
2865 | | reset_emu(); |
2866 | | reset_ksec(); |
2867 | | reset_ether(); |
2868 | | reset_mrt(); |
2869 | | reset_dwt(); |
2870 | | reset_curt(); |
2871 | | reset_dht(); |
2872 | | reset_dvt(); |
2873 | | reset_part(); |
2874 | | reset_kwd(); |
2875 | 2841 | } |