Эх сурвалжийг харах

Beginnings of synchronous mode support for V1.1.

Works but still unoptimized & slow.
Petteri Aimonen 3 жил өмнө
parent
commit
8e1f08f863

+ 1 - 1
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h

@@ -22,7 +22,7 @@ extern const char *g_azplatform_name;
 #elif defined(AZULSCSI_V1_1)
 #   define PLATFORM_NAME "AzulSCSI v1.1"
 #   define PLATFORM_REVISION "1.1"
-#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_ASYNC_50
+#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_5
 #   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
 #   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
 #   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192

+ 7 - 0
lib/AzulSCSI_platform_GD32F205/AzulSCSI_v1_1_gpio.h

@@ -95,6 +95,13 @@
 #define SCSI_ATN_PIN  GPIO_PIN_12
 #define SCSI_IN_ACK_IDX 0
 
+// Extra signals used with EXMC for synchronous mode
+#define SCSI_IN_ACK_EXMC_NWAIT_PORT GPIOD
+#define SCSI_IN_ACK_EXMC_NWAIT_PIN  GPIO_PIN_6
+#define SCSI_OUT_REQ_EXMC_NOE_PORT  GPIOD
+#define SCSI_OUT_REQ_EXMC_NOE_PIN   GPIO_PIN_4
+#define SCSI_EXMC_DATA_SHIFT 5
+
 // BSY pin uses EXTI interrupt
 #define SCSI_BSY_PORT GPIOB
 #define SCSI_BSY_PIN  GPIO_PIN_10

+ 27 - 4
lib/AzulSCSI_platform_GD32F205/scsiPhy.cpp

@@ -6,6 +6,7 @@
 #include "scsi_accel_asm.h"
 #include "scsi_accel_dma.h"
 #include "scsi_accel_greenpak.h"
+#include "scsi_accel_sync.h"
 #include "AzulSCSI_log.h"
 #include "AzulSCSI_log_trace.h"
 #include "AzulSCSI_config.h"
@@ -171,6 +172,10 @@ extern "C" void scsiPhyReset(void)
     g_scsi_ctrl_bsy = 0;
     init_irqs();
 
+#ifdef SCSI_SYNC_MODE_AVAILABLE
+    scsi_accel_sync_init();
+#endif
+
     selectPhyMode();
 
     if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER)
