|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.10! root 7: //
! 8: // DMAC (HD63450)
! 9: //
! 10:
1.1 root 11: #include "dmac.h"
1.1.1.3 root 12: #include "bus.h"
1.1.1.6 root 13: #include "interrupt.h"
1.1.1.10! root 14: #include "mpu.h"
! 15: #include "scheduler.h"
! 16:
! 17: // time 時間後に呼び出すコールバックをセットする。
! 18: // func の書式が面倒なのを省略して書きたいため。
! 19: #define CallAfter(func_, time_) do { \
! 20: event.func = ToEventCallback(&DMACDevice::func_); \
! 21: event.time = time_ * 80_nsec; \
! 22: gScheduler->StartEvent(event); \
! 23: } while (0)
1.1.1.2 root 24:
1.1.1.10! root 25: // グローバル参照用
! 26: DMACDevice *gDMAC;
1.1 root 27:
1.1.1.10! root 28: // コンストラクタ
1.1 root 29: DMACDevice::DMACDevice()
1.1.1.8 root 30: : inherited("DMAC")
1.1 root 31: {
32: devaddr = baseaddr;
33: devlen = 0x2000;
1.1.1.2 root 34:
35: for (int i = 0; i < countof(dmac.chan); i++) {
36: dmac.chan[i].ch = i;
37: dmac.chan[i].parent = this;
38: }
39: dmac.chan[0].desc = "FD";
40: dmac.chan[1].desc = "HD";
41: dmac.chan[2].desc = "User";
42: dmac.chan[3].desc = "ADPCM";
43:
1.1.1.10! root 44: event.Regist("DMAC");
1.1.1.8 root 45:
1.1.1.10! root 46: monitor.func = ToMonitorCallback(&DMACDevice::MonitorUpdate);
1.1.1.8 root 47: monitor.SetSize(80, 30);
48: monitor.Regist(ID_MONITOR_DMAC);
1.1 root 49: }
50:
1.1.1.10! root 51: // デストラクタ
1.1 root 52: DMACDevice::~DMACDevice()
53: {
1.1.1.10! root 54: gDMAC = NULL;
1.1 root 55: }
56:
1.1.1.10! root 57: // リセット
1.1.1.5 root 58: void
1.1.1.10! root 59: DMACDevice::ResetHard(bool poweron)
1.1.1.5 root 60: {
61: putlog(2, "リセット");
62:
63: // Clears GCR, DCR, OCR, SCR, CCR, CSR, CPR and CER for all channels.
64: // NIV and EIV are all set to $0F (uninitialized interrupt vector).
65: // MTC, MAR, DAR, BTC, BAR, MFC, DFC and BFC are not affected.
66:
67: dmac.gcr = 0;
68: for (int ch = 0; ch < countof(dmac.chan); ch++) {
69: DMAC::Channel *chan = &dmac.chan[ch];
70: chan->dcr = 0;
71: chan->ocr = 0;
72: chan->scr = 0;
73: chan->ccr = 0;
74: chan->csr = 0;
75: chan->active = false;
76: chan->pcl = false;
77: chan->cpr = 0;
78: chan->cer = 0;
79:
80: chan->niv = 0x0f;
81: chan->eiv = 0x0f;
82:
1.1.1.10! root 83: chan->priority = 0;
1.1.1.5 root 84: }
1.1.1.10! root 85:
! 86: // イベントを停止
! 87: event.SetName("DMAC");
! 88: gScheduler->StopEvent(event);
1.1.1.5 root 89: }
90:
1.1 root 91: uint64
1.1.1.7 root 92: DMACDevice::Read(uint32 offset)
1.1 root 93: {
94: uint8 data;
95: int ch;
96:
1.1.1.5 root 97: gMPU->AddCycle(37); // InsideOut p.135
98:
1.1.1.7 root 99: ch = offset / 0x40;
1.1.1.2 root 100: DMAC::Channel *chan = &dmac.chan[ch];
1.1.1.7 root 101: int n = offset % 0x40;
1.1 root 102: switch (n) {
103: case DMAC::CSR:
1.1.1.2 root 104: data = chan->PeekCSR();
105: putlog(4, "#%d CSR -> $%02x", ch, data);
1.1 root 106: break;
107:
108: case DMAC::CER:
109: data = chan->cer;
1.1.1.2 root 110: putlog(4, "#%d CER -> $%02x", ch, data);
1.1 root 111: break;
112:
113: case DMAC::DCR:
114: data = chan->dcr;
1.1.1.2 root 115: putlog(4, "#%d DCR -> $%02x", ch, data);
1.1 root 116: break;
117:
118: case DMAC::OCR:
119: data = chan->ocr;
1.1.1.2 root 120: putlog(4, "#%d OCR -> $%02x", ch, data);
1.1 root 121: break;
122:
123: case DMAC::SCR:
124: data = chan->scr;
1.1.1.2 root 125: putlog(4, "#%d SCR -> $%02x", ch, data);
1.1 root 126: break;
127:
128: case DMAC::CCR:
1.1.1.6 root 129: data = chan->ccr;
1.1.1.2 root 130: putlog(4, "#%d CCR -> $%02x", ch, data);
1.1 root 131: break;
132:
133: case DMAC::MTC:
134: data = chan->mtc >> 8;
1.1.1.2 root 135: putlog(4, "#%d MTC:H -> $%02x", ch, data);
1.1 root 136: break;
137: case DMAC::MTC + 1:
138: data = chan->mtc & 0xff;
1.1.1.2 root 139: putlog(4, "#%d MTC:L -> $%02x", ch, data);
1.1 root 140: break;
141:
142: case DMAC::MAR:
143: data = chan->mar >> 24;
1.1.1.2 root 144: putlog(4, "#%d MAR:0 -> $%02x", ch, data);
1.1 root 145: break;
146: case DMAC::MAR + 1:
147: data = (chan->mar >> 16) & 0xff;
1.1.1.2 root 148: putlog(4, "#%d MAR:1 -> $%02x", ch, data);
1.1 root 149: break;
150: case DMAC::MAR + 2:
151: data = (chan->mar >> 8) & 0xff;
1.1.1.2 root 152: putlog(4, "#%d MAR:2 -> $%02x", ch, data);
1.1 root 153: break;
154: case DMAC::MAR + 3:
155: data = chan->mar & 0xff;
1.1.1.2 root 156: putlog(4, "#%d MAR:3 -> $%02x", ch, data);
1.1 root 157: break;
158:
159: case DMAC::DAR:
160: data = chan->dar >> 24;
1.1.1.2 root 161: putlog(4, "#%d DAR:0 -> $%02x", ch, data);
1.1 root 162: break;
163: case DMAC::DAR + 1:
164: data = (chan->dar >> 16) & 0xff;
1.1.1.2 root 165: putlog(4, "#%d DAR:1 -> $%02x", ch, data);
1.1 root 166: break;
167: case DMAC::DAR + 2:
168: data = (chan->dar >> 8) & 0xff;
1.1.1.2 root 169: putlog(4, "#%d DAR:2 -> $%02x", ch, data);
1.1 root 170: break;
171: case DMAC::DAR + 3:
172: data = chan->dar & 0xff;
1.1.1.2 root 173: putlog(4, "#%d DAR:3 -> $%02x", ch, data);
1.1 root 174: break;
175:
176: case DMAC::BTC:
177: data = chan->btc >> 8;
1.1.1.2 root 178: putlog(4, "#%d BTC:H -> $%02x", ch, data);
1.1 root 179: break;
180: case DMAC::BTC + 1:
181: data = chan->btc & 0xff;
1.1.1.2 root 182: putlog(4, "#%d BTC:L -> $%02x", ch, data);
1.1 root 183: break;
184:
185: case DMAC::BAR:
186: data = chan->bar >> 24;
1.1.1.2 root 187: putlog(4, "#%d BAR:0 -> $%02x", ch, data);
1.1 root 188: break;
189: case DMAC::BAR + 1:
190: data = (chan->bar >> 16) & 0xff;
1.1.1.2 root 191: putlog(4, "#%d BAR:1 -> $%02x", ch, data);
1.1 root 192: break;
193: case DMAC::BAR + 2:
194: data = (chan->bar >> 8) & 0xff;
1.1.1.2 root 195: putlog(4, "#%d BAR:2 -> $%02x", ch, data);
1.1 root 196: break;
197: case DMAC::BAR + 3:
198: data = chan->bar & 0xff;
1.1.1.2 root 199: putlog(4, "#%d BAR:3 -> $%02x", ch, data);
1.1 root 200: break;
201:
202: case DMAC::NIV:
203: data = chan->niv;
1.1.1.2 root 204: putlog(4, "#%d NIV -> $%02x", ch, data);
1.1 root 205: break;
206:
207: case DMAC::EIV:
208: data = chan->eiv;
1.1.1.2 root 209: putlog(4, "#%d EIV -> $%02x", ch, data);
1.1 root 210: break;
211:
212: case DMAC::MFC:
213: data = chan->mfc;
1.1.1.2 root 214: putlog(4, "#%d MFC -> $%02x", ch, data);
1.1 root 215: break;
216:
217: case DMAC::CPR:
218: data = chan->cpr;
1.1.1.2 root 219: putlog(4, "#%d CPR -> $%02x", ch, data);
1.1 root 220: break;
221:
222: case DMAC::DFC:
223: data = chan->dfc;
1.1.1.2 root 224: putlog(4, "#%d DFC -> $%02x", ch, data);
1.1 root 225: break;
226:
227: case DMAC::BFC:
228: data = chan->bfc;
1.1.1.2 root 229: putlog(4, "#%d BFC -> $%02x", ch, data);
1.1 root 230: break;
231:
232: case DMAC::GCR:
233: if (ch == 3) {
234: data = dmac.gcr;
1.1.1.2 root 235: putlog(4, "GCR -> $%02x", data);
1.1 root 236: break;
237: } else {
238: data = 0xff;
239: }
240: break;
241:
242: default:
243: data = 0xff;
244: break;
245: }
246:
247: return data;
248: }
249:
250: uint64
1.1.1.7 root 251: DMACDevice::Write(uint32 offset, uint32 data)
1.1 root 252: {
253: int ch;
254:
1.1.1.5 root 255: gMPU->AddCycle(31); // InsideOut p.135
256:
1.1.1.7 root 257: ch = offset / 0x40;
1.1.1.2 root 258: DMAC::Channel *chan = &dmac.chan[ch];
1.1.1.7 root 259: int n = offset % 0x40;
1.1 root 260: switch (n) {
261: case DMAC::CSR:
1.1.1.2 root 262: chan->WriteCSR(data);
1.1.1.6 root 263: ChangeInterrupt();
1.1 root 264: break;
265:
266: case DMAC::CER:
267: // Read only
268: break;
269:
270: case DMAC::DCR:
1.1.1.2 root 271: putlog(4, "#%d DCR <- $%02x", ch, data);
1.1 root 272: chan->dcr = data & 0xfb;
273: break;
274:
275: case DMAC::OCR:
1.1.1.2 root 276: putlog(4, "#%d OCR <- $%02x", ch, data);
1.1 root 277: chan->ocr = data;
278: break;
279:
280: case DMAC::SCR:
1.1.1.2 root 281: putlog(4, "#%d SCR <- $%02x", ch, data);
1.1 root 282: chan->scr = data & 0x0f;
283: break;
284:
285: case DMAC::CCR:
1.1.1.2 root 286: putlog(4, "#%d CCR <- $%02x", ch, data);
287: chan->WriteCCR(data);
1.1.1.6 root 288: ChangeInterrupt();
1.1 root 289: break;
290:
291: case DMAC::MTC:
292: chan->mtc = (chan->mtc & 0x00ff) | (data << 8);
1.1.1.2 root 293: putlog(4, "#%d MTC:H <- $%02x (MTC=$%04x)", ch, data, chan->mtc);
1.1 root 294: break;
295: case DMAC::MTC + 1:
296: chan->mtc = (chan->mtc & 0xff00) | data;
1.1.1.2 root 297: putlog(4, "#%d MTC:L <- $%02x (MTC=$%04x)", ch, data, chan->mtc);
1.1 root 298: break;
299:
300: case DMAC::MAR:
301: chan->mar = (chan->mar & 0x00ffffff) | (data << 24);
1.1.1.2 root 302: putlog(4, "#%d MAR:0 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 303: break;
304: case DMAC::MAR + 1:
305: chan->mar = (chan->mar & 0xff00ffff) | (data << 16);
1.1.1.2 root 306: putlog(4, "#%d MAR:1 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 307: break;
308: case DMAC::MAR + 2:
309: chan->mar = (chan->mar & 0xffff00ff) | (data << 8);
1.1.1.2 root 310: putlog(4, "#%d MAR:2 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 311: break;
312: case DMAC::MAR + 3:
313: chan->mar = (chan->mar & 0xffffff00) | data;
1.1.1.2 root 314: putlog(4, "#%d MAR:3 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 315: break;
316:
317: case DMAC::DAR:
318: chan->dar = (chan->dar & 0x00ffffff) | (data << 24);
1.1.1.2 root 319: putlog(4, "#%d DAR:0 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 320: break;
321: case DMAC::DAR + 1:
322: chan->dar = (chan->dar & 0xff00ffff) | (data << 16);
1.1.1.2 root 323: putlog(4, "#%d DAR:1 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 324: break;
325: case DMAC::DAR + 2:
326: chan->dar = (chan->dar & 0xffff00ff) | (data << 8);
1.1.1.2 root 327: putlog(4, "#%d DAR:2 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 328: break;
329: case DMAC::DAR + 3:
330: chan->dar = (chan->dar & 0xffffff00) | data;
1.1.1.2 root 331: putlog(4, "#%d DAR:3 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 332: break;
333:
334: case DMAC::BTC:
335: chan->btc = (chan->btc & 0x00ff) | (data << 8);
1.1.1.2 root 336: putlog(4, "#%d BTC:H <- $%02x (BTC=$%04x)", ch, data, chan->btc);
1.1 root 337: break;
338: case DMAC::BTC + 1:
339: chan->btc = (chan->btc & 0xff00) | data;
1.1.1.2 root 340: putlog(4, "#%d BTC:L <- $%02x (BTC=$%04x)", ch, data, chan->btc);
1.1 root 341: break;
342:
343: case DMAC::BAR:
344: chan->bar = (chan->bar & 0x00ffffff) | (data << 24);
1.1.1.2 root 345: putlog(4, "#%d BAR:0 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 346: break;
347: case DMAC::BAR + 1:
348: chan->bar = (chan->bar & 0xff00ffff) | (data << 16);
1.1.1.2 root 349: putlog(4, "#%d BAR:1 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 350: break;
351: case DMAC::BAR + 2:
352: chan->bar = (chan->bar & 0xffff00ff) | (data << 8);
1.1.1.2 root 353: putlog(4, "#%d BAR:2 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 354: break;
355: case DMAC::BAR + 3:
356: chan->bar = (chan->bar & 0xffffff00) | data;
1.1.1.2 root 357: putlog(4, "#%d BAR:3 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 358: break;
359:
360: case DMAC::NIV:
1.1.1.2 root 361: putlog(4, "#%d NIV <- $%02x", ch, data);
1.1 root 362: chan->niv = data;
363: break;
364:
365: case DMAC::EIV:
1.1.1.2 root 366: putlog(4, "#%d EIV <- $%02x", ch, data);
1.1 root 367: chan->eiv = data;
368: break;
369:
370: case DMAC::MFC:
1.1.1.2 root 371: putlog(4, "#%d MFC <- $%02x", ch, data);
1.1 root 372: chan->mfc = data & 7;
373: break;
374:
375: case DMAC::CPR:
1.1.1.2 root 376: putlog(4, "#%d CPR <- $%02x", ch, data);
1.1 root 377: chan->cpr = data & 3;
1.1.1.10! root 378: // 実効プライオリティの上位4bitは cpr に等しい
! 379: chan->priority = (chan->cpr << 4);
1.1 root 380: break;
381:
382: case DMAC::DFC:
1.1.1.2 root 383: putlog(4, "#%d DFC <- $%02x", ch, data);
1.1 root 384: chan->dfc = data & 7;
385: break;
386:
387: case DMAC::BFC:
1.1.1.2 root 388: putlog(4, "#%d BFC <- $%02x", ch, data);
1.1 root 389: chan->bfc = data & 7;
390: break;
391:
392: case DMAC::GCR:
393: if (ch == 3) {
1.1.1.2 root 394: putlog(4, "GCR <- $%02x", data);
1.1 root 395: dmac.gcr = data;
396: }
397: break;
398:
399: default:
400: break;
401: }
402: return 0;
403: }
404:
405: uint64
1.1.1.7 root 406: DMACDevice::Peek(uint32 offset)
1.1 root 407: {
408: uint8 data;
409: int ch;
410:
1.1.1.7 root 411: ch = offset / 0x40;
1.1.1.2 root 412: const DMAC::Channel *chan = &dmac.chan[ch];
1.1.1.7 root 413: int n = offset % 0x40;
1.1 root 414: switch (n) {
415: case DMAC::CSR:
1.1.1.2 root 416: data = chan->PeekCSR();
1.1 root 417: break;
418:
419: case DMAC::CER:
420: data = chan->cer;
421: break;
422:
423: case DMAC::DCR:
424: data = chan->dcr;
425: break;
426:
427: case DMAC::OCR:
428: data = chan->ocr;
429: break;
430:
431: case DMAC::SCR:
432: data = chan->scr;
433: break;
434:
435: case DMAC::CCR:
1.1.1.6 root 436: data = chan->ccr;
1.1 root 437: break;
438:
439: case DMAC::MTC:
440: data = chan->mtc >> 8;
441: break;
442: case DMAC::MTC + 1:
443: data = chan->mtc & 0xff;
444: break;
445:
446: case DMAC::MAR:
447: data = chan->mar >> 24;
448: break;
449: case DMAC::MAR + 1:
450: data = (chan->mar >> 16) & 0xff;
451: break;
452: case DMAC::MAR + 2:
453: data = (chan->mar >> 8) & 0xff;
454: break;
455: case DMAC::MAR + 3:
456: data = chan->mar & 0xff;
457: break;
458:
459: case DMAC::DAR:
460: data = chan->dar >> 24;
461: break;
462: case DMAC::DAR + 1:
463: data = (chan->dar >> 16) & 0xff;
464: break;
465: case DMAC::DAR + 2:
466: data = (chan->dar >> 8) & 0xff;
467: break;
468: case DMAC::DAR + 3:
469: data = chan->dar & 0xff;
470: break;
471:
472: case DMAC::BTC:
473: data = chan->btc >> 8;
474: break;
475: case DMAC::BTC + 1:
476: data = chan->btc & 0xff;
477: break;
478:
479: case DMAC::BAR:
480: data = chan->bar >> 24;
481: break;
482: case DMAC::BAR + 1:
483: data = (chan->bar >> 16) & 0xff;
484: break;
485: case DMAC::BAR + 2:
486: data = (chan->bar >> 8) & 0xff;
487: break;
488: case DMAC::BAR + 3:
489: data = chan->bar & 0xff;
490: break;
491:
492: case DMAC::NIV:
493: data = chan->niv;
494: break;
495:
496: case DMAC::EIV:
497: data = chan->eiv;
498: break;
499:
500: case DMAC::MFC:
501: data = chan->mfc;
502: break;
503:
504: case DMAC::CPR:
505: data = chan->cpr;
506: break;
507:
508: case DMAC::DFC:
509: data = chan->dfc;
510: break;
511:
512: case DMAC::BFC:
513: data = chan->bfc;
514: break;
515:
516: case DMAC::GCR:
517: if (ch == 3) {
518: data = dmac.gcr;
519: break;
520: } else {
521: data = 0xff;
522: }
523: break;
524:
525: default:
526: data = 0xff;
527: break;
528: }
529:
530: return data;
531: }
532:
1.1.1.4 root 533: void
1.1.1.8 root 534: DMACDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 535: {
536: int x;
537: int y;
538:
1.1.1.8 root 539: screen.Clear();
1.1.1.2 root 540:
541: y = 1;
1.1.1.8 root 542: screen.Puts(0, y++, "CSR");
1.1.1.2 root 543: y += 2;
1.1.1.8 root 544: screen.Puts(0, y++, "CER");
545: screen.Puts(0, y++, "DCR:XRM");
546: screen.Puts(0, y++, "DCR:DTYP");
547: screen.Puts(0, y++, "DCR:DPS");
548: screen.Puts(0, y++, "DCR:PCL");
549: screen.Puts(0, y++, "OCR:DIR");
550: screen.Puts(0, y++, "OCR:SIZE");
551: screen.Puts(0, y++, "OCR:CHAIN");
552: screen.Puts(0, y++, "OCR:REQG");
553: screen.Puts(0, y++, "SCR:MAC");
554: screen.Puts(0, y++, "SCR:DAC");
555: screen.Puts(0, y++, "CCR");
1.1.1.2 root 556: y += 2;
1.1.1.8 root 557: screen.Puts(0, y++, "MTC");
558: screen.Puts(0, y++, "MAR");
559: screen.Puts(0, y++, "DAR");
560: screen.Puts(0, y++, "BTC");
561: screen.Puts(0, y++, "BAR");
562: screen.Puts(0, y++, "NIV");
563: screen.Puts(0, y++, "EIV");
564: screen.Puts(0, y++, "MFC");
565: screen.Puts(0, y++, "CPR");
566: screen.Puts(0, y++, "DFC");
567: screen.Puts(0, y++, "BFC");
1.1.1.2 root 568:
569: for (int ch = 0; ch < 4; ch++) {
570: DMAC::Channel *chan = &dmac.chan[ch];
571: int val;
572: x = 12 + ch * 17;
573: y = 0;
574:
575: // 地味だけど有効なチャンネルをハイライトしてみる
1.1.1.8 root 576: screen.Print(x, y++, (chan->active ? TA::Em : TA::Normal),
1.1.1.2 root 577: "#%d (%s)", chan->ch, chan->desc);
578:
579: // CSR
580: val = chan->PeekCSR();
1.1.1.8 root 581: screen.Print(x, y++, "$%02x", val);
1.1.1.2 root 582: static const char * const csrname[] = {
1.1.1.9 root 583: "COC", "BTC", "NDT", "ERR", "ACT", "-", "PCT", "PCS",
1.1.1.2 root 584: };
1.1.1.8 root 585: MonitorReg4(screen, x, y++, val >> 4, &csrname[0]);
586: MonitorReg4(screen, x, y++, val & 0xff, &csrname[4]);
1.1.1.2 root 587:
588: // CER
589: val = chan->cer & 0x1f;
590: const char *e;
591: if (val <= 0x11 && errnames[val]) {
592: e = errnames[val];
593: } else {
594: e = "?";
595: }
1.1.1.8 root 596: screen.Print(x, y, "$%02x", chan->cer);
1.1.1.2 root 597: if (val > 0) {
1.1.1.8 root 598: screen.Print(x + 3, y, ":%s", e);
1.1.1.2 root 599: }
600: y++;
601:
602: // DCR:XRM
603: static const char * const dcr_xrm[] = {
604: //1234567890123
605: "Burst",
606: "undefined",
607: "CycleW/O Hold",
608: "CycleWithHold",
609: };
610: val = chan->dcr >> 6;
1.1.1.8 root 611: screen.Print(x, y++, "%d:%s", val, dcr_xrm[val]);
1.1.1.2 root 612:
613: // DCR:DTYP
614: static const char * const dcr_dtyp[] = {
615: //1234567890123
616: "68000",
617: "6800",
618: "ACK",
619: "ACK+READY",
620: };
621: val = (chan->dcr >> 4) & 3;
1.1.1.8 root 622: screen.Print(x, y++, "%d:%s", val, dcr_dtyp[val]);
1.1.1.2 root 623:
624: // DCR:DPS
625: static const char * const dcr_dps[] = {
626: //1234567890123
627: "8bit",
628: "16bit",
629: };
630: val = (chan->dcr >> 3) & 1;
1.1.1.8 root 631: screen.Print(x, y++, "%d:%s", val, dcr_dps[val]);
1.1.1.2 root 632:
633: // DCR:PCL
1.1.1.8 root 634: screen.Print(x, y++, "XXX PCL");
1.1.1.2 root 635:
636: // OCR:DIR
637: static const char * const ocr_dir[] = {
638: //1234567890123
639: "MemoryToDevice",
640: "DeviceToMemory",
641: };
642: val = (chan->ocr >> 7);
1.1.1.8 root 643: screen.Print(x, y++, "%d:%s", val, ocr_dir[val]);
1.1.1.2 root 644:
645: // OCR:SIZE
646: static const char * const ocr_size[] = {
647: //1234567890123
648: "8bit",
649: "16bit",
650: "32bit",
651: "8bit Unpacked",
652: };
653: val = (chan->ocr >> 4) & 3;
1.1.1.8 root 654: screen.Print(x, y++, "%d:%s", val, ocr_size[val]);
1.1.1.2 root 655:
656: // OCR:CHAIN
657: static const char * const ocr_chain[] = {
658: //1234567890123
659: "NoChain",
660: "undefined",
661: "ArrayChain",
662: "LinkArrayChain",
663: };
664: val = (chan->ocr >> 2) & 3;
1.1.1.8 root 665: screen.Print(x, y++, "%d:%s", val, ocr_chain[val]);
1.1.1.2 root 666:
667: // OCR:REQG
668: static const char * const ocr_reqg[] = {
669: //1234567890123
670: "AutoReq(Limit)",
671: "AutoReq(Max)",
672: "ExternalReq",
673: "AutoThenExt",
674: };
675: val = (chan->ocr & 3);
1.1.1.8 root 676: screen.Print(x, y++, "%d:%s", val, ocr_reqg[val]);
1.1.1.2 root 677:
678: // SCR:MAC
679: static const char * const scr_xac[] = {
680: //1234567890123
681: "NoCount",
682: "CountUp",
683: "CountDown",
684: "undefined",
685: };
686: val = (chan->scr >> 2) & 3;
1.1.1.8 root 687: screen.Print(x, y++, "%d:%s", val, scr_xac[val]);
1.1.1.2 root 688: val = chan->scr & 3;
1.1.1.8 root 689: screen.Print(x, y++, "%d:%s", val, scr_xac[val]);
1.1.1.2 root 690:
691: // CCR
1.1.1.6 root 692: val = chan->ccr;
1.1.1.8 root 693: screen.Print(x, y++, "$%02x", val);
1.1.1.2 root 694: static const char * const ccrnames[] = {
1.1.1.9 root 695: "STR", "CNT", "HLT", "SAB", "INT", "-", "-", "-",
1.1.1.2 root 696: };
1.1.1.8 root 697: MonitorReg4(screen, x, y++, (val >> 4), &ccrnames[0]);
698: MonitorReg4(screen, x, y++, (val & 0xff), &ccrnames[4]);
1.1.1.2 root 699:
700: // MTC
1.1.1.8 root 701: screen.Print(x, y++, "$%04x", chan->mtc);
1.1.1.2 root 702: // MAR
703: // X680x0 がターゲットなので24bit超える設定は目立たせる
704: if (chan->mar > 0xffffff) {
1.1.1.8 root 705: screen.Print(x, y++, TA::On, "$%08x", chan->mar);
1.1.1.2 root 706: } else {
1.1.1.8 root 707: screen.Print(x, y++, "$%06x", chan->mar);
1.1.1.2 root 708: }
709: // DAR
710: if (chan->dar > 0xffffff) {
1.1.1.8 root 711: screen.Print(x, y++, TA::On, "$%08x", chan->dar);
1.1.1.2 root 712: } else {
1.1.1.8 root 713: screen.Print(x, y++, "$%06x", chan->dar);
1.1.1.2 root 714: }
715: // BTC
1.1.1.8 root 716: screen.Print(x, y++, "$%04x", chan->btc);
1.1.1.2 root 717: // BAR
718: if (chan->bar > 0xffffff) {
1.1.1.8 root 719: screen.Print(x, y++, TA::On, "$%08x", chan->bar);
1.1.1.2 root 720: } else {
1.1.1.8 root 721: screen.Print(x, y++, "$%06x", chan->bar);
1.1.1.2 root 722: }
723:
724: // NIV
1.1.1.8 root 725: screen.Print(x, y++, "$%02x", chan->niv);
1.1.1.2 root 726: // EIV
1.1.1.8 root 727: screen.Print(x, y++, "$%02x", chan->eiv);
1.1.1.2 root 728:
729: // MFC
1.1.1.8 root 730: screen.Print(x, y++, "$%02x", chan->mfc);
1.1.1.2 root 731: // CPR
1.1.1.8 root 732: screen.Print(x, y++, "$%02x", chan->cpr);
1.1.1.2 root 733: // DFC
1.1.1.8 root 734: screen.Print(x, y++, "$%02x", chan->dfc);
1.1.1.2 root 735: // BFC
1.1.1.8 root 736: screen.Print(x, y++, "$%02x", chan->bfc);
1.1.1.2 root 737:
738: if (ch == 3) {
1.1.1.8 root 739: screen.Print(x - 5, y++, "GCR: $%02x", dmac.gcr);
1.1.1.2 root 740: }
741: }
742: }
743:
744: // 4ビット分を表示する。MonitorUpdate の下請け
745: void
1.1.1.8 root 746: DMACDevice::MonitorReg4(TextScreen& screen,
1.1.1.4 root 747: int x, int y, uint32 reg, const char * const *names)
1.1.1.2 root 748: {
749: for (int i = 0; i < 4; i++) {
1.1.1.9 root 750: if (names[i][0] == '-') {
751: screen.Puts(x + i * 4, y, TA::Disable, "---");
752: } else {
753: bool b = reg & (1 << (3 - i));
754: screen.Puts(x + i * 4, y, TA::OnOff(b), names[i]);
755: }
1.1.1.2 root 756: }
757: }
758:
759: /*static*/ const char * const
760: DMACDevice::errnames[] = {
761: //12345678901
762: "", // $00 No Error
763: "ConfigErr", // $01
764: "OperTiming", // $02
765: NULL, // $03
766: NULL, // $04
767: "AddrErrInMAR", // $05
768: "AddrErrInDAR", // $06
769: "AddrErrInBAR", // $07
770: NULL, // $08
771: "BusErrInMAR", // $09
772: "BusErrInDAR", // $0a
773: "BusErrInBAR", // $0b
774: NULL, // $0c
775: "CntErrInMTC", // $0d
776: NULL, // $0e
777: "CntErrInBTC", // $0f
778: "ExternAbort", // $10
779: "SoftAbort", // $11
780: };
781:
782: // Read と Peek とそれ以外からも呼ばれるので副作用を持たせてはいけない。
783: uint8
784: DMAC::Channel::PeekCSR() const
785: {
786: uint32 val;
787:
788: val = csr & 0xf0;
789: if (active) {
790: val |= CSR_ACT;
791: }
792: // PCT は PCL が High から Low に変わるとセット
793: if (prev_pcl == true && pcl == false) {
794: val |= CSR_PCT;
795: }
796: if (pcl) {
797: val |= CSR_PCS;
798: }
799: return val;
800: }
801:
1.1.1.6 root 802: // CSR への書き込み。
803: // CSR への書き込みによって割り込み信号線が変化するかも知れないので
804: // この後呼び出し側が ChangeInterrupt() を呼ぶこと。
1.1 root 805: void
1.1.1.2 root 806: DMAC::Channel::WriteCSR(uint32 data)
1.1 root 807: {
1.1.1.2 root 808: // 上位4ビットは %1 の書き込みでクリア
809: csr &= ~(data & 0xf0);
810:
1.1.1.10! root 811: // PCT も %1 の書き込みでクリア。
1.1.1.2 root 812: // PCT は PCL が High → Low の時セットなので prev_pcl を下げればよい
813: if ((data & DMAC::CSR_PCT)) {
814: prev_pcl = false;
815: }
816:
1.1.1.7 root 817: parent->putlogf(4, lstr("#%d CSR <- $%02x (CSR = $%02x)",
818: ch, data, PeekCSR()));
1.1.1.2 root 819: }
820:
1.1.1.6 root 821: // CCR への書き込み。
822: // CCR への書き込みによって割り込み信号線が変化するかも知れないので
823: // この後呼び出し側が ChangeInterrupt() を呼ぶこと。
1.1 root 824: void
1.1.1.2 root 825: DMAC::Channel::WriteCCR(uint32 data)
1.1 root 826: {
1.1.1.2 root 827: // 割り込み許可ビットは常に反映
1.1.1.6 root 828: ccr &= ~DMAC::CCR_INT;
829: ccr |= (data & DMAC::CCR_INT);
1.1.1.2 root 830:
831: // SAB (Software Abort)
832: if ((data & DMAC::CCR_SAB)) {
833: // イベントを触るため親デバイスで処理する
834: parent->AbortTransfer(this);
835: }
836:
837: // HLT (Halt Operation)
838: if ((data & DMAC::CCR_HLT)) {
1.1.1.7 root 839: parent->putlogf(0, lstr("CCR HLT 未実装"));
1.1.1.2 root 840: }
841:
842: // CNT (Continue Operation)
843: if ((data & DMAC::CCR_CNT)) {
1.1.1.7 root 844: parent->putlogf(0, lstr("CCR CNT 未実装"));
1.1.1.2 root 845: }
846:
847: // STR (Start Operation)
848: if ((data & DMAC::CCR_STR)) {
849: StartTransfer();
850: }
1.1 root 851: }
852:
1.1.1.5 root 853: // 転送開始 (チャンネル側)
1.1.1.2 root 854: void
855: DMAC::Channel::StartTransfer()
856: {
857: // CSR の COC,BTC,NDT,ERR が立ってたら開始しない
858: if ((csr & 0xf0) != 0) {
859: cer = CER_CONFIG; // ?
860: csr |= CSR_ERR;
861: return;
862: }
863:
864: active = true;
865:
866: // XXX CER をどこかでクリアしないといけないようだがどこだ?
867: cer = 0;
868:
869: // 転送方法は DPS(1bit) と SIZE(2bit) で合計 8通り。
870: // (その中にさらに転送方向が2通りずつあるけど)
871: //
872: // xfertype DPS SIZE
873: // 0 8bit 8bit packed
874: // 1 8bit 16bit
875: // 2 8bit 32bit
876: // 3 8bit 8bit
877: // 4 16bit 8bit packed
878: // 5 16bit 16bit
879: // 6 16bit 32bit
880: // 7 16bit 8bit
881: xfertype = (GetDPS() << 2) | GetSIZE();
882:
883: // 転送モード
884: switch (GetREQG()) {
885: case DMAC::OCR_REQG_AUTO_LIM:
1.1.1.10! root 886: VMPANIC("REQG_AUTO_LIM 未実装");
1.1.1.2 root 887: break;
888:
889: case DMAC::OCR_REQG_AUTO_MAX:
890: // 自発的に転送を開始する
1.1.1.10! root 891: parent->StartTransfer();
1.1.1.2 root 892: break;
893:
894: case DMAC::OCR_REQG_EXTERNAL:
895: case DMAC::OCR_REQG_AUTOFIRST:
1.1.1.10! root 896: VMPANIC("未実装 REQG");
1.1.1.2 root 897: break;
898:
899: default:
900: __unreachable();
901: }
902: }
903:
1.1.1.5 root 904: // 転送開始 (デバイス側)
1.1.1.10! root 905: // (チャンネルが転送開始する際にデバイス側の private 変数(event)が必要に
1.1.1.5 root 906: // なるため、プロキシしている)
907: void
1.1.1.10! root 908: DMACDevice::StartTransfer()
1.1.1.5 root 909: {
1.1.1.10! root 910: if (event.IsRunning() == false) {
! 911: CallAfter(StartCallback, 0);
! 912: }
1.1.1.5 root 913: }
914:
1.1.1.10! root 915: // 転送開始
1.1.1.2 root 916: void
1.1.1.10! root 917: DMACDevice::StartCallback(Event& ev)
1.1.1.2 root 918: {
1.1.1.10! root 919: // 転送チャンネルの決定
! 920: int ch = -1;
! 921: uint8 prio = 255;
! 922: for (int i = 0; i < 4; i++) {
! 923: DMAC::Channel *chan = &dmac.chan[i];
! 924: if (chan->active) {
! 925: uint8 p = chan->priority;
! 926: if (p < prio) {
! 927: prio = p;
! 928: // 実効プライオリティのラウンドロビン用のところを上げておく
! 929: chan->priority = (p & 0xf0) | ((p & 0x0f) >> 1);
! 930: ch = i;
! 931: }
! 932: }
! 933: }
! 934: if (ch == -1) {
! 935: // 転送チャンネルはもうないのでイベントは停止したままにする
! 936: event.SetName("DMAC");
! 937: return;
! 938: }
! 939: xfer_chan = &dmac.chan[ch];
1.1.1.2 root 940:
1.1.1.10! root 941: // 実効プライオリティを同順位の最後に回す
! 942: xfer_chan->priority |= 0x08;
1.1.1.2 root 943:
1.1.1.10! root 944: if (xfer_chan->GetDIR() == DMAC::OCR_DIR_MtoD) {
! 945: xfer_src = xfer_chan->mar;
! 946: xfer_dst = xfer_chan->dar;
! 947: } else {
! 948: xfer_src = xfer_chan->dar;
! 949: xfer_dst = xfer_chan->mar;
! 950: }
! 951:
! 952: // XXX バスアービトレーションとか
! 953:
! 954: xfer_retry = 0;
! 955: event.SetName(string_format("DMAC #%d", ch));
! 956: CallAfter(ReadCallback, 1);
! 957: }
! 958:
! 959: // 転送エラー
! 960: void
! 961: DMACDevice::Error(uint64 r)
! 962: {
! 963: if ((int64)r == -2) {
! 964: // DTACK が出ていない (SPC)。
! 965: // 本当は DTACK が出たことをコールバックしてくれれば
! 966: // 効率がいいのだがポーリングでもかまわんだろう。
! 967: xfer_retry++;
! 968: putlog(4, "xfer_retry=%d", xfer_retry);
! 969: if (xfer_retry < 100) {
! 970: // 現在のイベントを再実行
! 971: event.time = 1 * 80_nsec;
! 972: gScheduler->StartEvent(event);
! 973: return;
! 974: }
! 975: // タイムアウトしたらバスエラーにフォールスルー
! 976: }
! 977:
! 978: // バスエラー
! 979: xfer_chan->csr |= DMAC::CSR_ERR;
! 980: xfer_chan->active = false;
! 981: ChangeInterrupt();
! 982: CallAfter(StartCallback, 0);
! 983: }
! 984:
! 985: // 転送(読み込み)
! 986: void
! 987: DMACDevice::ReadCallback(Event& ev)
! 988: {
! 989: uint64 r;
! 990:
! 991: // シングルアドレスモードはサポートしていない
1.1.1.2 root 992:
1.1.1.10! root 993: switch (xfer_chan->xfertype) {
! 994: case 0: // 8ビットポート、8ビットサイズ、パック動作
1.1.1.2 root 995: case 1: // 8ビットポート、16ビットサイズ
1.1.1.10! root 996: case 2: // 8ビットポート、32ビットサイズ
! 997: VMPANIC("未実装 xfer type");
! 998:
! 999: case 3: // 8ビットポート、8ビットサイズ、パックなし動作
! 1000: r = vm_phys_read_8(xfer_src);
! 1001: break;
! 1002:
! 1003: case 4: // 16ビットポート、8ビットサイズ、パック動作
! 1004: case 5: // 16ビットポート、16ビットサイズ
! 1005: case 6: // 16ビットポート、32ビットサイズ
! 1006: case 7: // 16ビットポート、8ビットサイズ、パックなし動作
! 1007: default:
! 1008: VMPANIC("未実装 xfer type");
! 1009: }
! 1010:
! 1011: if ((int64)r < 0) {
! 1012: Error(r);
! 1013: return;
! 1014: }
! 1015: xfer_retry = 0;
! 1016: xfer_data = r;
! 1017:
! 1018: CallAfter(WriteCallback, 4);
! 1019: }
1.1.1.2 root 1020:
1.1.1.10! root 1021: // 転送(書き込み)
! 1022: void
! 1023: DMACDevice::WriteCallback(Event& ev)
! 1024: {
! 1025: uint64 r;
! 1026: putlog(4, "WRITE xfer_data=$%02x", xfer_data);
! 1027:
! 1028: switch (xfer_chan->xfertype) {
! 1029: case 0: // 8ビットポート、8ビットサイズ、パック動作
! 1030: case 1: // 8ビットポート、16ビットサイズ
1.1.1.2 root 1031: case 2: // 8ビットポート、32ビットサイズ
1.1.1.10! root 1032: VMPANIC("未実装 xfer type");
1.1.1.2 root 1033:
1034: case 3: // 8ビットポート、8ビットサイズ、パックなし動作
1.1.1.10! root 1035: r = vm_phys_write_8(xfer_dst, xfer_data);
1.1.1.2 root 1036: break;
1037:
1038: case 4: // 16ビットポート、8ビットサイズ、パック動作
1039: case 5: // 16ビットポート、16ビットサイズ
1040: case 6: // 16ビットポート、32ビットサイズ
1041: case 7: // 16ビットポート、8ビットサイズ、パックなし動作
1.1.1.10! root 1042: default:
! 1043: VMPANIC("未実装 xfer type");
1.1.1.2 root 1044: }
1045:
1.1.1.10! root 1046: if ((int64)r < 0) {
! 1047: Error(r);
1.1.1.2 root 1048: return;
1049: }
1050:
1.1.1.10! root 1051: CallAfter(DoneCallback, 5);
! 1052: }
! 1053:
! 1054: // 1回の転送完了
! 1055: void
! 1056: DMACDevice::DoneCallback(Event& ev)
! 1057: {
! 1058: putlog(4, "DONE");
! 1059:
1.1.1.2 root 1060: // バスエラーでなければカウンタを更新
1061: // XXX とりあえず。後で書く
1.1.1.10! root 1062: switch (xfer_chan->GetMAC()) {
1.1.1.2 root 1063: case DMAC::SCR_COUNT_UP:
1.1.1.10! root 1064: xfer_chan->mar += 1;
1.1.1.2 root 1065: break;
1066: case DMAC::SCR_COUNT_DOWN:
1.1.1.10! root 1067: xfer_chan->mar -= 1;
1.1.1.2 root 1068: break;
1069: }
1.1.1.10! root 1070: switch (xfer_chan->GetDAC()) {
1.1.1.2 root 1071: case DMAC::SCR_COUNT_UP:
1.1.1.10! root 1072: xfer_chan->dar += 1;
1.1.1.2 root 1073: break;
1074: case DMAC::SCR_COUNT_DOWN:
1.1.1.10! root 1075: xfer_chan->dar -= 1;
1.1.1.2 root 1076: break;
1077: }
1078:
1.1.1.10! root 1079: xfer_chan->mtc--;
! 1080: if (xfer_chan->mtc == 0) {
1.1.1.2 root 1081: // 転送完了
1.1.1.10! root 1082: xfer_chan->csr |= DMAC::CSR_COC;
! 1083: xfer_chan->active = false;
1.1.1.6 root 1084: ChangeInterrupt();
1.1.1.2 root 1085: }
1086:
1.1.1.10! root 1087: CallAfter(StartCallback, 1);
1.1.1.2 root 1088: }
1089:
1090: // ソフトウェアアボート
1091: // (イベントを持つのでこれはデバイスクラスのメソッド)
1092: void
1093: DMACDevice::AbortTransfer(DMAC::Channel *chan)
1094: {
1095: putlog(2, "CCR SAB ソフトウェアアボート");
1096:
1097: // %1 を書き込むことで実際には SAB はセットされるが、ERR が立つと
1098: // SAB をクリアする動作のため、書き込んだ %1 が読めることはない。
1099: // ここでは SAB ビットのセットを省略。
1100:
1.1.1.10! root 1101: chan->active = false;
1.1.1.2 root 1102: chan->cer = DMAC::CER_SOFT_ABORT;
1.1.1.6 root 1103: // ERR ビットが立つと SAB をクリアする
1104: chan->csr |= DMAC::CSR_ERR;
1105: chan->ccr &= ~DMAC::CCR_SAB;
1106: ChangeInterrupt();
1107: }
1108:
1109: // 割り込み信号線の状態を変える。
1110: void
1111: DMACDevice::ChangeInterrupt()
1112: {
1113: bool irq = false;
1114:
1115: for (int ch = 0; ch < countof(dmac.chan); ch++) {
1116: DMAC::Channel *chan = &dmac.chan[ch];
1117:
1118: if ((chan->ccr & DMAC::CCR_INT) && chan->IsINTR()) {
1119: irq = true;
1120: }
1121: }
1122: gInterrupt->ChangeINT(this, irq);
1123: }
1124:
1125: // 割り込みアクノリッジ
1126: int
1127: DMACDevice::InterruptAcknowledge()
1128: {
1.1.1.10! root 1129: DMAC::Channel *chan;
! 1130: int top = -1;
! 1131: uint8 prio = 255;
! 1132:
! 1133: // 割り込みを発生させているトッププライオリティのチャンネルを検索
1.1.1.6 root 1134: for (int ch = 0; ch < countof(dmac.chan); ch++) {
1.1.1.10! root 1135: chan = &dmac.chan[ch];
1.1.1.6 root 1136:
1.1.1.10! root 1137: if ((chan->ccr & DMAC::CCR_INT) && chan->IsINTR()) {
! 1138: if (chan->priority < prio) {
! 1139: prio = chan->priority;
! 1140: top = ch;
1.1.1.6 root 1141: }
1.1.1.10! root 1142: }
! 1143: }
! 1144:
! 1145: if (top >= 0) {
! 1146: chan = &dmac.chan[top];
! 1147: if ((chan->csr & DMAC::CSR_ERR)) {
! 1148: return chan->eiv;
! 1149: } else {
! 1150: return chan->niv;
1.1.1.6 root 1151: }
1152: }
1153: // XXX 誰もいなかったら?
1.1.1.10! root 1154: VMPANIC("InterruptAcknowledge no active channels?");
1.1.1.2 root 1155: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.