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

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.12  root        7: //
                      8: // MFP (MC68901)
                      9: //
                     10: 
1.1.1.19  root       11: // タイマーについて。
                     12: //
                     13: // ディレイモードでは、プリスケーラで設定した回数だけ入力をカウントすると
                     14: // メインカウンタにパルスが入る。このパルスはメインカウンタを 1 減らす。
                     15: // メインカウンタが $01 になった次のパルスで (おそらく外から見ると $00 に
                     16: // ならないからこういう言い回しなのだが要するに 1 減らして内部的に $00 に
                     17: // なったらでいいと思う)、TxDR をリロードして「タイムアウトパルス」を起こす。
                     18: // タイムアウトパルスが起きると、割り込みを(許可されていれば)上げると共に、
                     19: // カウンタをリロードして、アウトプットピンの状態をトグルする。(MC68901.pdf)
                     20: //
                     21: // 1つのタイマーあたり
                     22: // o タイマー開始時のカウンタ初期値
                     23: // o タイマー開始時刻
                     24: // o 次回のリロード値
                     25: // を保持する。
                     26: //
                     27: // タイムアウトパルスとタイムアウトパルスの間は一定時間ごとにメインカウンタの
                     28: // 値が減算されていってるだけだし、割り込みを有効にしていなければメインカウンタ
                     29: // はタイムアウト周期でこの減算を繰り返しているだけなので、TxDR の読み出し値は
                     30: // 読み出し時刻から計算で求めることができる。
                     31: //
                     32: //  現在値 = 初期値 - int((現在時刻 - 開始時刻) / メインカウンタ周期) % 初期値
                     33: //
                     34: // 例えば、プリスケーラ 16分周(4usec)、カウント 5 の場合
                     35: //
                     36: //       (1)(2)                              (3)
                     37: //        v  v                               t+26
                     38: //          t+0  +4   +8   +12  +16  +20 +24  v  +28 +32  +36  +40   [usec]
                     39: //        ---+----+----+----+----+----+----+-----+----+----+----+--> time
                     40: //  TxDR  5  5    4    3    2    1    5    4     3    2    1    5
                     41: //
                     42: // (1) で TxDR に 5 をセット、(2) t+0 でタイマースタートして、(3) t+26 で
                     43: // TxDR を読み出された場合、値は
                     44: //    5 - int(((t+26 - t+0) % 20_usec) / 4_usec)
                     45: //  = 5 - int(6_usec / 4_usec)
                     46: //  = 5 - 1
                     47: //  = 4
                     48: //
                     49: // 一方割り込みが必要な場合は、(2) でタイマースタートして、(4)、(4')… の
                     50: // タイミングでタイマーイベントにより割り込みを起こす。
                     51: //
                     52: //          (2)                      (4)                      (4')
                     53: //           v                        v                        v
                     54: //        ---+----+----+----+----+----+----+----+----+----+----+--> time
                     55: //  TxDR  5  5    4    3    2    1    5    4    3    2    1    5
                     56: 
                     57: // 実時間追従について。
                     58: //
                     59: // MFP の実時間追従はタイマーの「割り込みに対してのみ」作用する。
                     60: // そもそも実時間追従とは、LUNA ではこの手のタイマーが固定のシステムクロック
                     61: // しかなくこれによるタイマー割り込み HZ 回でゲスト OS の時刻が1秒進むという
                     62: // ゲスト実装の特性と、割り込みの頻度は比較的低いことを利用した技法。
                     63: // 従って MFP でも 10msec 程度のタイマー割り込みであれば動作する。
                     64: //
                     65: // 一方 TxDR の減算 (プリスケーラ 200 分周でも 1 カウンタ減算が 50usec) は、
                     66: // 実時間軸を作っている syncer イベントの分解能 (仮想時間で 50msec) より
                     67: // 遥かに高いため、これを (syncer の) 実時間軸に追従させることは現状不可能。
                     68: // 例えば、より上位の割り込みが起きない Timer-C 割り込みのハンドラ冒頭で
                     69: // TCDR を読み出すと、通常はリロードされた初期値が読めるはずだが、これが
                     70: // 何が読めるか分からないという状態になる。
                     71: // NetBSD/x68k の timecounter=mfp はまさにこの TxDR の読み出しで時間差を計測
                     72: // して (10msec よりも高精度な 50usec 粒度で) 時間を進めようとするものなので
                     73: // (のはず)、TxDR の読み出しが信頼できなくなるこのモードでは使用できない。
                     74: // 一方 timecounter=clockinterrupt はタイマー割り込み1回で 1/HZ 秒ずつ進める
                     75: // (そのため時間の分解能は 1/HZ 秒 = 10msec になる) モード(のはず…)のため、
                     76: // 実時間追従でも動作する。
                     77: //
                     78: // nono のオプション clock-sync の値、動作モード(等速 or フルスピード) と
                     79: // ゲスト OS NetBSD の sysctl kern.timecounter.hardware の値の組み合わせは
                     80: // 以下のようになる。
                     81: //
                     82: //  clock-sync mode    sysctl timecounter
                     83: //  ---------- ----    ---------------
                     84: //  virtual            等速  mfp                             : ◯
                     85: //  virtual            等速  clockinterrupt  : ◯
                     86: //  virtual            フル  mfp                             : △
                     87: //  virtual            フル  clockinterrupt  : △
                     88: //  real               等速  mfp                             : ×
                     89: //  real               等速  clockinterrupt  : ◯
                     90: //  real               フル  mfp                             : ×
                     91: //  real               フル  clockinterrupt  : ◯
                     92: //
                     93: //  ◯: ゲスト OS の時間は実時間通りに進む。
                     94: //  △: VM 内の時間は実時間から切り離されてフルスピード時間軸で進む。
                     95: //  ×: ゲスト OS の時間が正しく進まない。
                     96: 
                     97: // Timer-B は 13 usec のタイムアウトごとに反転する出力ピン TOB を自身の
                     98: // TC, RC (UART の送受信クロック入力) に入れているだけで、割り込みは
                     99: // 使っていない。実機ではこれを変更するとキーボードと正しく通信できない
                    100: // ことになると思う。nono ではキーボードとの通信にこのクロック入力は
                    101: // 使っていないので、Timer-B は実質何もしていない。
                    102: 
1.1       root      103: #include "mfp.h"
1.1.1.20  root      104: #include "event.h"
1.1.1.7   root      105: #include "interrupt.h"
                    106: #include "keyboard.h"
1.1.1.21! root      107: #include "mainbus.h"
1.1.1.17  root      108: #include "monitor.h"
1.1.1.12  root      109: #include "scheduler.h"
1.1.1.19  root      110: #include "syncer.h"
1.1.1.9   root      111: #include "x68kkbd.h"
1.1       root      112: 
1.1.1.15  root      113: // InsideOut p.135
1.1.1.20  root      114: /*static*/ const busdata
                    115: MFPDevice::wait = busdata::Wait(24 * 40_nsec);
1.1.1.15  root      116: 
1.1       root      117: // コンストラクタ
                    118: MFPDevice::MFPDevice()
1.1.1.14  root      119:        : inherited(OBJ_MFP)
1.1       root      120: {
1.1.1.17  root      121:        monitor = gMonitorManager->Regist(ID_MONITOR_MFP, this);
1.1.1.21! root      122:        monitor->SetCallback(&MFPDevice::MonitorScreen);
1.1.1.17  root      123:        monitor->SetSize(77, 26);
1.1       root      124: }
                    125: 
                    126: // デストラクタ
                    127: MFPDevice::~MFPDevice()
                    128: {
1.1.1.14  root      129: }
                    130: 
                    131: // 初期化
                    132: bool
                    133: MFPDevice::Init()
                    134: {
                    135:        interrupt = GetInterruptDevice();
                    136:        keyboard = dynamic_cast<X68030Keyboard *>(GetKeyboard());
                    137: 
1.1.1.19  root      138:        // クロックの同期方法。
                    139:        syncer = GetSyncer();
                    140:        sync_rt = syncer->GetSyncRealtime();
                    141: 
                    142:        // TxDR は 1-256 の範囲でなければいけないので。
                    143:        for (int ch = 0; ch < countof(mfp.timer); ch++) {
                    144:                mfp.timer[ch].tdr = 256;
                    145:        }
                    146: 
1.1.1.20  root      147:        auto evman = GetEventManager();
1.1.1.16  root      148:        for (int ch = 0; ch < event.size(); ch++) {
1.1.1.20  root      149:                event[ch] = evman->Regist(this, ch,
                    150:                        ToEventCallback(&MFPDevice::TimerCallback),
                    151:                        string_format("MFP Timer-%c", ch + 'A'));
1.1.1.16  root      152:        }
                    153: 
                    154:        // キーボード周りは x68kkbd.cpp のコメント参照
1.1.1.20  root      155:        key_event = evman->Regist(this,
                    156:                ToEventCallback(&MFPDevice::KeyCallback),
                    157:                "MFP USART");
                    158:        key_event->time = 3750_usec;
1.1.1.16  root      159: 
1.1.1.14  root      160:        return true;
1.1       root      161: }
                    162: 
