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

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

unix.superglobalmegacorp.com

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