Forráskód Böngészése

Performance improvements

Read speed is now 2.4 MB/s, write speed 2.1 MB/s.
Petteri Aimonen 3 éve
szülő
commit
f510b781c0

+ 1 - 15
README.md

@@ -27,21 +27,7 @@ Configuration file
 Optional configuration can be stored in `azulscsi.ini`.
 If image file is found but configuration is missing, a default configuration is used.
 
-A single AzulSCSI device can represent multiple devices on the SCSI bus.
-The configuration sections are numbered `SCSI0` to `SCSI7` and correspond to images `HD00.hda` to `HD70.hda`.
-
-Example format for config file:
-
-    [SCSI]
-    # Settings that apply to all devices
-    Debug = 0   # Same effect as DIPSW2
-
-    [SCSI0]
-    Vendor = "QUANTUM "
-    Product = "FIREBALL1       "
-    Version = "1.0 "
-    Serial = "0123456789ABCDEF"
-    Quirks = 0   # 0: Standard, 1: Apple, 2: OMTI, 4: Xebec, 8: VMS
+Example config file is available here: [azulscsi.ini](azulscsi.ini).
 
 Performance
 -----------

+ 2 - 0
lib/AzulSCSI_platform_GD32F205/AzulSCSI_v1_0_gpio.h

@@ -17,6 +17,7 @@
 #define SCSI_OUT_DBP  GPIO_PIN_15
 #define SCSI_OUT_REQ  GPIO_PIN_9
 #define SCSI_OUT_DATA_MASK (SCSI_OUT_DB0 | SCSI_OUT_DB1 | SCSI_OUT_DB2 | SCSI_OUT_DB3 | SCSI_OUT_DB4 | SCSI_OUT_DB5 | SCSI_OUT_DB6 | SCSI_OUT_DB7 | SCSI_OUT_DBP)
+#define SCSI_OUT_REQ_IDX 9
 
 // SCSI input data port
 #define SCSI_IN_PORT  GPIOE
@@ -53,6 +54,7 @@
 #define SCSI_SEL_PIN  GPIO_PIN_11
 #define SCSI_ACK_PORT GPIOB
 #define SCSI_ACK_PIN  GPIO_PIN_12
+#define SCSI_IN_ACK_IDX 12
 
 // The SCSI_ATN pin was PB0 in prototype 2022a, but was moved to PC6 for 5V-tolerance
 #ifdef AZULSCSI_2022A_REVISION

+ 35 - 8
lib/AzulSCSI_platform_GD32F205/scsiPhy.cpp

@@ -59,6 +59,11 @@ static void scsi_bsy_deassert_interrupt()
             uint8_t atn_flag = SCSI_IN(ATN) ? SCSI_STS_SELECTION_ATN : 0;
             g_scsi_sts_selection = SCSI_STS_SELECTION_SUCCEEDED | atn_flag | sel_id;
         }
+
+        // selFlag is required for Philips P2000C which releases it after 600ns
+        // without waiting for BSY.
+        // Also required for some early Mac Plus roms
+        scsiDev.selFlag = *SCSI_STS_SELECTED;
     }
 }
 
