Annotation of previous_trunk/src/esp.c, revision 1.1.1.1

1.1       root        1: /* Emulation of NCR53C90(A)
                      2:  Includes informations from QEMU-NeXT
                      3:  */
                      4: 
                      5: #include "ioMem.h"
                      6: #include "ioMemTables.h"
                      7: #include "m68000.h"
                      8: #include "configuration.h"
                      9: #include "esp.h"
                     10: #include "sysReg.h"
                     11: #include "dma.h"
                     12: #include "scsi.h"
                     13: 
                     14: #define LOG_ESPDMA_LEVEL    LOG_DEBUG   /* Print debugging messages for ESP DMA registers */
                     15: #define LOG_ESPCMD_LEVEL    LOG_DEBUG   /* Print debugging messages for ESP commands */
                     16: #define LOG_ESPREG_LEVEL    LOG_DEBUG   /* Print debugging messages for ESP registers */
                     17: #define LOG_ESPFIFO_LEVEL   LOG_DEBUG   /* Print debugging messages for ESP FIFO */
                     18: 
                     19: 
                     20: #define IO_SEG_MASK    0x1FFFF
                     21: 
                     22: typedef enum {
                     23:     DISCONNECTED,
                     24:     INITIATOR,
                     25:     TARGET
                     26: } SCSI_STATE;
                     27: 
                     28: SCSI_STATE esp_state;
                     29: 
                     30: 
                     31: /* ESP FIFO */
                     32: #define ESP_FIFO_SIZE 16
                     33: Uint8 esp_fifo_read(void);
                     34: void esp_fifo_write(Uint8 val);
                     35: void esp_fifo_clear(void);
                     36: 
                     37: /* ESP Command Register */
                     38: Uint8 esp_cmd_state;
                     39: #define ESP_CMD_INPROGRESS  0x01
                     40: #define ESP_CMD_WAITING     0x02
                     41: void esp_start_command(Uint8 cmd);
                     42: void esp_finish_command(void);
                     43: void esp_command_clear(void);
                     44: void esp_command_write(Uint8 cmd);
                     45: 
                     46: /* ESP Registers */
                     47: Uint8 writetranscountl;
                     48: Uint8 writetranscounth;
                     49: Uint8 fifo[ESP_FIFO_SIZE];
                     50: Uint8 command[2];
                     51: Uint8 status;
                     52: Uint8 selectbusid;
                     53: Uint8 intstatus;
                     54: Uint8 selecttimeout;
                     55: Uint8 seqstep;
                     56: Uint8 syncperiod;
                     57: Uint8 fifoflags;
                     58: Uint8 syncoffset;
                     59: Uint8 configuration;
                     60: Uint8 clockconv;
                     61: Uint8 esptest;
                     62: 
                     63: Uint32 esp_counter;
                     64: 
                     65: 
                     66: /* Command Register */
                     67: #define CMD_DMA      0x80
                     68: #define CMD_CMD      0x7f
                     69: 
                     70: #define CMD_TYP_MASK 0x70
                     71: #define CMD_TYP_MSC  0x00
                     72: #define CMD_TYP_TGT  0x20
                     73: #define CMD_TYP_INR  0x10
                     74: #define CMD_TYP_DIS  0x40
                     75: 
                     76: /* Miscellaneous Commands */
                     77: #define CMD_NOP      0x00
                     78: #define CMD_FLUSH    0x01
                     79: #define CMD_RESET    0x02
                     80: #define CMD_BUSRESET 0x03
                     81: /* Initiator Commands */
                     82: #define CMD_TI       0x10
                     83: #define CMD_ICCS     0x11
                     84: #define CMD_MSGACC   0x12
                     85: #define CMD_PAD      0x18
                     86: #define CMD_SATN     0x1a
                     87: /* Disconnected Commands */
                     88: #define CMD_RESEL    0x40
                     89: #define CMD_SEL      0x41
                     90: #define CMD_SELATN   0x42
                     91: #define CMD_SELATNS  0x43
                     92: #define CMD_ENSEL    0x44
                     93: #define CMD_DISSEL   0x45
                     94: /* Target Commands */
                     95: #define CMD_SEMSG    0x20
                     96: #define CMD_SESTAT   0x21
                     97: #define CMD_SEDAT    0x22
                     98: #define CMD_DISSEQ   0x23
                     99: #define CMD_TERMSEQ  0x24
                    100: #define CMD_TCCS     0x25
                    101: #define CMD_DIS      0x27
                    102: #define CMD_RMSGSEQ  0x28
                    103: #define CMD_RCOMM    0x29
                    104: #define CMD_RDATA    0x2A
                    105: #define CMD_RCSEQ    0x2B
                    106: 
                    107: /* Status Register */
                    108: #define STAT_MASK    0xF8
                    109: #define STAT_PHASE   0x07
                    110: 
                    111: #define STAT_VGC     0x08
                    112: #define STAT_TC      0x10
                    113: #define STAT_PE      0x20
                    114: #define STAT_GE      0x40
                    115: #define STAT_INT     0x80
                    116: 
                    117: /* Bus ID Register */
                    118: #define BUSID_DID    0x07
                    119: 
                    120: /* Interrupt Status Register */
                    121: #define INTR_SEL     0x01
                    122: #define INTR_SELATN  0x02
                    123: #define INTR_RESEL   0x04
                    124: #define INTR_FC      0x08
                    125: #define INTR_BS      0x10
                    126: #define INTR_DC      0x20
                    127: #define INTR_ILL     0x40
                    128: #define INTR_RST     0x80
                    129: 
                    130: /* Sequence Step Register */
                    131: #define SEQ_0        0x00
                    132: #define SEQ_SELTIMEOUT 0x02
                    133: #define SEQ_CD       0x04
                    134: 
                    135: /* Configuration Register */
                    136: #define CFG1_RESREPT 0x40
                    137: 
                    138: 
                    139: /* ESP Status Variables */
                    140: Uint8 mode_dma;
                    141: 
                    142: /* Experimental */
                    143: #define ESP_CLOCK_FREQ  20      /* ESP is clocked at 20 MHz */
                    144: #define ESP_DELAY       100     /* Standard wait time for ESP interrupt (except bus reset and selection timeout) */
                    145: 
                    146: 
                    147: /* ESP DMA control and status registers */
                    148: 
                    149: void ESP_DMA_CTRL_Read(void) {
                    150:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_dma.control;
                    151:        Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    152: }
                    153: 
                    154: void ESP_DMA_CTRL_Write(void) {
                    155:     Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA control write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    156:     esp_dma.control = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    157:         
                    158:     if (esp_dma.control&ESPCTRL_FLUSH) {
                    159:         Log_Printf(LOG_ESPDMA_LEVEL, "flush DMA buffer\n");
                    160:                if (ConfigureParams.System.bTurbo) {
                    161:                        tdma_flush_buffer(0);
                    162:                } else {
                    163:                        dma_esp_flush_buffer();
                    164:                }
                    165:     }
                    166:     if (esp_dma.control&ESPCTRL_CHIP_TYPE) {
                    167:         Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is WD33C92\n");
                    168:     } else {
                    169:         Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is NCR53C90\n");
                    170:     }
                    171:     if (esp_dma.control&ESPCTRL_RESET) {
                    172:         Log_Printf(LOG_ESPDMA_LEVEL, "reset SCSI controller\n");
                    173:         esp_reset_hard();
                    174:     }
                    175:     if (esp_dma.control&ESPCTRL_DMA_READ) {
                    176:         Log_Printf(LOG_ESPDMA_LEVEL, "DMA from SCSI to mem\n");
                    177:     } else {
                    178:         Log_Printf(LOG_ESPDMA_LEVEL, "DMA from mem to SCSI\n");
                    179:     }
                    180:     if (esp_dma.control&ESPCTRL_MODE_DMA) {
                    181:         Log_Printf(LOG_ESPDMA_LEVEL, "mode DMA\n");
                    182:     } else {
                    183:         Log_Printf(LOG_ESPDMA_LEVEL, "mode PIO\n");
                    184:     }
                    185:     if (esp_dma.control&ESPCTRL_ENABLE_INT) {
                    186:         Log_Printf(LOG_ESPDMA_LEVEL, "Enable ESP interrupt");
                    187:         if (status&STAT_INT) {
                    188:             set_interrupt(INT_SCSI, SET_INT);
                    189:         }
                    190:     } else {
                    191:         Log_Printf(LOG_ESPDMA_LEVEL, "Block ESP interrupt");
                    192:         set_interrupt(INT_SCSI, RELEASE_INT);
                    193:     }
                    194:     switch (esp_dma.control&ESPCTRL_CLKMASK) {
                    195:         case ESPCTRL_CLK10MHz:
                    196:             Log_Printf(LOG_ESPDMA_LEVEL, "10 MHz clock\n");
                    197:             break;
                    198:         case ESPCTRL_CLK12MHz:
                    199:             Log_Printf(LOG_ESPDMA_LEVEL, "12.5 MHz clock\n");
                    200:             break;
                    201:         case ESPCTRL_CLK16MHz:
                    202:             Log_Printf(LOG_ESPDMA_LEVEL, "16.6 MHz clock\n");
                    203:             break;
                    204:         case ESPCTRL_CLK20MHz:
                    205:             Log_Printf(LOG_ESPDMA_LEVEL, "20 MHz clock\n");
                    206:             break;
                    207:         default:
                    208:             break;
                    209:     }
                    210: }
                    211: 
                    212: void ESP_DMA_FIFO_STAT_Read(void) {
                    213:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_dma.status;
                    214:        Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA FIFO status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    215: }
                    216: 
                    217: void ESP_DMA_FIFO_STAT_Write(void) {
                    218:        Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA FIFO status write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    219:     esp_dma.status = IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    220: }
                    221: 
                    222: void ESP_DMA_set_status(void) { /* this is just a guess */
                    223:     if ((esp_dma.status&ESPSTAT_STATE_MASK) == ESPSTAT_STATE_D0S1) {
                    224:         //Log_Printf(LOG_WARN,"DMA in buffer 0, SCSI in buffer 1\n");
                    225:         esp_dma.status = (esp_dma.status&~ESPSTAT_STATE_MASK)|ESPSTAT_STATE_D1S0;
                    226:     } else {
                    227:         //Log_Printf(LOG_WARN,"DMA in buffer 1, SCSI in buffer 0\n");
                    228:         esp_dma.status = (esp_dma.status&~ESPSTAT_STATE_MASK)|ESPSTAT_STATE_D0S1;
                    229:     }
                    230: }
                    231: 
                    232: /* ESP Registers */
                    233: 
                    234: void ESP_TransCountL_Read(void) { // 0x02014000
                    235:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=esp_counter&0xFF;
                    236:        Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountL read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    237: }
                    238: 
                    239: void ESP_TransCountL_Write(void) {
                    240:     writetranscountl=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    241:        Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountL write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    242: }
                    243: 
                    244: void ESP_TransCountH_Read(void) { // 0x02014001
                    245:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=(esp_counter>>8)&0xFF;
                    246:        Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCoundH read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    247: }
                    248: 
                    249: void ESP_TransCountH_Write(void) {
                    250:     writetranscounth=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    251:        Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountH write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    252: }
                    253: 
                    254: void ESP_FIFO_Read(void) { // 0x02014002
                    255:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_fifo_read();
                    256:     Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFO read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    257: }
                    258: 
                    259: void ESP_FIFO_Write(void) {
                    260:     esp_fifo_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
                    261:     Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFO write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    262: }
                    263: 
                    264: void ESP_Command_Read(void) { // 0x02014003
                    265:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=command[0];
                    266:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Command read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    267: }
                    268: 
                    269: void ESP_Command_Write(void) {
                    270:     esp_command_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
                    271:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Command write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    272: }
                    273: 
                    274: void ESP_Status_Read(void) { // 0x02014004
                    275:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=(status&STAT_MASK)|(SCSIbus.phase&STAT_PHASE);
                    276:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    277: }
                    278: 
                    279: void ESP_SelectBusID_Write(void) {
                    280:     selectbusid=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    281:        Log_Printf(LOG_ESPREG_LEVEL,"ESP SelectBusID write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    282: }
                    283: 
                    284: void ESP_IntStatus_Read(void) { // 0x02014005
                    285:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=intstatus;
                    286:     Log_Printf(LOG_ESPREG_LEVEL,"ESP IntStatus read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    287:     
                    288:     if (status&STAT_INT) {
                    289:             intstatus = 0x00;
                    290:             status &= ~(STAT_VGC | STAT_PE | STAT_GE);
                    291:             //seqstep = 0x00; /* FIXME: Is the data sheet really wrong with this? */
                    292:             esp_lower_irq();
                    293:     }
                    294: }
                    295: 
                    296: void ESP_SelectTimeout_Write(void) {
                    297:     selecttimeout=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    298:        Log_Printf(LOG_ESPREG_LEVEL,"ESP SelectTimeout write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    299: }
                    300: 
                    301: void ESP_SeqStep_Read(void) { // 0x02014006
                    302:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=seqstep;
                    303:        Log_Printf(LOG_ESPREG_LEVEL,"ESP SeqStep read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    304: }
                    305: 
                    306: void ESP_SyncPeriod_Write(void) {
                    307:     syncperiod=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    308:        Log_Printf(LOG_ESPREG_LEVEL,"ESP SyncPeriod write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    309: }
                    310: 
                    311: void ESP_FIFOflags_Read(void) { // 0x02014007
                    312:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=fifoflags;
                    313:        Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFOflags read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    314: }
                    315: 
                    316: void ESP_SyncOffset_Write(void) {
                    317:     syncoffset=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    318:        Log_Printf(LOG_ESPREG_LEVEL,"ESP SyncOffset write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    319: }
                    320: 
                    321: void ESP_Configuration_Read(void) { // 0x02014008
                    322:     IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=configuration;
                    323:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    324: }
                    325: 
                    326: void ESP_Configuration_Write(void) {
                    327:     configuration=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    328:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    329: }
                    330: 
                    331: void ESP_ClockConv_Write(void) { // 0x02014009
                    332:     clockconv=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    333:        Log_Printf(LOG_ESPREG_LEVEL,"ESP ClockConv write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    334: }
                    335: 
                    336: void ESP_Test_Write(void) { // 0x0201400a
                    337:     esptest=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
                    338:        Log_Printf(LOG_ESPREG_LEVEL,"ESP Test write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    339: }
                    340: 
                    341: /* System reads this register to check if we use old or new SCSI controller.
                    342:  * Return 0 to report old chip. */
                    343: void ESP_Conf2_Read(void) { // 0x0201400b
                    344:     if (ConfigureParams.System.nSCSI == NCR53C90)
                    345:         IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = 0x00;
                    346:     Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
                    347: }
                    348: 
                    349: 
                    350: /* Helper functions */
                    351: 
                    352: /* Functions for reading and writing ESP FIFO */
                    353: Uint8 esp_fifo_read(void) {
                    354:     int i;
                    355:     Uint8 val;
                    356:     
                    357:     if (fifoflags > 0) {
                    358:         val = fifo[0];
                    359:         for (i=0; i<(ESP_FIFO_SIZE-1); i++)
                    360:             fifo[i]=fifo[i+1];
                    361:         fifo[ESP_FIFO_SIZE-1] = 0x00;
                    362:         fifoflags--;
                    363:         Log_Printf(LOG_ESPFIFO_LEVEL,"ESP FIFO: Reading byte, val=%02x, size = %i", val, fifoflags);
                    364:     } else {
                    365:         val = 0x00;
                    366:         Log_Printf(LOG_WARN, "ESP FIFO read: FIFO is empty!\n");
                    367:     }
                    368:     return val;
                    369: }
                    370: 
                    371: void esp_fifo_write(Uint8 val) {
                    372:     if (fifoflags==ESP_FIFO_SIZE) {
                    373:         Log_Printf(LOG_WARN, "ESP FIFO write: FIFO overflow! Top of FIFO overwritten\n");
                    374:         fifo[fifoflags-1] = val;
                    375:         status |= STAT_GE;
                    376:     } else {
                    377:         fifoflags++;
                    378:         fifo[fifoflags-1] = val;
                    379:         Log_Printf(LOG_ESPFIFO_LEVEL,"ESP FIFO: Writing byte %i, val=%02x", fifoflags-1, fifo[fifoflags-1]);
                    380:     }
                    381: }
                    382: 
                    383: void esp_fifo_clear(void) {
                    384:     int i;
                    385:     for (i=0; i<ESP_FIFO_SIZE; i++) {
                    386:         fifo[i] = 0;
                    387:     }
                    388:     fifoflags &= 0xE0;
                    389: }
                    390: 
                    391: /* Functions for handling dual ranked command register */
                    392: void esp_command_write(Uint8 cmd) {
                    393:     if ((command[1]&CMD_CMD)==CMD_RESET && (cmd&CMD_CMD)!=CMD_NOP) {
                    394:         Log_Printf(LOG_WARN, "ESP command write: Chip reset in command register, not executing command.\n");
                    395:     } else {
                    396:         command[1] = cmd;
                    397:         
                    398:         if (esp_cmd_state&ESP_CMD_WAITING) {
                    399:             Log_Printf(LOG_WARN, "ESP command write: Error! Top of command register overwritten.\n");
                    400:             status |= STAT_GE;
                    401:         }
                    402:     }
                    403:     
                    404:     if ((command[1]&CMD_CMD)==CMD_RESET || (command[1]&CMD_CMD)==CMD_BUSRESET) {
                    405:         esp_start_command(command[1]);
                    406:         return;
                    407:     }
                    408:     
                    409:     if (esp_cmd_state&ESP_CMD_INPROGRESS) {
                    410:         esp_cmd_state |= ESP_CMD_WAITING;
                    411:     } else {
                    412:         command[0] = command[1];
                    413:         command[1] = 0x00;
                    414:         esp_start_command(command[0]);
                    415:     }
                    416: }
                    417: 
                    418: void esp_command_clear(void) {
                    419:     command[0] = 0x00;
                    420:     if ((command[1]&CMD_CMD)!=CMD_RESET) {
                    421:         command[1] = 0x00;
                    422:         esp_cmd_state &= ~ESP_CMD_WAITING;
                    423:     }
                    424: }
                    425: 
                    426: void esp_finish_command(void) {
                    427:     esp_cmd_state &= ~ESP_CMD_INPROGRESS;
                    428:     if (esp_cmd_state&ESP_CMD_WAITING) {
                    429:         command[0] = command[1];
                    430:         command[1] = 0x00;
                    431:         esp_cmd_state &= ~ESP_CMD_WAITING;
                    432:         esp_start_command(command[0]);
                    433:     }
                    434: }
                    435: 
                    436: void esp_start_command(Uint8 cmd) {
                    437:     esp_cmd_state |= ESP_CMD_INPROGRESS;
                    438:     
                    439:     /* Check if command is valid for actual state */
                    440:     if ((cmd&CMD_TYP_MASK)!=CMD_TYP_MSC) {
                    441:         if ((esp_state==TARGET && !(cmd&CMD_TYP_TGT)) ||
                    442:             (esp_state==INITIATOR && !(cmd&CMD_TYP_INR)) ||
                    443:             (esp_state==DISCONNECTED && !(cmd&CMD_TYP_DIS))) {
                    444:             Log_Printf(LOG_WARN, "ESP Command: Illegal command for actual ESP state ($%02X)!\n",cmd);
                    445:             esp_command_clear();
                    446:             intstatus |= INTR_ILL;
                    447:             CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    448:             return;
                    449:         }
                    450:     }
                    451:     
                    452:     /* Check if the command is a DMA command */
                    453:     if (cmd & CMD_DMA) {
                    454:         /* Load the internal counter on every DMA command, do not decrement actual registers! */
                    455:         esp_counter = writetranscountl | (writetranscounth << 8);
                    456:         if (esp_counter == 0) { /* 0 means maximum value */
                    457:             esp_counter = 0x10000;
                    458:         }
                    459:         status &= ~STAT_TC;
                    460:         mode_dma = 1;
                    461:     } else {
                    462:         mode_dma = 0;
                    463:     }
                    464:     
                    465:     switch (cmd & CMD_CMD) {
                    466:             /* Miscellaneous */
                    467:         case CMD_NOP:
                    468:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: NOP\n");
                    469:             esp_finish_command();
                    470:             break;
                    471:         case CMD_FLUSH:
                    472:             Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: flush FIFO\n");
                    473:             esp_flush_fifo();
                    474:             break;
                    475:         case CMD_RESET:
                    476:             Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: reset chip\n");
                    477:             esp_reset_hard();
                    478:             break;
                    479:         case CMD_BUSRESET:
                    480:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: reset SCSI bus\n");
                    481:             esp_bus_reset();
                    482:             break;
                    483:             /* Disconnected */
                    484:         case CMD_RESEL:
                    485:             Log_Printf(LOG_WARN, "ESP Command: reselect sequence\n");
                    486:             abort();
                    487:             break;
                    488:         case CMD_SEL:
                    489:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select without ATN sequence\n");
                    490:             esp_select(false);
                    491:             break;
                    492:         case CMD_SELATN:
                    493:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select with ATN sequence\n");
                    494:             esp_select(true);
                    495:             break;
                    496:         case CMD_SELATNS:
                    497:             Log_Printf(LOG_WARN, "ESP Command: select with ATN and stop sequence\n");
                    498:             abort();
                    499:             break;
                    500:         case CMD_ENSEL:
                    501:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: enable selection/reselection\n");
                    502:             esp_finish_command(); /* Our disk doesn't do reselections */
                    503:             break;
                    504:         case CMD_DISSEL:
                    505:             Log_Printf(LOG_WARN, "ESP Command: disable selection/reselection\n");
                    506:             abort();
                    507:             break;
                    508:             /* Initiator */
                    509:         case CMD_TI:
                    510:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer information\n");
                    511:             esp_transfer_info();
                    512:             break;
                    513:         case CMD_ICCS:
                    514:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: initiator command complete sequence\n");
                    515:             esp_initiator_command_complete();
                    516:             break;
                    517:         case CMD_MSGACC:
                    518:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: message accepted\n");
                    519:             esp_message_accepted();
                    520:             break;
                    521:         case CMD_PAD:
                    522:             Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer pad\n");
                    523:             esp_transfer_pad();
                    524:             break;
                    525:         case CMD_SATN:
                    526:             Log_Printf(LOG_WARN, "ESP Command: set ATN\n");
                    527:             abort();
                    528:             break;
                    529:             /* Target */
                    530:         case CMD_SEMSG:
                    531:         case CMD_SESTAT:
                    532:         case CMD_SEDAT:
                    533:         case CMD_DISSEQ:
                    534:         case CMD_TERMSEQ:
                    535:         case CMD_TCCS:
                    536:         case CMD_RMSGSEQ:
                    537:         case CMD_RCOMM:
                    538:         case CMD_RDATA:
                    539:         case CMD_RCSEQ:
                    540:             Log_Printf(LOG_WARN, "ESP Command: Target commands not emulated!\n");
                    541:             abort();
                    542:             break;
                    543:         case CMD_DIS:
                    544:             Log_Printf(LOG_WARN, "ESP Command: DISCONNECT not emulated!\n");
                    545:             abort();
                    546:             SCSIbus.phase = PHASE_ST;
                    547:             intstatus = INTR_DC;
                    548:             seqstep = SEQ_0;
                    549:             break;
                    550:             
                    551:         default:
                    552:             Log_Printf(LOG_WARN, "ESP Command: Illegal command!\n");
                    553:             esp_command_clear();
                    554:             intstatus |= INTR_ILL;
                    555:             CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    556:             break;
                    557:     }
                    558: }
                    559: 
                    560: 
                    561: /* This is the handler function for ESP delayed interrupts */
                    562: void ESP_InterruptHandler(void) {
                    563:        CycInt_AcknowledgeInterrupt();
                    564:     esp_raise_irq();
                    565: }
                    566: 
                    567: 
                    568: void esp_raise_irq(void) {
                    569:     if(!(status & STAT_INT)) {
                    570:         status |= STAT_INT;
                    571:         
                    572:         if (esp_dma.control&ESPCTRL_ENABLE_INT) {
                    573:             set_interrupt(INT_SCSI, SET_INT);
                    574:         }
                    575:         
                    576:         if (LOG_ESPCMD_LEVEL == LOG_WARN) {
                    577:             printf("[ESP] Raise IRQ: state=");
                    578:             switch (esp_state) {
                    579:                 case DISCONNECTED: printf("disconnected"); break;
                    580:                 case INITIATOR: printf("initiator"); break;
                    581:                 case TARGET: printf("target"); break;
                    582:                 default: printf("unknown"); break;
                    583:             }
                    584:             printf(", phase=");
                    585:             switch (SCSIbus.phase&STAT_PHASE) {
                    586:                 case PHASE_DO: printf("data out"); break;
                    587:                 case PHASE_DI: printf("data in"); break;
                    588:                 case PHASE_CD: printf("command"); break;
                    589:                 case PHASE_ST: printf("status"); break;
                    590:                 case PHASE_MI: printf("msg in"); break;
                    591:                 case PHASE_MO: printf("msg out"); break;
                    592:                 default: printf("unknown"); break;
                    593:             }
                    594:             if (status&STAT_TC) {
                    595:                 printf(", transfer complete");
                    596:             } else {
                    597:                 printf(", transfer not complete");
                    598:             }
                    599:             printf(", sequence step=%i", seqstep);
                    600:             printf(", interrupt status:\n");
                    601:             if (intstatus&INTR_RST) printf("bus reset\n");
                    602:             if (intstatus&INTR_BS) printf("bus service\n");
                    603:             if (intstatus&INTR_DC) printf("disconnected\n");
                    604:             if (intstatus&INTR_FC) printf("function complete\n");
                    605:             if (intstatus&INTR_ILL) printf("illegal command\n");
                    606:             if (intstatus&INTR_RESEL) printf("reselected\n");
                    607:             if (intstatus&INTR_SEL) printf("selected\n");
                    608:             if (intstatus&INTR_SELATN) printf("selected with ATN\n");
                    609:         }
                    610:     }
                    611: }
                    612: 
                    613: void esp_lower_irq(void) {
                    614:     if (status & STAT_INT) {
                    615:         status &= ~STAT_INT;
                    616:         
                    617:         set_interrupt(INT_SCSI, RELEASE_INT);
                    618:         
                    619:         Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Lower IRQ\n");
                    620:         
                    621:         esp_finish_command();
                    622:     }
                    623: }
                    624: 
                    625: /* Functions */
                    626: 
                    627: /* Reset chip */
                    628: void esp_reset_hard(void) {
                    629:     Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Hard reset\n");
                    630: 
                    631:     clockconv = 0x02;
                    632:     configuration &= ~0xF8; // clear chip test mode, parity enable, parity test, scsi request/int disable, slow cable mode
                    633:     esp_fifo_clear();
                    634:     syncperiod = 0x05;
                    635:     syncoffset = 0x00;
                    636:     status &= ~STAT_INT; // release interrupt
                    637:     set_interrupt(INT_SCSI, RELEASE_INT);
                    638:     intstatus = 0x00;
                    639:     status &= ~(STAT_VGC | STAT_PE | STAT_GE); // clear transfer complete aka valid group code, parity error, gross error
                    640:     esp_reset_soft();
                    641:     esp_finish_command();
                    642: }
                    643: 
                    644: 
                    645: 
                    646: void esp_reset_soft(void) {
                    647:     status &= ~STAT_TC; /* clear transfer count zero */
                    648:     
                    649:     /* check, if this is complete */
                    650:     mode_dma = 0;
                    651:     esp_counter = 0; /* reset counter, but not actual registers! */
                    652:     
                    653:     seqstep = 0x00;
                    654:     
                    655:     /* writetranscountl, writetranscounth, selectbusid, selecttimeout are not initialized by reset */
                    656: 
                    657:     /* This part is "disconnect reset" */
                    658:     esp_command_clear();
                    659:     esp_state = DISCONNECTED;
                    660: }
                    661: 
                    662: 
                    663: /* Reset SCSI bus */
                    664: void esp_bus_reset(void) {
                    665:     
                    666:     esp_reset_soft();
                    667:     if (!(configuration & CFG1_RESREPT)) {
                    668:         intstatus = INTR_RST;
                    669:         SCSIbus.phase = PHASE_MI; /* CHECK: why message in phase? */
                    670:         Log_Printf(LOG_ESPCMD_LEVEL,"[ESP] SCSI bus reset raising IRQ (configuration=$%02X)\n",configuration);
                    671:         CycInt_AddRelativeInterruptUs(500, 0, INTERRUPT_ESP); /* CHECK: how is this delay defined? */
                    672:     } else {
                    673:         Log_Printf(LOG_ESPCMD_LEVEL,"[ESP] SCSI bus reset not interrupting (configuration=$%02X)\n",configuration);
                    674:         esp_finish_command();
                    675:     }
                    676: }
                    677: 
                    678: 
                    679: /* Flush FIFO */
                    680: void esp_flush_fifo(void) {
                    681:     esp_fifo_clear();
                    682:     esp_finish_command();
                    683: }
                    684: 
                    685: 
                    686: /* Select with or without ATN */
                    687: void esp_select(bool atn) {
                    688:     int cmd_size;
                    689:     Uint8 identify_msg = 0;
                    690:     Uint8 commandbuf[SCSI_CDB_MAX_SIZE];
                    691: 
                    692:     seqstep = 0;
                    693:     
                    694:     /* First select our target */
                    695:     Uint8 target = selectbusid & BUSID_DID; /* Get bus ID from register */
                    696:     bool timeout = SCSIdisk_Select(target);
                    697:     if (timeout) {
                    698:         /* If a timeout occurs, generate disconnect interrupt */
                    699:         intstatus = INTR_DC;
                    700:         esp_command_clear();
                    701:         esp_state = DISCONNECTED;
                    702:         int seltout = (selecttimeout * 8192 * clockconv) / ESP_CLOCK_FREQ; /* timeout in microseconds */
                    703:         Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Target %i, timeout after %i microseconds",target,seltout);
                    704:         CycInt_AddRelativeInterruptUs(seltout, 0, INTERRUPT_ESP);
                    705:         return;
                    706:     }
                    707:     
                    708:     /* Next get our command */
                    709:     if(mode_dma == 1) {
                    710:         cmd_size = esp_counter;
                    711:         Log_Printf(LOG_WARN, "[ESP] Select: Reading command using DMA, size %i byte (not implemented!)",cmd_size);
                    712:         abort();
                    713:     } else {
                    714:         if (atn) { /* Read identify message from FIFO */
                    715:             SCSIbus.phase = PHASE_MO;
                    716:             seqstep = 1;
                    717:             identify_msg = esp_fifo_read();
                    718:             Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Reading message from FIFO");
                    719:             Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Identify Message: $%02X",identify_msg);
                    720:         }
                    721:         
                    722:         /* Read command from FIFO */
                    723:         SCSIbus.phase = PHASE_CD;
                    724:         seqstep = 3;
                    725:         for (cmd_size = 0; cmd_size < SCSI_CDB_MAX_SIZE && fifoflags > 0; cmd_size++) {
                    726:             commandbuf[cmd_size] = esp_fifo_read();
                    727:         }
                    728: 
                    729:         Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Reading command from FIFO, size: %i byte",cmd_size);
                    730:     }
                    731:     
                    732:     Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Target: %i",target);
                    733: 
                    734:     SCSIdisk_Receive_Command(commandbuf, identify_msg);
                    735:     seqstep = 4;
                    736:     esp_command_clear();
                    737: 
                    738:     intstatus = INTR_BS | INTR_FC;
                    739:     
                    740:     esp_state = INITIATOR;
                    741:     CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    742: }
                    743: 
                    744: 
                    745: /* DMA done: this is called as part of transfer info or transfer pad
                    746:  * after DMA transfer has completed. */
                    747: 
                    748: enum {
                    749:     ESP_IO_STATE_TRANSFERING,
                    750:     ESP_IO_STATE_FLUSHING,
                    751:     ESP_IO_STATE_DONE
                    752: } esp_io_state;
                    753: 
                    754: bool esp_transfer_done(bool write) {
                    755:     Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer done: ESP counter = %i, SCSI residual bytes: %i",
                    756:                esp_counter,scsi_buffer.size);
                    757:     
                    758:     if (esp_counter == 0) { /* Transfer done */
                    759:         intstatus = INTR_FC;
                    760:         status |= STAT_TC;
                    761:         CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    762:         return true;
                    763:     } else if ((write && SCSIbus.phase!=PHASE_DI) || (!write && SCSIbus.phase!=PHASE_DO)) { /* Phase change detected */
                    764:         esp_command_clear();
                    765:         intstatus = INTR_BS;
                    766:         CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    767:         return true;
                    768:     } /* else continue transfering data, no interrupt */
                    769:     return false;
                    770: }
                    771: 
                    772: 
                    773: /* Transfer information */
                    774: void esp_transfer_info(void) {
                    775:     if(mode_dma) {
                    776:         esp_io_state=ESP_IO_STATE_TRANSFERING;
                    777:         CycInt_AddRelativeInterruptUs(SCSI_Seek_Time() + SCSI_Sector_Time(), 100, INTERRUPT_ESP_IO);
                    778:     } else {
                    779:         Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] start PIO transfer");
                    780:         switch (SCSIbus.phase) {
                    781:             case PHASE_DI:
                    782:                 esp_fifo_write(SCSIdisk_Send_Data());
                    783:                 CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
                    784:                 break;
                    785:             case PHASE_MI:
                    786:                 CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
                    787:                 break;
                    788:             case PHASE_ST:
                    789:                 /* FIXME: What should happen here? */
                    790:                 Log_Printf(LOG_WARN, "[ESP] Error! Transfer info status phase");
                    791:                 CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
                    792:                 break;
                    793:             default:
                    794:                 Log_Printf(LOG_WARN, "[ESP] PIO transfer (unimplemented)");
                    795:                 abort();
                    796:                 break;
                    797:         }
                    798:     }
                    799: }
                    800: void ESP_IO_Handler(void) {
                    801:     CycInt_AcknowledgeInterrupt();
                    802:     
                    803:     switch (esp_io_state) {
                    804:         case ESP_IO_STATE_TRANSFERING:
                    805:             switch (SCSIbus.phase) {
                    806:                 case PHASE_DI:
                    807:                     dma_esp_write_memory();
                    808:                     if (esp_transfer_done(true)) {
                    809:                         esp_io_state=ESP_IO_STATE_FLUSHING;
                    810:                     }
                    811:                     break;
                    812:                 case PHASE_DO:
                    813:                     dma_esp_read_memory();
                    814:                     if (esp_transfer_done(false)) {
                    815:                         return;
                    816:                     }
                    817:                     break;
                    818:                     
                    819:                 default:
                    820:                     break;
                    821:             }
                    822:             break;
                    823:         case ESP_IO_STATE_FLUSHING:
                    824:             Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer done: Flushing DMA buffer.");
                    825:             dma_esp_write_memory();
                    826:             return;
                    827:             
                    828:         default:
                    829:             Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer: Unkown state (%i).",esp_io_state);
                    830:             return;
                    831:     }
                    832:     
                    833:     CycInt_AddRelativeInterruptUs(100, 0, INTERRUPT_ESP_IO);
                    834: }
                    835: 
                    836: 
                    837: /* Transfer padding */
                    838: void esp_transfer_pad(void) {
                    839:     Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer padding, ESP counter: %i bytes, SCSI resid: %i bytes\n",
                    840:                esp_counter, scsi_buffer.size);
                    841: 
                    842:     switch (SCSIbus.phase) {
                    843:         case PHASE_DI:
                    844:             while (SCSIbus.phase==PHASE_DI && esp_counter>0) {
                    845:                 SCSIdisk_Send_Data();
                    846:                 esp_counter--;
                    847:             }
                    848:             esp_transfer_done(true);
                    849:             break;
                    850:         case PHASE_DO:
                    851:             while (SCSIbus.phase==PHASE_DO && esp_counter>0) {
                    852:                 SCSIdisk_Receive_Data(0);
                    853:                 esp_counter--;
                    854:             }
                    855:             esp_transfer_done(false);
                    856:             break;
                    857:             
                    858:         default:
                    859:             abort();
                    860:             break;
                    861:     }
                    862: }
                    863: 
                    864: 
                    865: /* Initiator command complete */
                    866: void esp_initiator_command_complete(void) {
                    867:     
                    868:     if(mode_dma == 1) {
                    869:         Log_Printf(LOG_WARN, "ESP initiator command complete via DMA not implemented!");
                    870:         abort();
                    871:     } else {
                    872:         /* Receive status byte */
                    873:         esp_fifo_write(SCSIdisk_Send_Status()); /* Disk sets phase to msg in after status send */
                    874: 
                    875:         if (SCSIbus.phase!=PHASE_MI) { /* Stop sequence if no phase change to msg in occured */
                    876:             esp_command_clear();
                    877:             intstatus = INTR_BS;
                    878:             CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    879:             return;
                    880:         }
                    881:         
                    882:         /* Receive message byte */
                    883:         esp_fifo_write(SCSIdisk_Send_Message()); /* 0x00 = command complete */
                    884:     }
                    885: 
                    886:     intstatus = INTR_FC;
                    887:     CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    888: }
                    889: 
                    890: 
                    891: /* Message accepted */
                    892: void esp_message_accepted(void) {
                    893:     SCSIbus.phase = PHASE_ST; /* set at the end of iccs? */
                    894:     intstatus = INTR_BS;
                    895:     esp_state = DISCONNECTED; /* CHECK: only disconnected if message was cmd complete? */
                    896:     CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
                    897: }
                    898: 
                    899: 
                    900: 
                    901: #if 0 /* this is for target commands! */
                    902: /* Decode command to determine the command group and thus the
                    903:  * length of the incoming command. Set "valid group code" bit
                    904:  * in status register if the group is 0, 1, 5, 6, or 7 (group
                    905:  * 2 is also valid on NCR53C90A).
                    906:  */
                    907: Uint8 scsi_command_group = (commandbuf[0] & 0xE0) >> 5;
                    908: if(scsi_command_group < 3 || scsi_command_group > 4) {
                    909:     if(ConfigureParams.System.nSCSI == NCR53C90 && scsi_command_group == 2) {
                    910:         Log_Printf(LOG_WARN, "[ESP] Select: Invalid command group %i on NCR53C90\n", scsi_command_group);
                    911:         status &= ~STAT_VGC;
                    912:     } else {
                    913:         status |= STAT_VGC;
                    914:     }
                    915: } else {
                    916:     Log_Printf(LOG_WARN, "[ESP] Select: Invalid command group %i on NCR53C90A\n", scsi_command_group);
                    917:     status &= ~STAT_VGC;
                    918: }
                    919: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.