greenscsi/src/scsibus.ino

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
}
}