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

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: 
1.1.1.10  root        7: //
                      8: // PIO/PPI (i8255)
                      9: //
                     10: 
                     11: // IODevice
                     12: //    |
                     13: //    |  +-------------+
                     14: //    +--| i8255Device | (8255 としての共通部分)
                     15: //       +-------------+
                     16: //          |
                     17: //          |  +-----------+
                     18: //          +--| PPIDevice |  (X68030)
                     19: //          |  +-----------+
                     20: //          |
                     21: //          |  +------------+
                     22: //          +--| PIO0Device | (LUNA)
                     23: //          |  +------------+
                     24: //          |
                     25: //          |  +------------+
                     26: //          +--| PIO1Device | (LUNA)
                     27: //             +------------+
                     28: 
1.1       root       29: #include "pio.h"
1.1.1.9   root       30: #include "bitops.h"
1.1.1.12  root       31: #include "dipsw.h"
                     32: #include "interrupt.h"
1.1       root       33: #include "lcd.h"
1.1.1.3   root       34: #include "mainapp.h"
1.1.1.12  root       35: #include "mpu64180.h"
1.1.1.10  root       36: #include "power.h"
1.1       root       37: #include "scheduler.h"
                     38: 
                     39: //
                     40: // i8255
                     41: //
                     42: 
                     43: // コンストラクタ
1.1.1.14! root       44: i8255Device::i8255Device(uint objid_)
1.1.1.12  root       45:        : inherited(objid_)
1.1       root       46: {
                     47: }
                     48: 
                     49: // デストラクタ
                     50: i8255Device::~i8255Device()
                     51: {
                     52: }
                     53: 
1.1.1.4   root       54: // リセット
                     55: void
1.1.1.10  root       56: i8255Device::ResetHard(bool poweron)
1.1.1.4   root       57: {
                     58:        // clears the control register
                     59:        // and place ports A, B, and C in input mode.
                     60:        // The input latches in ports A, B, and C are not cleared.
                     61: 
                     62:        ctrl = 0b10011011;
                     63: }
                     64: 
1.1       root       65: // コントロールポートへの書き込み。
                     66: void
                     67: i8255Device::WriteCtrl(uint32 data)
                     68: {
                     69:        if ((data & 0x80)) {
                     70:                // 最上位が立っていればモード設定
                     71:                ctrl = data;
1.1.1.12  root       72:                if (__predict_false(loglevel >= 1)) {
                     73:                        if (loglevel >= 2) {
1.1.1.14! root       74:                                putlogn("Ctrl <- $%02x: GrA/Bmode=%u/%u PA=%s PB=%s PC=%s:%s",
1.1.1.12  root       75:                                        data,
                     76:                                        GetGroupAMode(), GetGroupBMode(),
                     77:                                        PortADir() == DIR_IN ? "IN" : "OUT",
                     78:                                        PortBDir() == DIR_IN ? "IN" : "OUT",
                     79:                                        PortCHDir() == DIR_IN ? "IN" : "OUT",
                     80:                                        PortCLDir() == DIR_IN ? "IN" : "OUT");
                     81:                        } else {
                     82:                                putlogn("Ctrl <- $%02x: SetMode", data);
                     83:                        }
                     84:                }
1.1       root       85: 
                     86:                // モード設定すると PC はゼロクリアされる
                     87:                for (int pc = 0; pc < 8; pc++) {
                     88:                        SetPC(pc, 0);
                     89:                }
                     90:        } else {
                     91:                // portC 出力
                     92:                //
                     93:                // 0  x  x  x  P  P  P  V
                     94:                //             |  |  |  +-- 書き込むビットデータ
                     95:                //             +--+--+----- 書き込むビット位置
                     96: 
1.1.1.14! root       97:                uint pc = (data >> 1) & 7;
        !            98:                uint val = data & 1;
        !            99:                putlog(2, "Ctrl <- $%02x: SetPC%u=%u", data, pc, val);
1.1       root      100:                SetPC(pc, val);
                    101:        }
                    102: }
                    103: 
1.1.1.14! root      104: bool
        !           105: i8255Device::PokePort(uint32 offset, uint32 data)
        !           106: {
        !           107:        return false;
        !           108: }
        !           109: 