1.1.1.12  root      163: // リセット
1.1.1.6   root      164: void
1.1.1.12  root      165: MFPDevice::ResetHard(bool poweron)
1.1.1.6   root      166: {
1.1.1.15  root      167:        // 3.3 RESET OPERATION には
1.1.1.6   root      168:        // All internal registers are cleared expect the TxDR, UDR, and TSR.
1.1.1.15  root      169:        // と書いてあるが、6.2.1 には TxDR はリセット時に $00 と書いてある。
                    170:        // 内部カウンタは影響を受けずに next_tdr だけリセットされるという
                    171:        // 意味だろうか。
1.1.1.6   root      172:        mfp.aer = 0;
                    173:        mfp.ddr = 0;
                    174:        mfp.ier.w = 0;
                    175:        mfp.ipr.w = 0;
                    176:        mfp.isr.w = 0;
                    177:        mfp.imr.w = 0;
1.1.1.16  root      178:        for (int i = 0; i < countof(mfp.timer); i++) {
                    179:                mfp.timer[i].tcr = 0;
                    180:                mfp.timer[i].next_tdr = 256;
1.1.1.6   root      181:        }
                    182:        mfp.scr = 0;
                    183:        mfp.ucr = 0;
                    184:        mfp.rsr = 0;
                    185:        // XXX TSR は変化しないがたぶんバッファはクリアされるので BE は立つ
                    186:        // ということかな。
                    187:        mfp.tsr = MFP::TSR_BE;
1.1       root      188: 
1.1.1.6   root      189:        // All timers are stopped.
1.1.1.19  root      190:        for (int ch = 0; ch < event.size(); ch++) {
                    191:                StopTimerEvent(ch);
1.1       root      192:        }
1.1.1.14  root      193:        scheduler->StopEvent(key_event);
1.1       root      194: 
1.1.1.6   root      195:        // USART RX and TX are disabled.
                    196:        // SO line is placed in HighZ.
                    197:        // The interrupt channels are disabled, and
                    198:        // any pending interrupts are cleared.
                    199:        // GPIO lines are placed in HighZ.
                    200:        // timer outputs are driven low.
                    201:        // External signals are nagated.
                    202:        // VR is initialized to $00 (not $0f).
1.1.1.7   root      203:        mfp.vr_vec = 0;
                    204:        mfp.vr_s   = 0;
1.1.1.13  root      205: 
                    206:        // CIRQ | FMIRQ | EXPON | ALARM にしておく
                    207:        mfp.gpip = 0x6b;
1.1.1.15  root      208: 
1.1.1.18  root      209:        // Human68k モードなら、10msec ごとに Timer-C 割り込みを上げる。
                    210:        // 時間計測用。
                    211:        if (gMainApp.human_mode) {
                    212:                WritePort(MFP::VR, 0x40);
1.1.1.19  root      213:                WritePort(MFP::IERB, 0x20);
1.1.1.18  root      214:                WritePort(MFP::TCDR, 200);
                    215:                WritePort(MFP::TCDCR, 0x70);
                    216:                WritePort(MFP::IMRB, 0x20);
                    217:        }
                    218: 
1.1.1.15  root      219:        ChangeInterrupt();
1.1.1.3   root      220: }
                    221: 
1.1.1.15  root      222: busdata
1.1.1.16  root      223: MFPDevice::ReadPort(uint32 offset)
1.1       root      224: {
1.1.1.15  root      225:        busdata data;
1.1.1.6   root      226: 
1.1.1.8   root      227:        switch (offset) {
1.1       root      228:         case MFP::GPIP:
                    229:                data = mfp.gpip;
                    230:                break;
                    231:         case MFP::AER:
                    232:                data = mfp.aer;
                    233:                break;
                    234:         case MFP::DDR:
                    235:                data = mfp.ddr;
                    236:                break;
                    237:         case MFP::IERA:
                    238:                data = mfp.ier.a;
                    239:                break;
                    240:         case MFP::IERB:
                    241:                data = mfp.ier.b;
                    242:                break;
                    243:         case MFP::IPRA:
                    244:                data = mfp.ipr.a;
                    245:                break;
                    246:         case MFP::IPRB:
                    247:                data = mfp.ipr.b;
                    248:                break;
                    249:         case MFP::ISRA:
                    250:                data = mfp.isr.a;
                    251:                break;
                    252:         case MFP::ISRB:
                    253:                data = mfp.isr.b;
                    254:                break;
                    255:         case MFP::IMRA:
                    256:                data = mfp.imr.a;
                    257:                break;
                    258:         case MFP::IMRB:
                    259:                data = mfp.imr.b;
                    260:                break;
                    261:         case MFP::VR:
1.1.1.7   root      262:                data = mfp.GetVR();
1.1       root      263:                break;
                    264:         case MFP::TACR:
1.1.1.16  root      265:                data = mfp.timer[0].tcr;
1.1       root      266:                break;
                    267:         case MFP::TBCR:
1.1.1.16  root      268:                data = mfp.timer[1].tcr;
1.1       root      269:                break;
                    270:         case MFP::TCDCR:
1.1.1.16  root      271:                data = mfp.GetTCDCR();
1.1       root      272:                break;
                    273:         case MFP::TADR:
                    274:                data = GetTDR(0);
                    275:                break;
                    276:         case MFP::TBDR:
                    277:                data = GetTDR(1);
                    278:                break;
                    279:         case MFP::TCDR:
                    280:                data = GetTDR(2);
                    281:                break;
                    282:         case MFP::TDDR:
                    283:                data = GetTDR(3);
                    284:                break;
                    285:         case MFP::SCR:
                    286:                data = mfp.scr;
                    287:                break;
                    288:         case MFP::UCR:
                    289:                data = mfp.ucr;
                    290:                break;
                    291:         case MFP::RSR:
                    292:                data = mfp.rsr;
                    293:                break;
                    294:         case MFP::TSR:
                    295:                data = mfp.tsr;
                    296:                break;
                    297:         case MFP::UDR:
1.1.1.9   root      298:                // UDR からデータを読み出したら Buffer Full をクリア
1.1       root      299:                data = mfp.udr;
1.1.1.9   root      300:                ClearBF();
1.1       root      301:                break;
1.1.1.4   root      302:         default:
                    303:                data = 0xff;
                    304:                break;
1.1       root      305:        }
1.1.1.15  root      306: 
1.1.1.16  root      307:        if (__predict_false(loglevel >= 3)) {
                    308:                if (offset == MFP::TCDR) {
                    309:                        putlog(4, "%s -> $%02x", regname[offset], data.Data());
                    310:                } else if (offset < MFP::RegMax) {
                    311:                        putlogn("%s -> $%02x", regname[offset], data.Data());
                    312:                } else {
1.1.1.21! root      313:                        putlogn("$%06x -> $%02x",
        !           314:                                GetMainbusDevice()->GetPaddr(), data.Data());
1.1.1.16  root      315:                }
                    316:        }
1.1.1.15  root      317:        data |= wait;
1.1.1.16  root      318:        data |= BusData::Size1;
1.1       root      319:        return data;
                    320: }
                    321: 
