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.