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