Annotation of nono/vm/goldfish_pic.cpp, revision 1.1.1.3

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Goldfish 割り込みコントローラ
                      9: //
                     10: 
                     11: // 32本の独立した割り込みソースを持ち、独立してマスクできるコントローラ。
                     12: // オリジナルの Google のドキュメントは用語がひどすぎてアレ。
                     13: //
                     14: // レジスタ仕様は次の通り。
                     15: //  +$00.L STATUS              R-: ペンディングしている割り込み数 (0-32)。
                     16: //  +$04.L PENDING             R-: 最も優先度の高いペンディング割り込み取得。
                     17: //  +$08.L CLEAR_ALL   -W: 割り込みペンディングをすべてクリアする。
                     18: //  +$0c.L DISABLE             -W: 指定の割り込みを無効にする。
                     19: //  +$10.L ENABLE              -W: 指定の割り込みを有効にする。
                     20: //
                     21: // bit0 (IRQ1) なら $00000001、bit31 (IRQ32) なら $80000000 で、
                     22: // IRQ1 側 (LSB 側) が優先度が高い。
                     23: //
                     24: // PENDING は最も優先度の高いペンディングのビットを(たぶん1つ)返す。
                     25: // ペンディング割り込みがなければ 0 を返す。
                     26: //
                     27: // CLEAR_ALL はすべての割り込みソース (ENABLE されていないものも含む)
                     28: // のレベルを low に落とす。enable 状態は変えない。
                     29: //
                     30: // ENABLE/DISABLE は指定したビット位置の割り込みを有効/無効にする。
                     31: //
                     32: // PENDING/ENABLE/DISABLE はいずれも
                     33: //
                     34: // nono では intmap の構造を流用するがここではレベル判定が不要なので、
                     35: // Goldfish の仕様通り 32ビットすべてで割り込みを受け付ける。
                     36: //
                     37: // ここまでが単体の Goldfish 割り込みコントローラの仕様で、このコントローラ
                     38: // にはレベルの概念はないので m68k で使う場合はこれを Lv1 から Lv6 までの
                     39: // 6個用意して、各自目的のレベルのコントローラに配線するという仕組み。
                     40: //
                     41: // MPU <--- Virt68kInterrupt <-+- GFPICDevice(Lv6)
                     42: //                             +- GFPICDevice(Lv5)
                     43: //                             +- GFPICDevice(Lv4)
                     44: //                             +- GFPICDevice(Lv3)
                     45: //                             +- GFPICDevice(Lv2)
                     46: //                             +- GFPICDevice(Lv1)
                     47: 
                     48: #include "goldfish_pic.h"
1.1.1.3 ! root       49: #include "monitor.h"
1.1       root       50: #include <algorithm>
                     51: 
                     52: // コンストラクタ
1.1.1.2   root       53: GFPICDevice::GFPICDevice(uint id_)
1.1       root       54:        : inherited(OBJ_GFPIC(id_))
                     55: {
                     56: }
                     57: 
                     58: // デストラクタ
                     59: GFPICDevice::~GFPICDevice()
                     60: {
                     61: }
                     62: 
                     63: // 初期化
                     64: bool
                     65: GFPICDevice::Init()
                     66: {
                     67:        if (inherited::Init() == false) {
                     68:                return false;
                     69:        }
                     70: 
                     71:        interrupt = GetInterruptDevice();
                     72: 
                     73:        return true;
                     74: }
                     75: 
                     76: // 電源オン/リセット
                     77: void
                     78: GFPICDevice::ResetHard(bool poweron)
                     79: {
1.1.1.3 ! root       80:        inherited::ResetHard(poweron);
        !            81: 
1.1       root       82:        intmap_enable = 0;
                     83:        ChangeInterrupt();
                     84: }
                     85: 
                     86: busdata
1.1.1.2   root       87: GFPICDevice::ReadPort(uint32 offset)
1.1       root       88: {
                     89:        busdata data;
                     90: 
                     91:        switch (offset) {
                     92:         case STATUS:
1.1.1.2   root       93:                data = GetSTATUS();
1.1       root       94:                putlog(2, "STATUS -> $%08x", data.Data());
                     95:                break;
                     96: 
                     97:         case PENDING:
1.1.1.2   root       98:                data = GetPENDING();
1.1       root       99:                putlog(2, "PENDING -> $%08x", data.Data());
                    100:                break;
                    101: 
                    102:         default:
                    103:                data.SetBusErr();
                    104:                break;
                    105:        }
                    106: 
1.1.1.2   root      107:        data |= BusData::Size4;
1.1       root      108:        return data;
                    109: }
                    110: 
                    111: busdata
1.1.1.2   root      112: GFPICDevice::WritePort(uint32 offset, uint32 data)
1.1       root      113: {
                    114:        busdata r;
                    115: 
                    116:        switch (offset) {
                    117:         case CLEAR_ALL:
                    118:                putlog(1, "CLEAR_ALL");
                    119:                intmap_status = 0;
                    120:                ChangeInterrupt();
                    121:                break;
                    122: 
                    123:         case DISABLE:
                    124:                putlog(1, "DISABLE $%08x", data);
                    125:                intmap_enable &= ~data;
                    126:                break;
                    127: 
                    128:         case ENABLE:
                    129:                putlog(1, "ENABLE  $%08x", data);
                    130:                intmap_enable |= data;
                    131:                break;
                    132: 
                    133:         default:
                    134:                r.SetBusErr();
                    135:                break;
                    136:        }
1.1.1.2   root      137: 
                    138:        r |= BusData::Size4;
1.1       root      139:        return r;
                    140: }
                    141: 
                    142: busdata
