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

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

unix.superglobalmegacorp.com

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