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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [testsuite/] [test-code-or1k/] [tick/] [tick.c] - Blame information for rev 538

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 90 jeremybenn
/* tick.c. Test of Or1ksim tick timer
2
 
3
   Copyright (C) 2005 György `nog' Jeney <nog@sdf.lonestar.org>
4
   Copyright (C) 2010 Embecosm Limited
5
 
6
   Contributor György `nog' Jeney <nog@sdf.lonestar.org>
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 "spr-defs.h"
29
#include "support.h"
30
 
31 538 julius
/*! Whether to perform spurious interrupt test */
32
#define DO_SPURIOUS_INT_TEST 0
33 90 jeremybenn
 
34
/*! Number of spurious interrupts we'll allow before properly disabling them */
35
#define MAX_SPURIOUS  5
36
 
37
/*! Convenience macro to check that a test has passed */
38
#define ASSERT(x, msg) ((x) ? printf ("Test succeeded %s\n", msg) : fail (msg))
39
 
40
/*! Convenience macro to check that a test has passed, but only print a
41
    message on failure. */
42
#define SILENT_ASSERT(x, msg) ((x) ?  : fail (msg))
43
 
44
/*! Convenience macros for accessing SPRs */
45
#define GET_TTMR() (mfspr (SPR_TTMR))
46
#define SET_TTMR(x) (mtspr (SPR_TTMR, x))
47
#define GET_TTCR() (mfspr (SPR_TTCR))
48
#define SET_TTCR(x) (mtspr (SPR_TTCR, x))
49
 
50
/*! Global count of number of times interrupt handler has been called  */
51
static volatile int tick_cnt = 0;
52
 
53 538 julius
#if DO_SPURIOUS_INT_TEST==1
54 90 jeremybenn
/*! Global flag to indicate if the TTMR_IP flag should be cleared */
55
static int clear_ip = 1;
56 538 julius
#endif
57 90 jeremybenn
 
58
 
59
/* --------------------------------------------------------------------------*/
60
/*!Report failure
61
 
62
  Terminate execution.
63
 
64
  @param[in] msg  Description of test which failed.                          */
65
/* --------------------------------------------------------------------------*/
66
static void
67
fail (char *msg)
68
{
69
  printf ("Test failed: %s\n", msg);
70
  report (0xeeeeeeee);
71
  exit (1);
72
 
73
}       /* fail () */
74
 
75
 
76
/* --------------------------------------------------------------------------*/
77
/*!Set a tick timer mode.
78
 
79
   All other bits and the period are masked
80
 
81
   @param[in] ttmr  The entire TTMR value.
82
   @param[in] mode  The new mode
83
 
84
   @return  The new TTMR with the mode set                                   */
85
/* --------------------------------------------------------------------------*/
86
static unsigned long int
87
set_mode (unsigned long int  ttmr,
88
          unsigned long int  mode)
89
{
90
  ttmr &= ~SPR_TTMR_M;
91
  ttmr |= mode & SPR_TTMR_M;
92
 
93
  return  ttmr;
94
 
95
}       /* set_mode () */
96
 
97
 
98
/* --------------------------------------------------------------------------*/
99
/*!Set a tick timer period.
100
 
101
   All other bits and the period are masked
102
 
103
   @param[in] ttmr    The entire TTMR value.
104
   @param[in] period  The new period
105
 
106
   @return  The new TTMR with the period set                                 */
107
/* --------------------------------------------------------------------------*/
108
static unsigned long int
109
set_period (unsigned long int  ttmr,
110
            unsigned long int  period)
111
{
112 538 julius
  ttmr &= ~SPR_TTMR_TP;
113
  ttmr |= period & SPR_TTMR_TP;
114 90 jeremybenn
 
115
  return  ttmr;
116
 
117
}       /* set_period () */
118
 
119
 
120
/* --------------------------------------------------------------------------*/
121
/*!Clear the mode register
122
 
123
   Period is zeroed, interrupt pending and enabled flags are cleared, disabled
124
   mode is set.
125
 
126
   @note  This function exists to allow for the disabled mode to be explicit,
127
          rather than assumed to be zero.
128
 
129
   @return  The new TTMR                                                     */
130
/* --------------------------------------------------------------------------*/
131
static unsigned long int
132
clear_ttmr ()
133
{
134
  unsigned long int  ttmr = SPR_TTMR_DI;
135
 
136
  SET_TTMR (ttmr);
137
 
138
  return  ttmr;
139
 
140
}       /* clear_ttmr () */
141
 
142
 
