// license:BSD-3-Clause // copyright-holders:Robbbert /*************************************************************************** SBC6510 from Josip Perusanec 18/12/2009 Skeleton driver. 2012-08-12 Working [Robbbert] CPU MOS 6510 (1MHz) ROM 4KB RAM 128KB CIA 6526 - for interrupt gen and scan of keyboard YM2149/AY-3-8910 - sound + HDD/CF IDE GAL16V8 - address decoder ATMEGA8 - gen. of PAL video signal (modified TellyMate) keyboard of C64 computer used Commands: A - (unknown) C - (unknown) E - (unknown) F - (unknown) G - (unknown) L - (unknown) R - (unknown) S - (unknown) Some commands expect a filename enclosed in double quotes. If the quotes are not there, it loops forever looking for them. Good example of bad programming. There is no help and no error messages. ToDo: - The ATMEGA8 is a CPU with Timer, 4 IO ports, UART, ADC, Watchdog all built in. This enormously complex device needs to be emulated. It also contains some (4k?) RAM, of which certain addresses have special meaning. For example bytes 0 and 1 control the serial video stream of bits. - When the system boots, there is a Y in the top corner. This is actually Esc-Y, which our terminal does not understand. - IDE interface. - Find out the proper way to use the monitor, there are no instructions and the slightest mistake can freeze the system. - No software to test with. ****************************************************************************/ #include "emu.h" #include "cpu/m6502/m6510.h" #include "cpu/avr8/avr8.h" #include "machine/mos6526.h" #include "sound/ay8910.h" #include "machine/terminal.h" #define TERMINAL_TAG "terminal" class sbc6510_state : public driver_device { public: sbc6510_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_videocpu(*this, "videocpu"), m_terminal(*this, TERMINAL_TAG) { } DECLARE_READ8_MEMBER(a2_r); DECLARE_WRITE8_MEMBER(a2_w); DECLARE_READ8_MEMBER(psg_a_r); DECLARE_READ8_MEMBER(psg_b_r); DECLARE_WRITE8_MEMBER(key_w); DECLARE_READ8_MEMBER(key_r); UINT8 m_term_data; UINT8 m_key_row; UINT8 m_2; virtual void machine_start() override; virtual void machine_reset() override; protected: ioport_port *m_io_port[8]; required_device m_maincpu; required_device m_videocpu; required_device m_terminal; }; static ADDRESS_MAP_START( sbc6510_mem, AS_PROGRAM, 8, sbc6510_state ) ADDRESS_MAP_UNMAP_HIGH AM_RANGE(0x0000, 0x0001) AM_RAM AM_RANGE(0x0002, 0x0002) AM_READWRITE(a2_r,a2_w) AM_RANGE(0x0003, 0xdfff) AM_RAM AM_RANGE(0xe000, 0xe00f) AM_MIRROR(0x1f0) AM_DEVREADWRITE("cia6526", mos6526_device, read, write) AM_RANGE(0xe800, 0xe800) AM_MIRROR(0x1ff) AM_DEVWRITE("ay8910", ay8910_device, address_w) AM_RANGE(0xea00, 0xea00) AM_MIRROR(0x1ff) AM_DEVREADWRITE("ay8910", ay8910_device, data_r, data_w) AM_RANGE(0xf000, 0xffff) AM_ROM ADDRESS_MAP_END static ADDRESS_MAP_START( sbc6510_video_mem, AS_PROGRAM, 8, sbc6510_state ) AM_RANGE(0x0000, 0x1fff) AM_ROM ADDRESS_MAP_END static ADDRESS_MAP_START( sbc6510_video_data, AS_DATA, 8, sbc6510_state ) AM_RANGE(0x0100, 0x04ff) AM_RAM ADDRESS_MAP_END static ADDRESS_MAP_START( sbc6510_video_io, AS_IO, 8, sbc6510_state ) ADDRESS_MAP_END /* Input ports */ static INPUT_PORTS_START( sbc6510 ) // cbm keyboard PORT_START( "X0" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Crsr Down Up") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Crsr Right Left") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Del Inst") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) PORT_START( "X1" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_START( "X2" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_START( "X3" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') PORT_START( "X4" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') PORT_START( "X5" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR('[') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') PORT_START( "X6" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x2191) PORT_CHAR(0x03C0) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('=') PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home Clr") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') PORT_CHAR(']') PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*') PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\xA3') PORT_START( "X7" ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_HOME) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CBM") PORT_CODE(KEYCODE_LALT) PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_SHIFT_2) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x2190) PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_START( "X8" ) /* unused */ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Restore") PORT_CODE(KEYCODE_PRTSCR) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_START("MAIN") PORT_BIT(0xff, IP_ACTIVE_HIGH, IPT_UNUSED) INPUT_PORTS_END READ8_MEMBER( sbc6510_state::a2_r ) { return m_2; } WRITE8_MEMBER( sbc6510_state::a2_w ) { m_2 = data; m_terminal->write(space, 0, data); } void sbc6510_state::machine_start() { char kbdrow[6]; for ( int i = 0; i < 8; i++ ) { sprintf(kbdrow,"X%X",i); m_io_port[i] = ioport(kbdrow); } } void sbc6510_state::machine_reset() { } READ8_MEMBER( sbc6510_state::psg_a_r ) { return 0xff; } READ8_MEMBER( sbc6510_state::psg_b_r ) { return 0x7f; } READ8_MEMBER( sbc6510_state::key_r ) { UINT8 data=0; for (int i = 0; i < 8; i++) { if (!BIT(m_key_row, i)) { data |= m_io_port[i]->read(); } } return ~data; } WRITE8_MEMBER( sbc6510_state::key_w ) { m_key_row = data; } static const gfx_layout charset_8x16 = { 8, 9, 256, 1, { 0 }, { STEP8(0,1) }, { 0*1024*2, 1*1024*2, 2*1024*2, 3*1024*2, 4*1024*2, 5*1024*2, 6*1024*2, 7*1024*2, 8*1024*2 }, 8 }; static GFXDECODE_START( sbc6510 ) GFXDECODE_ENTRY( "videocpu", 0x1500, charset_8x16, 0, 128 ) GFXDECODE_END static MACHINE_CONFIG_START( sbc6510, sbc6510_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu",M6510, XTAL_1MHz) MCFG_CPU_PROGRAM_MAP(sbc6510_mem) MCFG_CPU_ADD("videocpu",ATMEGA88, XTAL_16MHz) // MCFG_DEVICE_DISABLE() // trips SLEEP opcode, needs to be emulated MCFG_CPU_PROGRAM_MAP(sbc6510_video_mem) MCFG_CPU_DATA_MAP(sbc6510_video_data) MCFG_CPU_IO_MAP(sbc6510_video_io) MCFG_CPU_AVR8_EEPROM("eeprom") MCFG_GFXDECODE_ADD("gfxdecode", TERMINAL_TAG":palette", sbc6510) /* video hardware */ MCFG_DEVICE_ADD(TERMINAL_TAG, GENERIC_TERMINAL, 0) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("ay8910", AY8910, XTAL_1MHz) // Ports A and B connect to the IDE socket MCFG_AY8910_PORT_A_READ_CB(READ8(sbc6510_state, psg_a_r)) // port A read MCFG_AY8910_PORT_B_READ_CB(READ8(sbc6510_state, psg_b_r)) // port B read MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) MCFG_DEVICE_ADD("cia6526", MOS6526, XTAL_1MHz) MCFG_MOS6526_TOD(50) MCFG_MOS6526_IRQ_CALLBACK(INPUTLINE("maincpu", M6510_IRQ_LINE)) MCFG_MOS6526_PA_OUTPUT_CALLBACK(WRITE8(sbc6510_state, key_w)) MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(sbc6510_state, key_r)) MACHINE_CONFIG_END /* ROM definition */ ROM_START( sbc6510 ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) ROM_LOAD( "sbc6510.rom", 0xf000, 0x1000, CRC(e13a5e62) SHA1(1e7482e9b98b39d0cc456254fbe8fd0981e9377e)) ROM_REGION( 0x10000, "videocpu", ROMREGION_ERASEFF ) // ATMEGA8 at 16MHz ROM_LOAD( "video.bin", 0x0000, 0x2000, CRC(809f31ce) SHA1(4639de5f7b8f6c036d74f217ba85e7e897039094)) ROM_REGION( 0x200, "gal", ROMREGION_ERASEFF ) ROM_LOAD( "sbc6510.gal", 0x0000, 0x0117, CRC(f78f9927) SHA1(b951163958f5722032826d0d17a07c81dbd5f68e)) ROM_REGION( 0x2000, "eeprom", ROMREGION_ERASEFF ) ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ COMP( 2009, sbc6510, 0, 0, sbc6510, sbc6510, driver_device, 0, "Josip Perusanec", "SBC6510", MACHINE_NOT_WORKING )