|
|
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: {
79: // ボードの有無は nereid%d-enable だけで決まる。
80: for (int i = 0; i < 2; i++) {
81: std::string name = string_format("nereid%d-enable", i);
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 root 120: NereidDevice::Read8(uint32 addr)
121: {
122: putlog(2, "Read $%06x.B", addr);
123:
124: uint32 cs = Decoder(addr);
125: for (int i = 0; i < boards.size(); i++) {
126: if (cs == loc[i]) {
127: return boards[i]->Read8(addr);
128: }
129: }
1.1.1.2 ! root 130: return busdata::BusErr;
1.1 root 131: }
132:
1.1.1.2 ! root 133: busdata
1.1 root 134: NereidDevice::Read16(uint32 addr)
135: {
136: putlog(2, "Read $%06x.W", addr);
137:
138: uint32 cs = Decoder(addr);
139: for (int i = 0; i < boards.size(); i++) {
140: if (cs == loc[i]) {
141: return boards[i]->Read16(addr);
142: }
143: }
1.1.1.2 ! root 144: return busdata::BusErr;
1.1 root 145: }
146:
1.1.1.2 ! root 147: busdata
1.1 root 148: NereidDevice::Write8(uint32 addr, uint32 data)
149: {
150: putlog(2, "Write $%06x.B", addr);
151:
152: uint32 cs = Decoder(addr);
153: for (int i = 0; i < boards.size(); i++) {
154: if (cs == loc[i]) {
155: return boards[i]->Write8(addr, data);
156: }
157: }
1.1.1.2 ! root 158: return busdata::BusErr;
1.1 root 159: }
160:
1.1.1.2 ! root 161: busdata
1.1 root 162: NereidDevice::Write16(uint32 addr, uint32 data)
163: {
164: putlog(2, "Write $%06x.W", addr);
165:
166: uint32 cs = Decoder(addr);
167: for (int i = 0; i < boards.size(); i++) {
168: if (cs == loc[i]) {
169: return boards[i]->Write16(addr, data);
170: }
171: }
1.1.1.2 ! root 172: return busdata::BusErr;
1.1 root 173: }
174:
1.1.1.2 ! root 175: busdata
1.1 root 176: NereidDevice::Peek8(uint32 addr)
177: {
178: uint32 cs = Decoder(addr);
179:
180: for (int i = 0; i < boards.size(); i++) {
181: if (cs == loc[i]) {
182: return boards[i]->Peek8(addr);
183: }
184: }
1.1.1.2 ! root 185: return busdata::BusErr;
1.1 root 186: }
187:
188: void
189: NereidDevice::MonitorUpdate(Monitor *, TextScreen& screen)
190: {
191: int y;
192:
193: screen.Clear();
194:
195: // 0123456789012345678901234567890123456789
196: // #0 #1
197: // Board : NotInstalled NotInstalled
198: // Ethernet : Enable
199: // Address : $ece300
200: // Vector : $f9
201: // Bank Memory : 16MB
202: // Page Select: $ece380
203: // Bank Window: $ee0000
204: // CurrentPage: $00
205:
206: y = 1;
207: screen.Puts(0, y++, "Board :");
208: screen.Puts(1, y++, "Ethernet :");
209: screen.Puts(2, y++, "Address :");
210: screen.Puts(2, y++, "Vector :");
211: screen.Puts(1, y++, "Bank Memory :");
212: screen.Puts(2, y++, "Page Select:");
213: screen.Puts(2, y++, "Bank Window:");
214: screen.Puts(2, y++, "CurrentPage:");
215:
216: for (int i = 0; i < 2; i++) {
217: int x = 15 + i * 14;
218: TA attr;
219:
220: y = 0;
221: screen.Print(x, y++, "#%d", i);
222:
223: // ボードがささっているか
224: bool installed = (bool)boards[i];
225: if (installed) {
226: screen.Puts(x, y, "Installed");
227: } else {
228: screen.Puts(x, y, "NotInstalled");
229: }
230: y++;
231:
232: // イーサネット
233: attr = TA::Disable;
234: if (installed) {
235: if (boards[i]->IsNetEnable()) {
236: screen.Puts(x, y, "Available");
237: attr = TA::Normal;
238: } else {
239: screen.Puts(x, y, "NotAvailable");
240: }
241: } else {
242: screen.Puts(x, y, attr, "-");
243: }
244: y++;
245: screen.Print(x, y++, attr, "$%06x", 0xece300 + i * 0x800);
246: screen.Print(x, y++, attr, "$%02x", 0xf9 - i);
247:
248: // バンクメモリ
249: attr = TA::Disable;
250: int ramsize = 0;
251: if (installed) {
252: ramsize = boards[i]->GetBankRAMSize();
253: if (ramsize > 0) {
254: screen.Print(x, y, "%d MB", ramsize);
255: attr = TA::Normal;
256: } else {
257: screen.Puts(x, y, "Disabled");
258: }
259: } else {
260: screen.Puts(x, y, attr, "-");
261: }
262: y++;
263: screen.Print(x, y++, attr, "$%06x", 0xece3f0 + i * 0x800);
264: screen.Print(x, y++, attr, "$%06x", 0xee0000 + i * 0x10000);
265: if (installed) {
266: if (ramsize > 0) {
267: attr = TA::Normal;
268: } else {
269: attr = TA::Disable;
270: }
271: screen.Print(x, y, attr, "$%02x", boards[i]->GetPage());
272: } else {
273: screen.Puts(x, y, attr, "---");
274: }
275: }
276: }
277:
278:
279: //
280: // Nereid ボード1枚分
281: //
282:
283: // コンストラクタ
284: NereidBoardDevice::NereidBoardDevice(int id_)
285: : inherited(OBJ_NEREID_BOARD(id_))
286: {
287: id = id_;
288: }
289:
290: // デストラクタ
291: NereidBoardDevice::~NereidBoardDevice()
292: {
293: }
294:
295: bool
296: NereidBoardDevice::Create()
297: {
298: std::string netname = string_format("nereid%d-net", id);
299: std::string ramname = string_format("nereid%d-ram-size", id);
300:
301: const ConfigItem inet = gConfig->Find(netname);
302: bool net_enable = inet.AsInt();
303:
304: const ConfigItem iramsize = gConfig->Find(ramname);
305: ramsize_MB = iramsize.AsInt();
306: switch (ramsize_MB) {
307: case 0:
308: case 4:
309: case 16:
310: case -4:
311: case -16:
312: // 負数は、バンクメモリ無効時の制御ポート bit6 を明示したい場合用。
313: break;
314: default:
315: iramsize.Err("Valid value is one of 0, 4, 16 (or -4, -16)");
316: return false;
317: }
318:
319: // ネットワークが無効の場合 (これは正常な実機では起きないが)、
320: // RTL8019ASDevice インスタンスの生成自体を行わず、net は NULL。
321: if (net_enable) {
322: int vector;
323: if (id == 0) {
324: vector = 0xf9;
325: } else {
326: vector = 0xf8;
327: }
328: net.reset(new RTL8019ASDevice(id, vector));
329: }
330:
331: // バンクメモリは (DIPSW によって) 有効/無効どちらであっても
332: // BankRAMDevice インスタンスの生成自体は行う。
333: // ページレジスタは存在している(はずの)ため。
334: if (ramsize_MB <= 0) {
335: bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), 0));
336: } else {
337: bank.reset(new BankRAMDevice(OBJ_BANKRAM(id), ramsize_MB));
1.1.1.2 ! root 338: // I/O 空間への登録は X68kIO 側から行っている。
1.1 root 339: }
340: return true;
341: }
342:
343: inline uint32
344: NereidBoardDevice::Decoder(uint32 addr) const
345: {
346: return addr & 0xff;
347: }
348:
1.1.1.2 ! root 349: busdata
1.1 root 350: NereidBoardDevice::Read8(uint32 addr)
351: {
352: uint32 offset = Decoder(addr);
353:
354: if (offset < 0x40) {
355: if ((bool)net) {
356: return net->Read8(addr);
357: }
358: } else if (offset == 0xf0) {
359: return GetPage();
360:
361: } else if (offset == 0xf1) {
362: return GetCtrl();
363: }
1.1.1.2 ! root 364: return busdata::BusErr;
1.1 root 365: }
366:
1.1.1.2 ! root 367: busdata
1.1 root 368: NereidBoardDevice::Read16(uint32 addr)
369: {
370: uint32 offset = Decoder(addr);
1.1.1.2 ! root 371: uint32 data;
1.1 root 372:
373: if (offset < 0x40) {
374: if ((bool)net) {
375: return net->Read16(addr);
376: }
377: } else if (offset == 0xf0) {
378: data = GetPage() << 8;
379: data |= GetCtrl();
1.1.1.2 ! root 380: // XXX wait?
1.1 root 381: return data;
382: }
1.1.1.2 ! root 383: return busdata::BusErr;
1.1 root 384: }
385:
1.1.1.2 ! root 386: busdata
1.1 root 387: NereidBoardDevice::Write8(uint32 addr, uint32 data)
388: {
389: uint32 offset = Decoder(addr);
390:
391: if (offset < 0x40) {
392: if ((bool)net) {
393: return net->Write8(addr, data);
394: }
395: } else if (offset == 0xf0) {
396: SetPage(data);
397: return 0;
398:
399: } else if (offset == 0xf1) {
400: SetCtrl(data);
401: return 0;
402: }
1.1.1.2 ! root 403: return busdata::BusErr;
1.1 root 404: }
405:
1.1.1.2 ! root 406: busdata
1.1 root 407: NereidBoardDevice::Write16(uint32 addr, uint32 data)
408: {
409: uint32 offset = Decoder(addr);
410:
411: if (offset < 0x40) {
412: if ((bool)net) {
413: return net->Write16(addr, data);
414: }
415: } else if (offset == 0xf0) {
416: SetPage(data >> 8);
417: SetCtrl(data & 0xff);
418: return 0;
419: }
1.1.1.2 ! root 420: return busdata::BusErr;
1.1 root 421: }
422:
1.1.1.2 ! root 423: busdata
1.1 root 424: NereidBoardDevice::Peek8(uint32 addr)
425: {
426: uint32 offset = Decoder(addr);
427:
428: if (offset < 0x40) {
429: if ((bool)net) {
430: return net->Peek8(addr);
431: }
432: } else if (offset == 0xf0) {
433: return GetPage();
434:
435: } else if (offset == 0xf1) {
436: return GetCtrl();
437: }
1.1.1.2 ! root 438: return busdata::BusErr;
1.1 root 439: }
440:
441: // バンクページ選択レジスタの値を取得。
442: uint32
443: NereidBoardDevice::GetPage() const
444: {
445: return bank->GetPage();
446: }
447:
448: // バンクページ選択レジスタに値を設定。
449: void
450: NereidBoardDevice::SetPage(uint32 data)
451: {
452: bank->SetPage(data);
453: }
454:
455: // 制御ポートの値を取得。
456: uint32
457: NereidBoardDevice::GetCtrl() const
458: {
459: uint32 data;
460:
461: // bit7: バンクメモリ有効 (%0=無効、%1=有効)、DIPSW8 が見える
462: // bit6: バンクメモリサイズ (%0=4M、%1=16M)
463: // bit5: バンクメモリウィンドウ (%0=$EE0000、%1=$EF0000)、DIPSW6 が見える
464: // bit4
465: // bit3
466: // bit2: USB 割り込み
467: // bit1: USB 電源
468: // bit0: USB 有効
469:
470: // bit5、バンクメモリウィンドウは $EE0000 なら %0、$EF0000 なら %1 だが、
471: // 現状はボード #0 が $EE0000、ボード #1 が $EF0000 と固定してある。
472: data = id << 5;
473:
474: // bit7、bit6。
475: //
476: // bit6 は DIPSW1=OFF, DIPSW2=OFF (メインメモリへの割り当てなし、
477: // つまり 16MB 全部をバンクメモリに割ける) 時に %1 になる。
478: // まったく実用性はないけど再現できるようにしておく。
479: //
480: // DIP8 DIP1 DIP2 bit7 bit6 BankRAM nereid?-ram-size=
481: // ---------------+-----------+----------+------
482: // ON OFF OFF : 1 1 : 16MB | 16
483: // ON * * : 1 0 : 4MB | 4
484: // OFF OFF OFF : 0 1 : Disabled | 0
485: // OFF OFF OFF : 0 1 : Disabled | -16
486: // OFF * * : 0 0 : Disabled | -4
487: if (ramsize_MB > 0) {
488: data |= 0x80;
489: if (ramsize_MB != 4) {
490: data |= 0x40;
491: }
492: } else {
493: if (ramsize_MB != -4) {
494: data |= 0x40;
495: }
496: }
497:
498: // USB 関連は無効なままなので %0
499:
500: return data;
501: }
502:
503: void
504: NereidBoardDevice::SetCtrl(uint32 data)
505: {
506: // USB はないので書き込みは無効
507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.