The global interrupt enable is the output of the status register, which gets written at the end of E1 of the GIE instruction.
There is another register stage delay between the logical interrupt signal below and the "ic_irq" interrupt signal that goes to CPU pipeline and is responsible for saving the PC in the iret.
If we align the GIE and IDLE instructions on a 64 bit boundary in the code as a workaround, then we know that they will enter the pipeline together on consecutive cycles guaranteeing that the interrupt cannot sneak between the GIE and IDLE instructions (really on the GIE instruction). I agree it would have been better to enable interrupts automatically with the IDLE instruction.. but sometimes you get lucky
Here's the key RTL code snippet..
assign ic_irq_select[IRQW-1:0]= ic_masked_ilat[IRQW-1:0] & //only if the ILAT bit is not masked by IMASK
~ic_ilat_priority_en_n[IRQW-1:0] & //only if there is no masked ilat bit <current
~ic_ipend_priority_en_n[IRQW-1:0] & //only if there is no ipend bit <=current
ic_global_en[IRQW-1:0]; //global vector for nested interrupts
always @ (posedge clk or posedge reset)
if(reset)
ic_irq_entry[IRQW-1:0] <= {(IRQW){1'b0}};
else if(clk_en)
if(~sq_ic_wait) // safety stall signal
ic_irq_entry[IRQW-1:0] <= ic_irq_select[IRQW-1:0];// & ~ic_irq_entry[IRQW-1:0] ;
assign ic_irq =|(ic_irq_entry[IRQW-1:0]); //interrupt pipeline
assign ic_flush =|(ic_irq_select[IRQW-1:0]); //flush pipeline