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

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

unix.superglobalmegacorp.com

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