|
|
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:
1.1.1.2 root 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 */
1.1 root 18:
19:
20: #define IO_SEG_MASK 0x1FFFF
21:
22: typedef enum {
23: DISCONNECTED,
24: INITIATOR,
1.1.1.2 root 25: TARGET
1.1 root 26: } SCSI_STATE;
27:
1.1.1.2 root 28: SCSI_STATE esp_state;
1.1 root 29:
1.1.1.2 root 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);
1.1 root 45:
46: /* ESP Registers */
47: Uint8 writetranscountl;
48: Uint8 writetranscounth;
1.1.1.2 root 49: Uint8 fifo[ESP_FIFO_SIZE];
50: Uint8 command[2];
1.1 root 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:
1.1.1.2 root 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:
1.1 root 139: /* ESP Status Variables */
140: Uint8 mode_dma;
141:
1.1.1.2 root 142: /* Experimental */
143: #define ESP_CLOCK_FREQ 20 /* ESP is clocked at 20 MHz */
1.1.1.3 ! root 144: #define ESP_DELAY 100 /* Standard wait time for ESP interrupt (except bus reset and selection timeout) */
1.1 root 145:
146:
1.1.1.2 root 147: /* ESP DMA control and status registers */
1.1 root 148:
1.1.1.2 root 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];
1.1 root 157:
1.1.1.2 root 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: }
1.1 root 165: }
1.1.1.2 root 166: if (esp_dma.control&ESPCTRL_CHIP_TYPE) {
167: Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is WD33C92\n");
1.1 root 168: } else {
1.1.1.2 root 169: Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is NCR53C90\n");
1.1 root 170: }
1.1.1.2 root 171: if (esp_dma.control&ESPCTRL_RESET) {
172: Log_Printf(LOG_ESPDMA_LEVEL, "reset SCSI controller\n");
1.1 root 173: esp_reset_hard();
174: }
1.1.1.2 root 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");
1.1 root 179: }
1.1.1.2 root 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");
1.1 root 197: break;
1.1.1.2 root 198: case ESPCTRL_CLK12MHz:
199: Log_Printf(LOG_ESPDMA_LEVEL, "12.5 MHz clock\n");
1.1 root 200: break;
1.1.1.2 root 201: case ESPCTRL_CLK16MHz:
202: Log_Printf(LOG_ESPDMA_LEVEL, "16.6 MHz clock\n");
1.1 root 203: break;
1.1.1.2 root 204: case ESPCTRL_CLK20MHz:
205: Log_Printf(LOG_ESPDMA_LEVEL, "20 MHz clock\n");
1.1 root 206: break;
207: default:
208: break;
209: }
210: }
211:
1.1.1.2 root 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());
1.1 root 215: }
216:
1.1.1.2 root 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];
1.1 root 220: }
221:
1.1.1.2 root 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: }
1.1 root 231:
232: /* ESP Registers */
233:
1.1.1.2 root 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());
1.1 root 237: }
238:
1.1.1.2 root 239: void ESP_TransCountL_Write(void) {
1.1 root 240: writetranscountl=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
1.1.1.2 root 241: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountL write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
1.1 root 242: }
243:
1.1.1.2 root 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());
1.1 root 247: }
248:
1.1.1.2 root 249: void ESP_TransCountH_Write(void) {
1.1 root 250: writetranscounth=IoMem[IoAccessCurrentAddress & IO_SEG_MASK];
1.1.1.2 root 251: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountH write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
1.1 root 252: }
253:
1.1.1.2 root 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;
1.1 root 376: } else {
1.1.1.2 root 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;
1.1 root 389: }
390:
1.1.1.2 root 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: }
1.1 root 403:
1.1.1.2 root 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]);
1.1 root 415: }
416: }
417:
1.1.1.2 root 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: }
1.1 root 424: }
425:
1.1.1.2 root 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;
1.1 root 438:
1.1.1.2 root 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;
1.1.1.3 ! root 447: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1.1.2 root 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: }
1.1 root 459: status &= ~STAT_TC;
460: mode_dma = 1;
461: } else {
462: mode_dma = 0;
463: }
464:
1.1.1.2 root 465: switch (cmd & CMD_CMD) {
1.1 root 466: /* Miscellaneous */
467: case CMD_NOP:
1.1.1.2 root 468: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: NOP\n");
469: esp_finish_command();
1.1 root 470: break;
471: case CMD_FLUSH:
1.1.1.2 root 472: Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: flush FIFO\n");
1.1 root 473: esp_flush_fifo();
474: break;
475: case CMD_RESET:
1.1.1.2 root 476: Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: reset chip\n");
1.1 root 477: esp_reset_hard();
478: break;
479: case CMD_BUSRESET:
1.1.1.2 root 480: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: reset SCSI bus\n");
481: esp_bus_reset();
1.1 root 482: break;
483: /* Disconnected */
1.1.1.2 root 484: case CMD_RESEL:
485: Log_Printf(LOG_WARN, "ESP Command: reselect sequence\n");
486: abort();
487: break;
1.1 root 488: case CMD_SEL:
1.1.1.2 root 489: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select without ATN sequence\n");
490: esp_select(false);
1.1 root 491: break;
492: case CMD_SELATN:
1.1.1.2 root 493: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select with ATN sequence\n");
494: esp_select(true);
1.1 root 495: break;
496: case CMD_SELATNS:
1.1.1.2 root 497: Log_Printf(LOG_WARN, "ESP Command: select with ATN and stop sequence\n");
498: abort();
1.1 root 499: break;
500: case CMD_ENSEL:
1.1.1.2 root 501: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: enable selection/reselection\n");
502: esp_finish_command(); /* Our disk doesn't do reselections */
1.1 root 503: break;
504: case CMD_DISSEL:
1.1.1.2 root 505: Log_Printf(LOG_WARN, "ESP Command: disable selection/reselection\n");
506: abort();
1.1 root 507: break;
508: /* Initiator */
509: case CMD_TI:
1.1.1.2 root 510: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer information\n");
511: esp_transfer_info();
1.1 root 512: break;
513: case CMD_ICCS:
1.1.1.2 root 514: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: initiator command complete sequence\n");
515: esp_initiator_command_complete();
1.1 root 516: break;
517: case CMD_MSGACC:
1.1.1.2 root 518: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: message accepted\n");
519: esp_message_accepted();
520: break;
1.1 root 521: case CMD_PAD:
1.1.1.2 root 522: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer pad\n");
523: esp_transfer_pad();
1.1 root 524: break;
525: case CMD_SATN:
1.1.1.2 root 526: Log_Printf(LOG_WARN, "ESP Command: set ATN\n");
527: abort();
1.1 root 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:
1.1.1.2 root 540: Log_Printf(LOG_WARN, "ESP Command: Target commands not emulated!\n");
541: abort();
1.1 root 542: break;
543: case CMD_DIS:
1.1.1.2 root 544: Log_Printf(LOG_WARN, "ESP Command: DISCONNECT not emulated!\n");
545: abort();
546: SCSIbus.phase = PHASE_ST;
547: intstatus = INTR_DC;
1.1 root 548: seqstep = SEQ_0;
549: break;
550:
551: default:
552: Log_Printf(LOG_WARN, "ESP Command: Illegal command!\n");
1.1.1.2 root 553: esp_command_clear();
1.1 root 554: intstatus |= INTR_ILL;
1.1.1.3 ! root 555: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1 root 556: break;
557: }
558: }
559:
560:
1.1.1.2 root 561: /* This is the handler function for ESP delayed interrupts */
562: void ESP_InterruptHandler(void) {
563: CycInt_AcknowledgeInterrupt();
564: esp_raise_irq();
1.1 root 565: }
566:
567:
1.1.1.2 root 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: }
1.1 root 611: }
612:
1.1.1.2 root 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: }
1.1 root 623: }
624:
625: /* Functions */
626:
1.1.1.2 root 627: /* Reset chip */
1.1 root 628: void esp_reset_hard(void) {
1.1.1.2 root 629: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Hard reset\n");
630:
1.1 root 631: clockconv = 0x02;
632: configuration &= ~0xF8; // clear chip test mode, parity enable, parity test, scsi request/int disable, slow cable mode
1.1.1.2 root 633: esp_fifo_clear();
1.1 root 634: syncperiod = 0x05;
635: syncoffset = 0x00;
1.1.1.2 root 636: status &= ~STAT_INT; // release interrupt
637: set_interrupt(INT_SCSI, RELEASE_INT);
1.1 root 638: intstatus = 0x00;
1.1.1.2 root 639: status &= ~(STAT_VGC | STAT_PE | STAT_GE); // clear transfer complete aka valid group code, parity error, gross error
1.1 root 640: esp_reset_soft();
1.1.1.2 root 641: esp_finish_command();
1.1 root 642: }
643:
1.1.1.2 root 644:
645:
1.1 root 646: void esp_reset_soft(void) {
1.1.1.2 root 647: status &= ~STAT_TC; /* clear transfer count zero */
1.1 root 648:
1.1.1.2 root 649: /* check, if this is complete */
1.1 root 650: mode_dma = 0;
1.1.1.2 root 651: esp_counter = 0; /* reset counter, but not actual registers! */
652:
1.1 root 653: seqstep = 0x00;
1.1.1.2 root 654:
655: /* writetranscountl, writetranscounth, selectbusid, selecttimeout are not initialized by reset */
1.1 root 656:
1.1.1.2 root 657: /* This part is "disconnect reset" */
658: esp_command_clear();
659: esp_state = DISCONNECTED;
1.1 root 660: }
661:
662:
1.1.1.2 root 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);
1.1.1.3 ! root 671: CycInt_AddRelativeInterruptUs(500, 0, INTERRUPT_ESP); /* CHECK: how is this delay defined? */
1.1.1.2 root 672: } else {
673: Log_Printf(LOG_ESPCMD_LEVEL,"[ESP] SCSI bus reset not interrupting (configuration=$%02X)\n",configuration);
674: esp_finish_command();
1.1 root 675: }
676: }
677:
1.1.1.2 root 678:
679: /* Flush FIFO */
1.1 root 680: void esp_flush_fifo(void) {
1.1.1.2 root 681: esp_fifo_clear();
682: esp_finish_command();
1.1 root 683: }
684:
1.1.1.2 root 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);
1.1.1.3 ! root 704: CycInt_AddRelativeInterruptUs(seltout, 0, INTERRUPT_ESP);
1.1.1.2 root 705: return;
706: }
1.1 root 707:
1.1.1.2 root 708: /* Next get our command */
1.1 root 709: if(mode_dma == 1) {
1.1.1.2 root 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();
1.1 root 713: } else {
1.1.1.2 root 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: }
1.1 root 721:
1.1.1.2 root 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);
1.1 root 730: }
731:
1.1.1.2 root 732: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Target: %i",target);
1.1 root 733:
1.1.1.2 root 734: SCSIdisk_Receive_Command(commandbuf, identify_msg);
735: seqstep = 4;
736: esp_command_clear();
1.1 root 737:
1.1.1.2 root 738: intstatus = INTR_BS | INTR_FC;
1.1 root 739:
1.1.1.2 root 740: esp_state = INITIATOR;
1.1.1.3 ! root 741: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1 root 742: }
743:
744:
1.1.1.2 root 745: /* DMA done: this is called as part of transfer info or transfer pad
746: * after DMA transfer has completed. */
1.1 root 747:
1.1.1.2 root 748: enum {
749: ESP_IO_STATE_TRANSFERING,
750: ESP_IO_STATE_FLUSHING,
751: ESP_IO_STATE_DONE
752: } esp_io_state;
1.1 root 753:
1.1.1.2 root 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);
1.1 root 757:
1.1.1.2 root 758: if (esp_counter == 0) { /* Transfer done */
759: intstatus = INTR_FC;
760: status |= STAT_TC;
1.1.1.3 ! root 761: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1.1.2 root 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;
1.1.1.3 ! root 766: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1.1.2 root 767: return true;
768: } /* else continue transfering data, no interrupt */
769: return false;
770: }
1.1 root 771:
1.1.1.2 root 772:
773: /* Transfer information */
774: void esp_transfer_info(void) {
775: if(mode_dma) {
776: esp_io_state=ESP_IO_STATE_TRANSFERING;
1.1.1.3 ! root 777: CycInt_AddRelativeInterruptUs(SCSI_Seek_Time() + SCSI_Sector_Time(), 100, INTERRUPT_ESP_IO);
1.1.1.2 root 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());
1.1.1.3 ! root 783: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
1.1.1.2 root 784: break;
785: case PHASE_MI:
1.1.1.3 ! root 786: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
1.1.1.2 root 787: break;
788: case PHASE_ST:
789: /* FIXME: What should happen here? */
790: Log_Printf(LOG_WARN, "[ESP] Error! Transfer info status phase");
1.1.1.3 ! root 791: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP);
1.1.1.2 root 792: break;
793: default:
794: Log_Printf(LOG_WARN, "[ESP] PIO transfer (unimplemented)");
795: abort();
796: break;
1.1 root 797: }
798: }
1.1.1.2 root 799: }
800: void ESP_IO_Handler(void) {
801: CycInt_AcknowledgeInterrupt();
1.1 root 802:
1.1.1.2 root 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: }
1.1 root 832:
1.1.1.3 ! root 833: CycInt_AddRelativeInterruptUs(100, 0, INTERRUPT_ESP_IO);
1.1 root 834: }
835:
836:
1.1.1.2 root 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;
1.1 root 861: }
862: }
863:
864:
1.1.1.2 root 865: /* Initiator command complete */
866: void esp_initiator_command_complete(void) {
1.1 root 867:
1.1.1.2 root 868: if(mode_dma == 1) {
869: Log_Printf(LOG_WARN, "ESP initiator command complete via DMA not implemented!");
1.1 root 870: abort();
1.1.1.2 root 871: } else {
872: /* Receive status byte */
873: esp_fifo_write(SCSIdisk_Send_Status()); /* Disk sets phase to msg in after status send */
1.1 root 874:
1.1.1.2 root 875: if (SCSIbus.phase!=PHASE_MI) { /* Stop sequence if no phase change to msg in occured */
876: esp_command_clear();
877: intstatus = INTR_BS;
1.1.1.3 ! root 878: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1.1.2 root 879: return;
1.1 root 880: }
1.1.1.2 root 881:
882: /* Receive message byte */
883: esp_fifo_write(SCSIdisk_Send_Message()); /* 0x00 = command complete */
1.1 root 884: }
1.1.1.2 root 885:
886: intstatus = INTR_FC;
1.1.1.3 ! root 887: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1 root 888: }
889:
1.1.1.2 root 890:
891: /* Message accepted */
892: void esp_message_accepted(void) {
893: SCSIbus.phase = PHASE_ST; /* set at the end of iccs? */
1.1 root 894: intstatus = INTR_BS;
1.1.1.2 root 895: esp_state = DISCONNECTED; /* CHECK: only disconnected if message was cmd complete? */
1.1.1.3 ! root 896: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP);
1.1 root 897: }
898:
899:
900:
1.1.1.2 root 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;
1.1 root 914: }
1.1.1.2 root 915: } else {
916: Log_Printf(LOG_WARN, "[ESP] Select: Invalid command group %i on NCR53C90A\n", scsi_command_group);
917: status &= ~STAT_VGC;
1.1 root 918: }
1.1.1.2 root 919: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.