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