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

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

unix.superglobalmegacorp.com

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