Explorar el Código

Bring BS2 platform code up to date with main RP2040 code.

Upgraded SCSI acceleration code to newest version.

Moved the GPIO access macros from platform header to
platform_gpio header to match the main platform.

Use reformatted GPIO definitions by Morio to make the
file cleaner.

Co-authored-by: Morio <morio.earth@gmail.com>
Petteri Aimonen hace 2 años
padre
commit
0ab68dab66

+ 0 - 177
lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform_BS2.h

@@ -1,177 +0,0 @@
-// Platform-specific definitions for BlueSCSI Pico hardware.
-
-#pragma once
-
-#include <stdint.h>
-#include <Arduino.h>
-#include "BlueSCSI_platform_gpio.h"
-#include "scsiHostPhy.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* These are used in debug output and default SCSI strings */
-extern const char *g_platform_name;
-#define PLATFORM_NAME "BlueSCSI Pico"
-#define PLATFORM_REVISION "2.0"
-#define PLATFORM_MAX_SCSI_SPEED S2S_CFG_SPEED_SYNC_10
-#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_INITIATOR_MODE 1
-
-// 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
-
-// Debug logging function, can be used to print to e.g. serial port.
-// May get called from interrupt handlers.
-void platform_log(const char *s);
-void platform_emergency_log_save();
-
-// Timing and delay functions.
-// Arduino platform already provides these
-unsigned long millis(void);
-void delay(unsigned long ms);
-
-// Short delays, can be called from interrupt mode
-static inline void delay_ns(unsigned long ns)
-{
-    delayMicroseconds((ns + 999) / 1000);
-}
-
-// Approximate fast delay
-static inline void delay_100ns()
-{
-    asm volatile ("nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop \n nop");
-}
-
-// Initialize SD card and GPIO configuration
-void platform_init();
-
-// Initialization for main application, not used for bootloader
-void platform_late_init();
-
-// Disable the status LED
-void platform_disable_led(void);
-
-// Query whether initiator mode is enabled on targets with PLATFORM_HAS_INITIATOR_MODE
-bool platform_is_initiator_mode_enabled();
-
-// Setup soft watchdog if supported
-void platform_reset_watchdog();
-
-// 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);
-void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer);
-
-// Reprogram firmware in main program area.
-#ifndef RP2040_DISABLE_BOOTLOADER
-#define PLATFORM_BOOTLOADER_SIZE (128 * 1024)
-#define PLATFORM_FLASH_TOTAL_SIZE (1024 * 1024)
-#define PLATFORM_FLASH_PAGE_SIZE 4096
-bool platform_rewrite_flash_page(uint32_t offset, uint8_t buffer[PLATFORM_FLASH_PAGE_SIZE]);
-void platform_boot_to_main_firmware();
-#endif
-
-// ROM drive in the unused external flash area
-#ifndef RP2040_DISABLE_ROMDRIVE
-#define PLATFORM_HAS_ROM_DRIVE 1
-// Check maximum available space for ROM drive in bytes
-uint32_t platform_get_romdrive_maxsize();
-
-// Read ROM drive area
-bool platform_read_romdrive(uint8_t *dest, uint32_t start, uint32_t count);
-
-// Reprogram ROM drive area
-#define PLATFORM_ROMDRIVE_PAGE_SIZE 4096
-bool platform_write_romdrive(const uint8_t *data, uint32_t start, uint32_t count);
-#endif
-
-// Parity lookup tables for write and read from SCSI bus.
-// These are used by macros below and the code in scsi_accel_rp2040.cpp
-extern const uint16_t g_scsi_parity_lookup[256];
-extern const uint16_t g_scsi_parity_check_lookup[512];
-
-// Below are GPIO access definitions that are used from scsiPhy.cpp.
-
-// Write a single SCSI pin.
-// Example use: SCSI_OUT(ATN, 1) sets SCSI_ATN to low (active) state.
-#define SCSI_OUT(pin, state) \
-    *(state ? &sio_hw->gpio_clr : &sio_hw->gpio_set) = 1 << (SCSI_OUT_ ## pin)
-
-// Read a single SCSI pin.
-// Example use: SCSI_IN(ATN), returns 1 for active low state.
-#define SCSI_IN(pin) \
-    ((sio_hw->gpio_in & (1 << (SCSI_IN_ ## pin))) ? 0 : 1)
-
-// Set pin directions for initiator vs. target mode
-#define SCSI_ENABLE_INITIATOR() \
-    (sio_hw->gpio_oe_set = (1 << SCSI_OUT_ACK) | \
-                           (1 << SCSI_OUT_ATN)), \
-    (sio_hw->gpio_oe_clr = (1 << SCSI_IN_IO) | \
-                           (1 << SCSI_IN_CD) | \
-                           (1 << SCSI_IN_MSG) | \
-                           (1 << SCSI_IN_REQ))
-
-// Enable driving of shared control pins
-#define SCSI_ENABLE_CONTROL_OUT() \
-    (sio_hw->gpio_oe_set = (1 << SCSI_OUT_CD) | \
-                           (1 << SCSI_OUT_MSG))
-
-// Set SCSI data bus to output
-#define SCSI_ENABLE_DATA_OUT() \
-    (sio_hw->gpio_set = (1 << SCSI_DATA_DIR), \
-     sio_hw->gpio_oe_set = SCSI_IO_DATA_MASK)
-
-// Write SCSI data bus, also sets REQ to inactive.
-#define SCSI_OUT_DATA(data) \
-    gpio_put_masked(SCSI_IO_DATA_MASK | (1 << SCSI_OUT_REQ), \
-                    g_scsi_parity_lookup[(uint8_t)(data)] | (1 << SCSI_OUT_REQ)), \
-    SCSI_ENABLE_DATA_OUT()
-
-// Release SCSI data bus and REQ signal
-#define SCSI_RELEASE_DATA_REQ() \
-    (sio_hw->gpio_oe_clr = SCSI_IO_DATA_MASK, \
-     sio_hw->gpio_clr = (1 << SCSI_DATA_DIR), \
-     sio_hw->gpio_set = ((1 << SCSI_OUT_REQ)))
-
-// Release all SCSI outputs
-#define SCSI_RELEASE_OUTPUTS() \
-    SCSI_RELEASE_DATA_REQ(), \
-    sio_hw->gpio_set = (1 << SCSI_OUT_IO) | \
-                       (1 << SCSI_OUT_CD) | \
-                       (1 << SCSI_OUT_MSG) | \
-                       (1 << SCSI_OUT_RST) | \
-                       (1 << SCSI_OUT_BSY) | \
-                       (1 << SCSI_OUT_REQ) | \
-                       (1 << SCSI_OUT_SEL), \
-                       delay(1), \
-    sio_hw->gpio_oe_clr = (1 << SCSI_OUT_CD) | \
-                          (1 << SCSI_OUT_MSG)
-
-// Read SCSI data bus
-#define SCSI_IN_DATA() \
-    (~sio_hw->gpio_in & SCSI_IO_DATA_MASK) >> SCSI_IO_SHIFT
-
-#ifdef __cplusplus
-}
-
-// SD card driver for SdFat
-
-#ifdef SD_USE_SDIO
-class SdioConfig;
-extern SdioConfig g_sd_sdio_config;
-#define SD_CONFIG g_sd_sdio_config
-#define SD_CONFIG_CRASH g_sd_sdio_config
-#else
-class SdSpiConfig;
-extern SdSpiConfig g_sd_spi_config;
-#define SD_CONFIG g_sd_spi_config
-#define SD_CONFIG_CRASH g_sd_spi_config
-#endif
-
-#endif

+ 92 - 42
lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform_gpio_BS2.h

@@ -1,5 +1,25 @@
-// GPIO definitions for BlueSCSI Pico-based hardware
-
+/**
+ * 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/>.
+**/
+
+// GPIO definitions for BSv2-based hardware
 #pragma once
 
 #include <hardware/gpio.h>
@@ -22,65 +42,95 @@
 // Data direction control
 #define SCSI_DATA_DIR 9
 
-// SCSI control lines
-#define SCSI_OUT_IO   22  // Used to be 16
+// SCSI output status lines
+#define SCSI_OUT_IO   22
+#define SCSI_OUT_CD   18
+#define SCSI_OUT_MSG  20
+#define SCSI_OUT_RST  22
+#define SCSI_OUT_BSY  27
 #define SCSI_OUT_REQ  17
-
-#define SCSI_OUT_CD   18  // TODO hardware design
-#define SCSI_IN_SEL  18
-
 #define SCSI_OUT_SEL  19
 
-#define SCSI_OUT_MSG  20
-#define SCSI_IN_BSY  20  // TODO hardware design
-
-#define SCSI_IN_RST  21
-#define SCSI_OUT_RST  22  // Same as IO currently, not initialized or used
-
+// SCSI input status signals
+#define SCSI_IN_SEL  18
 #define SCSI_IN_ACK  26
-#define SCSI_OUT_BSY  27
 #define SCSI_IN_ATN  28
-
-// Status line outputs for initiator mode
-#define SCSI_OUT_ACK  10
-#define SCSI_OUT_ATN  29
-
-// Status line inputs for initiator mode
-#define SCSI_IN_IO    12
-#define SCSI_IN_CD    11
-#define SCSI_IN_MSG   13
-#define SCSI_IN_REQ   9
+#define SCSI_IN_BSY  20
+#define SCSI_IN_RST  21
 
 // Status LED pins
 #define LED_PIN      25
 #define LED_ON()     sio_hw->gpio_set = 1 << LED_PIN
 #define LED_OFF()    sio_hw->gpio_clr = 1 << LED_PIN
 
-// SDIO and SPI block
-#define SD_SPI_SCK   10
+// SD card pins in SDIO mode
 #define SDIO_CLK 10
-
-#define SD_SPI_MOSI  11
 #define SDIO_CMD 11
-
-#define SD_SPI_MISO  12
 #define SDIO_D0  12
-
 #define SDIO_D1  13
-
 #define SDIO_D2  14
-
 #define SDIO_D3  15
-#define SD_SPI_CS    15
 
-// IO expander I2C
-// #define GPIO_I2C_SDA 14
-// #define GPIO_I2C_SCL 15
+// SD card pins in SPI mode
+#define SD_SPI       spi0
+#define SD_SPI_SCK   10
+#define SD_SPI_MOSI  11
+#define SD_SPI_MISO  12
+#define SD_SPI_CS    15
 
-// DIP switch pins
-// #define DIP_INITIATOR 10
-// #define DIP_DBGLOG 28
-// #define DIP_TERM 9
 
 // Other pins
 #define SWO_PIN 16
+
+
+// Below are GPIO access definitions that are used from scsiPhy.cpp.
+
+// Write a single SCSI pin.
+// Example use: SCSI_OUT(ATN, 1) sets SCSI_ATN to low (active) state.
+#define SCSI_OUT(pin, state) \
+    *(state ? &sio_hw->gpio_clr : &sio_hw->gpio_set) = 1 << (SCSI_OUT_ ## pin)
+
+// Read a single SCSI pin.
+// Example use: SCSI_IN(ATN), returns 1 for active low state.
+#define SCSI_IN(pin) \
+    ((sio_hw->gpio_in & (1 << (SCSI_IN_ ## pin))) ? 0 : 1)
+
+// Enable driving of shared control pins
+#define SCSI_ENABLE_CONTROL_OUT() \
+    (sio_hw->gpio_oe_set = (1 << SCSI_OUT_CD) | \
+                           (1 << SCSI_OUT_MSG))
+
+// Set SCSI data bus to output
+#define SCSI_ENABLE_DATA_OUT() \
+    (sio_hw->gpio_set = (1 << SCSI_DATA_DIR), \
+     sio_hw->gpio_oe_set = SCSI_IO_DATA_MASK)
+
+// Write SCSI data bus, also sets REQ to inactive.
+#define SCSI_OUT_DATA(data) \
+    gpio_put_masked(SCSI_IO_DATA_MASK | (1 << SCSI_OUT_REQ), \
+                    g_scsi_parity_lookup[(uint8_t)(data)] | (1 << SCSI_OUT_REQ)), \
+    SCSI_ENABLE_DATA_OUT()
+
+// Release SCSI data bus and REQ signal
+#define SCSI_RELEASE_DATA_REQ() \
+    (sio_hw->gpio_oe_clr = SCSI_IO_DATA_MASK, \
+     sio_hw->gpio_clr = (1 << SCSI_DATA_DIR), \
+     sio_hw->gpio_set = (1 << SCSI_OUT_REQ))
+
+// Release all SCSI outputs
+#define SCSI_RELEASE_OUTPUTS() \
+    SCSI_RELEASE_DATA_REQ(), \
+    sio_hw->gpio_set = (1 << SCSI_OUT_IO) | \
+                       (1 << SCSI_OUT_CD) | \
+                       (1 << SCSI_OUT_MSG) | \
+                       (1 << SCSI_OUT_RST) | \
+                       (1 << SCSI_OUT_BSY) | \
+                       (1 << SCSI_OUT_REQ) | \
+                       (1 << SCSI_OUT_SEL), \
+                       delay(1), \
+    sio_hw->gpio_oe_clr = (1 << SCSI_OUT_CD) | \
+                          (1 << SCSI_OUT_MSG)
+
+// Read SCSI data bus
+#define SCSI_IN_DATA() \
+    (~sio_hw->gpio_in & SCSI_IO_DATA_MASK) >> SCSI_IO_SHIFT

+ 77 - 21
lib/ZuluSCSI_platform_RP2040/scsi_accel_BS2.pio

@@ -1,3 +1,23 @@
+; 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:
@@ -5,47 +25,56 @@
 ; -   8: DBP
 ; Side set is REQ pin
 
-.define REQ 17  ; was 9
-.define ACK 26  ; was 10
+.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 16-bit words that contain the 8 data bits + 1 parity bit.
-; 7 bits in each word are discarded.
+; 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, 7 [REQ_DLY-2]     side 1  ; Discard unused bits, wait for data preset time
+    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 asynchronous handshake.
-; Also works for synchronous mode down to 50 ns transfer period.
-; 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_accel_async_read
+; 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  ; Get number of bytes to receive
-    mov x, osr                  side 1  ; Store to counter X
-
-start:
+    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 null, 7                  side 1  ; Padding bits
-    jmp x-- start               side 1  ; Decrement byte count and jump to start
+    in y, 22                    side 1  ; Copy parity lookup table address
 
 ; Data state machine for synchronous writes.
-; Takes the lowest 9 bits of each 16 bit word and writes them to bus with REQ pulse.
+; 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
@@ -54,9 +83,9 @@ start:
 .program scsi_sync_write
     .side_set 1
 
-    out pins, 9     [0]         side 1  ; Write data and parity bit, wait for deskew delay
-    out null, 7     [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
+    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.
@@ -66,3 +95,30 @@ start:
     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

+ 108 - 17
lib/ZuluSCSI_platform_RP2040/scsi_accel_BS2.pio.h

@@ -8,6 +8,36 @@
 #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 //
 // ---------------------- //
@@ -19,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     
-    0x7567, //  2: out    null, 7         side 1 [5] 
+    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
@@ -40,35 +70,34 @@ static inline pio_sm_config scsi_accel_async_write_program_get_default_config(ui
 }
 #endif
 
-// --------------------- //
-// scsi_accel_async_read //
-// --------------------- //
+// --------------- //
+// scsi_accel_read //
+// --------------- //
 
-#define scsi_accel_async_read_wrap_target 0
-#define scsi_accel_async_read_wrap 6
+#define scsi_accel_read_wrap_target 0
+#define scsi_accel_read_wrap 5
 
-static const uint16_t scsi_accel_async_read_program_instructions[] = {
+static const uint16_t scsi_accel_read_program_instructions[] = {
             //     .wrap_target
     0x90a0, //  0: pull   block           side 1     
-    0xb027, //  1: mov    x, osr          side 1     
-    0x309a, //  2: wait   1 gpio, 26      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     
-    0x5067, //  5: in     null, 7         side 1     
-    0x1042, //  6: jmp    x--, 2          side 1     
+    0x5056, //  5: in     y, 22           side 1     
             //     .wrap
 };
 
 #if !PICO_NO_HARDWARE
-static const struct pio_program scsi_accel_async_read_program = {
-    .instructions = scsi_accel_async_read_program_instructions,
-    .length = 7,
+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_async_read_program_get_default_config(uint offset) {
+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_async_read_wrap_target, offset + scsi_accel_async_read_wrap);
+    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;
 }
@@ -84,7 +113,7 @@ static inline pio_sm_config scsi_accel_async_read_program_get_default_config(uin
 static const uint16_t scsi_sync_write_program_instructions[] = {
             //     .wrap_target
     0x7009, //  0: out    pins, 9         side 1     
-    0x6067, //  1: out    null, 7         side 0     
+    0x6077, //  1: out    null, 23        side 0     
     0x5061, //  2: in     null, 1         side 1     
             //     .wrap
 };
@@ -132,3 +161,65 @@ static inline pio_sm_config scsi_sync_write_pacer_program_get_default_config(uin
     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
+