1.1.1.12  root      110: // 共通部分を表示。
                    111: // 戻り値は表示を終えた次の行。
                    112: int
                    113: i8255Device::MonitorUpdateCommon(TextScreen& screen, int y)
                    114: {
                    115:        // Control = $xx
                    116:        //  GroupA (PortA,PortCH) Mode: 0(Basic I/O)
                    117:        //  GroupB (PortB,PortCL) Mode: 1(Strobed I/O)
                    118:        //  Port Direction: PA=OUT PB=IN  PC(H)=OUT PC(L)=OUT
                    119: 
                    120:        screen.Print(1, y, "Control = $%02x:", ctrl);
                    121:        static const char * const modestr[] = {
                    122:                "Basic I/O",
                    123:                "Strobed I/O",
                    124:                "BiDirection",
                    125:                "BiDirection",
                    126:        };
                    127:        const int x = 16;
1.1.1.14! root      128:        screen.Print(x, y++, "GroupA (PortA,PortCH) Mode: %u(%s)",
1.1.1.12  root      129:                GetGroupAMode(),
                    130:                modestr[GetGroupAMode()]);
1.1.1.14! root      131:        screen.Print(x, y++, "GroupB (PortB,PortCL) Mode: %u(%s)",
1.1.1.12  root      132:                GetGroupBMode(),
                    133:                modestr[GetGroupBMode()]);
                    134:        static const char *inoutstr[] = {
                    135:                "OUT",
                    136:                "IN ",
                    137:        };
                    138:        screen.Print(x, y++, "Port Direction: PA=%s PB=%s PC(H)=%s PC(L)=%s",
                    139:                inoutstr[PortADir()],
                    140:                inoutstr[PortBDir()],
                    141:                inoutstr[PortCHDir()],
                    142:                inoutstr[PortCLDir()]);
                    143: 
                    144:        return y;
                    145: }
                    146: 
1.1       root      147: //
                    148: // X68k PPI
                    149: //
                    150: 
1.1.1.13  root      151: // InsideOut p.135
                    152: static const busdata ppi_wait = busdata::Wait(19 * 40_nsec);
                    153: 
1.1       root      154: // コンストラクタ
                    155: PPIDevice::PPIDevice()
1.1.1.12  root      156:        : inherited(OBJ_PPI)
1.1       root      157: {
                    158: }
                    159: 
                    160: // デストラクタ
                    161: PPIDevice::~PPIDevice()
                    162: {
                    163: }
                    164: 
1.1.1.13  root      165: busdata
1.1.1.14! root      166: PPIDevice::ReadPort(uint32 offset)
1.1       root      167: {
1.1.1.13  root      168:        busdata data;
1.1.1.4   root      169: 
1.1.1.6   root      170:        switch (offset) {
1.1       root      171:         case 0:
                    172:         case 1:
1.1.1.13  root      173:                data = 0xff;
                    174:                break;
1.1       root      175:         case 2:
1.1.1.11  root      176:                putlog(0, "Read $e9a005 PortC (NOT IMPLEMENTED)");
1.1.1.13  root      177:                data = 0xff;
                    178:                break;
1.1       root      179:         case 3:
1.1.1.11  root      180:                putlog(0, "Read $e9a007 Ctrl (NOT IMPLEMENTED)");
1.1.1.13  root      181:                data = 0xff;
                    182:                break;
1.1       root      183:         default:
1.1.1.14! root      184:                VMPANIC("corrupted offset=%u", offset);
1.1       root      185:        }
1.1.1.13  root      186: 
                    187:        data |= ppi_wait;
1.1.1.14! root      188:        data |= BusData::Size1;
1.1.1.13  root      189:        return data;
1.1       root      190: }
                    191: 
1.1.1.13  root      192: busdata
1.1.1.14! root      193: PPIDevice::WritePort(uint32 offset, uint32 data)
1.1       root      194: {
1.1.1.6   root      195:        switch (offset) {
1.1       root      196:         case 0:
                    197:         case 1:
                    198:                break;
1.1.1.11  root      199:         case 2:        // PPI PortC
                    200:                for (int i = 0; i < 8; i++) {
                    201:                        SetPC(i, data & 1);
                    202:                        data >>= 1;
                    203:                }
1.1       root      204:                break;
                    205:         case 3:
1.1.1.11  root      206:                WriteCtrl(data);
1.1       root      207:                break;
                    208:         default:
1.1.1.14! root      209:                VMPANIC("corrupted offset=%u", offset);
1.1       root      210:        }
1.1.1.14! root      211:        busdata r = ppi_wait;
        !           212:        r |= BusData::Size1;
        !           213:        return r;
1.1       root      214: }
                    215: 
1.1.1.13  root      216: busdata
1.1.1.14! root      217: PPIDevice::PeekPort(uint32 offset)
1.1       root      218: {
                    219:        // XXX
                    220:        return 0xff;
                    221: }
                    222: 
1.1.1.10  root      223: // PortC 書き込み
                    224: void
