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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [common/] [dv-glue.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 psim.
2
 
3
    Copyright (C) 1994-1996,1998 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
#include "hw-main.h"
23
 
24
#ifdef HAVE_STRING_H
25
#include <string.h>
26
#else
27
#ifdef HAVE_STRINGS_H
28
#include <strings.h>
29
#endif
30
#endif
31
 
32
/* DEVICE
33
 
34
 
35
   glue - glue to interconnect and test hardware ports
36
 
37
 
38
   DESCRIPTION
39
 
40
 
41
   The glue device provides two functions.  Firstly, it provides a
42
   mechanism for inspecting and driving the port network.  Secondly,
43
   it provides a set of boolean primitives that can be used to apply
44
   combinatorial operations to the port network.
45
 
46
   Glue devices have a variable number of big endian <<output>>
47
   registers.  Each register is target-word sized.  The registers can
48
   be read and written.
49
 
50
   Writing to an output register results in an event being driven
51
   (level determined by the value written) on the devices
52
   corresponding output port.
53
 
54
   Reading an <<output>> register returns either the last value
55
   written or the most recently computed value (for that register) as
56
   a result of an event ariving on that port (which ever was computed
57
   last).
58
 
59
   At present the following sub device types are available:
60
 
61
   <<glue>>: In addition to driving its output interrupt port with any
62
   value written to an interrupt input port is stored in the
63
   corresponding <<output>> register.  Such input interrupts, however,
64
   are not propogated to an output interrupt port.
65
 
66
   <<glue-and>>: The bit-wise AND of the interrupt inputs is computed
67
   and then both stored in <<output>> register zero and propogated to
68
   output interrupt output port zero.
69
 
70
 
71
   PROPERTIES
72
 
73
 
74
   reg = <address> <size> (required)
75
 
76
   Specify the address (within the parent bus) that this device is to
77
   live.  The address must be 2048 * sizeof (word) (8k in a 32bit
78
   simulation) aligned.
79
 
80
 
81
   interrupt-ranges = <int-number> <range> (optional)
82
 
83
   If present, this specifies the number of valid interrupt inputs (up
84
   to the maximum of 2048).  By default, <<int-number>> is zero and
85
   range is determined by the <<reg>> size.
86
 
87
 
88
   PORTS
89
 
90
 
91
   int[0..] (input, output)
92
 
93
   Both an input and an output port.
94
 
95
 
96
   EXAMPLES
97
 
98
 
99
   Enable tracing of the device:
100
 
101
   | -t glue-device \
102
 
103
 
104
   Create source, bitwize-and, and sink glue devices.  Since the
105
   device at address <<0x10000>> is of size <<8>> it will have two
106
   output interrupt ports.
107
 
108
   | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
109
   | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
110
   | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
111
   | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
112
 
113
 
114
   Wire the two source interrupts to the AND device:
115
 
116
   | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
117
   | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
118
 
119
 
120
   Wire the AND device up to the sink so that the and's output is not
121
   left open.
122
 
123
   | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
124
 
125
 
126
   With the above configuration.  The client program is able to
127
   compute a two bit AND.  For instance the <<C>> stub below prints 1
128
   AND 0.
129
 
130
   |  unsigned *input = (void*)0xf0010000;
131
   |  unsigned *output = (void*)0xf0030000;
132
   |  unsigned ans;
133
   |  input[0] = htonl(1);
134
   |  input[1] = htonl(0);
135
   |  ans = ntohl(*output);
136
   |  write_string("AND is ");
137
   |  write_int(ans);
138
   |  write_line();
139
 
140
 
141
   BUGS
142
 
143
 
144
   A future implementation of this device may support multiple
145
   interrupt ranges.
146
 
147
   Some of the devices listed may not yet be fully implemented.
148
 
149
   Additional devices such as a D flip-flop (DFF), an inverter (INV)
150
   or a latch (LAT) may prove useful.
151
 
152
   */
153
 
154
 
155
enum {
156
  max_nr_ports = 2048,
157
};
158
 
159
enum hw_glue_type {
160
  glue_undefined = 0,
161
  glue_io,
162
  glue_and,
163
  glue_nand,
164
  glue_or,
165
  glue_xor,
166
  glue_nor,
167
  glue_not,
168
};
169
 
170
struct hw_glue {
171
  enum hw_glue_type type;
172
  int int_number;
173
  int *input;
174
  int nr_inputs;
175
  unsigned sizeof_input;
176
  /* our output registers */
177
  int space;
178
  unsigned_word address;
179
  unsigned sizeof_output;
180
  int *output;
181
  int nr_outputs;
182
};
183
 
184
 
185
static hw_io_read_buffer_method hw_glue_io_read_buffer;
186
static hw_io_write_buffer_method hw_glue_io_write_buffer;
187
static hw_port_event_method hw_glue_port_event;
188
const static struct hw_port_descriptor hw_glue_ports[];
189
 
190
static void
191
hw_glue_finish (struct hw *me)
192
{
193
  struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
194
 
195
  /* establish our own methods */
196
  set_hw_data (me, glue);
197
  set_hw_io_read_buffer (me, hw_glue_io_read_buffer);
198
  set_hw_io_write_buffer (me, hw_glue_io_write_buffer);
199
  set_hw_ports (me, hw_glue_ports);
200
  set_hw_port_event (me, hw_glue_port_event);
201
 
202
  /* attach to our parent bus */
203
  do_hw_attach_regs (me);
204
 
205
  /* establish the output registers */
206
  {
207
    reg_property_spec unit;
208
    int reg_nr;
209
    /* find a relevant reg entry */
210
    reg_nr = 0;
211
    while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
212
           && !hw_unit_size_to_attach_size (hw_parent (me),
213
                                            &unit.size,
214
                                            &glue->sizeof_output,
215
                                            me))
216
      reg_nr++;
217
    /* check out the size */
218
    if (glue->sizeof_output == 0)
219
      hw_abort (me, "at least one reg property size must be nonzero");
220
    if (glue->sizeof_output % sizeof (unsigned_word) != 0)
221
      hw_abort (me, "reg property size must be %d aligned",
222
                sizeof (unsigned_word));
223
    /* and the address */
224
    hw_unit_address_to_attach_address (hw_parent (me),
225
                                       &unit.address,
226
                                       &glue->space,
227
                                       &glue->address,
228
                                       me);
229
    if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
230
      hw_abort (me, "reg property address must be %d aligned",
231
                sizeof (unsigned_word) * max_nr_ports);
232
    glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
233
    glue->output = hw_zalloc (me, glue->sizeof_output);
234
  }
235
 
236
  /* establish the input ports */
237
  {
238
    const struct hw_property *ranges;
239
    ranges = hw_find_property (me, "interrupt-ranges");
240
    if (ranges == NULL)
241
      {
242
        glue->int_number = 0;
243
        glue->nr_inputs = glue->nr_outputs;
244
      }
245
    else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
246
      {
247
        hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
248
      }
249
    else
250
      {
251
        const unsigned_cell *int_range = ranges->array;
252
        glue->int_number = BE2H_cell (int_range[0]);
253
        glue->nr_inputs = BE2H_cell (int_range[1]);
254
      }
255
    glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
256
    glue->input = hw_zalloc (me, glue->sizeof_input);
257
  }
258
 
259
  /* determine our type */
260
  {
261
    const char *name = hw_name(me);
262
    if (strcmp (name, "glue") == 0)
263
      glue->type = glue_io;
264
    else if (strcmp (name, "glue-and") == 0)
265
      glue->type = glue_and;
266
    else
267
      hw_abort (me, "unimplemented glue type");
268
  }
269
 
270
  HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
271
             glue->int_number, glue->nr_inputs, glue->nr_outputs));
