`timescale 1ns / 1ps /** Interrupt Controller -- Control data (wrc): * [0]: set interrupt number for subsequent setting of the isr handler, [8+IntNumBits-1:8] is the isr number * [1]: enable interrupt, [8+NumInt-1:8] is the isr bitmap: bit = 1 enables the int, bit = 0 does not change the enabled status * [2]: disable interrupt, [8+NumInt-1:8] is the isr bitmap; bit = 1 disables the int, bit = 0 does not change the enabled status * [3]: trigger interrupt from software, [8+NumInt-1:8] is the isr number -- (c) 2020 - 2021 Gray, gray@grayraven.org https://oberon-rts.org/licences **/ module INTCTRL2 #(parameter NumInt = 4) ( input rst, clk, input wrc, wr, rti, // write ctrl data, write ISR data, return from interrupt signal input [NumInt-1:0] irq, // interrupt lines input [31:0] data, // bus for all data output reg [31:0] vdata, // ISR branch instruction that the CPU will load upon 'irqout' output reg irqout = 0, // interrupt line to the CPU, asserted 1 until rti = 1 output [NumInt-1:0] enabled // read enabled status via device IO ); localparam IntNumBits = $clog2(NumInt); reg [IntNumBits-1:0] setnum = 0; // interrupt number to set ISR in subsequent 'wr' reg [31:0] itab [NumInt-1:0]; // ISR table (contents: BR to address, as for RISC5 interrupt) reg [NumInt-1:0] intEn = 0; // bitmap: enabled interrupts reg [NumInt-1:0] intPnd = 0; // bitmap: pending interrupts reg [NumInt-1:0] swiTrig = 0; // bitmap: software-triggered interrupts assign enabled = intEn; // controls wire snum = wrc & data[0]; wire ien = wrc & data[1]; wire idi = wrc & data[2]; wire swi = wrc & data[3]; reg [NumInt-1:0] irq1; // for 'irq' edge detection integer i, j; always @(posedge clk) begin irq1 <= irq; intPnd <= ~rst ? 0 : intEn & ((irq & ~irq1) | swiTrig | intPnd); setnum <= snum ? data[8+IntNumBits-1:8] : setnum; itab[setnum] <= wr ? data : itab[setnum]; intEn <= ~rst ? 0 : ien ? (intEn | data[8+NumInt-1:8]) : idi ? (intEn & ~data[8+NumInt-1:8]) : intEn; swiTrig <= ~rst ? 0 : swi ? (swiTrig | data[8+NumInt-1:8]) : swiTrig; irqout <= ~rst | rti ? 0 : irqout; if (~irqout) begin i = 0; j = 1; while (i < NumInt && j > 0) begin if (intPnd[i]) begin vdata <= itab[i]; intPnd[i] <= 0; swiTrig[i] <= 0; irqout <= 1; j = 0; end i = i+1; end end end endmodule