Adding Some (Useful) Work To TXXDINIT

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]

TXXGMAIN, TXXFMAIN and TXXABEND

For now we just need something very simple for Getmain, Freemain and Abend processing.  This code will need to be updated but this will allow us to IPL and do some initial testing.

000000                                1 TXXGMAIN CSECT ,
                            00000     2          USING TXXGMAIN,R15
                                      3 *
000000 5410 F030      00030           4          N     R1,=A(X'00FFFFFF')   CLEAN UP LENGTH
000004 4110 1007      00007           5          LA    R1,7(,R1)            ROUND UP TO DOUBLE WORD
000008 5410 F034      00034           6          N     R1,=A(X'00FFFFF8')
                                      7 *
00000C 5800 F01C      0001C           8          L     R0,COREPTR
000010 1B01                           9          SR    R0,R1
000012 1810                          10          LR    R1,R0
000014 5010 F01C      0001C          11          ST    R1,COREPTR
000018 1FFF                          12          SLR   R15,R15
00001A 07FE                          13          BR    R14
                                     14 *
00001C 00100000                      16 COREPTR  DC    A(1024*1024)       1M

Getmain will round the requested length up to a double word value.  For now we will simply start at the 1 Meg mark and work backwards.  No attempt will be made to reuse memory when it is released via a Freemain.  This will allow us to IPL and run for a little while before we eventually start overlaying or Nucleus code.

000000                                1 TXXFMAIN CSECT ,
                            00000     2          USING TXXFMAIN,R15
000000 07FE                           3          BR    R14                RETURN TO CALLER

The Freemain routine is very simple.  It simply returns to the caller.

000000                                1 TXXABEND CSECT ,
                            00000     2          USING TXXABEND,R15
000000 8200 F008      00008           3          LPSW  ERRPSW
000008                                4          DS    0D
000008 00020000000BAD01               5 ERRPSW   DC    AL1(0,2,0,0),A(X'BAD01')

The Abend routine will simply load a wait state PSW.

Although the code in these routines is not very robust it now gives us everything we need to link edit the Nucleus and IPL.

[Next – Adding Some (Useful) Work To TXXDINIT]

TXXPOST – Post Routine

On entry to the P0st Routine Register 1 should point to an ECB and Register 0 contains a post code that is stored into the ECB.  The Post Routine is either called by the SVC 2 front end or directly through a branch entry.

000000                               13 TXXPOST  CSECT ,
                            00000    14          USING TXXPOST,R15        ESTABLISH BASE REGISTER
                                     15 *
000000 5400 F080      00080          16          N     R0,=A(X'3FFFFFFF') CLEAR WAIT/POST BITS
000004 5600 F084      00084          17          O     R0,=A(X'40000000') SET POST BIT
000008 5820 1000      00000          18          L     R2,0(,R1)          GET RB ADDRESS
                                     19 *
00000C 9180 1000      00000          20          TM    0(R1),X'80'        IS ECB WAITING
000010 47E0 F064      00000          21          BNO   POST901             NO - BRANCH

First we clean up the post code since the first two bits are reserved for the Wait and Post bit.  We then set the Post Bit (x’40’) to complete the post code.  The RB address pointer is loaded into R2 and then a test is done to see if a RB is waiting on the ECB.  If no RB is currently waiting we only need to store the post code into the ECB and exit.

000014 5000 1000      00000          23          ST    R0,0(,R1)          UPDATE ECB CONTENTS
000018 5420 F088      00088          24          N     R2,=A(X'00FFFFFF')  CLEAN UP 24 BIT
00001C 5810 0010      00010          25          L     R1,16              CVT
000020 5810 1004      00004          26          L     R1,CVTTASKQ-@CVT(,R1)  GET TASK QUEUE
000024 5810 1000      00000          27          L     R1,TCBNEXT-@TCB(,R1)   SKIP OVER WAIT TASK
000028                               28 POST010  DS    0H
000028 1211                          29          LTR   R1,R1                  END OF TCB CHAIN ?
00002A 4780 F06A      0006A          30          BZ    POST902                  YES - RB TO POST NOT FOUND
00002E 5830 1008      00008          31          L     R3,TCBRB-@TCB(,R1)     GET RB ADDRESS
000032                               32 POST020  DS    0H
000032 1233                          33          LTR   R3,R3                  END OF RB LIST
000034 4780 F046      00046          34          BZ    POST030                  YES - NEXT TCB
                                     35 *
000038 1923                          36          CR    R2,R3                  RB TO POST ?
00003A 4780 F04E      0004E          37          BE    POST040                  YES - GO POST IT
                                     38 *
00003E 5830 3000      00000          39          L     R3,RBNEXT-@RB(,R3)     NEXT RB
000042 47F0 F032      00032          40          B     POST020                   AND LOOP BACK
                                     41 *
