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

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

unix.superglobalmegacorp.com

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