mirror of
https://github.com/corundum/corundum.git
synced 2025-01-30 08:32:52 +08:00
merged changes in pcie
This commit is contained in:
commit
2a69e07acb
274
fpga/lib/pcie/rtl/irq_rate_limit.v
Normal file
274
fpga/lib/pcie/rtl/irq_rate_limit.v
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2022 Alex Forencich
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* IRQ rate limit module
|
||||
*/
|
||||
module irq_rate_limit #
|
||||
(
|
||||
// Interrupt configuration
|
||||
parameter IRQ_INDEX_WIDTH = 11
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* Interrupt request input
|
||||
*/
|
||||
input wire [IRQ_INDEX_WIDTH-1:0] in_irq_index,
|
||||
input wire in_irq_valid,
|
||||
output wire in_irq_ready,
|
||||
|
||||
/*
|
||||
* Interrupt request output
|
||||
*/
|
||||
output wire [IRQ_INDEX_WIDTH-1:0] out_irq_index,
|
||||
output wire out_irq_valid,
|
||||
input wire out_irq_ready,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [15:0] prescale,
|
||||
input wire [15:0] min_interval
|
||||
);
|
||||
|
||||
localparam [1:0]
|
||||
STATE_INIT = 2'd0,
|
||||
STATE_IDLE = 2'd1,
|
||||
STATE_IRQ_IN = 2'd2,
|
||||
STATE_IRQ_OUT = 2'd3;
|
||||
|
||||
reg [1:0] state_reg = STATE_INIT, state_next;
|
||||
|
||||
reg [IRQ_INDEX_WIDTH-1:0] cur_index_reg = 0, cur_index_next;
|
||||
reg [IRQ_INDEX_WIDTH-1:0] irq_index_reg = 0, irq_index_next;
|
||||
|
||||
reg mem_rd_en;
|
||||
reg mem_wr_en;
|
||||
reg [IRQ_INDEX_WIDTH-1:0] mem_addr;
|
||||
reg [17+1+1-1:0] mem_wr_data;
|
||||
reg [17+1+1-1:0] mem_rd_data_reg;
|
||||
reg mem_rd_data_valid_reg = 1'b0, mem_rd_data_valid_next;
|
||||
|
||||
(* ramstyle = "no_rw_check, mlab" *)
|
||||
reg [17+1+1-1:0] mem_reg[2**IRQ_INDEX_WIDTH-1:0];
|
||||
|
||||
reg in_irq_ready_reg = 0, in_irq_ready_next;
|
||||
|
||||
reg [IRQ_INDEX_WIDTH-1:0] out_irq_index_reg = 0, out_irq_index_next;
|
||||
reg out_irq_valid_reg = 0, out_irq_valid_next;
|
||||
|
||||
assign in_irq_ready = in_irq_ready_reg;
|
||||
|
||||
assign out_irq_index = out_irq_index_reg;
|
||||
assign out_irq_valid = out_irq_valid_reg;
|
||||
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
for (i = 0; i < 2**IRQ_INDEX_WIDTH; i = i + 1) begin
|
||||
mem_reg[i] = 0;
|
||||
end
|
||||
end
|
||||
|
||||
reg [15:0] prescale_count_reg = 0;
|
||||
reg [16:0] time_count_reg = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (prescale_count_reg != 0) begin
|
||||
prescale_count_reg <= prescale_count_reg - 1;
|
||||
end else begin
|
||||
prescale_count_reg <= prescale;
|
||||
time_count_reg <= time_count_reg + 1;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
prescale_count_reg <= 0;
|
||||
time_count_reg <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_INIT;
|
||||
|
||||
cur_index_next = cur_index_reg;
|
||||
irq_index_next = irq_index_reg;
|
||||
|
||||
in_irq_ready_next = 1'b0;
|
||||
|
||||
out_irq_index_next = out_irq_index_reg;
|
||||
out_irq_valid_next = out_irq_valid_reg && !out_irq_ready;
|
||||
|
||||
mem_rd_en = 1'b0;
|
||||
mem_wr_en = 1'b0;
|
||||
mem_addr = cur_index_reg;
|
||||
mem_wr_data = mem_rd_data_reg;
|
||||
mem_rd_data_valid_next = mem_rd_data_valid_reg;
|
||||
|
||||
case (state_reg)
|
||||
STATE_INIT: begin
|
||||
// init - clear all timers
|
||||
mem_addr = cur_index_reg;
|
||||
mem_wr_data[0] = 1'b0;
|
||||
mem_wr_data[1] = 1'b0;
|
||||
mem_wr_data[2 +: 17] = 0;
|
||||
mem_wr_en = 1'b1;
|
||||
cur_index_next = cur_index_reg + 1;
|
||||
if (cur_index_next != 0) begin
|
||||
state_next = STATE_INIT;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_IDLE: begin
|
||||
// idle - wait for requests and check timers
|
||||
in_irq_ready_next = 1'b1;
|
||||
if (in_irq_valid && in_irq_ready) begin
|
||||
// new interrupt request
|
||||
irq_index_next = in_irq_index;
|
||||
mem_addr = in_irq_index;
|
||||
mem_rd_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b1;
|
||||
in_irq_ready_next = 1'b0;
|
||||
state_next = STATE_IRQ_IN;
|
||||
end else if (mem_rd_data_valid_reg && mem_rd_data_reg[1] && (mem_rd_data_reg[2 +: 17] - time_count_reg) >> 16 != 0) begin
|
||||
// timer expired
|
||||
in_irq_ready_next = 1'b0;
|
||||
state_next = STATE_IRQ_OUT;
|
||||
end else begin
|
||||
// read next timer
|
||||
irq_index_next = cur_index_reg;
|
||||
mem_addr = cur_index_reg;
|
||||
mem_rd_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b1;
|
||||
cur_index_next = cur_index_reg + 1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_IRQ_IN: begin
|
||||
// pass through IRQ
|
||||
if (mem_rd_data_reg[1]) begin
|
||||
// timer running, set pending bit
|
||||
mem_addr = irq_index_reg;
|
||||
mem_wr_data[0] = 1'b1;
|
||||
mem_wr_data[1] = 1'b1;
|
||||
mem_wr_data[2 +: 17] = mem_rd_data_reg[2 +: 17];
|
||||
mem_wr_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b0;
|
||||
|
||||
in_irq_ready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end else if (!out_irq_valid || out_irq_ready) begin
|
||||
// timer not running, start timer and generate IRQ
|
||||
mem_addr = irq_index_reg;
|
||||
mem_wr_data[0] = 1'b0;
|
||||
mem_wr_data[1] = min_interval != 0;
|
||||
mem_wr_data[2 +: 17] = time_count_reg + min_interval;
|
||||
mem_wr_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b0;
|
||||
|
||||
out_irq_valid_next = 1'b1;
|
||||
out_irq_index_next = irq_index_reg;
|
||||
|
||||
in_irq_ready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
state_next = STATE_IRQ_IN;
|
||||
end
|
||||
end
|
||||
STATE_IRQ_OUT: begin
|
||||
// handle timer expiration
|
||||
if (mem_rd_data_reg[0]) begin
|
||||
// pending bit set, generate IRQ and restart timer
|
||||
if (!out_irq_valid || out_irq_ready) begin
|
||||
mem_addr = irq_index_reg;
|
||||
mem_wr_data[0] = 1'b0;
|
||||
mem_wr_data[1] = min_interval != 0;
|
||||
mem_wr_data[2 +: 17] = time_count_reg + min_interval;
|
||||
mem_wr_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b0;
|
||||
|
||||
out_irq_valid_next = 1'b1;
|
||||
out_irq_index_next = irq_index_reg;
|
||||
|
||||
in_irq_ready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
state_next = STATE_IRQ_OUT;
|
||||
end
|
||||
end else begin
|
||||
// pending bit not set, reset timer
|
||||
mem_addr = irq_index_reg;
|
||||
mem_wr_data[0] = 1'b0;
|
||||
mem_wr_data[1] = 1'b0;
|
||||
mem_wr_data[2 +: 17] = 0;
|
||||
mem_wr_en = 1'b1;
|
||||
mem_rd_data_valid_next = 1'b0;
|
||||
|
||||
in_irq_ready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
cur_index_reg <= cur_index_next;
|
||||
irq_index_reg <= irq_index_next;
|
||||
|
||||
in_irq_ready_reg <= in_irq_ready_next;
|
||||
|
||||
out_irq_index_reg <= out_irq_index_next;
|
||||
out_irq_valid_reg <= out_irq_valid_next;
|
||||
|
||||
if (mem_wr_en) begin
|
||||
mem_reg[mem_addr] <= mem_wr_data;
|
||||
end else if (mem_rd_en) begin
|
||||
mem_rd_data_reg <= mem_reg[mem_addr];
|
||||
end
|
||||
|
||||
mem_rd_data_valid_reg <= mem_rd_data_valid_next;
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_INIT;
|
||||
cur_index_reg <= 0;
|
||||
in_irq_ready_reg <= 1'b0;
|
||||
out_irq_valid_reg <= 1'b0;
|
||||
mem_rd_data_valid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
@ -164,9 +164,7 @@ reg [63:0] tbl_axil_mem_wr_data;
|
||||
reg pba_axil_mem_rd_en;
|
||||
|
||||
reg tbl_mem_rd_en;
|
||||
reg tbl_mem_wr_en;
|
||||
reg [TBL_ADDR_WIDTH-1:0] tbl_mem_addr;
|
||||
reg [63:0] tbl_mem_wr_data;
|
||||
reg pba_mem_rd_en;
|
||||
reg pba_mem_wr_en;
|
||||
reg [PBA_ADDR_WIDTH-1:0] pba_mem_addr;
|
||||
@ -244,9 +242,7 @@ always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
tbl_mem_rd_en = 1'b0;
|
||||
tbl_mem_wr_en = 1'b0;
|
||||
tbl_mem_addr = {irq_index_reg, 1'b0};
|
||||
tbl_mem_wr_data = 0;
|
||||
|
||||
pba_mem_rd_en = 1'b0;
|
||||
pba_mem_wr_en = 1'b0;
|
||||
@ -418,14 +414,12 @@ always @(posedge clk) begin
|
||||
|
||||
if (tbl_mem_rd_en) begin
|
||||
tbl_mem_rd_data_reg <= tbl_mem[tbl_mem_addr];
|
||||
end else if (tbl_mem_wr_en) begin
|
||||
tbl_mem[tbl_mem_addr] <= tbl_mem_wr_data;
|
||||
end
|
||||
|
||||
if (pba_mem_rd_en) begin
|
||||
pba_mem_rd_data_reg <= pba_mem[pba_mem_addr];
|
||||
end else if (pba_mem_wr_en) begin
|
||||
if (pba_mem_wr_en) begin
|
||||
pba_mem[pba_mem_addr] <= pba_mem_wr_data;
|
||||
end else if (pba_mem_rd_en) begin
|
||||
pba_mem_rd_data_reg <= pba_mem[pba_mem_addr];
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
|
@ -455,6 +455,15 @@ always @* begin
|
||||
end
|
||||
end
|
||||
|
||||
eop_index = 0;
|
||||
for (seg = 0; seg < INT_TLP_SEG_COUNT; seg = seg + 1) begin
|
||||
for (lane = 0; lane < INT_TLP_SEG_STRB_WIDTH; lane = lane + 1) begin
|
||||
if (out_tlp_strb[seg*INT_TLP_SEG_STRB_WIDTH+lane]) begin
|
||||
eop_index[seg*3 +: 3] = lane;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (!m_axis_cc_tvalid || m_axis_cc_tready) begin
|
||||
// remap header and sideband
|
||||
m_axis_cc_tdata_next = out_tlp_data;
|
||||
@ -467,13 +476,6 @@ always @* begin
|
||||
if (out_tlp_valid[seg]) begin
|
||||
m_axis_cc_tkeep_next[seg*INT_TLP_SEG_STRB_WIDTH +: INT_TLP_SEG_STRB_WIDTH] = out_tlp_strb[seg*INT_TLP_SEG_STRB_WIDTH +: INT_TLP_SEG_STRB_WIDTH];
|
||||
end
|
||||
|
||||
eop_index[seg*3 +: 3] = 0;
|
||||
for (lane = 0; lane < INT_TLP_SEG_STRB_WIDTH; lane = lane + 1) begin
|
||||
if (out_tlp_strb[seg*INT_TLP_SEG_STRB_WIDTH+lane]) begin
|
||||
eop_index[seg*3 +: 3] = lane;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (AXIS_PCIE_DATA_WIDTH == 512) begin
|
||||
|
68
fpga/lib/pcie/tb/irq_rate_limit/Makefile
Normal file
68
fpga/lib/pcie/tb/irq_rate_limit/Makefile
Normal file
@ -0,0 +1,68 @@
|
||||
# Copyright (c) 2022 Alex Forencich
|
||||
#
|
||||
# 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.
|
||||
|
||||
TOPLEVEL_LANG = verilog
|
||||
|
||||
SIM ?= icarus
|
||||
WAVES ?= 0
|
||||
|
||||
COCOTB_HDL_TIMEUNIT = 1ns
|
||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
||||
|
||||
DUT = irq_rate_limit
|
||||
TOPLEVEL = $(DUT)
|
||||
MODULE = test_$(DUT)
|
||||
VERILOG_SOURCES = ../../rtl/$(DUT).v
|
||||
|
||||
# module parameters
|
||||
export PARAM_IRQ_INDEX_WIDTH ?= 11
|
||||
|
||||
ifeq ($(SIM), icarus)
|
||||
PLUSARGS += -fst
|
||||
|
||||
COMPILE_ARGS += -P $(TOPLEVEL).IRQ_INDEX_WIDTH=$(PARAM_IRQ_INDEX_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
VERILOG_SOURCES += iverilog_dump.v
|
||||
COMPILE_ARGS += -s iverilog_dump
|
||||
endif
|
||||
else ifeq ($(SIM), verilator)
|
||||
COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH
|
||||
|
||||
COMPILE_ARGS += -GIRQ_INDEX_WIDTH=$(PARAM_IRQ_INDEX_WIDTH)
|
||||
|
||||
ifeq ($(WAVES), 1)
|
||||
COMPILE_ARGS += --trace-fst
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
|
||||
iverilog_dump.v:
|
||||
echo 'module iverilog_dump();' > $@
|
||||
echo 'initial begin' >> $@
|
||||
echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@
|
||||
echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
|
||||
echo 'end' >> $@
|
||||
echo 'endmodule' >> $@
|
||||
|
||||
clean::
|
||||
@rm -rf iverilog_dump.v
|
||||
@rm -rf dump.fst $(TOPLEVEL).fst
|
192
fpga/lib/pcie/tb/irq_rate_limit/test_irq_rate_limit.py
Normal file
192
fpga/lib/pcie/tb/irq_rate_limit/test_irq_rate_limit.py
Normal file
@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2022 Alex Forencich
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
|
||||
import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
from cocotbext.axi.stream import define_stream
|
||||
|
||||
|
||||
IrqBus, IrqTransaction, IrqSource, IrqSink, IrqMonitor = define_stream("Irq",
|
||||
signals=["index", "valid", "ready"]
|
||||
)
|
||||
|
||||
|
||||
class TB(object):
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
self.log = logging.getLogger("cocotb.tb")
|
||||
self.log.setLevel(logging.DEBUG)
|
||||
|
||||
cocotb.start_soon(Clock(dut.clk, 4, units="ns").start())
|
||||
|
||||
self.irq_source = IrqSource(IrqBus.from_prefix(dut, "in_irq"), dut.clk, dut.rst)
|
||||
self.irq_sink = IrqSink(IrqBus.from_prefix(dut, "out_irq"), dut.clk, dut.rst)
|
||||
|
||||
dut.prescale.setimmediatevalue(0)
|
||||
dut.min_interval.setimmediatevalue(0)
|
||||
|
||||
def set_idle_generator(self, generator=None):
|
||||
if generator:
|
||||
self.irq_source.set_pause_generator(generator())
|
||||
|
||||
def set_backpressure_generator(self, generator=None):
|
||||
if generator:
|
||||
self.irq_sink.set_pause_generator(generator())
|
||||
|
||||
async def cycle_reset(self):
|
||||
self.dut.rst.setimmediatevalue(0)
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst.value = 1
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
self.dut.rst.value = 0
|
||||
await RisingEdge(self.dut.clk)
|
||||
await RisingEdge(self.dut.clk)
|
||||
|
||||
|
||||
async def run_test_irq(dut, idle_inserter=None, backpressure_inserter=None):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
await tb.cycle_reset()
|
||||
|
||||
tb.set_idle_generator(idle_inserter)
|
||||
tb.set_backpressure_generator(backpressure_inserter)
|
||||
|
||||
dut.prescale.setimmediatevalue(249)
|
||||
dut.min_interval.setimmediatevalue(100)
|
||||
|
||||
tb.log.info("Test interrupts (single shot)")
|
||||
|
||||
for k in range(8):
|
||||
await tb.irq_source.send(IrqTransaction(index=k))
|
||||
|
||||
for k in range(8):
|
||||
irq = await tb.irq_sink.recv()
|
||||
tb.log.info(irq)
|
||||
assert irq.index == k
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
await Timer(110, 'us')
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
tb.log.info("Test interrupts (multiple)")
|
||||
|
||||
for n in range(5):
|
||||
for k in range(8):
|
||||
await tb.irq_source.send(IrqTransaction(index=k))
|
||||
|
||||
for k in range(8):
|
||||
irq = await tb.irq_sink.recv()
|
||||
tb.log.info(irq)
|
||||
assert irq.index == k
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
await Timer(99, 'us')
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
await Timer(11, 'us')
|
||||
|
||||
assert not tb.irq_sink.empty()
|
||||
|
||||
for k in range(8):
|
||||
irq = await tb.irq_sink.recv()
|
||||
tb.log.info(irq)
|
||||
assert irq.index == k
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
await Timer(110, 'us')
|
||||
|
||||
assert tb.irq_sink.empty()
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
|
||||
def cycle_pause():
|
||||
return itertools.cycle([1, 1, 1, 0])
|
||||
|
||||
|
||||
if cocotb.SIM_NAME:
|
||||
|
||||
for test in [
|
||||
run_test_irq
|
||||
]:
|
||||
|
||||
factory = TestFactory(test)
|
||||
factory.add_option("idle_inserter", [None, cycle_pause])
|
||||
factory.add_option("backpressure_inserter", [None, cycle_pause])
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
tests_dir = os.path.dirname(__file__)
|
||||
rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl'))
|
||||
|
||||
|
||||
def test_irq_rate_limit(request):
|
||||
dut = "irq_rate_limit"
|
||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||
toplevel = dut
|
||||
|
||||
verilog_sources = [
|
||||
os.path.join(rtl_dir, f"{dut}.v"),
|
||||
]
|
||||
|
||||
parameters = {}
|
||||
|
||||
parameters['IRQ_INDEX_WIDTH'] = 11
|
||||
|
||||
extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}
|
||||
|
||||
sim_build = os.path.join(tests_dir, "sim_build",
|
||||
request.node.name.replace('[', '-').replace(']', ''))
|
||||
|
||||
cocotb_test.simulator.run(
|
||||
python_search=[tests_dir],
|
||||
verilog_sources=verilog_sources,
|
||||
toplevel=toplevel,
|
||||
module=module,
|
||||
parameters=parameters,
|
||||
sim_build=sim_build,
|
||||
extra_env=extra_env,
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user