000046                               43 POST030  DS    0H
000046 5810 1000      00000          44          L     R1,TCBNEXT-@TCB(,R1)   NEXT TCB
00004A 47F0 F028      00028          45          B     POST010                   AND LOOP BACK

If there is a RB waiting on the ECB we need to validate the RB address.  We do this by scanning through the TCB chain looking at each RB chained to each TCB.  If the RB address in the ECB is not matched to a RB chained to a TCB we branch to generate an Abend.

00004E                               48 POST040  DS    0H
00004E 9200 3004      00004          49          MVI   RBWTCNT-@RB(R3),0  CLEAR WAIT COUNT FOR RB
                                     50 *
000052 5830 1008      00008          51          L     R3,TCBRB-@TCB(,R1)  POINT TO TOP RB FOR TCB
000056 9500 3004      00004          52          CLI   RBWTCNT-@RB(R3),0   WAITING ?
00005A 4770 F062      00062          53          BNE   POST050               YES - NOTHING TO UPDATE
                                     54 *
00005E 947F 1004      00004          55          NI    TCBFLGS-@TCB(R1),X'FF'-TCBFWAIT  CLEAR WAIT FLAG
                                     56 *
000062                               57 POST050  DS    0H
000062 07FE                          58          BR    R14                 RETURN TO CALLER

Once the RB address is validated we can clear the Wait Count in the RB.  If the RB at the top of the chain we can clear the Wait Flag in the TCB making it dispatchable one again.

000064                               62 POST060  DS    0H
000064 5000 1000      00000          63          ST    R0,0(,R1)          UPDATE ECB CONTENTS
000068 07FE                          64          BR    R14                 RETURN TO CALLER

The ECB is not currently being waited upon so we just store the post code and exit.

00006A                               66 POST902  DS    0H
00006A 5810 F08C      0008C          67          L     R1,=A(X'102')       ABEND CODE
00006E 47F0 F072      00072          68          B     POST999
                                     69 *
000072                               71 POST999  DS    0H
                                     72          @CALL ABEND
000072 58F0 0014      00014          73+         L     R15,20             MVT ADDRESS
000076 58F0 F020      00020          74+         L     R15,MVTABEND-@MVT(,R15) ROUTINE ADDRESS
00007A 05EF                          75+         BALR  R14,R15

Here we set the Abend code and call the Abend routine if the RB address in the ECB was not valid.

[Next – TXXGMAIN, GXXFMAIN, TXXABEND]

SVC 2 – Post

The Post SVC (SVC 2) is simply a front end that calls the Branch Entry Post Routine and then exits.

000000                               12 S002POST CSECT ,
000000 18CF                          13          LR    R12,R15            ESTABLISH
                            00000    14          USING S002POST,R12                BASE REGISTER
                                     15 *
                            00000    16          USING @TCB,R4
                            00000    17          USING @RB,R5
                                     18 *
                                     19          @CALL POST               CALL POST BRANCH ENTRY
000002 58F0 0014      00014          20+         L     R15,20             MVT ADDRESS
000006 58F0 F028      00028          21+         L     R15,MVTPOST-@MVT(,R15) ROUTINE ADDRESS
00000A 05EF                          22+         BALR  R14,R15
                                     23 *
00000C 58F0 0014      00014          25          L     R15,20              MVT ADDRESS
000010 58F0 F024      00024          26          L     R15,MVTEXIT-@MVT(,R15)   EXIT ROUTINE
000014 07FF                          27          BR    R15

[Next – TXXPOST – Post Routine]

SVC 1 – Wait

There is not branch entry for Wait.  It is only entered through a SVC call.  On entry R4 is the address of the TCB and R5 is the address of the current RB which is always true for any SVC routine.  Register 1 is a pointer to either an ECB or a list of ECB’s.  If the high order bit of R1 is zero it is the address of a single ECB.  If the high order bit is one then it is the address of a list of pointers to ECB’s.  The last pointer in the list must have the high order bit set to one.

000000                               11 S001WAIT CSECT ,
000000 18CF                          12          LR    R12,R15            ESTABLISH
                            00000    13          USING S001WAIT,R12                BASE REGISTER
                                     14 *
                            00000    15          USING @TCB,R4
                            00000    16          USING @RB,R5
                                     17 *
000002 18A1                          18          LR    R10,R1             COPY PARM LIST
000004 18B1                          19          LR    R11,R1             COPY PARM LIST
000006 1211                          20          LTR   R1,R1              CHECK FOR ECB OR LIST
000008 47D0 C048      00048          21          BNP   LIST               BRANCH IF LIST OF ECB'S

After initial setup the high-order bit of Register 1 is checked using the Load Test Register instruction.  If the high order bit is one then LTR will indicate a negative value.  If it is zero then LTR will indicate positive.

