浏览代码

Merge pull request #468 from ZuluSCSI/feature/scsi-ultra

Ultra SCSI (Fast20) support with reclocking the RP2040 and RP2350 line of boards and user editable reclocking timings
Alex Perez 1 年之前
父节点
当前提交
79b5c401dd
共有 56 个文件被更改,包括 1773 次插入2635 次删除
  1. 1 1
      lib/SCSI2SD/include/scsi2sd.h
  2. 36 24
      lib/SCSI2SD/src/firmware/scsi.c
  3. 29 0
      lib/SCSI2SD/src/firmware/timings.h
  4. 6 0
      lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp
  5. 13 25
      lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h
  6. 47 0
      lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_config.h
  7. 26 0
      lib/ZuluSCSI_platform_GD32F205/scsi2sd_timings.c
  8. 5 0
      lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.cpp
  9. 14 17
      lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.h
  10. 38 0
      lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_config.h
  11. 26 0
      lib/ZuluSCSI_platform_GD32F450/scsi2sd_timings.c
  12. 176 38
      lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.cpp
  13. 21 56
      lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.h
  14. 73 0
      lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_config.h
  15. 2 0
      lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_network.cpp
  16. 123 0
      lib/ZuluSCSI_platform_RP2MCU/custom_timings.cpp
  17. 35 0
      lib/ZuluSCSI_platform_RP2MCU/custom_timings.h
  18. 33 0
      lib/ZuluSCSI_platform_RP2MCU/scsi2sd_timings.c
  19. 6 9
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host.cpp
  20. 0 46
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico.pio
  21. 0 43
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico.pio.h
  22. 0 46
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico_2.pio
  23. 0 43
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico_2.pio.h
  24. 0 46
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2350A.pio
  25. 0 44
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2350A.pio.h
  26. 1 1
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2MCU.pio
  27. 0 0
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2MCU.pio.h
  28. 222 100
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target.cpp
  29. 0 124
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico.pio
  30. 0 225
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico.pio.h
  31. 0 124
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico_2.pio
  32. 0 224
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico_2.pio.h
  33. 0 225
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2040.pio.h
  34. 0 125
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2350A.pio
  35. 22 21
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2MCU.pio
  36. 31 31
      lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2MCU.pio.h
  37. 2 1
      lib/ZuluSCSI_platform_RP2MCU/sd_card_sdio.cpp
  38. 55 12
      lib/ZuluSCSI_platform_RP2MCU/sdio.cpp
  39. 0 164
      lib/ZuluSCSI_platform_RP2MCU/sdio_Pico.pio
  40. 0 121
      lib/ZuluSCSI_platform_RP2MCU/sdio_Pico.pio.h
  41. 0 164
      lib/ZuluSCSI_platform_RP2MCU/sdio_Pico_2.pio
  42. 0 121
      lib/ZuluSCSI_platform_RP2MCU/sdio_Pico_2.pio.h
  43. 0 164
      lib/ZuluSCSI_platform_RP2MCU/sdio_RP2350A.pio
  44. 0 121
      lib/ZuluSCSI_platform_RP2MCU/sdio_RP2350A.pio.h
  45. 30 29
      lib/ZuluSCSI_platform_RP2MCU/sdio_RP2MCU.pio
  46. 28 29
      lib/ZuluSCSI_platform_RP2MCU/sdio_RP2MCU.pio.h
  47. 333 0
      lib/ZuluSCSI_platform_RP2MCU/timings_RP2MCU.c
  48. 108 0
      lib/ZuluSCSI_platform_RP2MCU/timings_RP2MCU.h
  49. 84 57
      src/ZuluSCSI.cpp
  50. 1 0
      src/ZuluSCSI_cdrom.cpp
  51. 32 9
      src/ZuluSCSI_config.h
  52. 2 0
      src/ZuluSCSI_disk.cpp
  53. 2 1
      src/ZuluSCSI_settings.cpp
  54. 1 0
      src/ZuluSCSI_tape.cpp
  55. 10 4
      zuluscsi.ini
  56. 99 0
      zuluscsi_timings.ini

+ 1 - 1
lib/SCSI2SD/include/scsi2sd.h

@@ -102,7 +102,7 @@ typedef enum
 	S2S_CFG_SPEED_ASYNC_50,
 	S2S_CFG_SPEED_SYNC_5,
 	S2S_CFG_SPEED_SYNC_10,
-	S2S_CFG_SPEED_TURBO
+	S2S_CFG_SPEED_SYNC_20
 } S2S_CFG_SPEED;
 
 typedef struct __attribute__((packed))

+ 36 - 24
lib/SCSI2SD/src/firmware/scsi.c

@@ -28,6 +28,7 @@
 #include "led.h"
 #include "mode.h"
 #include "scsi2sd_time.h"
+#include "timings.h"
 #include "bsp.h"
 #include "cdrom.h"
 #include "network.h"
@@ -758,8 +759,16 @@ static void scsiReset()
 
 	for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 	{
-		scsiDev.targets[i].syncOffset = 0;
-		scsiDev.targets[i].syncPeriod = 0;
+		if (g_force_sync > 0)
+		{
+			scsiDev.targets[i].syncPeriod = g_force_sync;
+			scsiDev.targets[i].syncOffset = g_force_offset;
+		}
+		else
+		{
+			scsiDev.targets[i].syncOffset = 0;
+			scsiDev.targets[i].syncPeriod = 0;
+		}
 	}
 	scsiDev.minSyncPeriod = 0;
 
@@ -1105,31 +1114,26 @@ static void process_MessageOut()
 				//The speeds above correspond to syncPeriod values of 25, 18, 15 and 12 (maybe, the last 3 are truncated)
 				//We will set the syncPeriod and syncOffset to the fastest we 
 				//can support if the initiator requests a faster speed
-				if ((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO) &&
-					(transferPeriod <= 18))
+				if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_SYNC_20 || scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit)
 				{
-					scsiDev.target->syncPeriod = 18; // 20 corresponds to 12.5 MB/s
+					if (transferPeriod <= g_max_sync_20_period)
+						scsiDev.target->syncPeriod = g_max_sync_20_period;
+					else 
+						scsiDev.target->syncPeriod = transferPeriod;	
 				}
-				else if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO)
+				else if (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)
 				{
-					scsiDev.target->syncPeriod = transferPeriod;
+					if (transferPeriod <= g_max_sync_10_period)
+						scsiDev.target->syncPeriod = g_max_sync_10_period;
+					else
+						scsiDev.target->syncPeriod = transferPeriod;
 				}
-				else if (transferPeriod <= 25 &&
-					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
-						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
-				{
-					scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s
-
-				} else if (transferPeriod < 50 &&
-					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
-						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
+				else if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_SYNC_5)
 				{
-					scsiDev.target->syncPeriod = transferPeriod;
-				} else if (transferPeriod >= 50)
-				{
-					scsiDev.target->syncPeriod = transferPeriod;
-				} else {
-					scsiDev.target->syncPeriod = 50;
+					if (transferPeriod <= g_max_sync_5_period)
+						scsiDev.target->syncPeriod = g_max_sync_5_period;
+					else
+						scsiDev.target->syncPeriod = transferPeriod;
 				}
 			}
 
@@ -1350,8 +1354,16 @@ void scsiInit()
 		scsiDev.targets[i].sense.code = NO_SENSE;
 		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 
-		scsiDev.targets[i].syncOffset = 0;
-		scsiDev.targets[i].syncPeriod = 0;
+		if (g_force_sync > 0)
+		{
+			scsiDev.targets[i].syncPeriod = g_force_sync;
+			scsiDev.targets[i].syncOffset = g_force_offset;
+		}
+		else
+		{
+			scsiDev.targets[i].syncOffset = 0;
+			scsiDev.targets[i].syncPeriod = 0;
+		}
 
 		// Always "start" the device. Many systems (eg. Apple System 7)
 		// won't respond properly to

+ 29 - 0
lib/SCSI2SD/src/firmware/timings.h

@@ -0,0 +1,29 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#ifndef ZULUSCSI_SCSI2SD_TIMINGS_H
+#define ZULUSCSI_SCSI2SD_TIMINGS_H
+#include <stdint.h>
+extern uint8_t g_max_sync_20_period;
+extern uint8_t g_max_sync_10_period;
+extern uint8_t g_max_sync_5_period;
+extern uint8_t g_force_sync;
+extern uint8_t g_force_offset;
+#endif // ZULUSCSI_SCSI2SD_TIMINGS_H

+ 6 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.cpp

@@ -137,6 +137,12 @@ void SysTick_Handle_PreEmptively()
     __enable_irq();
 }
 
+uint32_t platform_sys_clock_in_hz()
+{
+    return rcu_clock_freq_get(CK_SYS);
+}
+
+
 /***************/
 /* GPIO init   */
 /***************/

+ 13 - 25
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform.h

@@ -27,6 +27,7 @@
 #include <gd32f20x.h>
 #include <gd32f20x_gpio.h>
 #include <scsi2sd.h>
+#include <ZuluSCSI_config.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -34,27 +35,6 @@ extern "C" {
 
 extern const char *g_platform_name;
 
-#if defined(ZULUSCSI_V1_0)
-#   if defined(ZULUSCSI_V1_0_mini)
-#       define PLATFORM_NAME "ZuluSCSI mini v1.0"
-#   else
-#       define PLATFORM_NAME "ZuluSCSI v1.0"
-#   endif
-#   define PLATFORM_REVISION "1.0"
-#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_ASYNC_50
-#   include "ZuluSCSI_v1_0_gpio.h"
-#else
-#   define PLATFORM_NAME "ZuluSCSI v1.1+"
-#   define PLATFORM_REVISION "1.1+"
-#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
-#   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
-#   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
-#   define PLATFORM_VERSION_1_1_PLUS
-#   define ZULUSCSI_HARDWARE_CONFIG
-#   include "ZuluSCSI_v1_1_gpio.h"
-#endif
-
 #include "platform_hw_config.h"
 
 enum ZuluSCSIVersion_t
@@ -69,10 +49,6 @@ enum ZuluSCSIVersion_t
 extern enum ZuluSCSIVersion_t g_zuluscsi_version;
 extern bool g_moved_select_in;
 
-#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
-#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
-#endif
-
 // Debug logging functions
 void platform_log(const char *s);
 
@@ -126,6 +102,18 @@ void platform_poll();
 // This function should return without significantly delay.
 uint8_t platform_get_buttons();
 
+// Return system clock in Hz
+uint32_t platform_sys_clock_in_hz();
+
+// Attempt to reclock the MCU - unsupported
+inline zuluscsi_reclock_status_t platform_reclock(zuluscsi_speed_grade_t speed_grade){return ZULUSCSI_RECLOCK_NOT_SUPPORTED;}
+
+// match string to speed grade - unsupported
+inline zuluscsi_speed_grade_t platform_string_to_speed_grade(const char *speed_grade_str, size_t length){return SPEED_GRADE_DEFAULT;}
+
+// Returns true if reboot was for mass storage - unsupported
+inline bool platform_rebooted_into_mass_storage() {return false;}
+
 // Reinitialize SD card connection and save log from interrupt context.
 // This can be used in crash handlers.
 void platform_emergency_log_save();

+ 47 - 0
lib/ZuluSCSI_platform_GD32F205/ZuluSCSI_platform_config.h

@@ -0,0 +1,47 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+#if defined(ZULUSCSI_V1_0)
+#   if defined(ZULUSCSI_V1_0_mini)
+#       define PLATFORM_NAME "ZuluSCSI mini v1.0"
+#   else
+#       define PLATFORM_NAME "ZuluSCSI v1.0"
+#   endif
+#   define PLATFORM_REVISION "1.0"
+#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_ASYNC_50
+#   include "ZuluSCSI_v1_0_gpio.h"
+#else
+#   define PLATFORM_NAME "ZuluSCSI v1.1+"
+#   define PLATFORM_REVISION "1.1+"
+#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
+#   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
+#   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
+#   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
+#   define PLATFORM_VERSION_1_1_PLUS
+#   define ZULUSCSI_HARDWARE_CONFIG
+#   include "ZuluSCSI_v1_1_gpio.h"
+#endif
+
+#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
+#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
+#endif
+
+#define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 10

+ 26 - 0
lib/ZuluSCSI_platform_GD32F205/scsi2sd_timings.c

@@ -0,0 +1,26 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#include "timings.h"
+uint8_t g_max_sync_20_period = 25;
+uint8_t g_max_sync_10_period = 25;
+uint8_t g_max_sync_5_period  = 50;
+uint8_t g_force_sync = 0;
+uint8_t g_force_offset = 15;

+ 5 - 0
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.cpp

@@ -128,6 +128,11 @@ void SysTick_Handle_PreEmptively()
     __enable_irq();
 }
 
+uint32_t platform_sys_clock_in_hz()
+{
+    return rcu_clock_freq_get(CK_SYS);
+}
+
 /***************/
 /* GPIO init   */
 /***************/

+ 14 - 17
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform.h

@@ -27,8 +27,7 @@
 #include <gd32f4xx.h>
 #include <gd32f4xx_gpio.h>
 #include <scsi2sd.h>
-#include "ZuluSCSI_config.h"
-
+#include <ZuluSCSI_config.h>
 
 #ifdef __cplusplus
 #include <SdFat.h>
@@ -38,21 +37,6 @@ extern "C" {
 
 extern const char *g_platform_name;
 
-#if defined(ZULUSCSI_V1_4)
-#   define PLATFORM_NAME "ZuluSCSI v1.4"
-#   define PLATFORM_REVISION "1.4"
-#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
-#   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
-#   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
-#   define PLATFORM_FLASH_SECTOR_ERASE
-#   include "ZuluSCSI_v1_4_gpio.h"
-#endif
-
-#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
-#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
-#endif
-
 // Debug logging functions
 void platform_log(const char *s);
 
@@ -110,6 +94,19 @@ void platform_poll();
 // This function should return without significantly delay.
 uint8_t platform_get_buttons();
 
+uint32_t platform_sys_clock_in_hz();
+
+// Attempt to reclock the MCU - unsupported
+inline zuluscsi_reclock_status_t platform_reclock(zuluscsi_speed_grade_t speed_grade){return ZULUSCSI_RECLOCK_NOT_SUPPORTED;}
+
+// match string to speed grade - unsupported
+inline zuluscsi_speed_grade_t platform_string_to_speed_grade(const char *speed_grade_str, size_t length){return SPEED_GRADE_DEFAULT;}
+
+// Returns true if reboot was for mass storage - unsupported
+inline bool platform_rebooted_into_mass_storage() {return false;}
+
+
+
 // Reinitialize SD card connection and save log from interrupt context.
 // This can be used in crash handlers.
 void platform_emergency_log_save();

+ 38 - 0
lib/ZuluSCSI_platform_GD32F450/ZuluSCSI_platform_config.h

@@ -0,0 +1,38 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+
+#if defined(ZULUSCSI_V1_4)
+#   define PLATFORM_NAME "ZuluSCSI v1.4"
+#   define PLATFORM_REVISION "1.4"
+#   define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
+#   define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 4096
+#   define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
+#   define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
+#   define PLATFORM_FLASH_SECTOR_ERASE
+#   include "ZuluSCSI_v1_4_gpio.h"
+#endif
+
+#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
+#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
+#endif
+
+#define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 10

+ 26 - 0
lib/ZuluSCSI_platform_GD32F450/scsi2sd_timings.c

@@ -0,0 +1,26 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#include "timings.h"
+uint8_t g_max_sync_20_period = 25;
+uint8_t g_max_sync_10_period = 25;
+uint8_t g_max_sync_5_period  = 50; 
+uint8_t g_force_sync = 0;
+uint8_t g_force_offset = 15;

+ 176 - 38
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.cpp

@@ -1,27 +1,26 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * https://www.gnu.org/licenses/gpl-3.0.html
  * ----
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version. 
- * 
+ * (at your option) any later version.
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details. 
- * 
+ * GNU General Public License for more details.
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 **/
 
 #include "ZuluSCSI_platform.h"
 #include "ZuluSCSI_log.h"
-#include "ZuluSCSI_config.h"
 #include <SdFat.h>
 #include <scsi.h>
 #include <assert.h>
@@ -37,6 +36,7 @@
 #include <hardware/structs/usb.h>
 #include <hardware/sync.h>
 #include "scsi_accel_target.h"
+#include "custom_timings.h"
 
 #ifndef PIO_FRAMEWORK_ARDUINO_NO_USB
 # include <SerialUSB.h>
@@ -48,7 +48,7 @@
 #ifdef ZULUSCSI_NETWORK
 extern "C" {
 #  include <pico/cyw43_arch.h>
-} 
+}
 #endif // ZULUSCSI_NETWORK
 
 #ifdef ENABLE_AUDIO_OUTPUT
@@ -58,12 +58,11 @@ extern "C" {
 extern bool g_rawdrive_active;
 
 extern "C" {
-
+#include "timings_RP2MCU.h"
 const char *g_platform_name = PLATFORM_NAME;
 static bool g_scsi_initiator = false;
 static uint32_t g_flash_chip_size = 0;
 static bool g_uart_initialized = false;
-
 /***************/
 /* GPIO init   */
 /***************/
@@ -82,13 +81,10 @@ static void gpio_conf(uint gpio, gpio_function_t fn, bool pullup, bool pulldown,
     }
 }
 
-#ifdef ENABLE_AUDIO_OUTPUT
-// Increases clk_sys and clk_peri to 135.428571MHz at runtime to support
-// division to audio output rates. Invoke before anything is using clk_peri
-// except for the logging UART, which is handled below.
-static void reclock_for_audio() {
+static void reclock() {
     // ensure UART is fully drained before we mess up its clock
-    uart_tx_wait_blocking(uart0);
+    if (uart_is_enabled(uart0))
+        uart_tx_wait_blocking(uart0);
     // switch clk_sys and clk_peri to pll_usb
     // see code in 2.15.6.1 of the datasheet for useful comments
     clock_configure(clk_sys,
@@ -101,23 +97,109 @@ static void reclock_for_audio() {
             CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
             48 * MHZ,
             48 * MHZ);
-    // reset PLL for 135.428571MHz
-    pll_init(pll_sys, 1, 948000000, 7, 1);
+    // reset PLL
+    pll_init(pll_sys,
+        g_zuluscsi_timings->pll.refdiv,
+        g_zuluscsi_timings->pll.vco_freq,
+        g_zuluscsi_timings->pll.post_div1,
+        g_zuluscsi_timings->pll.post_div2);
+
     // switch clocks back to pll_sys
     clock_configure(clk_sys,
             CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
             CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
-            135428571,
-            135428571);
+            g_zuluscsi_timings->clk_hz,
+            g_zuluscsi_timings->clk_hz);
     clock_configure(clk_peri,
             0,
             CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
-            135428571,
-            135428571);
+            g_zuluscsi_timings->clk_hz,
+            g_zuluscsi_timings->clk_hz);
     // reset UART for the new clock speed
-    uart_init(uart0, 1000000);
+    if (uart_is_enabled(uart0))
+        uart_init(uart0, 1000000);
+}
+
+uint32_t platform_sys_clock_in_hz()
+{
+    return clock_get_hz(clk_sys);
+}
+
+zuluscsi_speed_grade_t platform_string_to_speed_grade(const char *speed_grade_str, size_t length)
+{
+    static const char sg_default[] = "Default";
+    zuluscsi_speed_grade_t grade;
+
+#ifdef ENABLE_AUDIO_OUTPUT
+    logmsg("Audio output enabled, reclocking isn't possible");
+    return SPEED_GRADE_DEFAULT;
+#endif;
+
+    if (strcasecmp(speed_grade_str, sg_default) == 0)
+      grade = SPEED_GRADE_DEFAULT;
+    else if (strcasecmp(speed_grade_str, "TurboMax") == 0)
+      grade = SPEED_GRADE_MAX;
+    else if (strcasecmp(speed_grade_str, "TurboA") == 0)
+      grade = SPEED_GRADE_A;
+    else if (strcasecmp(speed_grade_str, "TurboB") == 0)
+      grade = SPEED_GRADE_B;
+    else if (strcasecmp(speed_grade_str, "TurboC") == 0)
+      grade = SPEED_GRADE_C;
+    else if (strcasecmp(speed_grade_str, "Custom") == 0)
+      grade = SPEED_GRADE_CUSTOM;
+    else
+    {
+      logmsg("Setting \"", speed_grade_str, "\" does not match any know speed grade, using default");
+      grade = SPEED_GRADE_DEFAULT;
+    }
+    return grade;
+}
+
+zuluscsi_reclock_status_t platform_reclock(zuluscsi_speed_grade_t speed_grade)
+{
+    CustomTimings ct;
+    if (speed_grade == SPEED_GRADE_CUSTOM)
+    {
+        if (ct.use_custom_timings())
+        {
+            logmsg("Custom timings found in \"", CUSTOM_TIMINGS_FILE, "\" overriding reclocking");
+            logmsg("Initial Clock set to ", (int) platform_sys_clock_in_hz(), "Hz");
+            if (ct.set_timings_from_file())
+            {
+                reclock();
+                logmsg("SDIO clock set to ", (int)((g_zuluscsi_timings->clk_hz / g_zuluscsi_timings->sdio.clk_div_pio + (5 * MHZ / 10)) / MHZ) , "MHz");
+                return ZULUSCSI_RECLOCK_CUSTOM;
+            }
+            else
+                return ZULUSCSI_RECLOCK_FAILED;
+        }
+        else
+        {
+            logmsg("Custom timings file, \"", CUSTOM_TIMINGS_FILE, "\" not found or disabled");
+            return ZULUSCSI_RECLOCK_FAILED;
+        }
+
+    }
+    else if (set_timings(speed_grade))
+    {
+        logmsg("Initial Clock set to ", (int) platform_sys_clock_in_hz(), "Hz");
+        reclock();
+        logmsg("SDIO clock set to ", (int)((g_zuluscsi_timings->clk_hz / g_zuluscsi_timings->sdio.clk_div_pio + (5 * MHZ / 10)) / MHZ) , "MHz");
+        return ZULUSCSI_RECLOCK_SUCCESS;
+    }
+    return ZULUSCSI_RECLOCK_FAILED;
+}
+
+bool platform_rebooted_into_mass_storage()
+{
+    volatile uint32_t* scratch0 = (uint32_t *)(WATCHDOG_BASE + WATCHDOG_SCRATCH0_OFFSET);
+    if (*scratch0 == REBOOT_INTO_MASS_STORAGE_MAGIC_NUM)
+    {
+        *scratch0 = 0;
+        return true;
+    }
+    return false;
 }
-#endif  // ENABLE_AUDIO_OUT
 
 #ifdef HAS_DIP_SWITCHES
 enum pin_setup_state_t  {SETUP_FALSE, SETUP_TRUE, SETUP_UNDETERMINED};
@@ -126,7 +208,7 @@ static pin_setup_state_t read_setup_ack_pin()
     /* Revision 2022d of the RP2040 hardware has problems reading initiator DIP switch setting.
      * The 74LVT245 hold current is keeping the GPIO_ACK state too strongly.
      * Detect this condition by toggling the pin up and down and seeing if it sticks.
-     * 
+     *
      * Revision 2023b and 2023c of the Pico boards have issues reading TERM and DEBUG DIP switch
      * settings. GPIO_ACK is externally pulled down to ground for later revisions.
      * If the state is detected as undetermined then the board is the 2023b or 2023c revision.
@@ -138,7 +220,7 @@ static pin_setup_state_t read_setup_ack_pin()
     gpio_conf(SCSI_IN_ACK,  GPIO_FUNC_SIO, false, true,  false, true,  false);
     delay(1);
     bool ack_state1 = gpio_get(SCSI_IN_ACK);
-    
+
     // Strong output low, then pullup
     //        pin             function       pup   pdown   out    state  fast
     gpio_conf(SCSI_IN_ACK,  GPIO_FUNC_SIO, false, false, true,  false, false);
@@ -169,7 +251,7 @@ void platform_init()
 
     pio_clear_instruction_memory(pio0);
     pio_clear_instruction_memory(pio1);
-    
+
     /* First configure the pins that affect external buffer directions.
      * RP2040 defaults to pulldowns, while these pins have external pull-ups.
      */
@@ -191,13 +273,13 @@ void platform_init()
 # if defined(ZULUSCSI_PICO) || defined(ZULUSCSI_PICO_2)
     // Initiator dip setting works on all rev 2023b, 2023c, and newer rev Pico boards
     g_scsi_initiator = !gpio_get(DIP_INITIATOR);
-    
-    working_dip = SETUP_UNDETERMINED != read_setup_ack_pin();    
+
+    working_dip = SETUP_UNDETERMINED != read_setup_ack_pin();
     if (working_dip)
     {
         dbglog = !gpio_get(DIP_DBGLOG);
         termination = !gpio_get(DIP_TERM);
-        
+
     }
 # else
     g_scsi_initiator = SETUP_TRUE == read_setup_ack_pin();
@@ -220,7 +302,7 @@ void platform_init()
 
 #ifdef HAS_DIP_SWITCHES
     if (working_dip)
-    {       
+    {
         logmsg("DIP switch settings: debug log ", (int)dbglog, ", termination ", (int)termination);
         g_log_debug = dbglog;
 
@@ -247,8 +329,14 @@ void platform_init()
 
 #ifdef ENABLE_AUDIO_OUTPUT
     logmsg("SP/DIF audio to expansion header enabled");
-    logmsg("-- Overclocking to 135.428571MHz");
-    reclock_for_audio();
+    if (platform_reclock(SPEED_GRADE_AUDIO) == ZULUSCSI_RECLOCK_SUCCESS)
+    {
+        logmsg("Reclocked for Audio Ouput at ", (int) platform_sys_clock_in_hz(), "Hz");
+    }
+    else
+    {
+        logmsg("Audio Output timings not found");
+    }
 #endif // ENABLE_AUDIO_OUTPUT
 
     // Get flash chip size
@@ -389,6 +477,7 @@ void platform_late_init()
         gpio_conf(SCSI_OUT_ATN,   GPIO_FUNC_SIO, false,false, true,  true, true);
 #endif  // PLATFORM_HAS_INITIATOR_MODE
     }
+    scsi_accel_rp2040_init();
 }
 
 void platform_post_sd_card_init() {}
@@ -399,7 +488,7 @@ bool platform_is_initiator_mode_enabled()
 }
 
 void platform_disable_led(void)
