// license:BSD-3-Clause
// copyright-holders:Curt Coder
/***************************************************************************
Sage II
For memory map look at :
http://www.thebattles.net/sage/img/SDT.pdf (pages 14-)
06/12/2009 Skeleton driver.
****************************************************************************/
/*
TODO:
- floppy loading
- TMS9914 IEEE-488 controller
- board 2 (4x 2651 USART)
- Winchester controller
*/
#include "includes/sage2.h"
#include "bus/rs232/rs232.h"
//**************************************************************************
// MEMORY MANAGEMENT UNIT
//**************************************************************************
//-------------------------------------------------
// read -
//-------------------------------------------------
READ8_MEMBER( sage2_state::read )
{
UINT8 data = 0xff;
if (m_reset || (offset >= 0xfe0000 && offset < 0xff4000))
{
data = m_rom[offset & 0x1fff];
}
else if (offset < 0x080000)
{
data = m_ram->pointer()[offset];
}
return data;
}
//-------------------------------------------------
// write -
//-------------------------------------------------
WRITE8_MEMBER( sage2_state::write )
{
if (offset < 0x080000)
{
m_ram->pointer()[offset] = data;
}
}
//**************************************************************************
// ADDRESS MAPS
//**************************************************************************
//-------------------------------------------------
// ADDRESS_MAP( sage2_mem )
//-------------------------------------------------
static ADDRESS_MAP_START( sage2_mem, AS_PROGRAM, 16, sage2_state )
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x000000, 0xfeffff) AM_READWRITE8(read, write, 0xffff)
AM_RANGE(0xffc000, 0xffc007) AM_DEVREADWRITE8(I8253_1_TAG, pit8253_device, read, write, 0x00ff)
AM_RANGE(0xffc010, 0xffc01f) AM_NOP //AM_DEVREADWRITE8(TMS9914_TAG, tms9914_device, read, write, 0x00ff)
AM_RANGE(0xffc020, 0xffc027) AM_DEVREADWRITE8(I8255A_0_TAG, i8255_device, read, write, 0x00ff) // i8255, DIPs + Floppy ctrl port
AM_RANGE(0xffc030, 0xffc031) AM_DEVREADWRITE8(I8251_1_TAG, i8251_device, data_r, data_w, 0x00ff)
AM_RANGE(0xffc032, 0xffc033) AM_DEVREADWRITE8(I8251_1_TAG, i8251_device, status_r, control_w, 0x00ff)
AM_RANGE(0xffc040, 0xffc043) AM_DEVREADWRITE8(I8259_TAG, pic8259_device, read, write, 0x00ff)
AM_RANGE(0xffc050, 0xffc053) AM_DEVICE8(UPD765_TAG, upd765a_device, map, 0x00ff)
AM_RANGE(0xffc060, 0xffc067) AM_DEVREADWRITE8(I8255A_1_TAG, i8255_device, read, write, 0x00ff) // i8255, Printer
AM_RANGE(0xffc070, 0xffc071) AM_DEVREADWRITE8(I8251_0_TAG, i8251_device, data_r, data_w, 0x00ff)
AM_RANGE(0xffc072, 0xffc073) AM_DEVREADWRITE8(I8251_0_TAG, i8251_device, status_r, control_w, 0x00ff)
AM_RANGE(0xffc080, 0xffc087) AM_MIRROR(0x78) AM_DEVREADWRITE8(I8253_0_TAG, pit8253_device, read, write, 0x00ff)
// AM_RANGE(0xffc400, 0xffc407) AM_DEVREADWRITE8(S2651_0_TAG, s2651_device, read, write, 0x00ff)
// AM_RANGE(0xffc440, 0xffc447) AM_DEVREADWRITE8(S2651_1_TAG, s2651_device, read, write, 0x00ff)
// AM_RANGE(0xffc480, 0xffc487) AM_DEVREADWRITE8(S2651_2_TAG, s2651_device, read, write, 0x00ff)
// AM_RANGE(0xffc4c0, 0xffc4c7) AM_DEVREADWRITE8(S2651_3_TAG, s2651_device, read, write, 0x00ff)
// AM_RANGE(0xffc500, 0xffc7ff) // Winchester drive ports
ADDRESS_MAP_END
//**************************************************************************
// INPUT PORTS
//**************************************************************************
//-------------------------------------------------
// INPUT_PORTS( sage2 )
//-------------------------------------------------
static INPUT_PORTS_START( sage2 )
PORT_START("J7")
PORT_DIPNAME( 0x07, 0x07, "Terminal Baud Rate" ) PORT_DIPLOCATION("J7:1,2,3")
PORT_DIPSETTING( 0x07, "19200" )
PORT_DIPSETTING( 0x06, "9600" )
PORT_DIPSETTING( 0x05, "4800" )
PORT_DIPSETTING( 0x04, "2400" )
PORT_DIPSETTING( 0x03, "1200" )
PORT_DIPSETTING( 0x02, "600" )
PORT_DIPSETTING( 0x01, "300" )
PORT_DIPSETTING( 0x00, "Reserved (19200)" )
PORT_DIPNAME( 0x08, 0x08, "Parity Control" ) PORT_DIPLOCATION("J7:4")
PORT_DIPSETTING( 0x08, "Even Parity" )
PORT_DIPSETTING( 0x00, "Disabled" )
PORT_DIPNAME( 0x30, 0x20, "Boot Device" ) PORT_DIPLOCATION("J7:5,6")
PORT_DIPSETTING( 0x30, "Debugger" )
PORT_DIPSETTING( 0x20, "Floppy Drive 0" )
PORT_DIPSETTING( 0x10, "Winchester" )
PORT_DIPSETTING( 0x00, "Reserved (Debugger)" )
PORT_DIPNAME( 0x40, 0x40, "Floppy Configuration" ) PORT_DIPLOCATION("J7:7")
PORT_DIPSETTING( 0x40, "96 TPI" )
PORT_DIPSETTING( 0x00, "48 TPI" )
PORT_DIPNAME( 0x80, 0x80, DEF_STR( Service_Mode ) ) PORT_DIPLOCATION("J7:8")
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_START("J6")
PORT_DIPNAME( 0x1f, 0x07, "IEEE-488 Bus Address" ) PORT_DIPLOCATION("J6:1,2,3,4,5")
PORT_DIPSETTING( 0x00, "0" )
PORT_DIPSETTING( 0x01, "1" )
PORT_DIPSETTING( 0x02, "2" )
PORT_DIPSETTING( 0x03, "3" )
PORT_DIPSETTING( 0x04, "4" )
PORT_DIPSETTING( 0x05, "5" )
PORT_DIPSETTING( 0x06, "6" )
PORT_DIPSETTING( 0x07, "7" )
PORT_DIPSETTING( 0x08, "8" )
PORT_DIPSETTING( 0x09, "9" )
PORT_DIPSETTING( 0x0a, "10" )
PORT_DIPSETTING( 0x0b, "11" )
PORT_DIPSETTING( 0x0c, "12" )
PORT_DIPSETTING( 0x0d, "13" )
PORT_DIPSETTING( 0x0e, "14" )
PORT_DIPSETTING( 0x0f, "15" )
PORT_DIPSETTING( 0x10, "16" )
PORT_DIPSETTING( 0x11, "17" )
PORT_DIPSETTING( 0x12, "18" )
PORT_DIPSETTING( 0x13, "19" )
PORT_DIPSETTING( 0x14, "20" )
PORT_DIPSETTING( 0x15, "21" )
PORT_DIPSETTING( 0x16, "22" )
PORT_DIPSETTING( 0x17, "23" )
PORT_DIPSETTING( 0x18, "24" )
PORT_DIPSETTING( 0x19, "25" )
PORT_DIPSETTING( 0x1a, "26" )
PORT_DIPSETTING( 0x1b, "27" )
PORT_DIPSETTING( 0x1c, "28" )
PORT_DIPSETTING( 0x1d, "29" )
PORT_DIPSETTING( 0x1e, "30" )
PORT_DIPSETTING( 0x1f, "31" )
PORT_DIPNAME( 0x20, 0x00, "IEEE-488 TALK" ) PORT_DIPLOCATION("J6:6")
PORT_DIPSETTING( 0x00, "Disabled" )
PORT_DIPSETTING( 0x20, "Enabled" )
PORT_DIPNAME( 0x40, 0x00, "IEEE-488 LISTEN" ) PORT_DIPLOCATION("J6:7")
PORT_DIPSETTING( 0x00, "Disabled" )
PORT_DIPSETTING( 0x40, "Enabled" )
PORT_DIPNAME( 0x80, 0x00, "IEEE-488 Consecutive Adresses" ) PORT_DIPLOCATION("J6:8")
PORT_DIPSETTING( 0x00, "1" )
PORT_DIPSETTING( 0x80, "2" )
INPUT_PORTS_END
//**************************************************************************
// DEVICE CONFIGURATION
//**************************************************************************
//-------------------------------------------------
// I8255A INTERFACE( ppi0_intf )
//-------------------------------------------------
/*
IR0 U74 OUT2
IR1 RX2I+
IR2 TX1I+
IR3 TX2I+
IR4 MI-
IR5 CNI+
IR6 U74 OUT0
IR7 SI+
*/
//-------------------------------------------------
// I8255A INTERFACE( ppi0_intf )
//-------------------------------------------------
WRITE8_MEMBER( sage2_state::ppi0_pc_w )
{
/*
bit signal
PC0 TC+
PC1 RDY+
PC2 FDIE+
PC3 SL0-
PC4 SL1-
PC5 MOT-
PC6 PCRMP-
PC7 FRES+
*/
// floppy terminal count
m_fdc->tc_w(BIT(data, 0));
// floppy ready
m_fdc->ready_w(BIT(data, 1));
// floppy interrupt enable
m_fdie = BIT(data, 2);
update_fdc_int();
// drive select
m_floppy = NULL;
if (!BIT(data, 3)) m_floppy = m_floppy0->get_device();
if (!BIT(data, 4)) m_floppy = m_floppy1->get_device();
m_fdc->set_floppy(m_floppy);
// floppy motor
if (m_floppy) m_floppy->mon_w(BIT(data, 5));
// FDC reset
if(BIT(data, 7)) m_fdc->reset();
}
//-------------------------------------------------
// I8255A INTERFACE( ppi1_intf )
//-------------------------------------------------
WRITE_LINE_MEMBER(sage2_state::write_centronics_ack)
{
if (!state)
{
m_pic->ir5_w(ASSERT_LINE);
}
}
WRITE_LINE_MEMBER(sage2_state::write_centronics_busy)
{
m_centronics_busy = state;
}
WRITE_LINE_MEMBER(sage2_state::write_centronics_perror)
{
m_centronics_perror = state;
}
WRITE_LINE_MEMBER(sage2_state::write_centronics_select)
{
m_centronics_select = state;
}
WRITE_LINE_MEMBER(sage2_state::write_centronics_fault)
{
m_centronics_fault = state;
}
READ8_MEMBER( sage2_state::ppi1_pb_r )
{
/*
bit signal
PB0 FDI+
PB1 WP+
PB2 RG-
PB3 CD-
PB4 BUSY
PB5 PAPER
PB6 SEL
PB7 FAULT-
*/
UINT8 data = 0;
// floppy interrupt
data = m_fdc->get_irq();
// floppy write protected
data = (m_floppy ? m_floppy->wpt_r() : 1) << 1;
// RS-232 ring indicator
// RS-232 carrier detect
// centronics
data |= m_centronics_busy << 4;
data |= m_centronics_perror << 5;
data |= m_centronics_select << 6;
data |= m_centronics_fault << 7;
return data;
}
WRITE8_MEMBER( sage2_state::ppi1_pc_w )
{
/*
bit signal
PC0 PRES-
PC1 U8 SC+
PC2 SI+
PC3 LEDR+
PC4 STROBE-
PC5 PRIME-
PC6 U38 CL-
PC7 RMI-
*/
if (!BIT(data, 0))
{
// clear parity error interrupt
m_maincpu->set_input_line(M68K_IRQ_7, CLEAR_LINE);
}
// s? interrupt
m_pic->ir7_w(BIT(data, 2));
// processor LED
output_set_led_value(0, BIT(data, 3));
// centronics
m_centronics->write_strobe(BIT(data, 4));
m_centronics->write_init(BIT(data, 5));
if (!BIT(data, 6))
{
// clear ACK interrupt
m_pic->ir5_w(CLEAR_LINE);
}
if (!BIT(data, 7))
{
// clear modem interrupt
m_pic->ir4_w(CLEAR_LINE);
}
}
WRITE_LINE_MEMBER( sage2_state::br1_w )
{
m_usart0->write_txc(state);
m_usart0->write_rxc(state);
}
WRITE_LINE_MEMBER( sage2_state::br2_w )
{
m_usart1->write_txc(state);
m_usart1->write_rxc(state);
}
//-------------------------------------------------
// upd765_interface fdc_intf
//-------------------------------------------------
static SLOT_INTERFACE_START( sage2_floppies )
SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) // Mitsubishi M4859
SLOT_INTERFACE_END
void sage2_state::update_fdc_int()
{
m_maincpu->set_input_line(M68K_IRQ_6, m_fdie && m_fdc_int);
}
WRITE_LINE_MEMBER( sage2_state::fdc_irq )
{
m_fdc_int = state;
update_fdc_int();
}
static DEVICE_INPUT_DEFAULTS_START( terminal )
DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_19200 )
DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_19200 )
DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 )
DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_7 )
DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_EVEN )
DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 )
DEVICE_INPUT_DEFAULTS_END
//**************************************************************************
// MACHINE INITIALIZATION
//**************************************************************************
//-------------------------------------------------
// MACHINE_START( sage2 )
//-------------------------------------------------
void sage2_state::machine_start()
{
// find memory regions
m_rom = memregion(M68000_TAG)->base();
}
void sage2_state::machine_reset()
{
m_reset = 1;
}
//**************************************************************************
// MACHINE DRIVERS
//**************************************************************************
//-------------------------------------------------
// MACHINE_CONFIG( sage2 )
//-------------------------------------------------
static MACHINE_CONFIG_START( sage2, sage2_state )
// basic machine hardware
MCFG_CPU_ADD(M68000_TAG, M68000, XTAL_16MHz/2)
MCFG_CPU_PROGRAM_MAP(sage2_mem)
// devices
MCFG_PIC8259_ADD(I8259_TAG, INPUTLINE(M68000_TAG, M68K_IRQ_1), VCC, NULL)
MCFG_DEVICE_ADD(I8255A_0_TAG, I8255A, 0)
MCFG_I8255_IN_PORTA_CB(IOPORT("J7"))
MCFG_I8255_IN_PORTB_CB(IOPORT("J6"))
MCFG_I8255_OUT_PORTC_CB(WRITE8(sage2_state, ppi0_pc_w))
MCFG_DEVICE_ADD(I8255A_1_TAG, I8255A, 0)
MCFG_I8255_OUT_PORTA_CB(DEVWRITE8("cent_data_out", output_latch_device, write))
MCFG_I8255_IN_PORTB_CB(READ8(sage2_state, ppi1_pb_r))
MCFG_I8255_OUT_PORTC_CB(WRITE8(sage2_state, ppi1_pc_w))
MCFG_DEVICE_ADD(I8253_0_TAG, PIT8253, 0)
MCFG_PIT8253_CLK0(0) // from U75 OUT0
MCFG_PIT8253_OUT0_HANDLER(DEVWRITELINE(I8259_TAG, pic8259_device, ir6_w))
MCFG_PIT8253_CLK1(XTAL_16MHz/2/125)
MCFG_PIT8253_OUT1_HANDLER(DEVWRITELINE(I8253_0_TAG, pit8253_device, write_clk2))
MCFG_PIT8253_CLK2(0) // from OUT2
MCFG_PIT8253_OUT2_HANDLER(DEVWRITELINE(I8259_TAG, pic8259_device, ir0_w))
MCFG_DEVICE_ADD(I8253_1_TAG, PIT8253, 0)
MCFG_PIT8253_CLK0(XTAL_16MHz/2/125)
MCFG_PIT8253_OUT0_HANDLER(DEVWRITELINE(I8253_0_TAG, pit8253_device, write_clk0))
MCFG_PIT8253_CLK1(XTAL_16MHz/2/13)
MCFG_PIT8253_OUT1_HANDLER(WRITELINE(sage2_state, br1_w))
MCFG_PIT8253_CLK2(XTAL_16MHz/2/13)
MCFG_PIT8253_OUT2_HANDLER(WRITELINE(sage2_state, br2_w))
MCFG_DEVICE_ADD(I8251_0_TAG, I8251, 0)
MCFG_I8251_TXD_HANDLER(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_txd))
MCFG_I8251_DTR_HANDLER(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_dtr))
MCFG_I8251_RTS_HANDLER(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_rts))
MCFG_I8251_RXRDY_HANDLER(DEVWRITELINE(M68000_TAG, m68000_base_device, write_irq5))
MCFG_I8251_TXRDY_HANDLER(DEVWRITELINE(I8259_TAG, pic8259_device, ir2_w))
MCFG_RS232_PORT_ADD(RS232_A_TAG, default_rs232_devices, "terminal")
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(I8251_0_TAG, i8251_device, write_rxd))
MCFG_RS232_DSR_HANDLER(DEVWRITELINE(I8251_0_TAG, i8251_device, write_dsr))
MCFG_DEVICE_CARD_DEVICE_INPUT_DEFAULTS("terminal", terminal)
MCFG_DEVICE_ADD(I8251_1_TAG, I8251, 0)
MCFG_I8251_TXD_HANDLER(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_txd))
MCFG_I8251_DTR_HANDLER(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_dtr))
MCFG_I8251_RTS_HANDLER(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_rts))
MCFG_I8251_RXRDY_HANDLER(DEVWRITELINE(I8259_TAG, pic8259_device, ir1_w))
MCFG_I8251_TXRDY_HANDLER(DEVWRITELINE(I8259_TAG, pic8259_device, ir3_w))
MCFG_RS232_PORT_ADD(RS232_B_TAG, default_rs232_devices, NULL)
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(I8251_1_TAG, i8251_device, write_rxd))
MCFG_RS232_DSR_HANDLER(DEVWRITELINE(I8251_1_TAG, i8251_device, write_dsr))
MCFG_UPD765A_ADD(UPD765_TAG, false, false)
MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(sage2_state, fdc_irq))
MCFG_CENTRONICS_ADD("centronics", centronics_printers, "printer")
MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(sage2_state, write_centronics_ack))
MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(sage2_state, write_centronics_busy))
MCFG_CENTRONICS_PERROR_HANDLER(WRITELINE(sage2_state, write_centronics_perror))
MCFG_CENTRONICS_SELECT_HANDLER(WRITELINE(sage2_state, write_centronics_select))
MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE(sage2_state, write_centronics_fault))
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":0", sage2_floppies, "525qd", floppy_image_device::default_floppy_formats)
MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":1", sage2_floppies, "525qd", floppy_image_device::default_floppy_formats)
MCFG_IEEE488_BUS_ADD()
// internal ram
MCFG_RAM_ADD(RAM_TAG)
MCFG_RAM_DEFAULT_SIZE("512K")
// software list
MCFG_SOFTWARE_LIST_ADD("flop_list", "sage2")
MACHINE_CONFIG_END
//**************************************************************************
// ROMS
//**************************************************************************
//-------------------------------------------------
// ROM( sage2 )
//-------------------------------------------------
ROM_START( sage2 )
ROM_REGION( 0x2000, M68000_TAG, 0 )
ROM_LOAD16_BYTE( "sage2.u18", 0x0000, 0x1000, CRC(ca9b312d) SHA1(99436a6d166aa5280c3b2d28355c4d20528fe48c) )
ROM_LOAD16_BYTE( "sage2.u17", 0x0001, 0x1000, CRC(27e25045) SHA1(041cd9d4617473d089f31f18cbb375046c3b61bb) )
ROM_END
//**************************************************************************
// DRIVER INITIALIZATION
//**************************************************************************
//-------------------------------------------------
// DRIVER_INIT( sage2 )
//-------------------------------------------------
DIRECT_UPDATE_MEMBER(sage2_state::sage2_direct_update_handler)
{
if (m_reset && address >= 0xfe0000)
{
m_reset = 0;
}
return address;
}
DRIVER_INIT_MEMBER(sage2_state,sage2)
{
address_space &program = machine().device<cpu_device>(M68000_TAG)->space(AS_PROGRAM);
program.set_direct_update_handler(direct_update_delegate(FUNC(sage2_state::sage2_direct_update_handler), this));
}
//**************************************************************************
// SYSTEM DRIVERS
//**************************************************************************
// YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS
COMP( 1982, sage2, 0, 0, sage2, sage2, sage2_state, sage2, "Sage Technology", "Sage II", GAME_NOT_WORKING | GAME_NO_SOUND )