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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [mn10300/] [dv-mn103cpu.c] - Blame information for rev 1765

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
   mn103cpu - mn10300 cpu virtual device
30
 
31
 
32
   DESCRIPTION
33
 
34
 
35
   Implements the external mn10300 functionality.  This includes the
36
   delivery of interrupts generated from other devices and the
37
   handling of device specific registers.
38
 
39
 
40
   PROPERTIES
41
 
42
 
43
   reg = <address> <size>
44
 
45
   Specify the address of the mn10300's control register block.  This
46
   block contains the Interrupt Vector Registers.
47
 
48
   The reg property value `0x20000000 0x42' locates the register block
49
   at the address specified in the mn10300 user guide.
50
 
51
 
52
   PORTS
53
 
54
 
55
   reset (input)
56
 
57
   Currently ignored.
58
 
59
 
60
   nmi (input)
61
 
62
   Deliver a non-maskable interrupt to the processor.
63
 
64
 
65
   level (input)
66
 
67
   Maskable interrupt level port port.  The interrupt controller
68
   notifies the processor of any change in the level of pending
69
   requested interrupts via this port.
70
 
71
 
72
   ack (output)
73
 
74
   Output signal indicating that the processor is delivering a level
75
   interrupt.  The value passed with the event specifies the level of
76
   the interrupt being delivered.
77
 
78
 
79
   BUGS
80
 
81
 
82
   When delivering an interrupt, this code assumes that there is only
83
   one processor (number 0).
84
 
85
   This code does not attempt to be efficient at handling pending
86
   interrupts.  It simply schedules the interrupt delivery handler
87
   every instruction cycle until all pending interrupts go away.  An
88
   alternative implementation might modify instructions that change
89
   the PSW and have them check to see if the change makes an interrupt
90
   delivery possible.
91
 
92
   */
93
 
94
 
95
/* The interrupt vectors */
96
 
97
enum { NR_VECTORS = 7, };
98
 
99
 
100
/* The interrupt controller register address blocks */
101
 
102
struct mn103cpu_block {
103
  unsigned_word base;
104
  unsigned_word bound;
105
};
106
 
107
 
108
struct mn103cpu {
109
  struct mn103cpu_block block;
110
  struct hw_event *pending_handler;
111
  int pending_level;
112
  int pending_nmi;
113
  int pending_reset;
114
  /* the visible registers */
115
  unsigned16 interrupt_vector[NR_VECTORS];
116
  unsigned16 internal_memory_control;
117
  unsigned16 cpu_mode;
118
};
119
 
120
 
121
 
122
/* input port ID's */
123
 
124
enum {
125
  RESET_PORT,
126
  NMI_PORT,
127
  LEVEL_PORT,
128
};
129
 
130
 
131
/* output port ID's */
132
 
133
enum {
134
  ACK_PORT,
135
};
136
 
137
static const struct hw_port_descriptor mn103cpu_ports[] = {
138
 
139
  /* interrupt inputs */
140
  { "reset", RESET_PORT, 0, input_port, },
141
  { "nmi", NMI_PORT, 0, input_port, },
142
  { "level", LEVEL_PORT, 0, input_port, },
143
 
144
  /* interrupt ack (latch) output from cpu */
145
  { "ack", ACK_PORT, 0, output_port, },
146
 
147
  { NULL, },
148
};
149
 
150
 
151
/* Finish off the partially created hw device.  Attach our local
152
   callbacks.  Wire up our port names etc */
153
 
154
static hw_io_read_buffer_method mn103cpu_io_read_buffer;
155
static hw_io_write_buffer_method mn103cpu_io_write_buffer;
156
static hw_port_event_method mn103cpu_port_event;
157
 
158
static void
159
attach_mn103cpu_regs (struct hw *me,
160
                      struct mn103cpu *controller)
161
{
162
  unsigned_word attach_address;
163
  int attach_space;
164
  unsigned attach_size;
165
  reg_property_spec reg;
166
  if (hw_find_property (me, "reg") == NULL)
167
    hw_abort (me, "Missing \"reg\" property");
168
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
169
    hw_abort (me, "\"reg\" property must contain three addr/size entries");
170
  hw_unit_address_to_attach_address (hw_parent (me),
171
                                     &reg.address,
172
                                     &attach_space,
173
                                     &attach_address,
174
                                     me);
175
  controller->block.base = attach_address;
176
  hw_unit_size_to_attach_size (hw_parent (me),
177
                               &reg.size,
178
                               &attach_size, me);
179
  controller->block.bound = attach_address + (attach_size - 1);
180
  if ((controller->block.base & 3) != 0)
181
    hw_abort (me, "cpu register block must be 4 byte aligned");
182
  hw_attach_address (hw_parent (me),
183
                     0,
184
                     attach_space, attach_address, attach_size,
185
                     me);
186
}
187
 
188
 
189
static void
190
mn103cpu_finish (struct hw *me)
191
{
192
  struct mn103cpu *controller;
193
 
194
  controller = HW_ZALLOC (me, struct mn103cpu);
195
  set_hw_data (me, controller);
196
  set_hw_io_read_buffer (me, mn103cpu_io_read_buffer);
197
  set_hw_io_write_buffer (me, mn103cpu_io_write_buffer);
198
  set_hw_ports (me, mn103cpu_ports);
199
  set_hw_port_event (me, mn103cpu_port_event);
200
 
201
  /* Attach ourself to our parent bus */
202
  attach_mn103cpu_regs (me, controller);
203
 
204
  /* Initialize the read-only registers */
205
  controller->pending_level = 7; /* FIXME */
206
  /* ... */
207
}
208
 
209
 
210
 
211
/* An event arrives on an interrupt port */
212
 
213
static void
214
deliver_mn103cpu_interrupt (struct hw *me,
215
                            void *data)
216
{
217
  struct mn103cpu *controller = hw_data (me);
218
  SIM_DESC simulator = hw_system (me);
219
  sim_cpu *cpu = STATE_CPU (simulator, 0);
220
 
221
  if (controller->pending_reset)
222
    {
223
      controller->pending_reset = 0;
224
      /* need to clear all registers et.al! */
225
      HW_TRACE ((me, "Reset!"));
226
      hw_abort (me, "Reset!");
227
    }
228
  else if (controller->pending_nmi)
229
    {
230
      controller->pending_nmi = 0;
231
      store_word (SP - 4, CIA_GET (cpu));
232
      store_half (SP - 8, PSW);
233
      PSW &= ~PSW_IE;
234
      SP = SP - 8;
235
      CIA_SET (cpu, 0x40000008);
236
      HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
237
                 (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
238
    }
239
  else if ((controller->pending_level < EXTRACT_PSW_LM)
240
           && (PSW & PSW_IE))
241
    {
242
      /* Don't clear pending level.  Request continues to be pending
243
         until the interrupt controller clears/changes it */
244
      store_word (SP - 4, CIA_GET (cpu));
245
      store_half (SP - 8, PSW);
246
      PSW &= ~PSW_IE;
247
      PSW &= ~PSW_LM;
248
      PSW |= INSERT_PSW_LM (controller->pending_level);
249
      SP = SP - 8;
250
      CIA_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
251
      HW_TRACE ((me, "port-out ack %d", controller->pending_level));
252
      hw_port_event (me, ACK_PORT, controller->pending_level);
253
      HW_TRACE ((me, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
254
                 controller->pending_level,
255
                 (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
256
    }
257
 
258
  if (controller->pending_level < 7) /* FIXME */
259
    {
260
      /* As long as there is the potential need to deliver an
261
         interrupt we keep rescheduling this routine. */
262
      if (controller->pending_handler != NULL)
263
        controller->pending_handler =
264
          hw_event_queue_schedule (me, 1, deliver_mn103cpu_interrupt, NULL);
265
    }
266
  else
267
    {
268
      /* Don't bother re-scheduling the interrupt handler as there is
269
         nothing to deliver */
270
      controller->pending_handler = NULL;
271
    }
272
 
273
}
274
 
275
 
276
static void
277
mn103cpu_port_event (struct hw *me,
278
                     int my_port,
279
                     struct hw *source,
280
                     int source_port,
281
                     int level)
282
{
283
  struct mn103cpu *controller = hw_data (me);
284
 
285
  /* Schedule our event handler *now* */
286
  if (controller->pending_handler == NULL)
287
    controller->pending_handler =
288
      hw_event_queue_schedule (me, 0, deliver_mn103cpu_interrupt, NULL);
289
 
290
  switch (my_port)
291
    {
292
 
293
    case RESET_PORT:
294
      controller->pending_reset = 1;
295
      HW_TRACE ((me, "port-in reset"));
296
      break;
297
 
298
    case NMI_PORT:
299
      controller->pending_nmi = 1;
300
      HW_TRACE ((me, "port-in nmi"));
301
      break;
302
 
303
    case LEVEL_PORT:
304
      controller->pending_level = level;
305
      HW_TRACE ((me, "port-in level=%d", level));
306
      break;
307
 
308
    default:
309
      hw_abort (me, "bad switch");
310
      break;
311
 
312
    }
313
}
314
 
315
 
316
/* Read/write to a CPU register */
317
 
318
enum mn103cpu_regs {
319
  INVALID_REG,
320
  IVR0_REG,
321
  IVR1_REG,
322
  IVR2_REG,
323
  IVR3_REG,
324
  IVR4_REG,
325
  IVR5_REG,
326
  IVR6_REG,
327
  IMCR_REG,
328
  CPUM_REG,
329
};
330
 
331
static enum mn103cpu_regs
332
decode_mn103cpu_addr (struct hw *me,
333
                      struct mn103cpu *controller,
334
                      unsigned_word base)
335
{
336
  switch (base - controller->block.base)
337
    {
338
    case 0x000: return IVR0_REG;
339
    case 0x004: return IVR1_REG;
340
    case 0x008: return IVR2_REG;
341
    case 0x00c: return IVR3_REG;
342
    case 0x010: return IVR4_REG;
343
    case 0x014: return IVR5_REG;
344
    case 0x018: return IVR6_REG;
345
    case 0x020: return IMCR_REG;
346
    case 0x040: return CPUM_REG;
347
    default: return INVALID_REG;
348
    }
349
}
350
 
351
static unsigned
352
mn103cpu_io_read_buffer (struct hw *me,
353
                         void *dest,
354
                         int space,
355
                         unsigned_word base,
356
                         unsigned nr_bytes)
357
{
358
  struct mn103cpu *controller = hw_data (me);
359
  unsigned16 val = 0;
360
  enum mn103cpu_regs reg = decode_mn103cpu_addr (me, controller, base);
361
 
362
  switch (reg)
363
    {
364
    case IVR0_REG:
365
    case IVR1_REG:
366
    case IVR2_REG:
367
    case IVR3_REG:
368
    case IVR4_REG:
369
    case IVR5_REG:
370
    case IVR6_REG:
371
      val = controller->interrupt_vector[reg - IVR0_REG];
372
      break;
373
    case IMCR_REG:
374
      val = controller->internal_memory_control;
375
      break;
376
    case CPUM_REG:
377
      val = controller->cpu_mode;
378
      break;
379
    default:
380
      /* just ignore the read */
381
      break;
382
    }
383
 
384
  if (nr_bytes == 2)
385
    *(unsigned16*) dest = H2LE_2 (val);
386
 
387
  return nr_bytes;
388
}
389
 
390
static unsigned
391
mn103cpu_io_write_buffer (struct hw *me,
392
                          const void *source,
393
                          int space,
394
                          unsigned_word base,
395
                          unsigned nr_bytes)
396
{
397
  struct mn103cpu *controller = hw_data (me);
398
  unsigned16 val;
399
  enum mn103cpu_regs reg;
400
 
401
  if (nr_bytes != 2)
402
    hw_abort (me, "must be two byte write");
403
 
404
  reg = decode_mn103cpu_addr (me, controller, base);
405
  val = LE2H_2 (* (unsigned16 *) source);
406
 
407
  switch (reg)
408
    {
409
    case IVR0_REG:
410
    case IVR1_REG:
411
    case IVR2_REG:
412
    case IVR3_REG:
413
    case IVR4_REG:
414
    case IVR5_REG:
415
    case IVR6_REG:
416
      controller->interrupt_vector[reg - IVR0_REG] = val;
417
      HW_TRACE ((me, "ivr%d = 0x%04lx", reg - IVR0_REG, (long) val));
418
      break;
419
    default:
420
      /* just ignore the write */
421
      break;
422
    }
423
 
424
  return nr_bytes;
425
}
426
 
427
 
428
const struct hw_descriptor dv_mn103cpu_descriptor[] = {
429
  { "mn103cpu", mn103cpu_finish, },
430
  { NULL },
431
};

powered by: WebSVN 2.1.0

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