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