// -----------------------------------------------------------------\r
// memmap helpers\r
\r
-#ifndef _ASM_MEMORY_C\r
-static\r
-#endif\r
-int PadRead(int i)\r
+static u32 read_pad_3btn(int i, u32 out_bits)\r
{\r
- int pad,value,data_reg;\r
- pad=~PicoPadInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
- data_reg=Pico.ioports[i+1];\r
+ u32 pad = ~PicoPadInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
+ u32 value;\r
\r
- // orr the bits, which are set as output\r
- value = data_reg&(Pico.ioports[i+4]|0x80);\r
+ if (out_bits & 0x40) // TH\r
+ value = pad & 0x3f; // ?1CB RLDU\r
+ else\r
+ value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU\r
\r
- if (PicoOpt & POPT_6BTN_PAD)\r
- {\r
- int phase = Pico.m.padTHPhase[i];\r
-\r
- if(phase == 2 && !(data_reg&0x40)) { // TH\r
- value|=(pad&0xc0)>>2; // ?0SA 0000\r
- return value;\r
- } else if(phase == 3) {\r
- if(data_reg&0x40)\r
- value|=(pad&0x30)|((pad>>8)&0xf); // ?1CB MXYZ\r
- else\r
- value|=((pad&0xc0)>>2)|0x0f; // ?0SA 1111\r
- return value;\r
- }\r
+ value |= out_bits & 0x40;\r
+ return value;\r
+}\r
+\r
+static u32 read_pad_6btn(int i, u32 out_bits)\r
+{\r
+ u32 pad = ~PicoPadInt[i]; // Get inverse of pad MXYZ SACB RLDU\r
+ int phase = Pico.m.padTHPhase[i];\r
+ u32 value;\r
+\r
+ if (phase == 2 && !(out_bits & 0x40)) {\r
+ value = (pad & 0xc0) >> 2; // ?0SA 0000\r
+ goto out;\r
+ }\r
+ else if(phase == 3) {\r
+ if (out_bits & 0x40)\r
+ return (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ\r
+ else\r
+ return ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111\r
+ goto out;\r
}\r
\r
- if(data_reg&0x40) // TH\r
- value|=(pad&0x3f); // ?1CB RLDU\r
- else value|=((pad&0xc0)>>2)|(pad&3); // ?0SA 00DU\r
+ if (out_bits & 0x40) // TH\r
+ value = pad & 0x3f; // ?1CB RLDU\r
+ else\r
+ value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU\r
\r
- return value; // will mirror later\r
+out:\r
+ value |= out_bits & 0x40;\r
+ return value;\r
}\r
\r
-#ifndef _ASM_MEMORY_C\r
+static u32 read_nothing(int i, u32 out_bits)\r
+{\r
+ return 0xff;\r
+}\r
+\r
+typedef u32 (port_read_func)(int index, u32 out_bits);\r
+\r
+static port_read_func *port_readers[3] = {\r
+ read_pad_3btn,\r
+ read_pad_3btn,\r
+ read_nothing\r
+};\r
\r
-static u32 io_ports_read(u32 a)\r
+static NOINLINE u32 port_read(int i)\r
+{\r
+ u32 data_reg = Pico.ioports[i + 1];\r
+ u32 ctrl_reg = Pico.ioports[i + 4] | 0x80;\r
+ u32 in, out;\r
+\r
+ out = data_reg & ctrl_reg;\r
+ out |= 0x7f & ~ctrl_reg; // pull-ups\r
+\r
+ in = port_readers[i](i, out);\r
+\r
+ return (in & ~ctrl_reg) | (data_reg & ctrl_reg);\r
+}\r
+\r
+void PicoSetInputDevice(int port, enum input_device device)\r
+{\r
+ port_read_func *func;\r
+\r
+ if (port < 0 || port > 2)\r
+ return;\r
+\r
+ switch (device) {\r
+ case PICO_INPUT_PAD_3BTN:\r
+ func = read_pad_3btn;\r
+ break;\r
+\r
+ case PICO_INPUT_PAD_6BTN:\r
+ func = read_pad_6btn;\r
+ break;\r
+\r
+ default:\r
+ func = read_nothing;\r
+ break;\r
+ }\r
+\r
+ port_readers[port] = func;\r
+}\r
+\r
+NOINLINE u32 io_ports_read(u32 a)\r
{\r
u32 d;\r
a = (a>>1) & 0xf;\r
switch (a) {\r
case 0: d = Pico.m.hardware; break; // Hardware value (Version register)\r
- case 1: d = PadRead(0); break;\r
- case 2: d = PadRead(1); break;\r
+ case 1: d = port_read(0); break;\r
+ case 2: d = port_read(1); break;\r
+ case 3: d = port_read(2); break;\r
default: d = Pico.ioports[a]; break; // IO ports can be used as RAM\r
}\r
return d;\r
}\r
\r
-static void NOINLINE io_ports_write(u32 a, u32 d)\r
+NOINLINE void io_ports_write(u32 a, u32 d)\r
{\r
a = (a>>1) & 0xf;\r
\r
// 6 button gamepad: if TH went from 0 to 1, gamepad changes state\r
- if (1 <= a && a <= 2 && (PicoOpt & POPT_6BTN_PAD))\r
+ if (1 <= a && a <= 2)\r
{\r
Pico.m.padDelay[a - 1] = 0;\r
if (!(Pico.ioports[a] & 0x40) && (d & 0x40))\r
Pico.ioports[a] = d;\r
}\r
\r
-#endif // _ASM_MEMORY_C\r
-\r
void NOINLINE ctl_write_z80busreq(u32 d)\r
{\r
d&=1; d^=1;\r
#endif\r
}\r
\r
+// vim:shiftwidth=2:ts=2:expandtab\r
.equ SRR_MAPPED, (1 << 0)\r
.equ SRR_READONLY, (1 << 1)\r
.equ SRF_EEPROM, (1 << 1)\r
-.equ POPT_6BTN_PAD, (1 << 5)\r
.equ POPT_EN_32X, (1 << 20)\r
\r
.text\r
PicoRead8_io: @ u32 a, u32 d\r
bic r2, r0, #0x001f @ most commonly we get i/o port read,\r
cmp r2, #0xa10000 @ so check for it first\r
- bne m_read8_not_io\r
-\r
-m_read8_misc_io:\r
- ands r0, r0, #0x1e\r
- beq m_read8_misc_hwreg\r
- cmp r0, #4\r
- movlt r0, #0\r
- moveq r0, #1\r
- ble PadRead\r
- ldr r3, =(Pico+0x22000)\r
- mov r0, r0, lsr #1 @ other IO ports (Pico.ioports[a])\r
- ldrb r0, [r3, r0]\r
- bx lr\r
-\r
-m_read8_misc_hwreg:\r
- ldr r3, =(Pico+0x22200)\r
- ldrb r0, [r3, #0x0f] @ Pico.m.hardware\r
- bx lr\r
+ beq io_ports_read\r
\r
m_read8_not_io:\r
and r2, r0, #0xfc00\r
cmp r2, #0xa10000 @ so check for it first\r
bne m_read16_not_io\r
stmfd sp!,{lr}\r
- bl m_read8_misc_io @ same as read8\r
+ bl io_ports_read @ same as read8\r
orr r0, r0, r0, lsl #8 @ only has bytes mirrored\r
ldmfd sp!,{pc}\r
\r
bic r2, r0, #0x1e @ most commonly we get i/o port write,\r
eor r2, r2, #0xa10000 @ so check for it first\r
eors r2, r2, #1\r
- bne m_write8_not_io\r
-\r
-m_write8_io:\r
- ldr r2, =PicoOpt\r
- and r0, r0, #0x1e\r
- ldr r2, [r2]\r
- ldr r3, =(Pico+0x22000) @ Pico.ioports\r
- tst r2, #POPT_6BTN_PAD\r
- beq m_write8_io_done\r
- cmp r0, #2\r
- cmpne r0, #4\r
- bne m_write8_io_done @ not likely to happen\r
- add r2, r3, #0x200 @ Pico+0x22200\r
- mov r12,#0\r
- cmp r0, #2\r
- streqb r12,[r2,#0x18]\r
- strneb r12,[r2,#0x19] @ Pico.m.padDelay[i] = 0\r
- tst r1, #0x40 @ TH\r
- beq m_write8_io_done\r
- ldrb r12,[r3, r0, lsr #1]\r
- tst r12,#0x40\r
- bne m_write8_io_done\r
- cmp r0, #2\r
- ldreqb r12,[r2,#0x0a]\r
- ldrneb r12,[r2,#0x0b] @ Pico.m.padTHPhase\r
- add r12,r12,#1\r
- streqb r12,[r2,#0x0a]\r
- strneb r12,[r2,#0x0b] @ Pico.m.padTHPhase\r
-m_write8_io_done:\r
- strb r1, [r3, r0, lsr #1]\r
- bx lr\r
+ beq io_ports_write\r
\r
m_write8_not_io:\r
tst r0, #1\r
PicoWrite16_io: @ u32 a, u32 d\r
bic r2, r0, #0x1f @ most commonly we get i/o port write,\r
cmp r2, #0xa10000 @ so check for it first\r
- beq m_write8_io\r
+ beq io_ports_write\r
\r
m_write16_not_io:\r
and r2, r0, #0xff00\r
Pico.video.pending_ints=0;\r
z80_reset();\r
\r
+ // my MD1 VA6 console has this in IO\r
+ Pico.ioports[1] = Pico.ioports[2] = Pico.ioports[3] = 0xff;\r
+\r
// default VDP register values (based on Fusion)\r
Pico.video.reg[0] = Pico.video.reg[1] = 0x04;\r
Pico.video.reg[0xc] = 0x81;\r
#define POPT_EN_Z80 (1<< 2)\r
#define POPT_EN_STEREO (1<< 3)\r
#define POPT_ALT_RENDERER (1<< 4) // 00 00x0\r
-#define POPT_6BTN_PAD (1<< 5)\r
+// unused (1<< 5)\r
// unused (1<< 6)\r
#define POPT_ACC_SPRITES (1<< 7)\r
#define POPT_DIS_32C_BORDER (1<< 8) // 00 0x00\r
\r
extern unsigned char media_id_header[0x100];\r
\r
+// memory.c\r
+enum input_device {\r
+ PICO_INPUT_NOTHING,\r
+ PICO_INPUT_PAD_3BTN,\r
+ PICO_INPUT_PAD_6BTN,\r
+};\r
+void PicoSetInputDevice(int port, enum input_device device);\r
+\r
#ifdef __cplusplus\r
} // End of extern "C"\r
#endif\r
#define CYCLES_S68K_ASD 241
// pad delay (for 6 button pads)
-#define PAD_DELAY \
- if (PicoOpt&POPT_6BTN_PAD) { \
- if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
- if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
- }
+#define PAD_DELAY() { \
+ if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
+ if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
+}
// CPUS_RUN
#ifndef CPUS_RUN
Pico.video.status|=0x200;
}
- PAD_DELAY
+ PAD_DELAY();
#ifdef PICO_CD
check_cd_dma();
#endif
Pico.video.status|=0x200;
memcpy(PicoPadInt, PicoPad, sizeof(PicoPadInt));
- PAD_DELAY
+ PAD_DELAY();
#ifdef PICO_CD
check_cd_dma();
#endif
pv->v_counter = (pv->v_counter << 1) | 1;
pv->v_counter &= 0xff;
- PAD_DELAY
+ PAD_DELAY();
#ifdef PICO_CD
check_cd_dma();
#endif
unsigned int PicoRead16_io(unsigned int a);\r
void PicoWrite8_io(unsigned int a, unsigned int d);\r
void PicoWrite16_io(unsigned int a, unsigned int d);\r
-void p32x_dreq1_trigger(void);\r
\r
// pico/memory.c\r
PICO_INTERNAL void PicoMemSetupPico(void);\r
// additional movie stuff\r
if (movie_data)\r
{\r
- if (movie_data[0x14] == '6')\r
- PicoOpt |= POPT_6BTN_PAD; // 6 button pad\r
- else PicoOpt &= ~POPT_6BTN_PAD;\r
+ enum input_device indev = (movie_data[0x14] == '6') ?\r
+ PICO_INPUT_PAD_6BTN : PICO_INPUT_PAD_3BTN;\r
+ PicoSetInputDevice(0, indev);\r
+ PicoSetInputDevice(1, indev);\r
+\r
PicoOpt |= POPT_DIS_VDP_FIFO; // no VDP fifo timing\r
if (movie_data[0xF] >= 'A') {\r
if (movie_data[0x16] & 0x80) {\r
defaultConfig.s_PicoCDBuffers = 0;\r
defaultConfig.confirm_save = EOPT_CONFIRM_SAVE;\r
defaultConfig.Frameskip = -1; // auto\r
+ defaultConfig.input_dev0 = PICO_INPUT_PAD_3BTN;\r
+ defaultConfig.input_dev1 = PICO_INPUT_PAD_3BTN;\r
defaultConfig.volume = 50;\r
defaultConfig.gamma = 100;\r
defaultConfig.scaling = 0;\r
int s_PicoAutoRgnOrder;
int s_PicoCDBuffers;
int Frameskip;
+ int input_dev0;
+ int input_dev1;
int confirm_save;
int CPUclock;
int volume;
static int mh_saveloadcfg(int id, int keys);
static const char *mgn_saveloadcfg(int id, int *offs);
+const char *indev_names[] = { "none", "3 button pad", "6 button pad", NULL };
+
static menu_entry e_menu_keyconfig[] =
{
mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
mee_handler_id("Emulator controls", MA_CTRL_EMU, key_config_loop_wrap),
- mee_onoff ("6 button pad", MA_OPT_6BUTTON_PAD, PicoOpt, POPT_6BTN_PAD),
+ mee_enum ("Input device 1", MA_OPT_INPUT_DEV0, currentConfig.input_dev0, indev_names),
+ mee_enum ("Input device 2", MA_OPT_INPUT_DEV1, currentConfig.input_dev1, indev_names),
mee_range ("Turbo rate", MA_CTRL_TURBO_RATE, currentConfig.turbo_rate, 1, 30),
mee_range ("Analog deadzone", MA_CTRL_DEADZONE, currentConfig.analog_deadzone, 1, 99),
mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_saveloadcfg, mgn_saveloadcfg),
me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, PicoGameLoaded);
me_loop(e_menu_keyconfig, &sel);
+
+ PicoSetInputDevice(0, currentConfig.input_dev0);
+ PicoSetInputDevice(1, currentConfig.input_dev1);
+
return 0;
}
MA_OPT_ENABLE_SOUND,
MA_OPT_SOUND_QUALITY,
MA_OPT_ARM940_SOUND,
- MA_OPT_6BUTTON_PAD,
+ MA_OPT_INPUT_DEV0,
+ MA_OPT_INPUT_DEV1,
MA_OPT_REGION,
MA_OPT_SRAM_STATES,
MA_OPT_CONFIRM_STATES,
{
static const struct retro_variable vars[] = {
//{ "region", "Region; Auto|NTSC|PAL" },
+ { "picodrive_input1", "Input device 1; 3 button pad|6 button pad|None" },
+ { "picodrive_input2", "Input device 2; 3 button pad|6 button pad|None" },
{ NULL, NULL },
};
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
- lprintf("RGB565 suppot required, sorry\n");
+ lprintf("RGB565 support required, sorry\n");
return false;
}
audio_batch_cb(PsndOut, len / 4);
}
+static enum input_device input_name_to_val(const char *name)
+{
+ if (strcmp(name, "3 button pad") == 0)
+ return PICO_INPUT_PAD_3BTN;
+ if (strcmp(name, "6 button pad") == 0)
+ return PICO_INPUT_PAD_6BTN;
+ if (strcmp(name, "None") == 0)
+ return PICO_INPUT_NOTHING;
+
+ lprintf("invalid picodrive_input: '%s'\n", name);
+ return PICO_INPUT_PAD_3BTN;
+}
+
+static void update_variables(void)
+{
+ struct retro_variable var;
+
+ var.value = NULL;
+ var.key = "picodrive_input1";
+ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+ PicoSetInputDevice(0, input_name_to_val(var.value));
+
+ var.value = NULL;
+ var.key = "picodrive_input2";
+ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+ PicoSetInputDevice(1, input_name_to_val(var.value));
+}
+
void retro_run(void)
{
bool updated = false;
int pad, i;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
- ; //update_variables(true);
+ update_variables();
input_poll_cb();
//PicoMessage = plat_status_msg_busy_next;
PicoMCDopenTray = disk_tray_open;
PicoMCDcloseTray = disk_tray_close;
+
+ update_variables();
}
void retro_deinit(void)
void pemu_prep_defconfig(void)
{
memset(&defaultConfig, 0, sizeof(defaultConfig));
- defaultConfig.s_PicoOpt|= POPT_6BTN_PAD; // for xmen proto
defaultConfig.s_PicoCDBuffers = 0;
defaultConfig.Frameskip = 0;
}