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

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

unix.superglobalmegacorp.com

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