mirror of
https://github.com/open-goal/jak-project
synced 2026-08-07 10:16:45 -04:00
156 lines
5.3 KiB
Common Lisp
156 lines
5.3 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
(bundles "ENGINE.CGO" "GAME.CGO")
|
|
(require "engine/ps2/timer-h.gc")
|
|
(require "kernel/gcommon.gc")
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Timer (EE timers)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun timer-reset ((timer timer-bank))
|
|
"Clear an EE hardware timer counter."
|
|
(#when PC_PORT
|
|
;; The host timer cannot be reset, so retain its current value as the new origin.
|
|
(if (= timer TIMER1_BANK) (set! *timer-reset-value* (get-bus-clock/256)) (format 0 "Unknown timer #x~X in timer-reset~%"))
|
|
(return (the uint 0)))
|
|
(#unless PC_PORT
|
|
(sync.l))
|
|
(set! (-> timer count) 0)
|
|
(#unless PC_PORT
|
|
(sync.l)))
|
|
|
|
(defun timer-count ((timer timer-bank))
|
|
"Read an EE hardware timer counter."
|
|
(#when PC_PORT
|
|
(when (= timer TIMER1_BANK)
|
|
(return (- (get-bus-clock/256) *timer-reset-value*)))
|
|
(format 0 "Unknown timer #x~X requested.~%" timer))
|
|
(#unless PC_PORT
|
|
(sync.l))
|
|
(let ((count (-> timer count))) (#unless PC_PORT (sync.l)) count))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Interrupt Control
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; cop0 status register "interrupt enable" flag
|
|
;; if cop0 status is needed anywhere else, move this elsewhere
|
|
(defconstant COP0_STATUS_IE (the-as uint #x1))
|
|
|
|
(#unless PC_PORT
|
|
(defun disable-irq ()
|
|
"Clear the global interrupt-enable bit."
|
|
(rlet ((status :type uint)) (m status Status) (logand! status (lognot COP0_STATUS_IE)) (m Status status) (sync.p))))
|
|
|
|
(#when PC_PORT
|
|
(defun disable-irq ()
|
|
"Clear the global interrupt-enable bit."
|
|
;; These assembly helpers are no-ops because host interrupts are not controlled by EE status.
|
|
(rlet ((status :type uint))
|
|
(.mfc0 status Status)
|
|
(logand! status (lognot COP0_STATUS_IE))
|
|
(.mtc0 Status status)
|
|
(.sync.p))))
|
|
|
|
(#unless PC_PORT
|
|
(defun enable-irq ()
|
|
"Set the global interrupt-enable bit."
|
|
(rlet ((status :type uint)) (m status Status) (logior! status COP0_STATUS_IE) (m Status status) (sync.p))))
|
|
|
|
(#when PC_PORT
|
|
(defun enable-irq ()
|
|
"Set the global interrupt-enable bit."
|
|
;; These assembly helpers are no-ops because host interrupts are not controlled by EE status.
|
|
(rlet ((status :type uint)) (.mfc0 status Status) (logior! status COP0_STATUS_IE) (.mtc0 Status status) (.sync.p))))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Stopwatch (CPU clock cycle counting)
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun stopwatch-init ((watch stopwatch))
|
|
"Initialize an idle stopwatch with no accumulated time."
|
|
(set! (-> watch begin-level) 0)
|
|
(set! (-> watch prev-time-elapsed) 0))
|
|
|
|
(defun stopwatch-reset ((watch stopwatch))
|
|
"Clear accumulated time and restart the current interval when running."
|
|
(set! (-> watch prev-time-elapsed) 0)
|
|
(when (> (-> watch begin-level) 0)
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(set! (-> watch start-time) count))))
|
|
|
|
(defun stopwatch-start ((watch stopwatch))
|
|
"Start an idle stopwatch from zero."
|
|
(when (zero? (-> watch begin-level))
|
|
(set! (-> watch begin-level) 1)
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(set! (-> watch start-time) count))))
|
|
|
|
(defun stopwatch-stop ((watch stopwatch))
|
|
"Stop a running stopwatch and accumulate its current interval."
|
|
(when (> (-> watch begin-level) 0)
|
|
(set! (-> watch begin-level) 0)
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(+! (-> watch prev-time-elapsed) (- count (-> watch start-time)))))
|
|
(none))
|
|
|
|
(defun stopwatch-begin ((watch stopwatch))
|
|
"Enter a nested timed region, starting the stopwatch at the outermost level."
|
|
(when (zero? (-> watch begin-level))
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(set! (-> watch start-time) count)))
|
|
(+! (-> watch begin-level) 1))
|
|
|
|
(defun stopwatch-end ((watch stopwatch))
|
|
"Leave a nested timed region, accumulating time when the outermost level ends.
|
|
Calls must be balanced: ending below level zero prevents later intervals from stopping."
|
|
(+! (-> watch begin-level) -1)
|
|
(when (zero? (-> watch begin-level))
|
|
(set! (-> watch begin-level) 0)
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(+! (-> watch prev-time-elapsed) (- count (-> watch start-time)))))
|
|
(none))
|
|
|
|
(defun stopwatch-elapsed-ticks ((watch stopwatch))
|
|
"Return accumulated CPU cycles, including the current running interval."
|
|
(let ((elapsed (-> watch prev-time-elapsed)))
|
|
(when (> (-> watch begin-level) 0)
|
|
(let ((count 0))
|
|
(#unless PC_PORT
|
|
(m count Count))
|
|
(#when PC_PORT
|
|
(set! count (the int (get-cpu-clock))))
|
|
(+! elapsed (- count (-> watch start-time)))))
|
|
elapsed))
|
|
|
|
(defglobalconstant EE_SECONDS_PER_TICK (/ 1.0 300000000)) ;; 300MHz is a "decent enough" estimate
|
|
|
|
(defmacro cpu-ticks-to-seconds (ticks)
|
|
"Convert 300 MHz EE cycle-counter ticks to seconds."
|
|
`(* ,EE_SECONDS_PER_TICK ,ticks))
|
|
|
|
(defun stopwatch-elapsed-seconds ((watch stopwatch))
|
|
"Return the stopwatch's elapsed CPU time in seconds."
|
|
(cpu-ticks-to-seconds (stopwatch-elapsed-ticks watch)))
|