1.1.1.15  root      322: busdata
1.1.1.16  root      323: MFPDevice::WritePort(uint32 offset, uint32 data)
1.1       root      324: {
1.1.1.8   root      325:        switch (offset) {
1.1       root      326:         case MFP::GPIP:
1.1.1.13  root      327:                putlog(0, "Write GPIP <- $%02x (NOT IMPLEMENTED)", data);
1.1       root      328:                mfp.gpip = data;
                    329:                break;
                    330:         case MFP::AER:
1.1.1.16  root      331:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      332:                mfp.aer = data;
                    333:                break;
                    334:         case MFP::DDR:
                    335:                if (data != 0) {
1.1.1.13  root      336:                        putlog(0, "Write DDR <- $%02x (NOT IMPLEMENTED)", data);
1.1       root      337:                }
                    338:                mfp.ddr = data;
                    339:                break;
                    340:         case MFP::IERA:
1.1.1.16  root      341:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.19  root      342:                SetIER((data << 8) | mfp.ier.b);
1.1       root      343:                break;
                    344:         case MFP::IERB:
1.1.1.16  root      345:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.19  root      346:                SetIER((mfp.ier.a << 8) | data);
1.1       root      347:                break;
                    348:         case MFP::IPRA:
1.1.1.16  root      349:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      350:                mfp.ipr.a = data;
1.1.1.7   root      351:                ChangeInterrupt();
1.1       root      352:                break;
                    353:         case MFP::IPRB:
1.1.1.16  root      354:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      355:                mfp.ipr.b = data;
1.1.1.7   root      356:                ChangeInterrupt();
1.1       root      357:                break;
                    358:         case MFP::ISRA:
1.1.1.16  root      359:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      360:                mfp.isr.a = data;
                    361:                break;
                    362:         case MFP::ISRB:
1.1.1.16  root      363:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      364:                mfp.isr.b = data;
                    365:                break;
                    366:         case MFP::IMRA:
1.1.1.16  root      367:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      368:                mfp.imr.a = data;
1.1.1.7   root      369:                ChangeInterrupt();
1.1       root      370:                break;
                    371:         case MFP::IMRB:
1.1.1.16  root      372:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      373:                mfp.imr.b = data;
1.1.1.7   root      374:                ChangeInterrupt();
1.1       root      375:                break;
                    376:         case MFP::VR:
1.1.1.7   root      377:                mfp.vr_vec = data & 0xf0;
                    378:                mfp.vr_s   = data & 0x08;
1.1.1.16  root      379:                putlog(2, "%s <- $%02x", regname[offset], mfp.GetVR());
1.1       root      380:                break;
                    381:         case MFP::TACR:
1.1.1.16  root      382:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      383:                SetTCR(0, data);
                    384:                break;
                    385:         case MFP::TBCR:
1.1.1.16  root      386:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      387:                SetTCR(1, data);
                    388:                break;
                    389:         case MFP::TCDCR:
1.1.1.16  root      390:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      391:                SetTCR(2, data >> 4);
                    392:                SetTCR(3, data & 7);
                    393:                break;
                    394:         case MFP::TADR:
1.1.1.16  root      395:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      396:                SetTDR(0, data);
                    397:                break;
                    398:         case MFP::TBDR:
1.1.1.16  root      399:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      400:                SetTDR(1, data);
                    401:                break;
                    402:         case MFP::TCDR:
1.1.1.16  root      403:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      404:                SetTDR(2, data);
                    405:                break;
                    406:         case MFP::TDDR:
1.1.1.16  root      407:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1       root      408:                SetTDR(3, data);
                    409:                break;
                    410:         case MFP::SCR:
1.1.1.13  root      411:                putlog(0, "SCR <- $%02x (NOT IMPLEMENTED)", data);
1.1       root      412:                mfp.scr = data;
                    413:                break;
                    414:         case MFP::UCR:
1.1.1.16  root      415:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4   root      416:                SetUCR(data);
1.1       root      417:                break;
                    418:         case MFP::RSR:
1.1.1.16  root      419:                putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4   root      420:                SetRSR(data);
1.1       root      421:                break;
                    422:         case MFP::TSR:
1.1.1.13  root      423:                if ((data & 0x0e)) {
                    424:                        // SO 端子関係の B, H, L ビットは未実装
                    425:                        putlog(0, "TSR <- $%02x (B,H,L bit NOT IMPLEMENTED)", data);
                    426:                }
1.1       root      427:                mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
                    428:                break;
                    429:         case MFP::UDR:
1.1.1.16  root      430:                if (__predict_false(loglevel >= 2)) {
                    431:                        if (data == 0x40 || data == 0x41) {
                    432:                                // MSCTRL だけ頻度が高いのでログレベルを上げておく
                    433:                                putlog(3, "%s <- $%02x", regname[offset], data);
                    434:                        } else {
                    435:                                putlogn("%s <- $%02x", regname[offset], data);
                    436:                        }
1.1.1.4   root      437:                }
                    438:                SetUDR(data);
                    439:                break;
                    440:         default:
1.1       root      441:                break;
                    442:        }
1.1.1.15  root      443: 
1.1.1.16  root      444:        busdata r = wait;
                    445:        r |= BusData::Size1;
                    446:        return r;
1.1       root      447: }
                    448: 
1.1.1.15  root      449: busdata
1.1.1.16  root      450: MFPDevice::PeekPort(uint32 offset)
1.1       root      451: {
                    452:        uint8 data;
                    453: 
1.1.1.8   root      454:        switch (offset) {
1.1       root      455:         case MFP::GPIP:
                    456:                data = mfp.gpip;
                    457:                break;
                    458:         case MFP::AER:
                    459:                data = mfp.aer;
                    460:                break;
                    461:         case MFP::DDR:
                    462:                data = mfp.ddr;
                    463:                break;
                    464:         case MFP::IERA:
                    465:                data = mfp.ier.a;
                    466:                break;
                    467:         case MFP::IERB:
                    468:                data = mfp.ier.b;
                    469:                break;
                    470:         case MFP::IPRA:
                    471:                data = mfp.ipr.a;
                    472:                break;
                    473:         case MFP::IPRB:
                    474:                data = mfp.ipr.b;
                    475:                break;
                    476:         case MFP::ISRA:
                    477:                data = mfp.isr.a;
                    478:                break;
                    479:         case MFP::ISRB:
                    480:                data = mfp.isr.b;
                    481:                break;
                    482:         case MFP::IMRA:
                    483:                data = mfp.imr.a;
                    484:                break;
                    485:         case MFP::IMRB:
                    486:                data = mfp.imr.b;
                    487:                break;
                    488:         case MFP::VR:
1.1.1.7   root      489:                data = mfp.GetVR();
1.1       root      490:                break;
                    491:         case MFP::TACR:
1.1.1.16  root      492:                data = mfp.timer[0].tcr;
1.1       root      493:                break;
                    494:         case MFP::TBCR:
1.1.1.16  root      495:                data = mfp.timer[1].tcr;
1.1       root      496:                break;
                    497:         case MFP::TCDCR:
1.1.1.16  root      498:                data = mfp.GetTCDCR();
1.1       root      499:                break;
                    500:         case MFP::TADR:
                    501:                data = GetTDR(0);
                    502:                break;
                    503:         case MFP::TBDR:
                    504:                data = GetTDR(1);
                    505:                break;
                    506:         case MFP::TCDR:
                    507:                data = GetTDR(2);
                    508:                break;
                    509:         case MFP::TDDR:
                    510:                data = GetTDR(3);
                    511:                break;
                    512:         case MFP::SCR:
                    513:                data = mfp.scr;
                    514:                break;
                    515:         case MFP::UCR:
                    516:                data = mfp.ucr;
                    517:                break;
                    518:         case MFP::RSR:
                    519:                data = mfp.rsr;
                    520:                break;
                    521:         case MFP::TSR:
                    522:                data = mfp.tsr;
                    523:                break;
                    524:         case MFP::UDR:
                    525:                data = mfp.udr;
                    526:                break;
1.1.1.4   root      527:         default:
                    528:                data = 0xff;
1.1       root      529:        }
                    530:        return data;
                    531: }
                    532: 
1.1.1.16  root      533: bool
                    534: MFPDevice::PokePort(uint32 offset, uint32 data)
                    535: {
                    536:        return false;
                    537: }
                    538: 
