]> begriffs open source - cmsis-freertos/blob - Demo/RX600_RX630-RSK_Renesas/RTOSDemo/main-full.c
Updated to FreeRTOS V10.0.1
[cmsis-freertos] / Demo / RX600_RX630-RSK_Renesas / RTOSDemo / main-full.c
1 /*
2  * FreeRTOS Kernel V10.0.1
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /* ****************************************************************************
29  * This project includes a lot of tasks and tests and is therefore complex.
30  * If you would prefer a much simpler project to get started with then select
31  * the 'Blinky' build configuration within the HEW IDE.  The Blinky build
32  * configuration uses main-blinky.c instead of main-full.c.
33  * ****************************************************************************
34  *
35  * Creates all the demo application tasks, then starts the scheduler.  The web
36  * documentation provides more details of the standard demo application tasks,
37  * which provide no particular functionality but do provide a good example of
38  * how to use the FreeRTOS API.  The tasks defined in flop.c are included in the
39  * set of standard demo tasks to ensure the floating point unit gets some
40  * exercise.
41  *
42  * In addition to the standard demo tasks, the following tasks and tests are
43  * defined and/or created within this file:
44  *
45  * "Reg test" tasks - These fill the registers with known values, then 
46  * repeatedly check that each register still contains its expected value for 
47  * the lifetime of the tasks.  Each task uses different values.  The tasks run 
48  * with very low priority so get preempted very frequently.  A check variable 
49  * is incremented on each iteration of the test loop.  A register containing an 
50  * unexpected value is indicative of an error in the context switching 
51  * mechanism and will result in a branch to a null loop - which in turn will 
52  * prevent the check variable from incrementing any further and allow the check 
53  * timer (described below) to determine that an error has occurred.  The nature 
54  * of the reg test tasks necessitates that they are written in assembly code.
55  *
56  * "Check Timer" and Callback Function - The check timer period is initially 
57  * set to five seconds.  The check timer callback function checks that all the 
58  * standard demo tasks are not only still executing, but are executing without 
59  * reporting any errors.  If the check timer discovers that a task has either 
60  * stalled, or reported an error, then it changes its own period from the 
61  * initial five seconds, to just 200ms.  The check timer callback function 
62  * also toggles LED 3 each time it is called.  This provides a visual 
63  * indication of the system status:  If the LED toggles every five seconds, 
64  * then no issues have been discovered.  If the LED toggles every 200ms, then 
65  * an issue has been discovered with at least one task.
66  *
67  * "High frequency timer test" - A high frequency periodic interrupt is
68  * generated using a timer - the interrupt is assigned a priority above
69  * configMAX_SYSCALL_INTERRUPT_PRIORITY, so will not be effected by anything
70  * the kernel is doing.  The frequency and priority of the interrupt, in
71  * combination with other standard tests executed in this demo, will result
72  * in interrupts nesting at least 3 and probably 4 deep.  This test is only
73  * included in build configurations that have the optimiser switched on.
74  *
75  * *NOTE 1* If LED3 is toggling every 5 seconds then all the demo application
76  * tasks are executing as expected and no errors have been reported in any
77  * tasks.  The toggle rate increasing to 200ms indicates that at least one task
78  * has reported unexpected behaviour.
79  *
80  * *NOTE 2* vApplicationSetupTimerInterrupt() is called by the kernel to let
81  * the application set up a timer to generate the tick interrupt.  In this
82  * example a compare match timer is used for this purpose.
83  *
84  * *NOTE 3* The CPU must be in Supervisor mode when the scheduler is started.
85  * The PowerON_Reset_PC() supplied in resetprg.c with this demo has
86  * Change_PSW_PM_to_UserMode() commented out to ensure this is the case.
87  *
88  * *NOTE 4* The IntQueue common demo tasks test interrupt nesting and make use
89  * of all the 8bit timers (as two cascaded 16bit units).
90 */
91
92 /* Hardware specific includes. */
93 #include "iodefine.h"
94
95 /* Kernel includes. */
96 #include "FreeRTOS.h"
97 #include "task.h"
98 #include "timers.h"
99 #include "semphr.h"
100
101 /* Standard demo includes. */
102 #include "partest.h"
103 #include "flash.h"
104 #include "IntQueue.h"
105 #include "BlockQ.h"
106 #include "death.h"
107 #include "integer.h"
108 #include "blocktim.h"
109 #include "semtest.h"
110 #include "PollQ.h"
111 #include "GenQTest.h"
112 #include "QPeek.h"
113 #include "recmutex.h"
114 #include "flop.h"
115
116 /* Values that are passed into the reg test tasks using the task parameter.  The
117 tasks check that the values are passed in correctly. */
118 #define mainREG_TEST_1_PARAMETER        ( 0x12121212UL )
119 #define mainREG_TEST_2_PARAMETER        ( 0x12345678UL )
120
121 /* Priorities at which the tasks are created. */
122 #define mainQUEUE_POLL_PRIORITY         ( tskIDLE_PRIORITY + 1 )
123 #define mainSEM_TEST_PRIORITY           ( tskIDLE_PRIORITY + 1 )
124 #define mainBLOCK_Q_PRIORITY            ( tskIDLE_PRIORITY + 2 )
125 #define mainCREATOR_TASK_PRIORITY   ( tskIDLE_PRIORITY + 3 )
126 #define mainFLASH_TASK_PRIORITY         ( tskIDLE_PRIORITY + 1 )
127 #define mainINTEGER_TASK_PRIORITY   ( tskIDLE_PRIORITY )
128 #define mainGEN_QUEUE_TASK_PRIORITY     ( tskIDLE_PRIORITY )
129 #define mainFLOP_TASK_PRIORITY          ( tskIDLE_PRIORITY )
130
131 /* The LED toggled by the check timer. */
132 #define mainCHECK_LED                           ( 3 )
133
134 /* The period at which the check timer will expire, in ms, provided no errors
135 have been reported by any of the standard demo tasks.  ms are converted to the
136 equivalent in ticks using the portTICK_PERIOD_MS constant. */
137 #define mainCHECK_TIMER_PERIOD_MS                       ( 5000UL / portTICK_PERIOD_MS )
138
139 /* The period at which the check timer will expire, in ms, if an error has been
140 reported in one of the standard demo tasks.  ms are converted to the equivalent
141 in ticks using the portTICK_PERIOD_MS constant. */
142 #define mainERROR_CHECK_TIMER_PERIOD_MS         ( 200UL / portTICK_PERIOD_MS )
143
144 /* A block time of zero simple means "Don't Block". */
145 #define mainDONT_BLOCK                          ( 0UL )
146
147 /*
148  * vApplicationMallocFailedHook() will only be called if
149  * configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
150  * function that will execute if a call to pvPortMalloc() fails.
151  * pvPortMalloc() is called internally by the kernel whenever a task, queue or
152  * semaphore is created.  It is also called by various parts of the demo
153  * application.
154  */
155 void vApplicationMallocFailedHook( void );
156
157 /*
158  * vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1
159  * in FreeRTOSConfig.h.  It is a hook function that is called on each iteration
160  * of the idle task.  It is essential that code added to this hook function
161  * never attempts to block in any way (for example, call xQueueReceive() with
162  * a block time specified).  If the application makes use of the vTaskDelete()
163  * API function (as this demo application does) then it is also important that
164  * vApplicationIdleHook() is permitted to return to its calling function because
165  * it is the responsibility of the idle task to clean up memory allocated by the
166  * kernel to any task that has since been deleted.
167  */
168 void vApplicationIdleHook( void );
169
170 /*
171  * vApplicationStackOverflowHook() will only be called if
172  * configCHECK_FOR_STACK_OVERFLOW is set to a non-zero value.  The handle and
173  * name of the offending task should be passed in the function parameters, but
174  * it is possible that the stack overflow will have corrupted these - in which
175  * case pxCurrentTCB can be inspected to find the same information.
176  */
177 void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );
178
179 /*
180  * The reg test tasks as described at the top of this file.
181  */
182 static void prvRegTest1Task( void *pvParameters );
183 static void prvRegTest2Task( void *pvParameters );
184
185 /*
186  * The actual implementation of the reg test functionality, which, because of
187  * the direct register access, have to be in assembly.
188  */
189 static void prvRegTest1Implementation( void );
190 static void prvRegTest2Implementation( void );
191
192 /*
193  * The check timer callback function, as described at the top of this file.
194  */
195 static void prvCheckTimerCallback( TimerHandle_t xTimer );
196
197
198 /*-----------------------------------------------------------*/
199
200 /* Variables that are incremented on each iteration of the reg test tasks -
201 provided the tasks have not reported any errors.  The check timer inspects these
202 variables to ensure they are still incrementing as expected.  If a variable
203 stops incrementing then it is likely that its associate task has stalled. */
204 unsigned long ulRegTest1CycleCount = 0UL, ulRegTest2CycleCount = 0UL;
205
206 /* The check timer.  This uses prvCheckTimerCallback() as its callback
207 function. */
208 static TimerHandle_t xCheckTimer = NULL;
209
210 /*-----------------------------------------------------------*/
211
212 void main(void)
213 {
214 extern void HardwareSetup( void );
215
216         /* Renesas provided CPU configuration routine.  The clocks are configured in
217         here. */
218         HardwareSetup();
219
220         /* Turn all LEDs off. */
221         vParTestInitialise();
222
223         /* Start the reg test tasks which test the context switching mechanism. */
224         xTaskCreate( prvRegTest1Task, "RegTst1", configMINIMAL_STACK_SIZE, ( void * ) mainREG_TEST_1_PARAMETER, tskIDLE_PRIORITY, NULL );
225         xTaskCreate( prvRegTest2Task, "RegTst2", configMINIMAL_STACK_SIZE, ( void * ) mainREG_TEST_2_PARAMETER, tskIDLE_PRIORITY, NULL );
226
227         /* Create the standard demo tasks. */
228         vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
229         vCreateBlockTimeTasks();
230         vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
231         vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
232         vStartIntegerMathTasks( mainINTEGER_TASK_PRIORITY );
233         vStartGenericQueueTasks( mainGEN_QUEUE_TASK_PRIORITY );
234         vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );
235         vStartQueuePeekTasks();
236         vStartRecursiveMutexTasks();
237         vStartInterruptQueueTasks();
238         vStartMathTasks( mainFLOP_TASK_PRIORITY );
239
240         /* The suicide tasks must be created last as they need to know how many
241         tasks were running prior to their creation in order to ascertain whether
242         or not the correct/expected number of tasks are running at any given time. */
243         vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );
244
245         /* Create the software timer that performs the 'check' functionality,
246         as described at the top of this file. */
247         xCheckTimer = xTimerCreate( "CheckTimer",/* A text name, purely to help debugging. */
248                                                                 ( mainCHECK_TIMER_PERIOD_MS ),          /* The timer period, in this case 5000ms (5s). */
249                                                                 pdTRUE,                                                         /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
250                                                                 ( void * ) 0,                                           /* The ID is not used, so can be set to anything. */
251                                                                 prvCheckTimerCallback                           /* The callback function that inspects the status of all the other tasks. */
252                                                           );
253                                                           
254         /* Sanity check that the check timer was indeed created. */
255         configASSERT( xCheckTimer );
256         
257         /* Start the check timer.  It will actually start when the scheduler is
258         started. */
259         xTimerStart( xCheckTimer, mainDONT_BLOCK );
260
261         /* Start the tasks running. */
262         vTaskStartScheduler();
263
264         /* If all is well, the following line will never be reached as the scheduler 
265         will be running.  If the following line is reached, there was insufficient
266         FreeRTOS heap available for the idle task to be created.  See
267         http://www.freertos.org/a00111.html and the malloc failed hook function for
268         more information. */
269         for( ;; );
270 }
271 /*-----------------------------------------------------------*/
272
273 static void prvCheckTimerCallback( TimerHandle_t xTimer )
274 {
275 static long lChangedTimerPeriodAlready = pdFALSE, lErrorStatus = pdPASS;
276 static volatile unsigned long ulLastRegTest1CycleCount = 0UL, ulLastRegTest2CycleCount = 0UL;
277
278         /* Check the standard demo tasks are running without error. */
279         if( xAreGenericQueueTasksStillRunning() != pdTRUE )
280         {
281                 lErrorStatus = pdFAIL;
282         }
283         else if( xAreQueuePeekTasksStillRunning() != pdTRUE )
284         {
285                 lErrorStatus = pdFAIL;
286         }
287         else if( xAreBlockingQueuesStillRunning() != pdTRUE )
288         {
289                 lErrorStatus = pdFAIL;
290         }
291         else if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
292         {
293                 lErrorStatus = pdFAIL;
294         }
295         else if( xAreSemaphoreTasksStillRunning() != pdTRUE )
296         {
297                 lErrorStatus = pdFAIL;
298         }
299         else if( xArePollingQueuesStillRunning() != pdTRUE )
300         {
301                 lErrorStatus = pdFAIL;
302         }
303         else if( xIsCreateTaskStillRunning() != pdTRUE )
304         {
305                 lErrorStatus = pdFAIL;
306         }
307         else if( xAreIntegerMathsTaskStillRunning() != pdTRUE )
308         {
309                 lErrorStatus = pdFAIL;
310         }
311         else if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
312         {
313                 lErrorStatus = pdFAIL;
314         }
315         else if( xAreIntQueueTasksStillRunning() != pdPASS )
316         {
317                 lErrorStatus = pdFAIL;
318         }
319         else if( xAreMathsTaskStillRunning() != pdPASS )
320         {
321                 lErrorStatus = pdFAIL;
322         }
323
324         /* Check the reg test tasks are still cycling.  They will stop incrementing
325         their loop counters if they encounter an error. */
326         if( ulRegTest1CycleCount == ulLastRegTest1CycleCount )
327         {
328                 lErrorStatus = pdFAIL;
329         }
330
331         if( ulRegTest2CycleCount == ulLastRegTest2CycleCount )
332         {
333                 lErrorStatus = pdFAIL;
334         }
335
336         ulLastRegTest1CycleCount = ulRegTest1CycleCount;
337         ulLastRegTest2CycleCount = ulRegTest2CycleCount;
338
339         /* Toggle the check LED to give an indication of the system status.  If
340         the LED toggles every 5 seconds then everything is ok.  A faster toggle
341         indicates an error. */
342         vParTestToggleLED( mainCHECK_LED );
343         
344         /* Was an error detected this time through the callback execution? */
345         if( lErrorStatus != pdPASS )
346         {
347                 if( lChangedTimerPeriodAlready == pdFALSE )
348                 {
349                         lChangedTimerPeriodAlready = pdTRUE;
350                         
351                         /* This call to xTimerChangePeriod() uses a zero block time.  
352                         Functions called from inside of a timer callback function must 
353                         *never* attempt to block. */
354                         xTimerChangePeriod( xCheckTimer, ( mainERROR_CHECK_TIMER_PERIOD_MS ), mainDONT_BLOCK );
355                 }
356         }
357 }
358 /*-----------------------------------------------------------*/
359
360 /* The RX port uses this callback function to configure its tick interrupt.
361 This allows the application to choose the tick interrupt source. */
362 void vApplicationSetupTimerInterrupt( void )
363 {
364         /* Enable compare match timer 0. */
365         MSTP( CMT0 ) = 0;
366
367         /* Interrupt on compare match. */
368         CMT0.CMCR.BIT.CMIE = 1;
369
370         /* Set the compare match value. */
371         CMT0.CMCOR = ( unsigned short ) ( ( ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ ) -1 ) / 8 );
372
373         /* Divide the PCLK by 8. */
374         CMT0.CMCR.BIT.CKS = 0;
375
376         /* Enable the interrupt... */
377         _IEN( _CMT0_CMI0 ) = 1;
378
379         /* ...and set its priority to the application defined kernel priority. */
380         _IPR( _CMT0_CMI0 ) = configKERNEL_INTERRUPT_PRIORITY;
381
382         /* Start the timer. */
383         CMT.CMSTR0.BIT.STR0 = 1;
384 }
385 /*-----------------------------------------------------------*/
386
387 /* This function is explained by the comments above its prototype at the top
388 of this file. */
389 void vApplicationMallocFailedHook( void )
390 {
391         for( ;; );
392 }
393 /*-----------------------------------------------------------*/
394
395 /* This function is explained by the comments above its prototype at the top
396 of this file. */
397 void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
398 {
399         for( ;; );
400 }
401 /*-----------------------------------------------------------*/
402
403 /* This function is explained by the comments above its prototype at the top
404 of this file. */
405 void vApplicationIdleHook( void )
406 {
407         /* If this is being executed then the kernel has been started.  Start the high
408         frequency timer test as described at the top of this file.  This is only
409         included in the optimised build configuration - otherwise it takes up too much
410         CPU time and can disrupt other tests. */
411         #ifdef INCLUDE_HIGH_FREQUENCY_TIMER_TEST
412         static portBASE_TYPE xTimerTestStarted = pdFALSE;
413         extern void vSetupHighFrequencyTimer( void );
414                 if( xTimerTestStarted == pdFALSE )
415                 {
416                         vSetupHighFrequencyTimer();
417                         xTimerTestStarted = pdTRUE;
418                 }
419         #endif
420 }
421 /*-----------------------------------------------------------*/
422
423 /* This function is explained in the comments at the top of this file. */
424 static void prvRegTest1Task( void *pvParameters )
425 {
426         if( ( ( unsigned long ) pvParameters ) != mainREG_TEST_1_PARAMETER )
427         {
428                 /* The parameter did not contain the expected value. */
429                 for( ;; )
430                 {
431                         /* Stop the tick interrupt so its obvious something has gone wrong. */
432                         taskDISABLE_INTERRUPTS();
433                 }
434         }
435
436         /* This is an inline asm function that never returns. */
437         prvRegTest1Implementation();
438 }
439 /*-----------------------------------------------------------*/
440
441 /* This function is explained in the comments at the top of this file. */
442 static void prvRegTest2Task( void *pvParameters )
443 {
444         if( ( ( unsigned long ) pvParameters ) != mainREG_TEST_2_PARAMETER )
445         {
446                 /* The parameter did not contain the expected value. */
447                 for( ;; )
448                 {
449                         /* Stop the tick interrupt so its obvious something has gone wrong. */
450                         taskDISABLE_INTERRUPTS();
451                 }
452         }
453
454         /* This is an inline asm function that never returns. */
455         prvRegTest2Implementation();
456 }
457 /*-----------------------------------------------------------*/
458
459 /* This function is explained in the comments at the top of this file. */
460 #pragma inline_asm prvRegTest1Implementation
461 static void prvRegTest1Implementation( void )
462 {
463         ; Put a known value in each register.
464         MOV.L   #1, R1
465         MOV.L   #2, R2
466         MOV.L   #3, R3
467         MOV.L   #4, R4
468         MOV.L   #5, R5
469         MOV.L   #6, R6
470         MOV.L   #7, R7
471         MOV.L   #8, R8
472         MOV.L   #9, R9
473         MOV.L   #10, R10
474         MOV.L   #11, R11
475         MOV.L   #12, R12
476         MOV.L   #13, R13
477         MOV.L   #14, R14
478         MOV.L   #15, R15
479
480         ; Loop, checking each iteration that each register still contains the
481         ; expected value.
482 TestLoop1:
483
484         ; Push the registers that are going to get clobbered.
485         PUSHM   R14-R15
486
487         ; Increment the loop counter to show this task is still getting CPU time.
488         MOV.L   #_ulRegTest1CycleCount, R14
489         MOV.L   [ R14 ], R15
490         ADD             #1, R15
491         MOV.L   R15, [ R14 ]
492
493         ; Yield to extend the text coverage.  Set the bit in the ITU SWINTR register.
494         MOV.L   #1, R14
495         MOV.L   #0872E0H, R15
496         MOV.B   R14, [R15]
497         NOP
498         NOP
499
500         ; Restore the clobbered registers.
501         POPM    R14-R15
502
503         ; Now compare each register to ensure it still contains the value that was
504         ; set before this loop was entered.
505         CMP             #1, R1
506         BNE             RegTest1Error
507         CMP             #2, R2
508         BNE             RegTest1Error
509         CMP             #3, R3
510         BNE             RegTest1Error
511         CMP             #4, R4
512         BNE             RegTest1Error
513         CMP             #5, R5
514         BNE             RegTest1Error
515         CMP             #6, R6
516         BNE             RegTest1Error
517         CMP             #7, R7
518         BNE             RegTest1Error
519         CMP             #8, R8
520         BNE             RegTest1Error
521         CMP             #9, R9
522         BNE             RegTest1Error
523         CMP             #10, R10
524         BNE             RegTest1Error
525         CMP             #11, R11
526         BNE             RegTest1Error
527         CMP             #12, R12
528         BNE             RegTest1Error
529         CMP             #13, R13
530         BNE             RegTest1Error
531         CMP             #14, R14
532         BNE             RegTest1Error
533         CMP             #15, R15
534         BNE             RegTest1Error
535
536         ; All comparisons passed, start a new itteratio of this loop.
537         BRA             TestLoop1
538
539 RegTest1Error:
540         ; A compare failed, just loop here so the loop counter stops incrementing
541         ; causing the check timer to indicate the error.
542         BRA RegTest1Error
543 }
544 /*-----------------------------------------------------------*/
545
546 /* This function is explained in the comments at the top of this file. */
547 #pragma inline_asm prvRegTest2Implementation
548 static void prvRegTest2Implementation( void )
549 {
550         ; Put a known value in each register.
551         MOV.L   #10, R1
552         MOV.L   #20, R2
553         MOV.L   #30, R3
554         MOV.L   #40, R4
555         MOV.L   #50, R5
556         MOV.L   #60, R6
557         MOV.L   #70, R7
558         MOV.L   #80, R8
559         MOV.L   #90, R9
560         MOV.L   #100, R10
561         MOV.L   #110, R11
562         MOV.L   #120, R12
563         MOV.L   #130, R13
564         MOV.L   #140, R14
565         MOV.L   #150, R15
566
567         ; Loop, checking on each iteration that each register still contains the
568         ; expected value.
569 TestLoop2:
570
571         ; Push the registers that are going to get clobbered.
572         PUSHM   R14-R15
573
574         ; Increment the loop counter to show this task is still getting CPU time.
575         MOV.L   #_ulRegTest2CycleCount, R14
576         MOV.L   [ R14 ], R15
577         ADD             #1, R15
578         MOV.L   R15, [ R14 ]
579
580         ; Restore the clobbered registers.
581         POPM    R14-R15
582
583         CMP             #10, R1
584         BNE             RegTest2Error
585         CMP             #20, R2
586         BNE             RegTest2Error
587         CMP             #30, R3
588         BNE             RegTest2Error
589         CMP             #40, R4
590         BNE             RegTest2Error
591         CMP             #50, R5
592         BNE             RegTest2Error
593         CMP             #60, R6
594         BNE             RegTest2Error
595         CMP             #70, R7
596         BNE             RegTest2Error
597         CMP             #80, R8
598         BNE             RegTest2Error
599         CMP             #90, R9
600         BNE             RegTest2Error
601         CMP             #100, R10
602         BNE             RegTest2Error
603         CMP             #110, R11
604         BNE             RegTest2Error
605         CMP             #120, R12
606         BNE             RegTest2Error
607         CMP             #130, R13
608         BNE             RegTest2Error
609         CMP             #140, R14
610         BNE             RegTest2Error
611         CMP             #150, R15
612         BNE             RegTest2Error
613
614         ; All comparisons passed, start a new itteratio of this loop.
615         BRA             TestLoop2
616
617 RegTest2Error:
618         ; A compare failed, just loop here so the loop counter stops incrementing
619         ; - causing the check timer to indicate the error.
620         BRA RegTest2Error
621 }
622 /*-----------------------------------------------------------*/
623