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

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

unix.superglobalmegacorp.com

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