diff options
Diffstat (limited to 'src/mess/machine/pc.c')
-rw-r--r-- | src/mess/machine/pc.c | 1787 |
1 files changed, 1787 insertions, 0 deletions
diff --git a/src/mess/machine/pc.c b/src/mess/machine/pc.c new file mode 100644 index 00000000000..fc31cbaa70b --- /dev/null +++ b/src/mess/machine/pc.c @@ -0,0 +1,1787 @@ +/*************************************************************************** + + machine/pc.c + + Functions to emulate general aspects of the machine + (RAM, ROM, interrupts, I/O ports) + + The information herein is heavily based on + 'Ralph Browns Interrupt List' + Release 52, Last Change 20oct96 + +***************************************************************************/ + +#include "emu.h" +#include "includes/pc.h" + +#include "machine/i8255.h" +#include "machine/ins8250.h" +#include "machine/mc146818.h" +#include "machine/pic8259.h" +#include "machine/pc_turbo.h" + +#include "video/pc_vga.h" +#include "video/pc_cga.h" +#include "video/pc_t1t.h" + +#include "machine/pit8253.h" + +#include "machine/pckeybrd.h" +#include "machine/pc_lpt.h" +#include "machine/pc_fdc.h" +#include "machine/upd765.h" +#include "includes/amstr_pc.h" +#include "includes/europc.h" +#include "machine/pcshare.h" +#include "imagedev/cassette.h" +#include "sound/speaker.h" + +#include "machine/8237dma.h" +#include "machine/wd17xx.h" + +#include "machine/ram.h" + +#include "imagedev/cassette.h" +#include "machine/pit8253.h" +#include "machine/pcshare.h" +#include "coreutil.h" + +#define VERBOSE_PIO 0 /* PIO (keyboard controller) */ + +#define PIO_LOG(N,M,A) \ + do { \ + if(VERBOSE_PIO>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +#define VERBOSE_DBG 0 /* general debug messages */ + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +/* + * EC-1841 memory controller. The machine can hold four memory boards; + * each board has a control register, its address is set by a DIP switch + * on the board itself. + * + * Only one board should be enabled for read, and one for write. + * Normally, this is the same board. + * + * Each board is divided into 4 banks, internally numbererd 0..3. + * POST tests each board on startup, and an error (indicated by + * I/O CH CK bus signal) causes it to disable failing bank(s) by writing + * 'reconfiguration code' (inverted number of failing memory bank) to + * the register. + + * bit 1-0 'reconfiguration code' + * bit 2 enable read access + * bit 3 enable write access + */ + +READ8_MEMBER(pc_state::ec1841_memboard_r) +{ + pc_state *st = space.machine().driver_data<pc_state>(); + return st->m_memboard[(offset % 4)]; +} + +WRITE8_MEMBER(pc_state::ec1841_memboard_w) +{ + pc_state *st = space.machine().driver_data<pc_state>(); + address_space *program = space.machine().device("maincpu")->memory().space(AS_PROGRAM); + running_machine &machine = space.machine(); + UINT8 current; + + DBG_LOG(1,"ec1841_memboard_w",("(%d) <- %02X at %s\n", offset, data, machine.describe_context())); + + // for now, handle only board 0 + if (offset > 0) { + st->m_memboard[offset] = data; + return; + } + + current = st->m_memboard[offset]; + + if (BIT(current, 2) && !BIT(data, 2)) { + // disable read access + program->unmap_read(0, 0x7ffff); + DBG_LOG(1,"ec1841_memboard_w",("unmap_read(%d)\n", offset)); + } + + if (BIT(current, 3) && !BIT(data, 3)) { + // disable write access + program->unmap_write(0, 0x7ffff); + DBG_LOG(1,"ec1841_memboard_w",("unmap_write(%d)\n", offset)); + } + + if (!BIT(current, 2) && BIT(data, 2)) { + // enable read access + program->install_read_bank(0, 0x7ffff, "bank10"); + DBG_LOG(1,"ec1841_memboard_w",("map_read(%d)\n", offset)); + } + + if (!BIT(current, 3) && BIT(data, 3)) { + // enable write access + program->install_write_bank(0, 0x7ffff, "bank10"); + DBG_LOG(1,"ec1841_memboard_w",("map_write(%d)\n", offset)); + } + + st->m_memboard[offset] = data; +} + +/************************************************************************* + * + * PC DMA stuff + * + *************************************************************************/ + +READ8_MEMBER(pc_state::pc_page_r) +{ + return 0xFF; +} + + +WRITE8_MEMBER(pc_state::pc_page_w) +{ + switch(offset % 4) + { + case 1: + m_dma_offset[0][2] = data; + break; + case 2: + m_dma_offset[0][3] = data; + break; + case 3: + m_dma_offset[0][0] = m_dma_offset[0][1] = data; + break; + } +} + + +static WRITE_LINE_DEVICE_HANDLER( pc_dma_hrq_changed ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + device_set_input_line(st->m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); + + /* Assert HLDA */ + i8237_hlda_w( device, state ); +} + + +READ8_MEMBER(pc_state::pc_dma_read_byte) +{ + UINT8 result; + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) + & 0x0F0000; + + result = space.read_byte( page_offset + offset); + return result; +} + + +WRITE8_MEMBER(pc_state::pc_dma_write_byte) +{ + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) + & 0x0F0000; + + space.write_byte( page_offset + offset, data); +} + + +static READ8_DEVICE_HANDLER( pc_dma8237_fdc_dack_r ) +{ + return pc_fdc_dack_r(device->machine()); +} + + +static READ8_DEVICE_HANDLER( pc_dma8237_hdc_dack_r ) +{ + return 0xff; +} + + +static WRITE8_DEVICE_HANDLER( pc_dma8237_fdc_dack_w ) +{ + pc_fdc_dack_w( device->machine(), data ); +} + + +static WRITE8_DEVICE_HANDLER( pc_dma8237_hdc_dack_w ) +{ +} + + +static WRITE8_DEVICE_HANDLER( pc_dma8237_0_dack_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + st->m_u73_q2 = 0; + i8237_dreq0_w( st->m_dma8237, st->m_u73_q2 ); +} + + +static WRITE_LINE_DEVICE_HANDLER( pc_dma8237_out_eop ) +{ + pc_fdc_set_tc_state( device->machine(), state == ASSERT_LINE ? 0 : 1 ); +} + +static void set_dma_channel(device_t *device, int channel, int state) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + + if (!state) st->m_dma_channel = channel; +} + +static WRITE_LINE_DEVICE_HANDLER( pc_dack0_w ) { set_dma_channel(device, 0, state); } +static WRITE_LINE_DEVICE_HANDLER( pc_dack1_w ) { set_dma_channel(device, 1, state); } +static WRITE_LINE_DEVICE_HANDLER( pc_dack2_w ) { set_dma_channel(device, 2, state); } +static WRITE_LINE_DEVICE_HANDLER( pc_dack3_w ) { set_dma_channel(device, 3, state); } + +I8237_INTERFACE( ibm5150_dma8237_config ) +{ + DEVCB_DEVICE_LINE("dma8237", pc_dma_hrq_changed), + DEVCB_DEVICE_LINE("dma8237", pc_dma8237_out_eop), + DEVCB_DRIVER_MEMBER(pc_state, pc_dma_read_byte), + DEVCB_DRIVER_MEMBER(pc_state, pc_dma_write_byte), + { DEVCB_NULL, DEVCB_NULL, DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_fdc_dack_r), DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_hdc_dack_r) }, + { DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_0_dack_w), DEVCB_NULL, DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_fdc_dack_w), DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_hdc_dack_w) }, + { DEVCB_DEVICE_LINE("dma8237", pc_dack0_w), DEVCB_DEVICE_LINE("dma8237", pc_dack1_w), DEVCB_DEVICE_LINE("dma8237", pc_dack2_w), DEVCB_DEVICE_LINE("dma8237", pc_dack3_w) } +}; + + +/************************************************************* + * + * pic8259 configuration + * + *************************************************************/ + +const struct pic8259_interface ibm5150_pic8259_config = +{ + DEVCB_CPU_INPUT_LINE("maincpu", 0), + DEVCB_LINE_VCC, + DEVCB_NULL +}; + + +/************************************************************* + * + * PCJR pic8259 configuration + * + * Part of the PCJR CRT POST test at address F0452/F0454 writes + * to the PIC enabling an IRQ which is then immediately fired, + * however it is expected that the actual IRQ is taken one + * instruction later (the irq bit is reset by the instruction + * at F0454). Delaying taking of an IRQ by one instruction for + * all cases breaks floppy emulation. This seems to be a really + * tight corner case. For now we delay the IRQ by one instruction + * only for the PCJR and only when it's inside the POST checks. + * + *************************************************************/ + +static emu_timer *pc_int_delay_timer; + +static TIMER_CALLBACK( pcjr_delayed_pic8259_irq ) +{ + device_set_input_line(machine.firstcpu, 0, param ? ASSERT_LINE : CLEAR_LINE); +} + +static WRITE_LINE_DEVICE_HANDLER( pcjr_pic8259_set_int_line ) +{ + if ( cpu_get_reg( device->machine().firstcpu, STATE_GENPC ) == 0xF0454 ) + { + pc_int_delay_timer->adjust( device->machine().firstcpu->cycles_to_attotime(1), state ); + } + else + { + device_set_input_line(device->machine().firstcpu, 0, state ? ASSERT_LINE : CLEAR_LINE); + } +} + +const struct pic8259_interface pcjr_pic8259_config = +{ + DEVCB_LINE(pcjr_pic8259_set_int_line), + DEVCB_LINE_VCC, + DEVCB_NULL +}; + + +/************************************************************************* + * + * PC Speaker related + * + *************************************************************************/ +UINT8 pc_speaker_get_spk(running_machine &machine) +{ + pc_state *st = machine.driver_data<pc_state>(); + return st->m_pc_spkrdata & st->m_pc_input; +} + + +void pc_speaker_set_spkrdata(running_machine &machine, UINT8 data) +{ + device_t *speaker = machine.device(SPEAKER_TAG); + pc_state *st = machine.driver_data<pc_state>(); + st->m_pc_spkrdata = data ? 1 : 0; + speaker_level_w( speaker, pc_speaker_get_spk(machine) ); +} + + +void pc_speaker_set_input(running_machine &machine, UINT8 data) +{ + device_t *speaker = machine.device(SPEAKER_TAG); + pc_state *st = machine.driver_data<pc_state>(); + st->m_pc_input = data ? 1 : 0; + speaker_level_w( speaker, pc_speaker_get_spk(machine) ); +} + + +/************************************************************* + * + * pit8253 configuration + * + *************************************************************/ + +static WRITE_LINE_DEVICE_HANDLER( ibm5150_pit8253_out1_changed ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + /* Trigger DMA channel #0 */ + if ( st->m_out1 == 0 && state == 1 && st->m_u73_q2 == 0 ) + { + st->m_u73_q2 = 1; + i8237_dreq0_w( st->m_dma8237, st->m_u73_q2 ); + } + st->m_out1 = state; +} + + +static WRITE_LINE_DEVICE_HANDLER( ibm5150_pit8253_out2_changed ) +{ + pc_speaker_set_input( device->machine(), state ); +} + + +const struct pit8253_config ibm5150_pit8253_config = +{ + { + { + XTAL_14_31818MHz/12, /* heartbeat IRQ */ + DEVCB_NULL, + DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w) + }, { + XTAL_14_31818MHz/12, /* dram refresh */ + DEVCB_NULL, + DEVCB_LINE(ibm5150_pit8253_out1_changed) + }, { + XTAL_14_31818MHz/12, /* pio port c pin 4, and speaker polling enough */ + DEVCB_NULL, + DEVCB_LINE(ibm5150_pit8253_out2_changed) + } + } +}; + + +/* + On the PC Jr the input for clock 1 seems to be selectable + based on bit 4(/5?) written to output port A0h. This is not + supported yet. + */ + +const struct pit8253_config pcjr_pit8253_config = +{ + { + { + XTAL_14_31818MHz/12, /* heartbeat IRQ */ + DEVCB_NULL, + DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w) + }, { + XTAL_14_31818MHz/12, /* dram refresh */ + DEVCB_NULL, + DEVCB_NULL + }, { + XTAL_14_31818MHz/12, /* pio port c pin 4, and speaker polling enough */ + DEVCB_NULL, + DEVCB_LINE(ibm5150_pit8253_out2_changed) + } + } +}; + +/* MC1502 uses single XTAL for everything -- incl. CGA? check */ + +const struct pit8253_config mc1502_pit8253_config = +{ + { + { + XTAL_16MHz/12, /* heartbeat IRQ */ + DEVCB_NULL, + DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w) + }, { + XTAL_16MHz/12, /* serial port */ + DEVCB_NULL, + DEVCB_NULL + }, { + XTAL_16MHz/12, /* pio port c pin 4, and speaker polling enough */ + DEVCB_NULL, + DEVCB_LINE(ibm5150_pit8253_out2_changed) + } + } +}; + +/********************************************************** + * + * COM hardware + * + **********************************************************/ + +/* called when a interrupt is set/cleared from com hardware */ +static WRITE_LINE_DEVICE_HANDLER( pc_com_interrupt_1 ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + pic8259_ir4_w(st->m_pic8259, state); +} + +static WRITE_LINE_DEVICE_HANDLER( pc_com_interrupt_2 ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + pic8259_ir3_w(st->m_pic8259, state); +} + +const ins8250_interface ibm5150_com_interface[4]= +{ + { + DEVCB_DEVICE_LINE_MEMBER("serport0", serial_port_device, tx), + DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, dtr_w), + DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, rts_w), + DEVCB_LINE(pc_com_interrupt_1), + DEVCB_NULL, + DEVCB_NULL + }, + { + DEVCB_DEVICE_LINE_MEMBER("serport1", serial_port_device, tx), + DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, dtr_w), + DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, rts_w), + DEVCB_LINE(pc_com_interrupt_2), + DEVCB_NULL, + DEVCB_NULL + }, + { + DEVCB_DEVICE_LINE_MEMBER("serport2", serial_port_device, tx), + DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, dtr_w), + DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, rts_w), + DEVCB_LINE(pc_com_interrupt_1), + DEVCB_NULL, + DEVCB_NULL + }, + { + DEVCB_DEVICE_LINE_MEMBER("serport3", serial_port_device, tx), + DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, dtr_w), + DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, rts_w), + DEVCB_LINE(pc_com_interrupt_2), + DEVCB_NULL, + DEVCB_NULL + } +}; + +const rs232_port_interface ibm5150_serport_config[4] = +{ + { + DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, rx_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, dcd_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, dsr_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, ri_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, cts_w) + }, + { + DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, rx_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, dcd_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, dsr_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, ri_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, cts_w) + }, + { + DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, rx_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, dcd_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, dsr_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, ri_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, cts_w) + }, + { + DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, rx_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, dcd_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, dsr_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, ri_w), + DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, cts_w) + } +}; + +/********************************************************** + * + * NMI handling + * + **********************************************************/ + +static UINT8 nmi_enabled; + +WRITE8_MEMBER(pc_state::pc_nmi_enable_w) +{ + logerror( "%08X: changing NMI state to %s\n", cpu_get_pc(&space.device()), data & 0x80 ? "enabled" : "disabled" ); + + nmi_enabled = data & 0x80; +} + +/************************************************************* + * + * PCJR NMI and raw keybaord handling + * + * raw signals on the keyboard cable: + * ---_-b0b1b2b3b4b5b6b7pa---------------------- + * | | | | | | | | | | | + * | | | | | | | | | | *--- 11 stop bits ( -- = 1 stop bit ) + * | | | | | | | | | *----- parity bit ( 0 = _-, 1 = -_ ) + * | | | | | | | | *------- bit 7 ( 0 = _-, 1 = -_ ) + * | | | | | | | *--------- bit 6 ( 0 = _-, 1 = -_ ) + * | | | | | | *----------- bit 5 ( 0 = _-, 1 = -_ ) + * | | | | | *------------- bit 4 ( 0 = _-, 1 = -_ ) + * | | | | *--------------- bit 3 ( 0 = _-, 1 = -_ ) + * | | | *----------------- bit 2 ( 0 = _-, 1 = -_ ) + * | | *------------------- bit 1 ( 0 = _-, 1 = -_ ) + * | *--------------------- bit 0 ( 0 = _-, 1 = -_ ) + * *----------------------- start bit (always _- ) + * + * An entire bit lasts for 440 uSec, half bit time is 220 uSec. + * Transferring an entire byte takes 21 x 440uSec. The extra + * time of the stop bits is to allow the CPU to do other things + * besides decoding keyboard signals. + * + * These signals get inverted before going to the PCJR + * handling hardware. The sequence for the start then + * becomes: + * + * __-_b0b1..... + * | + * *---- on the 0->1 transition of the start bit a keyboard + * latch signal is set to 1 and an NMI is generated + * when enabled. + * The keyboard latch is reset by reading from the + * NMI enable port (A0h). + * + *************************************************************/ + +static struct { + UINT8 transferring; + UINT8 latch; + UINT32 raw_keyb_data; + int signal_count; + emu_timer *keyb_signal_timer; +} pcjr_keyb; + + +READ8_MEMBER(pc_state::pcjr_nmi_enable_r) +{ + pcjr_keyb.latch = 0; + + return nmi_enabled; +} + + +static TIMER_CALLBACK( pcjr_keyb_signal_callback ) +{ + pcjr_keyb.raw_keyb_data = pcjr_keyb.raw_keyb_data >> 1; + pcjr_keyb.signal_count--; + + if ( pcjr_keyb.signal_count <= 0 ) + { + pcjr_keyb.keyb_signal_timer->adjust( attotime::never, 0, attotime::never ); + pcjr_keyb.transferring = 0; + } +} + + +static void pcjr_set_keyb_int(running_machine &machine, int state) +{ + pc_state *st = machine.driver_data<pc_state>(); + if ( state ) + { + UINT8 data = pc_keyb_read(); + UINT8 parity = 0; + int i; + + /* Calculate the raw data */ + for( i = 0; i < 8; i++ ) + { + if ( ( 1 << i ) & data ) + { + parity ^= 1; + } + } + pcjr_keyb.raw_keyb_data = 0; + pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | ( parity ? 1 : 2 ); + for( i = 0; i < 8; i++ ) + { + pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | ( ( data & 0x80 ) ? 1 : 2 ); + data <<= 1; + } + /* Insert start bit */ + pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | 1; + pcjr_keyb.signal_count = 20 + 22; + + /* we are now transferring a byte of keyboard data */ + pcjr_keyb.transferring = 1; + + /* Set timer */ + pcjr_keyb.keyb_signal_timer->adjust( attotime::from_usec(220), 0, attotime::from_usec(220) ); + + /* Trigger NMI */ + if ( ! pcjr_keyb.latch ) + { + pcjr_keyb.latch = 1; + if ( nmi_enabled & 0x80 ) + { + device_set_input_line( st->m_pit8253->machine().firstcpu, INPUT_LINE_NMI, PULSE_LINE ); + } + } + } +} + + +static void pcjr_keyb_init(running_machine &machine) +{ + pcjr_keyb.transferring = 0; + pcjr_keyb.latch = 0; + pcjr_keyb.raw_keyb_data = 0; + pc_keyb_set_clock( 1 ); +} + + + +/********************************************************** + * + * PPI8255 interface + * + * + * PORT A (input) + * + * Directly attached to shift register which stores data + * received from the keyboard. + * + * PORT B (output) + * 0 - PB0 - TIM2GATESPK - Enable/disable counting on timer 2 of the 8253 + * 1 - PB1 - SPKRDATA - Speaker data + * 2 - PB2 - - Enable receiving data from the keyboard when keyboard is not locked. + * 3 - PB3 - - Dipsswitch set selector + * 4 - PB4 - ENBRAMPCK - Enable ram parity check + * 5 - PB5 - ENABLEI/OCK - Enable expansion I/O check + * 6 - PB6 - - Connected to keyboard clock signal + * 0 = ignore keyboard signals + * 1 = accept keyboard signals + * 7 - PB7 - - Clear/disable shift register and IRQ1 line + * 0 = normal operation + * 1 = clear and disable shift register and clear IRQ1 flip flop + * + * PORT C + * 0 - PC0 - - Dipswitch 0/4 SW1 + * 1 - PC1 - - Dipswitch 1/5 SW1 + * 2 - PC2 - - Dipswitch 2/6 SW1 + * 3 - PC3 - - Dipswitch 3/7 SW1 + * 4 - PC4 - SPK - Speaker/cassette data + * 5 - PC5 - I/OCHCK - Expansion I/O check result + * 6 - PC6 - T/C2OUT - Output of 8253 timer 2 + * 7 - PC7 - PCK - Parity check result + * + * IBM5150 SW1: + * 0 - OFF - One or more floppy drives + * ON - Diskless operation + * 1 - OFF - 8087 present + * ON - No 8087 present + * 2+3 - Used to determine on board memory configuration + * OFF OFF - 64KB + * ON OFF - 48KB + * OFF ON - 32KB + * ON ON - 16KB + * 4+5 - Used to select display + * OFF OFF - Monochrome + * ON OFF - CGA, 80 column + * OFF ON - CGA, 40 column + * ON ON - EGA/VGA display + * 6+7 - Used to select number of disk drives + * OFF OFF - four disk drives + * ON OFF - three disk drives + * OFF ON - two disk drives + * ON ON - one disk drive + * + **********************************************************/ + +WRITE_LINE_MEMBER( pc_state::keyboard_clock_w ) +{ + if ( m_ppi_clock_signal != state ) + { + if ( m_ppi_keyb_clock && m_ppi_shift_enable ) + { + m_ppi_clock_signal = state; + if ( ! m_ppi_keyboard_clear ) + { + /* Data is clocked in on a high->low transition */ + if ( ! state ) + { + UINT8 trigger_irq = m_ppi_shift_register & 0x01; + + m_ppi_shift_register = ( m_ppi_shift_register >> 1 ) | ( m_ppi_data_signal << 7 ); + if ( trigger_irq ) + { + pic8259_ir1_w(m_pic8259, 1); + m_ppi_shift_enable = 0; + m_ppi_clock_signal = 0; + m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal); + } + } + } + } + } +} + + +WRITE_LINE_MEMBER( pc_state::keyboard_data_w ) +{ + m_ppi_data_signal = state; +} + + +static READ8_DEVICE_HANDLER (ibm5160_ppi_porta_r) +{ + int data = 0xFF; + running_machine &machine = device->machine(); + pc_state *st = device->machine().driver_data<pc_state>(); + + /* KB port A */ + if (st->m_ppi_keyboard_clear) + { + /* 0 0 - no floppy drives + * 1 Not used + * 2-3 The number of memory banks on the system board + * 4-5 Display mode + * 11 = monochrome + * 10 - color 80x25 + * 01 - color 40x25 + * 6-7 The number of floppy disk drives + */ + data = device->machine().root_device().ioport("DSW0")->read(); + } + else + { + data = st->m_ppi_shift_register; + } + PIO_LOG(1,"PIO_A_r",("$%02x\n", data)); + return data; +} + + +static READ8_DEVICE_HANDLER ( ibm5160_ppi_portc_r ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + int timer2_output = pit8253_get_output( st->m_pit8253, 2 ); + int data=0xff; + running_machine &machine = device->machine(); + + data&=~0x80; // no parity error + data&=~0x40; // no error on expansion board + /* KB port C: equipment flags */ +// if (pc_port[0x61] & 0x08) + if (st->m_ppi_portc_switch_high) + { + /* read hi nibble of S2 */ + data = (data & 0xf0) | ((device->machine().root_device().ioport("DSW0")->read() >> 4) & 0x0f); + PIO_LOG(1,"PIO_C_r (hi)",("$%02x\n", data)); + } + else + { + /* read lo nibble of S2 */ + data = (data & 0xf0) | (device->machine().root_device().ioport("DSW0")->read() & 0x0f); + PIO_LOG(1,"PIO_C_r (lo)",("$%02x\n", data)); + } + + if ( st->m_ppi_portb & 0x01 ) + { + data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 ); + } + data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 ); + + return data; +} + + +static WRITE8_DEVICE_HANDLER( ibm5160_ppi_portb_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + + /* PPI controller port B*/ + st->m_ppi_portb = data; + st->m_ppi_portc_switch_high = data & 0x08; + st->m_ppi_keyboard_clear = data & 0x80; + st->m_ppi_keyb_clock = data & 0x40; + pit8253_gate2_w(st->m_pit8253, BIT(data, 0)); + pc_speaker_set_spkrdata( device->machine(), data & 0x02 ); + + st->m_ppi_clock_signal = ( st->m_ppi_keyb_clock ) ? 1 : 0; + st->m_pc_kbdc->clock_write_from_mb(st->m_ppi_clock_signal); + + /* If PB7 is set clear the shift register and reset the IRQ line */ + if ( st->m_ppi_keyboard_clear ) + { + pic8259_ir1_w(st->m_pic8259, 0); + st->m_ppi_shift_register = 0; + st->m_ppi_shift_enable = 1; + } +} + + +I8255_INTERFACE( ibm5160_ppi8255_interface ) +{ + DEVCB_HANDLER(ibm5160_ppi_porta_r), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_HANDLER(ibm5160_ppi_portb_w), + DEVCB_HANDLER(ibm5160_ppi_portc_r), + DEVCB_NULL +}; + + +static READ8_DEVICE_HANDLER (pc_ppi_porta_r) +{ + int data = 0xFF; + running_machine &machine = device->machine(); + pc_state *st = device->machine().driver_data<pc_state>(); + + /* KB port A */ + if (st->m_ppi_keyboard_clear) + { + /* 0 0 - no floppy drives + * 1 Not used + * 2-3 The number of memory banks on the system board + * 4-5 Display mode + * 11 = monochrome + * 10 - color 80x25 + * 01 - color 40x25 + * 6-7 The number of floppy disk drives + */ + data = device->machine().root_device().ioport("DSW0")->read(); + } + else + { + data = pc_keyb_read(); + } + PIO_LOG(1,"PIO_A_r",("$%02x\n", data)); + return data; +} + + +static WRITE8_DEVICE_HANDLER( pc_ppi_portb_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + /* PPI controller port B*/ + st->m_ppi_portb = data; + st->m_ppi_portc_switch_high = data & 0x08; + st->m_ppi_keyboard_clear = data & 0x80; + st->m_ppi_keyb_clock = data & 0x40; + pit8253_gate2_w(st->m_pit8253, BIT(data, 0)); + pc_speaker_set_spkrdata( device->machine(), data & 0x02 ); + pc_keyb_set_clock( st->m_ppi_keyb_clock ); + + if ( st->m_ppi_keyboard_clear ) + pc_keyb_clear(); +} + + +I8255_INTERFACE( pc_ppi8255_interface ) +{ + DEVCB_HANDLER(pc_ppi_porta_r), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_HANDLER(pc_ppi_portb_w), + DEVCB_HANDLER(ibm5160_ppi_portc_r), + DEVCB_NULL +}; + + +static struct { + UINT8 pulsing; + UINT8 latch; /* keyboard scan code */ + UINT16 mask; /* input lines */ + emu_timer *keyb_signal_timer; +} mc1502_keyb; + + +/* check if any keys are pressed, raise IRQ1 if so */ + +static TIMER_CALLBACK( mc1502_keyb_signal_callback ) +{ + pc_state *st = machine.driver_data<pc_state>(); + UINT8 key = 0; + + key |= machine.root_device().ioport("Y1")->read(); + key |= machine.root_device().ioport("Y2")->read(); + key |= machine.root_device().ioport("Y3")->read(); + key |= machine.root_device().ioport("Y4")->read(); + key |= machine.root_device().ioport("Y5")->read(); + key |= machine.root_device().ioport("Y6")->read(); + key |= machine.root_device().ioport("Y7")->read(); + key |= machine.root_device().ioport("Y8")->read(); + key |= machine.root_device().ioport("Y9")->read(); + key |= machine.root_device().ioport("Y10")->read(); + key |= machine.root_device().ioport("Y11")->read(); + key |= machine.root_device().ioport("Y12")->read(); + DBG_LOG(1,"mc1502_k_s_c",("= %02X (%d) %s\n", key, mc1502_keyb.pulsing, + (key || mc1502_keyb.pulsing) ? " will IRQ" : "")); + + /* + If a key is pressed and we're not pulsing yet, start pulsing the IRQ1; + keep pulsing while any key is pressed, and pulse one time after all keys + are released. + */ + if (key) { + if (mc1502_keyb.pulsing < 2) { + mc1502_keyb.pulsing += 2; + } + } + + if (mc1502_keyb.pulsing) { + pic8259_ir1_w(st->m_pic8259, (mc1502_keyb.pulsing & 1)); + mc1502_keyb.pulsing--; + } +} + +static READ8_DEVICE_HANDLER ( mc1502_ppi_porta_r ) +{ + running_machine &machine = device->machine(); + + DBG_LOG(1,"mc1502_ppi_porta_r",("= %02X\n", mc1502_keyb.latch)); + return mc1502_keyb.latch; +} + +static WRITE8_DEVICE_HANDLER ( mc1502_ppi_porta_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + running_machine &machine = device->machine(); + + DBG_LOG(1,"mc1502_ppi_porta_w",("( %02X )\n", data)); + mc1502_keyb.latch = data; + if (mc1502_keyb.pulsing) + mc1502_keyb.pulsing--; + pic8259_ir1_w(st->m_pic8259, 0); +} + +static WRITE8_DEVICE_HANDLER ( mc1502_ppi_portb_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + running_machine &machine = device->machine(); + + DBG_LOG(2,"mc1502_ppi_portb_w",("( %02X )\n", data)); + st->m_ppi_portb = data; + pit8253_gate2_w(device->machine().device("pit8253"), BIT(data, 0)); + pc_speaker_set_spkrdata( device->machine(), data & 0x02 ); +} + +static READ8_DEVICE_HANDLER ( mc1502_ppi_portc_r ) +{ + running_machine &machine = device->machine(); + pc_state *st = device->machine().driver_data<pc_state>(); + int timer2_output = pit8253_get_output( device->machine().device("pit8253"), 2 ); + int data = 0xff; + double tap_val = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input()); + +// 0x80 -- serial RxD +// 0x40 -- CASS IN, also loops back T2OUT (gated by CASWR) + data = ( data & ~0x40 ) | ( tap_val < 0 ? 0x40 : 0x00 ) | ( (BIT(st->m_ppi_portb, 7) && timer2_output) ? 0x40 : 0x00 ); +// 0x20 -- T2OUT + data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 ); +// 0x10 -- SNDOUT + data = ( data & ~0x10 ) | ( (BIT(st->m_ppi_portb, 1) && timer2_output) ? 0x10 : 0x00 ); + + DBG_LOG(2,"mc1502_ppi_portc_r",("= %02X (tap_val %f t2out %d) at %s\n", + data, tap_val, timer2_output, machine.describe_context())); + return data; +} + +static READ8_DEVICE_HANDLER ( mc1502_kppi_porta_r ) +{ + running_machine &machine = device->machine(); + UINT8 key = 0; + + if (mc1502_keyb.mask & 0x0001) { key |= machine.root_device().ioport("Y1")->read(); } + if (mc1502_keyb.mask & 0x0002) { key |= machine.root_device().ioport("Y2")->read(); } + if (mc1502_keyb.mask & 0x0004) { key |= machine.root_device().ioport("Y3")->read(); } + if (mc1502_keyb.mask & 0x0008) { key |= machine.root_device().ioport("Y4")->read(); } + if (mc1502_keyb.mask & 0x0010) { key |= machine.root_device().ioport("Y5")->read(); } + if (mc1502_keyb.mask & 0x0020) { key |= machine.root_device().ioport("Y6")->read(); } + if (mc1502_keyb.mask & 0x0040) { key |= machine.root_device().ioport("Y7")->read(); } + if (mc1502_keyb.mask & 0x0080) { key |= machine.root_device().ioport("Y8")->read(); } + if (mc1502_keyb.mask & 0x0100) { key |= machine.root_device().ioport("Y9")->read(); } + if (mc1502_keyb.mask & 0x0200) { key |= machine.root_device().ioport("Y10")->read(); } + if (mc1502_keyb.mask & 0x0400) { key |= machine.root_device().ioport("Y11")->read(); } + if (mc1502_keyb.mask & 0x0800) { key |= machine.root_device().ioport("Y12")->read(); } + key ^= 0xff; + DBG_LOG(2,"mc1502_kppi_porta_r",("= %02X\n", key)); + return key; +} + +static WRITE8_DEVICE_HANDLER ( mc1502_kppi_portb_w ) +{ + running_machine &machine = device->machine(); + + mc1502_keyb.mask &= ~255; + mc1502_keyb.mask |= data ^ 255; + if (!BIT(data, 0)) + mc1502_keyb.mask |= 1 << 11; + else + mc1502_keyb.mask &= ~(1 << 11); + DBG_LOG(2,"mc1502_kppi_portb_w",("( %02X -> %04X )\n", data, mc1502_keyb.mask)); +} + +static WRITE8_DEVICE_HANDLER ( mc1502_kppi_portc_w ) +{ + running_machine &machine = device->machine(); + + mc1502_keyb.mask &= ~(7 << 8); + mc1502_keyb.mask |= ((data ^ 7) & 7) << 8; + DBG_LOG(2,"mc1502_kppi_portc_w",("( %02X -> %04X )\n", data, mc1502_keyb.mask)); +} + + +static WRITE8_DEVICE_HANDLER ( pcjr_ppi_portb_w ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + /* KB controller port B */ + st->m_ppi_portb = data; + st->m_ppi_portc_switch_high = data & 0x08; + pit8253_gate2_w(device->machine().device("pit8253"), BIT(data, 0)); + pc_speaker_set_spkrdata( device->machine(), data & 0x02 ); + + device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(( data & 0x08 ) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR); +} + + +/* + * On a PCJR none of the port A bits are connected. + */ +static READ8_DEVICE_HANDLER (pcjr_ppi_porta_r ) +{ + int data; + running_machine &machine = device->machine(); + + data = 0xff; + PIO_LOG(1,"PIO_A_r",("$%02x\n", data)); + return data; +} + + +/* + * Port C connections on a PCJR (notes from schematics): + * PC0 - KYBD LATCH + * PC1 - MODEM CD INSTALLED + * PC2 - DISKETTE CD INSTALLED + * PC3 - ATR CD IN + * PC4 - cassette audio + * PC5 - OUT2 from 8253 + * PC6 - KYBD IN + * PC7 - (keyboard) CABLE CONNECTED + */ +static READ8_DEVICE_HANDLER ( pcjr_ppi_portc_r ) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + int timer2_output = pit8253_get_output( device->machine().device("pit8253"), 2 ); + int data=0xff; + + data&=~0x80; + data &= ~0x04; /* floppy drive installed */ + if ( device->machine().device<ram_device>(RAM_TAG)->size() > 64 * 1024 ) /* more than 64KB ram installed */ + data &= ~0x08; + data = ( data & ~0x01 ) | ( pcjr_keyb.latch ? 0x01: 0x00 ); + if ( ! ( st->m_ppi_portb & 0x08 ) ) + { + double tap_val = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input()); + + if ( tap_val < 0 ) + { + data &= ~0x10; + } + else + { + data |= 0x10; + } + } + else + { + if ( st->m_ppi_portb & 0x01 ) + { + data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 ); + } + } + data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 ); + data = ( data & ~0x40 ) | ( ( pcjr_keyb.raw_keyb_data & 0x01 ) ? 0x40 : 0x00 ); + + return data; +} + + +I8255_INTERFACE( pcjr_ppi8255_interface ) +{ + DEVCB_HANDLER(pcjr_ppi_porta_r), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_HANDLER(pcjr_ppi_portb_w), + DEVCB_HANDLER(pcjr_ppi_portc_r), + DEVCB_NULL +}; + +I8255_INTERFACE( mc1502_ppi8255_interface ) +{ + DEVCB_HANDLER(mc1502_ppi_porta_r), + DEVCB_HANDLER(mc1502_ppi_porta_w), + DEVCB_NULL, + DEVCB_HANDLER(mc1502_ppi_portb_w), + DEVCB_HANDLER(mc1502_ppi_portc_r), + DEVCB_NULL +}; + +I8255_INTERFACE( mc1502_ppi8255_interface_2 ) +{ + DEVCB_HANDLER(mc1502_kppi_porta_r), + DEVCB_NULL, + DEVCB_NULL, + DEVCB_HANDLER(mc1502_kppi_portb_w), + DEVCB_NULL, + DEVCB_HANDLER(mc1502_kppi_portc_w) +}; + + +/********************************************************** + * + * NEC uPD765 floppy interface + * + **********************************************************/ + +static void pc_fdc_interrupt(running_machine &machine, int state) +{ + pc_state *st = machine.driver_data<pc_state>(); + if (st->m_pic8259) + { + pic8259_ir6_w(st->m_pic8259, state); + } +} + +static void pc_fdc_dma_drq(running_machine &machine, int state) +{ + pc_state *st = machine.driver_data<pc_state>(); + i8237_dreq2_w( st->m_dma8237, state); +} + +static device_t * pc_get_device(running_machine &machine ) +{ + return machine.device("upd765"); +} + +static const struct pc_fdc_interface fdc_interface_nc = +{ + pc_fdc_interrupt, + pc_fdc_dma_drq, + NULL, + pc_get_device +}; + + +static const struct pc_fdc_interface pcjr_fdc_interface_nc = +{ + pc_fdc_interrupt, + NULL, + NULL, + pc_get_device +}; + + +static void pc_set_irq_line(running_machine &machine,int irq, int state) +{ + pc_state *st = machine.driver_data<pc_state>(); + + switch (irq) + { + case 0: pic8259_ir0_w(st->m_pic8259, state); break; + case 1: pic8259_ir1_w(st->m_pic8259, state); break; + case 2: pic8259_ir2_w(st->m_pic8259, state); break; + case 3: pic8259_ir3_w(st->m_pic8259, state); break; + case 4: pic8259_ir4_w(st->m_pic8259, state); break; + case 5: pic8259_ir5_w(st->m_pic8259, state); break; + case 6: pic8259_ir6_w(st->m_pic8259, state); break; + case 7: pic8259_ir7_w(st->m_pic8259, state); break; + } +} + +static void pc_set_keyb_int(running_machine &machine, int state) +{ + pc_set_irq_line( machine, 1, state ); +} + +/* + * MC1502 uses a FD1793 clone instead of uPD765 + */ + +READ8_DEVICE_HANDLER( mc1502_wd17xx_aux_r ) +{ + UINT8 data; + + data = 0; + + return data; +} + +WRITE8_DEVICE_HANDLER( mc1502_wd17xx_aux_w ) +{ + // master reset + wd17xx_mr_w(device, BIT(data, 0)); + + // SIDE ONE + wd17xx_set_side(device, BIT(data, 1)); + + // bits 2, 3 -- motor on (drive 0, 1) + + // DRIVE SEL + wd17xx_set_drive(device, BIT(data, 4)); +} + +/* + * Accesses to this port block (halt the CPU until DRQ, INTRQ or MOTOR ON) + */ +READ8_DEVICE_HANDLER( mc1502_wd17xx_drq_r ) +{ + UINT8 data; + UINT64 newpc; + + data = wd17xx_drq_r(device); + if (!data && !wd17xx_intrq_r(device)) { + /* fake cpu halt by resetting PC one insn back */ + newpc = cpu_get_reg( device->machine().firstcpu, STATE_GENPC ); + cpu_set_reg( device->machine().firstcpu, STATE_GENPC, newpc - 1 ); + } + + return data; +} + +READ8_DEVICE_HANDLER( mc1502_wd17xx_motor_r ) +{ + UINT8 data; + + /* fake motor being always on */ + data = 1; + + return data; +} + + +/********************************************************** + * + * Initialization code + * + **********************************************************/ + +void mess_init_pc_common(running_machine &machine, UINT32 flags, void (*set_keyb_int_func)(running_machine &, int), void (*set_hdc_int_func)(running_machine &,int,int)) +{ + pc_state *state = machine.driver_data<pc_state>(); + if ( set_keyb_int_func != NULL ) + init_pc_common(machine, flags, set_keyb_int_func); + + /* MESS managed RAM */ + if ( machine.device<ram_device>(RAM_TAG)->pointer() ) + state->membank( "bank10" )->set_base( machine.device<ram_device>(RAM_TAG)->pointer() ); +} + + +DRIVER_INIT_MEMBER(pc_state,ibm5150) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line); + pc_rtc_init(machine()); +} + + +DRIVER_INIT_MEMBER(pc_state,pccga) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line); + pc_rtc_init(machine()); +} + + +DRIVER_INIT_MEMBER(pc_state,bondwell) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line); + pc_turbo_setup(machine(), machine().firstcpu, "DSW2", 0x02, 4.77/12, 1); +} + +DRIVER_INIT_MEMBER(pc_state,pcmda) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); +} + +DRIVER_INIT_MEMBER(pc_state,europc) +{ + UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000]; + UINT8 *rom = &machine().root_device().memregion("maincpu")->base()[0]; + int i; + + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; + + /* + fix century rom bios bug ! + if year <79 month (and not CENTURY) is loaded with 0x20 + */ + if (rom[0xff93e]==0xb6){ // mov dh, + UINT8 a; + rom[0xff93e]=0xb5; // mov ch, + for (i=0xf8000, a=0; i<0xfffff; i++ ) a+=rom[i]; + rom[0xfffff]=256-a; + } + + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); + + europc_rtc_init(machine()); +// europc_rtc_set_time(machine()); +} + +DRIVER_INIT_MEMBER(pc_state,t1000hx) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); + pc_turbo_setup(machine(), machine().firstcpu, "DSW2", 0x02, 4.77/12, 1); +} + +DRIVER_INIT_MEMBER(pc_state,pc200) +{ + UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000]; + int i; + + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; + + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); +} + +DRIVER_INIT_MEMBER(pc_state,ppc512) +{ + UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000]; + int i; + + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; + + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); +} +DRIVER_INIT_MEMBER(pc_state,pc1512) +{ + UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000]; + int i; + + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; + + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); +} + + +DRIVER_INIT_MEMBER(pc_state,pcjr) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pcjr_set_keyb_int, pc_set_irq_line); +} + +DRIVER_INIT_MEMBER(pc_state,mc1502) +{ + mess_init_pc_common(machine(), 0, NULL, pc_set_irq_line); +} + +static READ8_HANDLER( input_port_0_r ) { return space->machine().root_device().ioport("IN0")->read(); } + +DRIVER_INIT_MEMBER(pc_state,pc1640) +{ + address_space *io_space = machine().firstcpu->memory().space( AS_IO ); + + io_space->install_legacy_read_handler(0x278, 0x27b, FUNC(pc1640_port278_r), 0xffff); + io_space->install_legacy_read_handler(0x4278, 0x427b, FUNC(pc1640_port4278_r), 0xffff); + + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); +} + +DRIVER_INIT_MEMBER(pc_state,pc_vga) +{ + mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line); + + pc_vga_init(machine(), ::input_port_0_r, NULL); + pc_vga_io_init(machine(), machine().device("maincpu")->memory().space(AS_PROGRAM), 0xa0000, machine().device("maincpu")->memory().space(AS_IO), 0x0000); +} + +static IRQ_CALLBACK(pc_irq_callback) +{ + pc_state *st = device->machine().driver_data<pc_state>(); + return pic8259_acknowledge( st->m_pic8259 ); +} + + +MACHINE_START( pc ) +{ + pc_state *st = machine.driver_data<pc_state>(); + + st->m_pic8259 = machine.device("pic8259"); + st->m_dma8237 = machine.device("dma8237"); + st->m_pit8253 = machine.device("pit8253"); + pc_fdc_init( machine, &fdc_interface_nc ); +} + + +MACHINE_RESET( pc ) +{ + device_t *speaker = machine.device(SPEAKER_TAG); + pc_state *st = machine.driver_data<pc_state>(); + st->m_maincpu = machine.device("maincpu" ); + device_set_irq_callback(st->m_maincpu, pc_irq_callback); + + st->m_u73_q2 = 0; + st->m_out1 = 0; + st->m_pc_spkrdata = 0; + st->m_pc_input = 1; + st->m_dma_channel = 0; + memset(st->m_dma_offset,0,sizeof(st->m_dma_offset)); + st->m_ppi_portc_switch_high = 0; + st->m_ppi_speaker = 0; + st->m_ppi_keyboard_clear = 0; + st->m_ppi_keyb_clock = 0; + st->m_ppi_portb = 0; + st->m_ppi_clock_signal = 0; + st->m_ppi_data_signal = 0; + st->m_ppi_shift_register = 0; + st->m_ppi_shift_enable = 0; + + speaker_level_w( speaker, 0 ); +} + + +MACHINE_START( mc1502 ) +{ + pc_state *st = machine.driver_data<pc_state>(); + st->m_maincpu = machine.device("maincpu" ); + device_set_irq_callback(st->m_maincpu, pc_irq_callback); + + st->m_pic8259 = machine.device("pic8259"); + st->m_dma8237 = NULL; + st->m_pit8253 = machine.device("pit8253"); + + /* + Keyboard polling circuit holds IRQ1 high until a key is + pressed, then it starts a timer that pulses IRQ1 low each + 40ms (check) for 20ms (check) until all keys are released. + Last pulse causes BIOS to write a 'break' scancode into port 60h. + */ + pic8259_ir1_w(st->m_pic8259, 1); + memset(&mc1502_keyb, 0, sizeof(mc1502_keyb)); + mc1502_keyb.keyb_signal_timer = machine.scheduler().timer_alloc(FUNC(mc1502_keyb_signal_callback)); + mc1502_keyb.keyb_signal_timer->adjust( attotime::from_msec(20), 0, attotime::from_msec(20) ); +} + + +MACHINE_START( pcjr ) +{ + pc_state *st = machine.driver_data<pc_state>(); + pc_fdc_init( machine, &pcjr_fdc_interface_nc ); + pcjr_keyb.keyb_signal_timer = machine.scheduler().timer_alloc(FUNC(pcjr_keyb_signal_callback)); + pc_int_delay_timer = machine.scheduler().timer_alloc(FUNC(pcjr_delayed_pic8259_irq)); + st->m_maincpu = machine.device("maincpu" ); + device_set_irq_callback(st->m_maincpu, pc_irq_callback); + + st->m_pic8259 = machine.device("pic8259"); + st->m_dma8237 = NULL; + st->m_pit8253 = machine.device("pit8253"); +} + + +MACHINE_RESET( pcjr ) +{ + device_t *speaker = machine.device(SPEAKER_TAG); + pc_state *st = machine.driver_data<pc_state>(); + st->m_u73_q2 = 0; + st->m_out1 = 0; + st->m_pc_spkrdata = 0; + st->m_pc_input = 1; + st->m_dma_channel = 0; + memset(st->m_memboard,0xc,sizeof(st->m_memboard)); // check + memset(st->m_dma_offset,0,sizeof(st->m_dma_offset)); + st->m_ppi_portc_switch_high = 0; + st->m_ppi_speaker = 0; + st->m_ppi_keyboard_clear = 0; + st->m_ppi_keyb_clock = 0; + st->m_ppi_portb = 0; + st->m_ppi_clock_signal = 0; + st->m_ppi_data_signal = 0; + st->m_ppi_shift_register = 0; + st->m_ppi_shift_enable = 0; + speaker_level_w( speaker, 0 ); + + pcjr_keyb_init(machine); +} + + +DEVICE_IMAGE_LOAD( pcjr_cartridge ) +{ + UINT32 address; + UINT32 size; + + address = ( ! strcmp( ":cart2", image.device().tag() ) ) ? 0xd0000 : 0xe0000; + + if ( image.software_entry() ) + { + UINT8 *cart = image.get_software_region( "rom" ); + + size = image.get_software_region_length("rom" ); + + memcpy( image.device().machine().root_device().memregion("maincpu")->base() + address, cart, size ); + } + else + { + UINT8 header[0x200]; + + unsigned image_size = image.length(); + + /* Check for supported image sizes */ + switch( image_size ) + { + case 0x2200: + case 0x4200: + case 0x8200: + case 0x10200: + break; + default: + image.seterror(IMAGE_ERROR_UNSUPPORTED, "Invalid rom file size" ); + return IMAGE_INIT_FAIL; + } + + /* Read and verify the header */ + if ( 512 != image.fread( header, 512 ) ) + { + image.seterror(IMAGE_ERROR_UNSUPPORTED, "Unable to read header" ); + return IMAGE_INIT_FAIL; + } + + /* Read the cartridge contents */ + if ( ( image_size - 0x200 ) != image.fread(image.device().machine().root_device().memregion("maincpu")->base() + address, image_size - 0x200 ) ) + { + image.seterror(IMAGE_ERROR_UNSUPPORTED, "Unable to read cartridge contents" ); + return IMAGE_INIT_FAIL; + } + } + + return IMAGE_INIT_PASS; +} + + +/************************************************************************** + * + * Interrupt handlers. + * + **************************************************************************/ + +TIMER_DEVICE_CALLBACK( pc_frame_interrupt ) +{ + int scanline = param; + + if((scanline % 64) == 0) + pc_keyboard(); +} + +TIMER_DEVICE_CALLBACK( pc_vga_frame_interrupt ) +{ + int scanline = param; + + if((scanline % 64) == 0) + { + //vga_timer(); + pc_keyboard(); + } +} + +TIMER_DEVICE_CALLBACK( pcjr_frame_interrupt ) +{ + int scanline = param; + + if((scanline % 64) == 0 && pcjr_keyb.transferring == 0 ) + pc_keyboard(); +} + +/* +ibm xt bios +----------- + +fe0ac +fe10c +fe12b: hangs after reset +fe15e +fe19c +fe2c6 + graphics adapter sync signals +fe332 + search roms +fe35d + pic test +fe38f +fe3c6 +fe3e6 + 301 written + expect 0xaa after reset, send when lines activated in short time + (keyboard polling in frame interrupt is not quick enough now) +fe424 +fe448 + i/o expansion test +fe49c + memory test +fe500 + harddisk bios used +fe55c + disk booting + + f0bef + f0b85 + f096d + disk related + feca0 + prueft kanal 0 address register (memory refresh!?) + +ibm pc bios +----------- +fe104 +fe165 +fe1b4 +fe205 +fe23f +fe256 +fe363 +fe382 expansion test +fe3c4 + memory test +fe43b +fe443 call fe643 keyboard test +fe4a1 call ff979 tape!!! test +*/ + + +// damned old checkit doesn't test at standard addresses +// will do more when I have a program supporting it +static struct { + int data[0x18]; + emu_timer *timer; +} pc_rtc; + +static TIMER_CALLBACK(pc_rtc_timer) +{ + int year; + if (++pc_rtc.data[2]>=60) { + pc_rtc.data[2]=0; + if (++pc_rtc.data[3]>=60) { + pc_rtc.data[3]=0; + if (++pc_rtc.data[4]>=24) { + pc_rtc.data[4]=0; + pc_rtc.data[5]=(pc_rtc.data[5]%7)+1; + year=pc_rtc.data[9]+2000; + if (++pc_rtc.data[6]>=gregorian_days_in_month(pc_rtc.data[7], year)) { + pc_rtc.data[6]=1; + if (++pc_rtc.data[7]>12) { + pc_rtc.data[7]=1; + pc_rtc.data[9]=(pc_rtc.data[9]+1)%100; + } + } + } + } + } +} + +void pc_rtc_init(running_machine &machine) +{ + memset(&pc_rtc,0,sizeof(pc_rtc)); + pc_rtc.timer = machine.scheduler().timer_alloc(FUNC(pc_rtc_timer)); + pc_rtc.timer->adjust(attotime::zero, 0, attotime(1,0)); +} + +READ8_MEMBER(pc_state::pc_rtc_r) +{ + int data; + switch (offset) { + default: + data=pc_rtc.data[offset]; + } + logerror( "rtc read %.2x %.2x\n", offset, data); + return data; +} + +WRITE8_MEMBER(pc_state::pc_rtc_w) +{ + logerror( "rtc write %.2x %.2x\n", offset, data); + switch(offset) { + default: + pc_rtc.data[offset]=data; + } +} + +/************************************************************************* + * + * EXP + * expansion port + * + *************************************************************************/ + +// I even don't know what it is! +static struct { + /* + reg 0 ram behaviour if in + reg 3 write 1 to enable it + reg 4 ram behaviour ??? + reg 5,6 (5 hi, 6 lowbyte) ??? + */ + /* selftest in ibmpc, ibmxt */ + UINT8 reg[8]; +} pc_expansion={ { 0,0,0,0,0,0,1 } }; + +WRITE8_MEMBER(pc_state::pc_EXP_w) +{ + //DBG_LOG(1,"EXP_unit_w",("%.2x $%02x\n", offset, data)); + switch (offset) { + case 4: + pc_expansion.reg[4]=pc_expansion.reg[5]=pc_expansion.reg[6]=data; + break; + default: + pc_expansion.reg[offset] = data; + } +} + +READ8_MEMBER(pc_state::pc_EXP_r) +{ + int data; + UINT16 a; + switch (offset) { + case 6: + data = pc_expansion.reg[offset]; + a=(pc_expansion.reg[5]<<8)|pc_expansion.reg[6]; + a<<=1; + pc_expansion.reg[5]=a>>8; + pc_expansion.reg[6]=a&0xff; + break; + default: + data = pc_expansion.reg[offset]; + } + //DBG_LOG(1,"EXP_unit_r",("%.2x $%02x\n", offset, data)); + return data; +} + + + |