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

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,
1.1.1.11! root       77:                        "Set mode: groupA=%d groupB=%d portA=%s portB=%s portC=%s/%s",
1.1       root       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.11! root      129:                putlog(0, "Read $e9a005 PortC (NOT IMPLEMENTED)");
1.1.1.5   root      130:                return 0xff;
1.1       root      131:         case 3:
1.1.1.11! root      132:                putlog(0, "Read $e9a007 Ctrl (NOT IMPLEMENTED)");
        !           133:                return 0xff;
1.1       root      134:         default:
                    135:                __unreachable();
                    136:        }
                    137: }
                    138: 
                    139: uint64
1.1.1.6   root      140: PPIDevice::Write(uint32 offset, uint32 data)
1.1       root      141: {
1.1.1.4   root      142:        gMPU->AddCycle(19);     // InsideOut p.135
                    143: 
1.1.1.6   root      144:        switch (offset) {
1.1       root      145:         case 0:
                    146:         case 1:
                    147:                break;
1.1.1.11! root      148:         case 2:        // PPI PortC
        !           149:                for (int i = 0; i < 8; i++) {
        !           150:                        SetPC(i, data & 1);
        !           151:                        data >>= 1;
        !           152:                }
1.1       root      153:                break;
                    154:         case 3:
1.1.1.11! root      155:                WriteCtrl(data);
1.1       root      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
1.1.1.11! root      172: PPIDevice::SetPC(int pc, int val)
1.1.1.10  root      173: {
1.1.1.11! root      174:        switch (pc) {
        !           175:         case 0:        // ADPCM PAN Left Off
        !           176:                pan_left = !val;
        !           177:                break;
        !           178:         case 1:        // ADPCM PAN Right Off
        !           179:                pan_right = !val;
        !           180:                break;
        !           181:         case 2:        // ADPCM サンプリングレート
        !           182:                adpcm_rate = (adpcm_rate & 2) | val;
        !           183:                break;
        !           184:         case 3:        // ADPCM サンプリングレート
        !           185:                adpcm_rate = (val << 1) | (adpcm_rate & 1);
        !           186:                break;
        !           187: 
        !           188:         case 4:        // ジョイスティック #1 コントロール
        !           189:         case 5:        // ジョイスティック #2 コントロール
        !           190:         case 6:        // ジョイスティック #1 ボタン A
        !           191:         case 7:        // ジョイスティック #1 ボタン B
        !           192:                putlog(1, "SetPC(%d) <- %d (NOT IMPLEMENTED)", pc, val);
        !           193:                break;
        !           194:         default:
        !           195:                __unreachable();
        !           196:        }
1.1.1.10  root      197: }
                    198: 
1.1       root      199: //
                    200: // LUNA PIO0
                    201: //
                    202: // 仕様は 0x49000000 から 4バイトだが、
                    203: // 0x48000000 から 0x4c000000 の手前まで 4バイト単位でミラーが見える。
                    204: //
                    205: // LUNA の DIP-SW は #1, #2 にそれぞれ8個、計16個ある。
1.1.1.9   root      206: // DIP-SW #1, #2 が設定ファイルの luna-dipsw{1,2} に対応する。
                    207: // luna-dipsw{1,2} はいずれも "0"/"1" を8つ並べた文字列であり、
1.1       root      208: // 先頭が本体表記でいう 1番、末尾側が本体表記でいう 8番に対応する。
1.1.1.9   root      209: // 値は "0" が down、"1" が up を表す。
                    210: //
                    211: // PIO0Device 内ではこの設定を読み込んで bool dipsw1[8], dipsw2[8] の配列で
                    212: // 値を保持している。dipsw1[0] が本体表記1番、dipsw1[7] が本体表記 8番に対応
                    213: // する。値は false が down("0")、true が up("1") に対応する。
                    214: //
                    215: // PIO から読み出せる値のビットの並び順が機種によって異なる。
                    216: // LUNA-1  では 1番が LSB、8番が MSB の並び順、
                    217: // LUNA88K では 1番が MSB、8番が LSB の並び順。
                    218: // 値は、並び順に関わらずどちらも
                    219: // %0 が false = down = "0"、%1 が true = up = "1" である。
                    220: //
                    221: //    #1 #2 #3 #4 #5 #6 #7 #8
                    222: //  +-------------------------+
                    223: //  |    [] [] [] [] [] [] [] | 本体外観
                    224: //  | []                      |
                    225: //  +-------------------------+
                    226: //
                    227: // luna-dipsw1 = "01111111"    ← 設定ファイル
                    228: //                ||||||||     ↓ このクラスのメンバ変数
                    229: //                |||||||+- dipsw1[7] = true;
                    230: //                ||||||+-- dipsw1[6] = true;
                    231: //                |||||+--- dipsw1[5] = true;
                    232: //                ||||+---- dipsw1[4] = true;
                    233: //                |||+----- dipsw1[3] = true;
                    234: //                ||+------ dipsw1[2] = true;
                    235: //                |+------- dipsw1[1] = true;
                    236: //                +-------- dipsw1[0] = false;
                    237: //
                    238: //              b7   b6   b5   b4   b3   b2   b1   b0
                    239: //            +----+----+----+----+----+----+----+----+
                    240: // LUNA-1     | #8 | #7 | #6 | #5 | #4 | #3 | #2 | #1 |
                    241: // PortA      |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  0 | %1=UP, %0=DOWN
                    242: //            +----+----+----+----+----+----+----+----+
                    243: //
                    244: //              b7   b6   b5   b4   b3   b2   b1   b0
                    245: //            +----+----+----+----+----+----+----+----+
                    246: // LUNA88K    | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 |
                    247: // PortA      |  0 |  1 |  1 |  1 |  1 |  1 |  1 |  1 | %1=UP, %0=DOWN
                    248: //            +----+----+----+----+----+----+----+----+
1.1       root      249: //
1.1.1.3   root      250: // LUNA-1:
1.1       root      251: // #1-1 up なら UNIX をロードして移行。down なら ROM モニタで起動。
                    252: // #1-2 up ならディスプレイコンソール。down ならシリアルコンソール。
                    253: // #1-3 up - color display, down - force to have monochrome display
                    254: // #1-4 up - no write verification,
                    255: //      down - verification on every harddisk write operation
                    256: // #1-5 up - OS is UniOS-U (SystemV/COFF),
                    257: //      down - OS is UniOS (4.3BSD/a.out OMAGIC)
                    258: // #1-6 down - force monochrome display?
                    259: // #1-7 up - boot from local device, down - boot from network
                    260: // #1-8 up - normal boot, down - start diagnostics と書いてあるが
                    261: //      down にすると画面真っ暗で詳細不明。
                    262: //
                    263: // #2-x すべて up にすると /boot が自動的にカーネルを起動。一つでも down が
                    264: //      あれば /boot がプロンプトで停止。これは ROM ではなく NetBSD のブート
                    265: //      ローダの話。
                    266: //      どこか由来のソースコードらしいがたぶんビット演算を間違えている。
1.1.1.3   root      267: //
                    268: // LUNA88K:
                    269: // #1-1 up なら ROM モニタで停止、down ならマルチユーザブート。
                    270: //      OpenBSD カーネルも up なら UserKernelConfig で止まる模様?。
                    271: // #1-2 up なら外付けシリアルコンソール、down なら内蔵ビットマップ。
1.1.1.9   root      272: // #1-3..#1-7 は不明?
                    273: // #1-8 down なら自己診断後電源オフするようだ。
1.1.1.3   root      274: // #2-x はユーザ(?)
1.1       root      275: 
                    276: // コンストラクタ
                    277: PIO0Device::PIO0Device()
1.1.1.8   root      278:        : inherited("PIO0")
1.1       root      279: {
                    280:        devaddr = 0x49000000;
                    281:        devlen  = 4;
1.1.1.2   root      282: 
1.1.1.3   root      283:        // 機種固有パラメータ
                    284: 
                    285:        // LUNA-1 と LUNA88K で使いやすいように初期値を変えておく。
                    286:        switch (gMainApp.GetVMType()) {
1.1.1.11! root      287:         case VMType::LUNA1:
1.1.1.3   root      288:                gConfig->SetDefault("luna-dipsw1", "11110111");
1.1.1.9   root      289:                msb_first = false;
1.1.1.3   root      290:                break;
1.1.1.11! root      291:         case VMType::LUNA88K:
1.1.1.4   root      292:                gConfig->SetDefault("luna-dipsw1", "11111111");
1.1.1.9   root      293:                msb_first = true;
1.1.1.3   root      294:                break;
                    295:         default:
                    296:                __unreachable();
                    297:        }
                    298:        // DIP-SW#2 はユーザ定義(?)なので(今の所?)どちらも共通。
                    299:        gConfig->SetDefault("luna-dipsw2", "11111111");
                    300: 
1.1.1.10  root      301:        monitor.func = ToMonitorCallback(&PIO0Device::MonitorUpdate);
1.1.1.8   root      302:        monitor.SetSize(22, 11);
                    303:        monitor.Regist(ID_MONITOR_PIO0);
1.1       root      304: }
                    305: 
                    306: // デストラクタ
                    307: PIO0Device::~PIO0Device()
                    308: {
1.1.1.10  root      309:        gPIO0 = NULL;
1.1       root      310: }
                    311: 
                    312: bool
                    313: PIO0Device::Init()
                    314: {
                    315:        // XXX 本当はラッチのタイミングが違う気もするけど、とりあえずね
                    316: 
1.1.1.2   root      317:        const ConfigItem& item1 = gConfig->Find("luna-dipsw1");
1.1       root      318:        const std::string& str1 = item1.AsString();
                    319:        if (str1.size() != 8) {
                    320:                item1.Err("must be 8 digits");
                    321:                return false;
                    322:        }
                    323: 
1.1.1.2   root      324:        const ConfigItem& item2 = gConfig->Find("luna-dipsw2");
1.1       root      325:        const std::string& str2 = item2.AsString();
                    326:        if (str2.size() != 8) {
                    327:                item2.Err("must be 8 digits");
                    328:                return false;
                    329:        }
                    330:        for (int i = 0; i < 8; i++) {
                    331:                dipsw1[i] = (str1[i] != '0');
                    332:                dipsw2[i] = (str2[i] != '0');
                    333:        }
                    334:        return true;
                    335: }
                    336: 
1.1.1.10  root      337: // XXX ResetHard 未調査
1.1.1.7   root      338: 
1.1       root      339: uint64
1.1.1.6   root      340: PIO0Device::Read(uint32 offset)
1.1       root      341: {
                    342:        uint32 data;
                    343: 
1.1.1.6   root      344:        switch (offset) {
1.1       root      345:         case 0:
                    346:                // PortA
1.1.1.11! root      347:                data = GetPA();
        !           348:                putlog(1, "DIP-SW1 -> $%02x", data);
        !           349:                return data;
1.1       root      350: 
                    351:         case 1:
                    352:                // PortB
1.1.1.11! root      353:                data = GetPB();
        !           354:                putlog(1, "DIP-SW2 -> $%02x", data);
        !           355:                return data;
1.1       root      356: 
                    357:         case 2:
                    358:                // PortC
                    359:                data = GetPC();
1.1.1.11! root      360:                putlog(1, "PortC -> $%02x", data);
1.1       root      361:                return data;
                    362: 
                    363:         case 3:
                    364:                data = ReadCtrl();
1.1.1.11! root      365:                putlog(1, "Ctrl -> $%02x", data);
1.1       root      366:                return data;
                    367: 
                    368:         default:
                    369:                __unreachable();
                    370:        }
                    371: }
                    372: 
                    373: uint64
1.1.1.6   root      374: PIO0Device::Write(uint32 offset, uint32 data)
1.1       root      375: {
1.1.1.6   root      376:        switch (offset) {
1.1       root      377:         case 0:        // PIO0 PortA: DIPSW1 (入力のみ)
                    378:         case 1:        // PIO0 PortB: DIPSW2 (入力のみ)
                    379:                return 0;
                    380: 
                    381:         case 2:        // PIO0 PortC: ホスト割り込み制御
                    382:                for (int i = 0; i < 8; i++) {
                    383:                        SetPC(i, data & 1);
                    384:                        data >>= 1;
                    385:                }
                    386:                return 0;
                    387: 
                    388:         case 3:        // コントロール
                    389:                WriteCtrl(data);
                    390:                return 0;
                    391: 
                    392:         default:
                    393:                __unreachable();
                    394:        }
                    395: }
                    396: 
                    397: uint64
1.1.1.6   root      398: PIO0Device::Peek(uint32 offset)
1.1       root      399: {
1.1.1.6   root      400:        switch (offset) {
1.1       root      401:         case 0:
                    402:                return GetPA();
                    403: 
                    404:         case 1:
                    405:                return GetPB();
                    406: 
                    407:         case 2:
                    408:                return GetPC();
                    409: 
                    410:         case 3:
                    411:                return ReadCtrl();
                    412: 
                    413:         default:
                    414:                __unreachable();
                    415:        }
                    416: }
                    417: 
1.1.1.3   root      418: void
1.1.1.8   root      419: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2   root      420: {
                    421:        int y;
                    422: 
1.1.1.8   root      423:        screen.Clear();
1.1.1.2   root      424: 
                    425:        y = 0;
1.1.1.8   root      426:        screen.Print(0, y++, "PortA(DIPSW1):%c%c%c%c%c%c%c%c",
1.1.1.2   root      427:                (dipsw1[0] ? '1' : '0'),
                    428:                (dipsw1[1] ? '1' : '0'),
                    429:                (dipsw1[2] ? '1' : '0'),
                    430:                (dipsw1[3] ? '1' : '0'),
                    431:                (dipsw1[4] ? '1' : '0'),
                    432:                (dipsw1[5] ? '1' : '0'),
                    433:                (dipsw1[6] ? '1' : '0'),
                    434:                (dipsw1[7] ? '1' : '0'));
1.1.1.8   root      435:        screen.Print(0, y++, "PortB(DIPSW2):%c%c%c%c%c%c%c%c",
1.1.1.2   root      436:                (dipsw2[0] ? '1' : '0'),
                    437:                (dipsw2[1] ? '1' : '0'),
                    438:                (dipsw2[2] ? '1' : '0'),
                    439:                (dipsw2[3] ? '1' : '0'),
                    440:                (dipsw2[4] ? '1' : '0'),
                    441:                (dipsw2[5] ? '1' : '0'),
                    442:                (dipsw2[6] ? '1' : '0'),
                    443:                (dipsw2[7] ? '1' : '0'));
1.1.1.8   root      444:        screen.Puts(0, y++, "PortC");
                    445:        screen.Puts(1, y++, TA::OnOff(xp_reset), "b7: XP Reset");
                    446:        screen.Puts(1, y++, TA::OnOff(parity),   "b6: Parity");
1.1.1.9   root      447:        screen.Puts(1, y++, TA::Disable,         "b5: ---");
1.1.1.8   root      448:        screen.Puts(1, y++, TA::OnOff(int5en),   "b4: Int5 Enable");
                    449:        screen.Puts(1, y++, TA::OnOff(int5rq),   "b3: Int5 Request");
                    450:        screen.Puts(1, y++, TA::OnOff(int1en),   "b2: Int1 Enable");
1.1.1.9   root      451:        screen.Puts(1, y++, TA::Disable,         "b1: ---");
1.1.1.8   root      452:        screen.Puts(1, y++, TA::OnOff(int1rq),   "b0: Intq Request");
1.1.1.2   root      453: }
                    454: 
1.1       root      455: // PortA (DIP-SW 1) 読み込み
                    456: uint32
                    457: PIO0Device::GetPA() const
                    458: {
                    459:        uint32 data = 0;
                    460:        for (int i = 0; i < 8; i++) {
                    461:                data |= ((int)dipsw1[i]) << i;
                    462:        }
1.1.1.9   root      463:        if (msb_first) {
                    464:                data = bitrev(data);
                    465:        }
1.1       root      466:        return data & 0xff;
                    467: }
                    468: 
                    469: // PortB (DIP-SW 2) 読み込み
                    470: uint32
                    471: PIO0Device::GetPB() const
                    472: {
                    473:        uint32 data = 0;
                    474:        for (int i = 0; i < 8; i++) {
                    475:                data |= ((int)dipsw2[i]) << i;
                    476:        }
1.1.1.9   root      477:        if (msb_first) {
                    478:                data = bitrev(data);
                    479:        }
1.1       root      480:        return data & 0xff;
                    481: }
                    482: 
                    483: // PortC 読み込み
                    484: uint32
                    485: PIO0Device::GetPC() const
                    486: {
                    487:        uint32 data;
                    488: 
                    489:        data = 0x00     // XXX 空きビットは何が読めるか?
                    490:                 | (int1rq ? 0x01 : 0)
                    491:                 | (int1en ? 0x04 : 0)
                    492:                 | (int5rq ? 0x08 : 0)
                    493:                 | (int5en ? 0x10 : 0)
                    494:                 | (parity ? 0x40 : 0)
                    495:                 | (xp_reset?0x80 : 0);
                    496:        return data;
                    497: }
                    498: 
                    499: // PortC 書き込み
                    500: void
                    501: PIO0Device::SetPC(int pc, int val)
                    502: {
                    503:        switch (pc) {
                    504:         case 0:
                    505:                if ((val ^ int1rq)) {
                    506:                        int1rq = val;
1.1.1.11! root      507:                        putlog(0, "INT1 Interrupt Request %d (NOT IMPLEMENTED)", int1rq);
1.1       root      508:                }
                    509:                return;
                    510:         case 1:
                    511:                // Not Connected.
                    512:                return;
                    513:         case 2:
                    514:                if ((val ^ int1en)) {
                    515:                        int1en = val;
1.1.1.11! root      516:                        putlog(0, "INT1 Interrupt Enable %d (NOT IMPLEMENTED)", int1en);
1.1       root      517:                }
                    518:                return;
                    519:         case 3:
                    520:                if ((val ^ int5rq)) {
                    521:                        int5rq = val;
1.1.1.11! root      522:                        putlog(0, "INT5 Interrupt Request %d (NOT IMPLEMENTED)", int5rq);
1.1       root      523:                }
                    524:                return;
                    525:         case 4:
                    526:                if ((val ^ int5en)) {
                    527:                        int5en = val;
1.1.1.11! root      528:                        putlog(0, "INT5 Interrupt Enable %d (NOT IMPLEMENTED)", int5en);
1.1       root      529:                }
                    530:                return;
                    531:         case 5:
                    532:                // Not Connected.
                    533:                return;
                    534:         case 6:
                    535:                // パリティ有効/無効
                    536:                // 使わないので無視するが読み返しのために覚えておく
                    537:                parity = val;
                    538:                return;
                    539:         case 7:
                    540:                // XP リセット
                    541:                if ((val ^ xp_reset)) {
                    542:                        xp_reset = val;
1.1.1.11! root      543:                        putlog(0, "XP Reset %d (NOT IMPLEMENTED)", xp_reset);
1.1       root      544:                }
                    545:                return;
                    546:        }
1.1.1.10  root      547:        VMPANIC("invalid pc=%d", pc);
1.1       root      548: }
                    549: 
                    550: 
                    551: //
                    552: // LUNA PIO1
                    553: //
                    554: // 仕様は 0x4d000000 から 4バイトだが、
                    555: // 0x4c000000 から 0x50000000 の手前まで 4バイト単位でミラーが見える。
                    556: 
                    557: // コンストラクタ
                    558: PIO1Device::PIO1Device()
1.1.1.8   root      559:        : inherited("PIO1")
1.1       root      560: {
                    561:        devaddr = 0x4d000000;
                    562:        devlen  = 4;
                    563: 
                    564: }
                    565: 
                    566: // デストラクタ
                    567: PIO1Device::~PIO1Device()
                    568: {
1.1.1.10  root      569:        gPIO1 = NULL;
1.1       root      570: }
                    571: 
1.1.1.4   root      572: // リセット
                    573: void
1.1.1.10  root      574: PIO1Device::ResetHard(bool poweron)
1.1.1.4   root      575: {
1.1.1.10  root      576:        inherited::ResetHard(poweron);
1.1.1.4   root      577: 
1.1.1.11! root      578:        // デフォルトで PIO 出力は「1msec 後に電源オフ」という状態なので、
        !           579:        // 電源オンから 1msec 以内にソフトウェアがこれをキャンセルしないと
        !           580:        // いけないらしい。どうしてこうなった…。
        !           581:        gPower->SetSystemPowerOn(false);
1.1.1.4   root      582: }
                    583: 
1.1       root      584: uint64
1.1.1.6   root      585: PIO1Device::Read(uint32 offset)
1.1       root      586: {
                    587:        uint32 data;
                    588: 
1.1.1.6   root      589:        switch (offset) {
1.1       root      590:         case 0:
                    591:                // PIO1 PortA: LCD データ
                    592:                return gLCD->Read();
                    593: 
                    594:         case 1:
                    595:                // PIO1 PortB: 無効
                    596:                return 0xff;
                    597: 
                    598:         case 2:
                    599:                // PortC
                    600:                data = gLCD->Get();
                    601:                data |= xp_intreq ? 0 : 0x02;
                    602:                // 残りのビットは %1 だろうか?
                    603:                data |= 0x0d;
1.1.1.11! root      604:                putlog(1, "PortC -> $%02x", data);
1.1       root      605:                return data;
                    606: 
                    607:         case 3:
                    608:                data = ReadCtrl();
1.1.1.11! root      609:                putlog(1, "Ctrl -> $%02x", data);
1.1       root      610:                return data;
                    611: 
                    612:         default:
                    613:                __unreachable();
                    614:        }
                    615: }
                    616: 
                    617: uint64
1.1.1.6   root      618: PIO1Device::Write(uint32 offset, uint32 data)
1.1       root      619: {
1.1.1.6   root      620:        switch (offset) {
1.1       root      621:         case 0:        // PIO1 PortA: LCD データ
                    622:                gLCD->Write(data);
                    623:                return 0;
                    624: 
                    625:         case 1:        // PIO1 PortB: ローカル割り込み
                    626:                break;
                    627: 
                    628:         case 2:        // PIO1 PortC: LCD/パワーオフ制御
                    629:                for (int i = 0; i < 8; i++) {
                    630:                        SetPC(i, data & 1);
                    631:                        data >>= 1;
                    632:                }
                    633:                return 0;
                    634: 
                    635:         case 3:        // コントロール
                    636:                WriteCtrl(data);
                    637:                return 0;
                    638: 
                    639:         default:
                    640:                __unreachable();
                    641:        }
1.1.1.10  root      642:        VMPANIC("$%08X <- $%02X 未サポート書き込み", gMPU->GetPaddr(), data);
1.1       root      643:        return 0;
                    644: }
                    645: 
                    646: uint64
1.1.1.6   root      647: PIO1Device::Peek(uint32 offset)
1.1       root      648: {
                    649:        uint32 data;
                    650: 
1.1.1.6   root      651:        switch (offset) {
1.1       root      652:         case 0:        // PIO1 PortA LCD データ
                    653:                return gLCD->Peek();
                    654: 
                    655:         case 1:        // PIO1 PortB 無効
                    656:                return 0xff;
                    657: 
                    658:         case 2:        // PIO1 PortC
                    659:                data = gLCD->Get();
                    660:                data |= xp_intreq ? 0 : 0x02;
                    661:                // 残りのビットは %1 だろうか?
                    662:                data |= 0x0d;
                    663:                return data;
                    664: 
                    665:         case 3:
                    666:                return ReadCtrl();
                    667: 
                    668:         default:
                    669:                __unreachable();
                    670:        }
                    671: }
                    672: 
                    673: void
                    674: PIO1Device::SetPC(int pc, int val)
                    675: {
                    676:        switch (pc) {
                    677:         case 0:
                    678:         case 1:
                    679:         case 2:
                    680:         case 3:
                    681:                // PortC の下半分は入力ポートとして使われることを想定して
                    682:                // いるので、ここへの書き込みは起きないだろうし、無視する。
                    683:                return;
                    684: 
                    685:         case 4:
                    686:                power = val;
                    687:                if (power) {
                    688:                        // 電源オフ取り消し
1.1.1.11! root      689:                        putlog(1, "Power-off canceled");
        !           690:                        gPower->SetSystemPowerOn(true);
1.1       root      691:                } else {
                    692:                        // 1msec 後に電源オフ
1.1.1.11! root      693:                        putlog(1, "Power-off scheduled");
        !           694:                        gPower->SetSystemPowerOn(false);
1.1       root      695:                }
                    696:                return;
                    697:         case 5:
                    698:                gLCD->SetRW(val);
                    699:                return;
                    700:         case 6:
                    701:                gLCD->SetRS(val);
                    702:                return;
                    703:         case 7:
                    704:                gLCD->SetE(val);
                    705:                return;
                    706: 
                    707:         default:
                    708:                break;
                    709:        }
1.1.1.10  root      710:        VMPANIC("PC%d 未実装", pc);
1.1       root      711: }

unix.superglobalmegacorp.com

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