osborne1 improvements [Vas Crabb]

* Bank low 16k according to schematics, passes memory test
 * Correct vectoring of IEEE488 interrupt
 * Implement RESET key (generates NMI, F12 by default)
This commit is contained in:
Vas Crabb 2015-10-29 21:42:50 +11:00
parent 66768b1039
commit 314b8c650a
3 changed files with 246 additions and 363 deletions

View File

@ -37,10 +37,11 @@ used, and the value on the data bus is completley ignored.
02 - Set BIT 9 signal (map bank 3 into F000-FFFF) 02 - Set BIT 9 signal (map bank 3 into F000-FFFF)
03 - Clear BIT 9 signal (map bank 1/2 into F000-FFFF) 03 - Clear BIT 9 signal (map bank 1/2 into F000-FFFF)
Selecting between bank 1 and bank 2 is also affected by M1 and IRQACK
conditions using a set of three flipflops.
TODO: TODO:
- Implement ROM/IO bank selection properly
- Implement serial port - Implement serial port
- Implement reset key (generates NMI and affects bank selection)
- Verify frequency of the beep/audio alarm. - Verify frequency of the beep/audio alarm.
***************************************************************************/ ***************************************************************************/
@ -52,18 +53,23 @@ TODO:
static ADDRESS_MAP_START( osborne1_mem, AS_PROGRAM, 8, osborne1_state ) static ADDRESS_MAP_START( osborne1_mem, AS_PROGRAM, 8, osborne1_state )
AM_RANGE( 0x0000, 0x0FFF ) AM_READ_BANK("bank1") AM_WRITE( osborne1_0000_w ) AM_RANGE( 0x0000, 0x0FFF ) AM_READ_BANK("bank_0xxx") AM_WRITE(bank_0xxx_w)
AM_RANGE( 0x1000, 0x1FFF ) AM_READ_BANK("bank2") AM_WRITE( osborne1_1000_w ) AM_RANGE( 0x1000, 0x1FFF ) AM_READ_BANK("bank_1xxx") AM_WRITE(bank_1xxx_w)
AM_RANGE( 0x2000, 0x3FFF ) AM_READWRITE( osborne1_2000_r, osborne1_2000_w ) AM_RANGE( 0x2000, 0x3FFF ) AM_READWRITE(bank_2xxx_3xxx_r, bank_2xxx_3xxx_w)
AM_RANGE( 0x4000, 0xEFFF ) AM_RAM AM_RANGE( 0x4000, 0xEFFF ) AM_RAM
AM_RANGE( 0xF000, 0xFFFF ) AM_READ_BANK("bank3") AM_WRITE( osborne1_videoram_w ) AM_RANGE( 0xF000, 0xFFFF ) AM_READ_BANK("bank_fxxx") AM_WRITE(videoram_w)
ADDRESS_MAP_END
static ADDRESS_MAP_START( osborne1_op, AS_DECRYPTED_OPCODES, 8, osborne1_state )
AM_RANGE( 0x0000, 0xFFFF ) AM_READ(opcode_r)
ADDRESS_MAP_END ADDRESS_MAP_END
static ADDRESS_MAP_START( osborne1_io, AS_IO, 8, osborne1_state ) static ADDRESS_MAP_START( osborne1_io, AS_IO, 8, osborne1_state )
ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_UNMAP_HIGH
ADDRESS_MAP_GLOBAL_MASK(0xff) ADDRESS_MAP_GLOBAL_MASK(0xff)
AM_RANGE( 0x00, 0xff ) AM_WRITE( osborne1_bankswitch_w ) AM_RANGE( 0x00, 0xff ) AM_WRITE(bankswitch_w)
ADDRESS_MAP_END ADDRESS_MAP_END
@ -150,6 +156,16 @@ static INPUT_PORTS_START( osborne1 )
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("RESET")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RESET") PORT_CODE(KEYCODE_F12)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("CNF") PORT_START("CNF")
PORT_CONFNAME(0x01, 0x00, "Video Output") PORT_CONFNAME(0x01, 0x00, "Video Output")
PORT_CONFSETTING(0x00, "Standard") PORT_CONFSETTING(0x00, "Standard")
@ -157,14 +173,6 @@ static INPUT_PORTS_START( osborne1 )
INPUT_PORTS_END INPUT_PORTS_END
static const z80_daisy_config osborne1_daisy_chain[] =
{
/* { osborne1_z80_reset, osborne1_z80_irq_state, osborne1_z80_irq_ack, osborne1_z80_irq_reti, 0 }, */
{ "osborne1_daisy" },
{ NULL }
};
/* /*
* The Osborne-1 supports the following disc formats: * The Osborne-1 supports the following disc formats:
* - Osborne single density: 40 tracks, 10 sectors per track, 256-byte sectors (100 KByte) * - Osborne single density: 40 tracks, 10 sectors per track, 256-byte sectors (100 KByte)
@ -184,15 +192,15 @@ SLOT_INTERFACE_END
/* F4 Character Displayer */ /* F4 Character Displayer */
static const gfx_layout osborne1_charlayout = static const gfx_layout osborne1_charlayout =
{ {
8, 10, /* 8 x 10 characters */ 8, 10, // 8 x 10 characters
128, /* 128 characters */ 128, // 128 characters
1, /* 1 bits per pixel */ 1, // 1 bits per pixel
{ 0 }, /* no bitplanes */ { 0 }, // no bitplanes
/* x offsets */ // x offsets
{ 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 },
/* y offsets */ // y offsets
{ 0*128*8, 1*128*8, 2*128*8, 3*128*8, 4*128*8, 5*128*8, 6*128*8, 7*128*8, 8*128*8, 9*128*8 }, { 0*128*8, 1*128*8, 2*128*8, 3*128*8, 4*128*8, 5*128*8, 6*128*8, 7*128*8, 8*128*8, 9*128*8 },
8 /* every char takes 16 x 1 bytes */ 8 // every char takes 16 x 1 bytes
}; };
static GFXDECODE_START( osborne1 ) static GFXDECODE_START( osborne1 )
@ -203,10 +211,9 @@ GFXDECODE_END
static MACHINE_CONFIG_START( osborne1, osborne1_state ) static MACHINE_CONFIG_START( osborne1, osborne1_state )
MCFG_CPU_ADD("maincpu", Z80, MAIN_CLOCK/4) MCFG_CPU_ADD("maincpu", Z80, MAIN_CLOCK/4)
MCFG_CPU_PROGRAM_MAP(osborne1_mem) MCFG_CPU_PROGRAM_MAP(osborne1_mem)
MCFG_CPU_DECRYPTED_OPCODES_MAP(osborne1_op)
MCFG_CPU_IO_MAP(osborne1_io) MCFG_CPU_IO_MAP(osborne1_io)
MCFG_CPU_CONFIG( osborne1_daisy_chain ) MCFG_Z80_SET_IRQACK_CALLBACK(WRITELINE(osborne1_state, irqack_w))
MCFG_DEVICE_ADD( "osborne1_daisy", OSBORNE1_DAISY, 0 )
MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_UPDATE_DRIVER(osborne1_state, screen_update) MCFG_SCREEN_UPDATE_DRIVER(osborne1_state, screen_update)

