Browse Source

DMAC initial code

vampirefrog 1 year ago
parent
commit
a4cdeca8bb
2 changed files with 396 additions and 0 deletions
  1. 360
    0
      dmac.c
  2. 36
    0
      dmac.h

+ 360
- 0
dmac.c View File

@@ -0,0 +1,360 @@
1
+/* DMAC ◆ DMA controller */
2
+
3
+#include "v68.h"
4
+#include "dmac.h"
5
+
6
+static void dmac_transfer_start(int chan);
7
+static void dmac_transfer_abort(int chan);
8
+static void dmac_transfer_halt(int chan);
9
+static void dmac_transfer_continue(int chan);
10
+
11
+void dmac_init() {
12
+	for (int x = 0; x < 4; x++)
13
+	{
14
+		v68.dmac.channels[x].niv = 0x0f;
15
+		v68.dmac.channels[x].eiv = 0x0f;
16
+		v68.dmac.channels[x].cpr = 0;
17
+		v68.dmac.channels[x].dcr = 0;
18
+		v68.dmac.channels[x].ocr = 0;
19
+		v68.dmac.channels[x].scr = 0;
20
+		v68.dmac.channels[x].ccr = 0;
21
+		v68.dmac.channels[x].csr &= 0xfe;
22
+		v68.dmac.channels[x].cer = 0;
23
+		v68.dmac.channels[x].gcr = 0;
24
+
25
+		// m_timer[x]->adjust(attotime::never);
26
+		v68.dmac.halted[x] = 0;
27
+	}
28
+}
29
+
30
+static inline int dma_in_progress(int chan) {
31
+	return (v68.dmac.channels[chan].csr & 0x08) != 0;
32
+}
33
+
34
+void dmac_tick(int chan) {
35
+	int data;
36
+	int datasize = 1;
37
+
38
+	verbose1("dmac_tick chan=%d in_progress=%d\n", chan, dma_in_progress(chan));
39
+
40
+	if (!dma_in_progress(chan))  // DMA in progress in channel x
41
+		return;
42
+
43
+	if (v68.dmac.channels[chan].ocr & 0x80)  // direction: 1 = device -> memory
44
+	{
45
+		switch(v68.dmac.channels[chan].ocr & 0x30)  // operation size
46
+		{
47
+		case 0x00:  // 8 bit
48
+			data = m68k_read_memory_8(v68.dmac.channels[chan].dar);  // read from device address
49
+			m68k_write_memory_8(v68.dmac.channels[chan].mar, data);  // write to memory address
50
+			datasize = 1;
51
+			break;
52
+		case 0x10:  // 16 bit
53
+			data = m68k_read_memory_16(v68.dmac.channels[chan].dar);  // read from device address
54
+			m68k_write_memory_16(v68.dmac.channels[chan].mar, data);  // write to memory address
55
+			datasize = 2;
56
+			break;
57
+		case 0x20:  // 32 bit
58
+			data = m68k_read_memory_16(v68.dmac.channels[chan].dar) << 16;  // read from device address
59
+			data |= m68k_read_memory_16(v68.dmac.channels[chan].dar+2);
60
+			m68k_write_memory_16(v68.dmac.channels[chan].mar, (data & 0xffff0000) >> 16);  // write to memory address
61
+			m68k_write_memory_16(v68.dmac.channels[chan].mar+2, data & 0x0000ffff);
62
+			datasize = 4;
63
+			break;
64
+		case 0x30:  // 8 bit packed (?)
65
+			data = m68k_read_memory_8(v68.dmac.channels[chan].dar);  // read from device address
66
+			m68k_write_memory_8(v68.dmac.channels[chan].mar, data);  // write to memory address
67
+			datasize = 1;
68
+			break;
69
+		}
70
+		verbose2("dmac_tick device->memory dar=0x%08x mar=0x%08x data=0x%02x\n", v68.dmac.channels[chan].dar, v68.dmac.channels[chan].mar, data);
71
+	}
72
+	else  // memory -> device
73
+	{
74
+		switch(v68.dmac.channels[chan].ocr & 0x30)  // operation size
75
+		{
76
+		case 0x00:  // 8 bit
77
+			data = m68k_read_memory_8(v68.dmac.channels[chan].mar);  // read from memory address
78
+			m68k_write_memory_8(v68.dmac.channels[chan].dar, data);  // write to device address
79
+			datasize = 1;
80
+			break;
81
+		case 0x10:  // 16 bit
82
+			data = m68k_read_memory_16(v68.dmac.channels[chan].mar);  // read from memory address
83
+			m68k_write_memory_16(v68.dmac.channels[chan].dar, data);  // write to device address
84
+			datasize = 2;
85
+			break;
86
+		case 0x20:  // 32 bit
87
+			data = m68k_read_memory_16(v68.dmac.channels[chan].mar) << 16;  // read from memory address
88
+			data |= m68k_read_memory_16(v68.dmac.channels[chan].mar+2);  // read from memory address
89
+			m68k_write_memory_16(v68.dmac.channels[chan].dar, (data & 0xffff0000) >> 16);  // write to device address
90
+			m68k_write_memory_16(v68.dmac.channels[chan].dar+2, data & 0x0000ffff);  // write to device address
91
+			datasize = 4;
92
+			break;
93
+		case 0x30:  // 8 bit packed (?)
94
+			data = m68k_read_memory_8(v68.dmac.channels[chan].mar);  // read from memory address
95
+			m68k_write_memory_8(v68.dmac.channels[chan].dar, data);  // write to device address
96
+			verbose2("dmac_tick 0x%08x -> 0x%08x = 0x%02x\n", v68.dmac.channels[chan].mar, v68.dmac.channels[chan].dar, data);
97
+			datasize = 1;
98
+			break;
99
+		}
100
+		verbose2("dmac_tick memory->device mar=0x%08x dar=0x%08x data=0x%02x\n", v68.dmac.channels[chan].mar, v68.dmac.channels[chan].dar, data);
101
+	}
102
+
103
+
104
+	// decrease memory transfer counter
105
+	if (v68.dmac.channels[chan].mtc > 0)
106
+		v68.dmac.channels[chan].mtc--;
107
+
108
+	// handle change of memory and device addresses
109
+	if ((v68.dmac.channels[chan].scr & 0x03) == 0x01)
110
+		v68.dmac.channels[chan].dar+=datasize;
111
+	else if ((v68.dmac.channels[chan].scr & 0x03) == 0x02)
112
+		v68.dmac.channels[chan].dar-=datasize;
113
+
114
+	if ((v68.dmac.channels[chan].scr & 0x0c) == 0x04)
115
+		v68.dmac.channels[chan].mar+=datasize;
116
+	else if ((v68.dmac.channels[chan].scr & 0x0c) == 0x08)
117
+		v68.dmac.channels[chan].mar-=datasize;
118
+
119
+	if (v68.dmac.channels[chan].mtc <= 0)
120
+	{
121
+		// End of transfer
122
+		verbose2("dmac_tick End of transfer\n");
123
+		if ((v68.dmac.channels[chan].ocr & 0x0c) != 0 && v68.dmac.channels[chan].btc > 0)
124
+		{
125
+			v68.dmac.channels[chan].btc--;
126
+			v68.dmac.channels[chan].bar+=6;
127
+			v68.dmac.channels[chan].mar = m68k_read_memory_16(v68.dmac.channels[chan].bar) << 16;
128
+			v68.dmac.channels[chan].mar |= m68k_read_memory_16(v68.dmac.channels[chan].bar+2);
129
+			v68.dmac.channels[chan].mtc = m68k_read_memory_16(v68.dmac.channels[chan].bar+4);
130
+			return;
131
+		}
132
+		// m_timer[x]->adjust(attotime::never);
133
+		v68.dmac.channels[chan].csr |= 0xe0;  // channel operation complete, block transfer complete
134
+		v68.dmac.channels[chan].csr &= ~0x08;  // channel no longer active
135
+		v68.dmac.channels[chan].ccr &= ~0xc0;
136
+
137
+		// Burst transfer
138
+		if ((v68.dmac.channels[chan].dcr & 0xc0) == 0x00)
139
+		{
140
+			// m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
141
+		}
142
+	}
143
+}
144
+
145
+static void dmac_transfer_start(int chan) {
146
+	verbose1("dmac_transfer_start chan=%d\n", chan);
147
+	v68.dmac.channels[chan].csr &= ~0xe0;
148
+	v68.dmac.channels[chan].csr |= 0x08;  // Channel active
149
+	v68.dmac.channels[chan].csr &= ~0x30;  // Reset Error and Normal termination bits
150
+	if ((v68.dmac.channels[chan].ocr & 0x0c) != 0x00)  // Array chain or Link array chain
151
+	{
152
+		v68.dmac.channels[chan].mar = m68k_read_memory_16(v68.dmac.channels[chan].bar) << 16;
153
+		v68.dmac.channels[chan].mar |= m68k_read_memory_16(v68.dmac.channels[chan].bar+2);
154
+		v68.dmac.channels[chan].mtc = m68k_read_memory_16(v68.dmac.channels[chan].bar+4);
155
+		if (v68.dmac.channels[chan].btc > 0)
156
+			v68.dmac.channels[chan].btc--;
157
+	}
158
+
159
+	// Burst transfers will halt the CPU until the transfer is complete
160
+	if ((v68.dmac.channels[chan].dcr & 0xc0) == 0x00)  // Burst transfer
161
+	{
162
+		// m_cpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
163
+		// m_timer[channel]->adjust(attotime::zero, channel, m_burst_clock[channel]);
164
+	} else if (!(v68.dmac.channels[chan].ocr & 2)) {
165
+		// m_timer[channel]->adjust(attotime::from_usec(500), channel, m_our_clock[channel]);
166
+	} else if ((v68.dmac.channels[chan].ocr & 3) == 3) {
167
+		// m_timer[channel]->adjust(attotime::from_usec(500), channel, attotime::never);
168
+	} else if ((v68.dmac.channels[chan].ocr & 3) == 2) {
169
+		// m_timer[channel]->adjust(attotime::never, channel, attotime::never);
170
+	}
171
+
172
+	v68.dmac.transfer_size[chan] = v68.dmac.channels[chan].mtc;
173
+
174
+	verbose2("DMA: Transfer begins: size=0x%08x\n",v68.dmac.transfer_size[chan]);
175
+}
176
+
177
+static void dmac_transfer_abort(int chan) {
178
+	if (!dma_in_progress(chan))
179
+		return;
180
+
181
+	verbose3("DMA#%i: Transfer aborted\n",chan);
182
+	// m_timer[channel]->adjust(attotime::never);
183
+	v68.dmac.channels[chan].csr |= 0x90;  // channel error
184
+	v68.dmac.channels[chan].csr &= ~0x08;  // channel no longer active
185
+	v68.dmac.channels[chan].cer = 0x11;
186
+	v68.dmac.channels[chan].ccr &= ~0xc0;
187
+	// m_dma_error((offs_t)3, v68.dmac.channels[chan].ccr & 0x08);
188
+}
189
+
190
+static void dmac_transfer_halt(int chan) {
191
+	v68.dmac.halted[chan] = 1;
192
+	// m_timer[channel]->adjust(attotime::never);
193
+}
194
+
195
+static void dmac_transfer_continue(int chan) {
196
+	if (v68.dmac.halted[chan] != 0)
197
+	{
198
+		v68.dmac.halted[chan] = 0;
199
+		// m_timer[channel]->adjust(attotime::zero, channel, m_our_clock[channel]);
200
+	}
201
+}
202
+
203
+#define ACCESSING_BITS_0_7              ((mem_mask & 0x000000ffU) != 0)
204
+#define ACCESSING_BITS_8_15             ((mem_mask & 0x0000ff00U) != 0)
205
+void dmac_write_16(uint32_t addr, uint16_t data, uint16_t mem_mask) {
206
+	uint8_t chan = (addr >> 6) & 0x03;
207
+	uint8_t reg = (addr & 0x1f) >> 1;
208
+	verbose2("dmac_write_16 0x%08x = 0x%04x mask=0x%04x chan=%d reg=0x%02x\n", addr, data, mem_mask, chan, reg);
209
+	switch(reg) {
210
+		case 0x00:
211
+			if(ACCESSING_BITS_8_15) {
212
+				v68.dmac.channels[chan].csr &= ~((data & 0xf600) >> 8);
213
+				verbose2("DMA#%i: Channel status write : %02x data=0x%04x data&0xf600=0x%04x (data&0xf600)>>8=0x%04x ~((data&0xf600)>>8)=%04x\n",chan,v68.dmac.channels[chan].csr, data, data&0xf600, (data&0xf600)>>8, ~((data & 0xf600) >> 8));
214
+				// Clearing ERR also resets CER (which is otherwise read-only)
215
+				if ((data & 0x1000) != 0)
216
+					v68.dmac.channels[chan].cer = 0;
217
+			}
218
+			break;
219
+		case 0x02:  // DCR / OCR
220
+			if (ACCESSING_BITS_8_15)
221
+			{
222
+				v68.dmac.channels[chan].dcr = (data & 0xff00) >> 8;
223
+				verbose2("DMA#%i: Device Control write : %02x\n",chan,v68.dmac.channels[chan].dcr);
224
+			}
225
+			if (ACCESSING_BITS_0_7)
226
+			{
227
+				v68.dmac.channels[chan].ocr = data & 0x00ff;
228
+				verbose2("DMA#%i: Operation Control write : %02x\n",chan,v68.dmac.channels[chan].ocr);
229
+			}
230
+			break;
231
+		case 0x03:  // SCR / CCR
232
+			if (ACCESSING_BITS_8_15)
233
+			{
234
+				v68.dmac.channels[chan].scr = (data & 0xff00) >> 8;
235
+				verbose3("DMA#%i: Sequence Control write : %02x\n",chan,v68.dmac.channels[chan].scr);
236
+			}
237
+			if (ACCESSING_BITS_0_7)
238
+			{
239
+				v68.dmac.channels[chan].ccr = data & 0x00ff;
240
+				if ((data & 0x0080))
241
+					dmac_transfer_start(chan);
242
+				if (data & 0x0010)  // software abort
243
+					dmac_transfer_abort(chan);
244
+				if (data & 0x0020)  // halt operation
245
+					dmac_transfer_halt(chan);
246
+				if (data & 0x0040)  // continure operation
247
+					dmac_transfer_continue(chan);
248
+				verbose3("DMA#%i: Channel Control write : %02x\n",chan,v68.dmac.channels[chan].ccr);
249
+			}
250
+			break;
251
+		case 0x05:  // MTC
252
+			v68.dmac.channels[chan].mtc = data;
253
+			verbose2("DMA#%i:  Memory Transfer Counter write : 0x%04x\n",chan,v68.dmac.channels[chan].mtc);
254
+			break;
255
+		case 0x06:  // MAR (high)
256
+			v68.dmac.channels[chan].mar = (v68.dmac.channels[chan].mar & 0x0000ffff) | (data << 16);
257
+			verbose2("DMA#%i:  Memory Address write : %08x\n",chan,v68.dmac.channels[chan].mar);
258
+			break;
259
+		case 0x07:  // MAR (low)
260
+			v68.dmac.channels[chan].mar = (v68.dmac.channels[chan].mar & 0xffff0000) | (data & 0x0000ffff);
261
+			verbose2("DMA#%i:  Memory Address write : %08x\n",chan,v68.dmac.channels[chan].mar);
262
+			break;
263
+		case 0x0a:  // DAR (high)
264
+			v68.dmac.channels[chan].dar = (v68.dmac.channels[chan].dar & 0x0000ffff) | (data << 16);
265
+			verbose2("DMA#%i:  Device Address write : %08x\n",chan,v68.dmac.channels[chan].dar);
266
+			break;
267
+		case 0x0b:  // DAR (low)
268
+			v68.dmac.channels[chan].dar = (v68.dmac.channels[chan].dar & 0xffff0000) | (data & 0x0000ffff);
269
+			verbose2("DMA#%i:  Device Address write : %08x\n",chan,v68.dmac.channels[chan].dar);
270
+			break;
271
+		case 0x0d:  // BTC
272
+			v68.dmac.channels[chan].btc = data;
273
+			verbose3("DMA#%i:  Base Transfer Counter write : %04x\n",chan,v68.dmac.channels[chan].btc);
274
+			break;
275
+		case 0x0e:  // BAR (high)
276
+			v68.dmac.channels[chan].bar = (v68.dmac.channels[chan].bar & 0x0000ffff) | (data << 16);
277
+			verbose3("DMA#%i:  Base Address write : %08x\n",chan,v68.dmac.channels[chan].bar);
278
+			break;
279
+		case 0x0f:  // BAR (low)
280
+			v68.dmac.channels[chan].bar = (v68.dmac.channels[chan].bar & 0xffff0000) | (data & 0x0000ffff);
281
+			verbose3("DMA#%i:  Base Address write : %08x\n",chan,v68.dmac.channels[chan].bar);
282
+			break;
283
+		case 0x12:  // NIV
284
+			v68.dmac.channels[chan].niv = data & 0xff;
285
+			verbose3("DMA#%i:  Normal IRQ Vector write : %02x\n",chan,v68.dmac.channels[chan].niv);
286
+			break;
287
+		case 0x13:  // EIV
288
+			v68.dmac.channels[chan].eiv = data & 0xff;
289
+			verbose3("DMA#%i:  Error IRQ Vector write : %02x\n",chan,v68.dmac.channels[chan].eiv);
290
+			break;
291
+		case 0x14:  // MFC
292
+			v68.dmac.channels[chan].mfc = data & 0xff;
293
+			verbose3("DMA#%i:  Memory Function Code write : %02x\n",chan,v68.dmac.channels[chan].mfc);
294
+			break;
295
+		case 0x16:  // CPR
296
+			v68.dmac.channels[chan].cpr = data & 0xff;
297
+			verbose3("DMA#%i:  Channel Priority write : %02x\n",chan,v68.dmac.channels[chan].cpr);
298
+			break;
299
+		case 0x18:  // DFC
300
+			v68.dmac.channels[chan].dfc = data & 0xff;
301
+			verbose3("DMA#%i:  Device Function Code write : %02x\n",chan,v68.dmac.channels[chan].dfc);
302
+			break;
303
+		case 0x1c:  // BFC
304
+			v68.dmac.channels[chan].bfc = data & 0xff;
305
+			verbose3("DMA#%i:  Base Function Code write : %02x\n",chan,v68.dmac.channels[chan].bfc);
306
+			break;
307
+		case 0x1f:
308
+			v68.dmac.channels[chan].gcr = data & 0xff;
309
+			verbose3("DMA#%i:  General Control write : %02x\n",chan,v68.dmac.channels[chan].gcr);
310
+			break;
311
+	}
312
+}
313
+
314
+uint16_t dmac_read_16(uint32_t offset, uint16_t mem_mask) {
315
+	int chan = (offset >> 6) & 0x03;
316
+	int reg = (offset & 0x1f) >> 1;
317
+
318
+	verbose3("dmac_read_16 offset=0x%08x mem_mask=0x%04x chan=0x%02x reg=0x%02x\n", offset, mem_mask, chan, reg);
319
+
320
+	switch(reg)
321
+	{
322
+	case 0x00:  // CSR / CER
323
+		return (v68.dmac.channels[chan].csr << 8) | v68.dmac.channels[chan].cer;
324
+	case 0x02:  // DCR / OCR
325
+		return (v68.dmac.channels[chan].dcr << 8) | v68.dmac.channels[chan].ocr;
326
+	case 0x03:  // SCR / CCR
327
+		return (v68.dmac.channels[chan].scr << 8) | v68.dmac.channels[chan].ccr;
328
+	case 0x05:  // MTC
329
+		return v68.dmac.channels[chan].mtc;
330
+	case 0x06:  // MAR (high)
331
+		return (v68.dmac.channels[chan].mar & 0xffff0000) >> 16;
332
+	case 0x07:  // MAR (low)
333
+		return (v68.dmac.channels[chan].mar & 0x0000ffff);
334
+	case 0x0a:  // DAR (high)
335
+		return (v68.dmac.channels[chan].dar & 0xffff0000) >> 16;
336
+	case 0x0b:  // DAR (low)
337
+		return (v68.dmac.channels[chan].dar & 0x0000ffff);
338
+	case 0x0d:  // BTC
339
+		return v68.dmac.channels[chan].btc;
340
+	case 0x0e:  // BAR (high)
341
+		return (v68.dmac.channels[chan].bar & 0xffff0000) >> 16;
342
+	case 0x0f:  // BAR (low)
343
+		return (v68.dmac.channels[chan].bar & 0x0000ffff);
344
+	case 0x12:  // NIV
345
+		return v68.dmac.channels[chan].niv;
346
+	case 0x13:  // EIV
347
+		return v68.dmac.channels[chan].eiv;
348
+	case 0x14:  // MFC
349
+		return v68.dmac.channels[chan].mfc;
350
+	case 0x16:  // CPR
351
+		return v68.dmac.channels[chan].cpr;
352
+	case 0x18:  // DFC
353
+		return v68.dmac.channels[chan].dfc;
354
+	case 0x1c:  // BFC
355
+		return v68.dmac.channels[chan].bfc;
356
+	case 0x1f:  // GCR
357
+		return v68.dmac.channels[chan].gcr;
358
+	}
359
+	return 0xff;
360
+}

