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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [testsuite/] [test-code/] [lib-upcalls/] [lib-upcalls.c] - Blame information for rev 582

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

Line No. Rev Author Line
1 93 jeremybenn
/* lib-upcalls.c. Test of Or1ksim library upcall interface.
2
 
3
   Copyright (C) 1999-2006 OpenCores
4
   Copyright (C) 2010 Embecosm Limited
5
 
6
   Contributors various OpenCores participants
7
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8
 
9
   This file is part of OpenRISC 1000 Architectural Simulator.
10
 
11
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15
 
16
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20
 
21
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http:  www.gnu.org/licenses/>.  */
23
 
24
/* ----------------------------------------------------------------------------
25
   This code is commented throughout for use with Doxygen.
26
   --------------------------------------------------------------------------*/
27
 
28
#include <errno.h>
29
#include <stddef.h>
30
#include <stdlib.h>
31
#include <stdio.h>
32
#include <string.h>
33
 
34
#include "or1ksim.h"
35
 
36
 
37
/*! Memory mapped register memory */
38
static unsigned char *regv;
39
 
40
/*! Number of bytes of register memory */
41
static int  regc;
42
 
43
/*! Number of times each upcall has been called */
44
static int  upcall_count;
45
 
46
 
47
/* --------------------------------------------------------------------------*/
48
/*!Read upcall
49
 
50
   Upcall from Or1ksim to read a word from an external peripheral. Read the
51
   specified bytes from the peripheral if available.
52
 
53
   We only ever expect to get 4 byte reads here (modeling Wishbone).
54
 
55
   @note We receive the full address, since there is a single upcall routine,
56
         and this allows us to decode between potentially multiple devices.
57
 
58
   @todo We assume that the register memory size is a power of 2, making
59
         address shortening a simple modulo exercise. We should use a more
60
         generic solution.
61
 
62
   @note The mask is a byte mask. Since this is testing, we warn if any byte
63
         is not either 0xff or 0x00.
64
 
65
   @param[in]  class_ptr  A handle pass back from the initalization. Intended
66
                          for C++ callers, not used here.
67
   @param[in]  addr       Address to read from.
68
   @param[in]  mask       Byte mask for the read.
69
   @param[out] rdata      Buffer for the data read.
70
   @param[in]  data_len   Number of bytes in mask and rdata.
71
 
72
   @return  Zero on success, non-zero on failure.                            */
73
/* --------------------------------------------------------------------------*/
74
static int
75
read_upcall (void              *class_ptr,
76
             unsigned long int  addr,
77
             unsigned char      mask[],
78
             unsigned char      rdata[],
79
             int                data_len)
80
{
81
  unsigned long int  devaddr = addr % regc;
82
 
83
  upcall_count--;                       /* One less upcall to do */
84
 
85
  if (4 != data_len)
86
    {
87
      printf ("Warning: 4-byte reads only supported for this device.\n");
88
      return  -1;
89
    }
90
 
91
  if (devaddr > regc - data_len)
92
    {
93
      printf ("Warning: read from 0x%08lx out of range: zero result.\n",
94
              devaddr);
95
      return  -1;
96
    }
97
 
98
  /* Read the data */
99
  int  i;
100
 
101
  for (i = 0; i < 4; i++)
102
    {
103
      switch (mask[i])
104
        {
105
        case 0x00: rdata[i] = 0;                 break;
106
        case 0xff: rdata[i] = regv[devaddr + i]; break;
107
 
108
        default:
109
          printf ("Warning: invalid mask byte %d for read 0x%02x: "
110
                  "treated as 0xff.\n", i, mask[i]);
111
          rdata[i] = regv[devaddr + i];
112
          break;
113
        }
114
    }
115
 
116
  /* printf ("Read from 0x%08lx: vector [%02x %02x %02x %02x ], " */
117
  /*      "mask [%02x %02x %02x %02x ].\n", devaddr, rdata[0], rdata[1], */
118
  /*      rdata[2], rdata[3], mask[0], mask[1], mask[2], mask[3]); */
119
 
120
  return  0;                     /* Success */
121
 
122
}       /* read_upcall () */
123
 
124
 
