MAIN: ...
        ; now we want to activate keyboard reading
        MOV #KBINT, 60 ; interrupt vector address for keyboard interrupts
        MOV #200, 62  ; location 62 gives PSW -- see notes below
        MOV #100, KBSTATUS
        ...

Location 62 is used for the PSW in the interrupt vector -- remember that this is the word after location 60, because the PDP-11 is byte-addressed (and one word equals two bytes). The pdp11 handout documents the PSW: the top 3 bits are the priority, thus this sets the CPU priority to 4; the other bits in the PSW are set to zero because mostly we don't care about them. (Actually we care vitally that a few of them are off, such as 'T'.)

In writing to KBSTATUS, the second-most-significant bit [of the eight-bit byte] means to enable interrupts.
Note that KBSTATUS for read and for write can be very different things. Memory-mapped i/o registers are like that sometimes.

Now, we can do something while the interrupt service routine does its work:

BIGLOOP: ; the interesting part goes here
        ...
        ...

        ; process input if available
        TST IAVAIL
        BEQ BIGLOOP  ; do other things, not a busy wait, it's a "poll"
        ... retrieve input data ..
        CLR IAVAIL
        MOV# INPUT, IPOS  ; see below (perhaps insert this at a later point)
        ... do something with the input data ...
        BR BIGLOOP

Why not just test KBSTATUS? Well, suppose that there's no point doing anything about the input until we have a whole line. Then the ISR can deal with everything until we have the whole line.

More than that, not shown below, we're actually going to want to "echo" the user input as they type it. Quick response for this is important or it feels sluggish. Suppose the computation takes a few real seconds in bigloop. If you press a key, we want the echoing to happen more quickly than that, even if the actual processing of the line once you press return takes longer.

Maybe you think the above is lame, but a more-compelling example would be trickier, and involve more non-io code, thus obscuring the point of this question.

Now, the interrupt service routine:

IAVAIL: .WORD 0  ; boolean: have we read a line of input?
 INPUT: .BLK 120 ; reserve 80 words for an input line
  IPOS: .WORD 0  ; holds pointer within that "INPUT" array; used by ISR

KBINT:  TST IAVAIL
        BEQ CONT
        ; old input still pending
        TSTB TTYIN  ; throw it away (a "TST" does do a read from there!)
        RTI
CONT:   MOVB TTYIN, @IPOS
        ; we should be checking here to make sure we don't exceed the 80
        ;       characters, but this example is already sufficiently complex.
        CMPB @IPOS, #CR
        BNE ISMORE
        MOV #INPUT, IPOS  ; for next time
        INC IAVAIL  ; set it to 1
        RTI

ISMORE: INC IPOS
        RTI

Recall that the RTI instruction pops the PSW, thus also resetting the priority level, i.e. we can have another keyboard interrupt. That "200" above says that this interrupt is priority 4, so during our interrupt routine, higher priority interrupts will still get processed (pushing our PSW, so that when they do the RTI the priority level will return to 4). But during our interrupt routine, lower- or equal-level interrupts will not be processed. Neither will they be relieved. The MOVB TTYIN, @IPOS clears the bit which says that keyboard data is available, which causes the high bit of KBSTATUS to go back to 0. If we don't do this before we do the RTI, the RTI, in dropping the cpu priority level, will cause the interrupt to be signalled again.


[I/O problems] [CSC 258 additional problems] [main course page]