Implementing ACSI on the Raspberry Pi Pico

A developer-friendly guide for building virtual disks on the Atari ST

This article explains how to implement an ACSI device using a Raspberry Pi Pico / Pico W, including:

  • electrical concepts
  • bus timing
  • implementing READ/WRITE
  • essential commands
  • virtual block device design
  • testing
  • common pitfalls

It is written for developers who want to build:

  • virtual hard drives
  • network-based TNFS drives
  • flash-based configuration disks
  • RAM disks
  • floppy emulation layers

ACSI is simple, and the Pico is more than fast enough to implement a full ACSI target.


1. What is ACSI?

ACSI (Atari Computer System Interface) is the hard-disk interface of the Atari ST series.
Internally, it is a simplified version of SCSI-1, using:

  • an 8-bit bidirectional data bus
  • only a few control signals
  • simple 6-byte command blocks
  • 512-byte block transfers

Unlike full SCSI, ACSI has:

  • no arbitration
  • no bus mastering
  • no complex selection phase
  • no status phase

This makes emulation ideal for small microcontrollers.


2. Electrical Basics

ACSI is a 5V TTL bus.
The Pico (3.3V) must not connect directly to it — level shifting is mandatory.

Recommended level shifting

  • 74LVC245
    Bidirectional level shifter for D0–D7
  • 74LVC245 or 74AHCT245
    For ST → Pico control lines
  • 74LS07 / 74HCT07
    Open-collector output for _DRQ (and _IRQ)

Signal directions

| Signal | Direction     | Meaning                     |
|--------|---------------|-----------------------------|
| D0-D7  | Bidirectional | 8-bit data bus              |
| _CS    | ST -> Pico    | Chip select                 |
| A1     | ST -> Pico    | 0 = command, 1 = data       |
| R/W    | ST -> Pico    | 1 = read from device        |
| _ACK   | ST -> Pico    | Handshake per byte          |
| _DRQ   | Pico -> ST    | Data ready (open collector) |
| _IRQ   | Pico -> ST    | Optional                    |
| GND    |               | Ground                      |

Keep traces short, ground plane solid, and the 245 close to the connector.


3. Pico Software Architecture

A clean structure:

ACSI Command Handler
→ Block Device (512-byte sectors)
→ Optional FAT Layer
→ Backend (TNFS, Flash, RAM, Disk image)

3.1 ACSI Front-End

Responsible for:

  • detecting _CS
  • reading command bytes using _ACK
  • decoding opcodes
  • sending or receiving data
  • asserting _DRQ
  • maintaining sense codes

3.2 Block Device Layer

Implements:

  • read_sector(LBA, buffer)
  • write_sector(LBA, buffer)
  • always 512-byte sectors

3.3 Optional FAT Layer

Used if you want the virtual disk to appear as FAT16.


4. ACSI Command Handling

ACSI uses 6-byte SCSI command blocks.

TEST UNIT READY (0x00)

Reports "OK" if device is ready.

REQUEST SENSE (0x03)

Returns last error.

INQUIRY (0x12)

Returns vendor/product identification.

READ(6) (0x08)

Reads N × 512-byte sectors.

WRITE(6) (0x0A)

Writes sectors.
Return WRITE PROTECT sense code if read-only.

MODE SENSE(6) (0x1A)

Returns basic settings (block size, write protect flag).

Vendor commands (0xC0–0xFF)

For your own configuration protocol, e.g.:

  • GET_CONFIG
  • SET_SERVER
  • SET_WIFI
  • SAVE_CONFIG
  • RESET_DEVICE

5. Handshake Overview

Command Phase (A1 = 0, R/W = 0)

  • _CS low
  • 6 command bytes written
  • each byte strobed by _ACK

Data-In Phase (device → ST)

  • device drives D0–D7
  • device asserts _DRQ low
  • ST pulses _ACK to read each byte

Data-Out Phase (ST → device)

  • ST drives D0–D7
  • ST pulses _ACK
  • device reads on _ACK edges

6. Example: READ(6)

void handle_read6(uint8_t *cmd) {  
   uint32_t lba = ((cmd[1] & 0x1F) << 16) | (cmd[2] << 8) | cmd[3];  
   uint32_t count = cmd[4] ? cmd[4] : 256;  

   for (uint32_t i = 0; i < count; i++) {  
      read_sector(lba + i, buffer);  
      send_sector_over_acsi(buffer);  
   }  
}

7. Example: WRITE(6)

void handle_write6(uint8_t *cmd) {  
   if (readonly) {  
      set_sense_write_protect();  
      return CHECK_CONDITION;  
   }  

   uint32_t lba = ...;  
   uint32_t count = ...;  

   for (i = 0; i < count; i++) {  
      receive_sector_over_acsi(buffer);  
      write_sector(lba + i, buffer);  
   }  
}

8. Virtual Disks from Flash

You can embed a read-only FAT16 filesystem directly in the Pico’s flash.
Useful for a configuration tool.

Typical files:

  • CONFIG.PRG
  • README.TXT
  • SETTINGS.CFG

Advantages:

  • works without TNFS
  • instant boot
  • safe (read-only)
  • no SD card needed

9. Backend Options

TNFS

Perfect for network-backed storage.

Flash

For built-in configuration disks.

RAM

Ultra fast, fully volatile.

Disk images

Raw .img or .st files mapped on LBA basis.


10. Testing with an Oscilloscope

Check:

  • _CS low → device selected
  • _ACK pulses during command/data
  • _DRQ low when sending data
  • A1 toggles correctly
  • R/W matches direction
  • D0–D7 stable before _ACK

Trigger on falling edge of _CS.


11. Common Pitfalls

  • Wrong 245 direction → bus contention → ST freezes
  • DRQ not open-collector
  • INQUIRY wrong size (must be 36 bytes)
  • Missing REQUEST SENSE implementation
  • Bad timing on data bus
  • Weak or missing pull-ups

12. Conclusion

Using:

  • Raspberry Pi Pico
  • 74LVC245
  • 74HCT07 / 74LS07
  • Simple firmware

You can emulate:

  • multiple hard disks
  • TNFS network drives
  • flash configuration disks
  • RAM disks
  • floppy images

ACSI is simple, robust, and perfect for modern retro-storage devices.

Loading…
Loading the web debug toolbar…
Attempt #