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 (lkr), resolve PSW
138 contention in favour of IU. */
139 if(! STATE_CPU (sd
, 0)->left_kills_right_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 nia
= s_idecode_issue(sd
,
256 unqueue_writes (sd
, STATE_CPU (sd
, 0), cia
);
258 /* Only do the second instruction if the PC has not changed */
259 if ((nia
== INVALID_INSTRUCTION_ADDRESS
) &&
260 (! STATE_CPU (sd
, 0)->left_kills_right_p
)) {
261 STATE_CPU (sd
, 0)->unit
= any_unit
;
262 nia
= s_idecode_issue (sd
,
266 unqueue_writes (sd
, STATE_CPU (sd
, 0), cia
);
269 STATE_CPU (sd
, 0)->left_kills_right_p
= 0;
274 do_parallel (SIM_DESC sd
,
275 s_instruction_word left_insn
,
276 s_instruction_word right_insn
,
279 address_word nia_left
;
280 address_word nia_right
;
283 /* run the first instruction */
284 STATE_CPU (sd
, 0)->unit
= memory_unit
;
285 STATE_CPU (sd
, 0)->left_kills_right_p
= 0;
286 nia_left
= s_idecode_issue(sd
,
290 /* run the second instruction */
291 STATE_CPU (sd
, 0)->unit
= integer_unit
;
292 nia_right
= s_idecode_issue(sd
,
297 if (nia_left
== INVALID_INSTRUCTION_ADDRESS
) {
298 if (nia_right
== INVALID_INSTRUCTION_ADDRESS
)
299 nia
= INVALID_INSTRUCTION_ADDRESS
;
304 if (nia_right
== INVALID_INSTRUCTION_ADDRESS
)
307 sim_engine_abort (sd
, STATE_CPU (sd
, 0), cia
, "parallel jumps");
308 nia
= INVALID_INSTRUCTION_ADDRESS
;
312 unqueue_writes (sd
, STATE_CPU (sd
, 0), cia
);
324 STATIC_INLINE instruction_types
325 instruction_type(l_instruction_word insn
)
327 int fm0
= MASKED64(insn
, 0, 0) != 0;
328 int fm1
= MASKED64(insn
, 32, 32) != 0;
329 return ((fm0
<< 1) | fm1
);
335 sim_engine_run (SIM_DESC sd
,
342 address_word cia
= PC
;
344 l_instruction_word insn
= IMEM(cia
);
346 int rpt_c_was_nonzero
;
348 /* Before executing the instruction, we need to test whether or
349 not RPT_C is greater than zero, and save that state for use
350 after executing the instruction. In particular, we need to
351 not care whether the instruction changes RPT_C itself. */
353 rpt_c_was_nonzero
= (RPT_C
> 0);
355 /* Before executing the instruction, we need to check to see if
356 we have to decrement RPT_C, the repeat count register. Do this
357 if PC == RPT_E, but only if we are in an active repeat block. */
360 (RPT_C
> 0 || PSW_VAL (PSW_RP
) != 0))
365 /* Now execute the instruction at PC */
367 switch (instruction_type (insn
))
370 nia
= do_long (sd
, insn
, cia
);
374 nia
= do_2_short (sd
, insn
, insn
>> 32, integer_unit
, cia
);
378 nia
= do_2_short (sd
, insn
>> 32, insn
, memory_unit
, cia
);
381 nia
= do_parallel (sd
, insn
>> 32, insn
, cia
);
384 sim_engine_abort (sd
, STATE_CPU (sd
, 0), cia
,
385 "internal error - engine_run_until_stop - bad switch");
391 if (TRACE_ACTION
& TRACE_ACTION_CALL
)
392 call_occurred (sd
, STATE_CPU (sd
, 0), cia
, nia
);
394 if (TRACE_ACTION
& TRACE_ACTION_RETURN
)
395 return_occurred (sd
, STATE_CPU (sd
, 0), cia
, nia
);
400 /* Check now to see if we need to reset the RP bit in the PSW.
401 There are three conditions for this, the RP bit is already
402 set (just a speed optimization), the instruction we just
403 executed is the last instruction in the loop, and the repeat
404 count is currently zero. */
406 rp_was_set
= PSW_VAL (PSW_RP
);
407 if (rp_was_set
&& (PC
== RPT_E
) && RPT_C
== 0)
412 /* Now update the PC. If we just executed a jump instruction,
413 that takes precedence over everything else. Next comes
414 branching back to RPT_S as a result of a loop. Finally, the
415 default is to simply advance to the next inline
418 if (nia
!= INVALID_INSTRUCTION_ADDRESS
)
422 else if (rp_was_set
&& rpt_c_was_nonzero
&& (PC
== RPT_E
))
431 /* Check for DDBT (debugger debug trap) condition. Do this after
432 the repeat block checks so the excursion to the trap handler does
433 not alter looping state. */
435 if (cia
== IBA
&& PSW_VAL (PSW_DB
))
440 /* clear all bits in PSW except SM */
441 PSW
&= BIT32 (PSW_SM
);
443 PSW
|= BIT32 (PSW_DS
);
444 /* dispatch to DDBT handler */
445 PC
= 0xfffff128; /* debugger_debug_trap_address */
448 /* process any events */
449 /* FIXME - should L->R or L<-R insns count as two cycles? */
450 if (sim_events_tick (sd
))
452 sim_events_process (sd
);
458 /* d30v external interrupt handler.
460 Note: This should be replaced by a proper interrupt delivery
461 mechanism. This interrupt mechanism discards later interrupts if
462 an earlier interrupt hasn't been delivered.
464 Note: This interrupt mechanism does not reset its self when the
465 simulator is re-opened. */
468 d30v_interrupt_event (SIM_DESC sd
,
471 if (PSW_VAL (PSW_IE
))
472 /* interrupts not masked */
474 /* scrub any pending interrupt */
475 if (sd
->pending_interrupt
!= NULL
)
476 sim_events_deschedule (sd
, sd
->pending_interrupt
);
481 PC
= 0xfffff138; /* external interrupt */
484 else if (sd
->pending_interrupt
== NULL
)
485 /* interrupts masked and no interrupt pending */
487 sd
->pending_interrupt
= sim_events_schedule (sd
, 1,
488 d30v_interrupt_event
,