|
|
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.15 root 16: #include "monitor.h"
1.1.1.10 root 17: #include "mpu.h"
18: #include "scheduler.h"
1.1.1.16! root 19: #include "syncer.h"
1.1.1.10 root 20:
21: // time 時間後に呼び出すコールバックをセットする。
22: // func の書式が面倒なのを省略して書きたいため。
1.1.1.13 root 23: #define CallAfter(func_, time_, wait_) do { \
1.1.1.10 root 24: event.func = ToEventCallback(&DMACDevice::func_); \
1.1.1.13 root 25: event.time = time_ * 80_nsec + wait_; \
1.1.1.12 root 26: scheduler->StartEvent(event); \
1.1.1.10 root 27: } while (0)
1.1.1.2 root 28:
1.1.1.13 root 29: // InsideOut p.135
30: static const busdata read_wait = busdata::Wait(37 * 40_nsec);
31: static const busdata write_wait = busdata::Wait(31 * 40_nsec);
32:
1.1.1.10 root 33: // コンストラクタ
1.1 root 34: DMACDevice::DMACDevice()
1.1.1.12 root 35: : inherited(OBJ_DMAC)
1.1 root 36: {
1.1.1.11 root 37: for (int i = 0; i < channel.size(); i++) {
38: channel[i].ch = i;
39: }
40: channel[0].desc = "FD";
41: channel[1].desc = "HD";
42: channel[2].desc = "User";
43: channel[3].desc = "ADPCM";
44:
45: // PCL 信号線
46: // #0 はスーパーインポーズしてなければ常に Low
47: channel[0].pcl_pin = false;
48: channel[0].pcl_prev = false;
49: // #1 はプルアップされているので常に High
50: channel[1].pcl_pin = true;
51: channel[1].pcl_prev = true;
52: // #2 は外部スロット用だが未接続なので High
53: channel[2].pcl_pin = true;
54: channel[2].pcl_prev = true;
55: // #3 は未対応
1.1.1.2 root 56:
1.1.1.15 root 57: monitor = gMonitorManager->Regist(ID_MONITOR_DMAC, this);
58: monitor->func = ToMonitorCallback(&DMACDevice::MonitorUpdate);
59: monitor->SetSize(80, 34);
1.1 root 60: }
61:
1.1.1.10 root 62: // デストラクタ
1.1 root 63: DMACDevice::~DMACDevice()
64: {
1.1.1.12 root 65: }
66:
67: // 初期化
68: bool
69: DMACDevice::Init()
70: {
71: adpcm = GetADPCMDevice();
72: fdc = GetFDCDevice();
73: interrupt = GetInterruptDevice();
74: mainbus = GetMainbusDevice();
1.1.1.16! root 75: syncer = GetSyncer();
1.1.1.12 root 76:
1.1.1.14 root 77: event.SetName("DMAC");
78: scheduler->RegistEvent(event);
79:
1.1.1.12 root 80: return true;
1.1 root 81: }
82:
1.1.1.10 root 83: // リセット
1.1.1.5 root 84: void
1.1.1.10 root 85: DMACDevice::ResetHard(bool poweron)
1.1.1.5 root 86: {
1.1.1.11 root 87: putlog(2, "Reset");
1.1.1.5 root 88:
89: // Clears GCR, DCR, OCR, SCR, CCR, CSR, CPR and CER for all channels.
90: // NIV and EIV are all set to $0F (uninitialized interrupt vector).
91: // MTC, MAR, DAR, BTC, BAR, MFC, DFC and BFC are not affected.
92:
1.1.1.14 root 93: // 電源オン時、少なくとも BFC は $07 のようだ
94: // (X68030 IPLROM が #0, #1 の BFC を初期化していないので読める)。
95: // MFC、DFC くらいは同様かも知れない。
96: if (poweron) {
97: for (int ch = 0; ch < channel.size(); ch++) {
98: DMACChan *chan = &channel[ch];
99: chan->SetMFC(0x07);
100: chan->SetDFC(0x07);
101: chan->SetBFC(0x07);
102: }
103: }
104:
1.1.1.11 root 105: gcr = 0;
106: for (int ch = 0; ch < channel.size(); ch++) {
107: DMACChan *chan = &channel[ch];
108: chan->SetDCR(0);
109: chan->SetOCR(0);
110: chan->SetSCR(0);
111: chan->SetCCR(0);
1.1.1.5 root 112: chan->csr = 0;
113: chan->active = false;
114: chan->cpr = 0;
115: chan->cer = 0;
116:
117: chan->niv = 0x0f;
118: chan->eiv = 0x0f;
119:
1.1.1.10 root 120: chan->priority = 0;
1.1.1.5 root 121: }
1.1.1.16! root 122: syncer->RequestDMACActive(false);
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.16! root 1047: // CSR.ACT ビットの状態を変更。
! 1048: void
! 1049: DMACDevice::ChangeACT(DMACChan *chan, bool active)
! 1050: {
! 1051: chan->active = active;
! 1052:
! 1053: // チャンネルの ACT を変更した結果、
! 1054: // トータルでアクティブかどうかを Syncer に通知する。
! 1055: bool dmac_active =
! 1056: channel[0].active ||
! 1057: channel[1].active ||
! 1058: channel[2].active ||
! 1059: channel[3].active;
! 1060: syncer->RequestDMACActive(dmac_active);
! 1061: }
! 1062:
1.1.1.11 root 1063: // 転送開始
1.1.1.2 root 1064: void
1.1.1.14 root 1065: DMACDevice::StartTransfer(DMACChan *chan)
1.1.1.2 root 1066: {
1.1.1.11 root 1067: // Operation Timing Error (ii)
1068: // CSR の ACT,COC,BTC,NDT,ERR が立ってたら開始しない
1069: if (chan->active || (chan->csr & 0xf0) != 0) {
1070: Error(chan, DMAC::CER_TIMING);
1.1.1.2 root 1071: return;
1072: }
1073:
1.1.1.11 root 1074: // ACT を立てたら STR を下げる。
1.1.1.16! root 1075: ChangeACT(chan, true);
1.1.1.11 root 1076: chan->str = false;
1.1.1.2 root 1077:
1.1.1.11 root 1078: // XXX あとで移動する
1079: switch (chan->GetMAC()) {
1080: case DMAC::SCR_COUNT_UP:
1081: chan->mac = 1;
1082: break;
1083: case DMAC::SCR_COUNT_DOWN:
1084: putlog(0, "SCR:MAC CountDown Mode (NOT SUPPORTED)");
1085: chan->mac = -1;
1086: break;
1087: default:
1088: chan->mac = 0;
1089: break;
1090: }
1091: switch (chan->GetDAC()) {
1092: case DMAC::SCR_COUNT_UP:
1093: chan->dac = 1;
1094: break;
1095: case DMAC::SCR_COUNT_DOWN:
1096: putlog(0, "SCR:DAC CountDown Mode (NOT SUPPORTED)");
1097: chan->dac = -1;
1098: break;
1099: default:
1100: chan->dac = 0;
1101: break;
1102: }
1.1.1.2 root 1103:
1.1.1.11 root 1104: chan->data.Clear();
1.1.1.2 root 1105:
1106: // 転送モード
1.1.1.12 root 1107: uint reqg = chan->GetREQG();
1108: switch (reqg) {
1.1.1.11 root 1109: case DMAC::REQG_AUTO_LIM:
1.1.1.10 root 1110: VMPANIC("REQG_AUTO_LIM 未実装");
1.1.1.2 root 1111: break;
1112:
1.1.1.11 root 1113: case DMAC::REQG_AUTO_MAX:
1.1.1.2 root 1114: // 自発的に転送を開始する
1.1.1.11 root 1115: chan->req = true;
1116: break;
1117:
1118: case DMAC::REQG_EXTERNAL:
1119: // 外部リクエスト転送。ここでは何もしなくてよい
1.1.1.2 root 1120: break;
1121:
1.1.1.11 root 1122: case DMAC::REQG_AUTOFIRST:
1.1.1.10 root 1123: VMPANIC("未実装 REQG");
1.1.1.2 root 1124: break;
1125:
1126: default:
1.1.1.14 root 1127: VMPANIC("corrupted reqg=%u", reqg);
1.1.1.2 root 1128: }
1129:
1.1.1.11 root 1130: // 転送開始ログ。全パラメータは無理なので概要だけ表示。
1131: if (loglevel >= 1) {
1.1.1.14 root 1132: static const char * const countstr[] = {
1133: "-",
1134: "",
1135: "+",
1136: };
1.1.1.11 root 1137: std::string msg;
1138: if (chan->GetDIR() == DMAC::DIR_MtoD) {
1.1.1.14 root 1139: msg = string_format("$%06x%s to $%06x%s",
1140: chan->mar, countstr[chan->mac + 1],
1141: chan->dar, countstr[chan->dac + 1]);
1.1.1.11 root 1142: } else {
1.1.1.14 root 1143: msg = string_format("$%06x%s to $%06x%s",
1144: chan->dar, countstr[chan->dac + 1],
1145: chan->mar, countstr[chan->mac + 1]);
1.1.1.11 root 1146: }
1.1.1.14 root 1147: putlogn("#%u Start %s mtc=$%04x", chan->ch, msg.c_str(), chan->mtc);
1.1.1.11 root 1148: }
1149:
1.1.1.10 root 1150: if (event.IsRunning() == false) {
1.1.1.13 root 1151: CallAfter(StartCallback, 0, 0);
1.1.1.10 root 1152: }
1.1.1.5 root 1153: }
1154:
1.1.1.11 root 1155: // 今回転送するチャンネルを決定して返す。なければ NULL を返す。
1156: DMACChan *
1157: DMACDevice::SelectChannel()
1.1.1.2 root 1158: {
1.1.1.11 root 1159: DMACChan *chan;
1.1.1.10 root 1160: int ch = -1;
1161: uint8 prio = 255;
1.1.1.11 root 1162:
1163: for (int i = 0; i < channel.size(); i++) {
1164: chan = &channel[i];
1165: if (chan->active && (chan->req || chan->seq_index < chan->seq.size())) {
1.1.1.10 root 1166: uint8 p = chan->priority;
1167: if (p < prio) {
1168: prio = p;
1169: // 実効プライオリティのラウンドロビン用のところを上げておく
1170: chan->priority = (p & 0xf0) | ((p & 0x0f) >> 1);
1171: ch = i;
1172: }
1173: }
1174: }
1175: if (ch == -1) {
1176: // 転送チャンネルはもうないのでイベントは停止したままにする
1177: event.SetName("DMAC");
1.1.1.11 root 1178: return NULL;
1179: } else {
1180: chan = &channel[ch];
1.1.1.14 root 1181: event.SetName(string_format("DMAC #%u", chan->ch));
1.1.1.11 root 1182: return chan;
1183: }
1184: }
1185:
1186: // 転送開始
1187: void
1188: DMACDevice::StartCallback(Event& ev)
1189: {
1190: // チャンネルを決定
1191: auto chan = SelectChannel();
1192: if (chan == NULL) {
1.1.1.10 root 1193: return;
1194: }
1.1.1.2 root 1195:
1.1.1.10 root 1196: // 実効プライオリティを同順位の最後に回す
1.1.1.11 root 1197: chan->priority |= 0x08;
1.1.1.2 root 1198:
1.1.1.11 root 1199: chan->retry = 0;
1.1.1.10 root 1200:
1201: // XXX バスアービトレーションとか
1202:
1.1.1.11 root 1203: // 転送シーケンス決定
1204: chan->seq.clear();
1205: chan->seq_index = 0;
1206: if (chan->GetDIR() == DMAC::DIR_MtoD) {
1207: if (chan->GetDPS() == DMAC::DPS_8BIT) {
1208: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
1209: chan->seq.push_back(RD_M16);
1210: chan->seq.push_back(WR_D8);
1211: chan->seq.push_back(WR_D8);
1212: chan->seq.push_back(RD_M16);
1213: chan->seq.push_back(WR_D8);
1214: chan->seq.push_back(WR_D8);
1215: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
1216: chan->seq.push_back(RD_M16);
1217: chan->seq.push_back(WR_D8);
1218: chan->seq.push_back(WR_D8);
1219: } else {
1220: chan->seq.push_back(RD_M8);
1221: chan->seq.push_back(WR_D8);
1222: }
1223: } else {
1224: // DPS==16
1225: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
1226: chan->seq.push_back(RD_M16);
1227: chan->seq.push_back(WR_D16);
1228: chan->seq.push_back(RD_M16);
1229: chan->seq.push_back(WR_D16);
1230: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
1231: chan->seq.push_back(RD_M16);
1232: chan->seq.push_back(WR_D16);
1233: } else {
1234: chan->seq.push_back(RD_M8);
1235: chan->seq.push_back(WR_D8);
1236: }
1237: }
1238: } else { // DtoM
1239: if (chan->GetDPS() == DMAC::DPS_8BIT) {
1240: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
1241: chan->seq.push_back(RD_D8);
1242: chan->seq.push_back(RD_D8);
1243: chan->seq.push_back(WR_M16);
1244: chan->seq.push_back(RD_D8);
1245: chan->seq.push_back(RD_D8);
1246: chan->seq.push_back(WR_M16);
1247: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
1248: chan->seq.push_back(RD_D8);
1249: chan->seq.push_back(RD_D8);
1250: chan->seq.push_back(WR_M16);
1251: } else {
1252: chan->seq.push_back(RD_D8);
1253: chan->seq.push_back(WR_M8);
1254: }
1255: } else {
1256: // DPS==16
1257: if (chan->GetSIZE() == DMAC::SIZE_32BIT) {
1258: chan->seq.push_back(RD_D16);
1259: chan->seq.push_back(WR_M16);
1260: chan->seq.push_back(RD_D16);
1261: chan->seq.push_back(WR_M16);
1262: } else if (chan->GetSIZE() == DMAC::SIZE_16BIT) {
1263: chan->seq.push_back(RD_D16);
1264: chan->seq.push_back(WR_M16);
1265: } else {
1266: chan->seq.push_back(RD_D8);
1267: chan->seq.push_back(WR_M8);
1268: }
1269: }
1270: }
1271:
1.1.1.14 root 1272: if (__predict_false(loglevel >= 5)) {
1273: std::string ss;
1274: for (const auto op : chan->seq) {
1275: ss += ' ';
1276: ss += seqname[op];
1277: }
1278: putlogn("#%u %s seq:%s", chan->ch, __func__, ss.c_str());
1279: }
1280:
1.1.1.13 root 1281: CallAfter(TransferCallback, 1, 0);
1.1.1.11 root 1282: }
1283:
1284: // 転送処理
1285: void
1286: DMACDevice::TransferCallback(Event& ev)
1287: {
1288: // チャンネルを決定
1289: auto chan = SelectChannel();
1290: if (chan == NULL) {
1291: return;
1292: }
1293:
1.1.1.14 root 1294: uint op = chan->seq[chan->seq_index];
1295: putlog(5, "#%u %s [%u] %s",
1296: chan->ch, __func__, chan->seq_index, seqname[op]);
1297:
1.1.1.11 root 1298: uint64 data;
1.1.1.13 root 1299: busdata r;
1.1.1.11 root 1300:
1301: // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ
1302: switch (op) {
1303: case RD_D8:
1304: case RD_D16:
1305: case WR_D8:
1306: case WR_D16:
1307: AssertACK(chan);
1308: break;
1309: default:
1310: break;
1311: }
1312:
1313: // パック動作が起きるケースなら op を差し替える。
1314: if (chan->GetSIZE() == DMAC::SIZE_8BIT_PACK) {
1315: if (op == RD_M8) {
1316: if (chan->mtc > 1 && chan->mar % 2 == 0 && chan->GetMAC() != 0) {
1317: if (chan->data.Length() == 0) {
1318: op = RD_M16;
1319: } else {
1320: op = NOP;
1321: }
1322: }
1323: }
1324: if (op == WR_M8) {
1325: if (chan->data.Length() >= 2) {
1326: op = WR_M16;
1327: } else {
1328: if (chan->mtc > 1 && chan->mar % 2 == 0 && chan->GetMAC() != 0){
1329: op = NOP;
1330: }
1331: }
1332: }
1333: }
1334:
1.1.1.13 root 1335: // アドレスを生成。
1336: busaddr addr;
1.1.1.11 root 1337: switch (op) {
1338: case RD_M8:
1339: case RD_M16:
1.1.1.13 root 1340: case WR_M8:
1341: case WR_M16:
1.1.1.14 root 1342: addr = busaddr(chan->mar) | chan->mfc;
1.1.1.11 root 1343: break;
1344: case RD_D8:
1345: case RD_D16:
1.1.1.13 root 1346: case WR_D8:
1347: case WR_D16:
1.1.1.14 root 1348: addr = busaddr(chan->dar) | chan->dfc;
1.1.1.11 root 1349: break;
1.1.1.13 root 1350: default:
1.1.1.11 root 1351: break;
1.1.1.13 root 1352: }
1353:
1.1.1.14 root 1354: // サイズを指定。
1355: switch (op) {
1356: case RD_M8:
1357: case RD_D8:
1358: case WR_M8:
1359: case WR_D8:
1360: addr.ChangeSize(1);
1361: break;
1362: case RD_M16:
1363: case RD_D16:
1364: case WR_M16:
1365: case WR_D16:
1366: addr.ChangeSize(2);
1367: break;
1368: default:
1369: break;
1370: }
1371:
1372:
1.1.1.13 root 1373: // 書き込みならキューからデータを取得。
1374: switch (op) {
1375: case WR_M8:
1.1.1.11 root 1376: case WR_D8:
1377: data = chan->data.Dequeue();
1378: break;
1.1.1.13 root 1379: case WR_M16:
1.1.1.11 root 1380: case WR_D16:
1381: data = chan->data.Dequeue() << 8;
1382: data |= chan->data.Dequeue();
1383: break;
1384: default:
1.1.1.13 root 1385: data = 0;
1386: break;
1387: }
1388:
1389: // ユーザ空間へのアクセスが可能かどうかここで調べる。
1390: // 本来は DMAC ではなくメインバスで管理すべきことだが、パフォーマンスの
1391: // 観点から MPU 側に FC2 カットによる可動部を増やしたくないので、
1392: // アクセス頻度の低い DMAC 側で肩代わりしている。
1.1.1.14 root 1393: bool accessible =
1394: __predict_true(addr.IsSuper() || useraccess[addr.Addr() / 0x2000]);
1395:
1396: // 1回分のアクセス。
1397: switch (op) {
1398: case RD_M8:
1399: case RD_D8:
1400: case RD_M16:
1401: case RD_D16:
1402: if (accessible) {
1403: r = mainbus->Read(addr);
1404: // IODevice からの読み込みはポートサイズ単位で行う仕様なので、
1405: // ここでダイナミックバスサイジングの要領で必要な部分を抜き出す。
1406: // 実際の HD63450 は 68000 バス用のデバイスなので、このあたりの
1407: // バス変換を YUKI ちゃんなどの周辺回路がやってるはず。
1408: data = MainbusDevice::DYNAMIC_BUS_SIZING_R(addr, r);
1409: r.ChangeData(data);
1410: } else {
1411: r.SetBusErr();
1412: }
1413: break;
1414: case WR_M8:
1415: case WR_D8:
1416: case WR_M16:
1417: case WR_D16:
1418: if (accessible) {
1419: r = mainbus->Write(addr, data);
1420: } else {
1421: r.SetBusErr();
1.1.1.13 root 1422: }
1.1.1.14 root 1423: break;
1424: case NOP:
1425: r = 0;
1426: break;
1427: default:
1428: VMPANIC("corrupted op=%u", op);
1.1.1.13 root 1429: }
1.1.1.14 root 1430:
1.1.1.13 root 1431: if (__predict_false(loglevel >= 4)) {
1432: TransferLog(chan, op, addr, r, data);
1.1.1.11 root 1433: }
1434:
1435: // デバイスアクセスなら ACK#n 信号と DONE 信号のドライブ
1436: switch (op) {
1437: case RD_D8:
1438: case RD_D16:
1439: case WR_D8:
1440: case WR_D16:
1441: NegateACK(chan);
1442: break;
1443: default:
1444: break;
1445: }
1446:
1.1.1.13 root 1447: // バスエラー(もしくはリトライ)か。ACK を下ろした後で行う。
1448: if (r.IsOK() == false) {
1449: TransferError(chan, op, r, data);
1.1.1.11 root 1450: return;
1451: }
1452:
1453: // 読み込んだデータをキューに投入。バスエラー判定後に行う。
1454: switch (op) {
1455: case RD_M8:
1456: case RD_D8:
1.1.1.13 root 1457: chan->data.Enqueue(r.Data());
1.1.1.11 root 1458: break;
1459: case RD_M16:
1460: case RD_D16:
1.1.1.13 root 1461: chan->data.Enqueue(r.Data() >> 8);
1462: chan->data.Enqueue(r.Data() & 0xff);
1.1.1.11 root 1463: break;
1464: default:
1465: break;
1466: }
1467:
1468: // カウンタを更新。バスエラー判定後に行う。
1469: switch (op) {
1470: case RD_M8:
1471: case WR_M8:
1472: chan->mar += chan->mac;
1473: break;
1474: case RD_M16:
1475: case WR_M16:
1476: chan->mar += chan->mac * 2;
1477: break;
1478: case RD_D8:
1479: case WR_D8:
1480: chan->dar += chan->dac * 2;
1481: break;
1482: case RD_D16:
1483: case WR_D16:
1484: chan->dar += chan->dac * 2;
1485: break;
1486: case NOP:
1487: break;
1488: default:
1.1.1.14 root 1489: VMPANIC("corrupted op=%u", op);
1.1.1.11 root 1490: }
1491:
1492: // シーケンス完了で MTC の転送1回分
1493: if (++chan->seq_index >= chan->seq.size()) {
1494: chan->mtc -= 1;
1495:
1496: // すべての転送完了か
1497: if (__predict_false(chan->mtc == 0)) {
1498: chan->csr |= DMAC::CSR_COC;
1.1.1.16! root 1499: ChangeACT(chan, false);
1.1.1.11 root 1500: ChangeInterrupt();
1501: }
1502:
1503: // XXX ディレイはあとから見直す
1.1.1.13 root 1504: CallAfter(StartCallback, 4, r.GetWait());
1.1.1.11 root 1505: } else {
1506: // XXX ディレイはあとから見直す
1.1.1.13 root 1507: CallAfter(TransferCallback, 4, r.GetWait());
1.1.1.11 root 1508: }
1.1.1.10 root 1509: }
1510:
1511: // 転送エラー
1512: void
1.1.1.14 root 1513: DMACDevice::TransferError(DMACChan *chan, uint op, busdata r, uint32 data)
1.1.1.10 root 1514: {
1.1.1.13 root 1515: if (r.IsRetry()) {
1.1.1.10 root 1516: // DTACK が出ていない (SPC)。
1517: // 本当は DTACK が出たことをコールバックしてくれれば
1518: // 効率がいいのだがポーリングでもかまわんだろう。
1.1.1.11 root 1519: chan->retry++;
1520: if (chan->retry < 100) {
1.1.1.13 root 1521: // 書き込みがリトライになったら仕方ないので、今書こうとして
1522: // 取り出したデータをキューに戻してから再実行。うーんこの。
1523: switch (op) {
1524: case WR_M8:
1525: case WR_D8:
1526: chan->data.PushFront(data);
1527: break;
1528: case WR_M16:
1529: case WR_D16:
1530: chan->data.PushFront(data);
1531: chan->data.PushFront(data >> 8);
1532: break;
1533: default:
1534: break;
1535: }
1536:
1.1.1.10 root 1537: // 現在のイベントを再実行
1538: event.time = 1 * 80_nsec;
1.1.1.12 root 1539: scheduler->StartEvent(event);
1.1.1.10 root 1540: return;
1.1.1.13 root 1541: } else {
1542: // タイムアウトしたらバスエラーにフォールスルー
1.1.1.14 root 1543: putlog(3, "#%u retry exceeds", chan->ch);
1.1.1.10 root 1544: }
1545: }
1546:
1547: // バスエラー
1.1.1.11 root 1548: switch (op) {
1549: case RD_M8:
1550: case RD_M16:
1551: case WR_M8:
1552: case WR_M16:
1553: Error(chan, DMAC::CER_BUS_MAR);
1554: break;
1555: case RD_D8:
1556: case RD_D16:
1557: case WR_D8:
1558: case WR_D16:
1559: Error(chan, DMAC::CER_BUS_DAR);
1560: break;
1561: default:
1.1.1.14 root 1562: VMPANIC("corrupted op=%u", op);
1.1.1.11 root 1563: }
1564: }
1565:
1.1.1.13 root 1566: // 1転送ごとのログを出力。
1567: // ログを出力することが決まってから呼ばれる。
1568: void
1.1.1.14 root 1569: DMACDevice::TransferLog(DMACChan *chan, uint op, busaddr addr,
1.1.1.13 root 1570: busdata r, uint64 data)
1571: {
1.1.1.14 root 1572: // Nop
1.1.1.13 root 1573: // Read $%06x -> $xx
1574: // Read $%06x -> BusErr
1575: // Read $%06x -> $xx (1 retried)
1576: // Write $%06x <- $xx
1577: // Write $%06x <- $xx BusErr
1578: // Write $%06x <- $xx (1 retried)
1579:
1580: if (op == NOP) {
1.1.1.14 root 1581: putlogn("#%u Nop", chan->ch);
1.1.1.13 root 1582: return;
1583: }
1584:
1585: if (r.IsRetry()) {
1586: return;
1587: }
1588:
1589: const char *act;
1590: const char *dir;
1591: switch (op) {
1592: case RD_M8:
1593: case RD_D8:
1594: case RD_M16:
1595: case RD_D16:
1596: act = "Read ";
1597: dir = "->";
1598: break;
1599: case WR_M8:
1600: case WR_D8:
1601: case WR_M16:
1602: case WR_D16:
1603: act = "Write";
1604: dir = "<-";
1605: break;
1606: default:
1607: act = "";
1608: dir = "";
1609: break;
1610: }
1611:
1.1.1.14 root 1612: std::string str = string_format("#%u %s $%06x %s ",
1.1.1.13 root 1613: chan->ch, act, addr.Addr(), dir);
1614:
1615: switch (op) {
1616: case RD_M8:
1617: case RD_D8:
1618: if (r.IsOK()) {
1619: str += string_format("$%02x", r.Data());
1620: }
1621: break;
1622: case RD_M16:
1623: case RD_D16:
1624: if (r.IsOK()) {
1625: str += string_format("$%04x", r.Data());
1626: }
1627: case WR_M8:
1628: case WR_D8:
1629: str += string_format("$%02x", (uint32)data);
1630: break;
1631: case WR_M16:
1632: case WR_D16:
1633: str += string_format("$%04x", (uint32)data);
1634: break;
1635: default:
1636: break;
1637: }
1638:
1639: if (r.IsBusErr()) {
1640: str += " BusErr";
1641: }
1642:
1643: if (chan->retry != 0) {
1.1.1.14 root 1644: str += string_format(" (%u retried)", chan->retry);
1.1.1.13 root 1645: }
1646:
1647: putlogn("%s", str.c_str());
1648: }
1649:
1.1.1.11 root 1650: // エラー発生
1651: void
1652: DMACDevice::Error(DMACChan *chan, uint8 errcode)
1653: {
1654: // データシート p.43
1655: chan->cer = errcode;
1656: chan->csr |= DMAC::CSR_COC | DMAC::CSR_ERR;
1.1.1.16! root 1657: ChangeACT(chan, false);
1.1.1.11 root 1658: chan->str = false;
1659: chan->cnt = false;
1.1.1.10 root 1660: ChangeInterrupt();
1.1.1.13 root 1661: CallAfter(StartCallback, 0, 0);
1.1.1.10 root 1662: }
1663:
1.1.1.11 root 1664: // ACK#n 信号線をアサート
1.1.1.10 root 1665: void
1.1.1.11 root 1666: DMACDevice::AssertACK(DMACChan *chan)
1.1.1.10 root 1667: {
1.1.1.11 root 1668: switch (chan->ch) {
1669: case 0:
1.1.1.12 root 1670: fdc->AssertDACK(chan->mtc == 1);
1.1.1.11 root 1671: break;
1672: case 1:
1.1.1.13 root 1673: case 2:
1.1.1.11 root 1674: // 接続されていない
1675: break;
1676: case 3:
1.1.1.12 root 1677: adpcm->AssertDACK(chan->mtc == 1);
1.1.1.10 root 1678: break;
1679: default:
1.1.1.13 root 1680: __unreachable();
1.1.1.10 root 1681: }
1.1.1.11 root 1682: }
1.1.1.10 root 1683:
1.1.1.11 root 1684: // ACK#n 信号線をネゲート
1685: void
1686: DMACDevice::NegateACK(DMACChan *chan)
1687: {
1688: switch (chan->ch) {
1689: case 0:
1.1.1.12 root 1690: fdc->NegateDACK();
1.1.1.11 root 1691: break;
1692: case 1:
1.1.1.13 root 1693: case 2:
1.1.1.11 root 1694: // 接続されていない
1695: break;
1696: case 3:
1.1.1.12 root 1697: adpcm->NegateDACK();
1.1.1.11 root 1698: break;
1699: default:
1.1.1.13 root 1700: __unreachable();
1.1.1.10 root 1701: }
1702: }
1.1.1.2 root 1703:
1.1.1.11 root 1704: // REQ#n 信号線アサート (外部から呼ばれる)
1.1.1.10 root 1705: void
1.1.1.14 root 1706: DMACDevice::AssertREQ(uint ch)
1.1.1.10 root 1707: {
1.1.1.14 root 1708: assert(ch < 4);
1.1.1.10 root 1709:
1.1.1.11 root 1710: DMACChan *chan = &channel[ch];
1711: chan->req = true;
1.1.1.2 root 1712:
1.1.1.11 root 1713: // #3(ADPCM) の REQ は PCL にも繋がっている
1714: if (ch == 3) {
1715: chan->pcl_pin = true;
1.1.1.2 root 1716: }
1717:
1.1.1.11 root 1718: if (event.IsRunning() == false) {
1.1.1.12 root 1719: scheduler->StartEvent(event);
1.1.1.2 root 1720: }
1.1.1.10 root 1721: }
1722:
1.1.1.11 root 1723: // REQ#n 信号線ネゲート (外部から呼ばれる)
1.1.1.10 root 1724: void
1.1.1.14 root 1725: DMACDevice::NegateREQ(uint ch)
1.1.1.10 root 1726: {
1.1.1.14 root 1727: assert(ch < 4);
1.1.1.10 root 1728:
1.1.1.11 root 1729: DMACChan *chan = &channel[ch];
1730: chan->req = false;
1.1.1.2 root 1731:
1.1.1.11 root 1732: // #3(ADPCM) の REQ は PCL にも繋がっている
1733: if (ch == 3) {
1734: chan->pcl_pin = false;
1.1.1.2 root 1735: }
1736: }
1737:
1738: // ソフトウェアアボート
1739: void
1.1.1.11 root 1740: DMACDevice::AbortTransfer(DMACChan *chan)
1.1.1.2 root 1741: {
1.1.1.11 root 1742: putlog(2, "CCR SAB Software Abort");
1.1.1.2 root 1743:
1744: // %1 を書き込むことで実際には SAB はセットされるが、ERR が立つと
1745: // SAB をクリアする動作のため、書き込んだ %1 が読めることはない。
1746: // ここでは SAB ビットのセットを省略。
1747:
1.1.1.11 root 1748: chan->str = false;
1749: chan->cnt = false;
1.1.1.16! root 1750: ChangeACT(chan, false);
! 1751:
1.1.1.2 root 1752: chan->cer = DMAC::CER_SOFT_ABORT;
1.1.1.6 root 1753: // ERR ビットが立つと SAB をクリアする
1754: chan->csr |= DMAC::CSR_ERR;
1.1.1.11 root 1755: chan->sab = false;
1.1.1.6 root 1756: ChangeInterrupt();
1757: }
1758:
1.1.1.13 root 1759: // インデックス化されたアドレス start から end (の手前まで) のユーザ空間
1760: // アクセスの可否を設定する。x68kio から呼ばれる。
1761: // accessible true なら (MPU の FC2 ピンによらず) ユーザアクセス可能。
1762: // アドレスは 8KB 単位なので start=1 ならアドレスは $2000。
1763: void
1764: DMACDevice::SetUdevice(uint32 start, uint32 end, bool accessible)
1765: {
1766: for (int i = start; i < end; i++) {
1767: useraccess[i] = accessible;
1768: }
1769: }
1770:
1.1.1.6 root 1771: // 割り込み信号線の状態を変える。
1772: void
1773: DMACDevice::ChangeInterrupt()
1774: {
1775: bool irq = false;
1776:
1.1.1.11 root 1777: for (int ch = 0; ch < channel.size(); ch++) {
1778: DMACChan *chan = &channel[ch];
1.1.1.6 root 1779:
1.1.1.11 root 1780: if (chan->int_enable && chan->IsINTR()) {
1.1.1.6 root 1781: irq = true;
1782: }
1783: }
1.1.1.12 root 1784: interrupt->ChangeINT(this, irq);
1.1.1.6 root 1785: }
1786:
1787: // 割り込みアクノリッジ
1.1.1.13 root 1788: busdata
1.1.1.6 root 1789: DMACDevice::InterruptAcknowledge()
1790: {
1.1.1.11 root 1791: DMACChan *chan;
1.1.1.10 root 1792: int top = -1;
1793: uint8 prio = 255;
1794:
1795: // 割り込みを発生させているトッププライオリティのチャンネルを検索
1.1.1.11 root 1796: for (int ch = 0; ch < channel.size(); ch++) {
1797: chan = &channel[ch];
1.1.1.6 root 1798:
1.1.1.11 root 1799: if (chan->int_enable && chan->IsINTR()) {
1.1.1.10 root 1800: if (chan->priority < prio) {
1801: prio = chan->priority;
1802: top = ch;
1.1.1.6 root 1803: }
1.1.1.10 root 1804: }
1805: }
1806:
1.1.1.13 root 1807: if (__predict_true(top >= 0)) {
1.1.1.11 root 1808: chan = &channel[top];
1.1.1.10 root 1809: if ((chan->csr & DMAC::CSR_ERR)) {
1810: return chan->eiv;
1811: } else {
1812: return chan->niv;
1.1.1.6 root 1813: }
1.1.1.13 root 1814: } else {
1.1.1.14 root 1815: return BusData::BusErr;
1.1.1.6 root 1816: }
1.1.1.2 root 1817: }
1.1.1.11 root 1818:
1819: //
1820: // チャンネル
1821: //
1822:
1823: // CSR を取得する
1824: uint8
1825: DMACChan::GetCSR() const
1826: {
1827: uint32 val;
1828:
1829: val = csr & 0xf0;
1830: if (active) {
1831: val |= DMAC::CSR_ACT;
1832: }
1833: // PCT は PCL が High から Low に変わるとセット
1834: if (pcl_prev == true && pcl_pin == false) {
1835: val |= DMAC::CSR_PCT;
1836: }
1837: if (pcl_pin) {
1838: val |= DMAC::CSR_PCS;
1839: }
1840: return val;
1841: }
1842:
1843: // DCR を取得する
1844: uint8
1845: DMACChan::GetDCR() const
1846: {
1847: uint8 val;
1848:
1849: val = (xrm << 6);
1850: val |= (dtyp << 4);
1851: val |= (dps << 3);
1852: val |= dcr_pcl;
1853:
1854: return val;
1855: }
1856:
1857: // DCR を設定する
1858: void
1859: DMACChan::SetDCR(uint8 val)
1860: {
1861: xrm = (val >> 6);
1862: dtyp = (val >> 4) & 3;
1863: dps = (val >> 3) & 1;
1864: dcr_pcl = val & 3;
1865: }
1866:
1867: // OCR を取得する
1868: uint8
1869: DMACChan::GetOCR() const
1870: {
1871: uint8 val;
1872:
1873: val = (dir << 7);
1874: val |= (size << 4);
1875: val |= (chain << 2);
1876: val |= reqg;
1877:
1878: return val;
1879: }
1880:
1881: // OCR を設定する
1882: void
1883: DMACChan::SetOCR(uint8 val)
1884: {
1885: dir = (val >> 7);
1886: size = (val >> 4) & 3;
1887: chain = (val >> 2) & 3;
1888: reqg = val & 3;
1889: }
1890:
1891: // SCR を取得する
1892: uint8
1893: DMACChan::GetSCR() const
1894: {
1895: uint8 val;
1896:
1897: val = scr_mac << 2;
1898: val |= scr_dac;
1899:
1900: return val;
1901: }
1902:
1903: // SCR を設定する
1904: void
1905: DMACChan::SetSCR(uint8 val)
1906: {
1907: scr_mac = (val >> 2) & 3;
1908: scr_dac = val & 3;
1909: }
1910:
1911: // CCR を取得する
1912: uint8
1913: DMACChan::GetCCR() const
1914: {
1915: uint8 val = 0;
1916:
1917: if (str) {
1918: val |= DMAC::CCR_STR;
1919: }
1920: if (cnt) {
1921: val |= DMAC::CCR_CNT;
1922: }
1923: if (hlt) {
1924: val |= DMAC::CCR_HLT;
1925: }
1926: if (sab) {
1927: val |= DMAC::CCR_SAB;
1928: }
1929: if (int_enable) {
1930: val |= DMAC::CCR_INT;
1931: }
1932:
1933: return val;
1934: }
1935:
1936: // CCR を設定する (値を置く以上のことはしない)
1937: void
1938: DMACChan::SetCCR(uint8 val)
1939: {
1940: str = (val & DMAC::CCR_STR);
1941: cnt = (val & DMAC::CCR_CNT);
1942: hlt = (val & DMAC::CCR_HLT);
1943: sab = (val & DMAC::CCR_SAB);
1944: int_enable = (val & DMAC::CCR_INT);
1945: }
1946:
1947: // NIV を設定する
1948: void
1949: DMACChan::SetNIV(uint8 val)
1950: {
1951: niv = val;
1952: }
1953:
1954: // EIV を設定する
1955: void
1956: DMACChan::SetEIV(uint8 val)
1957: {
1958: eiv = val;
1959: }
1960:
1961: // MFC を設定する
1962: void
1963: DMACChan::SetMFC(uint8 val)
1964: {
1.1.1.13 root 1965: mfc = busaddr::FC(val & 0x07);
1.1.1.11 root 1966: }
1967:
1968: // CPR を設定する
1969: void
1970: DMACChan::SetCPR(uint8 val)
1971: {
1972: cpr = val & 0x03;
1973: // 実効プライオリティの上位4bitは cpr に等しい
1974: priority = cpr << 4;
1975: }
1976:
1977: // DFC を設定する
1978: void
1979: DMACChan::SetDFC(uint8 val)
1980: {
1.1.1.13 root 1981: dfc = busaddr::FC(val & 0x07);
1.1.1.11 root 1982: }
1983:
1984: // BFC を設定する
1985: void
1986: DMACChan::SetBFC(uint8 val)
1987: {
1.1.1.13 root 1988: bfc = busaddr::FC(val & 0x07);
1.1.1.11 root 1989: }
1.1.1.14 root 1990:
1991: // レジスタ名 (バイト)
1992: /*static*/ const char * const
1993: DMACDevice::regname1[0x40] = {
1994: "CSR", // 00
1995: "CER", // 01
1996: NULL, // 02
1997: NULL, // 03
1998: "DCR", // 04
1999: "OCR", // 05
2000: "SCR", // 06
2001: "CCR", // 07
2002: NULL, // 08
2003: NULL, // 09
2004: "MTC:H", // 0a
2005: "MTC:L", // 0b
2006: "MAR:0", // 0c
2007: "MAR:1", // 0d
2008: "MAR:2", // 0e
2009: "MAR:3", // 0f
2010: NULL, // 10
2011: NULL, // 11
2012: NULL, // 12
2013: NULL, // 13
2014: "DAR:0", // 14
2015: "DAR:1", // 15
2016: "DAR:2", // 16
2017: "DAR:3", // 17
2018: NULL, // 18
2019: NULL, // 19
2020: "BTC:H", // 1a
2021: "BTC:L", // 1b
2022: "BAR:0", // 1c
2023: "BAR:1", // 1d
2024: "BAR:2", // 1e
2025: "BAR:3", // 1f
2026: NULL, // 20
2027: NULL, // 21
2028: NULL, // 22
2029: NULL, // 23
2030: NULL, // 24
2031: "NIV", // 25
2032: NULL, // 26
2033: "EIV", // 27
2034: NULL, // 28
2035: "MFC", // 29
2036: NULL, // 2a
2037: NULL, // 2b
2038: NULL, // 2c
2039: "CPR", // 2d
2040: NULL, // 2e
2041: NULL, // 2f
2042: NULL, // 30
2043: "DFC", // 31
2044: NULL, // 32
2045: NULL, // 33
2046: NULL, // 34
2047: NULL, // 35
2048: NULL, // 36
2049: NULL, // 37
2050: NULL, // 38
2051: "BFC", // 39
2052: NULL, // 3a
2053: NULL, // 3b
2054: NULL, // 3c
2055: NULL, // 3d
2056: NULL, // 3e
2057: NULL, // 3f (GCR は別処理)
2058: };
2059:
2060: // レジスタ名 (ワード)
2061: /*static*/ const char * const
2062: DMACDevice::regname2[0x40 / 2] = {
2063: "CSR:CER", // 00
2064: NULL, // 02
2065: "DCR:OCR", // 04
2066: "SCR:CCR", // 06
2067: NULL, // 08
2068: "MTC", // 0a
2069: "MAR:H", // 0c
2070: "MAR:L", // 0e
2071: NULL, // 10
2072: NULL, // 12
2073: "DAR:H", // 14
2074: "DAR:L", // 16
2075: NULL, // 18
2076: "BTC", // 1a
2077: "BAR:H", // 1c
2078: "BAR:L", // 1e
2079: NULL, // 20
2080: NULL, // 22
2081: "NIV(W)", // 24
2082: "EIV(W)", // 26
2083: "MFC(W)", // 28
2084: NULL, // 2a
2085: "CPR(W)", // 2c
2086: NULL, // 2f
2087: "DFC(W)", // 30
2088: NULL, // 32
2089: NULL, // 34
2090: NULL, // 36
2091: "BFC(W)", // 38
2092: NULL, // 3a
2093: NULL, // 3c
2094: NULL, // 3e (GCR は別処理)
2095: };
2096:
2097: /*static*/ const char * const
2098: DMACDevice::seqname[DMACDevice::SEQ_MAX] =
2099: {
2100: "NOP",
2101: "RD_M8",
2102: "RD_M16",
2103: "RD_D8",
2104: "RD_D16",
2105: "WR_M8",
2106: "WR_M16",
2107: "WR_D8",
2108: "WR_D16",
2109: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.