00000C                               23 WAIT010  DS    0H
00000C 9180 1000      00000          24          TM    0(R1),X'80'        IS ECB ALREADY WAITING
000010 4710 C0E8      000E8          25          BO    WAIT900              YES - ABEND
                                     26 *
000014 9140 1000      00000          27          TM    0(R1),X'40'        ECB ALREADY POSTED
000018 4710 C03E      0003E          28          BO    WAIT020              YES - NO NEED TO WAIT
                                     29 *
00001C 1825                          30          LR    R2,R5               RB ADDRESS
00001E BF28 C0FC      000FC          31          ICM   R2,B'1000',=X'80'   SET WAIT BIT
000022 5020 1000      00000          32          ST    R2,0(,R1)           SAVE INTO ECB
                                     33 *
000026 9201 5004      00004          34          MVI   RBWTCNT,1           SET WAIT COUNT TO ONE
00002A 9680 4004      00004          35          OI    TCBFLGS,TCBFWAIT    SET WAIT BIT
                                     36 *
00002E 5810 0014      00014          37          L     R1,20               MVT ADDRESS
000032 5810 1024      00024          38          L     R1,MVTEXIT-@MVT(,R1)   EXIT ROUTINE
000036 5010 401C      0001C          39          ST    R1,TCBPSW+4         MAKE IT RESUME POINT FROM WAIT
00003A 5010 405C      0005C          40          ST    R1,TCBREG15         SET R15 TO EP AT RESUME
                                     41 *
00003E                               42 WAIT020  DS    0H
00003E 58F0 0014      00014          43          L     R15,20              MVT ADDRESS
000042 58F0 F004      00004          44          L     R15,MVTDISP-@MVT(,R15)  DISPATCHER ADDRESS
000046 07FF                          45          BR    R15

For a single ECB we begin by checking to see if the wait bit x’80’ is already set indicating the ECB is being waited on by another RB.  If it is set we branch to generate an Abend.  Next we check to see if the post bit x’40’ is set.  It is possible that the ECB was posted as complete before the Wait SVC was issued.  If it is already posted then we can just exit without waiting.

If we need to wait we place the address of our RB into the ECB and set the wait bit.  We also set the wait count in the RB to one.  Currently we allow only a wait count of one but have the option of changing this later.  Since we set the wait count in top RB we also need to set the wait bit in the TCB so the Dispatcher will not dispatch this TCB until the ECB is posted and the wait count in the RB is cleared.

Finally we get the address of the Exit routine and use it to update the contents of the TCB before branching to the Dispatcher.  We branch to the Dispatcher instead of the Exit routine because we want to interrupt execution of this RB at this point until the ECB has been posted.  If we branched to the Exit routine control would immediately be returned to the location immediately following the SVC 1.  To cause the wait we have set the Wait Bit in the TCB Flags so the TCB will not be dispatched.  When the post routine clears the Wait Bit the Dispatcher will at some point transfer control to this TCB.  When that happens we need to branch to the Exit Routine so control is returned to the caller of the SVC.  To accomplish this we set the PSW to point to the Exit Routine.  We must also replace the contents of Register 15 with the address of the Exit Routine.  Now when the Wait Bit is cleared and the Dispatcher transfers control to the TCB the PSW and register will be loaded from the TCB resulting in a branch to the Exit Routine.

000048                               49 LIST     DS    0H
000048                               50 LIST010  DS    0H
000048 5810 A000      00000          51          L     R1,0(,R10)         GET ECB ADDRESS
00004C 9180 1000      00000          52          TM    0(R1),X'80'        ECB ALREADY WAITING?
000050 4710 C0E8      000E8          53          BO    WAIT900             YES - ABEND
                                     54 *
000054 9180 A000      00000          55          TM    0(R10),X'80'      END OF LIST
000058 4710 C064      00064          56          BO    LIST020
                                     57 *
00005C 41A0 A004      00004          58          LA    R10,4(,R10)       NEXT ECB IN LIST
000060 47F0 C048      00048          59          B     LIST010           LOOP BACK

Processing a list of ECB’s is pretty much the same process but what have to loop through the list.  We begin by looping through the list to verify none of the ECB’s have the Wait Bit set.  If we find an ECB with the Wait Bit set we branch to Abend.

000064                               63 LIST020  DS    0H
000064 18AB                          64          LR    R10,R11           START OVER
000066                               65 LIST030  DS    0H
000066 5810 A000      00000          66          L     R1,0(,R10)        GET ECB ADDRESS
00006A 9140 1000      00000          67          TM    0(R1),X'40'       ALREADY POSTED ?
00006E 4710 C03E      0003E          68          BO    WAIT020            YES - NO NEED TO WAIT
                                     69 *
