|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // HD64180 演算部分
9: //
10:
11: #include "hd64180acc.h"
12:
13: /*static*/ inline uint32
14: hd64180acc::vflag_add(uint32 dst, uint32 src, uint32 res)
15: {
16: return (src ^ res) & (dst ^ res);
17: }
18:
19: /*static*/ inline uint32
20: hd64180acc::vflag_sub(uint32 dst, uint32 src, uint32 res)
21: {
22: return (src ^ dst) & (dst ^ res);
23: }
24:
25: /*static*/ inline uint32
26: hd64180acc::hflag_add(uint32 dst, uint32 src)
27: {
28: return (dst & 0x0f) + (src & 0x0f);
29: }
30:
31: /*static*/ inline uint32
32: hd64180acc::hflag_sub(uint32 dst, uint32 src)
33: {
34: return (dst & 0x0f) - (src & 0x0f);
35: }
36:
37: // LD A,I、LD A,R 命令のフラグ変化。
38: // S:* Z:* H:0 P/V:IEF2 N:0 C:-
39: uint32
40: hd64180acc::ld_ir8(uint32 src)
41: {
42: // P/V (IEF2) は呼び出し側で行う。
43:
44: S = Z = src;
45: SetH(false);
46: SetN(false);
47: return Z;
48: }
49:
50: // save_c が true なら C を変更しない。
51: // S:* Z:* H:* V:* N:0 C:*/-
52: uint32
53: hd64180acc::add_8(uint32 dst, uint32 src, bool save_c)
54: {
55: if (save_c) {
56: Z = dst + src;
57: } else {
58: CZ = dst + src;
59: }
60: S = Z;
61: H = hflag_add(dst, src);
62: LetV(vflag_add(dst, src, Z));
63: SetN(false);
64:
65: return (uint8)Z;
66: }
67:
68: // save_c が true なら C を変更しない。
69: // S:* Z:* H:* V:* N:0 C:*/-
70: uint32
71: hd64180acc::sub_8(uint32 dst, uint32 src, bool save_c)
72: {
73: if (save_c) {
74: Z = dst - src;
75: } else {
76: CZ = dst - src;
77: }
78: S = Z;
79: H = hflag_sub(dst, src);
80: LetV(vflag_sub(dst, src, Z));
81: SetN(true);
82:
83: return (uint8)Z;
84: }
85:
86: // S:* Z:* H:* V:* N:0 C:*
87: uint32
88: hd64180acc::adc_8(uint32 dst, uint32 src)
89: {
90: uint32 cin = IsC() ? 1 : 0;
91: uint32 res = dst + src + cin;
92:
93: CZ = res;
94: S = res;
95: LetV(vflag_add(dst, src, res));
96: H = hflag_add(dst, src);
97: H |= hflag_add(H, cin);
98: SetN(false);
99:
100: return Z;
101: }
102:
103: // S:* Z:* H:* V:* N:0 C:*
104: uint32
105: hd64180acc::sbc_8(uint32 dst, uint32 src)
106: {
107: uint32 cin = IsC() ? 1 : 0;
108: uint32 res = dst - src - cin;
109:
110: CZ = res;
111: S = res;
112: LetV(vflag_sub(dst, src, res));
113: H = hflag_sub(dst, src);
114: H |= hflag_sub(H, cin);
115: SetN(true);
116:
117: return Z;
118: }
119:
120: // S:- Z:- H:X PV:- N:0 C:*
121: uint32
122: hd64180acc::add_16(uint32 dst, uint32 src)
123: {
124: uint32 res = dst + src;
125: C = res >> 16;
126: SetN(false);
127: // XXX H は不定
128:
129: return res;
130: }
131:
132: // S:* Z:* H:X V:* N:0 C:*
133: uint32
134: hd64180acc::adc_16(uint32 dst, uint32 src)
135: {
136: // V のために2回に分けて計算しないといけない?
137: uint32 res = dst + src;
138: uint32 v = vflag_add(dst, src, res);
139:
140: dst = res;
141: src = IsC() ? 1 : 0;
142: res = dst + src;
143: v |= vflag_add(dst, src, res);
144:
145: LetV((uint32)(v >> 8));
146:
147: // C, S, Z は 16bit が対象でいい?
148: C = res >> 16;
149: S = res >> 8;
150: Z = res | S;
151:
152: SetN(false);
153:
154: // XXX H は本当は不定
155:
156: return res;
157: }
158:
159: // S:* Z:* H:X V:* N:1 C:*
160: uint32
161: hd64180acc::sbc_16(uint32 dst, uint32 src)
162: {
163: // V のために2回に分けて計算しないといけない?
164: uint32 res = dst - src;
165: uint32 v = vflag_sub(dst, src, res);
166:
167: dst = res;
168: src = IsC() ? 1 : 0;
169: res = dst - src;
170: v |= vflag_sub(dst, src, res);
171:
172: LetV((uint32)(v >> 8));
173:
174: // C, S, Z は 16bit が対象でいい?
175: C = res >> 16;
176: S = res >> 8;
177: Z = res | S;
178:
179: SetN(true);
180:
181: // XXX H は本当は不定
182:
183: return res;
184: }
185:
186: // BIT 命令
187: // S:X Z:* H:1 PV:X N:0 C:-
188: void
189: hd64180acc::bit_8(uint b, uint32 src)
190: {
191: Z = src & (1U << b);
192: SetH(true);
193: SetN(false);
194: // XXX S, P(V) は本当は不定
195: }
196:
197: // IN A,(n) 命令のフラグ変化。他からも色々呼ばれる。
198: // S:* Z:* H:0 P:* N:0 C:-
199: uint32
200: hd64180acc::in_8(uint32 src)
201: {
202: S = Z = src;
203: SetN(false);
204: SetH(false);
205: LetP(Z);
206: return Z;
207: }
208:
209: // OTIM/OTDM 命令のフラグ変化。
210: // 戻り値は演算後の B レジスタの値。
211: // HD64180.pdf p.110
212: // S:* Z:* H:* P:* N:* C:*
213: uint32
214: hd64180acc::outm_8(uint32 src, uint32 breg)
215: {
216: CZ = breg - 1;
217: S = Z;
218: H = hflag_sub(breg, 1);
219: LetP(Z); // 減算後の B のパリティ
220: N = (src & 0x80); // (HL) の MSB
221:
222: return Z;
223: }
224:
225: // S:* Z:* H:1 P:* N:0 C:0
226: uint32
227: hd64180acc::and_8(uint32 dst, uint32 src)
228: {
229: uint32 res;
230: SetC(false);
231: res = in_8(dst & src);
232: SetH(true); // これだけ H はセット
233: return res;
234: }
235:
236: // S:* Z:* H:0 P:* N:0 C:0
237: uint32
238: hd64180acc::or_8(uint32 dst, uint32 src)
239: {
240: SetC(false);
241: return in_8(dst | src);
242: }
243:
244: // S:* Z:* H:0 P:* N:0 C:0
245: uint32
246: hd64180acc::xor_8(uint32 dst, uint32 src)
247: {
248: SetC(false);
249: return in_8(dst ^ src);
250: }
251:
252: // S:* Z:* H:1 P:* N:0 C:0
253: void
254: hd64180acc::tst_8(uint32 dst, uint32 src)
255: {
256: in_8(dst & src);
257: SetH(true);
258: SetC(false);
259: }
260:
261: // S:* Z:* H:0 P:* N:0 C:*
262: uint32
263: hd64180acc::sla_8(uint32 src)
264: {
265: CZ = src << 1;
266: return in_8(Z);
267: }
268:
269: // S:* Z:* H:0 P:* N:0 C:*
270: uint32
271: hd64180acc::sra_8(uint32 src)
272: {
273: C = src;
274: Z = (src >> 1);
275: Z |= src & 0x80;
276: return in_8(Z);
277: }
278:
279: // S:* Z:* H:0 P:* N:0 C:*
280: uint32
1.1.1.3 ! root 281: hd64180acc::sll_8(uint32 src)
! 282: {
! 283: // bit0 に %1 が入るようだ
! 284: // http://www.z80.info/z80sflag.htm
! 285: CZ = (src << 1) | 1;
! 286: return in_8(Z);
! 287: }
! 288:
! 289: // S:* Z:* H:0 P:* N:0 C:*
! 290: uint32
1.1 root 291: hd64180acc::srl_8(uint32 src)
292: {
293: C = src;
294: Z = src >> 1;
295: return in_8(Z);
296: }
297:
298: // S Z H P N C
299: // RLA - - 0 - 0 * : rl_8()
300: // RL r * * 0 P 0 * : in_8(rl_8())
301: // RLD * * 0 P 0 - : in_8()
302:
303: uint32
304: hd64180acc::rl_8(uint32 src)
305: {
306: src <<= 1;
307: if (IsC()) {
308: src |= 0x01;
309: }
310: C = src >> 8;
311:
312: SetN(false);
313: SetH(false);
314:
315: return (uint8)src;
316: }
317:
318: uint32
319: hd64180acc::rlc_8(uint32 src)
320: {
321: src <<= 1;
322: if ((src & 0x100)) {
323: src |= 0x01;
324: }
325: C = src >> 8;
326:
327: SetN(false);
328: SetH(false);
329:
330: return (uint8)src;
331: }
332:
333: uint32
334: hd64180acc::rr_8(uint32 src)
335: {
336: src = (uint8)src;
337: if (IsC()) {
338: src |= 0x100;
339: }
340: C = src;
341: src >>= 1;
342:
343: SetN(false);
344: SetH(false);
345:
346: return (uint8)src;
347: }
348:
349: uint32
350: hd64180acc::rrc_8(uint32 src)
351: {
352: C = src;
353: src = (uint8)src;
354: src |= (C << 8);
355: src >>= 1;
356:
357: SetN(false);
358: SetH(false);
359:
360: return (uint8)src;
361: }
1.1.1.2 root 362:
363: uint32
364: hd64180acc::daa_8(uint32 src)
365: {
366: uint32 ah;
367: uint32 al;
368: uint32 b;
369: uint32 res;
370:
371: if (IsN() == false) {
372: bool tmpC = IsC(); // 入力時の状態
373: bool tmpH = IsH();
374:
375: bool resC = IsC(); // 出力用。C は入力と内部演算の和
376: bool resH; // 出力用。H は内部演算のみの和
377:
378: // 下位桁
379: ah = src >> 4;
380: al = src & 0xf;
381: if (al >= 0x0a || IsH()) {
382: b = 0x06;
383: } else {
384: b = 0;
385: }
386: src = add_8(src, b);
387: resC |= IsC();
388: resH = IsH();
389:
390: // 上位桁
391: ah = src >> 4;
392: al = src & 0xf;
393: if (ah >= 0x0a || tmpC) {
394: b = 0x60;
395:
396: // XXX 入力が 9A-9F で H=1 C=0 の時、
397: // 下位桁を補正して(6を足して) 上位桁が A になるのに、
398: // HD64180 ではこれを補正してないようだ。
399: if (0xa0 <= src && src < 0xa6 && tmpH && tmpC == false) {
400: b = 0;
401: }
402: } else {
403: b = 0;
404:
405: // XXX 入力が FA-FF で C=0 の時、
406: // 下位桁を補正して(6 を足して) C=1 00-05 に繰り上がるだけの
407: // はずが、HD64180 では 60 も足してしまうようだ。
408: if (IsC() && ah == 0x00 && tmpC == false) {
409: b = 0x60;
410: }
411: }
412: res = add_8(src, b);
413: resC |= IsC();
414: resH |= IsH();
415:
416: SetH(resH);
417: SetC(resC);
418: } else {
419: // N==1 (減算) 側は跡形なく動作が違う。
420: // 意味はさっぱり分からんけどとりあえず実機と同じ動作。
421:
422: bool resC = IsC();
423: b = 0;
424: if (IsH()) {
425: b += 0x06;
426: if (src < 0x06) {
427: resC = true;
428: }
429: }
430: if (IsC()) {
431: b += 0x60;
432: }
433: res = sub_8(src, b);
434:
435: SetC(resC);
436: }
437:
438: // P/V フラグは P
439: LetP(res);
440:
441: return res;
442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.