Annotation of nono/vm/pio.cpp, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.10! root        7: //
        !             8: // PIO/PPI (i8255)
        !             9: //
        !            10: 
        !            11: // IODevice
        !            12: //    |
        !            13: //    |  +-------------+
        !            14: //    +--| i8255Device | (8255 としての共通部分)
        !            15: //       +-------------+
        !            16: //          |
        !            17: //          |  +-----------+
        !            18: //          +--| PPIDevice |  (X68030)
        !            19: //          |  +-----------+
        !            20: //          |
        !            21: //          |  +------------+
        !            22: //          +--| PIO0Device | (LUNA)
        !            23: //          |  +------------+
        !            24: //          |
        !            25: //          |  +------------+
        !            26: //          +--| PIO1Device | (LUNA)
        !            27: //             +------------+
        !            28: 
1.1       root       29: #include "pio.h"
1.1.1.9   root       30: #include "bitops.h"
1.1.1.2   root       31: #include "config.h"
1.1       root       32: #include "lcd.h"
1.1.1.3   root       33: #include "mainapp.h"
1.1.1.10! root       34: #include "mpu.h"
        !            35: #include "power.h"
1.1       root       36: #include "scheduler.h"
                     37: 
1.1.1.10! root       38: // グローバル参照用
        !            39: PPIDevice *gPPI;
        !            40: PIO0Device *gPIO0;
        !            41: PIO1Device *gPIO1;
1.1       root       42: 
                     43: //
                     44: // i8255
                     45: //
                     46: 
                     47: // コンストラクタ
1.1.1.8   root       48: i8255Device::i8255Device(const std::string& objname_)
                     49:        : inherited(objname_)
1.1       root       50: {
                     51: }
                     52: 
                     53: // デストラクタ
                     54: i8255Device::~i8255Device()
                     55: {
                     56: }
                     57: 
1.1.1.4   root       58: // リセット
                     59: void
1.1.1.10! root       60: i8255Device::ResetHard(bool poweron)
1.1.1.4   root       61: {
                     62:        // clears the control register
                     63:        // and place ports A, B, and C in input mode.
                     64:        // The input latches in ports A, B, and C are not cleared.
                     65: 
                     66:        ctrl = 0b10011011;
                     67: }
                     68: 
1.1       root       69: // コントロールポートへの書き込み。
                     70: void
                     71: i8255Device::WriteCtrl(uint32 data)
                     72: {
                     73:        if ((data & 0x80)) {
                     74:                // 最上位が立っていればモード設定
                     75:                ctrl = data;
                     76:                putlog(1,
                     77:                        "モード設定 groupA=%d groupB=%d portA=%s portB=%s portC=%s/%s",
                     78:                        GetGroupAMode(), GetGroupBMode(),
                     79:                        PortADir() == DIR_IN ? "IN" : "OUT",
                     80:                        PortBDir() == DIR_IN ? "IN" : "OUT",
                     81:                        PortCHDir() == DIR_IN ? "IN" : "OUT",
                     82:                        PortCLDir() == DIR_IN ? "IN" : "OUT");
                     83: 
                     84:                // モード設定すると PC はゼロクリアされる
                     85:                for (int pc = 0; pc < 8; pc++) {
                     86:                        SetPC(pc, 0);
                     87:                }
                     88:        } else {
                     89:                // portC 出力
                     90:                //
                     91:                // 0  x  x  x  P  P  P  V
                     92:                //             |  |  |  +-- 書き込むビットデータ
                     93:                //             +--+--+----- 書き込むビット位置
                     94: 
                     95:                int pc = (data >> 1) & 7;
                     96:                int val = data & 1;
                     97:                SetPC(pc, val);
                     98:        }
                     99: }
                    100: 
                    101: //
                    102: // X68k PPI
                    103: //
                    104: 
                    105: // コンストラクタ
                    106: PPIDevice::PPIDevice()
1.1.1.8   root      107:        : inherited("PPI")
1.1       root      108: {
                    109:        devaddr = baseaddr;
                    110:        devlen  = 0x2000;
                    111: }
                    112: 
                    113: // デストラクタ
                    114: PPIDevice::~PPIDevice()
                    115: {
1.1.1.10! root      116:        gPPI = NULL;
1.1       root      117: }
                    118: 
                    119: uint64