+ 36
- 0
dmac.h View File

@@ -0,0 +1,36 @@
1
+#pragma once
2
+
3
+#include <stdint.h>
4
+
5
+struct dmac_channel {
6
+	uint8_t  csr; /* 0x00 R/W Channel Status Register    */
7
+	uint8_t  cer; /* 0x01 R   Channel Error Register     */
8
+	uint8_t  dcr; /* 0x04 R/W Device Control Register    */
9
+	uint8_t  ocr; /* 0x05 R/W Operation control register */
10
+	uint8_t  scr; /* 0x06 R/W Sequence control register  */
11
+	uint8_t  ccr; /* 0x07 R/W Channel control register   */
12
+	uint16_t mtc; /* 0x0a R/W Memory transfer counter    */
13
+	uint32_t mar; /* 0x0c R/W Memory address register    */
14
+	uint32_t dar; /* 0x14 R/W Device address register    */
15
+	uint16_t btc; /* 0x1a R/W Base transfer counter      */
16
+	uint32_t bar; /* 0x1c R/W Base address register      */
17
+	uint8_t  niv; /* 0x25 R/W Normal interrupt vector    */
18
+	uint8_t  eiv; /* 0x27 R/W Error interrupt vector     */
19
+	uint8_t  mfc; /* 0x29 R/W Memory function code       */
20
+	uint8_t  cpr; /* 0x2d R/W Channel priority register  */
21
+	uint8_t  dfc; /* 0x31 R/W Device function code       */
22
+	uint8_t  bfc; /* 0x39 R/W Base function code         */
23
+	uint8_t  gcr; /* 0x3f R/W General control register   */
24
+};
25
+
26
+struct dmac {
27
+	struct dmac_channel channels[4];
28
+	int halted[4];
29
+	int16_t transfer_size[4];
30
+	int drq_state[4];
31
+};
32
+
33
+void dmac_init(void);
34
+void dmac_write_16(uint32_t addr, uint16_t data, uint16_t mem_mask);
35
+uint16_t dmac_read_16(uint32_t addr, uint16_t mem_mask);
36
+void dmac_tick(int chan);

Loading…
Cancel
Save