(MESS) Apple II: Support Apple II Mouse Card [R. Belmont, Guru, Sharkpuncher]

This commit is contained in:
R. Belmont 2014-09-07 04:01:22 +00:00
parent 00f7c4d642
commit 40f25b183e
5 changed files with 628 additions and 2 deletions

2
.gitattributes vendored
View File

@ -474,6 +474,8 @@ src/emu/bus/a2bus/a2zipdrive.c svneol=native#text/plain
src/emu/bus/a2bus/a2zipdrive.h svneol=native#text/plain
src/emu/bus/a2bus/laser128.c svneol=native#text/plain
src/emu/bus/a2bus/laser128.h svneol=native#text/plain
src/emu/bus/a2bus/mouse.c svneol=native#text/plain
src/emu/bus/a2bus/mouse.h svneol=native#text/plain
src/emu/bus/a2bus/timemasterho.c svneol=native#text/plain
src/emu/bus/a2bus/timemasterho.h svneol=native#text/plain
src/emu/bus/a7800/a78_carts.h svneol=native#text/plain

530
src/emu/bus/a2bus/mouse.c Normal file
View File

@ -0,0 +1,530 @@
/*********************************************************************
mouse.c
Implemention of the Apple II Mouse Card
Apple II Mouse Interface PCB
Apple 1983
This is a mouse interface for the Apple II
PCB Layout
----------
apple computer
MOUSE INTERFACE
670-0030-C (C) 1983
Printed on back side - MOUSE INTERFACE 820-0104-B (C) 1983 APPLE COMPUTER
|-----------------------------------|
| PAL16R4 6821 |
| |
| J1 |
| 74SC245 |
| 68705P3 8516 |
| 74LS74 X1 X2 |
|-------------------| |-|
|-------------|
Notes:
J1 - 9 pin flat cable with female DB9 connector
68705P3 - Motorola MC68705P3 microcontroller (DIP28) labelled '341-0269 (C) APPLE'
PCB printed '(C) APPLE 1983 341-0269 or 342-0285'
8516 - Fujitsu MB8516 2k x8-bit EPROM (DIP24) labelled '341-0270-C (C) APPLE 1983'
PCB printed '(C) APPLE 1983 342-0270'
PAL16R4 - MMI PAL16R4ACN (DIP20) marked '341-0268-A'
PCB printed '(C) APPLE 1983 342-0268'
6821 - AMI 6821 Peripheral Interface Adapter (DIP40)
X1/X2 - Jumper pads. X1 is open, X2 is closed.
Hookup notes:
PIA port A connects to 68705 port A in its entirety (bi-directional)
PIA PB4-PB7 connects to 68705 PC0-3 (bi-directional)
PIA PB0 is 'sync latch'
PIA PB1 is A8 on the EPROM
PIA PB2 is A9 on the EPROM
PIA PB3 is A10 on the EPROM
68705 PB0 is mouse X1
68705 PB1 is mouse X0
68705 PB2 is mouse Y0
68705 PB3 is mouse Y1
68705 PB4 and 5 are N/C
68705 PB6 is IRQ for the slot
68705 PB7 is the mouse button
68705 is clocked at 2M
PIA is clocked at 1M
See the schematic at:
http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Digitizers/Apple%20Mouse%20Interface%20Card/Schematics/
*********************************************************************/
#include "mouse.h"
/***************************************************************************
PARAMETERS
***************************************************************************/
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
const device_type A2BUS_MOUSE = &device_creator<a2bus_mouse_device>;
#define MOUSE_ROM_REGION "a2mse_rom"
#define MOUSE_PIA_TAG "a2mse_pia"
#define MOUSE_MCU_TAG "a2mse_mcu"
#define MOUSE_MCU_ROM "a2mse_mcurom"
#define MOUSE_BUTTON_TAG "a2mse_button"
#define MOUSE_XAXIS_TAG "a2mse_x"
#define MOUSE_YAXIS_TAG "a2mse_y"
#define TIMER_68705 0
#define TIMER_QUADRATURE 1
static ADDRESS_MAP_START( mcu_mem, AS_PROGRAM, 8, a2bus_mouse_device )
ADDRESS_MAP_GLOBAL_MASK(0x7ff)
AM_RANGE(0x0000, 0x0000) AM_READWRITE(mcu_port_a_r, mcu_port_a_w)
AM_RANGE(0x0001, 0x0001) AM_READWRITE(mcu_port_b_r, mcu_port_b_w)
AM_RANGE(0x0002, 0x0002) AM_READWRITE(mcu_port_c_r, mcu_port_c_w)
AM_RANGE(0x0004, 0x0004) AM_WRITE(mcu_ddr_a_w)
AM_RANGE(0x0005, 0x0005) AM_WRITE(mcu_ddr_b_w)
AM_RANGE(0x0006, 0x0006) AM_WRITE(mcu_ddr_c_w)
AM_RANGE(0x0008, 0x0009) AM_READWRITE(mcu_timer_r, mcu_timer_w)
AM_RANGE(0x0010, 0x007f) AM_RAM
AM_RANGE(0x0080, 0x07ff) AM_ROM AM_REGION(MOUSE_MCU_ROM, 0x80)
ADDRESS_MAP_END
MACHINE_CONFIG_FRAGMENT( mouse )
MCFG_CPU_ADD(MOUSE_MCU_TAG, M68705, 2043600)
MCFG_CPU_PROGRAM_MAP(mcu_mem)
MCFG_DEVICE_ADD(MOUSE_PIA_TAG, PIA6821, 1021800)
MCFG_PIA_READPA_HANDLER(READ8(a2bus_mouse_device, pia_in_a))
MCFG_PIA_READPB_HANDLER(READ8(a2bus_mouse_device, pia_in_b))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(a2bus_mouse_device, pia_out_a))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(a2bus_mouse_device, pia_out_b))
MCFG_PIA_IRQA_HANDLER(WRITELINE(a2bus_mouse_device, pia_irqa_w))
MCFG_PIA_IRQB_HANDLER(WRITELINE(a2bus_mouse_device, pia_irqb_w))
MACHINE_CONFIG_END
ROM_START( mouse )
ROM_REGION(0x800, MOUSE_ROM_REGION, 0)
ROM_LOAD( "341-0270-c.4b", 0x000000, 0x000800, CRC(0bcd1e8e) SHA1(3a9d881a8a8d30f55b9719aceebbcf717f829d6f) )
ROM_REGION(0x800, MOUSE_MCU_ROM, 0)
ROM_LOAD( "341-0269.2b", 0x000000, 0x000800, CRC(94067f16) SHA1(3a2baa6648efe4456d3ec3721216e57c64f7acfc) )
ROM_REGION(0xc00, "pal", 0)
ROM_LOAD( "mmi_pal16r4a(jedec).2a", 0x000000, 0x000b04, CRC(1d620ee5) SHA1(5aa9a515c919ff7a18878649cac5d44f0c2abf28) )
ROM_LOAD( "mmi_pal16r4a(binary).2a", 0x000000, 0x000100, CRC(1da5c745) SHA1(ba267b69a2fda2a2348b140979ece562411bb37b) )
ROM_END
static INPUT_PORTS_START( mouse )
PORT_START(MOUSE_BUTTON_TAG) /* Mouse - button */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button") PORT_CODE(MOUSECODE_BUTTON1)
PORT_START(MOUSE_XAXIS_TAG) /* Mouse - X AXIS */
PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(40) PORT_KEYDELTA(0) PORT_PLAYER(1)
PORT_START(MOUSE_YAXIS_TAG) /* Mouse - Y AXIS */
PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(40) PORT_KEYDELTA(0) PORT_PLAYER(1)
INPUT_PORTS_END
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor a2bus_mouse_device::device_input_ports() const
{
return INPUT_PORTS_NAME( mouse );
}
//-------------------------------------------------
// machine_config_additions - device-specific
// machine configurations
//-------------------------------------------------
machine_config_constructor a2bus_mouse_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( mouse );
}
//-------------------------------------------------
// rom_region - device-specific ROM region
//-------------------------------------------------
const rom_entry *a2bus_mouse_device::device_rom_region() const
{
return ROM_NAME( mouse );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
device_t(mconfig, type, name, tag, owner, clock, shortname, source),
device_a2bus_card_interface(mconfig, *this),
m_pia(*this, MOUSE_PIA_TAG),
m_mcu(*this, MOUSE_MCU_TAG),
m_mouseb(*this, MOUSE_BUTTON_TAG),
m_mousex(*this, MOUSE_XAXIS_TAG),
m_mousey(*this, MOUSE_YAXIS_TAG)
{
m_started = false;
m_rom_bank = 0;
}
a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, A2BUS_MOUSE, "Apple II Mouse Card", tag, owner, clock, "a2mouse", __FILE__),
device_a2bus_card_interface(mconfig, *this),
m_pia(*this, MOUSE_PIA_TAG),
m_mcu(*this, MOUSE_MCU_TAG),
m_mouseb(*this, MOUSE_BUTTON_TAG),
m_mousex(*this, MOUSE_XAXIS_TAG),
m_mousey(*this, MOUSE_YAXIS_TAG)
{
m_started = false;
m_rom_bank = 0;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void a2bus_mouse_device::device_start()
{
// set_a2bus_device makes m_slot valid
set_a2bus_device();
astring tempstring;
m_rom = device().machine().root_device().memregion(this->subtag(tempstring, MOUSE_ROM_REGION))->base();
// allocate two timers: one for the 68705, one for the quadrature magic
m_timer = timer_alloc(TIMER_68705, NULL);
m_read_timer = timer_alloc(TIMER_QUADRATURE, NULL);
m_timer->adjust(attotime::never, TIMER_68705);
m_read_timer->adjust(attotime::never, TIMER_QUADRATURE);
// get 68705P3 mask option byte
m_mask_option = m_rom[0x784];
// register save state variables
save_item(NAME(m_ddr_a));
save_item(NAME(m_ddr_b));
save_item(NAME(m_ddr_c));
save_item(NAME(m_port_a_out));
save_item(NAME(m_port_b_out));
save_item(NAME(m_port_c_out));
save_item(NAME(m_port_a_in));
save_item(NAME(m_port_b_in));
save_item(NAME(m_port_c_in));
save_item(NAME(m_timer_cnt));
save_item(NAME(m_timer_ctl));
save_item(NAME(last_mx));
save_item(NAME(last_my));
save_item(NAME(count_x));
save_item(NAME(count_y));
}
void a2bus_mouse_device::device_reset()
{
m_started = true;
m_rom_bank = 0;
last_mx = last_my = count_x = count_y = 0;
m_timer_cnt = 0xff;
m_timer_ctl = 0x40; // disable interrupt, everything else clear
m_port_a_in = 0;
m_port_b_in = 0x80;
m_port_c_in = 0;
// are we emulating the mask part with a semi-programmable timer?
if (m_mask_option & 0x40)
{
m_timer_ctl |= m_mask_option & 0x17;
}
m_read_timer->adjust(attotime::from_hz(600.0), TIMER_QUADRATURE, attotime::from_hz(600.0));
}
/*-------------------------------------------------
read_c0nx - called for reads from this card's c0nx space
-------------------------------------------------*/
UINT8 a2bus_mouse_device::read_c0nx(address_space &space, UINT8 offset)
{
return m_pia->read(space, offset & 3);
}
/*-------------------------------------------------
write_c0nx - called for writes to this card's c0nx space
-------------------------------------------------*/
void a2bus_mouse_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data)
{
m_pia->write(space, offset & 3, data);
}
/*-------------------------------------------------
read_cnxx - called for reads from this card's cnxx space
-------------------------------------------------*/
UINT8 a2bus_mouse_device::read_cnxx(address_space &space, UINT8 offset)
{
return m_rom[offset+m_rom_bank];
}
READ8_MEMBER(a2bus_mouse_device::pia_in_a)
{
return m_port_a_out;
}
READ8_MEMBER(a2bus_mouse_device::pia_in_b)
{
return (m_port_c_out << 4);
}
WRITE8_MEMBER(a2bus_mouse_device::pia_out_a)
{
m_port_a_in = data;
}
WRITE8_MEMBER(a2bus_mouse_device::pia_out_b)
{
m_port_c_in &= 0xf0;
m_port_c_in |= ((data >> 4) & 0xf);
m_rom_bank = (data & 0xe) << 7;
}
WRITE_LINE_MEMBER(a2bus_mouse_device::pia_irqa_w)
{
}
WRITE_LINE_MEMBER(a2bus_mouse_device::pia_irqb_w)
{
}
READ8_MEMBER(a2bus_mouse_device::mcu_port_a_r)
{
return (m_port_a_out & m_ddr_a) | (m_port_a_in & ~m_ddr_a);
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_port_a_w)
{
m_port_a_out = data;
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_a_w)
{
m_ddr_a = data;
}
READ8_MEMBER(a2bus_mouse_device::mcu_port_b_r)
{
UINT8 b_in = m_port_b_in;
// clear the gates, leave everything else alone between pulses
m_port_b_in &= 0x85;
return (m_port_b_out & m_ddr_b) | (b_in & ~m_ddr_b);
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_port_b_w)
{
m_port_b_out = data;
if (!(data & 0x40))
{
raise_slot_irq();
}
else
{
lower_slot_irq();
}
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_b_w)
{
m_ddr_b = data;
}
READ8_MEMBER(a2bus_mouse_device::mcu_port_c_r)
{
return (m_port_c_out & m_ddr_c) | (m_port_c_in & ~m_ddr_c);
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_port_c_w)
{
m_port_c_out = data;
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_c_w)
{
m_ddr_c = data;
}
READ8_MEMBER(a2bus_mouse_device::mcu_timer_r)
{
if (offset == 1)
{
return m_timer_ctl;
}
return m_timer_cnt;
}
WRITE8_MEMBER(a2bus_mouse_device::mcu_timer_w)
{
static const int prescale[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
bool recalc = false;
// offset 0 = timer data (counts down)
if (offset == 0)
{
m_timer_cnt = data;
recalc = true;
}
// offset 1 = timer control: b7 = IRQ, b6 = IRQ mask (1=suppress),
// b5 = input select (0=CPU clk, 1=ext),
// b4 = enable external timer input,
// b3 = clear, b2-b0 = scaler (1/2/4/8/16/32/64/128)
else
{
// clearing the interrupt?
if ((m_timer_ctl & 0x80) && !(data & 0x80))
{
m_mcu->set_input_line(M68705_INT_TIMER, CLEAR_LINE);
}
if (m_mask_option & 0x40)
{
m_timer_ctl &= 0x3f;
m_timer_ctl |= (data & 0xc0);
}
else
{
// if any parameters that affect the timer changed, recalc now
if ((data & 0x3f) != (m_timer_ctl & 0x3f))
{
recalc = true;
}
// if prescaler reset, recalc
if (data & 0x8)
{
recalc = true;
}
m_timer_ctl = data;
}
}
if (recalc)
{
// recalculate the timer now
UINT32 m_ticks = 2043600 / 4;
m_ticks /= prescale[m_timer_ctl & 7];
m_ticks /= (int)(m_timer_cnt + 1);
m_timer->adjust(attotime::from_hz((double)m_ticks), TIMER_68705, attotime::from_hz((double)m_ticks));
}
}
/*
X0 = direction, 0 = left, 1 = right
X1 = gate, must go 0/1 for each pixel moved
Y0 = direction, 0 = up, 1 = down
Y1 = gate, must go 0/1 for each pixel moved
The direction must stay constant for a given train of gate pulses or the MCU will get confused.
*/
void a2bus_mouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (id == TIMER_68705) // 68705's built-in timer
{
m_timer_ctl |= 0x80; // indicate timer expired
if (!(m_timer_ctl & 0x40)) // if interrupt not suppressed, fire!
{
m_mcu->set_input_line(M68705_INT_TIMER, ASSERT_LINE);
}
}
else if (id == TIMER_QUADRATURE)
{
int new_mx, new_my;
m_port_b_in = 0x80;
// update button now
if (m_mouseb->read()) m_port_b_in &= ~0x80;
// read the axes
new_mx = m_mousex->read();
new_my = m_mousey->read();
// did X change?
if (new_mx != last_mx)
{
int diff = new_mx - last_mx;
/* check for wrap */
if (diff > 0x80)
diff = 0x100-diff;
if (diff < -0x80)
diff = -0x100-diff;
count_x += diff;
last_mx = new_mx;
}
// did Y change?
if (new_my != last_my)
{
int diff = new_my - last_my;
/* check for wrap */
if (diff > 0x80)
diff = 0x100-diff;
if (diff < -0x80)
diff = -0x100-diff;
count_y += diff;
last_my = new_my;
}
if (count_x)
{
if (count_x < 0)
{
count_x++;
}
else
{
count_x--;
m_port_b_in |= 0x01; // X1
}
m_port_b_in |= 0x02; // X0
}
else if (count_y)
{
if (count_y < 0)
{
count_y++;
}
else
{
count_y--;
m_port_b_in |= 0x04; // Y0
}
m_port_b_in |= 0x08; // Y1
}
}
}