1.1.1.5   root      539: void
1.1.1.21! root      540: MFPDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root      541: {
1.1.1.15  root      542:        MFP mfp_;
                    543:        std::array<uint8, 4> tdr_;
1.1       root      544:        int x;
                    545:        int y;
                    546: 
1.1.1.15  root      547:        // ローカルにコピー。
                    548:        memcpy(&mfp_, &mfp, sizeof(mfp));
                    549:        for (int ch = 0; ch < tdr_.size(); ch++) {
                    550:                tdr_[ch] = GetTDR(ch);
                    551:        }
                    552: 
1.1.1.10  root      553:        screen.Clear();
1.1       root      554: 
                    555:        // 0         1         2         3         4         5         6
1.1.1.7   root      556:        // 01234567890123456789012345678901234567890123456789012345678901234567890
                    557:        // $e88001(GPIP):$00   $e88007(IERA):$00   $e88019(TACR):$00   $e88027
1.1.1.13  root      558:        //                 IER    IMR  IPR  ISR            Mode        TDR Cnt
                    559:        // An:MPSC TxEmpty Enable Mask Pend Serv   Timer-A Delay(50us) 255 255
1.1       root      560: 
1.1.1.7   root      561: #define A(x)   (baseaddr + (x * 2) + 1)
                    562: 
                    563:        // レジスタ生値
                    564:        // 1列目(GPIP 関連と VR)
                    565:        x = 0;
                    566:        y = 0;
1.1.1.15  root      567:        screen.Print(x, y++, "$%06x(GPIP):$%02x", A(MFP::GPIP), mfp_.gpip);
                    568:        screen.Print(x, y++, "$%06x(AER): $%02x", A(MFP::AER),  mfp_.aer);
                    569:        screen.Print(x, y++, "$%06x(DDR): $%02x", A(MFP::DDR),  mfp_.ddr);
                    570:        screen.Print(x, y++, "$%06x(VR):  $%02x", A(MFP::VR),   mfp_.GetVR());
1.1.1.7   root      571:        // 2列目(割り込み関連)
                    572:        x = 20;
                    573:        y = 0;
1.1.1.15  root      574:        screen.Print(x, y++, "$%06x(IERA):$%02x", A(MFP::IERA), mfp_.ier.a);
                    575:        screen.Print(x, y++, "$%06x(IERB):$%02x", A(MFP::IERB), mfp_.ier.b);
                    576:        screen.Print(x, y++, "$%06x(IPRA):$%02x", A(MFP::IPRA), mfp_.ipr.a);
                    577:        screen.Print(x, y++, "$%06x(IPRB):$%02x", A(MFP::IPRB), mfp_.ipr.b);
                    578:        screen.Print(x, y++, "$%06x(ISRA):$%02x", A(MFP::ISRA), mfp_.isr.a);
                    579:        screen.Print(x, y++, "$%06x(ISRB):$%02x", A(MFP::ISRB), mfp_.isr.b);
                    580:        screen.Print(x, y++, "$%06x(IMRA):$%02x", A(MFP::IMRA), mfp_.imr.a);
                    581:        screen.Print(x, y++, "$%06x(IMRB):$%02x", A(MFP::IMRB), mfp_.imr.b);
1.1.1.7   root      582:        // 3列目(タイマー関連)
                    583:        x = 40;
                    584:        y = 0;
1.1.1.16  root      585:        screen.Print(x, y++, "$%06x(TACR): $%02x", A(MFP::TACR), mfp_.timer[0].tcr);
                    586:        screen.Print(x, y++, "$%06x(TBCR): $%02x", A(MFP::TBCR), mfp_.timer[1].tcr);
                    587:        screen.Print(x, y++, "$%06x(TCDCR):$%02x", A(MFP::TCDCR), mfp_.GetTCDCR());
1.1.1.15  root      588:        screen.Print(x, y++, "$%06x(TADR): $%02x", A(MFP::TADR), tdr_[0]);
                    589:        screen.Print(x, y++, "$%06x(TBDR): $%02x", A(MFP::TBDR), tdr_[1]);
                    590:        screen.Print(x, y++, "$%06x(TCDR): $%02x", A(MFP::TCDR), tdr_[2]);
                    591:        screen.Print(x, y++, "$%06x(TDDR): $%02x", A(MFP::TDDR), tdr_[3]);
1.1.1.7   root      592:        // 4列目(USART 関連)
                    593:        x = 61;
                    594:        y = 0;
1.1.1.15  root      595:        screen.Print(x, y++, "$%06x(SCR):$%02x", A(MFP::SCR), mfp_.scr);
                    596:        screen.Print(x, y++, "$%06x(UCR):$%02x", A(MFP::UCR), mfp_.ucr);
                    597:        screen.Print(x, y++, "$%06x(RSR):$%02x", A(MFP::RSR), mfp_.rsr);
                    598:        screen.Print(x, y++, "$%06x(TSR):$%02x", A(MFP::TSR), mfp_.tsr);
1.1.1.10  root      599:        screen.Print(x, y, "$%06x(UDR):", A(MFP::UDR));
1.1.1.15  root      600:        if ((int16)mfp_.udr >= 0) {
                    601:                screen.Print(x + 13, y, "$%02x", mfp_.udr);
1.1.1.7   root      602:        } else {
1.1.1.10  root      603:                screen.Print(x + 13, y, "---");
1.1.1.7   root      604:        }
                    605: 
1.1       root      606:        // 割り込み関連
1.1.1.7   root      607:        y = 9;
1.1.1.10  root      608:        screen.Print(0, y++, "<Interrupt>     %-6s %-4s %-4s %-4s",
1.1.1.7   root      609:                "IER", "IMR", "IPR", "ISR");
1.1       root      610:        for (int i = 15; i >= 0; i--, y++) {
1.1.1.20  root      611:                uint16 mask = (1U << i);
1.1.1.16  root      612:                screen.Print(0, y, "%c%u:%-12s %-6s %-4s %-4s %-4s",
1.1       root      613:                        i >= 8 ? 'A' : 'B',
                    614:                        (i % 8),
                    615:                        intrname[i],
1.1.1.15  root      616:                        (mfp_.ier.w & mask) ? "Enable" : "",
                    617:                        (mfp_.imr.w & mask) ? ""       : "Mask",        // %0 でマスクする
                    618:                        (mfp_.ipr.w & mask) ? "Pend"   : "",
                    619:                        (mfp_.isr.w & mask) ? "Serv"   : "");
1.1       root      620:        }
                    621: 
                    622:        // タイマー関連
1.1.1.13  root      623:        x = 40;
1.1.1.7   root      624:        y = 9;
1.1.1.15  root      625:        screen.Print(x, y++, "<Timer> Mode        TDR Next");
1.1       root      626:        for (int ch = 0; ch < 4; ch++) {
1.1.1.10  root      627:                screen.Print(x, y, "Timer-%c", ch + 'A');
1.1.1.16  root      628:                uint8 tcr = mfp_.timer[ch].tcr;
                    629:                if (tcr == 0) {
1.1.1.10  root      630:                        screen.Print(x + 8, y, "Stopped");
1.1.1.19  root      631:                } else if (tcr < 8) {
                    632:                        screen.Print(x + 8, y, "Delay(%s)", prescale_str[tcr]);
1.1.1.16  root      633:                } else if (tcr == 8) {
1.1.1.10  root      634:                        screen.Print(x + 8, y, "Event");
1.1       root      635:                } else {
1.1.1.19  root      636:                        screen.Print(x + 8, y, "Pulse(%s)", prescale_str[tcr - 8]);
1.1       root      637:                }
                    638: 
1.1.1.16  root      639:                screen.Print(x + 20, y, "%3u", tdr_[ch]);
                    640:                screen.Print(x + 25, y, "%3u", mfp_.timer[ch].next_tdr & 0xff);
1.1.1.7   root      641:                y++;
1.1       root      642:        }
                    643: 
                    644:        // GPIP 関連
1.1.1.13  root      645:        x = 40;
1.1.1.7   root      646:        y = 9 + 8;
1.1.1.10  root      647:        screen.Puts(x, y++, "<GPIP>    GPIP AER DDR");
1.1       root      648:        for (int i = 7; i >= 0; i--, y++) {
1.1.1.20  root      649:                uint mask = (1U << i);
1.1.1.16  root      650:                screen.Print(x, y, "b%u %-6s  %u   %u   %s", i, gpipname[i],
1.1.1.15  root      651:                        (mfp_.gpip & mask) ? 1 : 0,
                    652:                        (mfp_.aer & mask) ? 1 : 0,
                    653:                        (mfp_.ddr & mask) ? "OUT" : "IN");
1.1       root      654:        }
                    655: }
                    656: 
                    657: /*static*/ const char *
                    658: MFPDevice::intrname[] = {
                    659:        "RTC Alarm",
                    660:        "EXPON",
                    661:        "POW SW",
                    662:        "FM IRQ",
                    663:        "Timer-D",
                    664:        "Timer-C",
                    665:        "V-Disp",
                    666:        "---",
                    667:        "Timer-B",
                    668:        "MPSC TxErr",
                    669:        "MPSC TxEmpty",
                    670:        "MPSC RxErr",
                    671:        "MPSC RxFull",
                    672:        "Timer-A",
                    673:        "CRTC IRQ",
                    674:        "H-Sync",
                    675: };
                    676: 
                    677: /*static*/ const char *
                    678: MFPDevice::gpipname[] = {
                    679:        "ALARM",
                    680:        "EXPON",
                    681:        "POW SW",
                    682:        "FMIRQ",
                    683:        "V-Disp",
                    684:        "------",
                    685:        "CIRQ",
                    686:        "H-Sync",
                    687: };
                    688: 
                    689: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
