mirror of
https://github.com/dkgrizzly/GreenSCSI.git
synced 2025-01-22 10:30:19 +00:00
450 lines
11 KiB
C++
Executable File
450 lines
11 KiB
C++
Executable File
#include "config.h"
|
|
#include "scsi_defs.h"
|
|
|
|
/*
|
|
* Data uint8_t to GPIOB register setting value and parity table
|
|
*/
|
|
|
|
// Parity bit generation
|
|
#define PTY(V) ((1^((V)^((V)>>1)^((V)>>2)^((V)>>3)^((V)>>4)^((V)>>5)^((V)>>6)^((V)>>7)))&1)
|
|
|
|
// Set DBP
|
|
#define DBP(D) ((((uint32_t)(D)<<16)|(PTY(D)<<11)) ^ SCSI_DB_MASK)
|
|
|
|
#define DBP8(D) DBP(D),DBP(D+1),DBP(D+2),DBP(D+3),DBP(D+4),DBP(D+5),DBP(D+6),DBP(D+7)
|
|
#define DBP32(D) DBP8(D),DBP8(D+8),DBP8(D+16),DBP8(D+24)
|
|
|
|
// BSRR register control value that simultaneously performs DB set, DP set, and REQ = H (inactrive)
|
|
const uint32_t db_bsrr[256]={
|
|
DBP32(0x00),DBP32(0x20),DBP32(0x40),DBP32(0x60),
|
|
DBP32(0x80),DBP32(0xA0),DBP32(0xC0),DBP32(0xE0)
|
|
};
|
|
// Parity bit acquisition
|
|
#define PARITY(DB) ((db_bsrr[DB & 0xff] & 0x0800) >> 11)
|
|
|
|
// Macro cleaning
|
|
#undef DBP32
|
|
#undef DBP8
|
|
//#undef DBP
|
|
//#undef PTY
|
|
|
|
#if USE_DB2ID_TABLE
|
|
/* DB to SCSI-ID translation table */
|
|
const uint8_t db2scsiid[256]={
|
|
0xff,
|
|
0,
|
|
1,1,
|
|
2,2,2,2,
|
|
3,3,3,3,3,3,3,3,
|
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
|
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
|
};
|
|
#endif
|
|
|
|
// Put DB and DP in output mode
|
|
inline void SCSI_DB_OUTPUT(uint8_t d) {
|
|
GPIOB_PDOR = db_bsrr[d];
|
|
}
|
|
|
|
// Put DB and DP in input mode
|
|
inline void SCSI_DB_INPUT() {
|
|
GPIOB_PDDR = 0x00000000;
|
|
GPIOB_PDOR = SCSI_DB_MASK;
|
|
}
|
|
|
|
/*
|
|
* Bus reset interrupt.
|
|
*/
|
|
void onBusReset(void)
|
|
{
|
|
#if SUPPORT_SASI
|
|
// SASI I / F for X1 turbo has RST pulse write cycle +2 clock ==
|
|
// I can't filter because it only activates about 1.25us
|
|
if(!(m_sel->m_quirks & QUIRKS_SASI)) {
|
|
#endif
|
|
if(digitalRead(RST)) return;
|
|
delayMicroseconds(20);
|
|
if(digitalRead(RST)) return;
|
|
#if SUPPORT_SASI
|
|
}
|
|
#endif
|
|
|
|
SCSI_DB_INPUT();
|
|
|
|
LOGN("BusReset!");
|
|
m_isBusReset = true;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read by handshake.
|
|
*/
|
|
inline uint8_t readHandshake(void)
|
|
{
|
|
SET_REQ_ACTIVE();
|
|
while(!GET_ACK()) { if(m_isBusReset) { return 0; } }
|
|
uint8_t r = readIO();
|
|
SET_REQ_INACTIVE();
|
|
while(GET_ACK()) { if(m_isBusReset) { return 0; } }
|
|
return r;
|
|
}
|
|
|
|
inline void readHandshakeBlock(uint8_t *d, uint16_t len)
|
|
{
|
|
while(len) {
|
|
SET_REQ_ACTIVE();
|
|
while(!GET_ACK()) { if(m_isBusReset) { return; } }
|
|
*d++ = readIO();
|
|
len--;
|
|
SET_REQ_INACTIVE();
|
|
while(GET_ACK()) { if(m_isBusReset) { return; } }
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write with a handshake.
|
|
*/
|
|
inline void writeHandshake(uint8_t d)
|
|
{
|
|
GPIOB_PDDR = SCSI_DB_MASK;
|
|
SCSI_DB_OUTPUT(d);
|
|
|
|
SET_REQ_ACTIVE();
|
|
while(!GET_ACK()) { if(m_isBusReset) { return; } }
|
|
SET_REQ_INACTIVE();
|
|
SCSI_DB_INPUT();
|
|
while(GET_ACK()) { if(m_isBusReset) { return; } }
|
|
}
|
|
|
|
inline void writeHandshakeBlock(const uint8_t *d, uint16_t len)
|
|
{
|
|
GPIOB_PDDR = SCSI_DB_MASK;
|
|
while(len) {
|
|
SCSI_DB_OUTPUT(*d++);
|
|
SET_REQ_ACTIVE();
|
|
while(!GET_ACK()) { if(m_isBusReset) { return; } }
|
|
len--;
|
|
SET_REQ_INACTIVE();
|
|
while(GET_ACK()) { if(m_isBusReset) { return; } }
|
|
}
|
|
SCSI_DB_INPUT();
|
|
}
|
|
|
|
/*
|
|
* Data in phase.
|
|
* Send len uint8_ts of data array p.
|
|
*/
|
|
void writeDataPhase(int len, const uint8_t* p)
|
|
{
|
|
//LOGN("DATAIN PHASE");
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_ACTIVE();
|
|
|
|
#if READ_SPEED_OPTIMIZE
|
|
writeHandshakeBlock(p, len);
|
|
#else
|
|
for (int i = 0; i < len; i++) {
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
return;
|
|
}
|
|
writeHandshake(p[i]);
|
|
}
|
|
#endif
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Data in phase.
|
|
* Send len block while reading from SD card.
|
|
*/
|
|
void writeDataPhaseSD(uint32_t adds, uint32_t len)
|
|
{
|
|
#if READ_SPEED_OPTIMIZE
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAIN PHASE(SD)");
|
|
uint32_t pos = adds * m_sel->m_blocksize;
|
|
m_sel->m_file.seek(pos);
|
|
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_ACTIVE();
|
|
|
|
while(i < len) {
|
|
// Asynchronous reads will make it faster ...
|
|
#if READ_SPEED_OPTIMIZE
|
|
if((len-i) >= bigread) {
|
|
m_sel->m_file.read(m_buf, MAX_BLOCKSIZE);
|
|
writeHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
i += bigread;
|
|
} else {
|
|
m_sel->m_file.read(m_buf, m_sel->m_blocksize * (len-i));
|
|
writeHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
i = len;
|
|
}
|
|
#else
|
|
m_sel->m_file.read(m_buf, m_sel->m_blocksize);
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
return;
|
|
}
|
|
writeHandshake(m_buf[j]);
|
|
}
|
|
#endif
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Data in phase.
|
|
* Send len block while reading from SD card.
|
|
*/
|
|
void writeDataPhaseRaw(uint32_t adds, uint32_t len)
|
|
{
|
|
#if READ_SPEED_OPTIMIZE_RAW
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAIN PHASE(RAW)");
|
|
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
|
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_ACTIVE();
|
|
|
|
while(i < len) {
|
|
// Asynchronous reads will make it faster ...
|
|
#if READ_SPEED_OPTIMIZE_RAW
|
|
if((len-i) >= bigread) {
|
|
sd.card()->readSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
|
|
writeHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
i += bigread;
|
|
pos += (MAX_BLOCKSIZE / 512);
|
|
} else {
|
|
sd.card()->readSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
|
|
writeHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
i = len;
|
|
}
|
|
#else
|
|
sd.card()->readSectors(pos, m_buf, (m_sel->m_blocksize / 512));
|
|
pos++;
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
return;
|
|
}
|
|
writeHandshake(m_buf[j]);
|
|
}
|
|
#endif
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Data out phase.
|
|
* len block read
|
|
*/
|
|
void readDataPhase(int len, uint8_t* p)
|
|
{
|
|
//LOGN("DATAOUT PHASE");
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_INACTIVE();
|
|
|
|
#if WRITE_SPEED_OPTIMIZE
|
|
readHandshakeBlock(p, len);
|
|
#else
|
|
for(int i = 0; i < len; i++)
|
|
p[i] = readHandshake();
|
|
#endif
|
|
if(m_isBusReset) {
|
|
m_phase = PHASE_BUSFREE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Data out phase.
|
|
* Write to SD card while reading len block.
|
|
*/
|
|
void readDataPhaseSD(uint32_t adds, uint32_t len)
|
|
{
|
|
#if WRITE_SPEED_OPTIMIZE
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAOUT PHASE(SD)");
|
|
uint32_t pos = adds * m_sel->m_blocksize;
|
|
m_sel->m_file.seek(pos);
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_INACTIVE();
|
|
|
|
while(i < len) {
|
|
#if WRITE_SPEED_OPTIMIZE
|
|
if((len-i) >= bigread) {
|
|
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
m_sel->m_file.write(m_buf, MAX_BLOCKSIZE);
|
|
i += bigread;
|
|
} else {
|
|
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
m_sel->m_file.write(m_buf, m_sel->m_blocksize * (len-i));
|
|
i = len;
|
|
}
|
|
#else
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
return;
|
|
}
|
|
m_buf[j] = readHandshake();
|
|
}
|
|
m_sel->m_file.write(m_buf, m_sel->m_blocksize);
|
|
#endif
|
|
}
|
|
m_sel->m_file.flush();
|
|
}
|
|
|
|
/*
|
|
* Data out phase.
|
|
* Write to SD card while reading len block.
|
|
*/
|
|
void readDataPhaseRaw(uint32_t adds, uint32_t len)
|
|
{
|
|
#if WRITE_SPEED_OPTIMIZE_RAW
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAOUT PHASE(RAW)");
|
|
uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
|
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_INACTIVE();
|
|
|
|
while(i < len) {
|
|
#if WRITE_SPEED_OPTIMIZE_RAW
|
|
if((len-i) >= bigread) {
|
|
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
sd.card()->writeSectors(pos, m_buf, (MAX_BLOCKSIZE / 512));
|
|
i += bigread;
|
|
pos += (MAX_BLOCKSIZE / 512);
|
|
} else {
|
|
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
sd.card()->writeSectors(pos, m_buf, ((m_sel->m_blocksize * (len-i)) / 512));
|
|
i = len;
|
|
}
|
|
#else
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
return;
|
|
}
|
|
m_buf[j] = readHandshake();
|
|
}
|
|
sd.card()->writeSectors(pos, m_buf, (m_sel->m_blocksize / 512));
|
|
i++;
|
|
pos += (m_sel->m_blocksize / 512);
|
|
#endif
|
|
}
|
|
m_sel->m_file.flush();
|
|
}
|
|
|
|
/*
|
|
* Data out phase.
|
|
* Verify SD card while reading len block.
|
|
*/
|
|
void verifyDataPhaseSD(uint32_t adds, uint32_t len)
|
|
{
|
|
#if WRITE_SPEED_OPTIMIZE
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAOUT PHASE(SD)");
|
|
uint32_t pos = adds * m_sel->m_blocksize;
|
|
m_sel->m_file.seek(pos);
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_INACTIVE();
|
|
|
|
while(i < len) {
|
|
#if WRITE_SPEED_OPTIMIZE
|
|
if((len-i) >= bigread) {
|
|
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
//m_sel->m_file.verify(m_buf, MAX_BLOCKSIZE);
|
|
i += bigread;
|
|
} else {
|
|
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize * (len-i));
|
|
i = len;
|
|
}
|
|
#else
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
return;
|
|
}
|
|
m_buf[j] = readHandshake();
|
|
}
|
|
//m_sel->m_file.verify(m_buf, m_sel->m_blocksize);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Data out phase.
|
|
* Verify SD card while reading len block.
|
|
*/
|
|
void verifyDataPhaseRaw(uint32_t adds, uint32_t len)
|
|
{
|
|
#if WRITE_SPEED_OPTIMIZE_RAW
|
|
uint32_t bigread = (MAX_BLOCKSIZE / m_sel->m_blocksize);
|
|
#endif
|
|
uint32_t i = 0;
|
|
|
|
//LOGN("DATAOUT PHASE(RAW)");
|
|
//uint32_t pos = ((adds * m_sel->m_blocksize) / 512) + m_sel->m_firstSector;
|
|
SET_MSG_INACTIVE();
|
|
SET_CD_INACTIVE();
|
|
SET_IO_INACTIVE();
|
|
|
|
while(i < len) {
|
|
#if WRITE_SPEED_OPTIMIZE_RAW
|
|
if((len-i) >= bigread) {
|
|
readHandshakeBlock(m_buf, MAX_BLOCKSIZE);
|
|
i += bigread;
|
|
} else {
|
|
readHandshakeBlock(m_buf, m_sel->m_blocksize * (len-i));
|
|
i = len;
|
|
}
|
|
#else
|
|
for(unsigned int j = 0; j < m_sel->m_blocksize; j++) {
|
|
if(m_isBusReset) {
|
|
return;
|
|
}
|
|
m_buf[j] = readHandshake();
|
|
}
|
|
#endif
|
|
}
|
|
}
|