We can now IPL our Nucleus but if everything works correctly we simply idle waking up each time the Interval Timer expires, look for new work – which will never appear, and then wait again.  To make things a little more interesting we can add additional TCB’s in the TXXDINIT (Dispatcher initialization routine).  It is a pretty simple process.  We simply need to define an additional TCB and RB and then add them onto the TCB chain that begins with the Wait Task TCB.

                            00000    19          USING @RB,R5
                                     20 *
000016 4150 C158      00158          21          LA    R5,RB1
00001A D203 5008 C090 00008 00090    22          MVC   RBPSW(4),=X'FF000000'
000020 4110 C310      00310          23          LA    R1,EXIT
000024 5010 500C      0000C          24          ST    R1,RBPSW+4
000028 4110 C0F8      000F8          25          LA    R1,TCB1
00002C 5010 4000      00000          26          ST    R1,TCBNEXT
000030 1841                          27          LR    R4,R1
000032 D207 4018 5008 00018 00008    28          MVC   TCBPSW,RBPSW
000038 5050 4008      00008          29          ST    R5,TCBRB

We set the initial RB PSW to be enabled for interrupts and then set the instruction address to a routine called EXIT.

000310 0A03                         178 EXIT     SVC   3

The EXIT routine is pretty simple.  We issue a SVC 3.  This should drive our SVC interrupt handler, our SVC 3 routine and our Exit Routine.  If all is well the RB and TCB will be terminated resulting in only the Wait Task remaining.  Although it is not terribly exciting it does test quite a bit of code.

Now we can add another TCB and we will let it issue a Wait SVC to test the associated code.

00003C 4150 C208      00208          31          LA    R5,RB2
000040 D203 5008 C090 00008 00090    32          MVC   RBPSW(4),=X'FF000000'
000046 4110 C308      00308          33          LA    R1,WAIT
00004A 5010 500C      0000C          34          ST    R1,RBPSW+4
00004E 4110 C1A8      001A8          35          LA    R1,TCB2
000052 5010 4000      00000          36          ST    R1,TCBNEXT
000056 1841                          37          LR    R4,R1
000058 D207 4018 5008 00018 00008    38          MVC   TCBPSW,RBPSW
00005E 5050 4008      00008          39          ST    R5,TCBRB

Now we add another TCB and this time our instruction address points to a routine called WAIT.

000308                              172 WAIT     DS    0H
000308 05C0                         173          BALR  R12,0
                            0030A   174          USING *,R12
                                    175 *
00030A 4110 C00A      00314         176          LA    R1,ECB
00030E 0A01                         177          SVC   1
000310 0A03                         178          SVC   3
000314 00000000                     179 ECB      DC    F'0'

The WAIT routine needs to establish a Base Register.  We then point Register 1 to an ECB and issue the SVC call for the Wait SVC.  When we IPL now we should have our previous TCB that terminates leaving the Wait Task and this TCB on the TCB chain.  We then wait forever in our idle loop.  It does serve to test the first half of our Wait routine.

Now we can add a third task that will count down and issue a Post to the ECB.

000062 4150 C2B8      002B8          41          LA    R5,RB3
000066 D203 5008 C090 00008 00090    42          MVC   RBPSW(4),=X'FF000000'
00006C 4110 C318      00318          43          LA    R1,TIMER
000070 5010 500C      0000C          44          ST    R1,RBPSW+4
000074 4110 C258      00258          45          LA    R1,TCB3
000078 5010 4000      00000          46          ST    R1,TCBNEXT
00007C 1841                          47          LR    R4,R1
00007E D207 4018 5008 00018 00008    48          MVC   TCBPSW,RBPSW
000084 5050 4008      00008          49          ST    R5,TCBRB

The PSW for this task points to a routine called TIMER.

000318                              181 TIMER    DS    0H
000318 05C0                         182          BALR  R12,0
                            0031A   183          USING *,R12
00031A 5810 C04A      00364         184          L     R1,TIMECT
00031E 4120 0001      00001         185          LA    R2,1
000322 1B12                         186          SR    R1,R2
000324 1211                         187          LTR   R1,R1
000326 4780 C036      00350         188          BZ    TIMEPOST

The TIMER routine establishes a base register and then loads a counter.  One is subtracted from the value of the counter and it is stored back.  If the value of the counter has gone to zero we branch to Post the ECB.

00032A 5010 C04A      00364         189          ST    R1,TIMECT
00032E 5810 0010      00010         190          L     R1,16              CVT
000332 5810 1000      00000         191          L     R1,CVTCTCB-@CVT(,R1)
000336 50C0 101C      0001C         192          ST    R12,TCBPSW-@TCB+4(,R1)
00033A 50C0 1050      00050         193          ST    R12,TCBREG12-@TCB(,R1)
00033E 5810 0010      00010         194          L     R1,16
000342 5820 1004      00004         195          L     R2,CVTTASKQ-@CVT(,R1)
000346 5020 1000      00000         196          ST    R2,CVTCTCB-@CVT(,R1)
00034A 8200 C046      00360         197          LPSW  TIMEPSW
00034E 07FC                         198          BR    R12

If the counter is not zero we locate the current TCB and store Register 12 into the TCB as both R12 and the PSW instruction address.  This will cause these values to be loaded when the TCB is redispatched.  When then set the Wait Task TCB as the current TCB and load a enabled wait PSW.

000350                              199 TIMEPOST DS    0H
000350 5810 C04E      00368         200          L     R1,=A(ECB)
000354 4100 0000      00000         201          LA    R0,0
000358 0A02                         202          SVC   2
00035A 0A03                         203          SVC   3
000360                              204          DS    0D
000360 FF020000                     205 TIMEPSW  DC    AL1(255,2,0,0)
000364 00001000                     206 TIMECT   DC    A(X'1000')

When the counter goes to zero we issue a Post SVC to post the ECB and then exit via SVC 3.  This should cause our second TCB to become dispatchable.  It should wake up and exit via SVC 3.

Our counter is the address portion of the enabled wait PSW.  This gives us a visual indication on the Hercules console that something is really happening.

We now have the basics of process management implemented in our TXXOS Operating System!

[Next – I/O Management]