Annotation of nono/vm/pio.cpp, revision 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.