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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [sim/] [ppc/] [hw_glue.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 106 markom
/*  This file is part of the program psim.
2
 
3
    Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
4
 
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License
16
    along with this program; if not, write to the Free Software
17
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 
19
    */
20
 
21
 
22
#ifndef _HW_GLUE_C_
23
#define _HW_GLUE_C_
24
 
25
#include "device_table.h"
26
 
27
 
28
/* DEVICE
29
 
30
 
31
   glue - glue to interconnect and test interrupts
32
 
33
 
34
   DESCRIPTION
35
 
36
 
37
   The glue device provides two functions.  Firstly, it provides a
38
   mechanism for inspecting and driving the interrupt net.  Secondly,
39
   it provides a set of boolean primitives that can be used add
40
   combinatorial operations to the interrupt network.
41
 
42
   Glue devices have a variable number of big endian <<output>>
43
   registers.  Each host-word size.  The registers can be both read
44
   and written.
45
 
46
   Writing a value to an output register causes an interrupt (of the
47
   specified level) to be driven on the devices corresponding output
48
   interrupt port.
49
 
50
   Reading an <<output>> register returns either the last value
51
   written or the most recently computed value (for that register) as
52
   a result of an interrupt ariving (which ever was computed last).
53
 
54
   At present the following sub device types are available:
55
 
56
   <<glue>>: In addition to driving its output interrupt port with any
57
   value written to an interrupt input port is stored in the
58
   corresponding <<output>> register.  Such input interrupts, however,
59
   are not propogated to an output interrupt port.
60
 
61
   <<glue-and>>: The bit-wise AND of the interrupt inputs is computed
62
   and then both stored in <<output>> register zero and propogated to
63
   output interrupt output port zero.
64
 
65
 
66
   PROPERTIES
67
 
68
 
69
   reg = <address> <size> (required)
70
 
71
   Specify the address (within the parent bus) that this device is to
72
   live.  The address must be 2048 * sizeof(word) (8k in a 32bit
73
   simulation) aligned.
74
 
75
 
76
   interrupt-ranges = <int-number> <range> (optional)
77
 
78
   If present, this specifies the number of valid interrupt inputs (up
79
   to the maximum of 2048).  By default, <<int-number>> is zero and
80
   range is determined by the <<reg>> size.
81
 
82
 
83
   EXAMPLES
84
 
85
 
86
   Enable tracing of the device:
87
 
88
   | -t glue-device \
89
 
90
 
91
   Create source, bitwize-and, and sink glue devices.  Since the
92
   device at address <<0x10000>> is of size <<8>> it will have two
93
   output interrupt ports.
94
 
95
   | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
96
   | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
97
   | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
98
   | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
99
 
100
 
101
   Wire the two source interrupts to the AND device:
102
 
103
   | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
104
   | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
105
 
106
 
107
   Wire the AND device up to the sink so that the and's output is not
108
   left open.
109
 
110
   | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
111
 
112
 
113
   With the above configuration.  The client program is able to
114
   compute a two bit AND.  For instance the <<C>> stub below prints 1
115
   AND 0.
116
 
117
   |  unsigned *input = (void*)0xf0010000;
118
   |  unsigned *output = (void*)0xf0030000;
119
   |  unsigned ans;
120
   |  input[0] = htonl(1);
121
   |  input[1] = htonl(0);
122
   |  ans = ntohl(*output);
123
   |  write_string("AND is ");
124
   |  write_int(ans);
125
   |  write_line();
126
 
127
 
128
   BUGS
129
 
130
 
131
   A future implementation of this device may support multiple
132
   interrupt ranges.
133
 
134
   Some of the devices listed may not yet be fully implemented.
135
 
136
   Additional devices such as a dff, an inverter or a latch may be
137
   useful.
138
 
139
   */
140
 
141
 
142
enum {
143
  max_nr_interrupts = 2048,
144
};
145
 
146
typedef enum _hw_glue_type {
147
  glue_undefined = 0,
148
  glue_io,
149
  glue_and,
150
  glue_nand,
151
  glue_or,
152
  glue_xor,
153
  glue_nor,
154
  glue_not,
155
} hw_glue_type;
156
 
157
typedef struct _hw_glue_device {
158
  hw_glue_type type;
159
  int int_number;
160
  int *input;
161
  int nr_inputs;
162
  unsigned sizeof_input;
163
  /* our output registers */
164
  int space;
165
  unsigned_word address;
166
  unsigned sizeof_output;
167
  int *output;
168
  int nr_outputs;
169
} hw_glue_device;
170
 
171
 
172
static void
173
hw_glue_init_address(device *me)
174
{
175
  hw_glue_device *glue = (hw_glue_device*)device_data(me);
176
 
177
  /* attach to my parent */
178
  generic_device_init_address(me);
179
 
180
  /* establish the output registers */
181
  if (glue->output != NULL) {
182
    memset(glue->output, 0, glue->sizeof_output);
183
  }
184
  else {
185
    reg_property_spec unit;
186
    int reg_nr;
187
    /* find a relevant reg entry */
188
    reg_nr = 0;
189
    while (device_find_reg_array_property(me, "reg", reg_nr, &unit)
190
           && !device_size_to_attach_size(device_parent(me), &unit.size,
191
                                          &glue->sizeof_output, me))
192
      reg_nr++;
193
    /* check out the size */
194
    if (glue->sizeof_output == 0)
195
      device_error(me, "at least one reg property size must be nonzero");
196
    if (glue->sizeof_output % sizeof(unsigned_word) != 0)
197
      device_error(me, "reg property size must be %d aligned", sizeof(unsigned_word));
198
    /* and the address */
199
    device_address_to_attach_address(device_parent(me),
200
                                     &unit.address, &glue->space, &glue->address,
201
                                     me);
202
    if (glue->address % (sizeof(unsigned_word) * max_nr_interrupts) != 0)
203
      device_error(me, "reg property address must be %d aligned",
204
                   sizeof(unsigned_word) * max_nr_interrupts);
205
    glue->nr_outputs = glue->sizeof_output / sizeof(unsigned_word);
206
    glue->output = zalloc(glue->sizeof_output);
207
  }
208
 
209
  /* establish the input interrupt ports */
210
  if (glue->input != NULL) {
211
    memset(glue->input, 0, glue->sizeof_input);
212
  }
213
  else {
214
    const device_property *ranges = device_find_property(me, "interrupt-ranges");
215
    if (ranges == NULL) {
216
      glue->int_number = 0;
217
      glue->nr_inputs = glue->nr_outputs;
218
    }
219
    else if (ranges->sizeof_array != sizeof(unsigned_cell) * 2) {
220
      device_error(me, "invalid interrupt-ranges property (incorrect size)");
221
    }
222
    else {
223
      const unsigned_cell *int_range = ranges->array;
224
      glue->int_number = BE2H_cell(int_range[0]);
225
      glue->nr_inputs = BE2H_cell(int_range[1]);
226
    }
227
    glue->sizeof_input = glue->nr_inputs * sizeof(unsigned);
228
    glue->input = zalloc(glue->sizeof_input);
229
  }
230
 
231
  /* determine our type */
232
  if (glue->type == glue_undefined) {
233
    const char *name = device_name(me);
234
    if (strcmp(name, "glue") == 0)
235
      glue->type = glue_io;
236
    else if (strcmp(name, "glue-and") == 0)
237
      glue->type = glue_and;
238
    else
239
      device_error(me, "unimplemented glue type");
240
  }
241
 
242
  DTRACE(glue, ("int-number %d, nr_inputs %d, nr_outputs %d\n",
243
                glue->int_number, glue->nr_inputs, glue->nr_outputs));
244
}
245
 
246
static unsigned
247
hw_glue_io_read_buffer_callback(device *me,
248
                                void *dest,
249
                                int space,
250
                                unsigned_word addr,
251
                                unsigned nr_bytes,
252
                                cpu *processor,
253
                                unsigned_word cia)
254
{
255
  hw_glue_device *glue = (hw_glue_device*)device_data(me);
256
  int reg = ((addr - glue->address) / sizeof(unsigned_word)) % glue->nr_outputs;
257
  if (nr_bytes != sizeof(unsigned_word)
258
      || (addr % sizeof(unsigned_word)) != 0)
259
     device_error(me, "missaligned read access (%d:0x%lx:%d) not supported",
260
                  space, (unsigned long)addr, nr_bytes);
261
  *(unsigned_word*)dest = H2BE_4(glue->output[reg]);
262
  DTRACE(glue, ("read - interrupt %d (0x%lx), level %d\n",
263
                reg, (unsigned long) addr, glue->output[reg]));
264
  return nr_bytes;
265
}
266
 
267
 
268
static unsigned
269
hw_glue_io_write_buffer_callback(device *me,
270
                                 const void *source,
271
                                 int space,
272
                                 unsigned_word addr,
273
                                 unsigned nr_bytes,
274
                                 cpu *processor,
275
                                 unsigned_word cia)
276
{
277
  hw_glue_device *glue = (hw_glue_device*)device_data(me);
278
  int reg = ((addr - glue->address) / sizeof(unsigned_word)) % max_nr_interrupts;
279
  if (nr_bytes != sizeof(unsigned_word)
280
      || (addr % sizeof(unsigned_word)) != 0)
281
    device_error(me, "missaligned write access (%d:0x%lx:%d) not supported",
282
                 space, (unsigned long)addr, nr_bytes);
283
  glue->output[reg] = H2BE_4(*(unsigned_word*)source);
284
  DTRACE(glue, ("write - interrupt %d (0x%lx), level %d\n",
285
                reg, (unsigned long) addr, glue->output[reg]));
286
  device_interrupt_event(me, reg, glue->output[reg], processor, cia);
287
  return nr_bytes;
288
}
289
 
290
static void
291
hw_glue_interrupt_event(device *me,
292
                        int my_port,
293
                        device *source,
294
                        int source_port,
295
                        int level,
296
                        cpu *processor,
297
                        unsigned_word cia)
298
{
299
  hw_glue_device *glue = (hw_glue_device*)device_data(me);
300
  int i;
301
  if (my_port < glue->int_number
302
      || my_port >= glue->int_number + glue->nr_inputs)
303
    device_error(me, "interrupt %d outside of valid range", my_port);
304
  glue->input[my_port - glue->int_number] = level;
305
  switch (glue->type) {
306
  case glue_io:
307
    {
308
      int port = my_port % glue->nr_outputs;
309
      glue->output[port] = level;
310
      DTRACE(glue, ("input - interrupt %d (0x%lx), level %d\n",
311
                    my_port,
312
                    (unsigned long)glue->address + port * sizeof(unsigned_word),
313
                    level));
314
      break;
315
    }
316
  case glue_and:
317
    glue->output[0] = glue->input[0];
318
    for (i = 1; i < glue->nr_inputs; i++)
319
      glue->output[0] &= glue->input[i];
320
    DTRACE(glue, ("and - interrupt %d, level %d arrived - output %d\n",
321
                  my_port, level, glue->output[0]));
322
    device_interrupt_event(me, 0, glue->output[0], processor, cia);
323
    break;
324
  default:
325
    device_error(me, "operator not implemented");
326
    break;
327
  }
328
}
329
 
330
 
331
static const device_interrupt_port_descriptor hw_glue_interrupt_ports[] = {
332
  { "int", 0, max_nr_interrupts },
333
  { NULL }
334
};
335
 
336
 
337
static device_callbacks const hw_glue_callbacks = {
338
  { hw_glue_init_address, NULL },
339
  { NULL, }, /* address */
340
  { hw_glue_io_read_buffer_callback,
341
      hw_glue_io_write_buffer_callback, },
342
  { NULL, }, /* DMA */
343
  { hw_glue_interrupt_event, NULL, hw_glue_interrupt_ports }, /* interrupt */
344
  { NULL, }, /* unit */
345
  NULL, /* instance */
346
};
347
 
348
 
349
static void *
350
hw_glue_create(const char *name,
351
              const device_unit *unit_address,
352
              const char *args)
353
{
354
  /* create the descriptor */
355
  hw_glue_device *glue = ZALLOC(hw_glue_device);
356
  return glue;
357
}
358
 
359
 
360
const device_descriptor hw_glue_device_descriptor[] = {
361
  { "glue", hw_glue_create, &hw_glue_callbacks },
362
  { "glue-and", hw_glue_create, &hw_glue_callbacks },
363
  { "glue-nand", hw_glue_create, &hw_glue_callbacks },
364
  { "glue-or", hw_glue_create, &hw_glue_callbacks },
365
  { "glue-xor", hw_glue_create, &hw_glue_callbacks },
366
  { "glue-nor", hw_glue_create, &hw_glue_callbacks },
367
  { "glue-not", hw_glue_create, &hw_glue_callbacks },
368
  { NULL },
369
};
370
 
371
#endif /* _HW_GLUE_C_ */

powered by: WebSVN 2.1.0

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