1.1.1.6   root      120: PPIDevice::Read(uint32 offset)
1.1       root      121: {
1.1.1.4   root      122:        gMPU->AddCycle(19);     // InsideOut p.135
                    123: 
1.1.1.6   root      124:        switch (offset) {
1.1       root      125:         case 0:
                    126:         case 1:
                    127:                return 0xff;
                    128:         case 2:
1.1.1.6   root      129:                putlog(0, "$e9a005 PortC 未実装読み込み");
1.1.1.5   root      130:                return 0xff;
1.1       root      131:         case 3:
1.1.1.10! root      132:                VMPANIC("PPI $e9a007 未サポート読み込み");
1.1       root      133:         default:
                    134:                __unreachable();
                    135:        }
                    136: }
                    137: 
                    138: uint64
1.1.1.6   root      139: PPIDevice::Write(uint32 offset, uint32 data)
1.1       root      140: {
1.1.1.4   root      141:        gMPU->AddCycle(19);     // InsideOut p.135
                    142: 
1.1.1.6   root      143:        switch (offset) {
1.1       root      144:         case 0:
                    145:         case 1:
                    146:                break;
                    147:         case 2:
1.1.1.6   root      148:                putlog(0, "$e9a005 未実装書き込み $%02X (無視)", data);
1.1       root      149:                break;
                    150:         case 3:
                    151:                if (data != 0x92) {
1.1.1.10! root      152:                        VMPANIC("PPI $e9a007 未実装書き込み $%02X", data);
1.1       root      153:                } else {
1.1.1.6   root      154:                        putlog(0, "$e9a007 未実装書き込み $%02x (無視)", data);
1.1       root      155:                }
                    156:                break;
                    157:         default:
                    158:                __unreachable();
                    159:        }
                    160:        return 0;
                    161: }
                    162: 
                    163: uint64
1.1.1.6   root      164: PPIDevice::Peek(uint32 offset)
1.1       root      165: {
                    166:        // XXX
                    167:        return 0xff;
                    168: }
                    169: 
1.1.1.10! root      170: // PortC 書き込み
        !           171: void
        !           172: PPIDevice::SetPC(int pc, int data)
        !           173: {
        !           174:        VMPANIC("not impl");
        !           175: }
        !           176: 
1.1       root      177: //
                    178: // LUNA PIO0
                    179: //
                    180: // 仕様は 0x49000000 から 4バイトだが、
                    181: // 0x48000000 から 0x4c000000 の手前まで 4バイト単位でミラーが見える。
                    182: //
                    183: // LUNA の DIP-SW は #1, #2 にそれぞれ8個、計16個ある。
1.1.1.9   root      184: // DIP-SW #1, #2 が設定ファイルの luna-dipsw{1,2} に対応する。
                    185: // luna-dipsw{1,2} はいずれも "0"/"1" を8つ並べた文字列であり、