View File

@ -11,7 +11,6 @@
#include "emu.h" #include "emu.h"
#include "cpu/z80/z80.h" #include "cpu/z80/z80.h"
#include "cpu/z80/z80daisy.h"
#include "sound/beep.h" #include "sound/beep.h"
#include "machine/6821pia.h" #include "machine/6821pia.h"
#include "machine/6850acia.h" #include "machine/6850acia.h"
@ -39,18 +38,19 @@ public:
m_ieee(*this, IEEE488_TAG), m_ieee(*this, IEEE488_TAG),
m_floppy0(*this, "mb8877:0:525ssdd"), m_floppy0(*this, "mb8877:0:525ssdd"),
m_floppy1(*this, "mb8877:1:525ssdd"), m_floppy1(*this, "mb8877:1:525ssdd"),
m_row0(*this, "ROW0"), m_keyb_row0(*this, "ROW0"),
m_row1(*this, "ROW1"), m_keyb_row1(*this, "ROW1"),
m_row2(*this, "ROW2"), m_keyb_row2(*this, "ROW2"),
m_row3(*this, "ROW3"), m_keyb_row3(*this, "ROW3"),
m_row4(*this, "ROW4"), m_keyb_row4(*this, "ROW4"),
m_row5(*this, "ROW5"), m_keyb_row5(*this, "ROW5"),
m_row6(*this, "ROW6"), m_keyb_row6(*this, "ROW6"),
m_row7(*this, "ROW7"), m_keyb_row7(*this, "ROW7"),
m_btn_reset(*this, "RESET"),
m_cnf(*this, "CNF"), m_cnf(*this, "CNF"),
m_bank1(*this, "bank1"), m_bank_0xxx(*this, "bank_0xxx"),
m_bank2(*this, "bank2"), m_bank_1xxx(*this, "bank_1xxx"),
m_bank3(*this, "bank3"), m_bank_fxxx(*this, "bank_fxxx"),
m_region_maincpu(*this, "maincpu") { } m_region_maincpu(*this, "maincpu") { }
virtual void video_start(); virtual void video_start();
@ -69,26 +69,24 @@ public:
required_device<floppy_image_device> m_floppy0; required_device<floppy_image_device> m_floppy0;
required_device<floppy_image_device> m_floppy1; required_device<floppy_image_device> m_floppy1;
DECLARE_WRITE8_MEMBER(osborne1_0000_w); DECLARE_WRITE8_MEMBER(bank_0xxx_w);
DECLARE_WRITE8_MEMBER(osborne1_1000_w); DECLARE_WRITE8_MEMBER(bank_1xxx_w);
DECLARE_READ8_MEMBER(osborne1_2000_r); DECLARE_READ8_MEMBER(bank_2xxx_3xxx_r);
DECLARE_WRITE8_MEMBER(osborne1_2000_w); DECLARE_WRITE8_MEMBER(bank_2xxx_3xxx_w);
DECLARE_WRITE8_MEMBER(osborne1_videoram_w); DECLARE_WRITE8_MEMBER(videoram_w);
DECLARE_WRITE8_MEMBER(osborne1_bankswitch_w); DECLARE_READ8_MEMBER(opcode_r);
DECLARE_WRITE_LINE_MEMBER(ieee_pia_irq_a_func); DECLARE_WRITE8_MEMBER(bankswitch_w);
DECLARE_WRITE_LINE_MEMBER(irqack_w);
DECLARE_READ8_MEMBER(ieee_pia_pb_r); DECLARE_READ8_MEMBER(ieee_pia_pb_r);
DECLARE_WRITE8_MEMBER(ieee_pia_pb_w); DECLARE_WRITE8_MEMBER(ieee_pia_pb_w);
DECLARE_WRITE_LINE_MEMBER(video_pia_out_cb2_dummy); DECLARE_WRITE_LINE_MEMBER(ieee_pia_irq_a_func);
DECLARE_WRITE8_MEMBER(video_pia_port_a_w); DECLARE_WRITE8_MEMBER(video_pia_port_a_w);
DECLARE_WRITE8_MEMBER(video_pia_port_b_w); DECLARE_WRITE8_MEMBER(video_pia_port_b_w);
DECLARE_WRITE_LINE_MEMBER(video_pia_out_cb2_dummy);
DECLARE_WRITE_LINE_MEMBER(video_pia_irq_a_func); DECLARE_WRITE_LINE_MEMBER(video_pia_irq_a_func);
DECLARE_DIRECT_UPDATE_MEMBER(osborne1_opbase);
bool m_bank2_enabled;
UINT8 m_bit_9;
/* IRQ states */
bool m_pia_0_irq_state;
bool m_pia_1_irq_state;
/* video related */ /* video related */
UINT8 m_screen_pac; UINT8 m_screen_pac;
UINT8 m_resolution; UINT8 m_resolution;
@ -97,9 +95,6 @@ public:
UINT8 m_new_start_y; UINT8 m_new_start_y;
emu_timer *m_video_timer; emu_timer *m_video_timer;
UINT8 *m_p_chargen; UINT8 *m_p_chargen;
/* bankswitch setting */
UINT8 m_bankswitch;
bool m_in_irq_handler;
bool m_beep_state; bool m_beep_state;
DECLARE_DRIVER_INIT(osborne1); DECLARE_DRIVER_INIT(osborne1);
virtual void machine_reset(); virtual void machine_reset();
@ -107,41 +102,35 @@ public:
TIMER_CALLBACK_MEMBER(setup_osborne1); TIMER_CALLBACK_MEMBER(setup_osborne1);
protected: protected:
required_ioport m_row0; required_ioport m_keyb_row0;
required_ioport m_row1; required_ioport m_keyb_row1;
required_ioport m_row2; required_ioport m_keyb_row2;
required_ioport m_row3; required_ioport m_keyb_row3;
required_ioport m_row4; required_ioport m_keyb_row4;
required_ioport m_row5; required_ioport m_keyb_row5;
required_ioport m_row6; required_ioport m_keyb_row6;
required_ioport m_row7; required_ioport m_keyb_row7;
required_ioport m_btn_reset;
required_ioport m_cnf; required_ioport m_cnf;
required_memory_bank m_bank1;
required_memory_bank m_bank2; required_memory_bank m_bank_0xxx;
required_memory_bank m_bank3; required_memory_bank m_bank_1xxx;
required_memory_bank m_bank_fxxx;
required_memory_region m_region_maincpu; required_memory_region m_region_maincpu;
// bank switch control bits
UINT8 m_ub4a_q;
UINT8 m_ub6a_q;
UINT8 m_rom_mode;
UINT8 m_bit_9;
bool set_rom_mode(UINT8 value);
bool set_bit_9(UINT8 value);
void update_irq();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
}; };
// ======================> osborne1_daisy_device
class osborne1_daisy_device : public device_t,
public device_z80daisy_interface
{
public:
// construction/destruction
osborne1_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
private:
virtual void device_start();
// z80daisy_interface overrides
virtual int z80daisy_irq_state();
virtual int z80daisy_irq_ack();
virtual void z80daisy_irq_reti();
};
extern const device_type OSBORNE1_DAISY;
#endif /* OSBORNE1_H_ */ #endif /* OSBORNE1_H_ */