@@ -304,7 +309,12 @@ extern "C" void scsiStartWrite(const uint8_t* data, uint32_t count)
 {
     scsiLogDataIn(data, count);
 
-    if (g_scsi_phy_mode == PHY_MODE_PIO || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO)
+    if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
+    {
+        // Synchronous data transfer
+        scsi_accel_sync_startWrite(data, count, &scsiDev.resetFlag);
+    }
+    else if (g_scsi_phy_mode == PHY_MODE_PIO || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO)
     {
         // Software based bit-banging.
         // Write requests are queued and then executed in isWriteFinished() callback.
@@ -397,7 +407,11 @@ static bool isPollingWriteFinished(const uint8_t *data)
 
 extern "C" bool scsiIsWriteFinished(const uint8_t *data)
 {
-    if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
+    if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
+    {
+        return scsi_accel_sync_isWriteFinished(data);
+    }
+    else if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
     {
         return scsi_accel_dma_isWriteFinished(data);
     }
@@ -418,7 +432,11 @@ extern "C" bool scsiIsWriteFinished(const uint8_t *data)
 
 extern "C" void scsiFinishWrite()
 {
-    if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
+    if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
+    {
+        return scsi_accel_sync_finishWrite(&scsiDev.resetFlag);
+    }
+    else if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
     {
         scsi_accel_dma_finishWrite(&scsiDev.resetFlag);
     }
@@ -462,7 +480,12 @@ extern "C" void scsiRead(uint8_t* data, uint32_t count, int* parityError)
     uint32_t count_words = count / 4;
     bool use_greenpak = (g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO);
 
-    if (count_words * 4 == count && count_words >= 2 && use_greenpak)
+    if (g_scsi_phase == DATA_OUT && scsiDev.target->syncOffset > 0)
+    {
+        // Synchronous data transfer
+        scsi_accel_sync_read(data, count, parityError, &scsiDev.resetFlag);
+    }
+    else if (count_words * 4 == count && count_words >= 2 && use_greenpak)
     {
         // GreenPAK accelerated receive can handle a multiple of 4 bytes with minimum of 8 bytes.
         scsi_accel_greenpak_recv((uint32_t*)data, count_words, &scsiDev.resetFlag);

+ 0 - 3
lib/AzulSCSI_platform_GD32F205/scsiPhy.h

@@ -42,9 +42,6 @@ uint32_t scsiEnterPhaseImmediate(int phase);
 // Release all signals
 void scsiEnterBusFree(void);
 
-//void scsiSetDataCount(uint32_t count);
-//int scsiFifoReady(void);
-
 // Blocking data transfer
 void scsiWrite(const uint8_t* data, uint32_t count);
 void scsiRead(uint8_t* data, uint32_t count, int* parityError);

+ 115 - 0
lib/AzulSCSI_platform_GD32F205/scsi_accel_sync.cpp

@@ -0,0 +1,115 @@
+/* Synchronous mode SCSI implementation.
+ *
+ * In synchronous mode, the handshake mechanism is not used. Instead
+ * either end of the communication will just send a bunch of bytes
+ * and only afterwards checks that the number of acknowledgement
+ * pulses matches.
+ * 
+ * The receiving end should latch in the data at the falling edge of
+ * the request pulse (on either REQ or ACK pin). We use the GD32 EXMC
+ * peripheral to implement this latching with the NWAIT pin when
+ * reading data from the host. NOE is used to generate the REQ pulses.
+ * 
+ * Writing data to the host is simpler, as we can just write it out
+ * from the GPIO port at our own pace. A timer is used for generating
+ * the output pulses on REQ pin.
+ */
+
+#include "scsi_accel_sync.h"
+#include <AzulSCSI_log.h>
+#include <gd32f20x_exmc.h>
+
+#ifndef SCSI_SYNC_MODE_AVAILABLE
+
+void scsi_accel_sync_init() {}
+
+void scsi_accel_sync_read(uint8_t *data, uint32_t count, int* parityError, volatile int *resetFlag) {}
+void scsi_accel_sync_startWrite(const uint8_t* data, uint32_t count, volatile int *resetFlag) {}
+void scsi_accel_sync_stopWrite() {}
+void scsi_accel_sync_finishWrite(volatile int *resetFlag) {}
+bool scsi_accel_sync_isWriteFinished(const uint8_t* data) { return true; }
+
+#else
+
+void scsi_accel_sync_init()
+{
+    rcu_periph_clock_enable(RCU_EXMC);
+    rcu_periph_clock_enable(SCSI_TIMER_RCU);
+
+    exmc_norsram_timing_parameter_struct timing_param = {
+        .asyn_access_mode = EXMC_ACCESS_MODE_A,
+        .syn_data_latency = EXMC_DATALAT_2_CLK,
+        .syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK,
+        .bus_latency = 1,
+        .asyn_data_setuptime = 2,
+        .asyn_address_holdtime = 2,
+        .asyn_address_setuptime = 1
+    };
+
+    exmc_norsram_parameter_struct sram_param = {
+        .norsram_region = EXMC_BANK0_NORSRAM_REGION0,
+        .write_mode = EXMC_ASYN_WRITE,
+        .extended_mode = DISABLE,
+        .asyn_wait = ENABLE,
+        .nwait_signal = ENABLE,
+        .memory_write = DISABLE,
+        .nwait_config = EXMC_NWAIT_CONFIG_DURING,
+        .wrap_burst_mode = DISABLE,
+        .nwait_polarity = EXMC_NWAIT_POLARITY_HIGH,
+        .burst_mode = DISABLE,
+        .databus_width = EXMC_NOR_DATABUS_WIDTH_16B,
+        .memory_type = EXMC_MEMORY_TYPE_SRAM,
+        .address_data_mux = DISABLE,
+        .read_write_timing = &timing_param
+    };
+
+    exmc_norsram_init(&sram_param);
+
+    gpio_init(SCSI_IN_ACK_EXMC_NWAIT_PORT, GPIO_MODE_IN_FLOATING, 0, SCSI_IN_ACK_EXMC_NWAIT_PIN);
+}
+
+void scsi_accel_sync_read(uint8_t *data, uint32_t count, int* parityError, volatile int *resetFlag)
+{
+    exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION0);
+    gpio_init(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ_EXMC_NOE_PIN);
+    
+    for (int i = 0; i < count; i++)
+    {
+        uint32_t value = *(volatile uint32_t*)EXMC_NOR_PSRAM;
+        data[i] = ~(value >> SCSI_EXMC_DATA_SHIFT) & 0xFF;
+    }
+
+    gpio_init(SCSI_OUT_REQ_EXMC_NOE_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SCSI_OUT_REQ_EXMC_NOE_PIN);
+    exmc_norsram_disable(EXMC_BANK0_NORSRAM_REGION0);
+}
+
+void scsi_accel_sync_startWrite(const uint8_t* data, uint32_t count, volatile int *resetFlag)
+{
+    for (int i = 0; i < count; i++)
+    {
+        SCSI_OUT_DATA(data[i]);
+        delay_100ns();
+        SCSI_OUT(REQ, 1);
+        delay_ns(200);
+        SCSI_OUT(REQ, 0);
+        delay_ns(500);
+    }
+    SCSI_RELEASE_DATA_REQ();
+}
+
+void scsi_accel_sync_stopWrite()
+{
+
+}
+
+void scsi_accel_sync_finishWrite(volatile int *resetFlag)
+{
+
+}
+
+bool scsi_accel_sync_isWriteFinished(const uint8_t* data)
+{
+    return true;
+}
+
+#endif

+ 20 - 0
lib/AzulSCSI_platform_GD32F205/scsi_accel_sync.h

@@ -0,0 +1,20 @@
+// SCSI subroutines that implement synchronous mode SCSI.
+// Uses DMA for data transfer, EXMC for data input and
+// GD32 timer for the REQ pin toggling.
+
+#pragma once
+
+#include <stdint.h>
+#include "AzulSCSI_platform.h"
+
+#ifdef SCSI_IN_ACK_EXMC_NWAIT_PORT
+#define SCSI_SYNC_MODE_AVAILABLE
+#endif
+
+void scsi_accel_sync_init();
+
+void scsi_accel_sync_read(uint8_t *data, uint32_t count, int* parityError, volatile int *resetFlag);
+void scsi_accel_sync_startWrite(const uint8_t* data, uint32_t count, volatile int *resetFlag);
+void scsi_accel_sync_stopWrite();
+void scsi_accel_sync_finishWrite(volatile int *resetFlag);
+bool scsi_accel_sync_isWriteFinished(const uint8_t* data);