1.1       root      186: // 先頭が本体表記でいう 1番、末尾側が本体表記でいう 8番に対応する。
1.1.1.9   root      187: // 値は "0" が down、"1" が up を表す。
                    188: //
                    189: // PIO0Device 内ではこの設定を読み込んで bool dipsw1[8], dipsw2[8] の配列で
                    190: // 値を保持している。dipsw1[0] が本体表記1番、dipsw1[7] が本体表記 8番に対応
                    191: // する。値は false が down("0")、true が up("1") に対応する。
                    192: //
                    193: // PIO から読み出せる値のビットの並び順が機種によって異なる。
                    194: // LUNA-1  では 1番が LSB、8番が MSB の並び順、
                    195: // LUNA88K では 1番が MSB、8番が LSB の並び順。
                    196: // 値は、並び順に関わらずどちらも
                    197: // %0 が false = down = "0"、%1 が true = up = "1" である。
                    198: //
                    199: //    #1 #2 #3 #4 #5 #6 #7 #8
                    200: //  +-------------------------+
                    201: //  |    [] [] [] [] [] [] [] | 本体外観
                    202: //  | []                      |
                    203: //  +-------------------------+
                    204: //
                    205: // luna-dipsw1 = "01111111"    ← 設定ファイル
                    206: //                ||||||||     ↓ このクラスのメンバ変数
                    207: //                |||||||+- dipsw1[7] = true;
                    208: //                ||||||+-- dipsw1[6] = true;
                    209: //                |||||+--- dipsw1[5] = true;
                    210: //                ||||+---- dipsw1[4] = true;
                    211: //                |||+----- dipsw1[3] = true;
                    212: //                ||+------ dipsw1[2] = true;
                    213: //                |+------- dipsw1[1] = true;
                    214: //                +-------- dipsw1[0] = false;
                    215: //
                    216: //              b7   b6   b5   b4   b3   b2   b1   b0
                    217: //            +----+----+----+----+----+----+----+----+
                    218: // LUNA-1     | #8 | #7 | #6 | #5 | #4 | #3 | #2 | #1 |
                    219: // PortA      |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  0 | %1=UP, %0=DOWN
                    220: //            +----+----+----+----+----+----+----+----+
                    221: //
                    222: //              b7   b6   b5   b4   b3   b2   b1   b0
                    223: //            +----+----+----+----+----+----+----+----+
                    224: // LUNA88K    | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 |
                    225: // PortA      |  0 |  1 |  1 |  1 |  1 |  1 |  1 |  1 | %1=UP, %0=DOWN
                    226: //            +----+----+----+----+----+----+----+----+
1.1       root      227: //
1.1.1.3   root      228: // LUNA-1:
1.1       root      229: // #1-1 up なら UNIX をロードして移行。down なら ROM モニタで起動。
                    230: // #1-2 up ならディスプレイコンソール。down ならシリアルコンソール。
                    231: // #1-3 up - color display, down - force to have monochrome display
                    232: // #1-4 up - no write verification,
                    233: //      down - verification on every harddisk write operation
                    234: // #1-5 up - OS is UniOS-U (SystemV/COFF),
                    235: //      down - OS is UniOS (4.3BSD/a.out OMAGIC)
                    236: // #1-6 down - force monochrome display?
                    237: // #1-7 up - boot from local device, down - boot from network
                    238: // #1-8 up - normal boot, down - start diagnostics と書いてあるが
                    239: //      down にすると画面真っ暗で詳細不明。
                    240: //
                    241: // #2-x すべて up にすると /boot が自動的にカーネルを起動。一つでも down が
                    242: //      あれば /boot がプロンプトで停止。これは ROM ではなく NetBSD のブート
                    243: //      ローダの話。
                    244: //      どこか由来のソースコードらしいがたぶんビット演算を間違えている。
1.1.1.3   root      245: //
                    246: // LUNA88K:
                    247: // #1-1 up なら ROM モニタで停止、down ならマルチユーザブート。
                    248: //      OpenBSD カーネルも up なら UserKernelConfig で止まる模様?。
                    249: // #1-2 up なら外付けシリアルコンソール、down なら内蔵ビットマップ。
1.1.1.9   root      250: // #1-3..#1-7 は不明?
                    251: // #1-8 down なら自己診断後電源オフするようだ。
1.1.1.3   root      252: // #2-x はユーザ(?)
1.1       root      253: 
                    254: // コンストラクタ
                    255: PIO0Device::PIO0Device()
