|
|
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.