Our first version of a nucleus will not do much – but it will do something!  It will set a value in the Interval Timer.  The CPU will subtract from this value several times every second.  When the value goes to zero an External Interrupt will be generated.  This will cause the CPU to save the current PSW into the External Old PSW area in low core and load a new PSW from the External New PSW location.  In our interrupt routine we will reset the Interval Timer and load a PSW with the wait bit set – but enabled for interrupts.

TXXNUC   CSECT ,
         DC    X'00',X'00',AL2(0),AL4(DISPINIT)  INITIAL PSW
         DC    D'0'                              RST NEW PSW
*
         DC    A(CVT)                            COMM VECT TABLE
         DC    A(MVT)                            MOD  VECT TABLE
*
         DC    D'0'          EXT OLD PSW
         DC    D'0'          SVC OLD PSW
         DC    D'0'          PGM OLD PSW
         DC    D'0'          MCK OLD PSW
         DC    D'0'          I/O OLD PSW
*
         DC    D'0'          CHANNEL STATUS WORD
         DC    F'0'          CHANNEL ADDRESS WORD
         DC    F'0'
         DC    F'0'          INTERVAL TIMER
         DC    F'0'
*
         DC    X'00',X'00',AL2(0),AL4(EXTHNDLR)  EXT NEW PSW
         DC    X'00',X'00',AL2(0),AL4(SVCHNDLR)  SVC NEW PSW
         DC    X'00',X'00',AL2(0),AL4(PGMHNDLR)  PGM NEW PSW
         DC    X'00',X'00',AL2(0),AL4(@E@MCK)    MCK NEW PSW
         DC    X'00',X'00',AL2(0),AL4(IOHNDLR)   I/O NEW PSW
*
*
LOWCLEN  EQU   *-TXXNUC
LOWCFILL EQU   1024-LOWCLEN
         DC    (LOWCFILL)X'00'

We begin by filling in some low core values needed by the CPU.  We specify the PSW’s to be loaded when the corresponding interrupt occurs.  Finally we pad low core up to 1k (1024) with binary zeros.

EXTREGS  DC    16F'0'             EXT INTERRUPT REG SAVE
IOREGS   DC    16F'0'             I/O INTERRUPT REG SAVE
SVCREGS  DC    16F'0'             SVC INTERRUPT REG SAVE
PGMREGS  DC    16F'0'             PGM INTERRUPT REG SAVE
*
*
CVT      DC    A(0)     +++ PLACE HOLDER +++
MVT      DC    A(0)     +++ PLACE HOLDER +++

Next we go ahead and define some data areas.  These will not be used right now but they will be needed in later versions of our nucleus code.

         USING TXXNUC,0
*
SVCHNDLR DS    0H
PGMHNDLR DS    0H
IOHNDLR  DS    0H
         LPSW  WAITPSW
*
         DS    0D
WAITPSW  DC    X'00',X'02',AL2(0),A(X'EE9999')

If an SVC, Program, or I/O interrupt occurs we load a disabled wait PSW.

EXTHNDLR DS    0H
         L     R1,=A(X'80')       INTERVAL TIMER VALUE
         ST    R1,ITIMER-@LOWCORE SAVE INTO TIMER
*
         LPSW  IWAIT              LOAD WAIT PSW
*
         DS    0D
IWAIT    DC    AL1(255,2,0,0),AL4(X'FEAD')
*
*
DISPINIT DS    0H
         B     EXTHNDLR

When an External interrupt occurs we store a new value into the interval timer and then load an Enabled Wait PSW.  The PSW must be enabled for External interrupts so our interrupt routine will be invoked when the timer expires.

         @LOWCORE ,
*
         @REGS ,
         @@ERR ,
         END   ,

Finally we include our macros for mapping low core and registers.  I have also created a new macro called @@ERR to contain wait state codes.

Once the nucleus is assembled and link edited as TXXNUC we can fire up Hercules and IPL from our DASD volume.  We should see our enabled wait PSW with the code ‘FEAD’ and we should observe the CPU waking up and performing a few instructions before going  back into the wait state.

[Next – Dispatcher]