000072 9180 A000      00000          70          TM    0(R10),X'80'      END OF LIST
000076 4710 C082      00082          71          BO    LIST040
                                     72 *
00007A 41AA 0004      00004          73          LA    R10,4(R10)        NEXT ECB IN LIST
00007E 47F0 C066      00066          74          B     LIST030           LOOP BACK

Next we check to see if any of the ECB’s in the list are already posted.  If any one of the ECB’s has been posted we don’t need to wait.

000082                               78 LIST040  DS    0H
000082 18AB                          79          LR    R10,R11           START OVER AT TOP OF LIST
000084 1825                          80          LR    R2,R5             RB ADDRESS
000086 BF28 C0FC      000FC          81          ICM   R2,B'1000',=X'80'  SET WAIT BIT
00008A                               82 LIST050  DS    0H
00008A 5810 A000      00000          83          L     R1,0(,R10)        GET ECB ADDRESS
00008E 5020 1000      00000          84          ST    R2,0(,R1)         SET ECB CONTENTS
000092 9180 A000      00000          85          TM    0(R10),X'80'      END OF LIST
000096 4710 C0A2      000A2          86          BO    LIST060
                                     87 *
00009A 41A0 A004      00004          88          LA    R10,4(,R10)       NEXT ECB IN LIST
00009E 47F0 C08A      0008A          89          B     LIST050           LOOP BACK

Next we loop through the list and place the address of the RB into each ECB while we also set the Wait Bit.

0000A2                               92 LIST060  DS    0H
0000A2 9201 5004      00004          93          MVI   RBWTCNT,1           SET WAIT COUNT TO ONE
0000A6 9680 4004      00004          94          OI    TCBFLGS,TCBFWAIT    SET WAIT BIT
                                     95 *
0000AA 4110 C0C4      000C4          96          LA    R1,LIST070          RESUME HERE AFTER WAIT POSTED
0000AE 5010 401C      0001C          97          ST    R1,TCBPSW+4         MAKE IT RESUME POINT FROM WAIT
                                     98 *
0000B2 50B0 4024      00024          99          ST    R11,TCBREG1         R1 WILL POINT TO ECB LIST
0000B6 50C0 4050      00050         100          ST    R12,TCBREG12        R12 WILL CONTAIN BASE ADDRESS
                                    101 *
0000BA 58F0 0014      00014         102          L     R15,20              MVT ADDRESS
0000BE 58F0 F004      00004         103          L     R15,MVTDISP-@MVT(,R15)  DISPATCHER ADDRESS
0000C2 07FF                         104          BR    R15

Now we set up our branch to the Dispatcher.  Like before we set the RB Wait Count and the TCB Wait Flag.  Instead of setting up for a branch to the Exit Routine this time we come back to our code.  We set this up by updating the PSW in the TCB.  We also store Register 1 and Register 12 in the TCB so they will be available when the TCB is once again dispatched.

0000C4                              108 LIST070  DS    0H
0000C4 18A1                         109          LR    R10,R1             POINT TO ECB LIST
0000C6                              110 LIST080  DS    0H
0000C6 5810 1000      00000         111          L     R1,0(,R1)          ECB ADDRESS
0000CA 947F 1000      00000         112          NI    0(R1),X'FF'-X'80'  TURN OFF WAIT BIT
                                    113 *
0000CE 9180 A000      00000         114          TM    0(R10),X'80'       END OF LIST
0000D2 4710 C0DE      000DE         115          BO    LIST090
                                    116 *
0000D6 41A0 A004      00004         117          LA    R10,4(,R10)        NEXT ECB PTR
0000DA 47F0 C0C6      000C6         118          B     LIST080            LOOP BACK FOR NEXT ECB

When we get redispatched after the post we need to go through the ECB list and turn off the waiting bit for each ECB in the list.  Once that is done we branch to the Exit Routine.

0000DE                              121 LIST090  DS    0H
0000DE 58F0 0014      00014         122          L     R15,20              MVT ADDRESS
0000E2 58F0 F024      00024         123          L     R15,MVTEXIT-@MVT(,R15)   EXIT ROUTINE
0000E6 07FF                         124          BR    R15
                                    125 *
0000E8                              127 WAIT900  DS    0H
0000E8 5810 C0F8      000F8         128          L     R1,=A(X'101')      ABEND CODE
                                    129          @CALL ABEND
0000EC 58F0 0014      00014         130+         L     R15,20             MVT ADDRESS
0000F0 58F0 F020      00020         131+         L     R15,MVTABEND-@MVT(,R15) ROUTINE ADDRESS
0000F4 05EF                         132+         BALR  R14,R15

If a ECB with the Wait Bit was passed to the Wait SVC routine an Abend x’101′ will be issued.

[Next – SVC 2 – Post]

Wait / Post Overview

