소스 검색

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 2 년 전
부모
커밋
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
+