143
/* --------------------------------------------------------------------------*/
144
/*!Clear the count register
145
 
146
   Count is zeroed
147
 
148
   @return  The new TTCR                                                     */
149
/* --------------------------------------------------------------------------*/
150
static unsigned long int
151
clear_ttcr ()
152
{
153
  unsigned long int  ttcr = 0;
154
 
155
  SET_TTCR (ttcr);
156
 
157
  return  ttcr;
158
 
159
}       /* clear_ttcr () */
160
 
161
 
162
/* --------------------------------------------------------------------------*/
163
/*!Set a new timer.
164
 
165
   Convenience function for a common sequence
166
 
167
   @param[in] period  The period of the timer
168
   @param[in] mode    The timer mode
169
   @param[in] flags   Any falgs to set (usually IE)
170
 
171
   @return  The new value of TTMR                                            */
172
/* --------------------------------------------------------------------------*/
173
static unsigned long int
174
new_timer (unsigned long int  period,
175
           unsigned long int  mode,
176
           unsigned long int  flags)
177
{
178
  unsigned long int  ttmr;
179
 
180
  ttmr  = 0;
181
  ttmr  = set_period (ttmr, period);
182
  ttmr  = set_mode (ttmr, mode);
183
  ttmr |= flags;
184
 
185
  SET_TTMR (ttmr);
186
 
187
  return  ttmr;
188
 
189
}       /* new_timer () */
190
 
191
 
192
/* --------------------------------------------------------------------------*/
193
/*!Standard tick interrupt handler
194
 
195
  Up the count and clear the interrupt appropriately                        */
196
/* --------------------------------------------------------------------------*/
197
static void
198
tick_int (void)
199
{
200
  unsigned long int  ttmr = mfspr (SPR_TTMR);
201
 
202
  /* Make sure that the tick timer interrupt pending bit is set */
203
  SILENT_ASSERT (0 != (ttmr & SPR_TTMR_IP),
204
                 "IP bit not set in normal interrupt handler");
205
 
206
  /* One more interrupt handled */
207
  tick_cnt++;
208
 
209
  /* Clear interrupt (Write a 0 to SPR_TTMR_IP)
210
 
211
     If we programmed a one-shot timer, make sure to disable the interrupts,
212
     else we'd get a spurious interrupt */
213
  if (SPR_TTMR_SR == (ttmr & SPR_TTMR_M))
214
    {
215
      ttmr &= ~(SPR_TTMR_IP | SPR_TTMR_IE);
216
    }
217
  else
218
    {
219
      ttmr &= ~SPR_TTMR_IP;
220
    }
221
 
222
  mtspr (SPR_TTMR, ttmr);
223
 
224
}       /* tick_count () */
225
 
226
 
227 538 julius
#if DO_SPURIOUS_INT_TEST==1
228 90 jeremybenn
/* --------------------------------------------------------------------------*/
229
/*!Tick interrupt handler generting spurious interrupts
230
 
231
  If we have a one-shot timer set, then when we clear the interrupt (if a
232
  global flag allows), but leave the interrupt enabled we should get a
233
  spurious interrupt.
234
 
235
  Allow this to happen MAX_SPURIOUS times before disabling the interrupt.
236
 
237
  Up the count and clear the interrupt appropriately                        */
238
/* --------------------------------------------------------------------------*/
239
static void
240
tick_int_spurious (void)
241
{
242
  unsigned long int  ttmr = mfspr(SPR_TTMR);
243
 
244
  /* Make sure that the tick timer interrupt pending bit is set */
245
  SILENT_ASSERT (0 != (ttmr & SPR_TTMR_IP),
246
                 "IP bit not set in spurious interrupt handler");
247
 
248
  /* Clear interrupt if global flag allows it (Write a 0 to SPR_TTMR_IP) */
249
  if (clear_ip)
250
    {
251
      ttmr &= ~SPR_TTMR_IP;
252
      mtspr (SPR_TTMR, ttmr);
253
    }
254
 
255
  /* Allow MAX_SPURIOUS spurious spurious interrupt */
256
  if (++tick_cnt == MAX_SPURIOUS)
257
    {
258 458 julius
      /* Clear mode register completely */
259
      ttmr = 0;
260 90 jeremybenn
      mtspr (SPR_TTMR, ttmr);
261 458 julius
 
262
 
263 90 jeremybenn
    }
264
}       /* tick_int_spurious () */
265 538 julius
#endif
266 90 jeremybenn
 