View File

@ -3,80 +3,50 @@
/*************************************************************************** /***************************************************************************
There are three IRQ sources: There are three IRQ sources:
- IRQ0 - IRQ0 = IRQ from the serial ACIA
- IRQ1 = IRQA from the video PIA - IRQ1 = IRQA from the video PIA
- IRQ2 = IRQA from the IEEE488 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" #include "includes/osborne1.h"
#define RAMMODE (0x01)
WRITE8_MEMBER( osborne1_state::bank_0xxx_w )
WRITE8_MEMBER( osborne1_state::osborne1_0000_w )
{
/* Check whether regular RAM is enabled */
if ( !m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE) )
{ {
if (!m_rom_mode)
m_ram->pointer()[offset] = data; m_ram->pointer()[offset] = data;
} }
}
WRITE8_MEMBER( osborne1_state::bank_1xxx_w )
WRITE8_MEMBER( osborne1_state::osborne1_1000_w )
{
/* Check whether regular RAM is enabled */
if ( !m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE) )
{ {
if (!m_rom_mode)
m_ram->pointer()[0x1000 + offset] = data; m_ram->pointer()[0x1000 + offset] = data;
} }
}
READ8_MEMBER( osborne1_state::bank_2xxx_3xxx_r )
{
if (!m_rom_mode)
return m_ram->pointer()[0x2000 + offset];
READ8_MEMBER( osborne1_state::osborne1_2000_r )
{
UINT8 data = 0xFF;
/* Check whether regular RAM is enabled */
if ( !m_bank2_enabled )
{
data = m_ram->pointer()[ 0x2000 + offset ];
}
else
{
// This isn't really accurate - bus fighting will occur for many values // This isn't really accurate - bus fighting will occur for many values
// since each peripheral only checks two bits. We just return 0xFF for // since each peripheral only checks two bits. We just return 0xFF for
// any undocumented address. // any undocumented address.
UINT8 data = 0xFF;
switch (offset & 0x0F00) switch (offset & 0x0F00)
{ {
case 0x100: /* Floppy */ case 0x100: /* Floppy */
data = m_fdc->read(space, offset & 0x03); data = m_fdc->read(space, offset & 0x03);
break; break;
case 0x200: /* Keyboard */ case 0x200: /* Keyboard */
/* Row 0 */ if (offset & 0x01) data &= m_keyb_row0->read();
if ( offset & 0x01 ) data &= m_row0->read(); if (offset & 0x02) data &= m_keyb_row1->read();
/* Row 1 */ if (offset & 0x04) data &= m_keyb_row3->read();
if ( offset & 0x02 ) data &= m_row1->read(); if (offset & 0x08) data &= m_keyb_row4->read();
/* Row 2 */ if (offset & 0x10) data &= m_keyb_row5->read();
if ( offset & 0x04 ) data &= m_row3->read(); if (offset & 0x20) data &= m_keyb_row2->read();
/* Row 3 */ if (offset & 0x40) data &= m_keyb_row6->read();
if ( offset & 0x08 ) data &= m_row4->read(); if (offset & 0x80) data &= m_keyb_row7->read();
/* Row 4 */
if ( offset & 0x10 ) data &= m_row5->read();
/* Row 5 */
if ( offset & 0x20 ) data &= m_row2->read();
/* Row 6 */
if ( offset & 0x40 ) data &= m_row6->read();
/* Row 7 */
if ( offset & 0x80 ) data &= m_row7->read();
break; break;
case 0x400: /* SCREEN-PAC */ case 0x400: /* SCREEN-PAC */
if (m_screen_pac) data &= 0xFB; if (m_screen_pac) data &= 0xFB;
@ -90,142 +60,93 @@ READ8_MEMBER( osborne1_state::osborne1_2000_r )
data = m_pia1->read(space, offset & 0x03); data = m_pia1->read(space, offset & 0x03);
break; break;
} }
}
return data; return data;
} }
WRITE8_MEMBER( osborne1_state::bank_2xxx_3xxx_w )
WRITE8_MEMBER( osborne1_state::osborne1_2000_w )
{ {
#if 0 if (!m_rom_mode)
/* Check whether regular RAM is enabled */
if ( !m_bank2_enabled || (m_in_irq_handler && m_bankswitch == RAMMODE) )
{ {
m_ram->pointer()[0x2000 + offset] = data; m_ram->pointer()[0x2000 + offset] = data;
} }
else else
{ {
/* Handle writes to the I/O area */ // Handle writes to the I/O area
if ( 0x100 == (offset & 0x900) ) /* Floppy */ if ((offset & 0x900) == 0x100) // Floppy
m_fdc->write(space, offset & 0x03, data); m_fdc->write(space, offset & 0x03, data);
if ( 0x400 == (offset & 0xC00) ) /* SCREEN-PAC */ if ((offset & 0x900) == 0x900) // IEEE488 PIA
{
m_resolution = data & 0x01;
m_hc_left = (data >> 1) & 0x01;
}
if ( 0x900 == (offset & 0x900) ) /* IEEE488 PIA */
m_pia0->write(space, offset & 0x03, data); m_pia0->write(space, offset & 0x03, data);
if ( 0xA00 == (offset & 0xA00) ) /* Serial */ if ((offset & 0xA00) == 0xA00) // Serial
/* not implemented */; /* not implemented */;
if ( 0xC00 == (offset & 0xC00) ) /* Video PIA */ if ((offset & 0xC00) == 0x400) // SCREEN-PAC
m_pia1->write(space, offset & 0x03, data);
}
#else
// This code is a nasty hack that doesn't reflect hardware operation,
// but it gets us by while the bank selection implementation is inadequate
if ( ! m_bank2_enabled )
{ {
m_ram->pointer()[ 0x2000 + offset ] = data;
}
else
{
if ( m_in_irq_handler && m_bankswitch == RAMMODE )
{
m_ram->pointer()[ 0x2000 + offset ] = data;
}
/* Handle writes to the I/O area */
switch( offset & 0x1F00 )
{
case 0x100: /* Floppy */
m_fdc->write(space, offset & 0x03, data);
break;
case 0x400: /* SCREEN-PAC */
m_resolution = data & 0x01; m_resolution = data & 0x01;
m_hc_left = (data >> 1) & 0x01; m_hc_left = (data >> 1) & 0x01;
break; }
case 0x900: /* IEEE488 PIA */ if ((offset & 0xC00) == 0xC00) // Video PIA
m_pia0->write(space, offset & 0x03, data );
break;
case 0xA00: /* Serial */
break;
case 0xC00: /* Video PIA */
m_pia1->write(space, offset & 0x03, data); m_pia1->write(space, offset & 0x03, data);
break;
} }
} }
#endif
}
WRITE8_MEMBER( osborne1_state::videoram_w )
WRITE8_MEMBER( osborne1_state::osborne1_videoram_w )
{ {
/* Check whether the video attribute section is enabled */ // Attribute RAM is only one bit wide - low seven bits are discarded and read back high
if ( m_bit_9 ) if (m_bit_9) data |= 0x7F;
data |= 0x7F; reinterpret_cast<UINT8 *>(m_bank_fxxx->base())[offset] = data;
reinterpret_cast<UINT8 *>(m_bank3->base())[offset] = data;
} }
READ8_MEMBER( osborne1_state::opcode_r )
{
// Update the flipflops that control bank selection and NMI
UINT8 const new_ub6a_q = (m_btn_reset->read() & 0x80) ? 1 : 0;
if (!m_rom_mode)
{
set_rom_mode(m_ub4a_q ? 0 : 1);
m_ub4a_q = m_ub6a_q;
}
m_ub6a_q = new_ub6a_q;
m_maincpu->set_input_line(INPUT_LINE_NMI, m_ub6a_q ? CLEAR_LINE : ASSERT_LINE);
WRITE8_MEMBER( osborne1_state::osborne1_bankswitch_w ) // Now that's sorted out we can call the normal read handler
return m_maincpu->space(AS_PROGRAM).read_byte(offset);
}
WRITE8_MEMBER( osborne1_state::bankswitch_w )
{ {
switch (offset & 0x03) switch (offset & 0x03)
{ {
case 0x00: case 0x00:
m_bank2_enabled = 1; if (set_rom_mode(1))
m_bankswitch = 0x00; m_ub4a_q = m_ub6a_q;
break; break;
case 0x01: case 0x01:
m_bank2_enabled = 0; m_ub4a_q = 1;
m_bankswitch = 0x01; m_ub6a_q = 1;
set_rom_mode(0);
m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
break; break;
case 0x02: case 0x02:
m_bit_9 = 1; set_bit_9(1);
break; break;
case 0x03: case 0x03:
m_bit_9 = 0; set_bit_9(0);
break; break;
} }
if ( m_bank2_enabled )
{
m_bank1->set_base(m_region_maincpu->base());
m_bank2->set_base(m_region_maincpu->base());
}
else
{
m_bank1->set_base(m_ram->pointer());
m_bank2->set_base(m_ram->pointer() + 0x1000);
}
m_bank3->set_base(m_ram->pointer() + (m_bit_9 ? 0x10000 : 0xF000));
m_in_irq_handler = 0;
} }
WRITE_LINE_MEMBER( osborne1_state::irqack_w )
DIRECT_UPDATE_MEMBER(osborne1_state::osborne1_opbase)
{ {
if ( ( address & 0xF000 ) == 0x2000 ) // Update the flipflops that control bank selection and NMI
{ if (!m_rom_mode) set_rom_mode(m_ub4a_q ? 0 : 1);
if ( ! m_bank2_enabled ) m_ub4a_q = 0;
{ m_ub6a_q = (m_btn_reset->read() & 0x80) ? 1 : 0;
direct.explicit_configure(0x2000, 0x2fff, 0x0fff, m_ram->pointer() + 0x2000); m_maincpu->set_input_line(INPUT_LINE_NMI, m_ub6a_q ? CLEAR_LINE : ASSERT_LINE);
return ~0;
}
}
return address;
}
WRITE_LINE_MEMBER( osborne1_state::ieee_pia_irq_a_func )
{
m_pia_0_irq_state = state;
m_maincpu->set_input_line(0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE);
} }
READ8_MEMBER( osborne1_state::ieee_pia_pb_r ) READ8_MEMBER( osborne1_state::ieee_pia_pb_r )
{ {
/* /*
bit description bit description
0 0
@ -236,9 +157,7 @@ READ8_MEMBER( osborne1_state::ieee_pia_pb_r )
5 DAV 5 DAV
6 NDAC 6 NDAC
7 NRFD 7 NRFD
*/ */
UINT8 data = 0; UINT8 data = 0;
data |= m_ieee->eoi_r() << 3; data |= m_ieee->eoi_r() << 3;
@ -249,11 +168,9 @@ READ8_MEMBER( osborne1_state::ieee_pia_pb_r )
return data; return data;
} }
WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w ) WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w )
{ {
/* /*
bit description bit description
0 0
@ -264,9 +181,7 @@ WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w )
5 DAV 5 DAV
6 NDAC 6 NDAC
7 NRFD 7 NRFD
*/ */
m_ieee->eoi_w(BIT(data, 3)); m_ieee->eoi_w(BIT(data, 3));
m_ieee->atn_w(BIT(data, 4)); m_ieee->atn_w(BIT(data, 4));
m_ieee->dav_w(BIT(data, 5)); m_ieee->dav_w(BIT(data, 5));
@ -274,12 +189,16 @@ WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w )
m_ieee->nrfd_w(BIT(data, 7)); m_ieee->nrfd_w(BIT(data, 7));
} }
WRITE_LINE_MEMBER( osborne1_state::ieee_pia_irq_a_func )
{
update_irq();
}
WRITE_LINE_MEMBER( osborne1_state::video_pia_out_cb2_dummy ) WRITE_LINE_MEMBER( osborne1_state::video_pia_out_cb2_dummy )
{ {
} }
WRITE8_MEMBER( osborne1_state::video_pia_port_a_w ) WRITE8_MEMBER( osborne1_state::video_pia_port_a_w )
{ {
m_fdc->dden_w(BIT(data, 0)); m_fdc->dden_w(BIT(data, 0));
@ -293,7 +212,6 @@ WRITE8_MEMBER( osborne1_state::video_pia_port_a_w )
//logerror("Video pia port a write: %02X, density set to %s\n", data, data & 1 ? "FM" : "MFM" ); //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 ) WRITE8_MEMBER( osborne1_state::video_pia_port_b_w )
{ {
m_new_start_y = data & 0x1F; m_new_start_y = data & 0x1F;
@ -317,11 +235,9 @@ WRITE8_MEMBER( osborne1_state::video_pia_port_b_w )
//logerror("Video pia port b write: %02X\n", data ); //logerror("Video pia port b write: %02X\n", data );
} }
WRITE_LINE_MEMBER( osborne1_state::video_pia_irq_a_func ) WRITE_LINE_MEMBER( osborne1_state::video_pia_irq_a_func )
{ {
m_pia_1_irq_state = state; update_irq();
m_maincpu->set_input_line(0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE);
} }
@ -359,21 +275,16 @@ TIMER_CALLBACK_MEMBER(osborne1_state::osborne1_video_callback)
int const y = machine().first_screen()->vpos(); int const y = machine().first_screen()->vpos();
UINT8 ra = 0; UINT8 ra = 0;
/* Check for start of frame */ // Check for start/end of visible area and clear/set CA1 on video PIA
if (y == 0) if (y == 0)
{
/* Clear CA1 on video PIA */
m_pia1->ca1_w(0); m_pia1->ca1_w(0);
} else if (y == 240)
if ( y == 240 )
{
/* Set CA1 on video PIA */
m_pia1->ca1_w(1); m_pia1->ca1_w(1);
}
if (y < 240) if (y < 240)
{ {
ra = y % 10; ra = y % 10;
/* Draw a line of the display */ // Draw a line of the display
bool const hires = m_screen_pac & m_resolution; bool const hires = m_screen_pac & m_resolution;
UINT16 const row = (m_new_start_y + (y/10)) * 128 & 0xF80; UINT16 const row = (m_new_start_y + (y/10)) * 128 & 0xF80;
UINT16 const col = (m_new_start_x & (hires ? 0x60 : 0x7F)) - ((hires && m_hc_left) ? 8 : 0); UINT16 const col = (m_new_start_x & (hires ? 0x60 : 0x7F)) - ((hires && m_hc_left) ? 8 : 0);
@ -387,7 +298,7 @@ TIMER_CALLBACK_MEMBER(osborne1_state::osborne1_video_callback)
UINT8 const gfx = ((chr & 0x80) && (ra == 9)) ? 0xFF : m_p_chargen[(ra << 7) | (chr & 0x7F)]; UINT8 const gfx = ((chr & 0x80) && (ra == 9)) ? 0xFF : m_p_chargen[(ra << 7) | (chr & 0x7F)];
/* Display a scanline of a character */ // Display a scanline of a character
*p++ = BIT(gfx, 7) ? ( dim ? 2 : 1 ) : 0; *p++ = BIT(gfx, 7) ? ( dim ? 2 : 1 ) : 0;
if (!hires) { p[0] = p[-1]; p++; } if (!hires) { p[0] = p[-1]; p++; }
*p++ = BIT(gfx, 6) ? ( dim ? 2 : 1 ) : 0; *p++ = BIT(gfx, 6) ? ( dim ? 2 : 1 ) : 0;
@ -408,13 +319,13 @@ TIMER_CALLBACK_MEMBER(osborne1_state::osborne1_video_callback)
} }
if ((ra == 2) || (ra == 6)) if ((ra == 2) || (ra == 6))
{
m_beep->set_state(m_beep_state); m_beep->set_state(m_beep_state);
}
else else
{
m_beep->set_state(0); m_beep->set_state(0);
}
// Check reset key if necessary - it affects NMI
if (!m_ub6a_q)
m_maincpu->set_input_line(INPUT_LINE_NMI, (m_btn_reset->read() && 0x80) ? CLEAR_LINE : ASSERT_LINE);
m_video_timer->adjust(machine().first_screen()->time_until_pos(y + 1, 0)); m_video_timer->adjust(machine().first_screen()->time_until_pos(y + 1, 0));
} }
@ -428,12 +339,11 @@ TIMER_CALLBACK_MEMBER(osborne1_state::setup_osborne1)
void osborne1_state::machine_reset() void osborne1_state::machine_reset()
{ {
/* Initialize memory configuration */ // Initialize memory configuration
osborne1_bankswitch_w( m_maincpu->space(AS_IO), 0x00, 0 ); m_rom_mode = 0;
m_bit_9 = 1;
m_pia_0_irq_state = FALSE; set_rom_mode(1);
m_pia_1_irq_state = FALSE; set_bit_9(0);
m_in_irq_handler = 0;
m_screen_pac = 0 != (m_cnf->read() & 0x01); m_screen_pac = 0 != (m_cnf->read() & 0x01);
m_resolution = 0; m_resolution = 0;
@ -441,9 +351,6 @@ void osborne1_state::machine_reset()
m_p_chargen = memregion( "chargen" )->base(); m_p_chargen = memregion( "chargen" )->base();
memset(m_ram->pointer() + 0x10000, 0xFF, 0x1000); memset(m_ram->pointer() + 0x10000, 0xFF, 0x1000);
address_space& space = m_maincpu->space(AS_PROGRAM);
space.set_direct_update_handler(direct_update_delegate(FUNC(osborne1_state::osborne1_opbase), this));
} }
@ -463,77 +370,57 @@ void osborne1_state::video_start()
machine().first_screen()->register_screen_bitmap(m_bitmap); machine().first_screen()->register_screen_bitmap(m_bitmap);
} }
UINT32 osborne1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) UINT32 osborne1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{ {
copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
return 0; return 0;
} }
/****************************************************************
Osborne1 specific daisy chain code
****************************************************************/
const device_type OSBORNE1_DAISY = &device_creator<osborne1_daisy_device>; bool osborne1_state::set_rom_mode(UINT8 value)
//**************************************************************************
// 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, "osborne1_daisy", __FILE__),
device_z80daisy_interface(mconfig, *this)
{ {
if (value != m_rom_mode)
{
m_rom_mode = value;
if (m_rom_mode)
{
m_bank_0xxx->set_base(m_region_maincpu->base());
m_bank_1xxx->set_base(m_region_maincpu->base());
}
else
{
m_bank_0xxx->set_base(m_ram->pointer());
m_bank_1xxx->set_base(m_ram->pointer() + 0x1000);
}
return true;
}
else
{
return false;
}
} }
//------------------------------------------------- bool osborne1_state::set_bit_9(UINT8 value)
// device_start - device-specific startup
//-------------------------------------------------
void osborne1_daisy_device::device_start()
{ {
if (value != m_bit_9)
{
m_bit_9 = value;
m_bank_fxxx->set_base(m_ram->pointer() + (m_bit_9 ? 0x10000 : 0xF000));
return true;
}
else
{
return false;
}
} }
//************************************************************************** void osborne1_state::update_irq()
// 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;
state->osborne1_bankswitch_w( state->m_maincpu->space(AS_IO), 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()
{ {
if (m_pia0->irq_a_state())
m_maincpu->set_input_line_and_vector(INPUT_LINE_IRQ0, ASSERT_LINE, 0xF0);
else if (m_pia1->irq_a_state())
m_maincpu->set_input_line_and_vector(INPUT_LINE_IRQ0, ASSERT_LINE, 0xF8);
else
m_maincpu->set_input_line_and_vector(INPUT_LINE_IRQ0, CLEAR_LINE, 0xFE);
} }