;;; -*- Mode:LISP; Package:TIMERS; Base:10; Readtable:CL -*-


;;; Code for handling the 1024 and 16384 microsecond interrupts.

(defconstant %%sb-code-timer    (byte 1. 0.))
(defconstant %%sb-code-io       (byte 1. 1.))

(defconstant $$sequence-break    1.)
(defconstant $$no-sequence-break 0.)

(defsubst pulse-timer-interrupt-enable (interrupt-bit)
  ;; Pulsing acknowledges the interrupt.
  (let ((memctl (hw:read-memory-control)))
    (hw:write-memory-control
      (hw:dpb-unboxed hw:$$timer-interrupt-disable-reset
		      interrupt-bit
		      memctl))
    (hw:nop)
    (hw:write-memory-control memctl)
    (hw:nop)
    (hw:nop)
    nil
    ))

;;; We get called with from the trap handler with traps off.
;;; This is a quick routine, and we would waste time by
;;; dealing with turning traps on, adjusting the trap mask,
;;; etc.  Instead, we just blast away.

(defun handle-16384-microsecond-interrupt ()
  ;(trap::illop "Reached 16384 interrupt handler.")
  ;; Reset the interrupt
  (pulse-timer-interrupt-enable hw:%%memory-control-16384-interrupt)
  (update-time 16384.)
  nil)
;  (when (= $$sequence-break (hw:ldb gr::*sequence-break-code* %%sb-code-timer 0.))
;    (update-sequence-break-count))
;  (when (and gr::*request-sequence-break* gr::*allow-sequence-break*)
;    (trap::illop "What exactly is a sequence break?"))
;  )

(defun handle-1024-microsecond-interrupt ()
  ;; Just run one of these at once.
  ;; Reset the interrupt
  (pulse-timer-interrupt-enable hw:%%memory-control-1024-interrupt)
  (update-time 1024.)
  nil)

;;; Sequence break counter.

;;; This counter is set by the user to cause sequence breaks to occur.

(defun reset-sequence-break-count ()
  (setq gr::*ticks-till-next-sequence-break* gr::*ticks-between-sequence-break-requests*))

(defun update-sequence-break-count ()
  (if (< gr::*ticks-till-next-sequence-break* 0)
      (setq gr::*request-sequence-break* t)
      (decf gr::*ticks-till-next-sequence-break*)))

;;; We have a counter that counts down from a million.
;;; Every time we get a timer interrupt, we subtract the
;;; apropriate time in microseconds from the current counter.
;;; When the counter goes negative, about one second has elapsed.
;;; We then add one million to make it positive again.  This keeps
;;; the cumulative error at zero though at any one time, the error
;;; can be up to 1/60 second (or more if traps are off).

(defconstant one-million 1000000.)

(defun update-time (n)
  ;;; This routine is called with traps off (I hope).
;  (trap::illop "Update time.")
  (setq gr::*one-million-count* (- gr::*one-million-count* n))
  (when (minusp gr::*one-million-count*)
;    (trap::illop "Toggle time LED.")
    (setq gr::*one-million-count* (+ gr::*one-million-count* one-million))
    ;; Now increment global time, this will overflow at
    ;; 01:28:15 on February 7, 2036
    ;; I won't have to debug it...
    (setq gr::*elapsed-time-since-1900*
	  (hw:32+ gr::*elapsed-time-since-1900* (hw:unboxed-constant 1.)))
    ;; **debugging** Toggle one of the LEDs
    (hw:write-memory-control
      (hw:dpb-xor 1. hw:%%memory-control-led-0 (hw:read-memory-control)))
    (hw:nop))
    nil)