1.1.1.14! root      225: PPIDevice::SetPC(uint pc, uint val)
1.1.1.10  root      226: {
1.1.1.11  root      227:        switch (pc) {
                    228:         case 0:        // ADPCM PAN Left Off
                    229:                pan_left = !val;
1.1.1.14! root      230:                return;
1.1.1.11  root      231:         case 1:        // ADPCM PAN Right Off
                    232:                pan_right = !val;
1.1.1.14! root      233:                return;
1.1.1.11  root      234:         case 2:        // ADPCM サンプリングレート
                    235:                adpcm_rate = (adpcm_rate & 2) | val;
1.1.1.14! root      236:                return;
1.1.1.11  root      237:         case 3:        // ADPCM サンプリングレート
                    238:                adpcm_rate = (val << 1) | (adpcm_rate & 1);
1.1.1.14! root      239:                return;
1.1.1.11  root      240: 
                    241:         case 4:        // ジョイスティック #1 コントロール
                    242:         case 5:        // ジョイスティック #2 コントロール
                    243:         case 6:        // ジョイスティック #1 ボタン A
                    244:         case 7:        // ジョイスティック #1 ボタン B
1.1.1.14! root      245:                putlog(1, "SetPC(%u) <- %u (NOT IMPLEMENTED)", pc, val);
        !           246:                return;
1.1.1.11  root      247:         default:
1.1.1.14! root      248:                VMPANIC("corrupted pc=%u", pc);
1.1.1.11  root      249:        }
1.1.1.10  root      250: }
                    251: 
1.1       root      252: //
                    253: // LUNA PIO0
                    254: //
                    255: // 仕様は 0x49000000 から 4バイトだが、
1.1.1.12  root      256: // LUNA-I   では 0x48000000 から 0x4bffffff まで 4バイト単位のミラーが見える。
                    257: // LUNA-88K では 0x48000000 から 0x49ffffff までが
                    258: // (こちらはロングワード配置なので) 16バイト単位のミラーに見える。
1.1.1.9   root      259: //
                    260: // PIO から読み出せる値のビットの並び順が機種によって異なる。
1.1.1.12  root      261: // LUNA-I   では DIPSW 1番が LSB、8番が MSB の並び順、
                    262: // LUNA-88K では DIPSW 1番が MSB、8番が LSB の並び順。
1.1.1.9   root      263: // 値は、並び順に関わらずどちらも
                    264: // %0 が false = down = "0"、%1 が true = up = "1" である。
                    265: //
                    266: //    #1 #2 #3 #4 #5 #6 #7 #8
                    267: //  +-------------------------+
                    268: //  |    [] [] [] [] [] [] [] | 本体外観
                    269: //  | []                      |
                    270: //  +-------------------------+
                    271: //
                    272: // luna-dipsw1 = "01111111"    ← 設定ファイル
                    273: //                ||||||||     ↓ このクラスのメンバ変数
                    274: //                |||||||+- dipsw1[7] = true;
                    275: //                ||||||+-- dipsw1[6] = true;
                    276: //                |||||+--- dipsw1[5] = true;
                    277: //                ||||+---- dipsw1[4] = true;
                    278: //                |||+----- dipsw1[3] = true;
                    279: //                ||+------ dipsw1[2] = true;
                    280: //                |+------- dipsw1[1] = true;
                    281: //                +-------- dipsw1[0] = false;
                    282: //
                    283: //              b7   b6   b5   b4   b3   b2   b1   b0
                    284: //            +----+----+----+----+----+----+----+----+
1.1.1.12  root      285: // LUNA-I     | #8 | #7 | #6 | #5 | #4 | #3 | #2 | #1 |
1.1.1.9   root      286: // PortA      |  1 |  1 |  1 |  1 |  1 |  1 |  1 |  0 | %1=UP, %0=DOWN
                    287: //            +----+----+----+----+----+----+----+----+
                    288: //
                    289: //              b7   b6   b5   b4   b3   b2   b1   b0
                    290: //            +----+----+----+----+----+----+----+----+
1.1.1.12  root      291: // LUNA-88K   | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 |
1.1.1.9   root      292: // PortA      |  0 |  1 |  1 |  1 |  1 |  1 |  1 |  1 | %1=UP, %0=DOWN
                    293: //            +----+----+----+----+----+----+----+----+
1.1       root      294: //
1.1.1.12  root      295: // LUNA-I:
1.1       root      296: // #1-1 up なら UNIX をロードして移行。down なら ROM モニタで起動。
                    297: // #1-2 up ならディスプレイコンソール。down ならシリアルコンソール。
                    298: // #1-3 up - color display, down - force to have monochrome display
                    299: // #1-4 up - no write verification,
                    300: //      down - verification on every harddisk write operation
                    301: // #1-5 up - OS is UniOS-U (SystemV/COFF),
                    302: //      down - OS is UniOS (4.3BSD/a.out OMAGIC)
                    303: // #1-6 down - force monochrome display?
                    304: // #1-7 up - boot from local device, down - boot from network
                    305: // #1-8 up - normal boot, down - start diagnostics と書いてあるが
                    306: //      down にすると画面真っ暗で詳細不明。
                    307: //
                    308: // #2-x すべて up にすると /boot が自動的にカーネルを起動。一つでも down が
                    309: //      あれば /boot がプロンプトで停止。これは ROM ではなく NetBSD のブート
                    310: //      ローダの話。
                    311: //      どこか由来のソースコードらしいがたぶんビット演算を間違えている。
