;; nos   nut operating system
;;
;;  start                   12 Jan 2005
;;  run a single thread     21 Jan 2005
;;  run multi thread        24 Jan 2005
;;  signal wait, working    27 Jan 2005
;;  send, receive           20 Feb 2005

;;  nos0 a multi thread, no semaphore
;;  update to nut compiler  13 Aug 2006


(def print (x) () (sys 1 x))
(def printc (c) () (sys 2 c))
(def nl () () (sys 2 10))
(def space () () (sys 2 32))
(def not (b) () (if b 0 1))
(def != (a b) () (if (= a b) 0 1))
(def <= (a b) () (if (> a b) 0 1))
(def >= (a b) () (if (< a b) 0 1))
(def or (a b) () (if a 1 b))

;; ---------------------
;; global var

;; activep  the active process
;; status   10 time-out, 11 stopped, 12 blocked
;; pid      number of process created

(let activep status pid)
(let sseg)			;; free stack segment

(enum 10 TIMEOUT STOPPED BLOCKED)

;; ----------------------

;; process descriptor
;;   field:
;;   0 next, 1 prev,             double link
;;   2 id,   3 value,
;;   4 fp,   5 sp,   6 ip,       context
;;   7 inbox, 8 awaitbox, 9 msg  mail box
;;
;;   process state (value) :
;;    1 READY, 2 RUNNING, 3 WAIT, 4 DEAD, 5 SEND, 6 RECEIVE

(enum 1 READY RUNNING WAIT DEAD)

(def ei () () (sys 20))			;; enable int
(def di () () (sys 21))			;; disable int
(def blockp () () (sys 22))		;; block current process

;; doubly linked list
(def getNext (a) () (vec a 0))
(def getPrev (a) () (vec a 1))
(def setNext (a v) () (setv a 0 v))
(def setPrev (a v) () (setv a 1 v))

;; append a2 to the end of a1
(def appendDL (a1 a2) (b)
  (if (= a1 0)
    (do
    (setNext a2 a2)  ;; only one item
    (setPrev a2 a2)
    a2)
    ;; else
    (do
    (set b (getPrev a1))
    (setNext a2 a1)
    (setPrev a1 a2)
    (setNext b a2)
    (setPrev a2 b)
    a1)))

(def deleteDL (b) (a c)
  (if (= b (getNext b))
    0    ;; delete singleton
    ;; else
    (do
    (set a (getPrev b))
    (set c (getNext b))
    (setNext a c)
    (setPrev c a)
    c)))

;; process descriptor access functions
(def getId (p) () (vec p 2))
(def getValue (p) () (vec p 3))
(def setId (p id) () (setv p 2 id))
(def setValue (p v) () (setv p 3 v))

(def newp () (p)
  (do
  (set p (new 10))      ;; new pdes
  (setNext p 0)
  (setPrev p 0)
  (setValue p READY)
  (setv p 4 sseg)  		;; set fp'
  (setv p 5 (+ sseg 1)) ;; set sp'
  (setv p 6 0)     	    ;; set ip'
  (set sseg (+ sseg 1000))
  (setv p 7 0)
  (setv p 8 0)
  p))


;; -------- process management -------

;; show process list a
(def showp (a) (p)
  (do
  (set p a)
  (while (!= p 0)
    (do
    (print (vec p 2)) (space)
    (print (vec p 4)) (space)
    (print (vec p 7)) (space)
    (print (vec p 8)) (space)
    (set p (getNext p))
    (if (= p a) (set p 0))))
  (nl)))

(def wakeup (p) ()
  (do
  (setValue p READY)
  (set activep (appendDL activep p))))

;; return p
(def run (ads) (p)
  (do
  (di)
  (set p (newp))        ;; new pdes
  (setId p pid)
  (set pid (+ pid 1))
  (setv p 6 ads)     	;; set ip' to call.fun
  (set activep (appendDL activep p))
  p
  (ei)))

(def runnable (p) ()
  (do
  (setValue p RUNNING)
  (sys 24 p)))		    ;; restore C-state and ei

;; nos sim is responsible to save C-state
;; before running switchp
(def switchp () (nxt)
  (do
  (di)
  (if (or (= status TIMEOUT) (= status BLOCKED))
    (do
    (set nxt (getNext activep))
    (if (= nxt activep)     ;; one process
      (runnable activep)
      ;; else				;; switch next
      (do
      (setValue activep 1)  ;; READY
      (set activep nxt)
      (runnable nxt))))
    ;; else			    ;; status 11, STOPPED
    (do
    (set activep (deleteDL activep))
    (if (!= activep 0)
      (runnable activep))))
  (ei)))

(def bootnos () ()
  (runnable activep))

;; ----------- application ---------

(def add1 (x) () (print (+ x 1)))

(def main () (p)
  (do
  (di)
  (set activep 0)
  (set sseg 10000)
  (set pid 1)
  (set p (run (add1 10)))
  (bootnos)))

