Commit e8e1b0e9 authored by Jens Korinth's avatar Jens Korinth

Improve MSI-X interrupt controller for many channels (JAH)

parent 063c48e6
......@@ -427,7 +427,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>076f858a</spirit:value>
<spirit:value>01578a37</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
......@@ -443,7 +443,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>076f858a</spirit:value>
<spirit:value>01578a37</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
......@@ -810,7 +810,7 @@
<spirit:wire>
<spirit:direction>in</spirit:direction>
<spirit:vector>
<spirit:left spirit:format="long">7</spirit:left>
<spirit:left spirit:format="long">255</spirit:left>
<spirit:right spirit:format="long">0</spirit:right>
</spirit:vector>
<spirit:wireTypeDefs>
......@@ -1248,6 +1248,14 @@
<spirit:fileSets>
<spirit:fileSet>
<spirit:name>xilinx_anylanguagesynthesis_view_fileset</spirit:name>
<spirit:file>
<spirit:name>src/SizedFIFO.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
</spirit:file>
<spirit:file>
<spirit:name>src/BRAM2BE.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
</spirit:file>
<spirit:file>
<spirit:name>src/FIFO2.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
......@@ -1259,11 +1267,19 @@
<spirit:file>
<spirit:name>src/mkMSIXIntrCtrl.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
<spirit:userFileType>CHECKSUM_5d943023</spirit:userFileType>
<spirit:userFileType>CHECKSUM_ca68e109</spirit:userFileType>
</spirit:file>
</spirit:fileSet>
<spirit:fileSet>
<spirit:name>xilinx_anylanguagebehavioralsimulation_view_fileset</spirit:name>
<spirit:file>
<spirit:name>src/SizedFIFO.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
</spirit:file>
<spirit:file>
<spirit:name>src/BRAM2BE.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
</spirit:file>
<spirit:file>
<spirit:name>src/FIFO2.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
......@@ -1307,7 +1323,7 @@
<xilinx:displayName>MSIXIntrCtrl</xilinx:displayName>
<xilinx:definitionSource>package_project</xilinx:definitionSource>
<xilinx:coreRevision>1</xilinx:coreRevision>
<xilinx:coreCreationDateTime>2017-06-01T15:06:02Z</xilinx:coreCreationDateTime>
<xilinx:coreCreationDateTime>2017-06-02T07:28:21Z</xilinx:coreCreationDateTime>
<xilinx:tags>
<xilinx:tag xilinx:name="nopcore"/>
</xilinx:tags>
......@@ -1317,8 +1333,8 @@
<xilinx:checksum xilinx:scope="busInterfaces" xilinx:value="a9103989"/>
<xilinx:checksum xilinx:scope="addressSpaces" xilinx:value="39f94240"/>
<xilinx:checksum xilinx:scope="memoryMaps" xilinx:value="f3632d96"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="acf5da4d"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="06aeec95"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="a71d4d09"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="25002ad1"/>
<xilinx:checksum xilinx:scope="parameters" xilinx:value="4b2b81b7"/>
</xilinx:packagingInfo>
</spirit:vendorExtensions>
......
// Copyright (c) 2000-2011 Bluespec, Inc.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// $Revision$
// $Date$
`ifdef BSV_ASSIGNMENT_DELAY
`else
`define BSV_ASSIGNMENT_DELAY
`endif
// Dual-Ported BRAM (WRITE FIRST) with byte enables
module BRAM2BE(CLKA,
ENA,
WEA,
ADDRA,
DIA,
DOA,
CLKB,
ENB,
WEB,
ADDRB,
DIB,
DOB
);
parameter PIPELINED = 0;
parameter ADDR_WIDTH = 1;
parameter DATA_WIDTH = 1;
parameter CHUNKSIZE = 1;
parameter WE_WIDTH = 1;
parameter MEMSIZE = 1;
input CLKA;
input ENA;
input [WE_WIDTH-1:0] WEA;
input [ADDR_WIDTH-1:0] ADDRA;
input [DATA_WIDTH-1:0] DIA;
output [DATA_WIDTH-1:0] DOA;
input CLKB;
input ENB;
input [WE_WIDTH-1:0] WEB;
input [ADDR_WIDTH-1:0] ADDRB;
input [DATA_WIDTH-1:0] DIB;
output [DATA_WIDTH-1:0] DOB;
(* RAM_STYLE = "BLOCK" *)
reg [DATA_WIDTH-1:0] RAM[0:MEMSIZE-1] /* synthesis syn_ramstyle="no_rw_check" */ ;
reg [DATA_WIDTH-1:0] DOA_R;
reg [DATA_WIDTH-1:0] DOA_R2;
reg [DATA_WIDTH-1:0] DOB_R;
reg [DATA_WIDTH-1:0] DOB_R2;
`ifdef BSV_NO_INITIAL_BLOCKS
`else
// synopsys translate_off
integer i;
initial
begin : init_block
for (i = 0; i < MEMSIZE; i = i + 1) begin
RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } };
end
DOA_R = { ((DATA_WIDTH+1)/2) { 2'b10 } };
DOA_R2 = { ((DATA_WIDTH+1)/2) { 2'b10 } };
DOB_R = { ((DATA_WIDTH+1)/2) { 2'b10 } };
DOB_R2 = { ((DATA_WIDTH+1)/2) { 2'b10 } };
end
// synopsys translate_on
`endif // !`ifdef BSV_NO_INITIAL_BLOCKS
// PORT A
// iverilog does not support the full verilog-2001 language. This fixes that for simulation.
`ifdef __ICARUS__
reg [DATA_WIDTH-1:0] MASKA, IMASKA;
reg [DATA_WIDTH-1:0] DATA_A;
wire [DATA_WIDTH-1:0] DATA_Awr;
assign DATA_Awr = RAM[ADDRA];
always @(WEA or DIA or DATA_Awr) begin : combo1
integer j;
MASKA = 0;
IMASKA = 0;
for(j = WE_WIDTH-1; j >= 0; j = j - 1) begin
if (WEA[j]) MASKA = (MASKA << 8) | { { DATA_WIDTH-CHUNKSIZE { 1'b0 } }, { CHUNKSIZE { 1'b1 } } };
else MASKA = (MASKA << 8);
end
IMASKA = ~MASKA;
DATA_A = (DATA_Awr & IMASKA) | (DIA & MASKA);
end
always @(posedge CLKA) begin
if (ENA) begin
if (WEA) begin
RAM[ADDRA] <= `BSV_ASSIGNMENT_DELAY DATA_A;
DOA_R <= `BSV_ASSIGNMENT_DELAY DATA_A;
end
else begin
DOA_R <= `BSV_ASSIGNMENT_DELAY RAM[ADDRA];
end
end
end
`else
generate
genvar j;
for(j = 0; j < WE_WIDTH; j = j + 1) begin: porta_we
always @(posedge CLKA) begin
if (ENA) begin
if (WEA[j]) begin
RAM[ADDRA][((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY DIA[((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE];
DOA_R[((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY DIA[((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE];
end
else begin
DOA_R[((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY RAM[ADDRA][((j+1)*CHUNKSIZE)-1 : j*CHUNKSIZE];
end
end
end
end
endgenerate
`endif // !`ifdef __ICARUS__
// PORT B
// iverilog does not support the full verilog-2001 language. This fixes that for simulation.
`ifdef __ICARUS__
reg [DATA_WIDTH-1:0] MASKB, IMASKB;
reg [DATA_WIDTH-1:0] DATA_B;
wire [DATA_WIDTH-1:0] DATA_Bwr;
assign DATA_Bwr = RAM[ADDRB];
always @(WEB or DIB or DATA_Bwr) begin : combo2
integer j;
MASKB = 0;
IMASKB = 0;
for(j = WE_WIDTH-1; j >= 0; j = j - 1) begin
if (WEB[j]) MASKB = (MASKB << 8) | { { DATA_WIDTH-CHUNKSIZE { 1'b0 } }, { CHUNKSIZE { 1'b1 } } };
else MASKB = (MASKB << 8);
end
IMASKB = ~MASKB;
DATA_B = (DATA_Bwr & IMASKB) | (DIB & MASKB);
end
always @(posedge CLKB) begin
if (ENB) begin
if (WEB) begin
RAM[ADDRB] <= `BSV_ASSIGNMENT_DELAY DATA_B;
DOB_R <= `BSV_ASSIGNMENT_DELAY DATA_B;
end
else begin
DOB_R <= `BSV_ASSIGNMENT_DELAY RAM[ADDRB];
end
end
end
`else
generate
genvar k;
for(k = 0; k < WE_WIDTH; k = k + 1) begin: portb_we
always @(posedge CLKB) begin
if (ENB) begin
if (WEB[k]) begin
RAM[ADDRB][((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY DIB[((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE];
DOB_R[((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY DIB[((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE];
end
else begin
DOB_R[((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE] <= `BSV_ASSIGNMENT_DELAY RAM[ADDRB][((k+1)*CHUNKSIZE)-1 : k*CHUNKSIZE];
end
end
end
end
endgenerate
`endif // !`ifdef __ICARUS__
// Output drivers
always @(posedge CLKA) begin
DOA_R2 <= `BSV_ASSIGNMENT_DELAY DOA_R;
end
always @(posedge CLKB) begin
DOB_R2 <= `BSV_ASSIGNMENT_DELAY DOB_R;
end
assign DOA = (PIPELINED) ? DOA_R2 : DOA_R;
assign DOB = (PIPELINED) ? DOB_R2 : DOB_R;
endmodule // BRAM2BE
// Copyright (c) 2000-2012 Bluespec, Inc.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// $Revision$
// $Date$
`ifdef BSV_ASSIGNMENT_DELAY
`else
`define BSV_ASSIGNMENT_DELAY
`endif
`ifdef BSV_POSITIVE_RESET
`define BSV_RESET_VALUE 1'b1
`define BSV_RESET_EDGE posedge
`else
`define BSV_RESET_VALUE 1'b0
`define BSV_RESET_EDGE negedge
`endif
`ifdef BSV_ASYNC_RESET
`define BSV_ARESET_EDGE_META or `BSV_RESET_EDGE RST
`else
`define BSV_ARESET_EDGE_META
`endif
`ifdef BSV_RESET_FIFO_HEAD
`define BSV_ARESET_EDGE_HEAD `BSV_ARESET_EDGE_META
`else
`define BSV_ARESET_EDGE_HEAD
`endif
`ifdef BSV_RESET_FIFO_ARRAY
`define BSV_ARESET_EDGE_ARRAY `BSV_ARESET_EDGE_META
`else
`define BSV_ARESET_EDGE_ARRAY
`endif
// Sized fifo. Model has output register which improves timing
module SizedFIFO(CLK, RST, D_IN, ENQ, FULL_N, D_OUT, DEQ, EMPTY_N, CLR);
parameter p1width = 1; // data width
parameter p2depth = 3;
parameter p3cntr_width = 1; // log(p2depth-1)
// The -1 is allowed since this model has a fast output register
parameter guarded = 1;
localparam p2depth2 = (p2depth >= 2) ? (p2depth -2) : 0 ;
input CLK;
input RST;
input CLR;
input [p1width - 1 : 0] D_IN;
input ENQ;
input DEQ;
output FULL_N;
output EMPTY_N;
output [p1width - 1 : 0] D_OUT;
reg not_ring_full;
reg ring_empty;
reg [p3cntr_width-1 : 0] head;
wire [p3cntr_width-1 : 0] next_head;
reg [p3cntr_width-1 : 0] tail;
wire [p3cntr_width-1 : 0] next_tail;
// if the depth is too small, don't create an ill-sized array;
// instead, make a 1-sized array and let the initial block report an error
(* RAM_STYLE = "DISTRIBUTED" *)
reg [p1width - 1 : 0] arr[0: p2depth2];
reg [p1width - 1 : 0] D_OUT;
reg hasodata;
wire [p3cntr_width-1:0] depthLess2 = p2depth2[p3cntr_width-1:0] ;
wire [p3cntr_width-1 : 0] incr_tail;
wire [p3cntr_width-1 : 0] incr_head;
assign incr_tail = tail + 1'b1 ;
assign incr_head = head + 1'b1 ;
assign next_head = (head == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_head ;
assign next_tail = (tail == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_tail ;
assign EMPTY_N = hasodata;
assign FULL_N = not_ring_full;
`ifdef BSV_NO_INITIAL_BLOCKS
`else // not BSV_NO_INITIAL_BLOCKS
// synopsys translate_off
initial
begin : initial_block
integer i;
D_OUT = {((p1width + 1)/2){2'b10}} ;
ring_empty = 1'b1;
not_ring_full = 1'b1;
hasodata = 1'b0;
head = {p3cntr_width {1'b0}} ;
tail = {p3cntr_width {1'b0}} ;
for (i = 0; i <= p2depth2; i = i + 1)
begin
arr[i] = D_OUT ;
end
end
// synopsys translate_on
`endif // BSV_NO_INITIAL_BLOCKS
always @(posedge CLK `BSV_ARESET_EDGE_META)
begin
if (RST == `BSV_RESET_VALUE)
begin
head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ;
tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ;
ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1;
not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1;
hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0;
end // if (RST == `BSV_RESET_VALUE)
else
begin
casez ({CLR, DEQ, ENQ, hasodata, ring_empty})
// Clear operation
5'b1????: begin
head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ;
tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ;
ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1;
not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1;
hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0;
end
// -----------------------
// DEQ && ENQ case -- change head and tail if added to ring
5'b011?0: begin
tail <= `BSV_ASSIGNMENT_DELAY next_tail;
head <= `BSV_ASSIGNMENT_DELAY next_head;
end
// -----------------------
// DEQ only and NO data is in ring
5'b010?1: begin
hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0;
end
// DEQ only and data is in ring (move the head pointer)
5'b010?0: begin
head <= `BSV_ASSIGNMENT_DELAY next_head;
not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1;
ring_empty <= `BSV_ASSIGNMENT_DELAY next_head == tail ;
end
// -----------------------
// ENQ only when empty
5'b0010?: begin
hasodata <= `BSV_ASSIGNMENT_DELAY 1'b1;
end
// ENQ only when not empty
5'b0011?: begin
if ( not_ring_full ) // Drop this test to save redundant test
// but be warnned that with test fifo overflow causes loss of new data
// while without test fifo drops all but head entry! (pointer overflow)
begin
tail <= `BSV_ASSIGNMENT_DELAY next_tail;
ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b0;
not_ring_full <= `BSV_ASSIGNMENT_DELAY ! (next_tail == head) ;
end
end
endcase
end // else: !if(RST == `BSV_RESET_VALUE)
end // always @ (posedge CLK)
// Update the fast data out register
always @(posedge CLK `BSV_ARESET_EDGE_HEAD)
begin
`ifdef BSV_RESET_FIFO_HEAD
if (RST == `BSV_RESET_VALUE)
begin
D_OUT <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ;
end // if (RST == `BSV_RESET_VALUE)
else
`endif
begin
casez ({CLR, DEQ, ENQ, hasodata, ring_empty})
// DEQ && ENQ cases
5'b011?0: begin D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; end
5'b011?1: begin D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; end
// DEQ only and data is in ring
5'b010?0: begin D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; end
// ENQ only when empty
5'b0010?: begin D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; end
endcase
end // else: !if(RST == `BSV_RESET_VALUE)
end // always @ (posedge CLK)
// Update the memory array reset is OFF
always @(posedge CLK `BSV_ARESET_EDGE_ARRAY)
begin: array
`ifdef BSV_RESET_FIFO_ARRAY
if (RST == `BSV_RESET_VALUE)
begin: rst_array
integer i;
for (i = 0; i <= p2depth2 && p2depth > 2; i = i + 1)
begin
arr[i] <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ;
end
end // if (RST == `BSV_RESET_VALUE)
else
`endif
begin
if (!CLR && ENQ && ((DEQ && !ring_empty) || (!DEQ && hasodata && not_ring_full)))
begin
arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN;
end
end // else: !if(RST == `BSV_RESET_VALUE)
end // always @ (posedge CLK)
// synopsys translate_off
always@(posedge CLK)
begin: error_checks
reg deqerror, enqerror ;
deqerror = 0;
enqerror = 0;
if (RST == ! `BSV_RESET_VALUE)
begin
if ( ! EMPTY_N && DEQ )
begin
deqerror = 1 ;
$display( "Warning: SizedFIFO: %m -- Dequeuing from empty fifo" ) ;
end
if ( ! FULL_N && ENQ && (!DEQ || guarded) )
begin
enqerror = 1 ;
$display( "Warning: SizedFIFO: %m -- Enqueuing to a full fifo" ) ;
end
end
end // block: error_checks
// synopsys translate_on
// synopsys translate_off
// Some assertions about parameter values
initial
begin : parameter_assertions
integer ok ;
ok = 1 ;
if ( p2depth <= 1)
begin
ok = 0;
$display ( "Warning SizedFIFO: %m -- depth parameter increased from %0d to 2", p2depth);
end
if ( p3cntr_width <= 0 )
begin
ok = 0;
$display ( "ERROR SizedFIFO: %m -- width parameter must be greater than 0" ) ;
end
if ( ok == 0 ) $finish ;
end // initial begin
// synopsys translate_on
endmodule
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment