improve input handling
[picodrive.git] / pico / memory.c
index 88d43f0..664fd72 100644 (file)
@@ -186,62 +186,119 @@ void cyclone_crashed(u32 pc, struct Cyclone *context)
 // -----------------------------------------------------------------\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
@@ -252,8 +309,6 @@ static void NOINLINE io_ports_write(u32 a, u32 d)
   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
@@ -1177,3 +1232,4 @@ static void z80_mem_setup(void)
 #endif\r
 }\r
 \r
+// vim:shiftwidth=2:ts=2:expandtab\r