1 // license:BSD-3-Clause
2 // copyright-holders:Patrick Mackinlay
3 
4 /*
5  * National Semiconductor 32081 Floating-Point Unit.
6  *
7  * Sources:
8  *   - http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
9  *
10  * TODO:
11  *   - testing
12  */
13 
14 #include "emu.h"
15 #include "ns32081.h"
16 
17 #include "softfloat3/source/include/softfloat.h"
18 
19 #define LOG_GENERAL (1U << 0)
20 //#define VERBOSE (LOG_GENERAL)
21 
22 #include "logmacro.h"
23 
24 DEFINE_DEVICE_TYPE(NS32081, ns32081_device, "ns32081", "National Semiconductor 32081 Floating-Point Unit")
25 
26 enum fsr_mask : u32
27 {
28 	FSR_TT  = 0x00000007, // trap type
29 	FSR_UEN = 0x00000008, // underflow trap enable
30 	FSR_UF  = 0x00000010, // underflow flag
31 	FSR_IEN = 0x00000020, // inexact result trap enable
32 	FSR_IF  = 0x00000040, // inexact result flag
33 	FSR_RM  = 0x00000180, // rounding mode
34 	FSR_SWF = 0x0000fe00, // software field
35 };
36 
37 enum rm_mask : u32
38 {
39 	RM_N = 0x00000000, // round to nearest value
40 	RM_Z = 0x00000080, // round toward zero
41 	RM_U = 0x00000100, // round toward positive infinity
42 	RM_D = 0x00000180, // round toward negative infinity
43 };
44 
45 enum tt_mask : u32
46 {
47 	TT_UND = 0x00000001, // underflow
48 	TT_OVF = 0x00000002, // overflow
49 	TT_DVZ = 0x00000003, // divide by zero
50 	TT_ILL = 0x00000004, // illegal instruction
51 	TT_INV = 0x00000005, // invalid operation
52 	TT_INX = 0x00000006, // inexact result
53 	TT_RSV = 0x00000007, // reserved
54 };
55 
56 enum state : unsigned
57 {
58 	IDLE      = 0,
59 	OPERATION = 1, // awaiting operation word
60 	OPERAND   = 2, // awaiting operands
61 	STATUS    = 4, // status word available
62 	RESULT    = 5, // result word available
63 };
64 
65 enum idbyte : u8
66 {
67 	FORMAT_9  = 0x3e,
68 	FORMAT_11 = 0xbe,
69 };
70 
71 enum operand_length : unsigned
72 {
73 	LENGTH_F = 4, // single precision
74 	LENGTH_L = 8, // double precision
75 };
76 
77 enum size_code : unsigned
78 {
79 	SIZE_B = 0,
80 	SIZE_W = 1,
81 	SIZE_D = 3,
82 };
83 
ns32081_device(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)84 ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
85 	: device_t(mconfig, NS32081, tag, owner, clock)
86 	, ns32000_slave_interface(mconfig, *this)
87 {
88 }
89 
device_start()90 void ns32081_device::device_start()
91 {
92 	save_item(NAME(m_fsr));
93 	save_item(NAME(m_f));
94 
95 	save_item(NAME(m_idbyte));
96 	save_item(NAME(m_opword));
97 	save_item(STRUCT_MEMBER(m_op, expected));
98 	save_item(STRUCT_MEMBER(m_op, issued));
99 	save_item(STRUCT_MEMBER(m_op, value));
100 	save_item(NAME(m_status));
101 
102 	save_item(NAME(m_state));
103 	save_item(NAME(m_tcy));
104 
105 	m_complete = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32081_device::complete), this));
106 }
107 
device_reset()108 void ns32081_device::device_reset()
109 {
110 	m_fsr = 0;
111 	std::fill_n(&m_f[0], ARRAY_LENGTH(m_f), 0);
112 
113 	m_state = IDLE;
114 }
115 
state_add(device_state_interface & parent,int & index)116 void ns32081_device::state_add(device_state_interface &parent, int &index)
117 {
118 	parent.state_add(index++, "FSR", m_fsr).formatstr("%04X");
119 
120 	for (unsigned i = 0; i < 8; i++)
121 		parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X");
122 }
123 
read_st(int * icount)124 u16 ns32081_device::read_st(int *icount)
125 {
126 	if (m_state == STATUS)
127 	{
128 		m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
129 
130 		if (icount)
131 			*icount -= m_tcy;
132 
133 		LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
134 			(m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
135 
136 		return m_status;
137 	}
138 
139 	logerror("protocol error reading status word (%s)\n", machine().describe_context());
140 	return 0;
141 }
142 
read_op()143 u16 ns32081_device::read_op()
144 {
145 	if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
146 	{
147 		u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8));
148 		LOG("read_op word %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context());
149 
150 		m_op[2].issued += 2;
151 
152 		if (m_op[2].issued == m_op[2].expected)
153 		{
154 			LOG("read_op last result word issued\n");
155 			m_state = IDLE;
156 		}
157 
158 		return data;
159 	}
160 
161 	logerror("protocol error reading result word (%s)\n", machine().describe_context());
162 	return 0;
163 }
164 
write_id(u16 data)165 void ns32081_device::write_id(u16 data)
166 {
167 	bool const match = (data == FORMAT_9) || (data == FORMAT_11);
168 
169 	if (match)
170 	{
171 		LOG("write_id match 0x%04x (%s)\n", data, machine().describe_context());
172 		m_state = OPERATION;
173 	}
174 	else
175 	{
176 		LOG("write_id ignore 0x%04x (%s)\n", data, machine().describe_context());
177 		m_state = IDLE;
178 	}
179 
180 	m_idbyte = u8(data);
181 }
182 
write_op(u16 data)183 void ns32081_device::write_op(u16 data)
184 {
185 	switch (m_state)
186 	{
187 	case OPERATION:
188 		m_opword = swapendian_int16(data);
189 		LOG("write_op opword 0x%04x (%s)\n", m_opword, machine().describe_context());
190 
191 		// initialize operands
192 		for (operand &op : m_op)
193 		{
194 			op.expected = 0;
195 			op.issued = 0;
196 			op.value = 0;
197 		}
198 
199 		// decode operands
200 		if (m_idbyte == FORMAT_9)
201 		{
202 			// format 9: 1111 1222 22oo ofii
203 			unsigned const f_length = BIT(m_opword, 2) ? LENGTH_F : LENGTH_L;
204 			unsigned const size = m_opword & 3;
205 
206 			switch ((m_opword >> 3) & 7)
207 			{
208 			case 0: // movif
209 				m_op[0].expected = size + 1;
210 				m_op[2].expected = f_length;
211 				break;
212 			case 1: // lfsr
213 				m_op[0].expected = 4;
214 				break;
215 			case 2: // movlf
216 				m_op[0].expected = LENGTH_L;
217 				m_op[2].expected = f_length;
218 				break;
219 			case 3: // movfl
220 				m_op[0].expected = LENGTH_F;
221 				m_op[2].expected = f_length;
222 				break;
223 			case 4: // roundfi
224 			case 5: // truncfi
225 			case 7: // floorfi
226 				m_op[0].expected = f_length;
227 				m_op[2].expected = size + 1;
228 				break;
229 			case 6: // sfsr
230 				m_op[2].expected = 4;
231 				break;
232 			}
233 		}
234 		else if (m_idbyte == FORMAT_11)
235 		{
236 			// format 11: 1111 1222 22oo oo0f
237 			unsigned const opcode = (m_opword >> 2) & 15;
238 			unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L;
239 
240 			m_op[0].expected = f_length;
241 
242 			// even opcodes have two input operands
243 			if (!BIT(opcode, 0))
244 				m_op[1].expected = f_length;
245 
246 			// all operations except CMPf issue a result
247 			if (opcode != 2)
248 				m_op[2].expected = f_length;
249 		}
250 
251 		// operand 1 in register
252 		if (m_op[0].expected && !(m_opword & 0xc000))
253 		{
254 			// exclude integer operands
255 			if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) > 1)
256 			{
257 				unsigned const reg = (m_opword >> 11) & 7;
258 				LOG("write_op read f%d\n", reg);
259 
260 				m_op[0].value = m_f[reg ^ 0];
261 				if (m_op[0].expected == 8)
262 					m_op[0].value |= u64(m_f[reg ^ 1]) << 32;
263 
264 				m_op[0].issued = m_op[0].expected;
265 			}
266 		}
267 
268 		// operand 2 in register
269 		if (m_op[1].expected && !(m_opword & 0x0600))
270 		{
271 			unsigned const reg = (m_opword >> 6) & 7;
272 			LOG("write_op read f%d\n", reg);
273 
274 			m_op[1].value = m_f[reg ^ 0];
275 			if (m_op[1].expected == 8)
276 				m_op[1].value |= u64(m_f[reg ^ 1]) << 32;
277 
278 			m_op[1].issued = m_op[1].expected;
279 		}
280 
281 		m_state = OPERAND;
282 		break;
283 
284 	case OPERAND:
285 		// check awaiting operand word
286 		if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
287 		{
288 			unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
289 			operand &op = m_op[n];
290 
291 			LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context());
292 
293 			// insert word into operand value
294 			op.value |= u64(data) << (op.issued * 8);
295 			op.issued += 2;
296 		}
297 		else
298 			logerror("protocol error unexpected operand word 0x%04x (%s)\n", data, machine().describe_context());
299 		break;
300 	}
301 
302 	// start execution when all operands are available
303 	if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
304 		execute();
305 }
306 
execute()307 void ns32081_device::execute()
308 {
309 	softfloat_exceptionFlags = 0;
310 	m_fsr &= ~FSR_TT;
311 
312 	m_status = 0;
313 	m_tcy = 0;
314 
315 	switch (m_idbyte)
316 	{
317 	case FORMAT_9:
318 		// format 9: 1111 1222 22oo ofii
319 		{
320 			bool const single = BIT(m_opword, 2);
321 			unsigned const f_length = single ? LENGTH_F : LENGTH_L;
322 			unsigned const size = m_opword & 3;
323 
324 			switch ((m_opword >> 3) & 7)
325 			{
326 			case 0:
327 				// MOVif src,dest
328 				//       gen,gen
329 				//       read.i,write.f
330 				{
331 					s32 const src =
332 						(size == SIZE_D) ? s32(m_op[0].value) :
333 						(size == SIZE_W) ? s16(m_op[0].value) :
334 						s8(m_op[0].value);
335 
336 					if (single)
337 						m_op[2].value = i32_to_f32(src).v;
338 					else
339 						m_op[2].value = i32_to_f64(src).v;
340 					m_op[2].expected = f_length;
341 					m_tcy = 53;
342 				}
343 				break;
344 			case 1:
345 				// LFSR src
346 				//      gen
347 				//      read.D
348 				m_fsr = u16(m_op[0].value);
349 
350 				switch (m_fsr & FSR_RM)
351 				{
352 				case RM_N: softfloat_roundingMode = softfloat_round_near_even; break;
353 				case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break;
354 				case RM_U: softfloat_roundingMode = softfloat_round_max; break;
355 				case RM_D: softfloat_roundingMode = softfloat_round_min; break;
356 				}
357 				m_tcy = 18;
358 				break;
359 			case 2:
360 				// MOVLF src,dest
361 				//       gen,gen
362 				//       read.L,write.F
363 				m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v;
364 				m_op[2].expected = f_length;
365 				m_tcy = (m_opword & 0xc000) ? 23 : 27;
366 				break;
367 			case 3:
368 				// MOVFL src,dest
369 				//       gen,gen
370 				//       read.F,write.L
371 				m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v;
372 				m_op[2].expected = f_length;
373 				m_tcy = (m_opword & 0xc000) ? 22 : 26;
374 				break;
375 			case 4:
376 				// ROUNDfi src,dest
377 				//         gen,gen
378 				//         read.f,write.i
379 				if (single)
380 					m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true);
381 				else
382 					m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true);
383 
384 				if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
385 				|| (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
386 				|| (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
387 					softfloat_exceptionFlags |= softfloat_flag_overflow;
388 
389 				m_op[2].expected = size + 1;
390 				m_tcy = (m_opword & 0xc000) ? 53 : 66;
391 				break;
392 			case 5:
393 				// TRUNCfi src,dest
394 				//         gen,gen
395 				//         read.f,write.i
396 				if (single)
397 					m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true);
398 				else
399 					m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true);
400 
401 				if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
402 				|| (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
403 				|| (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
404 					softfloat_exceptionFlags |= softfloat_flag_overflow;
405 
406 				m_op[2].expected = size + 1;
407 				m_tcy = (m_opword & 0xc000) ? 53 : 66;
408 				break;
409 			case 6:
410 				// SFSR dest
411 				//      gen
412 				//      write.D
413 				m_op[2].value = m_fsr;
414 				m_op[2].expected = 4;
415 				m_tcy = 13;
416 				break;
417 			case 7:
418 				// FLOORfi src,dest
419 				//         gen,gen
420 				//         read.f,write.i
421 				if (single)
422 					m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true);
423 				else
424 					m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true);
425 
426 				if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
427 				|| (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
428 				|| (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
429 					softfloat_exceptionFlags |= softfloat_flag_overflow;
430 
431 				m_op[2].expected = size + 1;
432 				m_tcy = (m_opword & 0xc000) ? 53 : 66;
433 				break;
434 			}
435 		}
436 		break;
437 
438 	case FORMAT_11:
439 		// format 11: 1111122222oooo0f
440 		{
441 			bool const single = BIT(m_opword, 0);
442 			unsigned const f_length = single ? LENGTH_F : LENGTH_L;
443 
444 			switch ((m_opword >> 2) & 15)
445 			{
446 			case 0x0:
447 				// ADDf src,dest
448 				//      gen,gen
449 				//      read.f,rmw.f
450 				if (single)
451 					m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
452 				else
453 					m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
454 				m_op[2].expected = f_length;
455 				m_tcy = (m_opword & 0xc600) ? 70 : 74;
456 				break;
457 			case 0x1:
458 				// MOVf src,dest
459 				//      gen,gen
460 				//      read.f,write.f
461 				m_op[2].value = m_op[0].value;
462 				m_op[2].expected = f_length;
463 				m_tcy = (m_opword & 0xc000) ? 23 : 27;
464 				break;
465 			case 0x2:
466 				// CMPf src1,src2
467 				//      gen,gen
468 				//      read.f,read.f
469 				if (m_op[0].value == m_op[1].value)
470 					m_status |= SLAVE_Z;
471 				if ((single && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }))
472 				|| (!single && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value })))
473 					m_status |= SLAVE_N;
474 				m_tcy = (m_opword & 0xc600) ? 45 : 49;
475 				break;
476 			case 0x3:
477 				// Trap(SLAVE)
478 				m_fsr |= TT_ILL;
479 				m_status = SLAVE_Q;
480 				break;
481 			case 0x4:
482 				// SUBf src,dest
483 				//      gen,gen
484 				//      read.f,rmw.f
485 				if (single)
486 					m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
487 				else
488 					m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
489 				m_op[2].expected = f_length;
490 				m_tcy = (m_opword & 0xc600) ? 70 : 74;
491 				break;
492 			case 0x5:
493 				// NEGf src,dest
494 				//      gen,gen
495 				//      read.f,write.f
496 				if (single)
497 					m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
498 				else
499 					m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
500 				m_op[2].expected = f_length;
501 				m_tcy = (m_opword & 0xc000) ? 20 : 24;
502 				break;
503 			case 0x8:
504 				// DIVf src,dest
505 				//      gen,gen
506 				//      read.f,rmw.f
507 				if (single)
508 					m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
509 				else
510 					m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
511 				m_op[2].expected = f_length;
512 				m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (single ? 30 : 60);
513 				break;
514 			case 0x9:
515 				// Trap(SLAVE)
516 				m_fsr |= TT_ILL;
517 				m_status = SLAVE_Q;
518 				break;
519 			case 0xc:
520 				// MULf src,dest
521 				//      gen,gen
522 				//      read.f,rmw.f
523 				if (single)
524 					m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
525 				else
526 					m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
527 				m_op[2].expected = f_length;
528 				m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (single ? 14 : 28);
529 				break;
530 			case 0xd:
531 				// ABSf src,dest
532 				//      gen,gen
533 				//      read.f,write.f
534 				if (single)
535 					if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 }))
536 						m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
537 					else
538 						m_op[2].value = float32_t{ u32(m_op[0].value) }.v;
539 				else
540 					if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 }))
541 						m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
542 					else
543 						m_op[2].value = float64_t{ m_op[0].value }.v;
544 				m_op[2].expected = f_length;
545 				m_tcy = (m_opword & 0xc000) ? 20 : 24;
546 				break;
547 			}
548 		}
549 		break;
550 	}
551 
552 	// check for exceptions
553 	if (softfloat_exceptionFlags & softfloat_flag_underflow)
554 	{
555 		m_fsr |= FSR_UF | TT_UND;
556 
557 		if (m_fsr & FSR_UEN)
558 			m_status |= SLAVE_Q;
559 		else
560 			m_op[2].value = 0;
561 	}
562 	else if (softfloat_exceptionFlags & softfloat_flag_overflow)
563 	{
564 		m_fsr |= TT_OVF;
565 		m_status |= SLAVE_Q;
566 	}
567 	else if (softfloat_exceptionFlags & softfloat_flag_infinite)
568 	{
569 		m_fsr |= TT_DVZ;
570 		m_status |= SLAVE_Q;
571 	}
572 	else if (softfloat_exceptionFlags & softfloat_flag_invalid)
573 		m_fsr |= TT_INV;
574 	else if (softfloat_exceptionFlags & softfloat_flag_inexact)
575 	{
576 		m_fsr |= FSR_IF | TT_INX;
577 
578 		if (m_fsr & FSR_IEN)
579 			m_status |= SLAVE_Q;
580 	}
581 
582 	// exceptions suppress result issue
583 	if (m_status & SLAVE_Q)
584 		m_op[2].expected = 0;
585 
586 	if (VERBOSE & LOG_GENERAL)
587 	{
588 		static char const *format9[] = { "movif", "lfsr", "movlf", "movfl", "roundfi", "truncfi", "sfsr", "floorfi" };
589 		static char const *format11[] =
590 		{
591 			"addf", "movf", "cmpf", nullptr, "subf", "negf", nullptr, nullptr,
592 			"divf", nullptr, nullptr, nullptr, "mulf", "absf", nullptr, nullptr
593 		};
594 
595 		if (m_status & SLAVE_Q)
596 			LOG("execute %s 0x%x,0x%x exception\n",
597 				(m_idbyte == FORMAT_9)
598 					? format9[(m_opword >> 3) & 7]
599 					: format11[(m_opword >> 2) & 15],
600 				m_op[0].value, m_op[1].value);
601 		else
602 			LOG("execute %s 0x%x,0x%x result 0x%x\n",
603 				(m_idbyte == FORMAT_9)
604 					? format9[(m_opword >> 3) & 7]
605 					: format11[(m_opword >> 2) & 15],
606 				m_op[0].value, m_op[1].value, m_op[2].value);
607 	}
608 
609 	// write-back floating point register results
610 	if (m_op[2].expected && !(m_opword & 0x0600))
611 	{
612 		// exclude integer results (roundfi, truncfi, sfsr, floorfi)
613 		if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) < 4)
614 		{
615 			unsigned const reg = (m_opword >> 6) & 7;
616 
617 			LOG("execute write-back f%d\n", reg);
618 
619 			m_f[reg ^ 0] = u32(m_op[2].value >> 0);
620 			if (m_op[2].expected == 8)
621 				m_f[reg ^ 1] = u32(m_op[2].value >> 32);
622 
623 			m_op[2].issued = m_op[2].expected;
624 		}
625 	}
626 
627 	m_state = STATUS;
628 
629 	if (m_out_scb)
630 		m_complete->adjust(attotime::from_ticks(m_tcy, clock()));
631 }
632 
complete(void * buf,s32 param)633 void ns32081_device::complete(void *buf, s32 param)
634 {
635 	m_out_scb(0);
636 	m_out_scb(1);
637 }
638