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 93

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
   @note The endianness is specified on the command line, rather than being
217
         read from the or1ksim library, to allow tests for mismatched
218
         assumptions when using the library.
219
 
220
   @param[in] argc  Number of elements in argv
221
   @param[in] argv  Vector of program name and arguments
222
 
223
   @return  Return code for the program.                                     */
224
/* --------------------------------------------------------------------------*/
225
int
226
main (int   argc,
227
      char *argv[])
228
{
229
  char *reg_file;
230
 
231
  /* Parse args */
232
  switch (argc)
233
    {
234
    case 5:
235
      reg_file = NULL;
236
      break;
237
 
238
    case 6:
239
      reg_file = argv[5];
240
      break;
241
 
242
    default:
243
      printf ("usage: lib-upcalls <config-file> <image> "
244
              "<upcall_count> <reg_bytes> [<reg_file>]\n");
245
      return  1;
246
    }
247
 
248
  upcall_count = atoi (argv[3]);
249
 
250
  if (upcall_count <= 0)
251
    {
252
      printf ("ERROR: Upcall count must be positive\n");
253
      return  1;
254
    }
255
 
256
  regc = atoi (argv[4]);
257
 
258
  if (regc < 0)
259
    {
260
      printf ("ERROR: Register memory size must be positive\n");
261
      return  1;
262
    }
263
 
264
  /* Read the register file if provided. */
265
  regv = malloc (regc * sizeof (unsigned char));
266
 
267
  if (NULL == regv)
268
    {
269
      printf ("ERROR: Failed to allocate register memory\n");
270
      return  1;
271
    }
272
 
273
  int  next_free_byte = 0;
274
 
275
  if (NULL != reg_file)
276
    {
277
      FILE *fd = fopen (reg_file, "r");
278
 
279
      if (NULL == fd)
280
        {
281
          printf ("ERROR: Failed to open register file: %s\n",
282
                  strerror (errno));
283
          free (regv);
284
          return  1;
285
        }
286
 
287
      for (; next_free_byte < regc; next_free_byte++)
288
        {
289
          unsigned char  byte;
290
 
291
          if (1 == fscanf (fd, "%2hhx ", &byte))
292
            {
293
              regv[next_free_byte] = byte;
294
            }
295
          else
296
            {
297
              break;
298
            }
299
        }
300
 
301
      /* Should have read the whole file successfully. */
302
      if (ferror (fd))
303
        {
304
          printf ("ERROR: Reading register file: %s\n", strerror (errno));
305
          free (regv);
306
          return  1;
307
        }
308
 
309
      if (!feof (fd))
310
        {
311
          printf ("Warning: additional register file data ignored.\n");
312
        }
313
 
314
      if (0 != fclose (fd))
315
        {
316
          printf ("ERROR: Failed to close register file: %s\n",
317
                  strerror (errno));
318
          free (regv);
319
          return  1;
320
        }
321
    }
322
 
323
  /* Fill in any remaining bytes with zero */
324
  if (next_free_byte < regc)
325
    {
326
      (void)memset (&(regv[next_free_byte]), 0, regc - next_free_byte);
327
    }
328
 
329
  /* Initialize the program. Put the initialization message afterwards, or it
330
     will get swamped by the Or1ksim header. */
331
  if (0 == or1ksim_init (argv[1], argv[2], NULL, &read_upcall, &write_upcall))
332
    {
333
      printf ("Initalization succeeded.\n");
334
    }
335
  else
336
    {
337
      printf ("Initalization failed.\n");
338
      return  1;
339
    }
340
 
341
  /* Run repeatedly for 1 millisecond until we hit a breakpoint or all upcalls
342
     are done. */
343
  do
344
    {
345
      switch (or1ksim_run (1.0e-3))
346
        {
347
        case OR1KSIM_RC_OK:
348
          break;
349
 
350
        case OR1KSIM_RC_BRKPT:
351
          printf ("Test completed successfully: hit breakpoint.\n");
352
          return  0;
353
 
354
        default:
355
          printf ("ERROR: run failed\n");
356
          return  1;
357
        }
358
    }
359
  while (upcall_count > 0);
360
 
361
  /* A little longer to allow response to last upcall to be handled. */
362
  switch (or1ksim_run (1.0e-3))
363
    {
364
    case OR1KSIM_RC_OK:
365
      printf ("Test completed successfully: All upcalls processed.\n");
366
      return  0;
367
 
368
    case OR1KSIM_RC_BRKPT:
369
      printf ("Test completed successfully: hit breakpoint.\n");
370
      return  0;
371
 
372
    default:
373
      printf ("ERROR: run failed\n");
374
      return  1;
375
    }
376
}       /* main () */

powered by: WebSVN 2.1.0

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