Browse Source

RP2040: Fix hang with ModeSense command with synchronous mode on Amiga

The RP2040 accelerated code works in multiples of two bytes,
so a slower fallback code path is used to transfer command
responses that have an odd number of bytes.

This fallback code wasn't fully reliable with synchronous mode because
if an interrupt occurred in the middle, the response ACK pulse could be
missed.

Fixed by using falling edge interrupt register to detect ACK pulses.
Petteri Aimonen 3 years ago
parent
commit
f11c0d4750
1 changed files with 13 additions and 1 deletions
  1. 13 1
      lib/ZuluSCSI_platform_RP2040/scsiPhy.cpp

+ 13 - 1
lib/ZuluSCSI_platform_RP2040/scsiPhy.cpp

@@ -7,6 +7,7 @@
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_config.h"
 #include "scsi_accel_rp2040.h"
+#include "hardware/structs/iobank0.h"
 
 #include <scsi2sd.h>
 extern "C" {
@@ -252,6 +253,15 @@ void scsiEnterBusFree(void)
     } \
   }
 
+// In synchronous mode the ACK pulse can be very short, so use edge IRQ to detect it.
+#define CHECK_EDGE(pin) \
+    ((iobank0_hw->intr[pin / 8] >> (4 * (pin % 8))) & GPIO_IRQ_EDGE_FALL)
+
+#define SCSI_WAIT_ACTIVE_EDGE(pin) \
+  if (!CHECK_EDGE(SCSI_IN_ ## pin)) { \
+    while(!SCSI_IN(pin) && !CHECK_EDGE(SCSI_IN_ ## pin) && !scsiDev.resetFlag); \
+  }
+
 #define SCSI_WAIT_INACTIVE(pin) \
   if (SCSI_IN(pin)) { \
     if (SCSI_IN(pin)) { \
@@ -260,12 +270,14 @@ void scsiEnterBusFree(void)
   }
 
 // Write one byte to SCSI host using the handshake mechanism
+// This is suitable for both asynchronous and synchronous communication.
 static inline void scsiWriteOneByte(uint8_t value)
 {
     SCSI_OUT_DATA(value);
     delay_100ns(); // DB setup time before REQ
+    gpio_acknowledge_irq(SCSI_IN_ACK, GPIO_IRQ_EDGE_FALL);
     SCSI_OUT(REQ, 1);
-    SCSI_WAIT_ACTIVE(ACK);
+    SCSI_WAIT_ACTIVE_EDGE(ACK);
     SCSI_RELEASE_DATA_REQ();
     SCSI_WAIT_INACTIVE(ACK);
 }