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

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

unix.superglobalmegacorp.com

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