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

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

unix.superglobalmegacorp.com

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