ztto před 6 roky
revize
3ee2b14821
3 změnil soubory, kde provedl 725 přidání a 0 odebrání
  1. 724 0
      ArdSCSino.ino
  2. 1 0
      README.md
  3. binární
      pin.png

+ 724 - 0
ArdSCSino.ino

@@ -0,0 +1,724 @@
+/*
+ * SCSI-HDデバイスエミュレータ
+ */
+#include <SPI.h>
+#include <SdFat.h>
+
+//ENABLE_EXTENDED_TRANSFER_CLASSを1に設定する
+//libraries/SdFat/SdFatConfig.h
+SPIClass SPI_2(2);
+//SdFat  SD(2);
+SdFatEX  SD(&SPI_2);
+
+//#define SPI_SPEED SD_SCK_MHZ(18)
+      
+#define LOG(XX)    //Serial.println(XX)
+#define LOGHEX(XX) //Serial.println(XX, HEX)
+
+#define high 0
+#define low 1
+
+#define isHigh(XX) ((XX) == high)
+#define isLow(XX) ((XX) != high)
+
+#define gpio_mode(pin,val) gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val);
+#define gpio_write(pin,val) gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val)
+#define gpio_read(pin) gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit)
+
+//#define DB0       PA0     // SCSI:DB0
+//#define DB1       PA1     // SCSI:DB1
+//#define DB2       PA2     // SCSI:DB2
+//#define DB3       PA3     // SCSI:DB3
+//#define DB4       PA4     // SCSI:DB4
+//#define DB5       PA5     // SCSI:DB5
+//#define DB6       PA6     // SCSI:DB6
+//#define DB7       PA7     // SCSI:DB7
+//#define DBP       PA8     // SCSI:DBP
+
+#define ATN       PB0     // SCSI:ATN
+#define BSY       PB1     // SCSI:BSY
+#define ACK       PB10    // SCSI:ACK
+#define RST       PB11    // SCSI:RST
+#define MSG       PB5     // SCSI:MSG
+#define SEL       PB6     // SCSI:SEL
+#define CD        PB7     // SCSI:C/D
+#define REQ       PB8     // SCSI:REQ
+#define IO        PB9     // SCSI:I/O
+
+#define SD_CS     PB12     // SDCARD:CS
+#define LED       PC13     // LED
+
+#define SCSIID    0                 // SCSI-ID 
+
+#define BLOCKSIZE 512               // 1BLOCKサイズ
+uint8_t       m_senseKey = 0;       //センスキー
+volatile bool m_isBusReset = false; //バスリセット
+
+#define HDIMG_FILE "HD.HDS"         // HDイメージファイル名
+File          m_file;               // ファイルオブジェクト
+uint32_t      m_fileSize;           // ファイルサイズ
+byte          m_buf[BLOCKSIZE];     // 汎用バッファ
+
+int           m_msc;
+bool          m_msb[256];
+
+/*
+ * IO読み込み.
+ */
+inline byte readIO(void)
+{
+  byte bret =  0x00;
+
+  GPIOA->regs->CRL = 0x88888888; // Configure GPIOA[7:0]
+  uint32 ret = GPIOA->regs->IDR;
+  bret |= ((!bitRead(ret,7)) << 7);
+  bret |= ((!bitRead(ret,6)) << 6);
+  bret |= ((!bitRead(ret,5)) << 5);
+  bret |= ((!bitRead(ret,4)) << 4);
+  bret |= ((!bitRead(ret,3)) << 3);
+  bret |= ((!bitRead(ret,2)) << 2);
+  bret |= ((!bitRead(ret,1)) << 1);
+  bret |= ((!bitRead(ret,0)) << 0);
+  return bret;
+}
+
+/* 
+ * IO書き込み.
+ */
+inline void writeIO(byte v)
+{
+//  GPIOA->regs->CRL = 0x11111111; // Configure GPIOA PP[7:0]10MHz
+  GPIOA->regs->CRL = 0x33333333;  // Configure GPIOA PP[7:0]50MHz
+  GPIOA->regs->CRH = 0x00000003;  // Configure GPIOA PP[16:8]50MHz
+  uint32 retL =  0x00;
+  uint32 retH =  0x00;
+
+  if(!parity(v)) {
+    bitWrite(retL, 8, 1);
+  } else {
+    bitWrite(retH, 8, 1);
+  }
+  if(v & ( 1 << 7 )) {
+    bitWrite(retL, 7, 1);
+  } else {
+    bitWrite(retH, 7, 1);
+  }
+  if(v & ( 1 << 6 )) {
+    bitWrite(retL, 6, 1);
+  } else {
+    bitWrite(retH, 6, 1);
+  }
+  if(v & ( 1 << 5 )) {
+    bitWrite(retL, 5, 1);
+  } else {
+    bitWrite(retH, 5, 1);
+  }
+  if(v & ( 1 << 4 )) {
+    bitWrite(retL, 4, 1);
+  } else {
+    bitWrite(retH, 4, 1);
+  }
+  if(v & ( 1 << 3 )) {
+    bitWrite(retL, 3, 1);
+  } else {
+    bitWrite(retH, 3, 1);
+  }
+  if(v & ( 1 << 2 )) {
+    bitWrite(retL, 2, 1);
+  } else {
+    bitWrite(retH, 2, 1);
+  }
+  if(v & ( 1 << 1 )) {
+    bitWrite(retL, 1, 1);
+  } else {
+    bitWrite(retH, 1, 1);
+  }
+  if(v & ( 1 << 0 )) {
+    bitWrite(retL, 0, 1);
+  } else {
+    bitWrite(retH, 0, 1);
+  }
+  //ビットがLOWに設定される
+  GPIOA->regs->BRR = retL ;
+  // ビットがHIGHに設定される
+  GPIOA->regs->BSRR = retH ;
+}
+
+/*
+ * 初期化.
+ *  パリティチェック
+ */
+inline int parity(byte val) {
+  val ^= val >> 16;
+  val ^= val >> 8;
+  val ^= val >> 4;
+  val ^= val >> 2;
+  val ^= val >> 1;
+
+  return val & 0x00000001;
+}
+
+/*
+ * 初期化.
+ *  バスの初期化、PINの向きの設定を行う
+ */
+void setup()
+{
+  // PA15 / PB3 / PB4 が使えない
+  // JTAG デバッグ用に使われているからです。
+//  disableDebugPorts();
+//  afio_cfg_debug_ports(AFIO_DEBUG_NONE);
+
+  //シリアル初期化
+  Serial.begin(9600);
+  while (!Serial);
+
+  //PINの初期化
+  gpio_mode(LED, GPIO_OUTPUT_OD);
+  gpio_write(LED, low);
+
+  //GPIO(SCSI BUS)初期化
+  GPIOA->regs->CRL = 0x888888888; // Configure GPIOA[8:0]
+
+  gpio_mode(ATN, GPIO_INPUT_PU);
+  gpio_mode(BSY, GPIO_INPUT_PU);
+  gpio_mode(ACK, GPIO_INPUT_PU);
+  gpio_mode(RST, GPIO_INPUT_PU);
+  gpio_mode(SEL, GPIO_INPUT_PU);
+  
+  gpio_mode(MSG, GPIO_OUTPUT_PP);
+  gpio_mode(CD, GPIO_OUTPUT_PP);
+  gpio_mode(REQ, GPIO_OUTPUT_PP);
+  gpio_mode(IO, GPIO_OUTPUT_PP);
+
+  gpio_write(MSG, low);
+  gpio_write(CD, low);
+  gpio_write(REQ, low);
+  gpio_write(IO, low);
+
+  //RSTピンの状態がHIGHからLOWに変わったときに発生
+  attachInterrupt(PIN_MAP[RST].gpio_bit, onBusReset, FALLING);
+  
+  if(!SD.begin(SD_CS,SPI_FULL_SPEED)) {
+    Serial.println("SD initialization failed!");
+    onFalseInit();
+  }
+  //HDイメージファイル
+  m_file = SD.open(HDIMG_FILE, O_READ | O_WRITE);
+  if(!m_file) {
+    Serial.println("Error: open hdimg");
+    onFalseInit();
+  }
+  m_fileSize = m_file.size();
+  Serial.println("Found Valid HD Image File.");
+  Serial.print(m_fileSize);
+  Serial.println("byte");
+  Serial.print(m_fileSize / 1024);
+  Serial.println("KB");
+  Serial.print(m_fileSize / 1024 / 1024);
+  Serial.println("MB");
+}
+
+/*
+ * 初期化失敗.
+ */
+void onFalseInit(void)
+{
+  while(true) {
+    gpio_write(LED, high);
+    delay(500); 
+    gpio_write(LED, low);
+    delay(500);
+  }
+}
+
+/*
+ * バスリセット割り込み.
+ */
+void onBusReset(void)
+{
+  if(isHigh(gpio_read(RST))) {
+    delayMicroseconds(20);
+    if(isHigh(gpio_read(RST))) {
+      LOG("BusReset!");
+      m_isBusReset = true;
+    }
+  }
+}
+
+/*
+ * ハンドシェイクで読み込む.
+ */
+byte readHandshake(void)
+{
+  gpio_write(REQ, high);
+  while(isLow(gpio_read(ACK))) {
+    if(m_isBusReset) {
+      return 0;
+    }
+  }
+  byte r = readIO();
+  gpio_write(REQ, low);
+  while(isHigh(gpio_read(ACK))) {
+    if(m_isBusReset) {
+      return 0;
+    }
+  }
+  return r;  
+}
+
+/*
+ * ハンドシェイクで書込み.
+ */
+void writeHandshake(byte d)
+{
+  writeIO(d);
+  gpio_write(REQ, high);
+  while(isLow(gpio_read(ACK))) {
+    if(m_isBusReset) {
+      return;
+    }
+  }
+  gpio_write(REQ, low);
+  while(isHigh(gpio_read(ACK))) {
+    if(m_isBusReset) {
+      return;
+    }
+  }
+}
+
+/*
+ * データインフェーズ.
+ *  データ配列 p を len バイト送信する。
+ */
+void writeDataPhase(int len, byte* p)
+{
+  LOG("DATAIN PHASE");
+  gpio_write(MSG, low);
+  gpio_write(CD, low);
+  gpio_write(IO, high);
+  for (int i = 0; i < len; i++) {
+    if(m_isBusReset) {
+      return;
+    }
+    writeHandshake(p[i]);
+  }
+}
+
+/* 
+ * データインフェーズ.
+ *  SDカードからの読み込みながら len ブロック送信する。
+ */
+void writeDataPhaseSD(uint32_t adds, uint32_t len)
+{
+  LOG("DATAIN PHASE(SD)");
+  uint32_t pos = adds * BLOCKSIZE;
+  m_file.seek(pos);
+  gpio_write(MSG, low);
+  gpio_write(CD, low);
+  gpio_write(IO, high);
+  for(uint32_t i = 0; i < len; i++) {
+    m_file.read(m_buf, BLOCKSIZE);
+    for(int j = 0; j < BLOCKSIZE; j++) {
+      if(m_isBusReset) {
+        return;
+      }
+      writeHandshake(m_buf[j]);
+    }
+  }
+}
+
+/*
+ * データアウトフェーズ.
+ *  len ブロック読み込みながら SDカードへ書き込む。
+ */
+void readDataPhaseSD(uint32_t adds, uint32_t len)
+{
+  LOG("DATAOUT PHASE(SD)");
+  uint32_t pos = adds * BLOCKSIZE;
+  m_file.seek(pos);
+  gpio_write(MSG, low);
+  gpio_write(CD, low);
+  gpio_write(IO, low);
+  for(uint32_t i = 0; i < len; i++) {
+    for(int j = 0; j < BLOCKSIZE; j++) {
+      if(m_isBusReset) {
+        return;
+      }
+      m_buf[j] = readHandshake();
+    }
+    m_file.write(m_buf, BLOCKSIZE);
+  }
+  m_file.flush();
+}
+
+/*
+ * INQUIRY コマンド処理.
+ */
+void onInquiryCommand(byte len)
+{
+  byte buf[36] = {
+    0x00, //デバイスタイプ
+    0x00, //RMB = 0
+    0x01, //ISO,ECMA,ANSIバージョン
+    0x01, //レスポンスデータ形式
+    35 - 4, //追加データ長
+    0, 0, //Reserve
+    0x00, //サポート機能
+    'T', 'N', 'B', ' ', ' ', ' ', ' ', ' ',
+    'A', 'r', 'd', 'S', 'C', 'S', 'i', 'n', 'o', ' ', ' ',' ', ' ', ' ', ' ', ' ',
+    '0', '0', '1', '0',
+  };
+  writeDataPhase(len < 36 ? len : 36, buf);
+}
+
+/*
+ * REQUEST SENSE コマンド処理.
+ */
+void onRequestSenseCommand(byte len)
+{
+  byte buf[18] = {
+    0x70,   //CheckCondition
+    0,      //セグメント番号
+    0x00,   //センスキー
+    0, 0, 0, 0,  //インフォメーション
+    17 - 7 ,   //追加データ長
+    0,
+  };
+  buf[2] = m_senseKey;
+  m_senseKey = 0;
+  writeDataPhase(len < 18 ? len : 18, buf);  
+}
+
+/*
+ * READ CAPACITY コマンド処理.
+ */
+void onReadCapacityCommand(byte pmi)
+{
+  uint32_t bc = m_fileSize / BLOCKSIZE;
+  uint32_t bl = BLOCKSIZE;
+  uint8_t buf[8] = {
+    bc >> 24, bc >> 16, bc >> 8, bc,
+    bl >> 24, bl >> 16, bl >> 8, bl    
+  };
+  writeDataPhase(8, buf);
+}
+
+/*
+ * READ6/10 コマンド処理.
+ */
+byte onReadCommand(uint32_t adds, uint32_t len)
+{
+  LOG("-R");
+  LOGHEX(adds);
+  LOGHEX(len);
+  gpio_write(LED, high);
+  writeDataPhaseSD(adds, len);
+  gpio_write(LED, low);
+  return 0; //sts
+}
+
+/*
+ * WRITE6/10 コマンド処理.
+ */
+byte onWriteCommand(uint32_t adds, uint32_t len)
+{
+  LOG("-W");
+  LOGHEX(adds);
+  LOGHEX(len);
+  gpio_write(LED, high);
+  readDataPhaseSD(adds, len);
+  gpio_write(LED, low);
+  return 0; //sts
+}
+
+/*
+ * MODE SENSE コマンド処理.
+ */
+void onModeSenseCommand(byte dbd, int pageCode, uint32_t len)
+{
+  memset(m_buf, 0, sizeof(m_buf)); 
+  int a = 4;
+  if(dbd == 0) {
+    uint32_t bc = m_fileSize / BLOCKSIZE;
+    uint32_t bl = BLOCKSIZE;
+    byte c[8] = {
+      0,//デンシティコード
+      bc >> 16, bc >> 8, bc,
+      0, //Reserve
+      bl >> 16, bl >> 8, bl    
+    };
+    memcpy(&m_buf[4], c, 8);
+    a += 8;
+    m_buf[3] = 0x08;
+  }
+  switch(pageCode) {
+  case 0x3F:
+  case 0x03:  //ドライブパラメータ
+    m_buf[a + 0] = 0x03; //ページコード
+    m_buf[a + 1] = 0x16; // ページ長
+    m_buf[a + 11] = 0x3F;//セクタ数/トラック
+    a += 24;
+    if(pageCode != 0x3F) {
+      break;
+    }
+  case 0x04:  //ドライブパラメータ
+    {
+      uint32_t bc = m_fileSize / BLOCKSIZE;
+      m_buf[a + 0] = 0x04; //ページコード
+      m_buf[a + 1] = 0x16; // ページ長
+      m_buf[a + 2] = bc >> 16;// シリンダ長
+      m_buf[a + 3] = bc >> 8;
+      m_buf[a + 4] = bc;
+      m_buf[a + 5] = 1;   //ヘッド数
+      a += 24;
+    }
+    if(pageCode != 0x3F) {
+      break;
+    }
+  default:
+    break;
+  }
+  m_buf[0] = a - 1;
+  writeDataPhase(len < a ? len : a, m_buf);
+}
+
+/*
+ * MsgIn2.
+ */
+void MsgIn2(int msg)
+{
+  LOG("MsgIn2");
+  gpio_write(MSG, high);
+  gpio_write(CD, high);
+  gpio_write(IO, high);
+  writeHandshake(msg);
+}
+
+/*
+ * MsgOut2.
+ */
+void MsgOut2()
+{
+  LOG("MsgOut2");
+  gpio_write(MSG, high);
+  gpio_write(CD, high);
+  gpio_write(IO, low);
+  m_msb[m_msc] = readHandshake();
+  m_msc++;
+  m_msc %= 256;
+}
+
+/*
+ * メインループ.
+ */
+void loop() 
+{
+  int sts = 0;
+  int msg = 0;
+
+  //BSY,SELが+はバスフリー
+  // セレクションチェック
+  // BSYが-の間ループ
+  if(isHigh(gpio_read(BSY))) {
+    return;
+  }
+  // SELが+の間ループ
+  if(isLow(gpio_read(SEL))) {
+    return;
+  }
+  // BSY+ SEL-
+  byte db = readIO();  
+  if((db & (1 << SCSIID)) == 0) {
+    return;
+  }
+
+  LOG("Selection");
+  m_isBusReset = false;
+  // セレクトされたらBSYを-にする
+  gpio_mode(BSY, GPIO_OUTPUT_PP);
+  gpio_write(BSY, high);
+  while(isHigh(gpio_read(SEL))) {
+    if(m_isBusReset) {
+      goto BusFree;
+    }
+  }
+  if(isHigh(gpio_read(ATN))) {
+    bool syncenable = false;
+    int syncperiod = 50;
+    int syncoffset = 0;
+    m_msc = 0;
+    memset(m_msb, 0x00, sizeof(m_msb));
+    while(isHigh(gpio_read(ATN))) {
+      MsgOut2();
+    }
+    for(int i = 0; i < m_msc; i++) {
+      // ABORT
+      if (m_msb[i] == 0x06) {
+        goto BusFree;
+      }
+      // BUS DEVICE RESET
+      if (m_msb[i] == 0x0C) {
+        syncoffset = 0;
+        goto BusFree;
+      }
+      // IDENTIFY
+      if (m_msb[i] >= 0x80) {
+      }
+      // 拡張メッセージ
+      if (m_msb[i] == 0x01) {
+        // 同期転送が可能な時だけチェック
+        if (!syncenable || m_msb[i + 2] != 0x01) {
+          MsgIn2(0x07);
+          break;
+        }
+        // Transfer period factor(50 x 4 = 200nsに制限)
+        syncperiod = m_msb[i + 3];
+        if (syncperiod > 50) {
+          syncoffset = 50;
+        }
+        // REQ/ACK offset(16に制限)
+        syncoffset = m_msb[i + 4];
+        if (syncoffset > 16) {
+          syncoffset = 16;
+        }
+        // STDR応答メッセージ生成
+        MsgIn2(0x01);
+        MsgIn2(0x03);
+        MsgIn2(0x01);
+        MsgIn2(syncperiod);
+        MsgIn2(syncoffset);
+        break;
+      }
+    }
+  }
+
+  LOG("Command");
+  gpio_write(MSG, low);
+  gpio_write(CD, high);
+  gpio_write(IO, low);
+  int len;
+  byte cmd[12];
+  cmd[0] = readHandshake();
+  LOGHEX(cmd[0]);
+  len = 1;
+  switch(cmd[0] >> 5) {
+  case 0b000:
+    len = 6;
+    break;
+  case 0b001:
+    len = 10;
+    break;
+  case 0b010:
+    len = 10;
+    break;
+  case 0b101:
+    len = 12;
+    break;
+  default:
+    break;
+  }
+  for(int i = 1; i < len; i++ ) {
+    cmd[i] = readHandshake();
+    LOGHEX(cmd[i]);
+  }
+
+  switch(cmd[0]) {
+  case 0x00:
+    LOG("[Test Unit]");
+    break;
+  case 0x01:
+    LOG("[Rezero Unit]");
+    break;
+  case 0x03:
+    LOG("[RequestSense]");
+    onRequestSenseCommand(cmd[4]);
+    break;
+  case 0x04:
+    LOG("[FormatUnit]");
+    break;
+  case 0x06:
+    LOG("[FormatUnit]");
+    break;
+  case 0x07:
+    LOG("[ReassignBlocks]");
+    break;
+  case 0x08:
+    LOG("[Read6]");
+    sts = onReadCommand((((uint32_t)cmd[1] & 0x1F) << 16) | ((uint32_t)cmd[2] << 8) | cmd[3], (cmd[4] == 0) ? 0x100 : cmd[4]);
+    break;
+  case 0x0A:
+    LOG("[Write6]");
+    sts = onWriteCommand((((uint32_t)cmd[1] & 0x1F) << 16) | ((uint32_t)cmd[2] << 8) | cmd[3], (cmd[4] == 0) ? 0x100 : cmd[4]);
+    break;
+  case 0x0B:
+    LOG("[Seek6]");
+    break;
+  case 0x12:
+    LOG("[Inquiry]");
+    onInquiryCommand(cmd[4]);
+    break;
+  case 0x1A:
+    LOG("[ModeSense6]");
+    onModeSenseCommand(cmd[1]&0x80, cmd[2] & 0x3F, cmd[4]);
+    break;
+  case 0x1B:
+    LOG("[StartStopUnit]");
+    break;
+  case 0x1E:
+    LOG("[PreAllowMed.Removal]");
+    break;
+  case 0x25:
+    LOG("[ReadCapacity]");
+    onReadCapacityCommand(cmd[8]);
+    break;
+  case 0x28:
+    LOG("[Read10]");
+    sts = onReadCommand(((uint32_t)cmd[2] << 24) | ((uint32_t)cmd[3] << 16) | ((uint32_t)cmd[4] << 8) | cmd[5], ((uint32_t)cmd[7] << 8) | cmd[8]);
+    break;
+  case 0x2A:
+    LOG("[Write10]");
+    sts = onWriteCommand(((uint32_t)cmd[2] << 24) | ((uint32_t)cmd[3] << 16) | ((uint32_t)cmd[4] << 8) | cmd[5], ((uint32_t)cmd[7] << 8) | cmd[8]);
+    break;
+  case 0x2B:
+    LOG("[Seek10]");
+    break;
+  case 0x5A:
+    LOG("[ModeSense10]");
+    onModeSenseCommand(cmd[1] & 0x80, cmd[2] & 0x3F, ((uint32_t)cmd[7] << 8) | cmd[8]);
+    break;
+  default:
+    LOG("[*Unknown]");
+    sts = 2;
+    m_senseKey = 5;
+    break;
+  }
+  if(m_isBusReset) {
+     goto BusFree;
+  }
+
+  LOG("Sts");
+  gpio_write(MSG, low);
+  gpio_write(CD, high);
+  gpio_write(IO, high);
+  writeHandshake(sts);
+  if(m_isBusReset) {
+     goto BusFree;
+  }
+
+  LOG("MsgIn");
+  gpio_write(MSG, high);
+  gpio_write(CD, high);
+  gpio_write(IO, high);
+  writeHandshake(msg);
+
+BusFree:
+  LOG("BusFree");
+  m_isBusReset = false;
+  gpio_write(REQ, low);
+  gpio_write(MSG, low);
+  gpio_write(CD, low);
+  gpio_write(IO, low);
+//  gpio_write(BSY, low);
+  gpio_mode(BSY, GPIO_INPUT_PU);
+}

+ 1 - 0
README.md

@@ -0,0 +1 @@
+# ArdSCSino-stm32

binární
pin.png