|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // HD647180 コア
9: //
10:
11: #include "mpu64180.h"
12: #include "debugger.h"
1.1.1.6 root 13: #include "event.h"
1.1 root 14: #include "hd64180.h"
15: #include "hd647180.h"
16: #include "scheduler.h"
17:
18: #define OP_DEF(name) void __CONCAT(MPU64180Device::op_,name)()
19: #define OP_FUNC(name) __CONCAT(op_,name)()
20: #include "hd64180ops.cpp"
21:
22: void
1.1.1.6 root 23: MPU64180Device::ExecNormal(Event *ev)
1.1 root 24: {
25: uint64 cycle_start = used_cycle;
26:
27: ppc = reg.pc;
28: ixiy = USE_HL;
29: ixd = -1;
30: ops.clear();
31: intcheck = true;
32:
33: // R レジスタは命令ごとにカウント。7bit マスクは読み出し時に行う。
34: // 命令の前か後かは分からないが。
35: reg_r++;
36:
37: // 1バイト目処理
1.1.1.2 root 38: op = Fetch1();
1.1 root 39: if (__predict_false(opmode == OpMode::Halt)) {
40: // ホールトモードなら PC を戻し続けるだけ
41: reg.pc--;
42: CYCLE(3);
43: } else {
44: switch (op) {
45: #include "hd64180switch_00.inc"
46: default:
47: __unreachable();
48: }
49: }
50:
51: // 割り込みチェック。
52: if (__predict_true(intcheck)) {
53: // intmap が非ゼロなら割り込み発生中。
54: if (GetIEF1() == true && __predict_false(intmap != 0)) {
55: DoInterrupt();
56: }
57: } else {
58: // この命令境界での割り込みチェックを飛ばす。次からは行う。
59: intcheck = true;
60: }
61:
62: int cycle = used_cycle - cycle_start;
1.1.1.7 ! root 63: ev->time = cycle * clock_tsec;
1.1 root 64: scheduler->StartEvent(ev);
65: }
66:
67: // 不当命令。
68: // pos は不当命令になったバイト位置。2バイト目なら2。
69: void
70: MPU64180Device::op_illegal(int pos)
71: {
72: // ログ表示
73: std::string str;
74: for (auto o : ops) {
75: str += string_format(" %02x", o);
76: }
77: putlog(1, "Undefined opcode%s", str.c_str());
78:
79: itc_trap = true;
80: // 3バイト目なら UFO ビットをセット。
81: itc_ufo = (pos == 3);
82:
83: // XXX CYCLE
84:
85: // TRAP 割り込みはマスク不可能。
86: // IEF[12] not affected
87:
88: // (1) ITC の TRAP ビットを 1 にする
89: // (2) 未定義 opcode 位置の PC をスタックに保存する
90: // (3) ベクタを 0000H にする
91:
92: // PC は未定義命令の先頭番地ではなく、未定義 opcode だった位置?
93: // nono の実装ではフェッチと同時にインクリメントしているので、
94: // 1つ前でいい? HD64180.pdf p38-39
1.1.1.3 root 95: if (pos == 2) {
96: Push2(reg.pc - 1);
97: } else {
98: // DD CB d OP xx
99: // ^ PC
100: // d の位置をスタックに積む
101: Push2(reg.pc - 2);
102: }
1.1 root 103: ExceptionDirect(HD647180::IntmapTRAP, 0x0000);
104: }
105:
106: // 分岐
107: void
108: MPU64180Device::Jump(uint16 addr)
109: {
110: reg.pc = addr;
111:
112: // 命令本体(オペランドを含まない)を16ビット左詰めにする。
113: // 分岐命令は1バイト命令か ED XX か DD/FD XX の2バイト命令しかないはず。
1.1.1.4 root 114: // 上位ワードは $0000。
115: uint32 info;
1.1 root 116: if (ops[0] == 0xed || ops[0] == 0xdd || ops[0] == 0xfd) {
1.1.1.4 root 117: info = (ops[0] << 8) | ops[1];
1.1 root 118: } else {
1.1.1.4 root 119: info = (ops[0] << 8);
1.1 root 120: }
121:
1.1.1.4 root 122: brhist.AddEntry(GetPPC(), addr, info);
1.1 root 123: }
124:
125: //
126: // 割り込み。
127: //
128: // TRAP 0000H
129: // NMI 0066H
130: // INT0 mode0 命令をデータバスからフェッチ
131: // INT0 mode1 0038H
132: // INT0 mode2 Vectored (上位8bit が I レジスタ、下位8bit はデータバス)
133: // INT1 Vectored (I + IL + 固定コード)
134: // INT2 Vectored (〃)
135: // 内蔵割り込み Vectored (〃)
136:
137: // 内部の割り込みマップ (Intmap) をアサートする。
138: void
139: MPU64180Device::AssertIntmap(int source)
140: {
141: uint32 oldmap;
142: uint32 srcmap;
143:
144: oldmap = intmap;
145: srcmap = 1U << (31 - source);
146: intmap |= srcmap;
147:
148: if ((oldmap ^ intmap) != 0) {
149: // 立ち上がりエッジでカウント
150: int_counter[source]++;
151:
152: // ホールトモード、スリープモードなら解除
153: if (__predict_false((int)opmode >= (int)OpMode::Halt)) {
154: if (opmode == OpMode::Halt) {
155: // ホールトモードなら解除するだけ。
156: // XXX 割り込みは一つ次の命令境界で処理されるけど、いいか?
157: opmode = OpMode::Normal;
158: } else {
159: // スリープモードなら通常モードに戻す。
160: EnterWakeup();
161: }
162: }
163: }
164: }
165:
166: // 内部の割り込みマップ (Intmap) をネゲートする。
167: void
168: MPU64180Device::NegateIntmap(int source)
169: {
170: uint32 oldmap;
171: uint32 srcmap;
172:
173: oldmap = intmap;
174: srcmap = 1U << (31 - source);
175: intmap &= ~srcmap;
176:
177: if ((oldmap ^ intmap) != 0) {
178: // 今は立ち下がりで何もすることはない。
179: }
180: }
181:
182: // INT0 信号線をアサートする。(PIO1 から呼ばれる)
183: void
184: MPU64180Device::AssertINT0()
185: {
186: AssertIntmap(HD647180::IntmapINT0);
187: }
188:
189: // INT0 信号線をネゲートする。
190: void
191: MPU64180Device::NegateINT0()
192: {
193: NegateIntmap(HD647180::IntmapINT0);
194: }
195:
1.1.1.5 root 196: // ASCIn 割り込みをアサート/ネゲートする。
197: // IEF1 はこちらで加味する。
198: void
199: MPU64180Device::ChangeASCIInt(uint n, bool asci_req)
200: {
201: uint32 map = HD647180::IntmapASCI(n);
202:
203: if ((asci_req && GetIEF1())) {
204: AssertIntmap(map);
205: } else {
206: NegateIntmap(map);
207: }
208: }
209:
1.1 root 210: // マスカブル割り込みを処理する。(命令境界で呼ばれる)
211: void
212: MPU64180Device::DoInterrupt()
213: {
214: // まず割り込み禁止。
215: ief1 = false;
216: ief2 = false;
217:
218: // 優先順位の最も高い割り込みを一つ選択。
219: assert(intmap != 0);
1.1.1.2 root 220: uint source = __builtin_clz(intmap);
1.1 root 221:
222: // TRAP はここに来ない。NMI は LUNA では未接続のため未実装。
223: assert(source != HD647180::IntmapTRAP);
224: assert(source != HD647180::IntmapNMI);
225:
226: if (source == HD647180::IntmapINT0) {
227: // INT0 はモードによって分岐方法が異なる。
228:
229: // ただし mode0 と mode2 は使われてないので未対応。
230: if (int0mode != 1) {
1.1.1.2 root 231: PANIC("INT0 on mode%u (NOT IMPLEMENTED)", int0mode);
1.1 root 232: }
233:
234: // mode1 は固定番地へ
1.1.1.2 root 235: Push2(reg.pc);
1.1 root 236: ExceptionDirect(source, 0x0038);
237: } else {
238: // 残りはすべてベクタ方式。
239:
1.1.1.2 root 240: Push2(reg.pc);
1.1 root 241: ExceptionVector(source);
242: }
243:
244: // XXX あとで見る
245: // HD64180.pdf, p45. Figure 2.7.7
246: CYCLE(11);
247: }
248:
249: // 例外によって new_addr に直接ジャンプする。
250: // (HD64180 系の用語では例外ではなくて割り込みだが)
251: // source は Intmap*。
252: void
253: MPU64180Device::ExceptionDirect(int source, uint32 new_addr)
254: {
255: // 例外発生とジャンプを記録。
1.1.1.7 ! root 256: last_vector = source;
1.1 root 257: brhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
258: exhist.AddEntry(GetPPC(), new_addr, 0x80000000 | source);
259:
260: reg.pc = new_addr;
261: }
262:
263: // 例外ごとに固有のベクタにジャンプする。
264: // (HD64180 系の用語では例外ではなくて割り込みだが)
265: // source は Intmap*。
266: void
267: MPU64180Device::ExceptionVector(int source)
268: {
269: // 固定コード
270: static uint16 vector_offset[] = {
271: 0, // 0:TRAP
272: 0, // 1:NMI
273: 0, // 2:INT0
274:
275: 0x00, // 3:INT1
276: 0x02, // 4:INT2
277: 0x12, // 5:Input Capture
278: 0x14, // 6:Output Compare
279: 0x16, // 7:Timer Overflow
280: 0x04, // 8:Timer0 (PRT0)
281: 0x06, // 9:Timer1 (PRT1)
282: 0x08, // 10:DMA0
283: 0x0a, // 11:DMA1
284: 0x0c, // 12:CSIO
285: 0x0e, // 13:ASCI0
286: 0x10, // 14:ASCI1
287: };
288:
289: // 例外からベクタアドレスを求める。ベクタアドレスは以下の構成。
290: //
291: // F E D C B A 9 8 7 6 5 4 3 2 1 0
292: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
293: // | I レジスタ | IL | 固定コード |
294: // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
295: assert(source < countof(vector_offset));
296: uint32 vec_addr = (reg_i << 8) | intvec_low | vector_offset[source];
297:
298: // 例外発生を記録。
1.1.1.7 ! root 299: last_vector = source;
1.1 root 300: brhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
301: exhist.AddEntry(GetPPC(), -1, 0x80000000 | source);
302:
303: // ジャンプ先を読み込む
1.1.1.2 root 304: uint32 new_addr = Read2(vec_addr);
1.1 root 305:
306: // ベクタジャンプを記録。
307: brhist.AddEntry(vec_addr, new_addr, -1);
308:
309: reg.pc = new_addr;
310: }
311:
312:
313: //
314: // hd64180flag
315: //
316:
317: // F レジスタの値を取得する
318: uint8
319: hd64180flag::Get() const
320: {
321: uint8 f = 0;
322:
323: if (IsS()) f |= HD64180::FlagS;
324: if (IsZ()) f |= HD64180::FlagZ;
325: if (b5) f |= 0x20;
326: if (IsH()) f |= HD64180::FlagH;
327: if (b3) f |= 0x08;
328: if (IsPV()) f |= HD64180::FlagPV;
329: if (IsN()) f |= HD64180::FlagN;
330: if (IsC()) f |= HD64180::FlagC;
331:
332: return f;
333: }
334:
335: // F レジスタに代入する
336: void
337: hd64180flag::Set(uint8 val)
338: {
339: SetS(val & HD64180::FlagS);
340: SetZ(val & HD64180::FlagZ);
341: b5 = (val & 0x20);
342: SetH(val & HD64180::FlagH);
343: b3 = (val & 0x08);
344: SetPV(val & HD64180::FlagPV);
345: SetN(val & HD64180::FlagN);
346: SetC(val & HD64180::FlagC);
347: }
348:
349: // fff (0..7) の条件が成立すれば true を返す。
350: bool
351: hd64180flag::IsCond(uint fff) const
352: {
353: switch (fff) {
354: case 0: return !IsZ(); // NZ
355: case 1: return IsZ(); // Z
356: case 2: return !IsC(); // NC
357: case 3: return IsC(); // C
358: case 4: return !IsPV(); // PO
359: case 5: return IsPV(); // PE
360: case 6: return !IsS(); // P
361: case 7: return IsS(); // M
362: default:
363: PANIC("invalid cond = %u", fff);
364: }
365: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.