1.1.1.8   root      256:        : inherited("PIO0")
1.1       root      257: {
                    258:        devaddr = 0x49000000;
                    259:        devlen  = 4;
1.1.1.2   root      260: 
1.1.1.3   root      261:        // 機種固有パラメータ
                    262: 
                    263:        // LUNA-1 と LUNA88K で使いやすいように初期値を変えておく。
                    264:        switch (gMainApp.GetVMType()) {
                    265:         case VMTYPE_LUNA1:
                    266:                gConfig->SetDefault("luna-dipsw1", "11110111");
1.1.1.9   root      267:                msb_first = false;
1.1.1.3   root      268:                break;
                    269:         case VMTYPE_LUNA88K:
1.1.1.4   root      270:                gConfig->SetDefault("luna-dipsw1", "11111111");
1.1.1.9   root      271:                msb_first = true;
1.1.1.3   root      272:                break;
                    273:         default:
                    274:                __unreachable();
                    275:        }
                    276:        // DIP-SW#2 はユーザ定義(?)なので(今の所?)どちらも共通。
                    277:        gConfig->SetDefault("luna-dipsw2", "11111111");
                    278: 
1.1.1.10! root      279:        monitor.func = ToMonitorCallback(&PIO0Device::MonitorUpdate);
1.1.1.8   root      280:        monitor.SetSize(22, 11);
                    281:        monitor.Regist(ID_MONITOR_PIO0);
1.1       root      282: }
                    283: 
                    284: // デストラクタ
                    285: PIO0Device::~PIO0Device()
                    286: {
1.1.1.10! root      287:        gPIO0 = NULL;
1.1       root      288: }
                    289: 
                    290: bool
                    291: PIO0Device::Init()
                    292: {
                    293:        // XXX 本当はラッチのタイミングが違う気もするけど、とりあえずね
                    294: 
1.1.1.2   root      295:        const ConfigItem& item1 = gConfig->Find("luna-dipsw1");
1.1       root      296:        const std::string& str1 = item1.AsString();
                    297:        if (str1.size() != 8) {
                    298:                item1.Err("must be 8 digits");
                    299:                return false;
                    300:        }
                    301: 
1.1.1.2   root      302:        const ConfigItem& item2 = gConfig->Find("luna-dipsw2");
1.1       root      303:        const std::string& str2 = item2.AsString();
                    304:        if (str2.size() != 8) {
                    305:                item2.Err("must be 8 digits");
                    306:                return false;
                    307:        }
                    308:        for (int i = 0; i < 8; i++) {
                    309:                dipsw1[i] = (str1[i] != '0');
                    310:                dipsw2[i] = (str2[i] != '0');
                    311:        }
                    312:        return true;
                    313: }
                    314: 
1.1.1.10! root      315: // XXX ResetHard 未調査
1.1.1.7   root      316: 
1.1       root      317: uint64
1.1.1.6   root      318: PIO0Device::Read(uint32 offset)
1.1       root      319: {
                    320:        uint32 data;
                    321: 
1.1.1.6   root      322:        switch (offset) {
1.1       root      323:         case 0:
                    324:                // PortA
                    325:                putlog(1, "DIP-SW 1 読み込み");
                    326:                return GetPA();
                    327: 
                    328:         case 1:
                    329:                // PortB
                    330:                putlog(1, "DIP-SW 2 読み込み");
                    331:                return GetPB();
                    332: 
                    333:         case 2:
                    334:                // PortC
                    335:                data = GetPC();
1.1.1.6   root      336:                putlog(1, "PC 読み込み -> $%02x", data);
1.1       root      337:                return data;
                    338: 
                    339:         case 3:
                    340:                data = ReadCtrl();
                    341:                putlog(1, "コントロール読み込み -> $%02x", data);
                    342:                return data;
                    343: 
                    344:         default:
                    345:                __unreachable();
                    346:        }
                    347: }
                    348: 
                    349: uint64
1.1.1.6   root      350: PIO0Device::Write(uint32 offset, uint32 data)
1.1       root      351: {
1.1.1.6   root      352:        switch (offset) {
1.1       root      353:         case 0:        // PIO0 PortA: DIPSW1 (入力のみ)
                    354:         case 1:        // PIO0 PortB: DIPSW2 (入力のみ)
                    355:                return 0;
                    356: 
                    357:         case 2:        // PIO0 PortC: ホスト割り込み制御
                    358:                for (int i = 0; i < 8; i++) {
                    359:                        SetPC(i, data & 1);
                    360:                        data >>= 1;
                    361:                }
                    362:                return 0;
                    363: 
                    364:         case 3:        // コントロール
                    365:                WriteCtrl(data);
                    366:                return 0;
                    367: 
                    368:         default:
                    369:                __unreachable();
                    370:        }
                    371: }
                    372: 
                    373: uint64
1.1.1.6   root      374: PIO0Device::Peek(uint32 offset)
1.1       root      375: {
1.1.1.6   root      376:        switch (offset) {
1.1       root      377:         case 0:
                    378:                return GetPA();
                    379: 
                    380:         case 1:
                    381:                return GetPB();
                    382: 
                    383:         case 2:
                    384:                return GetPC();
                    385: 
                    386:         case 3:
                    387:                return ReadCtrl();
                    388: 
                    389:         default:
                    390:                __unreachable();
                    391:        }
                    392: }
                    393: 
