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