1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4 Copyright (C) 1996, 1997, Free Software Foundation
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 do_stack_swap (SIM_DESC sd)
46 sim_cpu *cpu = STATE_CPU (sd, 0);
47 unsigned new_sp = (PSW_VAL(PSW_SM) != 0);
48 if (cpu->regs.current_sp != new_sp)
50 cpu->regs.sp[cpu->regs.current_sp] = SP;
51 cpu->regs.current_sp = new_sp;
52 SP = cpu->regs.sp[cpu->regs.current_sp];
57 /* Implement ALU tracing of 32-bit registers. */
59 trace_alu32 (SIM_DESC sd,
64 unsigned32 value = *ptr;
66 if (ptr >= &GPR[0] && ptr <= &GPR[NR_GENERAL_PURPOSE_REGISTERS])
67 trace_one_insn (sd, cpu, cia, 1, "engine.c", __LINE__, "alu",
68 "Set register r%-2d = 0x%.8lx (%ld)",
69 ptr - &GPR[0], (long)value, (long)value);
71 else if (ptr == &PSW || ptr == &bPSW || ptr == &DPSW)
72 trace_one_insn (sd, cpu, cia, 1, "engine.c", __LINE__, "alu",
73 "Set register %s = 0x%.8lx%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
74 (ptr == &PSW) ? "psw" : ((ptr == &bPSW) ? "bpsw" : "dpsw"),
76 (value & (0x80000000 >> PSW_SM)) ? ", sm" : "",
77 (value & (0x80000000 >> PSW_EA)) ? ", ea" : "",
78 (value & (0x80000000 >> PSW_DB)) ? ", db" : "",
79 (value & (0x80000000 >> PSW_DS)) ? ", ds" : "",
80 (value & (0x80000000 >> PSW_IE)) ? ", ie" : "",
81 (value & (0x80000000 >> PSW_RP)) ? ", rp" : "",
82 (value & (0x80000000 >> PSW_MD)) ? ", md" : "",
83 (value & (0x80000000 >> PSW_F0)) ? ", f0" : "",
84 (value & (0x80000000 >> PSW_F1)) ? ", f1" : "",
85 (value & (0x80000000 >> PSW_F2)) ? ", f2" : "",
86 (value & (0x80000000 >> PSW_F3)) ? ", f3" : "",
87 (value & (0x80000000 >> PSW_S)) ? ", s" : "",
88 (value & (0x80000000 >> PSW_V)) ? ", v" : "",
89 (value & (0x80000000 >> PSW_VA)) ? ", va" : "",
90 (value & (0x80000000 >> PSW_C)) ? ", c" : "");
92 else if (ptr >= &CREG[0] && ptr <= &CREG[NR_CONTROL_REGISTERS])
93 trace_one_insn (sd, cpu, cia, 1, "engine.c", __LINE__, "alu",
94 "Set register cr%d = 0x%.8lx (%ld)",
95 ptr - &CREG[0], (long)value, (long)value);
98 /* Implement ALU tracing of 32-bit registers. */
100 trace_alu64 (SIM_DESC sd,
105 unsigned64 value = *ptr;
107 if (ptr >= &ACC[0] && ptr <= &ACC[NR_ACCUMULATORS])
108 trace_one_insn (sd, cpu, cia, 1, "engine.c", __LINE__, "alu",
109 "Set register a%-2d = 0x%.8lx 0x%.8lx",
111 (unsigned long)(unsigned32)(value >> 32),
112 (unsigned long)(unsigned32)value);
117 /* Process all of the queued up writes in order now */
119 unqueue_writes (SIM_DESC sd,
125 unsigned32 *psw_addr = &PSW;
128 for (i = 0; i < num; i++)
130 unsigned32 mask = WRITE32_MASK (i);
131 unsigned32 *ptr = WRITE32_PTR (i);
132 unsigned32 value = (*ptr & ~mask) | (WRITE32_VALUE (i) & mask);
137 /* If MU instruction was not a MVTSYS, resolve PSW
138 contention in favour of IU. */
139 if(! STATE_CPU (sd, 0)->mvtsys_left_p)
141 /* Detect contention in parallel writes to the same PSW flags.
142 The hardware allows the updates from IU to prevail over
145 unsigned32 flag_bits =
146 BIT32 (PSW_F0) | BIT32 (PSW_F1) |
147 BIT32 (PSW_F2) | BIT32 (PSW_F3) |
148 BIT32 (PSW_S) | BIT32 (PSW_V) |
149 BIT32 (PSW_VA) | BIT32 (PSW_C);
150 unsigned32 my_flag_bits = mask & flag_bits;
152 for (j = i + 1; j < num; j++)
153 if (WRITE32_PTR (j) == psw_addr && /* write to PSW */
154 WRITE32_MASK (j) & my_flag_bits) /* some of the same flags */
156 /* Recompute local mask & value, to suppress this
157 earlier write to the same flag bits. */
159 unsigned32 new_mask = mask & ~(WRITE32_MASK (j) & my_flag_bits);
161 /* There is a special case for the VA (accumulated
162 overflow) flag, in that it is only included in the
163 second instruction's mask if the overflow
164 occurred. Yet the hardware still suppresses the
165 first instruction's update to VA. So we kludge
166 this by inferring PSW_V -> PSW_VA for the second
169 if (WRITE32_MASK (j) & BIT32 (PSW_V))
171 new_mask &= ~BIT32 (PSW_VA);
174 value = (*ptr & ~new_mask) | (WRITE32_VALUE (i) & new_mask);
184 if (TRACE_ALU_P (cpu))
185 trace_alu32 (sd, cpu, cia, ptr);
190 for (i = 0; i < num; i++)
192 unsigned64 *ptr = WRITE64_PTR (i);
193 *ptr = WRITE64_VALUE (i);
196 if (TRACE_ALU_P (cpu))
197 trace_alu64 (sd, cpu, cia, ptr);
204 if (DID_TRAP == 1) /* ordinary trap */
207 PSW &= (BIT32 (PSW_DB) | BIT32 (PSW_SM));
210 else if (DID_TRAP == 2) /* debug trap */
213 PSW &= BIT32 (PSW_DS);
214 PSW |= BIT32 (PSW_DS);
224 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
228 do_long (SIM_DESC sd,
229 l_instruction_word instruction,
232 address_word nia = l_idecode_issue(sd,
236 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
241 do_2_short (SIM_DESC sd,
242 s_instruction_word insn1,
243 s_instruction_word insn2,
249 /* run the first instruction */
250 STATE_CPU (sd, 0)->unit = unit;
251 STATE_CPU (sd, 0)->left_kills_right_p = 0;
252 STATE_CPU (sd, 0)->mvtsys_left_p = 0;
253 nia = s_idecode_issue(sd,
257 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
259 /* Only do the second instruction if the PC has not changed */
260 if ((nia == INVALID_INSTRUCTION_ADDRESS) &&
261 (! STATE_CPU (sd, 0)->left_kills_right_p)) {
262 STATE_CPU (sd, 0)->unit = any_unit;
263 nia = s_idecode_issue (sd,
267 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
270 STATE_CPU (sd, 0)->left_kills_right_p = 0;
271 STATE_CPU (sd, 0)->mvtsys_left_p = 0;
276 do_parallel (SIM_DESC sd,
277 s_instruction_word left_insn,
278 s_instruction_word right_insn,
281 address_word nia_left;
282 address_word nia_right;
285 /* run the first instruction */
286 STATE_CPU (sd, 0)->unit = memory_unit;
287 STATE_CPU (sd, 0)->left_kills_right_p = 0;
288 STATE_CPU (sd, 0)->mvtsys_left_p = 0;
289 nia_left = s_idecode_issue(sd,
293 /* run the second instruction */
294 STATE_CPU (sd, 0)->unit = integer_unit;
295 nia_right = s_idecode_issue(sd,
300 if (nia_left == INVALID_INSTRUCTION_ADDRESS) {
301 if (nia_right == INVALID_INSTRUCTION_ADDRESS)
302 nia = INVALID_INSTRUCTION_ADDRESS;
307 if (nia_right == INVALID_INSTRUCTION_ADDRESS)
310 sim_engine_abort (sd, STATE_CPU (sd, 0), cia, "parallel jumps");
311 nia = INVALID_INSTRUCTION_ADDRESS;
315 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
327 STATIC_INLINE instruction_types
328 instruction_type(l_instruction_word insn)
330 int fm0 = MASKED64(insn, 0, 0) != 0;
331 int fm1 = MASKED64(insn, 32, 32) != 0;
332 return ((fm0 << 1) | fm1);
338 sim_engine_run (SIM_DESC sd,
345 address_word cia = PC;
347 l_instruction_word insn = IMEM(cia);
349 int rpt_c_was_nonzero;
351 /* Before executing the instruction, we need to test whether or
352 not RPT_C is greater than zero, and save that state for use
353 after executing the instruction. In particular, we need to
354 not care whether the instruction changes RPT_C itself. */
356 rpt_c_was_nonzero = (RPT_C > 0);
358 /* Before executing the instruction, we need to check to see if
359 we have to decrement RPT_C, the repeat count register. Do this
360 if PC == RPT_E, but only if we are in an active repeat block. */
363 (RPT_C > 0 || PSW_VAL (PSW_RP) != 0))
368 /* Now execute the instruction at PC */
370 switch (instruction_type (insn))
373 nia = do_long (sd, insn, cia);
377 nia = do_2_short (sd, insn, insn >> 32, integer_unit, cia);
381 nia = do_2_short (sd, insn >> 32, insn, memory_unit, cia);
384 nia = do_parallel (sd, insn >> 32, insn, cia);
387 sim_engine_abort (sd, STATE_CPU (sd, 0), cia,
388 "internal error - engine_run_until_stop - bad switch");
394 if (TRACE_ACTION & TRACE_ACTION_CALL)
395 call_occurred (sd, STATE_CPU (sd, 0), cia, nia);
397 if (TRACE_ACTION & TRACE_ACTION_RETURN)
398 return_occurred (sd, STATE_CPU (sd, 0), cia, nia);
403 /* Check now to see if we need to reset the RP bit in the PSW.
404 There are three conditions for this, the RP bit is already
405 set (just a speed optimization), the instruction we just
406 executed is the last instruction in the loop, and the repeat
407 count is currently zero. */
409 rp_was_set = PSW_VAL (PSW_RP);
410 if (rp_was_set && (PC == RPT_E) && RPT_C == 0)
415 /* Now update the PC. If we just executed a jump instruction,
416 that takes precedence over everything else. Next comes
417 branching back to RPT_S as a result of a loop. Finally, the
418 default is to simply advance to the next inline
421 if (nia != INVALID_INSTRUCTION_ADDRESS)
425 else if (rp_was_set && rpt_c_was_nonzero && (PC == RPT_E))
434 /* Check for DDBT (debugger debug trap) condition. Do this after
435 the repeat block checks so the excursion to the trap handler does
436 not alter looping state. */
438 if (cia == IBA && PSW_VAL (PSW_DB))
443 /* clear all bits in PSW except SM */
444 PSW &= BIT32 (PSW_SM);
446 PSW |= BIT32 (PSW_DS);
447 /* dispatch to DDBT handler */
448 PC = 0xfffff128; /* debugger_debug_trap_address */
451 /* process any events */
452 /* FIXME - should L->R or L<-R insns count as two cycles? */
453 if (sim_events_tick (sd))
455 sim_events_process (sd);
461 /* d30v external interrupt handler.
463 Note: This should be replaced by a proper interrupt delivery
464 mechanism. This interrupt mechanism discards later interrupts if
465 an earlier interrupt hasn't been delivered.
467 Note: This interrupt mechanism does not reset its self when the
468 simulator is re-opened. */
471 d30v_interrupt_event (SIM_DESC sd,
474 if (PSW_VAL (PSW_IE))
475 /* interrupts not masked */
477 /* scrub any pending interrupt */
478 if (sd->pending_interrupt != NULL)
479 sim_events_deschedule (sd, sd->pending_interrupt);
484 PC = 0xfffff138; /* external interrupt */
487 else if (sd->pending_interrupt == NULL)
488 /* interrupts masked and no interrupt pending */
490 sd->pending_interrupt = sim_events_schedule (sd, 1,
491 d30v_interrupt_event,