-{   
+{
     //        pin      function       pup   pdown  out    state fast
     gpio_conf(LED_PIN, GPIO_FUNC_SIO, false,false, false, false, false);
     logmsg("Disabling status LED");
@@ -438,6 +527,7 @@ void platform_emergency_log_save()
 
 
 static void usb_log_poll();
+static void usb_input_poll();
 
 __attribute__((noinline))
 void show_hardfault(uint32_t *sp)
@@ -527,17 +617,64 @@ static void usb_log_poll()
         uint32_t len = available;
         if (len == 0) return;
         if (len > CFG_TUD_CDC_EP_BUFSIZE) len = CFG_TUD_CDC_EP_BUFSIZE;
-        
+
         // Update log position by the actual number of bytes sent
         // If USB CDC buffer is full, this may be 0
         uint32_t actual = 0;
         actual = Serial.write(data, len);
         logpos -= available - actual;
     }
+
 #endif // PIO_FRAMEWORK_ARDUINO_NO_USB
 }
 
+// Grab input from USB Serial terminal
+static void usb_input_poll()
+{
+    #ifndef PIO_FRAMEWORK_ARDUINO_NO_USB
+    // Caputure reboot key sequence
+    static bool mass_storage_reboot_keyed = false;
+    static bool basic_reboot_keyed = false;
+    volatile uint32_t* scratch0 = (uint32_t *)(WATCHDOG_BASE + WATCHDOG_SCRATCH0_OFFSET);
+    int32_t available = Serial.available();
+    if(available > 0)
+    {
+        int32_t read = Serial.read();
+        switch((char) read)
+        {
+            case 'R':
+            case 'r':
+                basic_reboot_keyed = true;
+                mass_storage_reboot_keyed = false;
+                logmsg("Basic reboot requested, press 'y' to engage or any key to clear");
+                break;
+            case 'M':
+            case 'm':
+                mass_storage_reboot_keyed = true;
+                basic_reboot_keyed = false;
+                logmsg("Boot into mass storage requested, press 'y' to engage or any key to clear");
+                *scratch0 = REBOOT_INTO_MASS_STORAGE_MAGIC_NUM;
+                break;
+            case 'Y':
+            case 'y':
+                if (basic_reboot_keyed || mass_storage_reboot_keyed)
+                {
+                    logmsg("Rebooting", mass_storage_reboot_keyed ? " into mass storage": "");
+                    watchdog_reboot(0, 0, 2000);
+                }
+                break;
+            case '\n':
+                break;
 
+            default:
+                if (basic_reboot_keyed || mass_storage_reboot_keyed)
+                    logmsg("Cleared reboot setting");
+                mass_storage_reboot_keyed = false;
+                basic_reboot_keyed = false;
+        }
+    }
+#endif // PIO_FRAMEWORK_ARDUINO_NO_USB
+}
 // Use ADC to implement supply voltage monitoring for the +3.0V rail.
 // This works by sampling the temperature sensor channel, which has
 // a voltage of 0.7 V, allowing to calculate the VDD voltage.
