]> gitweb.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
a4091: emulate 53C710 SCSI loopback pins
authorBernie Innocenti <bernie@codewiz.org>
Thu, 9 Jul 2026 09:37:39 +0000 (11:37 +0200)
committerDimitris Panokostas <midwan@gmail.com>
Thu, 9 Jul 2026 09:37:39 +0000 (11:37 +0200)
The ncr7xx SCSI pin test drives the output latches and reads them back through the bus input registers in loopback mode. Model the A4091 loopback path for SBDL, SBCL, and SSTAT1, and add the missing SOCL write latch.

SCNTL1.ADB now latches instead of aborting the setup write, allowing the loopback reads to observe the driven SODL and SOCL state.

qemuvga/lsi53c710.cpp

index b61eaf8316542cd5489524645b88df9f02d0ac40..069f5fed201669442f1f76a4ff4895bcca6fefdd 100644 (file)
@@ -43,7 +43,7 @@ do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__); assert(false);} while
 
 #define LSI_SCNTL0_TRG    0x01
 #define LSI_SCNTL0_AAP    0x02
-#define LSI_SCNTL0_EPG    0x08
+#define LSI_SCNTL0_EPG    0x04
 #define LSI_SCNTL0_EPC    0x08
 #define LSI_SCNTL0_WATN   0x10,
 #define LSI_SCNTL0_START  0x20
@@ -142,6 +142,7 @@ do { write_log("lsi_scsi: error: " fmt , ## __VA_ARGS__); assert(false);} while
 #define LSI_CTEST2_DDIR   0x80
 
 #define LSI_CTEST4_SFWR   0x08
+#define LSI_CTEST4_SLBE   0x10
 
 #define LSI_CTEST5_BL2    0x04
 #define LSI_CTEST5_DDIR   0x08
@@ -295,6 +296,11 @@ static uint8_t lsi_scsi_parity(uint8_t val, uint8_t scntl1)
        return parity;
 }
 
+static bool lsi_scsi_loopback(LSIState710 *s)
+{
+       return (s->ctest4 & LSI_CTEST4_SLBE) && (s->scntl1 & LSI_SCNTL1_ADB);
+}
+
 static inline int lsi_irq_on_rsl(LSIState710 *s)
 {
        return 0; //return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
@@ -1683,7 +1689,15 @@ static uint8_t lsi_reg_readb2(LSIState710 *s, int offset)
         /* This is needed by the linux drivers.  We currently only update it
            during the MSG IN phase.  */
         return s->sidl;
+       case 0x0a: /* SBDL */
+               return lsi_scsi_loopback(s) ? s->sodl : 0;
     case 0xb: /* SBCL */
+               if (lsi_scsi_loopback(s)) {
+                       tmp = s->socl;
+                       if (!(s->scntl0 & LSI_SCNTL0_TRG))
+                               tmp &= ~0x48;
+                       return tmp;
+               }
                tmp = 0;
                if (s->scntl1 & LSI_SCNTL1_CON) {
                        /* NetBSD 1.x checks for REQ */
@@ -1707,7 +1721,13 @@ static uint8_t lsi_reg_readb2(LSIState710 *s, int offset)
         lsi_update_irq(s);
        return tmp;
     case 0x0e: /* SSTAT1 */
-        return s->sstat1;
+               tmp = s->sstat1 & ~0x03;
+               if (s->scntl1 & LSI_SCNTL1_RST)
+                       tmp |= 0x02;
+               if (lsi_scsi_loopback(s) && (s->scntl0 & LSI_SCNTL0_EPG) &&
+                       lsi_scsi_parity(s->sodl, s->scntl1))
+                       tmp |= 0x01;
+               return tmp;
     case 0x0f: /* SSTAT2 */
         return (s->sstat2 & 0x0f) | (s->scsi_fifo_count << 4);
     CASE_GET_REG32(dsa, 0x10)
@@ -1817,9 +1837,8 @@ static void lsi_reg_writeb(LSIState710 *s, int offset, uint8_t val)
         break;
     case 0x01: /* SCNTL1 */
         s->scntl1 = val;
-        if (val & LSI_SCNTL1_ADB) {
-            BADF("Immediate Arbritration not implemented\n");
-        }
+               /* SCNTL1.ADB drives SODL/SOCL onto the bus; in loopback mode the
+                  read handlers feed those latches back through SBDL/SBCL. */
         if (val & LSI_SCNTL1_RST) {
             if (!(s->sstat0 & LSI_SSTAT0_RST)) {
 //                qbus_reset_all(&s->bus.qbus);
@@ -1847,6 +1866,9 @@ static void lsi_reg_writeb(LSIState710 *s, int offset, uint8_t val)
                        s->scsi_fifo[s->scsi_fifo_count++] = (parity << 8) | val;
                }
                break;
+       case 0x07: /* SOCL */
+               s->socl = val;
+               break;
        case 0x0b: /* SBCL */
                lsi_set_phase (s, val & PHASE_MASK);
                break;