summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/unsp/unsp_fxxx.cpp
blob: 638f8d273876287197bd9b841453cce5c4892905 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
// license:GPL-2.0+
// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood

#include "emu.h"
#include "unsp.h"
#include "unspfe.h"

#include "debugger.h"

#include "unspdasm.h"

#define LOG_UNSP_MULS            (1U << 1)

#define VERBOSE             (0)

#include "logmacro.h"

inline void unsp_device::execute_fxxx_000_group(uint16_t op)
{
	//                          |   | |
	// DS16     1 1 1 1   1 1 1 0   0 0 i i   i i i i
	// DS Reg   1 1 1 1   - - - 0   0 0 1 0   w r r r
	// FR Reg   1 1 1 1   - - - 0   0 0 1 1   w r r r

	// FR = 'inner flag register' on ISA1.2+
	// does this mean 1.2+ do not store the registers in the upper bits of SR, or is this something else?
	// smartfp IRQ4 reads this and puts in on the stack

	if (((op & 0xffc0) == 0xfe00) && m_iso >= 12)
	{
		// ds = imm6
		set_ds(op & 0x003f);
		return;
	}
	else if (((op & 0xf1f8) == 0xf020) && m_iso >= 12)
	{
		// rx = ds
		m_core->m_r[op & 0x7] = get_ds();
		return;
	}
	else if (((op & 0xf1f8) == 0xf028) && m_iso >= 12)
	{
		// ds = rx
		set_ds(m_core->m_r[op & 0x7]);
		return;
	}
	else if (((op & 0xf1f8) == 0xf030) && m_iso >= 12)
	{
		m_core->m_r[op & 0x7] = get_fr();
		return;
	}
	else if (((op & 0xf1f8) == 0xf038) && m_iso >= 12)
	{
		set_fr(m_core->m_r[op & 0x7]);
		return;
	}

	// everything else falls through to the multiply

	// MUL us ( signed * unsigned )
	// MUL      1 1 1 1*  r r r 0*  0 0 0 0   1 r r r     (** = sign bits, fixed here)

	const uint16_t opa = (op >> 9) & 7;
	const uint16_t opb = op & 7;
	m_core->m_icount -= 12;

	LOGMASKED(LOG_UNSP_MULS, "%s: MUL us with %04x (unsigned) * %04x (signed) (fra:%d) :\n", machine().describe_context(), m_core->m_r[opa], m_core->m_r[opb], m_core->m_fra);

	uint32_t lres = m_core->m_r[opa] * m_core->m_r[opb];
	if (m_core->m_r[opb] & 0x8000)
	{
		lres -= m_core->m_r[opa] << 16;
	}
	m_core->m_r[REG_R4] = lres >> 16;
	m_core->m_r[REG_R3] = (uint16_t)lres;

	LOGMASKED(LOG_UNSP_MULS, "result was : %08x\n", lres);

	return;
}

