diff --git a/src/mess/drivers/fc100.c b/src/mess/drivers/fc100.c index 08a9246579a..b8f751bb557 100644 --- a/src/mess/drivers/fc100.c +++ b/src/mess/drivers/fc100.c @@ -11,11 +11,9 @@ Shift-Run to BREAK out of CLOAD. Cassette uses the uart. TODO: -- Sound -- Cassette - Hookup Graphics modes - Unknown i/o ports -- Does it have a cart slot? +- Does it have a cart slot? Yes. What address? - Expansion? - It misses keystrokes if you type quickly @@ -27,6 +25,10 @@ TODO: #include "cpu/z80/z80.h" #include "video/mc6847.h" #include "machine/i8251.h" +#include "machine/clock.h" +#include "sound/ay8910.h" +#include "imagedev/cassette.h" +#include "sound/wave.h" class fc100_state : public driver_device @@ -36,26 +38,30 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_s68047p(*this, "s68047p") - , m_videoram(*this, "videoram") + , m_p_videoram(*this, "videoram") + , m_cass(*this, "cassette") + , m_uart(*this, "uart") { } DECLARE_READ8_MEMBER(mc6847_videoram_r); + DECLARE_WRITE8_MEMBER(port31_w); + DECLARE_WRITE8_MEMBER(port33_w); DECLARE_WRITE_LINE_MEMBER(irq_w); + DECLARE_WRITE_LINE_MEMBER(txdata_callback); + DECLARE_WRITE_LINE_MEMBER(uart_clock_w); + TIMER_DEVICE_CALLBACK_MEMBER(timer_c); + TIMER_DEVICE_CALLBACK_MEMBER(timer_p); UINT8 *m_p_chargen; static UINT8 get_char_rom(running_machine &machine, UINT8 ch, int line) { fc100_state *state = machine.driver_data(); - return state->m_p_chargen[(ch&0x7F)*16+line]; + return state->m_p_chargen[ch*16+line]; } private: virtual void machine_start(); virtual void machine_reset(); - required_device m_maincpu; - required_device m_s68047p; - required_shared_ptr m_videoram; - // graphics signals UINT8 m_ag; UINT8 m_gm2; @@ -65,6 +71,14 @@ private: UINT8 m_css; UINT8 m_intext; UINT8 m_inv; + UINT8 m_cass_data[4]; + bool m_cass_state; + + required_device m_maincpu; + required_device m_s68047p; + required_shared_ptr m_p_videoram; + required_device m_cass; + required_device m_uart; }; @@ -94,8 +108,13 @@ static ADDRESS_MAP_START( fc100_io, AS_IO, 8, fc100_state ) AM_RANGE(0x0D, 0x0D) AM_READ_PORT("0D") AM_RANGE(0x0E, 0x0E) AM_READ_PORT("0E") AM_RANGE(0x0F, 0x0F) AM_READ_PORT("0F") + AM_RANGE(0x21, 0x21) AM_DEVWRITE("psg", ay8910_device, data_w) + AM_RANGE(0x22, 0x22) AM_DEVREAD("psg", ay8910_device, data_r) + AM_RANGE(0x23, 0x23) AM_DEVWRITE("psg", ay8910_device, address_w) + AM_RANGE(0x31, 0x31) AM_WRITE(port31_w) + AM_RANGE(0x33, 0x33) AM_WRITE(port33_w) // AM_RANGE(0x60, 0x61) writes 0 to both ports at boot - // AM_RANGE(0x70, 0x70) each screen character also gets written here + AM_RANGE(0x70, 0x70) AM_WRITENOP // each screen character also gets written here // AM_RANGE(0x71, 0x71) writes 0 at boot AM_RANGE(0xb0, 0xb0) AM_DEVREADWRITE("uart", i8251_device, data_r, data_w) AM_RANGE(0xb8, 0xb8) AM_DEVREADWRITE("uart", i8251_device, status_r, control_w) @@ -204,33 +223,7 @@ static INPUT_PORTS_START( fc100 ) INPUT_PORTS_END -void fc100_state::machine_start() -{ - m_ag = 0; - m_gm2 = 0; - m_gm1 = 0; - m_gm0 = 0; - m_as = 0; - m_css = 0; - m_intext = 0; - m_inv = 0; - - save_item(NAME(m_ag)); - save_item(NAME(m_gm2)); - save_item(NAME(m_gm1)); - save_item(NAME(m_gm0)); - save_item(NAME(m_as)); - save_item(NAME(m_css)); - save_item(NAME(m_intext)); - save_item(NAME(m_inv)); -} - - -void fc100_state::machine_reset() -{ - m_p_chargen = memregion("chargen")->base(); -} - +//********************* AUDIO ********************************** #if 0 WRITE8_MEMBER( fc100_state::ay_port_a_w ) { @@ -257,18 +250,19 @@ WRITE8_MEMBER( fc100_state::ay_port_b_w ) { //logerror("ay_port_b_w: %02X\n", data); } +#endif - -static const ay8910_interface fc100_ay8910_interface = +static const ay8910_interface ay8910_intf = { AY8910_LEGACY_OUTPUT, AY8910_DEFAULT_LOADS, - DEVCB_DRIVER_MEMBER(fc100_state, ay_port_a_r), - DEVCB_DRIVER_MEMBER(fc100_state, ay_port_b_r), - DEVCB_DRIVER_MEMBER(fc100_state, ay_port_a_w), - DEVCB_DRIVER_MEMBER(fc100_state, ay_port_b_w) + DEVCB_NULL,//DEVCB_DRIVER_MEMBER(fc100_state, ay_port_a_r), + DEVCB_NULL,//DEVCB_DRIVER_MEMBER(fc100_state, ay_port_b_r), + DEVCB_NULL,//DEVCB_DRIVER_MEMBER(fc100_state, ay_port_a_w), + DEVCB_NULL,//DEVCB_DRIVER_MEMBER(fc100_state, ay_port_b_w) }; -#endif + +//******************** VIDEO ********************************** READ8_MEMBER( fc100_state::mc6847_videoram_r ) { @@ -280,18 +274,18 @@ READ8_MEMBER( fc100_state::mc6847_videoram_r ) { // 256 x 192 / 6KB offset = ( ( offset & 0x1fc0 ) >> 1 ) | ( offset & 0x1f ); - return m_videoram[offset % 0xc00]; + return m_p_videoram[offset % 0xc00]; } else { // 256 x 96 / 3KB - return m_videoram[offset % 0xc00]; + return m_p_videoram[offset % 0xc00]; } } // Standard text - UINT8 data = m_videoram[offset]; - UINT8 attr = m_videoram[offset+0x200]; + UINT8 data = m_p_videoram[offset]; + UINT8 attr = m_p_videoram[offset+0x200]; m_s68047p->inv_w( BIT( attr, 0 )); @@ -321,6 +315,111 @@ static const mc6847_interface fc100_mc6847_interface = &fc100_state::get_char_rom }; +/* F4 Character Displayer */ +static const gfx_layout u53_charlayout = +{ + 7, 15, /* 7 x 15 characters */ + 256, /* 256 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 }, + 8*16 /* every char takes 16 bytes */ +}; + +static GFXDECODE_START( fc100 ) + GFXDECODE_ENTRY( "chargen", 0x0000, u53_charlayout, 0, 1 ) +GFXDECODE_END + +//********************** UART/CASSETTE *********************************** + +WRITE8_MEMBER( fc100_state::port31_w ) +{ + if (data == 8) + m_cass->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); +} + +WRITE8_MEMBER( fc100_state::port33_w ) +{ + if (data == 0) + m_cass->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); +} + +WRITE_LINE_MEMBER( fc100_state::txdata_callback ) +{ + m_cass_state = state; +} + +WRITE_LINE_MEMBER( fc100_state::uart_clock_w ) +{ + m_uart->write_txc(state); + m_uart->write_rxc(state); +} + +TIMER_DEVICE_CALLBACK_MEMBER( fc100_state::timer_c ) +{ + m_cass_data[3]++; + + if (m_cass_state) + m_cass->output(BIT(m_cass_data[3], 0) ? -1.0 : +1.0); // 2400Hz + else + m_cass->output(BIT(m_cass_data[3], 1) ? -1.0 : +1.0); // 1200Hz +} + +TIMER_DEVICE_CALLBACK_MEMBER( fc100_state::timer_p) +{ + /* cassette - turn 1200/2400Hz to a bit */ + m_cass_data[1]++; + UINT8 cass_ws = (m_cass->input() > +0.03) ? 1 : 0; + + if (cass_ws != m_cass_data[0]) + { + m_cass_data[0] = cass_ws; + m_uart->write_rxd((m_cass_data[1] < 12) ? 1 : 0); + m_cass_data[1] = 0; + } +} + +#if 0 +static const cassette_interface fc100_cassette_interface = +{ + cassette_default_formats, + NULL, + (cassette_state) (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED), + "fc100_cass", + NULL +}; +#endif + +//******************** MACHINE ****************************** + +void fc100_state::machine_start() +{ + m_ag = 0; + m_gm2 = 0; + m_gm1 = 0; + m_gm0 = 0; + m_as = 0; + m_css = 0; + m_intext = 0; + m_inv = 0; + + save_item(NAME(m_ag)); + save_item(NAME(m_gm2)); + save_item(NAME(m_gm1)); + save_item(NAME(m_gm0)); + save_item(NAME(m_as)); + save_item(NAME(m_css)); + save_item(NAME(m_intext)); + save_item(NAME(m_inv)); +} + +void fc100_state::machine_reset() +{ + m_p_chargen = memregion("chargen")->base(); +} static MACHINE_CONFIG_START( fc100, fc100_state ) /* basic machine hardware */ @@ -332,23 +431,39 @@ static MACHINE_CONFIG_START( fc100, fc100_state ) MCFG_MC6847_ADD("s68047p", S68047, 9159090/3, fc100_mc6847_interface ) // Clock not verified MCFG_MC6847_FSYNC_CALLBACK(WRITELINE(fc100_state, irq_w)) MCFG_SCREEN_MC6847_NTSC_ADD("screen", "s68047p") + MCFG_GFXDECODE_ADD("gfxdecode", "f4palette", fc100) + MCFG_PALETTE_ADD_MONOCHROME_AMBER("f4palette") + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + MCFG_SOUND_ADD("psg", AY8910, 9159090/3/2) /* AY-3-8910 - clock not verified */ + MCFG_SOUND_CONFIG(ay8910_intf) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.50) /* Devices */ + MCFG_CASSETTE_ADD("cassette", default_cassette_interface) //fc100_cassette_interface) MCFG_DEVICE_ADD("uart", I8251, 0) + MCFG_I8251_TXD_HANDLER(WRITELINE(fc100_state, txdata_callback)) + MCFG_DEVICE_ADD("uart_clock", CLOCK, XTAL_4_9152MHz/16/16) // gives 19200 + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(fc100_state, uart_clock_w)) + MCFG_TIMER_DRIVER_ADD_PERIODIC("timer_c", fc100_state, timer_c, attotime::from_hz(4800)) + MCFG_TIMER_DRIVER_ADD_PERIODIC("timer_p", fc100_state, timer_p, attotime::from_hz(40000)) MACHINE_CONFIG_END /* ROM definition */ ROM_START( fc100 ) ROM_REGION( 0x6000, "roms", 0 ) - ROM_LOAD( "08-01.u48", 0x0000, 0x2000, CRC(24e78e75) SHA1(13121706544256a702635448ed2950a75c13f491) ) - ROM_LOAD( "08-02.u49", 0x2000, 0x2000, CRC(e14fc7e9) SHA1(9c5821e65c1efe698e25668d24c36929ea4c3ad7) ) - ROM_LOAD( "06-03.u50", 0x4000, 0x2000, CRC(d783c84e) SHA1(6d1bf53995e08724d5ecc24198cdda4442eb2eb9) ) + ROM_LOAD( "08-01.u48", 0x0000, 0x2000, CRC(24e78e75) SHA1(13121706544256a702635448ed2950a75c13f491) ) + ROM_LOAD( "08-02.u49", 0x2000, 0x2000, CRC(e14fc7e9) SHA1(9c5821e65c1efe698e25668d24c36929ea4c3ad7) ) + ROM_LOAD( "06-03.u50", 0x4000, 0x2000, CRC(d783c84e) SHA1(6d1bf53995e08724d5ecc24198cdda4442eb2eb9) ) ROM_REGION( 0x1000, "chargen", 0 ) - ROM_LOAD( "cgen.u53", 0x0000, 0x1000, CRC(2de75b7f) SHA1(464369d98cbae92ffa322ebaa4404cf5b26825f1) ) + ROM_LOAD( "cg-04-01.u53", 0x0000, 0x1000, CRC(2de75b7f) SHA1(464369d98cbae92ffa322ebaa4404cf5b26825f1) ) ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME STATUS FLAGS */ -CONS( 1982, fc100, 0, 0, fc100, fc100, driver_device, 0, "Goldstar", "Famicom FC-100", GAME_IS_SKELETON ) +CONS( 1982, fc100, 0, 0, fc100, fc100, driver_device, 0, "Goldstar", "Famicom FC-100", GAME_NOT_WORKING )