1.1.1.3   root      394: void
1.1.1.8   root      395: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2   root      396: {
                    397:        int y;
                    398: 
1.1.1.8   root      399:        screen.Clear();
1.1.1.2   root      400: 
                    401:        y = 0;
1.1.1.8   root      402:        screen.Print(0, y++, "PortA(DIPSW1):%c%c%c%c%c%c%c%c",
1.1.1.2   root      403:                (dipsw1[0] ? '1' : '0'),
                    404:                (dipsw1[1] ? '1' : '0'),
                    405:                (dipsw1[2] ? '1' : '0'),
                    406:                (dipsw1[3] ? '1' : '0'),
                    407:                (dipsw1[4] ? '1' : '0'),
                    408:                (dipsw1[5] ? '1' : '0'),
                    409:                (dipsw1[6] ? '1' : '0'),
                    410:                (dipsw1[7] ? '1' : '0'));
1.1.1.8   root      411:        screen.Print(0, y++, "PortB(DIPSW2):%c%c%c%c%c%c%c%c",
1.1.1.2   root      412:                (dipsw2[0] ? '1' : '0'),
                    413:                (dipsw2[1] ? '1' : '0'),
                    414:                (dipsw2[2] ? '1' : '0'),
                    415:                (dipsw2[3] ? '1' : '0'),
                    416:                (dipsw2[4] ? '1' : '0'),
                    417:                (dipsw2[5] ? '1' : '0'),
                    418:                (dipsw2[6] ? '1' : '0'),
                    419:                (dipsw2[7] ? '1' : '0'));
1.1.1.8   root      420:        screen.Puts(0, y++, "PortC");
                    421:        screen.Puts(1, y++, TA::OnOff(xp_reset), "b7: XP Reset");
                    422:        screen.Puts(1, y++, TA::OnOff(parity),   "b6: Parity");
1.1.1.9   root      423:        screen.Puts(1, y++, TA::Disable,         "b5: ---");
1.1.1.8   root      424:        screen.Puts(1, y++, TA::OnOff(int5en),   "b4: Int5 Enable");
                    425:        screen.Puts(1, y++, TA::OnOff(int5rq),   "b3: Int5 Request");
                    426:        screen.Puts(1, y++, TA::OnOff(int1en),   "b2: Int1 Enable");
1.1.1.9   root      427:        screen.Puts(1, y++, TA::Disable,         "b1: ---");
1.1.1.8   root      428:        screen.Puts(1, y++, TA::OnOff(int1rq),   "b0: Intq Request");
1.1.1.2   root      429: }
                    430: 
