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

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

unix.superglobalmegacorp.com

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