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

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

unix.superglobalmegacorp.com

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