(MESS) NES input cleanup, part 5 and last (Simplified FC input too, added Arkanoid FC paddle

emulation, fixed P3 & P4 inputs in Jpn games using them). nw.

paddle now works in Chase HQ too (the NES one don't because of the different protocol), 
3rd & 4th players can enter inputs in Technos games, and it turned out that Lightgun was 
actually working (I had probably tested with a non-clean compile), so that at last all selectable 
input devices are finally working :-)
This commit is contained in:
Fabio Priuli 2013-06-15 16:30:05 +00:00
parent 1f2cde8956
commit 1ebbe17e7f
3 changed files with 197 additions and 188 deletions

View File

@ -59,7 +59,7 @@ ADDRESS_MAP_END
static INPUT_PORTS_START( nes_pads12 )
PORT_START("PAD1") /* Joypad 1 */
PORT_START("PAD1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 A") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 B") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
@ -69,7 +69,7 @@ static INPUT_PORTS_START( nes_pads12 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_START("PAD2") /* Joypad 2 */
PORT_START("PAD2")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
@ -82,7 +82,7 @@ static INPUT_PORTS_START( nes_pads12 )
INPUT_PORTS_END
static INPUT_PORTS_START( nes_pads34 )
PORT_START("PAD3") /* Joypad 3 */
PORT_START("PAD3")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 A") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 B") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
@ -92,7 +92,7 @@ static INPUT_PORTS_START( nes_pads34 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_START("PAD4") /* Joypad 4 */
PORT_START("PAD4")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 A") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 B") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
@ -105,27 +105,27 @@ static INPUT_PORTS_START( nes_pads34 )
INPUT_PORTS_END
static INPUT_PORTS_START( nes_zapper1 )
PORT_START("ZAPPER1_X") /* P1 zapper */
PORT_START("ZAPPER1_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0002)
PORT_START("ZAPPER1_Y") /* P1 zapper */
PORT_START("ZAPPER1_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0002)
PORT_START("ZAPPER1_T") /* P1 zapper trigger */
PORT_START("ZAPPER1_T")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P1 Lightgun Trigger") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0002)
INPUT_PORTS_END
static INPUT_PORTS_START( nes_zapper2 )
PORT_START("ZAPPER2_X") /* P2 zapper */
PORT_START("ZAPPER2_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0020)
PORT_START("ZAPPER2_Y") /* P2 zapper */
PORT_START("ZAPPER2_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255 ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0020)
PORT_START("ZAPPER2_T") /* P2 zapper trigger */
PORT_START("ZAPPER2_T")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P2 Lightgun Trigger") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0020)
INPUT_PORTS_END
static INPUT_PORTS_START( nes_paddle )
PORT_START("PADDLE") /* Arkanoid paddle */
PORT_START("PADDLE")
PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x62,0xf2) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0040)
PORT_START("PADDLE_BUTTON") /* Arkanoid paddle button */
PORT_START("PADDLE_BUTTON")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Paddle button") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0040)
INPUT_PORTS_END
@ -136,7 +136,7 @@ static INPUT_PORTS_START( nes )
PORT_INCLUDE( nes_zapper2 )
PORT_INCLUDE( nes_paddle )
PORT_START("CTRLSEL") /* Select Controller Type */
PORT_START("CTRLSEL")
PORT_CONFNAME( 0x000f, 0x0001, "P1 Controller")
PORT_CONFSETTING( 0x0000, "Unconnected" )
PORT_CONFSETTING( 0x0001, "Gamepad" )
@ -154,7 +154,7 @@ static INPUT_PORTS_START( nes )
PORT_CONFSETTING( 0x0000, "Unconnected" )
PORT_CONFSETTING( 0x1000, "Gamepad" )
PORT_START("CONFIG") /* configuration */
PORT_START("CONFIG")
PORT_CONFNAME( 0x01, 0x00, "Draw Top/Bottom 8 Lines")
PORT_CONFSETTING( 0x01, DEF_STR(No) )
PORT_CONFSETTING( 0x00, DEF_STR(Yes) )
@ -165,7 +165,7 @@ INPUT_PORTS_END
static INPUT_PORTS_START( fc_pads12 )
PORT_START("PAD1") /* Joypad 1 */
PORT_START("PAD1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 A") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 B") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
@ -175,7 +175,7 @@ static INPUT_PORTS_START( fc_pads12 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x000f, EQUALS, 0x0001)
PORT_START("PAD2") /* Joypad 2 */
PORT_START("PAD2")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x00f0, EQUALS, 0x0010)
@ -188,7 +188,7 @@ static INPUT_PORTS_START( fc_pads12 )
INPUT_PORTS_END
static INPUT_PORTS_START( fc_pads34 )
PORT_START("PAD3") /* Joypad 3 */
PORT_START("PAD3")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 A") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 B") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
@ -198,7 +198,7 @@ static INPUT_PORTS_START( fc_pads34 )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0x0f00, EQUALS, 0x0100)
PORT_START("PAD4") /* Joypad 4 */
PORT_START("PAD4")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 A") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 B") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf000, EQUALS, 0x1000)
@ -210,17 +210,19 @@ static INPUT_PORTS_START( fc_pads34 )
INPUT_PORTS_END
static INPUT_PORTS_START( fc_lightgun )
PORT_START("ZAPPER2_X") /* P2 zapper */
PORT_START("ZAPPER2_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x01)
PORT_START("ZAPPER2_Y") /* P2 zapper */
PORT_START("ZAPPER2_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255) PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x01)
PORT_START("ZAPPER2_T") /* P2 zapper trigger */
PORT_START("ZAPPER2_T")
PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Lightgun Trigger") PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x01)
INPUT_PORTS_END
static INPUT_PORTS_START( fc_paddle )
PORT_START("PADDLE") /* Arkanoid paddle */
PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(3) PORT_MINMAX(0x62,0xf2) PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x04)
PORT_START("PADDLE")
PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x62,0xf2) PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x04)
PORT_START("PADDLE_BUTTON")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Paddle button") PORT_PLAYER(2) PORT_CONDITION("EXP", 0x0f, EQUALS, 0x04)
INPUT_PORTS_END
static INPUT_PORTS_START( fc_cclimb )
@ -502,6 +504,7 @@ static INPUT_PORTS_START( famicom )
PORT_INCLUDE( fc_pads12 )
PORT_INCLUDE( fc_pads34 )
PORT_INCLUDE( fc_lightgun )
// FIXME: was it possible to attache two paddles in a Famicom (as the Arkanoid 2 box suggests)?!? investigate...
PORT_INCLUDE( fc_paddle )
// Crazy Climber is not really a separate controller, but a couple of small sticks to be
// put on top of d-pads of the regular controllers. Users should then control the game
@ -511,7 +514,7 @@ static INPUT_PORTS_START( famicom )
PORT_INCLUDE( subor_keyboard )
PORT_INCLUDE( mahjong_panel )
PORT_START("CTRLSEL") /* Select Controller Type */
PORT_START("CTRLSEL")
PORT_CONFNAME( 0x000f, 0x0001, "P1 Controller")
PORT_CONFSETTING( 0x0000, "Unconnected" )
PORT_CONFSETTING( 0x0001, "Gamepad" )
@ -527,7 +530,7 @@ static INPUT_PORTS_START( famicom )
PORT_CONFSETTING( 0x0000, "Unconnected" )
PORT_CONFSETTING( 0x1000, "Gamepad" )
PORT_START("EXP") /* expansion port */
PORT_START("EXP")
PORT_CONFNAME( 0x0f, 0x00, "Expansion Port")
PORT_CONFSETTING( 0x00, "(Empty)" )
PORT_CONFSETTING( 0x01, "Light Gun" )
@ -538,7 +541,7 @@ static INPUT_PORTS_START( famicom )
PORT_CONFSETTING( 0x06, "Mahjong Panel" )
PORT_CONFSETTING( 0x07, "Hori Twin Adapter" )
PORT_START("CONFIG") /* configuration */
PORT_START("CONFIG")
PORT_CONFNAME( 0x01, 0x00, "Draw Top/Bottom 8 Lines")
PORT_CONFSETTING( 0x01, DEF_STR(No) )
PORT_CONFSETTING( 0x00, DEF_STR(Yes) )
@ -546,7 +549,7 @@ static INPUT_PORTS_START( famicom )
PORT_CONFSETTING( 0x02, DEF_STR(No) )
PORT_CONFSETTING( 0x00, DEF_STR(Yes) )
PORT_START("FLIPDISK") /* fake keys */
PORT_START("FLIPDISK") /* fake key */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Change Disk Side")
INPUT_PORTS_END

