|
|
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.11! root 12: #include "adpcm.h"
1.1.1.3 root 13: #include "bus.h"
1.1.1.11! root 14: #include "fdc.h"
1.1.1.6 root 15: #include "interrupt.h"
1.1.1.10 root 16: #include "mpu.h"
17: #include "scheduler.h"
18:
19: // time 時間後に呼び出すコールバックをセットする。
20: // func の書式が面倒なのを省略して書きたいため。
21: #define CallAfter(func_, time_) do { \
22: event.func = ToEventCallback(&DMACDevice::func_); \
23: event.time = time_ * 80_nsec; \
24: gScheduler->StartEvent(event); \
25: } while (0)
1.1.1.2 root 26:
1.1.1.10 root 27: // グローバル参照用
28: DMACDevice *gDMAC;
1.1 root 29:
1.1.1.10 root 30: // コンストラクタ
1.1 root 31: DMACDevice::DMACDevice()
1.1.1.8 root 32: : inherited("DMAC")
1.1 root 33: {
34: devaddr = baseaddr;
35: devlen = 0x2000;
1.1.1.2 root 36:
1.1.1.11! root 37: for (int i = 0; i < channel.size(); i++) {
! 38: channel[i].ch = i;
! 39: }
! 40: channel[0].desc = "FD";
! 41: channel[1].desc = "HD";
! 42: channel[2].desc = "User";
! 43: channel[3].desc = "ADPCM";
! 44:
! 45: // PCL 信号線
! 46: // #0 はスーパーインポーズしてなければ常に Low
! 47: channel[0].pcl_pin = false;
! 48: channel[0].pcl_prev = false;
! 49: // #1 はプルアップされているので常に High
! 50: channel[1].pcl_pin = true;
! 51: channel[1].pcl_prev = true;
! 52: // #2 は外部スロット用だが未接続なので High
! 53: channel[2].pcl_pin = true;
! 54: channel[2].pcl_prev = true;
! 55: // #3 は未対応
1.1.1.2 root 56:
1.1.1.10 root 57: event.Regist("DMAC");
1.1.1.8 root 58:
1.1.1.10 root 59: monitor.func = ToMonitorCallback(&DMACDevice::MonitorUpdate);
1.1.1.11! root 60: monitor.SetSize(80, 34);
1.1.1.8 root 61: monitor.Regist(ID_MONITOR_DMAC);
1.1 root 62: }
63:
1.1.1.10 root 64: // デストラクタ
1.1 root 65: DMACDevice::~DMACDevice()
66: {
1.1.1.10 root 67: gDMAC = NULL;
1.1 root 68: }
69:
1.1.1.10 root 70: // リセット
1.1.1.5 root 71: void
1.1.1.10 root 72: DMACDevice::ResetHard(bool poweron)
1.1.1.5 root 73: {
1.1.1.11! root 74: putlog(2, "Reset");
1.1.1.5 root 75:
76: // Clears GCR, DCR, OCR, SCR, CCR, CSR, CPR and CER for all channels.
77: // NIV and EIV are all set to $0F (uninitialized interrupt vector).
78: // MTC, MAR, DAR, BTC, BAR, MFC, DFC and BFC are not affected.
79:
1.1.1.11! root 80: gcr = 0;
! 81: for (int ch = 0; ch < channel.size(); ch++) {
! 82: DMACChan *chan = &channel[ch];
! 83: chan->SetDCR(0);
! 84: chan->SetOCR(0);
! 85: chan->SetSCR(0);
! 86: chan->SetCCR(0);
1.1.1.5 root 87: chan->csr = 0;
88: chan->active = false;
89: chan->cpr = 0;
90: chan->cer = 0;
91:
92: chan->niv = 0x0f;
93: chan->eiv = 0x0f;
94:
1.1.1.10 root 95: chan->priority = 0;
1.1.1.5 root 96: }
1.1.1.10 root 97:
98: // イベントを停止
99: event.SetName("DMAC");
100: gScheduler->StopEvent(event);
1.1.1.5 root 101: }
102:
1.1 root 103: uint64
1.1.1.11! root 104: DMACDevice::Read8(uint32 addr)
1.1 root 105: {
106: uint8 data;
107:
1.1.1.5 root 108: gMPU->AddCycle(37); // InsideOut p.135
109:
1.1.1.11! root 110: uint32 offset = addr & 0xff;
! 111: int ch = offset / 0x40;
1.1.1.7 root 112: int n = offset % 0x40;
1.1.1.11! root 113: DMACChan *chan = &channel[ch];
! 114:
1.1 root 115: switch (n) {
116: case DMAC::CSR:
1.1.1.11! root 117: data = chan->GetCSR();
! 118: putlog(3, "#%d CSR -> $%02x", ch, data);
1.1 root 119: break;
120:
121: case DMAC::CER:
122: data = chan->cer;
1.1.1.11! root 123: putlog(3, "#%d CER -> $%02x", ch, data);
1.1 root 124: break;
125:
126: case DMAC::DCR:
1.1.1.11! root 127: data = chan->GetDCR();
! 128: putlog(3, "#%d DCR -> $%02x", ch, data);
1.1 root 129: break;
130:
131: case DMAC::OCR:
1.1.1.11! root 132: data = chan->GetOCR();
! 133: putlog(3, "#%d OCR -> $%02x", ch, data);
1.1 root 134: break;
135:
136: case DMAC::SCR:
1.1.1.11! root 137: data = chan->GetSCR();
! 138: putlog(3, "#%d SCR -> $%02x", ch, data);
1.1 root 139: break;
140:
141: case DMAC::CCR:
1.1.1.11! root 142: data = chan->GetCCR();
! 143: putlog(3, "#%d CCR -> $%02x", ch, data);
1.1 root 144: break;
145:
146: case DMAC::MTC:
147: data = chan->mtc >> 8;
1.1.1.11! root 148: putlog(3, "#%d MTC:H -> $%02x", ch, data);
1.1 root 149: break;
150: case DMAC::MTC + 1:
151: data = chan->mtc & 0xff;
1.1.1.11! root 152: putlog(3, "#%d MTC:L -> $%02x", ch, data);
1.1 root 153: break;
154:
155: case DMAC::MAR:
156: data = chan->mar >> 24;
1.1.1.11! root 157: putlog(3, "#%d MAR:0 -> $%02x", ch, data);
1.1 root 158: break;
159: case DMAC::MAR + 1:
160: data = (chan->mar >> 16) & 0xff;
1.1.1.11! root 161: putlog(3, "#%d MAR:1 -> $%02x", ch, data);
1.1 root 162: break;
163: case DMAC::MAR + 2:
164: data = (chan->mar >> 8) & 0xff;
1.1.1.11! root 165: putlog(3, "#%d MAR:2 -> $%02x", ch, data);
1.1 root 166: break;
167: case DMAC::MAR + 3:
168: data = chan->mar & 0xff;
1.1.1.11! root 169: putlog(3, "#%d MAR:3 -> $%02x", ch, data);
1.1 root 170: break;
171:
172: case DMAC::DAR:
173: data = chan->dar >> 24;
1.1.1.11! root 174: putlog(3, "#%d DAR:0 -> $%02x", ch, data);
1.1 root 175: break;
176: case DMAC::DAR + 1:
177: data = (chan->dar >> 16) & 0xff;
1.1.1.11! root 178: putlog(3, "#%d DAR:1 -> $%02x", ch, data);
1.1 root 179: break;
180: case DMAC::DAR + 2:
181: data = (chan->dar >> 8) & 0xff;
1.1.1.11! root 182: putlog(3, "#%d DAR:2 -> $%02x", ch, data);
1.1 root 183: break;
184: case DMAC::DAR + 3:
185: data = chan->dar & 0xff;
1.1.1.11! root 186: putlog(3, "#%d DAR:3 -> $%02x", ch, data);
1.1 root 187: break;
188:
189: case DMAC::BTC:
190: data = chan->btc >> 8;
1.1.1.11! root 191: putlog(3, "#%d BTC:H -> $%02x", ch, data);
1.1 root 192: break;
193: case DMAC::BTC + 1:
194: data = chan->btc & 0xff;
1.1.1.11! root 195: putlog(3, "#%d BTC:L -> $%02x", ch, data);
1.1 root 196: break;
197:
198: case DMAC::BAR:
199: data = chan->bar >> 24;
1.1.1.11! root 200: putlog(3, "#%d BAR:0 -> $%02x", ch, data);
1.1 root 201: break;
202: case DMAC::BAR + 1:
203: data = (chan->bar >> 16) & 0xff;
1.1.1.11! root 204: putlog(3, "#%d BAR:1 -> $%02x", ch, data);
1.1 root 205: break;
206: case DMAC::BAR + 2:
207: data = (chan->bar >> 8) & 0xff;
1.1.1.11! root 208: putlog(3, "#%d BAR:2 -> $%02x", ch, data);
1.1 root 209: break;
210: case DMAC::BAR + 3:
211: data = chan->bar & 0xff;
1.1.1.11! root 212: putlog(3, "#%d BAR:3 -> $%02x", ch, data);
1.1 root 213: break;
214:
215: case DMAC::NIV:
216: data = chan->niv;
1.1.1.11! root 217: putlog(3, "#%d NIV -> $%02x", ch, data);
1.1 root 218: break;
219:
220: case DMAC::EIV:
221: data = chan->eiv;
1.1.1.11! root 222: putlog(3, "#%d EIV -> $%02x", ch, data);
1.1 root 223: break;
224:
225: case DMAC::MFC:
226: data = chan->mfc;
1.1.1.11! root 227: putlog(3, "#%d MFC -> $%02x", ch, data);
1.1 root 228: break;
229:
230: case DMAC::CPR:
231: data = chan->cpr;
1.1.1.11! root 232: putlog(3, "#%d CPR -> $%02x", ch, data);
1.1 root 233: break;
234:
235: case DMAC::DFC:
236: data = chan->dfc;
1.1.1.11! root 237: putlog(3, "#%d DFC -> $%02x", ch, data);
1.1 root 238: break;
239:
240: case DMAC::BFC:
241: data = chan->bfc;
1.1.1.11! root 242: putlog(3, "#%d BFC -> $%02x", ch, data);
1.1 root 243: break;
244:
245: case DMAC::GCR:
246: if (ch == 3) {
1.1.1.11! root 247: data = gcr;
! 248: putlog(3, "GCR -> $%02x", data);
1.1 root 249: break;
250: } else {
251: data = 0xff;
252: }
253: break;
254:
255: default:
256: data = 0xff;
257: break;
258: }
259:
260: return data;
261: }
262:
263: uint64
1.1.1.11! root 264: DMACDevice::Read16(uint32 addr)
1.1 root 265: {
1.1.1.11! root 266: uint16 data;
! 267:
! 268: gMPU->AddCycle(37); // InsideOut p.135
! 269:
! 270: uint32 offset = addr & 0xff;
! 271: int ch = offset / 0x40;
! 272: int n = offset % 0x40;
! 273: DMACChan *chan = &channel[ch];
! 274:
! 275: switch (n) {
! 276: case DMAC::CSR: // CSR | CER
! 277: data = chan->GetCSR() << 8;
! 278: data |= chan->cer;
! 279: putlog(3, "#%d CSR:CER -> $%04x", ch, data);
! 280: break;
! 281:
! 282: case DMAC::DCR: // DCR | OCR
! 283: data = chan->GetDCR() << 8;
! 284: data |= chan->GetOCR();
! 285: putlog(3, "#%d DCR:OCR -> $%04x", ch, data);
! 286: break;
! 287:
! 288: case DMAC::SCR: // SCR | CCR
! 289: data = chan->GetSCR() << 8;
! 290: data |= chan->GetCCR();
! 291: putlog(3, "#%d SCR:CCR -> $%04x", ch, data);
! 292: break;
! 293:
! 294: case DMAC::MTC:
! 295: data = chan->mtc;
! 296: putlog(3, "#%d MTC -> $%04x", ch, data);
! 297: break;
! 298:
! 299: case DMAC::MAR:
! 300: data = chan->mar >> 16;
! 301: putlog(3, "#%d MAR:H -> $%04x", ch, data);
! 302: break;
! 303: case DMAC::MAR + 2:
! 304: data = chan->mar & 0xffff;
! 305: putlog(3, "#%d MAR:L -> $%04x", ch, data);
! 306: break;
! 307:
! 308: case DMAC::DAR:
! 309: data = chan->dar >> 16;
! 310: putlog(3, "#%d DAR:H -> $%04x", ch, data);
! 311: break;
! 312: case DMAC::DAR + 2:
! 313: data = chan->dar & 0xffff;
! 314: putlog(3, "#%d DAR:L -> $%04x", ch, data);
! 315: break;
! 316:
! 317: case DMAC::BTC:
! 318: data = chan->btc;
! 319: putlog(3, "#%d BTC -> $%04x", ch, data);
! 320: break;
! 321:
! 322: case DMAC::BAR:
! 323: data = chan->bar >> 16;
! 324: putlog(3, "#%d BAR:H -> $%04x", ch, data);
! 325: break;
! 326: case DMAC::BAR + 2:
! 327: data = chan->bar & 0xffff;
! 328: putlog(3, "#%d BAR:L -> $%04x", ch, data);
! 329: break;
! 330:
! 331: case DMAC::NIV:
! 332: data = chan->niv | 0xff00;
! 333: putlog(3, "#%d NIV -> $%04x", ch, data);
! 334: break;
! 335:
! 336: case DMAC::EIV:
! 337: data = chan->eiv | 0xff00;
! 338: putlog(3, "#%d EIV -> $%04x", ch, data);
! 339: break;
! 340:
! 341: case DMAC::MFC:
! 342: data = chan->mfc | 0xff00;
! 343: putlog(3, "#%d MFC -> $%04x", ch, data);
! 344: break;
! 345:
! 346: case DMAC::CPR:
! 347: data = chan->cpr | 0xff00;
! 348: putlog(3, "#%d CPR -> $%04x", ch, data);
! 349: break;
! 350:
! 351: case DMAC::DFC:
! 352: data = chan->dfc | 0xff00;
! 353: putlog(3, "#%d DFC -> $%04x", ch, data);
! 354: break;
! 355:
! 356: case DMAC::BFC:
! 357: data = chan->bfc | 0xff00;
! 358: putlog(3, "#%d BFC -> $%04x", ch, data);
! 359: break;
! 360:
! 361: case DMAC::GCR:
! 362: if (ch == 3) {
! 363: data = gcr | 0xff00;
! 364: putlog(3, "GCR -> $%04x", data);
! 365: break;
! 366: } else {
! 367: data = 0xffff;
! 368: }
! 369: break;
! 370:
! 371: default:
! 372: data = 0xffff;
! 373: break;
! 374: }
! 375:
! 376: return data;
! 377: }
! 378:
! 379: // STR か ACT が立っている時に書き込むとタイミングエラー
! 380: #define TIMING_ERR_IF_RUNNING do { \
! 381: if (chan->str || chan->active) { \
! 382: Error(chan, DMAC::CER_TIMING); \
! 383: break; \
! 384: } \
! 385: } while (0)
1.1 root 386:
1.1.1.11! root 387: // ログ表示版
! 388: #define TIMING_ERR_IF_RUNNING_log(regname) do { \
! 389: if (chan->str || chan->active) { \
! 390: putlog(2, "#%d %s <- $%02x", ch, regname, data); \
! 391: Error(chan, DMAC::CER_TIMING); \
! 392: break; \
! 393: } \
! 394: } while (0)
! 395:
! 396: uint64
! 397: DMACDevice::Write8(uint32 addr, uint32 data)
! 398: {
1.1.1.5 root 399: gMPU->AddCycle(31); // InsideOut p.135
400:
1.1.1.11! root 401: uint32 offset = addr & 0xff;
! 402: int ch = offset / 0x40;
1.1.1.7 root 403: int n = offset % 0x40;
1.1.1.11! root 404: DMACChan *chan = &channel[ch];
! 405:
1.1 root 406: switch (n) {
407: case DMAC::CSR:
1.1.1.11! root 408: WriteCSR(chan, data);
1.1 root 409: break;
410:
411: case DMAC::CER:
412: // Read only
413: break;
414:
415: case DMAC::DCR:
1.1.1.11! root 416: putlog(2, "#%d DCR <- $%02x", ch, data);
! 417: TIMING_ERR_IF_RUNNING;
! 418: chan->SetDCR(data);
1.1 root 419: break;
420:
421: case DMAC::OCR:
1.1.1.11! root 422: putlog(2, "#%d OCR <- $%02x", ch, data);
! 423: TIMING_ERR_IF_RUNNING;
! 424: chan->SetOCR(data);
1.1 root 425: break;
426:
427: case DMAC::SCR:
1.1.1.11! root 428: putlog(2, "#%d SCR <- $%02x", ch, data);
! 429: TIMING_ERR_IF_RUNNING;
! 430: chan->SetSCR(data);
1.1 root 431: break;
432:
433: case DMAC::CCR:
1.1.1.11! root 434: {
! 435: // %0 -> %1 に変化したビットだけを評価する。
! 436: uint8 up = (chan->GetCCR() ^ data) & data;
! 437: // バイトサイズのログを (up 込みで) 表示。
! 438: putlog(2, "#%d CCR <- $%02x (up=$%02x)", chan->ch, data, up);
! 439: // CCR を更新してから WriteCCR() で動作をする。
! 440: chan->SetCCR(data);
! 441: WriteCCR(chan, data, up);
1.1 root 442: break;
1.1.1.11! root 443: }
1.1 root 444:
445: case DMAC::MTC:
1.1.1.11! root 446: TIMING_ERR_IF_RUNNING_log("MTC:H");
1.1 root 447: chan->mtc = (chan->mtc & 0x00ff) | (data << 8);
1.1.1.11! root 448: putlog(2, "#%d MTC:H <- $%02x (MTC=$%04x)", ch, data, chan->mtc);
1.1 root 449: break;
450: case DMAC::MTC + 1:
1.1.1.11! root 451: TIMING_ERR_IF_RUNNING_log("MTC:L");
1.1 root 452: chan->mtc = (chan->mtc & 0xff00) | data;
1.1.1.11! root 453: putlog(2, "#%d MTC:L <- $%02x (MTC=$%04x)", ch, data, chan->mtc);
1.1 root 454: break;
455:
456: case DMAC::MAR:
1.1.1.11! root 457: TIMING_ERR_IF_RUNNING_log("MAR:0");
1.1 root 458: chan->mar = (chan->mar & 0x00ffffff) | (data << 24);
1.1.1.11! root 459: putlog(2, "#%d MAR:0 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 460: break;
461: case DMAC::MAR + 1:
1.1.1.11! root 462: TIMING_ERR_IF_RUNNING_log("MAR:1");
1.1 root 463: chan->mar = (chan->mar & 0xff00ffff) | (data << 16);
1.1.1.11! root 464: putlog(2, "#%d MAR:1 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 465: break;
466: case DMAC::MAR + 2:
1.1.1.11! root 467: TIMING_ERR_IF_RUNNING_log("MAR:2");
1.1 root 468: chan->mar = (chan->mar & 0xffff00ff) | (data << 8);
1.1.1.11! root 469: putlog(2, "#%d MAR:2 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 470: break;
471: case DMAC::MAR + 3:
1.1.1.11! root 472: TIMING_ERR_IF_RUNNING_log("MAR:3");
1.1 root 473: chan->mar = (chan->mar & 0xffffff00) | data;
1.1.1.11! root 474: putlog(2, "#%d MAR:3 <- $%02x (MAR=$%08x)", ch, data, chan->mar);
1.1 root 475: break;
476:
477: case DMAC::DAR:
1.1.1.11! root 478: TIMING_ERR_IF_RUNNING_log("DAR:0");
1.1 root 479: chan->dar = (chan->dar & 0x00ffffff) | (data << 24);
1.1.1.11! root 480: putlog(2, "#%d DAR:0 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 481: break;
482: case DMAC::DAR + 1:
1.1.1.11! root 483: TIMING_ERR_IF_RUNNING_log("DAR:1");
1.1 root 484: chan->dar = (chan->dar & 0xff00ffff) | (data << 16);
1.1.1.11! root 485: putlog(2, "#%d DAR:1 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 486: break;
487: case DMAC::DAR + 2:
1.1.1.11! root 488: TIMING_ERR_IF_RUNNING_log("DAR:2");
1.1 root 489: chan->dar = (chan->dar & 0xffff00ff) | (data << 8);
1.1.1.11! root 490: putlog(2, "#%d DAR:2 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 491: break;
492: case DMAC::DAR + 3:
1.1.1.11! root 493: TIMING_ERR_IF_RUNNING_log("DAR:3");
1.1 root 494: chan->dar = (chan->dar & 0xffffff00) | data;
1.1.1.11! root 495: putlog(2, "#%d DAR:3 <- $%02x (DAR=$%08x)", ch, data, chan->dar);
1.1 root 496: break;
497:
498: case DMAC::BTC:
499: chan->btc = (chan->btc & 0x00ff) | (data << 8);
1.1.1.11! root 500: putlog(2, "#%d BTC:H <- $%02x (BTC=$%04x)", ch, data, chan->btc);
1.1 root 501: break;
502: case DMAC::BTC + 1:
503: chan->btc = (chan->btc & 0xff00) | data;
1.1.1.11! root 504: putlog(2, "#%d BTC:L <- $%02x (BTC=$%04x)", ch, data, chan->btc);
1.1 root 505: break;
506:
507: case DMAC::BAR:
508: chan->bar = (chan->bar & 0x00ffffff) | (data << 24);
1.1.1.11! root 509: putlog(2, "#%d BAR:0 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 510: break;
511: case DMAC::BAR + 1:
512: chan->bar = (chan->bar & 0xff00ffff) | (data << 16);
1.1.1.11! root 513: putlog(2, "#%d BAR:1 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 514: break;
515: case DMAC::BAR + 2:
516: chan->bar = (chan->bar & 0xffff00ff) | (data << 8);
1.1.1.11! root 517: putlog(2, "#%d BAR:2 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 518: break;
519: case DMAC::BAR + 3:
520: chan->bar = (chan->bar & 0xffffff00) | data;
1.1.1.11! root 521: putlog(2, "#%d BAR:3 <- $%02x (BAR=$%08x)", ch, data, chan->bar);
1.1 root 522: break;
523:
524: case DMAC::NIV:
1.1.1.11! root 525: putlog(2, "#%d NIV <- $%02x", ch, data);
! 526: chan->SetNIV(data);
1.1 root 527: break;
528:
529: case DMAC::EIV:
1.1.1.11! root 530: putlog(2, "#%d EIV <- $%02x", ch, data);
! 531: chan->SetEIV(data);
1.1 root 532: break;
533:
534: case DMAC::MFC:
1.1.1.11! root 535: putlog(2, "#%d MFC <- $%02x", ch, data);
! 536: TIMING_ERR_IF_RUNNING;
! 537: chan->SetMFC(data);
1.1 root 538: break;
539:
540: case DMAC::CPR:
1.1.1.11! root 541: putlog(2, "#%d CPR <- $%02x", ch, data);
! 542: chan->SetCPR(data);
1.1 root 543: break;
544:
545: case DMAC::DFC:
1.1.1.11! root 546: putlog(2, "#%d DFC <- $%02x", ch, data);
! 547: TIMING_ERR_IF_RUNNING;
! 548: chan->SetDFC(data);
1.1 root 549: break;
550:
551: case DMAC::BFC:
1.1.1.11! root 552: putlog(2, "#%d BFC <- $%02x", ch, data);
! 553: chan->SetBFC(data);
1.1 root 554: break;
555:
556: case DMAC::GCR:
557: if (ch == 3) {
1.1.1.11! root 558: WriteGCR(data);
! 559: }
! 560: break;
! 561:
! 562: default:
! 563: break;
! 564: }
! 565: return 0;
! 566: }
! 567:
! 568: uint64
! 569: DMACDevice::Write16(uint32 addr, uint32 data)
! 570: {
! 571: gMPU->AddCycle(31); // InsideOut p.135
! 572:
! 573: uint32 offset = addr & 0xff;
! 574: int ch = offset / 0x40;
! 575: int n = offset % 0x40;
! 576: DMACChan *chan = &channel[ch];
! 577:
! 578: switch (n) {
! 579: case DMAC::CSR: // CSR | CER
! 580: // XXX ログがバイトサイズのまま出るがどうするか
! 581: WriteCSR(chan, data >> 8);
! 582: // CER は Read Only
! 583: break;
! 584:
! 585: case DMAC::DCR: // DCR | OCR
! 586: putlog(2, "#%d DCR:OCR <- $%04x", ch, data);
! 587: TIMING_ERR_IF_RUNNING;
! 588: chan->SetDCR(data >> 8);
! 589: chan->SetOCR(data & 0xff);
! 590: break;
! 591:
! 592: case DMAC::SCR: // SCR | CCR
! 593: {
! 594: // CCR の %0 -> %1 に変化したビットだけを取り出す。
! 595: uint8 up = (chan->GetCCR() ^ data) & data;
! 596: // ワードサイズのログを (CCR の up 込みで) 表示。
! 597: putlog(2, "#%d SCR:CCR <- $%04x (up=$%02x)", ch, data, up);
! 598: // 両方のレジスタの値を更新。
! 599: chan->SetSCR(data >> 8);
! 600: chan->SetCCR(data);
! 601: // ワード書き込みで STR が立っているとタイミングエラー (p.17) は
! 602: // ここで評価する。SCR 更新の後。
! 603: TIMING_ERR_IF_RUNNING;
! 604: // タイミングエラーでなければ CCR に基づいて動作。
! 605: WriteCCR(chan, data, up);
! 606: break;
! 607: }
! 608:
! 609: case DMAC::MTC:
! 610: putlog(2, "#%d MTC <- $%04x", ch, data);
! 611: TIMING_ERR_IF_RUNNING;
! 612: chan->mtc = data;
! 613: break;
! 614:
! 615: case DMAC::MAR:
! 616: TIMING_ERR_IF_RUNNING_log("MAR:H");
! 617: chan->mar = (chan->mar & 0x0000ffff) | (data << 16);
! 618: putlog(2, "#%d MAR:H <- $%04x (MAR=$%08x)", ch, data, chan->mar);
! 619: break;
! 620: case DMAC::MAR + 2:
! 621: TIMING_ERR_IF_RUNNING_log("MAR:L");
! 622: chan->mar = (chan->mar & 0xffff0000) | data;
! 623: putlog(2, "#%d MAR:L <- $%04x (MAR=$%08x)", ch, data, chan->mar);
! 624: break;
! 625:
! 626: case DMAC::DAR:
! 627: TIMING_ERR_IF_RUNNING_log("DAR:H");
! 628: chan->dar = (chan->dar & 0x0000ffff) | (data << 16);
! 629: putlog(2, "#%d DAR:H <- $%04x (DAR=$%08x)", ch, data, chan->dar);
! 630: break;
! 631: case DMAC::DAR + 2:
! 632: TIMING_ERR_IF_RUNNING_log("DAR:L");
! 633: chan->dar = (chan->dar & 0xffff0000) | data;
! 634: putlog(2, "#%d DAR:L <- $%04x (DAR=$%08x)", ch, data, chan->dar);
! 635: break;
! 636:
! 637: case DMAC::BTC:
! 638: putlog(2, "#%d BTC <- $%04x", ch, data);
! 639: TIMING_ERR_IF_RUNNING;
! 640: chan->btc = data;
! 641: break;
! 642:
! 643: case DMAC::BAR:
! 644: TIMING_ERR_IF_RUNNING_log("BAR:H");
! 645: chan->bar = (chan->bar & 0x0000ffff) | (data << 16);
! 646: putlog(2, "#%d BAR:H <- $%04x (BAR=$%08x)", ch, data, chan->bar);
! 647: break;
! 648: case DMAC::BAR + 2:
! 649: TIMING_ERR_IF_RUNNING_log("BAR:L");
! 650: chan->bar = (chan->bar & 0xffff0000) | data;
! 651: putlog(2, "#%d BAR:L <- $%04x (BAR=$%08x)", ch, data, chan->bar);
! 652: break;
! 653:
! 654: case DMAC::NIV:
! 655: putlog(2, "#%d NIV <- $%02x", ch, data);
! 656: chan->SetNIV(data);
! 657: break;
! 658:
! 659: case DMAC::EIV:
! 660: putlog(2, "#%d EIV <- $%02x", ch, data);
! 661: chan->SetEIV(data);
! 662: break;
! 663:
! 664: case DMAC::MFC:
! 665: putlog(2, "#%d MFC <- $%02x", ch, data);
! 666: TIMING_ERR_IF_RUNNING;
! 667: chan->SetMFC(data);
! 668: break;
! 669:
! 670: case DMAC::CPR:
! 671: putlog(2, "#%d CPR <- $%02x", ch, data);
! 672: chan->SetCPR(data);
! 673: break;
! 674:
! 675: case DMAC::DFC:
! 676: putlog(2, "#%d DFC <- $%02x", ch, data);
! 677: TIMING_ERR_IF_RUNNING;
! 678: chan->SetDFC(data);
! 679: break;
! 680:
! 681: case DMAC::BFC:
! 682: putlog(2, "#%d BFC <- $%02x", ch, data);
! 683: chan->SetBFC(data);
! 684: break;
! 685:
! 686: case DMAC::GCR - 1:
! 687: if (ch == 3) {
! 688: WriteGCR(data);
1.1 root 689: }
690: break;
691:
692: default:
693: break;
694: }
695: return 0;
696: }
697:
698: uint64
1.1.1.11! root 699: DMACDevice::Peek8(uint32 addr)
1.1 root 700: {
701: uint8 data;
702:
1.1.1.11! root 703: uint32 offset = addr & 0xff;
! 704: int ch = offset / 0x40;
1.1.1.7 root 705: int n = offset % 0x40;
1.1.1.11! root 706: DMACChan *chan = &channel[ch];
! 707:
1.1 root 708: switch (n) {
709: case DMAC::CSR:
1.1.1.11! root 710: data = chan->GetCSR();
1.1 root 711: break;
712:
713: case DMAC::CER:
714: data = chan->cer;
715: break;
716:
717: case DMAC::DCR:
1.1.1.11! root 718: data = chan->GetDCR();
1.1 root 719: break;
720:
721: case DMAC::OCR:
1.1.1.11! root 722: data = chan->GetOCR();
1.1 root 723: break;
724:
725: case DMAC::SCR:
1.1.1.11! root 726: data = chan->GetSCR();
1.1 root 727: break;
728:
729: case DMAC::CCR:
1.1.1.11! root 730: data = chan->GetCCR();
1.1 root 731: break;
732:
733: case DMAC::MTC:
734: data = chan->mtc >> 8;
735: break;
736: case DMAC::MTC + 1:
737: data = chan->mtc & 0xff;
738: break;
739:
740: case DMAC::MAR:
741: data = chan->mar >> 24;
742: break;
743: case DMAC::MAR + 1:
744: data = (chan->mar >> 16) & 0xff;
745: break;
746: case DMAC::MAR + 2:
747: data = (chan->mar >> 8) & 0xff;
748: break;
749: case DMAC::MAR + 3:
750: data = chan->mar & 0xff;
751: break;
752:
753: case DMAC::DAR:
754: data = chan->dar >> 24;
755: break;
756: case DMAC::DAR + 1:
757: data = (chan->dar >> 16) & 0xff;
758: break;
759: case DMAC::DAR + 2:
760: data = (chan->dar >> 8) & 0xff;
761: break;
762: case DMAC::DAR + 3:
763: data = chan->dar & 0xff;
764: break;
765:
766: case DMAC::BTC:
767: data = chan->btc >> 8;
768: break;
769: case DMAC::BTC + 1:
770: data = chan->btc & 0xff;
771: break;
772:
773: case DMAC::BAR:
774: data = chan->bar >> 24;
775: break;
776: case DMAC::BAR + 1:
777: data = (chan->bar >> 16) & 0xff;
778: break;
779: case DMAC::BAR + 2:
780: data = (chan->bar >> 8) & 0xff;
781: break;
782: case DMAC::BAR + 3:
783: data = chan->bar & 0xff;
784: break;
785:
786: case DMAC::NIV:
787: data = chan->niv;
788: break;
789:
790: case DMAC::EIV:
791: data = chan->eiv;
792: break;
793:
794: case DMAC::MFC:
795: data = chan->mfc;
796: break;
797:
798: case DMAC::CPR:
799: data = chan->cpr;
800: break;
801:
802: case DMAC::DFC:
803: data = chan->dfc;
804: break;
805:
806: case DMAC::BFC:
807: data = chan->bfc;
808: break;
809:
810: case DMAC::GCR:
811: if (ch == 3) {
1.1.1.11! root 812: data = gcr;
1.1 root 813: } else {
814: data = 0xff;
815: }
816: break;
817:
818: default:
819: data = 0xff;
820: break;
821: }
822:
823: return data;
824: }
825:
1.1.1.4 root 826: void
1.1.1.8 root 827: DMACDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 828: {
829: int x;
830: int y;
831:
1.1.1.8 root 832: screen.Clear();
1.1.1.2 root 833:
834: y = 1;
1.1.1.11! root 835: screen.Puts(0, y++, "BaseAddress");
! 836: screen.Print(0, y++, "+$%02x CSR:", DMAC::CSR);
1.1.1.2 root 837: y += 2;
1.1.1.11! root 838: screen.Print(0, y++, "+$%02x CER:", DMAC::CER);
! 839: screen.Print(0, y++, "+$%02x DCR:", DMAC::DCR);
! 840: screen.Print(5, y++, "%6s", ".XRM");
! 841: screen.Print(5, y++, "%6s", ".DTYP");
! 842: screen.Print(5, y++, "%6s", ".DPS");
! 843: screen.Print(5, y++, "%6s", ".PCL");
! 844: screen.Print(0, y++, "+$%02x OCR:", DMAC::OCR);
! 845: screen.Print(5, y++, "%6s", ".DIR");
! 846: screen.Print(5, y++, "%6s", ".SIZE");
! 847: screen.Print(5, y++, "%6s", ".CHAIN");
! 848: screen.Print(5, y++, "%6s", ".REQG");
! 849: screen.Print(0, y++, "+$%02x SCR:", DMAC::SCR);
! 850: screen.Print(5, y++, "%6s", ".MAC");
! 851: screen.Print(5, y++, "%6s", ".DAC");
! 852: screen.Print(0, y++, "+$%02x CCR:", DMAC::CCR);
1.1.1.2 root 853: y += 2;
1.1.1.11! root 854: screen.Print(0, y++, "+$%02x MTC:", DMAC::MTC);
! 855: screen.Print(0, y++, "+$%02x MAR:", DMAC::MAR);
! 856: screen.Print(0, y++, "+$%02x DAR:", DMAC::DAR);
! 857: screen.Print(0, y++, "+$%02x BTC:", DMAC::BTC);
! 858: screen.Print(0, y++, "+$%02x BAR:", DMAC::BAR);
! 859: screen.Print(0, y++, "+$%02x NIV:", DMAC::NIV);
! 860: screen.Print(0, y++, "+$%02x EIV:", DMAC::EIV);
! 861: screen.Print(0, y++, "+$%02x MFC:", DMAC::MFC);
! 862: screen.Print(0, y++, "+$%02x CPR:", DMAC::CPR);
! 863: screen.Print(0, y++, "+$%02x DFC:", DMAC::DFC);
! 864: screen.Print(0, y++, "+$%02x BFC:", DMAC::BFC);
1.1.1.2 root 865:
866: for (int ch = 0; ch < 4; ch++) {
1.1.1.11! root 867: DMACChan *chan = &channel[ch];
1.1.1.2 root 868: int val;
1.1.1.11! root 869: x = 13 + ch * 17;
1.1.1.2 root 870: y = 0;
871:
872: // 地味だけど有効なチャンネルをハイライトしてみる
1.1.1.8 root 873: screen.Print(x, y++, (chan->active ? TA::Em : TA::Normal),
1.1.1.2 root 874: "#%d (%s)", chan->ch, chan->desc);
875:
1.1.1.11! root 876: // アドレス
! 877: screen.Print(x, y++, "$%06x", baseaddr + ch * 0x40);
! 878:
1.1.1.2 root 879: // CSR
1.1.1.11! root 880: val = chan->GetCSR();
1.1.1.8 root 881: screen.Print(x, y++, "$%02x", val);
1.1.1.2 root 882: static const char * const csrname[] = {
1.1.1.11! root 883: "COC", "BTC", "NDT", "ERR", "ACT", "DIT", "PCT", "PCS",
1.1.1.2 root 884: };
1.1.1.8 root 885: MonitorReg4(screen, x, y++, val >> 4, &csrname[0]);
886: MonitorReg4(screen, x, y++, val & 0xff, &csrname[4]);
1.1.1.2 root 887:
888: // CER
1.1.1.11! root 889: val = chan->cer;
1.1.1.2 root 890: const char *e;
891: if (val <= 0x11 && errnames[val]) {
892: e = errnames[val];
893: } else {
894: e = "?";
895: }
1.1.1.8 root 896: screen.Print(x, y, "$%02x", chan->cer);
1.1.1.11! root 897: if (val != 0) {
1.1.1.8 root 898: screen.Print(x + 3, y, ":%s", e);
1.1.1.2 root 899: }
900: y++;
901:
1.1.1.11! root 902: // DCR
! 903: screen.Print(x, y++, "$%02x", chan->GetDCR());
! 904:
1.1.1.2 root 905: // DCR:XRM
906: static const char * const dcr_xrm[] = {
907: //1234567890123
908: "Burst",
909: "undefined",
910: "CycleW/O Hold",
911: "CycleWithHold",
912: };
1.1.1.11! root 913: val = chan->GetXRM();
1.1.1.8 root 914: screen.Print(x, y++, "%d:%s", val, dcr_xrm[val]);
1.1.1.2 root 915:
916: // DCR:DTYP
917: static const char * const dcr_dtyp[] = {
918: //1234567890123
919: "68000",
920: "6800",
921: "ACK",
922: "ACK+READY",
923: };
1.1.1.11! root 924: val = chan->GetDTYP();
1.1.1.8 root 925: screen.Print(x, y++, "%d:%s", val, dcr_dtyp[val]);
1.1.1.2 root 926:
927: // DCR:DPS
928: static const char * const dcr_dps[] = {
929: //1234567890123
930: "8bit",
931: "16bit",
932: };
1.1.1.11! root 933: val = chan->GetDPS();
1.1.1.8 root 934: screen.Print(x, y++, "%d:%s", val, dcr_dps[val]);
1.1.1.2 root 935:
936: // DCR:PCL
1.1.1.11! root 937: static const char * const dcr_pcl_name[] = {
! 938: //1234567890123
! 939: "Status",
! 940: "StatusInt",
! 941: "Pulse(output)",
! 942: "Abort",
! 943: };
! 944: val = chan->dcr_pcl;
! 945: screen.Print(x, y++, "%d:%s", val, dcr_pcl_name[val]);
! 946:
! 947: // OCR
! 948: screen.Print(x, y++, "$%02x", chan->GetOCR());
1.1.1.2 root 949:
950: // OCR:DIR
951: static const char * const ocr_dir[] = {
952: //1234567890123
953: "MemoryToDevice",
954: "DeviceToMemory",
955: };
1.1.1.11! root 956: val = chan->GetDIR();
1.1.1.8 root 957: screen.Print(x, y++, "%d:%s", val, ocr_dir[val]);
1.1.1.2 root 958:
959: // OCR:SIZE
960: static const char * const ocr_size[] = {
961: //1234567890123
1.1.1.11! root 962: "8bit (Packed)",
1.1.1.2 root 963: "16bit",
964: "32bit",
965: "8bit Unpacked",
966: };
1.1.1.11! root 967: val = chan->GetSIZE();
1.1.1.8 root 968: screen.Print(x, y++, "%d:%s", val, ocr_size[val]);
1.1.1.2 root 969:
970: // OCR:CHAIN
971: static const char * const ocr_chain[] = {
972: //1234567890123
973: "NoChain",
974: "undefined",
975: "ArrayChain",
976: "LinkArrayChain",
977: };
1.1.1.11! root 978: val = chan->GetCHAIN();
1.1.1.8 root 979: screen.Print(x, y++, "%d:%s", val, ocr_chain[val]);
1.1.1.2 root 980:
981: // OCR:REQG
982: static const char * const ocr_reqg[] = {
983: //1234567890123
984: "AutoReq(Limit)",
985: "AutoReq(Max)",
986: "ExternalReq",
987: "AutoThenExt",
988: };
1.1.1.11! root 989: val = chan->GetREQG();
1.1.1.8 root 990: screen.Print(x, y++, "%d:%s", val, ocr_reqg[val]);
1.1.1.2 root 991:
1.1.1.11! root 992: // SCR
! 993: screen.Print(x, y++, "$%02x", chan->GetSCR());
! 994:
! 995: // SCR:MAC,DAC
1.1.1.2 root 996: static const char * const scr_xac[] = {
997: //1234567890123
998: "NoCount",
999: "CountUp",
1000: "CountDown",
1001: "undefined",
1002: };
1.1.1.11! root 1003: val = chan->GetMAC();
1.1.1.8 root 1004: screen.Print(x, y++, "%d:%s", val, scr_xac[val]);
1.1.1.11! root 1005: val = chan->GetDAC();
1.1.1.8 root 1006: screen.Print(x, y++, "%d:%s", val, scr_xac[val]);
1.1.1.2 root 1007:
1008: // CCR
1.1.1.11! root 1009: val = chan->GetCCR();
1.1.1.8 root 1010: screen.Print(x, y++, "$%02x", val);
1.1.1.2 root 1011: static const char * const ccrnames[] = {
1.1.1.9 root 1012: "STR", "CNT", "HLT", "SAB", "INT", "-", "-", "-",
1.1.1.2 root 1013: };
1.1.1.8 root 1014: MonitorReg4(screen, x, y++, (val >> 4), &ccrnames[0]);
1015: MonitorReg4(screen, x, y++, (val & 0xff), &ccrnames[4]);
1.1.1.2 root 1016:
1017: // MTC
1.1.1.8 root 1018: screen.Print(x, y++, "$%04x", chan->mtc);
1.1.1.2 root 1019: // MAR
1020: // X680x0 がターゲットなので24bit超える設定は目立たせる
1021: if (chan->mar > 0xffffff) {
1.1.1.8 root 1022: screen.Print(x, y++, TA::On, "$%08x", chan->mar);
1.1.1.2 root 1023: } else {
1.1.1.8 root 1024: screen.Print(x, y++, "$%06x", chan->mar);
1.1.1.2 root 1025: }
1026: // DAR
1027: if (chan->dar > 0xffffff) {
1.1.1.8 root 1028: screen.Print(x, y++, TA::On, "$%08x", chan->dar);
1.1.1.2 root 1029: } else {
1.1.1.8 root 1030: screen.Print(x, y++, "$%06x", chan->dar);
1.1.1.2 root 1031: }
1032: // BTC
1.1.1.8 root 1033: screen.Print(x, y++, "$%04x", chan->btc);
1.1.1.2 root 1034: // BAR
1035: if (chan->bar > 0xffffff) {
1.1.1.8 root 1036: screen.Print(x, y++, TA::On, "$%08x", chan->bar);
1.1.1.2 root 1037: } else {
1.1.1.8 root 1038: screen.Print(x, y++, "$%06x", chan->bar);
1.1.1.2 root 1039: }
1040:
1041: // NIV
1.1.1.8 root 1042: screen.Print(x, y++, "$%02x", chan->niv);
1.1.1.2 root 1043: // EIV
1.1.1.8 root 1044: screen.Print(x, y++, "$%02x", chan->eiv);
1.1.1.2 root 1045:
1046: // MFC
1.1.1.8 root 1047: screen.Print(x, y++, "$%02x", chan->mfc);
1.1.1.2 root 1048: // CPR
1.1.1.8 root 1049: screen.Print(x, y++, "$%02x", chan->cpr);
1.1.1.2 root 1050: // DFC
1.1.1.8 root 1051: screen.Print(x, y++, "$%02x", chan->dfc);
1.1.1.2 root 1052: // BFC
1.1.1.8 root 1053: screen.Print(x, y++, "$%02x", chan->bfc);
1.1.1.2 root 1054:
1055: if (ch == 3) {
1.1.1.11! root 1056: screen.Print(x - 10, y++, "+$3f GCR: $%02x", gcr);
1.1.1.2 root 1057: }
1058: }
1059: }
1060:
1061: // 4ビット分を表示する。MonitorUpdate の下請け
1062: void
1.1.1.8 root 1063: DMACDevice::MonitorReg4(TextScreen& screen,
1.1.1.4 root 1064: int x, int y, uint32 reg, const char * const *names)
1.1.1.2 root 1065: {
1066: for (int i = 0; i < 4; i++) {
1.1.1.9 root 1067: if (names[i][0] == '-') {
1068: screen.Puts(x + i * 4, y, TA::Disable, "---");
1069: } else {
1070: bool b = reg & (1 << (3 - i));
1071: screen.Puts(x + i * 4, y, TA::OnOff(b), names[i]);
1072: }
1.1.1.2 root 1073: }
1074: }
1075:
1076: /*static*/ const char * const
1077: DMACDevice::errnames[] = {
1078: //12345678901
1079: "", // $00 No Error
1080: "ConfigErr", // $01
1081: "OperTiming", // $02
1082: NULL, // $03
1083: NULL, // $04
1084: "AddrErrInMAR", // $05
1085: "AddrErrInDAR", // $06
1086: "AddrErrInBAR", // $07
1087: NULL, // $08
1088: "BusErrInMAR", // $09
1089: "BusErrInDAR", // $0a
1090: "BusErrInBAR", // $0b
1091: NULL, // $0c
1092: "CntErrInMTC", // $0d
1093: NULL, // $0e
1094: "CntErrInBTC", // $0f
1095: "ExternAbort", // $10
1096: "SoftAbort", // $11
1097: };
1098:
1.1.1.6 root 1099: // CSR への書き込み。
1.1 root 1100: void
1.1.1.11! root 1101: DMACDevice::WriteCSR(DMACChan *chan, uint32 data)
1.1 root 1102: {
1.1.1.11! root 1103: // 上位3ビットと DIT は %1 の書き込みでクリア
! 1104: chan->csr &= ~(data & 0xe4);
! 1105:
! 1106: // ERR も %1 の書き込みでクリア。
! 1107: // このとき CER もクリアする。
! 1108: if ((data & DMAC::CSR_ERR)) {
! 1109: chan->csr &= ~DMAC::CSR_ERR;
! 1110: chan->cer = 0;
! 1111: }
1.1.1.2 root 1112:
1.1.1.10 root 1113: // PCT も %1 の書き込みでクリア。
1.1.1.11! root 1114: // PCT は PCL が High → Low の時セットなので pcl_prev を下げればよい
1.1.1.2 root 1115: if ((data & DMAC::CSR_PCT)) {
1.1.1.11! root 1116: chan->pcl_prev = false;
1.1.1.2 root 1117: }
1118:
1.1.1.11! root 1119: putlog(2, "#%d CSR <- $%02x (CSR = $%02x)", chan->ch, data, chan->GetCSR());
! 1120:
! 1121: ChangeInterrupt();
1.1.1.2 root 1122: }
1123:
1.1.1.11! root 1124: // GCR への書き込み。
1.1 root 1125: void
1.1.1.11! root 1126: DMACDevice::WriteGCR(uint8 data)
1.1 root 1127: {
1.1.1.11! root 1128: putlog(2, "GCR <- $%02x", data);
! 1129: gcr = data & 0x0f;
! 1130: }
! 1131:
! 1132: // CCR への書き込み。これだけいろいろ変則的なので注意。
! 1133: // up は data のうち %0 -> %1 に変化したビット。
! 1134: // SetCCR() 実行済み、ログは出力済み。
! 1135: void
! 1136: DMACDevice::WriteCCR(DMACChan *chan, uint32 data, uint8 up)
! 1137: {
! 1138: // コンフィギュレーションエラーのチェック。
! 1139: // データシート p43 Error Conditions (a)
! 1140: if ((up & DMAC::CCR_STR)) {
! 1141: // (i) The CNT bit is set at the same time STR bit in the chaining mode.
! 1142: if ((up & DMAC::CCR_CNT) && chan->IsChain()) {
! 1143: Error(chan, DMAC::CER_CONFIG);
! 1144: return;
! 1145: }
! 1146:
! 1147: if (chan->IsSingleAddress()) {
! 1148: // (ii) DTYP specifies a single addressing mode, and
! 1149: // the device port size is not the same as the operand size.
! 1150: if (chan->GetDPS() == DMAC::DPS_8BIT) {
! 1151: if (!(chan->GetSIZE() == DMAC::SIZE_8BIT_PACK ||
! 1152: chan->GetSIZE() == DMAC::SIZE_8BIT_UNPK))
! 1153: {
! 1154: Error(chan, DMAC::CER_CONFIG);
! 1155: return;
! 1156: }
! 1157: } else {
! 1158: if (!(chan->GetSIZE() == DMAC::SIZE_16BIT)) {
! 1159: Error(chan, DMAC::CER_CONFIG);
! 1160: return;
! 1161: }
! 1162: }
! 1163: } else {
! 1164: // (iii) DTYP specifies a dual addressing mode, DPS is 16 bits,
! 1165: // SIZE is 8 bits and REQG is "10" or "11".
! 1166: if (chan->GetDPS() == DMAC::DPS_16BIT) {
! 1167: // XXX UNPK は?
! 1168: if (chan->GetSIZE() == DMAC::SIZE_8BIT_PACK) {
! 1169: if (chan->GetREQG() == DMAC::REQG_EXTERNAL ||
! 1170: chan->GetREQG() == DMAC::REQG_AUTOFIRST)
! 1171: {
! 1172: Error(chan, DMAC::CER_CONFIG);
! 1173: return;
! 1174: }
! 1175: }
! 1176: }
! 1177: }
! 1178:
! 1179: // (iv) An undefined configuration is set in the registers.
! 1180: if (chan->GetXRM() == 1 ||
! 1181: chan->GetMAC() == 3 ||
! 1182: chan->GetDAC() == 3 ||
! 1183: chan->GetCHAIN() == 1)
! 1184: {
! 1185: Error(chan, DMAC::CER_CONFIG);
! 1186: return;
! 1187: }
! 1188: if (chan->IsSingleAddress() == false &&
! 1189: chan->GetSIZE() == DMAC::SIZE_8BIT_UNPK &&
! 1190: chan->GetDPS() != DMAC::DPS_8BIT)
! 1191: {
! 1192: Error(chan, DMAC::CER_CONFIG);
! 1193: return;
! 1194: }
! 1195:
! 1196: // (e) Count Error
! 1197: // ここでは (i), (ii) のみ
! 1198: if (chan->IsChain() == false && chan->mtc == 0) {
! 1199: Error(chan, DMAC::CER_COUNT_MTC);
! 1200: return;
! 1201: }
! 1202: if (chan->GetCHAIN() == DMAC::CHAIN_ARRAY && chan->btc == 0) {
! 1203: Error(chan, DMAC::CER_COUNT_BTC);
! 1204: return;
! 1205: }
! 1206: }
1.1.1.2 root 1207:
1208: // SAB (Software Abort)
1.1.1.11! root 1209: if ((up & DMAC::CCR_SAB)) {
! 1210: AbortTransfer(chan);
1.1.1.2 root 1211: }
1212:
1213: // HLT (Halt Operation)
1.1.1.11! root 1214: if ((up & DMAC::CCR_HLT)) {
! 1215: putlog(0, "CCR HLT (NOT IMPLEMENTED)");
1.1.1.2 root 1216: }
1217:
1218: // CNT (Continue Operation)
1.1.1.11! root 1219: if ((up & DMAC::CCR_CNT)) {
! 1220: // Opeation Timing Error (i)
! 1221: if (chan->IsChain() && chan->active) {
! 1222: Error(chan, DMAC::CER_TIMING);
! 1223: return;
! 1224: }
! 1225: if (chan->str == false && chan->active == false) {
! 1226: Error(chan, DMAC::CER_TIMING);
! 1227: return;
! 1228: }
! 1229: putlog(0, "CCR CNT (NOT IMPLEMENTED)");
1.1.1.2 root 1230: }
1231:
1232: // STR (Start Operation)
1.1.1.11! root 1233: if ((up & DMAC::CCR_STR)) {
! 1234: StartTransfer(chan);
1.1.1.2 root 1235: }
1.1.1.11! root 1236:
! 1237: ChangeInterrupt();
1.1 root 1238: }
1239:
1.1.1.11! root 1240: // 転送開始
1.1.1.2 root 1241: void
1.1.1.11! root 1242: DMACDevice::StartTransfer(DMACChan* chan)
1.1.1.2 root 1243: {
1.1.1.11! root 1244: // Operation Timing Error (ii)
! 1245: // CSR の ACT,COC,BTC,NDT,ERR が立ってたら開始しない
! 1246: if (chan->active || (chan->csr & 0xf0) != 0) {
! 1247: Error(chan, DMAC::CER_TIMING);
1.1.1.2 root 1248: return;
1249: }
1250:
1.1.1.11! root 1251: // ACT を立てたら STR を下げる。
! 1252: chan->active = true;
! 1253: chan->str = false;
1.1.1.2 root 1254:
1.1.1.11! root 1255: // XXX あとで移動する
! 1256: switch (chan->GetMAC()) {
! 1257: case DMAC::SCR_COUNT_UP:
! 1258: chan->mac = 1;
! 1259: break;
! 1260: case DMAC::SCR_COUNT_DOWN:
! 1261: putlog(0, "SCR:MAC CountDown Mode (NOT SUPPORTED)");
! 1262: chan->mac = -1;
! 1263: break;
! 1264: default:
! 1265: chan->mac = 0;
! 1266: break;
! 1267: }
! 1268: switch (chan->GetDAC()) {
! 1269: case DMAC::SCR_COUNT_UP:
! 1270: chan->dac = 1;
! 1271: break;
! 1272: case DMAC::SCR_COUNT_DOWN:
! 1273: putlog(0, "SCR:DAC CountDown Mode (NOT SUPPORTED)");
! 1274: chan->dac = -1;
! 1275: break;
! 1276: default:
! 1277: chan->dac = 0;
! 1278: break;
! 1279: }
1.1.1.2 root 1280:
1.1.1.11! root 1281: chan->data.Clear();
1.1.1.2 root 1282:
1283: // 転送モード
1.1.1.11! root 1284: switch (chan->GetREQG()) {
! 1285: case DMAC::REQG_AUTO_LIM:
1.1.1.10 root 1286: VMPANIC("REQG_AUTO_LIM 未実装");
1.1.1.2 root 1287: break;
1288:
1.1.1.11! root 1289: case DMAC::REQG_AUTO_MAX:
1.1.1.2 root 1290: // 自発的に転送を開始する
1.1.1.11! root 1291: chan->req = true;
! 1292: break;
! 1293:
! 1294: case DMAC::REQG_EXTERNAL:
! 1295: // 外部リクエスト転送。ここでは何もしなくてよい
1.1.1.2 root 1296: break;
1297:
1.1.1.11! root 1298: case DMAC::REQG_AUTOFIRST:
1.1.1.10 root 1299: VMPANIC("未実装 REQG");
1.1.1.2 root 1300: break;
1301:
1302: default:
1303: __unreachable();
1304: }
1305:
1.1.1.11! root 1306: // 転送開始ログ。全パラメータは無理なので概要だけ表示。
! 1307: if (loglevel >= 1) {
! 1308: std::string msg;
! 1309: if (chan->GetDIR() == DMAC::DIR_MtoD) {
! 1310: msg = string_format("$%06x to $%06x mtc=$%04x",
! 1311: chan->mar, chan->dar, chan->mtc);
! 1312: } else {
! 1313: msg = string_format("$%06x to $%06x mtc=$%04x",
! 1314: chan->dar, chan->mar, chan->mtc);
! 1315: }
! 1316: putlogn("#%d Start %s", chan->ch, msg.c_str());
! 1317: }
! 1318:
1.1.1.10 root 1319: if (event.IsRunning() == false) {
1320: CallAfter(StartCallback, 0);
1321: }
1.1.1.5 root 1322: }
1323:
1.1.1.11! root 1324: // 今回転送するチャンネルを決定して返す。なければ NULL を返す。
! 1325: DMACChan *
! 1326: DMACDevice::SelectChannel()
1.1.1.2 root 1327: {
1.1.1.11! root 1328: DMACChan *chan;
1.1.1.10 root 1329: int ch = -1;
1330: uint8 prio = 255;
1.1.1.11! root 1331:
! 1332: for (int i = 0; i < channel.size(); i++) {
! 1333: chan = &channel[i];
! 1334: if (chan->active && (chan->req || chan->seq_index < chan->seq.size())) {
1.1.1.10 root 1335: uint8 p = chan->priority;
1336: if (p < prio) {
1337: prio = p;
1338: // 実効プライオリティのラウンドロビン用のところを上げておく
1339: chan->priority = (p & 0xf0) | ((p & 0x0f) >> 1);
1340: ch = i;
1341: }
1342: }
1343: }
1344: if (ch == -1) {
1345: // 転送チャンネルはもうないのでイベントは停止したままにする
1346: event.SetName("DMAC");
1.1.1.11! root 1347: return NULL;
! 1348: } else {
! 1349: chan = &channel[ch];
! 1350: event.SetName(string_format("DMAC #%d", chan->ch));
! 1351: return chan;
! 1352: }
! 1353: }
! 1354:
! 1355: // 転送開始
! 1356: void
! 1357: DMACDevice::StartCallback(Event& ev)
! 1358: {
! 1359: // チャンネルを決定
! 1360: auto chan = SelectChannel();
! 1361: if (chan == NULL) {
1.1.1.10 root 1362: return;
1363: }
1.1.1.2 root 1364:
1.1.1.10 root 1365: // 実効プライオリティを同順位の最後に回す
1.1.1.11! root 1366: chan->priority |= 0x08;
1.1.1.2 root 1367:
1.1.1.11! root 1368: chan->retry = 0;
1.1.1.10 root 1369:
1370: // XXX バスアービトレーションとか
1371:
1.1.1.11! root 1372: // 転送シーケンス決定
! 1373: chan->seq.clear();
! 1374: chan->seq_index = 0;
! 1375: if (chan->GetDIR() == DMAC::DIR_MtoD) {
! 1376: if (chan->GetDPS() == DMAC::DPS_8BIT) {
! 1377: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
! 1378: chan->seq.push_back(RD_M16);
! 1379: chan->seq.push_back(WR_D8);
! 1380: chan->seq.push_back(WR_D8);
! 1381: chan->seq.push_back(RD_M16);
! 1382: chan->seq.push_back(WR_D8);
! 1383: chan->seq.push_back(WR_D8);
! 1384: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
! 1385: chan->seq.push_back(RD_M16);
! 1386: chan->seq.push_back(WR_D8);
! 1387: chan->seq.push_back(WR_D8);
! 1388: } else {
! 1389: chan->seq.push_back(RD_M8);
! 1390: chan->seq.push_back(WR_D8);
! 1391: }
! 1392: } else {
! 1393: // DPS==16
! 1394: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
! 1395: chan->seq.push_back(RD_M16);
! 1396: chan->seq.push_back(WR_D16);
! 1397: chan->seq.push_back(RD_M16);
! 1398: chan->seq.push_back(WR_D16);
! 1399: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
! 1400: chan->seq.push_back(RD_M16);
! 1401: chan->seq.push_back(WR_D16);
! 1402: } else {
! 1403: chan->seq.push_back(RD_M8);
! 1404: chan->seq.push_back(WR_D8);
! 1405: }
! 1406: }
! 1407: } else { // DtoM
! 1408: if (chan->GetDPS() == DMAC::DPS_8BIT) {
! 1409: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
! 1410: chan->seq.push_back(RD_D8);
! 1411: chan->seq.push_back(RD_D8);
! 1412: chan->seq.push_back(WR_M16);
! 1413: chan->seq.push_back(RD_D8);
! 1414: chan->seq.push_back(RD_D8);
! 1415: chan->seq.push_back(WR_M16);
! 1416: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
! 1417: chan->seq.push_back(RD_D8);
! 1418: chan->seq.push_back(RD_D8);
! 1419: chan->seq.push_back(WR_M16);
! 1420: } else {
! 1421: chan->seq.push_back(RD_D8);
! 1422: chan->seq.push_back(WR_M8);
! 1423: }
! 1424: } else {
! 1425: // DPS==16
! 1426: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
! 1427: chan->seq.push_back(RD_D16);
! 1428: chan->seq.push_back(WR_M16);
! 1429: chan->seq.push_back(RD_D16);
! 1430: chan->seq.push_back(WR_M16);
! 1431: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
! 1432: chan->seq.push_back(RD_D16);
! 1433: chan->seq.push_back(WR_M16);
! 1434: } else {
! 1435: chan->seq.push_back(RD_D8);
! 1436: chan->seq.push_back(WR_M8);
! 1437: }
! 1438: }
! 1439: }
! 1440:
! 1441: CallAfter(TransferCallback, 1);
! 1442: }
! 1443:
! 1444: // 転送処理
! 1445: void
! 1446: DMACDevice::TransferCallback(Event& ev)
! 1447: {
! 1448: // チャンネルを決定
! 1449: auto chan = SelectChannel();
! 1450: if (chan == NULL) {
! 1451: return;
! 1452: }
! 1453:
! 1454: int op = chan->seq[chan->seq_index];
! 1455: uint64 data;
! 1456:
! 1457: // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ
! 1458: switch (op) {
! 1459: case RD_D8:
! 1460: case RD_D16:
! 1461: case WR_D8:
! 1462: case WR_D16:
! 1463: AssertACK(chan);
! 1464: break;
! 1465: default:
! 1466: break;
! 1467: }
! 1468:
! 1469: // パック動作が起きるケースなら op を差し替える。
! 1470: if (chan->GetSIZE() == DMAC::SIZE_8BIT_PACK) {
! 1471: if (op == RD_M8) {
! 1472: if (chan->mtc > 1 && chan->mar % 2 == 0 && chan->GetMAC() != 0) {
! 1473: if (chan->data.Length() == 0) {
! 1474: op = RD_M16;
! 1475: } else {
! 1476: op = NOP;
! 1477: }
! 1478: }
! 1479: }
! 1480: if (op == WR_M8) {
! 1481: if (chan->data.Length() >= 2) {
! 1482: op = WR_M16;
! 1483: } else {
! 1484: if (chan->mtc > 1 && chan->mar % 2 == 0 && chan->GetMAC() != 0){
! 1485: op = NOP;
! 1486: }
! 1487: }
! 1488: }
! 1489: }
! 1490:
! 1491: // 1回分のアクセス
! 1492: data = 0;
! 1493: switch (op) {
! 1494: case RD_M8:
! 1495: data = vm_phys_read_8(chan->mar);
! 1496: break;
! 1497: case RD_M16:
! 1498: data = vm_phys_read_16(chan->mar);
! 1499: break;
! 1500: case RD_D8:
! 1501: data = vm_phys_read_8(chan->dar);
! 1502: break;
! 1503: case RD_D16:
! 1504: data = vm_phys_read_16(chan->dar);
! 1505: break;
! 1506: case WR_M8:
! 1507: data = chan->data.Dequeue();
! 1508: data = vm_phys_write_8(chan->mar, data);
! 1509: break;
! 1510: case WR_M16:
! 1511: data = chan->data.Dequeue() << 8;
! 1512: data |= chan->data.Dequeue();
! 1513: data = vm_phys_write_16(chan->mar, data);
! 1514: break;
! 1515: case WR_D8:
! 1516: data = chan->data.Dequeue();
! 1517: data = vm_phys_write_8(chan->dar, data);
! 1518: break;
! 1519: case WR_D16:
! 1520: data = chan->data.Dequeue() << 8;
! 1521: data |= chan->data.Dequeue();
! 1522: data = vm_phys_write_16(chan->dar, data);
! 1523: break;
! 1524: case NOP:
! 1525: break;
! 1526: default:
! 1527: __unreachable();
! 1528: }
! 1529:
! 1530: // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ
! 1531: switch (op) {
! 1532: case RD_D8:
! 1533: case RD_D16:
! 1534: case WR_D8:
! 1535: case WR_D16:
! 1536: NegateACK(chan);
! 1537: break;
! 1538: default:
! 1539: break;
! 1540: }
! 1541:
! 1542: // バスエラーか。ACK を下ろした後で行う。
! 1543: if ((int64)data < 0) {
! 1544: TransferError(chan, op, data);
! 1545: return;
! 1546: }
! 1547:
! 1548: // 読み込んだデータをキューに投入。バスエラー判定後に行う。
! 1549: switch (op) {
! 1550: case RD_M8:
! 1551: case RD_D8:
! 1552: chan->data.Enqueue(data);
! 1553: break;
! 1554: case RD_M16:
! 1555: case RD_D16:
! 1556: chan->data.Enqueue(data >> 8);
! 1557: chan->data.Enqueue(data & 0xff);
! 1558: break;
! 1559: default:
! 1560: break;
! 1561: }
! 1562:
! 1563: // カウンタを更新。バスエラー判定後に行う。
! 1564: switch (op) {
! 1565: case RD_M8:
! 1566: case WR_M8:
! 1567: chan->mar += chan->mac;
! 1568: break;
! 1569: case RD_M16:
! 1570: case WR_M16:
! 1571: chan->mar += chan->mac * 2;
! 1572: break;
! 1573: case RD_D8:
! 1574: case WR_D8:
! 1575: chan->dar += chan->dac * 2;
! 1576: break;
! 1577: case RD_D16:
! 1578: case WR_D16:
! 1579: chan->dar += chan->dac * 2;
! 1580: break;
! 1581: case NOP:
! 1582: break;
! 1583: default:
! 1584: __unreachable();
! 1585: }
! 1586:
! 1587: // シーケンス完了で MTC の転送1回分
! 1588: if (++chan->seq_index >= chan->seq.size()) {
! 1589: chan->mtc -= 1;
! 1590:
! 1591: // すべての転送完了か
! 1592: if (__predict_false(chan->mtc == 0)) {
! 1593: chan->csr |= DMAC::CSR_COC;
! 1594: chan->active = false;
! 1595: ChangeInterrupt();
! 1596: }
! 1597:
! 1598: // XXX ディレイはあとから見直す
! 1599: CallAfter(StartCallback, 4);
! 1600: } else {
! 1601: // XXX ディレイはあとから見直す
! 1602: CallAfter(TransferCallback, 4);
! 1603: }
1.1.1.10 root 1604: }
1605:
1606: // 転送エラー
1607: void
1.1.1.11! root 1608: DMACDevice::TransferError(DMACChan *chan, int op, uint64 r)
1.1.1.10 root 1609: {
1610: if ((int64)r == -2) {
1611: // DTACK が出ていない (SPC)。
1612: // 本当は DTACK が出たことをコールバックしてくれれば
1613: // 効率がいいのだがポーリングでもかまわんだろう。
1.1.1.11! root 1614: chan->retry++;
! 1615: putlog(4, "retry=%d", chan->retry);
! 1616: if (chan->retry < 100) {
1.1.1.10 root 1617: // 現在のイベントを再実行
1618: event.time = 1 * 80_nsec;
1619: gScheduler->StartEvent(event);
1620: return;
1621: }
1622: // タイムアウトしたらバスエラーにフォールスルー
1623: }
1624:
1625: // バスエラー
1.1.1.11! root 1626: switch (op) {
! 1627: case RD_M8:
! 1628: case RD_M16:
! 1629: case WR_M8:
! 1630: case WR_M16:
! 1631: Error(chan, DMAC::CER_BUS_MAR);
! 1632: break;
! 1633: case RD_D8:
! 1634: case RD_D16:
! 1635: case WR_D8:
! 1636: case WR_D16:
! 1637: Error(chan, DMAC::CER_BUS_DAR);
! 1638: break;
! 1639: default:
! 1640: __unreachable();
! 1641: }
! 1642: }
! 1643:
! 1644: // エラー発生
! 1645: void
! 1646: DMACDevice::Error(DMACChan *chan, uint8 errcode)
! 1647: {
! 1648: // データシート p.43
! 1649: chan->cer = errcode;
! 1650: chan->csr |= DMAC::CSR_COC | DMAC::CSR_ERR;
! 1651: chan->active = false;
! 1652: chan->str = false;
! 1653: chan->cnt = false;
1.1.1.10 root 1654: ChangeInterrupt();
1655: CallAfter(StartCallback, 0);
1656: }
1657:
1.1.1.11! root 1658: // ACK#n 信号線をアサート
1.1.1.10 root 1659: void
1.1.1.11! root 1660: DMACDevice::AssertACK(DMACChan *chan)
1.1.1.10 root 1661: {
1.1.1.11! root 1662: switch (chan->ch) {
! 1663: case 0:
! 1664: gFDC->AssertDACK(chan->mtc == 1);
! 1665: break;
! 1666: case 1:
! 1667: // 接続されていない
! 1668: break;
! 1669: case 3:
! 1670: gADPCM->AssertDACK(chan->mtc == 1);
1.1.1.10 root 1671: break;
1672: default:
1.1.1.11! root 1673: VMPANIC("未実装");
1.1.1.10 root 1674: }
1.1.1.11! root 1675: }
1.1.1.10 root 1676:
1.1.1.11! root 1677: // ACK#n 信号線をネゲート
! 1678: void
! 1679: DMACDevice::NegateACK(DMACChan *chan)
! 1680: {
! 1681: switch (chan->ch) {
! 1682: case 0:
! 1683: gFDC->NegateDACK();
! 1684: break;
! 1685: case 1:
! 1686: // 接続されていない
! 1687: break;
! 1688: case 3:
! 1689: gADPCM->NegateDACK();
! 1690: break;
! 1691: default:
! 1692: VMPANIC("未実装");
1.1.1.10 root 1693: }
1694: }
1.1.1.2 root 1695:
1.1.1.11! root 1696: // REQ#n 信号線アサート (外部から呼ばれる)
1.1.1.10 root 1697: void
1.1.1.11! root 1698: DMACDevice::AssertREQ(int ch)
1.1.1.10 root 1699: {
1.1.1.11! root 1700: assert(0 <= ch && ch < 4);
1.1.1.10 root 1701:
1.1.1.11! root 1702: DMACChan *chan = &channel[ch];
! 1703: chan->req = true;
1.1.1.2 root 1704:
1.1.1.11! root 1705: // #3(ADPCM) の REQ は PCL にも繋がっている
! 1706: if (ch == 3) {
! 1707: chan->pcl_pin = true;
1.1.1.2 root 1708: }
1709:
1.1.1.11! root 1710: if (event.IsRunning() == false) {
! 1711: gScheduler->StartEvent(event);
1.1.1.2 root 1712: }
1.1.1.10 root 1713: }
1714:
1.1.1.11! root 1715: // REQ#n 信号線ネゲート (外部から呼ばれる)
1.1.1.10 root 1716: void
1.1.1.11! root 1717: DMACDevice::NegateREQ(int ch)
1.1.1.10 root 1718: {
1.1.1.11! root 1719: assert(0 <= ch && ch < 4);
1.1.1.10 root 1720:
1.1.1.11! root 1721: DMACChan *chan = &channel[ch];
! 1722: chan->req = false;
1.1.1.2 root 1723:
1.1.1.11! root 1724: // #3(ADPCM) の REQ は PCL にも繋がっている
! 1725: if (ch == 3) {
! 1726: chan->pcl_pin = false;
1.1.1.2 root 1727: }
1728: }
1729:
1730: // ソフトウェアアボート
1731: void
1.1.1.11! root 1732: DMACDevice::AbortTransfer(DMACChan *chan)
1.1.1.2 root 1733: {
1.1.1.11! root 1734: putlog(2, "CCR SAB Software Abort");
1.1.1.2 root 1735:
1736: // %1 を書き込むことで実際には SAB はセットされるが、ERR が立つと
1737: // SAB をクリアする動作のため、書き込んだ %1 が読めることはない。
1738: // ここでは SAB ビットのセットを省略。
1739:
1.1.1.11! root 1740: chan->str = false;
! 1741: chan->cnt = false;
1.1.1.10 root 1742: chan->active = false;
1.1.1.2 root 1743: chan->cer = DMAC::CER_SOFT_ABORT;
1.1.1.6 root 1744: // ERR ビットが立つと SAB をクリアする
1745: chan->csr |= DMAC::CSR_ERR;
1.1.1.11! root 1746: chan->sab = false;
1.1.1.6 root 1747: ChangeInterrupt();
1748: }
1749:
1750: // 割り込み信号線の状態を変える。
1751: void
1752: DMACDevice::ChangeInterrupt()
1753: {
1754: bool irq = false;
1755:
1.1.1.11! root 1756: for (int ch = 0; ch < channel.size(); ch++) {
! 1757: DMACChan *chan = &channel[ch];
1.1.1.6 root 1758:
1.1.1.11! root 1759: if (chan->int_enable && chan->IsINTR()) {
1.1.1.6 root 1760: irq = true;
1761: }
1762: }
1763: gInterrupt->ChangeINT(this, irq);
1764: }
1765:
1766: // 割り込みアクノリッジ
1767: int
1768: DMACDevice::InterruptAcknowledge()
1769: {
1.1.1.11! root 1770: DMACChan *chan;
1.1.1.10 root 1771: int top = -1;
1772: uint8 prio = 255;
1773:
1774: // 割り込みを発生させているトッププライオリティのチャンネルを検索
1.1.1.11! root 1775: for (int ch = 0; ch < channel.size(); ch++) {
! 1776: chan = &channel[ch];
1.1.1.6 root 1777:
1.1.1.11! root 1778: if (chan->int_enable && chan->IsINTR()) {
1.1.1.10 root 1779: if (chan->priority < prio) {
1780: prio = chan->priority;
1781: top = ch;
1.1.1.6 root 1782: }
1.1.1.10 root 1783: }
1784: }
1785:
1786: if (top >= 0) {
1.1.1.11! root 1787: chan = &channel[top];
1.1.1.10 root 1788: if ((chan->csr & DMAC::CSR_ERR)) {
1789: return chan->eiv;
1790: } else {
1791: return chan->niv;
1.1.1.6 root 1792: }
1793: }
1794: // XXX 誰もいなかったら?
1.1.1.10 root 1795: VMPANIC("InterruptAcknowledge no active channels?");
1.1.1.2 root 1796: }
1.1.1.11! root 1797:
! 1798: //
! 1799: // チャンネル
! 1800: //
! 1801:
! 1802: // CSR を取得する
! 1803: uint8
! 1804: DMACChan::GetCSR() const
! 1805: {
! 1806: uint32 val;
! 1807:
! 1808: val = csr & 0xf0;
! 1809: if (active) {
! 1810: val |= DMAC::CSR_ACT;
! 1811: }
! 1812: // PCT は PCL が High から Low に変わるとセット
! 1813: if (pcl_prev == true && pcl_pin == false) {
! 1814: val |= DMAC::CSR_PCT;
! 1815: }
! 1816: if (pcl_pin) {
! 1817: val |= DMAC::CSR_PCS;
! 1818: }
! 1819: return val;
! 1820: }
! 1821:
! 1822: // DCR を取得する
! 1823: uint8
! 1824: DMACChan::GetDCR() const
! 1825: {
! 1826: uint8 val;
! 1827:
! 1828: val = (xrm << 6);
! 1829: val |= (dtyp << 4);
! 1830: val |= (dps << 3);
! 1831: val |= dcr_pcl;
! 1832:
! 1833: return val;
! 1834: }
! 1835:
! 1836: // DCR を設定する
! 1837: void
! 1838: DMACChan::SetDCR(uint8 val)
! 1839: {
! 1840: xrm = (val >> 6);
! 1841: dtyp = (val >> 4) & 3;
! 1842: dps = (val >> 3) & 1;
! 1843: dcr_pcl = val & 3;
! 1844: }
! 1845:
! 1846: // OCR を取得する
! 1847: uint8
! 1848: DMACChan::GetOCR() const
! 1849: {
! 1850: uint8 val;
! 1851:
! 1852: val = (dir << 7);
! 1853: val |= (size << 4);
! 1854: val |= (chain << 2);
! 1855: val |= reqg;
! 1856:
! 1857: return val;
! 1858: }
! 1859:
! 1860: // OCR を設定する
! 1861: void
! 1862: DMACChan::SetOCR(uint8 val)
! 1863: {
! 1864: dir = (val >> 7);
! 1865: size = (val >> 4) & 3;
! 1866: chain = (val >> 2) & 3;
! 1867: reqg = val & 3;
! 1868: }
! 1869:
! 1870: // SCR を取得する
! 1871: uint8
! 1872: DMACChan::GetSCR() const
! 1873: {
! 1874: uint8 val;
! 1875:
! 1876: val = scr_mac << 2;
! 1877: val |= scr_dac;
! 1878:
! 1879: return val;
! 1880: }
! 1881:
! 1882: // SCR を設定する
! 1883: void
! 1884: DMACChan::SetSCR(uint8 val)
! 1885: {
! 1886: scr_mac = (val >> 2) & 3;
! 1887: scr_dac = val & 3;
! 1888: }
! 1889:
! 1890: // CCR を取得する
! 1891: uint8
! 1892: DMACChan::GetCCR() const
! 1893: {
! 1894: uint8 val = 0;
! 1895:
! 1896: if (str) {
! 1897: val |= DMAC::CCR_STR;
! 1898: }
! 1899: if (cnt) {
! 1900: val |= DMAC::CCR_CNT;
! 1901: }
! 1902: if (hlt) {
! 1903: val |= DMAC::CCR_HLT;
! 1904: }
! 1905: if (sab) {
! 1906: val |= DMAC::CCR_SAB;
! 1907: }
! 1908: if (int_enable) {
! 1909: val |= DMAC::CCR_INT;
! 1910: }
! 1911:
! 1912: return val;
! 1913: }
! 1914:
! 1915: // CCR を設定する (値を置く以上のことはしない)
! 1916: void
! 1917: DMACChan::SetCCR(uint8 val)
! 1918: {
! 1919: str = (val & DMAC::CCR_STR);
! 1920: cnt = (val & DMAC::CCR_CNT);
! 1921: hlt = (val & DMAC::CCR_HLT);
! 1922: sab = (val & DMAC::CCR_SAB);
! 1923: int_enable = (val & DMAC::CCR_INT);
! 1924: }
! 1925:
! 1926: // NIV を設定する
! 1927: void
! 1928: DMACChan::SetNIV(uint8 val)
! 1929: {
! 1930: niv = val;
! 1931: }
! 1932:
! 1933: // EIV を設定する
! 1934: void
! 1935: DMACChan::SetEIV(uint8 val)
! 1936: {
! 1937: eiv = val;
! 1938: }
! 1939:
! 1940: // MFC を設定する
! 1941: void
! 1942: DMACChan::SetMFC(uint8 val)
! 1943: {
! 1944: mfc = val & 0x07;
! 1945: }
! 1946:
! 1947: // CPR を設定する
! 1948: void
! 1949: DMACChan::SetCPR(uint8 val)
! 1950: {
! 1951: cpr = val & 0x03;
! 1952: // 実効プライオリティの上位4bitは cpr に等しい
! 1953: priority = cpr << 4;
! 1954: }
! 1955:
! 1956: // DFC を設定する
! 1957: void
! 1958: DMACChan::SetDFC(uint8 val)
! 1959: {
! 1960: dfc = val & 0x07;
! 1961: }
! 1962:
! 1963: // BFC を設定する
! 1964: void
! 1965: DMACChan::SetBFC(uint8 val)
! 1966: {
! 1967: bfc = val & 0x07;
! 1968: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.