1.1.1.3   root      312: //
1.1.1.12  root      313: // LUNA-88K:
1.1.1.3   root      314: // #1-1 up なら ROM モニタで停止、down ならマルチユーザブート。
                    315: //      OpenBSD カーネルも up なら UserKernelConfig で止まる模様?。
                    316: // #1-2 up なら外付けシリアルコンソール、down なら内蔵ビットマップ。
1.1.1.9   root      317: // #1-3..#1-7 は不明?
                    318: // #1-8 down なら自己診断後電源オフするようだ。
1.1.1.3   root      319: // #2-x はユーザ(?)
1.1       root      320: 
                    321: // コンストラクタ
                    322: PIO0Device::PIO0Device()
1.1.1.12  root      323:        : inherited(OBJ_PIO0)
1.1       root      324: {
1.1.1.12  root      325:        // LUNA-I と LUNA-88K とでポートのビット並びが逆。どうして…
                    326:        if (gMainApp.IsLUNA88K()) {
1.1.1.9   root      327:                msb_first = true;
1.1.1.12  root      328:        } else {
                    329:                msb_first = false;
1.1.1.3   root      330:        }
                    331: 
1.1.1.12  root      332:        // PIO0/PIO1
1.1.1.10  root      333:        monitor.func = ToMonitorCallback(&PIO0Device::MonitorUpdate);
1.1.1.12  root      334:        monitor.SetSize(76, 15);
                    335:        monitor.Regist(ID_MONITOR_PIO);
1.1       root      336: }
                    337: 
                    338: // デストラクタ
                    339: PIO0Device::~PIO0Device()
                    340: {
                    341: }
                    342: 
1.1.1.12  root      343: // 初期化
1.1       root      344: bool
                    345: PIO0Device::Init()
                    346: {
1.1.1.12  root      347:        if (inherited::Init() == false) {
1.1       root      348:                return false;
                    349:        }
                    350: 
1.1.1.12  root      351:        interrupt = GetInterruptDevice();
                    352:        pio1 = GetPIO1Device();
                    353: 
1.1       root      354:        return true;
                    355: }
                    356: 
1.1.1.12  root      357: // リセット
                    358: void
                    359: PIO0Device::ResetHard(bool poweron)
                    360: {
                    361:        auto dipswdev = GetDipswDevice();
                    362: 
                    363:        // XXX 本当は XP から割り込みが上がったタイミングとからしいけど、
                    364:        //     XP が出来るまでは当面リセットでラッチにしておく。
                    365:        for (int i = 0; i < 8; i++) {
                    366:                dipsw1[i] = dipswdev->Get(i);
                    367:                dipsw2[i] = dipswdev->Get(i + 8);
                    368:        }
                    369: 
                    370:        // XXX どうなる?
                    371:        for (int i = 0; i < intreq.size(); i++) {
                    372:                intreq[i] = false;
                    373:                inten[i] = false;
                    374:        }
                    375: }
1.1.1.7   root      376: 
1.1.1.13  root      377: busdata
1.1.1.14! root      378: PIO0Device::ReadPort(uint32 offset)
1.1       root      379: {
1.1.1.14! root      380:        busdata data;
1.1       root      381: 
1.1.1.6   root      382:        switch (offset) {
1.1       root      383:         case 0:
                    384:                // PortA
1.1.1.11  root      385:                data = GetPA();
1.1.1.12  root      386: 
                    387:                // 割り込み要求(High)をクリア
                    388:                intreq[INT_H] = false;
                    389:                ChangeInterrupt();
                    390: 
1.1.1.14! root      391:                putlog(1, "DIP-SW1 -> $%02x", data.Data());
1.1.1.13  root      392:                break;
1.1       root      393: 
                    394:         case 1:
                    395:                // PortB
1.1.1.11  root      396:                data = GetPB();
1.1.1.12  root      397: 
                    398:                // 割り込み要求(Low)をクリア
                    399:                intreq[INT_L] = false;
                    400:                ChangeInterrupt();
                    401: 
1.1.1.14! root      402:                putlog(1, "DIP-SW2 -> $%02x", data.Data());
1.1.1.13  root      403:                break;
1.1       root      404: 
                    405:         case 2:
                    406:                // PortC
                    407:                data = GetPC();
1.1.1.14! root      408:                putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13  root      409:                break;
1.1       root      410: 
                    411:         case 3:
                    412:                data = ReadCtrl();
1.1.1.14! root      413:                putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13  root      414:                break;
1.1       root      415: 
                    416:         default:
1.1.1.14! root      417:                VMPANIC("corrupted offset=%u", offset);
1.1       root      418:        }
1.1.1.13  root      419: 
                    420:        // XXX wait?
1.1.1.14! root      421:        data |= BusData::Size1;
1.1.1.13  root      422:        return data;
1.1       root      423: }
                    424: 
