diff options
Diffstat (limited to 'src/mess/machine/at.c')
-rw-r--r-- | src/mess/machine/at.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/mess/machine/at.c b/src/mess/machine/at.c new file mode 100644 index 00000000000..1bccf1394ce --- /dev/null +++ b/src/mess/machine/at.c @@ -0,0 +1,347 @@ +/*************************************************************************** + + IBM AT Compatibles + +***************************************************************************/ + +#include "includes/at.h" + +#define LOG_PORT80 0 + +/************************************************************* + * + * pic8259 configuration + * + *************************************************************/ +READ8_MEMBER( at_state::get_slave_ack ) +{ + if (offset==2) // IRQ = 2 + return pic8259_acknowledge(m_pic8259_slave); + + return 0x00; +} + +const struct pic8259_interface at_pic8259_master_config = +{ + DEVCB_CPU_INPUT_LINE("maincpu", 0), + DEVCB_LINE_VCC, + DEVCB_DRIVER_MEMBER(at_state, get_slave_ack) +}; + +const struct pic8259_interface at_pic8259_slave_config = +{ + DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir2_w), + DEVCB_LINE_GND, + DEVCB_NULL +}; + + + +/************************************************************************* + * + * PC Speaker related + * + *************************************************************************/ + +void at_state::at_speaker_set_spkrdata(UINT8 data) +{ + m_at_spkrdata = data ? 1 : 0; + speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input); +} + +void at_state::at_speaker_set_input(UINT8 data) +{ + m_at_speaker_input = data ? 1 : 0; + speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input); +} + + + +/************************************************************* + * + * pit8254 configuration + * + *************************************************************/ + +WRITE_LINE_MEMBER( at_state::at_pit8254_out0_changed ) +{ + if (m_pic8259_master) + pic8259_ir0_w(m_pic8259_master, state); +} + + +WRITE_LINE_MEMBER( at_state::at_pit8254_out2_changed ) +{ + at_speaker_set_input( state ); +} + + +const struct pit8253_config at_pit8254_config = +{ + { + { + 4772720/4, /* heartbeat IRQ */ + DEVCB_NULL, + DEVCB_DRIVER_LINE_MEMBER(at_state, at_pit8254_out0_changed) + }, { + 4772720/4, /* dram refresh */ + DEVCB_NULL, + DEVCB_NULL + }, { + 4772720/4, /* pio port c pin 4, and speaker polling enough */ + DEVCB_NULL, + DEVCB_DRIVER_LINE_MEMBER(at_state, at_pit8254_out2_changed) + } + } +}; + + +/************************************************************************* + * + * PC DMA stuff + * + *************************************************************************/ + +READ8_MEMBER( at_state::at_page8_r ) +{ + UINT8 data = m_at_pages[offset % 0x10]; + + switch(offset % 8) + { + case 1: + data = m_dma_offset[BIT(offset, 3)][2]; + break; + case 2: + data = m_dma_offset[BIT(offset, 3)][3]; + break; + case 3: + data = m_dma_offset[BIT(offset, 3)][1]; + break; + case 7: + data = m_dma_offset[BIT(offset, 3)][0]; + break; + } + return data; +} + + +WRITE8_MEMBER( at_state::at_page8_w ) +{ + m_at_pages[offset % 0x10] = data; + + if (LOG_PORT80 && (offset == 0)) + { + logerror(" at_page8_w(): Port 80h <== 0x%02x (PC=0x%08x)\n", data, + (unsigned) cpu_get_reg(m_maincpu, STATE_GENPC)); + } + + switch(offset % 8) + { + case 1: + m_dma_offset[BIT(offset, 3)][2] = data; + break; + case 2: + m_dma_offset[BIT(offset, 3)][3] = data; + break; + case 3: + m_dma_offset[BIT(offset, 3)][1] = data; + break; + case 7: + m_dma_offset[BIT(offset, 3)][0] = data; + break; + } +} + + +WRITE_LINE_MEMBER( at_state::pc_dma_hrq_changed ) +{ + device_set_input_line(m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); + + /* Assert HLDA */ + m_dma8237_2->hack_w(state); +} + +READ8_MEMBER(at_state::pc_dma_read_byte) +{ + UINT8 result; + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000; + + result = space.read_byte(page_offset + offset); + return result; +} + + +WRITE8_MEMBER(at_state::pc_dma_write_byte) +{ + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000; + + space.write_byte(page_offset + offset, data); +} + + +READ8_MEMBER(at_state::pc_dma_read_word) +{ + UINT16 result; + offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000; + + result = space.read_word(page_offset + ( offset << 1 ) ); + m_dma_high_byte = result & 0xFF00; + + return result & 0xFF; +} + + +WRITE8_MEMBER(at_state::pc_dma_write_word) +{ + offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000; + + space.write_word(page_offset + ( offset << 1 ), m_dma_high_byte | data); +} + + +READ8_MEMBER( at_state::pc_dma8237_0_dack_r ) { return m_isabus->dack_r(0); } +READ8_MEMBER( at_state::pc_dma8237_1_dack_r ) { return m_isabus->dack_r(1); } +READ8_MEMBER( at_state::pc_dma8237_2_dack_r ) { return m_isabus->dack_r(2); } +READ8_MEMBER( at_state::pc_dma8237_3_dack_r ) { return m_isabus->dack_r(3); } +READ8_MEMBER( at_state::pc_dma8237_5_dack_r ) { return m_isabus->dack_r(5); } +READ8_MEMBER( at_state::pc_dma8237_6_dack_r ) { return m_isabus->dack_r(6); } +READ8_MEMBER( at_state::pc_dma8237_7_dack_r ) { return m_isabus->dack_r(7); } + + +WRITE8_MEMBER( at_state::pc_dma8237_0_dack_w ){ m_isabus->dack_w(0, data); } +WRITE8_MEMBER( at_state::pc_dma8237_1_dack_w ){ m_isabus->dack_w(1, data); } +WRITE8_MEMBER( at_state::pc_dma8237_2_dack_w ){ m_isabus->dack_w(2, data); } +WRITE8_MEMBER( at_state::pc_dma8237_3_dack_w ){ m_isabus->dack_w(3, data); } +WRITE8_MEMBER( at_state::pc_dma8237_5_dack_w ){ m_isabus->dack_w(5, data); } +WRITE8_MEMBER( at_state::pc_dma8237_6_dack_w ){ m_isabus->dack_w(6, data); } +WRITE8_MEMBER( at_state::pc_dma8237_7_dack_w ){ m_isabus->dack_w(7, data); } + +WRITE_LINE_MEMBER( at_state::at_dma8237_out_eop ) { m_isabus->eop_w(state == ASSERT_LINE ? 0 : 1 ); } + +static void set_dma_channel(device_t *device, int channel, int state) +{ + at_state *st = device->machine().driver_data<at_state>(); + if (!state) + st->m_dma_channel = channel; +} + +WRITE_LINE_MEMBER( at_state::pc_dack0_w ) { set_dma_channel(m_dma8237_1, 0, state); } +WRITE_LINE_MEMBER( at_state::pc_dack1_w ) { set_dma_channel(m_dma8237_1, 1, state); } +WRITE_LINE_MEMBER( at_state::pc_dack2_w ) { set_dma_channel(m_dma8237_1, 2, state); } +WRITE_LINE_MEMBER( at_state::pc_dack3_w ) { set_dma_channel(m_dma8237_1, 3, state); } +WRITE_LINE_MEMBER( at_state::pc_dack4_w ) { m_dma8237_1->hack_w(state ? 0 : 1); } // it's inverted +WRITE_LINE_MEMBER( at_state::pc_dack5_w ) { set_dma_channel(m_dma8237_2, 5, state); } +WRITE_LINE_MEMBER( at_state::pc_dack6_w ) { set_dma_channel(m_dma8237_2, 6, state); } +WRITE_LINE_MEMBER( at_state::pc_dack7_w ) { set_dma_channel(m_dma8237_2, 7, state); } + +I8237_INTERFACE( at_dma8237_1_config ) +{ + DEVCB_DEVICE_LINE_MEMBER("dma8237_2", am9517a_device, dreq0_w), + DEVCB_DRIVER_LINE_MEMBER(at_state, at_dma8237_out_eop), + DEVCB_DRIVER_MEMBER(at_state, pc_dma_read_byte), + DEVCB_DRIVER_MEMBER(at_state, pc_dma_write_byte), + { DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_0_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_1_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_2_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_3_dack_r) }, + { DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_0_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_1_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_2_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_3_dack_w) }, + { DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack0_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack1_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack2_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack3_w) } +}; + + +I8237_INTERFACE( at_dma8237_2_config ) +{ + DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dma_hrq_changed), + DEVCB_NULL, + DEVCB_DRIVER_MEMBER(at_state, pc_dma_read_word), + DEVCB_DRIVER_MEMBER(at_state, pc_dma_write_word), + { DEVCB_NULL, DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_5_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_6_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_7_dack_r) }, + { DEVCB_NULL, DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_5_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_6_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_7_dack_w) }, + { DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack4_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack5_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack6_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack7_w) } +}; + +READ8_MEMBER( at_state::at_portb_r ) +{ + UINT8 data = m_at_speaker; + data &= ~0xc0; /* AT BIOS don't likes this being set */ + + /* This needs fixing/updating not sure what this is meant to fix */ + if ( --m_poll_delay < 0 ) + { + m_poll_delay = 3; + m_at_offset1 ^= 0x10; + } + data = (data & ~0x10) | ( m_at_offset1 & 0x10 ); + + if ( pit8253_get_output(m_pit8254, 2 ) ) + data |= 0x20; + else + data &= ~0x20; /* ps2m30 wants this */ + + return data; +} + +WRITE8_MEMBER( at_state::at_portb_w ) +{ + m_at_speaker = data; + pit8253_gate2_w(m_pit8254, BIT(data, 0)); + at_speaker_set_spkrdata( BIT(data, 1)); + m_channel_check = BIT(data, 3); + m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0)); +} + + +/********************************************************** + * + * Init functions + * + **********************************************************/ + +static void init_at_common(running_machine &machine) +{ + at_state *state = machine.driver_data<at_state>(); + address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM); + + // The CS4031 chipset does this itself + if (machine.device("cs4031") == NULL) + { + /* MESS managed RAM */ + state->membank("bank10")->set_base(machine.device<ram_device>(RAM_TAG)->pointer()); + + if (machine.device<ram_device>(RAM_TAG)->size() > 0x0a0000) + { + offs_t ram_limit = 0x100000 + machine.device<ram_device>(RAM_TAG)->size() - 0x0a0000; + space->install_read_bank(0x100000, ram_limit - 1, "bank1"); + space->install_write_bank(0x100000, ram_limit - 1, "bank1"); + state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xa0000); + } + } + + state->m_at_offset1 = 0xff; +} + +DRIVER_INIT_MEMBER(at_state,atcga) +{ + init_at_common(machine()); +} + +DRIVER_INIT_MEMBER(at_state,atvga) +{ + init_at_common(machine()); +} + +static IRQ_CALLBACK(at_irq_callback) +{ + at_state *st = device->machine().driver_data<at_state>(); + return pic8259_acknowledge(st->m_pic8259_master); +} + +MACHINE_START( at ) +{ + device_set_irq_callback(machine.device("maincpu"), at_irq_callback); +} + +MACHINE_RESET( at ) +{ + at_state *st = machine.driver_data<at_state>(); + st->m_poll_delay = 4; + st->m_at_spkrdata = 0; + st->m_at_speaker_input = 0; +} |