|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.