Browse Source

Fix sync timings to split read and write period times

Michael McMaster 7 years ago
parent
commit
1620663ee9

+ 3 - 0
lib/SCSI2SD/CHANGELOG

@@ -1,3 +1,6 @@
+20180131		6.1.3
+	- Fix bug that caused stability issues with 10MB/s transfers.
+
 20171128		6.1.2
 	- Fix synchronous negotiation bugs
 

+ 3 - 3
lib/SCSI2SD/STM32CubeMX/SCSI2SD-V6/Src/fsmc.c

@@ -81,10 +81,10 @@ void MX_FSMC_Init(void)
   //   1 to write back to fsmc bus.
   Timing.DataSetupTime = 4;
 
-  // Allow a clock for us to release signals, plus 3 for the synchroniser to
-  // realise the cycle has ended. Need to avoid both devices acting as outputs
+  // Allow a clock for us to release signals
+  // Need to avoid both devices acting as outputs
   // on the multiplexed lines at the same time.
-  Timing.BusTurnAroundDuration = 4;
+  Timing.BusTurnAroundDuration = 1;
 
   Timing.CLKDivision = 16; // Ignored for async
   Timing.DataLatency = 17; // Ignored for async

BIN
lib/SCSI2SD/rtl/fpga_bitmap.o


+ 1 - 1
lib/SCSI2SD/src/firmware/config.c

@@ -38,7 +38,7 @@
 
 #include <string.h>
 
-static const uint16_t FIRMWARE_VERSION = 0x0612;
+static const uint16_t FIRMWARE_VERSION = 0x0613;
 
 // 1 flash row
 static const uint8_t DEFAULT_CONFIG[128] =

+ 5 - 2
lib/SCSI2SD/src/firmware/disk.c

@@ -718,8 +718,11 @@ void scsiDiskPoll()
 				process_MessageIn(); // Will go to BUS_FREE state
 
 				// Try and prevent anyone else using the SCSI bus while we're not ready.
-				*SCSI_CTRL_BSY = 1;
-				clearBSY = 1;
+				if (*SCSI_CTRL_BSY == 0) // Could be busy for a linked command
+				{
+					*SCSI_CTRL_BSY = 1;
+					clearBSY = 1;
+				}
 			}
 
 

+ 2 - 1
lib/SCSI2SD/src/firmware/scsi.c

@@ -815,13 +815,14 @@ static void process_MessageOut()
 				// After 80 we start to run out of bits in the fpga timing
 				// register.
 				(transferPeriod == 0) ||
+				(offset == 0) ||
 				((scsiDev.boardCfg.scsiSpeed != S2S_CFG_SPEED_NoLimit) &&
 					(scsiDev.boardCfg.scsiSpeed <= S2S_CFG_SPEED_ASYNC_50)))
 			{
 				scsiDev.target->syncOffset = 0;
 				scsiDev.target->syncPeriod = 0;
 			} else {
-				scsiDev.target->syncOffset = offset < 63 ? offset : 63;
+				scsiDev.target->syncOffset = offset <= 15 ? offset : 15;
 				// FAST20 / 50ns / 20MHz is disabled for now due to
 				// data corruption while reading data. We can count the
 				// ACK's correctly, but can't save the data to a register

+ 52 - 29
lib/SCSI2SD/src/firmware/scsiPhy.c

@@ -31,7 +31,7 @@
 static uint8_t asyncTimings[][4] =
 {
 /* Speed,    Assert,    Deskew,    Hold,    Glitch */
-{/*1.5MB/s*/ 28,        18,        13,      13},
+{/*1.5MB/s*/ 28,        18,        13,      15},
 {/*3.3MB/s*/ 13,        6,         6,       13},
 {/*5MB/s*/   9,         6,         6,       6}, // 80ns
 {/*safe*/    3,         6,         6,       6}, // Probably safe
@@ -58,7 +58,13 @@ static uint8_t asyncTimings[][4] =
 
 #define SCSI_FAST10_DESKEW 2 // 25ns
 #define SCSI_FAST10_HOLD 3 // 33ns
-#define SCSI_FAST10_ASSERT 3 // 30ns
+#define SCSI_FAST10_WRITE_ASSERT 3 // 30ns. Overall clocks only works if fpga overhead is 3.
+
+// Slow down the cycle to be valid. 2x assert period is TOO FAST when
+// reading data. It's ok when writing due to the deskew.
+// 50ns. ie. 100ns / 2. Rounded down because there's likely a few extra cycles
+// here and there.
+#define SCSI_FAST10_READ_ASSERT 5
 
 // Fastest possible timing, probably not 20MB/s
 #define SCSI_FAST20_DESKEW 1
@@ -74,12 +80,17 @@ static uint8_t asyncTimings[][4] =
 	: SCSI_FAST5_HOLD)
 
 
+// Number of overhead cycles per period.
+#define FPGA_OVERHEAD 2
+#define FPGA_CYCLES_PER_NS 9
+#define SCSI_PERIOD_CLKS(period) ((((int)period * 4) + (FPGA_CYCLES_PER_NS/2)) / FPGA_CYCLES_PER_NS)
+
 // 3.125MB/s (80 period) to < 10MB/s sync
 // Assumes a 108MHz fpga clock. (9 ns)
-// (((period * 4) / 2) * 0.8) / 9
-// Done using 3 fixed point math.
 // 3:0 Assertion count, variable
-#define syncAssertion(period) ((((((int)period) * 177) + 750)/1000) & 0xF)
+#define syncAssertionWrite(period,deskew) ((SCSI_PERIOD_CLKS(period) - deskew - FPGA_OVERHEAD + 1) / 2)
+#define syncAssertionRead(period) syncAssertionWrite(period,0)
+
 
 // Time until we consider ourselves selected
 // 400ns at 108MHz
@@ -481,13 +492,12 @@ scsiSetDefaultTiming()
 		asyncTiming[3]);
 }
 
