|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // MPU (HD647180)
9: //
10:
11: #pragma once
12:
1.1.1.3 root 13: #include "mpu.h"
1.1 root 14: #include "branchhistory.h"
15: #include "event.h"
16: #include "hd64180.h"
17: #include "message.h"
18: #include <array>
19:
1.1.1.5 ! root 20: class HD647180ASCIDevice;
1.1 root 21: class PIO0Device;
1.1.1.3 root 22: class SSGDevice;
1.1 root 23: class XPbusDevice;
24:
1.1.1.3 root 25: class MPU64180Device : public MPUDevice, private HD64180
1.1 root 26: {
1.1.1.3 root 27: using inherited = MPUDevice;
1.1 root 28:
29: // タイマー1個分
30: struct XPTimer {
31: uint16 count; // 現在のカウント
32: uint16 reload; // リロードカウント
33: uint16 tmpcount; // 読み出し時用の内部バッファ
34: bool running; // カウントダウン中なら true
35: bool intr_enable; // TIEn ビットの状態 (IEF1 の状態は含まない)
36:
37: // 割り込みフラグ TIFn はカウントが 0 になると立ち、
38: // その後 TCR と TDR をそれぞれ読むことで (AND 条件)、リセットできる。
39: // そのため、tif は 2ビットで管理し、
40: // カウントが 0 になれば $3 をセット、
41: // TCR の読み出しで bit0 をクリア、
42: // TDR の読み出しで bit1 をクリア、
43: // (tif != 0) なら割り込み状態、とする。
44: uint32 tif;
45: };
46:
47: public:
48: MPU64180Device();
1.1.1.2 root 49: ~MPU64180Device() override;
1.1 root 50:
51: void putlogn(const char *fmt, ...) const override;
1.1.1.5 ! root 52: bool Create() override;
1.1 root 53: bool Init() override;
54: void ResetHard(bool poweron) override;
55:
56: // 現在実行中の命令先頭の PC を取得
1.1.1.3 root 57: uint32 GetPPC() const override { return ppc; }
1.1 root 58:
59: // CPU の動作モードを返す。
60: OpMode GetOpMode() const { return opmode; }
61:
62: // RESET 信号をアサート(true)/ネゲート(false)する。
63: void ChangeRESET(bool);
64: void AssertRESET();
65: void NegateRESET();
66:
67: // プロセッサをリセット
68: void Reset();
69:
70: // INT0 信号線をアサートする (PIO1 から呼ばれる)。
71: // (ネゲートはローカルで行う)
72: void AssertINT0();
73:
1.1.1.5 ! root 74: // ASCI0/1 の割り込みをアサート/ネゲートする (ASCI から呼ばれる)。
! 75: void ChangeASCIInt(uint n, bool req);
! 76:
1.1 root 77: // ブランチ履歴 (例外履歴を含む)
78: BranchHistory_hd64180 brhist { OBJ_XP_BRHIST };
79: // 例外履歴のみ
80: BranchHistory_hd64180 exhist { OBJ_XP_EXHIST };
81:
82: // I, R レジスタ
83: uint8 GetI() const { return reg_i; }
84: uint8 GetR() const { return reg_r & 0x7f; }
85:
86: bool GetIEF1() const { return ief1; }
87: bool GetIEF2() const { return ief2; }
88:
89: // アドレス変換 (デバッガ用)
1.1.1.3 root 90: uint32 TranslatePeek(uint32) const;
1.1 root 91:
92: // MSXDOS エミュレーションのコールバックを指定する。
93: void SetSYSCALLCallback(void (*callback)(void *), void *arg);
94:
95: hd64180reg reg {};
96:
97: // 割り込み名
98: static std::vector<const char *> InterruptName;
99:
100: private:
101: void EnterNormal();
102: void EnterSleep();
103: void EnterWakeup();
104: void ExecTrace(Event& ev);
105: void ExecNormal(Event& ev);
106: void ExecSleep(Event& ev);
107: void ExecWakeup(Event& ev);
108: void SetExec(EventCallback_t);
109:
110: // トレース設定。デバッガから呼び出される。
111: void SetTrace(bool enable);
112: void TraceMessage(MessageID, uint32);
113:
114: uint32 GetIHL() const;
115: void SetIHL(uint32);
116: uint32 LeaIHL();
117: uint32 GetWW(uint) const;
118: void SetWW(uint, uint32);
119:
1.1.1.4 root 120: // CPU からの論理メモリアクセス
1.1.1.3 root 121: uint32 Fetch1();
122: uint32 Fetch2();
1.1.1.4 root 123: uint32 Read1(uint32 addr);
124: uint32 Write1(uint32 addr, uint32 data);
125: uint32 Read2(uint32 addr);
126: void Write2(uint32 addr, uint32 data);
127:
1.1 root 128: void Jump(uint16);
129: void op_illegal(int pos);
130:
131: void ops_ret();
132: void ops_ddfd(ixiy_t);
133: void ops_ldi(int);
134: void ops_cpi(int);
135: void ops_ini(int);
136: void ops_outi(int);
137: void ops_otim(int);
138: void ops_otmr_until();
139:
140: #define OP_PROTO(name) void __CONCAT(op_,name)()
141: #include "hd64180ops.h"
142: #undef OP_PROTO
143:
144: uint32 Translate(uint32) const;
145:
146: void AssertIntmap(int source);
147: void NegateIntmap(int source);
148: void NegateINT0();
149: void DoInterrupt();
150: void ExceptionDirect(int source, uint32 addr);
151: void ExceptionVector(int source);
152:
1.1.1.3 root 153: uint32 Peek1(uint32 addr) const;
154: uint32 Peek2(uint32 addr) const;
1.1 root 155:
1.1.1.3 root 156: void Push2(uint32 data);
157: uint32 Pop2();
1.1 root 158:
159: uint32 ReadIO(uint32 addr);
160: uint32 ReadInternalIO(uint32 offset);
161: uint32 ReadExternalIO(uint32 addr);
162: uint32 WriteIO(uint32 addr, uint32 data);
163: uint32 WriteInternalIO(uint32 offset, uint32 data);
164: uint32 WriteExternalIO(uint32 addr, uint32 data);
165: uint32 PeekIO(uint32 addr);
166: uint32 PeekInternalIO(uint32 offset);
167: uint32 PeekExternalIO(uint32 addr);
168: static std::string IOName(uint32 addr);
169:
170: uint32 ReadTMDRL(int ch);
171: uint32 ReadTMDRH(int ch);
172: uint32 ReadTCR();
173:
174: uint32 WriteTMDRL(int ch, uint32 data);
175: uint32 WriteTMDRH(int ch, uint32 data);
176: uint32 WriteRLDRL(int ch, uint32 data);
177: uint32 WriteRLDRH(int ch, uint32 data);
178: uint32 WriteTCR(uint32 data);
179: uint32 WriteDCNTL(uint32 data);
180: uint32 WriteIL(uint32 data);
181: uint32 WriteITC(uint32 data);
182: uint32 WriteRCR(uint32 data);
183: uint32 WriteCBR(uint32 data);
184: uint32 WriteBBR(uint32 data);
185: uint32 WriteCBAR(uint32 data);
186: uint32 WriteICR(uint32 data);
187: uint32 WriteRMCR(uint32 data);
188:
189: uint32 PeekTMDRL(int ch) const;
190: uint32 PeekTMDRH(int ch) const;
191: uint32 PeekRLDRL(int ch) const;
192: uint32 PeekRLDRH(int ch) const;
193: uint32 PeekTCR() const;
194: uint32 PeekFRC() const;
195: uint32 PeekDCNTL() const;
196: uint32 PeekIL() const;
197: uint32 PeekITC() const;
198: uint32 PeekRCR() const;
199: uint32 PeekCBR() const;
200: uint32 PeekBBR() const;
201: uint32 PeekCBAR() const;
202: uint32 PeekICR() const;
203: uint32 PeekRMCR() const;
204:
205: void CYCLE(int n) { used_cycle += n; }
206: void CYCLE_IX(int, int);
207:
208: // タイマー
209: void EnableTimer();
210: void ChangeTimerInterrupt();
211: void TimerCallback(Event& ev);
212: void MakeActiveTimer();
213:
214: uint16 ppc {};
215:
216: uint8 reg_i {}; // I レジスタ
217: uint8 reg_r {}; // R レジスタ
218:
1.1.1.3 root 219: uint ixiy {}; // 0=HL, 1=IX, 2=IY
1.1 root 220: // (IX+d)/(IY+d) の d。
221: // 読み込んでない時は (uint32)-1 にしておく。
222: // DD と DD CB で読む位置が違うので。
223: uint32 ixd {};
224:
225: bool ief1 {}; // IEF1: Interrupt Enable Flag1
226: bool ief2 {}; // IEF2: Interrupt Enable Flag2
1.1.1.3 root 227: uint int0mode {}; // INT0 mode
1.1 root 228: bool intcheck {}; // この命令後の境界で割り込みチェックするなら true
229:
230: // 割り込み信号線の状態
231: //
232: // bit 31 30 29 27 26 25 24 23 22 21 20 19 18 17 16 15 ... 0
233: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- --+
234: // intmap | 0| 0|I0|I1|I2|IC|OC|TV|T0|T1|D0|D1|CS|A0|A1| |
235: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-- ... --+
236: // 優先順位 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
237: //
238: // intmap (32bit) は最上位から割り込み優先順に 1ビットずつ割り当てる
239: // (ただし TRAP と NMI はここでは使わないので %0 のまま)。
240: // 割り込みが発生していなければ intmap == 0。
241: // 割り込みが発生すれば該当するビットを立てる。割り込みを処理する際は
242: // builtin_clz() で上から判定していく。
243: uint32 intmap {};
244:
245: // 割り込み回数 (アサートのエッジでカウントアップする)
246: // [0] が優先順位 0 (TRAP) の割り込み回数。
247: // [14] が優先順位 14 (ASCI1) の割り込み回数。
248: uint64 int_counter[15] {};
249:
250: // 動作モード。
251: // mode == Reset ならリセット信号アサート中。
252: OpMode opmode {};
253:
254: // 現在の命令列
255: std::vector<uint8> ops {};
256: // 直近の命令語
257: uint8 op {};
258:
259: uint64 clock_nsec {}; // MPU クロック [nsec]
260:
261: // 電源オンからの累積消費サイクル
262: uint64 used_cycle {};
263:
264: // タイマーと Free Running Counter
265: uint64 timer_epoch {};
266: std::array<XPTimer, 2> timer {};
267: std::vector<XPTimer *> active_timer {};
268: uint8 timer_toc {}; // Timer Output Control
269:
270: // DCNTL
271: uint32 memwait {}; // メモリウェイト
272: uint32 iowait {}; // I/O ウェイト
273: uint32 dcntl {}; // DCNTL の残り部分 (未実装)
274:
275: // IL: 割り込みベクタの下位バイト(のうち上位3ビット)。
276: // 書き込み時にマスクする。
277: uint32 intvec_low {};
278: // ITC: 割り込み制御
279: bool itc_trap {};
280: bool itc_ufo {};
281: bool itc_ite0 {}; // INT Enable 0
282: bool itc_ite1 {}; // INT Enable 1
283: bool itc_ite2 {}; // INT Enable 2
284:
285: // RCR
286: uint32 rcr {};
287:
288: // MMU
289: uint32 commbase {}; // Common Base Address
290: uint32 bankbase {}; // Bank Base Address
291: uint32 commarea {}; // Common Area の下限アドレス
292: uint32 bankarea {}; // Bank Area の下限アドレス
293:
294: // ICR
295: uint32 io_address {}; // I/O アドレスの開始番地
296:
297: // SYSCALL 用のコールバック
298: void (*syscall_callback)(void *) = NULL;
299: void *syscall_arg {};
300:
1.1.1.5 ! root 301: std::unique_ptr<HD647180ASCIDevice> asci /*{}*/;
! 302:
1.1 root 303: PIO0Device *pio0 {};
1.1.1.3 root 304: SSGDevice *ssg {};
1.1 root 305: XPbusDevice *xpbus {};
306:
307: // モニター
308: DECLARE_MONITOR_CALLBACK(MonitorUpdateReg);
309: DECLARE_MONITOR_CALLBACK(MonitorUpdateIO);
310: DECLARE_MONITOR_CALLBACK(MonitorUpdateIntr);
1.1.1.4 root 311: Monitor *reg_monitor {};
312: Monitor *io_monitor {};
313: Monitor *intr_monitor {};
1.1 root 314:
1.1.1.3 root 315: // 実行コールバック
316: EventCallback_t exec_func {};
317:
1.1 root 318: // イベント
319: Event timer_event { this };
320:
321: // 名前
322: static const char * const opmode_names[];
323: static std::vector<const char *> ionames;
324: };
325:
326: static inline MPU64180Device *GetMPU64180Device() {
327: return Object::GetObject<MPU64180Device>(OBJ_MPUXP);
328: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.