@@ -717,9 +854,10 @@ void platform_reset_watchdog()
 // Can be left empty or used for platform-specific processing.
 void platform_poll()
 {
+    usb_input_poll();
     usb_log_poll();
     adc_poll();
-    
+
 #ifdef ENABLE_AUDIO_OUTPUT
     audio_poll();
 #endif // ENABLE_AUDIO_OUTPUT

+ 21 - 56
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform.h

@@ -1,20 +1,20 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * https://www.gnu.org/licenses/gpl-3.0.html
  * ----
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version. 
- * 
+ * (at your option) any later version.
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details. 
- * 
+ * GNU General Public License for more details.
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 **/
@@ -25,6 +25,7 @@
 
 #include <stdint.h>
 #include <Arduino.h>
+#include "ZuluSCSI_config.h"
 #include "ZuluSCSI_platform_network.h"
 
 #ifdef ZULUSCSI_PICO
@@ -54,56 +55,9 @@ extern "C" {
 /* These are used in debug output and default SCSI strings */
 extern const char *g_platform_name;
 
-#ifdef ZULUSCSI_PICO
-# ifdef ZULUSCSI_DAYNAPORT
-#   define PLATFORM_NAME "ZuluSCSI Pico DaynaPORT"
-# else
-#   define PLATFORM_NAME "ZuluSCSI Pico"
-# endif
-# define PLATFORM_PID "Pico"
-# define PLATFORM_REVISION "2.0"
-# define PLATFORM_HAS_INITIATOR_MODE 1
-# define DISABLE_SWO
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#elif defined(ZULUSCSI_PICO_2)
-# define PLATFORM_NAME "ZuluSCSI Pico 2"
-# define PLATFORM_PID "Pico 2"
-# define PLATFORM_REVISION "2.0"
-# define PLATFORM_HAS_INITIATOR_MODE 1
-# define DISABLE_SWO
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_TURBO
-#elif defined(ZULUSCSI_RP2350A)
-# define PLATFORM_NAME "ZuluSCSI RP2350A"
-# define PLATFORM_PID "RP2350A"
-# define PLATFORM_REVISION "2.0"
-# define PLATFORM_HAS_INITIATOR_MODE 1
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_TURBO
-#elif defined(ZULUSCSI_BS2)
-# define PLATFORM_NAME "ZuluSCSI BS2"
-# define PLATFORM_PID "BS2"
-# define PLATFORM_REVISION "1.0"
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#else
-# define PLATFORM_NAME "ZuluSCSI RP2040"
-# define PLATFORM_PID "RP2040"
-# define PLATFORM_REVISION "2.0"
-# define PLATFORM_HAS_INITIATOR_MODE 1
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#endif
-
-#define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 32768
-#define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
-#define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
-#define SD_USE_SDIO 1
-#define PLATFORM_HAS_PARITY_CHECK 1
-
-#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
-#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
-#endif
-
 // NOTE: The driver supports synchronous speeds higher than 10MB/s, but this
 // has not been tested due to lack of fast enough SCSI adapter.
-// #define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_TURBO
+// #define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
 
 // Debug logging function, can be used to print to e.g. serial port.
 // May get called from interrupt handlers.
@@ -157,6 +111,17 @@ void platform_poll();
 // This function should return without significantly delay.
 uint8_t platform_get_buttons();
 
+uint32_t platform_sys_clock_in_hz();
+
+// Attempt to reclock the MCU
+zuluscsi_reclock_status_t platform_reclock(zuluscsi_speed_grade_t speed_grade);
+
+// convert string to speed grade
+zuluscsi_speed_grade_t platform_string_to_speed_grade(const char *speed_grade_str, size_t length);
+
+// Returns true if reboot was for mass storage
+bool platform_rebooted_into_mass_storage();
+
 // Set callback that will be called during data transfer to/from SD card.
 // This can be used to implement simultaneous transfer to SCSI bus.
 typedef void (*sd_callback_t)(uint32_t bytes_complete);

+ 73 - 0
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_config.h

@@ -0,0 +1,73 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+
+#ifdef ZULUSCSI_PICO
+# ifdef ZULUSCSI_DAYNAPORT
+#   define PLATFORM_NAME "ZuluSCSI Pico DaynaPORT"
+# else
+#   define PLATFORM_NAME "ZuluSCSI Pico"
+# endif
+# define PLATFORM_PID "Pico"
+# define PLATFORM_REVISION "2.0"
+# define PLATFORM_HAS_INITIATOR_MODE 1
+# define DISABLE_SWO
+# define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
+# define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 10
+#elif defined(ZULUSCSI_PICO_2)
+# define PLATFORM_NAME "ZuluSCSI Pico 2"
+# define PLATFORM_PID "Pico 2"
+# define PLATFORM_REVISION "2.0"
+# define PLATFORM_HAS_INITIATOR_MODE 1
+# define DISABLE_SWO
+# define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
+# define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 20
+#elif defined(ZULUSCSI_RP2350A)
+# define PLATFORM_NAME "ZuluSCSI RP2350A"
+# define PLATFORM_PID "RP2350A"
+# define PLATFORM_REVISION "2.0"
+# define PLATFORM_HAS_INITIATOR_MODE 1
+# define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
+# define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 20
+#elif defined(ZULUSCSI_BS2)
+# define PLATFORM_NAME "ZuluSCSI BS2"
+# define PLATFORM_PID "BS2"
+# define PLATFORM_REVISION "1.0"
+# define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
+# define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 10
+#else
+# define PLATFORM_NAME "ZuluSCSI RP2040"
+# define PLATFORM_PID "RP2040"
+# define PLATFORM_REVISION "2.0"
+# define PLATFORM_HAS_INITIATOR_MODE 1
+# define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_20
+# define PLATFORM_DEFAULT_SCSI_SPEED_SETTING 10
+#endif
+
+#define PLATFORM_OPTIMAL_MIN_SD_WRITE_SIZE 32768
+#define PLATFORM_OPTIMAL_MAX_SD_WRITE_SIZE 65536
+#define PLATFORM_OPTIMAL_LAST_SD_WRITE_SIZE 8192
+#define SD_USE_SDIO 1
+#define PLATFORM_HAS_PARITY_CHECK 1
+
+#ifndef PLATFORM_VDD_WARNING_LIMIT_mV
+#define PLATFORM_VDD_WARNING_LIMIT_mV 2800
+#endif

+ 2 - 0
lib/ZuluSCSI_platform_RP2MCU/ZuluSCSI_platform_network.cpp

@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #ifdef ZULUSCSI_NETWORK
+#include <Arduino.h>
 #include "ZuluSCSI_platform_network.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
@@ -24,6 +25,7 @@ extern "C" {
 
 #include <cyw43.h>
 #include <pico/cyw43_arch.h>
+#include <pico/unique_id.h>
 
 #ifndef CYW43_IOCTL_GET_RSSI
 #define CYW43_IOCTL_GET_RSSI (0xfe)

+ 123 - 0
lib/ZuluSCSI_platform_RP2MCU/custom_timings.cpp

@@ -0,0 +1,123 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+
+#include "custom_timings.h"
+#include <SdFat.h>
+#include <minIni.h>
+#include <ZuluSCSI_log.h>
+#include <ZuluSCSI_platform.h>
+extern SdFs SD;
+
+extern "C"
+{
+    #include <timings.h>
+}
+
+bool CustomTimings::use_custom_timings()
+{
+    return SD.exists(CUSTOM_TIMINGS_FILE) && !ini_getbool("settings", "disable", 0, CUSTOM_TIMINGS_FILE);
+}
+
+bool CustomTimings::set_timings_from_file()
+{
+    const char settings_section[] = "settings";
+    const char pll_section[] = "pll";
+    const char scsi_section[] = "scsi";
+    const char scsi_20_section[] = "scsi_20";
+    const char scsi_10_section[] = "scsi_10";
+    const char scsi_5_section[] = "scsi_5";
+    const char sdio_section[] = "sdio";
+
+
+    zuluscsi_timings_t custom_timings;
+
+
+    // pll
+    int32_t vco = ini_getl(pll_section, "vco_freq_hz", g_zuluscsi_timings->pll.vco_freq, CUSTOM_TIMINGS_FILE);
+    int32_t post_div1 = ini_getl(pll_section, "pd1", g_zuluscsi_timings->pll.post_div1, CUSTOM_TIMINGS_FILE);
+    int32_t post_div2 = ini_getl(pll_section, "pd2", g_zuluscsi_timings->pll.post_div2, CUSTOM_TIMINGS_FILE);
+
+    if (vco > 0 && post_div1 > 0 && post_div2 > 0)
+    {
+        if (vco / post_div1 / post_div2 > 250000000)
+        {
+            logmsg("Reclocking over 250MHz with the PLL settings is not allowed using ", CUSTOM_TIMINGS_FILE);
+            return false;
+        }
+    }
+    else
+    {
+        logmsg("Reclocking failed because 0 or negative PLL settings values");
+        return false;
+    }
+
+    g_zuluscsi_timings->pll.vco_freq = vco;
+    g_zuluscsi_timings->pll.post_div1 = post_div1;
+    g_zuluscsi_timings->pll.post_div2 = post_div2;
+    g_zuluscsi_timings->pll.refdiv =  ini_getl(pll_section, "refdiv", g_zuluscsi_timings->pll.refdiv, CUSTOM_TIMINGS_FILE);
+
+    char speed_grade_str[10];
+    ini_gets(settings_section, "extends_speed_grade", "Default", speed_grade_str, sizeof(speed_grade_str), CUSTOM_TIMINGS_FILE);
+    zuluscsi_speed_grade_t speed_grade =  platform_string_to_speed_grade(speed_grade_str, sizeof(speed_grade_str));
+    set_timings(speed_grade);
+
+    int32_t number_setting = ini_getl(settings_section, "boot_with_sync_value", 0, CUSTOM_TIMINGS_FILE);
+
+    if (number_setting > 0)
+    {
+        g_force_sync = number_setting;
+        number_setting = ini_getl(settings_section, "boot_with_offset_value", 15, CUSTOM_TIMINGS_FILE);
+        g_force_offset = number_setting > 15 ? 15 : number_setting;
+        logmsg("Forcing sync of ", (int) g_force_sync, " and offset of ", (int) g_force_offset);
+    }
+    g_zuluscsi_timings->clk_hz = ini_getl(settings_section, "clk_hz", g_zuluscsi_timings->clk_hz, CUSTOM_TIMINGS_FILE);
+
+
+    // scsi
+    g_zuluscsi_timings->scsi.clk_period_ps = ini_getl(scsi_section, "clk_period_ps", g_zuluscsi_timings->scsi.clk_period_ps, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi.req_delay = ini_getl(scsi_section, "req_delay_cc", g_zuluscsi_timings->scsi.req_delay, CUSTOM_TIMINGS_FILE);
+
+    // scsi 20
+    g_zuluscsi_timings->scsi_20.delay0 = ini_getl(scsi_20_section, "delay0_cc", g_zuluscsi_timings->scsi_20.delay0, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_20.delay1 = ini_getl(scsi_20_section, "delay1_cc", g_zuluscsi_timings->scsi_20.delay1, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_20.total_delay_adjust = ini_getl(scsi_20_section, "total_delay_adjust_cc", g_zuluscsi_timings->scsi_20.total_delay_adjust, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_20.max_sync = ini_getl(scsi_20_section, "max_sync", g_zuluscsi_timings->scsi_20.max_sync, CUSTOM_TIMINGS_FILE);
+
+    // scsi 10
+    g_zuluscsi_timings->scsi_10.delay0 = ini_getl(scsi_10_section, "delay0_cc", g_zuluscsi_timings->scsi_10.delay0, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_10.delay1 = ini_getl(scsi_10_section, "delay1_cc", g_zuluscsi_timings->scsi_10.delay1, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_10.total_delay_adjust = ini_getl(scsi_10_section, "total_delay_adjust_cc", g_zuluscsi_timings->scsi_10.total_delay_adjust, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_10.max_sync = ini_getl(scsi_10_section, "max_sync", g_zuluscsi_timings->scsi_10.max_sync, CUSTOM_TIMINGS_FILE);
+
+    // scsi 5
+    g_zuluscsi_timings->scsi_5.delay0 = ini_getl(scsi_5_section, "delay0_cc", g_zuluscsi_timings->scsi_5.delay0, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_5.delay1 = ini_getl(scsi_5_section, "delay1_cc", g_zuluscsi_timings->scsi_5.delay1, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_5.total_delay_adjust = ini_getl(scsi_5_section, "total_delay_adjust_cc", g_zuluscsi_timings->scsi_5.total_delay_adjust, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->scsi_5.max_sync = ini_getl(scsi_5_section, "max_sync", g_zuluscsi_timings->scsi_5.max_sync, CUSTOM_TIMINGS_FILE);
+
+    // sdio
+    g_zuluscsi_timings->sdio.clk_div_pio = ini_getl(sdio_section, "clk_div_pio", g_zuluscsi_timings->sdio.clk_div_pio, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->sdio.clk_div_1mhz = ini_getl(sdio_section, "clk_div_1mhz", g_zuluscsi_timings->sdio.clk_div_1mhz, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->sdio.delay0 = ini_getl(sdio_section, "delay0", g_zuluscsi_timings->sdio.delay0, CUSTOM_TIMINGS_FILE);
+    g_zuluscsi_timings->sdio.delay1 = ini_getl(sdio_section, "delay1", g_zuluscsi_timings->sdio.delay1, CUSTOM_TIMINGS_FILE);
+
+    return true;
+}

+ 35 - 0
lib/ZuluSCSI_platform_RP2MCU/custom_timings.h

@@ -0,0 +1,35 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#pragma once
+
+#define CUSTOM_TIMINGS_FILE "zuluscsi_timings.ini"
+
+extern "C"
+{
+    #include "timings_RP2MCU.h"
+}
+
+class CustomTimings
+{
+    public:
+        bool use_custom_timings();
+        bool set_timings_from_file();
+};

+ 33 - 0
lib/ZuluSCSI_platform_RP2MCU/scsi2sd_timings.c

@@ -0,0 +1,33 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#include "timings.h"
+#include "ZuluSCSI_platform.h"
+#if defined(ZULUSCSI_MCU_RP23XX)
+uint8_t g_max_sync_20_period = 18;
+uint8_t g_max_sync_10_period = 25;
+uint8_t g_max_sync_5_period  = 50; 
+#elif defined(ZULUSCSI_MCU_RP20XX)
+uint8_t g_max_sync_20_period = 25;
+uint8_t g_max_sync_10_period = 25;
+uint8_t g_max_sync_5_period  = 50; 
+#endif
+uint8_t g_force_sync = 0;
+uint8_t g_force_offset = 15;

+ 6 - 9
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host.cpp

@@ -31,15 +31,7 @@
 #include <hardware/sync.h>
 
 #ifdef PLATFORM_HAS_INITIATOR_MODE
-# ifdef ZULUSCSI_PICO_2
-#  include "scsi_accel_host_Pico_2.pio.h"
-# elif defined(ZULUSCSI_PICO)
-#  include "scsi_accel_host_Pico.pio.h"
-# elif defined(ZULUSCSI_RP2350A)
-#  include "scsi_accel_host_RP2350A.pio.h"
-# else
-#  include "scsi_accel_host_RP2040.pio.h"
-# endif
+# include "scsi_accel_host_RP2MCU.pio.h"
 
 #define SCSI_PIO pio0
 #define SCSI_SM 0
@@ -167,6 +159,11 @@ void scsi_accel_host_init()
 
     // Asynchronous / synchronous SCSI read
     g_scsi_host.pio_offset_async_read = pio_add_program(SCSI_PIO, &scsi_host_async_read_program);
+    //    wait 0 gpio REQ             side 1  ; Wait for REQ low
+    uint16_t instr = pio_encode_wait_gpio(false, SCSI_IN_REQ) | pio_encode_sideset(1, 1);
+    SCSI_PIO->instr_mem[g_scsi_host.pio_offset_async_read + 2] = instr;
+    instr =   pio_encode_wait_gpio(true, SCSI_IN_REQ) | pio_encode_sideset(1, 0);
+    SCSI_PIO->instr_mem[g_scsi_host.pio_offset_async_read + 5] = instr;
     g_scsi_host.pio_cfg_async_read = scsi_host_async_read_program_get_default_config(g_scsi_host.pio_offset_async_read);
     sm_config_set_in_pins(&g_scsi_host.pio_cfg_async_read, SCSI_IO_DB0);
     sm_config_set_sideset_pins(&g_scsi_host.pio_cfg_async_read, SCSI_OUT_ACK);

+ 0 - 46
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico.pio

@@ -1,46 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI initiator / host function
-; Run "pioasm scsi_accel_host.pio scsi_accel_host.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is ACK pin
-
-.define REQ 17
-.define ACK 26
-
-; Read from SCSI bus using asynchronous handshake.
-; Data is returned as 16-bit words that contain the 8 data bits + 1 parity bit.
-; Number of bytes to receive minus 1 should be written to TX fifo.
-; Number of bytes to receive must be divisible by 2.
-.program scsi_host_async_read
-    .side_set 1
-
-    pull block                  side 1  ; Get number of bytes to receive
-    mov x, osr                  side 1  ; Store to counter X
-
-start:
-    wait 0 gpio REQ             side 1  ; Wait for REQ low
-    in pins, 9                  side 0  ; Assert ACK, read GPIO
-    in null, 7                  side 0  ; Padding bits
-    wait 1 gpio REQ             side 0  ; Wait for REQ high
-    jmp x-- start               side 1  ; Deassert ACK, decrement byte count and jump to start

+ 0 - 43
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico.pio.h

@@ -1,43 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// -------------------- //
-// scsi_host_async_read //
-// -------------------- //
-
-#define scsi_host_async_read_wrap_target 0
-#define scsi_host_async_read_wrap 6
-
-static const uint16_t scsi_host_async_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0xb027, //  1: mov    x, osr          side 1     
-    0x3011, //  2: wait   0 gpio, 17      side 1     
-    0x4009, //  3: in     pins, 9         side 0     
-    0x4067, //  4: in     null, 7         side 0     
-    0x2091, //  5: wait   1 gpio, 17      side 0     
-    0x1042, //  6: jmp    x--, 2          side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_host_async_read_program = {
-    .instructions = scsi_host_async_read_program_instructions,
-    .length = 7,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_host_async_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_host_async_read_wrap_target, offset + scsi_host_async_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif

+ 0 - 46
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico_2.pio

@@ -1,46 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI initiator / host function
-; Run "pioasm scsi_accel_host.pio scsi_accel_host.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is ACK pin
-
-.define REQ 17
-.define ACK 26
-
-; Read from SCSI bus using asynchronous handshake.
-; Data is returned as 16-bit words that contain the 8 data bits + 1 parity bit.
-; Number of bytes to receive minus 1 should be written to TX fifo.
-; Number of bytes to receive must be divisible by 2.
-.program scsi_host_async_read
-    .side_set 1
-
-    pull block                  side 1  ; Get number of bytes to receive
-    mov x, osr                  side 1  ; Store to counter X
-
-start:
-    wait 0 gpio REQ             side 1  ; Wait for REQ low
-    in pins, 9                  side 0  ; Assert ACK, read GPIO
-    in null, 7                  side 0  ; Padding bits
-    wait 1 gpio REQ             side 0  ; Wait for REQ high
-    jmp x-- start               side 1  ; Deassert ACK, decrement byte count and jump to start

+ 0 - 43
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_Pico_2.pio.h

@@ -1,43 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// -------------------- //
-// scsi_host_async_read //
-// -------------------- //
-
-#define scsi_host_async_read_wrap_target 0
-#define scsi_host_async_read_wrap 6
-
-static const uint16_t scsi_host_async_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0xb027, //  1: mov    x, osr          side 1     
-    0x3011, //  2: wait   0 gpio, 17      side 1     
-    0x4009, //  3: in     pins, 9         side 0     
-    0x4067, //  4: in     null, 7         side 0     
-    0x2091, //  5: wait   1 gpio, 17      side 0     
-    0x1042, //  6: jmp    x--, 2          side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_host_async_read_program = {
-    .instructions = scsi_host_async_read_program_instructions,
-    .length = 7,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_host_async_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_host_async_read_wrap_target, offset + scsi_host_async_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif

+ 0 - 46
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2350A.pio

@@ -1,46 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI initiator / host function
-; Run "pioasm scsi_accel_host.pio scsi_accel_host.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is ACK pin
-
-.define REQ 9
-.define ACK 10
-
-; Read from SCSI bus using asynchronous handshake.
-; Data is returned as 16-bit words that contain the 8 data bits + 1 parity bit.
-; Number of bytes to receive minus 1 should be written to TX fifo.
-; Number of bytes to receive must be divisible by 2.
-.program scsi_host_async_read
-    .side_set 1
-
-    pull block                  side 1  ; Get number of bytes to receive
-    mov x, osr                  side 1  ; Store to counter X
-
-start:
-    wait 0 gpio REQ             side 1  ; Wait for REQ low
-    in pins, 9                  side 0  ; Assert ACK, read GPIO
-    in null, 7                  side 0  ; Padding bits
-    wait 1 gpio REQ             side 0  ; Wait for REQ high
-    jmp x-- start               side 1  ; Deassert ACK, decrement byte count and jump to start

+ 0 - 44
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2350A.pio.h

@@ -1,44 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// -------------------- //
-// scsi_host_async_read //
-// -------------------- //
-
-#define scsi_host_async_read_wrap_target 0
-#define scsi_host_async_read_wrap 6
-
-static const uint16_t scsi_host_async_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0xb027, //  1: mov    x, osr          side 1     
-    0x3009, //  2: wait   0 gpio, 9       side 1     
-    0x4009, //  3: in     pins, 9         side 0     
-    0x4067, //  4: in     null, 7         side 0     
-    0x2089, //  5: wait   1 gpio, 9       side 0     
-    0x1042, //  6: jmp    x--, 2          side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_host_async_read_program = {
-    .instructions = scsi_host_async_read_program_instructions,
-    .length = 7,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_host_async_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_host_async_read_wrap_target, offset + scsi_host_async_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-

+ 1 - 1
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2040.pio → lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2MCU.pio

@@ -24,7 +24,7 @@
 ; - 0-7: DB0-DB7
 ; -   8: DBP
 ; Side set is ACK pin
-
+; REQ is a dummy value, set by via pico-sdk encode functions
 .define REQ 9
 .define ACK 10
 

+ 0 - 0
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2040.pio.h → lib/ZuluSCSI_platform_RP2MCU/scsi_accel_host_RP2MCU.pio.h


+ 222 - 100
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target.cpp

@@ -1,38 +1,39 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
- * 
+ *
  * This work incorporates work from the following
  *  Copyright (c) 2023 joshua stein <jcs@jcs.org>
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * https://www.gnu.org/licenses/gpl-3.0.html
  * ----
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version. 
- * 
+ * (at your option) any later version.
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details. 
- * 
+ * GNU General Public License for more details.
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 **/
 
 /* Data flow in SCSI acceleration:
- *
- * 1. Application provides a buffer of bytes to send.
- * 2. Code in this module adds parity bit to the bytes and packs two bytes into 32 bit words.
- * 3. DMA controller copies the words to PIO peripheral FIFO.
- * 4. PIO peripheral handles low-level SCSI handshake and writes bytes and parity to GPIO.
- */
+*
+* 1. Application provides a buffer of bytes to send.
+* 2. Code in this module adds parity bit to the bytes and packs two bytes into 32 bit words.
+* 3. DMA controller copies the words to PIO peripheral FIFO.
+* 4. PIO peripheral handles low-level SCSI handshake and writes bytes and parity to GPIO.
+*/
 
 #include "ZuluSCSI_platform.h"
 #include "ZuluSCSI_log.h"
 #include "scsi_accel_target.h"
+#include "timings_RP2MCU.h"
 #include <hardware/pio.h>
 #include <hardware/dma.h>
 #include <hardware/irq.h>
@@ -44,15 +45,7 @@
 #include <audio.h>
 #endif // ENABLE_AUDIO_OUTPUT
 
-#if defined(ZULUSCSI_PICO) || defined(ZULUSCSI_BS2)
-# include "scsi_accel_target_Pico.pio.h"
-#elif defined(ZULUSCSI_PICO_2)
-# include "scsi_accel_target_Pico_2.pio.h"
-#elif defined(ZULUSCSI_RP2350A)
-# include "scsi_accel_target_RP2350A.pio.h"
-#else
-# include "scsi_accel_target_RP2040.pio.h"
-#endif
+#include "scsi_accel_target_RP2MCU.pio.h"
 
 // SCSI bus write acceleration uses up to 3 PIO state machines:
 // SM0: Convert data bytes to lookup addresses to add parity
@@ -98,7 +91,7 @@ static struct {
     uint8_t *app_buf; // Buffer provided by application
     uint32_t app_bytes; // Bytes available in application buffer
     uint32_t dma_bytes; // Bytes that have been scheduled for DMA so far
-    
+
     uint8_t *next_app_buf; // Next buffer from application after current one finishes
     uint32_t next_app_bytes; // Bytes in next buffer
 
@@ -123,7 +116,14 @@ static struct {
     pio_sm_config pio_cfg_read;
     pio_sm_config pio_cfg_read_parity;
     pio_sm_config pio_cfg_sync_read_pacer;
-    
+    bool pio_removed_parity;
+    bool pio_removed_async_write;
+    bool pio_removed_sync_write_pacer;
+    bool pio_removed_sync_write;
+    bool pio_removed_read;
+    bool pio_removed_read_parity;
+    bool pio_removed_sync_read_pacer;
+
     // DMA configurations for write
     dma_channel_config dmacfg_write_chA; // Data from RAM to scsi_parity PIO
     dma_channel_config dmacfg_write_chB; // Addresses from scsi_parity PIO to lookup DMA
@@ -138,8 +138,8 @@ static struct {
 } g_scsi_dma;
 
 enum scsidma_state_t { SCSIDMA_IDLE = 0,
-                       SCSIDMA_WRITE, SCSIDMA_WRITE_DONE,
-                       SCSIDMA_READ, SCSIDMA_READ_DONE };
+                    SCSIDMA_WRITE, SCSIDMA_WRITE_DONE,
+                    SCSIDMA_READ, SCSIDMA_READ_DONE };
 static const char* scsidma_states[5] = {"IDLE", "WRITE", "WRITE_DONE", "READ", "READ_DONE"};
 static volatile scsidma_state_t g_scsi_dma_state;
 static bool g_channels_claimed = false;
@@ -195,7 +195,7 @@ static void config_parity_sm_for_write()
     pio_sm_put(SCSI_DMA_PIO, SCSI_PARITY_SM, addrbase >> 9);
     pio_sm_exec(SCSI_DMA_PIO, SCSI_PARITY_SM, pio_encode_pull(false, false));
     pio_sm_exec(SCSI_DMA_PIO, SCSI_PARITY_SM, pio_encode_mov(pio_x, pio_osr));
-    
+
     // DMA channel B will copy addresses from parity PIO to DMA channel C read address register.
     // It is triggered by the parity SM RX FIFO request
     dma_channel_configure(SCSI_DMA_CH_B,
@@ -203,7 +203,7 @@ static void config_parity_sm_for_write()
         &dma_hw->ch[SCSI_DMA_CH_C].al3_read_addr_trig,
         &SCSI_DMA_PIO->rxf[SCSI_PARITY_SM],
         1, true);
-    
+
     // DMA channel C will read g_scsi_parity_lookup to copy data + parity to SCSI write state machine.
     // It is triggered by SCSI write machine TX FIFO request and chains to re-enable channel B.
     dma_channel_configure(SCSI_DMA_CH_C,
@@ -237,7 +237,7 @@ static void start_dma_write()
 
     uint8_t *src_buf = &g_scsi_dma.app_buf[g_scsi_dma.dma_bytes];
     g_scsi_dma.dma_bytes += bytes_to_send;
-    
+
     // Start DMA from current buffer to parity generator
     dma_channel_configure(SCSI_DMA_CH_A,
         &g_scsi_dma.dmacfg_write_chA,
@@ -298,7 +298,7 @@ void scsi_accel_rp2040_startWrite(const uint8_t* data, uint32_t count, volatile
     g_scsi_dma.dma_bytes = 0;
     g_scsi_dma.next_app_buf = 0;
     g_scsi_dma.next_app_bytes = 0;
-    
+
     if (must_reconfig_gpio)
     {
         SCSI_ENABLE_DATA_OUT();
@@ -355,7 +355,7 @@ void scsi_accel_rp2040_startWrite(const uint8_t* data, uint32_t count, volatile
             pio_sm_set_enabled(SCSI_DMA_PIO, SCSI_DATA_SM, true);
             pio_sm_set_enabled(SCSI_DMA_PIO, SCSI_PARITY_SM, true);
         }
-        
+
         dma_channel_set_irq0_enabled(SCSI_DMA_CH_A, true);
     }
 
@@ -372,7 +372,7 @@ bool scsi_accel_rp2040_isWriteFinished(const uint8_t* data)
 
     if (!data)
         return false;
-    
+
     // Check if this data item is still in queue.
     bool finished = true;
     uint32_t saved_irq = save_and_disable_interrupts();
@@ -383,7 +383,7 @@ bool scsi_accel_rp2040_isWriteFinished(const uint8_t* data)
         finished = false; // In current transfer
     }
     else if (data >= g_scsi_dma.next_app_buf &&
-             data < g_scsi_dma.next_app_buf + g_scsi_dma.next_app_bytes)
+            data < g_scsi_dma.next_app_buf + g_scsi_dma.next_app_bytes)
     {
         finished = false; // In queued transfer
     }
@@ -491,7 +491,7 @@ static void config_parity_sm_for_read()
     pio_sm_put(SCSI_DMA_PIO, SCSI_DATA_SM, addrbase >> 10);
     pio_sm_exec(SCSI_DMA_PIO, SCSI_DATA_SM, pio_encode_pull(false, false) | pio_encode_sideset(1, 1));
     pio_sm_exec(SCSI_DMA_PIO, SCSI_DATA_SM, pio_encode_mov(pio_y, pio_osr) | pio_encode_sideset(1, 1));
-    
+
     // For synchronous mode, the REQ pin is driven by SCSI_SYNC_SM, so disable it in SCSI_DATA_SM
     if (g_scsi_dma.syncOffset > 0)
     {
@@ -504,7 +504,7 @@ static void config_parity_sm_for_read()
         &SCSI_DMA_PIO->txf[SCSI_PARITY_SM],
         NULL,
         1, false);
-    
+
     // DMA channel C will copy addresses from data PIO to DMA channel B read address register.
     // It is triggered by the data SM RX FIFO request.
     // This triggers channel B by writing to READ_ADDR_TRIG
@@ -549,7 +549,7 @@ static void start_dma_read()
     pio_sm_set_enabled(SCSI_DMA_PIO, SCSI_DATA_SM, false);
     pio_sm_clear_fifos(SCSI_DMA_PIO, SCSI_PARITY_SM);
     pio_sm_clear_fifos(SCSI_DMA_PIO, SCSI_DATA_SM);
-    
+
     if (g_scsi_dma.app_bytes <= g_scsi_dma.dma_bytes)
     {
         // Buffer has been fully processed, swap it
@@ -559,7 +559,7 @@ static void start_dma_read()
         g_scsi_dma.next_app_buf = 0;
         g_scsi_dma.next_app_bytes = 0;
     }
-    
+
     // Check if we are all done.
     // From SCSIDMA_READ_DONE state we can either go to IDLE in stopRead()
     // or back to READ in startWrite().
@@ -584,10 +584,10 @@ static void start_dma_read()
         pio_sm_exec(SCSI_DMA_PIO, SCSI_SYNC_SM, pio_encode_pull(false, false) | pio_encode_sideset(1, 1));
         pio_sm_exec(SCSI_DMA_PIO, SCSI_SYNC_SM, pio_encode_mov(pio_x, pio_osr) | pio_encode_sideset(1, 1));
         hw_set_bits(&SCSI_DMA_PIO->sm[SCSI_SYNC_SM].shiftctrl, PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS);
-        
+
         // Prefill FIFOs to get correct syncOffset
         int prefill = 12 - g_scsi_dma.syncOffset;
-        
+
         // Always at least 1 word to avoid race condition between REQ and ACK pulses
         if (prefill < 1) prefill = 1;
 
@@ -604,7 +604,7 @@ static void start_dma_read()
             pio_sm_exec(SCSI_DMA_PIO, SCSI_SYNC_SM, pio_encode_push(false, false) | pio_encode_sideset(1, 1));
             prefill--;
         }
-        
+
         pio_sm_exec(SCSI_DMA_PIO, SCSI_SYNC_SM, pio_encode_jmp(g_scsi_dma.pio_offset_sync_read_pacer) | pio_encode_sideset(1, 1));
 
         // Start transfers
@@ -715,7 +715,7 @@ bool scsi_accel_rp2040_isReadFinished(const uint8_t* data)
         finished = false; // In current transfer
     }
     else if (data >= g_scsi_dma.next_app_buf &&
-             data < g_scsi_dma.next_app_buf + g_scsi_dma.next_app_bytes)
+            data < g_scsi_dma.next_app_buf + g_scsi_dma.next_app_bytes)
     {
         finished = false; // In queued transfer
     }
@@ -753,13 +753,13 @@ void scsi_accel_rp2040_finishRead(const uint8_t *data, uint32_t count, int *pari
             break;
         }
     }
-    
+
     if (g_scsi_dma_state == SCSIDMA_READ_DONE || *resetFlag)
     {
         // This was last buffer, release bus
         scsi_accel_rp2040_stopRead();
     }
-    
+
     // Check if any parity errors have been detected during the transfer so far
     if (parityError != NULL && (SCSI_DMA_PIO->irq & 1))
     {
@@ -768,6 +768,125 @@ void scsi_accel_rp2040_finishRead(const uint8_t *data, uint32_t count, int *pari
     }
 }
 
+/*******************************************************/
+/* Write SCSI PIO program timings and ACK pin          */
+/*******************************************************/
+static void zulu_pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset, bool &removed)
+{
+    if (!removed)
+    {
+        pio_remove_program(pio, program, loaded_offset);
+        removed = true;
+    }
+}
+
+static int pio_add_scsi_accel_async_write_program()
+{
+    zulu_pio_remove_program(SCSI_DMA_PIO,
+        &scsi_accel_async_write_program,
+        g_scsi_dma.pio_offset_async_write,
+        g_scsi_dma.pio_removed_async_write);
+
+    uint16_t rewrote_instructions[sizeof(scsi_accel_async_write_program_instructions)/sizeof(scsi_accel_async_write_program_instructions[0])];
+    pio_program rewrote_program = {rewrote_instructions,
+        scsi_accel_async_write_program.length,
+        scsi_accel_async_write_program.origin,
+        scsi_accel_async_write_program.pio_version};
+
+    memcpy(rewrote_instructions,
+        scsi_accel_async_write_program_instructions,
+        sizeof(scsi_accel_async_write_program_instructions));
+
+    // out null, 23         side 1  [0] ;[REQ_DLY-2]      ; Discard unused bits, wait for data preset time
+    uint8_t delay = g_zuluscsi_timings->scsi.req_delay - 2;
+    assert( delay <= 0xF);
+    rewrote_instructions[2] |= pio_encode_delay(delay);
+    // wait 1 gpio ACK      side 1      ; Wait for ACK to be inactive
+    rewrote_instructions[3] = pio_encode_wait_gpio(true, SCSI_IN_ACK) | pio_encode_sideset(1, 1);
+    // wait 0 gpio ACK      side 0      ; Assert REQ, wait for ACK low
+    rewrote_instructions[4] = pio_encode_wait_gpio(false, SCSI_IN_ACK) | pio_encode_sideset(1, 0);
+
+    g_scsi_dma.pio_removed_async_write = false;
+    return pio_add_program(SCSI_DMA_PIO, &rewrote_program);
+}
+
+static int pio_add_scsi_accel_read_program()
+{
+    zulu_pio_remove_program(SCSI_DMA_PIO,
+        &scsi_accel_read_program,
+        g_scsi_dma.pio_offset_read,
+        g_scsi_dma.pio_removed_read);
+
+    uint16_t rewrote_instructions[sizeof(scsi_accel_read_program_instructions)/sizeof(scsi_accel_read_program_instructions[0])];
+
+    pio_program rewrote_program = {
+        rewrote_instructions,
+        scsi_accel_read_program.length,
+        scsi_accel_read_program.origin,
+        scsi_accel_read_program.pio_version};
+
+    memcpy(rewrote_instructions,
+        scsi_accel_read_program_instructions,
+        sizeof(scsi_accel_read_program_instructions));
+
+    // wait 1 gpio ACK             side 1  ; Wait for ACK high
+    rewrote_instructions[1] = pio_encode_wait_gpio(true, SCSI_IN_ACK) | pio_encode_sideset(1, 1);
+    // wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
+    rewrote_instructions[3] = pio_encode_wait_gpio(false, SCSI_IN_ACK) | pio_encode_sideset(1, 0);
+    g_scsi_dma.pio_removed_read = false;
+    return pio_add_program(SCSI_DMA_PIO, &rewrote_program);
+}
+
+static int pio_add_scsi_sync_write_pacer_program()
+{
+    zulu_pio_remove_program(SCSI_DMA_PIO,
+        &scsi_sync_write_pacer_program,
+        g_scsi_dma.pio_offset_sync_write_pacer,
+        g_scsi_dma.pio_removed_sync_write_pacer);
+
+    uint16_t rewrote_instructions[sizeof(scsi_sync_write_pacer_program_instructions)/sizeof(scsi_sync_write_pacer_program_instructions[0])];
+
+    pio_program rewrote_program = {
+        rewrote_instructions,
+        scsi_sync_write_pacer_program.length,
+        scsi_sync_write_pacer_program.origin,
+        scsi_sync_write_pacer_program.pio_version};
+
+    memcpy(rewrote_instructions,
+        scsi_sync_write_pacer_program_instructions,
+        sizeof(scsi_sync_write_pacer_program_instructions));
+
+    // wait 1 gpio ACK
+    rewrote_instructions[0] = pio_encode_wait_gpio(true, SCSI_IN_ACK);
+    // wait 0 gpio ACK   ; Wait for falling edge on ACK
+    rewrote_instructions[1] = pio_encode_wait_gpio(false, SCSI_IN_ACK);
+    g_scsi_dma.pio_removed_sync_write_pacer = false;
+    return pio_add_program(SCSI_DMA_PIO, &rewrote_program);
+}
+
+static int pio_add_scsi_parity_program()
+{
+    g_scsi_dma.pio_removed_parity = false;
+    return pio_add_program(SCSI_DMA_PIO, &scsi_parity_program);
+}
+
+static int pio_add_scsi_sync_read_pacer_program()
+{
+    g_scsi_dma.pio_removed_sync_read_pacer = false;
+    return pio_add_program(SCSI_DMA_PIO, &scsi_sync_read_pacer_program);
+}
+
+static int pio_add_scsi_read_parity_program()
+{
+    g_scsi_dma.pio_removed_read_parity = false;
+    return pio_add_program(SCSI_DMA_PIO, &scsi_read_parity_program);
+}
+
+static int pio_add_scsi_sync_write_program()
+{
+    g_scsi_dma.pio_removed_sync_write = false;
+    return pio_add_program(SCSI_DMA_PIO, &scsi_sync_write_program);
+}
 /*******************************************************/
 /* Initialization functions common to read/write       */
 /*******************************************************/
@@ -868,7 +987,20 @@ void scsi_accel_rp2040_init()
 {
     g_scsi_dma_state = SCSIDMA_IDLE;
     scsidma_config_gpio();
-    
+
+    static bool first_init = true;
+    if (first_init)
+    {
+        g_scsi_dma.pio_removed_parity = true;
+        g_scsi_dma.pio_removed_async_write = true;
+        g_scsi_dma.pio_removed_sync_write_pacer = true;
+        g_scsi_dma.pio_removed_sync_write = true;
+        g_scsi_dma.pio_removed_read = true;
+        g_scsi_dma.pio_removed_read_parity = true;
+        g_scsi_dma.pio_removed_sync_read_pacer = true;
+        first_init = false;
+    }
+
     if (g_channels_claimed) {
         // Un-claim all SCSI state machines
         pio_sm_unclaim(SCSI_DMA_PIO, SCSI_PARITY_SM);
@@ -876,13 +1008,13 @@ void scsi_accel_rp2040_init()
         pio_sm_unclaim(SCSI_DMA_PIO, SCSI_SYNC_SM);
 
         // Remove all SCSI programs
-        pio_remove_program(SCSI_DMA_PIO, &scsi_parity_program, g_scsi_dma.pio_offset_parity);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_accel_async_write_program, g_scsi_dma.pio_offset_async_write);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_sync_write_pacer_program, g_scsi_dma.pio_offset_sync_write_pacer);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_sync_write_program, g_scsi_dma.pio_offset_sync_write);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_accel_read_program, g_scsi_dma.pio_offset_read);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_sync_read_pacer_program, g_scsi_dma.pio_offset_sync_read_pacer);
-        pio_remove_program(SCSI_DMA_PIO, &scsi_read_parity_program, g_scsi_dma.pio_offset_read_parity);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_parity_program, g_scsi_dma.pio_offset_parity, g_scsi_dma.pio_removed_parity);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_accel_async_write_program, g_scsi_dma.pio_offset_async_write, g_scsi_dma.pio_removed_async_write);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_sync_write_pacer_program, g_scsi_dma.pio_offset_sync_write_pacer, g_scsi_dma.pio_removed_sync_write_pacer);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_accel_read_program, g_scsi_dma.pio_offset_read, g_scsi_dma.pio_removed_read);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_sync_read_pacer_program, g_scsi_dma.pio_offset_sync_read_pacer, g_scsi_dma.pio_removed_sync_read_pacer);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_read_parity_program, g_scsi_dma.pio_offset_read_parity, g_scsi_dma.pio_removed_read_parity);
+        zulu_pio_remove_program(SCSI_DMA_PIO, &scsi_sync_write_program, g_scsi_dma.pio_offset_sync_write, g_scsi_dma.pio_removed_sync_write);
 
         // Un-claim all SCSI DMA channels
         dma_channel_unclaim(SCSI_DMA_CH_A);
@@ -893,7 +1025,7 @@ void scsi_accel_rp2040_init()
         // Set flag to re-initialize SCSI PIO system
         g_channels_claimed = false;
     }
-    
+
     if (!g_channels_claimed)
     {
         // Mark channels as being in use, unless it has been done already
@@ -906,15 +1038,15 @@ void scsi_accel_rp2040_init()
         dma_channel_claim(SCSI_DMA_CH_D);
         g_channels_claimed = true;
     }
-    
+
     // Parity lookup generator
-    g_scsi_dma.pio_offset_parity = pio_add_program(SCSI_DMA_PIO, &scsi_parity_program);
+    g_scsi_dma.pio_offset_parity = pio_add_scsi_parity_program();
     g_scsi_dma.pio_cfg_parity = scsi_parity_program_get_default_config(g_scsi_dma.pio_offset_parity);
     sm_config_set_out_shift(&g_scsi_dma.pio_cfg_parity, true, false, 32);
     sm_config_set_in_shift(&g_scsi_dma.pio_cfg_parity, true, true, 32);
 
     // Asynchronous SCSI write
-    g_scsi_dma.pio_offset_async_write = pio_add_program(SCSI_DMA_PIO, &scsi_accel_async_write_program);
+    g_scsi_dma.pio_offset_async_write = pio_add_scsi_accel_async_write_program();
     g_scsi_dma.pio_cfg_async_write = scsi_accel_async_write_program_get_default_config(g_scsi_dma.pio_offset_async_write);
     sm_config_set_out_pins(&g_scsi_dma.pio_cfg_async_write, SCSI_IO_DB0, 9);
     sm_config_set_sideset_pins(&g_scsi_dma.pio_cfg_async_write, SCSI_OUT_REQ);
@@ -922,20 +1054,12 @@ void scsi_accel_rp2040_init()
     sm_config_set_out_shift(&g_scsi_dma.pio_cfg_async_write, true, false, 32);
 
     // Synchronous SCSI write pacer / ACK handler
-    g_scsi_dma.pio_offset_sync_write_pacer = pio_add_program(SCSI_DMA_PIO, &scsi_sync_write_pacer_program);
+    g_scsi_dma.pio_offset_sync_write_pacer = pio_add_scsi_sync_write_pacer_program();
     g_scsi_dma.pio_cfg_sync_write_pacer = scsi_sync_write_pacer_program_get_default_config(g_scsi_dma.pio_offset_sync_write_pacer);
     sm_config_set_out_shift(&g_scsi_dma.pio_cfg_sync_write_pacer, true, true, 1);
 
-    // Synchronous SCSI data writer
-    g_scsi_dma.pio_offset_sync_write = pio_add_program(SCSI_DMA_PIO, &scsi_sync_write_program);
-    g_scsi_dma.pio_cfg_sync_write = scsi_sync_write_program_get_default_config(g_scsi_dma.pio_offset_sync_write);
-    sm_config_set_out_pins(&g_scsi_dma.pio_cfg_sync_write, SCSI_IO_DB0, 9);
-    sm_config_set_sideset_pins(&g_scsi_dma.pio_cfg_sync_write, SCSI_OUT_REQ);
-    sm_config_set_out_shift(&g_scsi_dma.pio_cfg_sync_write, true, true, 32);
-    sm_config_set_in_shift(&g_scsi_dma.pio_cfg_sync_write, true, true, 1);
-
     // Asynchronous / synchronous SCSI read
-    g_scsi_dma.pio_offset_read = pio_add_program(SCSI_DMA_PIO, &scsi_accel_read_program);
+    g_scsi_dma.pio_offset_read = pio_add_scsi_accel_read_program();
     g_scsi_dma.pio_cfg_read = scsi_accel_read_program_get_default_config(g_scsi_dma.pio_offset_read);
     sm_config_set_in_pins(&g_scsi_dma.pio_cfg_read, SCSI_IO_DB0);
     sm_config_set_sideset_pins(&g_scsi_dma.pio_cfg_read, SCSI_OUT_REQ);
@@ -943,18 +1067,27 @@ void scsi_accel_rp2040_init()
     sm_config_set_in_shift(&g_scsi_dma.pio_cfg_read, true, true, 32);
 
     // Synchronous SCSI read pacer
-    g_scsi_dma.pio_offset_sync_read_pacer = pio_add_program(SCSI_DMA_PIO, &scsi_sync_read_pacer_program);
+    g_scsi_dma.pio_offset_sync_read_pacer = pio_add_scsi_sync_read_pacer_program();
     g_scsi_dma.pio_cfg_sync_read_pacer = scsi_sync_read_pacer_program_get_default_config(g_scsi_dma.pio_offset_sync_read_pacer);
     sm_config_set_sideset_pins(&g_scsi_dma.pio_cfg_sync_read_pacer, SCSI_OUT_REQ);
 
     // Read parity check
-    g_scsi_dma.pio_offset_read_parity = pio_add_program(SCSI_DMA_PIO, &scsi_read_parity_program);
+    g_scsi_dma.pio_offset_read_parity = pio_add_scsi_read_parity_program();
     g_scsi_dma.pio_cfg_read_parity = scsi_read_parity_program_get_default_config(g_scsi_dma.pio_offset_read_parity);
     sm_config_set_out_shift(&g_scsi_dma.pio_cfg_read_parity, true, true, 32);
     sm_config_set_in_shift(&g_scsi_dma.pio_cfg_read_parity, true, false, 32);
 
+    // Synchronous SCSI data writer
+    g_scsi_dma.pio_offset_sync_write = pio_add_scsi_sync_write_program();
+    g_scsi_dma.pio_cfg_sync_write = scsi_sync_write_program_get_default_config(g_scsi_dma.pio_offset_sync_write);
+    sm_config_set_out_pins(&g_scsi_dma.pio_cfg_sync_write, SCSI_IO_DB0, 9);
+    sm_config_set_sideset_pins(&g_scsi_dma.pio_cfg_sync_write, SCSI_OUT_REQ);
+    sm_config_set_out_shift(&g_scsi_dma.pio_cfg_sync_write, true, true, 32);
+    sm_config_set_in_shift(&g_scsi_dma.pio_cfg_sync_write, true, true, 1);
+
+
     // Create DMA channel configurations so they can be applied quickly later
-    
+
     // For write to SCSI BUS:
     // Channel A: Bytes from RAM to scsi_parity PIO
     dma_channel_config cfg = dma_channel_get_default_config(SCSI_DMA_CH_A);
@@ -1033,7 +1166,7 @@ void scsi_accel_rp2040_init()
     channel_config_set_write_increment(&cfg, false);
     channel_config_set_dreq(&cfg, pio_get_dreq(SCSI_DMA_PIO, SCSI_DATA_SM, true));
     g_scsi_dma.dmacfg_read_chD = cfg;
-    
+
     // Interrupts are used for data buffer swapping
     irq_set_exclusive_handler(DMA_IRQ_0, scsi_dma_irq);
     irq_set_enabled(DMA_IRQ_0, true);
@@ -1094,54 +1227,43 @@ bool scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod)
             // The delays are in clock cycles, each taking 6.66 ns. (@150 MHz)
             // delay0: Delay from data write to REQ assertion (data setup)
             // delay1: Delay from REQ assert to REQ deassert (req pulse width)
-            // delay2: Delay from REQ deassert to data write (data hold)
-            int delay0, delay1, delay2, initialDelay, remainderDelay;
-#ifdef ZULUSCSI_MCU_RP23XX
-            int totalDelay = (syncPeriod * 4 * 100 + 333) / 667 ;    //The +333 is equivalent to rounding to the nearest integer
-#else
-            int totalDelay = syncPeriod * 4 / 8;
-#endif            
+            // delay2: Delay from REQ deassert to data write (negation period)
+            // see timings.c for delay periods in clock cycles
+            int delay0, delay1, delay2;
+            uint32_t up_rounder = g_zuluscsi_timings->scsi.clk_period_ps / 2 + 1;
+            uint32_t delay_in_ps = (syncPeriod * 4) * 1000;
+            // This is the delay in clock cycles rounded up
+            int totalDelay = (delay_in_ps + up_rounder) / g_zuluscsi_timings->scsi.clk_period_ps;
+
             if (syncPeriod < 25)
             {
                 // Fast-20 SCSI timing: 15 ns assertion period
                 // The hardware rise and fall time require some extra delay,
-                // the values below are tuned based on oscilloscope measurements.
                 // These delays are in addition to the 1 cycle that the PIO takes to execute the instruction
-                initialDelay = totalDelay / 3;
-                remainderDelay = totalDelay % 3;    //ReminderDelay will be 0, 1 or 2
-                delay0 = initialDelay - 1; //Data setup time, should be min 11.5ns according to the spec for FAST-20
-                delay2 = initialDelay - 1; //Data hold time, should be min 16.5ns according to the spec for FAST-20
-                delay1 = initialDelay - 1; //pulse width, should be min 15ns according to the spec for FAST-20
-                if (remainderDelay){
-                    delay2++;   //if we have "unassigned" delay time, give it to the one requiring the longest (hold time)
-                    remainderDelay--;
-                }
-                if (remainderDelay){
-                    delay1++;   //if we still have "unassigned" delay time, give it to the one requiring it the next (pulse width)
-                }
+                totalDelay += g_zuluscsi_timings->scsi_20.total_delay_adjust;
+                delay0 = g_zuluscsi_timings->scsi_20.delay0; //Data setup time, should be min 11.5ns according to the spec for FAST-20
+                delay1 = g_zuluscsi_timings->scsi_20.delay1; //pulse width, should be min 15ns according to the spec for FAST-20
+                delay2 = totalDelay - delay0 - delay1 - 3;  //Data hold time, should be min 16.5ns according to the spec for FAST-20
                 if (delay2 < 0) delay2 = 0;
                 if (delay2 > 15) delay2 = 15;
             }
             else if (syncPeriod < 50 )
             {
-                // \TODO set RP23XX timings here
-
                 // Fast-10 SCSI timing: 30 ns assertion period, 25 ns skew delay
                 // The hardware rise and fall time require some extra delay,
-                // the values below are tuned based on oscilloscope measurements.
-                delay0 = 4;
-                delay1 = 6;
+                totalDelay += g_zuluscsi_timings->scsi_10.total_delay_adjust;
+                delay0 = g_zuluscsi_timings->scsi_10.delay0; // 4;
+                delay1 = g_zuluscsi_timings->scsi_10.delay1; // 6;
                 delay2 = totalDelay - delay0 - delay1 - 3;
                 if (delay2 < 0) delay2 = 0;
                 if (delay2 > 15) delay2 = 15;
             }
             else
             {
-                // \TODO set RP23XX timings here
-
                 // Slow SCSI timing: 90 ns assertion period, 55 ns skew delay
-                delay0 = 7;
-                delay1 = 14;
+                totalDelay += g_zuluscsi_timings->scsi_5.total_delay_adjust;
+                delay0 = g_zuluscsi_timings->scsi_5.delay0;
+                delay1 = g_zuluscsi_timings->scsi_5.delay1;
                 delay2 = totalDelay - delay0 - delay1 - 3;
                 if (delay2 < 0) delay2 = 0;
                 if (delay2 > 15) delay2 = 15;

+ 0 - 124
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico.pio

@@ -1,124 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI communication
-; Run "pioasm scsi_accel.pio scsi_accel.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is REQ pin
-
-.define REQ 17
-.define ACK 26
-
-; Delay from data setup to REQ assertion.
-; deskew delay + cable skew delay = 55 ns minimum
-; One clock cycle is 8 ns => delay 7 clocks
-.define REQ_DLY 7
-
-; Adds parity to data that is to be written to SCSI
-; This works by generating addresses for DMA to fetch data from.
-; Register X should be initialized to the base address of the lookup table.
-.program scsi_parity
-    pull block
-    in NULL, 1
-    in OSR, 8
-    in X, 23
-
-; Write to SCSI bus using asynchronous handshake.
-; Data is written as 32-bit words that contain the 8 data bits + 1 parity bit.
-; 23 bits in each word are discarded.
-; Number of bytes to send must be multiple of 2.
-.program scsi_accel_async_write
-    .side_set 1
-
-    pull ifempty block          side 1  ; Get data from TX FIFO
-    out pins, 9                 side 1  ; Write data and parity bit
-    out null, 23 [REQ_DLY-2]    side 1  ; Discard unused bits, wait for data preset time
-    wait 1 gpio ACK             side 1  ; Wait for ACK to be inactive
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-
-; Read from SCSI bus using sync or async handshake.
-; Data is returned as 32-bit words:
-; - bit  0: always zero
-; - bits 1-8: data byte
-; - bit  9: parity bit
-; - bits 10-31: lookup table address
-; Lookup table address should be loaded into register Y.
-; One dummy word should be written to TX fifo for every byte to receive.
-.program scsi_accel_read
-    .side_set 1
-
-    pull block                  side 1  ; Pull from TX fifo for counting bytes and pacing sync mode
-    wait 1 gpio ACK             side 1  ; Wait for ACK high
-    in null, 1                  side 0  ; Zero bit because lookup table entries are 16-bit
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-    in pins, 9                  side 1  ; Deassert REQ, read GPIO
-    in y, 22                    side 1  ; Copy parity lookup table address
-
-; Data state machine for synchronous writes.
-; Takes the lowest 9 bits of each 32 bit word and writes them to bus with REQ pulse.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-;
-; Shifts one bit to ISR per every byte transmitted. This is used to control the transfer
-; pace, the RX fifo acts as a counter to keep track of unacknowledged bytes. The C code
-; can set the syncOffset by changing autopush threshold, e.g. threshold 3 = 12 bytes offset.
-.program scsi_sync_write
-    .side_set 1
-
-    out pins, 9      [0]        side 1  ; Write data and parity bit, wait for deskew delay
-    out null, 23     [0]        side 0  ; Assert REQ, wait for assert time
-    in null, 1       [0]        side 1  ; Deassert REQ, wait for transfer period, wait for space in ACK buffer
-
-; Data pacing state machine for synchronous writes.
-; Takes one bit from ISR on every falling edge of ACK.
-; The C code should set autopull threshold to match scsi_sync_write autopush threshold.
-; System DMA will then move words from scsi_sync_write RX fifo to scsi_sync_write_pacer TX fifo.
-.program scsi_sync_write_pacer
-    wait 1 gpio ACK
-    wait 0 gpio ACK   ; Wait for falling edge on ACK
-    out null, 1       ; Let scsi_sync_write send one more byte
-
-; Data pacing state machine for synchronous reads.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-; Number of bytes to receive minus one should be loaded into register X.
-; In synchronous mode this generates the REQ pulses and dummy words.
-; In asynchronous mode it just generates dummy words to feed to scsi_accel_read.
-.program scsi_sync_read_pacer
-    .side_set 1
-
-start:
-    push block      [0]      side 1  ; Send dummy word to scsi_accel_read, wait for transfer period
-    jmp x-- start   [0]      side 0  ; Assert REQ, wait for assert time
-
-finish:
-    jmp finish      [0]      side 1
-
-; Parity checker for reads from SCSI bus.
-; Receives 16-bit words from g_scsi_parity_check_lookup
-; Bottom 8 bits are the data byte, which is passed to output FIFO
-; The 9th bit is parity valid bit, which is 1 for valid and 0 for parity error.
-.program scsi_read_parity
-parity_valid:
-    out isr, 8                ; Take the 8 data bits for passing to RX fifo
-    push block                ; Push the data to RX fifo
-    out x, 24                 ; Take the parity valid bit, and the rest of 32-bit word
-    jmp x-- parity_valid      ; If parity valid bit is 1, repeat from start
-    irq set 0                 ; Parity error, set interrupt flag

+ 0 - 225
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico.pio.h

@@ -1,225 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ----------- //
-// scsi_parity //
-// ----------- //
-
-#define scsi_parity_wrap_target 0
-#define scsi_parity_wrap 3
-
-static const uint16_t scsi_parity_program_instructions[] = {
-            //     .wrap_target
-    0x80a0, //  0: pull   block                      
-    0x4061, //  1: in     null, 1                    
-    0x40e8, //  2: in     osr, 8                     
-    0x4037, //  3: in     x, 23                      
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_parity_program = {
-    .instructions = scsi_parity_program_instructions,
-    .length = 4,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_parity_wrap_target, offset + scsi_parity_wrap);
-    return c;
-}
-#endif
-
-// ---------------------- //
-// scsi_accel_async_write //
-// ---------------------- //
-
-#define scsi_accel_async_write_wrap_target 0
-#define scsi_accel_async_write_wrap 4
-
-static const uint16_t scsi_accel_async_write_program_instructions[] = {
-            //     .wrap_target
-    0x90e0, //  0: pull   ifempty block   side 1     
-    0x7009, //  1: out    pins, 9         side 1     
-    0x7577, //  2: out    null, 23        side 1 [5] 
-    0x309a, //  3: wait   1 gpio, 26      side 1     
-    0x201a, //  4: wait   0 gpio, 26      side 0     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_async_write_program = {
-    .instructions = scsi_accel_async_write_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_async_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_async_write_wrap_target, offset + scsi_accel_async_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_accel_read //
-// --------------- //
-
-#define scsi_accel_read_wrap_target 0
-#define scsi_accel_read_wrap 5
-
-static const uint16_t scsi_accel_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0x309a, //  1: wait   1 gpio, 26      side 1     
-    0x4061, //  2: in     null, 1         side 0     
-    0x201a, //  3: wait   0 gpio, 26      side 0     
-    0x5009, //  4: in     pins, 9         side 1     
-    0x5056, //  5: in     y, 22           side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_read_program = {
-    .instructions = scsi_accel_read_program_instructions,
-    .length = 6,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_read_wrap_target, offset + scsi_accel_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_sync_write //
-// --------------- //
-
-#define scsi_sync_write_wrap_target 0
-#define scsi_sync_write_wrap 2
-
-static const uint16_t scsi_sync_write_program_instructions[] = {
-            //     .wrap_target
-    0x7009, //  0: out    pins, 9         side 1     
-    0x6077, //  1: out    null, 23        side 0     
-    0x5061, //  2: in     null, 1         side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_program = {
-    .instructions = scsi_sync_write_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_wrap_target, offset + scsi_sync_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------------- //
-// scsi_sync_write_pacer //
-// --------------------- //
-
-#define scsi_sync_write_pacer_wrap_target 0
-#define scsi_sync_write_pacer_wrap 2
-
-static const uint16_t scsi_sync_write_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x209a, //  0: wait   1 gpio, 26                 
-    0x201a, //  1: wait   0 gpio, 26                 
-    0x6061, //  2: out    null, 1                    
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_pacer_program = {
-    .instructions = scsi_sync_write_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_pacer_wrap_target, offset + scsi_sync_write_pacer_wrap);
-    return c;
-}
-#endif
-
-// -------------------- //
-// scsi_sync_read_pacer //
-// -------------------- //
-
-#define scsi_sync_read_pacer_wrap_target 0
-#define scsi_sync_read_pacer_wrap 2
-
-static const uint16_t scsi_sync_read_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x9020, //  0: push   block           side 1     
-    0x0040, //  1: jmp    x--, 0          side 0     
-    0x1002, //  2: jmp    2               side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_read_pacer_program = {
-    .instructions = scsi_sync_read_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_read_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_read_pacer_wrap_target, offset + scsi_sync_read_pacer_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ---------------- //
-// scsi_read_parity //
-// ---------------- //
-
-#define scsi_read_parity_wrap_target 0
-#define scsi_read_parity_wrap 4
-
-static const uint16_t scsi_read_parity_program_instructions[] = {
-            //     .wrap_target
-    0x60c8, //  0: out    isr, 8                     
-    0x8020, //  1: push   block                      
-    0x6038, //  2: out    x, 24                      
-    0x0040, //  3: jmp    x--, 0                     
-    0xc000, //  4: irq    nowait 0                   
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_read_parity_program = {
-    .instructions = scsi_read_parity_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_read_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_read_parity_wrap_target, offset + scsi_read_parity_wrap);
-    return c;
-}
-#endif
-

+ 0 - 124
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico_2.pio

@@ -1,124 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI communication
-; Run "pioasm scsi_accel.pio scsi_accel.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is REQ pin
-
-.define REQ 17
-.define ACK 26
-
-; Delay from data setup to REQ assertion.
-; deskew delay + cable skew delay = 55 ns minimum
-; One clock cycle is 6.67 ns (150MHz) => delay 8.25 clocks or 9 clocks
-.define REQ_DLY 9
-
-; Adds parity to data that is to be written to SCSI
-; This works by generating addresses for DMA to fetch data from.
-; Register X should be initialized to the base address of the lookup table.
-.program scsi_parity
-    pull block
-    in NULL, 1
-    in OSR, 8
-    in X, 23
-
-; Write to SCSI bus using asynchronous handshake.
-; Data is written as 32-bit words that contain the 8 data bits + 1 parity bit.
-; 23 bits in each word are discarded.
-; Number of bytes to send must be multiple of 2.
-.program scsi_accel_async_write
-    .side_set 1
-
-    pull ifempty block          side 1  ; Get data from TX FIFO
-    out pins, 9                 side 1  ; Write data and parity bit
-    out null, 23 [REQ_DLY-2]    side 1  ; Discard unused bits, wait for data preset time
-    wait 1 gpio ACK             side 1  ; Wait for ACK to be inactive
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-
-; Read from SCSI bus using sync or async handshake.
-; Data is returned as 32-bit words:
-; - bit  0: always zero
-; - bits 1-8: data byte
-; - bit  9: parity bit
-; - bits 10-31: lookup table address
-; Lookup table address should be loaded into register Y.
-; One dummy word should be written to TX fifo for every byte to receive.
-.program scsi_accel_read
-    .side_set 1
-
-    pull block                  side 1  ; Pull from TX fifo for counting bytes and pacing sync mode
-    wait 1 gpio ACK             side 1  ; Wait for ACK high
-    in null, 1                  side 0  ; Zero bit because lookup table entries are 16-bit
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-    in pins, 9                  side 1  ; Deassert REQ, read GPIO
-    in y, 22                    side 1  ; Copy parity lookup table address
-
-; Data state machine for synchronous writes.
-; Takes the lowest 9 bits of each 32 bit word and writes them to bus with REQ pulse.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-;
-; Shifts one bit to ISR per every byte transmitted. This is used to control the transfer
-; pace, the RX fifo acts as a counter to keep track of unacknowledged bytes. The C code
-; can set the syncOffset by changing autopush threshold, e.g. threshold 3 = 12 bytes offset.
-.program scsi_sync_write
-    .side_set 1
-
-    out pins, 9      [0]        side 1  ; Write data and parity bit, wait for deskew delay
-    out null, 23     [0]        side 0  ; Assert REQ, wait for assert time
-    in null, 1       [0]        side 1  ; Deassert REQ, wait for transfer period, wait for space in ACK buffer
-
-; Data pacing state machine for synchronous writes.
-; Takes one bit from ISR on every falling edge of ACK.
-; The C code should set autopull threshold to match scsi_sync_write autopush threshold.
-; System DMA will then move words from scsi_sync_write RX fifo to scsi_sync_write_pacer TX fifo.
-.program scsi_sync_write_pacer
-    wait 1 gpio ACK
-    wait 0 gpio ACK   ; Wait for falling edge on ACK
-    out null, 1       ; Let scsi_sync_write send one more byte
-
-; Data pacing state machine for synchronous reads.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-; Number of bytes to receive minus one should be loaded into register X.
-; In synchronous mode this generates the REQ pulses and dummy words.
-; In asynchronous mode it just generates dummy words to feed to scsi_accel_read.
-.program scsi_sync_read_pacer
-    .side_set 1
-
-start:
-    push block      [0]      side 1  ; Send dummy word to scsi_accel_read, wait for transfer period
-    jmp x-- start   [0]      side 0  ; Assert REQ, wait for assert time
-
-finish:
-    jmp finish      [0]      side 1
-
-; Parity checker for reads from SCSI bus.
-; Receives 16-bit words from g_scsi_parity_check_lookup
-; Bottom 8 bits are the data byte, which is passed to output FIFO
-; The 9th bit is parity valid bit, which is 1 for valid and 0 for parity error.
-.program scsi_read_parity
-parity_valid:
-    out isr, 8                ; Take the 8 data bits for passing to RX fifo
-    push block                ; Push the data to RX fifo
-    out x, 24                 ; Take the parity valid bit, and the rest of 32-bit word
-    jmp x-- parity_valid      ; If parity valid bit is 1, repeat from start
-    irq set 0                 ; Parity error, set interrupt flag

+ 0 - 224
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_Pico_2.pio.h

@@ -1,224 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ----------- //
-// scsi_parity //
-// ----------- //
-
-#define scsi_parity_wrap_target 0
-#define scsi_parity_wrap 3
-
-static const uint16_t scsi_parity_program_instructions[] = {
-            //     .wrap_target
-    0x80a0, //  0: pull   block                      
-    0x4061, //  1: in     null, 1                    
-    0x40e8, //  2: in     osr, 8                     
-    0x4037, //  3: in     x, 23                      
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_parity_program = {
-    .instructions = scsi_parity_program_instructions,
-    .length = 4,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_parity_wrap_target, offset + scsi_parity_wrap);
-    return c;
-}
-#endif
-
-// ---------------------- //
-// scsi_accel_async_write //
-// ---------------------- //
-
-#define scsi_accel_async_write_wrap_target 0
-#define scsi_accel_async_write_wrap 4
-
-static const uint16_t scsi_accel_async_write_program_instructions[] = {
-            //     .wrap_target
-    0x90e0, //  0: pull   ifempty block   side 1     
-    0x7009, //  1: out    pins, 9         side 1     
-    0x7777, //  2: out    null, 23        side 1 [7] 
-    0x309a, //  3: wait   1 gpio, 26      side 1     
-    0x201a, //  4: wait   0 gpio, 26      side 0     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_async_write_program = {
-    .instructions = scsi_accel_async_write_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_async_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_async_write_wrap_target, offset + scsi_accel_async_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_accel_read //
-// --------------- //
-
-#define scsi_accel_read_wrap_target 0
-#define scsi_accel_read_wrap 5
-
-static const uint16_t scsi_accel_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0x309a, //  1: wait   1 gpio, 26      side 1     
-    0x4061, //  2: in     null, 1         side 0     
-    0x201a, //  3: wait   0 gpio, 26      side 0     
-    0x5009, //  4: in     pins, 9         side 1     
-    0x5056, //  5: in     y, 22           side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_read_program = {
-    .instructions = scsi_accel_read_program_instructions,
-    .length = 6,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_read_wrap_target, offset + scsi_accel_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_sync_write //
-// --------------- //
-
-#define scsi_sync_write_wrap_target 0
-#define scsi_sync_write_wrap 2
-
-static const uint16_t scsi_sync_write_program_instructions[] = {
-            //     .wrap_target
-    0x7009, //  0: out    pins, 9         side 1     
-    0x6077, //  1: out    null, 23        side 0     
-    0x5061, //  2: in     null, 1         side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_program = {
-    .instructions = scsi_sync_write_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_wrap_target, offset + scsi_sync_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------------- //
-// scsi_sync_write_pacer //
-// --------------------- //
-
-#define scsi_sync_write_pacer_wrap_target 0
-#define scsi_sync_write_pacer_wrap 2
-
-static const uint16_t scsi_sync_write_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x209a, //  0: wait   1 gpio, 26                 
-    0x201a, //  1: wait   0 gpio, 26                 
-    0x6061, //  2: out    null, 1                    
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_pacer_program = {
-    .instructions = scsi_sync_write_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_pacer_wrap_target, offset + scsi_sync_write_pacer_wrap);
-    return c;
-}
-#endif
-
-// -------------------- //
-// scsi_sync_read_pacer //
-// -------------------- //
-
-#define scsi_sync_read_pacer_wrap_target 0
-#define scsi_sync_read_pacer_wrap 2
-
-static const uint16_t scsi_sync_read_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x9020, //  0: push   block           side 1     
-    0x0040, //  1: jmp    x--, 0          side 0     
-    0x1002, //  2: jmp    2               side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_read_pacer_program = {
-    .instructions = scsi_sync_read_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_read_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_read_pacer_wrap_target, offset + scsi_sync_read_pacer_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ---------------- //
-// scsi_read_parity //
-// ---------------- //
-
-#define scsi_read_parity_wrap_target 0
-#define scsi_read_parity_wrap 4
-
-static const uint16_t scsi_read_parity_program_instructions[] = {
-            //     .wrap_target
-    0x60c8, //  0: out    isr, 8                     
-    0x8020, //  1: push   block                      
-    0x6038, //  2: out    x, 24                      
-    0x0040, //  3: jmp    x--, 0                     
-    0xc000, //  4: irq    nowait 0                   
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_read_parity_program = {
-    .instructions = scsi_read_parity_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_read_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_read_parity_wrap_target, offset + scsi_read_parity_wrap);
-    return c;
-}
-#endif

+ 0 - 225
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2040.pio.h

@@ -1,225 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ----------- //
-// scsi_parity //
-// ----------- //
-
-#define scsi_parity_wrap_target 0
-#define scsi_parity_wrap 3
-
-static const uint16_t scsi_parity_program_instructions[] = {
-            //     .wrap_target
-    0x80a0, //  0: pull   block                      
-    0x4061, //  1: in     null, 1                    
-    0x40e8, //  2: in     osr, 8                     
-    0x4037, //  3: in     x, 23                      
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_parity_program = {
-    .instructions = scsi_parity_program_instructions,
-    .length = 4,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_parity_wrap_target, offset + scsi_parity_wrap);
-    return c;
-}
-#endif
-
-// ---------------------- //
-// scsi_accel_async_write //
-// ---------------------- //
-
-#define scsi_accel_async_write_wrap_target 0
-#define scsi_accel_async_write_wrap 4
-
-static const uint16_t scsi_accel_async_write_program_instructions[] = {
-            //     .wrap_target
-    0x90e0, //  0: pull   ifempty block   side 1     
-    0x7009, //  1: out    pins, 9         side 1     
-    0x7577, //  2: out    null, 23        side 1 [5] 
-    0x308a, //  3: wait   1 gpio, 10      side 1     
-    0x200a, //  4: wait   0 gpio, 10      side 0     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_async_write_program = {
-    .instructions = scsi_accel_async_write_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_async_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_async_write_wrap_target, offset + scsi_accel_async_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_accel_read //
-// --------------- //
-
-#define scsi_accel_read_wrap_target 0
-#define scsi_accel_read_wrap 5
-
-static const uint16_t scsi_accel_read_program_instructions[] = {
-            //     .wrap_target
-    0x90a0, //  0: pull   block           side 1     
-    0x308a, //  1: wait   1 gpio, 10      side 1     
-    0x4061, //  2: in     null, 1         side 0     
-    0x200a, //  3: wait   0 gpio, 10      side 0     
-    0x5009, //  4: in     pins, 9         side 1     
-    0x5056, //  5: in     y, 22           side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_read_program = {
-    .instructions = scsi_accel_read_program_instructions,
-    .length = 6,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_accel_read_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_accel_read_wrap_target, offset + scsi_accel_read_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------- //
-// scsi_sync_write //
-// --------------- //
-
-#define scsi_sync_write_wrap_target 0
-#define scsi_sync_write_wrap 2
-
-static const uint16_t scsi_sync_write_program_instructions[] = {
-            //     .wrap_target
-    0x7009, //  0: out    pins, 9         side 1     
-    0x6077, //  1: out    null, 23        side 0     
-    0x5061, //  2: in     null, 1         side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_program = {
-    .instructions = scsi_sync_write_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_wrap_target, offset + scsi_sync_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// --------------------- //
-// scsi_sync_write_pacer //
-// --------------------- //
-
-#define scsi_sync_write_pacer_wrap_target 0
-#define scsi_sync_write_pacer_wrap 2
-
-static const uint16_t scsi_sync_write_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x208a, //  0: wait   1 gpio, 10                 
-    0x200a, //  1: wait   0 gpio, 10                 
-    0x6061, //  2: out    null, 1                    
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_pacer_program = {
-    .instructions = scsi_sync_write_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_pacer_wrap_target, offset + scsi_sync_write_pacer_wrap);
-    return c;
-}
-#endif
-
-// -------------------- //
-// scsi_sync_read_pacer //
-// -------------------- //
-
-#define scsi_sync_read_pacer_wrap_target 0
-#define scsi_sync_read_pacer_wrap 2
-
-static const uint16_t scsi_sync_read_pacer_program_instructions[] = {
-            //     .wrap_target
-    0x9020, //  0: push   block           side 1     
-    0x0040, //  1: jmp    x--, 0          side 0     
-    0x1002, //  2: jmp    2               side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_read_pacer_program = {
-    .instructions = scsi_sync_read_pacer_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_read_pacer_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_read_pacer_wrap_target, offset + scsi_sync_read_pacer_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ---------------- //
-// scsi_read_parity //
-// ---------------- //
-
-#define scsi_read_parity_wrap_target 0
-#define scsi_read_parity_wrap 4
-
-static const uint16_t scsi_read_parity_program_instructions[] = {
-            //     .wrap_target
-    0x60c8, //  0: out    isr, 8                     
-    0x8020, //  1: push   block                      
-    0x6038, //  2: out    x, 24                      
-    0x0040, //  3: jmp    x--, 0                     
-    0xc000, //  4: irq    nowait 0                   
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_read_parity_program = {
-    .instructions = scsi_read_parity_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_read_parity_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_read_parity_wrap_target, offset + scsi_read_parity_wrap);
-    return c;
-}
-#endif
-

+ 0 - 125
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2350A.pio

@@ -1,125 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-; RP2040 PIO program for accelerating SCSI communication
-; Run "pioasm scsi_accel.pio scsi_accel.pio.h" to regenerate the C header from this.
-; GPIO mapping:
-; - 0-7: DB0-DB7
-; -   8: DBP
-; Side set is REQ pin
-
-.define REQ 9
-.define ACK 10
-
-; Delay from data setup to REQ assertion.
-; deskew delay + cable skew delay = 55 ns minimum
-; One clock cycle is 6.67 ns (150MHz) => delay 8.25 clocks or 9 clocks
-.define REQ_DLY 9
-
-
-; Adds parity to data that is to be written to SCSI
-; This works by generating addresses for DMA to fetch data from.
-; Register X should be initialized to the base address of the lookup table.
-.program scsi_parity
-    pull block
-    in NULL, 1
-    in OSR, 8
-    in X, 23
-
-; Write to SCSI bus using asynchronous handshake.
-; Data is written as 32-bit words that contain the 8 data bits + 1 parity bit.
-; 23 bits in each word are discarded.
-; Number of bytes to send must be multiple of 2.
-.program scsi_accel_async_write
-    .side_set 1
-
-    pull ifempty block          side 1  ; Get data from TX FIFO
-    out pins, 9                 side 1  ; Write data and parity bit
-    out null, 23 [REQ_DLY-2]    side 1  ; Discard unused bits, wait for data preset time
-    wait 1 gpio ACK             side 1  ; Wait for ACK to be inactive
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-
-; Read from SCSI bus using sync or async handshake.
-; Data is returned as 32-bit words:
-; - bit  0: always zero
-; - bits 1-8: data byte
-; - bit  9: parity bit
-; - bits 10-31: lookup table address
-; Lookup table address should be loaded into register Y.
-; One dummy word should be written to TX fifo for every byte to receive.
-.program scsi_accel_read
-    .side_set 1
-
-    pull block                  side 1  ; Pull from TX fifo for counting bytes and pacing sync mode
-    wait 1 gpio ACK             side 1  ; Wait for ACK high
-    in null, 1                  side 0  ; Zero bit because lookup table entries are 16-bit
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
-    in pins, 9                  side 1  ; Deassert REQ, read GPIO
-    in y, 22                    side 1  ; Copy parity lookup table address
-
-; Data state machine for synchronous writes.
-; Takes the lowest 9 bits of each 32 bit word and writes them to bus with REQ pulse.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-;
-; Shifts one bit to ISR per every byte transmitted. This is used to control the transfer
-; pace, the RX fifo acts as a counter to keep track of unacknowledged bytes. The C code
-; can set the syncOffset by changing autopush threshold, e.g. threshold 3 = 12 bytes offset.
-.program scsi_sync_write
-    .side_set 1
-
-    out pins, 9      [0]        side 1  ; Write data and parity bit, wait for deskew delay
-    out null, 23     [0]        side 0  ; Assert REQ, wait for assert time
-    in null, 1       [0]        side 1  ; Deassert REQ, wait for transfer period, wait for space in ACK buffer
-
-; Data pacing state machine for synchronous writes.
-; Takes one bit from ISR on every falling edge of ACK.
-; The C code should set autopull threshold to match scsi_sync_write autopush threshold.
-; System DMA will then move words from scsi_sync_write RX fifo to scsi_sync_write_pacer TX fifo.
-.program scsi_sync_write_pacer
-    wait 1 gpio ACK
-    wait 0 gpio ACK   ; Wait for falling edge on ACK
-    out null, 1       ; Let scsi_sync_write send one more byte
-
-; Data pacing state machine for synchronous reads.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-; Number of bytes to receive minus one should be loaded into register X.
-; In synchronous mode this generates the REQ pulses and dummy words.
-; In asynchronous mode it just generates dummy words to feed to scsi_accel_read.
-.program scsi_sync_read_pacer
-    .side_set 1
-
-start:
-    push block      [0]      side 1  ; Send dummy word to scsi_accel_read, wait for transfer period
-    jmp x-- start   [0]      side 0  ; Assert REQ, wait for assert time
-
-finish:
-    jmp finish      [0]      side 1
-
-; Parity checker for reads from SCSI bus.
-; Receives 16-bit words from g_scsi_parity_check_lookup
-; Bottom 8 bits are the data byte, which is passed to output FIFO
-; The 9th bit is parity valid bit, which is 1 for valid and 0 for parity error.
-.program scsi_read_parity
-parity_valid:
-    out isr, 8                ; Take the 8 data bits for passing to RX fifo
-    push block                ; Push the data to RX fifo
-    out x, 24                 ; Take the parity valid bit, and the rest of 32-bit word
-    jmp x-- parity_valid      ; If parity valid bit is 1, repeat from start
-    irq set 0                 ; Parity error, set interrupt flag

+ 22 - 21
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2040.pio → lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2MCU.pio

@@ -24,13 +24,13 @@
 ; - 0-7: DB0-DB7
 ; -   8: DBP
 ; Side set is REQ pin
-
-.define REQ 9
+; ACK is a dummy value, Will be rewritten on initialization
 .define ACK 10
 
 ; Delay from data setup to REQ assertion.
 ; deskew delay + cable skew delay = 55 ns minimum
-; One clock cycle is 8 ns => delay 7 clocks
+; One clock cycle is x ns => delay (55 / x) clocks
+; REQ_DLY is a dummy value, will be rewritten
 .define REQ_DLY 7
 
 ; Adds parity to data that is to be written to SCSI
@@ -49,11 +49,11 @@
 .program scsi_accel_async_write
     .side_set 1
 
-    pull ifempty block          side 1  ; Get data from TX FIFO
-    out pins, 9                 side 1  ; Write data and parity bit
-    out null, 23 [REQ_DLY-2]    side 1  ; Discard unused bits, wait for data preset time
-    wait 1 gpio ACK             side 1  ; Wait for ACK to be inactive
-    wait 0 gpio ACK             side 0  ; Assert REQ, wait for ACK low
+    pull ifempty block   side 1      ; Get data from TX FIFO
+    out pins, 9          side 1      ; Write data and parity bit
+    out null, 23         side 1  [0] ;[REQ_DLY-2]      ; Discard unused bits, wait for data preset time
+    wait 1 gpio ACK      side 1      ; Wait for ACK to be inactive
+    wait 0 gpio ACK      side 0      ; Assert REQ, wait for ACK low
 
 ; Read from SCSI bus using sync or async handshake.
 ; Data is returned as 32-bit words:
@@ -73,19 +73,6 @@
     in pins, 9                  side 1  ; Deassert REQ, read GPIO
     in y, 22                    side 1  ; Copy parity lookup table address
 
-; Data state machine for synchronous writes.
-; Takes the lowest 9 bits of each 32 bit word and writes them to bus with REQ pulse.
-; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
-;
-; Shifts one bit to ISR per every byte transmitted. This is used to control the transfer
-; pace, the RX fifo acts as a counter to keep track of unacknowledged bytes. The C code
-; can set the syncOffset by changing autopush threshold, e.g. threshold 3 = 12 bytes offset.
-.program scsi_sync_write
-    .side_set 1
-
-    out pins, 9      [0]        side 1  ; Write data and parity bit, wait for deskew delay
-    out null, 23     [0]        side 0  ; Assert REQ, wait for assert time
-    in null, 1       [0]        side 1  ; Deassert REQ, wait for transfer period, wait for space in ACK buffer
 
 ; Data pacing state machine for synchronous writes.
 ; Takes one bit from ISR on every falling edge of ACK.
@@ -122,3 +109,17 @@ parity_valid:
     out x, 24                 ; Take the parity valid bit, and the rest of 32-bit word
     jmp x-- parity_valid      ; If parity valid bit is 1, repeat from start
     irq set 0                 ; Parity error, set interrupt flag
+
+; Data state machine for synchronous writes.
+; Takes the lowest 9 bits of each 32 bit word and writes them to bus with REQ pulse.
+; The delay times will be rewritten by C code to match the negotiated SCSI sync speed.
+;
+; Shifts one bit to ISR per every byte transmitted. This is used to control the transfer
+; pace, the RX fifo acts as a counter to keep track of unacknowledged bytes. The C code
+; can set the syncOffset by changing autopush threshold, e.g. threshold 3 = 12 bytes offset.
+.program scsi_sync_write
+    .side_set 1
+
+    out pins, 9      [0]        side 1  ; Write data and parity bit, wait for deskew delay
+    out null, 23     [0]        side 0  ; Assert REQ, wait for assert time
+    in null, 1       [0]        side 1  ; Deassert REQ, wait for transfer period, wait for space in ACK buffer

+ 31 - 31
lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2350A.pio.h → lib/ZuluSCSI_platform_RP2MCU/scsi_accel_target_RP2MCU.pio.h

@@ -49,7 +49,7 @@ static const uint16_t scsi_accel_async_write_program_instructions[] = {
             //     .wrap_target
     0x90e0, //  0: pull   ifempty block   side 1     
     0x7009, //  1: out    pins, 9         side 1     
-    0x7777, //  2: out    null, 23        side 1 [7] 
+    0x7077, //  2: out    null, 23        side 1     
     0x308a, //  3: wait   1 gpio, 10      side 1     
     0x200a, //  4: wait   0 gpio, 10      side 0     
             //     .wrap
@@ -103,36 +103,6 @@ static inline pio_sm_config scsi_accel_read_program_get_default_config(uint offs
 }
 #endif
 
-// --------------- //
-// scsi_sync_write //
-// --------------- //
-
-#define scsi_sync_write_wrap_target 0
-#define scsi_sync_write_wrap 2
-
-static const uint16_t scsi_sync_write_program_instructions[] = {
-            //     .wrap_target
-    0x7009, //  0: out    pins, 9         side 1     
-    0x6077, //  1: out    null, 23        side 0     
-    0x5061, //  2: in     null, 1         side 1     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program scsi_sync_write_program = {
-    .instructions = scsi_sync_write_program_instructions,
-    .length = 3,
-    .origin = -1,
-};
-
-static inline pio_sm_config scsi_sync_write_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + scsi_sync_write_wrap_target, offset + scsi_sync_write_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
 // --------------------- //
 // scsi_sync_write_pacer //
 // --------------------- //
@@ -222,3 +192,33 @@ static inline pio_sm_config scsi_read_parity_program_get_default_config(uint off
     return c;
 }
 #endif
+
+// --------------- //
+// scsi_sync_write //
+// --------------- //
+
+#define scsi_sync_write_wrap_target 0
+#define scsi_sync_write_wrap 2
+
+static const uint16_t scsi_sync_write_program_instructions[] = {
+            //     .wrap_target
+    0x7009, //  0: out    pins, 9         side 1     
+    0x6077, //  1: out    null, 23        side 0     
+    0x5061, //  2: in     null, 1         side 1     
+            //     .wrap
+};
+
+#if !PICO_NO_HARDWARE
+static const struct pio_program scsi_sync_write_program = {
+    .instructions = scsi_sync_write_program_instructions,
+    .length = 3,
+    .origin = -1,
+};
+
+static inline pio_sm_config scsi_sync_write_program_get_default_config(uint offset) {
+    pio_sm_config c = pio_get_default_sm_config();
+    sm_config_set_wrap(&c, offset + scsi_sync_write_wrap_target, offset + scsi_sync_write_wrap);
+    sm_config_set_sideset(&c, 1, false, false);
+    return c;
+}
+#endif

+ 2 - 1
lib/ZuluSCSI_platform_RP2MCU/sd_card_sdio.cpp

@@ -28,6 +28,7 @@
 
 #include "ZuluSCSI_log.h"
 #include "sdio.h"
+#include "timings_RP2MCU.h"
 #include <hardware/gpio.h>
 #include <SdFat.h>
 #include <SdCard/SdCardInfo.h>
@@ -92,7 +93,7 @@ bool SdioCard::begin(SdioConfig sdioConfig)
     sdio_status_t status;
     
     // Initialize at 1 MHz clock speed
-    rp2040_sdio_init(25);
+    rp2040_sdio_init(g_zuluscsi_timings->sdio.clk_div_1mhz);
 
     // Establish initial connection with the card
     for (int retries = 0; retries < 5; retries++)

+ 55 - 12
lib/ZuluSCSI_platform_RP2MCU/sdio.cpp

@@ -37,16 +37,9 @@
 #include <hardware/structs/scb.h>
 #include <ZuluSCSI_platform.h>
 #include <ZuluSCSI_log.h>
+#include "timings_RP2MCU.h"
 
-#if defined(ZULUSCSI_PICO) || defined(ZULUSCSI_BS2)
-# include "sdio_Pico.pio.h"
-#elif defined(ZULUSCSI_PICO_2)
-# include "sdio_Pico_2.pio.h"
-#elif defined(ZULUSCSI_RP2350A)
-# include "sdio_RP2350A.pio.h"
-#else
-# include "sdio_RP2040.pio.h"
-#endif
+# include "sdio_RP2MCU.pio.h"
 
 #define SDIO_PIO pio1
 #define SDIO_CMD_SM 0
@@ -813,7 +806,21 @@ void rp2040_sdio_init(int clock_divider)
     pio_clear_instruction_memory(SDIO_PIO);
 
     // Command & clock state machine
-    g_sdio.pio_cmd_clk_offset = pio_add_program(SDIO_PIO, &sdio_cmd_clk_program);
+    uint16_t temp_program_instr[32];
+    pio_program rewrite_sdio_cmd_clk_program = {
+        temp_program_instr,
+        sdio_cmd_clk_program.length,
+        sdio_cmd_clk_program.origin,
+        sdio_cmd_clk_program.pio_version };
+    memcpy(temp_program_instr, sdio_cmd_clk_program_instructions, sizeof(sdio_cmd_clk_program_instructions));
+    // Set the delays for the sdio_cmd_clk SDIO state machine
+    for (uint8_t i = 0; i < sizeof(sdio_cmd_clk_program_instructions) / sizeof(sdio_cmd_clk_program_instructions[0]); i++)
+    {
+        uint16_t instr = sdio_cmd_clk_program_instructions[i]
+            | ((i & 1) ? pio_encode_delay(g_zuluscsi_timings->sdio.delay0) : pio_encode_delay(g_zuluscsi_timings->sdio.delay1));
+        temp_program_instr[i] = instr;
+    }
+    g_sdio.pio_cmd_clk_offset = pio_add_program(SDIO_PIO, &rewrite_sdio_cmd_clk_program);
     pio_sm_config cfg = sdio_cmd_clk_program_get_default_config(g_sdio.pio_cmd_clk_offset);
     sm_config_set_out_pins(&cfg, SDIO_CMD, 1);
     sm_config_set_in_pins(&cfg, SDIO_CMD);
@@ -830,7 +837,22 @@ void rp2040_sdio_init(int clock_divider)
     pio_sm_set_enabled(SDIO_PIO, SDIO_CMD_SM, true);
 
     // Data reception program
-    g_sdio.pio_data_rx_offset = pio_add_program(SDIO_PIO, &sdio_data_rx_program);
+
+    // Set delays for sdio_data_rx PIO state machine
+    pio_program rewrite_sdio_data_rx_program = {
+        temp_program_instr,
+        sdio_data_rx_program.length,
+        sdio_data_rx_program.origin,
+        sdio_data_rx_program.pio_version };
+    memcpy(temp_program_instr, sdio_data_rx_program_instructions, sizeof(sdio_data_rx_program_instructions));
+    // wait 1 gpio SDIO_CLK_GPIO  [0]; [CLKDIV-1]
+    uint16_t instr = pio_encode_wait_gpio(true, SDIO_CLK) | pio_encode_delay(g_zuluscsi_timings->sdio.clk_div_pio - 1);
+    temp_program_instr[2] = instr;
+    // in PINS, 4                 [0]; [CLKDIV-2]
+    instr = sdio_data_rx_program_instructions[3] | pio_encode_delay(g_zuluscsi_timings->sdio.clk_div_pio - 2);
+    temp_program_instr[3] = instr;
+
+    g_sdio.pio_data_rx_offset = pio_add_program(SDIO_PIO, &rewrite_sdio_data_rx_program);
     g_sdio.pio_cfg_data_rx = sdio_data_rx_program_get_default_config(g_sdio.pio_data_rx_offset);
     sm_config_set_in_pins(&g_sdio.pio_cfg_data_rx, SDIO_D0);
     sm_config_set_in_shift(&g_sdio.pio_cfg_data_rx, false, true, 32);
@@ -838,7 +860,28 @@ void rp2040_sdio_init(int clock_divider)
     sm_config_set_clkdiv_int_frac(&g_sdio.pio_cfg_data_rx, clock_divider, 0);
 
     // Data transmission program
-    g_sdio.pio_data_tx_offset = pio_add_program(SDIO_PIO, &sdio_data_tx_program);
+
+    // Set delays for sdio_data_tx PIO state machine
+    pio_program rewrite_sdio_data_tx_program = {
+        temp_program_instr,
+        sdio_data_tx_program.length,
+        sdio_data_tx_program.origin,
+        sdio_data_tx_program.pio_version };
+    memcpy(temp_program_instr, sdio_data_tx_program_instructions, sizeof(sdio_data_tx_program_instructions));
+    // wait 0 gpio SDIO_CLK_GPIO  
+    instr = pio_encode_wait_gpio(false, SDIO_CLK);
+    temp_program_instr[0] = instr;
+    // wait 1 gpio SDIO_CLK_GPIO;  [0]; [CLKDIV + D1 - 1];
+    instr = pio_encode_wait_gpio(true, SDIO_CLK) | pio_encode_delay(g_zuluscsi_timings->sdio.clk_div_pio + g_zuluscsi_timings->sdio.delay1 - 1);
+    temp_program_instr[1] = instr;
+    
+    for (uint8_t i = 2; i < sizeof(sdio_data_tx_program_instructions) / sizeof(sdio_data_tx_program_instructions[0]); i++)
+    {    
+        uint16_t instr = sdio_data_tx_program_instructions[i]
+            | ((i & 1) ? pio_encode_delay(g_zuluscsi_timings->sdio.delay1) : pio_encode_delay(g_zuluscsi_timings->sdio.delay0));
+        temp_program_instr[i] = instr;
+    }
+    g_sdio.pio_data_tx_offset = pio_add_program(SDIO_PIO, &rewrite_sdio_data_tx_program);
     g_sdio.pio_cfg_data_tx = sdio_data_tx_program_get_default_config(g_sdio.pio_data_tx_offset);
     sm_config_set_in_pins(&g_sdio.pio_cfg_data_tx, SDIO_D0);
     sm_config_set_set_pins(&g_sdio.pio_cfg_data_tx, SDIO_D0, 4);

+ 0 - 164
lib/ZuluSCSI_platform_RP2MCU/sdio_Pico.pio

@@ -1,164 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-; RP2040 PIO program for implementing SD card access in SDIO mode
-; Run "pioasm rp2040_sdio.pio rp2040_sdio.pio.h" to regenerate the C header from this.
-
-; The RP2040 official work-in-progress code at
-; https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sd_card
-; may be useful reference, but this is independent implementation.
-;
-; For official SDIO specifications, refer to:
-; https://www.sdcard.org/downloads/pls/
-; "SDIO Physical Layer Simplified Specification Version 8.00"
-
-; Clock settings
-; For 3.3V communication the available speeds are:
-; - Default speed: max. 25 MHz clock
-; - High speed:    max. 50 MHz clock
-;
-; From the default RP2040 clock speed of 125 MHz, the closest dividers
-; are 3 for 41.7 MHz and 5 for 25 MHz. The CPU can apply further divider
-; through state machine registers for the initial handshake.
-;
-; Because data is written on the falling edge and read on the rising
-; edge, it is preferrable to have a long 0 state and short 1 state.
-;.define CLKDIV 3
-.define CLKDIV 5
-.define D0 ((CLKDIV + 1) / 2 - 1)
-.define D1 (CLKDIV/2 - 1)
-.define SDIO_CLK_GPIO 10
-
-; State machine 0 is used to:
-; - generate continuous clock on SDIO_CLK
-; - send CMD packets
-; - receive response packets
-;
-; Pin mapping for this state machine:
-; - Sideset    : CLK
-; - IN/OUT/SET : CMD
-; - JMP_PIN    : CMD
-;
-; The commands to send are put on TX fifo and must have two words:
-; Word 0 bits 31-24: Number of bits in command minus one (usually 47)
-; Word 0 bits 23-00: First 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 31-08: Last 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 07-00: Number of bits in response minus one (usually 47), or 0 if no response
-;
-; The response is put on RX fifo, starting with the MSB.
-; Partial last word will be padded with zero bits at the top.
-;
-; The state machine EXECCTRL should be set so that STATUS indicates TX FIFO < 2
-; and that AUTOPULL and AUTOPUSH are enabled.
-
-.program sdio_cmd_clk
-    .side_set 1
-
-    mov OSR, NULL       side 1 [D1]    ; Make sure OSR is full of zeros to prevent autopull
-
-wait_cmd:
-    mov Y, !STATUS      side 0 [D0]    ; Check if TX FIFO has data
-    jmp !Y wait_cmd     side 1 [D1]
-
-load_cmd:
-    out NULL, 32        side 0 [D0]    ; Load first word (trigger autopull)
-    out X, 8            side 1 [D1]    ; Number of bits to send
-    set pins, 1         side 0 [D0]    ; Initial state of CMD is high
-    set pindirs, 1      side 1 [D1]    ; Set SDIO_CMD as output
-
-send_cmd:
-    out pins, 1         side 0 [D0]    ; Write output on falling edge of CLK
-    jmp X-- send_cmd    side 1 [D1]
-
-prep_resp:
-    set pindirs, 0      side 0 [D0]    ; Set SDIO_CMD as input
-    out X, 8            side 1 [D1]    ; Get number of bits in response
-    nop                 side 0 [D0]    ; For clock alignment
-    jmp !X resp_done    side 1 [D1]    ; Check if we expect a response
-
-wait_resp:
-    nop                  side 0 [D0]
-    jmp PIN wait_resp    side 1 [D1]    ; Loop until SDIO_CMD = 0
-
-    ; Note: input bits are read at the same time as we write CLK=0.
-    ; Because the host controls the clock, the read happens before
-    ; the card sees the falling clock edge. This gives maximum time
-    ; for the data bit to settle.
-read_resp:
-    in PINS, 1          side 0 [D0]    ; Read input data bit
-    jmp X-- read_resp   side 1 [D1]    ; Loop to receive all data bits
-
-resp_done:
-    push                side 0 [D0]    ; Push the remaining part of response
-
-; State machine 1 is used to send and receive data blocks.
-; Pin mapping for this state machine:
-; - IN / OUT: SDIO_D0-D3
-; - GPIO defined at beginning of this file: SDIO_CLK
-
-; Data reception program
-; This program will wait for initial start of block token and then
-; receive a data block. The application must set number of nibbles
-; to receive minus 1 to Y register before running this program.
-.program sdio_data_rx
-
-wait_start:
-    mov X, Y                               ; Reinitialize number of nibbles to receive
-    wait 0 pin 0                           ; Wait for zero state on D0
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV-1]  ; Wait for rising edge and then whole clock cycle
-
-rx_data:
-    in PINS, 4                 [CLKDIV-2]  ; Read nibble
-    jmp X--, rx_data
-
-; Data transmission program
-;
-; Before running this program, pindirs should be set as output
-; and register X should be initialized with the number of nibbles
-; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
-; and register Y with the number of response bits minus 1 (typically 31).
-;
-; Words written to TX FIFO must be:
-; - Word 0: start token 0xFFFFFFF0
-; - Word 1-128: transmitted data (512 bytes)
-; - Word 129-130: CRC checksum
-; - Word 131: end token 0xFFFFFFFF
-;
-; After the card reports idle status, RX FIFO will get a word that
-; contains the D0 line response from card.
-
-.program sdio_data_tx
-    wait 0 gpio SDIO_CLK_GPIO  
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV + D1 - 1]; Synchronize so that write occurs on falling edge
-
-tx_loop:
-    out PINS, 4                [D0]    ; Write nibble and wait for whole clock cycle
-    jmp X-- tx_loop            [D1]
-
-    set pindirs, 0x00          [D0]    ; Set data bus as input
-
-.wrap_target
-response_loop:
-    in PINS, 1                 [D1]    ; Read D0 on rising edge
-    jmp Y--, response_loop     [D0]
-
-wait_idle:
-    wait 1 pin 0               [D1]    ; Wait for card to indicate idle condition
-    push                       [D0]    ; Push the response token
-.wrap

+ 0 - 121
lib/ZuluSCSI_platform_RP2MCU/sdio_Pico.pio.h

@@ -1,121 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ------------ //
-// sdio_cmd_clk //
-// ------------ //
-
-#define sdio_cmd_clk_wrap_target 0
-#define sdio_cmd_clk_wrap 17
-
-static const uint16_t sdio_cmd_clk_program_instructions[] = {
-            //     .wrap_target
-    0xb1e3, //  0: mov    osr, null       side 1 [1] 
-    0xa24d, //  1: mov    y, !status      side 0 [2] 
-    0x1161, //  2: jmp    !y, 1           side 1 [1] 
-    0x6260, //  3: out    null, 32        side 0 [2] 
-    0x7128, //  4: out    x, 8            side 1 [1] 
-    0xe201, //  5: set    pins, 1         side 0 [2] 
-    0xf181, //  6: set    pindirs, 1      side 1 [1] 
-    0x6201, //  7: out    pins, 1         side 0 [2] 
-    0x1147, //  8: jmp    x--, 7          side 1 [1] 
-    0xe280, //  9: set    pindirs, 0      side 0 [2] 
-    0x7128, // 10: out    x, 8            side 1 [1] 
-    0xa242, // 11: nop                    side 0 [2] 
-    0x1131, // 12: jmp    !x, 17          side 1 [1] 
-    0xa242, // 13: nop                    side 0 [2] 
-    0x11cd, // 14: jmp    pin, 13         side 1 [1] 
-    0x4201, // 15: in     pins, 1         side 0 [2] 
-    0x114f, // 16: jmp    x--, 15         side 1 [1] 
-    0x8220, // 17: push   block           side 0 [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_cmd_clk_program = {
-    .instructions = sdio_cmd_clk_program_instructions,
-    .length = 18,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_cmd_clk_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_cmd_clk_wrap_target, offset + sdio_cmd_clk_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_rx //
-// ------------ //
-
-#define sdio_data_rx_wrap_target 0
-#define sdio_data_rx_wrap 4
-
-static const uint16_t sdio_data_rx_program_instructions[] = {
-            //     .wrap_target
-    0xa022, //  0: mov    x, y                       
-    0x2020, //  1: wait   0 pin, 0                   
-    0x248A, //  2: wait   1 gpio, 10             [4] 
-    0x4304, //  3: in     pins, 4                [3] 
-    0x0043, //  4: jmp    x--, 3                     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_rx_program = {
-    .instructions = sdio_data_rx_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_rx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_rx_wrap_target, offset + sdio_data_rx_wrap);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_tx //
-// ------------ //
-
-#define sdio_data_tx_wrap_target 5
-#define sdio_data_tx_wrap 8
-
-static const uint16_t sdio_data_tx_program_instructions[] = {
-    0x200A, //  0: wait   0 gpio, 10                 
-    0x258A, //  1: wait   1 gpio, 10             [5] 
-    0x6204, //  2: out    pins, 4                [2] 
-    0x0142, //  3: jmp    x--, 2                 [1] 
-    0xe280, //  4: set    pindirs, 0             [2] 
-            //     .wrap_target
-    0x4101, //  5: in     pins, 1                [1] 
-    0x0285, //  6: jmp    y--, 5                 [2] 
-    0x21a0, //  7: wait   1 pin, 0               [1] 
-    0x8220, //  8: push   block                  [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_tx_program = {
-    .instructions = sdio_data_tx_program_instructions,
-    .length = 9,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_tx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_tx_wrap_target, offset + sdio_data_tx_wrap);
-    return c;
-}
-#endif
-

+ 0 - 164
lib/ZuluSCSI_platform_RP2MCU/sdio_Pico_2.pio

@@ -1,164 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-; RP2040 PIO program for implementing SD card access in SDIO mode
-; Run "pioasm rp2040_sdio.pio rp2040_sdio.pio.h" to regenerate the C header from this.
-
-; The RP2040 official work-in-progress code at
-; https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sd_card
-; may be useful reference, but this is independent implementation.
-;
-; For official SDIO specifications, refer to:
-; https://www.sdcard.org/downloads/pls/
-; "SDIO Physical Layer Simplified Specification Version 8.00"
-
-; Clock settings
-; For 3.3V communication the available speeds are:
-; - Default speed: max. 25 MHz clock
-; - High speed:    max. 50 MHz clock
-;
-; From the default RP2040 clock speed of 125 MHz, the closest dividers
-; are 3 for 41.7 MHz and 5 for 25 MHz. The CPU can apply further divider
-; through state machine registers for the initial handshake.
-;
-; Because data is written on the falling edge and read on the rising
-; edge, it is preferrable to have a long 0 state and short 1 state.
-;.define CLKDIV 3
-.define CLKDIV 5
-.define D0 ((CLKDIV + 1) / 2 - 1)
-.define D1 (CLKDIV/2 - 1)
-.define SDIO_CLK_GPIO 10
-
-; State machine 0 is used to:
-; - generate continuous clock on SDIO_CLK
-; - send CMD packets
-; - receive response packets
-;
-; Pin mapping for this state machine:
-; - Sideset    : CLK
-; - IN/OUT/SET : CMD
-; - JMP_PIN    : CMD
-;
-; The commands to send are put on TX fifo and must have two words:
-; Word 0 bits 31-24: Number of bits in command minus one (usually 47)
-; Word 0 bits 23-00: First 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 31-08: Last 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 07-00: Number of bits in response minus one (usually 47), or 0 if no response
-;
-; The response is put on RX fifo, starting with the MSB.
-; Partial last word will be padded with zero bits at the top.
-;
-; The state machine EXECCTRL should be set so that STATUS indicates TX FIFO < 2
-; and that AUTOPULL and AUTOPUSH are enabled.
-
-.program sdio_cmd_clk
-    .side_set 1
-
-    mov OSR, NULL       side 1 [D1]    ; Make sure OSR is full of zeros to prevent autopull
-
-wait_cmd:
-    mov Y, !STATUS      side 0 [D0]    ; Check if TX FIFO has data
-    jmp !Y wait_cmd     side 1 [D1]
-
-load_cmd:
-    out NULL, 32        side 0 [D0]    ; Load first word (trigger autopull)
-    out X, 8            side 1 [D1]    ; Number of bits to send
-    set pins, 1         side 0 [D0]    ; Initial state of CMD is high
-    set pindirs, 1      side 1 [D1]    ; Set SDIO_CMD as output
-
-send_cmd:
-    out pins, 1         side 0 [D0]    ; Write output on falling edge of CLK
-    jmp X-- send_cmd    side 1 [D1]
-
-prep_resp:
-    set pindirs, 0      side 0 [D0]    ; Set SDIO_CMD as input
-    out X, 8            side 1 [D1]    ; Get number of bits in response
-    nop                 side 0 [D0]    ; For clock alignment
-    jmp !X resp_done    side 1 [D1]    ; Check if we expect a response
-
-wait_resp:
-    nop                  side 0 [D0]
-    jmp PIN wait_resp    side 1 [D1]    ; Loop until SDIO_CMD = 0
-
-    ; Note: input bits are read at the same time as we write CLK=0.
-    ; Because the host controls the clock, the read happens before
-    ; the card sees the falling clock edge. This gives maximum time
-    ; for the data bit to settle.
-read_resp:
-    in PINS, 1          side 0 [D0]    ; Read input data bit
-    jmp X-- read_resp   side 1 [D1]    ; Loop to receive all data bits
-
-resp_done:
-    push                side 0 [D0]    ; Push the remaining part of response
-
-; State machine 1 is used to send and receive data blocks.
-; Pin mapping for this state machine:
-; - IN / OUT: SDIO_D0-D3
-; - GPIO defined at beginning of this file: SDIO_CLK
-
-; Data reception program
-; This program will wait for initial start of block token and then
-; receive a data block. The application must set number of nibbles
-; to receive minus 1 to Y register before running this program.
-.program sdio_data_rx
-
-wait_start:
-    mov X, Y                               ; Reinitialize number of nibbles to receive
-    wait 0 pin 0                           ; Wait for zero state on D0
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV-1]  ; Wait for rising edge and then whole clock cycle
-
-rx_data:
-    in PINS, 4                 [CLKDIV-2]  ; Read nibble
-    jmp X--, rx_data
-
-; Data transmission program
-;
-; Before running this program, pindirs should be set as output
-; and register X should be initialized with the number of nibbles
-; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
-; and register Y with the number of response bits minus 1 (typically 31).
-;
-; Words written to TX FIFO must be:
-; - Word 0: start token 0xFFFFFFF0
-; - Word 1-128: transmitted data (512 bytes)
-; - Word 129-130: CRC checksum
-; - Word 131: end token 0xFFFFFFFF
-;
-; After the card reports idle status, RX FIFO will get a word that
-; contains the D0 line response from card.
-
-.program sdio_data_tx
-    wait 0 gpio SDIO_CLK_GPIO  
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV + D1 - 1]; Synchronize so that write occurs on falling edge
-
-tx_loop:
-    out PINS, 4                [D0]    ; Write nibble and wait for whole clock cycle
-    jmp X-- tx_loop            [D1]
-
-    set pindirs, 0x00          [D0]    ; Set data bus as input
-
-.wrap_target
-response_loop:
-    in PINS, 1                 [D1]    ; Read D0 on rising edge
-    jmp Y--, response_loop     [D0]
-
-wait_idle:
-    wait 1 pin 0               [D1]    ; Wait for card to indicate idle condition
-    push                       [D0]    ; Push the response token
-.wrap

+ 0 - 121
lib/ZuluSCSI_platform_RP2MCU/sdio_Pico_2.pio.h

@@ -1,121 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ------------ //
-// sdio_cmd_clk //
-// ------------ //
-
-#define sdio_cmd_clk_wrap_target 0
-#define sdio_cmd_clk_wrap 17
-
-static const uint16_t sdio_cmd_clk_program_instructions[] = {
-            //     .wrap_target
-    0xb1e3, //  0: mov    osr, null       side 1 [1] 
-    0xa24d, //  1: mov    y, !status      side 0 [2] 
-    0x1161, //  2: jmp    !y, 1           side 1 [1] 
-    0x6260, //  3: out    null, 32        side 0 [2] 
-    0x7128, //  4: out    x, 8            side 1 [1] 
-    0xe201, //  5: set    pins, 1         side 0 [2] 
-    0xf181, //  6: set    pindirs, 1      side 1 [1] 
-    0x6201, //  7: out    pins, 1         side 0 [2] 
-    0x1147, //  8: jmp    x--, 7          side 1 [1] 
-    0xe280, //  9: set    pindirs, 0      side 0 [2] 
-    0x7128, // 10: out    x, 8            side 1 [1] 
-    0xa242, // 11: nop                    side 0 [2] 
-    0x1131, // 12: jmp    !x, 17          side 1 [1] 
-    0xa242, // 13: nop                    side 0 [2] 
-    0x11cd, // 14: jmp    pin, 13         side 1 [1] 
-    0x4201, // 15: in     pins, 1         side 0 [2] 
-    0x114f, // 16: jmp    x--, 15         side 1 [1] 
-    0x8220, // 17: push   block           side 0 [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_cmd_clk_program = {
-    .instructions = sdio_cmd_clk_program_instructions,
-    .length = 18,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_cmd_clk_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_cmd_clk_wrap_target, offset + sdio_cmd_clk_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_rx //
-// ------------ //
-
-#define sdio_data_rx_wrap_target 0
-#define sdio_data_rx_wrap 4
-
-static const uint16_t sdio_data_rx_program_instructions[] = {
-            //     .wrap_target
-    0xa022, //  0: mov    x, y                       
-    0x2020, //  1: wait   0 pin, 0                   
-    0x248A, //  2: wait   1 gpio, 10             [4] 
-    0x4304, //  3: in     pins, 4                [3] 
-    0x0043, //  4: jmp    x--, 3                     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_rx_program = {
-    .instructions = sdio_data_rx_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_rx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_rx_wrap_target, offset + sdio_data_rx_wrap);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_tx //
-// ------------ //
-
-#define sdio_data_tx_wrap_target 5
-#define sdio_data_tx_wrap 8
-
-static const uint16_t sdio_data_tx_program_instructions[] = {
-    0x200A, //  0: wait   0 gpio, 10                 
-    0x258A, //  1: wait   1 gpio, 10             [5] 
-    0x6204, //  2: out    pins, 4                [2] 
-    0x0142, //  3: jmp    x--, 2                 [1] 
-    0xe280, //  4: set    pindirs, 0             [2] 
-            //     .wrap_target
-    0x4101, //  5: in     pins, 1                [1] 
-    0x0285, //  6: jmp    y--, 5                 [2] 
-    0x21a0, //  7: wait   1 pin, 0               [1] 
-    0x8220, //  8: push   block                  [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_tx_program = {
-    .instructions = sdio_data_tx_program_instructions,
-    .length = 9,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_tx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_tx_wrap_target, offset + sdio_data_tx_wrap);
-    return c;
-}
-#endif
-

+ 0 - 164
lib/ZuluSCSI_platform_RP2MCU/sdio_RP2350A.pio

@@ -1,164 +0,0 @@
-; ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
-; 
-; ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
-; 
-; https://www.gnu.org/licenses/gpl-3.0.html
-; ----
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version. 
-; 
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-; GNU General Public License for more details. 
-; 
-; You should have received a copy of the GNU General Public License
-; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-; RP2040 PIO program for implementing SD card access in SDIO mode
-; Run "pioasm rp2040_sdio.pio rp2040_sdio.pio.h" to regenerate the C header from this.
-
-; The RP2040 official work-in-progress code at
-; https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sd_card
-; may be useful reference, but this is independent implementation.
-;
-; For official SDIO specifications, refer to:
-; https://www.sdcard.org/downloads/pls/
-; "SDIO Physical Layer Simplified Specification Version 8.00"
-
-; Clock settings
-; For 3.3V communication the available speeds are:
-; - Default speed: max. 25 MHz clock
-; - High speed:    max. 50 MHz clock
-;
-; From the default RP2040 clock speed of 125 MHz, the closest dividers
-; are 3 for 41.7 MHz and 5 for 25 MHz. The CPU can apply further divider
-; through state machine registers for the initial handshake.
-;
-; Because data is written on the falling edge and read on the rising
-; edge, it is preferrable to have a long 0 state and short 1 state.
-;.define CLKDIV 3
-.define CLKDIV 5
-.define D0 ((CLKDIV + 1) / 2 - 1)
-.define D1 (CLKDIV/2 - 1)
-.define SDIO_CLK_GPIO 18
-
-; State machine 0 is used to:
-; - generate continuous clock on SDIO_CLK
-; - send CMD packets
-; - receive response packets
-;
-; Pin mapping for this state machine:
-; - Sideset    : CLK
-; - IN/OUT/SET : CMD
-; - JMP_PIN    : CMD
-;
-; The commands to send are put on TX fifo and must have two words:
-; Word 0 bits 31-24: Number of bits in command minus one (usually 47)
-; Word 0 bits 23-00: First 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 31-08: Last 24 bits of the command packet, shifted out MSB first
-; Word 1 bits 07-00: Number of bits in response minus one (usually 47), or 0 if no response
-;
-; The response is put on RX fifo, starting with the MSB.
-; Partial last word will be padded with zero bits at the top.
-;
-; The state machine EXECCTRL should be set so that STATUS indicates TX FIFO < 2
-; and that AUTOPULL and AUTOPUSH are enabled.
-
-.program sdio_cmd_clk
-    .side_set 1
-
-    mov OSR, NULL       side 1 [D1]    ; Make sure OSR is full of zeros to prevent autopull
-
-wait_cmd:
-    mov Y, !STATUS      side 0 [D0]    ; Check if TX FIFO has data
-    jmp !Y wait_cmd     side 1 [D1]
-
-load_cmd:
-    out NULL, 32        side 0 [D0]    ; Load first word (trigger autopull)
-    out X, 8            side 1 [D1]    ; Number of bits to send
-    set pins, 1         side 0 [D0]    ; Initial state of CMD is high
-    set pindirs, 1      side 1 [D1]    ; Set SDIO_CMD as output
-
-send_cmd:
-    out pins, 1         side 0 [D0]    ; Write output on falling edge of CLK
-    jmp X-- send_cmd    side 1 [D1]
-
-prep_resp:
-    set pindirs, 0      side 0 [D0]    ; Set SDIO_CMD as input
-    out X, 8            side 1 [D1]    ; Get number of bits in response
-    nop                 side 0 [D0]    ; For clock alignment
-    jmp !X resp_done    side 1 [D1]    ; Check if we expect a response
-
-wait_resp:
-    nop                  side 0 [D0]
-    jmp PIN wait_resp    side 1 [D1]    ; Loop until SDIO_CMD = 0
-
-    ; Note: input bits are read at the same time as we write CLK=0.
-    ; Because the host controls the clock, the read happens before
-    ; the card sees the falling clock edge. This gives maximum time
-    ; for the data bit to settle.
-read_resp:
-    in PINS, 1          side 0 [D0]    ; Read input data bit
-    jmp X-- read_resp   side 1 [D1]    ; Loop to receive all data bits
-
-resp_done:
-    push                side 0 [D0]    ; Push the remaining part of response
-
-; State machine 1 is used to send and receive data blocks.
-; Pin mapping for this state machine:
-; - IN / OUT: SDIO_D0-D3
-; - GPIO defined at beginning of this file: SDIO_CLK
-
-; Data reception program
-; This program will wait for initial start of block token and then
-; receive a data block. The application must set number of nibbles
-; to receive minus 1 to Y register before running this program.
-.program sdio_data_rx
-
-wait_start:
-    mov X, Y                               ; Reinitialize number of nibbles to receive
-    wait 0 pin 0                           ; Wait for zero state on D0
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV-1]  ; Wait for rising edge and then whole clock cycle
-
-rx_data:
-    in PINS, 4                 [CLKDIV-2]  ; Read nibble
-    jmp X--, rx_data
-
-; Data transmission program
-;
-; Before running this program, pindirs should be set as output
-; and register X should be initialized with the number of nibbles
-; to send minus 1 (typically 8 + 1024 + 16 + 1 - 1 = 1048)
-; and register Y with the number of response bits minus 1 (typically 31).
-;
-; Words written to TX FIFO must be:
-; - Word 0: start token 0xFFFFFFF0
-; - Word 1-128: transmitted data (512 bytes)
-; - Word 129-130: CRC checksum
-; - Word 131: end token 0xFFFFFFFF
-;
-; After the card reports idle status, RX FIFO will get a word that
-; contains the D0 line response from card.
-
-.program sdio_data_tx
-    wait 0 gpio SDIO_CLK_GPIO  
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV + D1 - 1]; Synchronize so that write occurs on falling edge
-
-tx_loop:
-    out PINS, 4                [D0]    ; Write nibble and wait for whole clock cycle
-    jmp X-- tx_loop            [D1]
-
-    set pindirs, 0x00          [D0]    ; Set data bus as input
-
-.wrap_target
-response_loop:
-    in PINS, 1                 [D1]    ; Read D0 on rising edge
-    jmp Y--, response_loop     [D0]
-
-wait_idle:
-    wait 1 pin 0               [D1]    ; Wait for card to indicate idle condition
-    push                       [D0]    ; Push the response token
-.wrap

+ 0 - 121
lib/ZuluSCSI_platform_RP2MCU/sdio_RP2350A.pio.h

@@ -1,121 +0,0 @@
-// -------------------------------------------------- //
-// This file is autogenerated by pioasm; do not edit! //
-// -------------------------------------------------- //
-
-#pragma once
-
-#if !PICO_NO_HARDWARE
-#include "hardware/pio.h"
-#endif
-
-// ------------ //
-// sdio_cmd_clk //
-// ------------ //
-
-#define sdio_cmd_clk_wrap_target 0
-#define sdio_cmd_clk_wrap 17
-
-static const uint16_t sdio_cmd_clk_program_instructions[] = {
-            //     .wrap_target
-    0xb1e3, //  0: mov    osr, null       side 1 [1] 
-    0xa24d, //  1: mov    y, !status      side 0 [2] 
-    0x1161, //  2: jmp    !y, 1           side 1 [1] 
-    0x6260, //  3: out    null, 32        side 0 [2] 
-    0x7128, //  4: out    x, 8            side 1 [1] 
-    0xe201, //  5: set    pins, 1         side 0 [2] 
-    0xf181, //  6: set    pindirs, 1      side 1 [1] 
-    0x6201, //  7: out    pins, 1         side 0 [2] 
-    0x1147, //  8: jmp    x--, 7          side 1 [1] 
-    0xe280, //  9: set    pindirs, 0      side 0 [2] 
-    0x7128, // 10: out    x, 8            side 1 [1] 
-    0xa242, // 11: nop                    side 0 [2] 
-    0x1131, // 12: jmp    !x, 17          side 1 [1] 
-    0xa242, // 13: nop                    side 0 [2] 
-    0x11cd, // 14: jmp    pin, 13         side 1 [1] 
-    0x4201, // 15: in     pins, 1         side 0 [2] 
-    0x114f, // 16: jmp    x--, 15         side 1 [1] 
-    0x8220, // 17: push   block           side 0 [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_cmd_clk_program = {
-    .instructions = sdio_cmd_clk_program_instructions,
-    .length = 18,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_cmd_clk_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_cmd_clk_wrap_target, offset + sdio_cmd_clk_wrap);
-    sm_config_set_sideset(&c, 1, false, false);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_rx //
-// ------------ //
-
-#define sdio_data_rx_wrap_target 0
-#define sdio_data_rx_wrap 4
-
-static const uint16_t sdio_data_rx_program_instructions[] = {
-            //     .wrap_target
-    0xa022, //  0: mov    x, y                       
-    0x2020, //  1: wait   0 pin, 0                   
-    0x2492, //  2: wait   1 gpio, 18             [4] 
-    0x4304, //  3: in     pins, 4                [3] 
-    0x0043, //  4: jmp    x--, 3                     
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_rx_program = {
-    .instructions = sdio_data_rx_program_instructions,
-    .length = 5,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_rx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_rx_wrap_target, offset + sdio_data_rx_wrap);
-    return c;
-}
-#endif
-
-// ------------ //
-// sdio_data_tx //
-// ------------ //
-
-#define sdio_data_tx_wrap_target 5
-#define sdio_data_tx_wrap 8
-
-static const uint16_t sdio_data_tx_program_instructions[] = {
-    0x2012, //  0: wait   0 gpio, 18                 
-    0x2592, //  1: wait   1 gpio, 18             [5] 
-    0x6204, //  2: out    pins, 4                [2] 
-    0x0142, //  3: jmp    x--, 2                 [1] 
-    0xe280, //  4: set    pindirs, 0             [2] 
-            //     .wrap_target
-    0x4101, //  5: in     pins, 1                [1] 
-    0x0285, //  6: jmp    y--, 5                 [2] 
-    0x21a0, //  7: wait   1 pin, 0               [1] 
-    0x8220, //  8: push   block                  [2] 
-            //     .wrap
-};
-
-#if !PICO_NO_HARDWARE
-static const struct pio_program sdio_data_tx_program = {
-    .instructions = sdio_data_tx_program_instructions,
-    .length = 9,
-    .origin = -1,
-};
-
-static inline pio_sm_config sdio_data_tx_program_get_default_config(uint offset) {
-    pio_sm_config c = pio_get_default_sm_config();
-    sm_config_set_wrap(&c, offset + sdio_data_tx_wrap_target, offset + sdio_data_tx_wrap);
-    return c;
-}
-#endif
-

+ 30 - 29
lib/ZuluSCSI_platform_RP2MCU/sdio_RP2040.pio → lib/ZuluSCSI_platform_RP2MCU/sdio_RP2MCU.pio

@@ -40,6 +40,7 @@
 ; Because data is written on the falling edge and read on the rising
 ; edge, it is preferrable to have a long 0 state and short 1 state.
 ;.define CLKDIV 3
+; all Dummy values, to be recoded by C pico-sdk functions
 .define CLKDIV 5
 .define D0 ((CLKDIV + 1) / 2 - 1)
 .define D1 (CLKDIV/2 - 1)
@@ -70,42 +71,42 @@
 .program sdio_cmd_clk
     .side_set 1
 
-    mov OSR, NULL       side 1 [D1]    ; Make sure OSR is full of zeros to prevent autopull
+    mov OSR, NULL       side 1 [0] ;[D1]    ; Make sure OSR is full of zeros to prevent autopull
 
 wait_cmd:
-    mov Y, !STATUS      side 0 [D0]    ; Check if TX FIFO has data
-    jmp !Y wait_cmd     side 1 [D1]
+    mov Y, !STATUS      side 0 [0]; [D0]    ; Check if TX FIFO has data
+    jmp !Y wait_cmd     side 1 [0]; [D1]
 
 load_cmd:
-    out NULL, 32        side 0 [D0]    ; Load first word (trigger autopull)
-    out X, 8            side 1 [D1]    ; Number of bits to send
-    set pins, 1         side 0 [D0]    ; Initial state of CMD is high
-    set pindirs, 1      side 1 [D1]    ; Set SDIO_CMD as output
+    out NULL, 32        side 0 [0]; [D0]    ; Load first word (trigger autopull)
+    out X, 8            side 1 [0]; [D1]    ; Number of bits to send
+    set pins, 1         side 0 [0]; [D0]    ; Initial state of CMD is high
+    set pindirs, 1      side 1 [0]; [D1]    ; Set SDIO_CMD as output
 
 send_cmd:
-    out pins, 1         side 0 [D0]    ; Write output on falling edge of CLK
-    jmp X-- send_cmd    side 1 [D1]
+    out pins, 1         side 0 [0]; [D0]    ; Write output on falling edge of CLK
+    jmp X-- send_cmd    side 1 [0]; [D1]
 
 prep_resp:
-    set pindirs, 0      side 0 [D0]    ; Set SDIO_CMD as input
-    out X, 8            side 1 [D1]    ; Get number of bits in response
-    nop                 side 0 [D0]    ; For clock alignment
-    jmp !X resp_done    side 1 [D1]    ; Check if we expect a response
+    set pindirs, 0      side 0 [0]; [D0]    ; Set SDIO_CMD as input
+    out X, 8            side 1 [0]; [D1]    ; Get number of bits in response
+    nop                 side 0 [0]; [D0]    ; For clock alignment
+    jmp !X resp_done    side 1 [0]; [D1]    ; Check if we expect a response
 
 wait_resp:
-    nop                  side 0 [D0]
-    jmp PIN wait_resp    side 1 [D1]    ; Loop until SDIO_CMD = 0
+    nop                  side 0 [0]; [D0]
+    jmp PIN wait_resp    side 1 [0]; [D1]    ; Loop until SDIO_CMD = 0
 
     ; Note: input bits are read at the same time as we write CLK=0.
     ; Because the host controls the clock, the read happens before
     ; the card sees the falling clock edge. This gives maximum time
     ; for the data bit to settle.
 read_resp:
-    in PINS, 1          side 0 [D0]    ; Read input data bit
-    jmp X-- read_resp   side 1 [D1]    ; Loop to receive all data bits
+    in PINS, 1          side 0 [0]; [D0]    ; Read input data bit
+    jmp X-- read_resp   side 1 [0]; [D1]    ; Loop to receive all data bits
 
 resp_done:
-    push                side 0 [D0]    ; Push the remaining part of response
+    push                side 0 [0]; [D0]    ; Push the remaining part of response
 
 ; State machine 1 is used to send and receive data blocks.
 ; Pin mapping for this state machine:
@@ -121,10 +122,10 @@ resp_done:
 wait_start:
     mov X, Y                               ; Reinitialize number of nibbles to receive
     wait 0 pin 0                           ; Wait for zero state on D0
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV-1]  ; Wait for rising edge and then whole clock cycle
+    wait 1 gpio SDIO_CLK_GPIO  [0]; [CLKDIV-1]  ; Wait for rising edge and then whole clock cycle
 
 rx_data:
-    in PINS, 4                 [CLKDIV-2]  ; Read nibble
+    in PINS, 4                 [0]; [CLKDIV-2]  ; Read nibble
     jmp X--, rx_data
 
 ; Data transmission program
@@ -145,20 +146,20 @@ rx_data:
 
 .program sdio_data_tx
     wait 0 gpio SDIO_CLK_GPIO  
-    wait 1 gpio SDIO_CLK_GPIO  [CLKDIV + D1 - 1]; Synchronize so that write occurs on falling edge
+    wait 1 gpio SDIO_CLK_GPIO  [0]; [CLKDIV + D1 - 1]; Synchronize so that write occurs on falling edge
 
 tx_loop:
-    out PINS, 4                [D0]    ; Write nibble and wait for whole clock cycle
-    jmp X-- tx_loop            [D1]
+    out PINS, 4                [0]; [D0]    ; Write nibble and wait for whole clock cycle
+    jmp X-- tx_loop            [0]; [D1]
 
-    set pindirs, 0x00          [D0]    ; Set data bus as input
+    set pindirs, 0x00          [0]; [D0]    ; Set data bus as input
 
 .wrap_target
 response_loop:
-    in PINS, 1                 [D1]    ; Read D0 on rising edge
-    jmp Y--, response_loop     [D0]
-
+    in PINS, 1                 [0]; [D1]    ; Read D0 on rising edge
+    jmp Y--, response_loop     [0]; [D0]
+    
 wait_idle:
-    wait 1 pin 0               [D1]    ; Wait for card to indicate idle condition
-    push                       [D0]    ; Push the response token
+    wait 1 pin 0               [0]; [D1]    ; Wait for card to indicate idle condition
+    push                       [0]; [D0]    ; Push the response token
 .wrap

+ 28 - 29
lib/ZuluSCSI_platform_RP2MCU/sdio_RP2040.pio.h → lib/ZuluSCSI_platform_RP2MCU/sdio_RP2MCU.pio.h

@@ -17,24 +17,24 @@
 
 static const uint16_t sdio_cmd_clk_program_instructions[] = {
             //     .wrap_target
-    0xb1e3, //  0: mov    osr, null       side 1 [1] 
-    0xa24d, //  1: mov    y, !status      side 0 [2] 
-    0x1161, //  2: jmp    !y, 1           side 1 [1] 
-    0x6260, //  3: out    null, 32        side 0 [2] 
-    0x7128, //  4: out    x, 8            side 1 [1] 
-    0xe201, //  5: set    pins, 1         side 0 [2] 
-    0xf181, //  6: set    pindirs, 1      side 1 [1] 
-    0x6201, //  7: out    pins, 1         side 0 [2] 
-    0x1147, //  8: jmp    x--, 7          side 1 [1] 
-    0xe280, //  9: set    pindirs, 0      side 0 [2] 
-    0x7128, // 10: out    x, 8            side 1 [1] 
-    0xa242, // 11: nop                    side 0 [2] 
-    0x1131, // 12: jmp    !x, 17          side 1 [1] 
-    0xa242, // 13: nop                    side 0 [2] 
-    0x11cd, // 14: jmp    pin, 13         side 1 [1] 
-    0x4201, // 15: in     pins, 1         side 0 [2] 
-    0x114f, // 16: jmp    x--, 15         side 1 [1] 
-    0x8220, // 17: push   block           side 0 [2] 
+    0xb0e3, //  0: mov    osr, null       side 1     
+    0xa04d, //  1: mov    y, !status      side 0     
+    0x1061, //  2: jmp    !y, 1           side 1     
+    0x6060, //  3: out    null, 32        side 0     
+    0x7028, //  4: out    x, 8            side 1     
+    0xe001, //  5: set    pins, 1         side 0     
+    0xf081, //  6: set    pindirs, 1      side 1     
+    0x6001, //  7: out    pins, 1         side 0     
+    0x1047, //  8: jmp    x--, 7          side 1     
+    0xe080, //  9: set    pindirs, 0      side 0     
+    0x7028, // 10: out    x, 8            side 1     
+    0xa042, // 11: nop                    side 0     
+    0x1031, // 12: jmp    !x, 17          side 1     
+    0xa042, // 13: nop                    side 0     
+    0x10cd, // 14: jmp    pin, 13         side 1     
+    0x4001, // 15: in     pins, 1         side 0     
+    0x104f, // 16: jmp    x--, 15         side 1     
+    0x8020, // 17: push   block           side 0     
             //     .wrap
 };
 
@@ -64,8 +64,8 @@ static const uint16_t sdio_data_rx_program_instructions[] = {
             //     .wrap_target
     0xa022, //  0: mov    x, y                       
     0x2020, //  1: wait   0 pin, 0                   
-    0x2492, //  2: wait   1 gpio, 18             [4] 
-    0x4304, //  3: in     pins, 4                [3] 
+    0x2092, //  2: wait   1 gpio, 18                 
+    0x4004, //  3: in     pins, 4                    
     0x0043, //  4: jmp    x--, 3                     
             //     .wrap
 };
@@ -93,15 +93,15 @@ static inline pio_sm_config sdio_data_rx_program_get_default_config(uint offset)
 
 static const uint16_t sdio_data_tx_program_instructions[] = {
     0x2012, //  0: wait   0 gpio, 18                 
-    0x2592, //  1: wait   1 gpio, 18             [5] 
-    0x6204, //  2: out    pins, 4                [2] 
-    0x0142, //  3: jmp    x--, 2                 [1] 
-    0xe280, //  4: set    pindirs, 0             [2] 
+    0x2092, //  1: wait   1 gpio, 18                 
+    0x6004, //  2: out    pins, 4                    
+    0x0042, //  3: jmp    x--, 2                     
+    0xe080, //  4: set    pindirs, 0                 
             //     .wrap_target
-    0x4101, //  5: in     pins, 1                [1] 
-    0x0285, //  6: jmp    y--, 5                 [2] 
-    0x21a0, //  7: wait   1 pin, 0               [1] 
-    0x8220, //  8: push   block                  [2] 
+    0x4001, //  5: in     pins, 1                    
+    0x0085, //  6: jmp    y--, 5                     
+    0x20a0, //  7: wait   1 pin, 0                   
+    0x8020, //  8: push   block                      
             //     .wrap
 };
 
@@ -118,4 +118,3 @@ static inline pio_sm_config sdio_data_tx_program_get_default_config(uint offset)
     return c;
 }
 #endif
