s2.1 with interrupt


extension of s21 with interrupt and support instructions

int  xop  23      int r1  (r1 as int number), software int
reti xop  24      return from int
savr xop  25      savr r1 r2  (r1 as sp)
resr xop  26      resr r1 r2  (r1 as sp)


where savr/resr   save/restore registers r0..r15 to stack (M[sp])

interrupt vectore stored at 1000

Here is some example how to write interrupted routines.

Let make one process, do the counting of a global variable "cnt".  The main program is actually an empty loop but it also terminates the program when the count reach 10.  The process is an interrupt service routine (ISR).  When an interrupt occurs, ISR is called and executed to the instruction "reti" then it will return to main.

:main
  mv r1 #isr
  st r1 1000   ;; set up int vector
  mv r1 #0
  st r1 cnt    ;; cnt = 0
:loop
;; this is almost empty loop
  ld r1 cnt
  eq r2 r1 #10
  jf r2 loop
  trap stop

:isr
;; must not use r1
  ld r3 cnt
  add r3 r3 #1
  st r3 cnt
  reti


If the interrupt occurs every n instructions, then the program will take 10*n*(time in irs) instructions before it terminates.

Compare the above program to this plain count to 10 program.

:main
   mv r1 #0
   st r1 cnt
:loop
   ld r1 cnt
   add r1 r1 #1
   st r1 cnt
   eq r2 r1 #10
   jf r2 loop
   trap stop


This program will take 10*(time in loop) instructions to complete.

Now suppose we break the counting routine into two and make it so that 2 interrupts are required to complete one counting. We have to change the interrupt vector dynamically in order to schedule the next instruction when the interrupt occurs. Meanwhile we have to save all registers to make the ISR re-entrant.

:main
   mv r1 #isr1
   st r1 1000   ;; set int vec
   mv r1 #0
   st r1 cnt    ;; cnt = 0
:loop
;;   this is almost empty loop
   ld r1 cnt
   eq r2 r1 #10
   jf r2 loop
   trap stop
 

;;  the counting routine is split into two
:isr1
   ld r3 cnt
   add r3 r3 #1
   savr sp
   mv r3 #isr2
   st r3 1000     ;; change interrupt vector
   reti
:isr2
   resr sp
   st r3 cnt
   mv r3 #isr1
   st r3 1000     ;; change int vec
  reti

Now it will take twice the number of interrupt (of the previous example) to run the program to completion.

Exercise

The above example has just one process.  Make a program with two processes. Let them run concurrently using interrupt.

Task Switching (with interrupt)

It is error prone to schedule multiple processes with interrupt by altering interrupt vector as the above examples.  Now instead of making a process to be an interrupt service routine, we make a task-switcher to be an interrupt service routine that handle the shuffle of the program counter to change to another process every time an interrupt occurs.  The code of a process will be just a normal code.  All work to switch processes is done in one place in the task-switcher. 

:process1
....
...  <-  int1
:L1
....
...  <-  int3

:process2
...
...
... <- int2
:L2
...

:tswitch  (an isr)
   save next PC  (of the current process)
   savr          (of the current process)
   get next process
   resr          (of the next process)
   restore PC    (of the next process)
   reti          (return directly to PC of next process)


The time-line behavior of running process1 and process2 concurrently should be as follow.  Let us begin with process1 running until int-1 occurs.  Then, tswitch is executed. It saves the next PC (L1) of process1, save all registers then change the return-address to process2, restore all registers of the process2, then make a return from interrupt which will jump directly to process2.  The process2 runs until int-2 occurs. The tswitch is called. It will save L2, save all registers of process2, restore all registers of process1, get L1 to return-address, and make a jump to L1.  The process1 continues from L1 until an interrupt int-3 occurs, then tswitch will jump to L2 of process2 and doing all the housekeeping work. etc.  All the shuffling of PC of two processes and saving restoring registers are done in one place in tswitch routine during an interrupt.  This is how we manage concurrent processes.

We need instructions to save/restore the internal return-address register (remember that it is used in int/reti) so that we can manipulate save/restore PC of the process.

savt r1  xop 27   save return-address to r1
rest r1  xop 28   restore ret-ads from r1


We need data structure of each process to keep: its PC, its registers. It is called "stack segment" of each process.  Now, let us code the tswitch.

:tswitch
   savt r3     ;; save current process PC to r3
   savr sp
   mv sp #nextPCB  ;; pointer to data of next process
   resr sp
   rest r3     ;; restore next process PC to return-address
   reti

Code

    counti.txt     count to 10, each interrupt counts 1.
    counti2.txt   count to 10, two interrupts to count 1
    countsw.txt  the interrupt does switch task, show just one task

  last update  15 Apr 2016