1.1.1.19  root      690: /*static*/ const uint64
1.1.1.21! root      691: MFPDevice::prescale_tsec[8] = {
1.1       root      692:        0,
1.1.1.19  root      693:        1000_nsec,      // /4
                    694:        2500_nsec,      // /10
                    695:        4000_nsec,      // /16
                    696:        12500_nsec,     // /50
                    697:        16000_nsec,     // /64
                    698:        25000_nsec,     // /100
                    699:        50000_nsec,     // /200
1.1       root      700: };
                    701: 
                    702: /*static*/ const char *
                    703: MFPDevice::prescale_str[8] = {
                    704:        "",
                    705:        "1us",
                    706:        "2.5us",
                    707:        "4us",
                    708:        "12.5us",
                    709:        "16us",
                    710:        "25us",
                    711:        "50us",
                    712: };
                    713: 
1.1.1.7   root      714: // タイマーのチャンネルから MFP 割り込みチャンネル番号に変換する
1.1.1.16  root      715: /*static*/ const uint
1.1.1.4   root      716: MFPDevice::timer_vector[4] = {
                    717:        MFP::INTR_TIMER_A,
                    718:        MFP::INTR_TIMER_B,
                    719:        MFP::INTR_TIMER_C,
                    720:        MFP::INTR_TIMER_D,
                    721: };
1.1       root      722: 
1.1.1.19  root      723: // IER[AB] に new_ier (16 ビット全体) をセットする。
1.1.1.15  root      724: void
1.1.1.19  root      725: MFPDevice::SetIER(uint16 new_ier)
1.1.1.15  root      726: {
1.1.1.19  root      727:        // raising はこの書き込みで %0 -> %1 に変化するビットだけを立てたもの、
                    728:        // falling はこの書き込みで %1 -> %0 に変化するビットだけを立てたもの。
                    729:        uint16 raising = new_ier   & (mfp.ier.w ^ new_ier);
                    730:        uint16 falling = mfp.ier.w & (mfp.ier.w ^ new_ier);
                    731: 
                    732:        // タイマー用の event[] は、割り込みを起こす必要がある時しか回さない
                    733:        // 構造なので、割り込みなしでスタートしたタイマーをその動作中に後から
                    734:        // 割り込み許可に変更したら、ここで何事もなかったようにタイマーイベントを
                    735:        // 開始しなければいけない。
                    736:        for (int ch = 0; ch < countof(mfp.timer); ch++) {
                    737:                uint timer_mask = 1U << timer_vector[ch];
                    738:                if ((raising & timer_mask) != 0 && mfp.timer[ch].IsDelay()) {
1.1.1.20  root      739:                        event[ch]->SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1.1.19  root      740:                        RestartTimerEvent(ch);
                    741:                }
                    742:        }
1.1.1.15  root      743: 
                    744:        // IER を下げたところは IPR も下げる。(紙資料 p4-4)
1.1.1.19  root      745:        mfp.ipr.w &= ~falling;
1.1.1.15  root      746: 
                    747:        // どちらにしても新しい IER によって信号線の状態は変える。
1.1.1.19  root      748:        mfp.ier.w = new_ier;
1.1.1.15  root      749:        ChangeInterrupt();
                    750: }
                    751: 
1.1.1.19  root      752: // このタイマーの現在のメインカウンタの値を求める。
                    753: inline uint8
                    754: MFP::Timer::GetCounter(uint64 now, uint64 period) const
                    755: {
                    756:        uint8 data = tdr - (((now - start) / period) % tdr);
                    757:        return data;
                    758: }
                    759: 
1.1       root      760: // TxCR をセットする
                    761: void
                    762: MFPDevice::SetTCR(int ch, uint32 data)
                    763: {
1.1.1.19  root      764:        MFP::Timer& timer = mfp.timer[ch];
1.1       root      765:        uint32 prev;
                    766: 
1.1.1.19  root      767:        prev = timer.tcr;
1.1       root      768:        data &= 0x0f;
                    769: 
1.1.1.19  root      770:        timer.tcr = data;
1.1.1.7   root      771:        if (data == 0) {
                    772:                if (prev == 0) {
                    773:                        // 0 -> 0 なら何も起きない
                    774:                        return;
                    775:                } else if (prev < 8) {
                    776:                        // タイマー停止
1.1.1.13  root      777:                        putlog(1, "Timer-%c Stop", ch + 'A');
1.1.1.7   root      778: 
                    779:                        // ここで TDR を確定させる。
1.1.1.19  root      780:                        // タイマー動作中の TDR の参照はイベント開始時刻から求めていたが
                    781:                        // イベントを停止すると求められなくなるので、停止前に求めておく。
1.1.1.21! root      782:                        uint64 period = prescale_tsec[prev];
1.1.1.14  root      783:                        uint64 now = scheduler->GetVirtTime();
1.1.1.19  root      784:                        mfp.timer[ch].tdr = timer.GetCounter(now, period);
1.1.1.7   root      785: 
                    786:                        // でイベント停止
1.1.1.19  root      787:                        StopTimerEvent(ch);
1.1.1.7   root      788:                        return;
                    789:                } else if (prev == 8) {
                    790:                        // イベントカウントモードから停止しても何も起きないはず
                    791:                } else {
                    792:                        // パルス幅測定モード (未実装)
                    793:                }
1.1       root      794:                return;
1.1.1.7   root      795: 
                    796:        } else if (data < 8) {
1.1.1.19  root      797:                // タイマー開始。
1.1.1.7   root      798: 
1.1.1.19  root      799:                // タイマー開始時は TDR はリロードしない。
                    800:                // 割り込みを上げる必要がある時だけイベントを使う。
                    801: 
1.1.1.21! root      802:                uint64 period = prescale_tsec[data];
1.1.1.19  root      803:                uint64 now = scheduler->GetVirtTime();
                    804:                timer.start = now;
                    805:                if (IsTimerIntrEnable(ch)) {
1.1.1.20  root      806:                        event[ch]->time = period * timer.tdr;
                    807:                        event[ch]->SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1.1.19  root      808:                        if (sync_rt) {
                    809:                                // 自分の実時間軸の基準をここにする。
                    810:                                stime[ch] = syncer->GetRealTime();
                    811:                                // event.time はこの後変動するので、周期は別で覚えておく。
1.1.1.20  root      812:                                rt_period[ch] = event[ch]->time;
1.1.1.19  root      813: 
                    814:                                scheduler->StartRealtimeEvent(event[ch],
                    815:                                        stime[ch], rt_period[ch]);
                    816:                        } else {
                    817:                                scheduler->RestartEvent(event[ch]);
                    818:                        }
                    819:                } else {
1.1.1.20  root      820:                        event[ch]->SetName(string_format("MFP Timer-%c FreeRun", ch + 'A'));
1.1.1.19  root      821:                }
1.1.1.7   root      822: 
1.1.1.21! root      823:                putlog(1, "Timer-%c Start Delay mode(%u x %.1fusec)",
1.1.1.7   root      824:                        ch + 'A',
1.1.1.19  root      825:                        timer.tdr,
1.1.1.21! root      826:                        (double)period / 1_usec);
1.1.1.7   root      827:                return;
                    828: 
                    829:        } else if (data == 8) {
1.1       root      830:                // イベントカウントモード
                    831: 
                    832:                // TDR をロードする
1.1.1.19  root      833:                timer.next_tdr = timer.tdr;
1.1.1.13  root      834:                putlog(1, "Timer-%c Event count mode", ch + 'A');
1.1.1.19  root      835:                StopTimerEvent(ch);
1.1       root      836:                return;
                    837: 
                    838:        } else {
1.1.1.13  root      839:                putlog(0, "T%cCR Pulse-Width Measurement Mode $%02x (NOT IMPLEMENTED)",
1.1.1.7   root      840:                        ch + 'A', data);
1.1.1.19  root      841:                StopTimerEvent(ch);
1.1.1.7   root      842:                return;
1.1       root      843:        }
                    844: }
                    845: 
                    846: // TxDR の読み出し
