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