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

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

unix.superglobalmegacorp.com

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