A critical component to our Operating System is Wait and Post.  The Wait function allows a task to wait for an event to occur while the Post function is used to signal an event has occurred.  An Event Control Block (ECB) is used for communication between Wait and Post.  The ECB is a fullword (4 bytes) that represents an event.  A task issues a Wait against and ECB and a Post is issued to an ECB.

The ECB status is represented using the first two bits of the first byte.  The first bit (x’80’) indicates an ECB is being waited on.  The second bit (x’40’) indicates the ECB has been posted.

Only one TCB/RB may wait on an ECB at any one time.  The wait status is associated with the RB and is proprigated from the active RB to the TCB.

[Next – SVC 1 – Wait]

SVC 3 – Exit

SVC 3 is a SVC entry to the exit routine. The current RB at the time the SVC 3 is issued will be terminated. If no RB’s remain for the TCB the TCB will be terminated. This SVC is entered with interrupts disabled. On entry R4 points to the current TCB and R5 points to the current RB which will be the RB created for the SVC 3 interrupt – not the RB that was active when the SVC was issued. The SVC routine needs to remove the current RB so the Exit Routine will terminate the RB that issued the SVC call.

000000                               12 S003EXIT CSECT ,
000000 18CF                          13          LR    R12,R15            ESTABLISH
                            00000    14          USING S003EXIT,R12                BASE REGISTER
                                     15 *
                            00000    16          USING @TCB,R4
                            00000    17          USING @RB,R5

000002 1825                          22          LR    R2,R5              COPY CURRENT RB ADDRESS
000004 5850 5000      00000          23          L     R5,RBNEXT          NEXT RB ON CHAIN
000008 5050 4008      00008          24          ST    R5,TCBRB           UNCHAIN CURRENT RB
                                     25 *
00000C 4110 0050      00050          26          LA    R1,RBLEN           LENGTH OF RB
000010 BF18 C030      00030          27          ICM   R1,B'1000',=AL1(128)   SP=128
000014 1802                          28          LR    R0,R2                  RB ADDRESS
000016 58F0 0014      00014          29          L     R15,20                 POINT TO MVT
00001A 58F0 F01C      0001C          30          L     R15,MVTFMAIN-@MVT(,R15)    FREEMAIN BRANCH ENTRY
00001E 05EF                          31          BALR  R14,R15
                                     32 *
000020 58F0 0014      00014          33          L     R15,20                 POINT TO MVT
000024 58F0 F024      00024          34          L     R15,MVTEXIT-@MVT(,R15) EXIT ROUTINE
000028 07FF                          35          BR    R15

[Next – Wait / Post Overview]

TXXEXIT – Exit Routine

The Exit Routine terminates the top level RB and makes the next RB on the stack active.  If there are no more RB’s on the stack then the TCB is terminated.

000000                                9 TXXEXIT  CSECT ,
000000 18CF                          10          LR    R12,R15
                            00000    11          USING TXXEXIT,R12
                                     12 *
000002 8000 C0C8      000C8          13          SSM   =X'00'             DISABLE INTERRUPTS
                                     14 *
000006 5840 0010      00010          15          L     R4,16              CVT ADDRESS
00000A 5840 4000      00000          16          L     R4,CVTCTCB-@CVT(,R4)  GET TCB ADDRESS
00000E 5850 4008      00008          17          L     R5,TCBRB-@TCB(,R4)    GET RB  ADDRESS
                                     18 *
                            00000    19          USING @TCB,R4
                            00000    20          USING @RB,R5
                                     21 *
000012 1255                          22          LTR   R5,R5              ANY RB
000014 4780 C068      00068          23          BZ    XTCB                NO - TERMINATE TCB

Interrupts are disabled before any additional processing is done.  Since we will be modifying RB and TCB chains we don’t want the Dispatcher trying to dispatch a TCB we are modifying.  By disabling interrupts we know the Dispatcher will not gain control through an interrupt caused by the Interval Timer or and I/O interrupt.  We next get the current TCB address and the top level RB address.  If for some reason there is no RB we terminate the TCB.

000018 D23F 4020 5010 00020 00010    25          MVC   TCBREGS(64),RBREGS  COPY RB REGS TO TCB
00001E D207 4018 5008 00018 00008    26          MVC   TCBPSW(8),RBPSW     COPY RB PSW  TO TCB
000024 5810 5000      00000          27          L     R1,RBNEXT           NEXT RB ON CHAIN
000028 5010 4008      00008          28          ST    R1,TCBRB            UNCHAIN RB
                                     29 *
00002C 4110 0050      00050          30          LA    R1,RBLEN            LENGTH OF RB
000030 BF18 C0C9      000C9          31          ICM   R1,B'1000',=AL1(128)   SP=128
000034 1805                          32          LR    R0,R5                  RB ADDRESS TO FREE
                                     33          @CALL FREEMAIN               FREE STORAGE
