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

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;
1.1.1.2 ! root       26:                event[ch].SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1       root       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.