1.1.1.2   root      143: GFPICDevice::PeekPort(uint32 offset)
1.1       root      144: {
1.1.1.2   root      145:        switch (offset) {
                    146:         case STATUS:
                    147:                return GetSTATUS();
                    148: 
                    149:         case PENDING:
                    150:                return GetPENDING();
                    151: 
                    152:         default:
                    153:                return BusData::BusErr;
                    154:        }
1.1       root      155: }
                    156: 
                    157: // Virt68kInterrupt の下請け。上のサマリ部分。
                    158: void
                    159: GFPICDevice::MonitorUpdateSummary(TextScreen& screen, int x, int y)
                    160: {
                    161:        for (int i = 0; i < 32; i++) {
                    162:                uint32 bit = 0x8000'0000 >> i;
                    163:                if ((intmap_avail & bit) != 0) {
                    164:                        bool status = (intmap_status & bit);
                    165:                        bool enable = (intmap_enable & bit);
                    166:                        screen.Putc(x, y, TA::OnOff(status), (enable ? 'E' : 'D'));
                    167:                } else {
                    168:                        screen.Putc(x, y, '.');
                    169:                }
                    170:                x++;
                    171:                if ((i % 8) == 7) {
                    172:                        x++;
                    173:                }
                    174:        }
                    175: }
                    176: 
                    177: // Virt68kInterrupt の下請け。下の個別部分。
                    178: int
                    179: GFPICDevice::MonitorUpdateDetail(TextScreen& screen, int y, int lv)
                    180: {
                    181: // 0         1         2         3         4         5         6         7
                    182: // 01234567890123456789012345678901234567890123456789012345678901234567890123456
                    183: // Lv Device IM=7 IRQ         20         10         1                      Count
                    184: // 1  GFPIC1 Mask 21098765 43210987 65432109 87654321 01234567890123456789012345
                    185: //
                    186: // GFPIC1 IRQ22 XXXXX                                 01234567890123456789012345
                    187: 
                    188:        for (auto intmap : disp_list) {
                    189:                int clz = __builtin_clz(intmap);
                    190:                int irq = 32 - clz;
                    191:                const char *name = GetIntName(intmap);
                    192: 
1.1.1.2   root      193:                screen.Print(0, y, "GFPIC%u IRQ%2u", lv, irq);
1.1       root      194:                screen.Puts(13, y, TA::OnOff(intmap_status & intmap), name);
                    195:                screen.Print(51, y, "%26s", format_number(counter[clz]).c_str());
                    196:                y++;
                    197:        }
                    198: 
                    199:        return y;
                    200: }
                    201: 
1.1.1.2   root      202: // STATUS レジスタを返す。
                    203: uint32
                    204: GFPICDevice::GetSTATUS() const
                    205: {
                    206:        return __builtin_popcount(intmap_status);
                    207: }
                    208: 
                    209: // PENDING レジスタを返す。
                    210: uint32
                    211: GFPICDevice::GetPENDING() const
                    212: {
                    213:        // 一番下の立っているビットだけにして返す。
                    214:        return intmap_status & -intmap_status;
                    215: }
                    216: 
1.1       root      217: busdata
                    218: GFPICDevice::InterruptAcknowledge(int lv)
                    219: {
                    220:        // たぶん何もしない。
                    221:        return 0;
                    222: }
                    223: 
                    224: // 割り込み信号線の状態を変える
                    225: void
                    226: GFPICDevice::ChangeInterrupt()
                    227: {
                    228:        bool irq = (intmap_enable & intmap_status);
                    229:        interrupt->ChangeINT(this, irq);
                    230: }
                    231: 
                    232: // この PIC に IRQ を登録する。
                    233: // ここだけ子デバイスが自発的に登録を行う方式。
                    234: // irq は 1-32。
                    235: void
                    236: GFPICDevice::RegistIRQ(int irq, const char *name, Device *source)
                    237: {
                    238:        uint32 intmap = 1U << (irq - 1);
                    239: 
1.1.1.2   root      240:        assertmsg((intmap_avail & intmap) == 0, "IRQ=%u already registered", irq);
1.1       root      241: 
                    242:        RegistINT(intmap, name, source);
                    243: 
                    244:        // 表示順は IRQ01 -> IRQ32
                    245:        disp_list.push_back(intmap);
                    246:        std::sort(disp_list.begin(), disp_list.end());
                    247: 
                    248:        // ここで親の Virt68kInterrupt のモニタ行数を増やす。
                    249:        // 本当は登録がすべて終わった頃に Virt68kInterrupt から各 GFPIC
                    250:        // に問い合わせたいが、どちらも Init() での処理であり、オブジェクトの
                    251:        // 依存関係から無理なので、こっちから都度プッシュする。
                    252:        auto virt68kinterrupt = dynamic_cast<Virt68kInterrupt*>(interrupt);
                    253:        virt68kinterrupt->IncMonitorHeight();
                    254: }

unix.superglobalmegacorp.com

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