000036 58F0 0014      00014          34+         L     R15,20             MVT ADDRESS
00003A 58F0 F01C      0001C          35+         L     R15,MVTFMAIN-@MVT(,R15) ROUTINE ADDRESS
00003E 05EF                          36+         BALR  R14,R15

We unchain the top level RB by taking the forward pointer in the RB and storing it in the TCB.  Now that the RB is off the chain we can free the storage associated with it.

000040 5850 4008      00008          38          L     R5,TCBRB            GET NEW CURRENT RB ADDRESS
000044 1255                          39          LTR   R5,R5               ANY RB
000046 4780 C068      00068          40          BZ    XTCB                NO - TERMINATE TCB
                                     41 *
00004A 9500 5004      00004          42          CLI   RBWTCNT,0           IS RB WAITING
00004E 4780 C05A      0005A          43          BE    EXIT010              NO - BRANCH
                                     44 *
000052 9680 4004      00004          45          OI    TCBFLGS,TCBFWAIT    SET WAIT BIT
000056 47F0 C05E      0005E          46          B     EXIT020
                                     48 *
00005A                               49 EXIT010  DS    0H
00005A 947F 4004      00004          50          NI    TCBFLGS,X'FF'-TCBFWAIT  CLEAR WAIT BIT
00005E                               51 EXIT020  DS    0H
00005E 58F0 0014      00014          52          L     R15,20              MVT ADDRESS
000062 58F0 F004      00004          53          L     R15,MVTDISP-@MVT(,R15)   DISPATCHER ENTRY
000066 07FF                          54          BR    R15                 GO TO DISPATCHER

Next we get the new top level RB address.  If we just removed the last RB for the TCB this pointer will be null and we need to terminate the TCB.  If there is a top level RB we propagate the wait status of the RB to the TCB.  If the RB wait count is not zero the TCB wait flag is set.  If the RB wait count is zero the TCB wait flag is cleared.  Control is then transferred to the Dispatcher to select the next task to dispatch.

000068                               57 XTCB     DS    0H
000068 5810 0010      00010          58          L     R1,16              CVT ADDRESS
00006C 5810 1004      00004          59          L     R1,CVTTASKQ-@CVT(,R1)   TOP OF TASK QUEUE
                                     60 *
000070                               61 XTCB010  DS    0H
000070 5820 1000      00000          62          L     R2,0(,R1)          POINT TO NEXT TCB
000074 1222                          63          LTR   R2,R2              END OF CHAIN ?
000076 4780 C0B8      000B8          64          BZ    XTCB900            SHOULD NOT HAPPEN - CAN'T FIND TCB
                                     65 *
00007A 1924                          66          CR    R2,R4              IS THIS OUR TCB
00007C 4780 C086      00086          67          BE    XTCB020              YES - BRANCH
                                     68 *
000080 1812                          69          LR    R1,R2              CHECK NEXT
000082 47F0 C070      00070          70          B     XTCB010                      TCB

This routine terminates the TCB when no RB’s are left.  First the the TCB chain is searched to locate the TCB that points to the TCB we are terminating.  We need this TCB address so we can unchain the terminating TCB.

000086                               73 XTCB020  DS    0H
000086 5830 2000      00000          74          L     R3,0(,R2)          UNCHAIN THIS
00008A 5030 1000      00000          75          ST    R3,0(,R1)                     TCB FROM QUEUE
                                     76 *
00008E 58B0 0010      00010          77          L     R11,16             CVT
000092 5810 B004      00004          78          L     R1,CVTTASKQ-@CVT(,R11)   TOP OF QUEUE (WAIT TASK)
000096 5010 B000      00000          79          ST    R1,CVTCTCB-@CVT(,R11)    MAKE CURRENT TASK
                                     80 *
00009A 4110 0060      00060          81          LA    R1,TCBLEN          LENGTH OF TCB
00009E BF18 C0C9      000C9          82          ICM   R1,B'1000',=AL1(128)   SP=128
0000A2 1804                          83          LR    R0,R4                  ADDRESS OF TCB TO FREE
                                     84          @CALL FREEMAIN
0000A4 58F0 0014      00014          85+         L     R15,20             MVT ADDRESS
0000A8 58F0 F01C      0001C          86+         L     R15,MVTFMAIN-@MVT(,R15) ROUTINE ADDRESS
0000AC 05EF                          87+         BALR  R14,R15
                                     88 *
0000AE 58F0 0014      00014          89          L     R15,20             MVT ADDRESS
0000B2 58F0 F004      00004          90          L     R15,MVTDISP-@MVT(,R15)   DISPATCHER
0000B6 07FF                          91          BR    R15

The TCB is removed from the chain and the Wait Task is made the current task.  This is necessary so the current task pointer will point to a valid TCB.  Now the TCB storage is freed and control is passed to the Dispatcher.

