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