summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2017-05-08 22:31:28 -0700
committerMichael Pavone <pavone@retrodev.com>2017-05-08 22:31:28 -0700
commit0d21fde651a775c1dd86e9ce916d0f63814d8176 (patch)
treefdd5c41b0da45cec0b764ac22972488d74cd9ec1
parent20db9d95de69c67e745b7f84d61853b027ec409b (diff)
Implemented slow rise time of IO pins set as inputs, but not driven by device. Fixes input in Decap Attack and possibly other games with buggy controller code
-rw-r--r--genesis.c6
-rw-r--r--io.c71
-rw-r--r--io.h2
3 files changed, 73 insertions, 6 deletions
diff --git a/genesis.c b/genesis.c
index ff14c36..635965b 100644
--- a/genesis.c
+++ b/genesis.c
@@ -513,13 +513,13 @@ static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_
io_data_write(gen->io.ports+2, value, context->current_cycle);
break;
case 0x4:
- gen->io.ports[0].control = value;
+ io_control_write(gen->io.ports, value, context->current_cycle);
break;
case 0x5:
- gen->io.ports[1].control = value;
+ io_control_write(gen->io.ports+1, value, context->current_cycle);
break;
case 0x6:
- gen->io.ports[2].control = value;
+ io_control_write(gen->io.ports+2, value, context->current_cycle);
break;
case 0x7:
gen->io.ports[0].serial_out = value;
diff --git a/io.c b/io.c
index 3769ac8..b6ecabe 100644
--- a/io.c
+++ b/io.c
@@ -1506,6 +1506,16 @@ void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction
port->device.mouse.ready_cycle -= deduction;
}
}
+ for (int i = 0; i < 8; i++)
+ {
+ if (port->slow_rise_start[i] != CYCLE_NEVER) {
+ if (port->slow_rise_start[i] >= deduction) {
+ port->slow_rise_start[i] -= deduction;
+ } else {
+ port->slow_rise_start[i] = CYCLE_NEVER;
+ }
+ }
+ }
if (last_poll_cycle >= deduction) {
last_poll_cycle -= deduction;
} else {
@@ -1623,6 +1633,25 @@ enum {
KB_WRITE
};
+void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle)
+{
+ uint8_t changes = value ^ port->control;
+ if (changes) {
+ for (int i = 0; i < 8; i++)
+ {
+ if (!(value & 1 << i) && !(port->output & 1 << i)) {
+ //port switched from output to input and the output value was 0
+ //since there is a weak pull-up on input pins, this will lead
+ //to a slow rise from 0 to 1 if the pin isn't being externally driven
+ port->slow_rise_start[i] = current_cycle;
+ } else {
+ port->slow_rise_start[i] = CYCLE_NEVER;
+ }
+ }
+ port->control = value;
+ }
+}
+
void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle)
{
uint8_t old_output = (port->control & port->output) | (~port->control & 0xFF);
@@ -1766,12 +1795,34 @@ uint8_t get_scancode_bytes(io_port *port)
return bytes;
}
+#define SLOW_RISE_DEVICE (30*7)
+#define SLOW_RISE_INPUT (12*7)
+
+static uint8_t get_output_value(io_port *port, uint32_t current_cycle, uint32_t slow_rise_delay)
+{
+ uint8_t output = (port->control | 0x80) & port->output;
+ for (int i = 0; i < 8; i++)
+ {
+ if (!(port->control & 1 << i)) {
+ if (port->slow_rise_start[i] != CYCLE_NEVER) {
+ if (current_cycle - port->slow_rise_start[i] >= slow_rise_delay) {
+ output |= 1 << i;
+ }
+ } else {
+ output |= 1 << i;
+ }
+ }
+ }
+ return output;
+}
+
uint8_t io_data_read(io_port * port, uint32_t current_cycle)
{
+ uint8_t output = get_output_value(port, current_cycle, SLOW_RISE_DEVICE);
uint8_t control = port->control | 0x80;
- uint8_t output = (control & port->output) | (~control & 0xFF);
uint8_t th = output & 0x40;
uint8_t input;
+ uint8_t device_driven;
if (current_cycle - last_poll_cycle > MIN_POLL_INTERVAL) {
process_events();
last_poll_cycle = current_cycle;
@@ -1789,6 +1840,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
}
//controller output is logically inverted
input = ~input;
+ device_driven = 0x3F;
break;
}
case IO_GAMEPAD6:
@@ -1816,6 +1868,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
}
//controller output is logically inverted
input = ~input;
+ device_driven = 0x3F;
break;
}
case IO_MOUSE:
@@ -1875,6 +1928,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
}
input |= ((port->device.mouse.tr_counter & 1) == 0) << 4;
}
+ device_driven = 0x1F;
break;
}
case IO_SATURN_KEYBOARD:
@@ -1947,6 +2001,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
}
input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
}
+ device_driven = 0x1F;
break;
}
case IO_XBAND_KEYBOARD:
@@ -2008,6 +2063,8 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
input = 0xF;
}
input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
+ //this is not strictly correct at all times, but good enough for now
+ device_driven = 0x1F;
}
break;
}
@@ -2018,6 +2075,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
service_pipe(port);
}
input = port->input[th ? IO_TH1 : IO_TH0];
+ device_driven = 0x3F;
break;
case IO_GENERIC:
if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN)
@@ -2027,13 +2085,20 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle)
}
service_socket(port);
input = port->input[IO_TH0];
+ device_driven = 0x7F;
break;
#endif
default:
- input = 0xFF;
+ input = 0;
+ device_driven = 0;
break;
}
- uint8_t value = (input & (~control)) | (port->output & control);
+ uint8_t value = (input & (~control) & device_driven) | (port->output & control);
+ //deal with pins that are configured as inputs, but not being actively driven by the device
+ uint8_t floating = (~device_driven) & (~control);
+ if (floating) {
+ value |= get_output_value(port, current_cycle, SLOW_RISE_INPUT) & floating;
+ }
/*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) {
printf ("value: %X\n", value);
}*/
diff --git a/io.h b/io.h
index 958ffc8..5814c7a 100644
--- a/io.h
+++ b/io.h
@@ -60,6 +60,7 @@ typedef struct {
uint8_t output;
uint8_t control;
uint8_t input[3];
+ uint32_t slow_rise_start[8];
uint8_t serial_out;
uint8_t serial_in;
uint8_t serial_ctrl;
@@ -95,6 +96,7 @@ void set_keybindings(sega_io *io);
void map_all_bindings(sega_io *io);
void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io);
void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction);
+void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle);
void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle);
uint8_t io_data_read(io_port * pad, uint32_t current_cycle);
void handle_keydown(int keycode, uint8_t scancode);