فهرست منبع

Add configurable delays

Petteri Aimonen 3 سال پیش
والد
کامیت
a17c51f354
5فایلهای تغییر یافته به همراه85 افزوده شده و 13 حذف شده
  1. 9 0
      README.md
  2. 21 10
      lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.cpp
  3. 8 0
      lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h
  4. 42 3
      src/AzulSCSI.cpp
  5. 5 0
      src/AzulSCSI_config.h

+ 9 - 0
README.md

@@ -33,6 +33,15 @@ Example format for config file:
     Quirks = 0   # 0: Standard, 1: Sharp, 2: NEC PC98
     Debug = 0   # Same effect as DIPSW2
 
+    # Default timings that work with most devices
+    ARBITRATION_DELAY_US = 10
+    SELECTION_DELAY_US   = 10
+    COMMAND_DELAY_US     = 10
+    DATA_DELAY_US        = 10
+    STATUS_DELAY_US      = 10
+    MESSAGE_DELAY_US     = 10
+    REQ_TYPE_SETUP_NS    = 500
+
 Performance
 -----------
 With verbose log messages disabled, expected SCSI performance is 1.7 MB/s read and 1.5 MB/s write.

+ 21 - 10
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.cpp

@@ -9,6 +9,7 @@ extern "C" {
 const char *g_azplatform_name = "GD32F205 AzulSCSI v1.x";
 
 static volatile uint32_t g_millisecond_counter;
+static uint32_t g_ns_to_cycles; // Q0.32 fixed point format
 
 unsigned long millis()
 {
@@ -23,18 +24,26 @@ void delay(unsigned long ms)
 
 void delay_ns(unsigned long ns)
 {
-    int cycles = (ns * SysTick->LOAD) / 1024 / 1024;
-    cycles -= 10; // Call overhead
-    if (cycles > 0)
+    if (ns <= 100) return; // Approximate call overhead
+    ns -= 100;
+
+    uint32_t VAL_start = SysTick->VAL;
+
+    if (ns > 1000000)
     {
-        int end = (int)SysTick->VAL - cycles;
-        if (end < 0)
-        {
-            end += SysTick->LOAD;
-            while (SysTick->VAL < cycles);
-        }
-        while (SysTick->VAL > end);
+        int ms = ns / 1000000;
+        ns = ns - ms * 1000000;
+        delay(ms);
+    }
+
+    int cycles = ((uint64_t)ns * g_ns_to_cycles) >> 32;
+    int end = (int)VAL_start - cycles;
+    if (end <= 0)
+    {
+        end += SysTick->LOAD;
+        while (SysTick->VAL < end);
     }
+    while (SysTick->VAL > end);
 }
 
 void SysTick_Handler(void)
@@ -60,6 +69,8 @@ void azplatform_init()
     SystemCoreClockUpdate();
 
     // Enable SysTick to drive millis()
+    g_millisecond_counter = 0;
+    g_ns_to_cycles = ((uint64_t)SystemCoreClock << 32) / 1000000000;
     SysTick_Config(SystemCoreClock / 1000U);
     NVIC_SetPriority(SysTick_IRQn, 0x00U);
 

+ 8 - 0
lib/AzulSCSI_platform_GD32F205/AzulSCSI_platform.h

@@ -120,6 +120,14 @@ void delay(unsigned long ms);
 // Works in interrupt context also, max delay 500 000 ns, min delay about 500 ns
 void delay_ns(unsigned long ns);
 
+static inline void delay_us(unsigned long us)
+{
+    if (us > 0)
+    {
+        delay_ns(us * 1000);
+    }
+}
+
 // Approximate fast delay
 static inline void delay_100ns()
 {

+ 42 - 3
src/AzulSCSI.cpp

@@ -92,6 +92,16 @@ enum scsi_quirks_t {
   SCSI_QUIRKS_NEC_PC98 = 2
 } g_scsi_quirks;
 
+struct {
+  uint32_t ARBITRATION_DELAY_US;
+  uint32_t SELECTION_DELAY_US;
+  uint32_t COMMAND_DELAY_US;
+  uint32_t DATA_DELAY_US;
+  uint32_t STATUS_DELAY_US;
+  uint32_t MESSAGE_DELAY_US;
+  uint32_t REQ_TYPE_SETUP_NS;
+} g_scsi_timing;
+
 uint8_t SCSI_INFO_BUF[36] = {
   0x00, //device type
   0x00, //RMB = 0
@@ -138,6 +148,14 @@ void readSCSIDeviceConfig()
   {
     g_azlog_debug = true;
   }
+
+  g_scsi_timing.ARBITRATION_DELAY_US = ini_getl("SCSI", "ARBITRATION_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.SELECTION_DELAY_US   = ini_getl("SCSI", "SELECTION_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.COMMAND_DELAY_US     = ini_getl("SCSI", "COMMAND_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.DATA_DELAY_US        = ini_getl("SCSI", "DATA_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.STATUS_DELAY_US      = ini_getl("SCSI", "STATUS_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.MESSAGE_DELAY_US     = ini_getl("SCSI", "MESSAGE_DELAY_US", DEFAULT_SCSI_DELAY_US, CONFIGFILE);
+  g_scsi_timing.REQ_TYPE_SETUP_NS    = ini_getl("SCSI", "REQ_TYPE_SETUP_NS", DEFAULT_REQ_TYPE_SETUP_NS, CONFIGFILE);
 }
 
 /*********************************/
@@ -360,6 +378,8 @@ void writeDataPhase(int len, const uint8_t* p)
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,inactive);
   SCSI_OUT(IO ,  active);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
+
   for (int i = 0; i < len; i++) {
     if (g_busreset) break;
     writeHandshake(p[i]);
@@ -378,6 +398,7 @@ void writeDataPhase_FromSD(uint32_t adds, uint32_t len)
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,inactive);
   SCSI_OUT(IO ,  active);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
 
   uint8_t buf[MAX_BLOCKSIZE];
 
@@ -418,6 +439,8 @@ void readDataPhase(int len, uint8_t* p)
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,inactive);
   SCSI_OUT(IO ,inactive);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
+
   for(int i = 0; i < len; i++)
   {
     if (g_busreset) break;
@@ -437,6 +460,7 @@ void readDataPhase_ToSD(uint32_t adds, uint32_t len)
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,inactive);
   SCSI_OUT(IO ,inactive);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
 
   uint8_t buf[MAX_BLOCKSIZE];
 
@@ -735,8 +759,7 @@ int readSCSICommand(uint8_t cmd[12])
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,  active);
   SCSI_OUT(IO ,inactive);
-
-  delay_ns(500);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
 
   cmd[0] = readHandshake();
   if (g_busreset) return 0;
@@ -764,7 +787,8 @@ bool onATNMessage()
 
   SCSI_OUT(MSG,  active);
   SCSI_OUT(CD ,  active);
-  SCSI_OUT(IO ,inactive);  
+  SCSI_OUT(IO ,inactive);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
 
   uint8_t msg[256];
   memset(msg, 0x00, sizeof(msg));
@@ -847,6 +871,7 @@ bool onATNMessage()
     SCSI_OUT(MSG,  active);
     SCSI_OUT(CD ,  active);
     SCSI_OUT(IO ,  active);
+    delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
 
     for (int i = 0; i < responselen; i++)
     {
@@ -882,6 +907,8 @@ void scsi_loop()
 
   g_busreset = false;
   
+  delay_us(g_scsi_timing.ARBITRATION_DELAY_US);
+
   // Set BSY to-when selected
   SCSI_OUT(BSY, active);
   azdbg("SCSI device selected");
@@ -907,6 +934,8 @@ void scsi_loop()
     }
   }
   
+  delay_us(g_scsi_timing.SELECTION_DELAY_US);
+
   if(SCSI_IN(ATN))
   {
     if (!onATNMessage())
@@ -917,9 +946,13 @@ void scsi_loop()
     }
   }
 
+  delay_us(g_scsi_timing.COMMAND_DELAY_US);
+
   uint8_t cmd[12];
   int cmdlen = readSCSICommand(cmd);
 
+  delay_us(g_scsi_timing.DATA_DELAY_US);
+
   if (cmdlen == 0)
   {
     SCSI_RELEASE_OUTPUTS();
@@ -1012,10 +1045,13 @@ void scsi_loop()
      return;
   }
 
+  delay_us(g_scsi_timing.STATUS_DELAY_US);
+
   azdbg("Status: ", g_scsi_sts);
   SCSI_OUT(MSG,inactive);
   SCSI_OUT(CD ,  active);
   SCSI_OUT(IO ,  active);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
   writeHandshake(g_scsi_sts);
   
   if(g_busreset) {
@@ -1023,9 +1059,12 @@ void scsi_loop()
      return;
   }
 
+  delay_us(g_scsi_timing.MESSAGE_DELAY_US);
+
   SCSI_OUT(MSG,  active);
   SCSI_OUT(CD ,  active);
   SCSI_OUT(IO ,  active);
+  delay_ns(g_scsi_timing.REQ_TYPE_SETUP_NS);
   writeHandshake(0);
 
   azdbg("Command complete");

+ 5 - 0
src/AzulSCSI_config.h

@@ -28,6 +28,11 @@
 #define DEFAULT_PRODUCT "FIREBALL1       "
 #define DEFAULT_VERSION "1.0 "
 
+// Default delay for SCSI phases.
+// Can be adjusted in ini file
+#define DEFAULT_SCSI_DELAY_US 10
+#define DEFAULT_REQ_TYPE_SETUP_NS 500
+
 // Use streaming SCSI and SD transfers for higher performance
 #define STREAM_SD_TRANSFERS 1