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

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

unix.superglobalmegacorp.com

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