Magic‐1 CF Card Communication Protocol - retrotruestory/M1DEV GitHub Wiki

Magic-1 CF Card Communication Protocol

Based on the source code, here's how the Magic-1 communicates with the CF card:

CF Card Interface Configuration

// CF Configuration Constants
#define CF_MODE 0xE0        // MASTER, LBA mode
#define FEATURE_8_BIT 0x01  // 8-bit mode
#define CF_MASTER 0x02      // CF as master device

// Base I/O Address
unsigned char* cf_base = (unsigned char*)0xFF98;

CF Register Map

// CF Card Registers
#define DATA_PORT   0    // Data register
#define ERROR_REG   1    // Error register
#define FEATURE_REG 1    // Feature register
#define NUM_SECTORS 2    // Number of sectors
#define LBA_0       3    // LBA bits 0-7
#define LBA_1       4    // LBA bits 8-15
#define LBA_2       5    // LBA bits 16-23
#define LBA_3       6    // LBA bits 24-27 and mode
#define COMMAND_REG 7    // Command register
#define STATUS_REG  7    // Status register

Command Set

// CF Command Set
#define CMD_SET_FEATURE 0xEF  // Set feature command
#define CMD_RESET      0x04   // Reset device
#define CMD_DRIVE_ID   0xEC   // Identify device
#define CMD_READ       0x20   // Read sectors
#define CMD_WRITE      0x30   // Write sectors

Communication Protocol

  1. Card Initialization:
void cf_init(int drive, int mode) {
    // Reset CF card
    cf_base[FEATURE_REG] = CMD_RESET;
    cf_wait();
    
    // Set 8-bit mode
    cf_base[LBA_3] = mode;
    cf_base[FEATURE_REG] = FEATURE_8_BIT;
    cf_base[COMMAND_REG] = CMD_SET_FEATURE;
    cf_wait();
}
  1. Reading a Sector:
void cf_read_sector(int sector, char* buf, int drive) {
    // Setup LBA addressing
    cf_sector_setup(sector);
    
    // Issue read command
    cf_cmd_ready();
    cf_base[COMMAND_REG] = CMD_READ;
    
    // Read 512 bytes
    cf_read_512(buf);
}
  1. Writing a Sector:
void cf_write_sector(int sector, char* buf, int drive) {
    // Setup LBA addressing
    cf_sector_setup(sector);
    
    // Issue write command
    cf_cmd_ready();
    cf_base[COMMAND_REG] = CMD_WRITE;
    
    // Write 512 bytes
    cf_write_512(buf);
}

Status Checking

// Status Register Bits
#define BUSY_FLAG     0x80   // Card is busy
#define DRQ3_FLAG     0x08   // Data request
#define DRVRDY6_FLAG  0x40   // Drive ready

// Wait for card to be ready
int cf_wait() {
    for (i = 0; i < 30000; i++) {
        if ((cf_base[STATUS_REG] & BUSY_FLAG) == 0) {
            return 0;
        }
    }
    return -1; // timeout
}

Data Transfer

void cf_read_512(char* buf) {
    int i;
    cf_data_ready();
    // Read 512 bytes - note byte order swapping
    for (i = 0; i < 512; i += 2) {
        buf[i+1] = cf_base[DATA_PORT];
        buf[i] = cf_base[DATA_PORT];
    }
}

void cf_write_512(char* buf) {
    int i;
    cf_data_ready(); 
    // Write 512 bytes - note byte order swapping
    for (i = 0; i < 512; i += 2) {
        cf_base[DATA_PORT] = buf[i+1];
        cf_base[DATA_PORT] = buf[i];
    }
}

The protocol implements:

  • 8-bit data transfers
  • LBA addressing mode
  • Simple command/status protocol
  • 512-byte sector transfers
  • Hardware handshaking via status register
  • Error detection and timeout handling