Add PCIe tag manager
This commit is contained in:
parent
ff617532e0
commit
6e46c8e32d
168
rtl/pcie_tag_manager.v
Normal file
168
rtl/pcie_tag_manager.v
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2018 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
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* PCIe tag manager
|
||||
*/
|
||||
module pcie_tag_manager #
|
||||
(
|
||||
parameter PCIE_TAG_WIDTH = 8,
|
||||
parameter PCIE_TAG_COUNT = 256,
|
||||
parameter PCIE_EXT_TAG_ENABLE = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXIS tag output
|
||||
*/
|
||||
output wire [PCIE_TAG_WIDTH-1:0] m_axis_tag,
|
||||
output wire m_axis_tag_valid,
|
||||
input wire m_axis_tag_ready,
|
||||
|
||||
/*
|
||||
* AXIS tag output
|
||||
*/
|
||||
input wire [PCIE_TAG_WIDTH-1:0] s_axis_tag,
|
||||
input wire s_axis_tag_valid,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire ext_tag_enable,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire [PCIE_TAG_COUNT-1:0] active_tags
|
||||
);
|
||||
|
||||
// parameter assertions
|
||||
initial begin
|
||||
if (PCIE_TAG_WIDTH < $clog2(PCIE_TAG_COUNT)) begin
|
||||
$error("Error: PCIe tag width insufficient for requested tag count");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (PCIE_TAG_COUNT < 1 || PCIE_TAG_COUNT > 256) begin
|
||||
$error("Error: PCIe tag count must be between 1 and 256");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (PCIE_TAG_COUNT > 32 && !PCIE_EXT_TAG_ENABLE) begin
|
||||
$warning("Warning: PCIe tag count set larger than 32, but extended tag support is disabled");
|
||||
end
|
||||
|
||||
if (PCIE_TAG_COUNT <= 32 && PCIE_EXT_TAG_ENABLE) begin
|
||||
$warning("Warning: PCIe tag count set to 32 or less, but extended tag support is enabled");
|
||||
end
|
||||
end
|
||||
|
||||
reg [PCIE_TAG_COUNT-1:0] tag_active_reg = {PCIE_TAG_COUNT{1'b0}}, tag_active_next;
|
||||
reg [PCIE_TAG_COUNT-1:0] tag_mask_reg = {PCIE_TAG_COUNT{1'b0}}, tag_mask_next;
|
||||
|
||||
reg [PCIE_TAG_WIDTH-1:0] m_axis_tag_reg = {PCIE_TAG_WIDTH{1'b0}}, m_axis_tag_next;
|
||||
reg m_axis_tag_valid_reg = 1'b0, m_axis_tag_valid_next;
|
||||
|
||||
assign m_axis_tag = m_axis_tag_reg;
|
||||
assign m_axis_tag_valid = m_axis_tag_valid_reg;
|
||||
|
||||
assign active_tags = tag_active_reg;
|
||||
|
||||
wire tag_valid;
|
||||
wire [PCIE_TAG_WIDTH-1:0] tag_index;
|
||||
|
||||
priority_encoder #(
|
||||
.WIDTH(PCIE_TAG_COUNT),
|
||||
.LSB_PRIORITY("HIGH")
|
||||
)
|
||||
priority_encoder_inst (
|
||||
.input_unencoded(~tag_active_reg & (ext_tag_enable && PCIE_EXT_TAG_ENABLE ? {256{1'b1}} : {32{1'b1}})),
|
||||
.output_valid(tag_valid),
|
||||
.output_encoded(tag_index),
|
||||
.output_unencoded()
|
||||
);
|
||||
|
||||
wire masked_tag_valid;
|
||||
wire [PCIE_TAG_WIDTH-1:0] masked_tag_index;
|
||||
|
||||
priority_encoder #(
|
||||
.WIDTH(PCIE_TAG_COUNT),
|
||||
.LSB_PRIORITY("HIGH")
|
||||
)
|
||||
priority_encoder_masked (
|
||||
.input_unencoded(~tag_active_reg & tag_mask_reg & (ext_tag_enable && PCIE_EXT_TAG_ENABLE ? {256{1'b1}} : {32{1'b1}})),
|
||||
.output_valid(masked_tag_valid),
|
||||
.output_encoded(masked_tag_index),
|
||||
.output_unencoded()
|
||||
);
|
||||
|
||||
always @* begin
|
||||
tag_active_next = tag_active_reg;
|
||||
tag_mask_next = tag_mask_reg;
|
||||
|
||||
m_axis_tag_next = m_axis_tag_reg;
|
||||
m_axis_tag_valid_next = m_axis_tag_valid_reg && !m_axis_tag_ready;
|
||||
|
||||
if (s_axis_tag_valid) begin
|
||||
tag_active_next[s_axis_tag] = 1'b0;
|
||||
end
|
||||
|
||||
if (!m_axis_tag_valid || m_axis_tag_ready) begin
|
||||
if (tag_valid) begin
|
||||
if (masked_tag_valid) begin
|
||||
m_axis_tag_next = masked_tag_index;
|
||||
m_axis_tag_valid_next = 1'b1;
|
||||
tag_active_next[masked_tag_index] = 1'b1;
|
||||
tag_mask_next = {PCIE_TAG_COUNT{1'b1}} << (masked_tag_index + 1);
|
||||
end else begin
|
||||
m_axis_tag_next = tag_index;
|
||||
m_axis_tag_valid_next = 1'b1;
|
||||
tag_active_next[tag_index] = 1'b1;
|
||||
tag_mask_next = {PCIE_TAG_COUNT{1'b1}} << (tag_index + 1);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
tag_active_reg <= {PCIE_TAG_COUNT{1'b0}};
|
||||
tag_mask_reg <= {PCIE_TAG_COUNT{1'b0}};
|
||||
m_axis_tag_valid_reg <= 1'b0;
|
||||
end else begin
|
||||
tag_active_reg <= tag_active_next;
|
||||
tag_mask_reg <= tag_mask_next;
|
||||
m_axis_tag_valid_reg <= m_axis_tag_valid_next;
|
||||
end
|
||||
|
||||
m_axis_tag_reg <= m_axis_tag_next;
|
||||
end
|
||||
|
||||
endmodule
|
209
tb/test_pcie_tag_manager.py
Executable file
209
tb/test_pcie_tag_manager.py
Executable file
@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2018 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.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
|
||||
module = 'pcie_tag_manager'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/priority_encoder.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
PCIE_TAG_WIDTH = 8
|
||||
PCIE_TAG_COUNT = 256
|
||||
PCIE_EXT_TAG_ENABLE = 1
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
m_axis_tag_ready = Signal(bool(0))
|
||||
s_axis_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
|
||||
s_axis_tag_valid = Signal(bool(0))
|
||||
ext_tag_enable = Signal(bool(0))
|
||||
|
||||
# Outputs
|
||||
m_axis_tag = Signal(intbv(0)[PCIE_TAG_WIDTH:])
|
||||
m_axis_tag_valid = Signal(bool(0))
|
||||
active_tags = Signal(intbv(0)[PCIE_TAG_COUNT:])
|
||||
|
||||
# sources and sinks
|
||||
tag_sink_pause = Signal(bool(1))
|
||||
|
||||
tag_source = axis_ep.AXIStreamSource()
|
||||
|
||||
tag_source_logic = tag_source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tag,
|
||||
tvalid=s_axis_tag_valid,
|
||||
name='tag_source'
|
||||
)
|
||||
|
||||
tag_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
tag_sink_logic = tag_sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=m_axis_tag,
|
||||
tvalid=m_axis_tag_valid,
|
||||
tready=m_axis_tag_ready,
|
||||
pause=tag_sink_pause,
|
||||
name='tag_sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
m_axis_tag=m_axis_tag,
|
||||
m_axis_tag_valid=m_axis_tag_valid,
|
||||
m_axis_tag_ready=m_axis_tag_ready,
|
||||
s_axis_tag=s_axis_tag,
|
||||
s_axis_tag_valid=s_axis_tag_valid,
|
||||
ext_tag_enable=ext_tag_enable,
|
||||
active_tags=active_tags
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
ext_tag_enable.next = 0
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: activate all tags")
|
||||
current_test.next = 1
|
||||
|
||||
tag_sink_pause.next = 0
|
||||
|
||||
yield delay(300)
|
||||
|
||||
tag_sink_pause.next = 1
|
||||
|
||||
for k in range(32):
|
||||
assert tag_sink.recv().data[0] == k
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: return and reissue some tags")
|
||||
current_test.next = 2
|
||||
|
||||
for k in [2, 4, 6, 8]:
|
||||
tag_source.send([k])
|
||||
|
||||
tag_sink_pause.next = 0
|
||||
|
||||
yield delay(100)
|
||||
|
||||
tag_sink_pause.next = 1
|
||||
|
||||
for k in [2, 4, 6, 8]:
|
||||
assert tag_sink.recv().data[0] == k
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: activate all extended tags")
|
||||
current_test.next = 3
|
||||
|
||||
rst.next = 1
|
||||
ext_tag_enable.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
|
||||
tag_sink_pause.next = 0
|
||||
|
||||
yield delay(2100)
|
||||
|
||||
tag_sink_pause.next = 1
|
||||
|
||||
for k in range(256):
|
||||
assert tag_sink.recv().data[0] == k
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: return and reissue some tags")
|
||||
current_test.next = 4
|
||||
|
||||
for k in [10, 20, 30, 40, 50, 60]:
|
||||
tag_source.send([k])
|
||||
|
||||
tag_sink_pause.next = 0
|
||||
|
||||
yield delay(100)
|
||||
|
||||
tag_sink_pause.next = 1
|
||||
|
||||
for k in [10, 20, 30, 40, 50, 60]:
|
||||
assert tag_sink.recv().data[0] == k
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
93
tb/test_pcie_tag_manager.v
Normal file
93
tb/test_pcie_tag_manager.v
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2018 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
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
/*
|
||||
* Testbench for pcie_tag_manager
|
||||
*/
|
||||
module test_pcie_tag_manager;
|
||||
|
||||
// Parameters
|
||||
parameter PCIE_TAG_WIDTH = 8;
|
||||
parameter PCIE_TAG_COUNT = 256;
|
||||
parameter PCIE_EXT_TAG_ENABLE = 1;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg m_axis_tag_ready = 0;
|
||||
reg [PCIE_TAG_WIDTH-1:0] s_axis_tag = 0;
|
||||
reg s_axis_tag_valid = 0;
|
||||
reg ext_tag_enable = 0;
|
||||
|
||||
// Outputs
|
||||
wire [PCIE_TAG_WIDTH-1:0] m_axis_tag;
|
||||
wire m_axis_tag_valid;
|
||||
wire [PCIE_TAG_COUNT-1:0] active_tags;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
m_axis_tag_ready,
|
||||
s_axis_tag,
|
||||
s_axis_tag_valid,
|
||||
ext_tag_enable
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_tag,
|
||||
m_axis_tag_valid,
|
||||
active_tags
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_pcie_tag_manager.lxt");
|
||||
$dumpvars(0, test_pcie_tag_manager);
|
||||
end
|
||||
|
||||
pcie_tag_manager #(
|
||||
.PCIE_TAG_WIDTH(PCIE_TAG_WIDTH),
|
||||
.PCIE_TAG_COUNT(PCIE_TAG_COUNT),
|
||||
.PCIE_EXT_TAG_ENABLE(PCIE_EXT_TAG_ENABLE)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.m_axis_tag(m_axis_tag),
|
||||
.m_axis_tag_valid(m_axis_tag_valid),
|
||||
.m_axis_tag_ready(m_axis_tag_ready),
|
||||
.s_axis_tag(s_axis_tag),
|
||||
.s_axis_tag_valid(s_axis_tag_valid),
|
||||
.ext_tag_enable(ext_tag_enable),
|
||||
.active_tags(active_tags)
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user