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