267
/* --------------------------------------------------------------------------*/
268
/*!Waste a little time
269
 
270
  We are waiting for TTCR to increment
271
 
272
  @note This is an entirely arbitrary period. In particular excessive use of
273
  printf in an interrupt handler can tie up cycles and cause TTCR not
274
  to increment in time.                                               */
275
/* --------------------------------------------------------------------------*/
276
static void
277
waste_time (void)
278
{
279
  int          i;
280
  volatile int x;
281
 
282
  for (i = 0; i < 50; i++)
283
    {
284
      x = i;
285
    }
286
}       /* waste_time () */
287
 
288
/* --------------------------------------------------------------------------*/
289
/*!Wait for a tick timer exception
290
 
291
  This occurs when the tick count goes up. Reset the count once the
292
  exception is received.                                                    */
293
/* --------------------------------------------------------------------------*/
294
/* Waits for a tick timer exception */
295
static void
296
wait_match (void)
297
{
298
  while (!tick_cnt)
299
    {
300
    }
301
 
302
  tick_cnt = 0;
303
 
304
}       /* wait_match () */
305
 
306
 
307
/* --------------------------------------------------------------------------*/
308
/*!Main program testing tick timer
309
 
310
  Tests all aspecst of tick timer behavior.
311
 
312
  @return  Return code from the program (always zero).                      */
313
/* --------------------------------------------------------------------------*/
314
int
315
main()
316
{
317
  unsigned long int  ttmr;
318
  unsigned long int  ttcr;
319
 
320
  /* Use normal interrupt handler */
321
  excpt_tick = (unsigned long)tick_int;
322
 
323
  /* Enable tick interrupt */
324
  mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_TEE);
325
 
326
  /* Clear interrupt pending and interrupt enabled, zero the period, set
327
     disabled mode and set count to zero. */
328
  ttmr = clear_ttmr ();
329
  ttcr = clear_ttcr ();
330
 
331
  /* Waste some time to check if the timer is really disabled */
332
  waste_time ();
333
 
334
  /* Timer is disabled and shouldn't count, TTCR should still be 0 */
335
  ttcr = GET_TTCR ();
336
  ASSERT (0 == ttcr, "Tick timer not counting while disabled");
337
 
338
  /* Start timer in continous running mode.  Enable timer interrupt and set
339
   * the period to 0x100 */
340
  ttmr = new_timer (0x100, SPR_TTMR_CR, SPR_TTMR_IE);
341
 
342
  /* Wait for the timer to count up to the match value, get the count
343
     register value. Then waste some time and check that couting has
344
     continued. */
345
  wait_match ();
346
  ttcr = GET_TTCR ();
347
  waste_time();
348
 
349
  /* The timer should have kept counting and our saved TTCR should not be the
350
   * same as the current ttcr */
351
  ASSERT (ttcr < GET_TTCR (),
352
          "Tick timer kept counting during continuous mode");
353
 
354
  /* Clear the mode register flags, zero the period and set disabled
355
     mode. Then get the count register which should be unaffected by this. */
356
  ttmr = clear_ttmr ();
357
  ttcr = GET_TTCR ();
358
 
359
  /* Restart the timer in continous run mode and the counter will keep
360
     going. There should be no interrupts, since we haven't enabled
361
     them. Waste some time to allow the counter to advance. */
362
  ttmr = set_mode (ttmr, SPR_TTMR_CR);
363
  SET_TTMR (ttmr);
364
  waste_time ();
365
 
366
  /* The timer should have carried on from what was SPR_TTCR when we started
367
     it. */
368
  ASSERT (ttcr < GET_TTCR (), "Tick timer continued counting after restart");
369
 
370
  /* Disable the timer and waste some time to check that the count does not
371
     advance */
372
  ttmr = clear_ttmr ();
373
  ttcr = GET_TTCR ();
374
  waste_time ();
375
 
376
  /* Timer should be disabled and should not have counted */
377
  ASSERT(ttcr == GET_TTCR (), "Tick timer counter stops when disabled");
378
 
379
  /* Start in single run mode with a count of 0x100. Run until the match is
380
     hit, then check that the counter does not advance further while wasting
381
     time. */
382
  ttcr = clear_ttcr ();
383
  ttmr = new_timer (0x100, SPR_TTMR_SR, SPR_TTMR_IE);
384
 
385
  wait_match();
386
  ttcr = GET_TTCR ();
387
  waste_time();
388
 
389
  /* The timer should have stoped and the counter advanced no further. */
390
  ASSERT (ttcr == GET_TTCR (), "Timer stopped after match");
391
 
392
  /* The counter should still indicate single run mode */
393
  ttmr = GET_TTMR ();
