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