하드웨어 인터럽트와 IRQ 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

# 55.하드웨어 인터럽트와 IRQ 문서의 확인. 실행: python3 55_hardware-interrupt-irq_verify.py
# 8259 칩을 실제로 다루지 않는다. 문서 표의 번호 계산과, "우선순위가 낮은 요청은 기다린다",
# "IF가 0이면 받지 않는다"는 규칙을 작은 흉내기로 확인한다.

# 문서 표: INT 8~0Fh가 IRQ0~7
IRQ_TO_INT = {0: 0x08, 1: 0x09, 2: 0x0A, 3: 0x0B, 4: 0x0C, 5: 0x0D, 6: 0x0E, 7: 0x0F}


class Pic:
    """우선순위(숫자가 작을수록 높다고 두었다)가 있는 인터럽트 중재기 흉내."""

    def __init__(self):
        self.pending = set()
        self.in_service = []     # 처리 중인 IRQ 스택
        self.if_flag = 1
        self.log = []

    def request(self, irq):
        self.pending.add(irq)
        self.dispatch()

    def dispatch(self):
        if not self.if_flag or not self.pending:
            return
        best = min(self.pending)
        if self.in_service and best >= self.in_service[-1]:
            return               # 낮은(또는 같은) 우선순위는 끼어들지 못한다
        self.pending.remove(best)
        self.in_service.append(best)
        self.log.append(("start", best))

    def finish(self):
        self.log.append(("end", self.in_service.pop()))
        self.dispatch()

    def cli(self):
        self.if_flag = 0

    def sti(self):
        self.if_flag = 1
        self.dispatch()


if __name__ == "__main__":
    # IRQ n -> INT (8 + n), 벡터 칸의 오프셋 = (8 + n) × 4
    for irq, n in IRQ_TO_INT.items():
        assert n == 8 + irq
    assert IRQ_TO_INT[0] * 4 == 0x20 and IRQ_TO_INT[1] * 4 == 0x24 and IRQ_TO_INT[7] * 4 == 0x3C
    # IRQ 배정 표는 0~15, 16줄
    irq_names = ["System timer", "Keyboard", "Programmable Interrupt Controller", "COM2", "COM1", "LPT2",
                 "Floppy disk controller", "LPT1", "CMOS real-time clock",
                 "modem, video, network, sound, USB", "(available)", "(available)", "mouse",
                 "Math coprocessor", "Hard disk controller", "(available)"]
    assert len(irq_names) == 16 and irq_names[1] == "Keyboard" and irq_names[14] == "Hard disk controller"
    # 타이머는 초당 18.2번: 한 번에 약 55ms
    assert round(1000 / 18.2) == 55

    # 낮은 우선순위는 높은 우선순위 처리를 끊지 못한다
    p = Pic()
    p.request(1)                 # 키보드 처리 시작
    p.request(6)                 # 플로피: 기다린다
    assert p.in_service == [1] and p.pending == {6}
    p.request(0)                 # 타이머: 끼어든다
    assert p.in_service == [1, 0]
    p.finish()                   # 타이머 끝 -> 키보드로 돌아간다 (6은 아직 대기)
    assert p.in_service == [1] and p.pending == {6}
    p.finish()                   # 키보드 끝 -> 플로피 시작
    assert p.in_service == [6]
    assert p.log == [("start", 1), ("start", 0), ("end", 0), ("end", 1), ("start", 6)]
    # 동시에 온 요청은 우선순위 순서로 하나씩
    p = Pic()
    p.cli()
    for irq in (4, 1, 3):
        p.request(irq)
    assert p.in_service == [] and p.pending == {1, 3, 4}   # CLI 동안은 아무것도 시작하지 않는다
    p.sti()
    order = [p.in_service[-1]]
    p.finish(); order.append(p.in_service[-1])
    p.finish(); order.append(p.in_service[-1])
    assert order == [1, 3, 4]
    print("ALL CHECKS PASSED")