license
 
    
    ram_variable %watchfault
    

#BCM550h #BCM550j + [IF]
	: set_timeout_led ( --)
		_lock_word
			_breg_SS1 C@
			_#SS1_processor_fault OR	
			_breg_SS1 C!
		_unlock_word
		TRUE %watchfault !
	;
    
[ELSE]
	: set_timeout_led ( --)
		TRUE %watchfault !
	;
[THEN]

     _create_listhead watchdog_list
   
   
    zero
    DUP    CONSTANT _#watch_link             4+
    DUP    CONSTANT _#watch_delay            2+
    DUP    CONSTANT _#watch_address          4+
    DUP    CONSTANT _#watch_timeout_word     4+
    CONSTANT _#watch_user

    zero
    DUP    CONSTANT _#wdata_last_execution   4+
    DUP    CONSTANT _#wdata_between          4+
    DUP    CONSTANT _#wdata_active           1+
    DUP    CONSTANT _#wdata_fault            1+
    CONSTANT _#watch_localdata
    

	: trigger_clock
		$55 _breg_SWSR C!
		$AA _breg_SWSR C!
	;
	 

We do two tests, we look to see if the code has been executed within the set time. And we look to see if the time between execution ( as last set) is within the delay time. As (watchcheck) is often at a lower priority than the code being looked at we sometimes only get to look at a sub sample of the delay between execution times.

 
    : watchcheck ( -- )
    	watchdog_list
		BEGIN
			@ DUP
		WHILE
			DUP _#watch_address + @                \ list data(--
			\ we don't look until executed once.
			DUP _#wdata_active + C@ IF
				\ If we have timed out once don't bother again.
				DUP _#wdata_fault + C@ not IF      \ list data (--
					\ complain if it hasn't been executed for a while.
					DUP _#wdata_last_execution + @ \ list data last(--
					jump _#watch_delay + W@ +      \ list data timeout_time(--
					xclock- @ + 0> not IF        \ list data(--
						TRUE OVER _#wdata_fault + C!
						set_timeout_led
		  				\ Note we don't stop the system because of a user timeout 
		  				\ that is up to the users routine
    	  				OVER DUP _#watch_timeout_word + @execute  
					ELSE
						\ compalin if the task records execution delays that
						\ are too wide.
						DUP _#wdata_between + @ 
						jump _#watch_delay + W@ > IF
							TRUE OVER _#wdata_fault + C!
							set_timeout_led
							\ Note we don't stop the system because of a user timeout 
		  					\ that is up to the users routine
    	  					OVER DUP _#watch_timeout_word + @execute 
						THEN
					THEN
				THEN
			THEN
			DROP
		REPEAT
		DROP
		trigger_clock
	;
	 

The WATCHDOG words update the data areas. The watchdog task looks at the update values and executes watchdog if the values are not acceptable.

     
    | : watchdog_error ( addr --)
      TRUE OVER _#watch_user + @ C!
      pfa>cfa cfa>nfa
      panic" ?< WATCHDOG " .HEAD SPACE ."  TIMEOUT >?" ;
	 
 
ram_variable %timeout
%timeout #1sec watchdog execution_check
 >

The task that is being checked now has to execute execution_check every second or less. If not the watch_task will time it out. On timeout a panic message will be sent out the front port and %timeout will be set. It is up to other code to take more dastric actions such as bringing the machine to a halt.

Hardware will bring the processor to a helt if the watch_task routine isn't executed eabout very 4 seconds.

 	
	: watchdog ( addr_of_byte_to_set n --)
    	CREATE watchdog_list link_here
    	W, ( maximum time between executions)
    	ram_here , ( Last execution time storage address)
    	['] watchdog_error , 
		, ( address of byte to set)
    	_#watch_localdata ram_allot 
		DOES>
			_#watch_address + @  \ data(-- 
			DUP _#wdata_active + C@ IF
				xclock+ @
				OVER _#wdata_last_execution + @ -
				OVER _#wdata_between + !
				xclock+ @ SWAP _#wdata_last_execution + !
			ELSE
				TRUE OVER _#wdata_active + C!
				xclock+ @ SWAP _#wdata_last_execution + !
			THEN
	;

	: start_watchdog
		[ _#sypcr_watchdog_enable
		_#sypcr_timeout_enable_reset +
		_#sypcr_prescale +
		_#sypcr_swt + ]T LITERAL _breg_SYPCR C!

	;