1.1.1.13  root      425: busdata
1.1.1.14! root      426: PIO0Device::WritePort(uint32 offset, uint32 data)
1.1       root      427: {
1.1.1.6   root      428:        switch (offset) {
1.1       root      429:         case 0:        // PIO0 PortA: DIPSW1 (入力のみ)
                    430:         case 1:        // PIO0 PortB: DIPSW2 (入力のみ)
1.1.1.13  root      431:                break;
1.1       root      432: 
                    433:         case 2:        // PIO0 PortC: ホスト割り込み制御
                    434:                for (int i = 0; i < 8; i++) {
                    435:                        SetPC(i, data & 1);
                    436:                        data >>= 1;
                    437:                }
1.1.1.13  root      438:                break;
1.1       root      439: 
                    440:         case 3:        // コントロール
                    441:                WriteCtrl(data);
1.1.1.13  root      442:                break;
1.1       root      443: 
                    444:         default:
1.1.1.14! root      445:                VMPANIC("corrupted offset=%u", offset);
1.1       root      446:        }
1.1.1.13  root      447: 
                    448:        // XXX wait?
1.1.1.14! root      449:        busdata r = BusData::Size1;
        !           450:        return r;
1.1       root      451: }
                    452: 
1.1.1.13  root      453: busdata
1.1.1.14! root      454: PIO0Device::PeekPort(uint32 offset)
1.1       root      455: {
1.1.1.6   root      456:        switch (offset) {
1.1       root      457:         case 0:
                    458:                return GetPA();
                    459: 
                    460:         case 1:
                    461:                return GetPB();
                    462: 
                    463:         case 2:
                    464:                return GetPC();
                    465: 
                    466:         case 3:
                    467:                return ReadCtrl();
                    468: 
                    469:         default:
1.1.1.12  root      470:                return 0xff;
1.1       root      471:        }
                    472: }
                    473: 
1.1.1.12  root      474: // PIO0 が PIO0/PIO1 のモニタ両方を担当する。
1.1.1.3   root      475: void
1.1.1.8   root      476: PIO0Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2   root      477: {
                    478:        int y;
                    479: 
1.1.1.8   root      480:        screen.Clear();
1.1.1.2   root      481: 
1.1.1.12  root      482:        // PIO0
                    483:        screen.Puts(0, 0, "PIO0 (BaseAddr: $49000000)");
                    484:        y = MonitorUpdateCommon(screen, 1);
                    485: 
                    486:        // PIO0 固有部
                    487:        uint32 pa = GetPA();
                    488:        uint32 pb = GetPB();
                    489:        screen.Print(1, y,     "PortA(DIP-SW1)=$%02x:", pa);
                    490:        screen.Print(1, y + 1, "PortB(DIP-SW2)=$%02x:", pb);
                    491:        for (int i = 0; i < 8; i++) {
                    492:                // この図は bit7..0 をこの順で表示するので bitpos の向きは固定。
                    493:                int bitpos = 7 - i;
                    494:                // DIPSW の物理位置 #1 をバイトの下にするか上にするかが機種によって
                    495:                // 違う。どうして…。
                    496:                int label = (msb_first ? i : bitpos) + 1;
                    497: 
                    498:                bool d1 = (pa & (1U << bitpos));
                    499:                bool d2 = (pb & (1U << bitpos));
1.1.1.14! root      500:                screen.Print(21 + i * 7, y,     TA::OnOff(d1), "DIP1-%u", label);
        !           501:                screen.Print(21 + i * 7, y + 1, TA::OnOff(d2), "DIP2-%u", label);
1.1.1.12  root      502:        }
                    503:        y += 2;
                    504: 
                    505:        uint32 pc = GetPC();
                    506:        screen.Print(1, y, "PortC(XP etc.)=$%02x:", pc);
                    507:        static const char * const pcstr[] = {
                    508:                "XP RST", "PARITY", "------", "INT5EN",
                    509:                "INT5RQ", "INT1EN", "------", "INT1RQ",
                    510:        };
                    511:        for (int i = 0; i < 8; i++) {
                    512:                screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
                    513:        }
                    514:        y++;
                    515: 
                    516:        // PIO1 移譲
                    517:        y++;
                    518:        pio1->MonitorUpdatePIO1(screen, y);
1.1.1.2   root      519: }
                    520: 