91
src/emu/bus/a2bus/mouse.h Normal file
View File

@ -0,0 +1,91 @@
/*********************************************************************
mouse.h
Implemention of the Apple II Mouse Card
*********************************************************************/
#ifndef __A2BUS_MOUSE__
#define __A2BUS_MOUSE__
#include "emu.h"
#include "a2bus.h"
#include "machine/6821pia.h"
#include "cpu/m6805/m6805.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class a2bus_mouse_device:
public device_t,
public device_a2bus_card_interface
{
public:
// construction/destruction
a2bus_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
a2bus_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// optional information overrides
virtual machine_config_constructor device_mconfig_additions() const;
virtual const rom_entry *device_rom_region() const;
virtual ioport_constructor device_input_ports() const;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
DECLARE_READ8_MEMBER(pia_in_a);
DECLARE_READ8_MEMBER(pia_in_b);
DECLARE_WRITE8_MEMBER(pia_out_a);
DECLARE_WRITE8_MEMBER(pia_out_b);
DECLARE_WRITE_LINE_MEMBER(pia_irqa_w);
DECLARE_WRITE_LINE_MEMBER(pia_irqb_w);
DECLARE_READ8_MEMBER(mcu_port_a_r);
DECLARE_READ8_MEMBER(mcu_port_b_r);
DECLARE_READ8_MEMBER(mcu_port_c_r);
DECLARE_WRITE8_MEMBER(mcu_port_a_w);
DECLARE_WRITE8_MEMBER(mcu_port_b_w);
DECLARE_WRITE8_MEMBER(mcu_port_c_w);
DECLARE_WRITE8_MEMBER(mcu_ddr_a_w);
DECLARE_WRITE8_MEMBER(mcu_ddr_b_w);
DECLARE_WRITE8_MEMBER(mcu_ddr_c_w);
DECLARE_READ8_MEMBER(mcu_timer_r);
DECLARE_WRITE8_MEMBER(mcu_timer_w);
protected:
virtual void device_start();
virtual void device_reset();
// overrides of standard a2bus slot functions
virtual UINT8 read_c0nx(address_space &space, UINT8 offset);
virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data);
virtual UINT8 read_cnxx(address_space &space, UINT8 offset);
required_device<pia6821_device> m_pia;
required_device<m68705_device> m_mcu;
required_ioport m_mouseb, m_mousex, m_mousey;
private:
UINT8 *m_rom;
bool m_started;
int m_rom_bank;
UINT8 m_ddr_a;
UINT8 m_ddr_b;
UINT8 m_ddr_c;
UINT8 m_port_a_out;
UINT8 m_port_b_out;
UINT8 m_port_c_out;
UINT8 m_port_a_in;
UINT8 m_port_b_in;
UINT8 m_port_c_in;
UINT8 m_timer_cnt;
UINT8 m_timer_ctl;
UINT8 m_mask_option;
int last_mx, last_my, count_x, count_y;
emu_timer *m_timer, *m_read_timer;
};
// device type definition
extern const device_type A2BUS_MOUSE;
#endif /* __A2BUS_MOUSE__ */