394
  ASSERT ((ttmr & SPR_TTMR_SR) == SPR_TTMR_SR,
395
          "Timer still indicating one-shot mode after match");
396
 
397
  /* Disable the timer, then start auto-restarting timer every 0x1000 ticks. */
398
  ttmr = clear_ttmr ();
399
  ttcr = clear_ttcr ();
400
  ttmr = new_timer (0x1000, SPR_TTMR_RT, SPR_TTMR_IE);
401
 
402
  /* Wait for two matches, then disable the timer. If this doesn't work the
403
     test will time out, so no ASSERT here. */
404
  wait_match();
405
  ttcr = GET_TTCR ();
406
  wait_match();
407
 
408
  /* Start a one-shot counter but keep interrupts disabled */
409
  ttmr = clear_ttmr ();
410
  ttcr = clear_ttcr ();
411
  ttmr = new_timer (0x100, SPR_TTMR_SR, 0);
412
 
413
  /* Wait for the counter to stop */
414
  while (GET_TTCR () != 0x100)
415
    {
416
    }
417
 
418
  /* Make sure the counter has actually stopped and there have been no more
419
     interrupts (neither tick count nor pending flag. */
420
  waste_time();
421
  ttmr = GET_TTMR ();
422
 
423
  ASSERT (GET_TTCR () == 0x100, "One-shot timer stopped");
424
  ASSERT (tick_cnt == 0, "No more interrupts after one-shot timer");
425
  ASSERT (SPR_TTMR_IP != (ttmr & SPR_TTMR_IP),
426
          "IP flag not set after one-shot timer");
427
 
428
  /* Start a perpetual counter but with no interrupts enabled while it is
429
     still counting. */
430
  ttmr = clear_ttmr ();
431
  ttcr = clear_ttcr ();
432
  ttmr = new_timer (0x100, SPR_TTMR_CR, 0);
433
 
434
  /* Wait until it reaches its count. */
435
  while(GET_TTCR () < 0x100)
436
    {
437
    }
438
 
439
  /* Waste some time and check the counter has carried on past its count and
440
     that there have bee no more interrupts nor interrupts pending. */
441
  waste_time();
442
 
443
  ttmr = GET_TTMR ();
444
  ttcr = GET_TTCR ();
445
 
446
  ASSERT (ttcr > 0x100, "Perptual timer kept counting");
447
  ASSERT (tick_cnt == 0, "No more interrupts during perpetual timer count");
448
  ASSERT (SPR_TTMR_IP != (ttmr & SPR_TTMR_IP),
449
          "IP flag not set during perpetual timer count");
450
 
451
  /* Disable the timer interrupt */
452
  mtspr (SPR_SR, mfspr (SPR_SR) & ~SPR_SR_TEE);
453
 
454
  /* Set a one-shot timer, with the counter started at zero. */
455
  ttmr = clear_ttmr ();
456
  ttcr = clear_ttcr ();
457
  ttmr = new_timer (0x100, SPR_TTMR_SR, SPR_TTMR_IE);
458
 
459
  /* Wait for the interrupt pending bit to be set. */
460
  do
461
    {
462
      ttmr = GET_TTMR ();
463
    }
464
  while (0 == (ttmr & SPR_TTMR_IP));
465
 
466
  /* Give some time for a potential interrupt to occur */
467
  waste_time();
468
 
469
  /* No interrupt should have occured */
470
  ASSERT (tick_cnt == 0, "No interrupt when tick timer disabled");
471
 
472
  /* Enable tick interrupt */
473
  mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_TEE);
474
 
475
  /* Test Setting TTCR while counting. Set a period of 0x3000 but do not
476
     enable interrupts. */
477
  ttmr = clear_ttmr ();
478
  ttcr = clear_ttcr ();
479
  ttmr = new_timer (0x3000, SPR_TTMR_CR, 0);
480
 
481
  /* Wait for the count to reach 10 times our period. */
482
  while (GET_TTCR () < 0x30000)
483
    {
484
    }
485
 
486
  /* Waste some time and then reset the count to 0x50 */
487
  waste_time();
488
  SET_TTCR (0x50);
489
 
490
  /* Verify that after a short wait we have counted to more than 0x50, but
491
     less than 0x30000 */
492
  waste_time();
493
  ttcr = GET_TTCR ();
494
 
495
  ASSERT ((0x50 < ttcr) && (ttcr < 0x30000), "TTCR reset while counting");
496
 
497
  /* Disable the timer. Set the counter to a high value and start a single run
498
     timer with a low timer period. Demonstrate the counter wraps round and
499
     then triggers at the period. Need to reset the tick counter, since there
500
     may have been an interrupt during the previous period. */