1.1       root      521: // PortA (DIP-SW 1) 読み込み
                    522: uint32
                    523: PIO0Device::GetPA() const
                    524: {
                    525:        uint32 data = 0;
                    526:        for (int i = 0; i < 8; i++) {
                    527:                data |= ((int)dipsw1[i]) << i;
                    528:        }
1.1.1.9   root      529:        if (msb_first) {
                    530:                data = bitrev(data);
                    531:        }
1.1       root      532:        return data & 0xff;
                    533: }
                    534: 
                    535: // PortB (DIP-SW 2) 読み込み
                    536: uint32
                    537: PIO0Device::GetPB() const
                    538: {
                    539:        uint32 data = 0;
                    540:        for (int i = 0; i < 8; i++) {
                    541:                data |= ((int)dipsw2[i]) << i;
                    542:        }
1.1.1.9   root      543:        if (msb_first) {
                    544:                data = bitrev(data);
                    545:        }
1.1       root      546:        return data & 0xff;
                    547: }
                    548: 
                    549: // PortC 読み込み
                    550: uint32
                    551: PIO0Device::GetPC() const
                    552: {
                    553:        uint32 data;
                    554: 
                    555:        data = 0x00     // XXX 空きビットは何が読めるか?
1.1.1.12  root      556:                 | (intreq[INT_L]       ? 0x01 : 0)
                    557:                 | (inten[INT_L]        ? 0x04 : 0)
                    558:                 | (intreq[INT_H]       ? 0x08 : 0)
                    559:                 | (inten[INT_H]        ? 0x10 : 0)
                    560:                 | (parity                      ? 0x40 : 0)
                    561:                 | (xp_reset            ? 0x80 : 0);
1.1       root      562:        return data;
                    563: }
                    564: 
                    565: // PortC 書き込み
                    566: void
1.1.1.14! root      567: PIO0Device::SetPC(uint pc, uint val)
1.1       root      568: {
                    569:        switch (pc) {
                    570:         case 0:
1.1.1.12  root      571:                // INT1 割り込み要求 (Read Only)
1.1       root      572:                return;
                    573:         case 1:
                    574:                // Not Connected.
                    575:                return;
                    576:         case 2:
1.1.1.12  root      577:                inten[INT_L] = val;
                    578:                ChangeInterrupt();
1.1       root      579:                return;
                    580:         case 3:
1.1.1.12  root      581:                // INT5 割り込み要求 (Read Only)
1.1       root      582:                return;
                    583:         case 4:
1.1.1.12  root      584:                inten[INT_H] = val;
                    585:                ChangeInterrupt();
1.1       root      586:                return;
                    587:         case 5:
                    588:                // Not Connected.
                    589:                return;
                    590:         case 6:
                    591:                // パリティ有効/無効
                    592:                // 使わないので無視するが読み返しのために覚えておく
                    593:                parity = val;
                    594:                return;
                    595:         case 7:
                    596:                // XP リセット
                    597:                if ((val ^ xp_reset)) {
                    598:                        xp_reset = val;
1.1.1.14! root      599:                        putlog(1, "XP Reset %u", xp_reset);
1.1.1.12  root      600:                        auto mpu64180 = GetMPU64180Device();
                    601:                        mpu64180->ChangeRESET(xp_reset);
1.1       root      602:                }
                    603:                return;
1.1.1.14! root      604:         default:
        !           605:                VMPANIC("corrupted pc=%u", pc);
1.1       root      606:        }
                    607: }
                    608: 
1.1.1.12  root      609: // とりあえず、XP からここまではエッジトリガーで、
                    610: // ここから割り込みコントローラへはレベルトリガーとしておく。
                    611: 
                    612: // XP からの割り込み (High)
                    613: void
                    614: PIO0Device::InterruptXPHigh()
                    615: {
                    616:        intreq[INT_H] = true;
                    617:        ChangeInterrupt();
                    618: }
                    619: 
                    620: 
                    621: // XP からの割り込み (Low)
                    622: void
                    623: PIO0Device::InterruptXPLow()
                    624: {
                    625:        intreq[INT_L] = true;
                    626:        ChangeInterrupt();
                    627: }
                    628: 
                    629: // 割り込み状態を変更。
                    630: // intreq[], inten[] の変更で呼ぶこと。
                    631: void
                    632: PIO0Device::ChangeInterrupt()
                    633: {
                    634:        bool val;
                    635: 
                    636:        val = (inten[INT_H] && intreq[INT_H]);
                    637:        interrupt->ChangeINT(DEVICE_XPINT_HIGH, val);
                    638: 
                    639:        val = (inten[INT_L] && intreq[INT_L]);
                    640:        interrupt->ChangeINT(DEVICE_XPINT_LOW, val);
                    641: }
                    642: 
1.1       root      643: 
                    644: //
                    645: // LUNA PIO1
                    646: //
                    647: // 仕様は 0x4d000000 から 4バイトだが、