1.1.1.7   root      847: // (副作用はないので Peek 系からも呼び出してよい)
1.1       root      848: uint8
1.1.1.3   root      849: MFPDevice::GetTDR(int ch) const
1.1       root      850: {
1.1.1.19  root      851:        const MFP::Timer& timer = mfp.timer[ch];
1.1       root      852: 
1.1.1.19  root      853:        if (timer.IsStopped()) {
1.1.1.7   root      854:                // 停止中なら tdr に現在値が保持されている
1.1.1.19  root      855:                return timer.tdr & 0xff;
1.1.1.7   root      856: 
1.1.1.19  root      857:        } else if (timer.IsDelay()) {
                    858:                // ディレイモード動作中なら現在値は保持していないので、算出する。
                    859:                // XXX sync_rt == true で割り込み有効にしているタイマーの
                    860:                //     TDR を読み出しても割り込みと整合しないがもう仕方ない。
1.1.1.21! root      861:                uint64 period = prescale_tsec[timer.tcr];
1.1.1.14  root      862:                uint64 now = scheduler->GetVirtTime();
1.1.1.19  root      863:                return timer.GetCounter(now, period);
1.1       root      864: 
1.1.1.7   root      865:        } else {
                    866:                // イベントモード、パルス幅測定モードは未対応
1.1.1.19  root      867:                return timer.tdr & 0xff;
1.1       root      868: 
1.1.1.7   root      869:        }
1.1       root      870: }
                    871: 
                    872: // TxDR への書き込み
                    873: void
                    874: MFPDevice::SetTDR(int ch, uint32 data)
                    875: {
1.1.1.19  root      876:        MFP::Timer& timer = mfp.timer[ch];
1.1       root      877: 
1.1.1.15  root      878:        if (data == 0) {
                    879:                data = 256;
                    880:        }
1.1.1.19  root      881:        timer.next_tdr = data;
1.1.1.15  root      882: 
1.1.1.19  root      883:        if (timer.IsStopped()) {
1.1.1.15  root      884:                // 停止中の書き込みはメインカウンタも更新。
1.1.1.19  root      885:                timer.tdr = data;
1.1.1.7   root      886: 
1.1.1.19  root      887:        } else if (timer.IsDelay()) {
1.1.1.15  root      888:                // ディレイモード動作中の書き込みは
                    889:                // メインカウンタは影響を受けない。
1.1.1.19  root      890:                // 割り込みが回っていれば次の TimerCallback() で自動的にリロードされる
                    891:                // ので、ここでは何もしなくてよい。
                    892:                // フリーランの場合は、仕方ないので次のタイムアウトパルスで
                    893:                // 1回コールバックを呼んでリロードしてもらう。
                    894:                if (IsTimerIntrEnable(ch) == false) {
                    895:                        RestartTimerEvent(ch);
                    896:                }
1.1       root      897: 
1.1.1.7   root      898:        } else {
                    899:                // イベントモード、パルス幅測定モードは未対応
1.1.1.13  root      900:                putlog(0, "Write T%cDR $%02x during unsupported mode (NOT IMPLEMENTED)",
1.1.1.19  root      901:                        ch + 'A', timer.next_tdr);
1.1       root      902:        }
                    903: }
                    904: 
                    905: // イベントコールバック
                    906: void
1.1.1.20  root      907: MFPDevice::TimerCallback(Event *ev)
1.1       root      908: {
1.1.1.20  root      909:        int ch = ev->code;
1.1.1.19  root      910:        MFP::Timer& timer = mfp.timer[ch];
1.1       root      911: 
1.1.1.7   root      912:        // TDR がゼロになったところで呼ばれるので、TDR をリロードする
1.1.1.19  root      913:        if (__predict_false(timer.tdr != timer.next_tdr)) {
                    914:                timer.tdr = timer.next_tdr;
                    915:                timer.start = 0;
                    916:                // TDR (のリロード値) が変わったのでタイマー周りも再設定。
1.1.1.21! root      917:                uint64 period = prescale_tsec[timer.tcr];
1.1.1.20  root      918:                ev->time = period * timer.tdr;
1.1.1.19  root      919:                if (sync_rt) {
1.1.1.20  root      920:                        rt_period[ch] = ev->time;
1.1.1.19  root      921:                }
                    922:        }
                    923: 
                    924:        // カウントが変わったり基準点がまだなければ、基準点も更新。
                    925:        if (__predict_false(timer.start == 0)) {
                    926:                uint64 now = scheduler->GetVirtTime();
                    927:                timer.start = now;
                    928:        }
1.1       root      929: 
1.1.1.7   root      930:        // 割り込みを上げる
                    931:        SetInterrupt(timer_vector[ch]);
                    932: 
1.1.1.19  root      933:        // 次回の割り込みを起こす必要があれば、次のイベントをセット。
                    934:        // フリーラン動作中に TCR を書き換えられた時にはワンショットで来る。
                    935:        if (__predict_true(IsTimerIntrEnable(ch))) {
                    936:                if (sync_rt) {
                    937:                        // 実時間追従動作の場合。
                    938: 
                    939:                        // 足す前は前回の割り込み発生時刻なので、足すと現在時刻。
                    940:                        stime[ch] += rt_period[ch];
1.1.1.7   root      941: 
1.1.1.19  root      942:                        scheduler->StartRealtimeEvent(ev, stime[ch], rt_period[ch]);
                    943:                } else {
                    944:                        scheduler->RestartEvent(ev);
                    945:                }
                    946:        } else {
                    947:                // タイマー動作中に IER を下げた時にはここで次回以降のイベントを停止。
1.1.1.20  root      948:                ev->SetName(string_format("MFP Timer-%c FreeRun", ch + 'A'));
1.1.1.19  root      949:        }
                    950: }
                    951: 
                    952: // 次のタイムアウトパルス時刻にイベントを起こす。
                    953: void
                    954: MFPDevice::RestartTimerEvent(int ch)
                    955: {
                    956:        MFP::Timer& timer = mfp.timer[ch];
                    957: 
                    958:        assert(timer.start != 0);
                    959: 
                    960:        uint64 now = scheduler->GetVirtTime();
1.1.1.21! root      961:        uint64 period = prescale_tsec[timer.tcr];
1.1.1.19  root      962:        uint64 timeout = period * timer.tdr;
1.1.1.20  root      963:        event[ch]->time = timeout - ((now - timer.start) % timeout);
1.1.1.19  root      964:        scheduler->RestartEvent(event[ch]);
                    965: }
                    966: 
                    967: // タイマーイベントを停止する。
                    968: void
                    969: MFPDevice::StopTimerEvent(int ch)
                    970: {
                    971:        scheduler->StopEvent(event[ch]);
1.1.1.20  root      972:        event[ch]->SetName(string_format("MFP Timer-%c Stopped", ch + 'A'));
1.1.1.19  root      973:        mfp.timer[ch].start = 0;
                    974: }
                    975: 
                    976: // タイマー割り込みを行うなら true を返す。
                    977: // タイマーの動作、停止状態ではなく、あくまで割り込み設定のほう。
                    978: bool
                    979: MFPDevice::IsTimerIntrEnable(int ch) const
                    980: {
                    981:        // 割り込みを起こすかどうかは IER のみで決まる。
                    982:        return ((mfp.ier.w & (1U << timer_vector[ch])) != 0);
1.1.1.12  root      983: }
                    984: 
                    985: // HSync 入力
                    986: void
                    987: MFPDevice::SetHSync(bool hsync)
                    988: {
                    989:        SetGPIP(MFP::GPIP_HSYNC, hsync);
1.1       root      990: }
                    991: 
                    992: // VDisp 入力
                    993: void
                    994: MFPDevice::SetVDisp(bool vdisp)
                    995: {
1.1.1.19  root      996:        MFP::Timer& timer = mfp.timer[0];
                    997: 
1.1       root      998:        // TAI への入力はイベントカウントモードの時のみ
1.1.1.19  root      999:        if (timer.IsEvent()) {
1.1       root     1000:                // AER が示す方向と同じエッジ方向の時
1.1.1.20  root     1001:                bool aer = (mfp.aer & (1U << MFP::GPIP_VDISP));
1.1       root     1002:                if (aer == vdisp) {
                   1003:                        // カウンタを減算
1.1.1.19  root     1004:                        timer.tdr--;
                   1005:                        if (timer.tdr == 0) {
1.1       root     1006:                                // 0 になったらリロード
1.1.1.19  root     1007:                                timer.tdr = timer.next_tdr;
1.1       root     1008: 
1.1.1.7   root     1009:                                SetInterrupt(MFP::INTR_TIMER_A);
1.1       root     1010:                        }
                   1011:                }
                   1012:        }
                   1013: 
                   1014:        // GPIP への入力
                   1015:        SetGPIP(MFP::GPIP_VDISP, vdisp);
                   1016: }
                   1017: 
