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]