|
|
1.1 root 1: /* NeXT DMA Emulation
2: * Contains informations from QEMU-NeXT
3: * NeXT DMA consists of 12 channel processors with 128 bytes internal buffer for each channel
4: * 12 channels: SCSI, Sound in, Sound out, Optical disk, Printer, SCC, DSP,
5: * Ethernet transmit, Ethernet receive, Video, Memory to register, Register to memory
6: */
7:
8: #include "ioMem.h"
9: #include "ioMemTables.h"
10: #include "m68000.h"
11: #include "esp.h"
12: #include "sysReg.h"
13: #include "dma.h"
14: #include "configuration.h"
15: #include "ethernet.h"
16:
17:
18: #define LOG_DMA_LEVEL LOG_WARN
19:
20: #define IO_SEG_MASK 0x1FFFF
21:
22: /* read CSR bits */
23: #define DMA_ENABLE 0x01000000 /* enable dma transfer */
24: #define DMA_SUPDATE 0x02000000 /* single update */
25: #define DMA_COMPLETE 0x08000000 /* current dma has completed */
26: #define DMA_BUSEXC 0x10000000 /* bus exception occurred */
27: /* write CSR bits */
28: #define DMA_SETENABLE 0x00010000 /* set enable */
29: #define DMA_SETSUPDATE 0x00020000 /* set single update */
30: #define DMA_M2DEV 0x00000000 /* dma from mem to dev */
31: #define DMA_DEV2M 0x00040000 /* dma from dev to mem */
32: #define DMA_CLRCOMPLETE 0x00080000 /* clear complete conditional */
33: #define DMA_RESET 0x00100000 /* clr cmplt, sup, enable */
34: #define DMA_INITBUF 0x00200000 /* initialize DMA buffers */
35:
36:
37: /* Read and write CSR bits for 68030 based NeXT Computer.
38: * We convert these to 68040 values before using in functions.
39: * read CSR bits *
40: #define DMA_ENABLE 0x01
41: #define DMA_SUPDATE 0x02
42: #define DMA_COMPLETE 0x08
43: #define DMA_BUSEXC 0x10
44: * write CSR bits *
45: #define DMA_SETENABLE 0x01
46: #define DMA_SETSUPDATE 0x02
47: #define DMA_M2DEV 0x00
48: #define DMA_DEV2M 0x04
49: #define DMA_CLRCOMPLETE 0x08
50: #define DMA_RESET 0x10
51: #define DMA_INITBUF 0x20
52: */
53:
54:
55:
56: /* DMA registers */
57:
58: typedef struct {
59: Uint32 csr;
60: Uint32 saved_next;
61: Uint32 saved_limit;
62: Uint32 saved_start;
63: Uint32 saved_stop;
64: Uint32 next;
65: Uint32 limit;
66: Uint32 start;
67: Uint32 stop;
68: Uint32 init;
69: Uint32 size;
70: } DMA_CONTROL;
71:
72: DMA_CONTROL dma[16];
73:
74:
75:
76: int get_channel(Uint32 address) {
77: int channel = address&IO_SEG_MASK;
78: switch (channel) {
79: case 0x010: printf("channel SCSI:\n"); return CHANNEL_SCSI; break;
80: case 0x040: printf("channel Sound Out:\n"); return CHANNEL_SOUNDOUT; break;
81: case 0x050: printf("channel MO Disk:\n"); return CHANNEL_DISK; break;
82: case 0x080: printf("channel Sound in:\n"); return CHANNEL_SOUNDIN; break;
83: case 0x090: printf("channel Printer:\n"); return CHANNEL_PRINTER; break;
84: case 0x0c0: printf("channel SCC:\n"); return CHANNEL_SCC; break;
85: case 0x0d0: printf("channel DSP:\n"); return CHANNEL_DSP; break;
86: case 0x110: printf("channel Ethernet Tx:\n"); return CHANNEL_EN_TX; break;
87: case 0x150: printf("channel Ethernet Rx:\n"); return CHANNEL_EN_RX; break;
88: case 0x180: printf("channel Video:\n"); return CHANNEL_VIDEO; break;
89: case 0x1d0: printf("channel M2R:\n"); return CHANNEL_M2R; break;
90: case 0x1c0: printf("channel R2M:\n"); return CHANNEL_R2M; break;
91:
92: default:
93: Log_Printf(LOG_DMA_LEVEL, "Unknown DMA channel!\n");
94: return -1;
95: break;
96: }
97: }
98:
99: int get_interrupt_type(int channel) {
100: switch (channel) {
101: case CHANNEL_SCSI: return INT_SCSI_DMA; break;
102: case CHANNEL_SOUNDOUT: return INT_SND_OUT_DMA; break;
103: case CHANNEL_DISK: return INT_DISK_DMA; break;
104: case CHANNEL_SOUNDIN: return INT_SND_IN_DMA; break;
105: case CHANNEL_PRINTER: return INT_PRINTER_DMA; break;
106: case CHANNEL_SCC: return INT_SCC_DMA; break;
107: case CHANNEL_DSP: return INT_DSP_DMA; break;
108: case CHANNEL_EN_TX: return INT_EN_TX_DMA; break;
109: case CHANNEL_EN_RX: return INT_EN_RX_DMA; break;
110: case CHANNEL_VIDEO: return 0; break; // no interrupt? CHECK THIS
111: case CHANNEL_M2R: return INT_M2R_DMA; break;
112: case CHANNEL_R2M: return INT_R2M_DMA; break;
113:
114: default:
115: Log_Printf(LOG_DMA_LEVEL, "Unknown DMA interrupt!\n");
116: return 0;
117: break;
118: }
119: }
120:
121: void DMA_CSR_Read(void) { // 0x02000010, length of register is byte on 68030 based NeXT Computer
122: int channel = get_channel(IoAccessCurrentAddress);
123: if(ConfigureParams.System.nMachineType == NEXT_CUBE030) { // for 68030 based NeXT Computer
124: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = dma[channel].csr >> 24;
125: Log_Printf(LOG_DMA_LEVEL,"DMA CSR read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].csr >> 24, m68k_getpc());
126: } else {
127: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].csr);
128: Log_Printf(LOG_DMA_LEVEL,"DMA CSR read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].csr, m68k_getpc());
129: }
130: }
131:
132: void DMA_CSR_Write(void) {
133: int channel = get_channel(IoAccessCurrentAddress);
134: int interrupt = get_interrupt_type(channel);
135: Uint32 writecsr;
136: if(ConfigureParams.System.nMachineType == NEXT_CUBE030) { // for 68030 based NeXT Computer
137: writecsr = IoMem[IoAccessCurrentAddress & IO_SEG_MASK] << 16;
138: Log_Printf(LOG_DMA_LEVEL,"DMA CSR write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, writecsr >> 16, m68k_getpc());
139: } else {
140: writecsr = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
141: Log_Printf(LOG_DMA_LEVEL,"DMA CSR write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, writecsr, m68k_getpc());
142: }
143:
144: if(writecsr & DMA_DEV2M) {
145: if(ConfigureParams.System.nMachineType == NEXT_CUBE030) {
146: dma[channel].csr |= (0x04 << 24); // use 8 bit DMA_DEV2M value for 68030 based NeXT Computer
147: } else {
148: dma[channel].csr |= DMA_DEV2M;
149: }
150: Log_Printf(LOG_DMA_LEVEL,"DMA from dev to mem");
151: } else {
152: Log_Printf(LOG_DMA_LEVEL,"DMA from mem to dev");
153: }
154: if(writecsr & DMA_SETENABLE) {
155: dma[channel].csr |= DMA_ENABLE;
156: Log_Printf(LOG_DMA_LEVEL,"DMA enable transfer");
157: if ((channel == CHANNEL_EN_TX) && !(writecsr&DMA_DEV2M)) {
158: Ethernet_Transmit(); // Ethernet Transmit
159: }
160: }
161: if(writecsr & DMA_SETSUPDATE) {
162: dma[channel].csr |= DMA_SUPDATE;
163: Log_Printf(LOG_DMA_LEVEL,"DMA set single update");
164: }
165: if(writecsr & DMA_CLRCOMPLETE) {
166: dma[channel].csr &= ~DMA_COMPLETE;
167: Log_Printf(LOG_DMA_LEVEL,"DMA clear complete conditional");
168:
169: set_interrupt(interrupt, RELEASE_INT); // also somewhat experimental...
170: }
171: if(writecsr & DMA_RESET) {
172: dma[channel].csr &= ~(DMA_COMPLETE | DMA_SUPDATE | DMA_ENABLE | DMA_DEV2M);
173: Log_Printf(LOG_WARN,"DMA reset");
174:
175: set_interrupt(interrupt, RELEASE_INT); // also somewhat experimental...
176: }
177: if(writecsr & DMA_INITBUF) { // needs to be filled
178: Log_Printf(LOG_DMA_LEVEL,"DMA initialize buffers");
179: }
180: }
181:
182: void DMA_Saved_Next_Read(void) { // 0x02004000
183: int channel = get_channel(IoAccessCurrentAddress-0x3FF0);
184: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_next);
185: Log_Printf(LOG_DMA_LEVEL,"DMA SNext read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_next, m68k_getpc());
186: }
187:
188: void DMA_Saved_Next_Write(void) {
189: int channel = get_channel(IoAccessCurrentAddress-0x3FF0);
190: dma[channel].saved_next = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
191: Log_Printf(LOG_DMA_LEVEL,"DMA SNext write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_next, m68k_getpc());
192: }
193:
194: void DMA_Saved_Limit_Read(void) { // 0x02004004
195: int channel = get_channel(IoAccessCurrentAddress-0x3FF4);
196: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_limit);
197: Log_Printf(LOG_DMA_LEVEL,"DMA SLimit read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_limit, m68k_getpc());
198: }
199:
200: void DMA_Saved_Limit_Write(void) {
201: int channel = get_channel(IoAccessCurrentAddress-0x3FF4);
202: dma[channel].saved_limit = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
203: Log_Printf(LOG_DMA_LEVEL,"DMA SLimit write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_limit, m68k_getpc());
204: }
205:
206: void DMA_Saved_Start_Read(void) { // 0x02004008
207: int channel = get_channel(IoAccessCurrentAddress-0x3FF8);
208: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_start);
209: Log_Printf(LOG_DMA_LEVEL,"DMA SStart read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_start, m68k_getpc());
210: }
211:
212: void DMA_Saved_Start_Write(void) {
213: int channel = get_channel(IoAccessCurrentAddress-0x3FF8);
214: dma[channel].saved_start = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
215: Log_Printf(LOG_DMA_LEVEL,"DMA SStart write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_start, m68k_getpc());
216: }
217:
218: void DMA_Saved_Stop_Read(void) { // 0x0200400c
219: int channel = get_channel(IoAccessCurrentAddress-0x3FFC);
220: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].saved_stop);
221: Log_Printf(LOG_DMA_LEVEL,"DMA SStop read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_stop, m68k_getpc());
222: }
223:
224: void DMA_Saved_Stop_Write(void) {
225: int channel = get_channel(IoAccessCurrentAddress-0x3FFC);
226: dma[channel].saved_stop = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
227: Log_Printf(LOG_DMA_LEVEL,"DMA SStop write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].saved_stop, m68k_getpc());
228: }
229:
230: void DMA_Next_Read(void) { // 0x02004010
231: int channel = get_channel(IoAccessCurrentAddress-0x4000);
232: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].next);
233: Log_Printf(LOG_DMA_LEVEL,"DMA Next read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
234: }
235:
236: void DMA_Next_Write(void) {
237: int channel = get_channel(IoAccessCurrentAddress-0x4000);
238: dma[channel].next = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
239: Log_Printf(LOG_DMA_LEVEL,"DMA Next write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].next, m68k_getpc());
240: }
241:
242: void DMA_Limit_Read(void) { // 0x02004014
243: int channel = get_channel(IoAccessCurrentAddress-0x4004);
244: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].limit);
245: Log_Printf(LOG_DMA_LEVEL,"DMA Limit read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].limit, m68k_getpc());
246: }
247:
248: void DMA_Limit_Write(void) {
249: int channel = get_channel(IoAccessCurrentAddress-0x4004);
250: dma[channel].limit = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
251: Log_Printf(LOG_DMA_LEVEL,"DMA Limit write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].limit, m68k_getpc());
252: }
253:
254: void DMA_Start_Read(void) { // 0x02004018
255: int channel = get_channel(IoAccessCurrentAddress-0x4008);
256: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].start);
257: Log_Printf(LOG_DMA_LEVEL,"DMA Start read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].start, m68k_getpc());
258: }
259:
260: void DMA_Start_Write(void) {
261: int channel = get_channel(IoAccessCurrentAddress-0x4008);
262: dma[channel].start = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
263: Log_Printf(LOG_DMA_LEVEL,"DMA Start write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].start, m68k_getpc());
264: }
265:
266: void DMA_Stop_Read(void) { // 0x0200401c
267: int channel = get_channel(IoAccessCurrentAddress-0x400C);
268: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].stop);
269: Log_Printf(LOG_DMA_LEVEL,"DMA Stop read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].stop, m68k_getpc());
270: }
271:
272: void DMA_Stop_Write(void) {
273: int channel = get_channel(IoAccessCurrentAddress-0x400C);
274: dma[channel].stop = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
275: Log_Printf(LOG_DMA_LEVEL,"DMA Stop write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].stop, m68k_getpc());
276: }
277:
278: void DMA_Init_Read(void) { // 0x02004210
279: int channel = get_channel(IoAccessCurrentAddress-0x4200);
280: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].init);
281: Log_Printf(LOG_DMA_LEVEL,"DMA Init read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].init, m68k_getpc());
282: }
283:
284: void DMA_Init_Write(void) {
285: int channel = get_channel(IoAccessCurrentAddress-0x4200);
286: dma[channel].init = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
287: Log_Printf(LOG_DMA_LEVEL,"DMA Init write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].init, m68k_getpc());
288: }
289:
290: void DMA_Size_Read(void) { // 0x02004214
291: int channel = get_channel(IoAccessCurrentAddress-0x4204);
292: IoMem_WriteLong(IoAccessCurrentAddress & IO_SEG_MASK, dma[channel].size);
293: Log_Printf(LOG_DMA_LEVEL,"DMA Size read at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].size, m68k_getpc());
294: }
295:
296: void DMA_Size_Write(void) {
297: int channel = get_channel(IoAccessCurrentAddress-0x4204);
298: dma[channel].size = IoMem_ReadLong(IoAccessCurrentAddress & IO_SEG_MASK);
299: Log_Printf(LOG_DMA_LEVEL,"DMA Size write at $%08x val=$%08x PC=$%08x\n", IoAccessCurrentAddress, dma[channel].size, m68k_getpc());
300: }
301:
302:
303:
304: /* DMA Functions */
305:
306: /*void copy_to_scsidma_buffer(Uint8 device_outbuf[], int outbuf_size) {
307: memcpy(dma_buffer, device_outbuf, outbuf_size);
308: }*/
309:
310: /*void dma_clear_memory(Uint32 datalength) {
311: Uint32 start_addr;
312: Uint32 end_addr;
313:
314: if(dma_init == 0)
315: start_addr = dma_next;
316: else
317: start_addr = dma_init;
318:
319: end_addr = start_addr + datalength;
320:
321: NEXTMemory_Clear(start_addr, end_addr);
322: }*/
323:
324: void dma_memory_read(Uint8 *buf, Uint32 *size, int channel) {
325: Uint32 base_addr;
326: Uint8 align = 16;
327: Uint32 size_count = 0;
328: Uint32 read_addr;
329: int interrupt = get_interrupt_type(channel);
330:
331: if ((channel == CHANNEL_EN_TX) && !ConfigureParams.System.bTurbo)
332: *size = (dma[channel].limit&0x0FFFFFFF) - (dma[channel].init&0x0FFFFFFF);
333: else
334: *size = (dma[channel].limit&0x0FFFFFFF) - (dma[channel].next&0x0FFFFFFF);
335:
336: if(channel == CHANNEL_EN_RX || channel == CHANNEL_EN_TX)
337: align = 32;
338:
339: // if((*size % align) != 0) {
340: // *size -= *size % align;
341: // *size += align;
342: // }
343:
344: if(dma[channel].init == 0)
345: base_addr = dma[channel].next;
346: else
347: base_addr = dma[channel].init;
348:
349: Log_Printf(LOG_WARN, "[DMA] Read from mem: at $%08x, %i bytes",base_addr, *size);
350: for (size_count = 0; size_count < *size; size_count++) {
351: read_addr = base_addr + size_count;
352: buf[size_count] = NEXTMemory_ReadByte(read_addr);
353: }
354: printf("READ FROM MEMORY: %02x\n", buf[0]);
355:
356: dma[channel].csr |= DMA_COMPLETE | DMA_SUPDATE;
357:
358: set_interrupt(interrupt, SET_INT);
359: }
360:
361:
362: void dma_memory_write(Uint8 *buf, Uint32 size, int channel) {
363: Uint32 base_addr, tail_addr;
364: Uint8 align = 16;
365: Uint32 size_count = 0;
366: Uint32 write_addr;
367: Uint32 dma_tail = 0;
368: int interrupt = get_interrupt_type(channel);
369:
370: if(channel == CHANNEL_EN_RX || channel == CHANNEL_EN_TX)
371: align = 32;
372:
373: // if((size % align) != 0) {
374: // size -= size % align;
375: // size += align;
376: // }
377:
378:
379: if(dma[channel].init == 0) {
380: base_addr = dma[channel].next;
381: dma_tail = 0;
382: } else {
383: base_addr = dma[channel].init;
384:
385: /* If the transfer size is greater than (limit - init):
386: * Copy residual bytes to physical addresses at start. */
387: if (size > (dma[channel].limit - dma[channel].init)) {
388: tail_addr = dma[channel].start;
389: dma_tail = size - (dma[channel].limit - dma[channel].init);
390: size = (dma[channel].limit - dma[channel].init);
391: Log_Printf(LOG_WARN, "[DMA] Residual bytes: %i", dma_tail);
392: }
393: }
394:
395: Log_Printf(LOG_WARN, "[DMA] Write to mem: at $%08x, %i bytes",base_addr,size);
396: for (size_count = 0; size_count < size; size_count++) {
397: write_addr = base_addr + size_count;
398: NEXTMemory_WriteByte(write_addr, buf[size_count]);
399: }
400:
401: /* If there are residual bytes, copy them to physical addresses starting
402: * at "start". */
403:
404: if (dma_tail) {
405: Log_Printf(LOG_WARN, "[DMA] Write residual bytes at $%08x, %i bytes",tail_addr,dma_tail);
406: for (size_count = 0; size_count < dma_tail; size_count++) {
407: write_addr = tail_addr + size_count;
408: NEXTMemory_WriteByte(write_addr, buf[size+size_count]);
409: }
410: }
411:
412:
413: /* Test read/write */
414: Log_Printf(LOG_DMA_LEVEL, "DMA Write Test: $%02x,$%02x,$%02x,$%02x\n", NEXTMemory_ReadByte(base_addr),NEXTMemory_ReadByte(base_addr+16),NEXTMemory_ReadByte(base_addr+32),NEXTMemory_ReadByte(base_addr+384));
415: // NEXTMemory_WriteByte(base_addr, 0x77);
416: // Uint8 testvar = NEXTMemory_ReadByte(base_addr);
417: // Log_Printf(LOG_DMA_LEVEL, "Write Test: $%02x at $%08x", testvar, base_addr);
418:
419: dma[channel].init = 0;
420:
421: /* saved limit is checked to calculate packet size
422: by both the rom and netbsd */
423: dma[channel].saved_limit = dma[channel].next + size;
424: dma[channel].saved_next = dma[channel].next;
425:
426: if(!(dma[channel].csr & DMA_SUPDATE)||(channel==CHANNEL_EN_RX)) { // Ethernet: this needs to be checked!
427: dma[channel].next = dma[channel].start;
428: dma[channel].limit = dma[channel].stop;
429: }
430:
431: dma[channel].csr |= DMA_COMPLETE;
432:
433: set_interrupt(interrupt, SET_INT);
434: // set_interrupt(INT_SCSI_DMA, RELEASE_INT);
435: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.