|
|
1.1 root 1: /***************************************************************************
2:
3: i860dec.inc
4:
5: Execution engine for the Intel i860 emulator.
6:
7: Copyright (C) 1995-present Jason Eckhardt ([email protected])
8: Released for general non-commercial use under the MAME license
9: with the additional requirement that you are free to use and
10: redistribute this code in modified or unmodified form, provided
11: you list me in the credits.
12: Visit http://mamedev.org for licensing and usage restrictions.
13:
14: Changes for previous/NeXTdimension by Simon Schubiger (SC)
15:
16: ***************************************************************************/
17:
18: /*
19: * References:
20: * `i860 Microprocessor Programmer's Reference Manual', Intel, 1990.
21: *
22: * This code was originally written by Jason Eckhardt as part of an
23: * emulator for some i860-based Unix workstations (early 1990's) such
24: * as the Stardent Vistra 800 series and the OkiStation/i860 7300 series.
25: * The code you are reading now is the i860 CPU portion only, which has
26: * been adapted to (and simplified for) MAME.
27: * MAME-specific notes:
28: * - i860XR emulation only (i860XP unnecessary for MAME).
29: * - No emulation of data and instruction caches (unnecessary for MAME version).
30: * - No emulation of DIM mode or CS8 mode (unnecessary for MAME version).
31: * - No BL/IL/locked sequences (unnecessary for MAME).
32: * NeXTdimension specfic notes:
33: * - (SC) Added support for i860's MSB/LSB-first mode (BE = 1/0).
34: * - (SC) We assume that the host CPU is little endian (for now, will be fixed)
35: * - (SC) Instruction cache implemented (not present in MAME version)
36: * - (SC) Added dual-instruction-mode support (removed in MAME version)
37: * - (SC) Added rounding mode support and insn_fix
38: * Generic notes:
39: * - There is some amount of code duplication (e.g., see the
40: * various insn_* routines for the branches and FP routines) that
41: * could be eliminated.
42: * - The host's floating point types are used to emulate the i860's
43: * floating point. Should probably be made machine independent by
44: * using an IEEE FP emulation library. On the other hand, most machines
45: * today also use IEEE FP.
46: *
47: */
48: #include <math.h>
49: #include <fenv.h>
50: #include <assert.h>
51:
52: #pragma STDC FENV_ACCESS on
53:
54: #define DELAY_SLOT_PC() ((m_dim == DIM_FULL) ? 12 : 8)
55: #define DELAY_SLOT() do{\
56: m_pc += 4; \
57: UINT32 insn = ifetch(orig_pc+4);\
58: decode_exec(insn); \
59: if((m_dim == DIM_FULL) || (m_flow & DIM_OP)) {\
60: m_pc += 4; \
61: decode_exec(ifetch(orig_pc+8)); \
62: } \
63: m_pc = orig_pc;}while(0)
64:
65: int i860_cpu_device::delay_slots(UINT32 insn) {
66: int opc = (insn >> 26) & 0x3f;
67: if (opc == 0x10 || opc == 0x1a || opc == 0x1b || opc == 0x1d ||
68: opc == 0x1f || opc == 0x2d || (opc == 0x13 && (insn & 3) == 2))
69: return m_dim ? 2 : 1;
70: return 0;
71: }
72:
73: void i860_cpu_device::intr() {
74: m_flow |= EXT_INTR;
75: }
76:
77: /* This is the external interface for indicating an external interrupt
78: to the i860. */
79: void i860_cpu_device::gen_interrupt()
80: {
81: /* If interrupts are enabled, then set PSR.IN and prepare for trap.
82: Otherwise, the external interrupt is ignored. We also set
83: bit EPSR.INT (which tracks the INT pin). */
84: if (GET_PSR_IM ()) {
85: SET_PSR_IN (1);
86: m_flow |= TRAP_WAS_EXTERNAL;
87: }
88: SET_EPSR_INT (1);
89:
90: #if TRACE_EXT_INT
91: Log_Printf(LOG_WARN, "[i860] i860_gen_interrupt: External interrupt received %s", GET_PSR_IM() ? "[PSR.IN set, preparing to trap]" : "[ignored (interrupts disabled)]");
92: #endif
93: #if ENABLE_PERF_COUNTERS
94: m_intrs++;
95: #endif
96: }
97:
98:
99: /* This is the external interface for indicating an external interrupt
100: to the i860. */
101: void i860_cpu_device::clr_interrupt() {
102: SET_EPSR_INT (0);
103: }
104:
105: void i860_cpu_device::invalidate_icache() {
106: memset(m_icache_vaddr, 0xff, sizeof(UINT32) * (1<<I860_ICACHE_SZ));
107: #if ENABLE_PERF_COUNTERS
108: m_icache_inval++;
109: #endif
110: }
111:
112: void i860_cpu_device::invalidate_tlb() {
113: memset(m_tlb_vaddr, 0xff, sizeof(UINT32) * (1<<I860_TLB_SZ));
114: #if ENABLE_PERF_COUNTERS
115: m_tlb_inval++;
116: #endif
117: }
118:
119: UINT32 i860_cpu_device::ifetch_notrap(const UINT32 pc) {
120: UINT32 before = m_flow;
121: m_flow &= ~TRAP_MASK;
122: UINT32 result = ifetch(pc);
123: m_flow = before;
124: return result;
125: }
126:
127: UINT32 i860_cpu_device::ifetch(const UINT32 pc) {
128: return pc & 4 ? ifetch64(pc) >> 32 : ifetch64(pc);
129: }
130:
131: UINT64 i860_cpu_device::ifetch64(const UINT32 pc) {
132: const UINT32 vaddr = pc & ~7;
133: const int cidx = (vaddr>>3) & I860_ICACHE_MASK;
134: if(m_icache_vaddr[cidx] != vaddr) {
135: #if ENABLE_PERF_COUNTERS
136: m_icache_miss++;
137: #endif
138: UINT32 paddr;
139:
140: if (GET_DIRBASE_ATE ()) {
141: paddr = get_address_translation (pc, 0 /* is_dataref */, 0 /* is_write */) & ~7;
142: m_flow &= ~EXITING_IFETCH;
143: if (PENDING_TRAP() && (GET_PSR_DAT () || GET_PSR_IAT ())) {
144: m_flow |= EXITING_IFETCH;
145: return 0xffeeffeeffeeffeeLL;
146: }
147: } else
148: paddr = vaddr;
149:
150: m_icache_vaddr[cidx] = vaddr;
151: UINT64 insn64;
152: if (GET_DIRBASE_CS8()) {
153: insn64 = rdcs8(paddr+7); insn64 <<= 8;
154: insn64 |= rdcs8(paddr+6); insn64 <<= 8;
155: insn64 |= rdcs8(paddr+5); insn64 <<= 8;
156: insn64 |= rdcs8(paddr+4); insn64 <<= 8;
157: insn64 |= rdcs8(paddr+3); insn64 <<= 8;
158: insn64 |= rdcs8(paddr+2); insn64 <<= 8;
159: insn64 |= rdcs8(paddr+1); insn64 <<= 8;
160: insn64 |= rdcs8(paddr+0);
161: } else {
162: nd_board_rd64_be(paddr, (UINT32*)&insn64);
163: }
164: m_icache[cidx] = insn64;
165:
166: return insn64;
167: } else {
168: #if ENABLE_PERF_COUNTERS
169: m_icache_hit++;
170: #endif
171: return m_icache[cidx];
172: }
173: }
174:
175: /* Given a virtual address, perform the i860 address translation and
176: return the corresponding physical address.
177: vaddr: virtual address
178: is_dataref: 1 = load/store, 0 = instruction fetch.
179: is_write: 1 = writing to vaddr, 0 = reading from vaddr
180: The last two arguments are only used to determine what types
181: of traps should be taken.
182:
183: Page tables must always be in memory (not cached). So the routine
184: here only accesses memory.
185:
186: (SC) added TLB support. Read access updates even entries, Write access updates odd entries.
187: TLB lookup checks both entries. R/W separation is for DPS copy loops.
188: */
189: UINT32 i860_cpu_device::get_address_translation (UINT32 vaddr, int is_dataref, int is_write)
190: {
191: UINT32 voffset = vaddr & I860_PAGE_OFF_MASK;
192: UINT32 tlbidx = ((vaddr << 1) | is_write) & I860_TLB_MASK;
193:
194: if(m_tlb_vaddr[tlbidx] == (vaddr & I860_PAGE_FRAME_MASK)) {
195: #if ENABLE_PERF_COUNTERS
196: m_tlb_hit++;
197: #endif
198: return (m_tlb_paddr[tlbidx] & I860_PAGE_FRAME_MASK) + voffset;
199: }
200:
201: if(m_tlb_vaddr[tlbidx ^ 1] == (vaddr & I860_PAGE_FRAME_MASK)) {
202: #if ENABLE_PERF_COUNTERS
203: m_tlb_hit++;
204: #endif
205: return (m_tlb_paddr[tlbidx ^ 1] & I860_PAGE_FRAME_MASK) + voffset;
206: }
207:
208: #if ENABLE_PERF_COUNTERS
209: m_tlb_miss++;
210: #endif
211:
212: UINT32 vpage = (vaddr >> I860_PAGE_SZ) & 0x3ff;
213: UINT32 vdir = (vaddr >> 22) & 0x3ff;
214: UINT32 dtb = (m_cregs[CR_DIRBASE]) & I860_PAGE_FRAME_MASK;
215: UINT32 pg_dir_entry_a = 0;
216: UINT32 pg_dir_entry = 0;
217: UINT32 pg_tbl_entry_a = 0;
218: UINT32 pg_tbl_entry = 0;
219: UINT32 pfa1 = 0;
220: UINT32 pfa2 = 0;
221: UINT32 ret = 0;
222: UINT32 ttpde = 0;
223: UINT32 ttpte = 0;
224:
225: assert (GET_DIRBASE_ATE ());
226:
227: /* Get page directory entry at DTB:DIR:00. */
228: pg_dir_entry_a = dtb | (vdir << 2);
229: nd_board_rd32_le(pg_dir_entry_a, &pg_dir_entry);
230:
231: /* Check for non-present PDE. */
232: if (!(pg_dir_entry & 1))
233: {
234: /* PDE is not present, generate DAT or IAT. */
235: if (is_dataref)
236: SET_PSR_DAT (1);
237: else
238: SET_PSR_IAT (1);
239: m_flow |= TRAP_NORMAL;
240:
241: /* Dummy return. */
242: return 0;
243: }
244:
245: /* PDE Check for write protection violations. */
246: if (is_write && is_dataref
247: && !(pg_dir_entry & 2) /* W = 0. */
248: && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */
249: {
250: SET_PSR_DAT (1);
251: m_flow |= TRAP_NORMAL;
252: /* Dummy return. */
253: return 0;
254: }
255:
256: /* PDE Check for user-mode access to supervisor pages. */
257: if (GET_PSR_U ()
258: && !(pg_dir_entry & 4)) /* U = 0. */
259: {
260: if (is_dataref)
261: SET_PSR_DAT (1);
262: else
263: SET_PSR_IAT (1);
264: m_flow |= TRAP_NORMAL;
265: /* Dummy return. */
266: return 0;
267: }
268:
269: /* FIXME: How exactly to handle A check/update?. */
270:
271: /* Get page table entry at PFA1:PAGE:00. */
272: pfa1 = pg_dir_entry & I860_PAGE_FRAME_MASK;
273: pg_tbl_entry_a = pfa1 | (vpage << 2);
274: nd_board_rd32_le(pg_tbl_entry_a, &pg_tbl_entry);
275:
276: /* Check for non-present PTE. */
277: if (!(pg_tbl_entry & 1))
278: {
279: /* PTE is not present, generate DAT or IAT. */
280: if (is_dataref)
281: SET_PSR_DAT (1);
282: else
283: SET_PSR_IAT (1);
284: m_flow |= TRAP_NORMAL;
285:
286: /* Dummy return. */
287: return 0;
288: }
289:
290: /* PTE Check for write protection violations. */
291: if (is_write && is_dataref
292: && !(pg_tbl_entry & 2) /* W = 0. */
293: && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */
294: {
295: SET_PSR_DAT (1);
296: m_flow |= TRAP_NORMAL;
297: /* Dummy return. */
298: return 0;
299: }
300:
301: /* PTE Check for user-mode access to supervisor pages. */
302: if (GET_PSR_U ()
303: && !(pg_tbl_entry & 4)) /* U = 0. */
304: {
305: if (is_dataref)
306: SET_PSR_DAT (1);
307: else
308: SET_PSR_IAT (1);
309: m_flow |= TRAP_NORMAL;
310: /* Dummy return. */
311: return 0;
312: }
313:
314: /* Update A bit and check D bit. */
315: ttpde = pg_dir_entry | 0x20;
316: ttpte = pg_tbl_entry | 0x20;
317: nd_board_wr32_le(pg_dir_entry_a, &ttpde);
318: nd_board_wr32_le(pg_tbl_entry_a, &ttpte);
319:
320: if (is_write && is_dataref && (pg_tbl_entry & 0x40) == 0)
321: {
322: /* Log_Printf(LOG_WARN, "[i860] DAT trap on write without dirty bit v%08X/p%08X\n",
323: vaddr, (pg_tbl_entry & ~0xfff)|voffset); */
324: SET_PSR_DAT (1);
325: m_flow |= TRAP_NORMAL;
326: /* Dummy return. */
327: return 0;
328: }
329:
330: pfa2 = (pg_tbl_entry & I860_PAGE_FRAME_MASK);
331:
332: m_tlb_vaddr[tlbidx] = vaddr & I860_PAGE_FRAME_MASK;
333: m_tlb_paddr[tlbidx] = pfa2;
334:
335: ret = pfa2 | voffset;
336:
337: #if TRACE_ADDR_TRANSLATION
338: Log_Printf(LOG_WARN, "[i860] get_address_translation: virt(%08X) -> phys(%08X)\n", vaddr, ret);
339: #endif
340:
341: return ret;
342: }
343:
344: /* Write memory emulation.
345: addr = address to write.
346: size = size of write in bytes.
347: data = data to write. */
348: void i860_cpu_device::writemem_emu (UINT32 addr, int size, UINT8 *data) {
349: #if TRACE_RDWR_MEM
350: Log_Printf(LOG_WARN, "[i860] wrmem (ATE=%d) addr = %08X, size = %d, data = %08X\n", GET_DIRBASE_ATE (), addr, size, data); fflush(0);
351: #endif
352:
353: #if ENABLE_DEBUGGER
354: dbg_check_wr(addr, size, data);
355: #endif
356:
357: /* If virtual mode, do translation. */
358: if (GET_DIRBASE_ATE ())
359: {
360: UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 1 /* is_write */);
361: if (PENDING_TRAP() && (GET_PSR_IAT () || GET_PSR_DAT ()))
362: {
363: #if TRACE_PAGE_FAULT
364: Log_Printf(LOG_WARN, "[i860] %08X: ## Page fault (writememi_emu) virt=%08X", m_pc, addr);
365: #endif
366: SET_EXITING_MEMRW(EXITING_WRITEMEM);
367: return;
368: }
369: addr = phys;
370: }
371:
372: #if ENABLE_I860_DB_BREAK
373: /* First check for match to db register (before write). */
374: if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BW ())
375: {
376: SET_PSR_DAT (1);
377: m_flow |= TRAP_NORMAL;
378: return;
379: }
380: #endif
381:
382: /* Now do the actual write. */
383: wrmem[size](addr, (UINT32*)data);
384: }
385:
386:
387: /* Floating-point read mem routine.
388: addr = address to read.
389: size = size of read in bytes.
390: dest = memory to put read data. */
391: void i860_cpu_device::readmem_emu (UINT32 addr, int size, UINT8 *dest)
392: {
393: #if TRACE_RDWR_MEM
394: Log_Printf(LOG_WARN, "[i860] fp_rdmem (ATE=%d) addr = %08X, size = %d\n", GET_DIRBASE_ATE (), addr, size); fflush(0);
395: #endif
396:
397: /* If virtual mode, do translation. */
398: if (GET_DIRBASE_ATE ())
399: {
400: UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */);
401: if (PENDING_TRAP() && (GET_PSR_IAT () || GET_PSR_DAT ()))
402: {
403: #if TRACE_PAGE_FAULT
404: Log_Printf(LOG_WARN, "[i860] %08X: ## Page fault (fp_readmem_emu) virt=%08X",m_pc,addr);
405: // debugger();
406: #endif
407: SET_EXITING_MEMRW(EXITING_FPREADMEM);
408: return;
409: }
410: addr = phys;
411: }
412:
413: #if ENABLE_I860_DB_BREAK
414: /* First check for match to db register (before read). */
415: if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BR ())
416: {
417: SET_PSR_DAT (1);
418: m_flow |= TRAP_NORMAL;
419: return;
420: }
421: #endif
422: rdmem[size](addr, (UINT32*)dest);
423: }
424:
425:
426: /* Floating-point write mem routine.
427: addr = address to write.
428: size = size of write in bytes.
429: data = pointer to the data.
430: wmask = bit mask of bytes to write (only for pst.d). */
431: void i860_cpu_device::writemem_emu (UINT32 addr, int size, UINT8 *data, UINT32 wmask)
432: {
433: #if TRACE_RDWR_MEM
434: Log_Printf(LOG_WARN, "[i860] fp_wrmem (ATE=%d) addr = %08X, size = %d", GET_DIRBASE_ATE (), addr, size); fflush(0);
435: #endif
436:
437: /* If virtual mode, do translation. */
438: if (GET_DIRBASE_ATE ())
439: {
440: UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 1 /* is_write */);
441: if (PENDING_TRAP() && GET_PSR_DAT ())
442: {
443: #if TRACE_PAGE_FAULT
444: Log_Printf(LOG_WARN, "[i860] %08X: ## Page fault (fp_writememi_emu) virt=%08X", m_pc,addr);
445: // debugger();
446: #endif
447: SET_EXITING_MEMRW(EXITING_WRITEMEM);
448: return;
449: }
450: addr = phys;
451: }
452:
453: #if ENABLE_I860_DB_BREAK
454: /* First check for match to db register (before read). */
455: if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BW ())
456: {
457: SET_PSR_DAT (1);
458: m_flow |= TRAP_NORMAL;
459: return;
460: }
461: #endif
462:
463: if(size == 8 && wmask != 0xff) {
464: if (wmask & 0x80) wrmem[1](addr+0, (UINT32*)&data[0]);
465: if (wmask & 0x40) wrmem[1](addr+1, (UINT32*)&data[1]);
466: if (wmask & 0x20) wrmem[1](addr+2, (UINT32*)&data[2]);
467: if (wmask & 0x10) wrmem[1](addr+3, (UINT32*)&data[3]);
468: if (wmask & 0x08) wrmem[1](addr+4, (UINT32*)&data[4]);
469: if (wmask & 0x04) wrmem[1](addr+5, (UINT32*)&data[5]);
470: if (wmask & 0x02) wrmem[1](addr+6, (UINT32*)&data[6]);
471: if (wmask & 0x01) wrmem[1](addr+7, (UINT32*)&data[7]);
472: } else {
473: wrmem[size](addr, (UINT32*)data);
474: }
475: }
476:
477: /* Sign extend N-bit number. */
478: inline INT32 sign_ext (UINT32 x, int n)
479: {
480: INT32 t;
481: t = x >> (n - 1);
482: t = ((-t) << n) | x;
483: return t;
484: }
485:
486:
487: void i860_cpu_device::unrecog_opcode (UINT32 pc, UINT32 insn) {
488: debugger('d', "unrecognized opcode %08X pc=%08X", insn, pc);
489: SET_PSR_IT (1);
490: m_flow |= TRAP_NORMAL;
491: }
492:
493:
494: /* Execute "ld.c csrc2,idest" instruction. */
495: void i860_cpu_device::insn_ld_ctrl (UINT32 insn)
496: {
497: UINT32 csrc2 = get_creg (insn);
498: UINT32 idest = get_idest (insn);
499:
500: #if TRACE_UNDEFINED_I860
501: if (csrc2 > 5)
502: {
503: /* Control register not between 0..5. Undefined i860XR behavior. */
504: Log_Printf(LOG_WARN, "[i860:%08X] insn_ld_from_ctrl: bad creg in ld.c (ignored)", m_pc);
505: return;
506: }
507: #endif
508:
509: /* If this is a load of the fir, then there are two cases:
510: 1. First load of fir after a trap = usual value.
511: 2. Not first load of fir after a trap = address of the ld.c insn. */
512: if (csrc2 == CR_FIR)
513: {
514: if (m_flow & FIR_GETS_TRAP)
515: set_iregval (idest, m_cregs[csrc2]);
516: else
517: {
518: m_cregs[csrc2] = m_pc;
519: set_iregval (idest, m_cregs[csrc2]);
520: }
521: m_flow &= ~FIR_GETS_TRAP;
522: }
523: else
524: set_iregval (idest, m_cregs[csrc2]);
525: }
526:
527:
528: /* Execute "st.c isrc1,csrc2" instruction. */
529: void i860_cpu_device::insn_st_ctrl (UINT32 insn)
530: {
531: UINT32 csrc2 = get_creg (insn);
532: UINT32 isrc1 = get_isrc1 (insn);
533:
534: #if TRACE_UNDEFINED_I860
535: if (csrc2 > 5)
536: {
537: /* Control register not between 0..5. Undefined i860XR behavior. */
538: Log_Printf(LOG_WARN, "[i860:%08X] insn_st_to_ctrl: bad creg in st.c (ignored)", m_pc);
539: return;
540: }
541: #endif
542:
543: /* Look for CS8 bit turned off). */
544: if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 0x80) == 0 && GET_DIRBASE_CS8()) {
545: Log_Printf(LOG_WARN, "[i860:%08X] Leaving CS8 mode", m_pc);
546: Statusbar_SetNdLed(2);
547: }
548:
549: /* Look for ITI bit turned on (but it never actually is written --
550: it always appears to be 0). */
551: if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 0x20))
552: {
553: invalidate_icache();
554: invalidate_tlb();
555:
556: /* Make sure ITI isn't actually written. */
557: set_iregval (isrc1, (get_iregval (isrc1) & ~0x20));
558: }
559:
560: if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 1) && GET_DIRBASE_ATE () == 0){
561: Log_Printf(LOG_WARN, "[i860:%08X]** Switching to virtual addressing (ATE=1)", m_pc);
562: }
563:
564: /* Update the register -- unless it is fir which cannot be updated. */
565: if (csrc2 == CR_EPSR)
566: {
567: UINT32 enew = 0, tmp = 0;
568: /* Make sure unchangeable EPSR bits stay unchanged (DCS, stepping,
569: and type). Also, some bits are only writeable in supervisor
570: mode. */
571: if (GET_PSR_U ())
572: {
573: enew = get_iregval (isrc1) & ~(0x003e1fff | 0x00c06000);
574: tmp = m_cregs[CR_EPSR] & (0x003e1fff | 0x00c06000);
575: }
576: else
577: {
578: enew = get_iregval (isrc1) & ~0x003e1fff;
579: tmp = m_cregs[CR_EPSR] & 0x003e1fff;
580: }
581: if((enew ^ m_cregs[CR_EPSR]) & 0x00800000) { // BE/LE change
582: set_mem_access((enew & 0x00800000) != 0);
583: }
584: m_cregs[CR_EPSR] = enew | tmp;
585: }
586: else if (csrc2 == CR_PSR)
587: {
588: /* Some PSR bits are only writeable in supervisor mode. */
589: if (GET_PSR_U ())
590: {
591: UINT32 enew = get_iregval (isrc1) & ~PSR_SUPERVISOR_ONLY_MASK;
592: UINT32 tmp = m_cregs[CR_PSR] & PSR_SUPERVISOR_ONLY_MASK;
593: m_cregs[CR_PSR] = enew | tmp;
594: }
595: else
596: m_cregs[CR_PSR] = get_iregval (isrc1);
597: }
598: else if (csrc2 == CR_FSR)
599: {
600: /* I believe that only 21..17, 8..5, and 3..0 should be updated. */
601: UINT32 enew = get_iregval (isrc1) & 0x003e01ef;
602: UINT32 tmp = m_cregs[CR_FSR] & ~0x003e01ef;
603: m_cregs[CR_FSR] = enew | tmp;
604: switch(GET_FSR_RM()) {
605: case 0: fesetround(FE_TONEAREST); break;
606: case 1: fesetround(FE_DOWNWARD); break;
607: case 2: fesetround(FE_UPWARD); break;
608: case 3: fesetround(FE_TOWARDZERO); break;
609: }
610: }
611: else if (csrc2 != CR_FIR)
612: m_cregs[csrc2] = get_iregval (isrc1);
613: }
614:
615:
616: /* Execute "ld.{s,b,l} isrc1(isrc2),idest" or
617: "ld.{s,b,l} #const(isrc2),idest". */
618: void i860_cpu_device::insn_ldx (UINT32 insn)
619: {
620: UINT32 isrc1 = get_isrc1 (insn);
621: INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
622: UINT32 isrc2 = get_isrc2 (insn);
623: UINT32 idest = get_idest (insn);
624: UINT32 eff = 0;
625: /* Operand size, in bytes. */
626: int sizes[4] = { 1, 1, 2, 4};
627: int size = 0;
628: int form_disp_reg = 0;
629:
630: /* Bits 28 and 0 determine the operand size. */
631: size = sizes[((insn >> 27) & 2) | (insn & 1)];
632:
633: /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
634: form_disp_reg = (insn & 0x04000000);
635:
636: /* Get effective address depending on disp+reg or reg+reg form. */
637: if (form_disp_reg)
638: {
639: /* Chop off lower bits of displacement. */
640: immsrc1 &= ~(size - 1);
641: eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
642: }
643: else
644: eff = get_iregval (isrc1) + get_iregval (isrc2);
645:
646: #if TRACE_UNALIGNED_MEM
647: if (eff & (size - 1))
648: {
649: Log_Printf(LOG_WARN, "[i860:%08X] Unaligned access detected (%08X)", m_pc, eff);
650: SET_PSR_DAT (1);
651: m_flow |= TRAP_NORMAL;
652: return;
653: }
654: #endif
655:
656: /* The i860 sign-extends 8- or 16-bit integer loads.
657:
658: Below, the readmemi_emu() needs to happen outside of the
659: set_iregval macro (otherwise the readmem won't occur if r0
660: is the target register). */
661: if (size < 4) {
662: UINT32 readval = 0; readmem_emu(eff, size, (UINT8*)&readval);
663: readval = sign_ext (readval, size * 8);
664: /* Do not update register on page fault. */
665: if (GET_EXITING_MEMRW())
666: {
667: return;
668: }
669: set_iregval (idest, readval);
670: }
671: else
672: {
673: UINT32 readval; readmem_emu(eff, size, (UINT8*)&readval);
674: /* Do not update register on page fault. */
675: if (GET_EXITING_MEMRW())
676: {
677: return;
678: }
679: set_iregval (idest, readval);
680: }
681: }
682:
683:
684: /* Execute "st.x isrc1ni,#const(isrc2)" instruction (there is no
685: (reg + reg form). Store uses the split immediate, not the normal
686: 16-bit immediate as in ld.x. */
687: void i860_cpu_device::insn_stx (UINT32 insn)
688: {
689: INT32 immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
690: UINT32 isrc1 = get_isrc1 (insn);
691: UINT32 isrc2 = get_isrc2 (insn);
692: UINT32 eff = 0;
693: /* Operand size, in bytes. */
694: int sizes[4] = { 1, 1, 2, 4};
695: int size = 0;
696:
697: /* Bits 28 and 0 determine the operand size. */
698: size = sizes[((insn >> 27) & 2) | (insn & 1)];
699:
700: /* FIXME: Do any necessary traps. */
701:
702: /* Get effective address. Chop off lower bits of displacement. */
703: immsrc &= ~(size - 1);
704: eff = (UINT32)(immsrc + (INT32)get_iregval (isrc2));
705:
706: /* Write data (value of reg isrc1) to memory at eff. */
707: UINT32 tmp32 = get_iregval (isrc1);
708: writemem_emu (eff, size, (UINT8*)&tmp32);
709: if (GET_EXITING_MEMRW())
710: return;
711: }
712:
713:
714: /* Execute "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++",
715: "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++"
716: instruction. */
717: void i860_cpu_device::insn_fsty (UINT32 insn)
718: {
719: UINT32 isrc1 = get_isrc1 (insn);
720: INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
721: UINT32 isrc2 = get_isrc2 (insn);
722: UINT32 fdest = get_fdest (insn);
723: UINT32 eff = 0;
724: /* Operand size, in bytes. */
725: int sizes[4] = { 8, 4, 16, 4};
726: int size = 0;
727: int form_disp_reg = 0;
728: int auto_inc = (insn & 1);
729:
730: /* Bits 2 and 1 determine the operand size. */
731: size = sizes[((insn >> 1) & 3)];
732:
733: /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
734: form_disp_reg = (insn & 0x04000000);
735:
736: /* FIXME: Check for undefined behavior, non-even or non-quad
737: register operands for fst.d and fst.q respectively. */
738:
739: /* Get effective address depending on disp+reg or reg+reg form. */
740: if (form_disp_reg)
741: {
742: /* Chop off lower bits of displacement. */
743: immsrc1 &= ~(size - 1);
744: eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
745: }
746: else
747: eff = get_iregval (isrc1) + get_iregval (isrc2);
748:
749: #if TRACE_UNALIGNED_MEM
750: if (eff & (size - 1))
751: {
752: Log_Printf(LOG_WARN, "[i860:%08X] Unaligned access detected (%08X)", m_pc, eff);
753: SET_PSR_DAT (1);
754: m_flow |= TRAP_NORMAL;
755: return;
756: }
757: #endif
758:
759: /* Do (post) auto-increment. */
760: if (auto_inc)
761: {
762: set_iregval (isrc2, eff);
763: #if TRACE_UNDEFINED_I860
764: /* When auto-inc, isrc1 and isrc2 regs can't be the same. */
765: if (isrc1 == isrc2)
766: {
767: /* Undefined i860XR behavior. */
768: Log_Printf(LOG_WARN, "[i860:%08X] insn_fsty: isrc1 = isrc2 in fst with auto-inc (ignored)", m_pc);
769: return;
770: }
771: #endif
772: }
773:
774: /* Write data (value of freg fdest) to memory at eff. */
775: writemem_emu (eff, size, (UINT8 *)(&m_fregs[4 * fdest]), 0xff);
776: }
777:
778:
779: /* Execute "fld.y isrc1(isrc2),fdest", "fld.y isrc1(isrc2)++,idest",
780: "fld.y #const(isrc2),fdest" or "fld.y #const(isrc2)++,idest".
781: Where y = {l,d,q}. Note, there is no pfld.q, though. */
782: void i860_cpu_device::insn_fldy (UINT32 insn)
783: {
784: UINT32 isrc1 = get_isrc1 (insn);
785: INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
786: UINT32 isrc2 = get_isrc2 (insn);
787: UINT32 fdest = get_fdest (insn);
788: UINT32 eff = 0;
789: /* Operand size, in bytes. */
790: int sizes[4] = { 8, 4, 16, 4};
791: int size = 0;
792: int form_disp_reg = 0;
793: int auto_inc = (insn & 1);
794: int piped = (insn & 0x40000000);
795:
796: /* Bits 2 and 1 determine the operand size. */
797: size = sizes[((insn >> 1) & 3)];
798:
799: /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */
800: form_disp_reg = (insn & 0x04000000);
801:
802: #if TRACE_UNDEFINED_I860
803: /* There is no pipelined load quad. */
804: if (piped && size == 16)
805: {
806: unrecog_opcode (m_pc, insn);
807: return;
808: }
809: #endif
810:
811: /* FIXME: Check for undefined behavior, non-even or non-quad
812: register operands for fld.d and fld.q respectively. */
813:
814: /* Get effective address depending on disp+reg or reg+reg form. */
815: if (form_disp_reg)
816: {
817: /* Chop off lower bits of displacement. */
818: immsrc1 &= ~(size - 1);
819: eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
820: }
821: else
822: eff = get_iregval (isrc1) + get_iregval (isrc2);
823:
824: /* Do (post) auto-increment. */
825: if (auto_inc)
826: {
827: set_iregval (isrc2, eff);
828: #if TRACE_UNDEFINED_I860
829: /* When auto-inc, isrc1 and isrc2 regs can't be the same. */
830: if (isrc1 == isrc2)
831: {
832: /* Undefined i860XR behavior. */
833: Log_Printf(LOG_WARN, "[i860:%08X] insn_fldy: isrc1 = isrc2 in fst with auto-inc (ignored)", m_pc);
834: return;
835: }
836: #endif
837: }
838:
839: #if TRACE_UNALIGNED_MEM
840: if (eff & (size - 1))
841: {
842: Log_Printf(LOG_WARN, "[i860:%08X] Unaligned access detected (%08X)", m_pc, eff);
843: SET_PSR_DAT (1);
844: m_flow |= TRAP_NORMAL;
845: return;
846: }
847: #endif
848:
849: /* Update the load pipe if necessary. */
850: /* FIXME: Copy result-status bits to fsr from last stage. */
851: if (!piped)
852: {
853: /* Scalar version writes the current result to fdest. */
854: /* Read data at 'eff' into freg 'fdest' (reads to f0 or f1 are
855: thrown away). */
856: readmem_emu(eff, size, (UINT8 *)&(m_fregs[4 * fdest]));
857: if (fdest < 2) {
858: // (SC) special case with fdest=fr0/fr1. fr0 & fr1 are overwritten with values from mem
859: // but always read as zero. Fix it.
860: m_fregs[0] = 0; m_fregs[1] = 0; m_fregs[2] = 0; m_fregs[3] = 0;
861: m_fregs[4] = 0; m_fregs[5] = 0; m_fregs[6] = 0; m_fregs[7] = 0;
862: }
863: }
864: else
865: {
866: /* Read the data into a temp space first. This way we can test
867: for any traps before updating the pipeline. The pipeline must
868: stay unaffected after a trap so that the instruction can be
869: properly restarted. */
870: UINT8 bebuf[8];
871: readmem_emu (eff, size, bebuf);
872: if (PENDING_TRAP() && GET_EXITING_MEMRW())
873: goto ab_op;
874:
875: /* Pipelined version writes fdest with the result from the last
876: stage of the pipeline, with precision specified by the LRP
877: bit of the stage's result-status bits. */
878: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
879: /* Copy 3rd stage LRP to FSR. */
880: if (m_L[1 /* 2 */].stat.lrp)
881: m_cregs[CR_FSR] |= 0x04000000;
882: else
883: m_cregs[CR_FSR] &= ~0x04000000;
884: #endif
885: if (m_L[2].stat.lrp) /* 3rd (last) stage. */
886: set_fregval_d (fdest, m_L[2].val.d);
887: else
888: set_fregval_s (fdest, m_L[2].val.s);
889:
890: /* Now advance pipeline and write loaded data to first stage. */
891: m_L[2] = m_L[1];
892: m_L[1] = m_L[0];
893: if (size == 8) {
894: m_L[0].val.d = *((double*)bebuf);
895: m_L[0].stat.lrp = 1;
896: } else {
897: m_L[0].val.s = *((float*)bebuf);
898: m_L[0].stat.lrp = 0;
899: }
900: }
901:
902: ab_op:;
903: }
904:
905:
906: /* Execute "pst.d fdest,#const(isrc2)" or "fst.d fdest,#const(isrc2)++"
907: instruction. */
908: void i860_cpu_device::insn_pstd (UINT32 insn)
909: {
910: INT32 immsrc1 = sign_ext (get_imm16 (insn), 16);
911: UINT32 isrc2 = get_isrc2 (insn);
912: UINT32 fdest = get_fdest (insn);
913: UINT32 eff = 0;
914: int auto_inc = (insn & 1);
915: int pm = GET_PSR_PM ();
916: int i;
917: UINT32 wmask;
918: int orig_pm = pm;
919:
920: /* Get the pixel size, where:
921: PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */
922: int ps = GET_PSR_PS ();
923:
924: #if TRACE_UNDEFINED_I860
925: if (!(ps == 0 || ps == 1 || ps == 2))
926: Log_Printf(LOG_WARN, "[i860:%08X] insn_pstd: Undefined i860XR behavior, invalid value %d for pixel size", m_pc, ps);
927: #endif
928:
929: #if TRACE_UNDEFINED_I860
930: /* Bits 2 and 1 determine the operand size, which must always be
931: zero (indicating a 64-bit operand). */
932: if (insn & 0x6)
933: {
934: /* Undefined i860XR behavior. */
935: Log_Printf(LOG_WARN, "[i860:%08X] insn_pstd: bad operand size specifier", m_pc);
936: }
937: #endif
938:
939: /* FIXME: Check for undefined behavior, non-even register operands. */
940:
941: /* Get effective address. Chop off lower bits of displacement. */
942: immsrc1 &= ~(8 - 1);
943: eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2)));
944:
945: #if TRACE_UNALIGNED_MEM
946: if (eff & (8 - 1))
947: {
948: Log_Printf(LOG_WARN, "[i860:%08X] Unaligned access detected (%08X)", m_pc, eff);
949: SET_PSR_DAT (1);
950: m_flow |= TRAP_NORMAL;
951: return;
952: }
953: #endif
954:
955: /* Do (post) auto-increment. */
956: if (auto_inc)
957: set_iregval (isrc2, eff);
958:
959: /* Update the pixel mask depending on the pixel size. Shift PM
960: right by 8/2^ps bits. */
961: if (ps == 0)
962: pm = (pm >> 8) & 0x00;
963: else if (ps == 1)
964: pm = (pm >> 4) & 0x0f;
965: else if (ps == 2)
966: pm = (pm >> 2) & 0x3f;
967: SET_PSR_PM (pm);
968:
969: /* Write data (value of freg fdest) to memory at eff-- but only those
970: bytes that are enabled by the bits in PSR.PM. Bit 0 of PM selects
971: the pixel at the lowest address. */
972: wmask = 0;
973: for (i = 0; i < 8; )
974: {
975: if (ps == 0)
976: {
977: if (orig_pm & 0x80)
978: wmask |= 1 << (7-i);
979: i += 1;
980: }
981: else if (ps == 1)
982: {
983: if (orig_pm & 0x08)
984: wmask |= 0x3 << (6-i);
985: i += 2;
986: }
987: else if (ps == 2)
988: {
989: if (orig_pm & 0x02)
990: wmask |= 0xf << (4-i);
991: i += 4;
992: }
993: else
994: {
995: wmask = 0xff;
996: break;
997: }
998: orig_pm <<= 1;
999: }
1000: writemem_emu (eff, 8, (UINT8 *)(&m_fregs[4 * fdest]), wmask);
1001: }
1002:
1003:
1004: /* Execute "ixfr isrc1ni,fdest" instruction. */
1005: void i860_cpu_device::insn_ixfr (UINT32 insn)
1006: {
1007: UINT32 isrc1 = get_isrc1 (insn);
1008: UINT32 fdest = get_fdest (insn);
1009: UINT32 iv = 0;
1010:
1011: /* This is a bit-pattern transfer, not a conversion. */
1012: iv = get_iregval (isrc1);
1013: set_fregval_s (fdest, *(float *)&iv);
1014: }
1015:
1016:
1017: /* Execute "addu isrc1,isrc2,idest". */
1018: void i860_cpu_device::insn_addu (UINT32 insn)
1019: {
1020: UINT32 src1val;
1021: UINT32 isrc2 = get_isrc2 (insn);
1022: UINT32 idest = get_idest (insn);
1023: UINT32 tmp_dest_val = 0;
1024: UINT64 tmp = 0;
1025:
1026: src1val = get_iregval (get_isrc1 (insn));
1027:
1028: /* We don't update the actual idest register now because below we
1029: need to test the original src1 and src2 if either happens to
1030: be the destination register. */
1031: tmp_dest_val = src1val + get_iregval (isrc2);
1032:
1033: /* Set OF and CC flags.
1034: For unsigned:
1035: OF = bit 31 carry
1036: CC = bit 31 carry.
1037: */
1038: tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2));
1039: if ((tmp >> 32) & 1) {
1040: SET_PSR_CC (1);
1041: SET_EPSR_OF (1);
1042: } else {
1043: SET_PSR_CC (0);
1044: SET_EPSR_OF (0);
1045: }
1046:
1047: /* Now update the destination register. */
1048: set_iregval (idest, tmp_dest_val);
1049: }
1050:
1051:
1052: /* Execute "addu #const,isrc2,idest". */
1053: void i860_cpu_device::insn_addu_imm (UINT32 insn)
1054: {
1055: UINT32 src1val;
1056: UINT32 isrc2 = get_isrc2 (insn);
1057: UINT32 idest = get_idest (insn);
1058: UINT32 tmp_dest_val = 0;
1059: UINT64 tmp = 0;
1060:
1061: src1val = sign_ext (get_imm16 (insn), 16);
1062:
1063: /* We don't update the actual idest register now because below we
1064: need to test the original src1 and src2 if either happens to
1065: be the destination register. */
1066: tmp_dest_val = src1val + get_iregval (isrc2);
1067:
1068: /* Set OF and CC flags.
1069: For unsigned:
1070: OF = bit 31 carry
1071: CC = bit 31 carry.
1072: */
1073: tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2));
1074: if ((tmp >> 32) & 1)
1075: {
1076: SET_PSR_CC (1);
1077: SET_EPSR_OF (1);
1078: }
1079: else
1080: {
1081: SET_PSR_CC (0);
1082: SET_EPSR_OF (0);
1083: }
1084:
1085: /* Now update the destination register. */
1086: set_iregval (idest, tmp_dest_val);
1087: }
1088:
1089:
1090: /* Execute "adds isrc1,isrc2,idest". */
1091: void i860_cpu_device::insn_adds (UINT32 insn)
1092: {
1093: UINT32 src1val;
1094: UINT32 isrc2 = get_isrc2 (insn);
1095: UINT32 idest = get_idest (insn);
1096: UINT32 tmp_dest_val = 0;
1097: int sa, sb, sres;
1098:
1099: src1val = get_iregval (get_isrc1 (insn));
1100:
1101: /* We don't update the actual idest register now because below we
1102: need to test the original src1 and src2 if either happens to
1103: be the destination register. */
1104: tmp_dest_val = src1val + get_iregval (isrc2);
1105:
1106: /* Set OF and CC flags.
1107: For signed:
1108: OF = standard signed overflow.
1109: CC set if isrc2 < -isrc1
1110: CC clear if isrc2 >= -isrc1
1111: */
1112: sa = src1val & 0x80000000;
1113: sb = get_iregval (isrc2) & 0x80000000;
1114: sres = tmp_dest_val & 0x80000000;
1115: if (sa != sb && sa != sres)
1116: SET_EPSR_OF (1);
1117: else
1118: SET_EPSR_OF (0);
1119:
1120: if ((INT32)get_iregval (isrc2) < -(INT32)(src1val))
1121: SET_PSR_CC (1);
1122: else
1123: SET_PSR_CC (0);
1124:
1125: /* Now update the destination register. */
1126: set_iregval (idest, tmp_dest_val);
1127: }
1128:
1129:
1130: /* Execute "adds #const,isrc2,idest". */
1131: void i860_cpu_device::insn_adds_imm (UINT32 insn)
1132: {
1133: UINT32 src1val;
1134: UINT32 isrc2 = get_isrc2 (insn);
1135: UINT32 idest = get_idest (insn);
1136: UINT32 tmp_dest_val = 0;
1137: int sa, sb, sres;
1138:
1139: src1val = sign_ext (get_imm16 (insn), 16);
1140:
1141: /* We don't update the actual idest register now because below we
1142: need to test the original src1 and src2 if either happens to
1143: be the destination register. */
1144: tmp_dest_val = src1val + get_iregval (isrc2);
1145:
1146: /* Set OF and CC flags.
1147: For signed:
1148: OF = standard signed overflow.
1149: CC set if isrc2 < -isrc1
1150: CC clear if isrc2 >= -isrc1
1151: */
1152: sa = src1val & 0x80000000;
1153: sb = get_iregval (isrc2) & 0x80000000;
1154: sres = tmp_dest_val & 0x80000000;
1155: if (sa != sb && sa != sres)
1156: SET_EPSR_OF (1);
1157: else
1158: SET_EPSR_OF (0);
1159:
1160: if ((INT32)get_iregval (isrc2) < -(INT32)(src1val))
1161: SET_PSR_CC (1);
1162: else
1163: SET_PSR_CC (0);
1164:
1165: /* Now update the destination register. */
1166: set_iregval (idest, tmp_dest_val);
1167: }
1168:
1169:
1170: /* Execute "subu isrc1,isrc2,idest". */
1171: void i860_cpu_device::insn_subu (UINT32 insn)
1172: {
1173: UINT32 src1val;
1174: UINT32 isrc2 = get_isrc2 (insn);
1175: UINT32 idest = get_idest (insn);
1176: UINT32 tmp_dest_val = 0;
1177:
1178: src1val = get_iregval (get_isrc1 (insn));
1179:
1180: /* We don't update the actual idest register now because below we
1181: need to test the original src1 and src2 if either happens to
1182: be the destination register. */
1183: tmp_dest_val = src1val - get_iregval (isrc2);
1184:
1185: /* Set OF and CC flags.
1186: For unsigned:
1187: OF = NOT(bit 31 carry)
1188: CC = bit 31 carry.
1189: (i.e. CC set if isrc2 <= isrc1
1190: CC clear if isrc2 > isrc1
1191: */
1192: if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val)
1193: {
1194: SET_PSR_CC (1);
1195: SET_EPSR_OF (0);
1196: }
1197: else
1198: {
1199: SET_PSR_CC (0);
1200: SET_EPSR_OF (1);
1201: }
1202:
1203: /* Now update the destination register. */
1204: set_iregval (idest, tmp_dest_val);
1205: }
1206:
1207:
1208: /* Execute "subu #const,isrc2,idest". */
1209: void i860_cpu_device::insn_subu_imm (UINT32 insn)
1210: {
1211: UINT32 src1val;
1212: UINT32 isrc2 = get_isrc2 (insn);
1213: UINT32 idest = get_idest (insn);
1214: UINT32 tmp_dest_val = 0;
1215:
1216: src1val = sign_ext (get_imm16 (insn), 16);
1217:
1218: /* We don't update the actual idest register now because below we
1219: need to test the original src1 and src2 if either happens to
1220: be the destination register. */
1221: tmp_dest_val = src1val - get_iregval (isrc2);
1222:
1223: /* Set OF and CC flags.
1224: For unsigned:
1225: OF = NOT(bit 31 carry)
1226: CC = bit 31 carry.
1227: (i.e. CC set if isrc2 <= isrc1
1228: CC clear if isrc2 > isrc1
1229: */
1230: if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val)
1231: {
1232: SET_PSR_CC (1);
1233: SET_EPSR_OF (0);
1234: }
1235: else
1236: {
1237: SET_PSR_CC (0);
1238: SET_EPSR_OF (1);
1239: }
1240:
1241: /* Now update the destination register. */
1242: set_iregval (idest, tmp_dest_val);
1243: }
1244:
1245:
1246: /* Execute "subs isrc1,isrc2,idest". */
1247: void i860_cpu_device::insn_subs (UINT32 insn)
1248: {
1249: UINT32 src1val;
1250: UINT32 isrc2 = get_isrc2 (insn);
1251: UINT32 idest = get_idest (insn);
1252: UINT32 tmp_dest_val = 0;
1253: int sa, sb, sres;
1254:
1255: src1val = get_iregval (get_isrc1 (insn));
1256:
1257: /* We don't update the actual idest register now because below we
1258: need to test the original src1 and src2 if either happens to
1259: be the destination register. */
1260: tmp_dest_val = src1val - get_iregval (isrc2);
1261:
1262: /* Set OF and CC flags.
1263: For signed:
1264: OF = standard signed overflow.
1265: CC set if isrc2 > isrc1
1266: CC clear if isrc2 <= isrc1
1267: */
1268: sa = src1val & 0x80000000;
1269: sb = get_iregval (isrc2) & 0x80000000;
1270: sres = tmp_dest_val & 0x80000000;
1271: if (sa != sb && sa != sres)
1272: SET_EPSR_OF (1);
1273: else
1274: SET_EPSR_OF (0);
1275:
1276: if ((INT32)get_iregval (isrc2) > (INT32)(src1val))
1277: SET_PSR_CC (1);
1278: else
1279: SET_PSR_CC (0);
1280:
1281: /* Now update the destination register. */
1282: set_iregval (idest, tmp_dest_val);
1283: }
1284:
1285:
1286: /* Execute "subs #const,isrc2,idest". */
1287: void i860_cpu_device::insn_subs_imm (UINT32 insn)
1288: {
1289: UINT32 src1val;
1290: UINT32 isrc2 = get_isrc2 (insn);
1291: UINT32 idest = get_idest (insn);
1292: UINT32 tmp_dest_val = 0;
1293: int sa, sb, sres;
1294:
1295: src1val = sign_ext (get_imm16 (insn), 16);
1296:
1297: /* We don't update the actual idest register now because below we
1298: need to test the original src1 and src2 if either happens to
1299: be the destination register. */
1300: tmp_dest_val = src1val - get_iregval (isrc2);
1301:
1302: /* Set OF and CC flags.
1303: For signed:
1304: OF = standard signed overflow.
1305: CC set if isrc2 > isrc1
1306: CC clear if isrc2 <= isrc1
1307: */
1308: sa = src1val & 0x80000000;
1309: sb = get_iregval (isrc2) & 0x80000000;
1310: sres = tmp_dest_val & 0x80000000;
1311: if (sa != sb && sa != sres)
1312: SET_EPSR_OF (1);
1313: else
1314: SET_EPSR_OF (0);
1315:
1316: if ((INT32)get_iregval (isrc2) > (INT32)(src1val))
1317: SET_PSR_CC (1);
1318: else
1319: SET_PSR_CC (0);
1320:
1321: /* Now update the destination register. */
1322: set_iregval (idest, tmp_dest_val);
1323: }
1324:
1325:
1326: /* Execute "shl isrc1,isrc2,idest". */
1327: void i860_cpu_device::insn_shl (UINT32 insn)
1328: {
1329: UINT32 src1val = 0;
1330: UINT32 isrc2 = get_isrc2 (insn);
1331: UINT32 idest = get_idest (insn);
1332:
1333: src1val = get_iregval (get_isrc1 (insn));
1334: set_iregval (idest, get_iregval (isrc2) << src1val);
1335: }
1336:
1337:
1338: /* Execute "shl #const,isrc2,idest". */
1339: void i860_cpu_device::insn_shl_imm (UINT32 insn)
1340: {
1341: UINT32 src1val = 0;
1342: UINT32 isrc2 = get_isrc2 (insn);
1343: UINT32 idest = get_idest (insn);
1344:
1345: src1val = sign_ext (get_imm16 (insn), 16);
1346: set_iregval (idest, get_iregval (isrc2) << src1val);
1347: }
1348:
1349:
1350: /* Execute "shr isrc1,isrc2,idest". */
1351: void i860_cpu_device::insn_shr (UINT32 insn)
1352: {
1353: UINT32 src1val = 0;
1354: UINT32 isrc2 = get_isrc2 (insn);
1355: UINT32 idest = get_idest (insn);
1356:
1357: src1val = get_iregval (get_isrc1 (insn));
1358:
1359: /* The iregs array is UINT32, so this is a logical shift. */
1360: set_iregval (idest, get_iregval (isrc2) >> src1val);
1361:
1362: /* shr also sets the SC in psr (shift count). */
1363: SET_PSR_SC (src1val);
1364: }
1365:
1366:
1367: /* Execute "shr #const,isrc2,idest". */
1368: void i860_cpu_device::insn_shr_imm (UINT32 insn)
1369: {
1370: UINT32 src1val = 0;
1371: UINT32 isrc2 = get_isrc2 (insn);
1372: UINT32 idest = get_idest (insn);
1373:
1374: src1val = sign_ext (get_imm16 (insn), 16);
1375:
1376: /* The iregs array is UINT32, so this is a logical shift. */
1377: set_iregval (idest, get_iregval (isrc2) >> src1val);
1378:
1379: /* shr also sets the SC in psr (shift count). */
1380: SET_PSR_SC (src1val);
1381: }
1382:
1383:
1384: /* Execute "shra isrc1,isrc2,idest". */
1385: void i860_cpu_device::insn_shra (UINT32 insn)
1386: {
1387: UINT32 src1val = 0;
1388: UINT32 isrc2 = get_isrc2 (insn);
1389: UINT32 idest = get_idest (insn);
1390:
1391: src1val = get_iregval (get_isrc1 (insn));
1392:
1393: /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */
1394: set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val);
1395: }
1396:
1397:
1398: /* Execute "shra #const,isrc2,idest". */
1399: void i860_cpu_device::insn_shra_imm (UINT32 insn)
1400: {
1401: UINT32 src1val = 0;
1402: UINT32 isrc2 = get_isrc2 (insn);
1403: UINT32 idest = get_idest (insn);
1404:
1405: src1val = sign_ext (get_imm16 (insn), 16);
1406:
1407: /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */
1408: set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val);
1409: }
1410:
1411:
1412: /* Execute "shrd isrc1ni,isrc2,idest" instruction. */
1413: void i860_cpu_device::insn_shrd (UINT32 insn)
1414: {
1415: UINT32 isrc1 = get_isrc1 (insn);
1416: UINT32 isrc2 = get_isrc2 (insn);
1417: UINT32 idest = get_idest (insn);
1418: UINT32 sc = GET_PSR_SC ();
1419: UINT32 tmp;
1420:
1421: /* Do the operation:
1422: idest = low_32(isrc1ni:isrc2 >> sc). */
1423: if (sc == 0)
1424: tmp = get_iregval (isrc2);
1425: else
1426: {
1427: tmp = get_iregval (isrc1) << (32 - sc);
1428: tmp |= (get_iregval (isrc2) >> sc);
1429: }
1430: set_iregval (idest, tmp);
1431: }
1432:
1433:
1434: /* Execute "and isrc1,isrc2,idest". */
1435: void i860_cpu_device::insn_and (UINT32 insn)
1436: {
1437: UINT32 isrc1 = get_isrc1 (insn);
1438: UINT32 isrc2 = get_isrc2 (insn);
1439: UINT32 idest = get_idest (insn);
1440: UINT32 res = 0;
1441:
1442: /* Do the operation. */
1443: res = get_iregval (isrc1) & get_iregval (isrc2);
1444:
1445: /* Set flags. */
1446: if (res == 0)
1447: SET_PSR_CC (1);
1448: else
1449: SET_PSR_CC (0);
1450:
1451: set_iregval (idest, res);
1452: }
1453:
1454:
1455: /* Execute "and #const,isrc2,idest". */
1456: void i860_cpu_device::insn_and_imm (UINT32 insn)
1457: {
1458: UINT32 src1val = 0;
1459: UINT32 isrc2 = get_isrc2 (insn);
1460: UINT32 idest = get_idest (insn);
1461: UINT32 res = 0;
1462:
1463: /* Do the operation. */
1464: src1val = get_imm16 (insn);
1465: res = src1val & get_iregval (isrc2);
1466:
1467: /* Set flags. */
1468: if (res == 0)
1469: SET_PSR_CC (1);
1470: else
1471: SET_PSR_CC (0);
1472:
1473: set_iregval (idest, res);
1474: }
1475:
1476:
1477: /* Execute "andh #const,isrc2,idest". */
1478: void i860_cpu_device::insn_andh_imm (UINT32 insn)
1479: {
1480: UINT32 src1val = 0;
1481: UINT32 isrc2 = get_isrc2 (insn);
1482: UINT32 idest = get_idest (insn);
1483: UINT32 res = 0;
1484:
1485: /* Do the operation. */
1486: src1val = get_imm16 (insn);
1487: res = (src1val << 16) & get_iregval (isrc2);
1488:
1489: /* Set flags. */
1490: if (res == 0)
1491: SET_PSR_CC (1);
1492: else
1493: SET_PSR_CC (0);
1494:
1495: set_iregval (idest, res);
1496: }
1497:
1498:
1499: /* Execute "andnot isrc1,isrc2,idest". */
1500: void i860_cpu_device::insn_andnot (UINT32 insn)
1501: {
1502: UINT32 isrc1 = get_isrc1 (insn);
1503: UINT32 isrc2 = get_isrc2 (insn);
1504: UINT32 idest = get_idest (insn);
1505: UINT32 res = 0;
1506:
1507: /* Do the operation. */
1508: res = (~get_iregval (isrc1)) & get_iregval (isrc2);
1509:
1510: /* Set flags. */
1511: if (res == 0)
1512: SET_PSR_CC (1);
1513: else
1514: SET_PSR_CC (0);
1515:
1516: set_iregval (idest, res);
1517: }
1518:
1519:
1520: /* Execute "andnot #const,isrc2,idest". */
1521: void i860_cpu_device::insn_andnot_imm (UINT32 insn)
1522: {
1523: UINT32 src1val = 0;
1524: UINT32 isrc2 = get_isrc2 (insn);
1525: UINT32 idest = get_idest (insn);
1526: UINT32 res = 0;
1527:
1528: /* Do the operation. */
1529: src1val = get_imm16 (insn);
1530: res = (~src1val) & get_iregval (isrc2);
1531:
1532: /* Set flags. */
1533: if (res == 0)
1534: SET_PSR_CC (1);
1535: else
1536: SET_PSR_CC (0);
1537:
1538: set_iregval (idest, res);
1539: }
1540:
1541:
1542: /* Execute "andnoth #const,isrc2,idest". */
1543: void i860_cpu_device::insn_andnoth_imm (UINT32 insn)
1544: {
1545: UINT32 src1val = 0;
1546: UINT32 isrc2 = get_isrc2 (insn);
1547: UINT32 idest = get_idest (insn);
1548: UINT32 res = 0;
1549:
1550: /* Do the operation. */
1551: src1val = get_imm16 (insn);
1552: res = (~(src1val << 16)) & get_iregval (isrc2);
1553:
1554: /* Set flags. */
1555: if (res == 0)
1556: SET_PSR_CC (1);
1557: else
1558: SET_PSR_CC (0);
1559:
1560: set_iregval (idest, res);
1561: }
1562:
1563:
1564: /* Execute "or isrc1,isrc2,idest". */
1565: void i860_cpu_device::insn_or (UINT32 insn)
1566: {
1567: UINT32 isrc1 = get_isrc1 (insn);
1568: UINT32 isrc2 = get_isrc2 (insn);
1569: UINT32 idest = get_idest (insn);
1570: UINT32 res = 0;
1571:
1572: /* Do the operation. */
1573: res = get_iregval (isrc1) | get_iregval (isrc2);
1574:
1575: /* Set flags. */
1576: if (res == 0)
1577: SET_PSR_CC (1);
1578: else
1579: SET_PSR_CC (0);
1580:
1581: set_iregval (idest, res);
1582: }
1583:
1584:
1585: /* Execute "or #const,isrc2,idest". */
1586: void i860_cpu_device::insn_or_imm (UINT32 insn)
1587: {
1588: UINT32 src1val = 0;
1589: UINT32 isrc2 = get_isrc2 (insn);
1590: UINT32 idest = get_idest (insn);
1591: UINT32 res = 0;
1592:
1593: /* Do the operation. */
1594: src1val = get_imm16 (insn);
1595: res = src1val | get_iregval (isrc2);
1596:
1597: /* Set flags. */
1598: if (res == 0)
1599: SET_PSR_CC (1);
1600: else
1601: SET_PSR_CC (0);
1602:
1603: set_iregval (idest, res);
1604: }
1605:
1606:
1607: /* Execute "orh #const,isrc2,idest". */
1608: void i860_cpu_device::insn_orh_imm (UINT32 insn)
1609: {
1610: UINT32 src1val = 0;
1611: UINT32 isrc2 = get_isrc2 (insn);
1612: UINT32 idest = get_idest (insn);
1613: UINT32 res = 0;
1614:
1615: /* Do the operation. */
1616: src1val = get_imm16 (insn);
1617: res = (src1val << 16) | get_iregval (isrc2);
1618:
1619: /* Set flags. */
1620: if (res == 0)
1621: SET_PSR_CC (1);
1622: else
1623: SET_PSR_CC (0);
1624:
1625: set_iregval (idest, res);
1626: }
1627:
1628:
1629: /* Execute "xor isrc1,isrc2,idest". */
1630: void i860_cpu_device::insn_xor (UINT32 insn)
1631: {
1632: UINT32 isrc1 = get_isrc1 (insn);
1633: UINT32 isrc2 = get_isrc2 (insn);
1634: UINT32 idest = get_idest (insn);
1635: UINT32 res = 0;
1636:
1637: /* Do the operation. */
1638: res = get_iregval (isrc1) ^ get_iregval (isrc2);
1639:
1640: /* Set flags. */
1641: if (res == 0)
1642: SET_PSR_CC (1);
1643: else
1644: SET_PSR_CC (0);
1645:
1646: set_iregval (idest, res);
1647: }
1648:
1649:
1650: /* Execute "xor #const,isrc2,idest". */
1651: void i860_cpu_device::insn_xor_imm (UINT32 insn)
1652: {
1653: UINT32 src1val = 0;
1654: UINT32 isrc2 = get_isrc2 (insn);
1655: UINT32 idest = get_idest (insn);
1656: UINT32 res = 0;
1657:
1658: /* Do the operation. */
1659: src1val = get_imm16 (insn);
1660: res = src1val ^ get_iregval (isrc2);
1661:
1662: /* Set flags. */
1663: if (res == 0)
1664: SET_PSR_CC (1);
1665: else
1666: SET_PSR_CC (0);
1667:
1668: set_iregval (idest, res);
1669: }
1670:
1671:
1672: /* Execute "xorh #const,isrc2,idest". */
1673: void i860_cpu_device::insn_xorh_imm (UINT32 insn)
1674: {
1675: UINT32 src1val = 0;
1676: UINT32 isrc2 = get_isrc2 (insn);
1677: UINT32 idest = get_idest (insn);
1678: UINT32 res = 0;
1679:
1680: /* Do the operation. */
1681: src1val = get_imm16 (insn);
1682: res = (src1val << 16) ^ get_iregval (isrc2);
1683:
1684: /* Set flags. */
1685: if (res == 0)
1686: SET_PSR_CC (1);
1687: else
1688: SET_PSR_CC (0);
1689:
1690: set_iregval (idest, res);
1691: }
1692:
1693:
1694: /* Execute "trap isrc1ni,isrc2,idest" instruction. */
1695: void i860_cpu_device::insn_trap (UINT32 insn)
1696: {
1697: debugger('d', "Software TRAP");
1698: SET_PSR_IT (1);
1699: m_flow |= TRAP_NORMAL;
1700: }
1701:
1702:
1703: /* Execute "intovr" instruction. */
1704: void i860_cpu_device::insn_intovr (UINT32 insn)
1705: {
1706: if (GET_EPSR_OF ())
1707: {
1708: SET_PSR_IT (1);
1709: m_flow |= TRAP_NORMAL;
1710: }
1711: }
1712:
1713:
1714: /* Execute "bte isrc1,isrc2,sbroff". */
1715: void i860_cpu_device::insn_bte (UINT32 insn)
1716: {
1717: UINT32 src1val = 0;
1718: UINT32 isrc2 = get_isrc2 (insn);
1719: UINT32 target_addr = 0;
1720: INT32 sbroff = 0;
1721: int res = 0;
1722:
1723: src1val = get_iregval (get_isrc1 (insn));
1724:
1725: /* Compute the target address from the sbroff field. */
1726: sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
1727: target_addr = (INT32)m_pc + 4 + (sbroff << 2);
1728:
1729: /* Determine comparison result. */
1730: res = (src1val == get_iregval (isrc2));
1731:
1732: /* Branch routines always update the PC. */
1733: if (res)
1734: m_pc = target_addr;
1735: else
1736: m_pc += 4;
1737:
1738: SET_PC_UPDATED();
1739: }
1740:
1741:
1742: /* Execute "bte #const5,isrc2,sbroff". */
1743: void i860_cpu_device::insn_bte_imm (UINT32 insn)
1744: {
1745: UINT32 src1val = 0;
1746: UINT32 isrc2 = get_isrc2 (insn);
1747: UINT32 target_addr = 0;
1748: INT32 sbroff = 0;
1749: int res = 0;
1750:
1751: src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */
1752:
1753: /* Compute the target address from the sbroff field. */
1754: sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
1755: target_addr = (INT32)m_pc + 4 + (sbroff << 2);
1756:
1757: /* Determine comparison result. */
1758: res = (src1val == get_iregval (isrc2));
1759:
1760: /* Branch routines always update the PC. */
1761: if (res)
1762: m_pc = target_addr;
1763: else
1764: m_pc += 4;
1765:
1766: SET_PC_UPDATED();
1767: }
1768:
1769:
1770: /* Execute "btne isrc1,isrc2,sbroff". */
1771: void i860_cpu_device::insn_btne (UINT32 insn)
1772: {
1773: UINT32 src1val = 0;
1774: UINT32 isrc2 = get_isrc2 (insn);
1775: UINT32 target_addr = 0;
1776: INT32 sbroff = 0;
1777: int res = 0;
1778:
1779: src1val = get_iregval (get_isrc1 (insn));
1780:
1781: /* Compute the target address from the sbroff field. */
1782: sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
1783: target_addr = (INT32)m_pc + 4 + (sbroff << 2);
1784:
1785: /* Determine comparison result. */
1786: res = (src1val != get_iregval (isrc2));
1787:
1788: /* Branch routines always update the PC. */
1789: if (res)
1790: m_pc = target_addr;
1791: else
1792: m_pc += 4;
1793:
1794: SET_PC_UPDATED();
1795: }
1796:
1797:
1798: /* Execute "btne #const5,isrc2,sbroff". */
1799: void i860_cpu_device::insn_btne_imm (UINT32 insn)
1800: {
1801: UINT32 src1val = 0;
1802: UINT32 isrc2 = get_isrc2 (insn);
1803: UINT32 target_addr = 0;
1804: INT32 sbroff = 0;
1805: int res = 0;
1806:
1807: src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */
1808:
1809: /* Compute the target address from the sbroff field. */
1810: sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
1811: target_addr = (INT32)m_pc + 4 + (sbroff << 2);
1812:
1813: /* Determine comparison result. */
1814: res = (src1val != get_iregval (isrc2));
1815:
1816: /* Branch routines always update the PC. */
1817: if (res)
1818: m_pc = target_addr;
1819: else
1820: m_pc += 4;
1821:
1822: SET_PC_UPDATED();
1823: }
1824:
1825:
1826: /* Execute "bc lbroff" instruction. */
1827: void i860_cpu_device::insn_bc (UINT32 insn)
1828: {
1829: UINT32 target_addr = 0;
1830: INT32 lbroff = 0;
1831: int res = 0;
1832:
1833: /* Compute the target address from the lbroff field. */
1834: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1835: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1836:
1837: /* Determine comparison result. */
1838: res = m_dim_cc_valid ? m_dim_cc : (GET_PSR_CC () == 1);
1839:
1840: /* Branch routines always update the PC. */
1841: if (res)
1842: m_pc = target_addr;
1843: else
1844: m_pc += 4;
1845:
1846: SET_PC_UPDATED();
1847: }
1848:
1849:
1850: /* Execute "bnc lbroff" instruction. */
1851: void i860_cpu_device::insn_bnc (UINT32 insn)
1852: {
1853: UINT32 target_addr = 0;
1854: INT32 lbroff = 0;
1855: int res = 0;
1856:
1857: /* Compute the target address from the lbroff field. */
1858: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1859: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1860:
1861: /* Determine comparison result. */
1862: res = m_dim_cc_valid ? !(m_dim_cc) : (GET_PSR_CC () == 0);
1863:
1864: /* Branch routines always update the PC, since pc_updated is set
1865: in the decode routine. */
1866: if (res)
1867: m_pc = target_addr;
1868: else
1869: m_pc += 4;
1870:
1871: SET_PC_UPDATED();
1872: }
1873:
1874:
1875: /* Execute "bc.t lbroff" instruction. */
1876: void i860_cpu_device::insn_bct (UINT32 insn)
1877: {
1878: UINT32 target_addr = 0;
1879: INT32 lbroff = 0;
1880: int res = 0;
1881: UINT32 orig_pc = m_pc;
1882:
1883: /* Compute the target address from the lbroff field. */
1884: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1885: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1886:
1887: /* Determine comparison result. */
1888: res = (GET_PSR_CC () == 1);
1889:
1890: /* Careful. Unlike bla, the delay slot instruction is only executed
1891: if the branch is taken. */
1892: if (res)
1893: {
1894: /* Execute delay slot instruction. */
1895: DELAY_SLOT();
1896: if (PENDING_TRAP() )
1897: {
1898: m_flow |= TRAP_IN_DELAY_SLOT;
1899: goto ab_op;
1900: }
1901: }
1902:
1903: /* Since this branch is delayed, we must jump 2 or 3 instructions if
1904: if isn't taken. */
1905: if (res)
1906: m_pc = target_addr;
1907: else
1908: m_pc += DELAY_SLOT_PC();
1909:
1910: SET_PC_UPDATED();
1911:
1912: ab_op:
1913: ;
1914: }
1915:
1916:
1917: /* Execute "bnc.t lbroff" instruction. */
1918: void i860_cpu_device::insn_bnct (UINT32 insn)
1919: {
1920: UINT32 target_addr = 0;
1921: INT32 lbroff = 0;
1922: int res = 0;
1923: UINT32 orig_pc = m_pc;
1924:
1925: /* Compute the target address from the lbroff field. */
1926: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1927: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1928:
1929: /* Determine comparison result. */
1930: res = (GET_PSR_CC () == 0);
1931:
1932: /* Careful. Unlike bla, the delay slot instruction is only executed
1933: if the branch is taken. */
1934: if (res)
1935: {
1936: /* Execute delay slot instruction. */
1937: DELAY_SLOT();
1938: if (PENDING_TRAP() )
1939: {
1940: m_flow |= TRAP_IN_DELAY_SLOT;
1941: goto ab_op;
1942: }
1943: }
1944:
1945: /* Since this branch is delayed, we must jump 2 or 3 instructions if if isn't taken. */
1946: if (res)
1947: m_pc = target_addr;
1948: else
1949: m_pc += DELAY_SLOT_PC();
1950:
1951: SET_PC_UPDATED();
1952:
1953: ab_op:
1954: ;
1955: }
1956:
1957:
1958: /* Execute "call lbroff" instruction. */
1959: void i860_cpu_device::insn_call (UINT32 insn)
1960: {
1961: UINT32 target_addr = 0;
1962: INT32 lbroff = 0;
1963: UINT32 orig_pc = m_pc;
1964:
1965: /* Compute the target address from the lbroff field. */
1966: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1967: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1968:
1969: /* Execute the delay slot instruction. */
1970: DELAY_SLOT();
1971: if (PENDING_TRAP() )
1972: {
1973: m_flow |= TRAP_IN_DELAY_SLOT;
1974: goto ab_op;
1975: }
1976:
1977: /* Sets the return pointer (r1). */
1978: set_iregval (1, orig_pc + DELAY_SLOT_PC());
1979:
1980: /* New target. */
1981: m_pc = target_addr;
1982: SET_PC_UPDATED();
1983:
1984: ab_op:;
1985: }
1986:
1987:
1988: /* Execute "br lbroff". */
1989: void i860_cpu_device::insn_br (UINT32 insn)
1990: {
1991: UINT32 target_addr = 0;
1992: INT32 lbroff = 0;
1993: UINT32 orig_pc = m_pc;
1994:
1995: /* Compute the target address from the lbroff field. */
1996: lbroff = sign_ext ((insn & 0x03ffffff), 26);
1997: target_addr = (INT32)m_pc + 4 + (lbroff << 2);
1998:
1999: /* Execute the delay slot instruction. */
2000: DELAY_SLOT();
2001: if (PENDING_TRAP() )
2002: {
2003: m_flow |= TRAP_IN_DELAY_SLOT;
2004: goto ab_op;
2005: }
2006:
2007: /* New target. */
2008: m_pc = target_addr;
2009: SET_PC_UPDATED();
2010:
2011: ab_op:;
2012: }
2013:
2014:
2015: /* Execute "bri isrc1ni" instruction.
2016: Note: I didn't merge this code with calli because bri must do
2017: a lot of flag manipulation if any trap bits are set. */
2018: void i860_cpu_device::insn_bri (UINT32 insn)
2019: {
2020: UINT32 isrc1 = get_isrc1 (insn);
2021: UINT32 orig_pc = m_pc;
2022: UINT32 orig_psr = m_cregs[CR_PSR];
2023: UINT32 orig_src1_val = get_iregval (isrc1);
2024:
2025: #if 1 /* TURBO. */
2026: m_cregs[CR_PSR] &= ~PSR_ALL_TRAP_BITS_MASK;
2027: #endif
2028:
2029: if(m_dim && PENDING_TRAP())
2030: goto ab_op;
2031:
2032: /* Execute the delay slot instruction. */
2033: DELAY_SLOT();
2034:
2035: /* Delay slot insn caused a trap, abort operation. */
2036: if (PENDING_TRAP() )
2037: {
2038: m_flow |= TRAP_IN_DELAY_SLOT;
2039: goto ab_op;
2040: }
2041:
2042: /* If any trap bits are set, we need to do the return from
2043: trap work. Note, we must use the PSR value that existed
2044: before the delay slot instruction was executed since the
2045: delay slot instruction might itself cause a trap bit to
2046: be set. */
2047: if (orig_psr & PSR_ALL_TRAP_BITS_MASK)
2048: {
2049: /* Restore U and IM from their previous copies. */
2050: SET_PSR_U (GET_PSR_PU ());
2051: SET_PSR_IM (GET_PSR_PIM ());
2052:
2053: ret_from_trap();
2054: }
2055:
2056: /* Update PC. */
2057: m_pc = orig_src1_val;
2058:
2059: SET_PC_UPDATED();
2060: ab_op:;
2061: }
2062:
2063: /* Execute "calli isrc1ni" instruction. */
2064: void i860_cpu_device::insn_calli (UINT32 insn)
2065: {
2066: UINT32 isrc1 = get_isrc1 (insn);
2067: UINT32 orig_pc = m_pc;
2068: UINT32 orig_src1_val = get_iregval (isrc1);
2069:
2070: #if TRACE_UNDEFINED_I860
2071: /* Check for undefined behavior. */
2072: if (isrc1 == 1)
2073: {
2074: /* Src1 must not be r1. */
2075: Log_Printf(LOG_WARN, "[i860:%08X] insn_calli: isrc1 = r1 on a calli", m_pc);
2076: }
2077: #endif
2078:
2079: /* Set return pointer before executing delay slot instruction. */
2080: set_iregval (1, m_pc + DELAY_SLOT_PC());
2081:
2082: /* Execute the delay slot instruction. */
2083: DELAY_SLOT();
2084: if (PENDING_TRAP() )
2085: {
2086: set_iregval (1, orig_src1_val);
2087: m_flow |= TRAP_IN_DELAY_SLOT;
2088: goto ab_op;
2089: }
2090:
2091: /* Set new PC. */
2092: m_pc = orig_src1_val;
2093: SET_PC_UPDATED();
2094:
2095: ab_op:;
2096: }
2097:
2098:
2099: /* Execute "bla isrc1ni,isrc2,sbroff" instruction. */
2100: void i860_cpu_device::insn_bla (UINT32 insn)
2101: {
2102: UINT32 isrc1 = get_isrc1 (insn);
2103: UINT32 isrc2 = get_isrc2 (insn);
2104: UINT32 target_addr = 0;
2105: INT32 sbroff = 0;
2106: int lcc_tmp = 0;
2107: UINT32 orig_pc = m_pc;
2108: UINT32 orig_isrc2val = get_iregval (isrc2);
2109:
2110: #if TRACE_UNDEFINED_I860
2111: /* Check for undefined behavior. */
2112: if (isrc1 == isrc2)
2113: {
2114: /* Src1 and src2 the same is undefined i860XR behavior. */
2115: Log_Printf(LOG_WARN, "[i860:%08X] insn_bla: isrc1 and isrc2 are the same (ignored)", m_pc);
2116: return;
2117: }
2118: #endif
2119:
2120: /* Compute the target address from the sbroff field. */
2121: sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
2122: target_addr = (INT32)m_pc + 4 + (sbroff << 2);
2123:
2124: /* Determine comparison result based on opcode. */
2125: lcc_tmp = ((INT32)get_iregval (isrc2) >= -(INT32)get_iregval (isrc1));
2126:
2127: set_iregval (isrc2, get_iregval (isrc1) + orig_isrc2val);
2128:
2129: /* Execute the delay slot instruction. */
2130: DELAY_SLOT();
2131: if (PENDING_TRAP() )
2132: {
2133: m_flow |= TRAP_IN_DELAY_SLOT;
2134: goto ab_op;
2135: }
2136:
2137: if (GET_PSR_LCC ())
2138: m_pc = target_addr;
2139: else
2140: {
2141: /* Since this branch is delayed, we must jump 2 or 3 instructions if if isn't taken. */
2142: m_pc += DELAY_SLOT_PC();
2143: }
2144: SET_PSR_LCC (lcc_tmp);
2145:
2146: SET_PC_UPDATED();
2147: ab_op:;
2148: }
2149:
2150:
2151: /* Execute "flush #const(isrc2)" or "flush #const(isrc2)++" instruction. */
2152: void i860_cpu_device::insn_flush (UINT32 insn)
2153: {
2154: UINT32 src1val = sign_ext (get_imm16 (insn), 16);
2155: UINT32 isrc2 = get_isrc2 (insn);
2156: int auto_inc = (insn & 1);
2157: UINT32 eff = 0;
2158:
2159: /* Technically, idest should be encoded as r0 because idest
2160: is undefined after the instruction. We don't currently
2161: check for this.
2162:
2163: Flush D$ block at address #const+isrc2. Block is undefined
2164: after. The effective address must be 16-byte aligned.
2165:
2166: FIXME: Need to examine RB and RC and do this right.
2167: */
2168:
2169: /* Chop off lower bits of displacement to 16-byte alignment. */
2170: src1val &= ~(16-1);
2171: eff = src1val + get_iregval (isrc2);
2172: if (auto_inc)
2173: set_iregval (isrc2, eff);
2174:
2175: /* In user mode, the flush is ignored. */
2176: if (GET_PSR_U () == 0)
2177: {
2178: /* If line is dirty, write it to memory and invalidate.
2179: NOTE: The actual dirty write is unimplemented in the MAME version
2180: as we don't emulate the dcache. */
2181: }
2182: }
2183:
2184:
2185: /* Execute "[p]fmul.{ss,sd,dd} fsrc1,fsrc2,fdest" instruction or
2186: pfmul3.dd fsrc1,fsrc2,fdest.
2187:
2188: The pfmul3.dd differs from pfmul.dd in that it treats the pipeline
2189: as 3 stages, even though it is a double precision multiply. */
2190: void i860_cpu_device::insn_fmul (UINT32 insn)
2191: {
2192: UINT32 fsrc1 = get_fsrc1 (insn);
2193: UINT32 fsrc2 = get_fsrc2 (insn);
2194: UINT32 fdest = get_fdest (insn);
2195: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
2196: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
2197: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
2198: double dbl_tmp_dest = 0.0;
2199: float sgl_tmp_dest = 0.0;
2200: double dbl_last_stage_contents = 0.0;
2201: float sgl_last_stage_contents = 0.0;
2202: int is_pfmul3 = insn & 0x4;
2203: int num_stages = (src_prec && !is_pfmul3) ? 2 : 3;
2204:
2205: #if TRACE_UNDEFINED_I860
2206: /* Only .dd is valid for pfmul. */
2207: if (is_pfmul3 && (insn & 0x180) != 0x180)
2208: {
2209: unrecog_opcode (m_pc, insn);
2210: return;
2211: }
2212:
2213: /* Check for invalid .ds combination. */
2214: if ((insn & 0x180) == 0x100)
2215: {
2216: unrecog_opcode (m_pc, insn);
2217: return;
2218: }
2219: #endif
2220:
2221: /* For pipelined version, retrieve the contents of the last stage
2222: of the pipeline, whose precision is specified by the MRP bit
2223: of the stage's result-status bits. Note for pfmul, the number
2224: of stages is determined by the source precision of the current
2225: operation. */
2226: if (piped)
2227: {
2228: if (m_M[num_stages - 1].stat.mrp)
2229: dbl_last_stage_contents = m_M[num_stages - 1].val.d;
2230: else
2231: sgl_last_stage_contents = m_M[num_stages - 1].val.s;
2232: }
2233:
2234: /* Do the operation, being careful about source and result
2235: precision. */
2236: if (src_prec)
2237: {
2238: double v1 = get_fregval_d (fsrc1);
2239: double v2 = get_fregval_d (fsrc2);
2240:
2241: /* For pipelined mul, if fsrc2 is the same as fdest, then the last
2242: stage is bypassed to fsrc2 (rather than using the value in fsrc2).
2243: This bypass is not available for fsrc1, and is undefined behavior. */
2244: if (0 && piped && fdest != 0 && fsrc1 == fdest)
2245: v1 = dbl_last_stage_contents;
2246: if (piped && fdest != 0 && fsrc2 == fdest)
2247: v2 = dbl_last_stage_contents;
2248:
2249: if (res_prec)
2250: dbl_tmp_dest = v1 * v2;
2251: else
2252: sgl_tmp_dest = (float)(v1 * v2);
2253: }
2254: else
2255: {
2256: float v1 = get_fregval_s (fsrc1);
2257: float v2 = get_fregval_s (fsrc2);
2258:
2259: /* For pipelined mul, if fsrc2 is the same as fdest, then the last
2260: stage is bypassed to fsrc2 (rather than using the value in fsrc2).
2261: This bypass is not available for fsrc1, and is undefined behavior. */
2262: if (0 && piped && fdest != 0 && fsrc1 == fdest)
2263: v1 = sgl_last_stage_contents;
2264: if (piped && fdest != 0 && fsrc2 == fdest)
2265: v2 = sgl_last_stage_contents;
2266:
2267: if (res_prec)
2268: dbl_tmp_dest = (double)(v1 * v2);
2269: else
2270: sgl_tmp_dest = v1 * v2;
2271: }
2272:
2273: /* FIXME: Set result-status bits besides MRP. And copy to fsr from
2274: last stage. */
2275: /* FIXME: Scalar version flows through all stages. */
2276: /* FIXME: Mixed precision (only weird for pfmul). */
2277: if (!piped)
2278: {
2279: /* Scalar version writes the current calculation to the fdest
2280: register, with precision specified by the R bit. */
2281: if (res_prec)
2282: set_fregval_d (fdest, dbl_tmp_dest);
2283: else
2284: set_fregval_s (fdest, sgl_tmp_dest);
2285: }
2286: else
2287: {
2288: /* Pipelined version writes fdest with the result from the last
2289: stage of the pipeline. */
2290: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
2291: /* Copy 3rd stage MRP to FSR. */
2292: if (m_M[num_stages - 2 /* 1 */].stat.mrp)
2293: m_cregs[CR_FSR] |= 0x10000000;
2294: else
2295: m_cregs[CR_FSR] &= ~0x10000000;
2296: #endif
2297:
2298: if (m_M[num_stages - 1].stat.mrp)
2299: set_fregval_d (fdest, dbl_last_stage_contents);
2300: else
2301: set_fregval_s (fdest, sgl_last_stage_contents);
2302:
2303: /* Now advance pipeline and write current calculation to
2304: first stage. */
2305: if (num_stages == 3)
2306: {
2307: m_M[2] = m_M[1];
2308: m_M[1] = m_M[0];
2309: }
2310: else
2311: m_M[1] = m_M[0];
2312:
2313: if (res_prec)
2314: {
2315: m_M[0].val.d = dbl_tmp_dest;
2316: m_M[0].stat.mrp = 1;
2317: }
2318: else
2319: {
2320: m_M[0].val.s = sgl_tmp_dest;
2321: m_M[0].stat.mrp = 0;
2322: }
2323: }
2324: }
2325:
2326:
2327: /* Execute "fmlow.dd fsrc1,fsrc2,fdest" instruction. */
2328: void i860_cpu_device::insn_fmlow (UINT32 insn)
2329: {
2330: UINT32 fsrc1 = get_fsrc1 (insn);
2331: UINT32 fsrc2 = get_fsrc2 (insn);
2332: UINT32 fdest = get_fdest (insn);
2333:
2334: double v1 = get_fregval_d (fsrc1);
2335: double v2 = get_fregval_d (fsrc2);
2336: INT64 i1 = *(UINT64 *)&v1;
2337: INT64 i2 = *(UINT64 *)&v2;
2338: INT64 tmp = 0;
2339:
2340: #if TRACE_UNDEFINED_I860
2341: /* Only .dd is valid for fmlow. */
2342: if ((insn & 0x180) != 0x180)
2343: {
2344: unrecog_opcode (m_pc, insn);
2345: return;
2346: }
2347: #endif
2348:
2349: /* The lower 32-bits are obvious. What exactly goes in the upper
2350: bits?
2351: Technically, the upper-most 10 bits are undefined, but i'd like
2352: to be undefined in the same way as the real i860 if possible. */
2353:
2354: /* Keep lower 53 bits of multiply. */
2355: tmp = i1 * i2;
2356: tmp &= 0x001fffffffffffffULL;
2357: tmp |= (i1 & 0x8000000000000000LL) ^ (i2 & 0x8000000000000000LL);
2358: set_fregval_d (fdest, *(double *)&tmp);
2359: }
2360:
2361:
2362: /* Execute [p]fadd.{ss,sd,dd} fsrc1,fsrc2,fdest (.ds disallowed above). */
2363: void i860_cpu_device::insn_fadd_sub (UINT32 insn)
2364: {
2365: UINT32 fsrc1 = get_fsrc1 (insn);
2366: UINT32 fsrc2 = get_fsrc2 (insn);
2367: UINT32 fdest = get_fdest (insn);
2368: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
2369: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
2370: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
2371: int is_sub = insn & 1; /* 1 = sub, 0 = add. */
2372: double dbl_tmp_dest = 0.0;
2373: float sgl_tmp_dest = 0.0;
2374: double dbl_last_stage_contents = 0.0;
2375: float sgl_last_stage_contents = 0.0;
2376:
2377: #if TRACE_UNDEFINED_I860
2378: /* Check for invalid .ds combination. */
2379: if ((insn & 0x180) == 0x100)
2380: {
2381: unrecog_opcode (m_pc, insn);
2382: return;
2383: }
2384: #endif
2385:
2386: /* For pipelined version, retrieve the contents of the last stage
2387: of the pipeline, whose precision is specified by the ARP bit
2388: of the stage's result-status bits. There are always three stages
2389: for pfadd/pfsub. */
2390: if (piped)
2391: {
2392: if (m_A[2].stat.arp)
2393: dbl_last_stage_contents = m_A[2].val.d;
2394: else
2395: sgl_last_stage_contents = m_A[2].val.s;
2396: }
2397:
2398: /* Do the operation, being careful about source and result
2399: precision. */
2400: if (src_prec)
2401: {
2402: double v1 = get_fregval_d (fsrc1);
2403: double v2 = get_fregval_d (fsrc2);
2404:
2405: /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last
2406: stage is bypassed to fsrc1 (rather than using the value in fsrc1).
2407: Likewise for fsrc2. */
2408: if (piped && fdest != 0 && fsrc1 == fdest)
2409: v1 = dbl_last_stage_contents;
2410: if (piped && fdest != 0 && fsrc2 == fdest)
2411: v2 = dbl_last_stage_contents;
2412:
2413: if (res_prec)
2414: dbl_tmp_dest = is_sub ? v1 - v2 : v1 + v2;
2415: else
2416: sgl_tmp_dest = is_sub ? (float)(v1 - v2) : (float)(v1 + v2);
2417: }
2418: else
2419: {
2420: float v1 = get_fregval_s (fsrc1);
2421: float v2 = get_fregval_s (fsrc2);
2422:
2423: /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last
2424: stage is bypassed to fsrc1 (rather than using the value in fsrc1).
2425: Likewise for fsrc2. */
2426: if (piped && fdest != 0 && fsrc1 == fdest)
2427: v1 = sgl_last_stage_contents;
2428: if (piped && fdest != 0 && fsrc2 == fdest)
2429: v2 = sgl_last_stage_contents;
2430:
2431: if (res_prec)
2432: dbl_tmp_dest = is_sub ? (double)(v1 - v2) : (double)(v1 + v2);
2433: else
2434: sgl_tmp_dest = is_sub ? v1 - v2 : v1 + v2;
2435: }
2436:
2437: /* FIXME: Set result-status bits besides ARP. And copy to fsr from
2438: last stage. */
2439: /* FIXME: Scalar version flows through all stages. */
2440: if (!piped)
2441: {
2442: /* Scalar version writes the current calculation to the fdest
2443: register, with precision specified by the R bit. */
2444: if (res_prec)
2445: set_fregval_d (fdest, dbl_tmp_dest);
2446: else
2447: set_fregval_s (fdest, sgl_tmp_dest);
2448: }
2449: else
2450: {
2451: /* Pipelined version writes fdest with the result from the last
2452: stage of the pipeline, with precision specified by the ARP
2453: bit of the stage's result-status bits. */
2454: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
2455: /* Copy 3rd stage ARP to FSR. */
2456: if (m_A[1 /* 2 */].stat.arp)
2457: m_cregs[CR_FSR] |= 0x20000000;
2458: else
2459: m_cregs[CR_FSR] &= ~0x20000000;
2460: #endif
2461: if (m_A[2].stat.arp) /* 3rd (last) stage. */
2462: set_fregval_d (fdest, dbl_last_stage_contents);
2463: else
2464: set_fregval_s (fdest, sgl_last_stage_contents);
2465:
2466: /* Now advance pipeline and write current calculation to
2467: first stage. */
2468: m_A[2] = m_A[1];
2469: m_A[1] = m_A[0];
2470: if (res_prec)
2471: {
2472: m_A[0].val.d = dbl_tmp_dest;
2473: m_A[0].stat.arp = 1;
2474: }
2475: else
2476: {
2477: m_A[0].val.s = sgl_tmp_dest;
2478: m_A[0].stat.arp = 0;
2479: }
2480: }
2481: }
2482:
2483: /* Execute 0x32, [p]fix.{ss,sd,dd} (SC) added and implemented this */
2484: void i860_cpu_device::insn_fix(UINT32 insn) {
2485: UINT32 fsrc1 = get_fsrc1 (insn);
2486: UINT32 fdest = get_fdest (insn);
2487: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
2488: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
2489: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
2490:
2491: #if TRACE_UNDEFINED_I860
2492: /* Check for invalid .ds or .ss combinations. */
2493: if ((insn & 0x080) == 0) {
2494: unrecog_opcode (m_pc, insn);
2495: return;
2496: }
2497: #endif
2498:
2499: /* Do the operation, being careful about source and result
2500: precision. Operation: fdest = integer part of fsrc1 in
2501: lower 32-bits. */
2502: if (src_prec) {
2503: double v1 = get_fregval_d (fsrc1);
2504: INT32 iv = rint(v1);
2505: /* We always write a single, since the lower 32-bits of fdest
2506: get the result (and the even numbered reg is the lower). */
2507: set_fregval_s (fdest, *(float *)&iv);
2508: }
2509: else
2510: {
2511: float v1 = get_fregval_s (fsrc1);
2512: INT32 iv = rint(v1);
2513: /* We always write a single, since the lower 32-bits of fdest
2514: get the result (and the even numbered reg is the lower). */
2515: set_fregval_s (fdest, *(float *)&iv);
2516: }
2517:
2518: /* FIXME: Handle updating of pipestages for pfix. */
2519: /* Includes looking at ARP (add result precision.) */
2520: if (piped)
2521: {
2522: Log_Printf(LOG_WARN, "[i860:%08X] insn_fix: FIXME: pipelined not functional yet", m_pc);
2523: if (res_prec)
2524: set_fregval_d (fdest, 0.0);
2525: else
2526: set_fregval_s (fdest, 0.0);
2527: }
2528: }
2529:
2530: /* Operand types for PFAM/PFMAM routine below. */
2531: enum {
2532: OP_SRC1 = 0,
2533: OP_SRC2 = 1,
2534: OP_KI = 2,
2535: OP_KR = 4,
2536: OP_T = 8,
2537: OP_MPIPE = 16,
2538: OP_APIPE = 32,
2539: FLAGM = 64 /* Indicates PFMAM uses M rather than A pipe result. */
2540: };
2541:
2542: /* A table to map DPC value to source operands.
2543:
2544: The PFAM and PFMAM tables are nearly identical, and the only differences
2545: are that every time PFAM uses the A pipe, PFMAM uses the M pipe instead.
2546: So we only represent the PFAM table and use a special flag on any entry
2547: where the PFMAM table would use the M pipe rather than the A pipe.
2548: Also, entry 16 is not valid for PFMAM. */
2549: static const struct
2550: {
2551: int M_unit_op1;
2552: int M_unit_op2;
2553: int A_unit_op1;
2554: int A_unit_op2;
2555: int T_loaded;
2556: int K_loaded;
2557: } src_opers[] = {
2558: /* 0000 */ { OP_KR, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0},
2559: /* 0001 */ { OP_KR, OP_SRC2, OP_T, OP_MPIPE, 0, 1},
2560: /* 0010 */ { OP_KR, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0},
2561: /* 0011 */ { OP_KR, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1},
2562: /* 0100 */ { OP_KI, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0},
2563: /* 0101 */ { OP_KI, OP_SRC2, OP_T, OP_MPIPE, 0, 1},
2564: /* 0110 */ { OP_KI, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0},
2565: /* 0111 */ { OP_KI, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1},
2566: /* 1000 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0},
2567: /* 1001 */ { OP_SRC1, OP_SRC2, OP_APIPE|FLAGM, OP_MPIPE, 0, 0},
2568: /* 1010 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0},
2569: /* 1011 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 0},
2570: /* 1100 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0},
2571: /* 1101 */ { OP_SRC1, OP_SRC2, OP_T, OP_MPIPE, 0, 0},
2572: /* 1110 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0},
2573: /* 1111 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 0, 0}
2574: };
2575:
2576: float i860_cpu_device::get_fval_from_optype_s (UINT32 insn, int optype)
2577: {
2578: float retval = 0.0;
2579: UINT32 fsrc1 = get_fsrc1 (insn);
2580: UINT32 fsrc2 = get_fsrc2 (insn);
2581:
2582: optype &= ~FLAGM;
2583: switch (optype)
2584: {
2585: case OP_SRC1:
2586: retval = get_fregval_s (fsrc1);
2587: break;
2588: case OP_SRC2:
2589: retval = get_fregval_s (fsrc2);
2590: break;
2591: case OP_KI:
2592: retval = m_KI.s;
2593: break;
2594: case OP_KR:
2595: retval = m_KR.s;
2596: break;
2597: case OP_T:
2598: retval = m_T.s;
2599: break;
2600: case OP_MPIPE:
2601: /* Last stage is 3rd stage for single precision input. */
2602: retval = m_M[2].val.s;
2603: break;
2604: case OP_APIPE:
2605: retval = m_A[2].val.s;
2606: break;
2607: default:
2608: assert (0);
2609: }
2610:
2611: return retval;
2612: }
2613:
2614:
2615: double i860_cpu_device::get_fval_from_optype_d (UINT32 insn, int optype)
2616: {
2617: double retval = 0.0;
2618: UINT32 fsrc1 = get_fsrc1 (insn);
2619: UINT32 fsrc2 = get_fsrc2 (insn);
2620:
2621: optype &= ~FLAGM;
2622: switch (optype)
2623: {
2624: case OP_SRC1:
2625: retval = get_fregval_d (fsrc1);
2626: break;
2627: case OP_SRC2:
2628: retval = get_fregval_d (fsrc2);
2629: break;
2630: case OP_KI:
2631: retval = m_KI.d;
2632: break;
2633: case OP_KR:
2634: retval = m_KR.d;
2635: break;
2636: case OP_T:
2637: retval = m_T.d;
2638: break;
2639: case OP_MPIPE:
2640: /* Last stage is 2nd stage for double precision input. */
2641: retval = m_M[1].val.d;
2642: break;
2643: case OP_APIPE:
2644: retval = m_A[2].val.d;
2645: break;
2646: default:
2647: assert (0);
2648: }
2649:
2650: return retval;
2651: }
2652:
2653:
2654: /* Execute pf[m]{a,s}m.{ss,sd,dd} fsrc1,fsrc2,fdest (FP dual ops).
2655:
2656: Since these are always pipelined, the P bit is used to distinguish
2657: family pfam (P=1) from family pfmam (P=0), and the lower 4 bits
2658: of the extended opcode is the DPC.
2659:
2660: Note also that the S and R bits are slightly different than normal
2661: floating point operations. The S bit denotes the precision of the
2662: multiplication source, while the R bit denotes the precision of
2663: the addition source as well as precision of all results. */
2664: void i860_cpu_device::insn_dualop (UINT32 insn)
2665: {
2666: UINT32 fsrc1 = get_fsrc1 (insn);
2667: UINT32 fsrc2 = get_fsrc2 (insn);
2668: UINT32 fdest = get_fdest (insn);
2669: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
2670: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
2671: int is_pfam = insn & 0x400; /* 1 = pfam, 0 = pfmam. */
2672: int is_sub = insn & 0x10; /* 1 = pf[m]sm, 0 = pf[m]am. */
2673: double dbl_tmp_dest_mul = 0.0;
2674: float sgl_tmp_dest_mul = 0.0;
2675: double dbl_tmp_dest_add = 0.0;
2676: float sgl_tmp_dest_add = 0.0;
2677: double dbl_last_Mstage_contents = 0.0;
2678: float sgl_last_Mstage_contents = 0.0;
2679: double dbl_last_Astage_contents = 0.0;
2680: float sgl_last_Astage_contents = 0.0;
2681: int num_mul_stages = src_prec ? 2 : 3;
2682:
2683: int dpc = insn & 0xf;
2684: int M_unit_op1 = src_opers[dpc].M_unit_op1;
2685: int M_unit_op2 = src_opers[dpc].M_unit_op2;
2686: int A_unit_op1 = src_opers[dpc].A_unit_op1;
2687: int A_unit_op2 = src_opers[dpc].A_unit_op2;
2688: int T_loaded = src_opers[dpc].T_loaded;
2689: int K_loaded = src_opers[dpc].K_loaded;
2690:
2691: #if TRACE_UNDEFINED_I860
2692: /* Check for invalid .ds combination. */
2693: if ((insn & 0x180) == 0x100)
2694: {
2695: unrecog_opcode (m_pc, insn);
2696: return;
2697: }
2698: #endif
2699:
2700: if (is_pfam == 0)
2701: {
2702: #if TRACE_UNDEFINED_I860
2703: /* Check for invalid DPC combination 16 for PFMAM. */
2704: if (dpc == 16)
2705: {
2706: unrecog_opcode (m_pc, insn);
2707: return;
2708: }
2709: #endif
2710:
2711: /* PFMAM table adjustments (M_unit_op1 is never a pipe stage,
2712: so no adjustment made for it). */
2713: M_unit_op2 = (M_unit_op2 & FLAGM) ? OP_MPIPE : M_unit_op2;
2714: A_unit_op1 = (A_unit_op1 & FLAGM) ? OP_MPIPE : A_unit_op1;
2715: A_unit_op2 = (A_unit_op2 & FLAGM) ? OP_MPIPE : A_unit_op2;
2716: }
2717:
2718: /* FIXME: Check for fsrc1/fdest overlap for some mul DPC combinations. */
2719:
2720: /* Retrieve the contents of the last stage of the multiplier pipeline,
2721: whose precision is specified by the MRP bit of the stage's result-
2722: status bits. Note for multiply, the number of stages is determined
2723: by the source precision of the current operation. */
2724: if (m_M[num_mul_stages - 1].stat.mrp)
2725: dbl_last_Mstage_contents = m_M[num_mul_stages - 1].val.d;
2726: else
2727: sgl_last_Mstage_contents = m_M[num_mul_stages - 1].val.s;
2728:
2729: /* Similarly, retrieve the last stage of the adder pipe. */
2730: if (m_A[2].stat.arp)
2731: dbl_last_Astage_contents = m_A[2].val.d;
2732: else
2733: sgl_last_Astage_contents = m_A[2].val.s;
2734:
2735: /* Do the mul operation, being careful about source and result
2736: precision. */
2737: if (src_prec)
2738: {
2739: double v1 = get_fval_from_optype_d (insn, M_unit_op1);
2740: double v2 = get_fval_from_optype_d (insn, M_unit_op2);
2741:
2742: /* For mul, if fsrc2 is the same as fdest, then the last stage
2743: is bypassed to fsrc2 (rather than using the value in fsrc2).
2744: This bypass is not available for fsrc1, and is undefined behavior. */
2745: if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
2746: v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
2747: if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
2748: v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
2749:
2750: if (res_prec)
2751: dbl_tmp_dest_mul = v1 * v2;
2752: else
2753: sgl_tmp_dest_mul = (float)(v1 * v2);
2754: }
2755: else
2756: {
2757: float v1 = get_fval_from_optype_s (insn, M_unit_op1);
2758: float v2 = get_fval_from_optype_s (insn, M_unit_op2);
2759:
2760: /* For mul, if fsrc2 is the same as fdest, then the last stage
2761: is bypassed to fsrc2 (rather than using the value in fsrc2).
2762: This bypass is not available for fsrc1, and is undefined behavior. */
2763: if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
2764: v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
2765: if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
2766: v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
2767:
2768: if (res_prec)
2769: dbl_tmp_dest_mul = (double)(v1 * v2);
2770: else
2771: sgl_tmp_dest_mul = v1 * v2;
2772: }
2773:
2774: /* Do the add operation, being careful about source and result
2775: precision. Remember, the R bit indicates source and result precision
2776: here. */
2777: if (res_prec)
2778: {
2779: double v1 = get_fval_from_optype_d (insn, A_unit_op1);
2780: double v2 = get_fval_from_optype_d (insn, A_unit_op2);
2781:
2782: /* For add/sub, if fsrc1 is the same as fdest, then the last stage
2783: is bypassed to fsrc1 (rather than using the value in fsrc1).
2784: Likewise for fsrc2. */
2785: if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
2786: v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
2787: if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
2788: v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents;
2789:
2790: if (res_prec)
2791: dbl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2;
2792: else
2793: sgl_tmp_dest_add = is_sub ? (float)(v1 - v2) : (float)(v1 + v2);
2794: }
2795: else
2796: {
2797: float v1 = get_fval_from_optype_s (insn, A_unit_op1);
2798: float v2 = get_fval_from_optype_s (insn, A_unit_op2);
2799:
2800: /* For add/sub, if fsrc1 is the same as fdest, then the last stage
2801: is bypassed to fsrc1 (rather than using the value in fsrc1).
2802: Likewise for fsrc2. */
2803: if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest)
2804: v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
2805: if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest)
2806: v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents;
2807:
2808: if (res_prec)
2809: dbl_tmp_dest_add = is_sub ? (double)(v1 - v2) : (double)(v1 + v2);
2810: else
2811: sgl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2;
2812: }
2813:
2814: /* If necessary, load T. */
2815: if (T_loaded)
2816: {
2817: /* T is loaded from the result of the last stage of the multiplier. */
2818: if (m_M[num_mul_stages - 1].stat.mrp)
2819: m_T.d = dbl_last_Mstage_contents;
2820: else
2821: m_T.s = sgl_last_Mstage_contents;
2822: }
2823:
2824: /* If necessary, load KR or KI. */
2825: if (K_loaded)
2826: {
2827: /* KI or KR is loaded from the first register input. */
2828: if (M_unit_op1 == OP_KI)
2829: {
2830: if (src_prec)
2831: m_KI.d = get_fregval_d (fsrc1);
2832: else
2833: m_KI.s = get_fregval_s (fsrc1);
2834: }
2835: else if (M_unit_op1 == OP_KR)
2836: {
2837: if (src_prec)
2838: m_KR.d = get_fregval_d (fsrc1);
2839: else
2840: m_KR.s = get_fregval_s (fsrc1);
2841: }
2842: else
2843: assert (0);
2844: }
2845:
2846: /* Now update fdest (either from adder pipe or multiplier pipe,
2847: depending on whether the instruction is pfam or pfmam). */
2848: if (is_pfam)
2849: {
2850: /* Update fdest with the result from the last stage of the
2851: adder pipeline, with precision specified by the ARP
2852: bit of the stage's result-status bits. */
2853: if (m_A[2].stat.arp)
2854: set_fregval_d (fdest, dbl_last_Astage_contents);
2855: else
2856: set_fregval_s (fdest, sgl_last_Astage_contents);
2857: }
2858: else
2859: {
2860: /* Update fdest with the result from the last stage of the
2861: multiplier pipeline, with precision specified by the MRP
2862: bit of the stage's result-status bits. */
2863: if (m_M[num_mul_stages - 1].stat.mrp)
2864: set_fregval_d (fdest, dbl_last_Mstage_contents);
2865: else
2866: set_fregval_s (fdest, sgl_last_Mstage_contents);
2867: }
2868:
2869: /* FIXME: Set result-status bits besides MRP. And copy to fsr from
2870: last stage. */
2871: /* FIXME: Mixed precision (only weird for pfmul). */
2872: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
2873: /* Copy 3rd stage MRP to FSR. */
2874: if (m_M[num_mul_stages - 2 /* 1 */].stat.mrp)
2875: m_cregs[CR_FSR] |= 0x10000000;
2876: else
2877: m_cregs[CR_FSR] &= ~0x10000000;
2878: #endif
2879:
2880: /* Now advance multiplier pipeline and write current calculation to
2881: first stage. */
2882: if (num_mul_stages == 3)
2883: {
2884: m_M[2] = m_M[1];
2885: m_M[1] = m_M[0];
2886: }
2887: else
2888: m_M[1] = m_M[0];
2889:
2890: if (res_prec)
2891: {
2892: m_M[0].val.d = dbl_tmp_dest_mul;
2893: m_M[0].stat.mrp = 1;
2894: }
2895: else
2896: {
2897: m_M[0].val.s = sgl_tmp_dest_mul;
2898: m_M[0].stat.mrp = 0;
2899: }
2900:
2901: /* FIXME: Set result-status bits besides ARP. And copy to fsr from
2902: last stage. */
2903: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
2904: /* Copy 3rd stage ARP to FSR. */
2905: if (m_A[1 /* 2 */].stat.arp)
2906: m_cregs[CR_FSR] |= 0x20000000;
2907: else
2908: m_cregs[CR_FSR] &= ~0x20000000;
2909: #endif
2910:
2911: /* Now advance adder pipeline and write current calculation to
2912: first stage. */
2913: m_A[2] = m_A[1];
2914: m_A[1] = m_A[0];
2915: if (res_prec)
2916: {
2917: m_A[0].val.d = dbl_tmp_dest_add;
2918: m_A[0].stat.arp = 1;
2919: }
2920: else
2921: {
2922: m_A[0].val.s = sgl_tmp_dest_add;
2923: m_A[0].stat.arp = 0;
2924: }
2925: }
2926:
2927:
2928: /* Execute frcp.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */
2929: void i860_cpu_device::insn_frcp (UINT32 insn)
2930: {
2931: UINT32 fsrc2 = get_fsrc2 (insn);
2932: UINT32 fdest = get_fdest (insn);
2933: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
2934: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
2935:
2936: /* Do the operation, being careful about source and result
2937: precision. */
2938: if (src_prec)
2939: {
2940: double v = get_fregval_d (fsrc2);
2941: double res;
2942: if (v == (double)0.0)
2943: {
2944: /* Generate source-exception trap if fsrc2 is 0. */
2945: if (0 /* && GET_FSR_FTE () */)
2946: {
2947: SET_PSR_FT (1);
2948: SET_FSR_SE (1);
2949: m_flow |= GET_FSR_FTE ();
2950: }
2951: /* Set fdest to INF or some other exceptional value here? */
2952: }
2953: else
2954: {
2955: /* Real i860 isn't a precise as a real divide, but this should
2956: be okay. */
2957: SET_FSR_SE (0);
2958: *((UINT64 *)&v) &= 0xfffff00000000000ULL;
2959: res = (double)1.0/v;
2960: *((UINT64 *)&res) &= 0xfffff00000000000ULL;
2961: if (res_prec)
2962: set_fregval_d (fdest, res);
2963: else
2964: set_fregval_s (fdest, (float)res);
2965: }
2966: }
2967: else
2968: {
2969: float v = get_fregval_s (fsrc2);
2970: float res;
2971: if (v == 0.0)
2972: {
2973: /* Generate source-exception trap if fsrc2 is 0. */
2974: if (0 /* GET_FSR_FTE () */)
2975: {
2976: SET_PSR_FT (1);
2977: SET_FSR_SE (1);
2978: m_flow |= GET_FSR_FTE ();
2979: }
2980: /* Set fdest to INF or some other exceptional value here? */
2981: }
2982: else
2983: {
2984: /* Real i860 isn't a precise as a real divide, but this should
2985: be okay. */
2986: SET_FSR_SE (0);
2987: *((UINT32 *)&v) &= 0xffff8000;
2988: res = (float)1.0/v;
2989: *((UINT32 *)&res) &= 0xffff8000;
2990: if (res_prec)
2991: set_fregval_d (fdest, (double)res);
2992: else
2993: set_fregval_s (fdest, res);
2994: }
2995: }
2996: }
2997:
2998:
2999: /* Execute frsqr.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */
3000: void i860_cpu_device::insn_frsqr (UINT32 insn)
3001: {
3002: UINT32 fsrc2 = get_fsrc2 (insn);
3003: UINT32 fdest = get_fdest (insn);
3004: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
3005: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
3006:
3007: #if TRACE_UNDEFINED_I860
3008: /* Check for invalid .ds combination. */
3009: if ((insn & 0x180) == 0x100)
3010: {
3011: unrecog_opcode (m_pc, insn);
3012: return;
3013: }
3014:
3015: /* Check for invalid .ds combination. */
3016: if ((insn & 0x180) == 0x100)
3017: {
3018: unrecog_opcode (m_pc, insn);
3019: return;
3020: }
3021: #endif
3022:
3023: /* Do the operation, being careful about source and result
3024: precision. */
3025: if (src_prec)
3026: {
3027: double v = get_fregval_d (fsrc2);
3028: double res;
3029: if (v == 0.0 || v < 0.0)
3030: {
3031: /* Generate source-exception trap if fsrc2 is 0 or negative. */
3032: if (0 /* GET_FSR_FTE () */)
3033: {
3034: SET_PSR_FT (1);
3035: SET_FSR_SE (1);
3036: m_flow |= GET_FSR_FTE ();
3037: }
3038: /* Set fdest to INF or some other exceptional value here? */
3039: }
3040: else
3041: {
3042: SET_FSR_SE (0);
3043: *((UINT64 *)&v) &= 0xfffff00000000000ULL;
3044: res = (double)1.0/sqrt (v);
3045: *((UINT64 *)&res) &= 0xfffff00000000000ULL;
3046: if (res_prec)
3047: set_fregval_d (fdest, res);
3048: else
3049: set_fregval_s (fdest, (float)res);
3050: }
3051: }
3052: else
3053: {
3054: float v = get_fregval_s (fsrc2);
3055: float res;
3056: if (v == 0.0 || v < 0.0)
3057: {
3058: /* Generate source-exception trap if fsrc2 is 0 or negative. */
3059: if (0 /* GET_FSR_FTE () */)
3060: {
3061: SET_PSR_FT (1);
3062: SET_FSR_SE (1);
3063: m_flow |= GET_FSR_FTE ();
3064: }
3065: /* Set fdest to INF or some other exceptional value here? */
3066: }
3067: else
3068: {
3069: SET_FSR_SE (0);
3070: *((UINT32 *)&v) &= 0xffff8000;
3071: res = (float)1.0/sqrt (v);
3072: *((UINT32 *)&res) &= 0xffff8000;
3073: if (res_prec)
3074: set_fregval_d (fdest, (double)res);
3075: else
3076: set_fregval_s (fdest, res);
3077: }
3078: }
3079: }
3080:
3081:
3082: /* Execute fxfr fsrc1,idest. */
3083: void i860_cpu_device::insn_fxfr (UINT32 insn)
3084: {
3085: UINT32 fsrc1 = get_fsrc1 (insn);
3086: UINT32 idest = get_idest (insn);
3087: float fv = 0;
3088:
3089: /* This is a bit-pattern transfer, not a conversion. */
3090: fv = get_fregval_s (fsrc1);
3091: set_iregval (idest, *(UINT32 *)&fv);
3092: }
3093:
3094:
3095: /* Execute [p]ftrunc.{ss,sd,dd} fsrc1,idest. */
3096: /* FIXME: Is .ss really a valid combination? On the one hand,
3097: the programmer's reference (1990) lists ftrunc.p where .p
3098: is any of {ss,sd,dd}. On the other hand, a paragraph on the
3099: same page states that [p]ftrunc must specify double-precision
3100: results. Inconsistent.
3101: Update: The vendor SVR4 assembler does not accept .ss combination,
3102: so the latter sentence above appears to be the correct way. */
3103: void i860_cpu_device::insn_ftrunc (UINT32 insn)
3104: {
3105: UINT32 fsrc1 = get_fsrc1 (insn);
3106: UINT32 fdest = get_fdest (insn);
3107: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
3108: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
3109: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3110:
3111: #if TRACE_UNDEFINED_I860
3112: /* Check for invalid .ds or .ss combinations. */
3113: if ((insn & 0x080) == 0)
3114: {
3115: unrecog_opcode (m_pc, insn);
3116: return;
3117: }
3118: #endif
3119:
3120: /* Do the operation, being careful about source and result
3121: precision. Operation: fdest = integer part of fsrc1 in
3122: lower 32-bits. */
3123: if (src_prec)
3124: {
3125: double v1 = get_fregval_d (fsrc1);
3126: INT32 iv = (INT32)v1;
3127: /* We always write a single, since the lower 32-bits of fdest
3128: get the result (and the even numbered reg is the lower). */
3129: set_fregval_s (fdest, *(float *)&iv);
3130: }
3131: else
3132: {
3133: float v1 = get_fregval_s (fsrc1);
3134: INT32 iv = (INT32)v1;
3135: /* We always write a single, since the lower 32-bits of fdest
3136: get the result (and the even numbered reg is the lower). */
3137: set_fregval_s (fdest, *(float *)&iv);
3138: }
3139:
3140: /* FIXME: Handle updating of pipestages for pftrunc. */
3141: /* Includes looking at ARP (add result precision.) */
3142: if (piped)
3143: {
3144: Log_Printf(LOG_WARN, "[i860:%08X] insn_ftrunc: FIXME: pipelined not functional yet", m_pc);
3145: if (res_prec)
3146: set_fregval_d (fdest, 0.0);
3147: else
3148: set_fregval_s (fdest, 0.0);
3149: }
3150: }
3151:
3152:
3153: /* Execute [p]famov.{ss,sd,ds,dd} fsrc1,fdest. */
3154: void i860_cpu_device::insn_famov (UINT32 insn)
3155: {
3156: UINT32 fsrc1 = get_fsrc1 (insn);
3157: UINT32 fdest = get_fdest (insn);
3158: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
3159: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
3160: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3161: double dbl_tmp_dest = 0.0;
3162: double sgl_tmp_dest = 0.0;
3163:
3164: /* Do the operation, being careful about source and result
3165: precision. */
3166: if (src_prec)
3167: {
3168: double v1 = get_fregval_d (fsrc1);
3169: if (res_prec)
3170: dbl_tmp_dest = v1;
3171: else
3172: sgl_tmp_dest = (float)v1;
3173: }
3174: else
3175: {
3176: float v1 = get_fregval_s (fsrc1);
3177: if (res_prec)
3178: dbl_tmp_dest = (double)v1;
3179: else
3180: sgl_tmp_dest = v1;
3181: }
3182:
3183: /* FIXME: Set result-status bits besides ARP. And copy to fsr from
3184: last stage. */
3185: /* FIXME: Scalar version flows through all stages. */
3186: if (!piped)
3187: {
3188: /* Scalar version writes the current calculation to the fdest
3189: register, with precision specified by the R bit. */
3190: if (res_prec)
3191: set_fregval_d (fdest, dbl_tmp_dest);
3192: else
3193: set_fregval_s (fdest, sgl_tmp_dest);
3194: }
3195: else
3196: {
3197: /* Pipelined version writes fdest with the result from the last
3198: stage of the pipeline, with precision specified by the ARP
3199: bit of the stage's result-status bits. */
3200: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
3201: /* Copy 3rd stage ARP to FSR. */
3202: if (m_A[1 /* 2 */].stat.arp)
3203: m_cregs[CR_FSR] |= 0x20000000;
3204: else
3205: m_cregs[CR_FSR] &= ~0x20000000;
3206: #endif
3207: if (m_A[2].stat.arp) /* 3rd (last) stage. */
3208: set_fregval_d (fdest, m_A[2].val.d);
3209: else
3210: set_fregval_s (fdest, m_A[2].val.s);
3211:
3212: /* Now advance pipeline and write current calculation to
3213: first stage. */
3214: m_A[2] = m_A[1];
3215: m_A[1] = m_A[0];
3216: if (res_prec)
3217: {
3218: m_A[0].val.d = dbl_tmp_dest;
3219: m_A[0].stat.arp = 1;
3220: }
3221: else
3222: {
3223: m_A[0].val.s = sgl_tmp_dest;
3224: m_A[0].stat.arp = 0;
3225: }
3226: }
3227: }
3228:
3229:
3230: /* Execute [p]fiadd/sub.{ss,dd} fsrc1,fsrc2,fdest. */
3231: void i860_cpu_device::insn_fiadd_sub (UINT32 insn)
3232: {
3233: UINT32 fsrc1 = get_fsrc1 (insn);
3234: UINT32 fsrc2 = get_fsrc2 (insn);
3235: UINT32 fdest = get_fdest (insn);
3236: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
3237: int res_prec = insn & 0x080; /* 1 = double, 0 = single. */
3238: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3239: int is_sub = insn & 0x4; /* 1 = sub, 0 = add. */
3240: double dbl_tmp_dest = 0.0;
3241: float sgl_tmp_dest = 0.0;
3242:
3243: #if TRACE_UNDEFINED_I860
3244: /* Check for invalid .ds and .sd combinations. */
3245: if ((insn & 0x180) == 0x100 || (insn & 0x180) == 0x080)
3246: {
3247: unrecog_opcode (m_pc, insn);
3248: return;
3249: }
3250: #endif
3251:
3252: /* Do the operation, being careful about source and result
3253: precision. */
3254: if (src_prec)
3255: {
3256: double v1 = get_fregval_d (fsrc1);
3257: double v2 = get_fregval_d (fsrc2);
3258: UINT64 iv1 = *(UINT64 *)&v1;
3259: UINT64 iv2 = *(UINT64 *)&v2;
3260: UINT64 r;
3261: if (is_sub)
3262: r = iv1 - iv2;
3263: else
3264: r = iv1 + iv2;
3265: if (res_prec)
3266: dbl_tmp_dest = *(double *)&r;
3267: else
3268: assert (0); /* .ds not allowed. */
3269: }
3270: else
3271: {
3272: float v1 = get_fregval_s (fsrc1);
3273: float v2 = get_fregval_s (fsrc2);
3274: UINT64 iv1 = (UINT64)(*(UINT32 *)&v1);
3275: UINT64 iv2 = (UINT64)(*(UINT32 *)&v2);
3276: UINT32 r;
3277: if (is_sub)
3278: r = (UINT32)(iv1 - iv2);
3279: else
3280: r = (UINT32)(iv1 + iv2);
3281: if (res_prec)
3282: assert (0); /* .sd not allowed. */
3283: else
3284: sgl_tmp_dest = *(float *)&r;
3285: }
3286:
3287: /* FIXME: Copy result-status bit IRP to fsr from last stage. */
3288: /* FIXME: Scalar version flows through all stages. */
3289: if (!piped)
3290: {
3291: /* Scalar version writes the current calculation to the fdest
3292: register, with precision specified by the R bit. */
3293: if (res_prec)
3294: set_fregval_d (fdest, dbl_tmp_dest);
3295: else
3296: set_fregval_s (fdest, sgl_tmp_dest);
3297: }
3298: else
3299: {
3300: /* Pipelined version writes fdest with the result from the last
3301: stage of the pipeline, with precision specified by the IRP
3302: bit of the stage's result-status bits. */
3303: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
3304: /* Copy stage IRP to FSR. */
3305: if (res_prec)
3306: m_cregs[CR_FSR] |= 0x08000000;
3307: else
3308: m_cregs[CR_FSR] &= ~0x08000000;
3309: #endif
3310: if (m_G.stat.irp) /* 1st (and last) stage. */
3311: set_fregval_d (fdest, m_G.val.d);
3312: else
3313: set_fregval_s (fdest, m_G.val.s);
3314:
3315: /* Now write current calculation to first and only stage. */
3316: if (res_prec)
3317: {
3318: m_G.val.d = dbl_tmp_dest;
3319: m_G.stat.irp = 1;
3320: }
3321: else
3322: {
3323: m_G.val.s = sgl_tmp_dest;
3324: m_G.stat.irp = 0;
3325: }
3326: }
3327: }
3328:
3329:
3330: /* Execute pf{gt,le,eq}.{ss,dd} fsrc1,fsrc2,fdest.
3331: Opcode pfgt has R bit cleared; pfle has R bit set. */
3332: void i860_cpu_device::insn_fcmp (UINT32 insn) {
3333: UINT32 fsrc1 = get_fsrc1 (insn);
3334: UINT32 fsrc2 = get_fsrc2 (insn);
3335: UINT32 fdest = get_fdest (insn);
3336: int src_prec = insn & 0x100; /* 1 = double, 0 = single. */
3337: double dbl_tmp_dest = 0.0;
3338: double sgl_tmp_dest = 0.0;
3339: /* int is_eq = insn & 1; */
3340: int is_gt = ((insn & 0x81) == 0x00);
3341: int is_le = ((insn & 0x81) == 0x80);
3342:
3343: /* Save the CC for DIM bc/bnc */
3344: m_dim_cc = GET_PSR_CC();
3345: m_dim_cc_valid = m_dim != DIM_NONE;
3346:
3347: /* Do the operation. Source and result precision must be the same.
3348: pfgt: CC set if fsrc1 > fsrc2, else cleared.
3349: pfle: CC cleared if fsrc1 <= fsrc2, else set.
3350: pfeq: CC set if fsrc1 = fsrc2, else cleared.
3351:
3352: Note that the compares write an undefined (but non-exceptional)
3353: result into the first stage of the adder pipeline. We'll model
3354: this by just pushing in dbl_ or sgl_tmp_dest which equal 0.0. */
3355: if (src_prec) {
3356: double v1 = get_fregval_d (fsrc1);
3357: double v2 = get_fregval_d (fsrc2);
3358: if (is_gt) /* gt. */
3359: SET_PSR_CC_F (v1 > v2 ? 1 : 0);
3360: else if (is_le) /* le. */
3361: SET_PSR_CC_F (v1 <= v2 ? 0 : 1);
3362: else /* eq. */
3363: SET_PSR_CC_F (v1 == v2 ? 1 : 0);
3364: } else {
3365: float v1 = get_fregval_s (fsrc1);
3366: float v2 = get_fregval_s (fsrc2);
3367: if (is_gt) /* gt. */
3368: SET_PSR_CC_F (v1 > v2 ? 1 : 0);
3369: else if (is_le) /* le. */
3370: SET_PSR_CC_F (v1 <= v2 ? 0 : 1);
3371: else /* eq. */
3372: SET_PSR_CC_F (v1 == v2 ? 1 : 0);
3373: }
3374:
3375: /* FIXME: Set result-status bits besides ARP. And copy to fsr from
3376: last stage. */
3377: /* These write fdest with the result from the last
3378: stage of the pipeline, with precision specified by the ARP
3379: bit of the stage's result-status bits. */
3380: #if 1 /* FIXME: WIP on FSR update. This may not be correct. */
3381: /* Copy 3rd stage ARP to FSR. */
3382: if (m_A[1 /* 2 */].stat.arp)
3383: m_cregs[CR_FSR] |= 0x20000000;
3384: else
3385: m_cregs[CR_FSR] &= ~0x20000000;
3386: #endif
3387: if (m_A[2].stat.arp) /* 3rd (last) stage. */
3388: set_fregval_d (fdest, m_A[2].val.d);
3389: else
3390: set_fregval_s (fdest, m_A[2].val.s);
3391:
3392: /* Now advance pipeline and write current calculation to
3393: first stage. */
3394: m_A[2] = m_A[1];
3395: m_A[1] = m_A[0];
3396: if (src_prec) {
3397: m_A[0].val.d = dbl_tmp_dest;
3398: m_A[0].stat.arp = 1;
3399: } else {
3400: m_A[0].val.s = sgl_tmp_dest;
3401: m_A[0].stat.arp = 0;
3402: }
3403: }
3404:
3405:
3406: /* Execute [p]fzchk{l,s} fsrc1,fsrc2,fdest.
3407: The fzchk instructions have S and R bits set. */
3408: void i860_cpu_device::insn_fzchk (UINT32 insn)
3409: {
3410: UINT32 fsrc1 = get_fsrc1 (insn);
3411: UINT32 fsrc2 = get_fsrc2 (insn);
3412: UINT32 fdest = get_fdest (insn);
3413: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3414: int is_fzchks = insn & 8; /* 1 = fzchks, 0 = fzchkl. */
3415: double dbl_tmp_dest = 0.0;
3416: int i;
3417: double v1 = get_fregval_d (fsrc1);
3418: double v2 = get_fregval_d (fsrc2);
3419: UINT64 iv1 = *(UINT64 *)&v1;
3420: UINT64 iv2 = *(UINT64 *)&v2;
3421: UINT64 r = 0;
3422: char pm = GET_PSR_PM ();
3423:
3424: #if TRACE_UNDEFINED_I860
3425: /* Check for S and R bits set. */
3426: if ((insn & 0x180) != 0x180)
3427: {
3428: unrecog_opcode (m_pc, insn);
3429: return;
3430: }
3431: #endif
3432:
3433: /* Do the operation. The fzchks version operates in parallel on
3434: four 16-bit pixels, while the fzchkl operates on two 32-bit
3435: pixels (pixels are unsigned ordinals in this context). */
3436: if (is_fzchks)
3437: {
3438: pm = (pm >> 4) & 0x0f;
3439: for (i = 3; i >= 0; i--)
3440: {
3441: UINT16 ps1 = (iv1 >> (i * 16)) & 0xffff;
3442: UINT16 ps2 = (iv2 >> (i * 16)) & 0xffff;
3443: if (ps2 <= ps1)
3444: {
3445: r |= ((UINT64)ps2 << (i * 16));
3446: pm |= (1 << (7 - (3 - i)));
3447: }
3448: else
3449: {
3450: r |= ((UINT64)ps1 << (i * 16));
3451: pm &= ~(1 << (7 - (3 - i)));
3452: }
3453: }
3454: }
3455: else
3456: {
3457: pm = (pm >> 2) & 0x3f;
3458: for (i = 1; i >= 0; i--)
3459: {
3460: UINT32 ps1 = (iv1 >> (i * 32)) & 0xffffffff;
3461: UINT32 ps2 = (iv2 >> (i * 32)) & 0xffffffff;
3462: if (ps2 <= ps1)
3463: {
3464: r |= ((UINT64)ps2 << (i * 32));
3465: pm |= (1 << (7 - (1 - i)));
3466: }
3467: else
3468: {
3469: r |= ((UINT64)ps1 << (i * 32));
3470: pm &= ~(1 << (7 - (1 - i)));
3471: }
3472: }
3473: }
3474:
3475: dbl_tmp_dest = *(double *)&r;
3476: SET_PSR_PM (pm);
3477: m_merge = 0;
3478:
3479: /* FIXME: Copy result-status bit IRP to fsr from last stage. */
3480: /* FIXME: Scalar version flows through all stages. */
3481: if (!piped)
3482: {
3483: /* Scalar version writes the current calculation to the fdest
3484: register, always with double precision. */
3485: set_fregval_d (fdest, dbl_tmp_dest);
3486: }
3487: else
3488: {
3489: /* Pipelined version writes fdest with the result from the last
3490: stage of the pipeline, with precision specified by the IRP
3491: bit of the stage's result-status bits. */
3492: if (m_G.stat.irp) /* 1st (and last) stage. */
3493: set_fregval_d (fdest, m_G.val.d);
3494: else
3495: set_fregval_s (fdest, m_G.val.s);
3496:
3497: /* Now write current calculation to first and only stage. */
3498: m_G.val.d = dbl_tmp_dest;
3499: m_G.stat.irp = 1;
3500: }
3501: }
3502:
3503:
3504: /* Execute [p]form.dd fsrc1,fdest.
3505: The form.dd instructions have S and R bits set. */
3506: void i860_cpu_device::insn_form (UINT32 insn)
3507: {
3508: UINT32 fsrc1 = get_fsrc1 (insn);
3509: UINT32 fdest = get_fdest (insn);
3510: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3511: double dbl_tmp_dest = 0.0;
3512: double v1 = get_fregval_d (fsrc1);
3513: UINT64 iv1 = *(UINT64 *)&v1;
3514:
3515: #if TRACE_UNDEFINED_I860
3516: /* Check for S and R bits set. */
3517: if ((insn & 0x180) != 0x180)
3518: {
3519: unrecog_opcode (m_pc, insn);
3520: return;
3521: }
3522: #endif
3523:
3524: iv1 |= m_merge;
3525: dbl_tmp_dest = *(double *)&iv1;
3526: m_merge = 0;
3527:
3528: /* FIXME: Copy result-status bit IRP to fsr from last stage. */
3529: /* FIXME: Scalar version flows through all stages. */
3530: if (!piped)
3531: {
3532: /* Scalar version writes the current calculation to the fdest
3533: register, always with double precision. */
3534: set_fregval_d (fdest, dbl_tmp_dest);
3535: }
3536: else
3537: {
3538: /* Pipelined version writes fdest with the result from the last
3539: stage of the pipeline, with precision specified by the IRP
3540: bit of the stage's result-status bits. */
3541: if (m_G.stat.irp) /* 1st (and last) stage. */
3542: set_fregval_d (fdest, m_G.val.d);
3543: else
3544: set_fregval_s (fdest, m_G.val.s);
3545:
3546: /* Now write current calculation to first and only stage. */
3547: m_G.val.d = dbl_tmp_dest;
3548: m_G.stat.irp = 1;
3549: }
3550: }
3551:
3552:
3553: /* Execute [p]faddp fsrc1,fsrc2,fdest. */
3554: void i860_cpu_device::insn_faddp (UINT32 insn)
3555: {
3556: UINT32 fsrc1 = get_fsrc1 (insn);
3557: UINT32 fsrc2 = get_fsrc2 (insn);
3558: UINT32 fdest = get_fdest (insn);
3559: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3560: double dbl_tmp_dest = 0.0;
3561: double v1 = get_fregval_d (fsrc1);
3562: double v2 = get_fregval_d (fsrc2);
3563: UINT64 iv1 = *(UINT64 *)&v1;
3564: UINT64 iv2 = *(UINT64 *)&v2;
3565: UINT64 r = 0;
3566: int ps = GET_PSR_PS ();
3567:
3568: r = iv1 + iv2;
3569: dbl_tmp_dest = *(double *)&r;
3570:
3571: /* Update the merge register depending on the pixel size.
3572: PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */
3573: if (ps == 0)
3574: {
3575: m_merge = ((m_merge >> 8) & ~0xff00ff00ff00ff00ULL);
3576: m_merge |= (r & 0xff00ff00ff00ff00ULL);
3577: }
3578: else if (ps == 1)
3579: {
3580: m_merge = ((m_merge >> 6) & ~0xfc00fc00fc00fc00ULL);
3581: m_merge |= (r & 0xfc00fc00fc00fc00ULL);
3582: }
3583: else if (ps == 2)
3584: {
3585: m_merge = ((m_merge >> 8) & ~0xff000000ff000000ULL);
3586: m_merge |= (r & 0xff000000ff000000ULL);
3587: }
3588: #if TRACE_UNDEFINED_I860
3589: else
3590: Log_Printf(LOG_WARN, "[i860:%08X] insn_faddp: Undefined i860XR behavior, invalid value %d for pixel size", m_pc, ps);
3591: #endif
3592:
3593: /* FIXME: Copy result-status bit IRP to fsr from last stage. */
3594: /* FIXME: Scalar version flows through all stages. */
3595: if (!piped)
3596: {
3597: /* Scalar version writes the current calculation to the fdest
3598: register, always with double precision. */
3599: set_fregval_d (fdest, dbl_tmp_dest);
3600: }
3601: else
3602: {
3603: /* Pipelined version writes fdest with the result from the last
3604: stage of the pipeline, with precision specified by the IRP
3605: bit of the stage's result-status bits. */
3606: if (m_G.stat.irp) /* 1st (and last) stage. */
3607: set_fregval_d (fdest, m_G.val.d);
3608: else
3609: set_fregval_s (fdest, m_G.val.s);
3610:
3611: /* Now write current calculation to first and only stage. */
3612: m_G.val.d = dbl_tmp_dest;
3613: m_G.stat.irp = 1;
3614: }
3615: }
3616:
3617:
3618: /* Execute [p]faddz fsrc1,fsrc2,fdest. */
3619: void i860_cpu_device::insn_faddz (UINT32 insn)
3620: {
3621: UINT32 fsrc1 = get_fsrc1 (insn);
3622: UINT32 fsrc2 = get_fsrc2 (insn);
3623: UINT32 fdest = get_fdest (insn);
3624: int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */
3625: double dbl_tmp_dest = 0.0;
3626: double v1 = get_fregval_d (fsrc1);
3627: double v2 = get_fregval_d (fsrc2);
3628: UINT64 iv1 = *(UINT64 *)&v1;
3629: UINT64 iv2 = *(UINT64 *)&v2;
3630: UINT64 r = 0;
3631:
3632: r = iv1 + iv2;
3633: dbl_tmp_dest = *(double *)&r;
3634:
3635: /* Update the merge register. */
3636: m_merge = ((m_merge >> 16) & ~0xffff0000ffff0000ULL);
3637: m_merge |= (r & 0xffff0000ffff0000ULL);
3638:
3639: /* FIXME: Copy result-status bit IRP to fsr from last stage. */
3640: /* FIXME: Scalar version flows through all stages. */
3641: if (!piped)
3642: {
3643: /* Scalar version writes the current calculation to the fdest
3644: register, always with double precision. */
3645: set_fregval_d (fdest, dbl_tmp_dest);
3646: }
3647: else
3648: {
3649: /* Pipelined version writes fdest with the result from the last
3650: stage of the pipeline, with precision specified by the IRP
3651: bit of the stage's result-status bits. */
3652: if (m_G.stat.irp) /* 1st (and last) stage. */
3653: set_fregval_d (fdest, m_G.val.d);
3654: else
3655: set_fregval_s (fdest, m_G.val.s);
3656:
3657: /* Now write current calculation to first and only stage. */
3658: m_G.val.d = dbl_tmp_dest;
3659: m_G.stat.irp = 1;
3660: }
3661: }
3662:
3663:
3664: /* Flags for the decode table. */
3665: enum {
3666: DEC_MORE = 1, /* More decoding necessary. */
3667: DEC_DECODED = 2 /* Fully decoded, go. */
3668: };
3669:
3670:
3671: /* First-level decode table (i.e., for the 6 primary opcode bits). */
3672: const i860_cpu_device::decode_tbl_t i860_cpu_device::decode_tbl[64] = {
3673: /* A slight bit of decoding for loads and stores is done in the
3674: execution routines (operand size and addressing mode), which
3675: is why their respective entries are identical. */
3676: { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.b isrc1(isrc2),idest. */
3677: { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.b #const(isrc2),idest. */
3678: { &i860_cpu_device::insn_ixfr, DEC_DECODED}, /* ixfr isrc1ni,fdest. */
3679: { &i860_cpu_device::insn_stx, DEC_DECODED}, /* st.b isrc1ni,#const(isrc2). */
3680: { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.{s,l} isrc1(isrc2),idest. */
3681: { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.{s,l} #const(isrc2),idest. */
3682: { 0, 0},
3683: { &i860_cpu_device::insn_stx, DEC_DECODED}, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/
3684: { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* fld.{l,d,q} isrc1(isrc2)[++],fdest. */
3685: { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* fld.{l,d,q} #const(isrc2)[++],fdest. */
3686: { &i860_cpu_device::insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,isrc1(isrc2)[++] */
3687: { &i860_cpu_device::insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,#const(isrc2)[++] */
3688: { &i860_cpu_device::insn_ld_ctrl, DEC_DECODED}, /* ld.c csrc2,idest. */
3689: { &i860_cpu_device::insn_flush, DEC_DECODED}, /* flush #const(isrc2) (or autoinc). */
3690: { &i860_cpu_device::insn_st_ctrl, DEC_DECODED}, /* st.c isrc1,csrc2. */
3691: { &i860_cpu_device::insn_pstd, DEC_DECODED}, /* pst.d fdest,#const(isrc2)[++]. */
3692: { &i860_cpu_device::insn_bri, DEC_DECODED}, /* bri isrc1ni. */
3693: { &i860_cpu_device::insn_trap, DEC_DECODED}, /* trap isrc1ni,isrc2,idest. */
3694: { 0, DEC_MORE}, /* FP ESCAPE FORMAT, more decode. */
3695: { 0, DEC_MORE}, /* CORE ESCAPE FORMAT, more decode. */
3696: { &i860_cpu_device::insn_btne, DEC_DECODED}, /* btne isrc1,isrc2,sbroff. */
3697: { &i860_cpu_device::insn_btne_imm, DEC_DECODED}, /* btne #const,isrc2,sbroff. */
3698: { &i860_cpu_device::insn_bte, DEC_DECODED}, /* bte isrc1,isrc2,sbroff. */
3699: { &i860_cpu_device::insn_bte_imm, DEC_DECODED}, /* bte #const5,isrc2,idest. */
3700: { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest.*/
3701: { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/
3702: { &i860_cpu_device::insn_br, DEC_DECODED}, /* br lbroff. */
3703: { &i860_cpu_device::insn_call, DEC_DECODED}, /* call lbroff . */
3704: { &i860_cpu_device::insn_bc, DEC_DECODED}, /* bc lbroff. */
3705: { &i860_cpu_device::insn_bct, DEC_DECODED}, /* bc.t lbroff. */
3706: { &i860_cpu_device::insn_bnc, DEC_DECODED}, /* bnc lbroff. */
3707: { &i860_cpu_device::insn_bnct, DEC_DECODED}, /* bnc.t lbroff. */
3708: { &i860_cpu_device::insn_addu, DEC_DECODED}, /* addu isrc1,isrc2,idest. */
3709: { &i860_cpu_device::insn_addu_imm, DEC_DECODED}, /* addu #const,isrc2,idest. */
3710: { &i860_cpu_device::insn_subu, DEC_DECODED}, /* subu isrc1,isrc2,idest. */
3711: { &i860_cpu_device::insn_subu_imm, DEC_DECODED}, /* subu #const,isrc2,idest. */
3712: { &i860_cpu_device::insn_adds, DEC_DECODED}, /* adds isrc1,isrc2,idest. */
3713: { &i860_cpu_device::insn_adds_imm, DEC_DECODED}, /* adds #const,isrc2,idest. */
3714: { &i860_cpu_device::insn_subs, DEC_DECODED}, /* subs isrc1,isrc2,idest. */
3715: { &i860_cpu_device::insn_subs_imm, DEC_DECODED}, /* subs #const,isrc2,idest. */
3716: { &i860_cpu_device::insn_shl, DEC_DECODED}, /* shl isrc1,isrc2,idest. */
3717: { &i860_cpu_device::insn_shl_imm, DEC_DECODED}, /* shl #const,isrc2,idest. */
3718: { &i860_cpu_device::insn_shr, DEC_DECODED}, /* shr isrc1,isrc2,idest. */
3719: { &i860_cpu_device::insn_shr_imm, DEC_DECODED}, /* shr #const,isrc2,idest. */
3720: { &i860_cpu_device::insn_shrd, DEC_DECODED}, /* shrd isrc1ni,isrc2,idest. */
3721: { &i860_cpu_device::insn_bla, DEC_DECODED}, /* bla isrc1ni,isrc2,sbroff. */
3722: { &i860_cpu_device::insn_shra, DEC_DECODED}, /* shra isrc1,isrc2,idest. */
3723: { &i860_cpu_device::insn_shra_imm, DEC_DECODED}, /* shra #const,isrc2,idest. */
3724: { &i860_cpu_device::insn_and, DEC_DECODED}, /* and isrc1,isrc2,idest. */
3725: { &i860_cpu_device::insn_and_imm, DEC_DECODED}, /* and #const,isrc2,idest. */
3726: { 0, 0},
3727: { &i860_cpu_device::insn_andh_imm, DEC_DECODED}, /* andh #const,isrc2,idest. */
3728: { &i860_cpu_device::insn_andnot, DEC_DECODED}, /* andnot isrc1,isrc2,idest. */
3729: { &i860_cpu_device::insn_andnot_imm, DEC_DECODED}, /* andnot #const,isrc2,idest. */
3730: { 0, 0},
3731: { &i860_cpu_device::insn_andnoth_imm, DEC_DECODED}, /* andnoth #const,isrc2,idest. */
3732: { &i860_cpu_device::insn_or, DEC_DECODED}, /* or isrc1,isrc2,idest. */
3733: { &i860_cpu_device::insn_or_imm, DEC_DECODED}, /* or #const,isrc2,idest. */
3734: { 0, 0},
3735: { &i860_cpu_device::insn_orh_imm, DEC_DECODED}, /* orh #const,isrc2,idest. */
3736: { &i860_cpu_device::insn_xor, DEC_DECODED}, /* xor isrc1,isrc2,idest. */
3737: { &i860_cpu_device::insn_xor_imm, DEC_DECODED}, /* xor #const,isrc2,idest. */
3738: { 0, 0},
3739: { &i860_cpu_device::insn_xorh_imm, DEC_DECODED}, /* xorh #const,isrc2,idest. */
3740: };
3741:
3742:
3743: /* Second-level decode table (i.e., for the 3 core escape opcode bits). */
3744: const i860_cpu_device::decode_tbl_t i860_cpu_device::core_esc_decode_tbl[8] = {
3745: { 0, 0},
3746: { 0, 0}, /* lock (FIXME: unimplemented). */
3747: { &i860_cpu_device::insn_calli, DEC_DECODED}, /* calli isrc1ni. */
3748: { 0, 0},
3749: { &i860_cpu_device::insn_intovr, DEC_DECODED}, /* intovr. */
3750: { 0, 0},
3751: { 0, 0},
3752: { 0, 0}, /* unlock (FIXME: unimplemented). */
3753: };
3754:
3755:
3756: /* Second-level decode table (i.e., for the 7 FP extended opcode bits). */
3757: const i860_cpu_device::decode_tbl_t i860_cpu_device::fp_decode_tbl[128] = {
3758: /* Floating point instructions. The least significant 7 bits are
3759: the (extended) opcode and bits 10:7 are P,D,S,R respectively
3760: ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.).
3761: For some operations, I defer decoding the P,S,R bits to the
3762: emulation routine for them. */
3763: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x00 pf[m]am */
3764: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x01 pf[m]am */
3765: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x02 pf[m]am */
3766: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x03 pf[m]am */
3767: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x04 pf[m]am */
3768: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x05 pf[m]am */
3769: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x06 pf[m]am */
3770: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x07 pf[m]am */
3771: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x08 pf[m]am */
3772: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x09 pf[m]am */
3773: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0A pf[m]am */
3774: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0B pf[m]am */
3775: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0C pf[m]am */
3776: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0D pf[m]am */
3777: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0E pf[m]am */
3778: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0F pf[m]am */
3779: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x10 pf[m]sm */
3780: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x11 pf[m]sm */
3781: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x12 pf[m]sm */
3782: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x13 pf[m]sm */
3783: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x14 pf[m]sm */
3784: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x15 pf[m]sm */
3785: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x16 pf[m]sm */
3786: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x17 pf[m]sm */
3787: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x18 pf[m]sm */
3788: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x19 pf[m]sm */
3789: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1A pf[m]sm */
3790: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1B pf[m]sm */
3791: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1C pf[m]sm */
3792: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1D pf[m]sm */
3793: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1E pf[m]sm */
3794: { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1F pf[m]sm */
3795: { &i860_cpu_device::insn_fmul, DEC_DECODED}, /* 0x20 [p]fmul */
3796: { &i860_cpu_device::insn_fmlow, DEC_DECODED}, /* 0x21 fmlow.dd */
3797: { &i860_cpu_device::insn_frcp, DEC_DECODED}, /* 0x22 frcp.{ss,sd,dd} */
3798: { &i860_cpu_device::insn_frsqr, DEC_DECODED}, /* 0x23 frsqr.{ss,sd,dd} */
3799: { &i860_cpu_device::insn_fmul, DEC_DECODED}, /* 0x24 pfmul3.dd */
3800: { 0, 0}, /* 0x25 */
3801: { 0, 0}, /* 0x26 */
3802: { 0, 0}, /* 0x27 */
3803: { 0, 0}, /* 0x28 */
3804: { 0, 0}, /* 0x29 */
3805: { 0, 0}, /* 0x2A */
3806: { 0, 0}, /* 0x2B */
3807: { 0, 0}, /* 0x2C */
3808: { 0, 0}, /* 0x2D */
3809: { 0, 0}, /* 0x2E */
3810: { 0, 0}, /* 0x2F */
3811: { &i860_cpu_device::insn_fadd_sub, DEC_DECODED}, /* 0x30, [p]fadd.{ss,sd,dd} */
3812: { &i860_cpu_device::insn_fadd_sub, DEC_DECODED}, /* 0x31, [p]fsub.{ss,sd,dd} */
3813: { &i860_cpu_device::insn_fix, DEC_DECODED}, /* 0x32, [p]fix.{ss,sd,dd} */
3814: { &i860_cpu_device::insn_famov, DEC_DECODED}, /* 0x33, [p]famov.{ss,sd,ds,dd} */
3815: { &i860_cpu_device::insn_fcmp, DEC_DECODED}, /* 0x34, pf{gt,le}.{ss,dd} */
3816: { &i860_cpu_device::insn_fcmp, DEC_DECODED}, /* 0x35, pfeq.{ss,dd} */
3817: { 0, 0}, /* 0x36 */
3818: { 0, 0}, /* 0x37 */
3819: { 0, 0}, /* 0x38 */
3820: { 0, 0}, /* 0x39 */
3821: { &i860_cpu_device::insn_ftrunc, DEC_DECODED}, /* 0x3A, [p]ftrunc.{ss,sd,dd} */
3822: { 0, 0}, /* 0x3B */
3823: { 0, 0}, /* 0x3C */
3824: { 0, 0}, /* 0x3D */
3825: { 0, 0}, /* 0x3E */
3826: { 0, 0}, /* 0x3F */
3827: { &i860_cpu_device::insn_fxfr, DEC_DECODED}, /* 0x40, fxfr */
3828: { 0, 0}, /* 0x41 */
3829: { 0, 0}, /* 0x42 */
3830: { 0, 0}, /* 0x43 */
3831: { 0, 0}, /* 0x44 */
3832: { 0, 0}, /* 0x45 */
3833: { 0, 0}, /* 0x46 */
3834: { 0, 0}, /* 0x47 */
3835: { 0, 0}, /* 0x48 */
3836: { &i860_cpu_device::insn_fiadd_sub, DEC_DECODED}, /* 0x49, [p]fiadd.{ss,dd} */
3837: { 0, 0}, /* 0x4A */
3838: { 0, 0}, /* 0x4B */
3839: { 0, 0}, /* 0x4C */
3840: { &i860_cpu_device::insn_fiadd_sub, DEC_DECODED}, /* 0x4D, [p]fisub.{ss,dd} */
3841: { 0, 0}, /* 0x4E */
3842: { 0, 0}, /* 0x4F */
3843: { &i860_cpu_device::insn_faddp, DEC_DECODED}, /* 0x50, [p]faddp */
3844: { &i860_cpu_device::insn_faddz, DEC_DECODED}, /* 0x51, [p]faddz */
3845: { 0, 0}, /* 0x52 */
3846: { 0, 0}, /* 0x53 */
3847: { 0, 0}, /* 0x54 */
3848: { 0, 0}, /* 0x55 */
3849: { 0, 0}, /* 0x56 */
3850: { &i860_cpu_device::insn_fzchk, DEC_DECODED}, /* 0x57, [p]fzchkl */
3851: { 0, 0}, /* 0x58 */
3852: { 0, 0}, /* 0x59 */
3853: { &i860_cpu_device::insn_form, DEC_DECODED}, /* 0x5A, [p]form.dd */
3854: { 0, 0}, /* 0x5B */
3855: { 0, 0}, /* 0x5C */
3856: { 0, 0}, /* 0x5D */
3857: { 0, 0}, /* 0x5E */
3858: { &i860_cpu_device::insn_fzchk, DEC_DECODED}, /* 0x5F, [p]fzchks */
3859: { 0, 0}, /* 0x60 */
3860: { 0, 0}, /* 0x61 */
3861: { 0, 0}, /* 0x62 */
3862: { 0, 0}, /* 0x63 */
3863: { 0, 0}, /* 0x64 */
3864: { 0, 0}, /* 0x65 */
3865: { 0, 0}, /* 0x66 */
3866: { 0, 0}, /* 0x67 */
3867: { 0, 0}, /* 0x68 */
3868: { 0, 0}, /* 0x69 */
3869: { 0, 0}, /* 0x6A */
3870: { 0, 0}, /* 0x6B */
3871: { 0, 0}, /* 0x6C */
3872: { 0, 0}, /* 0x6D */
3873: { 0, 0}, /* 0x6E */
3874: { 0, 0}, /* 0x6F */
3875: { 0, 0}, /* 0x70 */
3876: { 0, 0}, /* 0x71 */
3877: { 0, 0}, /* 0x72 */
3878: { 0, 0}, /* 0x73 */
3879: { 0, 0}, /* 0x74 */
3880: { 0, 0}, /* 0x75 */
3881: { 0, 0}, /* 0x76 */
3882: { 0, 0}, /* 0x77 */
3883: { 0, 0}, /* 0x78 */
3884: { 0, 0}, /* 0x79 */
3885: { 0, 0}, /* 0x7A */
3886: { 0, 0}, /* 0x7B */
3887: { 0, 0}, /* 0x7C */
3888: { 0, 0}, /* 0x7D */
3889: { 0, 0}, /* 0x7E */
3890: { 0, 0}, /* 0x7F */
3891: };
3892:
3893: /*
3894: * Main decoder driver.
3895: * insn = instruction at the current PC to execute.
3896: * non_shadow = This insn is not in the shadow of a delayed branch - (SC) unused, removed).
3897: */
3898: void i860_cpu_device::decode_exec (UINT32 insn) {
3899: if(m_flow & EXITING_IFETCH) return;
3900:
3901: #if ENABLE_PERF_COUNTERS
3902: m_insn_decoded++;
3903: #endif
3904:
3905: #if ENABLE_DEBUGGER
3906: m_traceback[m_traceback_idx++] = m_pc;
3907: if(m_traceback_idx >= (sizeof(m_traceback) / sizeof(m_traceback[0])))
3908: m_traceback_idx = 0;
3909: #endif
3910:
3911: int unrecognized = 1;
3912: const int upper_6bits = (insn >> 26) & 0x3f;
3913: const char flags = decode_tbl[upper_6bits].flags;
3914: if (flags & DEC_DECODED) {
3915: (this->*decode_tbl[upper_6bits].insn_exec)(insn);
3916: unrecognized = 0;
3917: } else if (flags & DEC_MORE) {
3918: if (upper_6bits == 0x12) {
3919: /* FP instruction format handled here. */
3920: if (fp_decode_tbl[insn & 0x7f].flags & DEC_DECODED) {
3921: (this->*fp_decode_tbl[insn & 0x7f].insn_exec)(insn);
3922: unrecognized = 0;
3923: }
3924: } else if (upper_6bits == 0x13) {
3925: /* Core escape instruction format handled here. */
3926: if (core_esc_decode_tbl[insn & 0x3].flags & DEC_DECODED) {
3927: (this->*core_esc_decode_tbl[insn & 0x3].insn_exec)(insn);
3928: unrecognized = 0;
3929: }
3930: }
3931: }
3932:
3933: if (unrecognized)
3934: unrecog_opcode (m_pc, insn);
3935: }
3936:
3937:
3938: /* Set-up all the default power-on/reset values. */
3939: void i860_cpu_device::reset() {
3940: UINT32 UNDEF_VAL = 0x55aa5500;
3941:
3942: int i;
3943: /* On power-up/reset, i860 has values:
3944: PC = 0xffffff00.
3945: Integer registers: r0 = 0, others = undefined.
3946: FP registers: f0:f1 = 0, others undefined.
3947: psr: U = IM = BR = BW = 0; others = undefined.
3948: epsr: IL = WP = PBM = BE = 0; processor type, stepping, and
3949: DCS are proper and read-only; others = undefined.
3950: db: undefined.
3951: dirbase: DPS, BL, ATE = 0
3952: fir, fsr, KR, KI, MERGE: undefined. (what about T?)
3953:
3954: I$: flushed.
3955: D$: undefined (all modified bits = 0).
3956: TLB: flushed.
3957:
3958: Note that any undefined values are set to UNDEF_VAL patterns to
3959: try to detect defective i860 software. */
3960:
3961: /* PC is at trap address after reset. */
3962: m_pc = 0xffffff00;
3963:
3964: /* Set grs and frs to undefined/nonsense values, except r0. */
3965: for (i = 0; i < 32; i++){
3966: set_iregval (i, UNDEF_VAL | i);
3967: set_fregval_s (i, 0.0);
3968: }
3969: set_iregval (0, 0);
3970: set_fregval_s (0, 0.0);
3971: set_fregval_s (1, 0.0);
3972:
3973: /* Set whole psr to 0. This sets the proper bits to 0 as specified
3974: above, and zeroes the undefined bits. */
3975: m_cregs[CR_PSR] = 0;
3976:
3977: /* Set most of the epsr bits to 0 (as specified above), leaving
3978: undefined as zero as well. Then properly set processor type,
3979: step, and DCS. Type = EPSR[7..0], step = EPSR[12..8],
3980: DCS = EPSR[21..18] (2^[12+dcs] = cache size).
3981: We'll pretend to be stepping D0, since it has the fewest bugs
3982: (and I don't want to emulate the many defects in the earlier
3983: steppings).
3984: Proc type: 1 = XR, 2 = XP (XR has 8KB data cache -> DCS = 1).
3985: Steppings (XR): 3,4,5,6,7 = (B2, C0, B3, C1, D0 respectively).
3986: Steppings (XP): 0, 2, 3, 4 = (A0, B0, B1, B2) (any others?). */
3987: m_cregs[CR_EPSR] = 0x00040701;
3988:
3989: /* Set DPS, BL, ATE = 0 and the undefined parts also to 0. But CS8 mode to 1 */
3990: m_cregs[CR_DIRBASE] = 0x00000080;
3991:
3992: /* Set fir, fsr, KR, KI, MERGE, T to undefined. */
3993: m_cregs[CR_FIR] = UNDEF_VAL;
3994: m_cregs[CR_FSR] = UNDEF_VAL;
3995: m_KR.d = 0.0;
3996: m_KI.d = 0.0;
3997: m_T.d = 0.0;
3998: m_merge = 0;
3999: m_flow = 0;
4000:
4001: /* dual instruction mode is off after reset */
4002: m_dim = DIM_NONE;
4003: m_dim_cc_valid = false;
4004:
4005: /* invalidate caches */
4006: invalidate_icache();
4007: invalidate_tlb();
4008:
4009: /* memory access is little endian */
4010: set_mem_access(false);
4011:
4012: halt(false);
4013: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.