OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [d30v/] [engine.c] - Blame information for rev 1775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*  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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.