Digital Logic & Microprocessor — Interrupt Operations, NEC licence examination syllabus (Nepal Engineering Council).
The Interrupt Service Routine: borrowing the CPU without breaking it
An ISR must leave the machine exactly as it found it, or the interrupted program will crash.
Here's the constraint that shapes every ISR: the interrupted program has no idea it was interrupted. It expects its registers, its flags and its stack to be untouched when execution resumes. If your ISR uses the accumulator — and it almost certainly will — it must save and restore it. Forgetting this produces bugs that appear randomly, depending on exactly where the interrupt struck.
The structure of every ISR
MYISR: PUSH PSW ; save A and the FLAGS
PUSH B ; save BC pair
PUSH D ; save DE pair
PUSH H ; save HL pair
… ; the actual service work
; (keep it SHORT)
POP H ; restore in REVERSE order
POP D
POP B
POP PSW
EI ; re-enable interrupts
RET ; return to the interrupted program
Two rules that are easy to get wrong:
1. POP order must be the exact REVERSE of PUSH order —
the stack is LIFO.
2. PSW must be saved if the ISR does ANY arithmetic or
logic, because those change the flags.
Why PSW specifically: the interrupted program might have executed a CMP and be about to do a JZ. If your ISR runs an ADD in between, it overwrites the zero flag, and that JZ now branches on your result instead of the program's. PUSH PSW saves the accumulator and flags together as one 16-bit word, which is exactly why the instruction exists.
Latency and response time
INTERRUPT LATENCY = time from the signal arriving to the
first instruction of the ISR executing.
Components:
1. Finish the current instruction (up to 18 T on 8085)
2. Recognise and acknowledge (a few T)
3. Push the PC (2 memory writes) (6 T)
4. Load the vector into the PC (a few T)
Total for the 8085: roughly 12–18 T-states
at 3 MHz = 4–6 µs
Then ADD the register-saving PUSHes:
4 PUSHes × 12 T = 48 T = 16 µs
So the real "time to useful work" is around 20 µs —
mostly spent on housekeeping, not the actual service.
This is why ISRs must be short: every microsecond delays
every other pending interrupt.
Worked numerical 1 — a complete timer ISR
Write an ISR for RST 7.5 that increments a 16-bit counter stored at 2000H–2001H, and set up the vector.
; ---- vector table ----
ORG 003CH ; the RST 7.5 vector
JMP TIMERISR ; only 3 bytes fit comfortably
; ---- main program ----
ORG 0100H
MAIN: LXI SP, 3FFFH ; ALWAYS initialise the stack
; before enabling interrupts!
MVI A, 0BH ; mask: enable 7.5, mask 6.5,5.5
SIM
EI ; global enable
LOOP: JMP LOOP ; do other work here
; ---- the ISR ----
ORG 0200H
TIMERISR:
PUSH PSW ; save A and flags
PUSH H ; save HL (we use it)
LHLD 2000H ; load the 16-bit counter
INX H ; increment it
SHLD 2000H ; store it back
POP H ; restore in reverse
POP PSW
EI ; re-enable (the interrupt
; response disabled them)
RET
Critical details:
· LXI SP must come FIRST — an interrupt with an
uninitialised stack pointer will push the PC to a random
address and destroy memory.
· EI before RET, because the interrupt acknowledge
automatically executed a DI.
· INX H doesn't affect flags, but PUSH PSW is still good
practice in case the ISR grows.
Total ISR time: PUSH(12) + PUSH(12) + LHLD(16) + INX(6)
+ SHLD(16) + POP(10) + POP(10) + EI(4)
+ RET(10) = 96 T = 32 µs at 3 MHz
Worked numerical 2 — nested interrupts
What happens if a higher-priority interrupt arrives during an ISR? Show how to allow it safely.
By default the 8085 executes a DI when it accepts an
interrupt, so further maskable interrupts are BLOCKED
until the ISR does an EI. TRAP still gets through.
To ALLOW nesting (a higher-priority interrupt to preempt
your ISR), issue EI EARLY:
ISR: PUSH PSW
PUSH H
EI ; ← re-enable immediately after
; saving state
…service work…
DI ; disable while restoring
POP H
POP PSW
EI
RET
Why DI before the POPs: if an interrupt fired mid-restore,
the nested ISR's own PUSHes would sit on top of your
half-popped values, and the stack would unwind incorrectly.
STACK DEPTH RISK with nesting:
each nesting level consumes:
2 bytes (PC) + 8 bytes (4 PUSHes) = 10 bytes
With 4 interrupt sources all nesting:
4 × 10 = 40 bytes of stack
Plus whatever the main program was using. If the stack
collides with your data area, the program corrupts itself
— one of the hardest bugs to diagnose, because it depends
on interrupt timing.
Worked numerical 3 — ISR duration and missed interrupts
An ISR takes 300 µs. A device interrupts every 200 µs. What happens?
Interrupt period: 200 µs
ISR duration: 300 µs
The ISR has not finished before the next request arrives.
For a LEVEL-triggered interrupt (RST 6.5, 5.5, INTR):
the request is still asserted when the ISR ends, so it
fires again immediately. The CPU spends 100% of its time
in the ISR and the main program NEVER runs — effectively
a livelock.
For an EDGE-triggered interrupt (RST 7.5):
the second edge sets the internal flip-flop, so exactly
one pending interrupt is remembered. Subsequent edges
during the ISR are LOST.
Data loss rate: with a 300 µs ISR and 200 µs events,
roughly one in three events is missed.
Fixes:
1. Shorten the ISR — do minimal work (just grab the byte
into a buffer) and process later in the main loop
2. Use DMA if it's bulk data
3. Add hardware buffering (a FIFO) at the device
The general principle: an ISR should do the least possible
work — set a flag, queue a byte, and return.
💡 Exam angle: the PUSH/POP structure with reverse-order restoration is the core answer, and PUSH PSW's importance (flags!) is the detail examiners look for. Always show LXI SP before EI in a full program — forgetting stack initialisation is a classic deduction. Interrupt latency components and the "keep ISRs short" principle round out a full-mark answer.
Syllabus points
Role and structure of an ISR
Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.