// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void FASTRUN CS_IRQhandler() { // _CS Chip Select - ATARI is writing command or data to device, or reading handshake or status byte from device.
// we are inside CS (LOW) interrupt handler
// CS_IRQhandler() used only for command reading and then use nointerrupt() & bit bang the STATUS byte, but re-enable the interrupts() in STATUS sendStatus(uint8_t s).
// ToDo _CS _IRQ handshake under cpu control ( use nointerrupt() & bit bang )
// _______________________________
// | INPUTS | SN74LVC4245A | https://www.ti.com/lit/ds/symlink/sn74lvc4245a.pdf?HQS=dis-dk-null-digikeymode-dsf-pf-null-wwe&ts=1616938602079
// | OE | DIR | OPERATION | DIR NOTE: Need inverting buffer which produces the state opposite to the R_W on ATARI DB19 pin !!!
// |-----------------------------| DIR NOTE: So when its High on Atari its Low on DIR pin; From Teensy to Atari, use SN7406 Hex inverter Buffers With Open-Collector ?
// | L | L | B data to A bus | DIR - Inverted HIGH from ATARI A input to Device B input side, ATARI original signal is LOW from ATARI to Device COOMMAND write R/_W low
// | L | H | A data to B bus | DIR - Inverted LOW from Device B input to ATARI A input side, ATARI original signal is HIGH from Device to ATARI STATUS read R/_W high ( Device is on B input side )
// | H | X | Isolation | OE - tied to GND LOW -Enabled, TODO: NOTE 1 -OE
// -------------------------------
// SN74LVC4245A Pin Configuration and Functions pinout.
// ATARI ----_---- Teensy
// (5V) VCCA-|1 24|-VCCB (3.3V) , DIR NOTE: Need inverting buffer which produces the state opposite the input for ATARI DIR DB19 pin !!! ( ATARI DIR = LOW from ATARI to Device - HIGH from Device to ATARI )
// DIR-|2 23|-VCCB (3.3V) , ATARI DIR DB19 ACSI connector --> R/W Read/Write - Inverted HIGH from ATARI to Device (A data to B bus), Inverted LOW from Device to ATARI (B data to A bus)
//D0(LSB) A1-|3 22|-OE , OE - tied to GND LOW -Enabled, TODO: NOTE 1 -OE
// A2-|4 21|-B1 , A1 ~ A8 (5V) From ATARI DB19 ACSI connector, 01 to 08 <-> Data BUS 0-7 INPUT & OUTPUT
// A3-|5 20|-B2 , B1 ~ B8 (3.3V) From Device to ATARI (B data to A bus)
// A4-|6 19|-B3
// A5-|7 18|-B4
// A6-|8 17|-B5
// A7-|9 16|-B6
//D7(MSB) A8-|10 15|-B7
// GND-|11 14|-B8
// GND-|12 13|-GND
// ---------
// NOTE 1: TODO -OE pin MCU control when (A1 Address bit LOW) & (_CS Chip Select LOW) enabled & read the data bus 1st byte of new command if correct Controller# leave it enabled else disable.
// TODO -OE issue the control circuitry (DIR, OE) is powered by VCCA 5V.
//
// ----- ACSI Command Descriptor Block ---------------
// Byte 0 |xxxxxxxx|
// ||||||||
// |||------ Operation Code
// --------- Controller Number
/* T 4.1
//For Reading:
31 23 15 7 0
~ 1111 1111 1111 1111 0000 0000 0000 0000
0B0000 0011 1111 1111 0000 0000 0000 0000) >> 16; // BIT DATA 16,17,18,19,20,21,22,23,_A1 24,_CS 25. HEX 3FF0000
GPIO6_GDIR &= ~0x03FF0000; //Set the 8 Data and _A1 - _CS pins of GPIO6 as input (note the invert ~)
uint16_t DATA_IN = GPIO6_PSR >> 16; //sample and shift the bits to a 16bit value
//For writing
// only write to 8 bit data port not _A1 and _CS pins
GPIO6_GDIR |= 0x00FF0000; //Set as outputs 0B0000 0000 1111 1111 0000 0000 0000 0000
GPIO6_DR &= ~0x00FF0000; //Clear to 0
GPIO6_DR |= DATA_OUT << 16 //Write new value
//Alternatively there is also GPIO6_DR_SET, GPIO6_DR_CLEAR and GPIO6_DR_Toggle.
*/
GPIO_cs = GPIO6_PSR >> 16; //sample and shift the bits.
digitalWriteFast(_IRQ, HIGH); // high <-- (CS active low), when CS is low allways set irq high inactive
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ----- Command Phase -----------------------------------Alt+0175¯ ------
// DATA direction: From Atari to Target Device
// A1 ¯¯¯¯¯¯¯¯\___________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ LOW indicates 1st byte of new command.
// IRQ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\___________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\_____ Active low driven by target device to indicate (A) readness to accept another command byte (B) the availability of a byte to be read.
// _CS ¯¯¯¯¯¯¯¯¯¯¯¯¯\__________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\__________/¯¯¯¯¯¯¯¯¯¯
// | | | |
// R/_W ¯¯¯¯¯¯\______________________/¯¯¯¯¯¯\____________________/¯¯¯¯¯ LOW from ATARI to Device (Write), HIGH from Device to ATARI (Read)
// | | | | | | | |
// DATA =======><-------VALID--------><====><-------VALID--------><==== 8bit DATA Bus
// | | | | | | | |
// |<-a->|<--b--->|<-c->| |<-a->|<--b--->|<-c->|
// Byte 0 Byte 1 Byte n
// Timing
// a) 60 ns (max)
// b) 250 ns (max)
// c) 20 ns (max)
// IRQ Active LOW (open-collector) 1K Pullup on ATARI.
//
// T4.x GPIO_cs has its bits >> 16 shifted
if ((GPIO_cs & 0b000000000000000100000000) == 0) { // Check the A1 Address bit - When LOW during a _CS write, indicates 1st byte of new command
// 1001010010
// ID 6 ICD TIME CLOCK https://github.com/emutos/emutos/blob/2a55652646c3cc2b03cf3397e5168a10a428308e/bios/clock.c#L91
uint32_t D_ID = (GPIO_cs & 0b0000000011100000) >> (5);
//if ((D_ID == readerMask0) || (D_ID == readerMask1) || (D_ID == 6)) { // Check the device ID
if ((D_ID == readerMask0) || (D_ID == readerMask1)) { // Check the device ID, (NO ID 6 ICD CLOCK EMULATION)
// 3-State
digitalWriteFast(OE_SN74LS245N, HIGH); // -- ACSI OUT -- SN74LS245N -OE PIN (optional), Active LOW-Enabled.
/// if (((((GPIO_cs & 0b0000000011100000) >> (5)) == readerMask0) || (((GPIO_cs & 0b0000000011100000) >> (5)) == readerMask1)) || (((GPIO_cs & 0b0000000011100000) >> (5)) == 6)) { // Check the device ID
// if (((GPIO_cs & 0b0000000011100000) >> (5)) == readerMask0) {
CorrectDeviceIdFlag = true;
ACSI_ID_Flag = (GPIO_cs & 0b0000000011100000) >> 5;
// Serial.print("ACSI_ID "), Serial.println(ACSI_ID_Flag);
counter = 0;
if ((GPIO_cs & 0b00011111) == 0x1F) { // ICD extended command
//cmdLen_I = 11; // well this should set flag for icd CMD. then chek next byte for cmdLen(the first 3 bit) GROUP CODE.
isICD = true; // then it's a ICD command
cmdLen_I = 7; // ICD extended 6 byte commands
} else {
isICD = false;
cmdLen_I = 6;
}
//Serial.print("ID CORRECT: 0b"), Serial.print( GPIO_cs, BIN ), Serial.print(" HEX "), Serial.println( GPIO_cs, HEX );
} else {
CorrectDeviceIdFlag = false;
// 3-State
digitalWriteFast(OE_SN74LVC4245A, HIGH); // (active low) SN74LVC4245A -OE, Teensy 3.5 pin 34, Teensy 4.1 31, 3-State SN74LVC4245A Octal Bus Transceiver Outputs
Serial.print("A1 Device ID "), Serial.println((GPIO_cs & 0b0000000011100000) >> (5));
Serial.print("GPIO_cs ID INCORRECT: BIN "), Serial.print( GPIO_cs & 0b0000000011111111, BIN ), Serial.print(" HEX "), Serial.println( GPIO_cs & 0b0000000011111111, HEX );
Serial.print("Show all bits GPIO_cs: BIN "), Serial.println( GPIO_cs, BIN );
}
}
// Read the next bytes of the command
if (CorrectDeviceIdFlag == true) {
if (counter < cmdLen_I) {
if (counter == 0) {
cmdBuf_I[0] = GPIO_cs & 0b00011111;
} else if (counter == 1) {
if (isICD == true) {
cmdBuf_I[counter] = GPIO_cs & 0xff; //
// get the GROUP CODE see SCSI Commands Reference Manual, Rev. J (page 42)
switch ((GPIO_cs & 0xe0) >> 5) // get the length of the command, Common CDB fields
{
case 0: cmdLen_I = 7; break; // 6 byte commands
case 1: cmdLen_I = 11; break; // 10 byte commands, 1F (0x25 00100101) READ CAPACITY (10)
case 2: cmdLen_I = 11; break; // 10 byte commands
case 3: cmdLen_I = 7; break; // Reserved [a]
case 4: cmdLen_I = 17; break; // 16 byte commands
case 5: cmdLen_I = 13; break; // 12 byte commands
case 6: cmdLen_I = 7; break; // TODO FIX, C0h to FFh vendor specific.
default: cmdLen_I = 7; break;
// [a] The format of the commands using operation code 7Fh is described in 2.1.3. With
// the exception of operation code 7Fh, all group code 011b operation codes are reserved.
// 7Eh variable (more than 16 bytes)
// 7Fh extended (variable length; may contain one or more CDBs)
}
} else {
cmdBuf_I[counter] = GPIO_cs & 0xff;
}
} else {
cmdBuf_I[counter] = GPIO_cs & 0xff;
}
counter ++;
if (counter < cmdLen_I) {
delayNanoseconds(250); // not sure if this is needed?
digitalWriteFast(_IRQ, LOW); // low enabled <-- (active low)
}
}
if (counter >= cmdLen_I) {
digitalWriteFast(_IRQ, HIGH); // high disable <-- (active low)
CorrectDeviceIdFlag = false;
counter = 0;
CommandBool = true; //
}
}
}