|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // NEWS の各種制御ポート(?)
9: //
10:
11: // NWS-1750 の $e100'0000..$e1ff'ffff
12: //
13: // +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F'0000
14: // e100'0000 |TIC PE
15: // e110'0000 | I2D
16: // e120'0000 | ASD
17: // e130'0000 |L2E POW
18: // e140'0000 |
19: // e150'0000 |
20: // e160'0000 |
21: // e170'0000 |
22: // e180'0000 |
23: // e190'0000 |L2D
24: // e1a0'0000 |PD
25: // e1b0'0000 |
26: // e1c0'0000 |(*)
27: // e1d0'0000 |
28: // e1e0'0000 |
29: // e1f0'0000 |
30: //
31: // TIC: Timer Interrupt Control
32: // PE/PD: Parity Enable/Disable
33: // I2D: Lv2 Interrupt Disable
34: // ASD: AST Disable
35: // L2E/L2D: L2 Cache Enable/Disable
36: // POW: Power Control
37: // (*): IDROM, DIP-SW, Parity Vector, Interupt Status
38: //
39: // また、ここに書いてない $e000'0000 ブロックにあるデバイスも一部担当している。
40: // newsio.cpp 冒頭のメモリマップも参照。
41:
42: #include "newsctlr.h"
43: #include "dipsw.h"
44: #include "ethernet.h"
45: #include "interrupt.h"
46: #include "scheduler.h"
1.1.1.4 root 47: #include "textscreen.h"
1.1 root 48:
49: // コンストラクタ
50: NewsCtlrDevice::NewsCtlrDevice()
51: : inherited(OBJ_NEWSCTLR)
52: {
53: // ROM のうち固定のもの
54: oidrom[0] = 0x0d; // ModelID = NWS-1750
55: }
56:
57: // デストラクタ
58: NewsCtlrDevice::~NewsCtlrDevice()
59: {
60: }
61:
62: // 初期化
63: bool
64: NewsCtlrDevice::Init()
65: {
66: dipsw = GetDipswDevice();
67:
68: // ステータス読み出しのためにキャストしたのを持っておく
69: interrupt = dynamic_cast<NewsInterrupt*>(GetInterruptDevice());
70: assert(interrupt);
71:
72: // MAC アドレスを ROM にセット。
1.1.1.5 ! root 73: MacAddr macaddr;
1.1.1.2 root 74: if (EthernetDevice::GetConfigMacAddr(0, &macaddr, false) == false) {
1.1 root 75: // エラーメッセージは表示済み
76: return false;
77: }
78: putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str());
79: memcpy(&oidrom[8], &macaddr, sizeof(macaddr));
80:
1.1.1.4 root 81: timer_event.func = ToEventCallback(&NewsCtlrDevice::TimerCallback);
82: timer_event.time = 10_msec;
83: timer_event.SetName("SystemTimer");
84: scheduler->RegistEvent(timer_event);
85:
1.1 root 86: return true;
87: }
88:
89: void
90: NewsCtlrDevice::ResetHard(bool poweron)
91: {
92: // たぶん止まるだろう。知らんけど。
93: timer_intr = false;
94: timer_enable = false;
1.1.1.3 root 95: ChangeInterrupt();
1.1 root 96:
97: // たぶん消すだろう。知らんけど。
98: led = 0;
99:
100: // たぶん電源オンで即起動? 知らんけど。
101: if (poweron) {
102: scheduler->StartEvent(timer_event);
103: }
104: }
105:
1.1.1.3 root 106: busdata
1.1.1.4 root 107: NewsCtlrDevice::Read(busaddr addr)
1.1 root 108: {
1.1.1.4 root 109: uint32 paddr = addr.Addr() | 0xc0000000;
1.1 root 110:
1.1.1.4 root 111: if ((paddr >> 16) == 0xe1c0) {
112: uint idx = (paddr >> 8) & 3;
113: busdata data;
1.1 root 114: switch (idx) {
115: case 0: // e1c0'00xx
1.1.1.4 root 116: data = GetIDROM(paddr);
117: putlog(2, "$%08x.B (IDROM) -> $%02x", paddr, data.Data());
1.1 root 118: break;
119: case 2: // e1c0'02xx
120: // 割り込みステータス
121: data = interrupt->PeekStatus();
1.1.1.4 root 122: putlog(1, "$%08x.B (IntStat) -> $%02x", paddr, data.Data());
1.1 root 123: break;
124: default: // e1c0'01xx
125: // DIP-SW
126: data = GetDIPSW();
1.1.1.4 root 127: putlog(1, "$%08x.B (DIPSW) -> $%02x", paddr, data.Data());
1.1 root 128: break;
129: }
1.1.1.4 root 130: data |= BusData::Size1;
1.1 root 131: return data;
132: }
1.1.1.4 root 133: VMPANIC("Read($%08x)", paddr);
1.1 root 134: }
135:
1.1.1.3 root 136: busdata
1.1.1.4 root 137: NewsCtlrDevice::Write(busaddr addr, uint32 data)
1.1 root 138: {
1.1.1.4 root 139: uint32 paddr = addr.Addr() | 0xc0000000;
140: uint32 reqsize = addr.GetSize();
141: data >>= (reqsize - 1) * 8;
1.1 root 142:
1.1.1.4 root 143: if (paddr == 0xe0c8'0000) {
1.1 root 144: // PWS-1560 FDC?
145: putlog(0, "FDC <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 146:
147: } else if (paddr == 0xe0dc'0000) {
1.1 root 148: WriteLED(data);
1.1.1.4 root 149:
150: } else if (paddr == 0xe100'0000) {
1.1 root 151: WriteTimer(data);
1.1.1.4 root 152:
153: } else if (paddr == 0xe108'0000) {
1.1 root 154: // Parity enable?
155: putlog(0, "Parity enable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 156:
157: } else if (paddr == 0xe118'0000) {
1.1 root 158: // Level2 Interrupt ?
159: putlog(0, "Lv2 Interrupt disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 160:
161: } else if (paddr == 0xe128'0000) {
1.1 root 162: putlog(0, "AST disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 163:
164: } else if (paddr == 0xe130'0000) {
1.1 root 165: putlog(0, "L2 cache enable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 166:
167: } else if (paddr == 0xe138'0000) {
1.1 root 168: putlog(0, "Power Control <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 169:
170: } else if (paddr == 0xe190'0000) {
1.1 root 171: putlog(0, "L2 cache disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 172:
173: } else if (paddr == 0xe1a0'0000) {
1.1 root 174: putlog(0, "Parity disable? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 175:
176: } else if (paddr == 0xe1c0'0200) {
1.1 root 177: // XXX たぶん 0xe1c0'02ff まで全部同じかも
178: putlog(0, "Parity Vector? <- $%02x (NOT IMPLEMENTED)", data);
1.1.1.4 root 179:
180: } else {
181: VMPANIC("Write($%08x) <- $%02x", paddr, data);
1.1 root 182: }
183:
1.1.1.4 root 184: busdata r = BusData::Size1;
185: return r;
1.1 root 186: }
187:
1.1.1.3 root 188: busdata
1.1.1.4 root 189: NewsCtlrDevice::Peek1(uint32 addr)
1.1 root 190: {
191: addr |= 0xc0000000;
192:
193: if ((addr >> 16) == 0xe1c0) {
194: uint idx = (addr >> 8) & 3;
195: switch (idx) {
196: case 0: // e1c0'00xx
197: return GetIDROM(addr);
198: case 2: // e1c0'02xx
199: return interrupt->PeekStatus();
200: default: // e1c0'01xx
201: return GetDIPSW();
202: }
203: }
204:
1.1.1.4 root 205: return BusData::BusErr;
1.1.1.3 root 206: }
207:
208: // NewsIO の下請けとして呼ばれる。
209: void
210: NewsCtlrDevice::MonitorUpdateNewsCtlr(TextScreen& screen, int y)
211: {
212: // テーブル方式ではないので、Read/Write と手動で揃える…。
213:
214: uint32 addr = 0xe100;
215: for (int i = 0; i < 32; i++) {
216: screen.Print(0, y, "$%04x'0000:", addr);
217:
218: const char *name = NULL;
219: TA attr;
220: for (int j = 0; j < 8; j++) {
221: switch (addr) {
222: case 0xe100: name = "Timer"; break;
223: case 0xe108: name = "ParEn?"; break;
224: case 0xe118: name = "Lv2Int?"; break;
225: case 0xe128: name = "ASTDis?"; break;
226: case 0xe130: name = "L2CE?"; break;
227: case 0xe138: name = "Power"; break;
228: case 0xe190: name = "L2CD?"; break;
229: case 0xe1a0: name = "ParDis?"; break;
230: case 0xe1c0: name = "Misc"; break;
231: default:
232: name = NULL;
233: break;
234: }
235: if (name) {
236: attr = TA::Normal;
237: } else {
238: name = "NopIO";
239: attr = TA::Disable;
240: }
241: screen.Puts(12 + j * 8, y, attr, name);
242: addr++;
243: }
244: y++;
245: }
1.1 root 246: }
247:
248: // IDROM の値を返す。この関数は副作用を起こしてはいけない。
249: uint8
250: NewsCtlrDevice::GetIDROM(uint32 addr) const
251: {
252: uint32 data;
253:
254: // $e1c0'00xx はたぶん 256x4bit ROM。
255: //
256: // 生データ oidrom[] はバイトで持っておき(つまり128バイト)、
257: // アクセス時に分解する。
258: // 実際に使われているのはこのうち先頭の 16バイト(32ニブル)分のようだ。
259:
260: int n = (addr & 0xff) / 2;
261: if ((addr & 1) == 0) {
262: data = oidrom[n] >> 4;
263: } else {
264: data = oidrom[n];
265: }
266: return data | 0xf0;
267: }
268:
269: // DIPSW の状態を読み出す。この関数は副作用を起こしてはいけない。
270: // SW1 が LSB 側。
271: // オン(true)なら %0、オフ(false)なら %1。
272: uint8
273: NewsCtlrDevice::GetDIPSW() const
274: {
275: uint8 data = 0;
276:
277: for (int i = 0; i < 8; i++) {
278: if (dipsw->Get(i) == false) {
279: data |= 1U << i;
280: }
281: }
282: return data;
283: }
284:
285: // LED 制御ポート書き込み
286: void
287: NewsCtlrDevice::WriteLED(uint32 data)
288: {
289: // bit0 が緑 LED、bit1 がオレンジ LED のオンオフらしい。
290: led = data & 0x03;
291: putlog(1, "LED <- $%02x", led);
292: }
293:
294: // システムタイマー
295: void
296: NewsCtlrDevice::WriteTimer(uint32 data)
297: {
298: switch (data) {
299: case 0:
300: timer_enable = false;
301: timer_intr = false;
302: break;
303: case 1:
304: timer_enable = true;
305: break;
306: default:
307: VMPANIC("Unknown Timer Control $%02x", data);
308: break;
309: }
310: ChangeInterrupt();
311: }
312:
313: // システムタイマーイベント
314: void
315: NewsCtlrDevice::TimerCallback(Event& ev)
316: {
317: timer_intr = true;
318: ChangeInterrupt();
319:
320: // XXX clock-sync はまた後ほど
321: scheduler->RestartEvent(ev);
322: }
323:
324: // 割り込み信号線の状態を変える
325: void
326: NewsCtlrDevice::ChangeInterrupt()
327: {
328: interrupt->ChangeINT(this, (bool)(timer_enable && timer_intr));
329: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.