-void scsiEnterPhase(int phase)
+void scsiEnterPhase(int newPhase)
 {
 	// ANSI INCITS 362-2002 SPI-3 10.7.1:
 	// Phase changes are not allowed while REQ or ACK is asserted.
 	while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}
 
-	int newPhase = phase > 0 ? phase : 0;
 	int oldPhase = *SCSI_CTRL_PHASE;
 
 	if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {
@@ -505,7 +515,14 @@ void scsiEnterPhase(int phase)
 			}
 			else if (scsiDev.target->syncPeriod <= 25)
 			{
-				scsiSetTiming(SCSI_FAST10_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);
+				if (newPhase == DATA_IN)
+				{
+					scsiSetTiming(SCSI_FAST10_WRITE_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);
+				}
+				else
+				{
+					scsiSetTiming(SCSI_FAST10_READ_ASSERT, SCSI_FAST10_DESKEW, SCSI_FAST10_HOLD, 1);
+				}
 			}
 			else
 			{
@@ -514,26 +531,26 @@ void scsiEnterPhase(int phase)
 				int glitch =
 					scsiDev.target->syncPeriod < 35 ? 1 :
 						(scsiDev.target->syncPeriod < 45 ? 2 : 5);
+				int deskew = syncDeskew(scsiDev.target->syncPeriod);
+				int assertion;
+				if (newPhase == DATA_IN)
+				{
+					assertion = syncAssertionWrite(scsiDev.target->syncPeriod, deskew);
+				}
+				else
+				{
+					assertion = syncAssertionRead(scsiDev.target->syncPeriod);
+				}
 				scsiSetTiming(
-					syncAssertion(scsiDev.target->syncPeriod),
-					syncDeskew(scsiDev.target->syncPeriod),
+					assertion,
+					deskew,
 					syncHold(scsiDev.target->syncPeriod),
 					glitch);
 			}
 
-			// See note 26 in SCSI 2 standard: SCSI 1 implementations may assume
-			// "leading edge of the first REQ pulse beyond the REQ/ACK offset
-			// agreement would not occur until after the trailing edge of the
-			// last ACK pulse within the agreement."
-			// We simply subtract 1 from the offset to meet this requirement.
-			if (scsiDev.target->syncOffset >= 2)
-			{
-				*SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset - 1;
-			} else {
-				*SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
-			}
+			*SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
 		}
-		else
+		else if (newPhase >= 0)
 		{
 
 			*SCSI_CTRL_SYNC_OFFSET = 0;
@@ -564,14 +581,20 @@ void scsiEnterPhase(int phase)
 				asyncTiming[3]);
 		}
 
-		*SCSI_CTRL_PHASE = newPhase;
-		busSettleDelay();
+		if (newPhase >= 0)
+		{
+			*SCSI_CTRL_PHASE = newPhase;
+			busSettleDelay();
 
-		if (scsiDev.compatMode < COMPAT_SCSI2)
+			if (scsiDev.compatMode < COMPAT_SCSI2)
+			{
+				s2s_delay_us(100);
+			}
+		}
+		else
 		{
-			s2s_delay_us(100);
+			*SCSI_CTRL_PHASE = 0;
 		}
-
 	}
 }
 
@@ -587,10 +610,10 @@ void scsiPhyReset()
 		dmaInProgress = 0;
 	}
 
-	*SCSI_CTRL_PHASE = 0x00;
-	*SCSI_CTRL_BSY = 0x00;
 	s2s_fpgaReset(); // Clears fifos etc.
 
+	*SCSI_CTRL_PHASE = 0x00;
+	*SCSI_CTRL_BSY = 0x00;
 	scsiPhyFifoSel = 0;
 	*SCSI_FIFO_SEL = 0;
 	*SCSI_CTRL_DBX = 0;