View File

@ -555,9 +555,10 @@ public:
void fds_irq(int scanline, int vblank, int blanked);
UINT32 m_pad_latch[2];
UINT32 m_pad_latch[4];
UINT8 m_zapper_latch[2][3];
UINT8 m_paddle_latch, m_paddle_btn_latch;
UINT8 m_mjpanel_latch;
protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);

View File

@ -81,6 +81,7 @@ static void nes_state_register( running_machine &machine )
state->save_item(NAME(state->m_zapper_latch));
state->save_item(NAME(state->m_paddle_latch));
state->save_item(NAME(state->m_paddle_btn_latch));
state->save_item(NAME(state->m_mjpanel_latch));
}
@ -245,7 +246,7 @@ READ8_MEMBER(nes_state::nes_in0_r)
}
if (LOG_JOY)
logerror("joy 0 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, space.device().safe_pc(), m_in_0.shift, m_in_0.i0);
logerror("joy 0 read, val: %02x, pc: %04x\n", ret, space.device().safe_pc());
return ret;
}
@ -296,7 +297,7 @@ READ8_MEMBER(nes_state::nes_in1_r)
}
if (LOG_JOY)
logerror("joy 1 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, space.device().safe_pc(), m_in_1.shift, m_in_1.i0);
logerror("joy 1 read, val: %02x, pc: %04x\n", ret, space.device().safe_pc());
return ret;
}
@ -304,7 +305,10 @@ READ8_MEMBER(nes_state::nes_in1_r)
WRITE8_MEMBER(nes_state::nes_in0_w)
{
int cfg = m_io_ctrlsel->read();
if (LOG_JOY)
logerror("joy write, val: %02x, pc: %04x\n", data, space.device().safe_pc());
// Check if lightgun has been chosen as input: if so, enable crosshair
timer_set(attotime::zero, TIMER_ZAPPER_TICK);
@ -319,7 +323,8 @@ WRITE8_MEMBER(nes_state::nes_in0_w)
m_zapper_latch[0][2] = 0;
m_zapper_latch[1][0] = 0;
m_zapper_latch[1][1] = 0;
m_zapper_latch[1][2] = 0;
m_zapper_latch[1][2] = 0;
m_paddle_btn_latch = 0;
m_paddle_latch = 0;
// P1 inputs
@ -354,7 +359,8 @@ WRITE8_MEMBER(nes_state::nes_in0_w)
m_paddle_latch = (UINT8) (m_io_paddle->read() ^ 0xff);
break;
}
// P3 & P4 inputs in NES Four Score are read serially with P1 & P2
// P3 inputs
if ((cfg & 0x0f00))
m_pad_latch[0] |= ((m_io_pad[2]->read() << 8) | (0x08 << 16)); // pad 3 + signature
@ -373,29 +379,46 @@ WRITE8_MEMBER(nes_state::nes_in1_w)
READ8_MEMBER(nes_state::fc_in0_r)
{
int exp = m_io_exp->read();
/* Some games expect bit 6 to be set because the last entry on the data bus shows up */
/* in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there. */
UINT8 ret = 0x40;
if ((exp & 0x0f) == 0x02)
{
// tape input
if ((m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY)
{
double level = m_cassette->input();
if (level < 0)
ret |= 0x00;
else
ret |= 0x02;
}
// Some games expect bit 6 to be set because the last entry on the data bus shows up
// in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there.
UINT8 ret = 0x40;
ret |= (m_pad_latch[0] & 0x01);
// shift
m_pad_latch[0] >>= 1;
// EXP input
switch (exp & 0x0f)
{
case 0x02: // FC Keyboard: tape input
if ((m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY)
{
double level = m_cassette->input();
if (level < 0)
ret |= 0x00;
else
ret |= 0x02;
}
break;
case 0x04: // Arkanoid paddle
ret |= (m_paddle_btn_latch << 1); // button
break;
case 0x06: // Mahjong Panel
ret |= ((m_mjpanel_latch & 0x01) << 1);
m_mjpanel_latch >>= 1;
break;
case 0x07: // 'multitap' p3
ret |= ((m_pad_latch[2] & 0x01) << 1);
m_pad_latch[2] >>= 1;
break;
}
ret |= ((m_in_0.i0 >> m_in_0.shift) & 0x01);
if (LOG_JOY)
logerror("joy 0 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, space.device().safe_pc(), m_in_0.shift, m_in_0.i0);
m_in_0.shift++;
logerror("joy 0 read, val: %02x, pc: %04x\n", ret, space.device().safe_pc());
return ret;
}
@ -403,75 +426,76 @@ READ8_MEMBER(nes_state::fc_in0_r)
READ8_MEMBER(nes_state::fc_in1_r)
{
int exp = m_io_exp->read();
/* Some games expect bit 6 to be set because the last entry on the data bus shows up */
/* in the unused upper 3 bits, so typically a read from $4017 leaves 0x40 there. */
// Some games expect bit 6 to be set because the last entry on the data bus shows up
// in the unused upper 3 bits, so typically a read from $4017 leaves 0x40 there.
UINT8 ret = 0x40;
ret |= (m_pad_latch[1] & 0x01);
// row of the keyboard matrix are read 4-bits at time, and gets returned as bit1->bit4
if ((exp & 0x0f) == 0x02)
// shift
m_pad_latch[1] >>= 1;
// EXP input
switch (exp & 0x0f)
{
if (m_fck_scan < 9)
ret |= ~(((m_io_fckey[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e;
else
ret |= 0x1e;
}
if ((exp & 0x0f) == 0x03)
{
if (m_fck_scan < 12)
ret |= ~(((m_io_subkey[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e;
else
ret |= 0x1e;
}
/* Handle data line 0's serial output */
if ((exp & 0x0f) == 0x06)
ret |= (((m_in_1.i0 >> m_in_1.shift) & 0x01) << 1);
else
ret |= ((m_in_1.i0 >> m_in_1.shift) & 0x01);
/* zapper */
if ((exp & 0x0f) == 0x01)
{
int x = m_in_1.i1; /* read Zapper x-position */
int y = m_in_1.i2; /* read Zapper y-position */
UINT32 pix, color_base;
/* get the pixel at the gun position */
pix = m_ppu->get_pixel(x, y);
/* get the color base from the ppu */
color_base = m_ppu->get_colorbase();
/* look at the screen and see if the cursor is over a bright pixel */
if ((pix == color_base + 0x20) || (pix == color_base + 0x30) ||
(pix == color_base + 0x33) || (pix == color_base + 0x34))
{
ret &= ~0x08; /* sprite hit */
}
else
ret |= 0x08; /* no sprite hit */
/* If button 1 is pressed, indicate the light gun trigger is pressed */
ret |= ((m_in_1.i0 & 0x01) << 4);
}
/* arkanoid dial */
if ((exp & 0x0f) == 0x04)
{
/* Handle data line 2's serial output */
ret |= ((m_in_1.i2 >> m_in_1.shift) & 0x01) << 3;
/* Handle data line 3's serial output - bits are reversed */
/* NPW 27-Nov-2007 - there is no third subscript! commenting out */
/* ret |= ((m_in_1[3] >> m_in_1.shift) & 0x01) << 4; */
/* ret |= ((m_in_1[3] << m_in_1.shift) & 0x80) >> 3; */
case 0x01: // Lightgun
{
int x = m_zapper_latch[0][1]; // x-position
int y = m_zapper_latch[0][2]; // y-position
UINT32 pix, color_base;
// get the pixel at the gun position
pix = m_ppu->get_pixel(x, y);
// get the color base from the ppu
color_base = m_ppu->get_colorbase();
// check if the cursor is over a bright pixel
if ((pix == color_base + 0x20) || (pix == color_base + 0x30) ||
(pix == color_base + 0x33) || (pix == color_base + 0x34))
ret &= ~0x08; // sprite hit
else
ret |= 0x08; // no sprite hit
// light gun trigger
ret |= (m_zapper_latch[0][0] << 4);
}
break;
case 0x02: // FC Keyboard: rows of the keyboard matrix are read 4-bits at time and returned as bit1->bit4
if (m_fck_scan < 9)
ret |= ~(((m_io_fckey[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e;
else
ret |= 0x1e;
break;
case 0x03: // Subor Keyboard: rows of the keyboard matrix are read 4-bits at time and returned as bit1->bit4
if (m_fck_scan < 12)
ret |= ~(((m_io_subkey[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e;
else
ret |= 0x1e;
break;
case 0x04: // Arkanoid paddle
ret |= ((m_paddle_latch & 0x80) >> 6); // paddle data
m_paddle_latch <<= 1;
m_paddle_latch &= 0xff;
break;
case 0x06: // Mahjong Panel
ret |= ((m_mjpanel_latch & 0x01) << 1);
m_mjpanel_latch >>= 1;
break;
case 0x07: // 'multitap' p4
ret |= ((m_pad_latch[3] & 0x01) << 1);
m_pad_latch[3] >>= 1;
break;
}
if (LOG_JOY)
logerror("joy 1 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, space.device().safe_pc(), m_in_1.shift, m_in_1.i0);
m_in_1.shift++;
logerror("joy 1 read, val: %02x, pc: %04x\n", ret, space.device().safe_pc());
return ret;
}
@ -480,8 +504,11 @@ WRITE8_MEMBER(nes_state::fc_in0_w)
{
int cfg = m_io_ctrlsel->read();
int exp = m_io_exp->read();
/* Check if lightgun has been chosen as input: if so, enable crosshair */
if (LOG_JOY)
logerror("joy write, val: %02x, pc: %04x\n", data, space.device().safe_pc());
// Check if lightgun has been chosen as input: if so, enable crosshair
timer_set(attotime::zero, TIMER_LIGHTGUN_TICK);
if ((exp & 0x0f) == 0x02 || (exp & 0x0f) == 0x03)
@ -504,106 +531,84 @@ WRITE8_MEMBER(nes_state::fc_in0_w)
m_fck_scan = 0;
}
}
// check 'standard' inputs
if (data & 0x01)
return;
if (LOG_JOY)
logerror("joy 0 bits read: %d\n", m_in_0.shift);
/* Toggling bit 0 high then low resets both controllers */
m_in_0.shift = 0;
m_in_1.shift = 0;
m_in_0.i0 = 0;
m_in_0.i1 = 0;
m_in_0.i2 = 0;
m_in_1.i0 = 0;
m_in_1.i1 = 0;
m_in_1.i2 = 0;
m_in_2.i0 = 0;
m_in_2.i1 = 0;
m_in_2.i2 = 0;
m_in_3.i0 = 0;
m_in_3.i1 = 0;
m_in_3.i2 = 0;
// Toggling bit 0 high then low resets controllers
m_pad_latch[0] = 0;
m_pad_latch[1] = 0;
m_pad_latch[2] = 0;
m_pad_latch[3] = 0;
m_zapper_latch[0][0] = 0;
m_zapper_latch[0][1] = 0;
m_zapper_latch[0][2] = 0;
m_paddle_btn_latch = 0;
m_paddle_latch = 0;
m_mjpanel_latch = 0;
// P1 inputs
if ((cfg & 0x000f) == 0x0001) /* gamepad 1 */
m_in_0.i0 = m_io_pad[0]->read();
else if ((cfg & 0x000f) == 0x0002) /* crazy climber controller (left stick) */
m_in_0.i0 = m_io_cc_left->read();
switch (cfg & 0x000f)
{
case 0x01: // pad 1
m_pad_latch[0] = m_io_pad[0]->read();
break;
case 0x02: // crazy climber (left stick)
m_pad_latch[0] = m_io_cc_left->read();
break;
}
// P2 inputs
if ((cfg & 0x00f0) == 0x0010) /* gamepad 2 */
m_in_1.i0 = m_io_pad[1]->read();
else if ((cfg & 0x00f0) == 0x0020) /* crazy climber controller (right stick) */
m_in_1.i0 = m_io_cc_right->read();
switch ((cfg & 0x00f0) >> 4)
{
case 0x01: // pad 2
m_pad_latch[1] = m_io_pad[1]->read();
break;
case 0x02: // crazy climber (right stick)
m_pad_latch[1] = m_io_cc_right->read();
break;
}
// P3 & P4 inputs in Famicom (e.g. through Hori Twin Adapter or Hori 4 Players Adapter)
// are read in parallel with P1 & P2 (just using diff bits)
// P3 inputs
if ((exp & 0x0f) == 7 && (cfg & 0x0f00) == 0x0100)
{
m_in_2.i0 = m_io_pad[2]->read();
m_in_0.i0 |= (m_in_2.i0 << 8) | (0x08 << 16);
}
m_pad_latch[2] = m_io_pad[2]->read(); // pad 3
// P4 inputs
if ((exp & 0x0f) == 7 && (cfg & 0xf000) == 0x1000)
{
m_in_3.i0 = m_io_pad[3]->read();
m_in_1.i0 |= (m_in_3.i0 << 8) | (0x04 << 16);
}
m_pad_latch[3] = m_io_pad[3]->read(); // pad 4
// EXP input
switch (exp & 0x0f)
{
case 0x01: // Lightgun
m_in_0.i0 = m_io_zapper2_t->read();
m_in_0.i1 = m_io_zapper2_x->read();
m_in_0.i2 = m_io_zapper2_y->read();
m_zapper_latch[0][0] = m_io_zapper2_t->read();
m_zapper_latch[0][1] = m_io_zapper2_x->read();
m_zapper_latch[0][2] = m_io_zapper2_y->read();
break;
#if 0
case 0x02: // FC Keyboard
// here we should also have the tape output
if (BIT(data, 2)) // keyboard active
{
UINT8 out = BIT(data, 1); // scan
if (m_fck_mode && !out && ++m_fck_scan > 9)
m_fck_scan = 0;
m_fck_mode = out; // access lower or upper 4 bits
if (BIT(data, 0)) // reset
m_fck_scan = 0;
}
break;
case 0x03: // Subor Keyboard
if (BIT(data, 2)) // keyboard active
{
UINT8 out = BIT(data, 1); // scan
if (m_fck_mode && !out && ++m_fck_scan > 12)
m_fck_scan = 0;
m_fck_mode = out; // access lower or upper 4 bits
if (BIT(data, 0)) // reset
m_fck_scan = 0;
}
// these are scanned differently than other devices:
// writes to $4016 with bit2 set always update the
// line counter and writing bit0 set resets the counter
break;
#endif
case 0x04: // Arkanoid paddle
m_in_1.i0 |= (UINT8) ((UINT8) m_io_paddle->read() + (UINT8)0x52) ^ 0xff;
m_paddle_btn_latch = m_io_paddle_btn->read();
m_paddle_latch = (UINT8) (m_io_paddle->read() ^ 0xff);
break;
case 0x06: // Mahjong Panel
if (data & 0xf8)
logerror("Error: Mahjong panel read with mux data %02x\n", (data & 0xfe));
else
m_in_1.i0 = m_io_mahjong[(data & 0xfe) >> 1]->read();
m_mjpanel_latch = m_io_mahjong[(data & 0xfe) >> 1]->read();
break;
}