1.1.1.12  root      648: // LUNA-I   では 0x4c000000 から 0x4fffffff まで 4バイト単位でミラーが見える。
                    649: // LUNA-88K では 0x4c000000 から 0x4dffffff までが
                    650: // (こちらはロングワード配置なので) 16バイト単位のミラーに見える。
1.1       root      651: 
                    652: // コンストラクタ
                    653: PIO1Device::PIO1Device()
1.1.1.12  root      654:        : inherited(OBJ_PIO1)
1.1       root      655: {
                    656: }
                    657: 
                    658: // デストラクタ
                    659: PIO1Device::~PIO1Device()
                    660: {
1.1.1.12  root      661: }
                    662: 
                    663: // 初期化
                    664: bool
                    665: PIO1Device::Init()
                    666: {
                    667:        if (inherited::Init() == false) {
                    668:                return false;
                    669:        }
                    670: 
                    671:        lcd = GetLCDDevice();
                    672:        mpu64180 = GetMPU64180Device();
                    673:        powerdev = GetPowerDevice();
                    674: 
                    675:        return true;
1.1       root      676: }
                    677: 
1.1.1.4   root      678: // リセット
                    679: void
1.1.1.10  root      680: PIO1Device::ResetHard(bool poweron)
1.1.1.4   root      681: {
1.1.1.10  root      682:        inherited::ResetHard(poweron);
1.1.1.4   root      683: 
1.1.1.14! root      684:        // 電源ユニットは POWF* 信号が 'L' になると 1msec 後に電源オフになる。
        !           685:        // 正確には「1msec 以内に 'H' にすれば回避できる」なので、実際に電源が
        !           686:        // オフになるのはそれよりもっと十分長いとは思われる。
        !           687:        // 8255 リセット時、ポート C の各ピンは入力モードになっているので、
        !           688:        // ハイインピーダンス。たぶん電源的にも 'H' になってると想像する。
        !           689:        // なので電源オンで POWF* がハイインピーダンスなだけでは電源オフ
        !           690:        // タイマーは動作しないんじゃないかな。
        !           691:        power = true;
        !           692:        powerdev->SetSystemPowerOn(power);
1.1.1.4   root      693: }
                    694: 
1.1.1.13  root      695: busdata
1.1.1.14! root      696: PIO1Device::ReadPort(uint32 offset)
1.1       root      697: {
1.1.1.14! root      698:        busdata data;
1.1       root      699: 
1.1.1.6   root      700:        switch (offset) {
1.1       root      701:         case 0:
                    702:                // PIO1 PortA: LCD データ
1.1.1.13  root      703:                data = lcd->Read();
                    704:                break;
1.1       root      705: 
                    706:         case 1:
                    707:                // PIO1 PortB: 無効
1.1.1.13  root      708:                data = 0xff;
                    709:                break;
1.1       root      710: 
                    711:         case 2:
                    712:                // PortC
1.1.1.12  root      713:                data = lcd->Get();
1.1       root      714:                data |= xp_intreq ? 0 : 0x02;
                    715:                // 残りのビットは %1 だろうか?
                    716:                data |= 0x0d;
1.1.1.14! root      717:                putlog(1, "PortC -> $%02x", data.Data());
1.1.1.13  root      718:                break;
1.1       root      719: 
                    720:         case 3:
                    721:                data = ReadCtrl();
1.1.1.14! root      722:                putlog(1, "Ctrl -> $%02x", data.Data());
1.1.1.13  root      723:                break;
1.1       root      724: 
                    725:         default:
1.1.1.14! root      726:                VMPANIC("corrupted offset=%u", offset);
1.1       root      727:        }
1.1.1.13  root      728: 
                    729:        // XXX wait?
1.1.1.14! root      730:        data |= BusData::Size1;
1.1.1.13  root      731:        return data;
1.1       root      732: }
                    733: 
1.1.1.13  root      734: busdata
1.1.1.14! root      735: PIO1Device::WritePort(uint32 offset, uint32 data)
1.1       root      736: {
1.1.1.6   root      737:        switch (offset) {
1.1       root      738:         case 0:        // PIO1 PortA: LCD データ
1.1.1.12  root      739:                lcd->Write(data);
1.1.1.13  root      740:                break;
1.1       root      741: 
1.1.1.12  root      742:         case 1:        // PIO1 PortB: XP の INT0 をアサート
                    743:                // データ不問でアサートする。
                    744:                putlog(1, "Assert XP INT0");
                    745:                mpu64180->AssertINT0();
1.1.1.13  root      746:                break;
1.1       root      747: 
                    748:         case 2:        // PIO1 PortC: LCD/パワーオフ制御
                    749:                for (int i = 0; i < 8; i++) {
                    750:                        SetPC(i, data & 1);
                    751:                        data >>= 1;
                    752:                }
1.1.1.13  root      753:                break;
1.1       root      754: 
                    755:         case 3:        // コントロール
                    756:                WriteCtrl(data);
1.1.1.13  root      757:                break;
1.1       root      758: 
                    759:         default:
1.1.1.14! root      760:                VMPANIC("corrupted offset=%u", offset);
1.1       root      761:        }
1.1.1.13  root      762: 
                    763:        // XXX wait?
1.1.1.14! root      764:        busdata r = BusData::Size1;
        !           765:        return r;
1.1       root      766: }
                    767: 