501
  ttmr = clear_ttmr ();
502
  ttcr = 0x20000;
503
  SET_TTCR (ttcr);
504
 
505
  ttmr = new_timer (0x100, SPR_TTMR_SR, SPR_TTMR_IE);
506
 
507
  /* The counter should start counting from 0x20000 and wrap around to 0x100
508
   * causeing an interrupt. Check we keep on counting. */
509
  waste_time();
510
  ASSERT (GET_TTCR () > 0x20000, "Timer started counting from high value");
511
 
512 538 julius
  /* If TTCR is greater than TTMR_TP then the interrupt gets delivered after
513
     TTCR wraps around to 0 and counts to SPR_TTMR_TP.
514 90 jeremybenn
 
515
     Set up an auto-restart timer to wrap around. Reset the tick count,
516
     because it may have incremented since the last match. */
517
  ttmr = clear_ttmr ();
518
  ttcr = 0xffffc00;
519
  SET_TTCR (ttcr);
520
 
521
  tick_cnt = 0;
522
  ttmr = new_timer (0x10000, SPR_TTMR_RT, SPR_TTMR_IE);
523
 
524
  /* Wait for the trigger, then check that we have restarted. */
525
  wait_match();
526
  ttcr = GET_TTCR ();
527
 
528
  ASSERT (ttcr < 0x10000, "Auto-restart wrapped round");
529
 
530
  /* Test wrap around in continuous mode. Reset the tick count in case we
531
     have had another interrupt. */
532
  ttmr = clear_ttmr ();
533
  ttcr = 0xffffc00;
534
  SET_TTCR (ttcr);
535
 
536
  tick_cnt = 0;
537
  ttmr = new_timer (0x10000, SPR_TTMR_CR, SPR_TTMR_IE);
538
 
539
  /* Wait for trigger, then check that we have carried on counting. */
540
  wait_match();
541 538 julius
  ttcr = GET_TTCR () & SPR_TTCR_CNT;
542 90 jeremybenn
 
543 538 julius
  ASSERT ((0x00010000 < ttcr) && (ttcr < 0xfffffc00),
544 90 jeremybenn
          "Continuous mode wrapped round");
545
 
546 538 julius
#if DO_SPURIOUS_INT_TEST==1
547
 
548 90 jeremybenn
  /* Disable the timer and set up the special spurious interrupt handler, to
549
     check spurious interrupts occur as expected. */
550
  ttmr = clear_ttmr ();
551
  excpt_tick = (unsigned long)tick_int_spurious;
552
 
553
  /* Set up a disabled timer with a period of 0x100. */
554
  clear_ttcr ();
555
  ttmr = new_timer (0x100, SPR_TTMR_DI, SPR_TTMR_IE);
556
 
557
  /* Set up the count to match the period, and check that spurious interrupts
558
     are generated, even though the timer is disabled. */
559
  ttcr = 0x100;
560
  SET_TTCR (ttcr);
561
 
562
  while(tick_cnt != MAX_SPURIOUS)
563
    {
564
    }
565
 
566
  /* Check the count has not changed */
567
  ttcr = GET_TTCR ();
568
  ASSERT (0x100 == ttcr, "Spurious interrupts handled with matching period");
569
 
570
  /* Reset the tick count, then test setting TTCR first then TTMR */
571
  tick_cnt = 0;
572
  ttcr = 0x101;
573
  SET_TTCR (ttcr);
574
  ttmr = new_timer (0x101, SPR_TTMR_DI, SPR_TTMR_IE);
575
 
576
  while(tick_cnt != MAX_SPURIOUS)
577
    {
578
    }
579
 
580
  ttcr = GET_TTCR ();
581
  ASSERT (0x101 == ttcr, "Spurious interrupts handled after TTCR and TTMR");
582
 
583
  /* Set countinous counter, but make sure we never clear the TTMR_IP bit */
584
  tick_cnt = 0;
585
  clear_ip = 0;
586
 
587 458 julius
  clear_ttcr ();
588 90 jeremybenn
  ttmr = new_timer (0x100, SPR_TTMR_CR, SPR_TTMR_IE);
589
 
590
  while(tick_cnt != MAX_SPURIOUS)
591
    {
592
    }
593
 
594 538 julius
#endif
595
 
596 90 jeremybenn
  /* If we get here everything worked. */
597
  report(0xdeaddead);
598
  return 0;
599
 
600
}       /* main () */
601
 

powered by: WebSVN 2.1.0

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