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