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