1.1       root      431: // PortA (DIP-SW 1) 読み込み
                    432: uint32
                    433: PIO0Device::GetPA() const
                    434: {
                    435:        uint32 data = 0;
                    436:        for (int i = 0; i < 8; i++) {
                    437:                data |= ((int)dipsw1[i]) << i;
                    438:        }
1.1.1.9   root      439:        if (msb_first) {
                    440:                data = bitrev(data);
                    441:        }
1.1       root      442:        return data & 0xff;
                    443: }
                    444: 
                    445: // PortB (DIP-SW 2) 読み込み
                    446: uint32
                    447: PIO0Device::GetPB() const
                    448: {
                    449:        uint32 data = 0;
                    450:        for (int i = 0; i < 8; i++) {
                    451:                data |= ((int)dipsw2[i]) << i;
                    452:        }
1.1.1.9   root      453:        if (msb_first) {
                    454:                data = bitrev(data);
                    455:        }
1.1       root      456:        return data & 0xff;
                    457: }
                    458: 
                    459: // PortC 読み込み
                    460: uint32
                    461: PIO0Device::GetPC() const
                    462: {
                    463:        uint32 data;
                    464: 
                    465:        data = 0x00     // XXX 空きビットは何が読めるか?
                    466:                 | (int1rq ? 0x01 : 0)
                    467:                 | (int1en ? 0x04 : 0)
                    468:                 | (int5rq ? 0x08 : 0)
                    469:                 | (int5en ? 0x10 : 0)
                    470:                 | (parity ? 0x40 : 0)
                    471:                 | (xp_reset?0x80 : 0);
                    472:        return data;
                    473: }
                    474: 
                    475: // PortC 書き込み
                    476: void
                    477: PIO0Device::SetPC(int pc, int val)
                    478: {
                    479:        switch (pc) {
                    480:         case 0:
                    481:                if ((val ^ int1rq)) {
                    482:                        int1rq = val;
                    483:                        putlog(0, "INT1割り込み要求 %d (未実装)", int1rq);
                    484:                }
                    485:                return;
                    486:         case 1:
                    487:                // Not Connected.
                    488:                return;
                    489:         case 2:
                    490:                if ((val ^ int1en)) {
                    491:                        int1en = val;
                    492:                        putlog(0, "INT1割り込み許可 %d (未実装)", int1en);
                    493:                }
                    494:                return;
                    495:         case 3:
                    496:                if ((val ^ int5rq)) {
                    497:                        int5rq = val;
                    498:                        putlog(0, "INT5割り込み要求 %d (未実装)", int5rq);
                    499:                }
                    500:                return;
                    501:         case 4:
                    502:                if ((val ^ int5en)) {
                    503:                        int5en = val;
                    504:                        putlog(0, "INT5割り込み許可 %d (未実装)", int5en);
                    505:                }
                    506:                return;
                    507:         case 5:
                    508:                // Not Connected.
                    509:                return;
                    510:         case 6:
                    511:                // パリティ有効/無効
                    512:                // 使わないので無視するが読み返しのために覚えておく
                    513:                parity = val;
                    514:                return;
                    515:         case 7:
                    516:                // XP リセット
                    517:                if ((val ^ xp_reset)) {
                    518:                        xp_reset = val;
                    519:                        putlog(0, "XPリセット %d (未実装)", xp_reset);
                    520:                }
                    521:                return;
                    522:        }
1.1.1.10! root      523:        VMPANIC("invalid pc=%d", pc);
1.1       root      524: }
                    525: 
                    526: 
                    527: //
                    528: // LUNA PIO1
                    529: //
                    530: // 仕様は 0x4d000000 から 4バイトだが、
                    531: // 0x4c000000 から 0x50000000 の手前まで 4バイト単位でミラーが見える。
                    532: 
                    533: // コンストラクタ
                    534: PIO1Device::PIO1Device()
1.1.1.8   root      535:        : inherited("PIO1")
1.1       root      536: {
                    537:        devaddr = 0x4d000000;
                    538:        devlen  = 4;
                    539: 
1.1.1.10! root      540:        poffevent.func = ToEventCallback(&PIO1Device::PowerOffCallback);
        !           541:        poffevent.time = 1_msec;
        !           542:        poffevent.Regist("PIO1 Power Off");
1.1       root      543: }
                    544: 
                    545: // デストラクタ
                    546: PIO1Device::~PIO1Device()
                    547: {
1.1.1.10! root      548:        gPIO1 = NULL;
1.1       root      549: }
                    550: 
1.1.1.4   root      551: // リセット
                    552: void
1.1.1.10! root      553: PIO1Device::ResetHard(bool poweron)
1.1.1.4   root      554: {
1.1.1.10! root      555:        inherited::ResetHard(poweron);
1.1.1.4   root      556: 
1.1.1.10! root      557:        gScheduler->StopEvent(poffevent);
1.1.1.4   root      558: }
                    559: 
1.1       root      560: uint64
1.1.1.6   root      561: PIO1Device::Read(uint32 offset)
1.1       root      562: {
                    563:        uint32 data;
                    564: 
1.1.1.6   root      565:        switch (offset) {
1.1       root      566:         case 0:
                    567:                // PIO1 PortA: LCD データ
                    568:                return gLCD->Read();
                    569: 
                    570:         case 1:
                    571:                // PIO1 PortB: 無効
                    572:                return 0xff;
                    573: 
                    574:         case 2:
                    575:                // PortC
                    576:                data = gLCD->Get();
                    577:                data |= xp_intreq ? 0 : 0x02;
                    578:                // 残りのビットは %1 だろうか?
                    579:                data |= 0x0d;
                    580:                putlog(1, "PC 読み込み -> $%02x", data);
                    581:                return data;
                    582: 
                    583:         case 3:
                    584:                data = ReadCtrl();
                    585:                putlog(1, "コントロール読み込み -> $%02x", data);
                    586:                return data;
                    587: 
                    588:         default:
                    589:                __unreachable();
                    590:        }
                    591: }
                    592: 
                    593: uint64
