|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
1.1.1.3 root 8: // メインバス (共通部分)
1.1 root 9: //
10:
1.1.1.3 root 11: // メインバス付近に必要な機能は次のようになっている。
12: //
13: // Luna News X68k X68kIO XPbus
14: // InitMainbus o o o o x
15: // FC access o o o o x
16: // SwitchBoot o o o o x
17: // ResetByMPU o o o *1 x (*1:どっちでもいい)
18: //
19: // Access Map o o o x x
1.1.1.6 root 20: // HV access o o o x ?
1.1.1.4 root 21: // Peek4 o o o x x
1.1.1.3 root 22: // Singleton o o o x x
23: //
24: // もともと FC 付きアクセス機能を Mainbus からX68kIO に伸ばすために
25: // MainbusDevice を導入したが、一方モニタの登録などでは Mainbus は
26: // システムに複数存在してはならないため、これらは同時に成立しない。
27: // そのため、表の上半分の機能を MainbusBaseDevice として独立させ、
28: // X68kIO はここから派生。表の下半分の機能を MainbusDevice とする。
29: //
30: // XPbus はどちらも不要なので (XP プロセッサから見ればメインバスだが、
31: // ここの Mainbus はそういう意味ではないので) ただの IODevice。
32:
33: // IODevice
34: // |
35: // | +-------------------+
36: // +--| MainbusBaseDevice | (InitMainbus() と FC アクセスを持つ)
37: // | +-------------------+
38: // | |
39: // | | +---------------+
40: // | +--| MainbusDevice | (これがメインバス、システムに1つ)
41: // | | +---------------+
42: // | | |
43: // | | | +-----------------+
44: // | | +--| Mainbus24Device | (上位8ビットがテーブルで表せるメインバス)
45: // | | | +-----------------+
46: // | | | |
47: // | | | +-- LunaMainbus
48: // | | | | +-- Luna1Mainbus
49: // | | | | +-- Luna88kMainbus
50: // | | | +-- NewsMainbus
51: // | | | +-- Virt68kMainbus
52: // | | +-- X68kMainbus (上位8ビットが IODevice で表せないため)
53: // | |
54: // | +-- X68kIODevice
55: // |
56: // +-- XPbusDevice (これはただの IODevice)
57:
1.1 root 58: #include "mainbus.h"
1.1.1.5 root 59: #include "monitor.h"
1.1.1.3 root 60:
61: //
62: // メインバスの素質を持つ基本クラス
63: //
1.1 root 64:
65: // コンストラクタ
1.1.1.4 root 66: MainbusBaseDevice::MainbusBaseDevice(uint objid_)
1.1.1.3 root 67: : inherited(objid_)
1.1 root 68: {
69: }
70:
71: // デストラクタ
1.1.1.3 root 72: MainbusBaseDevice::~MainbusBaseDevice()
1.1 root 73: {
74: }
75:
1.1.1.3 root 76: // MPU の RESET 命令によるリセット
77: void
78: MainbusBaseDevice::ResetByMPU()
1.1 root 79: {
1.1.1.3 root 80: }
1.1 root 81:
1.1.1.3 root 82: // ブートページを切り替える際の共通処理。
83: // 派生クラスから呼ぶこと。
84: void
85: MainbusBaseDevice::SwitchBootPage(bool isrom)
86: {
87: // ログ表示
88: if (isrom) {
89: putlog(1, "SwitchBootPage ROM (Boot)");
1.1 root 90: } else {
1.1.1.3 root 91: putlog(1, "SwitchBootPage RAM (Normal)");
1.1 root 92: }
93: }
94:
1.1.1.3 root 95: // モニタ表示用にデバイス名を整形。
96: // 7文字に切り詰めるのと、括弧があれば取り除いて Disable 色にする。
97: /*static*/ std::pair<std::string, TA>
98: MainbusBaseDevice::FormatDevName(const Device *dev)
1.1 root 99: {
1.1.1.3 root 100: std::string name = dev->GetName();
101: TA attr;
102:
103: if (name[0] == '(') {
104: // 括弧付きなら、括弧を取り除いて Disable 色で表示
105: int len = std::min(7, (int)name.size() - 2);
106: name = name.substr(1, len);
107: attr = TA::Disable;
1.1 root 108: } else {
1.1.1.3 root 109: name = name.substr(0, 7);
110: attr = TA::Normal;
1.1 root 111: }
1.1.1.3 root 112:
113: return std::make_pair(name, attr);
1.1 root 114: }
115:
1.1.1.3 root 116:
117: //
118: // メインバス (基本クラス)
119: //
120:
121: // コンストラクタ
1.1.1.4 root 122: MainbusDevice::MainbusDevice(uint objid_)
1.1.1.3 root 123: : inherited(objid_)
1.1 root 124: {
1.1.1.5 root 125: accstat_monitor = gMonitorManager->Regist(ID_MONITOR_ACCSTAT, this);
126: accstat_monitor->func =
1.1.1.4 root 127: ToMonitorCallback(&MainbusDevice::MonitorUpdateAccStat);
128: // 表示行数が機種ごとに異なるので継承側でセットしている。
129:
130: // 通常は 32bit 空間全体 (そうでない機種はコンストラクタで上書きする)
131: accstat_baseaddr = 0;
132: accstat_bitlen = 32;
1.1.1.3 root 133: }
134:
135: // デストラクタ
136: MainbusDevice::~MainbusDevice()
137: {
138: }
1.1 root 139:
1.1.1.4 root 140: // 初期化
141: bool
142: MainbusDevice::Init()
143: {
144: // アクセス状況の表示用配列。
145: accstat_rw.resize(AccStat::MAINLEN >> (32 - accstat_bitlen));
146:
147: return true;
148: }
149:
150: // リセット
151: void
152: MainbusDevice::ResetHard(bool poweron)
153: {
154: inherited::ResetHard(poweron);
155:
156: std::fill(accstat_read.begin(), accstat_read.end(), 0);
157: std::fill(accstat_write.begin(), accstat_write.end(), 0);
158: }
159:
160: // ハイパーバイザ的読み込み (ミスアライン可)。
161: // addr はアドレスとサイズを指定すること。
162: // バスエラーが起きればその時点で BusData::BusErr を返す。
163: busdata
164: MainbusDevice::HVReadN(busaddr addr)
165: {
166: addr |= BusAddr::SRead;
167:
168: uint32 reqsize = addr.GetSize();
169: busdata data;
170: do {
171: busdata bd = Read(addr);
172: if (__predict_false(bd.IsBusErr())) {
173: return bd;
174: }
175: data |= DYNAMIC_BUS_SIZING_R(addr, bd);
176: } while (addr.GetSize() != 0);
177:
178: data |= busdata::Size(reqsize);
179: return data;
180: }
181:
1.1.1.3 root 182: // ハイパーバイザ的読み込み
183: busdata
1.1.1.4 root 184: MainbusDevice::HVRead1(uint32 paddr)
1.1.1.3 root 185: {
1.1.1.4 root 186: busaddr addr = busaddr(paddr) | BusAddr::Size1;
187: return HVReadN(addr);
1.1.1.3 root 188: }
189:
190: // ハイパーバイザ的読み込み (ミスアライン可)
191: busdata
1.1.1.4 root 192: MainbusDevice::HVRead2(uint32 paddr)
1.1.1.3 root 193: {
1.1.1.4 root 194: busaddr addr = busaddr(paddr) | BusAddr::Size2;
195: return HVReadN(addr);
1.1 root 196: }
197:
1.1.1.3 root 198: // ハイパーバイザ的読み込み (ミスアライン可)
199: busdata
1.1.1.4 root 200: MainbusDevice::HVRead4(uint32 paddr)
1.1 root 201: {
1.1.1.4 root 202: busaddr addr = busaddr(paddr) | BusAddr::Size4;
203: return HVReadN(addr);
204: }
205:
206: // ハイパーバイザ的書き込み (ミスアライン可)。
207: // addr はアドレスとサイズを指定すること。属性は SRead 固定。
208: // バスエラーが起きればその時点で busdata::BusErr を返す。
209: busdata
210: MainbusDevice::HVWriteN(busaddr addr, uint32 data)
211: {
212: addr |= BusAddr::SWrite;
213: do {
214: busdata r = Write(addr, data);
215: if (__predict_false(r.IsBusErr())) {
216: return r;
217: }
218: DYNAMIC_BUS_SIZING_W(addr, data, r);
219: } while (addr.GetSize() != 0);
220:
221: return 0;
1.1 root 222: }
223:
1.1.1.3 root 224: // ハイパーバイザ的書き込み
225: busdata
1.1.1.4 root 226: MainbusDevice::HVWrite1(uint32 paddr, uint32 data)
1.1 root 227: {
1.1.1.4 root 228: busaddr addr = busaddr(paddr) | BusAddr::Size1;
229: return HVWriteN(addr, data);
1.1.1.3 root 230: }
1.1 root 231:
1.1.1.3 root 232: // ハイパーバイザ的書き込み (ミスアライン可)
233: busdata
1.1.1.4 root 234: MainbusDevice::HVWrite2(uint32 paddr, uint32 data)
1.1.1.3 root 235: {
1.1.1.4 root 236: busaddr addr = busaddr(paddr) | BusAddr::Size2;
237: return HVWriteN(addr, data);
1.1.1.3 root 238: }
239:
240: // ハイパーバイザ的書き込み (ミスアライン可)
241: busdata
1.1.1.4 root 242: MainbusDevice::HVWrite4(uint32 paddr, uint32 data)
1.1.1.3 root 243: {
1.1.1.4 root 244: busaddr addr = busaddr(paddr) | BusAddr::Size4;
245: return HVWriteN(addr, data);
1.1 root 246: }
247:
248: uint64
1.1.1.4 root 249: MainbusDevice::Peek4(uint32 addr)
1.1 root 250: {
251: uint64 data;
252:
253: if (__predict_false((addr & 3) != 0))
254: VMPANIC("unaligned access $%08x", addr);
255:
1.1.1.4 root 256: data = Peek1(addr++) << 24;
257: data |= Peek1(addr++) << 16;
258: data |= Peek1(addr++) << 8;
259: data |= Peek1(addr);
1.1 root 260: return data;
261: }
262:
1.1.1.4 root 263: void
264: MainbusDevice::MonitorUpdateAccStat(Monitor *, TextScreen& screen)
265: {
266: std::array<char, 64 + 5> buf;
267:
268: #define UPDATE_RW(rw_ptr) do { \
269: uint64 dst = *(uint64 *)(rw_ptr); \
270: dst <<= 2; \
271: dst &= 0xfcfcfcfc'fcfcfcfc; \
272: dst |= src; \
273: *(uint64 *)(rw_ptr) = dst; \
274: } while (0)
275:
276: // R|W をマージしながらコピー。
277: if (__predict_true(accstat_rw.size() == AccStat::MAINLEN)) {
278: // 全域。
279: for (int i = 0; i < AccStat::MAINLEN; i += 8) {
280: uint64 src = *(uint64 *)&accstat_read[i]
281: | *(uint64 *)&accstat_write[i];
282: UPDATE_RW(&accstat_rw[i]);
283: }
284: } else {
285: // NEWS なら表示に使うのは前 1/4 のみで、後ろはミラー。
286: // ただしアドレス表記は $c000'0000 以降(後ろの 1/4)。
287: uint offset = accstat_rw.size();
288: uint ndiv = accstat_read.size() / offset;
289: for (int i = 0, iend = accstat_rw.size(); i < iend; i += 8) {
290: uint64 src = 0;
291: for (int j = 0; j < ndiv; j++) {
292: src |= *(uint64 *)&accstat_read[i + j * offset];
293: src |= *(uint64 *)&accstat_write[i + j * offset];
294: }
295: UPDATE_RW(&accstat_rw[i]);
296: }
297: }
298:
299: // 読んだのでリセット。
300: std::fill(accstat_read.begin(), accstat_read.end(), 0);
301: std::fill(accstat_write.begin(), accstat_write.end(), 0);
302:
303: screen.Clear();
304:
305: static_assert(AccStat::SHIFT >= 20, "");
306: screen.Print(0, 0,
307: "Shows %ubit space. %uMB/char. 'R':Read, 'W':Write, 'A':Read+Write",
308: accstat_bitlen, 1U << (AccStat::SHIFT - 20));
309: screen.Print(12, 1,
310: "+$00 +$01 +$02 +$03 +$04 +$05 +$06 +$07");
311:
312: uint32 baseaddr = accstat_baseaddr;
313: for (int y = 0, yend = accstat_rw.size() / 64; y < yend; y++) {
314: const uint8 *a = &accstat_rw[y * 64];
315: uint8 avail = accstat_avail[y];
316: char *d = &buf[0];
317: std::fill(buf.begin(), buf.end() - 1, ' ');
318: for (int i = 0; i < 8; i++) {
319: // 先頭に空白を入れといて、参照時は buf+1 から参照する。
320: if ((i & 1) == 0) {
321: d++;
322: }
323: if ((int8)avail < 0) {
324: // 何かしらデバイスがある。16MB、8文字分。
325: for (int j = 0; j < 8; j++) {
326: uint op = *a & 3;
327: *d++ = ".RWA"[op];
328: a++;
329: }
330: } else {
331: // この 16MB には何のデバイスもない。
332: d += 8;
333: a += 8;
334: }
335: avail <<= 1;
336: }
337: *d = '\0';
338: screen.Print(0, y + 2, "$%02x00'0000: %s",
339: baseaddr + y * 0x08, &buf[1]);
340: }
341: }
342:
1.1.1.3 root 343:
344: //
345: // 上位8ビットがテーブルで表せる構造のメインバス。
346: //
347:
348: // コンストラクタ (オブジェクト名指定なし)
349: Mainbus24Device::Mainbus24Device()
350: : MainbusDevice(OBJ_MAINBUS)
351: {
1.1.1.5 root 352: monitor = gMonitorManager->Regist(ID_MONITOR_MAINBUS, this);
353: monitor->func = ToMonitorCallback(&Mainbus24Device::MonitorUpdate);
354: monitor->SetSize(75, 33);
1.1.1.3 root 355: }
356:
357: Mainbus24Device::~Mainbus24Device()
358: {
359: }
360:
361: // アクセス状況のエリア情報初期化。
362: // 継承側の InitMainbus() の終わりで呼ぶこと。
363: void
364: Mainbus24Device::InitAccStat()
365: {
1.1.1.4 root 366: for (int i = 0; i < accstat_avail.size(); i++) {
1.1.1.3 root 367: uint bits = 0;
368: for (int j = 0; j < 8; j++) {
369: int n = i * 8 + j;
370: int id = devtable[n]->GetId();
371: bits <<= 1;
372: if (id != OBJ_BUSERR && id != OBJ_NOPIO) {
373: bits |= 1;
374: }
375: }
1.1.1.4 root 376: accstat_avail[i] = bits;
1.1.1.3 root 377: }
378:
379: // デバッグ用
380: if (0) {
1.1.1.4 root 381: for (int i = 0; i < accstat_avail.size(); i++) {
1.1.1.3 root 382: printf("%02x: ", i);
1.1.1.4 root 383: uint8 a = accstat_avail[i];
1.1.1.3 root 384: for (int j = 0; j < 8; j++) {
385: if ((int8)a < 0) {
386: printf("1");
387: } else {
388: printf("0");
389: }
390: a <<= 1;
391: }
392: printf("\n");
393: }
394: }
395: }
396:
397: inline IODevice *
398: Mainbus24Device::Decoder(uint32 addr) const
1.1 root 399: {
400: return devtable[addr >> 24];
401: }
402:
1.1.1.3 root 403: busdata
1.1.1.4 root 404: Mainbus24Device::Read(busaddr addr)
1.1.1.3 root 405: {
1.1.1.4 root 406: uint32 pa = addr.Addr();
407: accstat_read[pa >> AccStat::SHIFT] = AccStat::READ;
408: IODevice *dev = Decoder(pa);
409: return dev->Read(addr);
1.1.1.3 root 410: }
411:
412: busdata
1.1.1.4 root 413: Mainbus24Device::Write(busaddr addr, uint32 data)
1.1 root 414: {
1.1.1.4 root 415: uint32 pa = addr.Addr();
416: accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE;
417: IODevice *dev = Decoder(pa);
418: return dev->Write(addr, data);
1.1.1.3 root 419: }
420:
421: busdata
1.1.1.4 root 422: Mainbus24Device::ReadBurst16(busaddr addr, uint32 *dst)
1.1.1.3 root 423: {
1.1.1.4 root 424: uint32 pa = addr.Addr();
425: IODevice *dev = Decoder(pa);
426: busdata r = dev->ReadBurst16(addr, dst);
427: if (__predict_true(r.IsBusErr() == false)) {
428: accstat_read[pa >> AccStat::SHIFT] = AccStat::READ;
429: }
430: return r;
1.1.1.3 root 431: }
432:
433: busdata
1.1.1.4 root 434: Mainbus24Device::WriteBurst16(busaddr addr, const uint32 *src)
1.1.1.3 root 435: {
1.1.1.4 root 436: uint32 pa = addr.Addr();
437: IODevice *dev = Decoder(pa);
438: busdata r = dev->WriteBurst16(addr, src);
439: if (__predict_true(r.IsBusErr() == false)) {
440: accstat_write[pa >> AccStat::SHIFT] = AccStat::WRITE;
441: }
442: return r;
1.1.1.3 root 443: }
1.1 root 444:
1.1.1.3 root 445: busdata
1.1.1.4 root 446: Mainbus24Device::Peek1(uint32 addr)
1.1.1.3 root 447: {
448: IODevice *dev = Decoder(addr);
1.1.1.4 root 449: return dev->Peek1(addr);
1.1 root 450: }
451:
1.1.1.3 root 452: bool
1.1.1.4 root 453: Mainbus24Device::Poke1(uint32 addr, uint32 data)
1.1 root 454: {
1.1.1.3 root 455: IODevice *dev = Decoder(addr);
1.1.1.4 root 456: return dev->Poke1(addr, data);
1.1 root 457: }
458:
1.1.1.2 root 459: void
1.1.1.3 root 460: Mainbus24Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 461: {
462: screen.Clear();
463:
464: // 012345678901234567890
465: // $0000'0000: 1234567
466:
467: for (int i = 0; i < 8; i++) {
468: screen.Print(12 + i * 8, 0, "+$0%x", i);
469: }
470:
471: int idx = 0;
472: for (int i = 0; i < devtable.size() / 8; i++) {
473: screen.Print(0, i + 1, "$%02x00'0000:", idx);
474: for (int j = 0; j < 8; j++) {
475: auto pair = FormatDevName(devtable[idx]);
476: const std::string& name = pair.first;
477: TA attr = pair.second;
478: screen.Print(12 + j * 8, i + 1, attr, "%s", name.c_str());
479: idx++;
480: }
481: }
482: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.