1 " ***********************************************************
  2 " *                                                         *
  3 " * Copyright, (C) Honeywell Bull Inc., 1987                *
  4 " *                                                         *
  5 " * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6 " *                                                         *
  7 " * Copyright (c) 1972 by Massachusetts Institute of        *
  8 " * Technology and Honeywell Information Systems, Inc.      *
  9 " *                                                         *
 10 " ***********************************************************
 11 
 12 " iom_interrupt:  IOM interrupt handler
 13 " Stolen from iom_manager and ii November 1980 by C. Hornig
 14 " Added loop protocol for IOM switch checking, January 1985 by M. Pandolf
 15 "         see iom_connect$connect_and_identify for the other half of the protocol
 16 
 17           name      iom_interrupt
 18 
 19           segdef    interrupt_entry     " interrupt vector transfers here
 20           segdef    iilink              " ITS ptr to linkage section
 21           segdef    prds_prs            " ITS ptr to space for spri
 22           segdef    prds_scu            " ITS ptr to space for SCU
 23 
 24           tempd     hlr_arglist(4)      " argument list for interrupt handler
 25           tempd     time                " time handler called
 26           tempd     imw_save            " current IMW for scan
 27           temp      int_level           " interrupt level for handler (1 3 5 7)
 28           temp      index               " index for this channel
 29           temp      chantab_base        " offset in chantab for this IOM
 30           temp      device              " offset in per_device for this channel
 31           temp      chx                 " channel index from chantab
 32           temp      int_count           " handlers called this time around
 33 
 34 " Index register conventions:
 35 
 36 "         X0 - internal subroutine calls.
 37 "         X1 - index into devtab.
 38 "         X2 - index into mailbox.
 39 "         X3 - Used to index iomd.per_iom.
 40 "         X4 - interrupt cell #.
 41 "         X5 - interrupt level #.
 42 "         X6 - index in status queue
 43 
 44 " Pointer Register Conventions:
 45 
 46 "         AP -> machine conditions
 47 "         AB -> inetrnal calls
 48 "         BP -> <iom_data>|0
 49 "         BB -> mailbox for this IOM.
 50 "         LP -> linkage section
 51 "         LB -> status queue
 52 
 53 
 54 " These are initialized by initialize_faults
 55 
 56           even
 57 iilink:   its       -1,1                " our LP
 58 prds_prs: its       -1,1                " where to store PRs
 59 prds_scu: its       -1,1                " and CU info
 60 
 61 three_args_nd:
 62           zero      6,4
 63 zero:     zero      0
 64 
 65 push_value:
 66           push
 67 
 68 chanpos:                                " table of chantab offsets
 69           zero      0,0*4*per_iom_size+32
 70           zero      0,1*4*per_iom_size+32
 71           zero      0,2*4*per_iom_size+32
 72           zero      0,3*4*per_iom_size+32
 73           zero      0,0*4*per_iom_size
 74           zero      0,1*4*per_iom_size
 75           zero      0,2*4*per_iom_size
 76           zero      0,3*4*per_iom_size
 77 " ^L
 78 " This entry is transferred to by the interrupt vector.
 79 " It is responsible for calling the interrupt handlers of various DIM's
 80 " for which interrupts have been stored in the IMW array.
 81 " It calls the interrupt routine as follows:
 82 "         call int_proc (idx, int_level, data_word)
 83 " where int_level (1 3 5 7) corresponds to the level passed by the channel
 84 " to the IOM and data_word in the system fault or special status word.
 85 
 86           inhibit   on        <+><+><+><+><+><+><+><+><+><+><+><+><+>
 87 
 88 interrupt_entry:
 89           spri      prds_prs-*,ic*      " save pointer registers
 90           eppbp     prds_prs-*,ic*      " ab -> machine conditions
 91           sreg      bp|mc.regs          " save registers
 92           lxl7      bp|mc.scu.indicators_word
 93           canx7     scu.ir.mif,du       " check for EIS
 94           tze       2,ic                " so we can save
 95           spl       bp|mc.eis_info      " the pointers and lengths
 96 
 97           epplp     iilink-*,ic*        " set up LP
 98 
 99           tsx0      fim_util$v_time_init " meter virtual time
