Annotation of nono/vm/dmac.cpp, revision 1.1.1.16

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.