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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [mips/] [dv-tx3904cpu.c] - Blame information for rev 578

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

powered by: WebSVN 2.1.0

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