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 0 // 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 5
- typedef struct hddimg_struct
- {
- FsFile m_file; // File object
- uint64_t m_fileSize; // File size
- size_t m_blocksize; // SCSI BLOCK size
- }HDDIMG;
- // Declare functions
- void 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 1 // 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 5
- enum 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 image
- typedef __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__
|