-

+ 333 - 0
lib/ZuluSCSI_platform_RP2MCU/timings_RP2MCU.c

@@ -0,0 +1,333 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#include "timings_RP2MCU.h"
+#include <string.h>
+#include "timings.h"
+
+
+static zuluscsi_timings_t  predefined_timings[]  = {
+    {
+        .clk_hz = 125000000,
+
+        .pll =
+        {
+            .refdiv = 1,
+            .vco_freq = 1500000000,
+            .post_div1 = 6,
+            .post_div2 = 2
+        },
+
+        .scsi =
+        {
+            .req_delay = 7,
+            .clk_period_ps = 8000
+        },
+
+        .scsi_20 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+
+        },
+
+        .scsi_10 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+        },
+
+        .scsi_5 =
+        {
+            .delay0 = 10 - 1,
+            .delay1 = 15 - 1,
+            .total_delay_adjust = -1,
+            .max_sync = 50,
+        },
+
+        .sdio =
+        {
+            .clk_div_1mhz = 25, // = 125MHz clk / clk_div_pio
+            .clk_div_pio = 5,
+            .delay0 = 3 - 1, // subtract one for the instruction delay
+            .delay1 = 2 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+    },
+    {
+        .clk_hz = 133000000,
+
+        .pll =
+        {
+            .refdiv = 1,
+            .vco_freq = 1596000000,
+            .post_div1 = 6,
+            .post_div2 = 2
+        },
+
+        .scsi =
+        {
+            .req_delay = 7,
+            .clk_period_ps = 7519
+        },
+
+        .scsi_20 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+
+        },
+
+        .scsi_10 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+        },
+
+        .scsi_5 =
+        {
+            .delay0 = 10 - 1,
+            .delay1 = 15 - 1,
+            .total_delay_adjust = -1,
+            .max_sync = 50,
+        },
+
+        .sdio =
+        {
+            .clk_div_1mhz = 25,
+            .clk_div_pio = 5,
+            .delay0 = 3 - 1, // subtract one for the instruction delay
+            .delay1 = 2 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+    },
+    {
+        .clk_hz = 135428571,
+
+        .pll =
+        {
+            .refdiv = 1,
+            .vco_freq = 948000000,
+            .post_div1 = 7,
+            .post_div2 = 1
+        },
+
+        .scsi =
+        {
+            .req_delay = 7,
+            .clk_period_ps = 7384
+        },
+
+        .scsi_20 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+
+        },
+
+        .scsi_10 =
+        {
+            .delay0 = 4,
+            .delay1 = 6,
+            .total_delay_adjust = -1,
+            .max_sync = 25,
+        },
+
+        .scsi_5 =
+        {
+            .delay0 = 10 - 1,
+            .delay1 = 15 - 1,
+            .total_delay_adjust = -1,
+            .max_sync = 50,
+        },
+
+        .sdio =
+        {
+            .clk_div_1mhz = 27 , // = 135MHz clk / clk_div_pio
+            .clk_div_pio = 5,
+            .delay0 = 3 - 1, // subtract one for the instruction delay
+            .delay1 = 2 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+    },
+    {
+        .clk_hz = 150000000,
+
+        .pll =
+        {
+            .refdiv = 1,
+            .vco_freq = 1500000000,
+            .post_div1 = 5,
+            .post_div2 = 2
+        },
+
+        .scsi =
+        {
+            .req_delay = 9,
+            .clk_period_ps = 6667
+        },
+
+        .scsi_20 =
+        {
+            .delay0 = 3 - 1,
+            .delay1 = 4 - 1,
+            .total_delay_adjust = 0,
+            .max_sync = 18,
+
+        },
+
+        .scsi_10 =
+        {
+            .delay0 = 4 - 1,
+            .delay1 = 5 - 1,
+            .total_delay_adjust = 0,
+            .max_sync = 25,
+
+        },
+
+        .scsi_5 =
+        {
+            .delay0 = 10 - 1,
+            .delay1 = 15, // should be 18 - 1 but max currently is 15
+            .total_delay_adjust = 0,
+            .max_sync = 50,
+
+        },
+
+        .sdio =
+        {
+            .clk_div_1mhz = 30, // = 150MHz clk / clk_div_pio
+            .clk_div_pio = 5,
+            .delay0 = 3 - 1, // subtract one for the instruction delay
+            .delay1 = 2 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+    },
+    {
+        .clk_hz = 250000000,
+
+        .pll =
+        {
+            .refdiv = 1,
+            .vco_freq = 1500000000,
+            .post_div1 = 6,
+            .post_div2 = 1
+        },
+
+        .scsi =
+        {
+            .req_delay = 14,
+            .clk_period_ps = 4000,
+        },
+
+        .scsi_20 =
+        {
+            .delay0 = 3 - 1,
+            .delay1 = 5 - 1,
+            .total_delay_adjust = 1,
+            .max_sync = 12,
+
+        },
+
+        .scsi_10 =
+        {
+            .delay0 = 6 - 1,
+            .delay1 = 9 - 1,
+            .total_delay_adjust = 1,
+            .max_sync = 25,
+        },
+
+        .scsi_5 =
+        {
+            .delay0 = 15, // maxed out should be 16
+            .delay1 = 15, // maxed out should be 30
+            .total_delay_adjust = 1,
+            .max_sync = 50,
+        },
+#ifdef ZULUSCSI_PICO_2
+        .sdio =
+        {
+            .clk_div_1mhz = 30, // set by trail and error
+            .clk_div_pio = 6, // SDIO at 41.7MHz
+            .delay0 = 4 - 1, // subtract one for the instruction delay
+            .delay1 = 2 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+#else
+        .sdio =
+        {
+            .clk_div_1mhz = 50, // = 250MHz clk / clk_div_pio
+            .clk_div_pio = 5, // SDIO at 50MHz
+            .delay0 = 4 - 1, // subtract one for the instruction delay
+            .delay1 = 1 - 1  // clk_div_pio - delay0 and subtract one for the instruction delay
+        }
+
+#endif
+    },
+};
+    zuluscsi_timings_t  current_timings;
+
+#ifdef ENABLE_AUDIO_OUTPUT
+    zuluscsi_timings_t *g_zuluscsi_timings = &predefined_timings[2];
+#elif defined(ZULUSCSI_MCU_RP23XX)
+    zuluscsi_timings_t *g_zuluscsi_timings = &predefined_timings[3];
+#elif defined(ZULUSCSI_PICO)
+    zuluscsi_timings_t *g_zuluscsi_timings = &predefined_timings[1];
+#else
+    zuluscsi_timings_t *g_zuluscsi_timings = &predefined_timings[0];
+#endif
+
+
+bool set_timings(zuluscsi_speed_grade_t speed_grade)
+{
+    uint8_t timings_index;
+
+    switch (speed_grade)
+    {
+        case SPEED_GRADE_MAX:
+        case SPEED_GRADE_A:
+            timings_index = 4;
+            break;
+        case SPEED_GRADE_B:
+            timings_index = 3;
+            break;
+        case SPEED_GRADE_C:
+            timings_index  = 1;
+            break;
+        case SPEED_GRADE_AUDIO:
+            timings_index = 2;
+            break;
+    }   
+    if (speed_grade != SPEED_GRADE_DEFAULT && speed_grade != SPEED_GRADE_CUSTOM)
+    {
+        g_zuluscsi_timings = &current_timings;
+        memcpy(g_zuluscsi_timings, &predefined_timings[timings_index], sizeof(current_timings));
+        g_max_sync_10_period = g_zuluscsi_timings->scsi_10.max_sync;
+        g_max_sync_20_period = g_zuluscsi_timings->scsi_20.max_sync;
+        g_max_sync_5_period = g_zuluscsi_timings->scsi_5.max_sync;
+        return true;
+    }
+    return false;
+}

+ 108 - 0
lib/ZuluSCSI_platform_RP2MCU/timings_RP2MCU.h

@@ -0,0 +1,108 @@
+/**
+ * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+#ifndef ZULUSCSI_TIMINGS_RP2MCU_H
+#define ZULUSCSI_TIMINGS_RP2MCU_H
+#include <stdint.h>
+#include <stdbool.h>
+#include <ZuluSCSI_config.h>
+
+typedef struct
+{
+    uint32_t clk_hz;
+    struct
+    {
+        // These numbers are for pico-sdk's pll_init() function
+        // their values can be obtained using the script:
+        // "/src/rp2_common/hardware_clocks/scripts/vcocalc.py" 
+        uint8_t refdiv;
+        uint32_t vco_freq;
+        uint8_t post_div1;
+        uint8_t post_div2;
+    } pll;
+    struct
+    {
+        // Delay from data setup to REQ assertion.
+        // deskew delay + cable skew delay = 55 ns minimum
+        // One clock cycle is x ns => delay (55 / x) clocks
+        uint8_t req_delay;
+        // Period of the system clock in pico seconds
+        uint32_t clk_period_ps;
+    } scsi;
+
+
+    // delay0: Data Setup Time - Delay from data write to REQ assertion
+    // delay1  Transmit Assertion time from REQ assert to REQ deassert (req pulse) 
+    // delay2: Negation period - (total_delay - d0 - d1): total_delay spec is the sync value * 4 in ns width)
+    // both values are in clock cycles minus 1 for the pio instruction delay
+    // delay0 spec: Ultra(20):  11.5ns  Fast(10): 23ns  SCSI-1(5): 23ns
+    // delay1 spec: Ultra(20):  16.5ns  Fast(10): 33ns  SCSI-1(5): 53ns 
+    // delay2 spec: Ultra(20):  15ns    Fast(10): 30ns  SCSI-1(5): 80ns 
+    // total_delay_adjust is manual adjustment value, when checked with a scope
+    // Max sync - the minimum sync period ("max" clock rate) that is supported at this clock rate, the number is 1/4 the actual value in ns
+    struct
+    {
+        uint8_t delay0;
+        uint8_t delay1;
+        int16_t total_delay_adjust;
+        uint8_t max_sync;
+    } scsi_20;
+
+    struct
+    {
+        uint8_t delay0;
+        uint8_t delay1;
+        int16_t total_delay_adjust;
+        uint8_t max_sync;
+    } scsi_10;
+
+    struct
+    {
+        uint8_t delay0;
+        uint8_t delay1;
+        int16_t total_delay_adjust;
+        uint8_t max_sync;
+    } scsi_5;
+
+
+    struct
+    {
+        // System clock speed in MHz clk / clk_div_pio
+        uint8_t clk_div_1mhz;
+
+        // System clock speed / clk_div_pio <= 50MHz
+        // At 125Hz, the closest dividers 5 is used for 25 MHz for
+        // stability at that clock speed
+        // The CPU can apply further divider through state machine
+        // registers for the initial handshake.
+        uint8_t clk_div_pio;
+        // clk_div_pio = (delay0 + 1) + (delay1 + 1)
+        // delay1 should be shorter than delay0
+        uint8_t delay0; // subtract one for the instruction delay
+        uint8_t delay1; // clk_div_pio - delay0 and subtract one for the instruction delay
+    } sdio;
+
+} zuluscsi_timings_t;
+
+extern  zuluscsi_timings_t *g_zuluscsi_timings;
+
+// Sets timings to the speed_grade, returns false on SPEED_GRADE_DEFAULT and SPEED_GRADE_CUSTOM
+bool set_timings(zuluscsi_speed_grade_t speed_grade);
+#endif // ZULUSCSI_TIMINGS_RP2MCU_H

+ 84 - 57
src/ZuluSCSI.cpp

@@ -1,47 +1,47 @@
-/*  
+/*
  *  ZuluSCSI™
  *  Copyright (c) 2022-2024 Rabbit Hole Computing™
- * 
+ *
  * This project is based on BlueSCSI:
  *
  *  BlueSCSI
  *  Copyright (c) 2021  Eric Helgeson, Androda
- *  
+ *
  * This work incorporates work by following
  *  Copyright (c) 2023 joshua stein <jcs@jcs.org>
  *  Copyright (c) 2023 zigzagjoe
- * 
- *  This file is free software: you may copy, redistribute and/or modify it  
- *  under the terms of the GNU General Public License as published by the  
- *  Free Software Foundation, either version 2 of the License, or (at your  
- *  option) any later version.  
- *  
- *  This file is distributed in the hope that it will be useful, but  
- *  WITHOUT ANY WARRANTY; without even the implied warranty of  
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
- *  General Public License for more details.  
- *  
- *  You should have received a copy of the GNU General Public License  
- *  along with this program.  If not, see https://github.com/erichelgeson/bluescsi.  
- *  
- * This file incorporates work covered by the following copyright and  
- * permission notice:  
- *  
- *     Copyright (c) 2019 komatsu   
- *  
- *     Permission to use, copy, modify, and/or distribute this software  
- *     for any purpose with or without fee is hereby granted, provided  
- *     that the above copyright notice and this permission notice appear  
- *     in all copies.  
- *  
- *     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL  
- *     WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED  
- *     WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE  
- *     AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR  
- *     CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS  
- *     OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,  
- *     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN  
- *     CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  
+ *
+ *  This file is free software: you may copy, redistribute and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation, either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This file is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see https://github.com/erichelgeson/bluescsi.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ *     Copyright (c) 2019 komatsu
+ *
+ *     Permission to use, copy, modify, and/or distribute this software
+ *     for any purpose with or without fee is hereby granted, provided
+ *     that the above copyright notice and this permission notice appear
+ *     in all copies.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ *     WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ *     WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ *     AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ *     CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ *     OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ *     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ *     CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include <SdFat.h>
@@ -129,7 +129,7 @@ void save_logfile(bool always = false)
     {
       g_logfile.write(log_get_buffer(&prev_log_pos));
       g_logfile.flush();
-      
+
       prev_log_len = loglen;
       prev_log_save = millis();
     }
@@ -166,13 +166,13 @@ void print_sd_info()
   uint64_t size = (uint64_t)SD.vol()->clusterCount() * SD.vol()->bytesPerCluster();
   logmsg("SD card detected, FAT", (int)SD.vol()->fatType(),
           " volume size: ", (int)(size / 1024 / 1024), " MB");
-  
+
   cid_t sd_cid;
 
   if(SD.card()->readCID(&sd_cid))
   {
     logmsg("SD MID: ", (uint8_t)sd_cid.mid, ", OID: ", (uint8_t)sd_cid.oid[0], " ", (uint8_t)sd_cid.oid[1]);
-    
+
     char sdname[6] = {sd_cid.pnm[0], sd_cid.pnm[1], sd_cid.pnm[2], sd_cid.pnm[3], sd_cid.pnm[4], 0};
     logmsg("SD Name: ", sdname);
     logmsg("SD Date: ", (int)sd_cid.mdtMonth(), "/", sd_cid.mdtYear());
@@ -571,7 +571,7 @@ bool findHDDImages()
   for (int i = 0; i < NUM_SCSIID; i++)
   {
     const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
-    
+
     if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
     {
       int capacity_kB = ((uint64_t)cfg->scsiSectors * cfg->bytesPerSector) / 1024;
@@ -610,7 +610,7 @@ bool findHDDImages()
           }
         }
     }
-  } 
+  }
 
   if (removable_count == 1)
   {
@@ -619,8 +619,8 @@ bool findHDDImages()
       logmsg("Eject set to device with ID: ", last_removable_device);
     else if (eject_btn_set == 0)
     {
-      logmsg("Found 1 removable device, to set an eject button see EjectButton in the, '", CONFIGFILE,"', or the http://zuluscsi.com/manual");
-    } 
+      logmsg("Found 1 removable device, to set an eject button see EjectButton in the '", CONFIGFILE,"', or the http://zuluscsi.com/manual");
+    }
   }
   else if (removable_count > 1)
   {
@@ -642,7 +642,7 @@ bool findHDDImages()
     }
     else
     {
-      logmsg("Multiple removable devices, to set an eject button see EjectButton in the, '", CONFIGFILE,"', or the http://zuluscsi.com/manual");
+      logmsg("Multiple removable devices, to set an eject button see EjectButton in the '", CONFIGFILE,"', or the http://zuluscsi.com/manual");
     }
   }
   return foundImage;
@@ -750,19 +750,19 @@ static void reinitSCSI()
 
     logmsg("Direct/Raw mode enabled, using hardware switches for configuration");
     logmsg("-- SCSI ID set via DIP switch to ", (int) g_hw_config.scsi_id());
-    char raw_filename[32];  
-    uint32_t start =  g_scsi_settings.getDevice(scsiId)->sectorSDBegin; 
+    char raw_filename[32];
+    uint32_t start =  g_scsi_settings.getDevice(scsiId)->sectorSDBegin;
     uint32_t end = g_scsi_settings.getDevice(scsiId)->sectorSDEnd;
 
     if (start == end && end == 0)
     {
       strcpy(raw_filename, "RAW:0:0xFFFFFFFF");
-    } 
+    }
     else
     {
       snprintf(raw_filename, sizeof(raw_filename), "RAW:0x%X:0x%X", start, end);
     }
-    
+
     success = scsiDiskOpenHDDImage(scsiId, raw_filename, 0,
                                    g_hw_config.blocksize(), g_hw_config.device_type());
     if (success)
@@ -778,7 +778,7 @@ static void reinitSCSI()
   }
   else
 #endif // ZULUSCSI_HARDWARE_CONFIG
-  { 
+  {
     readSCSIDeviceConfig();
     findHDDImages();
 
@@ -814,7 +814,7 @@ static void reinitSCSI()
     platform_network_wifi_join(scsiDev.boardCfg.wifiSSID, scsiDev.boardCfg.wifiPassword);
   }
 #endif // ZULUSCSI_NETWORK
-  
+
 }
 // Place all the setup code that requires the SD card to be initialized here
 // Which is pretty much everything after platform_init and and platform_late_init
@@ -847,16 +847,42 @@ static void zuluscsi_setup_sd_card()
     } while (!g_sdcard_present);
     logmsg("SD card init succeeded after retry");
   }
-
+  
+  static const char sg_default[] = "Default"; 
   if (g_sdcard_present)
   {
+    char speed_grade_str[10];
+    ini_gets("SCSI", "SpeedGrade", sg_default, speed_grade_str, sizeof(speed_grade_str), CONFIGFILE);
+    zuluscsi_speed_grade_t grade = platform_string_to_speed_grade(speed_grade_str, sizeof(speed_grade_str));
+    if (grade != SPEED_GRADE_DEFAULT)
+    {
+      zuluscsi_reclock_status_t status = platform_reclock(grade);
+      switch (status)
+      {
+        case ZULUSCSI_RECLOCK_NOT_SUPPORTED:
+          logmsg("Reclocking this board is not supported");
+          break;
+        case ZULUSCSI_RECLOCK_FAILED:
+          logmsg("Reclocking failed");
+          break;
+        case ZULUSCSI_RECLOCK_SUCCESS:
+          logmsg("Reclocking was successful");
+          break;
+        case ZULUSCSI_RECLOCK_CUSTOM:
+          logmsg("Custom reclocking timings used");
+          break;
+      }
+      g_sdcard_present = mountSDCard();
+      reinitSCSI();
+    }
+
     if (SD.clusterCount() == 0)
     {
       logmsg("SD card without filesystem!");
     }
 
     print_sd_info();
-    
+
     char presetName[32];
     ini_gets("SCSI", "System", "", presetName, sizeof(presetName), CONFIGFILE);
     scsi_system_settings_t *cfg = g_scsi_settings.initSystem(presetName);
@@ -868,8 +894,8 @@ static void zuluscsi_setup_sd_card()
     }
     platform_post_sd_card_init();
     reinitSCSI();
-    
-    
+
+
     boot_delay_ms = cfg->initPostDelay;
     if (boot_delay_ms > 0)
     {
@@ -900,10 +926,11 @@ extern "C" void zuluscsi_setup(void)
 
 #ifdef PLATFORM_MASS_STORAGE
   static bool check_mass_storage = true;
-  if (check_mass_storage && g_scsi_settings.getSystem()->enableUSBMassStorage)
+  if ((check_mass_storage && g_scsi_settings.getSystem()->enableUSBMassStorage)
+      || platform_rebooted_into_mass_storage())
   {
     check_mass_storage = false;
-    
+
     // perform checks to see if a computer is attached and return true if we should enter MSC mode.
     if (platform_sense_msc())
     {
@@ -913,7 +940,7 @@ extern "C" void zuluscsi_setup(void)
     }
   }
 #endif
-
+  logmsg("Clock set to: ", (int) platform_sys_clock_in_hz(), "Hz");
   logmsg("Initialization complete!");
 }
 
@@ -978,7 +1005,7 @@ extern "C" void zuluscsi_main_loop(void)
   if (!g_sdcard_present)
   {
     // Try to remount SD card
-    do 
+    do
     {
       g_sdcard_present = mountSDCard();
 

+ 1 - 0
src/ZuluSCSI_cdrom.cpp

@@ -31,6 +31,7 @@
 #include "ZuluSCSI_cdrom.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
+#include "ZuluSCSI_platform.h"
 #include "ZuluSCSI_settings.h"
 #include <CUEParser.h>
 #include <assert.h>

+ 32 - 9
src/ZuluSCSI_config.h

@@ -1,21 +1,21 @@
-/** 
+/**
  * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
  * Portions copyright (c) 2023 joshua stein <jcs@jcs.org>
- * 
- * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
- * 
+ *
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version.
+ *
  * https://www.gnu.org/licenses/gpl-3.0.html
  * ----
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version. 
- * 
+ * (at your option) any later version.
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details. 
- * 
+ * GNU General Public License for more details.
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 **/
@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include <ZuluSCSI_platform.h>
+#include <ZuluSCSI_platform_config.h>
 
 // Use variables for version number
 #define FW_VER_NUM      "24.11.01"
@@ -124,3 +124,26 @@
 // Zip disk  media sizes
 #define ZIP100_DISK_SIZE    100663296 // bytes
 #define ZIP250_DISK_SIZE    250640384 // bytes
+
+// Settings for rebooting
+#define REBOOT_INTO_MASS_STORAGE_MAGIC_NUM 0x5eeded
+
+// Reclocking return status
+typedef enum
+{
+    ZULUSCSI_RECLOCK_SUCCESS,
+    ZULUSCSI_RECLOCK_CUSTOM,
+    ZULUSCSI_RECLOCK_NOT_SUPPORTED,
+    ZULUSCSI_RECLOCK_FAILED
+} zuluscsi_reclock_status_t;
+
+typedef enum
+{
+    SPEED_GRADE_DEFAULT,
+    SPEED_GRADE_MAX,
+    SPEED_GRADE_CUSTOM,
+    SPEED_GRADE_A,
+    SPEED_GRADE_B,
+    SPEED_GRADE_C,
+    SPEED_GRADE_AUDIO,
+} zuluscsi_speed_grade_t;

+ 2 - 0
src/ZuluSCSI_disk.cpp

@@ -1114,6 +1114,8 @@ void s2s_configInit(S2S_BoardCfg* config)
         config->scsiSpeed = S2S_CFG_SPEED_ASYNC_50;
     else if (maxSyncSpeed < 10 && config->scsiSpeed > S2S_CFG_SPEED_SYNC_5)
         config->scsiSpeed = S2S_CFG_SPEED_SYNC_5;
+    else if (maxSyncSpeed < 20 && config->scsiSpeed > S2S_CFG_SPEED_SYNC_10)
+        config->scsiSpeed = S2S_CFG_SPEED_SYNC_10;
 
     logmsg("-- SelectionDelay = ", (int)config->selectionDelay);
 

+ 2 - 1
src/ZuluSCSI_settings.cpp

@@ -26,6 +26,7 @@
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
 #include "ZuluSCSI_settings.h"
+#include "ZuluSCSI_platform.h"
 #include <strings.h>
 #include <minIni.h>
 #include <minIni_cache.h>
@@ -284,7 +285,7 @@ scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
     // Default settings for host compatibility 
     cfgSys.quirks = img.quirks;
     cfgSys.selectionDelay = 255;
-    cfgSys.maxSyncSpeed = 10;
+    cfgSys.maxSyncSpeed = PLATFORM_DEFAULT_SCSI_SPEED_SETTING;
     cfgSys.initPreDelay = 0;
     cfgSys.initPostDelay = 0;
     cfgSys.phyMode = 0;

+ 1 - 0
src/ZuluSCSI_tape.cpp

@@ -26,6 +26,7 @@
 #include "ZuluSCSI_disk.h"
 #include "ZuluSCSI_log.h"
 #include "ZuluSCSI_config.h"
+#include <ZuluSCSI_platform.h>
 
 extern "C" {
 #include <scsi.h>

+ 10 - 4
zuluscsi.ini

@@ -1,4 +1,5 @@
 
+# See http://zuluscsi.com/manual for more information about setting up your ZuluSCSI
 [SCSI]
 # Settings that apply to all SCSI IDs
 
@@ -26,10 +27,15 @@
 #EnableSelLatch = 0 # For Philips P2000C and other devices that release SEL signal before BSY
 #EnableParity = 1 # Enable parity checks on platforms that support it (RP2040)
 #MapLunsToIDs = 0 # For Philips P2000C simulate multiple LUNs
-#MaxSyncSpeed = 10 # Set to 5 or 10 to enable synchronous SCSI mode, 0 to disable
 #InitPreDelay = 0  # How many milliseconds to delay before the SCSI interface is initialized
 #InitPostDelay = 0 # How many milliseconds to delay after the SCSI interface is initialized
 
+# Will attempt to reclock the board if the board supports both reclocking and the choosen speed
+# SpeedGrade = Default # TurboMax - max speed, TurboA - mode A, TurboC, etc
+# When reclocking the board MaxSyncSpeed may need to be increased, see manual for details
+# MaxSyncSpeed = 10 # Set to 5, 10, or 20 to enable synchronous SCSI mode, 0 to disable
+
+
 # ROM settings
 #DisableROMDrive = 1 # Disable the ROM drive if it has been loaded to flash
 #ROMDriveSCSIID = 7 # Override ROM drive's SCSI ID
@@ -37,7 +43,7 @@
 #Initiator settings
 #InitiatorID = 7 # SCSI ID, 0-7, when the device is in initiator mode, default is 7
 #InitiatorMaxRetry = 5 #  number of retries on failed reads 0-255, default is 5
-#InitiatorImageHandling = 0 # 0: skip exisitng images, 1: create new image with incrementing suffix, 2: overwrite exising image
+#InitiatorImageHandling = 0 # 0: skip existing images, 1: create new image with incrementing suffix, 2: overwrite existing image
 
 #EnableCDAudio = 0 # 1: Enable CD audio - an external I2S DAC on the v1.2 is required
 
@@ -50,7 +56,7 @@
 #Product = "FIREBALL1"
 #Version = "1.0"
 #Serial = "0123456789ABCDEF"
-#Type = 0     # 0: Fixed, 1: Removable, 2: Optical, 3: Floppy, 4: Mag-optical, 
+#Type = 0     # 0: Fixed, 1: Removable, 2: Optical, 3: Floppy, 4: Mag-optical,
               # 5: Tape,  6: Network,   7: Zip100
 #VendorExtensions = 0 # Bit flags for specific extensions per device type
 #  CDROM - 1: Plextor's d8h vendor command
@@ -69,7 +75,7 @@
 # Mount SD card as a mass storage device before entering SCSI emulator
 # EnableUSBMassStorage = 1 # setting this to one will mount the SD card if the USB cord is plugged in
 # USBMassStorageWaitPeriod = 1000 # Number of milliseconds the device will wait for the host to mount SD card
-#   May need to be increased if coneneted through a USB hub
+#   May need to be increased if connected through a USB hub
 
 # SCSI DaynaPORT settings
 #WiFiSSID = "Wifi SSID string"

+ 99 - 0
zuluscsi_timings.ini

@@ -0,0 +1,99 @@
+[settings]
+disable = False # True: disable custom settings - default false: use the settings of this file
+
+# extends_speed_grade lets you choose a built in timing setting as a template
+# this is the same value as would be set as SpeedGrade in zuluscsi.ini
+# this allows the ability to use a minimum of the below settings in your zuluscsi_timings.ini file
+extends_speed_grade = Default # Default, TurboMax, TurboA, TurboB, etc
+
+# boot_with_sync value setting starts the board at an assumed sync value
+# boot_with_offset value setting starts the board at an assumed offset value
+# these are values are usually requested by the host to negotiate sync transfers
+# this is for users who are restarting their boards while the system is running
+# to test their settings and don't want to reboot their computers to renegotiate sync
+# if a USB serial console is used, settings can be change using the key presses 'm' then 'y'
+# for rebooting in mass storage mode, making changes to 'zuluscsi_timings.ini' then
+# ejecting the mass storage device
+# ** hot swapping like this is not recommended **
+# the sync value is explained below
+boot_with_sync_value = 0 # default value is 0 meaning this feature is off
+boot_with_offset_value = 15 # default value and max value is 15, if boot_with_sync_value is 0 this value is
+
+
+clk_hz = 250000000 # reclock target system frequency in Hz
+
+[pll]
+# These values can be found by using the script from the Pico-SDK:
+# pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py
+refdiv =  1 # reference divider
+vco_freq_hz = 1500000000 # vco frequency in Hz
+pd1 = 6 # Post divider 1
+pd2 = 1 # Post divider 2
+
+[scsi]
+# Period of the system clock in picoseconds
+clk_period_ps = 4000 # 1 / clk_hz * 10^12
+# Delay from data setup to REQ assertion.
+# deskew delay + cable skew delay = 55 ns minimum
+req_delay_cc = 14 # 55ns / clk_period_ps * 1000 rounded up
+
+# The next settings are for different SCSI synchronous clock speeds
+    # delay0: Data Setup Time - Delay from data write to REQ assertion
+    # delay1: Transmit Assertion time from REQ assert to REQ deassert (req pulse)
+    # delay2: Negation period - this value is calculated by the firmware: (total_delay - d0 - d1)
+    # total_delay spec is the sync value * 4 in ns
+
+    # Delay0 and Delay1 values are in clock cycles minus 1 for the pio instruction delay
+    #  SCSI clock:  Ultra(20)     Fast(10)  SCSI-1(5)
+    # delay0 spec:     11.5ns         23ns       23ns
+    # delay1 spec:     16.5ns         33ns       53ns
+    # delay2 spec:   min 15ns     min 30ns   min 80ns
+    # total_delay_adjust is manual adjustment value, when checked with a scope
+
+    # sync value is what the SCSI controller sends to the device to negotiate it' sync speed
+    # These are the fastest sync values for each synchronous clock speed
+    #   12 (48ns)  is for Fast20 21MB/s
+    #   25 (100ns) is for Fast10 10MB/s
+    #   50 (200ns) is for Fast5   5MB/s
+    # max_sync - the minimum sync period ("max" meaning fastest throughput) that
+    # is supported at this clock rate, the throughput is 1/4 the actual value in ns
+    # the max transfer speed is 1 / (4 * max_sync) in MB/s
+    # Though the ZuluSCSI generally isn't able to achieve that, it can get close on reads
+
+# the maximum value that delay0_cc and delay1_cc can be set to is 15
+    # due to the way the Programmable IO on the RP2 series chips work
+[scsi_20]
+# These are the Ultra (Fast 20) synchronous SCSI settings, SCSI running at 20MHz
+delay0_cc = 2 # 3 - 1 - delay 0 in clock cycles minus 1
+delay1_cc = 4 # 5 - 1 - delay 1 in clock cycles minus 1
+total_delay_adjust_cc = 1 # adjustment to the total sync period in clock cylces
+max_sync = 12 # the max sync supported by the board in Fast20, total sync periods in ns / 4
+
+[scsi_10]
+# These are the Fast (Fast 10) synchronous SCSI settings, SCSI runnings at 10MHz
+delay0_cc = 5 # 6 - 1
+delay1_cc = 8 # 9 - 1
+total_delay_adjust_cc = 1
+max_sync = 25
+
+[scsi_5]
+# These are the SCSI-1 (Fast 5) synchronous SCSI settings, SCSI runnings at 5MHz
+delay0_cc = 15 # maxed out, should probably be around 16
+delay1_cc = 15 # maxed out, should probably be around be 30
+total_delay_adjust_cc = 1
+max_sync = 50
+
+
+[sdio]
+# These settings determine the clock setting and duty cycle of the SDIO clock
+clk_div_pio = 5 # clk_hz / clk_div_pio should be between 25MHz and 50MHz
+# SDIO first communicates to the SD card at 1MHz, clk_div_1mhz divides the SDIO clock down to 1MHz
+clk_div_1mhz = 50 # this should be the SDIO clock speed in MHz, but for some SDIO clockspeeds using a smaller value worked
+# delay0 and delay1 determine the duty cycle of the SDIO clock
+# their total should equal clk_div_pio. but they both have 1 subtracted from
+# them to accommodate the clock cycle a PIO instruction takes
+# their max value is 15
+delay0 = 3 # 4 - 1
+delay1 = 0 # 1 - 1
+
+# Please post your findings to https://github.com/ZuluSCSI/ZuluSCSI-firmware/discussions