summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/apf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/apf.c')
-rw-r--r--src/mess/drivers/apf.c767
1 files changed, 767 insertions, 0 deletions
diff --git a/src/mess/drivers/apf.c b/src/mess/drivers/apf.c
new file mode 100644
index 00000000000..f64e21e208b
--- /dev/null
+++ b/src/mess/drivers/apf.c
@@ -0,0 +1,767 @@
+/******************************************************************************
+
+driver by ?
+
+PeT mess@utanet.at around February 2008:
+ added apfm1000 cartridge loading
+ fixed apfm1000 pads
+ added apf video mode
+
+todo for apf m1000:
+ add exact cpu/video timing. memory controller+6847 memory operations hold cpu
+ (backgammon relies on exact video timing)
+ support special cartridges (basic, space destroyer)
+
+
+0000- 2000-2003 PIA of M1000. is itself repeated until 3fff.
+She controls " keypads ", the way of video and the loudspeaker. Putting to 0 one of the 4 least
+significant bits of 2002, the corresponding line of keys is ***reflxed mng in 2000 (32 keys altogether).
+The other four bits of 2002 control the video way. Bit 0 of 2003 controls the interruptions. Bit 3 of 2003 controls
+the loudspeaker. 4000-47ff ROM of M1000. is repeated until 5fff and in e000-ffff. 6000-6003 PIA of the APF.
+is itself repeated until 63ff. She controls the keyboard of the APF and the cassette. The value of the
+number that represents the three bits less significant of 6002 they determine the line of eight
+keys that it is ***reflxed mng in 6000. Bit 4 of 6002 controls the motor of the cassette. Bit 5 of
+6002 activates or deactivates the recording. Bit 5 of 6002 indicates the level of recording in
+the cassette. 6400-64ff would be the interface Here series, optional. 6500-66ff would be the
+disk controller Here, optional. 6800-77ff ROM (" cartridge ") 7800-7fff Probably ROM. The BASIC
+leaves frees this zone. 8000-9fff ROM (" cartridge ") A000-BFFF ram (8 Kb) C000-DFFF ram
+additional (8 Kb) E000-FFFF ROM of M1000 (to see 4000-47FF) The interruption activates with
+the vertical synchronism of the video. routine that it executes is in the ROM of M1000
+and puts the video in way text during a short interval, so that the first line is seen of
+text screen in the superior part of the graphical screen.
+
+
+6600, 6500-6503 wd179x disc controller? 6400, 6401
+
+Status 19-09-2011
+=================
+- apfimag
+-- Loads tapes but then the machine freezes
+-- Appears to be no error checking; some tapes load as garbage
+-- With wave-sound, the cassette sound is completely overdriven with lots of noise before the tape starts.
+ The problem is not evident when the wav is played with media player.
+
+
+- apfm1000
+-- About half of the carts have severe video problems.
+-- Of the remainder, some freeze at start
+
+******************************************************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6800/m6800.h"
+#include "video/mc6847.h"
+#include "sound/speaker.h"
+#include "sound/wave.h"
+#include "machine/6821pia.h"
+#include "machine/wd17xx.h"
+#include "imagedev/flopdrv.h"
+#include "formats/basicdsk.h"
+#include "imagedev/cassette.h"
+#include "imagedev/cartslot.h"
+#include "formats/apf_apt.h"
+
+
+class apf_state : public driver_device
+{
+public:
+ apf_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_crtc(*this, "mc6847"),
+ m_speaker(*this, SPEAKER_TAG),
+ m_pia0(*this, "pia_0"),
+ m_pia1(*this, "pia_1"),
+ m_cass(*this, CASSETTE_TAG),
+ m_fdc(*this, "wd179x")
+ ,
+ m_p_videoram(*this, "p_videoram"){ }
+
+ required_device<cpu_device> m_maincpu;
+ required_device<mc6847_base_device> m_crtc;
+ required_device<device_t> m_speaker;
+ required_device<device_t> m_pia0;
+ optional_device<device_t> m_pia1;
+ optional_device<cassette_image_device> m_cass;
+ optional_device<device_t> m_fdc;
+ DECLARE_READ8_MEMBER(apf_mc6847_videoram_r);
+ DECLARE_WRITE_LINE_MEMBER(apf_mc6847_fs_w);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_a_func);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_b_func);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_ca1_func);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_cb1_func);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_ca2_func);
+ DECLARE_READ8_MEMBER(apf_m1000_pia_in_cb2_func);
+ DECLARE_WRITE8_MEMBER(apf_m1000_pia_out_a_func);
+ DECLARE_WRITE8_MEMBER(apf_m1000_pia_out_b_func);
+ DECLARE_WRITE_LINE_MEMBER(apf_m1000_pia_out_ca2_func);
+ DECLARE_WRITE8_MEMBER(apf_m1000_pia_out_cb2_func);
+ DECLARE_WRITE_LINE_MEMBER(apf_m1000_irq_a_func);
+ DECLARE_WRITE_LINE_MEMBER(apf_m1000_irq_b_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_a_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_b_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_ca1_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_cb1_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_ca2_func);
+ DECLARE_READ8_MEMBER(apf_imagination_pia_in_cb2_func);
+ DECLARE_WRITE8_MEMBER(apf_imagination_pia_out_a_func);
+ DECLARE_WRITE8_MEMBER(apf_imagination_pia_out_b_func);
+ DECLARE_WRITE8_MEMBER(apf_imagination_pia_out_ca2_func);
+ DECLARE_WRITE8_MEMBER(apf_imagination_pia_out_cb2_func);
+ DECLARE_WRITE_LINE_MEMBER(apf_imagination_irq_a_func);
+ DECLARE_WRITE_LINE_MEMBER(apf_imagination_irq_b_func);
+ DECLARE_WRITE8_MEMBER(apf_dischw_w);
+ DECLARE_READ8_MEMBER(serial_r);
+ DECLARE_WRITE8_MEMBER(serial_w);
+ DECLARE_WRITE8_MEMBER(apf_wd179x_command_w);
+ DECLARE_WRITE8_MEMBER(apf_wd179x_track_w);
+ DECLARE_WRITE8_MEMBER(apf_wd179x_sector_w);
+ DECLARE_WRITE8_MEMBER(apf_wd179x_data_w);
+ DECLARE_READ8_MEMBER(apf_wd179x_status_r);
+ DECLARE_READ8_MEMBER(apf_wd179x_track_r);
+ DECLARE_READ8_MEMBER(apf_wd179x_sector_r);
+ DECLARE_READ8_MEMBER(apf_wd179x_data_r);
+ unsigned char m_keyboard_data;
+ unsigned char m_pad_data;
+ UINT8 m_mc6847_css;
+ required_shared_ptr<UINT8> m_p_videoram;
+ UINT8 m_apf_ints;
+ void apf_update_ints(UINT8 intnum);
+};
+
+
+READ8_MEMBER( apf_state::apf_mc6847_videoram_r )
+{
+ m_crtc->css_w(m_mc6847_css && BIT(m_p_videoram[offset + 0x200], 6));
+ m_crtc->inv_w(BIT(m_p_videoram[offset + 0x200], 6));
+ m_crtc->as_w(BIT(m_p_videoram[offset + 0x200], 7));
+
+ return m_p_videoram[offset + 0x200];
+}
+
+WRITE_LINE_MEMBER( apf_state::apf_mc6847_fs_w )
+{
+ apf_update_ints(0x10);
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_a_func)
+{
+ UINT8 data=~0;
+
+ if (!BIT(m_pad_data, 3))
+ data &= ioport("joy3")->read();
+ if (!BIT(m_pad_data, 2))
+ data &= ioport("joy2")->read();
+ if (!BIT(m_pad_data, 1))
+ data &= ioport("joy1")->read();
+ if (!BIT(m_pad_data, 0))
+ data &= ioport("joy0")->read();
+
+ return data;
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_b_func)
+{
+ return 0xff;
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_ca1_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_cb1_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_ca2_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_m1000_pia_in_cb2_func)
+{
+ return 0;
+}
+
+
+WRITE8_MEMBER( apf_state::apf_m1000_pia_out_a_func)
+{
+}
+
+//static unsigned char previous_mode;
+
+WRITE8_MEMBER( apf_state::apf_m1000_pia_out_b_func )
+{
+ /* bit 7..4 video control -- TODO: bit 5 and 4? */
+ m_crtc->ag_w(BIT(data, 7));
+ m_crtc->gm0_w(BIT(data, 6));
+
+ /* bit 3..0 keypad line select */
+ m_pad_data = data;
+}
+
+WRITE_LINE_MEMBER( apf_state::apf_m1000_pia_out_ca2_func)
+{
+ m_mc6847_css = state;
+}
+
+WRITE8_MEMBER( apf_state::apf_m1000_pia_out_cb2_func)
+{
+ speaker_level_w(m_speaker, data);
+}
+
+/* use bit 0 to identify state of irq from pia 0 */
+/* use bit 1 to identify state of irq from pia 0 */
+/* use bit 2 to identify state of irq from pia 1 */
+/* use bit 3 to identify state of irq from pia 1 */
+/* use bit 4 to identify state of irq from video */
+
+void apf_state::apf_update_ints(UINT8 intnum)
+{
+ if (intnum)
+ m_apf_ints |= intnum;
+ else
+ m_apf_ints &= ~intnum;
+
+ m_maincpu->set_input_line(0, m_apf_ints ? HOLD_LINE : CLEAR_LINE);
+}
+
+WRITE_LINE_MEMBER( apf_state::apf_m1000_irq_a_func )
+{
+ apf_update_ints(0x01);
+}
+
+
+WRITE_LINE_MEMBER( apf_state::apf_m1000_irq_b_func )
+{
+ //logerror("pia 0 irq b %d\n",state);
+
+ apf_update_ints(0x02);
+}
+
+static const pia6821_interface apf_m1000_pia_interface=
+{
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_a_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_b_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_ca1_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_cb1_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_ca2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_in_cb2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_out_a_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_out_b_func),
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_m1000_pia_out_ca2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_m1000_pia_out_cb2_func),
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_m1000_irq_a_func),
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_m1000_irq_b_func)
+};
+
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_a_func)
+{
+ return m_keyboard_data;
+}
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_b_func)
+{
+ UINT8 data = 0;
+
+ if (m_cass->input() > 0.0038)
+ data =(1<<7);
+
+ return data;
+}
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_ca1_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_cb1_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_ca2_func)
+{
+ return 0;
+}
+
+READ8_MEMBER( apf_state::apf_imagination_pia_in_cb2_func)
+{
+ return 0;
+}
+
+
+WRITE8_MEMBER( apf_state::apf_imagination_pia_out_a_func)
+{
+}
+
+WRITE8_MEMBER( apf_state::apf_imagination_pia_out_b_func)
+{
+ /* bits 2..0 = keyboard line */
+ /* bit 3 = ??? */
+ /* bit 4 = cassette motor */
+ /* bit 5 = ?? */
+ /* bit 6 = cassette write data */
+ /* bit 7 = ??? */
+
+ int keyboard_line;
+ static const char *const keynames[] = { "key0", "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
+
+ keyboard_line = data & 0x07;
+ m_keyboard_data = ioport(keynames[keyboard_line])->read();
+
+ /* bit 4: cassette motor control */
+ m_cass->change_state(BIT(data, 4) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ /* bit 6: cassette write */
+ m_cass->output(BIT(data, 6) ? -1.0 : 1.0);
+}
+
+WRITE8_MEMBER( apf_state::apf_imagination_pia_out_ca2_func)
+{
+}
+
+WRITE8_MEMBER( apf_state::apf_imagination_pia_out_cb2_func)
+{
+}
+
+WRITE_LINE_MEMBER( apf_state::apf_imagination_irq_a_func )
+{
+ apf_update_ints(0x04);
+}
+
+WRITE_LINE_MEMBER( apf_state::apf_imagination_irq_b_func )
+{
+ apf_update_ints(0x08);
+}
+
+static const pia6821_interface apf_imagination_pia_interface=
+{
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_a_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_b_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_ca1_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_cb1_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_ca2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_in_cb2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_out_a_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_out_b_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_out_ca2_func),
+ DEVCB_DRIVER_MEMBER(apf_state, apf_imagination_pia_out_cb2_func),
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_imagination_irq_a_func),
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_imagination_irq_b_func)
+};
+
+
+static MACHINE_START( apf_imagination )
+{
+ apf_state *state = machine.driver_data<apf_state>();
+
+ state->m_apf_ints = 0;
+
+ if (state->m_cass) // apfimag only
+ state->m_cass->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+}
+
+WRITE8_MEMBER( apf_state::apf_dischw_w)
+{
+ /* bit 3 is index of drive to select */
+ UINT8 drive = (data>>3) & 0x01;
+
+ wd17xx_set_drive(m_fdc, drive);
+
+ logerror("disc w %04x %04x\n",offset,data);
+}
+
+READ8_MEMBER( apf_state::serial_r)
+{
+ logerror("serial r %04x\n",offset);
+ return 0;
+}
+
+WRITE8_MEMBER( apf_state::serial_w)
+{
+ logerror("serial w %04x %04x\n",offset,data);
+}
+
+WRITE8_MEMBER( apf_state::apf_wd179x_command_w)
+{
+ wd17xx_command_w(m_fdc, offset,~data);
+}
+
+WRITE8_MEMBER( apf_state::apf_wd179x_track_w)
+{
+ wd17xx_track_w(m_fdc, offset,~data);
+}
+
+WRITE8_MEMBER( apf_state::apf_wd179x_sector_w)
+{
+ wd17xx_sector_w(m_fdc, offset,~data);
+}
+
+WRITE8_MEMBER( apf_state::apf_wd179x_data_w)
+{
+ wd17xx_data_w(m_fdc, offset,~data);
+}
+
+READ8_MEMBER( apf_state::apf_wd179x_status_r)
+{
+ return ~wd17xx_status_r(m_fdc, offset);
+}
+
+READ8_MEMBER( apf_state::apf_wd179x_track_r)
+{
+ return ~wd17xx_track_r(m_fdc, offset);
+}
+
+READ8_MEMBER( apf_state::apf_wd179x_sector_r)
+{
+ return ~wd17xx_sector_r(m_fdc, offset);
+}
+
+READ8_MEMBER( apf_state::apf_wd179x_data_r)
+{
+ return wd17xx_data_r(m_fdc, offset); // should this be inverted like the rest?
+}
+
+static ADDRESS_MAP_START( apf_imagination_map, AS_PROGRAM, 8, apf_state )
+ AM_RANGE( 0x00000, 0x003ff) AM_RAM AM_SHARE("p_videoram") AM_MIRROR(0x1c00)
+ AM_RANGE( 0x02000, 0x03fff) AM_DEVREADWRITE("pia_0", pia6821_device, read, write)
+ AM_RANGE( 0x04000, 0x047ff) AM_ROM AM_REGION("maincpu", 0x10000) AM_MIRROR(0x1800)
+ AM_RANGE( 0x06000, 0x063ff) AM_DEVREADWRITE("pia_1", pia6821_device, read, write)
+ AM_RANGE( 0x06400, 0x064ff) AM_READWRITE(serial_r, serial_w)
+ AM_RANGE( 0x06500, 0x06500) AM_READWRITE(apf_wd179x_status_r, apf_wd179x_command_w)
+ AM_RANGE( 0x06501, 0x06501) AM_READWRITE(apf_wd179x_track_r, apf_wd179x_track_w)
+ AM_RANGE( 0x06502, 0x06502) AM_READWRITE(apf_wd179x_sector_r, apf_wd179x_sector_w)
+ AM_RANGE( 0x06503, 0x06503) AM_READWRITE(apf_wd179x_data_r, apf_wd179x_data_w)
+ AM_RANGE( 0x06600, 0x06600) AM_WRITE(apf_dischw_w)
+ AM_RANGE( 0x06800, 0x077ff) AM_ROM
+ AM_RANGE( 0x07800, 0x07fff) AM_NOP
+ AM_RANGE( 0x08000, 0x09fff) AM_ROM
+ AM_RANGE( 0x0a000, 0x0dfff) AM_RAM
+ AM_RANGE( 0x0e000, 0x0e7ff) AM_ROM AM_REGION("maincpu", 0x10000) AM_MIRROR(0x1800)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( apf_m1000_map, AS_PROGRAM, 8, apf_state )
+ AM_RANGE( 0x00000, 0x003ff) AM_RAM AM_SHARE("p_videoram") AM_MIRROR(0x1c00)
+ AM_RANGE( 0x02000, 0x03fff) AM_DEVREADWRITE("pia_0", pia6821_device, read, write)
+ AM_RANGE( 0x04000, 0x047ff) AM_ROM AM_REGION("maincpu", 0x10000) AM_MIRROR(0x1800)
+ AM_RANGE( 0x06800, 0x077ff) AM_ROM
+ AM_RANGE( 0x08000, 0x09fff) AM_ROM AM_REGION("maincpu", 0x8000)
+ AM_RANGE( 0x0a000, 0x0dfff) AM_RAM
+ AM_RANGE( 0x0e000, 0x0e7ff) AM_ROM AM_REGION("maincpu", 0x10000) AM_MIRROR(0x1800)
+ADDRESS_MAP_END
+
+/* The following input ports definitions are wrong and can't be debugged unless the driver
+ is capable of running more cartridges. However each of the controllers supported by the M-1000
+ have these features:
+
+ 1 8-way joystick
+ 1 big red fire button on the upper side
+ 12-keys keypad with the following layout
+
+ 7 8 9 0
+ 4 5 6 Cl
+ 1 2 3 En
+
+ On the control panel of the M-1000 there are two big buttons: a Reset key and the Power switch
+
+ Reference: http://www.nausicaa.net/~lgreenf/apfpage2.htm
+*/
+
+static INPUT_PORTS_START( apf_m1000 )
+
+ /*
+ There must be a bug lurking somewhere, because the lines 0-3 are not detected correctly:
+ Using another known APF emulator, this simple Basic program can be used to read
+ the joysticks and the keyboard:
+
+ 10 PRINT KEY$(n);
+ 20 GOTO 10
+
+ where n = 0, 1 or 2 - 0 = keyboard, 1,2 = joysticks #1 and #2
+
+ When reading the keyboard KEY$(0) returns the character associated to the key, with the
+ following exceptions:
+
+ Ctrl = CHR$(1)
+ Rept = CHR$(2)
+ Here Is = CHR$(4)
+ Rubout = CHR$(8)
+
+ When reading the joysticks, KEY$() = "N", "S", "E", "W" for the directions
+ "0" - "9" for the keypad digits
+ "?" for "Cl"
+ "!" for "En"
+
+ Current code doesn't behaves this way...
+
+ */
+
+/*
+ ? player right is player 1
+ */
+
+ /* line 0 */
+ PORT_START("joy0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 1") PORT_CODE(KEYCODE_1) PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 0") PORT_CODE(KEYCODE_0) PORT_PLAYER(1)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 4") PORT_CODE(KEYCODE_4) PORT_PLAYER(1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 7") PORT_CODE(KEYCODE_7) PORT_PLAYER(1)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 1") PORT_CODE(KEYCODE_1_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 0") PORT_CODE(KEYCODE_0_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 4") PORT_CODE(KEYCODE_4_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 7") PORT_CODE(KEYCODE_7_PAD) PORT_PLAYER(2)
+
+ /* line 1 */
+ PORT_START("joy1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_NAME("PAD 1/RIGHT down") PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_NAME("PAD 1/RIGHT right") PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_NAME("PAD 1/RIGHT up") PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_NAME("PAD 1/RIGHT left") PORT_PLAYER(1) PORT_8WAY
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_NAME("PAD 2/LEFT down") PORT_PLAYER(2) PORT_8WAY
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_NAME("PAD 2/LEFT right") PORT_PLAYER(2) PORT_8WAY
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_NAME("PAD 2/LEFT up") PORT_PLAYER(2) PORT_8WAY
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_NAME("PAD 2/LEFT left") PORT_PLAYER(2) PORT_8WAY
+
+ /* line 2 */
+ PORT_START("joy2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 3") PORT_CODE(KEYCODE_3) PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT clear") PORT_CODE(KEYCODE_DEL) PORT_PLAYER(1)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 6") PORT_CODE(KEYCODE_6) PORT_PLAYER(1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 9") PORT_CODE(KEYCODE_9) PORT_PLAYER(1)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 3") PORT_CODE(KEYCODE_3_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT clear") PORT_CODE(KEYCODE_DEL_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 6") PORT_CODE(KEYCODE_6_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 9") PORT_CODE(KEYCODE_9_PAD) PORT_PLAYER(2)
+
+ /* line 3 */
+ PORT_START("joy3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 2") PORT_CODE(KEYCODE_2) PORT_PLAYER(1)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT enter/fire") PORT_CODE(KEYCODE_ENTER) PORT_PLAYER(1)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 5") PORT_CODE(KEYCODE_5) PORT_PLAYER(1)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 1/RIGHT 8") PORT_CODE(KEYCODE_8) PORT_PLAYER(1)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 2") PORT_CODE(KEYCODE_2_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT enter/fire") PORT_CODE(KEYCODE_ENTER_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 5") PORT_CODE(KEYCODE_5_PAD) PORT_PLAYER(2)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PAD 2/LEFT 8") PORT_CODE(KEYCODE_8_PAD) PORT_PLAYER(2)
+
+// PORT_INCLUDE( m6847_artifacting ) // breaks apfimag keyboard
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START( apf_imagination )
+
+ PORT_INCLUDE( apf_m1000 )
+
+ /* Reference: http://www.nausicaa.net/~lgreenf/apfpage2.htm */
+
+ /* keyboard line 0 */
+ PORT_START("key0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q IF") PORT_CODE(KEYCODE_Q) PORT_CHAR('q')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 \" LET") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 ! GOSUB") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W STEP") PORT_CODE(KEYCODE_W) PORT_CHAR('w')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s')
+
+ /* keyboard line 1 */
+ PORT_START("key1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R READ") PORT_CODE(KEYCODE_R) PORT_CHAR('r')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 # DATA") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $ INPUT") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E STOP") PORT_CODE(KEYCODE_E) PORT_CHAR('e')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d')
+
+ /* keyboard line 2 */
+ PORT_START("key2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N ^") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('^')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T NEXT") PORT_CODE(KEYCODE_T) PORT_CHAR('t')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 & FOR") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 % DIM") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y PRINT") PORT_CODE(KEYCODE_Y) PORT_CHAR('y')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h')
+
+ /* keyboard line 3 */
+ PORT_START("key3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M ]") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR(']')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I LIST") PORT_CODE(KEYCODE_I) PORT_CHAR('i')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 ' RETURN") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K [") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('[')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 ( THEN") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U END") PORT_CODE(KEYCODE_U) PORT_CHAR('u')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j')
+
+ /* keyboard line 4 */
+ PORT_START("key4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O _ REM") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('_')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 GOTO") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L \\") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('\\')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 ) ON") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P @ USING") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('@')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+
+ /* keyboard line 5 */
+ PORT_START("key5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(32)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(": *") PORT_CODE(KEYCODE_MINUS) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(13)
+/* Not sure about the following, could be also bit 0x10 or 0x40: using other known APF emulators as benchmark,
+ it looks like that Line Feed is not intercepted by KEY$(). Unless a better method is devised (APF assembly?)
+ I'll stick with this assignment.
+*/
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(10)
+ PORT_BIT(0x10, 0x10, IPT_UNUSED) /* ??? */
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- = RESTORE") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT(0x40, 0x40, IPT_UNUSED) /* ??? */
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Rubout") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(8)
+
+ /* line 6 */
+ PORT_START("key6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+/* This key displays the glyph "[", but a quick test reveals that its ASCII code is 27. */
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_TAB) PORT_CHAR(27)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Rept") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(UCHAR_MAMEKEY(TAB))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Here Is") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+/* It's very likely these inputs are actually disconnected: if connected they act as a duplicate of key "X" and "Z" */
+// PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Another X") PORT_CODE(KEYCODE_8_PAD)
+// PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Another Z") PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT(0x40, 0x40, IPT_UNUSED)
+ PORT_BIT(0x80, 0x80, IPT_UNUSED)
+
+ /* line 7 */
+ PORT_START("key7")
+ PORT_BIT(0xff, 0xff, IPT_UNUSED) /* ??? */
+
+INPUT_PORTS_END
+
+
+
+static const cassette_interface apf_cassette_interface =
+{
+ apf_cassette_formats,
+ NULL,
+ (cassette_state)(CASSETTE_PLAY),
+ NULL,
+ NULL
+};
+
+static LEGACY_FLOPPY_OPTIONS_START(apfimag)
+ LEGACY_FLOPPY_OPTION(apfimag, "apd", "APF disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([40])
+ SECTORS([8])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+static const floppy_interface apfimag_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD_40,
+ LEGACY_FLOPPY_OPTIONS_NAME(apfimag),
+ NULL,
+ NULL
+};
+
+static const mc6847_interface apf_mc6847_intf =
+{
+ "screen",
+ DEVCB_DRIVER_MEMBER(apf_state, apf_mc6847_videoram_r),
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(apf_state, apf_mc6847_fs_w)
+};
+
+static MACHINE_CONFIG_START( apf_imagination, apf_state )
+
+ /* basic machine hardware */
+ // MCFG_CPU_ADD("maincpu", M6800, 3750000) /* 7.8336 MHz, only 6800p type used 1 MHz max*/
+ MCFG_CPU_ADD("maincpu", M6800, 1000000 ) /* backgammon uses timing from vertical interrupt to switch between video modes during frame */
+ MCFG_CPU_PROGRAM_MAP(apf_imagination_map)
+
+ MCFG_MACHINE_START( apf_imagination )
+
+ /* video hardware */
+ MCFG_SCREEN_MC6847_NTSC_ADD("screen", "mc6847")
+ MCFG_MC6847_ADD("mc6847", MC6847_NTSC, XTAL_3_579545MHz, apf_mc6847_intf)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ //MCFG_SOUND_WAVE_ADD(WAVE_TAG, CASSETTE_TAG)
+ //MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15)
+ MCFG_SOUND_ADD(SPEAKER_TAG, SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ /* Devices */
+ MCFG_PIA6821_ADD( "pia_0", apf_m1000_pia_interface )
+ MCFG_PIA6821_ADD( "pia_1", apf_imagination_pia_interface )
+ MCFG_CASSETTE_ADD( CASSETTE_TAG, apf_cassette_interface )
+ MCFG_FD1793_ADD("wd179x", default_wd17xx_interface ) // TODO confirm type
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(apfimag_floppy_interface)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( apf_m1000, apf_imagination )
+ MCFG_CPU_MODIFY( "maincpu" )
+ MCFG_CPU_PROGRAM_MAP( apf_m1000_map)
+
+ MCFG_DEVICE_REMOVE( "pia_1" )
+
+// MCFG_DEVICE_REMOVE( WAVE_TAG )
+ MCFG_DEVICE_REMOVE( CASSETTE_TAG )
+ MCFG_LEGACY_FLOPPY_2_DRIVES_REMOVE()
+
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_INTERFACE("apfm1000_cart")
+
+ /* software lists */
+ MCFG_SOFTWARE_LIST_ADD("cart_list","apfm1000")
+MACHINE_CONFIG_END
+
+
+/***************************************************************************
+
+ Game driver(s)
+
+***************************************************************************/
+
+ROM_START(apfimag)
+ ROM_REGION(0x10000+0x0800,"maincpu",0)
+ ROM_LOAD("apf_4000.rom",0x010000, 0x00800, CRC(2a331a33) SHA1(387b90882cd0b66c192d9cbaa3bec250f897e4f1))
+ ROM_LOAD("basic_68.rom",0x06800, 0x01000, CRC(ef049ab8) SHA1(c4c12aade95dd89a4750fe7f89d57256c93da068))
+ ROM_LOAD("basic_80.rom",0x08000, 0x02000, CRC(a4c69fae) SHA1(7f98aa482589bf7c5a26d338fec105e797ba43f6))
+ROM_END
+
+ROM_START(apfm1000)
+ ROM_REGION(0x10000+0x0800,"maincpu",0)
+ ROM_LOAD("apf_4000.rom",0x010000, 0x0800, CRC(2a331a33) SHA1(387b90882cd0b66c192d9cbaa3bec250f897e4f1))
+// ROM_LOAD("apf-m1000rom.bin",0x010000, 0x0800, CRC(cc6ac840) SHA1(1110a234bcad99bd0894ad44c591389d16376ca4))
+ ROM_CART_LOAD("cart", 0x8000, 0x2000, ROM_OPTIONAL)
+ROM_END
+
+/***************************************************************************
+
+ Game driver(s)
+
+***************************************************************************/
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
+COMP(1977, apfimag, 0, 0, apf_imagination, apf_imagination, driver_device, 0, "APF Electronics Inc", "APF Imagination Machine" , GAME_NOT_WORKING )
+CONS(1978, apfm1000, 0, 0, apf_m1000, apf_m1000, driver_device, 0, "APF Electronics Inc", "APF M-1000" , GAME_NOT_WORKING)