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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [sim/] [mips/] [dv-tx3904cpu.c] - Blame information for rev 866

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

Line No. Rev Author Line
1 330 jeremybenn
/*  This file is part of the program GDB, the GNU debugger.
2
 
3
    Copyright (C) 1998, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4
    Contributed by Cygnus Solutions.
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 3 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, see <http://www.gnu.org/licenses/>.
18
 
19
    */
20
 
21
 
22
#include "sim-main.h"
23
#include "hw-main.h"
24
 
25
/* DEVICE
26
 
27
 
28
   tx3904cpu - tx3904 cpu virtual device
29
 
30
 
31
   DESCRIPTION
32
 
33
 
34
   Implements the external tx3904 functionality.  This includes the
35
   delivery of of interrupts generated from other devices and the
36
   handling of device specific registers.
37
 
38
 
39
   PROPERTIES
40
 
41
   none
42
 
43
 
44
   PORTS
45
 
46
 
47
   reset (input)
48
 
49
   Currently ignored.
50
 
51
 
52
   nmi (input)
53
 
54
   Deliver a non-maskable interrupt to the processor.
55
 
56
 
57
   level (input)
58
 
59
   Deliver a maskable interrupt of given level, corresponding to
60
   IP[5:0], to processor.
61
 
62
 
63
 
64
   BUGS
65
 
66
 
67
   When delivering an interrupt, this code assumes that there is only
68
   one processor (number 0).
69
 
70
   This code does not attempt to be efficient at handling pending
71
   interrupts.  It simply schedules the interrupt delivery handler
72
   every instruction cycle until all pending interrupts go away.  An
73
   alternative implementation might modify instructions that change
74
   the PSW and have them check to see if the change makes an interrupt
75
   delivery possible.
76
 
77
   */
78
 
79
 
80
 
81
struct tx3904cpu {
82
  /* Pending interrupts for delivery by event handler */
83
  int pending_reset, pending_nmi, pending_level;
84
  struct hw_event* event;
85
};
86
 
87
 
88
 
89
/* input port ID's */
90
 
91
enum {
92
  RESET_PORT,
93
  NMI_PORT,
94
  LEVEL_PORT,
95
};
96
 
97
 
98
static const struct hw_port_descriptor tx3904cpu_ports[] = {
99
 
100
  /* interrupt inputs */
101
  { "reset", RESET_PORT, 0, input_port, },
102
  { "nmi", NMI_PORT, 0, input_port, },
103
  { "level", LEVEL_PORT, 0, input_port, },
104
 
105
  { NULL, },
106
};
107
 
108
 
109
/* Finish off the partially created hw device.  Attach our local
110
   callbacks.  Wire up our port names etc */
111
 
112
static hw_port_event_method tx3904cpu_port_event;
113
 
114
 
115
 
116
static void
117
tx3904cpu_finish (struct hw *me)
118
{
119
  struct tx3904cpu *controller;
120
 
121
  controller = HW_ZALLOC (me, struct tx3904cpu);
122
  set_hw_data (me, controller);
123
  set_hw_ports (me, tx3904cpu_ports);
124
  set_hw_port_event (me, tx3904cpu_port_event);
125
 
126
  /* Initialize the pending interrupt flags */
127
  controller->pending_level = 0;
128
  controller->pending_reset = 0;
129
  controller->pending_nmi = 0;
130
  controller->event = NULL;
131
}
132
 
133
 
134
 
135
/* An event arrives on an interrupt port */
136
 
137
static void
138
deliver_tx3904cpu_interrupt (struct hw *me,
139
                            void *data)
140
{
141
  struct tx3904cpu *controller = hw_data (me);
142
  SIM_DESC sd = hw_system (me);
143
  sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
144
  address_word cia = CIA_GET (cpu);
145
 
146
#define CPU cpu
147
#define SD current_state
148
 
149
  if (controller->pending_reset)
150
    {
151
      controller->pending_reset = 0;
152
      HW_TRACE ((me, "reset pc=0x%08lx", (long) CIA_GET (cpu)));
153
      SignalExceptionNMIReset();
154
    }
155
  else if (controller->pending_nmi)
156
    {
157
      controller->pending_nmi = 0;
158
      HW_TRACE ((me, "nmi pc=0x%08lx", (long) CIA_GET (cpu)));
159
      SignalExceptionNMIReset();
160
    }
161
  else if (controller->pending_level)
162
    {
163
      HW_TRACE ((me, "interrupt level=%d pc=0x%08lx sr=0x%08lx",
164
                 controller->pending_level,
165
                 (long) CIA_GET (cpu), (long) SR));
166
 
167
      /* Clear CAUSE register.  It may stay this way if the interrupt
168
         was cleared with a negative pending_level. */
169
      CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
170
 
171
      if(controller->pending_level > 0) /* interrupt set */
172
        {
173
          /* set hardware-interrupt subfields of CAUSE register */
174
          CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift;
175
 
176
          /* check for enabled / unmasked interrupts */
177
          if((SR & status_IEc) &&
178
             (controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
179
            {
180
              controller->pending_level = 0;
181
              SignalExceptionInterrupt(0 /* dummy value */);
182
            }
183
          else
184
            {
185
              /* reschedule soon */
186
              if(controller->event != NULL)
187
                hw_event_queue_deschedule(me, controller->event);
188
              controller->event =
189
                hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
190
            }
191
        } /* interrupt set */
192
    }
193
#undef CPU cpu
194
#undef SD current_state
195
}
196
 
197
 
198
static void
199
tx3904cpu_port_event (struct hw *me,
200
                     int my_port,
201
                     struct hw *source,
202
                     int source_port,
203
                     int level)
204
{
205
  struct tx3904cpu *controller = hw_data (me);
206
 
207
  switch (my_port)
208
    {
209
    case RESET_PORT:
210
      controller->pending_reset = 1;
211
      HW_TRACE ((me, "port-in reset"));
212
      break;
213
 
214
    case NMI_PORT:
215
      controller->pending_nmi = 1;
216
      HW_TRACE ((me, "port-in nmi"));
217
      break;
218
 
219
    case LEVEL_PORT:
220
      /* level == 0 means that the interrupt was cleared */
221
      if(level == 0)
222
        controller->pending_level = -1; /* signal end of interrupt */
223
      else
224
        controller->pending_level = level;
225
      HW_TRACE ((me, "port-in level=%d", level));
226
      break;
227
 
228
    default:
229
      hw_abort (me, "bad switch");
230
      break;
231
    }
232
 
233
  /* Schedule an event to be delivered immediately after current
234
     instruction. */
235
  if(controller->event != NULL)
236
    hw_event_queue_deschedule(me, controller->event);
237
  controller->event =
238
    hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
239
}
240
 
241
 
242
const struct hw_descriptor dv_tx3904cpu_descriptor[] = {
243
  { "tx3904cpu", tx3904cpu_finish, },
244
  { NULL },
245
};

powered by: WebSVN 2.1.0

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