100 
101           tsx0      fim_util$check_interrupt " make sure we're not not prds
102 
103           tsx0      fim_util$check_mct  " go save M.C.s and hregs
104                                         " if trace is on
105           nop                           " return ic +1
106 
107 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
108 "
109 "         Establish a stack frame and mask interrupts.
110 "
111           epbpsb    prds$               " use prds
112           ldx7      push_value-*,ic     " get size of stack frame
113           tsx0      fim_util$push_stack " push the frame
114 
115           tsx0      fim_util$set_mask   " mask to sys level
116 
117           inhibit   off       <-><-><-><-><-><-><-><-><-><-><-><->
118 
119           tsx0      fim_util$reset_mode_reg
120                                         " turn on hist regs and cache
121           ldq       bp|mc.scu.fault_data_word
122           anq       scu.fi_num_mask,dl  " get the interrupt number
123           qrl       scu.fi_num_shift
124           eax4      0,ql                " interrupt cell in X4
125 " ^L
126           anq       =7,dl               " get base channel table position
127           lda       chanpos,ql
128           sta       chantab_base        " save it for later
129 
130           eaa       0,x4                " get interrupt cell
131           arl       18+2                " interrupt level in AL
132           ora       =1,dl               " always odd
133           sta       int_level           " save for handler
134 
135           ldaq      three_args_nd-*,ic  " Build argument list for handler
136           staq      hlr_arglist         " call handler (index, int_level, ""b)
137           epplb     index
138           sprilb    hlr_arglist+2
139           epplb     int_level
140           sprilb    hlr_arglist+4
141           epplb     zero-*,ic
142           sprilb    hlr_arglist+6
143 "
144 "         set up to search IMW area
145 "
146           eppbp     iom_data$
147           stz       int_count           " no interrupts yet
148 
149 "
150 "         wait until any IOM switch checking is completed
151 "
152 
153 imw_wait:
154           odd
155           ldac      bp|iom_data.imw_lock
156           tze       -1,ic               " loop while lock in transition
157           tpl       imw_read
158           sta       bp|iom_data.imw_lock" restore -1 into lock
159           tra       imw_wait            " and continue looping
160 
161 imw_read:
162           aos       bp|iom_data.n_intr_procs " bump number of cpus handling interrupts
163           aos       bp|iom_data.imw_lock " was 0 from ldac, now is 1
164 
165           ldac      iom_mailbox$+iom_mailbox_seg.imw_array_word,x4
166           tze       null_int-*,ic       " no IMW bit set
167 
168           ldq       0,du                " make a fake float number
169           lde       0,du
170           lrl       1
171           tra       imw_begin-*,ic      " start scanning
172 
173 " Scan the IMW for any bits on and process these interrupts.
174 
175 imw_retry:
176           dfld      imw_save            " get back remaining bits
177           tze       interrupt_return    " no bits left
178 
179 imw_begin:
180           ldi       0,dl                " clear hex and overflow bits
181           fno
182           era       =o200000,du         " clear the bit
183           dfst      imw_save
184 
185           lda       imw_save            " get channel number
186           ars       36-8                " in AL
187           neg       0
188           ada       chantab_base        " add chantab offset
189           sta       index               " store in case of error
190 
191           mrl       (pr,al),(pr),fill(0) " Reference the channel table.
192           desc9a    bp|iom_data.per_iom+per_iom.chantab_word,1
193           desc9a    chx,4               " Word will be leading zero padded.
194 
195           eppap     hlr_arglist
196 
197           ldq       chx                 " chx in QL
198           tze       invalid_int-*,ic    " Ignore interrupt if channel not assigned.
199           mpy       per_device_size,dl
200           eax1      -per_device_size,ql " index into per_device
201 
202           lda       bp|iom_data.per_device+per_device.flags,x1
203                                         " is there a handler?
204           cana      per_device.in_use,du
205           tze       invalid_int-*,ic    " Return if no handler assigned.
206 
207           lda       bp|iom_data.per_device+per_device.index,x1
208           sta       index               " save the handler's index
209           stx1      device              " save per_device index for ext. call
210 
211           rccl      sys_info$clock_,*   " Get int_time now.
212           staq      time                " And save it.
213 
214           short_call bp|iom_data.per_device+per_device.handler,x1*
215                                         " Call handler.
216 
217           rccl      sys_info$clock_,*   " Get int_time again.
218           sbaq      time                " Compute delta.
219 
220           eppbp     iom_data$           " re-establish addressability
221           ldx1      device              " restore per_device offset
222           adaq      bp|iom_data.per_device+per_device.interrupt_time,x1
223           staq      bp|iom_data.per_device+per_device.interrupt_time,x1
224           ldaq      bp|iom_data.per_device+per_device.interrupts,x1
225           adl       =1,dl               " update meters
226           staq      bp|iom_data.per_device+per_device.interrupts,x1
227           aos       int_count           " count interrupts
228 
229           tra       imw_retry-*,ic      " find more interrupts
230 
231 
232 invalid_int:
233           aos       bp|iom_data.invalid_interrupts
234                                         " meter unexpected interrupts
235           short_call iom_error$invalid_interrupt
236                                         " and tell the world
237           eppbp     iom_data$           " re-establish addressability
238           tra       imw_retry-*,ic      " find more channels
239 " ^L
240 null_int:                               " meter interrupts with null IMW
241           aos       bp|iom_data.null_interrupts
242 
243 interrupt_return:
244           lda       int_count           " meter multiple interrupts
245           cmpa      =1,dl
246           tmoz      2,ic
247           aos       bp|iom_data.multiple_interrupts
248 
249           ldaq      tc_data$interrupt_count
250           adl       1,dl                " count interrupts
251           staq      tc_data$interrupt_count
252 
253           odd
254           ldac      bp|iom_data.imw_lock
255           tze       -1,ic               " loop while lock in transition
256 
257           lcq       1,dl                " decrement count of cpus in interrupt handler
258           asq       bp|iom_data.n_intr_procs
259 
260           sta       bp|iom_data.imw_lock
261 
262 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
263 "
264 "         Relinquish stack frame and open interrupt mask.
265 "
266           eppbp     prds_prs-*,ic*      " restore MC ptr
267 
268           tsx0      fim_util$restore_mask
269           inhibit   on        <+><+><+><+><+><+><+><+><+><+><+><+>
270 
271           epbpsb    sp|0                get ptr to base of stack
272           sprisp    sb|stack_header.stack_end_ptr  pop our stack frame
273 
274 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
275 "
276 "         Perform interrupt metering and exit.
277 "
278           ldaq      bp|mc.fault_time    " get fault time
279           ana       =o777777,dl         " clear CPU type
280           staq      prds$iitemp         " save for now
281           rccl      sys_info$clock_,*   " read the clock
282           sbaq      prds$iitemp         " compute real time spent
283           adaq      tc_data$interrupt_time " add in to total
284           staq      tc_data$interrupt_time "      ..
285 
286           odd
287           tsx0      fim_util$v_time_calc " compute virtual time
288 
289           lxl1      bp|mc.scu.indicators_word
290           canx1     scu.ir.mif,du       " check for EIS if not don't reload pl
291           tze       2,ic
292           lpl       bp|mc.eis_info      restore pointers and lengths
293           lreg      bp|mc.regs          and registers
294           lpri      prds_prs-*,ic*      restore prs
295           rcu       prds_scu-*,ic*      and dismiss the interrupt
296 " ^L
297           include   iom_data
298           include   mc
299           include   stack_header
300 
301           end