125
/* --------------------------------------------------------------------------*/
126
/*!Write upcall
127
 
128
   Upcall from Or1ksim to write a word to an external peripheral. Read the
129
   specified bytes from the peripheral if available.
130
 
131
   We only ever expect to get 4 byte reads here (modeling Wishbone).
132
 
133
   @note We receive the full address, since there is a single upcall routine,
134
         and this allows us to decode between potentially multiple devices.
135
 
136
   @todo We assume that the register memory size is a power of 2, making
137
         address shortening a simple modulo exercise. We should use a more
138
         generic solution.
139
 
140
   @note The mask is a byte mask. Since this is testing, we warn if any byte
141
         is not either 0xff or 0x00.
142
 
143
   @param[in] class_ptr  A handle pass back from the initalization. Intended
144
                         for C++ callers, not used here.
145
   @param[in] addr       Address to write to.
146
   @param[in] mask       Byte mask for the write.
147
   @param[in] wdata      The data to write.
148
   @param[in] data_len   Number of bytes in mask and rdata.
149
 
150
   @return  Zero on success, non-zero on failure.                            */
151
/* --------------------------------------------------------------------------*/
152
static int
153
write_upcall (void              *class_ptr,
154
              unsigned long int  addr,
155
              unsigned char      mask[],
156
              unsigned char      wdata[],
157
              int                data_len)
158
{
159
  unsigned long int  devaddr  = addr % regc;
160
 
161
  upcall_count--;                       /* One less upcall to do */
162
 
163
  if (4 != data_len)
164
    {
165
      printf ("Warning: 4-byte writes only supported for this device.\n");
166
      return  -1;
167
    }
168
 
169
  if (devaddr > regc - data_len)
170
    {
171
      printf ("Warning: write to 0x%08lx out of range: ignored.\n",
172
              devaddr);
173
      return  -1;
174
    }
175
 
176
  /* printf ("Write to 0x%08lx: vector [%02x %02x %02x %02x ], " */
177
  /*      "mask [%02x %02x %02x %02x ].\n", devaddr, wdata[0], wdata[1], */
178
  /*      wdata[2], wdata[3], mask[0], mask[1], mask[2], mask[3]); */
179
 
180
  /* Write the data */
181
  int  i;
182
 
183
  for (i = 0; i < 4; i++)
184
    {
185
      switch (mask[i])
186
        {
187
        case 0x00:                               break;
188
        case 0xff: regv[devaddr + i] = wdata[i]; break;
189
 
190
        default:
191
          printf ("Warning: invalid mask byte %d for write 0x%02x: "
192
                  "treated as 0xff.\n", i, mask[i]);
193
          regv[devaddr + i] = wdata[i];
194
          break;
195
        }
196
    }
197
 
198
  return  0;                     /* Success */
199
 
200
}       /* write_upcall () */
201
 
202
 
203
/* --------------------------------------------------------------------------*/
204
/*!Main program
205
 
206
   Build an or1ksim program using the library which loads a program and config
207
   from the command line which will drive upcalls.
208
 
209
   lib-upcalls <config-file> <image> <upcall_count> <reg_bytes> [<reg_file>]
210
 
211
   A register memory of <reg_bytes> bytes is initalized from <reg_file> if
212
   present, or zeroed if not. <image> is run continuously, making upcalls,
213
   which are satisfied using the register memory. The program exits
214
   successfully when <upcall_count> upcalls have been made.
215
 
216
   @param[in] argc  Number of elements in argv
217
   @param[in] argv  Vector of program name and arguments
218
 
219
   @return  Return code for the program.                                     */
220
/* --------------------------------------------------------------------------*/
221
int
222
main (int   argc,
223
      char *argv[])
