1 // license:BSD-3-Clause
2 // copyright-holders:Farfetch'd, R. Belmont
3 /*
4 * CMPC: What happens to _S flag if the strings are identical?
5 * I suppose that it will be cleared. And is it set or cleared
6 * when the first one is a substring of the second? I suppose
7 * cleared (since _S should be (src > dst))
8 * MOVC: Why MOVCS does not exist in downward version?
9 * SHCHDB / SHCHDH: R27 is filled with the offset from the start or from the end?
10 *
11 * Strange stuff:
12 * SCHC opcodes does *not* modify _Z flag as stated in V60 manual:
13 * they do the opposite (set if not found, reset if found)
14 */
15
16 #define F7AEND() \
17 return m_amlength1 + m_amlength2 + 4;
18
19 #define F7BEND() \
20 return m_amlength1 + m_amlength2 + 3;
21
22 #define F7CEND() \
23 return m_amlength1 + m_amlength2 + 3;
24
25 #define F7BCREATEBITMASK(x) \
26 x = ((1 << (x)) - 1)
27
28 #define F7CCREATEBITMASK(x) \
29 x = ((1 << (x)) - 1)
30
F7aDecodeOperands(am_func DecodeOp1,uint8_t dim1,am_func DecodeOp2,uint8_t dim2)31 void v60_device::F7aDecodeOperands(am_func DecodeOp1, uint8_t dim1, am_func DecodeOp2, uint8_t dim2)
32 {
33 uint8_t appb;
34 // Decode first operand
35 m_moddim = dim1;
36 m_modm = m_subop & 0x40;
37 m_modadd = PC + 2;
38 m_amlength1 = (this->*DecodeOp1)();
39 m_flag1 = m_amflag;
40 m_op1 = m_amout;
41
42 // Decode length
43 appb = OpRead8(PC + 2 + m_amlength1);
44 if (appb & 0x80)
45 m_lenop1 = m_reg[appb & 0x1F];
46 else
47 m_lenop1 = appb;
48
49 // Decode second operand
50 m_moddim = dim2;
51 m_modm = m_subop & 0x20;
52 m_modadd = PC + 3 + m_amlength1;
53 m_amlength2 = (this->*DecodeOp2)();
54 m_flag2 = m_amflag;
55 m_op2 = m_amout;
56
57 // Decode length
58 appb = OpRead8(PC + 3 + m_amlength1 + m_amlength2);
59 if (appb & 0x80)
60 m_lenop2 = m_reg[appb & 0x1F];
61 else
62 m_lenop2 = appb;
63 }
64
F7bDecodeFirstOperand(am_func DecodeOp1,uint8_t dim1)65 void v60_device::F7bDecodeFirstOperand(am_func DecodeOp1, uint8_t dim1)
66 {
67 uint8_t appb;
68 // Decode first operand
69 m_moddim = dim1;
70 m_modm = m_subop & 0x40;
71 m_modadd = PC + 2;
72 m_amlength1 = (this->*DecodeOp1)();
73 m_flag1 = m_amflag;
74 m_op1 = m_amout;
75
76 // Decode ext
77 appb = OpRead8(PC + 2 + m_amlength1);
78 if (appb & 0x80)
79 m_lenop1 = m_reg[appb & 0x1F];
80 else
81 m_lenop1 = appb;
82 }
83
84
F7bWriteSecondOperand(uint8_t dim2)85 void v60_device::F7bWriteSecondOperand(uint8_t dim2)
86 {
87 m_moddim = dim2;
88 m_modm = m_subop & 0x20;
89 m_modadd = PC + 3 + m_amlength1;
90 m_amlength2 = WriteAM();
91 }
92
93
F7bDecodeOperands(am_func DecodeOp1,uint8_t dim1,am_func DecodeOp2,uint8_t dim2)94 void v60_device::F7bDecodeOperands(am_func DecodeOp1, uint8_t dim1, am_func DecodeOp2, uint8_t dim2)
95 {
96 // Decode first operand
97 F7bDecodeFirstOperand(DecodeOp1, dim1);
98 m_bamoffset1 = m_bamoffset;
99
100 // Decode second operand
101 m_moddim = dim2;
102 m_modm = m_subop & 0x20;
103 m_modadd = PC + 3 + m_amlength1;
104 m_amlength2 = (this->*DecodeOp2)();
105 m_flag2 = m_amflag;
106 m_op2 = m_amout;
107 m_bamoffset2 = m_bamoffset;
108 }
109
F7cDecodeOperands(am_func DecodeOp1,uint8_t dim1,am_func DecodeOp2,uint8_t dim2)110 void v60_device::F7cDecodeOperands(am_func DecodeOp1, uint8_t dim1, am_func DecodeOp2, uint8_t dim2)
111 {
112 uint8_t appb;
113 // Decode first operand
114 m_moddim = dim1;
115 m_modm = m_subop & 0x40;
116 m_modadd = PC + 2;
117 m_amlength1 = (this->*DecodeOp1)();
118 m_flag1 = m_amflag;
119 m_op1 = m_amout;
120
121 // Decode second operand
122 m_moddim = dim2;
123 m_modm = m_subop & 0x20;
124 m_modadd = PC + 2 + m_amlength1;
125 m_amlength2 = (this->*DecodeOp2)();
126 m_flag2 = m_amflag;
127 m_op2 = m_amout;
128
129 // Decode ext
130 appb = OpRead8(PC + 2 + m_amlength1 + m_amlength2);
131 if (appb & 0x80)
132 m_lenop1 = m_reg[appb & 0x1F];
133 else
134 m_lenop1 = appb;
135 }
136
137 #define F7CLOADOP1BYTE(appb) \
138 if (m_flag1) \
139 appb = (uint8_t)(m_reg[m_op1]&0xFF); \
140 else \
141 appb = m_program->read_byte(m_op1);
142
143 #define F7CLOADOP2BYTE(appb) \
144 if (m_flag2) \
145 appb = (uint8_t)(m_reg[m_op2]&0xFF); \
146 else \
147 appb = m_program->read_byte(m_op2);
148
149
150 #define F7CSTOREOP2BYTE() \
151 if (m_flag2) \
152 SETREG8(m_reg[m_op2], appb); \
153 else \
154 m_program->write_byte(m_op2, appb);
155
156 #define F7CSTOREOP2HALF() \
157 if (m_flag2) \
158 SETREG16(m_reg[m_op2], apph); \
159 else \
160 m_program->write_word_unaligned(m_op2, apph);
161
opCMPSTRB(uint8_t bFill,uint8_t bStop)162 uint32_t v60_device::opCMPSTRB(uint8_t bFill, uint8_t bStop)
163 {
164 uint32_t i, dest;
165 uint8_t c1, c2;
166
167 F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
168
169 // Filling
170 if (bFill)
171 {
172 if (m_lenop1 < m_lenop2)
173 {
174 for (i = m_lenop1; i < m_lenop2; i++)
175 m_program->write_byte(m_op1 + i,(uint8_t)R26);
176 }
177 else if (m_lenop2 < m_lenop1)
178 {
179 for (i = m_lenop2; i < m_lenop1; i++)
180 m_program->write_byte(m_op2 + i,(uint8_t)R26);
181 }
182 }
183
184 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
185
186 _Z = 0;
187 _S = 0;
188 if (bStop) _CY = 1;
189
190 for (i = 0; i < dest; i++)
191 {
192 c1 = m_program->read_byte(m_op1 + i);
193 c2 = m_program->read_byte(m_op2 + i);
194
195 if (c1 > c2)
196 {
197 _S = 1; break;
198 }
199 else if (c2 > c1)
200 {
201 _S = 0; break;
202 }
203
204 if (bStop)
205 if (c1 == (uint8_t)R26 || c2 == (uint8_t)R26)
206 {
207 _CY = 0;
208 break;
209 }
210 }
211
212 R28 = m_lenop1 + i;
213 R27 = m_lenop2 + i;
214
215 if (i == dest)
216 {
217 if (m_lenop1 > m_lenop2)
218 _S = 1;
219 else if (m_lenop2 > m_lenop1)
220 _S = 0;
221 else
222 _Z = 1;
223 }
224
225 F7AEND();
226 }
227
opCMPSTRH(uint8_t bFill,uint8_t bStop)228 uint32_t v60_device::opCMPSTRH(uint8_t bFill, uint8_t bStop)
229 {
230 uint32_t i, dest;
231 uint16_t c1, c2;
232
233 F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
234
235 // Filling
236 if (bFill)
237 {
238 if (m_lenop1 < m_lenop2)
239 {
240 for (i = m_lenop1; i < m_lenop2; i++)
241 m_program->write_word_unaligned(m_op1 + i * 2,(uint16_t)R26);
242 }
243 else if (m_lenop2 < m_lenop1)
244 {
245 for (i = m_lenop2; i < m_lenop1; i++)
246 m_program->write_word_unaligned(m_op2 + i * 2,(uint16_t)R26);
247 }
248 }
249
250 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
251
252 _Z = 0;
253 _S = 0;
254 if (bStop) _CY = 1;
255
256 for (i = 0; i < dest; i++)
257 {
258 c1 = m_program->read_word_unaligned(m_op1 + i * 2);
259 c2 = m_program->read_word_unaligned(m_op2 + i * 2);
260
261 if (c1 > c2)
262 {
263 _S = 1; break;
264 }
265 else if (c2 > c1)
266 {
267 _S = 0; break;
268 }
269
270 if (bStop)
271 if (c1 == (uint16_t)R26 || c2 == (uint16_t)R26)
272 {
273 _CY = 0;
274 break;
275 }
276 }
277
278 R28 = m_lenop1 + i * 2;
279 R27 = m_lenop2 + i * 2;
280
281 if (i == dest)
282 {
283 if (m_lenop1 > m_lenop2)
284 _S = 1;
285 else if (m_lenop2 > m_lenop1)
286 _S = 0;
287 else
288 _Z = 1;
289 }
290
291 F7AEND();
292 }
293
294
295
opMOVSTRUB(uint8_t bFill,uint8_t bStop)296 uint32_t v60_device::opMOVSTRUB(uint8_t bFill, uint8_t bStop) /* TRUSTED (0, 0) (1, 0) */
297 {
298 uint32_t i, dest;
299 uint8_t c1;
300
301 // if (bStop)
302 // {
303 // int a = 1;
304 // }
305
306 F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
307
308 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
309
310 for (i = 0; i < dest; i++)
311 {
312 m_program->write_byte(m_op2 + i,(c1 = m_program->read_byte(m_op1 + i)));
313
314 if (bStop && c1 == (uint8_t)R26)
315 break;
316 }
317
318 R28 = m_op1 + i;
319 R27 = m_op2 + i;
320
321 if (bFill && m_lenop1 < m_lenop2)
322 {
323 for (;i < m_lenop2; i++)
324 m_program->write_byte(m_op2 + i,(uint8_t)R26);
325
326 R27 = m_op2 + i;
327 }
328
329
330 F7AEND();
331 }
332
opMOVSTRDB(uint8_t bFill,uint8_t bStop)333 uint32_t v60_device::opMOVSTRDB(uint8_t bFill, uint8_t bStop)
334 {
335 uint32_t i, dest;
336 uint8_t c1;
337
338 F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0);
339
340 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
341
342 for (i = 0; i < dest; i++)
343 {
344 m_program->write_byte(m_op2 + (dest - i - 1),(c1 = m_program->read_byte(m_op1 + (dest - i - 1))));
345
346 if (bStop && c1 == (uint8_t)R26)
347 break;
348 }
349
350 R28 = m_op1 + (m_lenop1 - i - 1);
351 R27 = m_op2 + (m_lenop2 - i - 1);
352
353 if (bFill && m_lenop1 < m_lenop2)
354 {
355 for (;i < m_lenop2; i++)
356 m_program->write_byte(m_op2 + dest + (m_lenop2 - i - 1),(uint8_t)R26);
357
358 R27 = m_op2 + (m_lenop2 - i - 1);
359 }
360
361
362 F7AEND();
363 }
364
365
opMOVSTRUH(uint8_t bFill,uint8_t bStop)366 uint32_t v60_device::opMOVSTRUH(uint8_t bFill, uint8_t bStop) /* TRUSTED (0, 0) (1, 0) */
367 {
368 uint32_t i, dest;
369 uint16_t c1;
370
371 // if (bStop)
372 // { int a = 1; }
373
374 F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1);
375
376 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
377
378 for (i = 0; i < dest; i++)
379 {
380 m_program->write_word_unaligned(m_op2 + i * 2,(c1 = m_program->read_word_unaligned(m_op1 + i * 2)));
381
382 if (bStop && c1 == (uint16_t)R26)
383 break;
384 }
385
386 R28 = m_op1 + i * 2;
387 R27 = m_op2 + i * 2;
388
389 if (bFill && m_lenop1 < m_lenop2)
390 {
391 for (;i < m_lenop2; i++)
392 m_program->write_word_unaligned(m_op2 + i * 2,(uint16_t)R26);
393
394 R27 = m_op2 + i * 2;
395 }
396
397 F7AEND();
398 }
399
opMOVSTRDH(uint8_t bFill,uint8_t bStop)400 uint32_t v60_device::opMOVSTRDH(uint8_t bFill, uint8_t bStop)
401 {
402 uint32_t i, dest;
403 uint16_t c1;
404
405 // if (bFill | bStop)
406 // { int a = 1; }
407
408 F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1);
409
410 // if (m_lenop1 != m_lenop2)
411 // { int a = 1; }
412
413 dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2);
414
415 for (i = 0; i < dest; i++)
416 {
417 m_program->write_word_unaligned(m_op2 + (dest - i - 1) * 2,(c1 = m_program->read_word_unaligned(m_op1 + (dest - i - 1) * 2)));
418
419 if (bStop && c1 == (uint16_t)R26)
420 break;
421 }
422
423 R28 = m_op1 + (m_lenop1 - i - 1) * 2;
424 R27 = m_op2 + (m_lenop2 - i - 1) * 2;
425
426 if (bFill && m_lenop1 < m_lenop2)
427 {
428 for (;i < m_lenop2; i++)
429 m_program->write_word_unaligned(m_op2 + (m_lenop2 - i - 1) * 2,(uint16_t)R26);
430
431 R27 = m_op2 + (m_lenop2 - i - 1) * 2;
432 }
433
434 F7AEND();
435 }
436
opSEARCHUB(uint8_t bSearch)437 uint32_t v60_device::opSEARCHUB(uint8_t bSearch)
438 {
439 uint8_t appb;
440 uint32_t i;
441
442 F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0);
443
444 for (i = 0; i < m_lenop1; i++)
445 {
446 appb = (m_program->read_byte(m_op1 + i) == (uint8_t)m_op2);
447 if ((bSearch && appb) || (!bSearch && !appb))
448 break;
449 }
450
451 R28 = m_op1 + i;
452 R27 = i;
453
454 // This is the opposite as stated in V60 manual...
455 if (i != m_lenop1)
456 _Z = 0;
457 else
458 _Z = 1;
459
460 F7BEND();
461 }
462
opSEARCHUH(uint8_t bSearch)463 uint32_t v60_device::opSEARCHUH(uint8_t bSearch)
464 {
465 uint8_t appb;
466 uint32_t i;
467
468 F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1);
469
470 for (i = 0; i < m_lenop1; i++)
471 {
472 appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (uint16_t)m_op2);
473 if ((bSearch && appb) || (!bSearch && !appb))
474 break;
475 }
476
477 R28 = m_op1 + i * 2;
478 R27 = i;
479
480 if (i != m_lenop1)
481 _Z = 0;
482 else
483 _Z = 1;
484
485 F7BEND();
486 }
487
opSEARCHDB(uint8_t bSearch)488 uint32_t v60_device::opSEARCHDB(uint8_t bSearch)
489 {
490 uint8_t appb;
491 int32_t i;
492
493 F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0);
494
495 for (i = m_lenop1; i >= 0; i--)
496 {
497 appb = (m_program->read_byte(m_op1 + i) == (uint8_t)m_op2);
498 if ((bSearch && appb) || (!bSearch && !appb))
499 break;
500 }
501
502 R28 = m_op1 + i;
503 R27 = i;
504
505 // This is the opposite as stated in V60 manual...
506 if ((uint32_t)i != m_lenop1)
507 _Z = 0;
508 else
509 _Z = 1;
510
511 F7BEND();
512 }
513
opSEARCHDH(uint8_t bSearch)514 uint32_t v60_device::opSEARCHDH(uint8_t bSearch)
515 {
516 uint8_t appb;
517 int32_t i;
518
519 F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1);
520
521 for (i = m_lenop1 - 1; i >= 0; i--)
522 {
523 appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (uint16_t)m_op2);
524 if ((bSearch && appb) || (!bSearch && !appb))
525 break;
526 }
527
528 R28 = m_op1 + i * 2;
529 R27 = i;
530
531 if ((uint32_t)i != m_lenop1)
532 _Z = 0;
533 else
534 _Z = 1;
535
536 F7BEND();
537 }
538
539
opSCHCUB()540 uint32_t v60_device::opSCHCUB() { return opSEARCHUB(1); }
opSCHCUH()541 uint32_t v60_device::opSCHCUH() { return opSEARCHUH(1); }
opSCHCDB()542 uint32_t v60_device::opSCHCDB() { return opSEARCHDB(1); }
opSCHCDH()543 uint32_t v60_device::opSCHCDH() { return opSEARCHDH(1); }
opSKPCUB()544 uint32_t v60_device::opSKPCUB() { return opSEARCHUB(0); }
opSKPCUH()545 uint32_t v60_device::opSKPCUH() { return opSEARCHUH(0); }
opSKPCDB()546 uint32_t v60_device::opSKPCDB() { return opSEARCHDB(0); }
opSKPCDH()547 uint32_t v60_device::opSKPCDH() { return opSEARCHDH(0); }
548
opCMPCB()549 uint32_t v60_device::opCMPCB() { return opCMPSTRB(0, 0); }
opCMPCH()550 uint32_t v60_device::opCMPCH() { return opCMPSTRH(0, 0); }
opCMPCFB()551 uint32_t v60_device::opCMPCFB() { return opCMPSTRB(1, 0); }
opCMPCFH()552 uint32_t v60_device::opCMPCFH() { return opCMPSTRH(1, 0); }
opCMPCSB()553 uint32_t v60_device::opCMPCSB() { return opCMPSTRB(0, 1); }
opCMPCSH()554 uint32_t v60_device::opCMPCSH() { return opCMPSTRH(0, 1); }
555
opMOVCUB()556 uint32_t v60_device::opMOVCUB() { return opMOVSTRUB(0, 0); }
opMOVCUH()557 uint32_t v60_device::opMOVCUH() { return opMOVSTRUH(0, 0); }
opMOVCFUB()558 uint32_t v60_device::opMOVCFUB() { return opMOVSTRUB(1, 0); }
opMOVCFUH()559 uint32_t v60_device::opMOVCFUH() { return opMOVSTRUH(1, 0); }
opMOVCSUB()560 uint32_t v60_device::opMOVCSUB() { return opMOVSTRUB(0, 1); }
opMOVCSUH()561 uint32_t v60_device::opMOVCSUH() { return opMOVSTRUH(0, 1); }
562
opMOVCDB()563 uint32_t v60_device::opMOVCDB() { return opMOVSTRDB(0, 0); }
opMOVCDH()564 uint32_t v60_device::opMOVCDH() { return opMOVSTRDH(0, 0); }
opMOVCFDB()565 uint32_t v60_device::opMOVCFDB() { return opMOVSTRDB(1, 0); }
opMOVCFDH()566 uint32_t v60_device::opMOVCFDH() { return opMOVSTRDH(1, 0); }
567
opEXTBFZ()568 uint32_t v60_device::opEXTBFZ() /* TRUSTED */
569 {
570 F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
571
572 F7BCREATEBITMASK(m_lenop1);
573
574 m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
575
576 F7bWriteSecondOperand(2);
577
578 F7BEND();
579 }
580
opEXTBFS()581 uint32_t v60_device::opEXTBFS() /* TRUSTED */
582 {
583 F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
584
585 F7BCREATEBITMASK(m_lenop1);
586
587 m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
588 if (m_modwritevalw & ((m_lenop1 + 1) >> 1))
589 m_modwritevalw |= ~m_lenop1;
590
591 F7bWriteSecondOperand(2);
592
593 F7BEND();
594 }
595
opEXTBFL()596 uint32_t v60_device::opEXTBFL()
597 {
598 uint32_t appw;
599
600 F7bDecodeFirstOperand(&v60_device::BitReadAM, 11);
601
602 appw = m_lenop1;
603 F7BCREATEBITMASK(m_lenop1);
604
605 m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1;
606 m_modwritevalw <<= 32 - appw;
607
608 F7bWriteSecondOperand(2);
609
610 F7BEND();
611 }
612
opSCHBS(uint32_t bSearch1)613 uint32_t v60_device::opSCHBS(uint32_t bSearch1)
614 {
615 uint32_t i, data;
616 uint32_t offset;
617
618 F7bDecodeFirstOperand(&v60_device::BitReadAMAddress, 10);
619
620 // Read first uint8_t
621 m_op1 += m_bamoffset / 8;
622 data = m_program->read_byte(m_op1);
623 offset = m_bamoffset & 7;
624
625 // Scan bitstring
626 for (i = 0; i < m_lenop1; i++)
627 {
628 // Update the work register
629 R28 = m_op1;
630
631 // There is a 0 / 1 at current offset?
632 if ((bSearch1 && (data&(1 << offset))) ||
633 (!bSearch1 && !(data&(1 << offset))))
634 break;
635
636 // Next bit please
637 offset++;
638 if (offset == 8)
639 {
640 // Next uint8_t please
641 offset = 0;
642 m_op1++;
643 data = m_program->read_byte(m_op1);
644 }
645 }
646
647 // Set zero if bit not found
648 _Z = (i == m_lenop1);
649
650 // Write to destination the final offset
651 m_modwritevalw = i;
652 F7bWriteSecondOperand(2);
653
654 F7BEND();
655 }
656
opSCH0BSU()657 uint32_t v60_device::opSCH0BSU() { return opSCHBS(0); }
opSCH1BSU()658 uint32_t v60_device::opSCH1BSU() { return opSCHBS(1); }
659
opINSBFR()660 uint32_t v60_device::opINSBFR()
661 {
662 uint32_t appw;
663 F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11);
664
665 F7CCREATEBITMASK(m_lenop1);
666
667 m_op2 += m_bamoffset / 8;
668 appw = m_program->read_dword_unaligned(m_op2);
669 m_bamoffset &= 7;
670
671 appw &= ~(m_lenop1 << m_bamoffset);
672 appw |= (m_lenop1 & m_op1) << m_bamoffset;
673
674 m_program->write_dword_unaligned(m_op2, appw);
675
676 F7CEND();
677 }
678
opINSBFL()679 uint32_t v60_device::opINSBFL()
680 {
681 uint32_t appw;
682 F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11);
683
684 m_op1 >>= (32 - m_lenop1);
685
686 F7CCREATEBITMASK(m_lenop1);
687
688 m_op2 += m_bamoffset / 8;
689 appw = m_program->read_dword_unaligned(m_op2);
690 m_bamoffset &= 7;
691
692 appw &= ~(m_lenop1 << m_bamoffset);
693 appw |= (m_lenop1 & m_op1) << m_bamoffset;
694
695 m_program->write_dword_unaligned(m_op2, appw);
696
697 F7CEND();
698 }
699
opMOVBSD()700 uint32_t v60_device::opMOVBSD()
701 {
702 uint32_t i;
703 uint8_t srcdata, dstdata;
704
705 F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10);
706
707 // if (m_lenop1 != 1)
708 // { int a = 1; }
709
710 m_bamoffset1 += m_lenop1 - 1;
711 m_bamoffset2 += m_lenop1 - 1;
712
713 m_op1 += m_bamoffset1 / 8;
714 m_op2 += m_bamoffset2 / 8;
715
716 m_bamoffset1 &= 7;
717 m_bamoffset2 &= 7;
718
719 srcdata = m_program->read_byte(m_op1);
720 dstdata = m_program->read_byte(m_op2);
721
722 for (i = 0; i < m_lenop1; i++)
723 {
724 // Update work registers
725 R28 = m_op1;
726 R27 = m_op2;
727
728 dstdata &= ~(1 << m_bamoffset2);
729 dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2;
730
731 if (m_bamoffset1 == 0)
732 {
733 m_bamoffset1 = 8;
734 m_op1--;
735 srcdata = m_program->read_byte(m_op1);
736 }
737 if (m_bamoffset2 == 0)
738 {
739 m_program->write_byte(m_op2, dstdata);
740 m_bamoffset2 = 8;
741 m_op2--;
742 dstdata = m_program->read_byte(m_op2);
743 }
744
745 m_bamoffset1--;
746 m_bamoffset2--;
747 }
748
749 // Flush of the final data
750 if (m_bamoffset2 != 7)
751 m_program->write_byte(m_op2, dstdata);
752
753 F7BEND();
754 }
755
opMOVBSU()756 uint32_t v60_device::opMOVBSU()
757 {
758 uint32_t i;
759 uint8_t srcdata, dstdata;
760
761 F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10);
762
763 m_op1 += m_bamoffset1 / 8;
764 m_op2 += m_bamoffset2 / 8;
765
766 m_bamoffset1 &= 7;
767 m_bamoffset2 &= 7;
768
769 srcdata = m_program->read_byte(m_op1);
770 dstdata = m_program->read_byte(m_op2);
771
772 for (i = 0; i < m_lenop1; i++)
773 {
774 // Update work registers
775 R28 = m_op1;
776 R27 = m_op2;
777
778 dstdata &= ~(1 << m_bamoffset2);
779 dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2;
780
781 m_bamoffset1++;
782 m_bamoffset2++;
783 if (m_bamoffset1 == 8)
784 {
785 m_bamoffset1 = 0;
786 m_op1++;
787 srcdata = m_program->read_byte(m_op1);
788 }
789 if (m_bamoffset2 == 8)
790 {
791 m_program->write_byte(m_op2, dstdata);
792 m_bamoffset2 = 0;
793 m_op2++;
794 dstdata = m_program->read_byte(m_op2);
795 }
796 }
797
798 // Flush of the final data
799 if (m_bamoffset2 != 0)
800 m_program->write_byte(m_op2, dstdata);
801
802 F7BEND();
803 }
804
805 // RADM 0x20f4b8 holds the time left
806
opADDDC()807 uint32_t v60_device::opADDDC()
808 {
809 uint8_t appb;
810 uint8_t src, dst;
811
812 F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
813
814 if (m_lenop1 != 0)
815 {
816 logerror("ADDDC %x (pat: %x)\n", m_op1, m_lenop1);
817 }
818
819 F7CLOADOP2BYTE(appb);
820
821 src = (uint8_t)(m_op1 >> 4) * 10 + (uint8_t)(m_op1 & 0xF);
822 dst = (appb >> 4) * 10 + (appb & 0xF);
823
824 appb = src + dst + (_CY?1:0);
825
826 if (appb >= 100)
827 {
828 appb -= 100;
829 _CY = 1;
830 }
831 else
832 _CY = 0;
833
834 // compute z flag:
835 // cleared if result non-zero or carry generated
836 // unchanged otherwise
837 if (appb != 0 || _CY)
838 _Z = 0;
839
840 appb = ((appb / 10) << 4) | (appb % 10);
841
842 F7CSTOREOP2BYTE();
843 F7CEND();
844 }
845
opSUBDC()846 uint32_t v60_device::opSUBDC()
847 {
848 int8_t appb;
849 uint32_t src, dst;
850
851 F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
852
853 if (m_lenop1 != 0)
854 {
855 logerror("SUBDC %x (pat: %x)\n", m_op1, m_lenop1);
856 }
857
858 F7CLOADOP2BYTE(appb);
859
860 src = (uint32_t)(m_op1 >> 4) * 10 + (uint32_t)(m_op1 & 0xF);
861 dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
862
863 // Note that this APPB must be SIGNED!
864 appb = (int32_t)dst - (int32_t)src - (_CY?1:0);
865
866 if (appb < 0)
867 {
868 appb += 100;
869 _CY = 1;
870 }
871 else
872 _CY = 0;
873
874 // compute z flag:
875 // cleared if result non-zero or carry generated
876 // unchanged otherwise
877 if (appb != 0 || _CY)
878 _Z = 0;
879
880 appb = ((appb / 10) << 4) | (appb % 10);
881
882 F7CSTOREOP2BYTE();
883 F7CEND();
884 }
885
opSUBRDC()886 uint32_t v60_device::opSUBRDC()
887 {
888 int8_t appb;
889 uint32_t src, dst;
890
891 F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0);
892
893 if (m_lenop1 != 0)
894 {
895 logerror("SUBRDC %x (pat: %x)\n", m_op1, m_lenop1);
896 }
897
898 F7CLOADOP2BYTE(appb);
899
900 src = (uint32_t)(m_op1 >> 4) * 10 + (uint32_t)(m_op1 & 0xF);
901 dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF);
902
903 // Note that this APPB must be SIGNED!
904 appb = (int32_t)src - (int32_t)dst - (_CY?1:0);
905
906 if (appb < 0)
907 {
908 appb += 100;
909 _CY = 1;
910 }
911 else
912 _CY = 0;
913
914 // compute z flag:
915 // cleared if result non-zero or carry generated
916 // unchanged otherwise
917 if (appb != 0 || _CY)
918 _Z = 0;
919
920 appb = ((appb / 10) << 4) | (appb % 10);
921
922 F7CSTOREOP2BYTE();
923 F7CEND();
924 }
925
opCVTDPZ()926 uint32_t v60_device::opCVTDPZ()
927 {
928 uint16_t apph;
929
930 F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 1);
931
932 apph = (uint16_t)(((m_op1 >> 4) & 0xF) | ((m_op1 & 0xF) << 8));
933 apph |= (m_lenop1);
934 apph |= (m_lenop1 << 8);
935
936 // Z flag is unchanged if src is zero, cleared otherwise
937 if (m_op1 != 0) _Z = 0;
938
939 F7CSTOREOP2HALF();
940 F7CEND();
941 }
942
opCVTDZP()943 uint32_t v60_device::opCVTDZP()
944 {
945 uint8_t appb;
946 F7cDecodeOperands(&v60_device::ReadAM, 1, &v60_device::ReadAMAddress, 0);
947
948 if ((m_op1 & 0xF0) != (m_lenop1 & 0xF0) || ((m_op1 >> 8) & 0xF0) != (m_lenop1 & 0xF0))
949 {
950 // Decimal exception
951 logerror("CVTD.ZP Decimal exception #1!\n");
952 }
953
954 if ((m_op1 & 0xF) > 9 || ((m_op1 >> 8) & 0xF) > 9)
955 {
956 // Decimal exception
957 logerror("CVTD.ZP Decimal exception #2!\n");
958 }
959
960 appb = (uint8_t)(((m_op1 >> 8) & 0xF) | ((m_op1 & 0xF) << 4));
961 if (appb != 0) _Z = 0;
962
963 F7CSTOREOP2BYTE();
964 F7CEND();
965 }
966
op58UNHANDLED()967 uint32_t v60_device::op58UNHANDLED()
968 {
969 fatalerror("Unhandled 58 opcode at PC: /%06x\n", PC);
970 return 0; /* never reached, fatalerror won't return */
971 }
972
op5AUNHANDLED()973 uint32_t v60_device::op5AUNHANDLED()
974 {
975 fatalerror("Unhandled 5A opcode at PC: /%06x\n", PC);
976 return 0; /* never reached, fatalerror won't return */
977 }
978
op5BUNHANDLED()979 uint32_t v60_device::op5BUNHANDLED()
980 {
981 fatalerror("Unhandled 5B opcode at PC: /%06x\n", PC);
982 return 0; /* never reached, fatalerror won't return */
983 }
984
op5DUNHANDLED()985 uint32_t v60_device::op5DUNHANDLED()
986 {
987 fatalerror("Unhandled 5D opcode at PC: /%06x\n", PC);
988 return 0; /* never reached, fatalerror won't return */
989 }
990
op59UNHANDLED()991 uint32_t v60_device::op59UNHANDLED()
992 {
993 fatalerror("Unhandled 59 opcode at PC: /%06x\n", PC);
994 return 0; /* never reached, fatalerror won't return */
995 }
996
997 const v60_device::am_func v60_device::s_Op59Table[32] =
998 {
999 &v60_device::opADDDC,
1000 &v60_device::opSUBDC,
1001 &v60_device::opSUBRDC,
1002 &v60_device::op59UNHANDLED,
1003 &v60_device::op59UNHANDLED,
1004 &v60_device::op59UNHANDLED,
1005 &v60_device::op59UNHANDLED,
1006 &v60_device::op59UNHANDLED,
1007 &v60_device::op59UNHANDLED,
1008 &v60_device::op59UNHANDLED,
1009 &v60_device::op59UNHANDLED,
1010 &v60_device::op59UNHANDLED,
1011 &v60_device::op59UNHANDLED,
1012 &v60_device::op59UNHANDLED,
1013 &v60_device::op59UNHANDLED,
1014 &v60_device::op59UNHANDLED,
1015 &v60_device::opCVTDPZ,
1016 &v60_device::op59UNHANDLED,
1017 &v60_device::op59UNHANDLED,
1018 &v60_device::op59UNHANDLED,
1019 &v60_device::op59UNHANDLED,
1020 &v60_device::op59UNHANDLED,
1021 &v60_device::op59UNHANDLED,
1022 &v60_device::op59UNHANDLED,
1023 &v60_device::opCVTDZP,
1024 &v60_device::op59UNHANDLED,
1025 &v60_device::op59UNHANDLED,
1026 &v60_device::op59UNHANDLED,
1027 &v60_device::op59UNHANDLED,
1028 &v60_device::op59UNHANDLED,
1029 &v60_device::op59UNHANDLED,
1030 &v60_device::op59UNHANDLED
1031 };
1032
1033
1034 const v60_device::am_func v60_device::s_Op5BTable[32] =
1035 {
1036 &v60_device::opSCH0BSU,
1037 &v60_device::op5BUNHANDLED,
1038 &v60_device::opSCH1BSU,
1039 &v60_device::op5BUNHANDLED,
1040 &v60_device::op5BUNHANDLED,
1041 &v60_device::op5BUNHANDLED,
1042 &v60_device::op5BUNHANDLED,
1043 &v60_device::op5BUNHANDLED,
1044 &v60_device::opMOVBSU,
1045 &v60_device::opMOVBSD,
1046 &v60_device::op5BUNHANDLED,
1047 &v60_device::op5BUNHANDLED,
1048 &v60_device::op5BUNHANDLED,
1049 &v60_device::op5BUNHANDLED,
1050 &v60_device::op5BUNHANDLED,
1051 &v60_device::op5BUNHANDLED,
1052 &v60_device::op5BUNHANDLED,
1053 &v60_device::op5BUNHANDLED,
1054 &v60_device::op5BUNHANDLED,
1055 &v60_device::op5BUNHANDLED,
1056 &v60_device::op5BUNHANDLED,
1057 &v60_device::op5BUNHANDLED,
1058 &v60_device::op5BUNHANDLED,
1059 &v60_device::op5BUNHANDLED,
1060 &v60_device::op5BUNHANDLED,
1061 &v60_device::op5BUNHANDLED,
1062 &v60_device::op5BUNHANDLED,
1063 &v60_device::op5BUNHANDLED,
1064 &v60_device::op5BUNHANDLED,
1065 &v60_device::op5BUNHANDLED,
1066 &v60_device::op5BUNHANDLED,
1067 &v60_device::op5BUNHANDLED
1068 };
1069
1070
1071 const v60_device::am_func v60_device::s_Op5DTable[32] =
1072 {
1073 &v60_device::op5DUNHANDLED,
1074 &v60_device::op5DUNHANDLED,
1075 &v60_device::op5DUNHANDLED,
1076 &v60_device::op5DUNHANDLED,
1077 &v60_device::op5DUNHANDLED,
1078 &v60_device::op5DUNHANDLED,
1079 &v60_device::op5DUNHANDLED,
1080 &v60_device::op5DUNHANDLED,
1081 &v60_device::opEXTBFS,
1082 &v60_device::opEXTBFZ,
1083 &v60_device::opEXTBFL,
1084 &v60_device::op5DUNHANDLED,
1085 &v60_device::op5DUNHANDLED,
1086 &v60_device::op5DUNHANDLED,
1087 &v60_device::op5DUNHANDLED,
1088 &v60_device::op5DUNHANDLED,
1089 &v60_device::op5DUNHANDLED,
1090 &v60_device::op5DUNHANDLED,
1091 &v60_device::op5DUNHANDLED,
1092 &v60_device::op5DUNHANDLED,
1093 &v60_device::op5DUNHANDLED,
1094 &v60_device::op5DUNHANDLED,
1095 &v60_device::op5DUNHANDLED,
1096 &v60_device::op5DUNHANDLED,
1097 &v60_device::opINSBFR,
1098 &v60_device::opINSBFL,
1099 &v60_device::op5DUNHANDLED,
1100 &v60_device::op5DUNHANDLED,
1101 &v60_device::op5DUNHANDLED,
1102 &v60_device::op5DUNHANDLED,
1103 &v60_device::op5DUNHANDLED,
1104 &v60_device::op5DUNHANDLED
1105 };
1106
1107 const v60_device::am_func v60_device::s_Op58Table[32] =
1108 {
1109 &v60_device::opCMPCB,
1110 &v60_device::opCMPCFB,
1111 &v60_device::opCMPCSB,
1112 &v60_device::op58UNHANDLED,
1113 &v60_device::op58UNHANDLED,
1114 &v60_device::op58UNHANDLED,
1115 &v60_device::op58UNHANDLED,
1116 &v60_device::op58UNHANDLED,
1117 &v60_device::opMOVCUB,
1118 &v60_device::opMOVCDB,
1119 &v60_device::opMOVCFUB,
1120 &v60_device::opMOVCFDB,
1121 &v60_device::opMOVCSUB,
1122 &v60_device::op58UNHANDLED,
1123 &v60_device::op58UNHANDLED,
1124 &v60_device::op58UNHANDLED,
1125 &v60_device::op58UNHANDLED,
1126 &v60_device::op58UNHANDLED,
1127 &v60_device::op58UNHANDLED,
1128 &v60_device::op58UNHANDLED,
1129 &v60_device::op58UNHANDLED,
1130 &v60_device::op58UNHANDLED,
1131 &v60_device::op58UNHANDLED,
1132 &v60_device::op58UNHANDLED,
1133 &v60_device::opSCHCUB,
1134 &v60_device::opSCHCDB,
1135 &v60_device::opSKPCUB,
1136 &v60_device::opSKPCDB,
1137 &v60_device::op58UNHANDLED,
1138 &v60_device::op58UNHANDLED,
1139 &v60_device::op58UNHANDLED,
1140 &v60_device::op58UNHANDLED
1141 };
1142
1143 const v60_device::am_func v60_device::s_Op5ATable[32] =
1144 {
1145 &v60_device::opCMPCH,
1146 &v60_device::opCMPCFH,
1147 &v60_device::opCMPCSH,
1148 &v60_device::op5AUNHANDLED,
1149 &v60_device::op5AUNHANDLED,
1150 &v60_device::op5AUNHANDLED,
1151 &v60_device::op5AUNHANDLED,
1152 &v60_device::op5AUNHANDLED,
1153 &v60_device::opMOVCUH,
1154 &v60_device::opMOVCDH,
1155 &v60_device::opMOVCFUH,
1156 &v60_device::opMOVCFDH,
1157 &v60_device::opMOVCSUH,
1158 &v60_device::op5AUNHANDLED,
1159 &v60_device::op5AUNHANDLED,
1160 &v60_device::op5AUNHANDLED,
1161 &v60_device::op5AUNHANDLED,
1162 &v60_device::op5AUNHANDLED,
1163 &v60_device::op5AUNHANDLED,
1164 &v60_device::op5AUNHANDLED,
1165 &v60_device::op5AUNHANDLED,
1166 &v60_device::op5AUNHANDLED,
1167 &v60_device::op5AUNHANDLED,
1168 &v60_device::op5AUNHANDLED,
1169 &v60_device::opSCHCUH,
1170 &v60_device::opSCHCDH,
1171 &v60_device::opSKPCUH,
1172 &v60_device::opSKPCDH,
1173 &v60_device::op5AUNHANDLED,
1174 &v60_device::op5AUNHANDLED,
1175 &v60_device::op5AUNHANDLED,
1176 &v60_device::op5AUNHANDLED
1177 };
1178
op58()1179 uint32_t v60_device::op58()
1180 {
1181 m_subop = OpRead8(PC + 1);
1182
1183 return (this->*s_Op58Table[m_subop & 0x1F])();
1184 }
1185
op5A()1186 uint32_t v60_device::op5A()
1187 {
1188 m_subop = OpRead8(PC + 1);
1189
1190 return (this->*s_Op5ATable[m_subop & 0x1F])();
1191 }
1192
op5B()1193 uint32_t v60_device::op5B()
1194 {
1195 m_subop = OpRead8(PC + 1);
1196
1197 return (this->*s_Op5BTable[m_subop & 0x1F])();
1198 }
1199
op5D()1200 uint32_t v60_device::op5D()
1201 {
1202 m_subop = OpRead8(PC + 1);
1203
1204 return (this->*s_Op5DTable[m_subop & 0x1F])();
1205 }
1206
op59()1207 uint32_t v60_device::op59()
1208 {
1209 m_subop = OpRead8(PC + 1);
1210
1211 return (this->*s_Op59Table[m_subop & 0x1F])();
1212 }
1213