@@ -124,23 +129,36 @@ extern "C" uint32_t scsiEnterPhaseImmediate(int phase)
 
     if (phase != g_scsi_phase)
     {
+        int oldphase = g_scsi_phase;
+        g_scsi_phase = (SCSI_PHASE)phase;
+        scsiLogPhaseChange(phase);
+        
         if (phase < 0)
         {
             // Other communication on bus or reset state
             SCSI_RELEASE_OUTPUTS();
+            return 0;
         }
         else
         {
             SCSI_OUT(MSG, phase & __scsiphase_msg);
             SCSI_OUT(CD,  phase & __scsiphase_cd);
             SCSI_OUT(IO,  phase & __scsiphase_io);
-        }
+        
+            int delayNs = 400; // Bus settle delay
+            if ((oldphase & __scsiphase_io) != (phase & __scsiphase_io))
+            {
+                delayNs += 400; // Data release delay
+            }
 
-        scsiLogPhaseChange(phase);
-        g_scsi_phase = (SCSI_PHASE)phase;
+            if (scsiDev.compatMode < COMPAT_SCSI2)
+            {
+                // EMU EMAX needs 100uS ! 10uS is not enough.
+                delayNs += 100000;
+            }
 
-        // Hardcoded 100 us delay for now.
-        return 100000;
+            return delayNs;
+        }
     }
     else
     {
@@ -239,11 +257,20 @@ extern "C" void scsiRead(uint8_t* data, uint32_t count, int* parityError)
 {
     *parityError = 0;
 
-    for (uint32_t i = 0; i < count; i++)
+    uint32_t count_words = count / 4;
+    if (count_words * 4 == count)
+    {
+        // Use accelerated subroutine
+        scsi_accel_asm_recv((uint32_t*)data, count_words, &scsiDev.resetFlag);
+    }
+    else
     {
-        if (scsiDev.resetFlag) break;
+        for (uint32_t i = 0; i < count; i++)
+        {
+            if (scsiDev.resetFlag) break;
 
-        data[i] = scsiReadOneByte();
+            data[i] = scsiReadOneByte();
+        }
     }
 
     scsiLogDataOut(data, count);

+ 55 - 3
lib/AzulSCSI_platform_GD32F205/scsi_accel_asm.cpp

@@ -15,6 +15,15 @@
 "    send_data" x "_%=: \n" \
 "        str     %[tmp1], [%[out_port_bop]] \n"
 
+// Read data from SCSI port, set REQ high, store data to d at bit offset b
+#define ASM_RECV_DATA(d, b, x) \
+"    recv_data" x "_%=: \n" \
+"        ldr     %[tmp1], [%[in_port_istat]] \n" \
+"        mov     %[tmp2], %[req_high_bop] \n" \
+"        str     %[tmp2], [%[out_port_bop]] \n" \
+"        ubfx    %[tmp1], %[tmp1], %[data_in_shift], #8 \n" \
+"        bfi     %[" d "], %[tmp1], #" b ", #8 \n"
+
 // Wait for ACK to be high, set REQ low, wait ACK low
 #define ASM_HANDSHAKE(x) \
 "        ldr     %[tmp2], [%[ack_pin_bb]] \n" \
@@ -52,13 +61,12 @@
 
 // Send bytes to SCSI bus using the asynchronous handshake mechanism
 // Takes 4 bytes at a time for sending from buf.
-// Returns the next buffer pointer.
 void scsi_accel_asm_send(const uint32_t *buf, uint32_t num_words, volatile int *resetFlag)
 {
     volatile uint32_t *out_port_bop = (volatile uint32_t*)&GPIO_BOP(SCSI_OUT_PORT);
     const uint32_t *byte_lookup = g_scsi_out_byte_to_bop;
-    uint32_t ack_pin_bb = PERIPH_BB_BASE + (((uint32_t)&GPIO_ISTAT(SCSI_ACK_PORT)) - APB1_BUS_BASE) * 32 + 12 * 4;
-    uint32_t req_pin_bb = PERIPH_BB_BASE + (((uint32_t)out_port_bop) - APB1_BUS_BASE) * 32 + (9 + 16) * 4;
+    uint32_t ack_pin_bb = PERIPH_BB_BASE + (((uint32_t)&GPIO_ISTAT(SCSI_ACK_PORT)) - APB1_BUS_BASE) * 32 + SCSI_IN_ACK_IDX * 4;
+    uint32_t req_pin_bb = PERIPH_BB_BASE + (((uint32_t)out_port_bop) - APB1_BUS_BASE) * 32 + (SCSI_OUT_REQ_IDX + 16) * 4;
     register uint32_t tmp1 = 0;
     register uint32_t tmp2 = 0;
     register uint32_t data = 0;
@@ -96,5 +104,49 @@ void scsi_accel_asm_send(const uint32_t *buf, uint32_t num_words, volatile int *
                   [reset_flag] "r" (resetFlag)
     : /* Clobber */ );
 
+    SCSI_RELEASE_DATA_REQ();
+}
+
+// Read bytes from SCSI bus using asynchronous handshake mechanism
+// Takes 4 bytes at a time.
+void scsi_accel_asm_recv(uint32_t *buf, uint32_t num_words, volatile int *resetFlag)
+{
+    volatile uint32_t *out_port_bop = (volatile uint32_t*)&GPIO_BOP(SCSI_OUT_PORT);
+    volatile uint32_t *in_port_istat = (volatile uint32_t*)&GPIO_ISTAT(SCSI_IN_PORT);
+    uint32_t ack_pin_bb = PERIPH_BB_BASE + (((uint32_t)&GPIO_ISTAT(SCSI_ACK_PORT)) - APB1_BUS_BASE) * 32 + SCSI_IN_ACK_IDX * 4;
+    uint32_t req_pin_bb = PERIPH_BB_BASE + (((uint32_t)out_port_bop) - APB1_BUS_BASE) * 32 + (SCSI_OUT_REQ_IDX + 16) * 4;
+    register uint32_t tmp1 = 0;
+    register uint32_t tmp2 = 0;
+    register uint32_t data = 0;
+
+    asm volatile (
+    "inner_loop_%=: \n" \
+        ASM_HANDSHAKE("0")
+        ASM_RECV_DATA("data", "0", "0")
+        
+        ASM_HANDSHAKE("8")
+        ASM_RECV_DATA("data", "8", "8")
+        
+        ASM_HANDSHAKE("16")
+        ASM_RECV_DATA("data", "16", "16")
+        
+        ASM_HANDSHAKE("24")
+        ASM_RECV_DATA("data", "24", "24")
+
+    "   mvn      %[data], %[data] \n" \
+    "   str      %[data], [%[buf]], #4 \n" \
+    "   subs     %[num_words], %[num_words], #1 \n" \
+    "   bne     inner_loop_%= \n"
+    : /* Output */ [tmp1] "+l" (tmp1), [tmp2] "+l" (tmp2), [data] "+r" (data),
+                   [buf] "+r" (buf), [num_words] "+r" (num_words)
+    : /* Input */ [ack_pin_bb] "r" (ack_pin_bb),
+                  [req_pin_bb] "r" (req_pin_bb),
+                  [out_port_bop] "r"(out_port_bop),
+                  [in_port_istat] "r" (in_port_istat),
+                  [reset_flag] "r" (resetFlag),
+                  [data_in_shift] "I" (SCSI_IN_SHIFT),
+                  [req_high_bop] "I" (SCSI_OUT_REQ)
+    : /* Clobber */ );
+
     SCSI_RELEASE_DATA_REQ();
 }

+ 1 - 0
lib/AzulSCSI_platform_GD32F205/scsi_accel_asm.h

@@ -5,3 +5,4 @@
 #include <stdint.h>
 
 void scsi_accel_asm_send(const uint32_t *buf, uint32_t num_words, volatile int *resetFlag);
+void scsi_accel_asm_recv(uint32_t *buf, uint32_t num_words, volatile int *resetFlag);

+ 20 - 4
lib/AzulSCSI_platform_GD32F205/sd_card_spi.cpp

@@ -118,7 +118,10 @@ public:
         if (m_stream_callback && buf == m_stream_buffer + m_stream_count)
         {
             stream = true;
-            m_stream_count += count;
+        }
+        else if (m_stream_callback)
+        {
+            azdbg("Stream buffer mismatch: ", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
         }
 
         // Use DMA to stream dummy TX data and store RX data
@@ -146,7 +149,7 @@ public:
 
             if (stream)
             {
-                uint32_t complete = (count - DMA_CHCNT(DMA0, SD_SPI_RX_DMA_CHANNEL));
+                uint32_t complete = m_stream_count + (count - DMA_CHCNT(DMA0, SD_SPI_RX_DMA_CHANNEL));
                 m_stream_callback(complete);
             }
         }
@@ -160,6 +163,11 @@ public:
         DMA_CHCTL(DMA0, SD_SPI_RX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
         DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
 
+        if (stream)
+        {
+            m_stream_count += count;
+        }
+
         return 0;
     }
 
@@ -170,7 +178,10 @@ public:
         if (m_stream_callback && buf == m_stream_buffer + m_stream_count)
         {
             stream = true;
-            m_stream_count += count;
+        }
+        else if (m_stream_callback)
+        {
+            azdbg("Stream buffer mismatch: ", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
         }
 
         // Use DMA to stream TX data
@@ -193,7 +204,7 @@ public:
 
             if (stream)
             {
-                uint32_t complete = (count - DMA_CHCNT(DMA0, SD_SPI_TX_DMA_CHANNEL));
+                uint32_t complete = m_stream_count + (count - DMA_CHCNT(DMA0, SD_SPI_TX_DMA_CHANNEL));
                 m_stream_callback(complete);
             }
         }
@@ -207,6 +218,11 @@ public:
 
         SPI_CTL1(SD_SPI) &= ~(SPI_CTL1_DMAREN | SPI_CTL1_DMATEN);
         DMA_CHCTL(DMA0, SD_SPI_TX_DMA_CHANNEL) &= ~DMA_CHXCTL_CHEN;
+
+        if (stream)
+        {
+            m_stream_count += count;
+        }
     }
 
     void setSckSpeed(uint32_t maxSck) {

+ 27 - 5
src/AzulSCSI_disk.cpp

@@ -111,17 +111,39 @@ void scsiDiskLoadConfig(int target_idx)
 extern "C"
 void s2s_configInit(S2S_BoardCfg* config)
 {
+    azlog("Reading configuration");
     memset(config, 0, sizeof(S2S_BoardCfg));
     memcpy(config->magic, "BCFG", 4);
-    config->flags = ini_getl("SCSI", "Flags", 0, CONFIGFILE);
+    config->flags = 0;
     config->startupDelay = 0;
     config->selectionDelay = ini_getl("SCSI", "SelectionDelay", 255, CONFIGFILE);
-    config->flags6 = ini_getl("SCSI", "Flags6", 0, CONFIGFILE);
-    config->scsiSpeed = ini_getl("SCSI", "SCSISpeed", PLATFORM_MAX_SCSI_SPEED, CONFIGFILE);
+    config->flags6 = 0;
+    config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;
+    
+    azlog("-- SelectionDelay: ", (int)config->selectionDelay);
+
+    if (ini_getbool("SCSI", "EnableUnitAttention", false, CONFIGFILE))
+    {
+        azlog("-- EnableUnitAttention is on");
+        config->flags |= S2S_CFG_ENABLE_UNIT_ATTENTION;
+    }
+
+    if (ini_getbool("SCSI", "EnableSCSI2", true, CONFIGFILE))
+    {
+        azlog("-- EnableSCSI2 is on");
+        config->flags |= S2S_CFG_ENABLE_SCSI2;
+    }
+
+    if (ini_getbool("SCSI", "EnableSelLatch", false, CONFIGFILE))
+    {
+        azlog("-- EnableSelLatch is on");
+        config->flags |= S2S_CFG_ENABLE_SEL_LATCH;
+    }
 
-    if (config->scsiSpeed > PLATFORM_MAX_SCSI_SPEED)
+    if (ini_getbool("SCSI", "MapLunsToIDs", false, CONFIGFILE))
     {
-        config->scsiSpeed = PLATFORM_MAX_SCSI_SPEED;
+        azlog("-- MapLunsToIDs is on");
+        config->flags |= S2S_CFG_MAP_LUNS_TO_IDS;
     }
 }