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