diff options
Diffstat (limited to 'src/devices/cpu/i86/i186.cpp')
-rw-r--r-- | src/devices/cpu/i86/i186.cpp | 1116 |
1 files changed, 642 insertions, 474 deletions
diff --git a/src/devices/cpu/i86/i186.cpp b/src/devices/cpu/i86/i186.cpp index e20db304930..ac6ce5e6788 100644 --- a/src/devices/cpu/i86/i186.cpp +++ b/src/devices/cpu/i86/i186.cpp @@ -3,16 +3,26 @@ // Peripheral code from rmnimbus driver by Phill Harvey-Smith which is // based on the Leland sound driver by Aaron Giles and Paul Leaman +// Note: the X1 input (typically an XTAL) is divided by 2 internally. +// The device clock should therefore be twice the desired operating +// frequency (and twice the speed rating suffixed to the part number). +// Some high-performance AMD versions, however, generate the system +// clock with a PLL and only support XTAL dividers other than 1 for +// compatibility and power-saving modes. + #include "emu.h" #include "i186.h" -#include "debugger.h" #include "i86inline.h" -#define LOG_PORTS 0 -#define LOG_INTERRUPTS 0 -#define LOG_INTERRUPTS_EXT 0 -#define LOG_TIMER 0 -#define LOG_DMA 0 +#define LOG_PORTS (1U << 1) +#define LOG_INTERRUPTS (1U << 2) +#define LOG_INTERRUPTS_EXT (1U << 3) +#define LOG_TIMER (1U << 4) +#define LOG_DMA (1U << 5) +#define LOG_DMA_HIFREQ (1U << 6) + +#define VERBOSE (0) +#include "logmacro.h" /* external int priority masks */ @@ -118,21 +128,29 @@ const uint8_t i80186_cpu_device::m_i80186_timing[] = 33, /* (80186) BOUND */ }; -DEFINE_DEVICE_TYPE(I80186, i80186_cpu_device, "i80186", "Intel I80186") -DEFINE_DEVICE_TYPE(I80188, i80188_cpu_device, "i80188", "Intel I80188") +DEFINE_DEVICE_TYPE(I80186, i80186_cpu_device, "i80186", "Intel 80186") +DEFINE_DEVICE_TYPE(I80188, i80188_cpu_device, "i80188", "Intel 80188") +DEFINE_DEVICE_TYPE(AM186EM, am186em_device, "am186em", "AMD Am186EM") +DEFINE_DEVICE_TYPE(AM188EM, am188em_device, "am188em", "AMD Am188EM") + +i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : i80186_cpu_device(mconfig, I80186, tag, owner, clock, 16) +{ +} i80188_cpu_device::i80188_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : i80186_cpu_device(mconfig, I80188, tag, owner, clock, 8) { - memcpy(m_timing, m_i80186_timing, sizeof(m_i80186_timing)); - set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(i80186_cpu_device::int_callback), this)); } -i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : i80186_cpu_device(mconfig, I80186, tag, owner, clock, 16) +am186em_device::am186em_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : i80186_cpu_device(mconfig, AM186EM, tag, owner, clock, 16) +{ +} + +am188em_device::am188em_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : i80186_cpu_device(mconfig, AM188EM, tag, owner, clock, 8) { - memcpy(m_timing, m_i80186_timing, sizeof(m_i80186_timing)); - set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(i80186_cpu_device::int_callback), this)); } i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int data_bus_size) @@ -140,16 +158,21 @@ i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, device_type , m_program_config("program", ENDIANNESS_LITTLE, data_bus_size, 20, 0) , m_opcodes_config("opcodes", ENDIANNESS_LITTLE, data_bus_size, 20, 0) , m_io_config("io", ENDIANNESS_LITTLE, data_bus_size, 16, 0) - , m_read_slave_ack_func(*this) + , m_read_slave_ack_func(*this, 0) , m_out_chip_select_func(*this) , m_out_tmrout0_func(*this) , m_out_tmrout1_func(*this) + , m_irmx_irq_cb(*this) + , m_irqa_cb(*this) + , m_irmx_irq_ack(*this) { + memcpy(m_timing, m_i80186_timing, sizeof(m_i80186_timing)); + set_irq_acknowledge_callback(*this, FUNC(i80186_cpu_device::inta_callback)); } device_memory_interface::space_config_vector i80186_cpu_device::memory_space_config() const { - if(has_configured_map(AS_OPCODES)) + if (has_configured_map(AS_OPCODES)) return space_config_vector { std::make_pair(AS_PROGRAM, &m_program_config), std::make_pair(AS_OPCODES, &m_opcodes_config), @@ -171,25 +194,25 @@ uint8_t i80186_cpu_device::fetch() void i80186_cpu_device::execute_run() { - while(m_icount > 0 ) + while (m_icount > 0) { - if((m_dma[0].drq_state && (m_dma[0].control & ST_STOP)) || (m_dma[1].drq_state && (m_dma[1].control & ST_STOP))) + if ((m_dma[0].drq_state && (m_dma[0].control & ST_STOP)) || (m_dma[1].drq_state && (m_dma[1].control & ST_STOP))) { int channel = m_last_dma ? 0 : 1; m_last_dma = !m_last_dma; - if(!(m_dma[1].drq_state && (m_dma[1].control & ST_STOP))) + if (!(m_dma[1].drq_state && (m_dma[1].control & ST_STOP))) channel = 0; - else if(!(m_dma[0].drq_state && (m_dma[0].control & ST_STOP))) + else if (!(m_dma[0].drq_state && (m_dma[0].control & ST_STOP))) channel = 1; - else if((m_dma[0].control & CHANNEL_PRIORITY) && !(m_dma[1].control & CHANNEL_PRIORITY)) + else if ((m_dma[0].control & CHANNEL_PRIORITY) && !(m_dma[1].control & CHANNEL_PRIORITY)) channel = 0; - else if((m_dma[1].control & CHANNEL_PRIORITY) && !(m_dma[0].control & CHANNEL_PRIORITY)) + else if ((m_dma[1].control & CHANNEL_PRIORITY) && !(m_dma[0].control & CHANNEL_PRIORITY)) channel = 1; m_icount--; drq_callback(channel); continue; } - if ( m_seg_prefix_next ) + if (m_seg_prefix_next) { m_seg_prefix = true; m_seg_prefix_next = false; @@ -200,15 +223,15 @@ void i80186_cpu_device::execute_run() m_seg_prefix = false; /* Dispatch IRQ */ - if ( m_pending_irq && m_no_interrupt == 0 ) + if (m_pending_irq && m_no_interrupt == 0) { - if ( m_pending_irq & NMI_IRQ ) + if (m_pending_irq & NMI_IRQ) { interrupt(2); m_pending_irq &= ~NMI_IRQ; m_halt = false; } - else if ( m_IF ) + else if (m_IF) { /* the actual vector is retrieved after pushing flags */ /* and clearing the IF */ @@ -217,22 +240,23 @@ void i80186_cpu_device::execute_run() } } - if(m_halt) + if (m_halt) { + debugger_wait_hook(); m_icount = 0; return; } /* No interrupt allowed between last instruction and this one */ - if ( m_no_interrupt ) + if (m_no_interrupt) { m_no_interrupt--; } /* trap should allow one instruction to be executed */ - if ( m_fire_trap ) + if (m_fire_trap) { - if ( m_fire_trap >= 2 ) + if (m_fire_trap >= 2) { interrupt(1); m_fire_trap = 0; @@ -280,12 +304,11 @@ void i80186_cpu_device::execute_run() case 0x62: // i_bound { - uint32_t low,high,tmp; m_modrm = fetch(); - low = GetRMWord(); - high = GetnextRMWord(); - tmp = RegWord(); - if (tmp<low || tmp>high) + uint32_t low = GetRMWord(); + uint32_t high = GetnextRMWord(); + uint32_t tmp = RegWord(); + if (tmp < low || tmp > high) interrupt(5); CLK(BOUND); logerror("%06x: bound %04x high %04x low %04x tmp\n", m_pc, high, low, tmp); @@ -293,16 +316,15 @@ void i80186_cpu_device::execute_run() break; case 0x68: // i_push_d16 - PUSH( fetch_word() ); + PUSH(fetch_word()); CLK(PUSH_IMM); break; case 0x69: // i_imul_d16 { - uint32_t tmp; DEF_r16w(); - tmp = fetch_word(); - m_dst = (int32_t)((int16_t)m_src)*(int32_t)((int16_t)tmp); + uint32_t tmp = fetch_word(); + m_dst = (int32_t)((int16_t)m_src) * (int32_t)((int16_t)tmp); m_CarryVal = m_OverVal = (((int32_t)m_dst) >> 15 != 0) && (((int32_t)m_dst) >> 15 != -1); RegWord(m_dst); CLKM(IMUL_RRI16, IMUL_RMI16); @@ -310,16 +332,15 @@ void i80186_cpu_device::execute_run() break; case 0x6a: // i_push_d8 - PUSH( (uint16_t)((int16_t)((int8_t)fetch())) ); + PUSH((uint16_t)((int16_t)((int8_t)fetch()))); CLK(PUSH_IMM); break; case 0x6b: // i_imul_d8 { - uint32_t src2; DEF_r16w(); - src2= (uint16_t)((int16_t)((int8_t)fetch())); - m_dst = (int32_t)((int16_t)m_src)*(int32_t)((int16_t)src2); + uint32_t src2 = (uint16_t)(int8_t)fetch(); + m_dst = (int32_t)((int16_t)m_src) * (int32_t)((int16_t)src2); m_CarryVal = m_OverVal = (((int32_t)m_dst) >> 15 != 0) && (((int32_t)m_dst) >> 15 != -1); RegWord(m_dst); CLKM(IMUL_RRI8, IMUL_RMI8); @@ -345,7 +366,7 @@ void i80186_cpu_device::execute_run() case 0x8e: // i_mov_sregw m_modrm = fetch(); m_src = GetRMWord(); - CLKM(MOV_SR,MOV_SM); + CLKM(MOV_SR, MOV_SM); switch (m_modrm & 0x38) { case 0x00: /* mov es,ew */ @@ -368,21 +389,20 @@ void i80186_cpu_device::execute_run() case 0xc0: // i_rotshft_bd8 { - uint8_t c; m_modrm = fetch(); m_src = GetRMByte(); m_dst = m_src; - c = fetch() & 0x1f; - CLKM(ROT_REG_BASE,ROT_M8_BASE); + uint8_t c = fetch() & 0x1f; + CLKM(ROT_REG_BASE, ROT_M8_BASE); m_icount -= m_timing[ROT_REG_BIT] * c; if (c) { - switch ( m_modrm & 0x38 ) + switch (m_modrm & 0x38) { - case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x00: do { ROL_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; case 0x30: case 0x20: SHL_BYTE(c); break; case 0x28: SHR_BYTE(c); break; @@ -394,21 +414,20 @@ void i80186_cpu_device::execute_run() case 0xc1: // i_rotshft_wd8 { - uint8_t c; m_modrm = fetch(); m_src = GetRMWord(); m_dst = m_src; - c = fetch() & 0x1f; - CLKM(ROT_REG_BASE,ROT_M16_BASE); + uint8_t c = fetch() & 0x1f; + CLKM(ROT_REG_BASE, ROT_M16_BASE); m_icount -= m_timing[ROT_REG_BIT] * c; if (c) { - switch ( m_modrm & 0x38 ) + switch (m_modrm & 0x38) { - case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x00: do { ROL_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; case 0x30: case 0x20: SHL_WORD(c); break; case 0x28: SHR_WORD(c); break; @@ -421,19 +440,18 @@ void i80186_cpu_device::execute_run() case 0xc8: // i_enter { uint16_t nb = fetch(); - uint32_t level; - nb |= fetch() << 8; - level = fetch(); + + uint32_t level = fetch(); CLK(!level ? ENTER0 : (level == 1) ? ENTER1 : ENTER_BASE); - if(level > 1) + if (level > 1) m_icount -= level * m_timing[ENTER_COUNT]; PUSH(m_regs.w[BP]); m_regs.w[BP] = m_regs.w[SP]; m_regs.w[SP] -= nb; - for (int i=1; i<level; i++) + for (int i = 1; i < level; i++) { - PUSH( GetMemW(SS,m_regs.w[BP] - i*2) ); + PUSH(GetMemW(SS, m_regs.w[BP] - i * 2)); } if (level) { @@ -450,22 +468,20 @@ void i80186_cpu_device::execute_run() case 0xd2: // i_rotshft_bcl { - uint8_t c; - m_modrm = fetch(); m_src = GetRMByte(); m_dst = m_src; - c = m_regs.b[CL] & 0x1f; - CLKM(ROT_REG_BASE,ROT_M16_BASE); + uint8_t c = m_regs.b[CL] & 0x1f; + CLKM(ROT_REG_BASE, ROT_M16_BASE); m_icount -= m_timing[ROT_REG_BIT] * c; if (c) { - switch ( m_modrm & 0x38 ) + switch (m_modrm & 0x38) { - case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; - case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x00: do { ROL_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c > 0); PutbackRMByte(m_dst); break; case 0x30: case 0x20: SHL_BYTE(c); break; case 0x28: SHR_BYTE(c); break; @@ -477,22 +493,20 @@ void i80186_cpu_device::execute_run() case 0xd3: // i_rotshft_wcl { - uint8_t c; - m_modrm = fetch(); m_src = GetRMWord(); m_dst = m_src; - c = m_regs.b[CL] & 0x1f; - CLKM(ROT_REG_BASE,ROT_M16_BASE); + uint8_t c = m_regs.b[CL] & 0x1f; + CLKM(ROT_REG_BASE, ROT_M16_BASE); m_icount -= m_timing[ROT_REG_BIT] * c; if (c) { - switch ( m_modrm & 0x38 ) + switch (m_modrm & 0x38) { - case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; - case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x00: do { ROL_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c > 0); PutbackRMWord(m_dst); break; case 0x30: case 0x20: SHL_WORD(c); break; case 0x28: SHR_WORD(c); break; @@ -510,7 +524,7 @@ void i80186_cpu_device::execute_run() case 0xdd: case 0xde: case 0xdf: - if(m_reloc & 0x8000) + if (m_reloc & 0x8000) { m_ip = m_prev_ip; interrupt(7); @@ -520,7 +534,7 @@ void i80186_cpu_device::execute_run() GetRMByte(); CLK(NOP); // The 80187 has the FSTSW AX instruction - if((m_modrm == 0xe0) && (op == 0xdf)) + if ((m_modrm == 0xe0) && (op == 0xdf)) m_regs.w[AX] = 0xffff; // FPU not present break; @@ -543,26 +557,78 @@ void i80186_cpu_device::execute_run() switch (next) { - case 0x6c: CLK(OVERRIDE); if (c) do { i_insb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; - case 0x6d: CLK(OVERRIDE); if (c) do { i_insw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; - case 0x6e: CLK(OVERRIDE); if (c) do { i_outsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; - case 0x6f: CLK(OVERRIDE); if (c) do { i_outsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6c: + CLK(OVERRIDE); + if (c) + { + do + { + i_insb(); + c--; + } while (c > 0 && m_icount > 0); + } + m_regs.w[CX] = c; + m_seg_prefix = false; + m_seg_prefix_next = false; + break; + case 0x6d: + CLK(OVERRIDE); + if (c) + { + do + { + i_insw(); + c--; + } while (c > 0 && m_icount > 0); + } + m_regs.w[CX] = c; + m_seg_prefix = false; + m_seg_prefix_next = false; + break; + case 0x6e: + CLK(OVERRIDE); + if (c) + { + do + { + i_outsb(); + c--; + } while (c > 0 && m_icount > 0); + } + m_regs.w[CX] = c; + m_seg_prefix = false; + m_seg_prefix_next = false; + break; + case 0x6f: + CLK(OVERRIDE); + if (c) + { + do + { + i_outsw(); + c--; + } while (c > 0 && m_icount > 0); + } + m_regs.w[CX] = c; + m_seg_prefix = false; + m_seg_prefix_next = false; + break; default: // Decrement IP and pass on m_ip -= 1 + (m_seg_prefix_next ? 1 : 0); pass = true; break; } - if(!pass) + if (!pass) { - if(c) + if (c) m_ip = m_prev_ip; break; } } - // through to default + [[fallthrough]]; default: - if(!common_op(op)) + if (!common_op(op)) { m_icount -= 10; // UD fault timing? logerror("%06x: Invalid Opcode %02x\n", m_pc, op); @@ -584,7 +650,7 @@ void i80186_cpu_device::device_start() state_add( I8086_VECTOR, "V", m_int_vector).formatstr("%02X"); state_add( I8086_PC, "PC", m_pc ).callimport().formatstr("%05X"); - state_add( STATE_GENPCBASE, "CURPC", m_pc ).callimport().formatstr("%05X").noshow(); + state_add<uint32_t>( STATE_GENPCBASE, "CURPC", [this] { return (m_sregs[CS] << 4) + m_prev_ip; }).mask(0xfffff).noshow(); state_add( I8086_HALT, "HALT", m_halt ).mask(1); // Most of these mnemonics are borrowed from the Intel 80C186EA/80C188EA User's Manual. @@ -618,7 +684,7 @@ void i80186_cpu_device::device_start() state_add( I80186_REQST, "REQST", m_intr.request ).formatstr("%04X"); state_add( I80186_PRIMSK, "PRIMSK", m_intr.priority_mask ).formatstr("%04X"); state_add( I80186_INTSTS, "INTSTS", m_intr.status ).formatstr("%04X"); - state_add( I80186_TCUCON, "TCUCON", m_intr.timer ).formatstr("%04X"); + state_add( I80186_TCUCON, "TCUCON", m_intr.timer[0] ).formatstr("%04X"); state_add( I80186_DMA0CON, "DMA0CON", m_intr.dma[0] ).formatstr("%04X"); state_add( I80186_DMA1CON, "DMA1CON", m_intr.dma[1] ).formatstr("%04X"); state_add( I80186_I0CON, "I0CON", m_intr.ext[0] ).formatstr("%04X"); @@ -628,27 +694,15 @@ void i80186_cpu_device::device_start() state_add( I80186_POLLSTS, "POLLSTS", m_intr.poll_status ).formatstr("%04X"); // register for savestates - save_item(NAME(m_timer[0].control)); - save_item(NAME(m_timer[0].maxA)); - save_item(NAME(m_timer[0].maxB)); - save_item(NAME(m_timer[0].active_count)); - save_item(NAME(m_timer[0].count)); - save_item(NAME(m_timer[1].control)); - save_item(NAME(m_timer[1].maxA)); - save_item(NAME(m_timer[1].maxB)); - save_item(NAME(m_timer[1].active_count)); - save_item(NAME(m_timer[1].count)); - save_item(NAME(m_timer[2].control)); - save_item(NAME(m_timer[2].maxA)); - save_item(NAME(m_timer[2].count)); - save_item(NAME(m_dma[0].source)); - save_item(NAME(m_dma[0].dest)); - save_item(NAME(m_dma[0].count)); - save_item(NAME(m_dma[0].control)); - save_item(NAME(m_dma[1].source)); - save_item(NAME(m_dma[1].dest)); - save_item(NAME(m_dma[1].count)); - save_item(NAME(m_dma[1].control)); + save_item(STRUCT_MEMBER(m_timer, control)); + save_item(STRUCT_MEMBER(m_timer, maxA)); + save_item(STRUCT_MEMBER(m_timer, maxB)); + save_item(STRUCT_MEMBER(m_timer, count)); + save_item(STRUCT_MEMBER(m_dma, source)); + save_item(STRUCT_MEMBER(m_dma, dest)); + save_item(STRUCT_MEMBER(m_dma, count)); + save_item(STRUCT_MEMBER(m_dma, control)); + save_item(NAME(m_intr.vector)); save_item(NAME(m_intr.pending)); save_item(NAME(m_intr.ack_mask)); save_item(NAME(m_intr.priority_mask)); @@ -674,15 +728,13 @@ void i80186_cpu_device::device_start() memset(&m_intr, 0, sizeof(intr_state)); memset(&m_mem, 0, sizeof(mem_state)); m_reloc = 0; + m_last_dma = 0; - m_timer[0].int_timer = timer_alloc(TIMER_INT0); - m_timer[1].int_timer = timer_alloc(TIMER_INT1); - m_timer[2].int_timer = timer_alloc(TIMER_INT2); + m_timer[0].int_timer = timer_alloc(FUNC(i80186_cpu_device::timer_elapsed), this); + m_timer[1].int_timer = timer_alloc(FUNC(i80186_cpu_device::timer_elapsed), this); + m_timer[2].int_timer = timer_alloc(FUNC(i80186_cpu_device::timer_elapsed), this); - m_out_tmrout0_func.resolve_safe(); - m_out_tmrout1_func.resolve_safe(); - m_read_slave_ack_func.resolve_safe(0); - m_out_chip_select_func.resolve_safe(); + m_irmx_irq_ack.resolve_safe(0); } void i80186_cpu_device::device_reset() @@ -690,7 +742,9 @@ void i80186_cpu_device::device_reset() i8086_common_cpu_device::device_reset(); /* reset the interrupt state */ m_intr.priority_mask = 0x0007; - m_intr.timer = 0x000f; + m_intr.timer[0] = 0x000f; + m_intr.timer[1] = 0x000f; + m_intr.timer[2] = 0x000f; m_intr.dma[0] = 0x000f; m_intr.dma[1] = 0x000f; m_intr.ext[0] = 0x000f; @@ -709,55 +763,54 @@ void i80186_cpu_device::device_reset() m_reloc = 0x20ff; m_mem.upper = 0xfffb; - for (auto & elem : m_dma) + for (dma_state &elem : m_dma) { elem.drq_state = false; elem.control = 0; } - for (auto & elem : m_timer) + for (timer_state &elem : m_timer) { elem.control = 0; elem.maxA = 0; elem.maxB = 0; - elem.active_count = false; elem.count = 0; } } uint8_t i80186_cpu_device::read_port_byte(uint16_t port) { - if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + if (!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) { - if(port & 1) - return internal_port_r(*m_io, (port >> 1) & 0x7f, 0xff00) >> 8; + if (port & 1) + return internal_port_r((port >> 1) & 0x7f, 0xff00) >> 8; else - return internal_port_r(*m_io, (port >> 1) & 0x7f, 0x00ff) & 0xff; + return internal_port_r((port >> 1) & 0x7f, 0x00ff) & 0xff; } return m_io->read_byte(port); } uint16_t i80186_cpu_device::read_port_word(uint16_t port) { - if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + if (!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) { // Unaligned reads from the internal bus are swapped rather than split - if(port & 1) - return swapendian_int16(internal_port_r(*m_io, (port >> 1) & 0x7f)); + if (port & 1) + return swapendian_int16(internal_port_r((port >> 1) & 0x7f)); else - return internal_port_r(*m_io, (port >> 1) & 0x7f); + return internal_port_r((port >> 1) & 0x7f); } return m_io->read_word_unaligned(port); } void i80186_cpu_device::write_port_byte(uint16_t port, uint8_t data) { - if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + if (!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) { - if(port & 1) - internal_port_w(*m_io, (port >> 1) & 0x7f, data << 8, 0xff00); + if (port & 1) + internal_port_w((port >> 1) & 0x7f, data << 8); else - internal_port_w(*m_io, (port >> 1) & 0x7f, data, 0x00ff); + internal_port_w((port >> 1) & 0x7f, data); } else m_io->write_byte(port, data); @@ -765,13 +818,13 @@ void i80186_cpu_device::write_port_byte(uint16_t port, uint8_t data) void i80186_cpu_device::write_port_byte_al(uint16_t port) { - if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + if (!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) { // Both AH and AL are written onto the internal bus - if(port & 1) - internal_port_w(*m_io, (port >> 1) & 0x7f, swapendian_int16(m_regs.w[AX]), 0xff00); + if (port & 1) + internal_port_w((port >> 1) & 0x7f, swapendian_int16(m_regs.w[AX])); else - internal_port_w(*m_io, (port >> 1) & 0x7f, m_regs.w[AX], 0x00ff); + internal_port_w((port >> 1) & 0x7f, m_regs.w[AX]); } else m_io->write_byte(port, m_regs.w[AL]); @@ -779,13 +832,13 @@ void i80186_cpu_device::write_port_byte_al(uint16_t port) void i80186_cpu_device::write_port_word(uint16_t port, uint16_t data) { - if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + if (!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) { // Unaligned writes to the internal bus are swapped rather than split - if(port & 1) - internal_port_w(*m_io, (port >> 1) & 0x7f, swapendian_int16(data)); + if (port & 1) + internal_port_w((port >> 1) & 0x7f, swapendian_int16(data)); else - internal_port_w(*m_io, (port >> 1) & 0x7f, data); + internal_port_w((port >> 1) & 0x7f, data); } else m_io->write_word_unaligned(port, data); @@ -793,9 +846,9 @@ void i80186_cpu_device::write_port_word(uint16_t port, uint16_t data) uint8_t i80186_cpu_device::read_byte(uint32_t addr) { - if((m_reloc & 0x1000) && (addr >> 8) == (m_reloc & 0xfff)) + if ((m_reloc & 0x1000) && ((addr >> 8) & 0xfff) == (m_reloc & 0xfff)) { - uint16_t ret = internal_port_r(*m_program, (addr >> 1) & 0x7f, (addr & 1) ? 0xff00 : 0x00ff); + uint16_t ret = internal_port_r((addr >> 1) & 0x7f, (addr & 1) ? 0xff00 : 0x00ff); return (addr & 1) ? (ret >> 8) : (ret & 0xff); } return m_program->read_byte(addr); @@ -803,34 +856,34 @@ uint8_t i80186_cpu_device::read_byte(uint32_t addr) uint16_t i80186_cpu_device::read_word(uint32_t addr) { - if((m_reloc & 0x1000) && (addr >> 8) == (m_reloc & 0xfff)) + if ((m_reloc & 0x1000) && ((addr >> 8) & 0xfff) == (m_reloc & 0xfff)) { // Unaligned reads from the internal bus are swapped rather than split - if(addr & 1) - return swapendian_int16(internal_port_r(*m_program, (addr >> 1) & 0x7f)); + if (addr & 1) + return swapendian_int16(internal_port_r((addr >> 1) & 0x7f)); else - return internal_port_r(*m_program, (addr >> 1) & 0x7f); + return internal_port_r((addr >> 1) & 0x7f); } return m_program->read_word_unaligned(addr); } void i80186_cpu_device::write_byte(uint32_t addr, uint8_t data) { - if((m_reloc & 0x1000) && (addr >> 8) == (m_reloc & 0xfff)) - internal_port_w(*m_program, (addr >> 1) & 0x7f, (addr & 1) ? (data << 8) : data, (addr & 1) ? 0xff00 : 0x00ff); + if ((m_reloc & 0x1000) && ((addr >> 8) & 0xfff) == (m_reloc & 0xfff)) + internal_port_w((addr >> 1) & 0x7f, (addr & 1) ? (data << 8) : data); else m_program->write_byte(addr, data); } void i80186_cpu_device::write_word(uint32_t addr, uint16_t data) { - if((m_reloc & 0x1000) && (addr >> 8) == (m_reloc & 0xfff)) + if ((m_reloc & 0x1000) && ((addr >> 8) & 0xfff) == (m_reloc & 0xfff)) { // Unaligned writes from the internal bus are swapped rather than split - if(addr & 1) - internal_port_w(*m_program, (addr >> 1) & 0x7f, swapendian_int16(data)); + if (addr & 1) + internal_port_w((addr >> 1) & 0x7f, swapendian_int16(data)); else - internal_port_w(*m_program, (addr >> 1) & 0x7f, data); + internal_port_w((addr >> 1) & 0x7f, data); } else m_program->write_word_unaligned(addr, data); @@ -841,72 +894,91 @@ void i80186_cpu_device::write_word(uint32_t addr, uint16_t data) * 80186 interrupt controller * *************************************/ -IRQ_CALLBACK_MEMBER(i80186_cpu_device::int_callback) +IRQ_CALLBACK_MEMBER(i80186_cpu_device::inta_callback) { - uint8_t vector; - uint16_t old; - uint16_t oldreq; + // s-state 0 is irqack + m_irqa_cb(ASSERT_LINE); + m_irqa_cb(CLEAR_LINE); + if (BIT(m_reloc, 14)) + return m_irmx_irq_ack(device, irqline); + return int_callback(device, irqline); +} - if (LOG_INTERRUPTS) - logerror("(%f) **** Acknowledged interrupt vector %02X\n", machine().time().as_double(), m_intr.poll_status & 0x1f); +IRQ_CALLBACK_MEMBER(i80186_cpu_device::int_callback) +{ + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Acknowledged interrupt vector %02X\n", machine().time().as_double(), m_intr.poll_status & 0x1f); /* clear the interrupt */ set_input_line(0, CLEAR_LINE); m_intr.pending = 0; - oldreq = m_intr.request; + uint16_t oldreq = m_intr.request; /* clear the request and set the in-service bit */ - if(m_intr.ack_mask & 0xf0) + if (m_intr.ack_mask & 0xf0) { int i; - for(i = 0; i < 4; i++) - if((m_intr.ack_mask >> (i + 4)) & 1) + for (i = 0; i < 4; i++) + if (BIT(m_intr.ack_mask, i + 4)) break; - if(!(m_intr.ext[i] & EXTINT_CTRL_LTM)) + if (!(m_intr.ext[i] & EXTINT_CTRL_LTM)) m_intr.request &= ~m_intr.ack_mask; } else m_intr.request &= ~m_intr.ack_mask; - if((LOG_INTERRUPTS) && (m_intr.request!=oldreq)) - logerror("intr.request changed from %02X to %02X\n",oldreq,m_intr.request); + if (m_intr.request != oldreq) + LOGMASKED(LOG_INTERRUPTS, "intr.request changed from %02X to %02X\n", oldreq, m_intr.request); - old = m_intr.in_service; + uint16_t old = m_intr.in_service; m_intr.in_service |= m_intr.ack_mask; - if((LOG_INTERRUPTS) && (m_intr.in_service!=old)) - logerror("intr.in_service changed from %02X to %02X\n",old,m_intr.in_service); + if (m_intr.in_service != old) + LOGMASKED(LOG_INTERRUPTS, "intr.in_service changed from %02X to %02X\n",old,m_intr.in_service); - if (m_intr.ack_mask == 0x0001) + uint8_t vector; + if (!BIT(m_reloc, 14)) + { + if (m_intr.ack_mask == 0x0001) + { + switch (m_intr.poll_status & 0x1f) + { + case 0x08: m_intr.status &= ~0x01; break; + case 0x12: m_intr.status &= ~0x02; break; + case 0x13: m_intr.status &= ~0x04; break; + } + } + + /* return the vector */ + switch(m_intr.poll_status & 0x1F) + { + case 0x0C: vector = (m_intr.ext[0] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(0) : (m_intr.poll_status & 0x1f); break; + case 0x0D: vector = (m_intr.ext[1] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(1) : (m_intr.poll_status & 0x1f); break; + default: + vector = m_intr.poll_status & 0x1f; break; + } + } + else { - switch (m_intr.poll_status & 0x1f) + if (m_intr.ack_mask & 0x31) { - case 0x08: m_intr.status &= ~0x01; break; - case 0x12: m_intr.status &= ~0x02; break; - case 0x13: m_intr.status &= ~0x04; break; + if (m_intr.ack_mask & 1) + m_intr.status &= ~0x01; + else if (m_intr.ack_mask & 0x10) + m_intr.status &= ~0x02; + else if (m_intr.ack_mask & 0x20) + m_intr.status &= ~0x04; } + vector = m_intr.poll_status & 0xff; } m_intr.ack_mask = 0; /* a request no longer pending */ m_intr.poll_status &= ~0x8000; - /* return the vector */ - switch(m_intr.poll_status & 0x1F) - { - case 0x0C: vector = (m_intr.ext[0] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(0) : (m_intr.poll_status & 0x1f); break; - case 0x0D: vector = (m_intr.ext[1] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(1) : (m_intr.poll_status & 0x1f); break; - default: - vector = m_intr.poll_status & 0x1f; break; - } - - if (LOG_INTERRUPTS) - { - logerror("intr.ext[0]=%04X intr.ext[1]=%04X\n",m_intr.ext[0],m_intr.ext[1]); - logerror("Int %02X Calling vector %02X\n",m_intr.poll_status,vector); - } + LOGMASKED(LOG_INTERRUPTS, "intr.ext[0]=%04X intr.ext[1]=%04X\n", m_intr.ext[0], m_intr.ext[1]); + LOGMASKED(LOG_INTERRUPTS, "Int %02X Calling vector %02X\n", m_intr.poll_status, vector); return vector; } @@ -915,111 +987,144 @@ IRQ_CALLBACK_MEMBER(i80186_cpu_device::int_callback) void i80186_cpu_device::update_interrupt_state() { int new_vector = 0; - int Priority; - int IntNo; - if (LOG_INTERRUPTS) - logerror("update_interrupt_status: req=%04X stat=%04X serv=%04X priority_mask=%4X\n", m_intr.request, m_intr.status, m_intr.in_service, m_intr.priority_mask); + LOGMASKED(LOG_INTERRUPTS, "update_interrupt_status: req=%04X stat=%04X serv=%04X priority_mask=%4X\n", m_intr.request, m_intr.status, m_intr.in_service, m_intr.priority_mask); /* loop over priorities */ - for (Priority = 0; Priority <= m_intr.priority_mask; Priority++) + for (int priority = 0; priority <= m_intr.priority_mask; priority++) { /* note: by checking 4 bits, we also verify that the mask is off */ - if ((m_intr.timer & 0x0F) == Priority) + if (BIT(m_reloc, 14)) { - /* if we're already servicing something at this level, don't generate anything new */ - if (m_intr.in_service & 0x01) - return; + for (int int_num = 0; int_num < 3; int_num++) + { + if ((m_intr.timer[int_num] & 0x0f) == priority) + { + int irq = (1 << int_num); + /* if we're already servicing something at this level, don't generate anything new */ + if (m_intr.in_service & 0x01) + return; - /* if there's something pending, generate an interrupt */ - if (m_intr.status & 0x07) + /* if there's something pending, generate an interrupt */ + if (m_intr.status & irq) + { + new_vector = m_intr.vector | priority; + /* set the clear mask and generate the int */ + m_intr.ack_mask = int_num ? (8 << int_num) : 1; + goto generate_int; + } + } + } + } + else + { + if ((m_intr.timer[0] & 0x0f) == priority) { - if (m_intr.status & 1) - new_vector = 0x08; - else if (m_intr.status & 2) - new_vector = 0x12; - else if (m_intr.status & 4) - new_vector = 0x13; - else - logerror("Invalid timer interrupt!\n"); + /* if we're already servicing something at this level, don't generate anything new */ + if (m_intr.in_service & 0x01) + return; + + /* if there's something pending, generate an interrupt */ + if (m_intr.status & 0x07) + { + if (m_intr.status & 1) + new_vector = 0x08; + else if (m_intr.status & 2) + new_vector = 0x12; + else if (m_intr.status & 4) + new_vector = 0x13; + else + logerror("Invalid timer interrupt!\n"); - /* set the clear mask and generate the int */ - m_intr.ack_mask = 0x0001; - goto generate_int; + /* set the clear mask and generate the int */ + m_intr.ack_mask = 0x0001; + goto generate_int; + } } } /* check DMA interrupts */ - for (IntNo = 0; IntNo < 2; IntNo++) - if ((m_intr.dma[IntNo] & 0x0F) == Priority) + for (int int_num = 0; int_num < 2; int_num++) + if ((m_intr.dma[int_num] & 0x0F) == priority) { /* if we're already servicing something at this level, don't generate anything new */ - if (m_intr.in_service & (0x04 << IntNo)) + if (m_intr.in_service & (0x04 << int_num)) return; /* if there's something pending, generate an interrupt */ - if (m_intr.request & (0x04 << IntNo)) + if (m_intr.request & (0x04 << int_num)) { - new_vector = 0x0a + IntNo; + if (BIT(m_reloc, 14)) + new_vector = m_intr.vector | priority; + else + new_vector = 0x0a + int_num; /* set the clear mask and generate the int */ - m_intr.ack_mask = 0x0004 << IntNo; + m_intr.ack_mask = 0x0004 << int_num; goto generate_int; } } + if (BIT(m_reloc, 14)) + continue; + /* check external interrupts */ - for (IntNo = 0; IntNo < 4; IntNo++) + for (int int_num = 0; int_num < 4; int_num++) { - if ((m_intr.ext[IntNo] & 0x0F) == Priority) + if ((m_intr.ext[int_num] & 0x0f) == priority) { - if (LOG_INTERRUPTS) - logerror("Int%d priority=%d\n",IntNo,Priority); + LOGMASKED(LOG_INTERRUPTS, "Int%d priority=%d\n", int_num, priority); /* if we're already servicing something at this level, don't generate anything new */ - if ((m_intr.in_service & (0x10 << IntNo)) && !(m_intr.ext[IntNo] & EXTINT_CTRL_SFNM)) + if ((m_intr.in_service & (0x10 << int_num)) && !(m_intr.ext[int_num] & EXTINT_CTRL_SFNM)) return; /* if there's something pending, generate an interrupt */ - if (m_intr.request & (0x10 << IntNo)) + if (m_intr.request & (0x10 << int_num)) { - if((IntNo >= 2) && (m_intr.ext[IntNo - 2] & EXTINT_CTRL_CASCADE)) + if((int_num >= 2) && (m_intr.ext[int_num - 2] & EXTINT_CTRL_CASCADE)) { - logerror("i186: %06x: irq %d use when set for cascade mode\n", m_pc, IntNo); - m_intr.request &= ~(0x10 << IntNo); + logerror("i186: %06x: irq %d use when set for cascade mode\n", m_pc, int_num); + m_intr.request &= ~(0x10 << int_num); continue; } /* otherwise, generate an interrupt for this request */ - new_vector = 0x0c + IntNo; + new_vector = 0x0c + int_num; /* set the clear mask and generate the int */ - m_intr.ack_mask = 0x0010 << IntNo; + m_intr.ack_mask = 0x0010 << int_num; goto generate_int; } - else if ((m_intr.in_service & (0x10 << IntNo)) && (m_intr.ext[IntNo] & EXTINT_CTRL_SFNM)) + else if ((m_intr.in_service & (0x10 << int_num)) && (m_intr.ext[int_num] & EXTINT_CTRL_SFNM)) return; // if an irq is in service and sfnm is enabled, stop here } } } m_intr.pending = 0; - set_input_line(0, CLEAR_LINE); + if (!BIT(m_reloc, 14)) + set_input_line(0, CLEAR_LINE); + else + m_irmx_irq_cb(CLEAR_LINE); return; generate_int: /* generate the appropriate interrupt */ m_intr.poll_status = 0x8000 | new_vector; if (!m_intr.pending) - set_input_line(0, ASSERT_LINE); + { + if (!BIT(m_reloc, 14)) + set_input_line(0, ASSERT_LINE); + else + m_irmx_irq_cb(ASSERT_LINE); + } m_intr.pending = 1; - if (LOG_INTERRUPTS) logerror("(%f) **** Requesting interrupt vector %02X\n", machine().time().as_double(), new_vector); + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Requesting interrupt vector %02X\n", machine().time().as_double(), new_vector); } void i80186_cpu_device::handle_eoi(int data) { - int Priority; - int IntNo; - int handled=0; + bool handled = false; /* specific case */ if (!(data & 0x8000)) @@ -1038,39 +1143,57 @@ void i80186_cpu_device::handle_eoi(int data) case 0x0f: m_intr.in_service &= ~0x80; break; default: logerror("%05X:ERROR - 80186 EOI with unknown vector %02X\n", m_pc, data & 0x1f); } - if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for vector %02X\n", machine().time().as_double(), data & 0x1f); + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Got EOI for vector %02X\n", machine().time().as_double(), data & 0x1f); } - /* non-specific case */ else { /* loop over priorities */ - for (Priority = 0; ((Priority <= 7) && !handled); Priority++) + for (int priority = 0; priority <= 7 && !handled; priority++) { /* check for in-service timers */ - if ((m_intr.timer & 0x07) == Priority && (m_intr.in_service & 0x01)) + if (BIT(m_reloc, 14)) { - m_intr.in_service &= ~0x01; - if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for timer\n", machine().time().as_double()); - handled=1; + for (int int_num = 0; int_num < 2 && !handled; int_num++) + { + int mask = int_num ? (8 << int_num) : 1; + if ((m_intr.timer[int_num] & 0x07) == priority && (m_intr.in_service & mask)) + { + m_intr.in_service &= ~mask; + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Got EOI for timer%d\n", machine().time().as_double(), int_num); + handled = true; + } + } + } + else + { + if ((m_intr.timer[0] & 0x07) == priority && (m_intr.in_service & 0x01)) + { + m_intr.in_service &= ~0x01; + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Got EOI for timer\n", machine().time().as_double()); + handled = true; + } } /* check for in-service DMA interrupts */ - for (IntNo = 0; ((IntNo < 2) && !handled) ; IntNo++) - if ((m_intr.dma[IntNo] & 0x07) == Priority && (m_intr.in_service & (0x04 << IntNo))) + for (int int_num = 0; int_num < 2 && !handled; int_num++) + if ((m_intr.dma[int_num] & 0x07) == priority && (m_intr.in_service & (0x04 << int_num))) { - m_intr.in_service &= ~(0x04 << IntNo); - if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for DMA%d\n", machine().time().as_double(), IntNo); - handled=1; + m_intr.in_service &= ~(0x04 << int_num); + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Got EOI for DMA%d\n", machine().time().as_double(), int_num); + handled = true; } + if (BIT(m_reloc, 14)) + continue; + /* check external interrupts */ - for (IntNo = 0; ((IntNo < 4) && !handled) ; IntNo++) - if ((m_intr.ext[IntNo] & 0x07) == Priority && (m_intr.in_service & (0x10 << IntNo))) + for (int int_num = 0; int_num < 4 && !handled; int_num++) + if ((m_intr.ext[int_num] & 0x07) == priority && (m_intr.in_service & (0x10 << int_num))) { - m_intr.in_service &= ~(0x10 << IntNo); - if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for INT%d\n", machine().time().as_double(), IntNo); - handled=1; + m_intr.in_service &= ~(0x10 << int_num); + LOGMASKED(LOG_INTERRUPTS, "(%f) **** Got EOI for INT%d\n", machine().time().as_double(), int_num); + handled = true; } } } @@ -1078,23 +1201,34 @@ void i80186_cpu_device::handle_eoi(int data) } /* Trigger an external interrupt, optionally supplying the vector to take */ -void i80186_cpu_device::external_int(uint16_t intno, int state) +void i80186_cpu_device::external_int(uint16_t int_num, int state) { - if (!(m_intr.ext_state & (1 << intno)) == !state) + if (BIT(m_reloc, 14)) + { + if (!int_num) + { + set_input_line(0, state); + return; + } + logerror("irq to line %d in irmx mode\n", int_num); + return; + } + + if (!(m_intr.ext_state & (1 << int_num)) == !state) return; - if (LOG_INTERRUPTS_EXT) logerror("generating external int %02X\n",intno); + LOGMASKED(LOG_INTERRUPTS_EXT, "generating external int %02X\n", int_num); if (!state) { - m_intr.request &= ~(0x10 << intno); - m_intr.ack_mask &= ~(0x10 << intno); - m_intr.ext_state &= ~(1 << intno); + m_intr.request &= ~(0x10 << int_num); + m_intr.ack_mask &= ~(0x10 << int_num); + m_intr.ext_state &= ~(1 << int_num); } else // Turn on the requested request bit and handle interrupt { - m_intr.request |= (0x10 << intno); - m_intr.ext_state |= (1 << intno); + m_intr.request |= 0x10 << int_num; + m_intr.ext_state |= 1 << int_num; } update_interrupt_state(); } @@ -1105,107 +1239,92 @@ void i80186_cpu_device::external_int(uint16_t intno, int state) * *************************************/ -void i80186_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(i80186_cpu_device::timer_elapsed) { - switch(id) - { - case TIMER_INT0: - case TIMER_INT1: - case TIMER_INT2: - { - int which = param; - timer_state *t = &m_timer[which]; + int which = param; + timer_state *t = &m_timer[which]; - if (LOG_TIMER) logerror("Hit interrupt callback for timer %d\n", which); + LOGMASKED(LOG_TIMER, "Hit interrupt callback for timer %d\n", which); - /* set the max count bit */ - t->control |= 0x0020; + /* set the max count bit */ + t->control |= 0x0020; - /* request an interrupt */ - if (t->control & 0x2000) - { - m_intr.status |= 0x01 << which; - update_interrupt_state(); - if (LOG_TIMER) logerror(" Generating timer interrupt\n"); - } + /* request an interrupt */ + if (t->control & 0x2000) + { + m_intr.status |= 0x01 << which; + update_interrupt_state(); + LOGMASKED(LOG_TIMER, " Generating timer interrupt\n"); + } - if(which == 2) - { - if((m_dma[0].control & (TIMER_DRQ | ST_STOP)) == TIMER_DRQ) - drq_callback(0); - if((m_dma[1].control & (TIMER_DRQ | ST_STOP)) == TIMER_DRQ) - drq_callback(1); - if((m_timer[0].control & 0x800c) == 0x8008) - inc_timer(0); - if((m_timer[1].control & 0x800c) == 0x8008) - inc_timer(1); - } + if (which == 2) + { + if ((m_dma[0].control & (TIMER_DRQ | ST_STOP)) == (TIMER_DRQ | ST_STOP)) + drq_callback(0); + if ((m_dma[1].control & (TIMER_DRQ | ST_STOP)) == (TIMER_DRQ | ST_STOP)) + drq_callback(1); + if ((m_timer[0].control & 0x800c) == 0x8008) + inc_timer(0); + if ((m_timer[1].control & 0x800c) == 0x8008) + inc_timer(1); + } + else + { + if (!(t->control & 2)) + { + if (which) + m_out_tmrout1_func(1); else - { - if(!(t->control & 2)) - { - if(which) - m_out_tmrout1_func(1); - else - m_out_tmrout0_func(1); - } - else - { - if(which) - m_out_tmrout1_func(t->active_count); - else - m_out_tmrout0_func(t->active_count); - } - } - - /* if we're continuous or altcounting, reset */ - if((t->control & 1) || ((t->control & 2) && (which != 2) && !t->active_count)) - { - int count; - if((t->control & 2) && (which != 2)) - { - count = t->active_count ? t->maxA : t->maxB; - if(!t->active_count) - { - t->active_count = 1; - t->control |= 0x1000; - } - else - { - t->active_count = 0; - t->control &= ~0x1000; - } - } - else - count = t->maxA; - - count = count ? count : 0x10000; - if(!(t->control & 4)) - t->int_timer->adjust((attotime::from_hz(clock()/8) * count), which); - if (LOG_TIMER) logerror(" Repriming interrupt\n"); - } + m_out_tmrout0_func(1); + } + else + { + if (which) + m_out_tmrout1_func((t->control & 0x1000) ? 1 : 0); else - { - t->int_timer->adjust(attotime::never, which); - t->control &= ~0x9000; - } - t->count = 0; - break; + m_out_tmrout0_func((t->control & 0x1000) ? 1 : 0); } + } - default: - break; + /* if we're continuous or altcounting, reset */ + if ((t->control & 1) || ((t->control & 2) && !(t->control & 0x1000))) + { + if ((t->control & 2) && !(t->control & 0x1000)) + t->control |= 0x1000; + else + t->control &= ~0x1000; + + restart_timer(which); + LOGMASKED(LOG_TIMER, " Repriming interrupt\n"); + } + else + { + t->int_timer->adjust(attotime::never, which); + t->control &= ~0x9000; } + t->count = 0; } +void i80186_cpu_device::restart_timer(int which) +{ + timer_state *t = &m_timer[which]; + /* Only run timer 0,1 when not incremented via timer 2 pre-scaler */ + if (which != 2 && (t->control & 0x800c) == 0x8008) + return; + + int count = (t->control & 0x1000) ? t->maxB : t->maxA; + if (!(t->control & 4)) + t->int_timer->adjust(cycles_to_attotime(4 * (count ? count : 0x10000)), which); +} + void i80186_cpu_device::internal_timer_sync(int which) { timer_state *t = &m_timer[which]; /* if we have a timing timer running, adjust the count */ - if ((t->control & 0x8000) && !(t->control & 0x0c)) - t->count = (((which != 2) && t->active_count) ? t->maxB : t->maxA) - t->int_timer->remaining().as_ticks(clock() / 8); + if ((t->control & 0x8000) && !(t->control & 0x0c) && t->int_timer->enabled()) + t->count = ((t->control & 0x1000) ? t->maxB : t->maxA) - attotime_to_cycles(t->int_timer->remaining()) / 4; } void i80186_cpu_device::inc_timer(int which) @@ -1215,20 +1334,19 @@ void i80186_cpu_device::inc_timer(int which) t->count++; if (t->control & 2) { - if (t->count == (t->active_count ? t->maxB : t->maxA)) - device_timer(*t->int_timer, which, which, nullptr); + if (t->count == ((t->control & 0x1000) ? t->maxB : t->maxA)) + timer_elapsed(which); } else if (t->count == t->maxA) - device_timer(*t->int_timer, which, which, nullptr); + timer_elapsed(which); } void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_maxA, int new_maxB, int new_control) { timer_state *t = &m_timer[which]; - int update_int_timer = 0; + bool update_int_timer = false; - if (LOG_TIMER) - logerror("internal_timer_update: %d, new_count=%d, new_maxA=%d, new_maxB=%d,new_control=%d\n", which, new_count, new_maxA, new_maxB, new_control); + LOGMASKED(LOG_TIMER, "internal_timer_update: %d, new_count=%d, new_maxA=%d, new_maxB=%d, new_control=%d\n", which, new_count, new_maxA, new_maxB, new_control); /* if we have a new count and we're on, update things */ if (new_count != -1) @@ -1236,7 +1354,7 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ if (t->control & 0x8000) { internal_timer_sync(which); - update_int_timer = 1; + update_int_timer = true; } t->count = new_count; } @@ -1247,7 +1365,7 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ if (t->control & 0x8000) { internal_timer_sync(which); - update_int_timer = 1; + update_int_timer = true; } t->maxA = new_maxA; @@ -1264,7 +1382,7 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ if (t->control & 0x8000) { internal_timer_sync(which); - update_int_timer = 1; + update_int_timer = true; } t->maxB = new_maxB; @@ -1278,7 +1396,6 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ /* handle control changes */ if (new_control != -1) { - int diff; uint16_t resbits = (which == 2) ? 0x1fde : 0x1fc0; /* merge back in the bits we don't modify */ @@ -1289,12 +1406,8 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ new_control = (new_control & ~0x8000) | (t->control & 0x8000); new_control &= ~0x4000; - /* check for control bits we don't handle */ - diff = new_control ^ t->control; - if (diff & 0x0010) - logerror("%05X:ERROR! -unsupported timer mode %04X\n", m_pc, new_control); - /* if we have real changes, update things */ + uint16_t diff = new_control ^ t->control; if (diff != 0) { /* if we're going off, make sure our timers are gone */ @@ -1302,23 +1415,27 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ { /* compute the final count */ internal_timer_sync(which); - update_int_timer = 1; + update_int_timer = true; } /* if we're going on, start the timers running except with external clock or prescale */ else if ((diff & 0x8000) && (new_control & 0x8000) && !(new_control & 0xc)) { - update_int_timer = 1; + update_int_timer = true; } /* if something about the interrupt timer changed, force an update */ if (!(diff & 0x8000) && (diff & 0x2000)) { internal_timer_sync(which); - update_int_timer = 1; + update_int_timer = true; } } + /* RIU is cleared whenever ALT = 0 */ + if (!(new_control & 0x0002)) + new_control &= ~0x1000; + /* set the new control register */ t->control = new_control; } @@ -1326,15 +1443,13 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ /* update the interrupt timer */ if (update_int_timer) { - t->active_count = 0; - t->control &= ~0x1000; - if ((t->control & 0x8000) && !(t->control & 4)) + if ((t->control & 0x8004) == 0x8000 && (!(t->control & 0x10) || t->int_timer->enabled())) { - int diff = t->maxA - t->count; + int diff = ((t->control & 0x1000) ? t->maxB : t->maxA) - t->count; if (diff <= 0) diff += 0x10000; - t->int_timer->adjust(attotime::from_hz(clock()/8) * diff, which); - if (LOG_TIMER) logerror("Set interrupt timer for %d\n", which); + t->int_timer->adjust(cycles_to_attotime(4 * diff), which); + LOGMASKED(LOG_TIMER, "Set interrupt timer for %d\n", which); } else { @@ -1343,6 +1458,22 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ } } +void i80186_cpu_device::external_tmrin(int which, int state) +{ + // TODO: make this an actual edge trigger + if (state) + { + if ((m_timer[which].control & 0x8004) == 0x8004) + inc_timer(which); + else if ((m_timer[which].control & 0x8014) == 0x8010) + { + m_timer[which].count = 0; + restart_timer(which); + LOGMASKED(LOG_TIMER, "Retriggered timer %d\n", which); + } + } +} + /************************************* @@ -1354,19 +1485,13 @@ void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_ void i80186_cpu_device::update_dma_control(int which, int new_control) { dma_state *d = &m_dma[which]; - int diff; /* handle the CHG bit */ if (!(new_control & CHG_NOCHG)) new_control = (new_control & ~ST_STOP) | (d->control & ST_STOP); new_control &= ~CHG_NOCHG; - /* check for control bits we don't handle */ - diff = new_control ^ d->control; - if ((LOG_DMA) && (diff & 0x6811)) - logerror("%05X:ERROR! - unsupported DMA mode %04X\n", m_pc, new_control); - - if (LOG_DMA) logerror("Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest); + LOGMASKED(LOG_DMA, "Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest); /* set the new control register */ d->control = new_control; @@ -1380,13 +1505,11 @@ void i80186_cpu_device::drq_callback(int which) uint8_t dma_byte; uint8_t incdec_size; - if (LOG_DMA>1) - logerror("Control=%04X, src=%05X, dest=%05X, count=%04X\n",dma->control,dma->source,dma->dest,dma->count); + LOGMASKED(LOG_DMA_HIFREQ, "Control=%04X, src=%05X, dest=%05X, count=%04X\n", dma->control, dma->source, dma->dest, dma->count); if (!(dma->control & ST_STOP)) { - if(LOG_DMA) - logerror("%05X:ERROR! - drq%d with dma channel stopped\n", m_pc, which); + LOGMASKED(LOG_DMA, "%05X:ERROR! - drq%d with dma channel stopped\n", m_pc, which); return; } @@ -1432,103 +1555,127 @@ void i80186_cpu_device::drq_callback(int which) dma->count -= 1; // Terminate if count is zero, and terminate flag set - if (((dma->control & TERMINATE_ON_ZERO) || !(dma->control & SYNC_MASK)) && (dma->count == 0)) + if (((dma->control & TERMINATE_ON_ZERO) || !(dma->control & SYNC_MASK)) && dma->count == 0) { dma->control &= ~ST_STOP; - if (LOG_DMA) logerror("DMA terminated\n"); + LOGMASKED(LOG_DMA, "DMA terminated\n"); } // Interrupt if count is zero, and interrupt flag set - if ((dma->control & INTERRUPT_ON_ZERO) && (dma->count == 0)) + if ((dma->control & INTERRUPT_ON_ZERO) && dma->count == 0) { - if (LOG_DMA>1) logerror("DMA%d - requesting interrupt: count = %04X, source = %04X\n", which, dma->count, dma->source); + LOGMASKED(LOG_DMA_HIFREQ, "DMA%d - requesting interrupt: count = %04X, source = %04X\n", which, dma->count, dma->source); m_intr.request |= 0x04 << which; update_interrupt_state(); } } -READ16_MEMBER(i80186_cpu_device::internal_port_r) +uint16_t i80186_cpu_device::internal_port_r(offs_t offset, uint16_t mem_mask) { int temp, which; switch (offset) { + case 0x10: + LOGMASKED(LOG_PORTS, "%05X:read interrupt vector\n", m_pc); + return m_intr.vector; + case 0x11: - if (LOG_PORTS) logerror("%05X:ERROR - read from 80186 EOI\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:ERROR - read from 80186 EOI\n", m_pc); break; case 0x12: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt poll\n", m_pc); if (m_intr.poll_status & 0x8000) - int_callback(*this, 0); + inta_callback(*this, 0); return m_intr.poll_status; case 0x13: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll status\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt poll status\n", m_pc); return m_intr.poll_status; case 0x14: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt mask\n", m_pc); - temp = (m_intr.timer >> 3) & 0x01; + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt mask\n", m_pc); + temp = (m_intr.timer[0] >> 3) & 0x01; temp |= (m_intr.dma[0] >> 1) & 0x04; temp |= (m_intr.dma[1] >> 0) & 0x08; - temp |= (m_intr.ext[0] << 1) & 0x10; - temp |= (m_intr.ext[1] << 2) & 0x20; - temp |= (m_intr.ext[2] << 3) & 0x40; - temp |= (m_intr.ext[3] << 4) & 0x80; + if (BIT(m_reloc, 14)) + { + temp |= (m_intr.timer[1] << 1) & 0x10; + temp |= (m_intr.timer[2] << 2) & 0x20; + } + else + { + temp |= (m_intr.ext[0] << 1) & 0x10; + temp |= (m_intr.ext[1] << 2) & 0x20; + temp |= (m_intr.ext[2] << 3) & 0x40; + temp |= (m_intr.ext[3] << 4) & 0x80; + } return temp; case 0x15: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt priority mask\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt priority mask\n", m_pc); return m_intr.priority_mask; case 0x16: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt in-service\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt in-service\n", m_pc); return m_intr.in_service; case 0x17: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt request\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt request\n", m_pc); temp = m_intr.request & ~0x0001; if (m_intr.status & 0x0007) temp |= 1; return temp; case 0x18: - if (LOG_PORTS) logerror("%05X:read 80186 interrupt status\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 interrupt status\n", m_pc); return m_intr.status; case 0x19: - if (LOG_PORTS) logerror("%05X:read 80186 timer interrupt control\n", m_pc); - return m_intr.timer; + LOGMASKED(LOG_PORTS, "%05X:read 80186 timer interrupt control\n", m_pc); + return m_intr.timer[0]; case 0x1a: - if (LOG_PORTS) logerror("%05X:read 80186 DMA 0 interrupt control\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA 0 interrupt control\n", m_pc); return m_intr.dma[0]; case 0x1b: - if (LOG_PORTS) logerror("%05X:read 80186 DMA 1 interrupt control\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA 1 interrupt control\n", m_pc); return m_intr.dma[1]; case 0x1c: - if (LOG_PORTS) logerror("%05X:read 80186 INT 0 interrupt control\n", m_pc); - return m_intr.ext[0]; + LOGMASKED(LOG_PORTS, "%05X:read 80186 INT 0 interrupt control\n", m_pc); + if (BIT(m_reloc, 14)) + return m_intr.timer[1]; + else + return m_intr.ext[0]; case 0x1d: - if (LOG_PORTS) logerror("%05X:read 80186 INT 1 interrupt control\n", m_pc); - return m_intr.ext[1]; + LOGMASKED(LOG_PORTS, "%05X:read 80186 INT 1 interrupt control\n", m_pc); + if (BIT(m_reloc, 14)) + return m_intr.timer[2]; + else + return m_intr.ext[1]; case 0x1e: - if (LOG_PORTS) logerror("%05X:read 80186 INT 2 interrupt control\n", m_pc); - return m_intr.ext[2]; + LOGMASKED(LOG_PORTS, "%05X:read 80186 INT 2 interrupt control\n", m_pc); + if (BIT(m_reloc, 14)) + return 0; + else + return m_intr.ext[2]; case 0x1f: - if (LOG_PORTS) logerror("%05X:read 80186 INT 3 interrupt control\n", m_pc); - return m_intr.ext[3]; + LOGMASKED(LOG_PORTS, "%05X:read 80186 INT 3 interrupt control\n", m_pc); + if (BIT(m_reloc, 14)) + return 0; + else + return m_intr.ext[3]; case 0x28: case 0x2c: case 0x30: - if (LOG_PORTS) logerror("%05X:read 80186 Timer %d count\n", m_pc, (offset - 0x28) / 4); + LOGMASKED(LOG_PORTS, "%05X:read 80186 Timer %d count\n", m_pc, (offset - 0x28) / 4); which = (offset - 0x28) / 4; if (ACCESSING_BITS_0_7) internal_timer_sync(which); @@ -1537,76 +1684,76 @@ READ16_MEMBER(i80186_cpu_device::internal_port_r) case 0x29: case 0x2d: case 0x31: - if (LOG_PORTS) logerror("%05X:read 80186 Timer %d max A\n", m_pc, (offset - 0x29) / 4); + LOGMASKED(LOG_PORTS, "%05X:read 80186 Timer %d max A\n", m_pc, (offset - 0x29) / 4); which = (offset - 0x29) / 4; return m_timer[which].maxA; case 0x2a: case 0x2e: - if (LOG_PORTS) logerror("%05X:read 80186 Timer %d max B\n", m_pc, (offset - 0x2a) / 4); + LOGMASKED(LOG_PORTS, "%05X:read 80186 Timer %d max B\n", m_pc, (offset - 0x2a) / 4); which = (offset - 0x2a) / 4; return m_timer[which].maxB; case 0x2b: case 0x2f: case 0x33: - if (LOG_PORTS) logerror("%05X:read 80186 Timer %d control\n", m_pc, (offset - 0x2b) / 4); + LOGMASKED(LOG_PORTS, "%05X:read 80186 Timer %d control\n", m_pc, (offset - 0x2b) / 4); which = (offset - 0x2b) / 4; return m_timer[which].control; case 0x50: - if (LOG_PORTS) logerror("%05X:read 80186 upper chip select\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 upper chip select\n", m_pc); return m_mem.upper; case 0x51: - if (LOG_PORTS) logerror("%05X:read 80186 lower chip select\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 lower chip select\n", m_pc); return m_mem.lower; case 0x52: - if (LOG_PORTS) logerror("%05X:read 80186 peripheral chip select\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 peripheral chip select\n", m_pc); return m_mem.peripheral; case 0x53: - if (LOG_PORTS) logerror("%05X:read 80186 middle chip select\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 middle chip select\n", m_pc); return m_mem.middle; case 0x54: - if (LOG_PORTS) logerror("%05X:read 80186 middle P chip select\n", m_pc); + LOGMASKED(LOG_PORTS, "%05X:read 80186 middle P chip select\n", m_pc); return m_mem.middle_size; case 0x60: case 0x68: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower source address\n", m_pc, (offset - 0x60) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d lower source address\n", m_pc, (offset - 0x60) / 8); which = (offset - 0x60) / 8; return m_dma[which].source; case 0x61: case 0x69: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper source address\n", m_pc, (offset - 0x61) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d upper source address\n", m_pc, (offset - 0x61) / 8); which = (offset - 0x61) / 8; return m_dma[which].source >> 16; case 0x62: case 0x6a: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower dest address\n", m_pc, (offset - 0x62) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d lower dest address\n", m_pc, (offset - 0x62) / 8); which = (offset - 0x62) / 8; return m_dma[which].dest; case 0x63: case 0x6b: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper dest address\n", m_pc, (offset - 0x63) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d upper dest address\n", m_pc, (offset - 0x63) / 8); which = (offset - 0x63) / 8; return m_dma[which].dest >> 16; case 0x64: case 0x6c: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d transfer count\n", m_pc, (offset - 0x64) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d transfer count\n", m_pc, (offset - 0x64) / 8); which = (offset - 0x64) / 8; return m_dma[which].count; case 0x65: case 0x6d: - if (LOG_PORTS) logerror("%05X:read 80186 DMA%d control\n", m_pc, (offset - 0x65) / 8); + LOGMASKED(LOG_PORTS, "%05X:read 80186 DMA%d control\n", m_pc, (offset - 0x65) / 8); which = (offset - 0x65) / 8; return m_dma[which].control; @@ -1614,7 +1761,7 @@ READ16_MEMBER(i80186_cpu_device::internal_port_r) return m_reloc; default: - if (LOG_PORTS) logerror("%05X:read 80186 port %02X\n", m_pc, offset); + LOGMASKED(LOG_PORTS, "%05X:read 80186 port %02X\n", m_pc, offset); break; } @@ -1627,108 +1774,129 @@ READ16_MEMBER(i80186_cpu_device::internal_port_r) * *************************************/ -WRITE16_MEMBER(i80186_cpu_device::internal_port_w) +void i80186_cpu_device::internal_port_w(offs_t offset, uint16_t data) { int which; switch (offset) { + case 0x10: + LOGMASKED(LOG_PORTS, "%05X:write interrupt vector = %04X\n", m_pc, data); + m_intr.vector = data & 0xf8; + break; + case 0x11: - if (LOG_PORTS) logerror("%05X:80186 EOI = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 EOI = %04X\n", m_pc, data); handle_eoi(data); update_interrupt_state(); break; case 0x12: - if (LOG_PORTS) logerror("%05X:ERROR - write to 80186 interrupt poll = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:ERROR - write to 80186 interrupt poll = %04X\n", m_pc, data); break; case 0x13: - if (LOG_PORTS) logerror("%05X:ERROR - write to 80186 interrupt poll status = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:ERROR - write to 80186 interrupt poll status = %04X\n", m_pc, data); break; case 0x14: - if (LOG_PORTS) logerror("%05X:80186 interrupt mask = %04X\n", m_pc, data); - m_intr.timer = (m_intr.timer & ~0x08) | ((data << 3) & 0x08); + LOGMASKED(LOG_PORTS, "%05X:80186 interrupt mask = %04X\n", m_pc, data); + m_intr.timer[0] = (m_intr.timer[0] & ~0x08) | ((data << 3) & 0x08); m_intr.dma[0] = (m_intr.dma[0] & ~0x08) | ((data << 1) & 0x08); m_intr.dma[1] = (m_intr.dma[1] & ~0x08) | ((data << 0) & 0x08); - m_intr.ext[0] = (m_intr.ext[0] & ~0x08) | ((data >> 1) & 0x08); - m_intr.ext[1] = (m_intr.ext[1] & ~0x08) | ((data >> 2) & 0x08); - m_intr.ext[2] = (m_intr.ext[2] & ~0x08) | ((data >> 3) & 0x08); - m_intr.ext[3] = (m_intr.ext[3] & ~0x08) | ((data >> 4) & 0x08); + if (BIT(m_reloc, 14)) + { + m_intr.timer[1] = (m_intr.timer[1] & ~0x08) | ((data >> 1) & 0x08); + m_intr.timer[2] = (m_intr.timer[2] & ~0x08) | ((data >> 2) & 0x08); + } + else + { + m_intr.ext[0] = (m_intr.ext[0] & ~0x08) | ((data >> 1) & 0x08); + m_intr.ext[1] = (m_intr.ext[1] & ~0x08) | ((data >> 2) & 0x08); + m_intr.ext[2] = (m_intr.ext[2] & ~0x08) | ((data >> 3) & 0x08); + m_intr.ext[3] = (m_intr.ext[3] & ~0x08) | ((data >> 4) & 0x08); + } update_interrupt_state(); break; case 0x15: - if (LOG_PORTS) logerror("%05X:80186 interrupt priority mask = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 interrupt priority mask = %04X\n", m_pc, data); m_intr.priority_mask = data & 0x0007; update_interrupt_state(); break; case 0x16: - if (LOG_PORTS) logerror("%05X:80186 interrupt in-service = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 interrupt in-service = %04X\n", m_pc, data); m_intr.in_service = data & 0x00ff; update_interrupt_state(); break; case 0x17: - if (LOG_PORTS) logerror("%05X:80186 interrupt request = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 interrupt request = %04X\n", m_pc, data); m_intr.request = (m_intr.request & ~0x000c) | (data & 0x000c); update_interrupt_state(); break; case 0x18: - if (LOG_PORTS) logerror("%05X:WARNING - wrote to 80186 interrupt status = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:WARNING - wrote to 80186 interrupt status = %04X\n", m_pc, data); m_intr.status = (m_intr.status & ~0x8007) | (data & 0x8007); update_interrupt_state(); break; case 0x19: - if (LOG_PORTS) logerror("%05X:80186 timer interrupt contol = %04X\n", m_pc, data); - m_intr.timer = data & 0x000f; + LOGMASKED(LOG_PORTS, "%05X:80186 timer interrupt contol = %04X\n", m_pc, data); + m_intr.timer[0] = data & 0x000f; update_interrupt_state(); break; case 0x1a: - if (LOG_PORTS) logerror("%05X:80186 DMA 0 interrupt control = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA 0 interrupt control = %04X\n", m_pc, data); m_intr.dma[0] = data & 0x000f; update_interrupt_state(); break; case 0x1b: - if (LOG_PORTS) logerror("%05X:80186 DMA 1 interrupt control = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA 1 interrupt control = %04X\n", m_pc, data); m_intr.dma[1] = data & 0x000f; update_interrupt_state(); break; case 0x1c: - if (LOG_PORTS) logerror("%05X:80186 INT 0 interrupt control = %04X\n", m_pc, data); - m_intr.ext[0] = data & 0x007f; + LOGMASKED(LOG_PORTS, "%05X:80186 INT 0 interrupt control = %04X\n", m_pc, data); + if (BIT(m_reloc, 14)) + m_intr.timer[1] = data & 0x000f; + else + m_intr.ext[0] = data & 0x007f; update_interrupt_state(); break; case 0x1d: - if (LOG_PORTS) logerror("%05X:80186 INT 1 interrupt control = %04X\n", m_pc, data); - m_intr.ext[1] = data & 0x007f; + LOGMASKED(LOG_PORTS, "%05X:80186 INT 1 interrupt control = %04X\n", m_pc, data); + if (BIT(m_reloc, 14)) + m_intr.timer[2] = data & 0x000f; + else + m_intr.ext[1] = data & 0x007f; update_interrupt_state(); break; case 0x1e: - if (LOG_PORTS) logerror("%05X:80186 INT 2 interrupt control = %04X\n", m_pc, data); - m_intr.ext[2] = data & 0x001f; + LOGMASKED(LOG_PORTS, "%05X:80186 INT 2 interrupt control = %04X\n", m_pc, data); + if (!BIT(m_reloc, 14)) + m_intr.ext[2] = data & 0x001f; update_interrupt_state(); break; case 0x1f: - if (LOG_PORTS) logerror("%05X:80186 INT 3 interrupt control = %04X\n", m_pc, data); - m_intr.ext[3] = data & 0x001f; + LOGMASKED(LOG_PORTS, "%05X:80186 INT 3 interrupt control = %04X\n", m_pc, data); + if (!BIT(m_reloc, 14)) + m_intr.ext[3] = data & 0x001f; update_interrupt_state(); break; case 0x28: case 0x2c: case 0x30: - if (LOG_PORTS) logerror("%05X:80186 Timer %d count = %04X\n", m_pc, (offset - 0x28) / 4, data); + LOGMASKED(LOG_PORTS, "%05X:80186 Timer %d count = %04X\n", m_pc, (offset - 0x28) / 4, data); which = (offset - 0x28) / 4; internal_timer_update(which, data, -1, -1, -1); break; @@ -1736,14 +1904,14 @@ WRITE16_MEMBER(i80186_cpu_device::internal_port_w) case 0x29: case 0x2d: case 0x31: - if (LOG_PORTS) logerror("%05X:80186 Timer %d max A = %04X\n", m_pc, (offset - 0x29) / 4, data); + LOGMASKED(LOG_PORTS, "%05X:80186 Timer %d max A = %04X\n", m_pc, (offset - 0x29) / 4, data); which = (offset - 0x29) / 4; internal_timer_update(which, -1, data, -1, -1); break; case 0x2a: case 0x2e: - if (LOG_PORTS) logerror("%05X:80186 Timer %d max B = %04X\n", m_pc, (offset - 0x2a) / 4, data); + LOGMASKED(LOG_PORTS, "%05X:80186 Timer %d max B = %04X\n", m_pc, (offset - 0x2a) / 4, data); which = (offset - 0x2a) / 4; internal_timer_update(which, -1, -1, data, -1); break; @@ -1751,79 +1919,79 @@ WRITE16_MEMBER(i80186_cpu_device::internal_port_w) case 0x2b: case 0x2f: case 0x33: - if (LOG_PORTS) logerror("%05X:80186 Timer %d control = %04X\n", m_pc, (offset - 0x2b) / 4, data); + LOGMASKED(LOG_PORTS, "%05X:80186 Timer %d control = %04X\n", m_pc, (offset - 0x2b) / 4, data); which = (offset - 0x2b) / 4; internal_timer_update(which, -1, -1, -1, data); break; case 0x50: - if (LOG_PORTS) logerror("%05X:80186 upper chip select = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 upper chip select = %04X\n", m_pc, data); m_mem.upper = data | 0xc038; m_out_chip_select_func(0, m_mem.upper, 0xffff); break; case 0x51: - if (LOG_PORTS) logerror("%05X:80186 lower chip select = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 lower chip select = %04X\n", m_pc, data); m_mem.lower = (data & 0x3fff) | 0x0038; m_out_chip_select_func(1, m_mem.lower, 0xffff); break; case 0x52: - if (LOG_PORTS) logerror("%05X:80186 peripheral chip select = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 peripheral chip select = %04X\n", m_pc, data); m_mem.peripheral = data | 0x0038; m_out_chip_select_func(2, m_mem.peripheral, 0xffff); break; case 0x53: - if (LOG_PORTS) logerror("%05X:80186 middle chip select = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 middle chip select = %04X\n", m_pc, data); m_mem.middle = data | 0x01f8; m_out_chip_select_func(3, m_mem.middle, 0xffff); break; case 0x54: - if (LOG_PORTS) logerror("%05X:80186 middle P chip select = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 middle P chip select = %04X\n", m_pc, data); m_mem.middle_size = data | 0x8038; m_out_chip_select_func(4, m_mem.middle_size, 0xffff); break; case 0x60: case 0x68: - if (LOG_PORTS) logerror("%05X:80186 DMA%d lower source address = %04X\n", m_pc, (offset - 0x60) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d lower source address = %04X\n", m_pc, (offset - 0x60) / 8, data); which = (offset - 0x60) / 8; m_dma[which].source = (m_dma[which].source & ~0x0ffff) | (data & 0x0ffff); break; case 0x61: case 0x69: - if (LOG_PORTS) logerror("%05X:80186 DMA%d upper source address = %04X\n", m_pc, (offset - 0x61) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d upper source address = %04X\n", m_pc, (offset - 0x61) / 8, data); which = (offset - 0x61) / 8; m_dma[which].source = (m_dma[which].source & ~0xf0000) | ((data << 16) & 0xf0000); break; case 0x62: case 0x6a: - if (LOG_PORTS) logerror("%05X:80186 DMA%d lower dest address = %04X\n", m_pc, (offset - 0x62) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d lower dest address = %04X\n", m_pc, (offset - 0x62) / 8, data); which = (offset - 0x62) / 8; m_dma[which].dest = (m_dma[which].dest & ~0x0ffff) | (data & 0x0ffff); break; case 0x63: case 0x6b: - if (LOG_PORTS) logerror("%05X:80186 DMA%d upper dest address = %04X\n", m_pc, (offset - 0x63) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d upper dest address = %04X\n", m_pc, (offset - 0x63) / 8, data); which = (offset - 0x63) / 8; m_dma[which].dest = (m_dma[which].dest & ~0xf0000) | ((data << 16) & 0xf0000); break; case 0x64: case 0x6c: - if (LOG_PORTS) logerror("%05X:80186 DMA%d transfer count = %04X\n", m_pc, (offset - 0x64) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d transfer count = %04X\n", m_pc, (offset - 0x64) / 8, data); which = (offset - 0x64) / 8; m_dma[which].count = data; break; case 0x65: case 0x6d: - if (LOG_PORTS) logerror("%05X:80186 DMA%d control = %04X\n", m_pc, (offset - 0x65) / 8, data); + LOGMASKED(LOG_PORTS, "%05X:80186 DMA%d control = %04X\n", m_pc, (offset - 0x65) / 8, data); which = (offset - 0x65) / 8; update_dma_control(which, data); if((m_dma[which].control & (SYNC_MASK | ST_STOP | TIMER_DRQ)) == ST_STOP) @@ -1836,12 +2004,12 @@ WRITE16_MEMBER(i80186_cpu_device::internal_port_w) case 0x7f: // 80188 byte output to this port is *not* masked! - if (LOG_PORTS) logerror("%05X:80186 relocation register = %04X\n", m_pc, data); + LOGMASKED(LOG_PORTS, "%05X:80186 relocation register = %04X\n", m_pc, data); m_reloc = data; break; default: - if (LOG_PORTS) logerror("%05X:80186 port %02X = %04X\n", m_pc, offset, data); + LOGMASKED(LOG_PORTS, "%05X:80186 port %02X = %04X\n", m_pc, offset, data); break; } } |