|
|
1.1 root 1: /* NeXT DMA Emulation
2: * Contains informations from QEMU-NeXT
1.1.1.3 ! root 3: * NeXT Integrated Channel Processor (ISP) consists of 12 channel processors
! 4: * with 128 bytes internal buffer for each channel.
! 5: * 12 channels:
! 6: * SCSI, Sound in, Sound out, Optical disk, Printer, SCC, DSP,
1.1 root 7: * Ethernet transmit, Ethernet receive, Video, Memory to register, Register to memory
8: */
9:
10: #include "ioMem.h"
11: #include "ioMemTables.h"
12: #include "m68000.h"
1.1.1.3 ! root 13: #include "scsi.h"
1.1 root 14: #include "esp.h"
1.1.1.3 ! root 15: #include "mo.h"
! 16: #include "scc.h"
1.1 root 17: #include "sysReg.h"
18: #include "dma.h"
19: #include "configuration.h"
20: #include "ethernet.h"
1.1.1.3 ! root 21: #include "floppy.h"
! 22: #include "printer.h"
! 23: #include "snd.h"
! 24: #include "dsp.h"
! 25: #include "mmu_common.h"
1.1 root 26:
27:
28:
1.1.1.3 ! root 29: #define LOG_DMA_LEVEL LOG_DEBUG
1.1 root 30:
1.1.1.3 ! root 31: #define IO_SEG_MASK 0x1FFFF
1.1 root 32:
1.1.1.3 ! root 33: enum {
! 34: CHANNEL_SCSI, // 0x00000010
! 35: CHANNEL_SOUNDOUT, // 0x00000040
! 36: CHANNEL_DISK, // 0x00000050
! 37: CHANNEL_SOUNDIN, // 0x00000080
! 38: CHANNEL_PRINTER, // 0x00000090
! 39: CHANNEL_SCC, // 0x000000c0
! 40: CHANNEL_DSP, // 0x000000d0
! 41: CHANNEL_EN_TX, // 0x00000110
! 42: CHANNEL_EN_RX, // 0x00000150
! 43: CHANNEL_VIDEO, // 0x00000180
! 44: CHANNEL_M2R, // 0x000001d0
! 45: CHANNEL_R2M // 0x000001c0
! 46: } DMA_CHANNEL;
! 47:
! 48: int get_channel(Uint32 address);
! 49: int get_interrupt_type(int channel);
! 50: void dma_interrupt(int channel);
! 51: void dma_initialize_buffer(int channel, Uint8 offset);
1.1 root 52:
53:
1.1.1.3 ! root 54: struct {
! 55: Uint8 csr;
1.1 root 56: Uint32 saved_next;
57: Uint32 saved_limit;
58: Uint32 saved_start;
59: Uint32 saved_stop;
60: Uint32 next;
61: Uint32 limit;
62: Uint32 start;
63: Uint32 stop;
1.1.1.3 ! root 64:
! 65: Uint8 direction;
! 66: } dma[12];
! 67:
! 68:
! 69: /* DMA internal buffers */
! 70: #define DMA_BURST_SIZE 16
1.1 root 71:
1.1.1.3 ! root 72: int espdma_buf_size = 0;
! 73: int espdma_buf_limit = 0;
! 74: Uint8 espdma_buf[DMA_BURST_SIZE];
! 75: int modma_buf_size = 0;
! 76: int modma_buf_limit = 0;
! 77: Uint8 modma_buf[DMA_BURST_SIZE];
1.1 root 78:
79:
1.1.1.3 ! root 80: /* Read and write CSR bits for 68030 based NeXT Computer. */
! 81:
! 82: /* read CSR bits */
! 83: #define DMA_ENABLE 0x01 /* enable dma transfer */
! 84: #define DMA_SUPDATE 0x02 /* single update */
! 85: #define DMA_COMPLETE 0x08 /* current dma has completed */
! 86: #define DMA_BUSEXC 0x10 /* bus exception occurred */
! 87: /* write CSR bits */
! 88: #define DMA_SETENABLE 0x01 /* set enable */
! 89: #define DMA_SETSUPDATE 0x02 /* set single update */
! 90: #define DMA_M2DEV 0x00 /* dma from mem to dev */
! 91: #define DMA_DEV2M 0x04 /* dma from dev to mem */
! 92: #define DMA_CLRCOMPLETE 0x08 /* clear complete conditional */
! 93: #define DMA_RESET 0x10 /* clr cmplt, sup, enable */
! 94: #define DMA_INITBUF 0x20 /* initialize DMA buffers */
! 95:
! 96: /* CSR masks */
! 97: #define DMA_CMD_MASK (DMA_SETENABLE|DMA_SETSUPDATE|DMA_CLRCOMPLETE|DMA_RESET|DMA_INITBUF)
! 98: #define DMA_STAT_MASK (DMA_ENABLE|DMA_SUPDATE|DMA_COMPLETE|DMA_BUSEXC)
! 99:
! 100:
! 101: /* Read and write CSR bits for 68040 based Machines.
! 102: * We convert these to 68030 values before using in functions.
! 103: * read CSR bits *
! 104: #define DMA_ENABLE 0x01000000
! 105: #define DMA_SUPDATE 0x02000000
! 106: #define DMA_COMPLETE 0x08000000
! 107: #define DMA_BUSEXC 0x10000000
! 108: * write CSR bits *
! 109: #define DMA_SETENABLE 0x00010000
! 110: #define DMA_SETSUPDATE 0x00020000
! 111: #define DMA_M2DEV 0x00000000
! 112: #define DMA_DEV2M 0x00040000
! 113: #define DMA_CLRCOMPLETE 0x00080000
! 114: #define DMA_RESET 0x00100000
! 115: #define DMA_INITBUF 0x00200000
! 116: */
! 117:
! 118:
! 119:
! 120: static inline Uint32 dma_getlong(Uint8 *buf, Uint32 pos) {
! 121: return (buf[pos] << 24) | (buf[pos+1] << 16) | (buf[pos+2] << 8) | buf[pos+3];
! 122: }
! 123:
! 124: static inline void dma_putlong(Uint32 val, Uint8 *buf, Uint32 pos) {
! 125: buf[pos] = val >> 24;
! 126: buf[pos+1] = val >> 16;
! 127: buf[pos+2] = val >> 8;
! 128: buf[pos+3] = val;
! 129: }
! 130:
1.1 root 131:
132: int get_channel(Uint32 address) {
133: int channel = address&IO_SEG_MASK;
1.1.1.3 ! root 134:
1.1 root 135: switch (channel) {
1.1.1.3 ! root 136: case 0x010: Log_Printf(LOG_DMA_LEVEL,"channel SCSI:"); return CHANNEL_SCSI; break;
! 137: case 0x040: Log_Printf(LOG_DMA_LEVEL,"channel Sound Out:"); return CHANNEL_SOUNDOUT; break;
! 138: case 0x050: Log_Printf(LOG_DMA_LEVEL,"channel MO Disk:"); return CHANNEL_DISK; break;
! 139: case 0x080: Log_Printf(LOG_DMA_LEVEL,"channel Sound in:"); return CHANNEL_SOUNDIN; break;
! 140: case 0x090: Log_Printf(LOG_DMA_LEVEL,"channel Printer:"); return CHANNEL_PRINTER; break;
! 141: case 0x0c0: Log_Printf(LOG_DMA_LEVEL,"channel SCC:"); return CHANNEL_SCC; break;
! 142: case 0x0d0: Log_Printf(LOG_DMA_LEVEL,"channel DSP:"); return CHANNEL_DSP; break;
! 143: case 0x110: Log_Printf(LOG_DMA_LEVEL,"channel Ethernet Tx:"); return CHANNEL_EN_TX; break;
! 144: case 0x150: Log_Printf(LOG_DMA_LEVEL,"channel Ethernet Rx:"); return CHANNEL_EN_RX; break;
! 145: case 0x180: Log_Printf(LOG_DMA_LEVEL,"channel Video:"); return CHANNEL_VIDEO; break;
! 146: case 0x1d0: Log_Printf(LOG_DMA_LEVEL,"channel M2R:"); return CHANNEL_M2R; break;
! 147: case 0x1c0: Log_Printf(LOG_DMA_LEVEL,"channel R2M:"); return CHANNEL_R2M; break;
1.1 root 148:
149: default:
1.1.1.3 ! root 150: Log_Printf(LOG_WARN, "Unknown DMA channel!\n");
1.1 root 151: return -1;
152: break;
153: }
154: }
155:
156: int get_interrupt_type(int channel) {
157: switch (channel) {
158: case CHANNEL_SCSI: return INT_SCSI_DMA; break;
159: case CHANNEL_SOUNDOUT: return INT_SND_OUT_DMA; break;
160: case CHANNEL_DISK: return INT_DISK_DMA; break;
161: case CHANNEL_SOUNDIN: return INT_SND_IN_DMA; break;
162: case CHANNEL_PRINTER: return INT_PRINTER_DMA; break;
163: case CHANNEL_SCC: return INT_SCC_DMA; break;
164: case CHANNEL_DSP: return INT_DSP_DMA; break;
165: case CHANNEL_EN_TX: return INT_EN_TX_DMA; break;
166: case CHANNEL_EN_RX: return INT_EN_RX_DMA; break;
1.1.1.3 ! root 167: case CHANNEL_VIDEO: return INT_VIDEO; break;
1.1 root 168: case CHANNEL_M2R: return INT_M2R_DMA; break;
169: case CHANNEL_R2M: return INT_R2M_DMA; break;
170:
171: default:
1.1.1.3 ! root 172: Log_Printf(LOG_WARN, "Unknown DMA interrupt!\n");
1.1 root 173: return 0;
174: break;
175: }
176: }
177:
178: void DMA_CSR_Read(void) { // 0x02000010, length of register is byte on 68030 based NeXT Computer
179: int channel = get_channel(IoAccessCurrentAddress);
1.1.1.3 ! root 180:
! 181: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = dma[channel].csr;
! 182: IoMem[(IoAccessCurrentAddress+1) & IO_SEG_MASK] = IoMem[(IoAccessCurrentAddress+2) & IO_SEG_MASK] = IoMem[(IoAccessCurrentAddress+3) & IO_SEG_MASK] = 0x00; // just to be sure
! 183: Log_Printf(LOG_DMA_LEVEL,"DMA CSR read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].csr, m68k_getpc());
1.1 root 184: }
185:
186: void DMA_CSR_Write(void) {
187: int channel = get_channel(IoAccessCurrentAddress);
188: int interrupt = get_interrupt_type(channel);
1.1.1.3 ! root 189: Uint8 writecsr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]|IoMem[(IoAccessCurrentAddress+1) & IO_SEG_MASK]|IoMem[(IoAccessCurrentAddress+2) & IO_SEG_MASK]|IoMem[(IoAccessCurrentAddress+3) & IO_SEG_MASK];
! 190:
! 191: Log_Printf(LOG_DMA_LEVEL,"DMA CSR write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, writecsr, m68k_getpc());
! 192:
! 193: /* For debugging */
! 194: if(writecsr&DMA_DEV2M)
1.1 root 195: Log_Printf(LOG_DMA_LEVEL,"DMA from dev to mem");
1.1.1.3 ! root 196: else
1.1 root 197: Log_Printf(LOG_DMA_LEVEL,"DMA from mem to dev");
1.1.1.3 ! root 198:
! 199: switch (writecsr&DMA_CMD_MASK) {
! 200: case DMA_RESET:
! 201: Log_Printf(LOG_DMA_LEVEL,"DMA reset"); break;
! 202: case DMA_INITBUF:
! 203: Log_Printf(LOG_DMA_LEVEL,"DMA initialize buffers"); break;
! 204: case (DMA_RESET | DMA_INITBUF):
! 205: case (DMA_RESET | DMA_INITBUF | DMA_CLRCOMPLETE):
! 206: Log_Printf(LOG_DMA_LEVEL,"DMA reset and initialize buffers"); break;
! 207: case DMA_CLRCOMPLETE:
! 208: Log_Printf(LOG_DMA_LEVEL,"DMA end chaining"); break;
! 209: case (DMA_SETSUPDATE | DMA_CLRCOMPLETE):
! 210: Log_Printf(LOG_DMA_LEVEL,"DMA continue chaining"); break;
! 211: case DMA_SETENABLE:
! 212: Log_Printf(LOG_DMA_LEVEL,"DMA start single transfer"); break;
! 213: case (DMA_SETENABLE | DMA_SETSUPDATE):
! 214: case (DMA_SETENABLE | DMA_SETSUPDATE | DMA_CLRCOMPLETE):
! 215: Log_Printf(LOG_DMA_LEVEL,"DMA start chaining"); break;
! 216: case 0:
! 217: Log_Printf(LOG_DMA_LEVEL,"DMA no command"); break;
! 218: default:
! 219: Log_Printf(LOG_DMA_LEVEL,"DMA: unknown command!"); break;
1.1 root 220: }
1.1.1.3 ! root 221:
! 222: /* Handle CSR bits */
! 223: dma[channel].direction = writecsr&DMA_DEV2M;
! 224:
! 225: if (writecsr&DMA_RESET) {
! 226: dma[channel].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | DMA_ENABLE);
1.1.1.2 root 227: }
1.1.1.3 ! root 228: if (writecsr&DMA_INITBUF) {
! 229: dma_initialize_buffer(channel, 0);
1.1 root 230: }
1.1.1.3 ! root 231: if (writecsr&DMA_SETSUPDATE) {
1.1 root 232: dma[channel].csr |= DMA_SUPDATE;
233: }
1.1.1.3 ! root 234: if (writecsr&DMA_SETENABLE) {
! 235: dma[channel].csr |= DMA_ENABLE;
! 236: switch (channel) {
! 237: case CHANNEL_M2R:
! 238: case CHANNEL_R2M:
! 239: if (dma[channel].next==dma[channel].limit) {
! 240: dma[channel].csr&= ~DMA_ENABLE;
! 241: }
! 242: if ((dma[CHANNEL_M2R].csr&DMA_ENABLE)&&(dma[CHANNEL_R2M].csr&DMA_ENABLE)) {
! 243: /* Enable Memory to Memory DMA, if read and write channels are enabled */
! 244: dma_m2m_write_memory();
! 245: }
! 246: break;
! 247:
! 248: default: break;
! 249: }
1.1 root 250: }
1.1.1.3 ! root 251: if (writecsr&DMA_CLRCOMPLETE) {
! 252: dma[channel].csr &= ~DMA_COMPLETE;
1.1 root 253: }
1.1.1.3 ! root 254:
! 255: set_interrupt(interrupt, RELEASE_INT); // experimental
1.1 root 256: }
257:
258: void DMA_Saved_Next_Read(void) { // 0x02004000
259: int channel = get_channel(IoAccessCurrentAddress-0x3FF0);
260: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_next);
261: Log_Printf(LOG_DMA_LEVEL,"DMA SNext read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_next, m68k_getpc());
262: }
263:
264: void DMA_Saved_Next_Write(void) {
265: int channel = get_channel(IoAccessCurrentAddress-0x3FF0);
266: dma[channel].saved_next = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
267: Log_Printf(LOG_DMA_LEVEL,"DMA SNext write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_next, m68k_getpc());
268: }
269:
270: void DMA_Saved_Limit_Read(void) { // 0x02004004
271: int channel = get_channel(IoAccessCurrentAddress-0x3FF4);
272: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_limit);
273: Log_Printf(LOG_DMA_LEVEL,"DMA SLimit read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_limit, m68k_getpc());
274: }
275:
276: void DMA_Saved_Limit_Write(void) {
277: int channel = get_channel(IoAccessCurrentAddress-0x3FF4);
278: dma[channel].saved_limit = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
279: Log_Printf(LOG_DMA_LEVEL,"DMA SLimit write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_limit, m68k_getpc());
280: }
281:
282: void DMA_Saved_Start_Read(void) { // 0x02004008
283: int channel = get_channel(IoAccessCurrentAddress-0x3FF8);
284: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_start);
285: Log_Printf(LOG_DMA_LEVEL,"DMA SStart read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_start, m68k_getpc());
286: }
287:
288: void DMA_Saved_Start_Write(void) {
289: int channel = get_channel(IoAccessCurrentAddress-0x3FF8);
290: dma[channel].saved_start = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
291: Log_Printf(LOG_DMA_LEVEL,"DMA SStart write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_start, m68k_getpc());
292: }
293:
294: void DMA_Saved_Stop_Read(void) { // 0x0200400c
295: int channel = get_channel(IoAccessCurrentAddress-0x3FFC);
296: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_stop);
297: Log_Printf(LOG_DMA_LEVEL,"DMA SStop read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_stop, m68k_getpc());
298: }
299:
300: void DMA_Saved_Stop_Write(void) {
301: int channel = get_channel(IoAccessCurrentAddress-0x3FFC);
302: dma[channel].saved_stop = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
303: Log_Printf(LOG_DMA_LEVEL,"DMA SStop write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_stop, m68k_getpc());
304: }
305:
306: void DMA_Next_Read(void) { // 0x02004010
307: int channel = get_channel(IoAccessCurrentAddress-0x4000);
308: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].next);
309: Log_Printf(LOG_DMA_LEVEL,"DMA Next read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
310: }
311:
312: void DMA_Next_Write(void) {
313: int channel = get_channel(IoAccessCurrentAddress-0x4000);
314: dma[channel].next = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
315: Log_Printf(LOG_DMA_LEVEL,"DMA Next write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
316: }
317:
318: void DMA_Limit_Read(void) { // 0x02004014
319: int channel = get_channel(IoAccessCurrentAddress-0x4004);
320: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].limit);
321: Log_Printf(LOG_DMA_LEVEL,"DMA Limit read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].limit, m68k_getpc());
322: }
323:
324: void DMA_Limit_Write(void) {
325: int channel = get_channel(IoAccessCurrentAddress-0x4004);
326: dma[channel].limit = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
327: Log_Printf(LOG_DMA_LEVEL,"DMA Limit write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].limit, m68k_getpc());
328: }
329:
330: void DMA_Start_Read(void) { // 0x02004018
331: int channel = get_channel(IoAccessCurrentAddress-0x4008);
332: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].start);
333: Log_Printf(LOG_DMA_LEVEL,"DMA Start read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].start, m68k_getpc());
334: }
335:
336: void DMA_Start_Write(void) {
337: int channel = get_channel(IoAccessCurrentAddress-0x4008);
338: dma[channel].start = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
339: Log_Printf(LOG_DMA_LEVEL,"DMA Start write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].start, m68k_getpc());
340: }
341:
342: void DMA_Stop_Read(void) { // 0x0200401c
343: int channel = get_channel(IoAccessCurrentAddress-0x400C);
344: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].stop);
345: Log_Printf(LOG_DMA_LEVEL,"DMA Stop read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].stop, m68k_getpc());
346: }
347:
348: void DMA_Stop_Write(void) {
349: int channel = get_channel(IoAccessCurrentAddress-0x400C);
350: dma[channel].stop = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
351: Log_Printf(LOG_DMA_LEVEL,"DMA Stop write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].stop, m68k_getpc());
352: }
353:
354: void DMA_Init_Read(void) { // 0x02004210
355: int channel = get_channel(IoAccessCurrentAddress-0x4200);
1.1.1.3 ! root 356: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].next);
! 357: Log_Printf(LOG_DMA_LEVEL,"DMA Init read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
1.1 root 358: }
359:
360: void DMA_Init_Write(void) {
361: int channel = get_channel(IoAccessCurrentAddress-0x4200);
1.1.1.3 ! root 362: dma[channel].next = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
! 363: dma_initialize_buffer(channel, dma[channel].next&0xF);
! 364: Log_Printf(LOG_DMA_LEVEL,"DMA Init write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
1.1 root 365: }
366:
1.1.1.3 ! root 367: /* Initialize DMA internal buffer */
! 368:
! 369: void dma_initialize_buffer(int channel, Uint8 offset) {
! 370: if (offset>0) {
! 371: Log_Printf(LOG_WARN, "DMA Initializing buffer with offset %i", offset);
! 372: }
! 373: switch (channel) {
! 374: case CHANNEL_SCSI:
! 375: esp_dma.status = 0x00; /* just a guess */
! 376: espdma_buf_size = 0;
! 377: espdma_buf_limit = offset;
! 378: break;
! 379: case CHANNEL_DISK:
! 380: modma_buf_size = 0;
! 381: modma_buf_limit = offset;
! 382: break;
! 383: default:
! 384: break;
! 385: }
1.1 root 386: }
387:
1.1.1.3 ! root 388: /* DMA interrupt functions */
! 389:
! 390: void dma_interrupt(int channel) {
! 391: int interrupt = get_interrupt_type(channel);
! 392:
! 393: /* If we have reached limit, generate an interrupt and set the flags */
! 394: if (dma[channel].next==dma[channel].limit) {
! 395:
! 396: dma[channel].csr |= DMA_COMPLETE;
! 397:
! 398: if (dma[channel].csr & DMA_SUPDATE) { /* if we are in chaining mode */
! 399: dma[channel].next = dma[channel].start;
! 400: dma[channel].limit = dma[channel].stop;
! 401: /* Set bits in CSR */
! 402: dma[channel].csr &= ~DMA_SUPDATE; /* 1st done */
! 403: } else {
! 404: dma[channel].csr &= ~DMA_ENABLE; /* all done */
! 405: }
! 406: set_interrupt(interrupt, SET_INT);
! 407: } else if (dma[channel].csr&DMA_BUSEXC) {
! 408: set_interrupt(interrupt, SET_INT);
! 409: }
1.1 root 410: }
411:
412:
1.1.1.3 ! root 413: /* Functions for delayed interrupts */
! 414:
! 415: /* Handler functions for DMA M2M delyed interrupts */
! 416: void M2RDMA_InterruptHandler(void) {
! 417: CycInt_AcknowledgeInterrupt();
! 418: dma_interrupt(CHANNEL_M2R);
! 419: }
! 420: void R2MDMA_InterruptHandler(void) {
! 421: CycInt_AcknowledgeInterrupt();
! 422: dma_interrupt(CHANNEL_R2M);
! 423: }
1.1 root 424:
425:
1.1.1.3 ! root 426: /* DMA Read and Write Memory Functions */
1.1 root 427:
1.1.1.3 ! root 428: /* Channel SCSI (shared with floppy drive) */
! 429: void dma_esp_write_memory(void) {
! 430: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Write to memory at $%08x, %i bytes (ESP counter %i)",
! 431: dma[CHANNEL_SCSI].next,dma[CHANNEL_SCSI].limit-dma[CHANNEL_SCSI].next,esp_counter);
1.1 root 432:
1.1.1.3 ! root 433: if (!(dma[CHANNEL_SCSI].csr&DMA_ENABLE)) {
! 434: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Error! DMA not enabled!");
! 435: return;
! 436: }
! 437: if ((dma[CHANNEL_SCSI].limit%DMA_BURST_SIZE) || (dma[CHANNEL_SCSI].next%4)) {
! 438: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 439: dma[CHANNEL_SCSI].next, dma[CHANNEL_SCSI].limit);
! 440: abort();
! 441: }
! 442:
! 443: TRY(prb) {
! 444: if (espdma_buf_size>0) {
! 445: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Starting with %i residual bytes in DMA buffer.", espdma_buf_size);
! 446: }
! 447:
! 448: while (dma[CHANNEL_SCSI].next<=dma[CHANNEL_SCSI].limit) {
! 449: /* Fill DMA channel FIFO (only if limit < FIFO size) */
! 450: if (espdma_buf_limit<DMA_BURST_SIZE) {
! 451: if (floppy_select) {
! 452: while (espdma_buf_limit<DMA_BURST_SIZE && flp_buffer.size>0) {
! 453: espdma_buf[espdma_buf_limit]=flp_buffer.data[flp_buffer.limit-flp_buffer.size];
! 454: flp_buffer.size--;
! 455: espdma_buf_limit++;
! 456: espdma_buf_size++;
! 457: }
! 458: } else {
! 459: while (espdma_buf_limit<DMA_BURST_SIZE && esp_counter>0 && SCSIbus.phase==PHASE_DI) {
! 460: espdma_buf[espdma_buf_limit]=SCSIdisk_Send_Data();
! 461: esp_counter--;
! 462: espdma_buf_limit++;
! 463: espdma_buf_size++;
! 464: }
! 465: }
! 466: }
! 467:
! 468: if (espdma_buf_limit<DMA_BURST_SIZE) { /* Not complete, stop */
! 469: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: No more data. Stopping with %i residual bytes.",
! 470: espdma_buf_size);
! 471: break;
! 472: } else { /* Empty DMA channel FIFO (only if limit reached FIFO size) */
! 473: ESP_DMA_set_status();
! 474:
! 475: while (dma[CHANNEL_SCSI].next<dma[CHANNEL_SCSI].limit && espdma_buf_size>0) {
! 476: NEXTMemory_WriteLong(dma[CHANNEL_SCSI].next, dma_getlong(espdma_buf, DMA_BURST_SIZE-espdma_buf_size));
! 477: dma[CHANNEL_SCSI].next+=4;
! 478: espdma_buf_size-=4;
! 479: }
! 480: if (espdma_buf_size>0) { /* Not complete, stop */
! 481: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Channel limit reached. Stopping with %i residual bytes.",
! 482: espdma_buf_size);
! 483: break;
! 484: }
! 485: espdma_buf_limit = espdma_buf_size; /* Should be 0 */
! 486: }
! 487: }
! 488: } CATCH(prb) {
! 489: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Bus error while writing to %08x",dma[CHANNEL_SCSI].next);
! 490: dma[CHANNEL_SCSI].csr &= ~DMA_ENABLE;
! 491: dma[CHANNEL_SCSI].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 492: } ENDTRY
1.1 root 493:
1.1.1.3 ! root 494: dma_interrupt(CHANNEL_SCSI);
! 495: }
! 496:
! 497: void dma_esp_flush_buffer(void) {
! 498: if (!(dma[CHANNEL_SCSI].csr&DMA_ENABLE)) {
! 499: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Not flushing buffer. DMA not enabled.");
! 500: return;
! 501: }
! 502: if (dma[CHANNEL_SCSI].direction!=DMA_DEV2M) {
! 503: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Not flushing buffer. Bad direction!");
! 504: return;
! 505: }
! 506:
! 507: TRY(prb) {
! 508: if (dma[CHANNEL_SCSI].next<dma[CHANNEL_SCSI].limit) {
! 509: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Flush buffer to memory at $%08x, 4 bytes",dma[CHANNEL_SCSI].next);
! 510: if (espdma_buf_size>0) {
! 511: /* Write one long word to memory */
! 512: NEXTMemory_WriteLong(dma[CHANNEL_SCSI].next, dma_getlong(espdma_buf, espdma_buf_limit-espdma_buf_size));
! 513: espdma_buf_size-=4;
! 514: }
! 515: dma[CHANNEL_SCSI].next+=4;
! 516: } else {
! 517: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Not flushing buffer. DMA done.");
! 518: }
! 519: } CATCH(prb) {
! 520: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Bus error while flushing to %08x",dma[CHANNEL_SCSI].next);
! 521: dma[CHANNEL_SCSI].csr &= ~DMA_ENABLE;
! 522: dma[CHANNEL_SCSI].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 523: } ENDTRY
1.1 root 524:
1.1.1.3 ! root 525: dma_interrupt(CHANNEL_SCSI);
! 526: }
1.1 root 527:
1.1.1.3 ! root 528: void dma_esp_read_memory(void) {
! 529: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Read from memory at $%08x, %i bytes (ESP counter %i)",
! 530: dma[CHANNEL_SCSI].next,dma[CHANNEL_SCSI].limit-dma[CHANNEL_SCSI].next,esp_counter);
1.1 root 531:
1.1.1.3 ! root 532: if (!(dma[CHANNEL_SCSI].csr&DMA_ENABLE)) {
! 533: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Error! DMA not enabled!");
! 534: return;
! 535: }
! 536: if ((dma[CHANNEL_SCSI].limit%DMA_BURST_SIZE) || (dma[CHANNEL_SCSI].next%4)) {
! 537: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 538: dma[CHANNEL_SCSI].next, dma[CHANNEL_SCSI].limit);
! 539: abort();
! 540: }
1.1 root 541:
1.1.1.3 ! root 542: TRY(prb) {
! 543: if (espdma_buf_size>0) {
! 544: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Starting with %i residual bytes in DMA buffer.", espdma_buf_size);
! 545: }
! 546:
! 547: while (dma[CHANNEL_SCSI].next<dma[CHANNEL_SCSI].limit) {
! 548: /* Read data from memory to DMA channel FIFO (only if limit < FIFO size) */
! 549: if (espdma_buf_limit<DMA_BURST_SIZE) {
! 550: while (dma[CHANNEL_SCSI].next<dma[CHANNEL_SCSI].limit && espdma_buf_limit<DMA_BURST_SIZE) {
! 551: dma_putlong(NEXTMemory_ReadLong(dma[CHANNEL_SCSI].next), espdma_buf, espdma_buf_limit);
! 552: dma[CHANNEL_SCSI].next+=4;
! 553: espdma_buf_limit+=4;
! 554: espdma_buf_size+=4;
! 555: }
! 556: }
! 557:
! 558: if (espdma_buf_limit<DMA_BURST_SIZE) { /* Not complete, stop */
! 559: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Channel limit reached. Stopping with %i residual bytes.",
! 560: espdma_buf_size);
! 561: break;
! 562: } else { /* Empty DMA channel FIFO (only if limit reached FIFO size) */
! 563: ESP_DMA_set_status();
! 564:
! 565: if (floppy_select) {
! 566: while (espdma_buf_size>0 && flp_buffer.size<flp_buffer.limit) {
! 567: flp_buffer.data[flp_buffer.size]=espdma_buf[espdma_buf_limit-espdma_buf_size];
! 568: flp_buffer.size++;
! 569: espdma_buf_size--;
! 570: }
! 571: } else {
! 572: while (espdma_buf_size>0 && esp_counter>0 && SCSIbus.phase==PHASE_DO) {
! 573: SCSIdisk_Receive_Data(espdma_buf[espdma_buf_limit-espdma_buf_size]);
! 574: esp_counter--;
! 575: espdma_buf_size--;
! 576: }
! 577: }
! 578: if (espdma_buf_size>0) { /* Not complete, stop */
! 579: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: No more data request. Stopping with %i residual bytes.",
! 580: espdma_buf_size);
! 581: break;
! 582: }
! 583: espdma_buf_limit = espdma_buf_size; /* Should be 0 */
! 584: }
! 585: }
! 586: } CATCH(prb) {
! 587: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Bus error while reading from %08x",dma[CHANNEL_SCSI].next);
! 588: dma[CHANNEL_SCSI].csr &= ~DMA_ENABLE;
! 589: dma[CHANNEL_SCSI].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 590: } ENDTRY
1.1 root 591:
1.1.1.3 ! root 592: if ((floppy_select && flp_buffer.size<flp_buffer.limit) || SCSIbus.phase==PHASE_DO) {
! 593: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Warning! Data not yet written to disk.");
! 594: if (espdma_buf_size!=0) {
! 595: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: WARNING: Loss of data in DMA buffer possible!");
! 596: }
! 597: }
1.1 root 598:
1.1.1.3 ! root 599: dma_interrupt(CHANNEL_SCSI);
! 600: }
! 601:
! 602:
! 603: /* Channel MO */
! 604: void dma_mo_write_memory(void) {
! 605: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: Write to memory at $%08x, %i bytes",
! 606: dma[CHANNEL_DISK].next,dma[CHANNEL_DISK].limit-dma[CHANNEL_DISK].next);
1.1 root 607:
1.1.1.3 ! root 608: if (!(dma[CHANNEL_DISK].csr&DMA_ENABLE)) {
! 609: Log_Printf(LOG_WARN, "[DMA] Channel MO: Error! DMA not enabled!");
! 610: return;
! 611: }
! 612: if ((dma[CHANNEL_DISK].limit%DMA_BURST_SIZE) || (dma[CHANNEL_DISK].next%4)) {
! 613: Log_Printf(LOG_WARN, "[DMA] Channel MO: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 614: dma[CHANNEL_DISK].next, dma[CHANNEL_DISK].limit);
! 615: abort();
1.1 root 616: }
1.1.1.3 ! root 617:
! 618: TRY(prb) {
! 619: if (modma_buf_size>0) {
! 620: Log_Printf(LOG_WARN, "[DMA] Channel MO: Starting with %i residual bytes in DMA buffer.", modma_buf_size);
! 621: }
! 622:
! 623: while (dma[CHANNEL_DISK].next<=dma[CHANNEL_DISK].limit) {
! 624: /* Fill DMA channel FIFO (only if limit < FIFO size) */
! 625: if (modma_buf_limit<DMA_BURST_SIZE) {
! 626: while (modma_buf_limit<DMA_BURST_SIZE && ecc_buffer[eccout].size>0) {
! 627: modma_buf[modma_buf_limit]=ecc_buffer[eccout].data[ecc_buffer[eccout].limit-ecc_buffer[eccout].size];
! 628: ecc_buffer[eccout].size--;
! 629: modma_buf_limit++;
! 630: modma_buf_size++;
! 631: }
! 632: }
! 633:
! 634: if (modma_buf_limit<DMA_BURST_SIZE) { /* Not complete, stop */
! 635: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: No more data. Stopping with %i residual bytes.",
! 636: modma_buf_size);
! 637: break;
! 638: } else { /* Empty DMA channel FIFO (only if limit reached FIFO size) */
! 639: while (dma[CHANNEL_DISK].next<dma[CHANNEL_DISK].limit && modma_buf_size>0) {
! 640: NEXTMemory_WriteLong(dma[CHANNEL_DISK].next, dma_getlong(modma_buf, DMA_BURST_SIZE-modma_buf_size));
! 641: dma[CHANNEL_DISK].next+=4;
! 642: modma_buf_size-=4;
! 643: }
! 644: if (modma_buf_size>0) { /* Not complete, stop */
! 645: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: Channel limit reached. Stopping with %i residual bytes.",
! 646: modma_buf_size);
! 647: break;
! 648: }
! 649: modma_buf_limit = modma_buf_size; /* Should be 0 */
! 650: }
! 651: }
! 652: } CATCH(prb) {
! 653: Log_Printf(LOG_WARN, "[DMA] Channel MO: Bus error while writing to %08x",dma[CHANNEL_DISK].next);
! 654: dma[CHANNEL_DISK].csr &= ~DMA_ENABLE;
! 655: dma[CHANNEL_DISK].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 656: } ENDTRY
! 657:
! 658: dma_interrupt(CHANNEL_DISK);
! 659: }
1.1 root 660:
1.1.1.3 ! root 661: void dma_mo_read_memory(void) {
! 662: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: Read from memory at $%08x, %i bytes",
! 663: dma[CHANNEL_DISK].next,dma[CHANNEL_DISK].limit-dma[CHANNEL_DISK].next);
1.1 root 664:
1.1.1.3 ! root 665: if (!(dma[CHANNEL_DISK].csr&DMA_ENABLE)) {
! 666: Log_Printf(LOG_WARN, "[DMA] Channel MO: Error! DMA not enabled!");
! 667: return;
! 668: }
! 669: if ((dma[CHANNEL_DISK].limit%DMA_BURST_SIZE) || (dma[CHANNEL_DISK].next%4)) {
! 670: Log_Printf(LOG_WARN, "[DMA] Channel MO: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 671: dma[CHANNEL_DISK].next, dma[CHANNEL_DISK].limit);
! 672: abort();
! 673: }
! 674:
! 675: TRY(prb) {
! 676: if (modma_buf_size>0) {
! 677: Log_Printf(LOG_WARN, "[DMA] Channel MO: Starting with %i residual bytes in DMA buffer.", modma_buf_size);
! 678: }
! 679:
! 680: while (dma[CHANNEL_DISK].next<dma[CHANNEL_DISK].limit) {
! 681: /* Read data from memory to DMA channel FIFO (only if limit < FIFO size) */
! 682: if (modma_buf_limit<DMA_BURST_SIZE) {
! 683: while (dma[CHANNEL_DISK].next<dma[CHANNEL_DISK].limit && modma_buf_limit<DMA_BURST_SIZE) {
! 684: dma_putlong(NEXTMemory_ReadLong(dma[CHANNEL_DISK].next), modma_buf, modma_buf_limit);
! 685: dma[CHANNEL_DISK].next+=4;
! 686: modma_buf_limit+=4;
! 687: modma_buf_size+=4;
! 688: }
! 689: }
! 690:
! 691: if (modma_buf_limit<DMA_BURST_SIZE) { /* Not complete, stop */
! 692: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: Channel limit reached. Stopping with %i residual bytes.",
! 693: modma_buf_size);
! 694: break;
! 695: } else { /* Empty DMA channel FIFO (only if limit reached FIFO size) */
! 696: while (modma_buf_size>0 && ecc_buffer[eccin].size<ecc_buffer[eccin].limit) {
! 697: ecc_buffer[eccin].data[ecc_buffer[eccin].size]=modma_buf[modma_buf_limit-modma_buf_size];
! 698: ecc_buffer[eccin].size++;
! 699: modma_buf_size--;
! 700: }
! 701: if (modma_buf_size>0) { /* Not complete, stop */
! 702: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: No more data request. Stopping with %i residual bytes.",
! 703: modma_buf_size);
! 704: break;
! 705: }
! 706: modma_buf_limit = modma_buf_size; /* Should be 0 */
! 707: }
! 708: }
! 709: } CATCH(prb) {
! 710: Log_Printf(LOG_WARN, "[DMA] Channel MO: Bus error while reading from %08x",dma[CHANNEL_DISK].next);
! 711: dma[CHANNEL_DISK].csr &= ~DMA_ENABLE;
! 712: dma[CHANNEL_DISK].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 713: } ENDTRY
! 714:
! 715: if (ecc_buffer[eccin].size<ecc_buffer[eccin].limit) {
! 716: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel MO: Warning! Data not yet written to disk.");
! 717: if (modma_buf_size!=0) {
! 718: Log_Printf(LOG_WARN, "[DMA] Channel MO: WARNING: Loss of data in DMA buffer possible!");
! 719: }
! 720: }
! 721:
! 722: dma_interrupt(CHANNEL_DISK);
1.1 root 723: }
724:
725:
1.1.1.3 ! root 726: /* Channel Sound Out (FIXME: is this channel buffered?) */
! 727: void dma_sndout_read_memory(void) {
! 728: if (dma[CHANNEL_SOUNDOUT].csr&DMA_ENABLE) {
! 729: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel Sound Out: Read from memory at $%08x, %i bytes",
! 730: dma[CHANNEL_SOUNDOUT].next,dma[CHANNEL_SOUNDOUT].limit-dma[CHANNEL_SOUNDOUT].next);
1.1 root 731:
1.1.1.3 ! root 732: if ((dma[CHANNEL_SOUNDOUT].limit%4) || (dma[CHANNEL_SOUNDOUT].next%4)) {
! 733: Log_Printf(LOG_WARN, "[DMA] Channel Sound Out: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 734: dma[CHANNEL_SOUNDOUT].next, dma[CHANNEL_SOUNDOUT].limit);
! 735: abort();
! 736: }
! 737:
! 738: TRY(prb) {
! 739: while (dma[CHANNEL_SOUNDOUT].next<dma[CHANNEL_SOUNDOUT].limit && snd_buffer.size<snd_buffer.limit) {
! 740: snd_buffer.data[snd_buffer.size]=NEXTMemory_ReadByte(dma[CHANNEL_SOUNDOUT].next);
! 741: snd_buffer.size++;
! 742: dma[CHANNEL_SOUNDOUT].next++;
! 743: }
! 744: } CATCH(prb) {
! 745: Log_Printf(LOG_WARN, "[DMA] Channel Sound Out: Bus error reading from %08x",dma[CHANNEL_SOUNDOUT].next);
! 746: dma[CHANNEL_SOUNDOUT].csr &= ~DMA_ENABLE;
! 747: dma[CHANNEL_SOUNDOUT].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 748: } ENDTRY
! 749:
! 750: dma_interrupt(CHANNEL_SOUNDOUT);
! 751: }
! 752: }
1.1 root 753:
1.1.1.3 ! root 754:
! 755: /* Channel Printer */
! 756: void dma_printer_read_memory(void) {
! 757: if (dma[CHANNEL_PRINTER].csr&DMA_ENABLE) {
! 758: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel Printer: Read from memory at $%08x, %i bytes",
! 759: dma[CHANNEL_PRINTER].next,dma[CHANNEL_PRINTER].limit-dma[CHANNEL_PRINTER].next);
1.1 root 760:
1.1.1.3 ! root 761: if ((dma[CHANNEL_PRINTER].limit%4) || (dma[CHANNEL_PRINTER].next%4)) {
! 762: Log_Printf(LOG_WARN, "[DMA] Channel Printer: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 763: dma[CHANNEL_PRINTER].next, dma[CHANNEL_PRINTER].limit);
! 764: abort();
1.1 root 765: }
1.1.1.3 ! root 766:
! 767: TRY(prb) {
! 768: while (dma[CHANNEL_PRINTER].next<dma[CHANNEL_PRINTER].limit && lp_buffer.size<lp_buffer.limit) {
! 769: lp_buffer.data[lp_buffer.size]=NEXTMemory_ReadByte(dma[CHANNEL_PRINTER].next);
! 770: lp_buffer.size++;
! 771: dma[CHANNEL_PRINTER].next++;
! 772: }
! 773: } CATCH(prb) {
! 774: Log_Printf(LOG_WARN, "[DMA] Channel Printer: Bus error reading from %08x",dma[CHANNEL_PRINTER].next);
! 775: dma[CHANNEL_PRINTER].csr &= ~DMA_ENABLE;
! 776: dma[CHANNEL_PRINTER].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 777: } ENDTRY
! 778:
! 779: dma_interrupt(CHANNEL_PRINTER);
1.1 root 780: }
1.1.1.3 ! root 781: }
! 782:
1.1 root 783:
1.1.1.3 ! root 784: /* Channel Ethernet (this channel does not use DMA buffering) */
! 785: #define EN_EOP 0x80000000 /* end of packet */
! 786: #define EN_BOP 0x40000000 /* beginning of packet */
! 787: #define ENADDR(x) ((x)&~(EN_EOP|EN_BOP))
! 788:
! 789: Uint32 saved_next_turbo = 0;
! 790:
! 791: void dma_enet_interrupt(int channel) {
! 792: int interrupt = get_interrupt_type(channel);
! 793:
! 794: dma[channel].csr |= DMA_COMPLETE;
! 795:
! 796: if (dma[channel].csr & DMA_SUPDATE) { /* if we are in chaining mode */
! 797: /* Update pointers */
! 798: saved_next_turbo = dma[channel].next;
! 799: dma[channel].next = dma[channel].start;
! 800: dma[channel].limit = dma[channel].stop;
! 801: /* Set bits in CSR */
! 802: dma[channel].csr &= ~DMA_SUPDATE; /* 1st done */
! 803: } else {
! 804: dma[channel].csr &= ~DMA_ENABLE; /* all done */
! 805: }
! 806: set_interrupt(interrupt, SET_INT);
! 807: }
! 808:
! 809: /* This is done by hardware on ethernet transmitter error (coll, short, etc) */
! 810: /* TODO: check if this is true and call from transmitter */
! 811: void dma_enet_read_retry(void) {
! 812: dma[CHANNEL_EN_TX].next = dma[CHANNEL_EN_TX].saved_next;
! 813: dma[CHANNEL_EN_TX].limit = dma[CHANNEL_EN_TX].saved_limit;
! 814: dma[CHANNEL_EN_TX].start = dma[CHANNEL_EN_TX].saved_start;
! 815: dma[CHANNEL_EN_TX].stop = dma[CHANNEL_EN_TX].saved_stop;
! 816: }
! 817:
! 818: void dma_enet_write_memory(bool eop) {
! 819: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel Ethernet Receive: Write to memory at $%08x, %i bytes",
! 820: dma[CHANNEL_EN_RX].next,dma[CHANNEL_EN_RX].limit-dma[CHANNEL_EN_RX].next);
! 821:
! 822: if (!(dma[CHANNEL_EN_RX].csr&DMA_ENABLE)) {
! 823: Log_Printf(LOG_WARN, "[DMA] Channel Ethernet Receive: Error! DMA not enabled!");
! 824: return;
! 825: }
! 826: if ((dma[CHANNEL_EN_RX].limit%DMA_BURST_SIZE) || (dma[CHANNEL_EN_RX].next%DMA_BURST_SIZE)) {
! 827: Log_Printf(LOG_WARN, "[DMA] Channel Ethernet Receive: Error! Bad alignment! (Next: $%08X, Limit: $%08X)",
! 828: dma[CHANNEL_EN_RX].next, dma[CHANNEL_EN_RX].limit);
! 829: abort();
1.1 root 830: }
831:
1.1.1.3 ! root 832: TRY(prb) {
! 833: while (dma[CHANNEL_EN_RX].next<dma[CHANNEL_EN_RX].limit && enet_rx_buffer.size>0) {
! 834: NEXTMemory_WriteByte(dma[CHANNEL_EN_RX].next, enet_rx_buffer.data[enet_rx_buffer.limit-enet_rx_buffer.size]);
! 835: enet_rx_buffer.size--;
! 836: dma[CHANNEL_EN_RX].next++;
! 837: }
! 838: } CATCH(prb) {
! 839: Log_Printf(LOG_WARN, "[DMA] Channel Ethernet Receive: Bus error while writing to %08x",dma[CHANNEL_EN_RX].next);
! 840: dma[CHANNEL_EN_RX].csr &= ~DMA_ENABLE;
! 841: dma[CHANNEL_EN_RX].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 842: } ENDTRY
1.1 root 843:
1.1.1.3 ! root 844: if (enet_rx_buffer.size==0) {
! 845: if (eop) { /* TODO: check if this is correct */
! 846: Log_Printf(LOG_WARN, "[DMA] Channel Ethernet Receive: Last buffer of chain done.");
! 847: dma[CHANNEL_EN_RX].next|=EN_BOP;
1.1 root 848: }
1.1.1.3 ! root 849: dma[CHANNEL_EN_RX].saved_limit = dma[CHANNEL_EN_RX].next;
1.1 root 850: }
851:
1.1.1.3 ! root 852: dma_enet_interrupt(CHANNEL_EN_RX);
! 853: }
! 854:
! 855: bool dma_enet_read_memory(void) {
! 856: if (dma[CHANNEL_EN_TX].csr&DMA_ENABLE) {
! 857: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel Ethernet Transmit: Read from memory at $%08x, %i bytes",
! 858: dma[CHANNEL_EN_TX].next,ENADDR(dma[CHANNEL_EN_TX].limit)-dma[CHANNEL_EN_TX].next);
! 859:
! 860: TRY(prb) {
! 861: while (dma[CHANNEL_EN_TX].next<ENADDR(dma[CHANNEL_EN_TX].limit) && enet_tx_buffer.size<enet_tx_buffer.limit) {
! 862: enet_tx_buffer.data[enet_tx_buffer.size]=NEXTMemory_ReadByte(dma[CHANNEL_EN_TX].next);
! 863: enet_tx_buffer.size++;
! 864: dma[CHANNEL_EN_TX].next++;
! 865: }
! 866: } CATCH(prb) {
! 867: Log_Printf(LOG_WARN, "[DMA] Channel Ethernet Transmit: Bus error while writing to %08x",dma[CHANNEL_EN_TX].next);
! 868: dma[CHANNEL_EN_TX].csr &= ~DMA_ENABLE;
! 869: dma[CHANNEL_EN_TX].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 870: } ENDTRY
! 871:
! 872: if (dma[CHANNEL_EN_TX].limit&EN_EOP) {
! 873: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel Ethernet Transmit: Packet done.");
! 874: dma_enet_interrupt(CHANNEL_EN_TX);
! 875: return true;
! 876: }
! 877: dma_enet_interrupt(CHANNEL_EN_TX);
! 878: }
! 879: return false;
! 880: }
! 881:
! 882:
! 883: /* Memory to Memory */
! 884: #define DMA_M2M_CYCLES 1//((DMA_BURST_SIZE * 3) / 4)
! 885:
! 886: void dma_m2m_write_memory(void) {
! 887: int i;
! 888: int time = 0;
! 889: Uint32 m2m_buffer[DMA_BURST_SIZE/4];
1.1 root 890:
1.1.1.3 ! root 891: if (((dma[CHANNEL_R2M].limit-dma[CHANNEL_R2M].next)%DMA_BURST_SIZE) ||
! 892: ((dma[CHANNEL_M2R].limit-dma[CHANNEL_M2R].next)%DMA_BURST_SIZE)) {
! 893: Log_Printf(LOG_WARN, "[DMA] Channel M2M: Error! Memory not burst size aligned!");
! 894: }
1.1 root 895:
1.1.1.3 ! root 896: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel M2M: Copying %i bytes from $%08X to $%08X.",
! 897: dma[CHANNEL_R2M].limit-dma[CHANNEL_R2M].next,dma[CHANNEL_M2R].next,dma[CHANNEL_R2M].next);
1.1 root 898:
1.1.1.3 ! root 899: while (dma[CHANNEL_R2M].next<dma[CHANNEL_R2M].limit) {
! 900: time+=DMA_M2M_CYCLES;
! 901:
! 902: if (dma[CHANNEL_M2R].next<dma[CHANNEL_M2R].limit) {
! 903: TRY(prb) {
! 904: /* (Re)fill the buffer, if there is still data to read */
! 905: for (i=0; i<DMA_BURST_SIZE; i+=4) {
! 906: m2m_buffer[i/4]=NEXTMemory_ReadLong(dma[CHANNEL_M2R].next+i);
! 907: }
! 908: dma[CHANNEL_M2R].next+=DMA_BURST_SIZE;
! 909: } CATCH(prb) {
! 910: Log_Printf(LOG_WARN, "[DMA] Channel M2M: Bus error while reading from %08x",dma[CHANNEL_M2R].next+i);
! 911: dma[CHANNEL_M2R].csr &= ~DMA_ENABLE;
! 912: dma[CHANNEL_M2R].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 913: } ENDTRY
! 914:
! 915: if ((dma[CHANNEL_M2R].next==dma[CHANNEL_M2R].limit)||(dma[CHANNEL_M2R].csr&DMA_BUSEXC)) {
! 916: CycInt_AddRelativeInterrupt(time/4, INT_CPU_CYCLE, INTERRUPT_M2R);
! 917: }
! 918: }
! 919:
! 920: TRY(prb) {
! 921: /* Write the contents of the buffer to memory */
! 922: for (i=0; i<DMA_BURST_SIZE; i+=4) {
! 923: NEXTMemory_WriteLong(dma[CHANNEL_R2M].next+i, m2m_buffer[i/4]);
! 924: }
! 925: dma[CHANNEL_R2M].next+=DMA_BURST_SIZE;
! 926: } CATCH(prb) {
! 927: Log_Printf(LOG_WARN, "[DMA] Channel M2M: Bus error while writing to %08x",dma[CHANNEL_R2M].next+i);
! 928: dma[CHANNEL_R2M].csr &= ~DMA_ENABLE;
! 929: dma[CHANNEL_R2M].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 930: } ENDTRY
1.1 root 931: }
1.1.1.3 ! root 932: CycInt_AddRelativeInterrupt(time/4, INT_CPU_CYCLE, INTERRUPT_R2M);
! 933: }
1.1 root 934:
1.1.1.3 ! root 935:
! 936: /* Channel DSP */
! 937: #define LOG_DMA_DSP_LEVEL LOG_DEBUG
! 938:
! 939: void dma_dsp_write_memory(Uint8 val) {
! 940: Log_Printf(LOG_DMA_DSP_LEVEL, "[DMA] Channel DSP: Write to memory at $%08x, %i bytes",
! 941: dma[CHANNEL_DSP].next,dma[CHANNEL_DSP].limit-dma[CHANNEL_DSP].next);
! 942:
! 943: if (!(dma[CHANNEL_DSP].csr&DMA_ENABLE)) {
! 944: Log_Printf(LOG_WARN, "[DMA] Channel DSP: Error! DMA not enabled!");
! 945: return;
! 946: }
! 947:
! 948: TRY(prb) {
! 949: if (dma[CHANNEL_DSP].next<dma[CHANNEL_DSP].limit) {
! 950: NEXTMemory_WriteByte(dma[CHANNEL_DSP].next, val);
! 951: dma[CHANNEL_DSP].next++;
! 952: }
! 953: } CATCH(prb) {
! 954: Log_Printf(LOG_WARN, "[DMA] Channel DSP: Bus error while writing to %08x",dma[CHANNEL_DSP].next);
! 955: dma[CHANNEL_DSP].csr &= ~DMA_ENABLE;
! 956: dma[CHANNEL_DSP].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 957: } ENDTRY
! 958:
! 959: if (dma[CHANNEL_DSP].next==dma[CHANNEL_DSP].limit) {
! 960: DSP_SetIRQB();
! 961: dma_interrupt(CHANNEL_DSP);
! 962: }
! 963: }
! 964:
! 965: Uint8 dma_dsp_read_memory(void) {
! 966: Uint8 val = 0;
! 967:
! 968: Log_Printf(LOG_DMA_DSP_LEVEL, "[DMA] Channel DSP: Read from memory at $%08x, %i bytes",
! 969: dma[CHANNEL_DSP].next,dma[CHANNEL_DSP].limit-dma[CHANNEL_DSP].next);
! 970:
! 971: if (!(dma[CHANNEL_DSP].csr&DMA_ENABLE)) {
! 972: Log_Printf(LOG_WARN, "[DMA] Channel DSP: Error! DMA not enabled!");
! 973: return val;
! 974: }
! 975:
! 976: TRY(prb) {
! 977: if (dma[CHANNEL_DSP].next<dma[CHANNEL_DSP].limit) {
! 978: val = NEXTMemory_ReadByte(dma[CHANNEL_DSP].next);
! 979: dma[CHANNEL_DSP].next++;
! 980: }
! 981: } CATCH(prb) {
! 982: Log_Printf(LOG_WARN, "[DMA] Channel DSP: Bus error while writing to %08x",dma[CHANNEL_DSP].next);
! 983: dma[CHANNEL_DSP].csr &= ~DMA_ENABLE;
! 984: dma[CHANNEL_DSP].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 985: } ENDTRY
! 986:
! 987: if (dma[CHANNEL_DSP].next==dma[CHANNEL_DSP].limit) {
! 988: DSP_SetIRQB();
! 989: dma_interrupt(CHANNEL_DSP);
! 990: }
! 991: return val;
! 992: }
! 993:
! 994: bool dma_dsp_ready(void) {
! 995: if (!(dma[CHANNEL_DSP].csr&DMA_ENABLE) ||
! 996: !(dma[CHANNEL_DSP].next<dma[CHANNEL_DSP].limit)) {
! 997: Log_Printf(LOG_DEBUG, "[DMA] Channel DSP: Not ready!");
! 998: return false;
! 999: } else {
! 1000: return true;
! 1001: }
! 1002: }
! 1003:
! 1004:
! 1005: /* ---------------------- DMA Scratchpad ---------------------- */
! 1006:
! 1007: /* This is used to interrupt at vertical screen retrace.
! 1008: * TODO: find out how the interrupt is generated in real
! 1009: * hardware using the Limit register of the DMA chip.
! 1010: * (0xEA * 1024 = visible videomem size)
! 1011: */
! 1012:
! 1013:
! 1014: /* Interrupt Handler (called from Video_InterruptHandler in video.c) */
! 1015: void dma_video_interrupt(void) {
! 1016: if (dma[CHANNEL_VIDEO].limit==0xEA) {
! 1017: set_interrupt(INT_VIDEO, SET_INT); /* interrupt is released by writing to CSR */
! 1018: } else if (dma[CHANNEL_VIDEO].limit && dma[CHANNEL_VIDEO].limit!=0xEA) {
! 1019: abort();
! 1020: }
! 1021: }
! 1022:
! 1023:
! 1024: /* FIXME: This is just for passing power-on test. Add real SCC channel later. */
! 1025:
! 1026: void dma_scc_read_memory(void) {
! 1027: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCC: Read from memory at $%08x, %i bytes",
! 1028: dma[CHANNEL_SCC].next,dma[CHANNEL_SCC].limit-dma[CHANNEL_SCC].next);
! 1029: while (dma[CHANNEL_SCC].next<dma[CHANNEL_SCC].limit) {
! 1030: scc_buf[0]=NEXTMemory_ReadByte(dma[CHANNEL_SCC].next);
! 1031: dma[CHANNEL_SCC].next++;
! 1032: }
1.1 root 1033:
1.1.1.3 ! root 1034: dma_interrupt(CHANNEL_SCC);
! 1035: }
! 1036:
! 1037:
! 1038: /* DMA CSR on Turbo systems */
! 1039:
! 1040: /* CSR read bits */
! 1041: #define TDMA_BYTECOUNT_MASK 0x00000007
! 1042: #define TDMA_WRITEPTR_MASK 0x00000018
! 1043: #define TDMA_READPTR_MASK 0x00000060
! 1044: #define TDMA_DIRTY_MASK 0x00000180
! 1045: #define TDMA_BUFSEL 0x00000200
! 1046:
! 1047: #define TDMA_ENABLE 0x01000000
! 1048: #define TDMA_SUPDATE 0x02000000
! 1049: #define TDMA_COMPLETE 0x08000000
! 1050: #define TDMA_BUSEXC 0x10000000
! 1051:
! 1052: /* CSR write bits */
! 1053: #define TDMA_SETENABLE 0x00010000
! 1054: #define TDMA_SETSUPDATE 0x00020000
! 1055: #define TDMA_DEV2M 0x00040000
! 1056: #define TDMA_CLRCOMPLETE 0x00080000
! 1057: #define TDMA_RESET 0x00100000
! 1058: #define TDMA_SETCOMPLETE 0x00200000
! 1059: #define TDMA_FLUSH 0x00400000
! 1060: #define TDMA_BUFRESET 0x00800000
! 1061:
! 1062: /* CSR masks */
! 1063: #define TDMA_CMD_MASK 0x00FB0000
! 1064:
! 1065: void TDMA_CSR_Read(void) { // 0x02000010, length of register is byte on 68030 based NeXT Computer
! 1066: int channel = get_channel(IoAccessCurrentAddress);
! 1067:
! 1068: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].csr<<24);
! 1069:
! 1070: Log_Printf(LOG_DMA_LEVEL,"DMA CSR read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].csr<<24, m68k_getpc());
! 1071: }
! 1072:
! 1073: void TDMA_CSR_Write(void) {
! 1074: int channel = get_channel(IoAccessCurrentAddress);
! 1075: int interrupt = get_interrupt_type(channel);
! 1076: Uint32 writecsr = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
! 1077:
! 1078: Log_Printf(LOG_DMA_LEVEL,"DMA CSR write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, writecsr, m68k_getpc());
! 1079:
! 1080: /* For debugging */
! 1081: if(writecsr&TDMA_DEV2M)
! 1082: Log_Printf(LOG_DMA_LEVEL,"DMA from dev to mem");
! 1083: else
! 1084: Log_Printf(LOG_DMA_LEVEL,"DMA from mem to dev");
! 1085:
! 1086: switch (writecsr&TDMA_CMD_MASK) {
! 1087: case TDMA_RESET:
! 1088: Log_Printf(LOG_DMA_LEVEL,"DMA reset"); break;
! 1089: case (TDMA_RESET | TDMA_BUFRESET):
! 1090: case (TDMA_RESET | TDMA_BUFRESET | TDMA_CLRCOMPLETE):
! 1091: Log_Printf(LOG_DMA_LEVEL,"DMA reset and initialize buffers"); break;
! 1092: case TDMA_CLRCOMPLETE:
! 1093: Log_Printf(LOG_DMA_LEVEL,"DMA end chaining"); break;
! 1094: case (TDMA_SETSUPDATE | TDMA_CLRCOMPLETE):
! 1095: Log_Printf(LOG_DMA_LEVEL,"DMA continue chaining"); break;
! 1096: case TDMA_SETENABLE:
! 1097: Log_Printf(LOG_DMA_LEVEL,"DMA start single transfer"); break;
! 1098: case (TDMA_SETENABLE | TDMA_SETSUPDATE):
! 1099: case (TDMA_SETENABLE | TDMA_SETSUPDATE | TDMA_CLRCOMPLETE):
! 1100: Log_Printf(LOG_DMA_LEVEL,"DMA start chaining"); break;
! 1101: case 0:
! 1102: Log_Printf(LOG_DMA_LEVEL,"DMA no command"); break;
! 1103: default:
! 1104: Log_Printf(LOG_WARN,"DMA: unknown command!"); break;
! 1105: }
! 1106:
! 1107: /* Handle CSR bits */
! 1108: dma[channel].direction = (writecsr>>16)&DMA_DEV2M;
! 1109:
! 1110: if (writecsr&TDMA_RESET) {
! 1111: dma[channel].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | DMA_ENABLE);
! 1112: }
! 1113: if (writecsr&TDMA_BUFRESET) {
! 1114: dma_initialize_buffer(channel, 0);
! 1115: }
! 1116: if (writecsr&TDMA_SETSUPDATE) {
! 1117: dma[channel].csr |= DMA_SUPDATE;
! 1118: }
! 1119: if (writecsr&TDMA_SETENABLE) {
! 1120: dma[channel].csr |= DMA_ENABLE;
! 1121: }
! 1122: if (writecsr&TDMA_CLRCOMPLETE) {
! 1123: dma[channel].csr &= ~DMA_COMPLETE;
! 1124: }
! 1125:
! 1126: set_interrupt(interrupt, RELEASE_INT);
! 1127: }
! 1128:
! 1129: void TDMA_Saved_Next_Read(void) { // 0x02004050
! 1130: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, saved_next_turbo);
! 1131: Log_Printf(LOG_DMA_LEVEL,"TDMA SNext read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, saved_next_turbo, m68k_getpc());
! 1132: }
! 1133:
! 1134: /* Flush DMA buffer */
! 1135: /* FIXME: Implement function for all buffered channels */
! 1136: void tdma_flush_buffer(int channel) {
! 1137: int i;
! 1138:
! 1139: if (!(dma[CHANNEL_SCSI].csr&DMA_ENABLE)) {
! 1140: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Not flushing buffer. DMA not enabled.");
! 1141: return;
! 1142: }
! 1143: if (dma[CHANNEL_SCSI].direction!=DMA_DEV2M) {
! 1144: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Not flushing buffer. Bad direction!");
! 1145: return;
! 1146: }
! 1147:
! 1148: TRY(prb) {
! 1149: Log_Printf(LOG_DMA_LEVEL, "[DMA] Channel SCSI: Flush buffer to memory at $%08x, %i bytes",
! 1150: dma[CHANNEL_SCSI].next,espdma_buf_size);
! 1151:
! 1152: for (i = 0; i < DMA_BURST_SIZE; i+=4) {
! 1153: if (dma[CHANNEL_SCSI].next<dma[CHANNEL_SCSI].limit) {
! 1154: if (espdma_buf_size) {
! 1155: NEXTMemory_WriteLong(dma[CHANNEL_SCSI].next, dma_getlong(espdma_buf, espdma_buf_limit-espdma_buf_size));
! 1156: espdma_buf_size-=4;
! 1157: }
! 1158: dma[CHANNEL_SCSI].next+=4;
! 1159: }
! 1160: }
! 1161: } CATCH(prb) {
! 1162: Log_Printf(LOG_WARN, "[DMA] Channel SCSI: Bus error while flushing to %08x",dma[CHANNEL_SCSI].next);
! 1163: dma[CHANNEL_SCSI].csr &= ~DMA_ENABLE;
! 1164: dma[CHANNEL_SCSI].csr |= (DMA_COMPLETE|DMA_BUSEXC);
! 1165: } ENDTRY
! 1166:
! 1167: dma_interrupt(CHANNEL_SCSI);
1.1 root 1168: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.