224
{
225
  char *reg_file;
226
 
227
  /* Parse args */
228
  switch (argc)
229
    {
230
    case 5:
231
      reg_file = NULL;
232
      break;
233
 
234
    case 6:
235
      reg_file = argv[5];
236
      break;
237
 
238
    default:
239
      printf ("usage: lib-upcalls <config-file> <image> "
240
              "<upcall_count> <reg_bytes> [<reg_file>]\n");
241
      return  1;
242
    }
243
 
244
  upcall_count = atoi (argv[3]);
245
 
246
  if (upcall_count <= 0)
247
    {
248
      printf ("ERROR: Upcall count must be positive\n");
249
      return  1;
250
    }
251
 
252
  regc = atoi (argv[4]);
253
 
254
  if (regc < 0)
255
    {
256
      printf ("ERROR: Register memory size must be positive\n");
257
      return  1;
258
    }
259
 
260
  /* Read the register file if provided. */
261
  regv = malloc (regc * sizeof (unsigned char));
262
 
263
  if (NULL == regv)
264
    {
265
      printf ("ERROR: Failed to allocate register memory\n");
266
      return  1;
267
    }
268
 
269
  int  next_free_byte = 0;
270
 
271
  if (NULL != reg_file)
272
    {
273
      FILE *fd = fopen (reg_file, "r");
274
 
275
      if (NULL == fd)
276
        {
277
          printf ("ERROR: Failed to open register file: %s\n",
278
                  strerror (errno));
279
          free (regv);
280
          return  1;
281
        }
282
 
283
      for (; next_free_byte < regc; next_free_byte++)
284
        {
285
          unsigned char  byte;
286
 
287
          if (1 == fscanf (fd, "%2hhx ", &byte))
288
            {
289
              regv[next_free_byte] = byte;
290
            }
291
          else
292
            {
293
              break;
294
            }
295
        }
296
 
297
      /* Should have read the whole file successfully. */
298
      if (ferror (fd))
299
        {
300
          printf ("ERROR: Reading register file: %s\n", strerror (errno));
301
          free (regv);
302
          return  1;
303
        }
304
 
305
      if (!feof (fd))
306
        {
307
          printf ("Warning: additional register file data ignored.\n");
308
        }
309
 
310
      if (0 != fclose (fd))
311
        {
312
          printf ("ERROR: Failed to close register file: %s\n",
313
                  strerror (errno));
314
          free (regv);
315
          return  1;
316
        }
317
    }
318
 
319
  /* Fill in any remaining bytes with zero */
320
  if (next_free_byte < regc)
321
    {
322
      (void)memset (&(regv[next_free_byte]), 0, regc - next_free_byte);
323
    }
324
 
325 220 jeremybenn
  /* Dummy argv array to pass arguments to or1ksim_init. Varies depending on
326
     whether an image file is specified. */
327
  int   dummy_argc;
328
  char *dummy_argv[5];
329
 
330
  dummy_argv[0] = "libsim";
331
  dummy_argv[1] = "-q";
332
  dummy_argv[2] = "-f";
333
  dummy_argv[3] = argv[1];
334
  dummy_argv[4] = argv[2];
335
 
336
  dummy_argc = 5;
337
 
338 93 jeremybenn
  /* Initialize the program. Put the initialization message afterwards, or it
339
     will get swamped by the Or1ksim header. */
340 220 jeremybenn
  if (0 == or1ksim_init (dummy_argc, dummy_argv, NULL, &read_upcall,
341
                         &write_upcall))
342 93 jeremybenn
    {
343
      printf ("Initalization succeeded.\n");
344
    }
345
  else
346
    {
347
      printf ("Initalization failed.\n");
348
      return  1;
349
    }
350
 
351
  /* Run repeatedly for 1 millisecond until we hit a breakpoint or all upcalls
352
     are done. */
353
  do
354
    {
355
      switch (or1ksim_run (1.0e-3))
356
        {
357
        case OR1KSIM_RC_OK:
358
          break;
359
 
360 458 julius
        case OR1KSIM_RC_HALTED:
361
          printf ("Test completed successfully: hit exit l.nop.\n");
362
          return  0;
363
 
364 93 jeremybenn
        case OR1KSIM_RC_BRKPT:
365
          printf ("Test completed successfully: hit breakpoint.\n");
366
          return  0;
367 458 julius
 
368 93 jeremybenn
        default:
369
          printf ("ERROR: run failed\n");
370
          return  1;
371 458 julius
        }
372 93 jeremybenn
    }
373
  while (upcall_count > 0);
374
 
375
  /* A little longer to allow response to last upcall to be handled. */
376
  switch (or1ksim_run (1.0e-3))
377
    {
378
    case OR1KSIM_RC_OK:
379
      printf ("Test completed successfully: All upcalls processed.\n");
380
      return  0;
381
 
382 458 julius
    case OR1KSIM_RC_HALTED:
383
      printf ("Test completed successfully: hit exit l.nop.\n");
384
      return  0;
385
 
386 93 jeremybenn
    case OR1KSIM_RC_BRKPT:
387
      printf ("Test completed successfully: hit breakpoint.\n");
388
      return  0;
389
 
390
    default:
391
      printf ("ERROR: run failed\n");
392
      return  1;
393
    }
394
}       /* main () */

powered by: WebSVN 2.1.0

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