]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/d30v/engine.c
import gdb-19990422 snapshot
[thirdparty/binutils-gdb.git] / sim / d30v / engine.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4 Copyright (C) 1996, 1997, Free Software Foundation
5
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.
10
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.
15
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.
19
20 */
21
22
23 #ifndef ENGINE_C
24 #define ENGINE_C
25
26 #include "sim-main.h"
27
28 #include <stdio.h>
29 #include <ctype.h>
30
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #else
38 #ifdef HAVE_STRINGS_H
39 #include <strings.h>
40 #endif
41 #endif
42
43 static void
44 do_stack_swap (SIM_DESC sd)
45 {
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)
49 {
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];
53 }
54 }
55
56 #if WITH_TRACE
57 /* Implement ALU tracing of 32-bit registers. */
58 static void
59 trace_alu32 (SIM_DESC sd,
60 sim_cpu *cpu,
61 address_word cia,
62 unsigned32 *ptr)
63 {
64 unsigned32 value = *ptr;
65
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);
70
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"),
75 (long)value,
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" : "");
91
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);
96 }
97
98 /* Implement ALU tracing of 32-bit registers. */
99 static void
100 trace_alu64 (SIM_DESC sd,
101 sim_cpu *cpu,
102 address_word cia,
103 unsigned64 *ptr)
104 {
105 unsigned64 value = *ptr;
106
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",
110 ptr - &ACC[0],
111 (unsigned long)(unsigned32)(value >> 32),
112 (unsigned long)(unsigned32)value);
113
114 }
115 #endif
116
117 /* Process all of the queued up writes in order now */
118 void
119 unqueue_writes (SIM_DESC sd,
120 sim_cpu *cpu,
121 address_word cia)
122 {
123 int i, num;
124 int did_psw = 0;
125 unsigned32 *psw_addr = &PSW;
126
127 num = WRITE32_NUM;
128 for (i = 0; i < num; i++)
129 {
130 unsigned32 mask = WRITE32_MASK (i);
131 unsigned32 *ptr = WRITE32_PTR (i);
132 unsigned32 value = (*ptr & ~mask) | (WRITE32_VALUE (i) & mask);
133 int j;
134
135 if (ptr == psw_addr)
136 {
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)
140 {
141 /* Detect contention in parallel writes to the same PSW flags.
142 The hardware allows the updates from IU to prevail over
143 those from MU. */
144
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;
151
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 */
155 {
156 /* Recompute local mask & value, to suppress this
157 earlier write to the same flag bits. */
158
159 unsigned32 new_mask = mask & ~(WRITE32_MASK (j) & my_flag_bits);
160
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
167 instruction. */
168
169 if (WRITE32_MASK (j) & BIT32 (PSW_V))
170 {
171 new_mask &= ~BIT32 (PSW_VA);
172 }
173
174 value = (*ptr & ~new_mask) | (WRITE32_VALUE (i) & new_mask);
175 }
176 }
177
178 did_psw = 1;
179 }
180
181 *ptr = value;
182
183 #if WITH_TRACE
184 if (TRACE_ALU_P (cpu))
185 trace_alu32 (sd, cpu, cia, ptr);
186 #endif
187 }
188
189 num = WRITE64_NUM;
190 for (i = 0; i < num; i++)
191 {
192 unsigned64 *ptr = WRITE64_PTR (i);
193 *ptr = WRITE64_VALUE (i);
194
195 #if WITH_TRACE
196 if (TRACE_ALU_P (cpu))
197 trace_alu64 (sd, cpu, cia, ptr);
198 #endif
199 }
200
201 WRITE32_NUM = 0;
202 WRITE64_NUM = 0;
203
204 if (DID_TRAP == 1) /* ordinary trap */
205 {
206 bPSW = PSW;
207 PSW &= (BIT32 (PSW_DB) | BIT32 (PSW_SM));
208 did_psw = 1;
209 }
210 else if (DID_TRAP == 2) /* debug trap */
211 {
212 DPSW = PSW;
213 PSW &= BIT32 (PSW_DS);
214 PSW |= BIT32 (PSW_DS);
215 did_psw = 1;
216 }
217 DID_TRAP = 0;
218
219 if (did_psw)
220 do_stack_swap (sd);
221 }
222
223
224 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
225 thing */
226
227 static address_word
228 do_long (SIM_DESC sd,
229 l_instruction_word instruction,
230 address_word cia)
231 {
232 address_word nia = l_idecode_issue(sd,
233 instruction,
234 cia);
235
236 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
237 return nia;
238 }
239
240 static address_word
241 do_2_short (SIM_DESC sd,
242 s_instruction_word insn1,
243 s_instruction_word insn2,
244 cpu_units unit,
245 address_word cia)
246 {
247 address_word nia;
248
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,
254 insn1,
255 cia);
256
257 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
258
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,
264 insn2,
265 cia);
266
267 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
268 }
269
270 STATE_CPU (sd, 0)->left_kills_right_p = 0;
271 STATE_CPU (sd, 0)->mvtsys_left_p = 0;
272 return nia;
273 }
274
275 static address_word
276 do_parallel (SIM_DESC sd,
277 s_instruction_word left_insn,
278 s_instruction_word right_insn,
279 address_word cia)
280 {
281 address_word nia_left;
282 address_word nia_right;
283 address_word nia;
284
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,
290 left_insn,
291 cia);
292
293 /* run the second instruction */
294 STATE_CPU (sd, 0)->unit = integer_unit;
295 nia_right = s_idecode_issue(sd,
296 right_insn,
297 cia);
298
299 /* merge the PC's */
300 if (nia_left == INVALID_INSTRUCTION_ADDRESS) {
301 if (nia_right == INVALID_INSTRUCTION_ADDRESS)
302 nia = INVALID_INSTRUCTION_ADDRESS;
303 else
304 nia = nia_right;
305 }
306 else {
307 if (nia_right == INVALID_INSTRUCTION_ADDRESS)
308 nia = nia_left;
309 else {
310 sim_engine_abort (sd, STATE_CPU (sd, 0), cia, "parallel jumps");
311 nia = INVALID_INSTRUCTION_ADDRESS;
312 }
313 }
314
315 unqueue_writes (sd, STATE_CPU (sd, 0), cia);
316 return nia;
317 }
318
319
320 typedef enum {
321 p_insn = 0,
322 long_insn = 3,
323 l_r_insn = 1,
324 r_l_insn = 2,
325 } instruction_types;
326
327 STATIC_INLINE instruction_types
328 instruction_type(l_instruction_word insn)
329 {
330 int fm0 = MASKED64(insn, 0, 0) != 0;
331 int fm1 = MASKED64(insn, 32, 32) != 0;
332 return ((fm0 << 1) | fm1);
333 }
334
335
336
337 void
338 sim_engine_run (SIM_DESC sd,
339 int last_cpu_nr,
340 int nr_cpus,
341 int siggnal)
342 {
343 while (1)
344 {
345 address_word cia = PC;
346 address_word nia;
347 l_instruction_word insn = IMEM(cia);
348 int rp_was_set;
349 int rpt_c_was_nonzero;
350
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. */
355
356 rpt_c_was_nonzero = (RPT_C > 0);
357
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. */
361
362 if (PC == RPT_E &&
363 (RPT_C > 0 || PSW_VAL (PSW_RP) != 0))
364 {
365 RPT_C --;
366 }
367
368 /* Now execute the instruction at PC */
369
370 switch (instruction_type (insn))
371 {
372 case long_insn:
373 nia = do_long (sd, insn, cia);
374 break;
375 case r_l_insn:
376 /* L <- R */
377 nia = do_2_short (sd, insn, insn >> 32, integer_unit, cia);
378 break;
379 case l_r_insn:
380 /* L -> R */
381 nia = do_2_short (sd, insn >> 32, insn, memory_unit, cia);
382 break;
383 case p_insn:
384 nia = do_parallel (sd, insn >> 32, insn, cia);
385 break;
386 default:
387 sim_engine_abort (sd, STATE_CPU (sd, 0), cia,
388 "internal error - engine_run_until_stop - bad switch");
389 nia = -1;
390 }
391
392 if (TRACE_ACTION)
393 {
394 if (TRACE_ACTION & TRACE_ACTION_CALL)
395 call_occurred (sd, STATE_CPU (sd, 0), cia, nia);
396
397 if (TRACE_ACTION & TRACE_ACTION_RETURN)
398 return_occurred (sd, STATE_CPU (sd, 0), cia, nia);
399
400 TRACE_ACTION = 0;
401 }
402
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. */
408
409 rp_was_set = PSW_VAL (PSW_RP);
410 if (rp_was_set && (PC == RPT_E) && RPT_C == 0)
411 {
412 PSW_SET (PSW_RP, 0);
413 }
414
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
419 instruction. */
420
421 if (nia != INVALID_INSTRUCTION_ADDRESS)
422 {
423 PC = nia;
424 }
425 else if (rp_was_set && rpt_c_was_nonzero && (PC == RPT_E))
426 {
427 PC = RPT_S;
428 }
429 else
430 {
431 PC = cia + 8;
432 }
433
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. */
437
438 if (cia == IBA && PSW_VAL (PSW_DB))
439 {
440 DPC = PC;
441 PSW_SET (PSW_EA, 1);
442 DPSW = PSW;
443 /* clear all bits in PSW except SM */
444 PSW &= BIT32 (PSW_SM);
445 /* add DS bit */
446 PSW |= BIT32 (PSW_DS);
447 /* dispatch to DDBT handler */
448 PC = 0xfffff128; /* debugger_debug_trap_address */
449 }
450
451 /* process any events */
452 /* FIXME - should L->R or L<-R insns count as two cycles? */
453 if (sim_events_tick (sd))
454 {
455 sim_events_process (sd);
456 }
457 }
458 }
459
460
461 /* d30v external interrupt handler.
462
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.
466
467 Note: This interrupt mechanism does not reset its self when the
468 simulator is re-opened. */
469
470 void
471 d30v_interrupt_event (SIM_DESC sd,
472 void *data)
473 {
474 if (PSW_VAL (PSW_IE))
475 /* interrupts not masked */
476 {
477 /* scrub any pending interrupt */
478 if (sd->pending_interrupt != NULL)
479 sim_events_deschedule (sd, sd->pending_interrupt);
480 /* deliver */
481 bPSW = PSW;
482 bPC = PC;
483 PSW = 0;
484 PC = 0xfffff138; /* external interrupt */
485 do_stack_swap (sd);
486 }
487 else if (sd->pending_interrupt == NULL)
488 /* interrupts masked and no interrupt pending */
489 {
490 sd->pending_interrupt = sim_events_schedule (sd, 1,
491 d30v_interrupt_event,
492 data);
493 }
494 }
495
496 #endif