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