|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2023 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // Nereid Ethernet/メモリ/USB 複合ボード (のうち Ethernet/バンクメモリ)
9: //
10:
11: // Nereid の DIPSW
12: //
13: // SW1,2 : RAM をメインメモリとして使う場合の容量
14: // OFF,OFF = 割り当てない (この時だけバンクメモリが 16MB 使える)
15: // SW3,4,5 : RAM をメインメモリとして使う場合の開始アドレス
16: // SW6 : RAM をバンクメモリとして使う場合のウィンドウ
17: // OFF = $ee0000
18: // ON = $ef0000
19: // SW7 : アドレス、割り込みベクタ設定
20: // OFF = $ece3xx, $f9, $fb
21: // ON = $ecebxx, $f8, $fa
22: // SW8 : バンクメモリ有効無効
23: // OFF = 無効
24: // ON = 有効
25: //
26: // バンクメモリの容量は、SW1-2 でメインメモリに割り当てた余りのうち
27: // 4MB か 16MB のどちらか。Nereid のメモリをメインメモリに割り当てる機能は
28: // (意味がないので) 実装せず、SW1-2 を設定した結果バンクメモリ容量が 4MB か
29: // 16MB にできるところだけ再現する。
30: //
31: // Nereid は SW-6,7 により2枚まで同時に運用することが可能。
32: // SW6 と SW7 の組み合わせは本来自由だが、そこまで自由度を上げるメリットは
33: // なさそうなので、ここでは
34: // Nereid#0 が SW6=OFF、SW7=OFF
35: // Nereid#1 が SW6=ON、 SW7=ON
36: // と固定して扱う。
37:
38: // 各デバイスのアドレス配置、割り込みベクタ
39: //
40: // #0 (SW7=OFF) #1 (SW7=ON)
41: // -------------- --------------
42: // $ece300-ece33f $eceb00-eceb3f : RTL8019AS (偶数アドレスのみ)
43: // $ece380-ece383 $eceb80-eceb83 : SL811HS/T (奇数アドレスのみ)
44: // $ece3f0 $ecebf0 : バンクページ選択
45: // $ece3f1 $ecebf1 : 制御ポート
46: //
47: // $f9 $f8 : RTL8019AS 割り込みベクタ
48: // $fb $fa : SL811HS/T 割り込みベクタ
49:
50: #include "nereid.h"
51: #include "bankram.h"
52: #include "config.h"
53: #include "rtl8019as.h"
54:
55: //
56: // Nereid 空間担当デバイス
57: //
58:
59: // boards[0]、board[1] を所有し、アクセスをディスパッチする。
60:
61: // コンストラクタ
62: NereidDevice::NereidDevice()
63: : inherited(OBJ_NEREID)
64: {
65: monitor.func = ToMonitorCallback(&NereidDevice::MonitorUpdate);
66: monitor.SetSize(41, 9);
67: monitor.Regist(ID_MONITOR_NEREID);
68: }
69:
70: // デストラクタ
71: NereidDevice::~NereidDevice()
72: {
73: }
74:
75: // デバイス作成
76: bool
77: NereidDevice::Create()
78: {
1.1.1.3 ! root 79: // ボードの有無は nereid%u-enable だけで決まる。
1.1 root 80: for (int i = 0; i < 2; i++) {
1.1.1.3 ! root 81: std::string name = string_format("nereid%u-enable", i);
1.1 root 82: bool enable = gConfig->Find(name).AsInt();
83:
84: if (enable) {
85: boards[i].reset(new NereidBoardDevice(i));
86:
87: // 配置場所
88: if (i == 0) {
89: loc[i] = 0x03; // $ece300-
90: } else {
91: loc[i] = 0x0b; // $eceb00-
92: }
93: } else {
94: // アドレス比較で一致させないため -1 にしておく。
95: loc[i] = -1;
96: }
97: }
98:
99: return true;
100: }
101:
102: // Nereid が1枚でもささっていれば true。
103: // (X68kIO.Init() から呼ばれる)
104: bool
105: NereidDevice::IsInstalled() const
106: {
107: return (bool)boards[0] || (bool)boards[1];
108: }
109:
110: inline uint32
111: NereidDevice::Decoder(uint32 addr) const
112: {
113: // ここで返すのはオフセットではなく、チップセレクトに近い。
114: // $ece3xx or $ecebxx の $3 か $b のところ (厳密にはそれを含む
115: // 5ビット) を返し、あらかじめ用意してある loc[i] と比較する。
116: return (addr >> 8) & 0x1f;
117: }
118:
1.1.1.2 root 119: busdata
1.1.1.3 ! root 120: NereidDevice::Read(busaddr addr)
1.1 root 121: {
1.1.1.3 ! root 122: uint32 paddr = addr.Addr();
1.1 root 123:
1.1.1.3 ! root 124: putlog(2, "Read $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
1.1 root 125:
1.1.1.3 ! root 126: uint32 cs = Decoder(paddr);
1.1 root 127: for (int i = 0; i < boards.size(); i++) {
128: if (cs == loc[i]) {
1.1.1.3 ! root 129: return boards[i]->Read(addr);
1.1 root 130: }
131: }
132:
1.1.1.3 ! root 133: return BusData::BusErr;
1.1 root 134: }
135:
1.1.1.2 root 136: busdata
1.1.1.3 ! root 137: NereidDevice::Write(busaddr addr, uint32 data)
1.1 root 138: {
1.1.1.3 ! root 139: uint32 paddr = addr.Addr();
1.1 root 140:
1.1.1.3 ! root 141: putlog(2, "Write $%06x.%c", paddr, (addr.GetSize() == 1 ? 'B' : 'W'));
! 142:
! 143: uint32 cs = Decoder(paddr);
1.1 root 144: for (int i = 0; i < boards.size(); i++) {
145: if (cs == loc[i]) {
1.1.1.3 ! root 146: return boards[i]->Write(addr, data);
1.1 root 147: }
148: }
1.1.1.3 ! root 149: return BusData::BusErr;
1.1 root 150: }
151:
1.1.1.2 root 152: busdata
1.1.1.3 ! root 153: NereidDevice::Peek1(uint32 addr)
1.1 root 154: {
155: uint32 cs = Decoder(addr);
156:
157: for (int i = 0; i < boards.size(); i++) {
158: if (cs == loc[i]) {
1.1.1.3 ! root 159: return boards[i]->Peek1(addr);
1.1 root 160: }
161: }
1.1.1.3 ! root 162: return BusData::BusErr;
1.1 root 163: }
164:
165: void
166: NereidDevice::MonitorUpdate(Monitor *, TextScreen& screen)
167: {
168: int y;
169:
170: screen.Clear();
171:
172: // 0123456789012345678901234567890123456789
173: // #0 #1
174: // Board : NotInstalled NotInstalled
175: // Ethernet : Enable
176: // Address : $ece300
177: // Vector : $f9
178: // Bank Memory : 16MB
179: // Page Select: $ece380
180: // Bank Window: $ee0000
181: // CurrentPage: $00
182:
183: y = 1;
184: screen.Puts(0, y++, "Board :");
185: screen.Puts(1, y++, "Ethernet :");
186: screen.Puts(2, y++, "Address :");
187: screen.Puts(2, y++, "Vector :");
188: screen.Puts(1, y++, "Bank Memory :");
189: screen.Puts(2, y++, "Page Select:");
190: screen.Puts(2, y++, "Bank Window:");
191: screen.Puts(2, y++, "CurrentPage:");
192:
193: for (int i = 0; i < 2; i++) {
194: int x = 15 + i * 14;
195: TA attr;
196:
197: y = 0;
1.1.1.3 ! root 198: screen.Print(x, y++, "#%u", i);
1.1 root 199:
200: // ボードがささっているか
201: bool installed = (bool)boards[i];
202: if (installed) {
203: screen.Puts(x, y, "Installed");
204: } else {
205: screen.Puts(x, y, "NotInstalled");
206: }
207: y++;
208:
209: // イーサネット
210: attr = TA::Disable;
211: if (installed) {
212: if (boards[i]->IsNetEnable()) {
213: screen.Puts(x, y, "Available");
214: attr = TA::Normal;
215: } else {
216: screen.Puts(x, y, "NotAvailable");
217: }
218: } else {
219: screen.Puts(x, y, attr, "-");
220: }
221: y++;
222: screen.Print(x, y++, attr, "$%06x", 0xece300 + i * 0x800);
223: screen.Print(x, y++, attr, "$%02x", 0xf9 - i);
224:
225: // バンクメモリ
226: attr = TA::Disable;
227: int ramsize = 0;
228: if (installed) {
229: ramsize = boards[i]->GetBankRAMSize();
230: if (ramsize > 0) {
1.1.1.3 ! root 231: screen.Print(x, y, "%u MB", ramsize);
1.1 root 232: attr = TA::Normal;
233: } else {
234: screen.Puts(x, y, "Disabled");
235: }
236: } else {
237: screen.Puts(x, y, attr, "-");
238: }
239: y++;
240: screen.Print(x, y++, attr, "$%06x", 0xece3f0 + i * 0x800);
241: screen.Print(x, y++, attr, "$%06x", 0xee0000 + i * 0x10000);
242: if (installed) {
243: if (ramsize > 0) {
244: attr = TA::Normal;
245: } else {
246: attr = TA::Disable;
247: }
248: screen.Print(x, y, attr, "$%02x", boards[i]->GetPage());
249: } else {
250: screen.Puts(x, y, attr, "---");
251: }
252: }
253: }
254:
255:
256: //
257: // Nereid ボード1枚分
258: //
259:
260: // コンストラクタ
261: NereidBoardDevice::NereidBoardDevice(int id_)
262: : inherited(OBJ_NEREID_BOARD(id_))
263: {
264: id = id_;
265: }
266:
267: // デストラクタ
268: NereidBoardDevice::~NereidBoardDevice()
269: {
270: }
271:
272: bool
273: NereidBoardDevice::Create()
274: {
1.1.1.3 ! root 275: std::string netname = string_format("nereid%u-net", id);
! 276: std::string ramname = string_format("nereid%u-ram-size", id);
1.1 root 277:
278: const ConfigItem inet = gConfig->Find(netname);
279: bool net_enable = inet.AsInt();
280:
281: const ConfigItem iramsize = gConfig->Find(ramname);
282: ramsize_MB = iramsize.AsInt();
283: switch (ramsize_MB) {
284: case 0:
285: case 4:
286: case 16:
287: case -4:
288: case -16:
289: // 負数は、バンクメモリ無効時の制御ポート bit6 を明示したい場合用。
290: break;
291: default:
292: iramsize.Err("Valid value is one of 0, 4, 16 (or -4, -16)");
293: return false;
294: }
295:
296: // ネットワークが無効の場合 (これは正常な実機では起きないが)、
297: // RTL8019ASDevice インスタンスの生成自体を行わず、net は NULL。
298: if (net_enable) {
299: int vector;
300: if (id == 0) {
301: vector = 0xf9;
302: } else {
303: vector = 0xf8;
304: }
305: net.reset(new RTL8019ASDevice(id, vector));
306: }
307:
308: // バンクメモリは (DIPSW によって) 有効/無効どちらであっても
309: // BankRAMDevice インスタンスの生成自体は行う。
310: // ページレジスタは存在している(はずの)ため。
311: if (ramsize_MB <= 0) {
312: bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), 0));
313: } else {
314: bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), ramsize_MB));
1.1.1.2 root 315: // I/O 空間への登録は X68kIO 側から行っている。
1.1 root 316: }
317: return true;
318: }
319:
320: inline uint32
321: NereidBoardDevice::Decoder(uint32 addr) const
322: {
323: return addr & 0xff;
324: }
325:
1.1.1.2 root 326: busdata
1.1.1.3 ! root 327: NereidBoardDevice::Read(busaddr addr)
1.1 root 328: {
1.1.1.3 ! root 329: busdata data = BusData::BusErr;
1.1 root 330:
1.1.1.3 ! root 331: uint32 paddr = addr.Addr();
! 332: uint32 offset = Decoder(paddr);
1.1 root 333:
334: if (offset < 0x40) {
335: if ((bool)net) {
1.1.1.3 ! root 336: return net->Read(addr);
1.1 root 337: }
1.1.1.3 ! root 338: } else {
! 339: uint32 reqsize = addr.GetSize();
! 340: uint32 datasize = std::min(2 - (paddr & 1), reqsize);
! 341: if (datasize == 1) {
! 342: if (offset == 0xf0) {
! 343: data = GetPage();
! 344: } else if (offset == 0xf1) {
! 345: data = GetCtrl();
! 346: }
! 347: data |= BusData::Size1;
! 348: } else {
! 349: if (offset == 0xf0) {
! 350: data = GetPage() << 8;
! 351: data |= GetCtrl();
! 352: }
! 353: data |= BusData::Size2;
1.1 root 354: }
355: }
1.1.1.3 ! root 356: return data;
1.1 root 357: }
358:
1.1.1.2 root 359: busdata
1.1.1.3 ! root 360: NereidBoardDevice::Write(busaddr addr, uint32 data)
1.1 root 361: {
1.1.1.3 ! root 362: busdata r;
! 363:
! 364: uint32 paddr = addr.Addr();
! 365: uint32 offset = Decoder(paddr);
1.1 root 366:
367: if (offset < 0x40) {
368: if ((bool)net) {
1.1.1.3 ! root 369: return net->Write(addr, data);
! 370: }
! 371: } else {
! 372: uint32 reqsize = addr.GetSize();
! 373: uint32 datasize = std::min(2 - (paddr & 1), reqsize);
! 374: data >>= (reqsize - datasize) * 8;
! 375: if (datasize == 1) {
! 376: if (offset == 0xf0) {
! 377: SetPage(data);
! 378: } else if (offset == 0xf1) {
! 379: SetCtrl(data);
! 380: } else {
! 381: r.SetBusErr();
! 382: }
! 383: r |= BusData::Size1;
! 384: } else {
! 385: if (offset == 0xf0) {
! 386: SetPage(data >> 8);
! 387: SetCtrl(data & 0xff);
! 388: } else {
! 389: r.SetBusErr();
! 390: }
! 391: r |= BusData::Size2;
1.1 root 392: }
393: }
1.1.1.3 ! root 394: return r;
1.1 root 395: }
396:
1.1.1.2 root 397: busdata
1.1.1.3 ! root 398: NereidBoardDevice::Peek1(uint32 addr)
1.1 root 399: {
400: uint32 offset = Decoder(addr);
401:
402: if (offset < 0x40) {
403: if ((bool)net) {
1.1.1.3 ! root 404: return net->Peek1(addr);
1.1 root 405: }
406: } else if (offset == 0xf0) {
407: return GetPage();
408:
409: } else if (offset == 0xf1) {
410: return GetCtrl();
411: }
1.1.1.3 ! root 412: return BusData::BusErr;
1.1 root 413: }
414:
415: // バンクページ選択レジスタの値を取得。
416: uint32
417: NereidBoardDevice::GetPage() const
418: {
419: return bank->GetPage();
420: }
421:
422: // バンクページ選択レジスタに値を設定。
423: void
424: NereidBoardDevice::SetPage(uint32 data)
425: {
426: bank->SetPage(data);
427: }
428:
429: // 制御ポートの値を取得。
430: uint32
431: NereidBoardDevice::GetCtrl() const
432: {
433: uint32 data;
434:
435: // bit7: バンクメモリ有効 (%0=無効、%1=有効)、DIPSW8 が見える
436: // bit6: バンクメモリサイズ (%0=4M、%1=16M)
437: // bit5: バンクメモリウィンドウ (%0=$EE0000、%1=$EF0000)、DIPSW6 が見える
438: // bit4
439: // bit3
440: // bit2: USB 割り込み
441: // bit1: USB 電源
442: // bit0: USB 有効
443:
444: // bit5、バンクメモリウィンドウは $EE0000 なら %0、$EF0000 なら %1 だが、
445: // 現状はボード #0 が $EE0000、ボード #1 が $EF0000 と固定してある。
446: data = id << 5;
447:
448: // bit7、bit6。
449: //
450: // bit6 は DIPSW1=OFF, DIPSW2=OFF (メインメモリへの割り当てなし、
451: // つまり 16MB 全部をバンクメモリに割ける) 時に %1 になる。
452: // まったく実用性はないけど再現できるようにしておく。
453: //
454: // DIP8 DIP1 DIP2 bit7 bit6 BankRAM nereid?-ram-size=
455: // ---------------+-----------+----------+------
456: // ON OFF OFF : 1 1 : 16MB | 16
457: // ON * * : 1 0 : 4MB | 4
458: // OFF OFF OFF : 0 1 : Disabled | 0
459: // OFF OFF OFF : 0 1 : Disabled | -16
460: // OFF * * : 0 0 : Disabled | -4
461: if (ramsize_MB > 0) {
462: data |= 0x80;
463: if (ramsize_MB != 4) {
464: data |= 0x40;
465: }
466: } else {
467: if (ramsize_MB != -4) {
468: data |= 0x40;
469: }
470: }
471:
472: // USB 関連は無効なままなので %0
473:
474: return data;
475: }
476:
477: void
478: NereidBoardDevice::SetCtrl(uint32 data)
479: {
480: // USB はないので書き込みは無効
481: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.