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