diff options
Diffstat (limited to 'src/mess/machine/osborne1.c')
-rw-r--r-- | src/mess/machine/osborne1.c | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/src/mess/machine/osborne1.c b/src/mess/machine/osborne1.c new file mode 100644 index 00000000000..b8fa04c81a8 --- /dev/null +++ b/src/mess/machine/osborne1.c @@ -0,0 +1,543 @@ +/*************************************************************************** + +There are three IRQ sources: +- IRQ0 +- IRQ1 = IRQA from the video PIA +- IRQ2 = IRQA from the IEEE488 PIA + +Interrupt handling on the Osborne-1 is a bit awkward. When an interrupt is +taken by the Z80 the ROMMODE is enabled on each fetch of an instruction +byte. During execution of an instruction the previous ROMMODE setting seems +to be used. Side effect of this is that when an interrupt is taken and the +stack pointer is pointing to 0000-3FFF then the return address will still +be written to RAM if RAM was switched in. + +***************************************************************************/ + +#include "includes/osborne1.h" + +#define RAMMODE (0x01) + + +WRITE8_MEMBER( osborne1_state::osborne1_0000_w ) +{ + /* Check whether regular RAM is enabled */ + if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) ) + machine().device<ram_device>(RAM_TAG)->pointer()[ offset ] = data; +} + + +WRITE8_MEMBER( osborne1_state::osborne1_1000_w ) +{ + /* Check whether regular RAM is enabled */ + if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) ) + machine().device<ram_device>(RAM_TAG)->pointer()[ 0x1000 + offset ] = data; +} + + +READ8_MEMBER( osborne1_state::osborne1_2000_r ) +{ + UINT8 data = 0xFF; + + /* Check whether regular RAM is enabled */ + if ( ! m_bank2_enabled ) + data = machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ]; + else + { + switch( offset & 0x0F00 ) + { + case 0x100: /* Floppy */ + data = wd17xx_r( m_fdc, offset ); + break; + case 0x200: /* Keyboard */ + /* Row 0 */ + if ( offset & 0x01 ) data &= ioport("ROW0")->read(); + /* Row 1 */ + if ( offset & 0x02 ) data &= ioport("ROW1")->read(); + /* Row 2 */ + if ( offset & 0x04 ) data &= ioport("ROW3")->read(); + /* Row 3 */ + if ( offset & 0x08 ) data &= ioport("ROW4")->read(); + /* Row 4 */ + if ( offset & 0x10 ) data &= ioport("ROW5")->read(); + /* Row 5 */ + if ( offset & 0x20 ) data &= ioport("ROW2")->read(); + /* Row 6 */ + if ( offset & 0x40 ) data &= ioport("ROW6")->read(); + /* Row 7 */ + if ( offset & 0x80 ) data &= ioport("ROW7")->read(); + break; + case 0x900: /* IEEE488 PIA */ + data = m_pia0->read(space, offset & 0x03 ); + break; + case 0xA00: /* Serial */ + break; + case 0xC00: /* Video PIA */ + data = m_pia1->read(space, offset & 0x03 ); + break; + } + } + return data; +} + + +WRITE8_MEMBER( osborne1_state::osborne1_2000_w ) +{ + /* Check whether regular RAM is enabled */ + if ( ! m_bank2_enabled ) + machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ] = data; + else + { + if ( m_in_irq_handler && m_bankswitch == RAMMODE ) + { + machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ] = data; + } + /* Handle writes to the I/O area */ + switch( offset & 0x0F00 ) + { + case 0x100: /* Floppy */ + wd17xx_w( m_fdc, offset, data ); + break; + case 0x900: /* IEEE488 PIA */ + m_pia0->write(space, offset & 0x03, data ); + break; + case 0xA00: /* Serial */ + break; + case 0xC00: /* Video PIA */ + m_pia1->write(space, offset & 0x03, data ); + break; + } + } +} + + +WRITE8_MEMBER( osborne1_state::osborne1_3000_w ) +{ + /* Check whether regular RAM is enabled */ + if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) ) + machine().device<ram_device>(RAM_TAG)->pointer()[ 0x3000 + offset ] = data; +} + + +WRITE8_MEMBER( osborne1_state::osborne1_videoram_w ) +{ + /* Check whether the video attribute section is enabled */ + if ( m_bank3_enabled ) + data |= 0x7F; + + m_bank4_ptr[offset] = data; +} + + +WRITE8_MEMBER( osborne1_state::osborne1_bankswitch_w ) +{ + switch( offset ) + { + case 0x00: + m_bank2_enabled = 1; + m_bank3_enabled = 0; + break; + case 0x01: + m_bank2_enabled = 0; + m_bank3_enabled = 0; + break; + case 0x02: + m_bank2_enabled = 1; + m_bank3_enabled = 1; + break; + case 0x03: + m_bank2_enabled = 1; + m_bank3_enabled = 0; + break; + } + if ( m_bank2_enabled ) + { + membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() ); + membank("bank2")->set_base(m_empty_4K ); + membank("bank3")->set_base(m_empty_4K ); + } + else + { + membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() ); + membank("bank2")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x1000 ); + membank("bank3")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x3000 ); + } + m_bank4_ptr = machine().device<ram_device>(RAM_TAG)->pointer() + ( ( m_bank3_enabled ) ? 0x10000 : 0xF000 ); + membank("bank4")->set_base(m_bank4_ptr ); + m_bankswitch = offset; + m_in_irq_handler = 0; +} + + +DIRECT_UPDATE_MEMBER(osborne1_state::osborne1_opbase) +{ + if ( ( address & 0xF000 ) == 0x2000 ) + { + if ( ! m_bank2_enabled ) + { + direct.explicit_configure(0x2000, 0x2fff, 0x0fff, machine().device<ram_device>(RAM_TAG)->pointer() + 0x2000); + return ~0; + } + } + return address; +} + + +WRITE_LINE_MEMBER( osborne1_state::ieee_pia_irq_a_func ) +{ + m_pia_0_irq_state = state; + cputag_set_input_line(machine(), "maincpu", 0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE); +} + + +READ8_MEMBER( osborne1_state::ieee_pia_pb_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 EOI + 4 + 5 DAV + 6 NDAC + 7 NRFD + + */ + + UINT8 data = 0; + + data |= m_ieee->eoi_r() << 3; + data |= m_ieee->dav_r() << 5; + data |= m_ieee->ndac_r() << 6; + data |= m_ieee->nrfd_r() << 7; + + return data; +} + + +WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 EOI + 4 ATN + 5 DAV + 6 NDAC + 7 NRFD + + */ + + m_ieee->eoi_w(BIT(data, 3)); + m_ieee->atn_w(BIT(data, 4)); + m_ieee->dav_w(BIT(data, 5)); + m_ieee->ndac_w(BIT(data, 6)); + m_ieee->nrfd_w(BIT(data, 7)); +} + + +const pia6821_interface osborne1_ieee_pia_config = +{ + DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r), /* in_a_func */ + DEVCB_DRIVER_MEMBER(osborne1_state, ieee_pia_pb_r), /* in_b_func */ + DEVCB_NULL, /* in_ca1_func */ + DEVCB_NULL, /* in_cb1_func */ + DEVCB_NULL, /* in_ca2_func */ + DEVCB_NULL, /* in_cb2_func */ + DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w), /* out_a_func */ + DEVCB_DRIVER_MEMBER(osborne1_state, ieee_pia_pb_w), /* out_b_func */ + DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, ifc_w), /* out_ca2_func */ + DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, ren_w), /* out_cb2_func */ + DEVCB_DRIVER_LINE_MEMBER(osborne1_state, ieee_pia_irq_a_func), /* irq_a_func */ + DEVCB_NULL /* irq_b_func */ +}; + + +WRITE8_MEMBER( osborne1_state::video_pia_out_cb2_dummy ) +{ +} + + +WRITE8_MEMBER( osborne1_state::video_pia_port_a_w ) +{ + wd17xx_dden_w(m_fdc, BIT(data, 0)); + + data -= 0xea; // remove bias + + m_new_start_x = (data >> 1); + if (m_new_start_x) + m_new_start_x--; + + //logerror("Video pia port a write: %02X, density set to %s\n", data, data & 1 ? "FM" : "MFM" ); +} + + +WRITE8_MEMBER( osborne1_state::video_pia_port_b_w ) +{ + m_new_start_y = data & 0x1F; + m_beep_state = BIT(data, 5); + + if (BIT(data, 6)) + wd17xx_set_drive( m_fdc, 0 ); + else + if (BIT(data, 7)) + wd17xx_set_drive( m_fdc, 1 ); + + //logerror("Video pia port b write: %02X\n", data ); +} + + +WRITE_LINE_MEMBER( osborne1_state::video_pia_irq_a_func ) +{ + m_pia_1_irq_state = state; + cputag_set_input_line(machine(), "maincpu", 0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE); +} + + +const pia6821_interface osborne1_video_pia_config = +{ + DEVCB_NULL, /* in_a_func */ + DEVCB_NULL, /* in_b_func */ + DEVCB_NULL, /* in_ca1_func */ + DEVCB_NULL, /* in_cb1_func */ + DEVCB_NULL, /* in_ca2_func */ + DEVCB_NULL, /* in_cb2_func */ + DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_port_a_w), /* out_a_func */ + DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_port_b_w), /* out_b_func */ + DEVCB_NULL, /* out_ca2_func */ + DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_out_cb2_dummy), /* out_cb2_func */ + DEVCB_DRIVER_LINE_MEMBER(osborne1_state, video_pia_irq_a_func), /* irq_a_func */ + DEVCB_NULL /* irq_b_func */ +}; + + +//static const struct aica6850_interface osborne1_6850_config = +//{ +// 10, /* tx_clock */ +// 10, /* rx_clock */ +// NULL, /* rx_pin */ +// NULL, /* tx_pin */ +// NULL, /* cts_pin */ +// NULL, /* rts_pin */ +// NULL, /* dcd_pin */ +// NULL /* int_callback */ +//}; + + +static TIMER_CALLBACK(osborne1_video_callback) +{ + osborne1_state *state = machine.driver_data<osborne1_state>(); + int y = machine.primary_screen->vpos(); + UINT8 ra=0,chr,gfx,dim; + UINT16 x,ma; + + /* Check for start of frame */ + if ( y == 0 ) + { + /* Clear CA1 on video PIA */ + state->m_pia1->ca1_w(0); + } + if ( y == 240 ) + { + /* Set CA1 on video PIA */ + state->m_pia1->ca1_w(1); + } + if ( y < 240 ) + { + ra = y % 10; + /* Draw a line of the display */ + ma = (state->m_new_start_y + (y/10)) * 128 + state->m_new_start_x; + UINT16 *p = &state->m_bitmap.pix16(y); + + for ( x = 0; x < 52; x++ ) + { + chr = machine.device<ram_device>(RAM_TAG)->pointer()[ 0xF000 + ( (ma+x) & 0xFFF ) ]; + dim = machine.device<ram_device>(RAM_TAG)->pointer()[ 0x10000 + ( (ma+x) & 0xFFF ) ] & 0x80; + + if ( (chr & 0x80) && (ra == 9) ) + gfx = 0xFF; + else + gfx = state->m_p_chargen[ (ra << 7) | ( chr & 0x7F ) ]; + + /* Display a scanline of a character */ + *p++ = BIT(gfx, 7) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 6) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 5) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 4) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 3) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 2) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 1) ? ( dim ? 1 : 2 ) : 0; + *p++ = BIT(gfx, 0) ? ( dim ? 1 : 2 ) : 0; + } + } + + if ( (ra==2) || (ra== 6) ) + { + beep_set_state( state->m_beep, state->m_beep_state ); + } + else + { + beep_set_state( state->m_beep, 0 ); + } + + state->m_video_timer->adjust(machine.primary_screen->time_until_pos(y + 1, 0 )); +} + +static TIMER_CALLBACK( setup_osborne1 ) +{ + osborne1_state *state = machine.driver_data<osborne1_state>(); + beep_set_state( state->m_beep, 0 ); + beep_set_frequency( state->m_beep, 300 /* 60 * 240 / 2 */ ); + state->m_pia1->ca1_w(0); +} + +static void osborne1_load_proc(device_image_interface &image) +{ + int size = image.length(); + osborne1_state *state = image.device().machine().driver_data<osborne1_state>(); + + switch( size ) + { + case 40 * 10 * 256: + wd17xx_dden_w(state->m_fdc, ASSERT_LINE); + break; + case 40 * 5 * 1024: + wd17xx_dden_w(state->m_fdc, CLEAR_LINE); + break; + case 40 * 8 * 512: + wd17xx_dden_w(state->m_fdc, ASSERT_LINE); + break; + case 40 * 18 * 128: + wd17xx_dden_w(state->m_fdc, ASSERT_LINE); + break; + case 40 * 9 * 512: + wd17xx_dden_w(state->m_fdc, CLEAR_LINE); + break; + } +} + +MACHINE_RESET( osborne1 ) +{ + osborne1_state *state = machine.driver_data<osborne1_state>(); + int drive; + address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM); + /* Initialize memory configuration */ + state->osborne1_bankswitch_w( *space, 0x00, 0 ); + + state->m_pia_0_irq_state = FALSE; + state->m_pia_1_irq_state = FALSE; + state->m_in_irq_handler = 0; + + state->m_p_chargen = state->memregion( "chargen" )->base(); + + memset( machine.device<ram_device>(RAM_TAG)->pointer() + 0x10000, 0xFF, 0x1000 ); + + for(drive=0;drive<2;drive++) + floppy_install_load_proc(floppy_get_device(machine, drive), osborne1_load_proc); + + space->set_direct_update_handler(direct_update_delegate(FUNC(osborne1_state::osborne1_opbase), state)); +} + + +DRIVER_INIT_MEMBER(osborne1_state,osborne1) +{ + + m_empty_4K = auto_alloc_array(machine(), UINT8, 0x1000 ); + memset( m_empty_4K, 0xFF, 0x1000 ); + + /* Configure the 6850 ACIA */ +// acia6850_config( 0, &osborne1_6850_config ); + m_video_timer = machine().scheduler().timer_alloc(FUNC(osborne1_video_callback)); + m_video_timer->adjust(machine().primary_screen->time_until_pos(1, 0 )); + + machine().scheduler().timer_set(attotime::zero, FUNC(setup_osborne1)); +} + + +void osborne1_state::video_start() +{ + machine().primary_screen->register_screen_bitmap(m_bitmap); +} + +UINT32 osborne1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + +/**************************************************************** + Osborne1 specific daisy chain code +****************************************************************/ + +const device_type OSBORNE1_DAISY = &device_creator<osborne1_daisy_device>; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z80ctc_device - constructor +//------------------------------------------------- +osborne1_daisy_device::osborne1_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OSBORNE1_DAISY, "Osborne 1 daisy", tag, owner, clock), + device_z80daisy_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void osborne1_daisy_device::device_start() +{ +} + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int osborne1_daisy_device::z80daisy_irq_state() +{ + osborne1_state *state = machine().driver_data<osborne1_state>(); + return ( state->m_pia_1_irq_state ? Z80_DAISY_INT : 0 ); +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int osborne1_daisy_device::z80daisy_irq_ack() +{ + osborne1_state *state = machine().driver_data<osborne1_state>(); + /* Enable ROM and I/O when IRQ is acknowledged */ + UINT8 old_bankswitch = state->m_bankswitch; + address_space* space = device().machine().device("maincpu")->memory().space(AS_PROGRAM); + + state->osborne1_bankswitch_w( *space, 0, 0 ); + state->m_bankswitch = old_bankswitch; + state->m_in_irq_handler = 1; + return 0xF8; +} + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void osborne1_daisy_device::z80daisy_irq_reti() +{ +} |