View File

@ -764,6 +764,7 @@ BUSOBJS += $(BUSOBJ)/a2bus/a2diskiing.o
BUSOBJS += $(BUSOBJ)/a2bus/a2mcms.o
BUSOBJS += $(BUSOBJ)/a2bus/a2dx1.o
BUSOBJS += $(BUSOBJ)/a2bus/timemasterho.o
BUSOBJS += $(BUSOBJ)/a2bus/mouse.o
endif
#-------------------------------------------------

View File

@ -226,6 +226,7 @@ Address bus A0-A11 is Y0-Y11
#include "bus/a2bus/a2mcms.h"
#include "bus/a2bus/a2dx1.h"
#include "bus/a2bus/timemasterho.h"
#include "bus/a2bus/mouse.h"
#include "bus/a2bus/a2estd80col.h"
#include "bus/a2bus/a2eext80col.h"
#include "bus/a2bus/a2eramworks3.h"
@ -366,12 +367,12 @@ INPUT_PORTS_END
PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH)
INPUT_PORTS_END
*/
static INPUT_PORTS_START( apple2_gameport )
INPUT_PORTS_START( apple2_gameport )
PORT_INCLUDE( apple2_joystick )
//PORT_INCLUDE( apple2_paddle )
INPUT_PORTS_END
static INPUT_PORTS_START( apple2_sysconfig )
INPUT_PORTS_START( apple2_sysconfig )
PORT_START("a2_config")
PORT_CONFNAME(0x03, 0x00, "Composite monitor type")
PORT_CONFSETTING(0x00, "Color")
@ -1028,6 +1029,7 @@ static SLOT_INTERFACE_START(apple2_cards)
SLOT_INTERFACE("mcms2", A2BUS_MCMS2) /* Mountain Computer Music System, card 2 of 2. must be in card 1's slot + 1! */
SLOT_INTERFACE("dx1", A2BUS_DX1) /* Decillonix DX-1 sampler card */
SLOT_INTERFACE("tm2ho", A2BUS_TIMEMASTERHO) /* Applied Engineering TimeMaster II H.O. */
SLOT_INTERFACE("mouse", A2BUS_MOUSE) /* Apple II Mouse Card */
SLOT_INTERFACE_END
static SLOT_INTERFACE_START(apple2eaux_cards)