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