Annotation of nono/vm/mfp.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2017 [email protected]
        !             4: //
        !             5: 
        !             6: #include "mfp.h"
        !             7: #include "mpu.h"
        !             8: #include "mystring.h"
        !             9: #include "scheduler.h"
        !            10: 
        !            11: MFPDevice *gMFP;
        !            12: 
        !            13: // コンストラクタ
        !            14: MFPDevice::MFPDevice()
        !            15: {
        !            16:        logname = "mfp";
        !            17:        devname = "MFP";
        !            18:        devaddr = baseaddr;
        !            19:        devlen  = 0x2000;
        !            20:        monitor.Init(65, 17);
        !            21: 
        !            22:        for (int ch = 0; ch < countof(event); ch++) {
        !            23:                event[ch].dev = this;
        !            24:                event[ch].func = (DeviceCallback_t)&MFPDevice::TimerCallback;
        !            25:                event[ch].code = ch;
        !            26:                event[ch].name = string_format("MFP Timer-%c", ch + 'A');
        !            27:        }
        !            28: }
        !            29: 
        !            30: // デストラクタ
        !            31: MFPDevice::~MFPDevice()
        !            32: {
        !            33: }
        !            34: 
        !            35: // MPU の RESET 命令によるリセット
        !            36: void
        !            37: MFPDevice::ResetSoft()
        !            38: {
        !            39:        // TxDR, UDR, TSR はクリアされない
        !            40: 
        !            41:        // ?
        !            42:        mfp.tsr = 0x80;
        !            43: 
        !            44:        // それ以外のすべてのレジスタはクリア?
        !            45:        mfp.vr = 0;
        !            46: 
        !            47:        // タイマーはすべてストップなのでイベントを削除
        !            48:        for (int ch = 0; ch < countof(event); ch++) {
        !            49:                gScheduler->DelEvent(&event[ch]);
        !            50:        }
        !            51: 
        !            52:        // ペンディング割り込みクリア
        !            53: 
        !            54: }
        !            55: 
        !            56: uint64
        !            57: MFPDevice::Read8(uint32 addr)
        !            58: {
        !            59:        uint8 data;
        !            60: 
        !            61:        if (addr % 2 == 0)
        !            62:                return (uint64)-1;
        !            63: 
        !            64:        int n = (addr - baseaddr) / 2;
        !            65:        switch (n) {
        !            66:         case MFP::GPIP:
        !            67:                data = mfp.gpip;
        !            68:                break;
        !            69:         case MFP::AER:
        !            70:                data = mfp.aer;
        !            71:                break;
        !            72:         case MFP::DDR:
        !            73:                data = mfp.ddr;
        !            74:                break;
        !            75:         case MFP::IERA:
        !            76:                data = mfp.ier.a;
        !            77:                break;
        !            78:         case MFP::IERB:
        !            79:                data = mfp.ier.b;
        !            80:                break;
        !            81:         case MFP::IPRA:
        !            82:                data = mfp.ipr.a;
        !            83:                break;
        !            84:         case MFP::IPRB:
        !            85:                data = mfp.ipr.b;
        !            86:                break;
        !            87:         case MFP::ISRA:
        !            88:                data = mfp.isr.a;
        !            89:                break;
        !            90:         case MFP::ISRB:
        !            91:                data = mfp.isr.b;
        !            92:                break;
        !            93:         case MFP::IMRA:
        !            94:                data = mfp.imr.a;
        !            95:                break;
        !            96:         case MFP::IMRB:
        !            97:                data = mfp.imr.b;
        !            98:                break;
        !            99:         case MFP::VR:
        !           100:                data = mfp.vr;
        !           101:                break;
        !           102:         case MFP::TACR:
        !           103:                data = mfp.tcr[0];
        !           104:                break;
        !           105:         case MFP::TBCR:
        !           106:                data = mfp.tcr[1];
        !           107:                break;
        !           108:         case MFP::TCDCR:
        !           109:                data = (mfp.tcr[2] << 4) | mfp.tcr[3];
        !           110:                break;
        !           111:         case MFP::TADR:
        !           112:                data = GetTDR(0);
        !           113:                break;
        !           114:         case MFP::TBDR:
        !           115:                data = GetTDR(1);
        !           116:                break;
        !           117:         case MFP::TCDR:
        !           118:                data = GetTDR(2);
        !           119:                break;
        !           120:         case MFP::TDDR:
        !           121:                data = GetTDR(3);
        !           122:                break;
        !           123:         case MFP::SCR:
        !           124:                data = mfp.scr;
        !           125:                break;
        !           126:         case MFP::UCR:
        !           127:                data = mfp.ucr;
        !           128:                break;
        !           129:         case MFP::RSR:
        !           130:                data = mfp.rsr;
        !           131:                break;
        !           132:         case MFP::TSR:
        !           133:                data = mfp.tsr;
        !           134:                break;
        !           135:         case MFP::UDR:
        !           136:                data = mfp.udr;
        !           137:                break;
        !           138:         default:
        !           139:                return (uint64)-1;
        !           140:        }
        !           141:        return data;
        !           142: }
        !           143: 
        !           144: uint64
        !           145: MFPDevice::Read16(uint32 addr)
        !           146: {
        !           147:        return (0xff00 | Read8(addr + 1));
        !           148: }
        !           149: 
        !           150: uint64
        !           151: MFPDevice::Write8(uint32 addr, uint32 data)
        !           152: {
        !           153:        if (addr % 2 == 0)
        !           154:                return (uint64)-1;
        !           155: 
        !           156:        int n = (addr - baseaddr) / 2;
        !           157:        switch (n) {
        !           158:         case MFP::GPIP:
        !           159:                putlog(0, "GPIP <- $%02x 未実装書き込み", data);
        !           160:                mfp.gpip = data;
        !           161:                break;
        !           162:         case MFP::AER:
        !           163:                putlog(0, "AER <- $%02x 未実装書き込み", data);
        !           164:                mfp.aer = data;
        !           165:                break;
        !           166:         case MFP::DDR:
        !           167:                if (data != 0) {
        !           168:                        putlog(0, "DDR <- $%02x 未実装書き込み", data);
        !           169:                }
        !           170:                mfp.ddr = data;
        !           171:                break;
        !           172:         case MFP::IERA:
        !           173:                putlog(2, "IERA <- $%02x", data);
        !           174:                mfp.ier.a = data;
        !           175:                break;
        !           176:         case MFP::IERB:
        !           177:                putlog(2, "IERB <- $%02x", data);
        !           178:                mfp.ier.b = data;
        !           179:                break;
        !           180:         case MFP::IPRA:
        !           181:                putlog(2, "IPRA <- $%02x", data);
        !           182:                mfp.ipr.a = data;
        !           183:                break;
        !           184:         case MFP::IPRB:
        !           185:                putlog(2, "IPRB <- $%02x", data);
        !           186:                mfp.ipr.b = data;
        !           187:                break;
        !           188:         case MFP::ISRA:
        !           189:                putlog(2, "ISRA <- $%02x", data);
        !           190:                mfp.isr.a = data;
        !           191:                break;
        !           192:         case MFP::ISRB:
        !           193:                putlog(2, "ISRB <- $%02x", data);
        !           194:                mfp.isr.b = data;
        !           195:                break;
        !           196:         case MFP::IMRA:
        !           197:                putlog(2, "IMRA <- $%02x", data);
        !           198:                mfp.imr.a = data;
        !           199:                break;
        !           200:         case MFP::IMRB:
        !           201:                putlog(2, "IMRB <- $%02x", data);
        !           202:                mfp.imr.b = data;
        !           203:                break;
        !           204:         case MFP::VR:
        !           205:                mfp.vr = data & 0xf0;
        !           206:                putlog(2, "VR <- $%02x", mfp.vr);
        !           207:                break;
        !           208:         case MFP::TACR:
        !           209:                putlog(2, "TACR <- $%02x", data);
        !           210:                SetTCR(0, data);
        !           211:                break;
        !           212:         case MFP::TBCR:
        !           213:                putlog(2, "TBCR <- $%02x", data);
        !           214:                SetTCR(1, data);
        !           215:                break;
        !           216:         case MFP::TCDCR:
        !           217:                putlog(2, "TCDCR <- $%02x", data);
        !           218:                SetTCR(2, data >> 4);
        !           219:                SetTCR(3, data & 7);
        !           220:                break;
        !           221:         case MFP::TADR:
        !           222:                putlog(2, "TADR <- $%02x", data);
        !           223:                SetTDR(0, data);
        !           224:                break;
        !           225:         case MFP::TBDR:
        !           226:                putlog(2, "TBDR <- $%02x", data);
        !           227:                SetTDR(1, data);
        !           228:                break;
        !           229:         case MFP::TCDR:
        !           230:                putlog(2, "TCDR <- $%02x", data);
        !           231:                SetTDR(2, data);
        !           232:                break;
        !           233:         case MFP::TDDR:
        !           234:                putlog(2, "TDDR <- $%02x", data);
        !           235:                SetTDR(3, data);
        !           236:                break;
        !           237:         case MFP::SCR:
        !           238:                putlog(0, "SCR <- $%02x 未実装書き込み", data);
        !           239:                mfp.scr = data;
        !           240:                break;
        !           241:         case MFP::UCR:
        !           242:                putlog(0, "UCR <- $%02x 未実装書き込み", data);
        !           243:                mfp.ucr = data & 0xfe;
        !           244:                break;
        !           245:         case MFP::RSR:
        !           246:                putlog(0, "RSR <- $%02x 未実装書き込み", data);
        !           247:                mfp.rsr = data;
        !           248:                break;
        !           249:         case MFP::TSR:
        !           250:                putlog(0, "TSR <- $%02x 未実装書き込み", data);
        !           251:                mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
        !           252:                break;
        !           253:         case MFP::UDR:
        !           254:                putlog(0, "UDR <- $%02x 未実装書き込み", data);
        !           255:                mfp.udr = data;
        !           256:                break;
        !           257:         default:
        !           258:                return (uint64)-1;
        !           259:        }
        !           260:        return 0;
        !           261: }
        !           262: 
        !           263: uint64
        !           264: MFPDevice::Write16(uint32 addr, uint32 data)
        !           265: {
        !           266:        return Write8(addr + 1, data);
        !           267: }
        !           268: 
        !           269: uint64
        !           270: MFPDevice::Peek8(uint32 addr)
        !           271: {
        !           272:        uint8 data;
        !           273: 
        !           274:        if (addr % 2 == 0) {
        !           275:                return (uint64)-1;
        !           276:        }
        !           277:        int n = (addr - baseaddr) / 2;
        !           278:        switch (n) {
        !           279:         case MFP::GPIP:
        !           280:                data = mfp.gpip;
        !           281:                break;
        !           282:         case MFP::AER:
        !           283:                data = mfp.aer;
        !           284:                break;
        !           285:         case MFP::DDR:
        !           286:                data = mfp.ddr;
        !           287:                break;
        !           288:         case MFP::IERA:
        !           289:                data = mfp.ier.a;
        !           290:                break;
        !           291:         case MFP::IERB:
        !           292:                data = mfp.ier.b;
        !           293:                break;
        !           294:         case MFP::IPRA:
        !           295:                data = mfp.ipr.a;
        !           296:                break;
        !           297:         case MFP::IPRB:
        !           298:                data = mfp.ipr.b;
        !           299:                break;
        !           300:         case MFP::ISRA:
        !           301:                data = mfp.isr.a;
        !           302:                break;
        !           303:         case MFP::ISRB:
        !           304:                data = mfp.isr.b;
        !           305:                break;
        !           306:         case MFP::IMRA:
        !           307:                data = mfp.imr.a;
        !           308:                break;
        !           309:         case MFP::IMRB:
        !           310:                data = mfp.imr.b;
        !           311:                break;
        !           312:         case MFP::VR:
        !           313:                data = mfp.vr;
        !           314:                break;
        !           315:         case MFP::TACR:
        !           316:                data = mfp.tcr[0];
        !           317:                break;
        !           318:         case MFP::TBCR:
        !           319:                data = mfp.tcr[1];
        !           320:                break;
        !           321:         case MFP::TCDCR:
        !           322:                data = (mfp.tcr[2] << 4) | mfp.tcr[3];
        !           323:                break;
        !           324:         case MFP::TADR:
        !           325:                data = GetTDR(0);
        !           326:                break;
        !           327:         case MFP::TBDR:
        !           328:                data = GetTDR(1);
        !           329:                break;
        !           330:         case MFP::TCDR:
        !           331:                data = GetTDR(2);
        !           332:                break;
        !           333:         case MFP::TDDR:
        !           334:                data = GetTDR(3);
        !           335:                break;
        !           336:         case MFP::SCR:
        !           337:                data = mfp.scr;
        !           338:                break;
        !           339:         case MFP::UCR:
        !           340:                data = mfp.ucr;
        !           341:                break;
        !           342:         case MFP::RSR:
        !           343:                data = mfp.rsr;
        !           344:                break;
        !           345:         case MFP::TSR:
        !           346:                data = mfp.tsr;
        !           347:                break;
        !           348:         case MFP::UDR:
        !           349:                data = mfp.udr;
        !           350:                break;
        !           351:         default:
        !           352:                data = 0xff;
        !           353:                break;
        !           354:        }
        !           355:        return data;
        !           356: }
        !           357: 
        !           358: bool
        !           359: MFPDevice::MonitorUpdate()
        !           360: {
        !           361:        int x;
        !           362:        int y;
        !           363: 
        !           364:        monitor.Clear();
        !           365: 
        !           366:        // 0         1         2         3         4         5         6
        !           367:        // 012345678901234567890123456789012345678901234567890123456789012345
        !           368:        //                 IER    IMR  IPR  ISR           Mode        TDR Cnt
        !           369:        // An:MPSC TxEmpty Enable Mask Pend Serv  Timer-A Delay(50us) 255 255
        !           370: 
        !           371:        // 割り込み関連
        !           372:        monitor.Print(0, 0, "   %-12s %-6s %-4s %-4s %-4s",
        !           373:                "", "IER", "IMR", "IPR", "ISR");
        !           374:        y = 1;
        !           375:        for (int i = 15; i >= 0; i--, y++) {
        !           376:                uint16 mask = (1 << i);
        !           377:                monitor.Print(0, y, "%c%d:%-12s %-6s %-4s %-4s %-4s",
        !           378:                        i >= 8 ? 'A' : 'B',
        !           379:                        (i % 8),
        !           380:                        intrname[i],
        !           381:                        (mfp.ier.w & mask) ? "Enable" : "",
        !           382:                        (mfp.imr.w & mask) ? ""       : "Mask", // %0 でマスクする
        !           383:                        (mfp.ipr.w & mask) ? "Pend"   : "",
        !           384:                        (mfp.isr.w & mask) ? "Serv"   : "");
        !           385:        }
        !           386: 
        !           387:        // タイマー関連
        !           388:        x = 39;
        !           389:        y = 1;
        !           390:        for (int ch = 0; ch < 4; ch++) {
        !           391:                y = ch + 1;
        !           392:                monitor.Print(x, y, "Timer-%c", ch + 'A');
        !           393:                if (mfp.tcr[ch] == 0) {
        !           394:                        monitor.Print(x + 8, y, "Stopped");
        !           395:                } else if (mfp.tcr[ch] == 8) {
        !           396:                        monitor.Print(x + 8, y, "Event");
        !           397:                } else if (mfp.tcr[ch] > 8) {
        !           398:                        monitor.Print(x + 8, y, "Pulse(%s)", prescale_str[mfp.tcr[ch] - 8]);
        !           399:                } else {
        !           400:                        monitor.Print(x + 8, y, "Delay(%s)", prescale_str[mfp.tcr[ch]]);
        !           401:                }
        !           402: 
        !           403:                monitor.Print(x + 19, y, "%3d", GetTDR(ch));
        !           404:                monitor.Print(x + 23, y, "%3d", mfp.tdr[ch]);
        !           405:        }
        !           406: 
        !           407:        // GPIP 関連
        !           408:        x = 39;
        !           409:        y = 8;
        !           410:        monitor.Print(x, y++, "GPIP Name GPIP AER DDR");
        !           411:        for (int i = 7; i >= 0; i--, y++) {
        !           412:                uint mask = (1 << i);
        !           413:                monitor.Print(x, y, "b%d %-6s  %d   %d   %s", i, gpipname[i],
        !           414:                        (mfp.gpip & mask) ? 1 : 0,
        !           415:                        (mfp.aer & mask) ? 1 : 0,
        !           416:                        (mfp.ddr & mask) ? "OUT" : "IN");
        !           417:        }
        !           418: 
        !           419:        return true;
        !           420: }
        !           421: 
        !           422: /*static*/ const char *
        !           423: MFPDevice::intrname[] = {
        !           424:        "RTC Alarm",
        !           425:        "EXPON",
        !           426:        "POW SW",
        !           427:        "FM IRQ",
        !           428:        "Timer-D",
        !           429:        "Timer-C",
        !           430:        "V-Disp",
        !           431:        "---",
        !           432:        "Timer-B",
        !           433:        "MPSC TxErr",
        !           434:        "MPSC TxEmpty",
        !           435:        "MPSC RxErr",
        !           436:        "MPSC RxFull",
        !           437:        "Timer-A",
        !           438:        "CRTC IRQ",
        !           439:        "H-Sync",
        !           440: };
        !           441: 
        !           442: /*static*/ const char *
        !           443: MFPDevice::gpipname[] = {
        !           444:        "ALARM",
        !           445:        "EXPON",
        !           446:        "POW SW",
        !           447:        "FMIRQ",
        !           448:        "V-Disp",
        !           449:        "------",
        !           450:        "CIRQ",
        !           451:        "H-Sync",
        !           452: };
        !           453: 
        !           454: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
        !           455: /*static*/ const int
        !           456: MFPDevice::prescale_ns[8] = {
        !           457:        0,
        !           458:        1000,   // /4
        !           459:        2500,   // /10
        !           460:        4000,   // /16
        !           461:        12500,  // /50
        !           462:        16000,  // /64
        !           463:        25000,  // /100
        !           464:        50000,  // /200
        !           465: };
        !           466: 
        !           467: /*static*/ const char *
        !           468: MFPDevice::prescale_str[8] = {
        !           469:        "",
        !           470:        "1us",
        !           471:        "2.5us",
        !           472:        "4us",
        !           473:        "12.5us",
        !           474:        "16us",
        !           475:        "25us",
        !           476:        "50us",
        !           477: };
        !           478: 
        !           479: // タイマーのチャンネルからベクタ(ビット番号) に変換する
        !           480: /*static*/ const int
        !           481: MFPDevice::timer_vector[4] = { 13, 8, 5, 4 };
        !           482: 
        !           483: // このタイマーで割り込みを上げる必要があるかどうかを返す
        !           484: bool
        !           485: MFPDevice::IsTimerIntrEnable(uint ch) const
        !           486: {
        !           487:        assert(ch < 4);
        !           488:        __assume(ch < 4);
        !           489: 
        !           490:        // 割り込みが無効なら false
        !           491:        if ((mfp.ier.w & (1 << timer_vector[ch])) == 0) {
        !           492:                return false;
        !           493:        }
        !           494: 
        !           495:        // 割り込みがマスクされていれば false
        !           496:        if ((mfp.imr.w & (1 << timer_vector[ch])) == 0) {
        !           497:                return false;
        !           498:        }
        !           499: 
        !           500:        // そうでなければ、割り込みを上げる必要がある
        !           501:        return true;
        !           502: }
        !           503: 
        !           504: // TxCR をセットする
        !           505: void
        !           506: MFPDevice::SetTCR(int ch, uint32 data)
        !           507: {
        !           508:        uint32 prev;
        !           509: 
        !           510:        prev = mfp.tcr[ch];
        !           511:        data &= 0x0f;
        !           512: 
        !           513:        mfp.tcr[ch] = data;
        !           514:        if (mfp.tcr[ch] > 0x08) {
        !           515:                putlog(0, "T%cCR サポートしていないモード $%02x",
        !           516:                        ch + 'A', mfp.tcr[ch]);
        !           517:                return;
        !           518:        }
        !           519:        if (mfp.tcr[ch] == 8) {
        !           520:                // イベントカウントモード
        !           521: 
        !           522:                // TDR をロードする
        !           523:                mfp.initial_tdr[ch] = mfp.tdr[ch];
        !           524:                putlog(1, "Timer-%c イベントカウントモード", ch + 'A');
        !           525:                return;
        !           526: 
        !           527:        } else if (mfp.tcr[ch] == 0) {
        !           528:                // タイマー停止
        !           529:                if (prev != 0) {
        !           530:                        putlog(1, "Timer-%c 停止", ch + 'A');
        !           531:                }
        !           532:                mfp.timer_start[ch] = 0;
        !           533:                gScheduler->DelEvent(&event[ch]);
        !           534:                return;
        !           535: 
        !           536:        } else {
        !           537:                // タイマー開始
        !           538:                int scale = prescale_ns[mfp.tcr[ch]];
        !           539:                if (prev == 0) {
        !           540:                        // タイマー停止中に開始
        !           541:                        // ここで initial_tdr にロード
        !           542:                        mfp.initial_tdr[ch] = mfp.tdr[ch] ?: 256;
        !           543:                        mfp.timer_start[ch] = gScheduler->GetVirtTime();
        !           544:                } else {
        !           545:                        // タイマー動作中に(再)開始
        !           546: 
        !           547:                        // タイマー動作中に TxCR に書き込むと、TxDR は影響を受けずに、
        !           548:                        // プリスケーラのカウンタがリセットされる。
        !           549:                        // 例えば、TCR = 0x01 (プリスケール 10)、TDR = 0x05 で、
        !           550:                        // プリスケールカウントが12回進行した時点で TCR に再び 0x01
        !           551:                        // (プリスケール10) が書き込まれた場合、以下のようになるはず。
        !           552:                        //
        !           553:                        //             time ->
        !           554:                        // prescale cnt| 0 1 2 3 4 5 6 7 8 9 0 1 2
        !           555:                        // main count  | 5 ----------------> 4 -->
        !           556:                        //                                        * ここで TCR 書き込み
        !           557:                        // TCR書き込み後のprescale cnt |          0 1 2 3 4 5 6 7 8 9 0 1
        !           558:                        // TCR書き込み後のmain count   |          4 ----------------> 3 ->
        !           559:                        uint64 ellapsed;
        !           560:                        uint deccount;
        !           561: 
        !           562:                        // タイマー開始時からの経過時間
        !           563:                        ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
        !           564: 
        !           565:                        // タイマー開始時から今までのメインカウンタ減算回数
        !           566:                        deccount = ellapsed / scale;
        !           567: 
        !           568:                        // 再設定
        !           569:                        mfp.initial_tdr[ch] -= deccount;
        !           570:                        mfp.timer_start[ch] += gScheduler->GetVirtTime();
        !           571:                }
        !           572: 
        !           573:                // 割り込みを上げる必要があれば、カウントダウン終了時にイベントを
        !           574:                // 起こす。
        !           575:                // 割り込みを上げる必要がない場合は、TxDR を読み出す時に正しい値が
        !           576:                // 算出できるだけでよくて、それは timer_start 等により行えているので
        !           577:                // 他には何もしなくてよい。Timer-B 対策。
        !           578:                if (IsTimerIntrEnable(ch)) {
        !           579:                        event[ch].time = mfp.initial_tdr[ch] * scale;
        !           580:                        gScheduler->AddEvent(&event[ch]);
        !           581:                }
        !           582: 
        !           583:                putlog(1, "Timer-%c ディレイモード開始(%d.%d x %d usec)",
        !           584:                        ch + 'A',
        !           585:                        scale / 1000,
        !           586:                        (scale / 100) % 10,
        !           587:                        mfp.initial_tdr[ch]);
        !           588:        }
        !           589: }
        !           590: 
        !           591: // TxDR の読み出し
        !           592: // タイマーデータレジスタの現在値は保持しておらず、
        !           593: // タイマー開始時刻と減算量が分かっているので読み出しのたびに求める。
        !           594: // この操作に副作用はないので Peek/Monitor でも使用可能。
        !           595: uint8
        !           596: MFPDevice::GetTDR(int ch)
        !           597: {
        !           598:        uint64 ellapsed;
        !           599:        uint64 count;
        !           600:        uint32 data;
        !           601: 
        !           602:        // イベントカウントモードなら initial_tdr が読める?
        !           603:        if (mfp.tcr[ch] == 8) {
        !           604:                return mfp.initial_tdr[ch];
        !           605:        }
        !           606: 
        !           607:        // タイマー停止中なら TxDR と同じでよい?
        !           608:        if (mfp.tcr[ch] == 0) {
        !           609:                return mfp.tdr[ch];
        !           610:        }
        !           611: 
        !           612:        // タイマー開始時からの経過時間
        !           613:        ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
        !           614: 
        !           615:        // タイマー開始時から現在までのメインカウンタ減算回数
        !           616:        count = ellapsed / prescale_ns[mfp.tcr[ch]];
        !           617: 
        !           618:        // カウント終了時に割り込みが上がる設定になっていれば
        !           619:        // count は必ず 0 から initail_tdr-1 までの範囲だが、
        !           620:        // カウント終了時に割り込みが上がる設定になっていない場合は
        !           621:        // 経過時間とそれに伴い count はひたすら増える。
        !           622:        // そのため initial_tdr で modulo する。
        !           623:        count %= mfp.initial_tdr[ch];
        !           624: 
        !           625:        // count は減算回数だが、
        !           626:        // TxDR レジスタの読み出し値は減算カウンタの現在値。
        !           627:        // TxDR = 10 で開始して count = 0 のうちは TxDR 読み出しは 10。
        !           628:        // TxDR = 10 で開始して count = 1 のうちは TxDR 読み出しは 9。
        !           629:        //  :
        !           630:        // TxDR = 10 で開始して count = 9 のうちは TxDR 読み出しは 1。
        !           631:        data = mfp.initial_tdr[ch] - count;
        !           632: 
        !           633:        return data;
        !           634: }
        !           635: 
        !           636: // TxDR への書き込み
        !           637: void
        !           638: MFPDevice::SetTDR(int ch, uint32 data)
        !           639: {
        !           640:        uint64 ellapsed;
        !           641:        uint64 scale;
        !           642:        uint64 period;
        !           643:        uint64 timer_end;
        !           644: 
        !           645:        mfp.tdr[ch] = data;
        !           646: 
        !           647:        // イベントカウントモードなら即ロード
        !           648:        if (mfp.tcr[ch] == 8) {
        !           649:                mfp.initial_tdr[ch] = mfp.tdr[ch];
        !           650:        }
        !           651: 
        !           652:        // カウント終了時に割り込みが上がる設定になっていれば、
        !           653:        // そのイベントコールバックで tdr を initial_tdr にロードするが、
        !           654:        // 割り込みが上がらない設定の場合、そのままでは tdr をリロードする
        !           655:        // 機会がない。そのためこのケースでは書き込み時点の次のカウント終了
        !           656:        // 時にイベントを起こす必要がある。
        !           657:        //
        !           658:        // TCR=1(プリスケール10)、TDR=5 で 38カウント目に TDR がセットされた
        !           659:        // 場合、ここから 12カウント目がリロードタイミング。
        !           660:        //
        !           661:        // pre | 0 ... 0 ... 0 ... 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
        !           662:        // main| 5 --> 4 --> 3 --> 2 ------------->*
        !           663:        //                                         |<--------------------->|
        !           664:        //                                          イベントを起こすまでの時間
        !           665:        if (IsTimerIntrEnable(ch) == false) {
        !           666:                // タイマー開始時から現在までの経過時間
        !           667:                ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
        !           668:                // プリスケールカウント時間 (上でいう1カウントの時間)
        !           669:                scale = prescale_ns[mfp.tcr[ch]];
        !           670:                // 1タイマー期間(上でいう50カウントに相当する時間)
        !           671:                period = scale * mfp.initial_tdr[ch];
        !           672:                // タイマー開始時から次のタイムアップ時刻までの時間
        !           673:                timer_end = ((ellapsed + period - 1) / period) * period;
        !           674:                // タイムアップ時刻
        !           675:                timer_end = mfp.timer_start[ch] + timer_end;
        !           676:                // 現在から次のタイムアップ時刻まで
        !           677:                event[ch].time = timer_end - gScheduler->GetVirtTime();
        !           678:                gScheduler->AddEvent(&event[ch]);
        !           679: 
        !           680:                putlog(3, "Timer-%c TDR 更新予約 %d.%09d", ch + 'A',
        !           681:                        (int)(event[ch].time / (1000 * 1000 * 1000)),
        !           682:                        (int)(event[ch].time % (1000 * 1000 * 1000)));
        !           683:        }
        !           684: }
        !           685: 
        !           686: // イベントコールバック
        !           687: void
        !           688: MFPDevice::TimerCallback(int arg)
        !           689: {
        !           690:        int ch = arg;
        !           691:        int prevtdr;
        !           692:        uint64 ellapsed;
        !           693:        uint64 scale;
        !           694:        uint64 period;
        !           695:        uint64 timer_end;
        !           696: 
        !           697:        // タイムアップした時刻を計算。現在時刻ではない。
        !           698:        // 現在時刻はタイムアップした直後の命令境界の時刻なので。
        !           699: 
        !           700:        // タイマー開始時から現在までの経過時間
        !           701:        ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
        !           702:        // 1プリスケール期間
        !           703:        scale = prescale_ns[mfp.tcr[ch]];
        !           704:        // 1タイマー期間
        !           705:        period = scale * mfp.initial_tdr[ch];
        !           706:        // タイマー開始時から直近のタイムアップ時刻まで
        !           707:        timer_end = (ellapsed / period) * period;
        !           708: 
        !           709:        // TxDR がゼロになったので TxDR をリロード
        !           710:        prevtdr = mfp.initial_tdr[ch];
        !           711:        mfp.initial_tdr[ch] = mfp.tdr[ch] ?: 256;
        !           712:        // 今タイムアップ時刻を次のタイマー起点に更新
        !           713:        mfp.timer_start[ch] += timer_end;
        !           714: 
        !           715:        // 割り込み有効なら
        !           716:        if (IsTimerIntrEnable(ch)) {
        !           717:                // 1タイマー期間を新しい TDR で再計算
        !           718:                period = prescale_ns[mfp.tcr[ch]] * mfp.initial_tdr[ch];
        !           719:                // イベント再設定
        !           720:                event[ch].time = period;
        !           721:                gScheduler->AddEvent(&event[ch]);
        !           722: 
        !           723:                // 割り込みを上げる
        !           724:                gMPU->Interrupt(6, mfp.vr + timer_vector[ch]);
        !           725:        }
        !           726: 
        !           727:        if (mfp.initial_tdr[ch] != prevtdr) {
        !           728:                putlog(1, "Timer-%c ディレイモード更新(%u.%u x %u usec)",
        !           729:                        ch + 'A',
        !           730:                        (uint)(scale / 1000),
        !           731:                        (uint)((scale / 100) % 10),
        !           732:                        (uint)mfp.initial_tdr[ch]);
        !           733:        }
        !           734: }
        !           735: 
        !           736: // VDisp 入力
        !           737: void
        !           738: MFPDevice::SetVDisp(bool vdisp)
        !           739: {
        !           740:        // TAI への入力はイベントカウントモードの時のみ
        !           741:        if (mfp.tcr[0] == 8) {
        !           742:                // AER が示す方向と同じエッジ方向の時
        !           743:                bool aer = (mfp.aer & (1 << MFP::GPIP_VDISP));
        !           744:                if (aer == vdisp) {
        !           745:                        // カウンタを減算
        !           746:                        mfp.initial_tdr[0]--;
        !           747:                        if (mfp.initial_tdr[0] == 0) {
        !           748:                                // 0 になったらリロード
        !           749:                                mfp.initial_tdr[0] = mfp.tdr[0];
        !           750: 
        !           751:                                // XXX ここで割り込みを上げる
        !           752:                        }
        !           753:                }
        !           754:        }
        !           755: 
        !           756:        // GPIP への入力
        !           757:        SetGPIP(MFP::GPIP_VDISP, vdisp);
        !           758: }
        !           759: 
        !           760: // GPIP への入力。
        !           761: // num はビット番号(0..7)。
        !           762: void
        !           763: MFPDevice::SetGPIP(int num, bool val)
        !           764: {
        !           765:        bool aer = (mfp.aer & (1 << num));
        !           766:        bool old = (mfp.gpip & (1 << num));
        !           767: 
        !           768:        // 立ち上がりか立ち下がりで割り込みを上げる (AER による)
        !           769:        // AER OLD VAL   Interrupt
        !           770:        //   0   0   0   0
        !           771:        //   0   0   1   0
        !           772:        //   0   1   0   1
        !           773:        //   0   1   1   0
        !           774:        //   1   0   0   0
        !           775:        //   1   0   1   1
        !           776:        //   1   1   0   0
        !           777:        //   1   1   1   0
        !           778:        if ((old != val) & (aer == val)) {
        !           779:                // XXX ここで割り込みを上げる
        !           780:        }
        !           781: 
        !           782:        if (val) {
        !           783:                mfp.gpip |= (1 << num);
        !           784:        } else {
        !           785:                mfp.gpip &= ~(1 << num);
        !           786:        }
        !           787: }

unix.superglobalmegacorp.com

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