1.1.1.6   root      594: PIO1Device::Write(uint32 offset, uint32 data)
1.1       root      595: {
1.1.1.6   root      596:        switch (offset) {
1.1       root      597:         case 0:        // PIO1 PortA: LCD データ
                    598:                gLCD->Write(data);
                    599:                return 0;
                    600: 
                    601:         case 1:        // PIO1 PortB: ローカル割り込み
                    602:                break;
                    603: 
                    604:         case 2:        // PIO1 PortC: LCD/パワーオフ制御
                    605:                for (int i = 0; i < 8; i++) {
                    606:                        SetPC(i, data & 1);
                    607:                        data >>= 1;
                    608:                }
                    609:                return 0;
                    610: 
                    611:         case 3:        // コントロール
                    612:                WriteCtrl(data);
                    613:                return 0;
                    614: 
                    615:         default:
                    616:                __unreachable();
                    617:        }
1.1.1.10! root      618:        VMPANIC("$%08X <- $%02X 未サポート書き込み", gMPU->GetPaddr(), data);
1.1       root      619:        return 0;
                    620: }
                    621: 
                    622: uint64
1.1.1.6   root      623: PIO1Device::Peek(uint32 offset)
1.1       root      624: {
                    625:        uint32 data;
                    626: 
1.1.1.6   root      627:        switch (offset) {
1.1       root      628:         case 0:        // PIO1 PortA LCD データ
                    629:                return gLCD->Peek();
                    630: 
                    631:         case 1:        // PIO1 PortB 無効
                    632:                return 0xff;
                    633: 
                    634:         case 2:        // PIO1 PortC
                    635:                data = gLCD->Get();
                    636:                data |= xp_intreq ? 0 : 0x02;
                    637:                // 残りのビットは %1 だろうか?
                    638:                data |= 0x0d;
                    639:                return data;
                    640: 
                    641:         case 3:
                    642:                return ReadCtrl();
                    643: 
                    644:         default:
                    645:                __unreachable();
                    646:        }
                    647: }
                    648: 
                    649: void
                    650: PIO1Device::SetPC(int pc, int val)
                    651: {
                    652:        switch (pc) {
                    653:         case 0:
                    654:         case 1:
                    655:         case 2:
                    656:         case 3:
                    657:                // PortC の下半分は入力ポートとして使われることを想定して
                    658:                // いるので、ここへの書き込みは起きないだろうし、無視する。
                    659:                return;
                    660: 
                    661:         case 4:
                    662:                power = val;
                    663:                if (power) {
                    664:                        // 電源オフ取り消し
                    665:                        putlog(1, "電源 OFF 取消");
1.1.1.10! root      666:                        gScheduler->StopEvent(poffevent);
1.1       root      667:                } else {
                    668:                        // 1msec 後に電源オフ
                    669:                        putlog(1, "電源 OFF 指示");
1.1.1.10! root      670:                        gScheduler->RestartEvent(poffevent);
1.1       root      671:                }
                    672:                return;
                    673:         case 5:
                    674:                gLCD->SetRW(val);
                    675:                return;
                    676:         case 6:
                    677:                gLCD->SetRS(val);
                    678:                return;
                    679:         case 7:
                    680:                gLCD->SetE(val);
                    681:                return;
                    682: 
                    683:         default:
                    684:                break;
                    685:        }
1.1.1.10! root      686:        VMPANIC("PC%d 未実装", pc);
1.1       root      687: }
                    688: 
1.1.1.10! root      689: // 電源オフイベントのコールバック
1.1       root      690: void
1.1.1.4   root      691: PIO1Device::PowerOffCallback(Event& ev)
1.1       root      692: {
                    693:        putlog(0, "電源 OFF");
1.1.1.10! root      694:        gPower->MakePowerOffExit();
1.1       root      695: }

unix.superglobalmegacorp.com

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