272
}
273
 
274
static unsigned
275
hw_glue_io_read_buffer (struct hw *me,
276
                        void *dest,
277
                        int space,
278
                        unsigned_word addr,
279
                        unsigned nr_bytes)
280
{
281
  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
282
  int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
283
  if (nr_bytes != sizeof (unsigned_word)
284
      || (addr % sizeof (unsigned_word)) != 0)
285
    hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
286
              space, (unsigned long)addr, nr_bytes);
287
  *(unsigned_word*)dest = H2BE_4(glue->output[reg]);
288
  HW_TRACE ((me, "read - port %d (0x%lx), level %d",
289
             reg, (unsigned long) addr, glue->output[reg]));
290
  return nr_bytes;
291
}
292
 
293
 
294
static unsigned
295
hw_glue_io_write_buffer (struct hw *me,
296
                         const void *source,
297
                         int space,
298
                         unsigned_word addr,
299
                         unsigned nr_bytes)
300
{
301
  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
302
  int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
303
  if (nr_bytes != sizeof (unsigned_word)
304
      || (addr % sizeof (unsigned_word)) != 0)
305
    hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
306
              space, (unsigned long) addr, nr_bytes);
307
  glue->output[reg] = H2BE_4 (*(unsigned_word*)source);
308
  HW_TRACE ((me, "write - port %d (0x%lx), level %d",
309
             reg, (unsigned long) addr, glue->output[reg]));
310
  hw_port_event (me, reg, glue->output[reg]);
311
  return nr_bytes;
312
}
313
 
314
static void
315
hw_glue_port_event (struct hw *me,
316
                    int my_port,
317
                    struct hw *source,
318
                    int source_port,
319
                    int level)
320
{
321
  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
322
  int i;
323
  if (my_port < glue->int_number
324
      || my_port >= glue->int_number + glue->nr_inputs)
325
    hw_abort (me, "port %d outside of valid range", my_port);
326
  glue->input[my_port - glue->int_number] = level;
327
  switch (glue->type)
328
    {
329
    case glue_io:
330
      {
331
        int port = my_port % glue->nr_outputs;
332
        glue->output[port] = level;
333
        HW_TRACE ((me, "input - port %d (0x%lx), level %d",
334
                   my_port,
335
                   (unsigned long) glue->address + port * sizeof (unsigned_word),
336
                   level));
337
        break;
338
      }
339
    case glue_and:
340
      {
341
        glue->output[0] = glue->input[0];
342
        for (i = 1; i < glue->nr_inputs; i++)
343
          glue->output[0] &= glue->input[i];
344
        HW_TRACE ((me, "and - port %d, level %d arrived - output %d",
345
                   my_port, level, glue->output[0]));
346
        hw_port_event (me, 0, glue->output[0]);
347
        break;
348
      }
349
    default:
350
      {
351
        hw_abort (me, "operator not implemented");
352
        break;
353
      }
354
    }
355
}
356
 
357
 
358
static const struct hw_port_descriptor hw_glue_ports[] = {
359
  { "int", 0, max_nr_ports },
360
  { NULL }
361
};
362
 
363
 
364
const struct hw_descriptor dv_glue_descriptor[] = {
365
  { "glue", hw_glue_finish, },
366
  { "glue-and", hw_glue_finish, },
367
  { "glue-nand", hw_glue_finish, },
368
  { "glue-or", hw_glue_finish, },
369
  { "glue-xor", hw_glue_finish, },
370
  { "glue-nor", hw_glue_finish, },
371
  { "glue-not", hw_glue_finish, },
372
  { NULL },
373
};

powered by: WebSVN 2.1.0

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