
// mos in Rz
//  new data structure for process queue
//  update  8 Feb 2025 

Q, qq           // Q process queue, qq points to currentp in Q
nump		// number of active process
currentp	// current process

newp()
  return malloc(16)

newStack()
  return malloc(64)

newFrame()
  return malloc(64)

// function prototype
new(v)
appendL(L,a)

enqueue(p)	      // put p in process queue
  nump = nump + 1
  e = new(p)
  appendL(Q,e)       // add it to the end of queue
  e[1] = Q[0]        // make list circular   

dequeue()	     // dequeue the current process
  nump = nump - 1
  p = currentp
  p[3] = 0           // mark it not-active

createp(ads)
  p = newp()             // new PCB
  p[0] = ads             // p.PC
  p[1] = newStack()+16   // p.SP, offset for initial popm
  p[2] = newFrame()      // p.FP
  p[3] = 1		 // p.state, ready
  enqueue(p)
  return p

nextQ()
  qq = qq[1]      // next
  return qq[0]    // get p

nextp()           // next process from process queue
  p = nextQ()
  while( p[3] == 0 )   // not ready
    p = nextQ()
  return p	     

terminate()          // terminate the current process
  asm("di #0")
  dequeue()
  asm("int #0")     // task switch

// task switch
//    use r1 but it will be restore
//    store state PC,SP,FP in PCB
#noframe
int0()
  asm("di #0")
  asm("trap sp #15")		// save currentp context
  asm("push sp rads")		// save link register
  asm("push sp retval")         // save retval register
  asm("ld r1 currentp")		// save current process
  asm("st r31 @0 r1")		// p.PC = RetAds
  asm("st sp @1 r1")		// p.SP = sp
  asm("st fp @2 r1")		// p.FP = fp
  
  if(nump == 0)
    asm("trap r0 #0")		// no process, stop simulation
  currentp = nextp()		// update currentp

  asm("ld r1 currentp")	        // restore next process
  asm("ld r31 @0 r1")           // restore p.PC
  asm("ld sp @1 r1")   	        // restore p.SP
  asm("ld fp @2 r1")            // restore p.FP
  asm("pop sp retval")          // restore retval
  asm("pop sp rads")            // restore link 
  asm("trap sp #16")		// restore context

boot()
  currentp = newp()    // zeroth process not in Q	
  asm("int #0")	       // run task in Q


// ---- manage list -----

freelist 

new(v)      // get a cell
  if( freelist == 0 )
    a = malloc(2)
  else
    a = freelist
    freelist = a[1]   // next
  a[0] = v 
  a[1] = 0
  return a

free(a)   // free a cell
  a[1] = freelist
  freelist = a

//  single link list with header
//    header[0] points to head of list
//    header[1] points to end of list

appendL(L,a)    	// append list L with cell a
  if( L[0] == 0 )	// empty list
    L[0] = a
  else
    b = L[1]		// L.end
    b[1] = a		// link end to a
  L[1] = a		// update L.end

deleteL(L)		// delete head from L
  a = L[0]		// L.head
  b = L[1]		// L.end
  if( a == b )		// singleton
    L[0] = 0		// empty
    L[1] = 0
  else
    L[0] = a[1]		// update L.head to next
  p = a[0]
  free(a)
  return p

// function prototype
clock1()
clock2()

main()
  asm("di #0")
  nump = 0
  freelist = 0
  Q = malloc(2)        // make a list header
  p = createp(&clock1)
  p = createp(&clock2) 
  qq = Q[0]            // point to Q head
  settimer0(200)
  boot()

// ------------- applications ----------

cnt1, cnt2

clock1()
  cnt1 = 0
  while(1)
    cnt1 = cnt1 + 1
    print(cnt1)
    doze()

clock2()
  cnt2 = 100
  while(1)
    cnt2 = cnt2 + 1
    print(cnt2)
    doze()

// ------------------------------------------

   