1.1.1.13  root     1018: // 電源ボタン状態入力 (PowerDevice から呼ばれる)
                   1019: void
                   1020: MFPDevice::SetPowSW(bool powsw)
                   1021: {
                   1022:        SetGPIP(MFP::GPIP_POWSW, powsw);
                   1023: }
                   1024: 
                   1025: // ALARM 信号入力 (RTC の ALARM_OUT 出力端子)
                   1026: void
                   1027: MFPDevice::SetAlarmOut(bool alarm)
                   1028: {
                   1029:        SetGPIP(MFP::GPIP_ALARM, alarm);
                   1030: }
                   1031: 
1.1       root     1032: // GPIP への入力。
                   1033: // num はビット番号(0..7)。
                   1034: void
                   1035: MFPDevice::SetGPIP(int num, bool val)
                   1036: {
1.1.1.20  root     1037:        bool aer = (mfp.aer & (1U << num));
                   1038:        bool old = (mfp.gpip & (1U << num));
1.1       root     1039: 
                   1040:        // 立ち上がりか立ち下がりで割り込みを上げる (AER による)
                   1041:        // AER OLD VAL   Interrupt
                   1042:        //   0   0   0   0
                   1043:        //   0   0   1   0
                   1044:        //   0   1   0   1
                   1045:        //   0   1   1   0
                   1046:        //   1   0   0   0
                   1047:        //   1   0   1   1
                   1048:        //   1   1   0   0
                   1049:        //   1   1   1   0
1.1.1.3   root     1050:        if ((old != val) && (aer == val)) {
1.1.1.13  root     1051:                // ここで割り込みを上げる
                   1052:                // XXX GPIP ビット番号と INTR の対応どうなってんの
                   1053:                int intr;
                   1054:                if (num < 4) {
                   1055:                        intr = num;
                   1056:                } else if (num < 6) {
                   1057:                        intr = num + 2;
                   1058:                } else {
                   1059:                        intr = num - MFP::GPIP_CIRQ + MFP::INTR_CRTC_IRQ;
                   1060:                }
                   1061:                SetInterrupt(intr);
1.1       root     1062:        }
                   1063: 
                   1064:        if (val) {
1.1.1.20  root     1065:                mfp.gpip |= (1U << num);
1.1       root     1066:        } else {
1.1.1.20  root     1067:                mfp.gpip &= ~(1U << num);
1.1       root     1068:        }
                   1069: }
1.1.1.4   root     1070: 
                   1071: // UCR への書き込み
                   1072: void
                   1073: MFPDevice::SetUCR(uint32 data)
                   1074: {
                   1075:        mfp.ucr = data;
                   1076: 
                   1077:        if ((mfp.ucr & MFP::UCR_CLK) == 0) {
1.1.1.13  root     1078:                putlog(0, "UCR CLK=0 (NOT IMPLEMENTED)");
1.1.1.4   root     1079:        }
                   1080:        if (((mfp.ucr & MFP::UCR_WL) >> 5) != 0) {
1.1.1.16  root     1081:                putlog(0, "UCR WL=%u (NOT IMPLEMENTED)", (mfp.ucr >> 5) & 3);
1.1.1.4   root     1082:        }
                   1083:        if (((mfp.ucr & MFP::UCR_ST) >> 3) != 1) {
1.1.1.16  root     1084:                putlog(0, "UCR ST=%u (NOT IMPLEMENTED)", (mfp.ucr >> 3) & 3);
1.1.1.4   root     1085:        }
                   1086: }
                   1087: 
                   1088: // RSR への書き込み
                   1089: void
                   1090: MFPDevice::SetRSR(uint32 data)
                   1091: {
                   1092:        uint32 old = mfp.rsr;
                   1093: 
                   1094:        mfp.rsr = data;
                   1095: 
                   1096:        if ((old & MFP::RSR_RE) == 0 && (mfp.rsr & MFP::RSR_RE)) {
                   1097:                // RE 0 -> 1
                   1098:        }
                   1099:        if ((old & MFP::RSR_RE) && (mfp.rsr & MFP::RSR_RE) == 0) {
                   1100:                // RE 1 -> 0
1.1.1.9   root     1101:                // 上位4ビットのステータスを %0 に
                   1102:                mfp.rsr &= ~(MFP::RSR_OE | MFP::RSR_PE | MFP::RSR_FE);
                   1103:                ClearBF();
1.1.1.4   root     1104:        }
                   1105: }
                   1106: 
1.1.1.9   root     1107: // RSR::BF (Buffer Full) をセットする
                   1108: void
                   1109: MFPDevice::SetBF()
                   1110: {
                   1111:        mfp.rsr |= MFP::RSR_BF;
                   1112: }
                   1113: 
                   1114: // RSR::BF (Buffer Full) をクリアする
                   1115: void
                   1116: MFPDevice::ClearBF()
                   1117: {
                   1118:        mfp.rsr &= ~MFP::RSR_BF;
                   1119: 
                   1120:        // バッファが空いたのでキーボードに次の転送を催促。
                   1121:        // 実際のハードウェアでは、キーボードが本体 MFP が Ready になるのを待って
                   1122:        // いるが、それに相当。
                   1123:        // システムポートの KEYCTRL はキーボード側で処理している。
1.1.1.16  root     1124:        if (RxIsReady()) {
                   1125:                keyboard->Ready();
                   1126:        }
1.1.1.9   root     1127: }
                   1128: 
1.1.1.4   root     1129: // UDR への書き込み
                   1130: void
                   1131: MFPDevice::SetUDR(uint32 data)
                   1132: {
                   1133:        if ((mfp.tsr & MFP::TSR_TE)) {
1.1.1.14  root     1134:                keyboard->Command(data);
1.1.1.4   root     1135:        }
                   1136: }
                   1137: 
1.1.1.9   root     1138: // __
                   1139: // RR 線の状態を返す。アサートなら true。
                   1140: bool
                   1141: MFPDevice::IsRR() const
1.1.1.4   root     1142: {
1.1.1.9   root     1143:        //        __
                   1144:        // 実際の RR 信号線は、BF が立っていて、PE | FE がクリアされている場合に
                   1145:        // アサートされる。ただしエミュレータでは Parity Error も Frame Error も
                   1146:        // 起きないので、この2ビットは無視する。
                   1147:        return ((mfp.rsr & MFP::RSR_BF) != 0);
1.1.1.4   root     1148: }
                   1149: 
