| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 | #ifndef __BLACKSASI_H__#define __BLACKSASI_H__#include "sdcard.h"#include "gpio.h"#include "log.h"#include "config.h"#include "scsi.h"// Log File#define VERSION "0.xx-SNAPSHOT-BLACKSASI-2022-09-28"#define LOG_FILENAME "LOG.txt"#define DEBUG            1      // 0:No debug information output                                // 1: Debug information output to USB Serial                                // 2: Debug information output to LOG.txt (slow)#define SCSI_SELECT      0      // 0 for STANDARD                                // 1 for SHARP X1turbo                                // 2 for NEC PC98/*#define READ_SPEED_OPTIMIZE  1 // Faster reads#define WRITE_SPEED_OPTIMIZE 1 // Speeding up writes#define USE_DB2ID_TABLE      1 // Use table to get ID from SEL-DB*/// SCSI config#define NUM_SCSIID  7          // Maximum number of supported SCSI-IDs (The minimum is 0)#define NUM_SCSILUN 2          // Maximum number of LUNs supported     (The minimum is 0)#define READ_PARITY_CHECK 0    // Perform read parity check (unverified)// HDD format#define MAX_BLOCKSIZE 2048     // Maximum BLOCK size#if DEBUG == 1#define serial Serial#define LOG(XX)      serial.print(XX)#define LOGHEX(XX)   serial.print(XX, HEX)#define LOGDEC(XX)   serial.print(XX, DEC)#define LOGBIN(XX)   serial.print(XX, BIN)#define LOGN(XX)     serial.println(XX)#define LOGHEXN(XX)  serial.println(XX, HEX)#define LOGDECN(XX)  serial.println(XX, DEC)#define LOGBIN_N(XX) serial.println(XX, BIN)#elif DEBUG == 2#define LOG(XX)      LOG_FILE.print(XX); LOG_FILE.sync();#define LOGHEX(XX)   LOG_FILE.print(XX, HEX); LOG_FILE.sync();#define LOGDEC(XX)   LOG_FILE.print(XX, DEC); LOG_FILE.sync();#define LOGBIN(XX)   LOG_FILE.print(XX, BIN); LOG_FILE.sync();#define LOGN(XX)     LOG_FILE.println(XX); LOG_FILE.sync();#define LOGHEXN(XX)  LOG_FILE.println(XX, HEX); LOG_FILE.sync();#define LOGDECN(XX)  LOG_FILE.println(XX, DEC); LOG_FILE.sync();#define LOGBIN_N(XX) LOG_FILE.println(XX, BIN); LOG_FILE.sync();#else#define LOG(XX)       //serial.print(XX)#define LOGHEX(XX)    //serial.print(XX, HEX)#define LOGDEC(XX)    //serial.print(XX, DEC)#define LOGBIN(XX)    //serial.print(XX, BIN)#define LOGN(XX)      //serial.println(XX)#define LOGHEXN(XX)   //serial.println(XX, HEX)#define LOGDECN(XX)   //serial.println(XX, DEC)#define LOGBIN_N(XX)  //serial.println(XX, BIN)#endif#define active   1#define inactive 0#define high 0#define low 1#define isHigh(XX) ((XX) == high)#define isLow(XX) ((XX) != high)#define TR_INPUT 1#define TR_OUTPUT 0#define DB_INPUT 0#define DB_OUTPUT 1// GPIO register port#define PAREG GPIOA->regs#define PBREG GPIOB->regs#define PCREG GPIOC->regs#define PDREG GPIOD->regs#define PEREG GPIOE->regs// Termination control (LOW is active)#define TERMINATION_HIGH()      GPIOREG(BOARD_SCSI_TERM_HIGH)->BSRR = (1 << BOARD_SCSI_TERM_HIGH % 16) << 16 | (1 << BOARD_SCSI_TERM_LOW % 16);#define TERMINATION_LOW()       GPIOREG(BOARD_SCSI_TERM_HIGH)->BSRR = (1 << BOARD_SCSI_TERM_LOW % 16) << 16 | (1 << BOARD_SCSI_TERM_HIGH % 16);#define TERMINATION_OFF()       GPIOREG(BOARD_SCSI_TERM_HIGH)->BSRR = (1 << BOARD_SCSI_TERM_HIGH % 16) | (1 << BOARD_SCSI_TERM_LOW % 16);// Enable SCSI buffers#define SCSI_OUTPUT_DISABLE()    GPIOREG(BOARD_TRANS_OE)->BSRR = (1 << (BOARD_TRANS_OE & 15)) << 16;#define SCSI_OUTPUT_ENABLE()   GPIOREG(BOARD_TRANS_OE)->BSRR = (1 << (BOARD_TRANS_OE  & 15));// SCSI Data Direction#define SCSI_DATABUS_OUT()       GPIOREG(BOARD_SCSI_DTD)->BSRR = (1 << (BOARD_SCSI_DTD & 15)) << 16; #define SCSI_DATABUS_IN()      GPIOREG(BOARD_SCSI_DTD)->BSRR = (1 << (BOARD_SCSI_DTD  & 15))// Virtual pin (Arduio compatibility is slow, so make it MCU-dependent)#define PA(BIT)       (BIT)#define PB(BIT)       (BIT + 16)#define PC(BIT)       (BIT + 32)#define PD(BIT)       (BIT + 48)#define PE(BIT)       (BIT + 64)// Virtual pin decoding#define GPIOREG(VPIN)     ((VPIN) >= 16 ? ((VPIN) >= 32 ? ((VPIN) >= 48 ? ((VPIN) >= 64 ? PEREG : PDREG) : PCREG) : PBREG) : PAREG)#define BITMASK(VPIN)     (1 << ((VPIN) & 15))#define vATN       PB(14)     // SCSI:ATN#define vBSY       PB(6)      // SCSI:BSY#define vACK       PB(7)      // SCSI:ACK#define vRST       PA(15)     // SCSI:RST#define vMSG       PE(2)      // SCSI:MSG#define vSEL       PE(3)      // SCSI:SEL#define vCD        PE(4)      // SCSI:C/D#define vREQ       PE(5)      // SCSI:REQ#define vIO        PE(6)      // SCSI:I/O#define vSD_CS     PB(1)      // SDCARD:CS#define vDTD       PC(0)      // SCSI:DTD#define vIND       PC(1)      // SCSI:IND#define vTAD       PC(2)      // SCSI:TAD#define vTRANS_OE  PB(12)     // SCSI:TRANS_OE// SCSI output pin control: active LOW (direct pin drive)#define SCSI_OUT(VPIN,ACTIVE) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN) << ((ACTIVE) ? 16 : 0); }// SCSI input pin check (inactive=0,active=1)#define SCSI_IN(VPIN) ((~GPIOREG(VPIN)->IDR >> ((VPIN) & 15)) & 1)// HDDiamge file#define HDIMG_ID_POS  2                 // Position to embed ID number#define HDIMG_LUN_POS 3                 // Position to embed LUN numbers#define HDIMG_BLK_POS 5                 // Position to embed block size numbers#define MAX_FILE_PATH 32                // Maximum file name length// SCSI#define SCSI_INFO_BUF_SIZE 36#define SCSI_INFO_VENDOR_SIZE 9#define SCSI_INFO_PRODUCT_SIZE 17#define SCSI_INFO_VERSION_SIZE 5typedef struct hddimg_struct{	FsFile      m_file;                 // File object	uint64_t    m_fileSize;             // File size	size_t      m_blocksize;            // SCSI BLOCK size}HDDIMG;// Declare functionsvoid onFalseInit(void);void onBusReset(void);void switchImage(void);void initFileLog(int);void finalizeFileLog(void);// SCSI config#define MAX_SCSIID  7          // Maximum number of supported SCSI-IDs (The minimum is 0)#define MAX_SCSILUN 8          // Maximum number of LUNs supported     (The minimum is 0)#define NUM_SCSIID  MAX_SCSIID // Number of enabled SCSI IDs#define NUM_SCSILUN 2          // Number of enabled LUNs#define READ_PARITY_CHECK 0    // Perform read parity check (unverified)#define DEFAULT_SCSI_ID 1#define DEFAULT_SCSI_LUN 0#define SCSI_BUF_SIZE 512      // Size of the SCSI Buffer#define HDD_BLOCK_SIZE 512#define OPTICAL_BLOCK_SIZE 2048// HDD format#define MAX_BLOCKSIZE 4096     // Maximum BLOCK size// LED ERRORS#define ERROR_FALSE_INIT  3#define ERROR_NO_SDCARD   5enum SCSI_DEVICE_TYPE{  SCSI_DEVICE_HDD,  SCSI_DEVICE_OPTICAL,};#define CDROM_RAW_SECTORSIZE    2352#define CDROM_COMMON_SECTORSIZE 2048#define MAX_SCSI_COMMAND  0xff#define SCSI_COMMAND_HANDLER(x) static byte x(SCSI_DEVICE *dev, const byte *cdb)#define NOP(x) for(unsigned _nopcount = x; _nopcount; _nopcount--) { asm("NOP"); }/* SCSI Timing delays */// Due to limitations in timing granularity all of these are "very" rough estimates#define SCSI_BUS_SETTLE() NOP(30);                            // spec 400ns ours ~420us#define SCSI_DATA_RELEASE() NOP(30);                          // spec 400ns ours ~420us#define SCSI_HOLD_TIME() asm("NOP"); asm("NOP"); asm("NOP");  // spec 45ns ours ~42ns#define SCSI_DESKEW() // asm("NOP"); asm("NOP"); asm("NOP");     // spec 45ns ours ~42ns#define SCSI_CABLE_SKEW() // asm("NOP");                         // spec 10ns ours ~14ns#define SCSI_RESET_HOLD() asm("NOP"); asm("NOP");             // spec 25ns ours ~28ns#define SCSI_DISCONNECTION_DELAY() NOP(15);                   // spec 200ns ours ~210ns/* SCSI phases+=============-===============-==================================-============+|    Signal   |  Phase name   |       Direction of transfer      |  Comment   ||-------------|               |                                  |            || MSG|C/D|I/O |               |                                  |            ||----+---+----+---------------+----------------------------------+------------||  0 | 0 | 0  |  DATA OUT     |       Initiator to target     \  |  Data      ||  0 | 0 | 1  |  DATA IN      |       Initiator from target   /  |  phase     ||  0 | 1 | 0  |  COMMAND      |       Initiator to target        |            ||  0 | 1 | 1  |  STATUS       |       Initiator from target      |            ||  1 | 0 | 0  |  *            |                                  |            ||  1 | 0 | 1  |  *            |                                  |            ||  1 | 1 | 0  |  MESSAGE OUT  |       Initiator to target     \  |  Message   ||  1 | 1 | 1  |  MESSAGE IN   |       Initiator from target   /  |  phase     ||-----------------------------------------------------------------------------|| Key:  0 = False,  1 = True,  * = Reserved for future standardization        |+=============================================================================+ */// SCSI phase change as single write to port B#define SCSIPHASEMASK(MSGACTIVE, CDACTIVE, IOACTIVE) ((BITMASK(vMSG)<<((MSGACTIVE)?16:0)) | (BITMASK(vCD)<<((CDACTIVE)?16:0)) | (BITMASK(vIO)<<((IOACTIVE)?16:0)))#define SCSI_PHASE_DATAOUT SCSIPHASEMASK(inactive, inactive, inactive)#define SCSI_PHASE_DATAIN SCSIPHASEMASK(inactive, inactive, active)#define SCSI_PHASE_COMMAND SCSIPHASEMASK(inactive, active, inactive)#define SCSI_PHASE_STATUS SCSIPHASEMASK(inactive, active, active)#define SCSI_PHASE_MESSAGEOUT SCSIPHASEMASK(active, active, inactive)#define SCSI_PHASE_MESSAGEIN SCSIPHASEMASK(active, active, active)#define SCSI_PHASE_CHANGE(MASK) { PEREG->BSRR = (MASK); }//BLACKSASI clean this up and use defines// Data pins//                                                         5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 static const uint32_t scsiDbOutputRegOr_PDREG         = 0b00000000000000010101010101010101;static const uint32_t scsiDbInputOutputAnd_PDREG      = 0b00000000000000000000000000000000;static const uint32_t scsiDbInputOutputPullAnd_PDREG  = 0b00000000000000010101010101010101;// Control pins//                                                         5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 static const uint32_t scsiDbInputOutputPullAnd_PEREG  = 0b00000000000000000001010101010001;static const uint32_t scsiDbInputOutputPullAnd_PBREG  = 0b00010001000100000101000000000000;// Put DB and DP in output mode and control buffers#define SCSI_DB_OUTPUT() { PDREG->MODER = (PDREG->MODER & scsiDbInputOutputAnd_PDREG) | scsiDbOutputRegOr_PDREG;  SCSI_DATABUS_OUT() ;}// Put DB and DP in input mode and control buffers#define SCSI_DB_INPUT()  { PDREG->MODER = (PDREG->MODER & scsiDbInputOutputAnd_PDREG); SCSI_DATABUS_IN();}#define SCSI_SET_PULL()  { PDREG->PUPDR |= scsiDbInputOutputPullAnd_PDREG; PEREG->PUPDR = PEREG->PUPDR | scsiDbInputOutputPullAnd_PEREG; PBREG->PUPDR = PBREG->PUPDR | scsiDbInputOutputPullAnd_PBREG; }// Transceiver control definitions#define TRANSCEIVER_IO_SET(VPIN,TRX_INPUT) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN) << ((TRX_INPUT) ? 16 : 0); }#define PTY(V)   (1^((V)^((V)>>1)^((V)>>2)^((V)>>3)^((V)>>4)^((V)>>5)^((V)>>6)^((V)>>7))&1)//                                                      5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 static const uint32_t SCSI_TARGET_PORTB_AND        = 0b11001111111111110000111111111111;static const uint32_t SCSI_TARGET_PORTB_OR         = 0b00010000000000000101000000000000;//                                                      5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 static const uint32_t SCSI_TARGET_PORTE_AND        = 0b11111111111111111100000011000011;static const uint32_t SCSI_TARGET_PORTE_OR         = 0b00000000000000000001010100010000;// Turn on the output only for BSY//#define SCSI_BSY_ACTIVE()      { PEREG->MODER = (PEREG->MODER & SCSI_TARGET_PORTE_AND) | SCSI_TARGET_PORTE_OR; PDREG->MODER = (PDREG->MODER & SCSI_TARGET_PORTD_AND) | SCSI_TARGET_PORTD_OR; SCSI_OUT(vBSY, active) }#define SCSI_BSY_ACTIVE()      { pinMode(BOARD_SCSI_BSY, OUTPUT); SCSI_OUT(vBSY,  active) }// BSY,REQ,MSG,CD,IO Turn off output, BSY is the last input#define SCSI_TARGET_INACTIVE() { PEREG->MODER = (PEREG->MODER & SCSI_TARGET_PORTE_AND); PBREG->MODER = (PBREG->MODER & SCSI_TARGET_PORTB_AND); TRANSCEIVER_IO_SET(vTAD,TR_INPUT); }#define SCSI_TARGET_ACTIVE()   { PEREG->MODER = (PEREG->MODER & SCSI_TARGET_PORTE_AND) | SCSI_TARGET_PORTE_OR; PBREG->MODER = (PBREG->MODER & SCSI_TARGET_PORTB_AND) | SCSI_TARGET_PORTB_OR; }// HDDimage file#define HDIMG_ID_POS  2                 // Position to embed ID number#define HDIMG_LUN_POS 3                 // Position to embed LUN numbers#define HDIMG_BLK_POS 5                 // Position to embed block size numbers#define MAX_FILE_PATH 64                // Maximum file name length/* *  Data byte to BSRR register setting value and parity table*//** * BSRR register generator * Totally configurable for which pin is each data bit, which pin is PTY, and which pin is REQ. * The only requirement is that data and parity pins are in the same GPIO block. * REQ can be specified as -1 to ignore, as it doesn't have to be in the same GPIO block. * This is dramatically slower than the original static array, but is easier to configure */static uint32_t genBSRR(uint32_t data) {  uint8_t masks[] = {0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, 7UL};  // Positions array indicates which bit position each data bit goes in  // positions[0] is for data bit 0, position[1] for data bit 1, etc  // DB0, DB1, DB2, DB4, DB5, DB6, DB7 in order  uint8_t positions[] = {0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, 7UL};  uint8_t dbpPosition = 8UL;  int reqPosition = 0;  uint8_t bitsAsserted = 0; //PM2022 Fix this in better way since we now have the bits correct  uint32_t output = 0x00000000;  //output |=(~data) | (data << 16);  for (int i = 0; i < 8; i++) {    if (data & (0x1 << masks[i])) {      // There's a one in this bit position, BSRR reset      output |= 0x1 << (positions[i] + 16);      bitsAsserted++;    } else {      // There's a 0 in this bit position, BSRR set high      output |= (0x1 << positions[i]);    }  }  // Set the parity bit  if (bitsAsserted % 2 == 0) {    // Even number of bits asserted, Parity asserted (0, low, BSRR reset)    output |= 0x01 << (dbpPosition + 16);  } else {    // Odd number of bits asserted, Parity deasserted (1, high, BSRR set)    output |= 0x01 << dbpPosition;  }  // BSRR set REQ if specified  // Only set > 0 if it's in the same GPIO block as DB and DBP  if (reqPosition > 0) {    output |= 0x01 << reqPosition;  }  return output;}// BSRR register control value that simultaneously performs DB set, DP set, and REQ = H (inactrive)//uint32_t db_bsrr[256];// Parity bit acquisition#define PARITY(DB) (db_bsrr[DB]&1)#define READ_DATA_BUS() (byte)((~(uint32_t)GPIOD->regs->IDR)>>8)struct SCSI_INQUIRY_DATA{  union  {  struct {    // bitfields are in REVERSE order for ARM    // byte 0    byte peripheral_device_type:5;    byte peripheral_qualifier:3;    // byte 1    byte reserved_byte2:7;    byte rmb:1;    // byte 2    byte ansi_version:3;    byte always_zero_byte3:5;    // byte 3    byte response_format:4;    byte reserved_byte4:2;    byte tiop:1;    byte always_zero_byte4:1;    // byte 4    byte additional_length;    // byte 5-6    byte reserved_byte5;    byte reserved_byte6;    // byte 7    byte sync:1;    byte always_zero_byte7_more:4;    byte always_zero_byte7:3;    // byte 8-15    char vendor[8];    // byte 16-31    char product[16];    // byte 32-35    char revision[4];    // byte 36    byte release;    // 37-46    char revision_date[10];  };  // raw bytes  byte raw[64];  };};// HDD imagetypedef __attribute__((aligned(4))) struct _SCSI_DEVICE{	FsFile        *m_file;                  // File object	uint64_t      m_fileSize;               // File size	uint16_t      m_blocksize;              // SCSI BLOCK size  uint16_t      m_rawblocksize;           // OPTICAL raw sector size  uint8_t       m_type;                   // SCSI device type  uint32_t      m_blockcount;             // blockcount  bool          m_raw;                    // Raw disk  SCSI_INQUIRY_DATA *inquiry_block;       // SCSI information  uint8_t       m_senseKey;               // Sense key  uint16_t      m_additional_sense_code;  // ASC/ASCQ   bool          m_mode2;                  // MODE2 CDROM  uint8_t       m_sector_offset;          // optical sector offset for missing sync header} SCSI_DEVICE;#endif // __BLACKSASI_H__
 |