0000B8                               95 XTCB900  DS    0H
0000B8 8200 C0C0      000C0          96          LPSW  XTCBPSW
                                     97 *
0000C0                               98          DS    0D
0000C0 0002000000EE0005              99 XTCBPSW  DC    AL1(0,2,0,0),A(@E@EXIT)

If the terminating TCB is not found on the TCB chain an  unrecoverable error has occurred and a wait state PSW is loaded.

[Next – SVC 3 – Exit]

TXXSVCIR – SVC Interrupt Handler

SVC routines are defined in a SVC Table Module.  The SVC table is a two-level index to the SVC routine.  The first level is a 256 byte table.  Each byte corresponds to a SVC number. If the corresponding byte in the table is zero then the SVC routine is not defined.  If the value is non-zero it is an index into a vector table that points to the SVC routine.

For example the first level table of x’00 02 03 01 00…’ would define three SVC’s.  SVC 0 is not defined, but 1,2 and 3 are.  The values in the table are not the SVC number but they are an index.  The vector table would have A(SVC02, SVC03, SVC01).  The order of the pointers in the vector table correspond with the values in the first level table.

The vector table entry also indicates if the SVC routine should be called enabled or disabled for interrupts.  If the high-order bit in the address is one, the routine is called with interrupts disabled.

X’80’,VL3(SVC-Disabled)  or X’00’,VL3(SVC-Enabled)

The first thing the SVC Interrupt Handler does is to look up the SVC in the first level table:

000000                                8 TXXSVCIR CSECT ,
000000 18CF                           9          LR    R12,R15            ESTABLISH
                            00000    10          USING TXXSVCIR,R12                BASE REGISTER
                                     11 *
                            00000    12          USING @TCB,R4
                                     13 *
000002 1FBB                          14          SLR   R11,R11
000004 BFB3 401A      0001A          15          ICM   R11,B'0011',TCBPSW+2   GET INTERRUPT CODE
000008 58A0 0014      00014          16          L     R10,20                 MVT
00000C 58A0 A014      00014          17          L     R10,MVTSVCTB-@MVT(,R10)  POINT TO SVC TABLE
000010 5AB0 A000      00000          18          A     R11,0(,R10)            SVC TABLE INDEX
000014 1F11                          19          SLR   R1,R1
000016 4310 B000      00000          20          IC    R1,0(,R11)             GET INDEX PTR
00001A 1211                          21          LTR   R1,R1                  CHECK IF DEFINED
00001C 4780 C084      00084          22          BZ    BADSVC                 NO - BAD SVC
                                     23 *
000020 8910 0002      00002          24          SLL   R1,2                   MULTIPLY BY 4
000024 58B0 A004      00004          25          L     R11,4(,R10)            SVC VECTOR TABLE
000028 1AB1                          26          AR    R11,R1                 INDEX INTO TABLE

The SVC interrupt number is obtained from the SVC Old PSW that was stored in the TCB.  This value is used as an index into the first level table.  If the indexed byte is zero the SVC is not defined.  The indexed byte is then multiplied by 4 to become an index into the vector table.

00002A 4110 0050      00050          28          LA    R1,RBLEN               GET LENGTH OF RB
00002E BF18 C0A0      000A0          29          ICM   R1,B'1000',=AL1(128)   SP=128
                                     30          @CALL GETMAIN                GETMAIN STORAGE
000032 58F0 0014      00014          31+         L     R15,20             MVT ADDRESS
000036 58F0 F018      00018          32+         L     R15,MVTGMAIN-@MVT(,R15) ROUTINE ADDRESS
00003A 05EF                          33+         BALR  R14,R15
00003C 12FF                          34          LTR   R15,R15                CHECK RC
00003E 4770 C094      00094          35          BNZ   GETMFAIL                 BRANCH IF FAILED

A new RB is now needed to create a new execution environment for the SVC code to run under while preserving the calling environment.  A branch entry to GETMAIN is made to allocate the storage for the new RB.

000042 1851                          37          LR    R5,R1                  COPY ADDRESS OF NEW RB
                            00000    38          USING @RB,R5
                                     39 *
000044 D74F 5000 5000 00000 00000    40          XC    0(RBLEN,R5),0(R5)      CLEAR STORAGE
00004A D207 5008 4018 00008 00018    41          MVC   RBPSW,TCBPSW           COPY IN CURRENT PSW
000050 D23F 5010 4020 00010 00020    42          MVC   RBREGS,TCBREGS         COPY IN REGISTERS

The storage for the new RB is cleared and the registers and PSW from the TCB are copied into the new RB.

