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