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

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

unix.superglobalmegacorp.com

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