inline void unsp_device::execute_fxxx_001_group(uint16_t op)
{
	//                             |   | |
	// CALL16      1 1 1 1   - - 0 0   0 1 a a   a a a a   (+imm16)

	if ((op & 0xf3c0) == 0xf040)
	{
		m_core->m_icount -= 9;
		uint16_t r1 = read16(UNSP_LPC);
		add_lpc(1);
		push(m_core->m_r[REG_PC], &m_core->m_r[REG_SP]);
		push(m_core->m_r[REG_SR], &m_core->m_r[REG_SP]);
		m_core->m_r[REG_PC] = r1;
		m_core->m_r[REG_SR] &= 0xffc0;
		m_core->m_r[REG_SR] |= op & 0x3f;
		return;
	}
	// MEM bitop   1 1 1 1   - D 1 0   0 1 b b   o o o o   (+imm16)   ( BITOP {ds:}[A16],offset )
	else if (((op & 0xf3c0) == 0xf240) && m_iso >= 20)
	{
		uint8_t bitop =  (op & 0x0030) >> 4;
		uint8_t offset = (op & 0x000f) >> 0;
		uint8_t d =      (op & 0x0400) >> 10;
		uint16_t imm16 = read16(UNSP_LPC);
		add_lpc(1);

		if (d)
		{
			switch (bitop)
			{
			case 0x0: // tstb
				logerror("tstb ds:[%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;

			case 0x1: // setb
				logerror("setb ds:[%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;

			case 0x2: // clrb
				logerror("clrb ds:[%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;

			case 0x3: // invb
				logerror("invb ds:[%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;
			}
		}
		else
		{
			switch (bitop)
			{
			case 0x0: // tstb
				logerror("tstb [%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;

			case 0x1: // setb    (bkrankp uses this)
			{
				uint16_t temp = read16(imm16);
				temp |= (1 << offset);
				write16(imm16, temp);
				break;
			}
			case 0x2: // clrb
				logerror("clrb [%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;

			case 0x3: // invb
				logerror("invb [%04x],%d\n", imm16, offset);
				unimplemented_opcode(op);
				break;
			}
		}

		return;
	}

	logerror("<DUNNO>\n");
	unimplemented_opcode(op);
	return;
}

inline void unsp_device::execute_fxxx_010_group(uint16_t op)
{
	//                         |   | |
	// JMPF    1 1 1 1   1 1 1 0   1 0 a a   a a a a    (+imm16)

	if ((op & 0xffc0) == 0xfe80) // apparently 1.2 and above, but jak_capb needs it and otherwise seems 1.0 / 1.1?
	{
		m_core->m_icount -= 5;
		m_core->m_r[REG_PC] = read16(UNSP_LPC);
		m_core->m_r[REG_SR] &= 0xffc0;
		m_core->m_r[REG_SR] |= op & 0x3f;
		return;
	}

	// signed * unsigned  (size 16,1,2,3,4,5,6,7)
	// MULS    1 1 1 1*  r r r 0*  1 0*s s   s r r r    (1* = sign bit, 0* = sign bit 0* = upper size bit)

	// MULS us with upper size bit not set
	logerror("MULS us\n");
	unimplemented_opcode(op);
	return;
}

inline void unsp_device::execute_fxxx_011_group(uint16_t op)
{
	//                         |   | |
	// JMPR    1 1 1 1   1 1 1 0   1 1 - -   - - - -
	if (((op & 0xffc0) == 0xfec0) && m_iso >= 12)
	{
		m_core->m_icount -= 5;
		m_core->m_r[REG_PC] = m_core->m_r[REG_R3];
		m_core->m_r[REG_SR] &= 0xffc0;
		m_core->m_r[REG_SR] |= m_core->m_r[REG_R4] & 0x3f;
		return;
	}

	// signed * unsigned  (size 8,9,10,11,12,13,14,15)
	// MULS    1 1 1 1*  r r r 0*  1 1*s s   s r r r    (1* = sign bit, 0* = sign bit 1* = upper size bit)

	// MULS us with upper size bit set
	logerror("MULS us\n");
	unimplemented_opcode(op);

	return;
}

inline void unsp_device::execute_fxxx_100_group(uint16_t op)
{
	//                          |   | |
	// signed * signed
	// MUL      1 1 1 1*  r r r 1*  0 0 0 0   1 r r r     (** = sign bits, fixed here)

	if ((op & 0xf1f8) == 0xf108)
	{
		const uint16_t opa = (op >> 9) & 7;
		const uint16_t opb = op & 7;

		LOGMASKED(LOG_UNSP_MULS, "%s: MUL ss with %04x (signed) * %04x (signed) (fra:%d) :\n", machine().describe_context(), m_core->m_r[opa], m_core->m_r[opb], m_core->m_fra);

		m_core->m_icount -= 12;
		uint32_t lres = m_core->m_r[opa] * m_core->m_r[opb];
		if (m_core->m_r[opb] & 0x8000)
		{
			lres -= m_core->m_r[opa] << 16;
		}
		if (m_core->m_r[opa] & 0x8000)
		{
			lres -= m_core->m_r[opb] << 16;
		}
		m_core->m_r[REG_R4] = lres >> 16;
		m_core->m_r[REG_R3] = (uint16_t)lres;

		LOGMASKED(LOG_UNSP_MULS, "result was : %08x\n", lres);

		return;
	}

	logerror("<DUNNO>\n");
	unimplemented_opcode(op);
	return;
}

void unsp_12_device::execute_divq(uint16_t op)
{
	uint32_t orig_dividend = 0;
	if (m_core->m_divq_bit == UINT_MAX)
	{
		m_core->m_divq_bit = 15;
		m_core->m_divq_dividend = (m_core->m_r[REG_R4] << 16) | m_core->m_r[REG_R3];
		m_core->m_divq_divisor = m_core->m_r[REG_R2];
		m_core->m_divq_a = 0;
	}
	orig_dividend = m_core->m_divq_dividend;
	m_core->m_aq = BIT(m_core->m_divq_a, 31);
	if (m_core->m_aq)
	{
		m_core->m_divq_a += m_core->m_divq_a + BIT(m_core->m_divq_dividend, 15) + m_core->m_divq_divisor;
	}
	else
	{
		m_core->m_divq_a += m_core->m_divq_a + BIT(m_core->m_divq_dividend, 15) - m_core->m_divq_divisor;
	}
	m_core->m_divq_dividend <<= 1;
	m_core->m_divq_dividend++;
	m_core->m_divq_dividend ^= BIT(m_core->m_divq_a, 31);
	m_core->m_r[REG_R3] = (uint16_t)m_core->m_divq_dividend;
	m_core->m_divq_bit--;
}

bool unsp_12_device::op_is_divq(const uint16_t op)
{
	return (op & 0xf163) == 0xf163;
}

void unsp_12_device::execute_fxxx_101_group(uint16_t op)
{
	// FIR_MOV   1 1 1 1   - - - 1   0 1 0 0   0 1 0 f
	// Fraction  1 1 1 1   - - - 1   0 1 0 0   0 1 1 f
	// SECBANK   1 1 1 1   - - - 1   0 1 0 0   1 0 1 S
	// NESTMODE  1 1 1 1   - - - 1   0 1 0 0   1 1 N 1
	// CALLR     1 1 1 1   - - - 1   0 1 1 -   - 0 0 1
	// DIVS      1 1 1 1   - - - 1   0 1 1 -   - 0 1 0
	// DIVQ      1 1 1 1   - - - 1   0 1 1 -   - 0 1 1
	// EXP       1 1 1 1   - - - 1   0 1 1 -   - 1 0 0

	m_core->m_icount -= 1; // Unknown count

	switch (op)
	{
	case 0xf146: case 0xf346: case 0xf546: case 0xf746: case 0xf946: case 0xfb46: case 0xfd46: case 0xff46:
		m_core->m_fra = 0;
		return;

	case 0xf147: case 0xf347: case 0xf547: case 0xf747: case 0xf947: case 0xfb47: case 0xfd47: case 0xff47:
		m_core->m_fra = 1;
		return;

	case 0xf14a: case 0xf34a: case 0xf54a: case 0xf74a: case 0xf94a: case 0xfb4a: case 0xfd4a: case 0xff4a:
		if (m_core->m_bnk)
		{
			std::swap<uint32_t>(m_core->m_r[REG_R1], m_core->m_secbank[REG_SR1]);
			std::swap<uint32_t>(m_core->m_r[REG_R2], m_core->m_secbank[REG_SR2]);
			std::swap<uint32_t>(m_core->m_r[REG_R3], m_core->m_secbank[REG_SR3]);
			std::swap<uint32_t>(m_core->m_r[REG_R4], m_core->m_secbank[REG_SR4]);
		}
		m_core->m_bnk = 0;
		return;

	case 0xf14b: case 0xf34b: case 0xf54b: case 0xf74b: case 0xf94b: case 0xfb4b: case 0xfd4b: case 0xff4b:
		if (m_core->m_bnk == 0)
		{
			std::swap<uint32_t>(m_core->m_r[REG_R1], m_core->m_secbank[REG_SR1]);
			std::swap<uint32_t>(m_core->m_r[REG_R2], m_core->m_secbank[REG_SR2]);
			std::swap<uint32_t>(m_core->m_r[REG_R3], m_core->m_secbank[REG_SR3]);
			std::swap<uint32_t>(m_core->m_r[REG_R4], m_core->m_secbank[REG_SR4]);
		}
		m_core->m_bnk = 1;
		return;

	case 0xf14d: case 0xf34d: case 0xf54d: case 0xf74d: case 0xf94d: case 0xfb4d: case 0xfd4d: case 0xff4d:
		m_core->m_ine = 0;
		return;

	case 0xf14f: case 0xf34f: case 0xf54f: case 0xf74f: case 0xf94f: case 0xfb4f: case 0xfd4f: case 0xff4f:
		m_core->m_ine = 1;
		return;

	case 0xf144: case 0xf344: case 0xf544: case 0xf744: case 0xf944: case 0xfb44: case 0xfd44: case 0xff44:
		m_core->m_fir_move = 1;
		return;

	case 0xf145: case 0xf345: case 0xf545: case 0xf745: case 0xf945: case 0xfb45: case 0xfd45: case 0xff45:
		m_core->m_fir_move = 0;
		return;

	case 0xf161: case 0xf361: case 0xf561: case 0xf761: case 0xf961: case 0xfb61: case 0xfd61: case 0xff61:
	case 0xf169: case 0xf369: case 0xf569: case 0xf769: case 0xf969: case 0xfb69: case 0xfd69: case 0xff69:
	case 0xf171: case 0xf371: case 0xf571: case 0xf771: case 0xf971: case 0xfb71: case 0xfd71: case 0xff71:
	case 0xf179: case 0xf379: case 0xf579: case 0xf779: case 0xf979: case 0xfb79: case 0xfd79: case 0xff79:
	{
		uint32_t addr = m_core->m_r[REG_R3] | ((m_core->m_r[REG_R4] & 0x3f) << 16);
		push(m_core->m_r[REG_PC], &m_core->m_r[REG_SP]);
		push(m_core->m_r[REG_SR], &m_core->m_r[REG_SP]);
		m_core->m_r[REG_PC] = addr & 0x0000ffff;
		m_core->m_r[REG_SR] &= 0xffc0;
		m_core->m_r[REG_SR] |= ((addr & 0x003f0000) >> 16);
		return;
	}

	case 0xf162: case 0xf362: case 0xf562: case 0xf762: case 0xf962: case 0xfb62: case 0xfd62: case 0xff62:
	case 0xf16a: case 0xf36a: case 0xf56a: case 0xf76a: case 0xf96a: case 0xfb6a: case 0xfd6a: case 0xff6a:
	case 0xf172: case 0xf372: case 0xf572: case 0xf772: case 0xf972: case 0xfb72: case 0xfd72: case 0xff72:
	case 0xf17a: case 0xf37a: case 0xf57a: case 0xf77a: case 0xf97a: case 0xfb7a: case 0xfd7a: case 0xff7a:
		logerror("divs mr, r2\n");
		unimplemented_opcode(op);
		return;

	case 0xf163: case 0xf363: case 0xf563: case 0xf763: case 0xf963: case 0xfb63: case 0xfd63: case 0xff63:
	case 0xf16b: case 0xf36b: case 0xf56b: case 0xf76b: case 0xf96b: case 0xfb6b: case 0xfd6b: case 0xff6b:
	case 0xf173: case 0xf373: case 0xf573: case 0xf773: case 0xf973: case 0xfb73: case 0xfd73: case 0xff73:
	case 0xf17b: case 0xf37b: case 0xf57b: case 0xf77b: case 0xf97b: case 0xfb7b: case 0xfd7b: case 0xff7b:
		execute_divq(op);
		return;

	case 0xf164: case 0xf364: case 0xf564: case 0xf764: case 0xf964: case 0xfb64: case 0xfd64: case 0xff64:
	case 0xf16c: case 0xf36c: case 0xf56c: case 0xf76c: case 0xf96c: case 0xfb6c: case 0xfd6c: case 0xff6c:
	case 0xf174: case 0xf374: case 0xf574: case 0xf774: case 0xf974: case 0xfb74: case 0xfd74: case 0xff74:
	case 0xf17c: case 0xf37c: case 0xf57c: case 0xf77c: case 0xf97c: case 0xfb7c: case 0xfd7c: case 0xff7c:
	{
		uint16_t r4 = m_core->m_r[REG_R4];

		if (r4 & 0x8000)
		{
			// r2 undefined (code will check for this and avoid calculations
		}
		else
		{
			m_core->m_r[REG_R2] = count_leading_zeros(r4) - 17; // -17 because count_leading_zeros works with 32-bit values
		}

		return;
	}

	default:
		return unsp_device::execute_fxxx_101_group(op);
	}
}


void unsp_device::execute_fxxx_101_group(uint16_t op)
{
	//                           |   | |
	// INT SET   1 1 1 1   - - - 1   0 1 0 0   0 0 F I
	// BREAK     1 1 1 1   - - - 1   0 1 1 -   - 0 0 0
	// NOP       1 1 1 1   - - - 1   0 1 1 -   - 1 0 1

	// IRQ       1 1 1 1   - - - 1   0 1 0 0   1 0 0 I
	// FIRQ      1 1 1 1   - - - 1   0 1 0 0   1 1 F 0

	m_core->m_icount -= 2;

	switch (op)
	{
	case 0xf140: case 0xf340: case 0xf540: case 0xf740: case 0xf940: case 0xfb40: case 0xfd40: case 0xff40:
		m_core->m_enable_irq = 0;
		m_core->m_enable_fiq = 0;
		return;

	case 0xf141: case 0xf341: case 0xf541: case 0xf741: case 0xf941: case 0xfb41: case 0xfd41: case 0xff41:
		m_core->m_enable_irq = 1;
		m_core->m_enable_fiq = 0;
		return;

	case 0xf142: case 0xf342: case 0xf542: case 0xf742: case 0xf942: case 0xfb42: case 0xfd42: case 0xff42:
		m_core->m_enable_irq = 0;
		m_core->m_enable_fiq = 1;
		return;

	case 0xf143: case 0xf343: case 0xf543: case 0xf743: case 0xf943: case 0xfb43: case 0xfd43: case 0xff43:
		m_core->m_enable_irq = 1;
		m_core->m_enable_fiq = 1;
		return;

	case 0xf144: case 0xf344: case 0xf544: case 0xf744: case 0xf944: case 0xfb44: case 0xfd44: case 0xff44:
		m_core->m_fir_move = 1;
		return;

	case 0xf145: case 0xf345: case 0xf545: case 0xf745: case 0xf945: case 0xfb45: case 0xfd45: case 0xff45:
		m_core->m_fir_move = 0;
		return;

	case 0xf160: case 0xf360: case 0xf560: case 0xf760: case 0xf960: case 0xfb60: case 0xfd60: case 0xff60:
	case 0xf168: case 0xf368: case 0xf568: case 0xf768: case 0xf968: case 0xfb68: case 0xfd68: case 0xff68:
	case 0xf170: case 0xf370: case 0xf570: case 0xf770: case 0xf970: case 0xfb70: case 0xfd70: case 0xff70:
	case 0xf178: case 0xf378: case 0xf578: case 0xf778: case 0xf978: case 0xfb78: case 0xfd78: case 0xff78:
		// break (call vector fff5?)
		unimplemented_opcode(op);
		return;

	case 0xf165: case 0xf365: case 0xf565: case 0xf765: case 0xf965: case 0xfb65: case 0xfd65: case 0xff65:
	case 0xf16d: case 0xf36d: case 0xf56d: case 0xf76d: case 0xf96d: case 0xfb6d: case 0xfd6d: case 0xff6d:
	case 0xf175: case 0xf375: case 0xf575: case 0xf775: case 0xf975: case 0xfb75: case 0xfd75: case 0xff75:
	case 0xf17d: case 0xf37d: case 0xf57d: case 0xf77d: case 0xf97d: case 0xfb7d: case 0xfd7d: case 0xff7d:
		// nothing
		return;

	// these are in code that otherwise seems like ISA1.0 / 1.1 (jak_disf for example) but spec says it's only in ISA 1.2?
	case 0xf148: case 0xf348: case 0xf548: case 0xf748: case 0xf948: case 0xfb48: case 0xfd48: case 0xff48:
		m_core->m_enable_irq = 0;
		return;

	case 0xf149: case 0xf349: case 0xf549: case 0xf749: case 0xf949: case 0xfb49: case 0xfd49: case 0xff49:
		m_core->m_enable_irq = 1;
		return;

	case 0xf14c: case 0xf34c: case 0xf54c: case 0xf74c: case 0xf94c: case 0xfb4c: case 0xfd4c: case 0xff4c:
		m_core->m_enable_fiq = 0;
		return;

	case 0xf14e: case 0xf34e: case 0xf54e: case 0xf74e: case 0xf94e: case 0xfb4e: case 0xfd4e: case 0xff4e:
		m_core->m_enable_fiq = 1;
		return;

	default:
		unimplemented_opcode(op);
		return;
	}

	return;
}


inline void unsp_device::execute_fxxx_110_group(uint16_t op)
{
	//uint32_t len = 1;

	// some sources say this is FFc0, but smartfp clearly uses ff80
	// EXTOP   1 1 1 1   1 1 1 1   1 0 0 0   0 0 0 0    (+16 bit imm)
	if ((op == 0xff80) && m_iso >= 20)
	{
		return execute_extended_group(op);
	}

	//                         |   | |
	// signed * signed  (size 16,1,2,3,4,5,6,7)
	// MULS    1 1 1 1*  r r r 1*  1 0*s s   s r r r    (1* = sign bit, 1* = sign bit 0* = upper size bit)

	// MULS ss with upper size bit not set
	const uint16_t size = ((op >> 3) & 7) ? ((op >> 3) & 7) : 16;
	const uint16_t rd = (op >> 9) & 7;
	const uint16_t rs = op & 7;
	execute_muls_ss(rd, rs, size);
}

void unsp_device::execute_muls_ss(const uint16_t rd, const uint16_t rs, const uint16_t size)
{
	const uint32_t rdv = m_core->m_r[rd];
	const uint32_t rsv = m_core->m_r[rs];
	int64_t lres = 0;
	uint16_t values[16];
	for (uint16_t i = 0; i < size; i++)
	{
		values[i] = read16(rdv + i);
		const uint16_t rhs = read16(rsv + i);
		uint32_t tres = values[i] * rhs;
		if (values[i] & 0x8000)
		{
			tres -= rhs << 16;
		}
		if (rhs & 0x8000)
		{
			tres -= values[i] << 16;
		}
		lres += (int64_t)(int32_t)tres;
	}
	m_core->m_sb = 0;
	if (m_core->m_fir_move)
	{
		for (uint16_t i = size - 1; i > 0; i--)
		{
			write16(rdv + i, values[i - 1]);
		}
	}
	m_core->m_r[rd] += size;
	m_core->m_r[rs] += size;
	m_core->m_r[REG_R4] = (uint16_t)(lres >> 16);
	m_core->m_r[REG_R3] = (uint16_t)lres;
}

inline void unsp_device::execute_fxxx_111_group(uint16_t op)
{
	//uint32_t len = 1;
	//                         |   | |


	// signed * signed  (size 8,9,10,11,12,13,14,15)
	// MULS    1 1 1 1*  r r r 1*  1 1*s s   s r r r    (1* = sign bit, 1* = sign bit 1* = upper size bit)

	// MULS ss with upper size bit set.
	const uint16_t rd = (op >> 9) & 7;
	const uint16_t rs = op & 7;
	execute_muls_ss(rd, rs, ((op >> 3) & 7) + 8);
}

void unsp_device::execute_fxxx_group(uint16_t op)
{
	switch ((op & 0x01c0) >> 6)
	{
	case 0x0:
		return execute_fxxx_000_group(op);

	case 0x1:
		return execute_fxxx_001_group(op);

	case 0x2:
		return execute_fxxx_010_group(op);

	case 0x3:
		return execute_fxxx_011_group(op);

	case 0x4:
		return execute_fxxx_100_group(op);

	case 0x5:
		return execute_fxxx_101_group(op);

	case 0x6:
		return execute_fxxx_110_group(op);

	case 0x7:
		return execute_fxxx_111_group(op);

	}

	return;
}