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

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

unix.superglobalmegacorp.com

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