000056 5810 4008      00008          44          L     R1,TCBRB               CURRENT RB PTR
00005A 5010 5000      00000          45          ST    R1,RBNEXT              CHAIN ON
00005E 5050 4008      00008          46          ST    R5,TCBRB                       NEW RB
000062 5810 5014      00014          47          L     R1,RBREG1              RESTORE REG 1
000066 5800 5010      00010          48          L     R0,RBREG0              RESTORE REG 0

The new RB is added to the top of the RB chain.  The RB chain is a push-down stack with the TCB pointing to the top of the stack.

00006A 58F0 B000      00000          50          L     R15,0(,R11)            GET SVC EP
00006E 58E0 0014      00014          51          L     R14,20                 MVT ADDRESS
000072 58E0 E024      00024          52          L     R14,MVTEXIT-@MVT(,R14) SET EXIT AS RETURN ADDR

Now the SVC routine entry point is loaded into Register 15.  The Exit Routine address is loaded into Register 14 as the return point from the SVC routine.

000076 9180 B000      00000          54          TM    0(R11),X'80'           DISABLED EXECUTION
00007A 4710 C082      00082          55          BO    SVCHND00               YES - BRANCH
                                     56 *
00007E 8000 C0A1      000A1          57          SSM   =X'FF'                 ENABLE FOR INTERRUPTS
                                     58 *
000082                               59 SVCHND00 DS    0H
000082 07FF                          60          BR    R15

Now the high-level bit in the vector entry is checked to determine if the SVC routine should be called with interrupts enabled or disabled.  If the bit is not set, indicating interrupts enabled, the Set System Mask (SSM) instruction is used to enable interrupts.

000084                               63 BADSVC   DS    0F
000084 4110 0FFF      00FFF          64          LA    R1,X'FFF'          ABEND CODE
                                     65          @CALL ABEND              CALL ABEND
000088 58F0 0014      00014          66+         L     R15,20             MVT ADDRESS
00008C 58F0 F020      00020          67+         L     R15,MVTABEND-@MVT(,R15) ROUTINE ADDRESS
000090 05EF                          68+         BALR  R14,R15
                                     70 *
000094                               71 GETMFAIL DS    0F
000094 8200 C098      00098          72          LPSW  ERRPSW             ERROR - OUT OF MEMORY
                                     73 *
000098                               76          DS    0D
000098 0002000000EE0004              77 ERRPSW   DC    AL1(0,2,0,0),A(@E@SVCM)      DISABLED WAIT PSW

Finally if the SVC is not defined in the SVC table the Abend routine is called (actually branched to since it does not return to the caller).  The abend code is set to x’FFF’ to indicate an undefined SVC.  If the Getmain request failed a disabled wait PSW is loaded.

[Next – TXXEXIT – Exit Routine]

TXXDINIT – Dispatcher Initialization

For now the Dispatcher initialization routine will simply add the dummy Wait Task to the TCB queue.  This dummy task TCB must always be present and must be the first TCB on the queue.  Because we are not adding any other TCB’s to the queue for now the only thing that will happen when we IPL is the Dispatcher will enter the enabled wait until the Interval Timer expires at which time the Dispatcher will once again enter the enabled wait.  Later we will add additional TCB’s that will perform some work.

000000                                4 TXXDINIT CSECT ,
000000 18CF                           5          LR    R12,R15             ESTABLISH
                            00000     6          USING TXXDINIT,R12                 BASE REGISTER
                                      7 *
000002 58B0 0010      00010           8          L     R11,16              CVT ADDRESS
                            00000     9          USING @CVT,R11
                                     10 *
000006 4140 C098      00098          11          LA    R4,WAITTASK         POINT TO DUMMY WAIT TASK
                            00000    12          USING @TCB,R4
                                     13 *
00000A 9640 4004      00004          14          OI    TCBFLGS,TCBFNDSP    DO NOT DISPATCH TASK
                                     15 *
00000E 5040 B004      00004          16          ST    R4,CVTTASKQ         ADD TO TASK QUEUE
000012 5040 B000      00000          17          ST    R4,CVTCTCB          MAKE IT CURRENT TASK
000088 07FE                          51          BR    R14                 RETURN TO CALLER

The only thing we need to do to set up the TCB is to set the Do Not Dispatch flag (TCBFNDSP).

                                     60          PUSH PRINT
                                     61          PRINT NOGEN
                                     62          @TCB  ,
                                    110          @RB   ,
                                    142          POP   PRINT

000094                              146 TXXDINIT CSECT ,
000098                              147 WAITTASK DS    0D
000098 0000000000000000             148          DC    (TCBLEN)X'00'

Because we want to refer the length of the TCB control block DSECT to define the Wait Task TCB storage, the equate for TCBLEN must be defined before it is used.  To do so, we can include the @TCB macro to define the DSECT and then we continue the CSECT.

[Next – TXXSVCIR – SVC Interrupt Routine]