// license:BSD-3-Clause // copyright-holders:Nigel Barnes,Ryan Holtz /*************************************************************************** Intel SBC 80/10 and SBC 80/10A Single Board Computers The difference between the SBC 80/10 and SBC 80/10A is in the type and quantity of memory available on each board. There is no speaker or storage facility in the standard kit. Download the User Manual to get the operating procedures. Monitor Commands: D Display memory command G Program execute command I Insert instructions into memory M Move memory command R Read hexadecimal file S Substitute memory command W Write hexadecimal file X Examine and modify CPU registers command No known manual or schematic of the video board. ****************************************************************************/ #include "emu.h" #include "cpu/i8085/i8085.h" #include "machine/i8255.h" #include "machine/i8251.h" #include "machine/clock.h" #include "bus/rs232/rs232.h" //#include "machine/ay31015.h" #define I8255A_1_TAG "ppi8255_1" #define I8255A_2_TAG "ppi8255_2" #define I8251A_TAG "usart" #define I8251A_BAUD_TAG "usart_baud" #define RS232_TAG "rs232" class isbc8010_state : public driver_device { public: isbc8010_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_usart(*this, I8251A_TAG) , m_ppi_0(*this, I8255A_1_TAG) , m_ppi_1(*this, I8255A_2_TAG) , m_rs232(*this, RS232_TAG) , m_usart_baud_rate(*this, I8251A_BAUD_TAG) , m_usart_divide_counter(0) , m_usart_clock_state(0) { } void isbc8010b(machine_config &config); void isbc8010a(machine_config &config); void isbc8010(machine_config &config); private: uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); DECLARE_WRITE_LINE_MEMBER( usart_clock_tick ); void isbc8010_io(address_map &map); void isbc8010_mem(address_map &map); void isbc8010a_mem(address_map &map); void isbc8010b_mem(address_map &map); required_device m_maincpu; required_device m_usart; required_device m_ppi_0; required_device m_ppi_1; required_device m_rs232; required_ioport m_usart_baud_rate; uint8_t m_usart_divide_counter; uint8_t m_usart_clock_state; }; void isbc8010_state::isbc8010_mem(address_map &map) { map.unmap_value_high(); map(0x0000, 0x0fff).rom(); map(0x3c00, 0x3fff).ram(); } void isbc8010_state::isbc8010a_mem(address_map &map) { map.unmap_value_high(); map(0x0000, 0x1fff).rom(); map(0x3c00, 0x3fff).ram(); } void isbc8010_state::isbc8010b_mem(address_map &map) { map.unmap_value_high(); map(0x0000, 0x3bff).rom(); map(0x3c00, 0x3fff).ram(); } void isbc8010_state::isbc8010_io(address_map &map) { map.unmap_value_high(); map.global_mask(0xff); map(0xe4, 0xe7).rw(m_ppi_0, FUNC(i8255_device::read), FUNC(i8255_device::write)); map(0xe8, 0xeb).rw(m_ppi_1, FUNC(i8255_device::read), FUNC(i8255_device::write)); map(0xec, 0xed).mirror(0x02).rw(m_usart, FUNC(i8251_device::read), FUNC(i8251_device::write)); //AM_RANGE(0xf0, 0xf7) MCS0 - iSBX Multimodule //AM_RANGE(0xf8, 0xff) MCS1 - iSBX Multimodule } static INPUT_PORTS_START( isbc8010 ) PORT_START(I8251A_BAUD_TAG) PORT_DIPNAME( 0x3f, 0x01, "i8251 Baud Rate" ) PORT_DIPSETTING( 0x01, "4800") PORT_DIPSETTING( 0x02, "2400") PORT_DIPSETTING( 0x04, "1200") PORT_DIPSETTING( 0x08, "600") PORT_DIPSETTING( 0x10, "300") PORT_DIPSETTING( 0x20, "150") PORT_DIPSETTING( 0x40, "75") INPUT_PORTS_END #if 0 /* Graphics Output */ const gfx_layout sdk80_charlayout = { 7, 8, /* character cell is 7 pixels wide by 8 pixels high */ 64, /* 64 characters in 2513 character generator ROM */ 1, /* 1 bitplane */ { 0 }, /* 5 visible pixels per row, starting at bit 3, with MSB being 0: */ { 3, 4, 5, 6, 7 }, /* pixel rows stored from top to bottom: */ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, 8 * 8 /* 8 8-bit pixel rows per character */ }; static GFXDECODE_START( gfx_isbc8010 ) GFXDECODE_ENTRY( "gfx1", 0x0000, sdk80_charlayout, 0, 1 ) GFXDECODE_END #endif uint32_t isbc8010_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; } WRITE_LINE_MEMBER( isbc8010_state::usart_clock_tick ) { uint8_t old_counter = m_usart_divide_counter; m_usart_divide_counter++; uint8_t transition = (old_counter ^ m_usart_divide_counter) & m_usart_baud_rate->read(); if (transition) { m_usart->write_txc(m_usart_clock_state); m_usart->write_rxc(m_usart_clock_state); m_usart_clock_state ^= 1; } } static DEVICE_INPUT_DEFAULTS_START( terminal ) // set up terminal to default to 4800 DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_4800 ) DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_4800 ) DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 ) DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) DEVICE_INPUT_DEFAULTS_END MACHINE_CONFIG_START(isbc8010_state::isbc8010) /* basic machine hardware */ MCFG_DEVICE_ADD("maincpu", I8080A, XTAL(18'432'000)/9) MCFG_DEVICE_PROGRAM_MAP(isbc8010_mem) MCFG_DEVICE_IO_MAP(isbc8010_io) I8251(config, m_usart, 0); m_usart->txd_handler().set(RS232_TAG, FUNC(rs232_port_device::write_txd)); m_usart->dtr_handler().set(RS232_TAG, FUNC(rs232_port_device::write_dtr)); m_usart->rts_handler().set(RS232_TAG, FUNC(rs232_port_device::write_rts)); I8255A(config, m_ppi_0); I8255A(config, m_ppi_1); RS232_PORT(config, m_rs232, default_rs232_devices, "terminal"); m_rs232->rxd_handler().set(m_usart, FUNC(i8251_device::write_rxd)); m_rs232->dsr_handler().set(m_usart, FUNC(i8251_device::write_dsr)); m_rs232->cts_handler().set(m_usart, FUNC(i8251_device::write_cts)); m_rs232->set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); MCFG_DEVICE_ADD("usart_clock", CLOCK, XTAL(18'432'000)/60) MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, isbc8010_state, usart_clock_tick)) /* video hardware */ // 96364 crt controller // MCFG_SCREEN_ADD("screen", RASTER) // MCFG_SCREEN_REFRESH_RATE(60) /* Video is blanked for 70 out of 262 scanlines per refresh cycle. Each scanline is composed of 65 character times, 40 of which are visible, and each character time is 7 dot times; a dot time is 2 cycles of the fundamental 14.31818 MHz oscillator. The total blanking time is about 4450 microseconds. */ // MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((int) (70 * 65 * 7 * 2 / 14.31818))) /* It would be nice if we could implement some sort of display overscan here. */ // MCFG_SCREEN_SIZE(40 * 7, 24 * 8) // MCFG_SCREEN_VISIBLE_AREA(0, 40 * 7 - 1, 0, 24 * 8 - 1) // MCFG_SCREEN_UPDATE_DRIVER(sdk80_state, screen_update) // MCFG_SCREEN_PALETTE("palette") // MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_sdk80) // MCFG_PALETTE_ADD_MONOCHROME("palette") // Video board UART // MCFG_DEVICE_ADD( "hd6402", AY31015, 0 ) // MCFG_AY31015_TX_CLOCK(( XTAL(16'000'000) / 16 ) / 256) // MCFG_AY31015_RX_CLOCK(( XTAL(16'000'000) / 16 ) / 256) // MCFG_AY51013_READ_SI_CB(READ8(*this, sdk80_state, nascom1_hd6402_si)) // MCFG_AY51013_WRITE_SO_CB(WRITE8(*this, sdk80_state, nascom1_hd6402_so)) /* Devices */ // i8279_device &kbdc(I8279(config, "i8279", 3100000)); // based on divider // kbdc.out_irq_callback().set_inputline("maincpu", I8085_RST55_LINE); // irq // kbdc.out_sl_callback().set(FUNC(sdk80_state::scanlines_w)); // scan SL lines // kbdc.out_disp_callback().set(FUNC(sdk80_state::digit_w)); // display A&B // kbdc.in_rl_callback().set(FUNC(sdk80_state::kbd_r)); // kbd RL lines // kbdc.in_shift_callback().set_constant(1); // Shift key // kbdc.in_ctrl_callback().set_constant(1); MACHINE_CONFIG_END MACHINE_CONFIG_START(isbc8010_state::isbc8010a) isbc8010(config); /* basic machine hardware */ MCFG_DEVICE_MODIFY( "maincpu" ) MCFG_DEVICE_PROGRAM_MAP(isbc8010a_mem) MACHINE_CONFIG_END MACHINE_CONFIG_START(isbc8010_state::isbc8010b) isbc8010(config); /* basic machine hardware */ MCFG_DEVICE_MODIFY("maincpu") MCFG_DEVICE_PROGRAM_MAP(isbc8010b_mem) MACHINE_CONFIG_END /* ROM definition */ ROM_START( isbc8010 ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_DEFAULT_BIOS("mon11") ROM_SYSTEM_BIOS( 0, "mon11", "80/10 Monitor v1.1" ) ROMX_LOAD( "sbc80p.a23", 0x0000, 0x0400, CRC(bd49a7d6) SHA1(3b2f18abf35efe05f38eb08bf0c6d0f45fa7ae0a), ROM_BIOS(0)) ROMX_LOAD( "sbc80p.a24", 0x0400, 0x0400, CRC(18131631) SHA1(6fb29df38e056c966dcc95885bc59c2a3caf4baf), ROM_BIOS(0)) ROM_SYSTEM_BIOS( 1, "bas80", "BASIC-80" ) ROMX_LOAD( "basic_blc_1.a24", 0x0000, 0x0400, CRC(b5e75aee) SHA1(6bd1eb9586d72544e8afb4ae43ecedcefa14da33), ROM_BIOS(1)) ROMX_LOAD( "basic_blc_2.a25", 0x0400, 0x0400, CRC(0a9ad1ed) SHA1(92c47eadcf8b18eeedcccaa3deb9f1518aaceeae), ROM_BIOS(1)) ROMX_LOAD( "basic_blc_3.a26", 0x0800, 0x0400, CRC(bc898e4b) SHA1(adc000534db0f736a75fbceed360dc220e02c30d), ROM_BIOS(1)) ROMX_LOAD( "basic_blc_4.a27", 0x0c00, 0x0400, CRC(568e8b6d) SHA1(22960193d3b0ae1b5d876d8c3b3f3b40db01358c), ROM_BIOS(1)) /* 512-byte Signetics 2513 character generator ROM at location D2-D3 */ ROM_REGION(0x0200, "gfx1",0) ROM_LOAD("s2513.d2", 0x0000, 0x0200, CRC(a7e567fc) SHA1(b18aae0a2d4f92f5a7e22640719bbc4652f3f4ee)) /* 256x4 PROM located on the video board, schematic location P7, to be moved into separate device later */ ROM_REGION( 0x0120, "proms", 0 ) ROM_LOAD( "6300__d7.p7", 0x0020, 0x0100, CRC(3eb3a8e4) SHA1(19097b5f60d1030f8b82d9f1d3a241f93e5c75d6) ) ROM_END #define rom_isbc8010a rom_isbc8010 #define rom_isbc8010b rom_isbc8010 /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ COMP( 1975, isbc8010, 0, 0, isbc8010, isbc8010, isbc8010_state, empty_init, "Intel", "iSBC 80/10", MACHINE_NO_SOUND_HW ) COMP( 1977, isbc8010a, isbc8010, 0, isbc8010a, isbc8010, isbc8010_state, empty_init, "Intel", "iSBC 80/10A", MACHINE_NO_SOUND_HW ) COMP( 1979, isbc8010b, isbc8010, 0, isbc8010b, isbc8010, isbc8010_state, empty_init, "Intel", "iSBC 80/10B", MACHINE_NO_SOUND_HW )