|
|
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" ! 49: #include <algorithm> ! 50: ! 51: // コンストラクタ ! 52: GFPICDevice::GFPICDevice(int id_) ! 53: : inherited(OBJ_GFPIC(id_)) ! 54: { ! 55: } ! 56: ! 57: // デストラクタ ! 58: GFPICDevice::~GFPICDevice() ! 59: { ! 60: } ! 61: ! 62: // 初期化 ! 63: bool ! 64: GFPICDevice::Init() ! 65: { ! 66: if (inherited::Init() == false) { ! 67: return false; ! 68: } ! 69: ! 70: interrupt = GetInterruptDevice(); ! 71: ! 72: return true; ! 73: } ! 74: ! 75: // 電源オン/リセット ! 76: void ! 77: GFPICDevice::ResetHard(bool poweron) ! 78: { ! 79: intmap_enable = 0; ! 80: ChangeInterrupt(); ! 81: } ! 82: ! 83: busdata ! 84: GFPICDevice::Read32(uint32 addr) ! 85: { ! 86: uint32 offset = addr & 0xfff; ! 87: busdata data; ! 88: ! 89: switch (offset) { ! 90: case STATUS: ! 91: data = __builtin_popcount(intmap_status); ! 92: putlog(2, "STATUS -> $%08x", data.Data()); ! 93: break; ! 94: ! 95: case PENDING: ! 96: // 一番下の立っているビットだけにして返す。 ! 97: data = intmap_status & -intmap_status; ! 98: putlog(2, "PENDING -> $%08x", data.Data()); ! 99: break; ! 100: ! 101: default: ! 102: data.SetBusErr(); ! 103: break; ! 104: } ! 105: ! 106: return data; ! 107: } ! 108: ! 109: busdata ! 110: GFPICDevice::Write32(uint32 addr, uint32 data) ! 111: { ! 112: uint32 offset = addr & 0xfff; ! 113: busdata r; ! 114: ! 115: switch (offset) { ! 116: case CLEAR_ALL: ! 117: putlog(1, "CLEAR_ALL"); ! 118: intmap_status = 0; ! 119: ChangeInterrupt(); ! 120: break; ! 121: ! 122: case DISABLE: ! 123: putlog(1, "DISABLE $%08x", data); ! 124: intmap_enable &= ~data; ! 125: break; ! 126: ! 127: case ENABLE: ! 128: putlog(1, "ENABLE $%08x", data); ! 129: intmap_enable |= data; ! 130: break; ! 131: ! 132: default: ! 133: r.SetBusErr(); ! 134: break; ! 135: } ! 136: return r; ! 137: } ! 138: ! 139: busdata ! 140: GFPICDevice::Peek8(uint32 addr) ! 141: { ! 142: return busdata::BusErr; ! 143: } ! 144: ! 145: // Virt68kInterrupt の下請け。上のサマリ部分。 ! 146: void ! 147: GFPICDevice::MonitorUpdateSummary(TextScreen& screen, int x, int y) ! 148: { ! 149: for (int i = 0; i < 32; i++) { ! 150: uint32 bit = 0x8000'0000 >> i; ! 151: if ((intmap_avail & bit) != 0) { ! 152: bool status = (intmap_status & bit); ! 153: bool enable = (intmap_enable & bit); ! 154: screen.Putc(x, y, TA::OnOff(status), (enable ? 'E' : 'D')); ! 155: } else { ! 156: screen.Putc(x, y, '.'); ! 157: } ! 158: x++; ! 159: if ((i % 8) == 7) { ! 160: x++; ! 161: } ! 162: } ! 163: } ! 164: ! 165: // Virt68kInterrupt の下請け。下の個別部分。 ! 166: int ! 167: GFPICDevice::MonitorUpdateDetail(TextScreen& screen, int y, int lv) ! 168: { ! 169: // 0 1 2 3 4 5 6 7 ! 170: // 01234567890123456789012345678901234567890123456789012345678901234567890123456 ! 171: // Lv Device IM=7 IRQ 20 10 1 Count ! 172: // 1 GFPIC1 Mask 21098765 43210987 65432109 87654321 01234567890123456789012345 ! 173: // ! 174: // GFPIC1 IRQ22 XXXXX 01234567890123456789012345 ! 175: ! 176: for (auto intmap : disp_list) { ! 177: int clz = __builtin_clz(intmap); ! 178: int irq = 32 - clz; ! 179: const char *name = GetIntName(intmap); ! 180: ! 181: screen.Print(0, y, "GFPIC%d IRQ%2d", lv, irq); ! 182: screen.Puts(13, y, TA::OnOff(intmap_status & intmap), name); ! 183: screen.Print(51, y, "%26s", format_number(counter[clz]).c_str()); ! 184: y++; ! 185: } ! 186: ! 187: return y; ! 188: } ! 189: ! 190: busdata ! 191: GFPICDevice::InterruptAcknowledge(int lv) ! 192: { ! 193: // たぶん何もしない。 ! 194: return 0; ! 195: } ! 196: ! 197: // 割り込み信号線の状態を変える ! 198: void ! 199: GFPICDevice::ChangeInterrupt() ! 200: { ! 201: bool irq = (intmap_enable & intmap_status); ! 202: interrupt->ChangeINT(this, irq); ! 203: } ! 204: ! 205: // この PIC に IRQ を登録する。 ! 206: // ここだけ子デバイスが自発的に登録を行う方式。 ! 207: // irq は 1-32。 ! 208: void ! 209: GFPICDevice::RegistIRQ(int irq, const char *name, Device *source) ! 210: { ! 211: uint32 intmap = 1U << (irq - 1); ! 212: ! 213: assertmsg((intmap_avail & intmap) == 0, "IRQ=%d already registered", irq); ! 214: ! 215: RegistINT(intmap, name, source); ! 216: ! 217: // 表示順は IRQ01 -> IRQ32 ! 218: disp_list.push_back(intmap); ! 219: std::sort(disp_list.begin(), disp_list.end()); ! 220: ! 221: // ここで親の Virt68kInterrupt のモニタ行数を増やす。 ! 222: // 本当は登録がすべて終わった頃に Virt68kInterrupt から各 GFPIC ! 223: // に問い合わせたいが、どちらも Init() での処理であり、オブジェクトの ! 224: // 依存関係から無理なので、こっちから都度プッシュする。 ! 225: auto virt68kinterrupt = dynamic_cast<Virt68kInterrupt*>(interrupt); ! 226: virt68kinterrupt->IncMonitorHeight(); ! 227: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.