1.1.1.13  root      768: busdata
1.1.1.14! root      769: PIO1Device::PeekPort(uint32 offset)
1.1       root      770: {
1.1.1.6   root      771:        switch (offset) {
1.1       root      772:         case 0:        // PIO1 PortA LCD データ
1.1.1.12  root      773:                return lcd->Peek();
1.1       root      774: 
                    775:         case 1:        // PIO1 PortB 無効
                    776:                return 0xff;
                    777: 
                    778:         case 2:        // PIO1 PortC
1.1.1.12  root      779:                return GetPC();
1.1       root      780: 
                    781:         case 3:
                    782:                return ReadCtrl();
                    783: 
                    784:         default:
1.1.1.12  root      785:                return 0xff;
1.1       root      786:        }
                    787: }
                    788: 
1.1.1.12  root      789: // PIO0 の下請け。
                    790: void
                    791: PIO1Device::MonitorUpdatePIO1(TextScreen& screen, int y)
                    792: {
                    793:        screen.Puts(0, y++, "PIO1 (BaseAddr: $4d000000)");
                    794: 
                    795:        // 共通部分
                    796:        y = MonitorUpdateCommon(screen, y++);
                    797: 
                    798:        // PIO1 固有部
                    799:        screen.Print(1, y++, "PortA(LCDDATA)=$%02x", lcd->Peek());
                    800:        screen.Print(1, y++, "PortB(NotConn)=$%02x", 0xff);
                    801:        uint32 pc = GetPC();
                    802:        screen.Print(1, y, "PortC(LCD etc)=$%02x:", pc);
                    803:        static const char * const pcstr[] = {
                    804:                "LCD E",  "LCD RS", "LCD RD", "!PWOFF",
                    805:                "------", "------", "!XPINT", "------",
                    806:        };
                    807:        for (int i = 0; i < 8; i++) {
                    808:                screen.Puts(21 + i * 7, y, TA::OnOff(pc & (1U << (7 - i))), pcstr[i]);
                    809:        }
                    810: }
                    811: 
                    812: uint32
                    813: PIO1Device::GetPC() const
                    814: {
                    815:        uint32 data;
                    816: 
                    817:        data = lcd->Get();
                    818:        data |= xp_intreq ? 0 : 0x02;
                    819:        data |= power ? 0x10 : 0;
                    820:        // 残りのビットは %1 だろうか?
                    821:        data |= 0x0d;
                    822: 
                    823:        return data;
                    824: }
                    825: 
1.1       root      826: void
1.1.1.14! root      827: PIO1Device::SetPC(uint pc, uint val)
1.1       root      828: {
                    829:        switch (pc) {
                    830:         case 0:
                    831:         case 1:
                    832:         case 2:
                    833:         case 3:
                    834:                // PortC の下半分は入力ポートとして使われることを想定して
                    835:                // いるので、ここへの書き込みは起きないだろうし、無視する。
                    836:                return;
                    837: 
                    838:         case 4:
1.1.1.14! root      839:                // 8255 はモード変更 (WriteCtrl) をするとポート C を 'L' にするが、
        !           840:                // PC4 (POWF*) が 'L' だと電源オフ指示なので、1msec 以内に
        !           841:                // ソフトウェアでこれをキャンセルしないといけない。
        !           842:                // どうしてこうなった…。
1.1       root      843:                power = val;
                    844:                if (power) {
                    845:                        // 電源オフ取り消し
1.1.1.11  root      846:                        putlog(1, "Power-off canceled");
1.1.1.12  root      847:                        powerdev->SetSystemPowerOn(true);
1.1       root      848:                } else {
                    849:                        // 1msec 後に電源オフ
1.1.1.11  root      850:                        putlog(1, "Power-off scheduled");
1.1.1.12  root      851:                        powerdev->SetSystemPowerOn(false);
1.1       root      852:                }
                    853:                return;
                    854:         case 5:
1.1.1.12  root      855:                lcd->SetRW(val);
1.1       root      856:                return;
                    857:         case 6:
1.1.1.12  root      858:                lcd->SetRS(val);
1.1       root      859:                return;
                    860:         case 7:
1.1.1.12  root      861:                lcd->SetE(val);
1.1       root      862:                return;
                    863: 
                    864:         default:
1.1.1.14! root      865:                VMPANIC("corrupted pc=%u", pc);
1.1       root      866:        }
                    867: }

unix.superglobalmegacorp.com

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