1.1.1.9   root     1150: // キーボードからの受信が可能なら true を返す。
1.1.1.4   root     1151: bool
1.1.1.9   root     1152: MFPDevice::RxIsReady() const
1.1.1.4   root     1153: {
1.1.1.9   root     1154:        // __
                   1155:        // RR は本来 MFP から CPU/DMAC など上位に対しての Ready で、
                   1156:        // UDR にデータが用意できたので引き取ってほしいの意。
                   1157:        // X680x0 ではこれを CPU/DMAC (上位) 向けではなく、下位のキーボードからの
                   1158:        // フロー制御に流用しており、
                   1159:        // 上位への(本来の)「UDR にデータが用意できた」(IsRR() = true) は、
                   1160:        // キーボードに対しては「UDR にデータがあるので送信禁止」、
                   1161:        // 上位への(本来の)「UDR にデータが用意できていない」(IsRR() = false) は、
                   1162:        // キーボードに対しては「UDR は空いているので送信してよい」と
                   1163:        // ここで意味が論理反転することに注意。
                   1164:        //
                   1165:        // また、システムポートの KEYCTRL は X680x0Keyboard 側で処理しているので
                   1166:        // こちらでは不要。
                   1167:        //
                   1168:        // UDR が空いていてキーボードからデータが送られてきている間は RR は Ready
                   1169:        // だが、そもそもキーボードは送出作業中で、新たな送信はできないはずなので
                   1170:        // この場合、つまり key_event の動作中も false (送信不可) にする。
                   1171: 
1.1.1.20  root     1172:        return !IsRR() && !key_event->IsRunning();
1.1.1.4   root     1173: }
                   1174: 
                   1175: // キーボードからデータを受信
                   1176: void
                   1177: MFPDevice::Rx(uint32 data)
                   1178: {
1.1.1.9   root     1179:        // ここは受信したビットをシフトレジスタへ入れ始めたところに相当する
                   1180:        // ので、まだ Buffer Full は立てない。
1.1.1.4   root     1181: 
1.1.1.20  root     1182:        key_event->code = data;
1.1.1.14  root     1183:        scheduler->RestartEvent(key_event);
1.1.1.4   root     1184: }
                   1185: 
                   1186: // キーボードからのデータが受信し終わった頃に呼ばれるイベント。
                   1187: void
1.1.1.20  root     1188: MFPDevice::KeyCallback(Event *ev)
1.1.1.4   root     1189: {
1.1.1.9   root     1190:        // UDR にデータを置いて Buffer Full をセット
1.1.1.20  root     1191:        mfp.udr = ev->code;
1.1.1.9   root     1192:        SetBF();
                   1193: 
                   1194:        // Manual 7-5 7.2.1 Receiver Interrupt Channels より
                   1195:        // | 割り込みは1文字受信ごとに1回しか発生しませんが、2つの専用割り込み
                   1196:        // | チャネルにより、正常な受信状態と異常な受信状態に別々のベクター番号を
                   1197:        // | 割り当てることができます。受信したワードにエラーがあり、エラー割り込み
                   1198:        // | チャネルが有効な場合は、エラーチャネルのみに割り込みが発生します。
                   1199:        // | しかし、エラーチャネルが無効の場合、エラー状態の割り込みは、
                   1200:        // | バッファフル状態の割り込みと一緒にバッファフル割り込みチャネルに
                   1201:        // | 生成されます。どのエラー条件で割り込みが発生したかを判断するためには、
                   1202:        // | 常にRSRを読み出す必要があります。
                   1203:        // XXX: まだエラー状態は実装されていない、なおエラーは起きないので
                   1204:        // メモだけのままかも知れない。
1.1.1.4   root     1205: 
1.1.1.7   root     1206:        SetInterrupt(MFP::INTR_RXFULL);
                   1207: }
                   1208: 
                   1209: // 必要なら割り込みを上げる。
                   1210: // ch は MFP 内の割り込みチャンネル番号。MFP::INTR_*
                   1211: void
                   1212: MFPDevice::SetInterrupt(uint ch)
                   1213: {
                   1214:        assertmsg(ch < 16, "ch=%u", ch);
                   1215:        __assume(ch < 16);
                   1216: 
                   1217:        uint b = (1U << ch);
                   1218: 
                   1219:        // IER で割り込みが無効なら何もしない
                   1220:        if ((mfp.ier.w & b) == 0) {
                   1221:                return;
1.1.1.4   root     1222:        }
1.1.1.7   root     1223: 
                   1224:        // IPR にペンディングを立てる
                   1225:        mfp.ipr.w |= b;
                   1226: 
                   1227:        // 割り込み信号線の状態を変える
                   1228:        ChangeInterrupt();
                   1229: }
                   1230: 
                   1231: // 割り込み信号線の状態を変える
                   1232: void
                   1233: MFPDevice::ChangeInterrupt()
                   1234: {
                   1235:        // ペンディングの割り込みがあればアサートされる、
                   1236:        // IPR をクリアするか IMR をクリアすると /IRQ はネゲートされる。
                   1237:        bool irq = ((mfp.ipr.w & mfp.imr.w) != 0);
1.1.1.14  root     1238:        interrupt->ChangeINT(this, irq);
1.1.1.7   root     1239: }
                   1240: 
                   1241: // 割り込みアクノリッジ
1.1.1.15  root     1242: busdata
1.1.1.7   root     1243: MFPDevice::InterruptAcknowledge()
                   1244: {
1.1.1.15  root     1245:        busdata data;
                   1246: 
                   1247:        // IPR が誰も立ってなければ、無視するっぽい?
                   1248:        // 実際には MFP がバスエラーを出しているのではなく、MFP は俺知らない
                   1249:        // と思って放置してると上位回路 (たぶん SAKI ちゃん) がタイムアウトして
                   1250:        // MPU にバスエラー応答する。
1.1.1.7   root     1251:        uint32 pending = mfp.ipr.w;
1.1.1.15  root     1252:        if (__predict_false(pending == 0)) {
                   1253:                data.SetBusErr();
                   1254:        } else {
                   1255:                // ch はこの時点で IPR に立ってる一番優先度の高いチャンネルのビット
                   1256:                int ch = 31 - __builtin_clz(pending);
                   1257:                uint b = (1U << ch);
1.1.1.7   root     1258: 
1.1.1.15  root     1259:                // MPU にベクタを引き渡したので Pending をクリア
                   1260:                mfp.ipr.w &= ~b;
                   1261:                ChangeInterrupt();
1.1.1.7   root     1262: 
1.1.1.15  root     1263:                // ソフトウェア EOI なら In Service を立てる
                   1264:                if (mfp.vr_s) {
                   1265:                        mfp.isr.w |= b;
                   1266:                }
1.1.1.7   root     1267: 
1.1.1.15  root     1268:                data = mfp.vr_vec + ch;
1.1.1.7   root     1269:        }
                   1270: 
1.1.1.15  root     1271:        // /IEI ネゲート時の /IACK と /IEI の関係がいまいち分からないけど、
                   1272:        // とりあえず /IACK がアサートされてから 3 MFP クロック後に
                   1273:        // データバスにベクタを供給、次の 1 MFP クロックで DTACK 応答。
                   1274:        // で次の 1 MFP クロック以内に CPU が /IACK を下げるとして、
                   1275:        // 計 5 MFP クロック (= 1.25_usec) としておく。
                   1276:        const busdata intack_wait = busdata::Wait(5 * 250_nsec);
                   1277:        data |= intack_wait;
                   1278: 
                   1279:        return data;
1.1.1.4   root     1280: }
1.1.1.16  root     1281: 
                   1282: /*static*/ const char *
                   1283: MFPDevice::regname[MFP::RegMax] = {
                   1284:        "GPIP",
                   1285:        "AER",
                   1286:        "DDR",
                   1287:        "IERA",
                   1288:        "IERB",
                   1289:        "IPRA",
                   1290:        "IPRB",
                   1291:        "ISRA",
                   1292:        "ISRB",
                   1293:        "IMRA",
                   1294:        "IMRB",
                   1295:        "VR",
                   1296:        "TACR",
                   1297:        "TBCR",
                   1298:        "TCDCR",
                   1299:        "TADR",
                   1300:        "TBDR",
                   1301:        "TCDR",
                   1302:        "TDDR",
                   1303:        "SCR",
                   1304:        "UCR",
                   1305:        "RSR",
                   1306:        "TSR",
                   1307:        "UDR",
                   1308: };

unix.superglobalmegacorp.com

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