|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 [email protected]
4: //
5:
6: #include "m88100.h"
7: #include "m88100excep.h"
8: #include "debugger.h"
9: #include "cvprompt.h"
10: #include "mpu.h"
11:
12: #define OP_DEF(name) void __CONCAT(m88kcpu::op_,name)()
13: #define OP_FUNC(name) __CONCAT(op_,name)()
14: #include "m88100ops.cpp"
15:
16: // リセット例外のようなもの?
17: void
18: m88kcpu::Reset(uint32 reset_vector)
19: {
20: // TODO: 未完成
21: psr = 0x800003ff;
22: // SFD1 = 0;
23: psr &= ~PSR_SFD1;
24:
25: #if TEST_INTERRUPT
26: psr &= ~PSR_IND;
27: psr &= ~PSR_SFRZ;
28: #endif
29:
30: vbr = 0;
31:
32: // 実際には m88k MPU はリセット直後は 0 番地から実行を開始するので、
33: // 大抵の場合システムでリセット直後は 0 番地付近に ROM を見せるように
34: // してあるのだと思うが、ここではその代わりに ROM のアドレスを指定して、
35: // 直接そこから実行を開始することにする。
36: fip = reset_vector;
37: nip = 0;
38: xip = 0;
39:
40: fetch();
41: }
42:
43: // request サイクル分実行する。
44: uint32
45: m88kcpu::Run(uint64 request)
46: {
47: uint64 goal_cycle = total_cycle + request;
48: bool is_release = false;
49: bool is_intr = false;
50:
51: while (!is_release) {
52: // shift pipeline
53: opX = opF;
54: xip = nip;
55:
56: // prefetch next inst
57: fetch();
58:
59: // この時点で実行しようとする命令が opX に入っている
60:
61: if (atomic_reqflag != 0) {
62: // 何かが起きた
63:
64: // 割り込みの認識
65: // 割り込みの実行は命令実行完了後、次のプリフェッチの前
66: if ((atomic_reqflag & CPU_REQ_INTR)) {
67: atomic_reqflag &= ~CPU_REQ_INTR;
68: is_intr = true;
69: #if TEST_INTERRUPT
70: atomic_reqflag |= CPU_REQ_PROMPT;
71: #endif
72: }
73:
74: if ((atomic_reqflag & CPU_REQ_TRACE)) {
75: // デバッガプロンプトを出すかどうかを判断する
76: //inst_count++;
77: if (debugger_check()) {
78: atomic_reqflag |= CPU_REQ_PROMPT;
79: }
80: }
81:
82: if ((atomic_reqflag & CPU_REQ_PROMPT)) {
83: // デバッガプロンプトのための実行停止
84:
85: // プロンプト獲得を通知
86: gCVPrompt->NotifyAcquire();
87:
88: // プロンプト解放を待機
89: gCVPrompt->WaitRelease();
90:
91: // プロンプトを抜けたのでここでフラグを落とす
92: atomic_reqflag &= ~CPU_REQ_PROMPT;
93: }
94:
95: if ((atomic_reqflag & CPU_REQ_RELEASE)) {
96: // 中断リクエスト受信
97: // この命令を実行し終わったら抜ける
98: atomic_reqflag &= ~CPU_REQ_RELEASE;
99: is_release = true;
100: }
101: }
102:
103: if (OpIsBusErr(opX)) {
104: // プリフェッチしていた命令がバスエラー
105: Exception(M88K_EXCEP_INST);
106: continue;
107: }
108:
109: uint32 op12 = op32_to_12(opX);
110:
111: switch (op12) {
112: #include "m88100switch.inc"
113: default:
114: __unreachable();
115: }
116:
117: if (is_intr) {
118: is_intr = false;
119: if (!(psr & PSR_IND)) {
120: gMPU->putlog(4, "INTR take");
121: ExceptionCore(M88K_EXCEP_INTERRUPT, ExceptionKind::INTR);
122: continue;
123: } else {
124: gMPU->putlog(4, "INTR DISABLE");
125: }
126: }
127:
128: total_cycle++;
129: if (total_cycle >= goal_cycle)
130: break;
131: }
132:
133: return atomic_reqflag;
134: }
135:
136: // この命令後に実行を中断して VM に戻る
137: void
138: m88kcpu::Release()
139: {
140: atomic_reqflag |= CPU_REQ_RELEASE;
141: }
142:
143: // 通常の例外。
144: // エラー、割り込み、TRAP からは使いません。
145: // vec はベクタ番号。
146: void
147: m88kcpu::Exception(int vec)
148: {
149: ExceptionCore(vec, ExceptionKind::NORMAL);
150: }
151:
152: // 例外処理コア部分
153: // vec はベクタ番号。
154: void
155: m88kcpu::ExceptionCore(int vec, ExceptionKind cause)
156: {
157: if (psr & PSR_SFRZ) {
158: if (cause != ExceptionKind::TRAP) {
159: gMPU->putlog(2, "SFRZ Error Exception");
160: vec = M88K_EXCEP_ERROR;
161: cause = ExceptionKind::ERROR;
162: }
163: } else {
164: gMPU->putlog(2, "Exception %x", vec);
165: sxip = xip;
166: snip = nip;
167: sfip = fip;
168:
169: sxip |= SIP_V;
170: snip |= SIP_V;
171: // XXX:実機と異なり、fip は常にフェッチ前なので V=0
172: // ^^^^ コレ自体怪しい. INTERRUPT とか。
173: // でもたぶん例外ハンドラでここのビット見ないだろうなあ
174:
175: if (OpIsBusErr(opX)) {
176: sxip |= SIP_E; // E bit
177: }
178: if (OpIsBusErr(opF)) {
179: snip |= SIP_E; // E bit
180: }
181:
182: if (vec == M88K_EXCEP_UNIMPL_OP) {
183: sxip &= ~SIP_V;
184: }
185: }
186:
187: epsr = psr;
188: psr |= PSR_SUPER | PSR_SFD1 | PSR_IND | PSR_SFRZ;
189:
190: fip = vbr + (vec << 3);
191: fetch();
192: if (OpIsBusErr(opF)) {
193: if (cause == ExceptionKind::ERROR) {
194: // double bus fault
195: // 実機は無限ループ状態
196: PANIC("Infinite ERROR (double bus fault)");
197: } else {
198: ExceptionCore(M88K_EXCEP_ERROR, ExceptionKind::ERROR);
199: }
200: }
201: }
202:
203: // データアクセス例外(Read)
204: void
205: m88kcpu::ReadDataException(uint32 addr, uint32 flag)
206: {
207: // ミスアラインドはこの例外より前にチェックされていて、
208: // ここにはアラインドしかこない。
209: dma0 = addr & ~0x3;
210: dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
211: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
212: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
213: | (flag & DM_LOCK) // xmem でセット
214: | (FLD_D << 7)
215: | (flag & DM_SIGNED)
216: | ((flag & DM_EN_MASK) >> (addr & 0x03))
217: | 0 // DM_WRITE = 0
218: | DM_VALID;
219: Exception(M88K_EXCEP_DATA);
220: }
221:
222: // データアクセス例外(Write)
223: void
224: m88kcpu::WriteDataException(uint32 addr, uint32 data, uint32 flag)
225: {
226: // ミスアラインドはこの例外より前にチェックされていて、
227: // ここにはアラインドしかこない。
228: dma0 = addr & ~0x3;
229: dmt0 = ((psr & PSR_BO_LE) ? DM_BO : 0)
230: | (((psr & PSR_SUPER) && !(flag & DM_USR)) ? DM_DAS : 0)
231: | (flag & DM_DOUB1) // ダブルワードの第1アクセスのときセット
232: | (flag & DM_LOCK) // xmem でセット
233: | (FLD_D << 7)
234: | (flag & DM_SIGNED)
235: | ((flag & DM_EN_MASK) >> (addr & 0x03))
236: | DM_WRITE
237: | DM_VALID;
238:
239: // dmd は Byte Enable 位置に配置される
240: if (flag & DM_SIZE_B) {
241: dmd0 = data << ((3 - (addr & 0x03)) * 8);
242: } else if (flag & DM_SIZE_H) {
243: dmd0 = data << ((2 - (addr & 0x03)) * 16);
244: } else {
245: dmd0 = data;
246: }
247: Exception(M88K_EXCEP_DATA);
248: }
249:
250: void
251: m88kcpu::Interrupt()
252: {
253: atomic_reqflag |= CPU_REQ_INTR;
254: gMPU->putlog(4, "INTERRUPT ACK (アドレスは不正確)");
255: }
256:
257: void
258: m88kcpu::fpu_unimpl()
259: {
260: printf("%s\n", __func__);
261: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.