|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // メインバス
9: //
10:
11: #include "mainbus.h"
12: #include "mainram.h"
13:
14: // コンストラクタ
15: MainbusDevice::MainbusDevice()
16: : inherited(OBJ_MAINBUS)
17: {
1.1.1.2 ! root 18: monitor.func = ToMonitorCallback(&MainbusDevice::MonitorUpdate);
! 19: monitor.SetSize(75, 33);
! 20: monitor.Regist(ID_MONITOR_MAINBUS);
1.1 root 21: }
22:
23: // デストラクタ
24: MainbusDevice::~MainbusDevice()
25: {
26: }
27:
28: uint64
29: MainbusDevice::Read8(uint32 addr)
30: {
31: uint64 data;
32:
33: if (addr < direct_ram_size) {
34: data = MainRAMDevice::mainram[HLB(addr)];
35: } else {
36: IODevice *dev = devtable[addr >> 24];
37: data = dev->Read8(addr);
38: }
39: return data;
40: }
41:
42: uint64
43: MainbusDevice::Read16(uint32 addr)
44: {
45: uint64 data;
46:
47: if (__predict_false((addr & 1) != 0))
48: VMPANIC("unaligned access $%08x", addr);
49:
50: if (addr < direct_ram_size) {
51: data = *(uint16 *)&MainRAMDevice::mainram[HLW(addr)];
52: } else {
53: IODevice *dev = devtable[addr >> 24];
54: data = dev->Read16(addr);
55: }
56: return data;
57: }
58:
59: uint64
60: MainbusDevice::Read32(uint32 addr)
61: {
62: uint64 data;
63:
64: if (__predict_false((addr & 3) != 0))
65: VMPANIC("unaligned access $%08x", addr);
66:
67: if (addr < direct_ram_size) {
68: data = *(uint32 *)&MainRAMDevice::mainram[addr];
69: } else {
70: IODevice *dev = devtable[addr >> 24];
71: data = dev->Read32(addr);
72: }
73: return data;
74: }
75:
76: uint64
77: MainbusDevice::Write8(uint32 addr, uint32 data)
78: {
79: if (addr < direct_ram_size) {
80: MainRAMDevice::mainram[HLB(addr)] = data;
81: return 0;
82: } else {
83: IODevice *dev = devtable[addr >> 24];
84: return dev->Write8(addr, data);
85: }
86: }
87:
88: uint64
89: MainbusDevice::Write16(uint32 addr, uint32 data)
90: {
91: if (__predict_false((addr & 1) != 0))
92: VMPANIC("unaligned access $%08x", addr);
93:
94: if (addr < direct_ram_size) {
95: *(uint16 *)&MainRAMDevice::mainram[HLW(addr)] = data;
96: return 0;
97: } else {
98: IODevice *dev = devtable[addr >> 24];
99: return dev->Write16(addr, data);
100: }
101: }
102:
103: uint64
104: MainbusDevice::Write32(uint32 addr, uint32 data)
105: {
106: if (__predict_false((addr & 3) != 0))
107: VMPANIC("unaligned access $%08x", addr);
108:
109: if (addr < direct_ram_size) {
110: *(uint32 *)&MainRAMDevice::mainram[addr] = data;
111: return 0;
112: } else {
113: IODevice *dev = devtable[addr >> 24];
114: return dev->Write32(addr, data);
115: }
116: }
117:
118: uint64
119: MainbusDevice::Peek8(uint32 addr)
120: {
121: uint64 data;
122:
123: if (addr < direct_ram_size) {
124: data = MainRAMDevice::mainram[HLB(addr)];
125: } else {
126: IODevice *dev = devtable[addr >> 24];
127: data = dev->Peek8(addr);
128: }
129: return data;
130: }
131:
132: // これだけオーバーライドではないので注意。
133: uint64
134: MainbusDevice::Peek32(uint32 addr)
135: {
136: uint64 data;
137:
138: if (__predict_false((addr & 3) != 0))
139: VMPANIC("unaligned access $%08x", addr);
140:
141: if (addr < direct_ram_size) {
142: data = *(uint32 *)&MainRAMDevice::mainram[addr];
143: } else {
144: IODevice *dev = devtable[addr >> 24];
145: data = dev->Peek8(addr++) << 24;
146: data |= dev->Peek8(addr++) << 16;
147: data |= dev->Peek8(addr++) << 8;
148: data |= dev->Peek8(addr);
149: }
150: return data;
151: }
152:
153: // このアドレスを担当する次段の IODevice を返す (IOContainerDevice 用)
154: IODevice *
155: MainbusDevice::GetDevice(uint32 addr) const
156: {
157: return devtable[addr >> 24];
158: }
159:
160: // デバイスをセットする。すでにあれば更新する。
161: // idx は devtable[] のインデックス (16MB 単位)。
162: /*static*/ void
163: MainbusDevice::SetDevice(int idx, IODevice *dev)
164: {
165: assert(idx < devtable.size());
166:
167: devtable[idx] = dev;
168: }
169:
170: // デバイステーブルの src から len 個を dst にコピーする。(ミラーを作る)
171: /*static*/ void
172: MainbusDevice::CopyDevtable(int dst, int src, int len)
173: {
174: memcpy(&devtable[dst], &devtable[src], sizeof(devtable[0]) * len);
175: }
176:
1.1.1.2 ! root 177: void
! 178: MainbusDevice::MonitorUpdate(Monitor *, TextScreen& screen)
! 179: {
! 180: screen.Clear();
! 181:
! 182: // 012345678901234567890
! 183: // $0000'0000: 1234567
! 184:
! 185: for (int i = 0; i < 8; i++) {
! 186: screen.Print(12 + i * 8, 0, "+$0%x", i);
! 187: }
! 188:
! 189: int idx = 0;
! 190: for (int i = 0; i < devtable.size() / 8; i++) {
! 191: screen.Print(0, i + 1, "$%02x00'0000:", idx);
! 192: for (int j = 0; j < 8; j++) {
! 193: auto pair = FormatDevName(devtable[idx]);
! 194: const std::string& name = pair.first;
! 195: TA attr = pair.second;
! 196: screen.Print(12 + j * 8, i + 1, attr, "%s", name.c_str());
! 197: idx++;
! 198: }
! 199: }
! 200: }
! 201:
! 202: // モニタ表示用にデバイス名を整形。
! 203: // 7文字に切り詰めるのと、括弧があれば取り除いて Disable 色にする。
! 204: /*static*/ std::pair<std::string, TA>
! 205: MainbusDevice::FormatDevName(const Device *dev)
! 206: {
! 207: std::string name = dev->GetName();
! 208: TA attr;
! 209:
! 210: if (name[0] == '(') {
! 211: // 括弧付きなら、括弧を取り除いて Disable 色で表示
! 212: int len = std::min(7, (int)name.size() - 2);
! 213: name = name.substr(1, len);
! 214: attr = TA::Disable;
! 215: } else {
! 216: name = name.substr(0, 7);
! 217: attr = TA::Normal;
! 218: }
! 219:
! 220: return std::make_pair(name, attr);
! 221: }
! 222:
1.1 root 223: // Mainbus は1つしかないので、スタティック変数にしておく。
224: /*static*/ std::array<IODevice *, 256> MainbusDevice::devtable;
225:
226: // RAM へのアクセスは、アクセスアドレスが direct_ram_size 未満なら ram[] を
227: // 直接アクセスし、そうでなければデバイスクラス経由でアクセスする。
228: // 高速モードでは RAM デバイスを経由すること自体とその中でアクセスウェイトを
229: // 計算する分を回避したい。
230: /*static*/ int MainbusDevice::direct_ram_size;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.