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