|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
9: #include "device.h"
10: #include "scheduler.h"
11:
12: struct MFP
13: {
14: static const int GPIP = 0; // $E88001
15: static const int AER = 1; // $E88003
16: static const int DDR = 2; // $E88005
17: static const int IERA = 3; // $E88007
18: static const int IERB = 4; // $E88009
19: static const int IPRA = 5; // $E8800B
20: static const int IPRB = 6; // $E8800D
21: static const int ISRA = 7; // $E8800F
22: static const int ISRB = 8; // $E88011
23: static const int IMRA = 9; // $E88013
24: static const int IMRB = 10; // $E88015
25: static const int VR = 11; // $E88017
26: static const int TACR = 12; // $E88019
27: static const int TBCR = 13; // $E8801B
28: static const int TCDCR = 14; // $E8801D
29: static const int TADR = 15; // $E8801F
30: static const int TBDR = 16; // $E88021
31: static const int TCDR = 17; // $E88023
32: static const int TDDR = 18; // $E88025
33: static const int SCR = 19; // $E88027
34: static const int UCR = 20; // $E88029
35: static const int RSR = 21; // $E8802B
36: static const int TSR = 22; // $E8802D
37: static const int UDR = 23; // $E8802F
38:
39: union ir16 {
40: uint16 w;
41: struct {
42: #if BYTE_ORDER == LITTLE_ENDIAN
43: uint8 b, a;
44: #else
45: uint8 a, b;
46: #endif
47: };
48: };
49:
50: // ハードウェア未実装ビットは書き込み時に '0' にする
51:
52: uint8 gpip;
53: uint8 aer;
54: uint8 ddr;
55: static const int GPIP_HSYNC = 7;
56: static const int GPIP_CIRQ = 6;
57: // 5 は常に '1'
58: static const int GPIP_VDISP = 4;
59: static const int GPIP_FMIRQ = 3;
60: static const int GPIP_POWSW = 2;
61: static const int GPIP_EXPON = 1;
62: static const int GPIP_ALARM = 0;
63:
1.1.1.3 root 64: static const uint INTR_RTC_ALARM = 0;
65: static const uint INTR_EXPON = 1;
66: static const uint INTR_POW_SW = 2;
67: static const uint INTR_FM_IRQ = 3;
68: static const uint INTR_TIMER_D = 4;
69: static const uint INTR_TIMER_C = 5;
70: static const uint INTR_VDISP = 6;
71: static const uint INTR_unused = 7;
72: static const uint INTR_TIMER_B = 8;
73: static const uint INTR_TXERR = 9;
74: static const uint INTR_TXEMPTY = 10;
75: static const uint INTR_RXERR = 11;
76: static const uint INTR_RXFULL = 12;
77: static const uint INTR_TIMER_A = 13;
78: static const uint INTR_CRTC_IRQ = 14;
79: static const uint INTR_HSYNC = 15;
1.1 root 80: ir16 ier;
81: ir16 ipr;
82: ir16 isr;
83: ir16 imr;
84: uint8 vr; // V7 V6 V5 V4 S --- --- ---
85:
86: // TDR のカウンタをメインカウンタと呼び、このメインカウンタを
87: // 1減らすためのカウンタをプリスケーラカウンタと呼ぶ。
88: // 実際のハードウェアは 4MHz のクロック入力ごとにプリスケーラカウンタを
89: // カウントしていき指定回数カウントすればメインカウンタを1減らすのだが、
90: // この実装ではどちらのカウンタも持たず、タイマー開始時刻と現在時刻で
91: // 管理する。そのため、メインカウンタもプリスケーラカウンタも必要なら
92: // この時間差から求める。
93: //
94: // X680x0 の MFP は 4MHz なので、1クロックは 0.25 usec。
95: // TxCR = 1 の時プリスケール回数は 10 なので、入力クロック10回
96: // (2.5usec) ごとにメインカウンタを 1 減らす。
97: // TxDR = 5 から開始すれば 50 カウント (12.5 usec) 後にタイムアップする。
98: // そのためタイマー開始時から現在 3 usec 経過していれば 3 / 0.25 = 12 で
99: // 総入力クロックは12回、メインカウンタは 1 減っており、プリスケール
100: // カウントは10回中残り 8回を指していることになる。
101:
102: uint8 tcr[4]; // --- --- --- RST AC3 AC2 AC1 AC0 : TACR
103: // --- --- --- RST BC3 BC2 BC1 BC0 : TBCR
104: // --- CC2 CC1 CC0 --- DC2 DC1 DC0 : TCDCR
105:
106: // tdr はカウンタの設定値。
107: // タイマー停止中に TxDR に書き込まれると、initial_tdr に即反映される。
108: // タイマー動作中に TxDR に書き込まれると、initial_tdr に反映されるのは
109: // 次のリロードタイミング。
110: uint8 tdr[4];
111:
112: // initial_tdr はカウントダウン開始時点での TxDR の値。
113: // カウンタが 1 から 0 になるタイミングで tdr の値をリロードする。
114: // tdr に $00 を書き込むと 256 カウントになるため、
115: // initial_tdr は 1..256 の値をとる。
116: uint initial_tdr[4];
117:
118: uint64 timer_start[4]; // タイマー開始時の仮想時刻
119:
120: uint8 scr;
1.1.1.3 root 121:
122: // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
123: // UCR | CLK | WL | ST | PE | E/O | --- |
124: // | | | | +--------- %1で偶数パリティ
125: // | | | +--------------- %1でパリティエラー
126: // | | +------------------- スタート/ストップビット
127: // | +--- データ長 %00 同期
128: // | %00:8bit, %01:7bit %01 非同期 1bit/1bit
129: // | %10:6bit, %11:5bit %10 非同期 1bit/1.5bit
130: // | %11 非同期 1bit/2bit
131: // |
132: // +------------------------------------- %1 送受信速度が入力の1/16
133: static const uint32 UCR_CLK = 0x80;
134: static const uint32 UCR_WL = 0x60;
135: static const uint32 UCR_ST = 0x18;
136: static const uint32 UCR_PE = 0x04;
137: static const uint32 UCR_EO = 0x02;
138: uint8 ucr;
139:
140: // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
141: // RSR | BF | OE | PE | FE | B | CIP | SS | RE |
142: // | | | | | | | +--- %1 RX Enable
143: // | | | | | | +--------- Sync Stop
144: // | | | | | +--------------- 非同期なら
145: // | | | | | %1 Detect Start Bit
146: // | | | | | %0 Detect Stop Bit
147: // | | | | +--------------------- %1 非同期ならBreak
148: // | | | +--------------------------- %1 Framing Error
149: // | | +--------------------------------- %1 Parity Error
150: // | +--------------------------------------- %1 Overflow Error
151: // +--------------------------------------------- %1 RX Buffer Full
152: static const uint32 RSR_BF = 0x80;
153: static const uint32 RSR_OE = 0x40;
154: static const uint32 RSR_PE = 0x20;
155: static const uint32 RSR_FE = 0x10;
156: static const uint32 RSR_B = 0x08;
157: static const uint32 RSR_CIP = 0x04;
158: static const uint32 RSR_SS = 0x02;
159: static const uint32 RSR_RE = 0x01;
1.1 root 160: uint8 rsr;
1.1.1.3 root 161:
162: // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
163: // TSR | BE | UE | AT | END | B | H | L | TE |
164: // | | | +--- %1 TX Enable
165: // | | +--------------------------- %1 TX Disabled
166: // | +--------------------------------------- %1 Underrun Error
167: // +--------------------------------------------- %1 TX Buffer Empty
168: static const uint32 TSR_BE = 0x80;
169: static const uint32 TSR_UE = 0x40;
170: static const uint32 TSR_AT = 0x20;
171: static const uint32 TSR_END = 0x10;
172: static const uint32 TSR_B = 0x08;
173: static const uint32 TSR_H = 0x04;
174: static const uint32 TSR_L = 0x02;
175: static const uint32 TSR_TE = 0x01;
1.1 root 176: uint8 tsr;
177:
1.1.1.3 root 178: // 送受信レジスタ。
179: // 受信データがなければ -1 にする
180: uint16 udr;
1.1 root 181: };
182:
183: class MFPDevice
184: : public IODevice
185: {
1.1.1.3 root 186: using inherited = IODevice;
1.1 root 187:
188: static const int baseaddr = 0xe88000;
189:
190: public:
191: MFPDevice();
1.1.1.3 root 192: ~MFPDevice() override;
1.1 root 193:
1.1.1.5 ! root 194: void ResetHard() override;
1.1.1.3 root 195: void ResetSoft() override;
1.1.1.4 root 196: void MonitorUpdate(TextScreen&) override;
1.1 root 197:
198: // VDisp 入力
199: void SetVDisp(bool vdisp);
200:
1.1.1.3 root 201: // KEY CTRL 状態を設定する
202: void SetKeyCtrl(bool ctrl);
203:
204: // RR 線の状態を返す
205: bool IsRR() const;
206:
207: // キーボードからデータを受信
208: void Rx(uint32 data);
1.1.1.2 root 209:
1.1.1.3 root 210: protected:
211: // BusIO インタフェース
212: static const uint32 NPORT = 0x20;
213: uint64 Read(uint32 addr);
214: uint64 Write(uint32 addr, uint32 data);
215: uint64 Peek(uint32 addr);
216:
217: private:
1.1.1.5 ! root 218: void Reset();
1.1 root 219: bool IsTimerIntrEnable(uint ch) const;
220: void SetTCR(int ch, uint32 data);
1.1.1.2 root 221: uint8 GetTDR(int ch) const;
1.1 root 222: void SetTDR(int ch, uint32 data);
223:
224: // GPIP の信号状態をセットする
225: void SetGPIP(int num, bool val);
226:
1.1.1.3 root 227: void SetUCR(uint32 data);
228: void SetRSR(uint32 data);
229: void SetUDR(uint32 data);
230:
231: // イベントコールバック
1.1.1.5 ! root 232: void TimerCallback(Event& ev);
! 233: void KeyCallback(Event& ev);
1.1 root 234:
235: struct MFP mfp {};
236: Event event[4] {};
1.1.1.3 root 237: Event key_event {};
238:
239: // Receiver Ready 線の状態
240: bool rr {};
241:
242: // システムポート#4 の KEY CTRL 状態
243: bool key_ctrl {};
1.1 root 244:
245: static const char *intrname[];
246: static const char *gpipname[];
247: static const int prescale_ns[8];
248: static const char *prescale_str[8];
249: static const int timer_vector[4];
250: };
251:
1.1.1.2 root 252: extern std::unique_ptr<MFPDevice> gMFP;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.