Skip to content

Commit 5c3c7e7

Browse files
committed
V7 microcode + eu.v: IRET interrupt-recognition fix
Real 8086 only delays interrupt recognition after STI / MOV SS / POP SS. MCL86jr was also deferring after IRET, which broke the BIOS timer ISR's return path: IRET pops FLAGS (with IF=1) and the very next 18.2Hz tick that lands during the return-from-ISR should be taken immediately. MCL86jr was skipping that poll and the tick got dropped until the next real new_instruction edge. Two pieces needed fixing in tandem: 1. Microcode (Microcode_MCL86.txt). IRET's terminating jump went to 0x0474 (the legacy skip-INT path used by POP/MOV SS). Redirected to the with-INT-poll ending at 0x0FCB. 2. EU (eu.v). intr_enable_delayed only updates on new_instruction edges, so even with the with-INT-poll path the IRET microcode's post-FLAGS-load INT poll would still see IF=0 from before the restore. eu.v now detects the "OR r0 into FLAGS" microcode step (at ROM addr 0x0532; BRAM has 1-cycle synchronous read so the detection is gated on eu_rom_address == 0x0533) and syncs intr_enable_delayed in-cycle from bit 9 of the ALU output. Must come BEFORE the eu_flag_i==0 short-circuit because eu_flag_i is the OLD value at this point. Caught running King's Quest I on PCjr under the cosim: the BIOS timer ISR IRETs to user code, and the next 18.2 Hz tick races the return.
1 parent 063896e commit 5c3c7e7

4 files changed

Lines changed: 51 additions & 5 deletions

File tree

MCL86/Core/MCL86_Microcode_Xilinx_Version_7.coe

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

MCL86/Core/Microcode_MCL86.txt

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@
6060
// /0x0D63 entirely by jumping from 0x0D6B to a new SS-specific
6161
// debounce + skip-INT path at 0x0FD0-0x0FD1.
6262
//
63+
// Revision 7.0 5/11/2026
64+
// IRET (0xCF) interrupt-recognition fix. Real 8086 only delays
65+
// interrupt recognition after STI / MOV SS / POP SS; IRET does not.
66+
// MCL86jr's microcode and EU both deferred INT after IRET for two
67+
// reasons, both fixed here:
68+
// 1. IRET's ending jumped to the legacy 0x0470-0x0478 skip-INT
69+
// path. Switched to the V6 with-INT-poll path (0x0FCB).
70+
// 2. Even with the with-INT-poll path, the EU's intr_enable_delayed
71+
// register only updates on new_instruction edges, so the IRET
72+
// microcode's post-FLAGS-load intr poll would still see IF=0.
73+
// eu.v now also bypasses that delay when the microcode is at
74+
// IRET's "OR r0 into FLAGS" step (eu_rom_address == 0x0532),
75+
// syncing intr_enable_delayed from the ALU output's bit 9 in
76+
// the same cycle.
77+
// Caught running King's Quest I on PCjr: BIOS timer ISR's IRET to
78+
// user code races the next 18.2Hz tick.
79+
//
6380
//------------------------------------------------------------------------
6481
//
6582
// Copyright (c) 2020 Ted Fried
@@ -5676,7 +5693,13 @@ p 00 00000 00001 0531
56765693
p 01 00000 00001 488F
56775694
p 01 00000 00001 0000
56785695
#
5679-
# OR r0 into Flags register
5696+
# OR r0 into Flags register. eu.v detects this microcode step (when
5697+
# eu_rom_data delivers this word, which is when eu_rom_address has
5698+
# already advanced to 0x0533 due to the 1-cycle synchronous BRAM
5699+
# read) and immediately syncs intr_enable_delayed from bit 9 of the
5700+
# ALU output, so the post-load intr poll sees IF=1 without waiting
5701+
# for the next new_instruction edge. Real 8086 takes pending
5702+
# interrupts right after IRET.
56805703
p 00 00000 00001 0532
56815704
p 01 00000 00001 5889
56825705
p 01 00000 00001 0000
@@ -5711,10 +5734,14 @@ p 00 00000 00001 0538
57115734
p 01 00000 00001 4DDF
57125735
p 01 00000 00001 0000
57135736
#
5714-
# Jump unconditional to common code that waits for prefetch queue, then returns to main loop skipping all interrupts.
5737+
# Jump to PFQ-wait entry of the with-INT-poll ending (0xFCB). Real
5738+
# 8086 only delays interrupt recognition after STI / MOV SS / POP SS;
5739+
# IRET should NOT defer — the BIOS timer ISR returns via IRET and
5740+
# expects the NEXT 18.2Hz tick to be taken immediately if it lands
5741+
# during IRET. Was 0x0474 (legacy skip-INT path used by POP/MOV SS).
57155742
p 00 00000 00001 0539
57165743
p 01 00000 00001 1000
5717-
p 01 00000 00001 0474
5744+
p 01 00000 00001 0FCB
57185745
#
57195746
# -----------------------------------------------------
57205747
#

MCL86jr/FPGA/src4synth/MCL86_Microcode_Xilinx_Version_7.coe

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

MCL86jr/FPGA/src4synth/eu.v

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,22 @@ else
405405

406406
// Delay the INTR enable flag until after the next instruction begins.
407407
// No delay when it is disabled.
408-
if (eu_flag_i==1'b0)
408+
// Exception: when the microcode is executing IRET's "OR r0 into
409+
// FLAGS" step, update intr_enable_delayed in the same cycle
410+
// directly from bit 9 of the ALU output (= the new popped IF).
411+
// The microcode word is at ROM address 0x0532; ROM has 1-cycle
412+
// synchronous read, so eu_rom_data shows that word when
413+
// eu_rom_address has advanced to 0x0533. Must come BEFORE the
414+
// eu_flag_i==0 short-circuit because eu_flag_i is still the OLD
415+
// value at this point (typically 0 — we're returning from an ISR
416+
// that ran with CLI). Real 8086 only delays interrupt recognition
417+
// after STI / MOV SS / POP SS — not after IRET.
418+
if (eu_stall_pipeline==1'b0 && eu_opcode_type!=3'h0 && eu_opcode_type!=3'h1
419+
&& eu_rom_address==13'h0533)
420+
begin
421+
intr_enable_delayed <= eu_alu_out[9];
422+
end
423+
else if (eu_flag_i==1'b0)
409424
begin
410425
intr_enable_delayed <= 1'b0;
411426
end
@@ -623,7 +638,7 @@ else
623638
4'hB : eu_register_r2 <= eu_alu_out[15:0];
624639
4'hC : eu_register_r3 <= eu_alu_out[15:0];
625640
4'hD : eu_biu_command <= eu_alu_out[15:0];
626-
//4'hE : ;
641+
//4'hE : ;
627642
4'hF : eu_biu_dataout <= eu_alu_out[15:0];
628643
default : ;
629644
endcase

0 commit comments

Comments
 (0)