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 528

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

powered by: WebSVN 2.1.0

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