stack-machine/irq_ctl.v

174 lines
4.7 KiB
Verilog

// synthesis attribute slice_utilization_ratio of IRQ_CTL is 7;
module IRQ_CTL (CLK_I, RST_I, IRQ_O, IADR_O, IACK_I,
ADR_I, DAT_I, DAT_O, STB_I, WE_I, SEL_I, ACK_O,
IRQ7, IRQ6, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0);
// Address layout (bytes):
// 0x00..0x03 IADR0
// 0x04..0x07 IADR1
// 0x08..0x0B IADR2
// 0x0C..0x0F IADR3
// 0x10..0x13 IADR4
// 0x14..0x17 IADR5
// 0x18..0x1B IADR6
// 0x1C..0x1F IADR7
// 0x20 polarity[irq7..irq0]
// 0x21 trigger[irq7..irq0]
// 0x22 mask[irq7..irq0]
// 0x23 status[irq7..irq0]
// 0x24..0x3F reserved (0)
// Triggers
`define TR_LEVEL 1'b0
`define TR_EDGE 1'b1
// Polarities
`define PL_LOW 1'b0
`define PL_HIGH 1'b1
`define PE_FALLING 1'b0
`define PE_RISING 1'b1
input CLK_I, RST_I, IACK_I, STB_I, WE_I;
output IRQ_O, ACK_O;
output [31:0] IADR_O;
input [3:0] ADR_I;
input [31:0] DAT_I;
output [31:0] DAT_O;
input [3:0] SEL_I;
input IRQ7, IRQ6, IRQ5, IRQ4;
input IRQ3, IRQ2, IRQ1, IRQ0;
// synthesis attribute ram_style of IADR is distributed;
reg [31:0] IADR[0:7];
reg [7:0] TRIGGER = 8'h00;
reg [7:0] POLARITY = 8'hFF;
reg [7:0] MASK = 8'h00;
reg [7:0] STATUS = 8'h00;
reg [7:0] PREV_IRQS = 8'h00;
reg [7:0] DELIVERED = 8'h00;
wire [7:0] PRIO_MASK = ~( DELIVERED | (DELIVERED<<1) | (DELIVERED<<2) | (DELIVERED<<3) |
(DELIVERED<<4) | (DELIVERED<<5) | (DELIVERED<<6) | (DELIVERED<<7) );
wire [7:0] IRQS = { IRQ7, IRQ6, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 };
wire [7:0] MASKED_IRQS = STATUS & MASK & PRIO_MASK;
// synthesis attribute priority_extract of HIGHEST_IRQ is force;
reg [2:0] HIGHEST_IRQ;
always @*
begin
if (MASKED_IRQS[0]) HIGHEST_IRQ <= 3'b000;
else if (MASKED_IRQS[1]) HIGHEST_IRQ <= 3'b001;
else if (MASKED_IRQS[2]) HIGHEST_IRQ <= 3'b010;
else if (MASKED_IRQS[3]) HIGHEST_IRQ <= 3'b011;
else if (MASKED_IRQS[4]) HIGHEST_IRQ <= 3'b100;
else if (MASKED_IRQS[5]) HIGHEST_IRQ <= 3'b101;
else if (MASKED_IRQS[6]) HIGHEST_IRQ <= 3'b110;
else if (MASKED_IRQS[7]) HIGHEST_IRQ <= 3'b111;
else HIGHEST_IRQ <= 3'bXXX;
end
// synthesis attribute decoder_extract of HIGHEST_BIT is yes;
reg [7:0] HIGHEST_BIT;
always @*
begin
case (HIGHEST_IRQ)
3'b000: HIGHEST_BIT <= 8'b00000001;
3'b001: HIGHEST_BIT <= 8'b00000010;
3'b010: HIGHEST_BIT <= 8'b00000100;
3'b011: HIGHEST_BIT <= 8'b00001000;
3'b100: HIGHEST_BIT <= 8'b00010000;
3'b101: HIGHEST_BIT <= 8'b00100000;
3'b110: HIGHEST_BIT <= 8'b01000000;
default: HIGHEST_BIT <= 8'b10000000;
endcase
end
wire [7:0] CLEAR_IRQS =
(STB_I & WE_I & (ADR_I == 4'b1000) & SEL_I[0]) ? DAT_I[7:0] : 8'h00;
// T[x] P[x] PIRQ[x] IRQ[x] | triggered
// 0 0 0 0 | 1
// 0 0 0 1 | 0
// 0 0 1 0 | 1
// 0 0 1 1 | 0
//
// 0 1 0 0 | 0
// 0 1 0 1 | 1
// 0 1 1 0 | 0
// 0 1 1 1 | 1
//
// 1 0 0 0 | 0
// 1 0 0 1 | 0
// 1 0 1 0 | 1
// 1 0 1 1 | 0
//
// 1 1 0 0 | 0
// 1 1 0 1 | 1
// 1 1 1 0 | 0
// 1 1 1 1 | 0
wire [7:0] TRIGGERED_IRQS;
generate
genvar i;
for (i=0; i<=7; i=i+1)
begin : trigger_luts
LUT4 #(
.INIT(16'b0010_0100_1010_0101)
) TriggerLUT (
.I3(TRIGGER[i]),
.I2(POLARITY[i]),
.I1(PREV_IRQS[i]),
.I0(IRQS[i]),
.O(TRIGGERED_IRQS[i])
);
end
endgenerate
always @(posedge CLK_I)
begin
if (RST_I)
begin
TRIGGER <= 8'h00;
POLARITY <= 8'hFF;
MASK <= 8'h00;
STATUS <= 8'h00;
PREV_IRQS <= 8'h00;
DELIVERED <= 8'h00;
end
else
begin
STATUS <= (STATUS & ~CLEAR_IRQS) | TRIGGERED_IRQS;
PREV_IRQS <= IRQS;
if (IACK_I)
DELIVERED <= (DELIVERED & ~CLEAR_IRQS) | HIGHEST_BIT;
else
DELIVERED <= (DELIVERED & ~CLEAR_IRQS);
if (STB_I & WE_I & ~ADR_I[3])
IADR[ADR_I[2:0]] <= DAT_I;
if (STB_I & WE_I & (ADR_I == 4'b1000))
begin
if (SEL_I[3]) TRIGGER <= DAT_I[31:24];
if (SEL_I[2]) POLARITY <= DAT_I[23:16];
if (SEL_I[1]) MASK <= DAT_I[15: 8];
end
end
end
wire [31:0] IADR_DATA, TPMS_DATA;
assign IADR_O = IADR[HIGHEST_IRQ];
assign IADR_DATA = IADR[ADR_I[2:0]];
assign IRQ_O = |MASKED_IRQS;
assign ACK_O = STB_I;
assign TPMS_DATA = { TRIGGER, POLARITY, MASK, STATUS };
assign DAT_O = ~ADR_I[3] ? IADR_DATA : TPMS_DATA;
endmodule