mirror of
https://github.com/corundum/corundum.git
synced 2025-01-30 08:32:52 +08:00
merged changes in axis
This commit is contained in:
commit
bd0d05411b
328
lib/axis/rtl/axis_cobs_decode.v
Normal file
328
lib/axis/rtl/axis_cobs_decode.v
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI4-Stream consistent overhead byte stuffing (COBS) decoder
|
||||||
|
*/
|
||||||
|
module axis_cobs_decode
|
||||||
|
(
|
||||||
|
input wire clk,
|
||||||
|
input wire rst,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI input
|
||||||
|
*/
|
||||||
|
input wire [7:0] input_axis_tdata,
|
||||||
|
input wire input_axis_tvalid,
|
||||||
|
output wire input_axis_tready,
|
||||||
|
input wire input_axis_tlast,
|
||||||
|
input wire input_axis_tuser,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI output
|
||||||
|
*/
|
||||||
|
output wire [7:0] output_axis_tdata,
|
||||||
|
output wire output_axis_tvalid,
|
||||||
|
input wire output_axis_tready,
|
||||||
|
output wire output_axis_tlast,
|
||||||
|
output wire output_axis_tuser
|
||||||
|
);
|
||||||
|
|
||||||
|
// state register
|
||||||
|
localparam [1:0]
|
||||||
|
STATE_IDLE = 2'd0,
|
||||||
|
STATE_SEGMENT = 2'd1,
|
||||||
|
STATE_NEXT_SEGMENT = 2'd2;
|
||||||
|
|
||||||
|
reg [1:0] state_reg = STATE_IDLE, state_next;
|
||||||
|
|
||||||
|
reg [7:0] count_reg = 8'd0, count_next;
|
||||||
|
reg suppress_zero_reg = 1'b0, suppress_zero_next;
|
||||||
|
|
||||||
|
reg [7:0] temp_tdata_reg = 8'd0, temp_tdata_next;
|
||||||
|
reg temp_tvalid_reg = 1'b0, temp_tvalid_next;
|
||||||
|
|
||||||
|
// internal datapath
|
||||||
|
reg [7:0] output_axis_tdata_int;
|
||||||
|
reg output_axis_tvalid_int;
|
||||||
|
reg output_axis_tready_int_reg = 1'b0;
|
||||||
|
reg output_axis_tlast_int;
|
||||||
|
reg output_axis_tuser_int;
|
||||||
|
wire output_axis_tready_int_early;
|
||||||
|
|
||||||
|
reg input_axis_tready_reg = 1'b0, input_axis_tready_next;
|
||||||
|
|
||||||
|
assign input_axis_tready = input_axis_tready_reg;
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
|
||||||
|
count_next = count_reg;
|
||||||
|
suppress_zero_next = suppress_zero_reg;
|
||||||
|
|
||||||
|
temp_tdata_next = temp_tdata_reg;
|
||||||
|
temp_tvalid_next = temp_tvalid_reg;
|
||||||
|
|
||||||
|
output_axis_tdata_int = 8'd0;
|
||||||
|
output_axis_tvalid_int = 1'b0;
|
||||||
|
output_axis_tlast_int = 1'b0;
|
||||||
|
output_axis_tuser_int = 1'b0;
|
||||||
|
|
||||||
|
input_axis_tready_next = 1'b0;
|
||||||
|
|
||||||
|
case (state_reg)
|
||||||
|
STATE_IDLE: begin
|
||||||
|
// idle state
|
||||||
|
input_axis_tready_next = output_axis_tready_int_early | ~temp_tvalid_reg;
|
||||||
|
|
||||||
|
// output final word
|
||||||
|
output_axis_tdata_int = temp_tdata_reg;
|
||||||
|
output_axis_tvalid_int = temp_tvalid_reg;
|
||||||
|
output_axis_tlast_int = temp_tvalid_reg;
|
||||||
|
temp_tvalid_next = temp_tvalid_reg & ~output_axis_tready_int_reg;
|
||||||
|
|
||||||
|
if (input_axis_tready & input_axis_tvalid) begin
|
||||||
|
// valid input data
|
||||||
|
// skip any leading zeros
|
||||||
|
if (input_axis_tdata != 8'd0) begin
|
||||||
|
// store count value and zero suppress
|
||||||
|
count_next = input_axis_tdata-1;
|
||||||
|
suppress_zero_next = (input_axis_tdata == 8'd255);
|
||||||
|
input_axis_tready_next = output_axis_tready_int_early;
|
||||||
|
if (input_axis_tdata == 8'd1) begin
|
||||||
|
// next byte will be count value
|
||||||
|
state_next = STATE_NEXT_SEGMENT;
|
||||||
|
end else begin
|
||||||
|
// next byte will be data
|
||||||
|
state_next = STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
STATE_SEGMENT: begin
|
||||||
|
// receive segment
|
||||||
|
input_axis_tready_next = output_axis_tready_int_early;
|
||||||
|
|
||||||
|
if (input_axis_tready & input_axis_tvalid) begin
|
||||||
|
// valid input data
|
||||||
|
// store in temp register
|
||||||
|
temp_tdata_next = input_axis_tdata;
|
||||||
|
temp_tvalid_next = 1'b1;
|
||||||
|
// move temp to output
|
||||||
|
output_axis_tdata_int = temp_tdata_reg;
|
||||||
|
output_axis_tvalid_int = temp_tvalid_reg;
|
||||||
|
// decrement count
|
||||||
|
count_next = count_reg - 1;
|
||||||
|
if (input_axis_tdata == 8'd0) begin
|
||||||
|
// got a zero byte in a frame - mark it as an error and re-sync
|
||||||
|
temp_tvalid_next = 1'b0;
|
||||||
|
output_axis_tvalid_int = 1'b1;
|
||||||
|
output_axis_tuser_int = 1'b1;
|
||||||
|
output_axis_tlast_int = 1'b1;
|
||||||
|
input_axis_tready_next = 1'b1;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end else if (input_axis_tlast) begin
|
||||||
|
// end of frame
|
||||||
|
if (count_reg == 8'd1 && ~input_axis_tuser) begin
|
||||||
|
// end of frame indication at correct time, go to idle to output final byte
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
// end of frame indication at invalid time or tuser assert, so mark as an error and re-sync
|
||||||
|
temp_tvalid_next = 1'b0;
|
||||||
|
output_axis_tvalid_int = 1'b1;
|
||||||
|
output_axis_tuser_int = 1'b1;
|
||||||
|
output_axis_tlast_int = 1'b1;
|
||||||
|
input_axis_tready_next = 1'b1;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else if (count_reg == 8'd1) begin
|
||||||
|
// next byte will be count value
|
||||||
|
state_next = STATE_NEXT_SEGMENT;
|
||||||
|
end else begin
|
||||||
|
// next byte will be data
|
||||||
|
state_next = STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
state_next = STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
STATE_NEXT_SEGMENT: begin
|
||||||
|
// next segment
|
||||||
|
input_axis_tready_next = output_axis_tready_int_early;
|
||||||
|
|
||||||
|
if (input_axis_tready & input_axis_tvalid) begin
|
||||||
|
// valid input data
|
||||||
|
// store zero in temp if not suppressed
|
||||||
|
temp_tdata_next = 8'd0;
|
||||||
|
temp_tvalid_next = ~suppress_zero_reg;
|
||||||
|
// move temp to output
|
||||||
|
output_axis_tdata_int = temp_tdata_reg;
|
||||||
|
output_axis_tvalid_int = temp_tvalid_reg;
|
||||||
|
if (input_axis_tdata == 8'd0) begin
|
||||||
|
// got a zero byte delineating the end of the frame, so mark as such and re-sync
|
||||||
|
temp_tvalid_next = 1'b0;
|
||||||
|
output_axis_tuser_int = input_axis_tuser;
|
||||||
|
output_axis_tlast_int = 1'b1;
|
||||||
|
input_axis_tready_next = 1'b1;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end else if (input_axis_tlast) begin
|
||||||
|
if (input_axis_tdata == 8'd1 && ~input_axis_tuser) begin
|
||||||
|
// end of frame indication at correct time, go to idle to output final byte
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
// end of frame indication at invalid time or tuser assert, so mark as an error and re-sync
|
||||||
|
temp_tvalid_next = 1'b0;
|
||||||
|
output_axis_tvalid_int = 1'b1;
|
||||||
|
output_axis_tuser_int = 1'b1;
|
||||||
|
output_axis_tlast_int = 1'b1;
|
||||||
|
input_axis_tready_next = 1'b1;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// otherwise, store count value and zero suppress
|
||||||
|
count_next = input_axis_tdata-1;
|
||||||
|
suppress_zero_next = (input_axis_tdata == 8'd255);
|
||||||
|
input_axis_tready_next = output_axis_tready_int_early;
|
||||||
|
if (input_axis_tdata == 8'd1) begin
|
||||||
|
// next byte will be count value
|
||||||
|
state_next = STATE_NEXT_SEGMENT;
|
||||||
|
end else begin
|
||||||
|
// next byte will be data
|
||||||
|
state_next = STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
state_next = STATE_NEXT_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
state_reg <= STATE_IDLE;
|
||||||
|
temp_tvalid_reg <= 1'b0;
|
||||||
|
input_axis_tready_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
state_reg <= state_next;
|
||||||
|
temp_tvalid_reg <= temp_tvalid_next;
|
||||||
|
input_axis_tready_reg <= input_axis_tready_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
temp_tdata_reg <= temp_tdata_next;
|
||||||
|
|
||||||
|
count_reg <= count_next;
|
||||||
|
suppress_zero_reg <= suppress_zero_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// output datapath logic
|
||||||
|
reg [7:0] output_axis_tdata_reg = 8'd0;
|
||||||
|
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
|
||||||
|
reg output_axis_tlast_reg = 1'b0;
|
||||||
|
reg output_axis_tuser_reg = 1'b0;
|
||||||
|
|
||||||
|
reg [7:0] temp_axis_tdata_reg = 8'd0;
|
||||||
|
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
|
||||||
|
reg temp_axis_tlast_reg = 1'b0;
|
||||||
|
reg temp_axis_tuser_reg = 1'b0;
|
||||||
|
|
||||||
|
// datapath control
|
||||||
|
reg store_axis_int_to_output;
|
||||||
|
reg store_axis_int_to_temp;
|
||||||
|
reg store_axis_temp_to_output;
|
||||||
|
|
||||||
|
assign output_axis_tdata = output_axis_tdata_reg;
|
||||||
|
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||||
|
assign output_axis_tlast = output_axis_tlast_reg;
|
||||||
|
assign output_axis_tuser = output_axis_tuser_reg;
|
||||||
|
|
||||||
|
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||||
|
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// transfer sink ready state to source
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
|
||||||
|
store_axis_int_to_output = 1'b0;
|
||||||
|
store_axis_int_to_temp = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b0;
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg) begin
|
||||||
|
// input is ready
|
||||||
|
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||||
|
// output is ready or currently not valid, transfer data to output
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_output = 1'b1;
|
||||||
|
end else begin
|
||||||
|
// output is not ready, store input in temp
|
||||||
|
temp_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_temp = 1'b1;
|
||||||
|
end
|
||||||
|
end else if (output_axis_tready) begin
|
||||||
|
// input is not ready, but output is ready
|
||||||
|
output_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
output_axis_tvalid_reg <= 1'b0;
|
||||||
|
output_axis_tready_int_reg <= 1'b0;
|
||||||
|
temp_axis_tvalid_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
output_axis_tvalid_reg <= output_axis_tvalid_next;
|
||||||
|
output_axis_tready_int_reg <= output_axis_tready_int_early;
|
||||||
|
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// datapath
|
||||||
|
if (store_axis_int_to_output) begin
|
||||||
|
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end else if (store_axis_temp_to_output) begin
|
||||||
|
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||||
|
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||||
|
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (store_axis_int_to_temp) begin
|
||||||
|
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
473
lib/axis/rtl/axis_cobs_encode.v
Normal file
473
lib/axis/rtl/axis_cobs_encode.v
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI4-Stream consistent overhead byte stuffing (COBS) encoder
|
||||||
|
*/
|
||||||
|
module axis_cobs_encode #
|
||||||
|
(
|
||||||
|
// append zero for in band framing
|
||||||
|
parameter APPEND_ZERO = 1
|
||||||
|
)
|
||||||
|
(
|
||||||
|
input wire clk,
|
||||||
|
input wire rst,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI input
|
||||||
|
*/
|
||||||
|
input wire [7:0] input_axis_tdata,
|
||||||
|
input wire input_axis_tvalid,
|
||||||
|
output wire input_axis_tready,
|
||||||
|
input wire input_axis_tlast,
|
||||||
|
input wire input_axis_tuser,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AXI output
|
||||||
|
*/
|
||||||
|
output wire [7:0] output_axis_tdata,
|
||||||
|
output wire output_axis_tvalid,
|
||||||
|
input wire output_axis_tready,
|
||||||
|
output wire output_axis_tlast,
|
||||||
|
output wire output_axis_tuser
|
||||||
|
);
|
||||||
|
|
||||||
|
// state register
|
||||||
|
localparam [1:0]
|
||||||
|
INPUT_STATE_IDLE = 2'd0,
|
||||||
|
INPUT_STATE_SEGMENT = 2'd1,
|
||||||
|
INPUT_STATE_FINAL_ZERO = 2'd2,
|
||||||
|
INPUT_STATE_APPEND_ZERO = 2'd3;
|
||||||
|
|
||||||
|
reg [1:0] input_state_reg = INPUT_STATE_IDLE, input_state_next;
|
||||||
|
|
||||||
|
localparam [0:0]
|
||||||
|
OUTPUT_STATE_IDLE = 1'd0,
|
||||||
|
OUTPUT_STATE_SEGMENT = 1'd1;
|
||||||
|
|
||||||
|
reg [0:0] output_state_reg = OUTPUT_STATE_IDLE, output_state_next;
|
||||||
|
|
||||||
|
reg [7:0] input_count_reg = 8'd0, input_count_next;
|
||||||
|
reg [7:0] output_count_reg = 8'd0, output_count_next;
|
||||||
|
reg fail_frame_reg = 1'b0, fail_frame_next;
|
||||||
|
|
||||||
|
// internal datapath
|
||||||
|
reg [7:0] output_axis_tdata_int;
|
||||||
|
reg output_axis_tvalid_int;
|
||||||
|
reg output_axis_tready_int_reg = 1'b0;
|
||||||
|
reg output_axis_tlast_int;
|
||||||
|
reg output_axis_tuser_int;
|
||||||
|
wire output_axis_tready_int_early;
|
||||||
|
|
||||||
|
reg input_axis_tready_mask;
|
||||||
|
|
||||||
|
assign input_axis_tready = code_fifo_in_tready & data_fifo_in_tready & input_axis_tready_mask;
|
||||||
|
|
||||||
|
reg [7:0] code_fifo_in_tdata;
|
||||||
|
reg code_fifo_in_tvalid;
|
||||||
|
reg code_fifo_in_tlast;
|
||||||
|
reg code_fifo_in_tuser;
|
||||||
|
wire code_fifo_in_tready;
|
||||||
|
|
||||||
|
wire [7:0] code_fifo_out_tdata;
|
||||||
|
wire code_fifo_out_tvalid;
|
||||||
|
wire code_fifo_out_tlast;
|
||||||
|
wire code_fifo_out_tuser;
|
||||||
|
reg code_fifo_out_tready;
|
||||||
|
|
||||||
|
axis_fifo #(
|
||||||
|
.ADDR_WIDTH(8),
|
||||||
|
.DATA_WIDTH(8)
|
||||||
|
)
|
||||||
|
code_fifo_inst (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
// AXI input
|
||||||
|
.input_axis_tdata(code_fifo_in_tdata),
|
||||||
|
.input_axis_tvalid(code_fifo_in_tvalid),
|
||||||
|
.input_axis_tready(code_fifo_in_tready),
|
||||||
|
.input_axis_tlast(code_fifo_in_tlast),
|
||||||
|
.input_axis_tuser(code_fifo_in_tuser),
|
||||||
|
// AXI output
|
||||||
|
.output_axis_tdata(code_fifo_out_tdata),
|
||||||
|
.output_axis_tvalid(code_fifo_out_tvalid),
|
||||||
|
.output_axis_tready(code_fifo_out_tready),
|
||||||
|
.output_axis_tlast(code_fifo_out_tlast),
|
||||||
|
.output_axis_tuser(code_fifo_out_tuser)
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [7:0] data_fifo_in_tdata;
|
||||||
|
reg data_fifo_in_tvalid;
|
||||||
|
reg data_fifo_in_tlast;
|
||||||
|
wire data_fifo_in_tready;
|
||||||
|
|
||||||
|
wire [7:0] data_fifo_out_tdata;
|
||||||
|
wire data_fifo_out_tvalid;
|
||||||
|
wire data_fifo_out_tlast;
|
||||||
|
reg data_fifo_out_tready;
|
||||||
|
|
||||||
|
axis_fifo #(
|
||||||
|
.ADDR_WIDTH(8),
|
||||||
|
.DATA_WIDTH(8)
|
||||||
|
)
|
||||||
|
data_fifo_inst (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
// AXI input
|
||||||
|
.input_axis_tdata(data_fifo_in_tdata),
|
||||||
|
.input_axis_tvalid(data_fifo_in_tvalid),
|
||||||
|
.input_axis_tready(data_fifo_in_tready),
|
||||||
|
.input_axis_tlast(data_fifo_in_tlast),
|
||||||
|
.input_axis_tuser(1'b0),
|
||||||
|
// AXI output
|
||||||
|
.output_axis_tdata(data_fifo_out_tdata),
|
||||||
|
.output_axis_tvalid(data_fifo_out_tvalid),
|
||||||
|
.output_axis_tready(data_fifo_out_tready),
|
||||||
|
.output_axis_tlast(data_fifo_out_tlast),
|
||||||
|
.output_axis_tuser()
|
||||||
|
);
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
|
||||||
|
input_count_next = input_count_reg;
|
||||||
|
|
||||||
|
fail_frame_next = fail_frame_reg;
|
||||||
|
|
||||||
|
input_axis_tready_mask = 1'b0;
|
||||||
|
|
||||||
|
code_fifo_in_tdata = 8'd0;
|
||||||
|
code_fifo_in_tvalid = 1'b0;
|
||||||
|
code_fifo_in_tlast = 1'b0;
|
||||||
|
code_fifo_in_tuser = 1'b0;
|
||||||
|
|
||||||
|
data_fifo_in_tdata = input_axis_tdata;
|
||||||
|
data_fifo_in_tvalid = 1'b0;
|
||||||
|
data_fifo_in_tlast = 1'b0;
|
||||||
|
|
||||||
|
case (input_state_reg)
|
||||||
|
INPUT_STATE_IDLE: begin
|
||||||
|
// idle state
|
||||||
|
input_axis_tready_mask = 1'b1;
|
||||||
|
fail_frame_next = 1'b0;
|
||||||
|
|
||||||
|
if (input_axis_tready & input_axis_tvalid) begin
|
||||||
|
// valid input data
|
||||||
|
|
||||||
|
if (input_axis_tdata == 8'd0 || (input_axis_tlast & input_axis_tuser)) begin
|
||||||
|
// got a zero or propagated error, so store a zero code
|
||||||
|
code_fifo_in_tdata = 8'd1;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
if (input_axis_tlast) begin
|
||||||
|
// last byte, so close out the frame
|
||||||
|
fail_frame_next = input_axis_tuser;
|
||||||
|
input_state_next = INPUT_STATE_FINAL_ZERO;
|
||||||
|
end else begin
|
||||||
|
// return to idle to await next segment
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// got something other than a zero, so store it and init the segment counter
|
||||||
|
input_count_next = 8'd2;
|
||||||
|
data_fifo_in_tdata = input_axis_tdata;
|
||||||
|
data_fifo_in_tvalid = 1'b1;
|
||||||
|
if (input_axis_tlast) begin
|
||||||
|
// last byte, so store the code and close out the frame
|
||||||
|
code_fifo_in_tdata = 8'd2;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
if (APPEND_ZERO) begin
|
||||||
|
// zero frame mode, need to add a zero code to end the frame
|
||||||
|
input_state_next = INPUT_STATE_APPEND_ZERO;
|
||||||
|
end else begin
|
||||||
|
// normal frame mode, close out the frame
|
||||||
|
data_fifo_in_tlast = 1'b1;
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// await more segment data
|
||||||
|
input_state_next = INPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
INPUT_STATE_SEGMENT: begin
|
||||||
|
// encode segment
|
||||||
|
input_axis_tready_mask = 1'b1;
|
||||||
|
fail_frame_next = 1'b0;
|
||||||
|
|
||||||
|
if (input_axis_tready & input_axis_tvalid) begin
|
||||||
|
// valid input data
|
||||||
|
|
||||||
|
if (input_axis_tdata == 8'd0 || (input_axis_tlast & input_axis_tuser)) begin
|
||||||
|
// got a zero or propagated error, so store the code
|
||||||
|
code_fifo_in_tdata = input_count_reg;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
if (input_axis_tlast) begin
|
||||||
|
// last byte, so close out the frame
|
||||||
|
fail_frame_next = input_axis_tuser;
|
||||||
|
input_state_next = INPUT_STATE_FINAL_ZERO;
|
||||||
|
end else begin
|
||||||
|
// return to idle to await next segment
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// got something other than a zero, so store it and increment the segment counter
|
||||||
|
input_count_next = input_count_reg+1;
|
||||||
|
data_fifo_in_tdata = input_axis_tdata;
|
||||||
|
data_fifo_in_tvalid = 1'b1;
|
||||||
|
if (input_count_reg == 8'd254) begin
|
||||||
|
// 254 bytes in frame, so dump and reset counter
|
||||||
|
code_fifo_in_tdata = input_count_reg+1;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
input_count_next = 8'd1;
|
||||||
|
end
|
||||||
|
if (input_axis_tlast) begin
|
||||||
|
// last byte, so store the code and close out the frame
|
||||||
|
code_fifo_in_tdata = input_count_reg+1;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
if (APPEND_ZERO) begin
|
||||||
|
// zero frame mode, need to add a zero code to end the frame
|
||||||
|
input_state_next = INPUT_STATE_APPEND_ZERO;
|
||||||
|
end else begin
|
||||||
|
// normal frame mode, close out the frame
|
||||||
|
data_fifo_in_tlast = 1'b1;
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
// await more segment data
|
||||||
|
input_state_next = INPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
input_state_next = INPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
INPUT_STATE_FINAL_ZERO: begin
|
||||||
|
// final zero code required
|
||||||
|
input_axis_tready_mask = 1'b0;
|
||||||
|
|
||||||
|
if (code_fifo_in_tready) begin
|
||||||
|
// push a zero code and close out frame
|
||||||
|
if (fail_frame_reg) begin
|
||||||
|
code_fifo_in_tdata = 8'd2;
|
||||||
|
code_fifo_in_tuser = 1'b1;
|
||||||
|
end else begin
|
||||||
|
code_fifo_in_tdata = 8'd1;
|
||||||
|
end
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
if (APPEND_ZERO) begin
|
||||||
|
// zero frame mode, need to add a zero code to end the frame
|
||||||
|
input_state_next = INPUT_STATE_APPEND_ZERO;
|
||||||
|
end else begin
|
||||||
|
// normal frame mode, close out the frame
|
||||||
|
code_fifo_in_tlast = 1'b1;
|
||||||
|
fail_frame_next = 1'b0;
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
input_state_next = INPUT_STATE_FINAL_ZERO;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
INPUT_STATE_APPEND_ZERO: begin
|
||||||
|
// append zero for zero framing
|
||||||
|
input_axis_tready_mask = 1'b0;
|
||||||
|
|
||||||
|
if (code_fifo_in_tready) begin
|
||||||
|
// push frame termination code and close out frame
|
||||||
|
code_fifo_in_tdata = 8'd0;
|
||||||
|
code_fifo_in_tlast = 1'b1;
|
||||||
|
code_fifo_in_tuser = fail_frame_reg;
|
||||||
|
code_fifo_in_tvalid = 1'b1;
|
||||||
|
fail_frame_next = 1'b0;
|
||||||
|
input_state_next = INPUT_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
input_state_next = INPUT_STATE_APPEND_ZERO;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
output_state_next = OUTPUT_STATE_IDLE;
|
||||||
|
|
||||||
|
output_count_next = output_count_reg;
|
||||||
|
|
||||||
|
output_axis_tdata_int = 8'd0;
|
||||||
|
output_axis_tvalid_int = 1'b0;
|
||||||
|
output_axis_tlast_int = 1'b0;
|
||||||
|
output_axis_tuser_int = 1'b0;
|
||||||
|
|
||||||
|
code_fifo_out_tready = 1'b0;
|
||||||
|
|
||||||
|
data_fifo_out_tready = 1'b0;
|
||||||
|
|
||||||
|
case (output_state_reg)
|
||||||
|
OUTPUT_STATE_IDLE: begin
|
||||||
|
// idle state
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg & code_fifo_out_tvalid) begin
|
||||||
|
// transfer out code byte and load counter
|
||||||
|
output_axis_tdata_int = code_fifo_out_tdata;
|
||||||
|
output_axis_tlast_int = code_fifo_out_tlast;
|
||||||
|
output_axis_tuser_int = code_fifo_out_tuser & code_fifo_out_tlast;
|
||||||
|
output_count_next = code_fifo_out_tdata-1;
|
||||||
|
output_axis_tvalid_int = 1'b1;
|
||||||
|
code_fifo_out_tready = 1'b1;
|
||||||
|
if (code_fifo_out_tdata == 8'd0 || code_fifo_out_tdata == 8'd1 || code_fifo_out_tuser) begin
|
||||||
|
// frame termination and zero codes will be followed by codes
|
||||||
|
output_state_next = OUTPUT_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
// transfer out data
|
||||||
|
output_state_next = OUTPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
output_state_next = OUTPUT_STATE_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
OUTPUT_STATE_SEGMENT: begin
|
||||||
|
// segment output
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg & data_fifo_out_tvalid) begin
|
||||||
|
// transfer out data byte and decrement counter
|
||||||
|
output_axis_tdata_int = data_fifo_out_tdata;
|
||||||
|
output_axis_tlast_int = data_fifo_out_tlast;
|
||||||
|
output_count_next = output_count_reg - 1;
|
||||||
|
output_axis_tvalid_int = 1'b1;
|
||||||
|
data_fifo_out_tready = 1'b1;
|
||||||
|
if (output_count_reg == 1'b1) begin
|
||||||
|
// done with segment, get a code byte next
|
||||||
|
output_state_next = OUTPUT_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
// more data to transfer
|
||||||
|
output_state_next = OUTPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
output_state_next = OUTPUT_STATE_SEGMENT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
input_state_reg <= INPUT_STATE_IDLE;
|
||||||
|
output_state_reg <= OUTPUT_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
input_state_reg <= input_state_next;
|
||||||
|
output_state_reg <= output_state_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
input_count_reg <= input_count_next;
|
||||||
|
output_count_reg <= output_count_next;
|
||||||
|
fail_frame_reg <= fail_frame_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// output datapath logic
|
||||||
|
reg [7:0] output_axis_tdata_reg = 8'd0;
|
||||||
|
reg output_axis_tvalid_reg = 1'b0, output_axis_tvalid_next;
|
||||||
|
reg output_axis_tlast_reg = 1'b0;
|
||||||
|
reg output_axis_tuser_reg = 1'b0;
|
||||||
|
|
||||||
|
reg [7:0] temp_axis_tdata_reg = 8'd0;
|
||||||
|
reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next;
|
||||||
|
reg temp_axis_tlast_reg = 1'b0;
|
||||||
|
reg temp_axis_tuser_reg = 1'b0;
|
||||||
|
|
||||||
|
// datapath control
|
||||||
|
reg store_axis_int_to_output;
|
||||||
|
reg store_axis_int_to_temp;
|
||||||
|
reg store_axis_temp_to_output;
|
||||||
|
|
||||||
|
assign output_axis_tdata = output_axis_tdata_reg;
|
||||||
|
assign output_axis_tvalid = output_axis_tvalid_reg;
|
||||||
|
assign output_axis_tlast = output_axis_tlast_reg;
|
||||||
|
assign output_axis_tuser = output_axis_tuser_reg;
|
||||||
|
|
||||||
|
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||||
|
assign output_axis_tready_int_early = output_axis_tready | (~temp_axis_tvalid_reg & (~output_axis_tvalid_reg | ~output_axis_tvalid_int));
|
||||||
|
|
||||||
|
always @* begin
|
||||||
|
// transfer sink ready state to source
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
|
||||||
|
store_axis_int_to_output = 1'b0;
|
||||||
|
store_axis_int_to_temp = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b0;
|
||||||
|
|
||||||
|
if (output_axis_tready_int_reg) begin
|
||||||
|
// input is ready
|
||||||
|
if (output_axis_tready | ~output_axis_tvalid_reg) begin
|
||||||
|
// output is ready or currently not valid, transfer data to output
|
||||||
|
output_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_output = 1'b1;
|
||||||
|
end else begin
|
||||||
|
// output is not ready, store input in temp
|
||||||
|
temp_axis_tvalid_next = output_axis_tvalid_int;
|
||||||
|
store_axis_int_to_temp = 1'b1;
|
||||||
|
end
|
||||||
|
end else if (output_axis_tready) begin
|
||||||
|
// input is not ready, but output is ready
|
||||||
|
output_axis_tvalid_next = temp_axis_tvalid_reg;
|
||||||
|
temp_axis_tvalid_next = 1'b0;
|
||||||
|
store_axis_temp_to_output = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (rst) begin
|
||||||
|
output_axis_tvalid_reg <= 1'b0;
|
||||||
|
output_axis_tready_int_reg <= 1'b0;
|
||||||
|
temp_axis_tvalid_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
output_axis_tvalid_reg <= output_axis_tvalid_next;
|
||||||
|
output_axis_tready_int_reg <= output_axis_tready_int_early;
|
||||||
|
temp_axis_tvalid_reg <= temp_axis_tvalid_next;
|
||||||
|
end
|
||||||
|
|
||||||
|
// datapath
|
||||||
|
if (store_axis_int_to_output) begin
|
||||||
|
output_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
output_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
output_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end else if (store_axis_temp_to_output) begin
|
||||||
|
output_axis_tdata_reg <= temp_axis_tdata_reg;
|
||||||
|
output_axis_tlast_reg <= temp_axis_tlast_reg;
|
||||||
|
output_axis_tuser_reg <= temp_axis_tuser_reg;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (store_axis_int_to_temp) begin
|
||||||
|
temp_axis_tdata_reg <= output_axis_tdata_int;
|
||||||
|
temp_axis_tlast_reg <= output_axis_tlast_int;
|
||||||
|
temp_axis_tuser_reg <= output_axis_tuser_int;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
482
lib/axis/tb/test_axis_cobs_decode.py
Executable file
482
lib/axis/tb/test_axis_cobs_decode.py
Executable file
@ -0,0 +1,482 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
|
||||||
|
Copyright (c) 2016 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
|
||||||
|
|
||||||
|
try:
|
||||||
|
from queue import Queue
|
||||||
|
except ImportError:
|
||||||
|
from Queue import Queue
|
||||||
|
|
||||||
|
import axis_ep
|
||||||
|
|
||||||
|
module = 'axis_cobs_decode'
|
||||||
|
testbench = 'test_axis_cobs_decode'
|
||||||
|
|
||||||
|
srcs = []
|
||||||
|
|
||||||
|
srcs.append("../rtl/%s.v" % module)
|
||||||
|
srcs.append("%s.v" % testbench)
|
||||||
|
|
||||||
|
src = ' '.join(srcs)
|
||||||
|
|
||||||
|
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||||
|
|
||||||
|
def dut_axis_cobs_decode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser):
|
||||||
|
|
||||||
|
if os.system(build_cmd):
|
||||||
|
raise Exception("Error running build command")
|
||||||
|
return Cosimulation("vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||||
|
clk=clk,
|
||||||
|
rst=rst,
|
||||||
|
current_test=current_test,
|
||||||
|
input_axis_tdata=input_axis_tdata,
|
||||||
|
input_axis_tvalid=input_axis_tvalid,
|
||||||
|
input_axis_tready=input_axis_tready,
|
||||||
|
input_axis_tlast=input_axis_tlast,
|
||||||
|
input_axis_tuser=input_axis_tuser,
|
||||||
|
output_axis_tdata=output_axis_tdata,
|
||||||
|
output_axis_tvalid=output_axis_tvalid,
|
||||||
|
output_axis_tready=output_axis_tready,
|
||||||
|
output_axis_tlast=output_axis_tlast,
|
||||||
|
output_axis_tuser=output_axis_tuser)
|
||||||
|
|
||||||
|
def cobs_encode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
enc = bytearray()
|
||||||
|
|
||||||
|
seg = bytearray()
|
||||||
|
code = 1
|
||||||
|
|
||||||
|
new_data = True
|
||||||
|
|
||||||
|
for b in block:
|
||||||
|
if b == 0:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = True
|
||||||
|
else:
|
||||||
|
code += 1
|
||||||
|
seg.append(b)
|
||||||
|
new_data = True
|
||||||
|
if code == 255:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = False
|
||||||
|
|
||||||
|
if new_data:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
|
||||||
|
return bytes(enc)
|
||||||
|
|
||||||
|
def cobs_decode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
dec = bytearray()
|
||||||
|
|
||||||
|
it = iter(bytearray(block))
|
||||||
|
code = 0
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
if 0 in block:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while i < len(block):
|
||||||
|
code = block[i]
|
||||||
|
i += 1
|
||||||
|
if i+code-1 > len(block):
|
||||||
|
return None
|
||||||
|
for k in range(code-1):
|
||||||
|
dec.append(block[i])
|
||||||
|
i += 1
|
||||||
|
if code < 255 and i < len(block):
|
||||||
|
dec.append(0)
|
||||||
|
|
||||||
|
return bytes(dec)
|
||||||
|
|
||||||
|
def prbs31(state = 0x7fffffff):
|
||||||
|
while True:
|
||||||
|
for i in range(8):
|
||||||
|
if bool(state & 0x08000000) ^ bool(state & 0x40000000):
|
||||||
|
state = ((state & 0x3fffffff) << 1) | 1
|
||||||
|
else:
|
||||||
|
state = (state & 0x3fffffff) << 1
|
||||||
|
yield state & 0xff
|
||||||
|
|
||||||
|
def bench():
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
clk = Signal(bool(0))
|
||||||
|
rst = Signal(bool(0))
|
||||||
|
current_test = Signal(intbv(0)[8:])
|
||||||
|
|
||||||
|
input_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
input_axis_tvalid = Signal(bool(0))
|
||||||
|
input_axis_tlast = Signal(bool(0))
|
||||||
|
input_axis_tuser = Signal(bool(0))
|
||||||
|
output_axis_tready = Signal(bool(0))
|
||||||
|
|
||||||
|
# Outputs
|
||||||
|
input_axis_tready = Signal(bool(0))
|
||||||
|
output_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
output_axis_tvalid = Signal(bool(0))
|
||||||
|
output_axis_tlast = Signal(bool(0))
|
||||||
|
output_axis_tuser = Signal(bool(0))
|
||||||
|
|
||||||
|
# sources and sinks
|
||||||
|
source_queue = Queue()
|
||||||
|
source_pause = Signal(bool(0))
|
||||||
|
sink_queue = Queue()
|
||||||
|
sink_pause = Signal(bool(0))
|
||||||
|
|
||||||
|
source = axis_ep.AXIStreamSource(clk,
|
||||||
|
rst,
|
||||||
|
tdata=input_axis_tdata,
|
||||||
|
tvalid=input_axis_tvalid,
|
||||||
|
tready=input_axis_tready,
|
||||||
|
tlast=input_axis_tlast,
|
||||||
|
tuser=input_axis_tuser,
|
||||||
|
fifo=source_queue,
|
||||||
|
pause=source_pause,
|
||||||
|
name='source')
|
||||||
|
|
||||||
|
sink = axis_ep.AXIStreamSink(clk,
|
||||||
|
rst,
|
||||||
|
tdata=output_axis_tdata,
|
||||||
|
tvalid=output_axis_tvalid,
|
||||||
|
tready=output_axis_tready,
|
||||||
|
tlast=output_axis_tlast,
|
||||||
|
tuser=output_axis_tuser,
|
||||||
|
fifo=sink_queue,
|
||||||
|
pause=sink_pause,
|
||||||
|
name='sink')
|
||||||
|
|
||||||
|
# DUT
|
||||||
|
dut = dut_axis_cobs_decode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser)
|
||||||
|
|
||||||
|
@always(delay(4))
|
||||||
|
def clkgen():
|
||||||
|
clk.next = not clk
|
||||||
|
|
||||||
|
def wait_normal():
|
||||||
|
i = 4
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 4
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_source():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
source_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
source_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_sink():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
sink_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
sink_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
for payload_len in list(range(1,33))+list(range(253,259))+[512]:
|
||||||
|
gen = prbs31()
|
||||||
|
for block in [bytearray([0]*payload_len),
|
||||||
|
bytearray([k%255+1 for k in range(payload_len)]),
|
||||||
|
b'\x00'+bytearray([k%255+1 for k in range(payload_len)])+b'\x00',
|
||||||
|
bytearray([next(gen) for i in range(payload_len)])]:
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 1: test packet, length %d" % payload_len)
|
||||||
|
current_test.next = 1
|
||||||
|
|
||||||
|
enc = cobs_encode(block)
|
||||||
|
|
||||||
|
test_frame = axis_ep.AXIStreamFrame(enc)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 2: test packet, length %d, zero frame" % payload_len)
|
||||||
|
current_test.next = 2
|
||||||
|
|
||||||
|
enc = cobs_encode(block)
|
||||||
|
|
||||||
|
test_frame = axis_ep.AXIStreamFrame(enc+b'\x00')
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 3: back-to-back packets, length %d" % payload_len)
|
||||||
|
current_test.next = 3
|
||||||
|
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(enc)
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(enc)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 4: back-to-back packets, length %d, zero frame" % payload_len)
|
||||||
|
current_test.next = 4
|
||||||
|
|
||||||
|
test_frame = axis_ep.AXIStreamFrame(enc+b'\x00'+enc+b'\x00')
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 5: tuser assert and bad frame, length %d" % payload_len)
|
||||||
|
current_test.next = 5
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(enc)
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(enc+b'\x02')
|
||||||
|
test_frame3 = axis_ep.AXIStreamFrame(enc)
|
||||||
|
|
||||||
|
test_frame1.user = 1
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
source_queue.put(test_frame3)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 6: tuser assert and bad frame, length %d, zero frame" % payload_len)
|
||||||
|
current_test.next = 6
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(enc+b'\x00')
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(enc+b'\x02\x00')
|
||||||
|
test_frame3 = axis_ep.AXIStreamFrame(enc+b'\x00')
|
||||||
|
|
||||||
|
test_frame1.user = 1
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
source_queue.put(test_frame3)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
raise StopSimulation
|
||||||
|
|
||||||
|
return dut, source, sink, clkgen, check
|
||||||
|
|
||||||
|
def test_bench():
|
||||||
|
sim = Simulation(bench())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("Running test...")
|
||||||
|
test_bench()
|
91
lib/axis/tb/test_axis_cobs_decode.v
Normal file
91
lib/axis/tb/test_axis_cobs_decode.v
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016 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 axis_cobs_decode
|
||||||
|
*/
|
||||||
|
module test_axis_cobs_decode;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
reg clk = 0;
|
||||||
|
reg rst = 0;
|
||||||
|
reg [7:0] current_test = 0;
|
||||||
|
|
||||||
|
reg [7:0] input_axis_tdata = 0;
|
||||||
|
reg input_axis_tvalid = 0;
|
||||||
|
reg input_axis_tlast = 0;
|
||||||
|
reg input_axis_tuser = 0;
|
||||||
|
reg output_axis_tready = 0;
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
wire input_axis_tready;
|
||||||
|
wire [7:0] output_axis_tdata;
|
||||||
|
wire output_axis_tvalid;
|
||||||
|
wire output_axis_tlast;
|
||||||
|
wire output_axis_tuser;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// myhdl integration
|
||||||
|
$from_myhdl(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tready);
|
||||||
|
$to_myhdl(input_axis_tready,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser);
|
||||||
|
|
||||||
|
// dump file
|
||||||
|
$dumpfile("test_axis_cobs_decode.lxt");
|
||||||
|
$dumpvars(0, test_axis_cobs_decode);
|
||||||
|
end
|
||||||
|
|
||||||
|
axis_cobs_decode
|
||||||
|
UUT (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.input_axis_tdata(input_axis_tdata),
|
||||||
|
.input_axis_tvalid(input_axis_tvalid),
|
||||||
|
.input_axis_tready(input_axis_tready),
|
||||||
|
.input_axis_tlast(input_axis_tlast),
|
||||||
|
.input_axis_tuser(input_axis_tuser),
|
||||||
|
.output_axis_tdata(output_axis_tdata),
|
||||||
|
.output_axis_tvalid(output_axis_tvalid),
|
||||||
|
.output_axis_tready(output_axis_tready),
|
||||||
|
.output_axis_tlast(output_axis_tlast),
|
||||||
|
.output_axis_tuser(output_axis_tuser)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
381
lib/axis/tb/test_axis_cobs_encode.py
Executable file
381
lib/axis/tb/test_axis_cobs_encode.py
Executable file
@ -0,0 +1,381 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
|
||||||
|
Copyright (c) 2016 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
|
||||||
|
|
||||||
|
try:
|
||||||
|
from queue import Queue
|
||||||
|
except ImportError:
|
||||||
|
from Queue import Queue
|
||||||
|
|
||||||
|
import axis_ep
|
||||||
|
|
||||||
|
module = 'axis_cobs_encode'
|
||||||
|
testbench = 'test_axis_cobs_encode'
|
||||||
|
|
||||||
|
srcs = []
|
||||||
|
|
||||||
|
srcs.append("../rtl/%s.v" % module)
|
||||||
|
srcs.append("../rtl/axis_fifo.v")
|
||||||
|
srcs.append("%s.v" % testbench)
|
||||||
|
|
||||||
|
src = ' '.join(srcs)
|
||||||
|
|
||||||
|
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||||
|
|
||||||
|
def dut_axis_cobs_encode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser):
|
||||||
|
|
||||||
|
if os.system(build_cmd):
|
||||||
|
raise Exception("Error running build command")
|
||||||
|
return Cosimulation("vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||||
|
clk=clk,
|
||||||
|
rst=rst,
|
||||||
|
current_test=current_test,
|
||||||
|
input_axis_tdata=input_axis_tdata,
|
||||||
|
input_axis_tvalid=input_axis_tvalid,
|
||||||
|
input_axis_tready=input_axis_tready,
|
||||||
|
input_axis_tlast=input_axis_tlast,
|
||||||
|
input_axis_tuser=input_axis_tuser,
|
||||||
|
output_axis_tdata=output_axis_tdata,
|
||||||
|
output_axis_tvalid=output_axis_tvalid,
|
||||||
|
output_axis_tready=output_axis_tready,
|
||||||
|
output_axis_tlast=output_axis_tlast,
|
||||||
|
output_axis_tuser=output_axis_tuser)
|
||||||
|
|
||||||
|
def cobs_encode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
enc = bytearray()
|
||||||
|
|
||||||
|
seg = bytearray()
|
||||||
|
code = 1
|
||||||
|
|
||||||
|
new_data = True
|
||||||
|
|
||||||
|
for b in block:
|
||||||
|
if b == 0:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = True
|
||||||
|
else:
|
||||||
|
code += 1
|
||||||
|
seg.append(b)
|
||||||
|
new_data = True
|
||||||
|
if code == 255:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = False
|
||||||
|
|
||||||
|
if new_data:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
|
||||||
|
return bytes(enc)
|
||||||
|
|
||||||
|
def cobs_decode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
dec = bytearray()
|
||||||
|
|
||||||
|
it = iter(bytearray(block))
|
||||||
|
code = 0
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
if 0 in block:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while i < len(block):
|
||||||
|
code = block[i]
|
||||||
|
i += 1
|
||||||
|
if i+code-1 > len(block):
|
||||||
|
return None
|
||||||
|
for k in range(code-1):
|
||||||
|
dec.append(block[i])
|
||||||
|
i += 1
|
||||||
|
if code < 255 and i < len(block):
|
||||||
|
dec.append(0)
|
||||||
|
|
||||||
|
return bytes(dec)
|
||||||
|
|
||||||
|
def prbs31(state = 0x7fffffff):
|
||||||
|
while True:
|
||||||
|
for i in range(8):
|
||||||
|
if bool(state & 0x08000000) ^ bool(state & 0x40000000):
|
||||||
|
state = ((state & 0x3fffffff) << 1) | 1
|
||||||
|
else:
|
||||||
|
state = (state & 0x3fffffff) << 1
|
||||||
|
yield state & 0xff
|
||||||
|
|
||||||
|
def bench():
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
APPEND_ZERO = 0
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
clk = Signal(bool(0))
|
||||||
|
rst = Signal(bool(0))
|
||||||
|
current_test = Signal(intbv(0)[8:])
|
||||||
|
|
||||||
|
input_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
input_axis_tvalid = Signal(bool(0))
|
||||||
|
input_axis_tlast = Signal(bool(0))
|
||||||
|
input_axis_tuser = Signal(bool(0))
|
||||||
|
output_axis_tready = Signal(bool(0))
|
||||||
|
|
||||||
|
# Outputs
|
||||||
|
input_axis_tready = Signal(bool(0))
|
||||||
|
output_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
output_axis_tvalid = Signal(bool(0))
|
||||||
|
output_axis_tlast = Signal(bool(0))
|
||||||
|
output_axis_tuser = Signal(bool(0))
|
||||||
|
|
||||||
|
# sources and sinks
|
||||||
|
source_queue = Queue()
|
||||||
|
source_pause = Signal(bool(0))
|
||||||
|
sink_queue = Queue()
|
||||||
|
sink_pause = Signal(bool(0))
|
||||||
|
|
||||||
|
source = axis_ep.AXIStreamSource(clk,
|
||||||
|
rst,
|
||||||
|
tdata=input_axis_tdata,
|
||||||
|
tvalid=input_axis_tvalid,
|
||||||
|
tready=input_axis_tready,
|
||||||
|
tlast=input_axis_tlast,
|
||||||
|
tuser=input_axis_tuser,
|
||||||
|
fifo=source_queue,
|
||||||
|
pause=source_pause,
|
||||||
|
name='source')
|
||||||
|
|
||||||
|
sink = axis_ep.AXIStreamSink(clk,
|
||||||
|
rst,
|
||||||
|
tdata=output_axis_tdata,
|
||||||
|
tvalid=output_axis_tvalid,
|
||||||
|
tready=output_axis_tready,
|
||||||
|
tlast=output_axis_tlast,
|
||||||
|
tuser=output_axis_tuser,
|
||||||
|
fifo=sink_queue,
|
||||||
|
pause=sink_pause,
|
||||||
|
name='sink')
|
||||||
|
|
||||||
|
# DUT
|
||||||
|
dut = dut_axis_cobs_encode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser)
|
||||||
|
|
||||||
|
@always(delay(4))
|
||||||
|
def clkgen():
|
||||||
|
clk.next = not clk
|
||||||
|
|
||||||
|
def wait_normal():
|
||||||
|
i = 4
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 4
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_source():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
source_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
source_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_sink():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
sink_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
sink_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
for payload_len in list(range(1,33))+list(range(253,259))+[512]:
|
||||||
|
gen = prbs31()
|
||||||
|
for block in [bytearray([0]*payload_len),
|
||||||
|
bytearray([k%255+1 for k in range(payload_len)]),
|
||||||
|
b'\x00'+bytearray([k%255+1 for k in range(payload_len)])+b'\x00',
|
||||||
|
bytearray([next(gen) for i in range(payload_len)])]:
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 1: test packet, length %d" % payload_len)
|
||||||
|
current_test.next = 1
|
||||||
|
|
||||||
|
enc = cobs_encode(block)
|
||||||
|
|
||||||
|
test_frame = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc
|
||||||
|
assert cobs_decode(rx_frame.data) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||||
|
current_test.next = 2
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(block)
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc
|
||||||
|
assert cobs_decode(rx_frame.data) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc
|
||||||
|
assert cobs_decode(rx_frame.data) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 3: tuser assert, length %d" % payload_len)
|
||||||
|
current_test.next = 3
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(block)
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
test_frame1.user = 1
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(rx_frame.data) == None
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc
|
||||||
|
assert cobs_decode(rx_frame.data) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
raise StopSimulation
|
||||||
|
|
||||||
|
return dut, source, sink, clkgen, check
|
||||||
|
|
||||||
|
def test_bench():
|
||||||
|
sim = Simulation(bench())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("Running test...")
|
||||||
|
test_bench()
|
94
lib/axis/tb/test_axis_cobs_encode.v
Normal file
94
lib/axis/tb/test_axis_cobs_encode.v
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016 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 axis_cobs_encode
|
||||||
|
*/
|
||||||
|
module test_axis_cobs_encode;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
parameter APPEND_ZERO = 0;
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
reg clk = 0;
|
||||||
|
reg rst = 0;
|
||||||
|
reg [7:0] current_test = 0;
|
||||||
|
|
||||||
|
reg [7:0] input_axis_tdata = 0;
|
||||||
|
reg input_axis_tvalid = 0;
|
||||||
|
reg input_axis_tlast = 0;
|
||||||
|
reg input_axis_tuser = 0;
|
||||||
|
reg output_axis_tready = 0;
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
wire input_axis_tready;
|
||||||
|
wire [7:0] output_axis_tdata;
|
||||||
|
wire output_axis_tvalid;
|
||||||
|
wire output_axis_tlast;
|
||||||
|
wire output_axis_tuser;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// myhdl integration
|
||||||
|
$from_myhdl(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tready);
|
||||||
|
$to_myhdl(input_axis_tready,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser);
|
||||||
|
|
||||||
|
// dump file
|
||||||
|
$dumpfile("test_axis_cobs_encode.lxt");
|
||||||
|
$dumpvars(0, test_axis_cobs_encode);
|
||||||
|
end
|
||||||
|
|
||||||
|
axis_cobs_encode #(
|
||||||
|
.APPEND_ZERO(APPEND_ZERO)
|
||||||
|
)
|
||||||
|
UUT (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.input_axis_tdata(input_axis_tdata),
|
||||||
|
.input_axis_tvalid(input_axis_tvalid),
|
||||||
|
.input_axis_tready(input_axis_tready),
|
||||||
|
.input_axis_tlast(input_axis_tlast),
|
||||||
|
.input_axis_tuser(input_axis_tuser),
|
||||||
|
.output_axis_tdata(output_axis_tdata),
|
||||||
|
.output_axis_tvalid(output_axis_tvalid),
|
||||||
|
.output_axis_tready(output_axis_tready),
|
||||||
|
.output_axis_tlast(output_axis_tlast),
|
||||||
|
.output_axis_tuser(output_axis_tuser)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
381
lib/axis/tb/test_axis_cobs_encode_zero_frame.py
Executable file
381
lib/axis/tb/test_axis_cobs_encode_zero_frame.py
Executable file
@ -0,0 +1,381 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
|
||||||
|
Copyright (c) 2016 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
|
||||||
|
|
||||||
|
try:
|
||||||
|
from queue import Queue
|
||||||
|
except ImportError:
|
||||||
|
from Queue import Queue
|
||||||
|
|
||||||
|
import axis_ep
|
||||||
|
|
||||||
|
module = 'axis_cobs_encode'
|
||||||
|
testbench = 'test_axis_cobs_encode_zero_frame'
|
||||||
|
|
||||||
|
srcs = []
|
||||||
|
|
||||||
|
srcs.append("../rtl/%s.v" % module)
|
||||||
|
srcs.append("../rtl/axis_fifo.v")
|
||||||
|
srcs.append("%s.v" % testbench)
|
||||||
|
|
||||||
|
src = ' '.join(srcs)
|
||||||
|
|
||||||
|
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||||
|
|
||||||
|
def dut_axis_cobs_encode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser):
|
||||||
|
|
||||||
|
if os.system(build_cmd):
|
||||||
|
raise Exception("Error running build command")
|
||||||
|
return Cosimulation("vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||||
|
clk=clk,
|
||||||
|
rst=rst,
|
||||||
|
current_test=current_test,
|
||||||
|
input_axis_tdata=input_axis_tdata,
|
||||||
|
input_axis_tvalid=input_axis_tvalid,
|
||||||
|
input_axis_tready=input_axis_tready,
|
||||||
|
input_axis_tlast=input_axis_tlast,
|
||||||
|
input_axis_tuser=input_axis_tuser,
|
||||||
|
output_axis_tdata=output_axis_tdata,
|
||||||
|
output_axis_tvalid=output_axis_tvalid,
|
||||||
|
output_axis_tready=output_axis_tready,
|
||||||
|
output_axis_tlast=output_axis_tlast,
|
||||||
|
output_axis_tuser=output_axis_tuser)
|
||||||
|
|
||||||
|
def cobs_encode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
enc = bytearray()
|
||||||
|
|
||||||
|
seg = bytearray()
|
||||||
|
code = 1
|
||||||
|
|
||||||
|
new_data = True
|
||||||
|
|
||||||
|
for b in block:
|
||||||
|
if b == 0:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = True
|
||||||
|
else:
|
||||||
|
code += 1
|
||||||
|
seg.append(b)
|
||||||
|
new_data = True
|
||||||
|
if code == 255:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
code = 1
|
||||||
|
seg = bytearray()
|
||||||
|
new_data = False
|
||||||
|
|
||||||
|
if new_data:
|
||||||
|
enc.append(code)
|
||||||
|
enc.extend(seg)
|
||||||
|
|
||||||
|
return bytes(enc)
|
||||||
|
|
||||||
|
def cobs_decode(block):
|
||||||
|
block = bytearray(block)
|
||||||
|
dec = bytearray()
|
||||||
|
|
||||||
|
it = iter(bytearray(block))
|
||||||
|
code = 0
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
if 0 in block:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while i < len(block):
|
||||||
|
code = block[i]
|
||||||
|
i += 1
|
||||||
|
if i+code-1 > len(block):
|
||||||
|
return None
|
||||||
|
for k in range(code-1):
|
||||||
|
dec.append(block[i])
|
||||||
|
i += 1
|
||||||
|
if code < 255 and i < len(block):
|
||||||
|
dec.append(0)
|
||||||
|
|
||||||
|
return bytes(dec)
|
||||||
|
|
||||||
|
def prbs31(state = 0x7fffffff):
|
||||||
|
while True:
|
||||||
|
for i in range(8):
|
||||||
|
if bool(state & 0x08000000) ^ bool(state & 0x40000000):
|
||||||
|
state = ((state & 0x3fffffff) << 1) | 1
|
||||||
|
else:
|
||||||
|
state = (state & 0x3fffffff) << 1
|
||||||
|
yield state & 0xff
|
||||||
|
|
||||||
|
def bench():
|
||||||
|
|
||||||
|
# Parameters
|
||||||
|
APPEND_ZERO = 1
|
||||||
|
|
||||||
|
# Inputs
|
||||||
|
clk = Signal(bool(0))
|
||||||
|
rst = Signal(bool(0))
|
||||||
|
current_test = Signal(intbv(0)[8:])
|
||||||
|
|
||||||
|
input_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
input_axis_tvalid = Signal(bool(0))
|
||||||
|
input_axis_tlast = Signal(bool(0))
|
||||||
|
input_axis_tuser = Signal(bool(0))
|
||||||
|
output_axis_tready = Signal(bool(0))
|
||||||
|
|
||||||
|
# Outputs
|
||||||
|
input_axis_tready = Signal(bool(0))
|
||||||
|
output_axis_tdata = Signal(intbv(0)[8:])
|
||||||
|
output_axis_tvalid = Signal(bool(0))
|
||||||
|
output_axis_tlast = Signal(bool(0))
|
||||||
|
output_axis_tuser = Signal(bool(0))
|
||||||
|
|
||||||
|
# sources and sinks
|
||||||
|
source_queue = Queue()
|
||||||
|
source_pause = Signal(bool(0))
|
||||||
|
sink_queue = Queue()
|
||||||
|
sink_pause = Signal(bool(0))
|
||||||
|
|
||||||
|
source = axis_ep.AXIStreamSource(clk,
|
||||||
|
rst,
|
||||||
|
tdata=input_axis_tdata,
|
||||||
|
tvalid=input_axis_tvalid,
|
||||||
|
tready=input_axis_tready,
|
||||||
|
tlast=input_axis_tlast,
|
||||||
|
tuser=input_axis_tuser,
|
||||||
|
fifo=source_queue,
|
||||||
|
pause=source_pause,
|
||||||
|
name='source')
|
||||||
|
|
||||||
|
sink = axis_ep.AXIStreamSink(clk,
|
||||||
|
rst,
|
||||||
|
tdata=output_axis_tdata,
|
||||||
|
tvalid=output_axis_tvalid,
|
||||||
|
tready=output_axis_tready,
|
||||||
|
tlast=output_axis_tlast,
|
||||||
|
tuser=output_axis_tuser,
|
||||||
|
fifo=sink_queue,
|
||||||
|
pause=sink_pause,
|
||||||
|
name='sink')
|
||||||
|
|
||||||
|
# DUT
|
||||||
|
dut = dut_axis_cobs_encode(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tready,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tready,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser)
|
||||||
|
|
||||||
|
@always(delay(4))
|
||||||
|
def clkgen():
|
||||||
|
clk.next = not clk
|
||||||
|
|
||||||
|
def wait_normal():
|
||||||
|
i = 4
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 4
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_source():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
source_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
source_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
def wait_pause_sink():
|
||||||
|
i = 2
|
||||||
|
while i > 0:
|
||||||
|
i = max(0, i-1)
|
||||||
|
if input_axis_tvalid or output_axis_tvalid or not source_queue.empty():
|
||||||
|
i = 2
|
||||||
|
sink_pause.next = True
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
sink_pause.next = False
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
for payload_len in list(range(1,33))+list(range(253,259))+[512]:
|
||||||
|
gen = prbs31()
|
||||||
|
for block in [bytearray([0]*payload_len),
|
||||||
|
bytearray([k%255+1 for k in range(payload_len)]),
|
||||||
|
b'\x00'+bytearray([k%255+1 for k in range(payload_len)])+b'\x00',
|
||||||
|
bytearray([next(gen) for i in range(payload_len)])]:
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 1: test packet, length %d" % payload_len)
|
||||||
|
current_test.next = 1
|
||||||
|
|
||||||
|
enc = cobs_encode(block)
|
||||||
|
|
||||||
|
test_frame = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc+b'\x00'
|
||||||
|
assert cobs_decode(rx_frame.data[:-1]) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||||
|
current_test.next = 2
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(block)
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc+b'\x00'
|
||||||
|
assert cobs_decode(rx_frame.data[:-1]) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc+b'\x00'
|
||||||
|
assert cobs_decode(rx_frame.data[:-1]) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
print("test 3: tuser assert, length %d" % payload_len)
|
||||||
|
current_test.next = 3
|
||||||
|
|
||||||
|
test_frame1 = axis_ep.AXIStreamFrame(block)
|
||||||
|
test_frame2 = axis_ep.AXIStreamFrame(block)
|
||||||
|
|
||||||
|
test_frame1.user = 1
|
||||||
|
|
||||||
|
for wait in wait_normal, wait_pause_source, wait_pause_sink:
|
||||||
|
source_queue.put(test_frame1)
|
||||||
|
source_queue.put(test_frame2)
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
yield wait()
|
||||||
|
|
||||||
|
yield clk.posedge
|
||||||
|
yield clk.posedge
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(rx_frame.data[:-1]) == None
|
||||||
|
assert rx_frame.user[-1]
|
||||||
|
|
||||||
|
rx_frame = sink_queue.get(False)
|
||||||
|
|
||||||
|
assert cobs_decode(enc) == block
|
||||||
|
assert rx_frame.data == enc+b'\x00'
|
||||||
|
assert cobs_decode(rx_frame.data[:-1]) == block
|
||||||
|
assert not rx_frame.user[-1]
|
||||||
|
|
||||||
|
assert sink_queue.empty()
|
||||||
|
|
||||||
|
yield delay(100)
|
||||||
|
|
||||||
|
raise StopSimulation
|
||||||
|
|
||||||
|
return dut, source, sink, clkgen, check
|
||||||
|
|
||||||
|
def test_bench():
|
||||||
|
sim = Simulation(bench())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("Running test...")
|
||||||
|
test_bench()
|
94
lib/axis/tb/test_axis_cobs_encode_zero_frame.v
Normal file
94
lib/axis/tb/test_axis_cobs_encode_zero_frame.v
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016 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 axis_cobs_encode
|
||||||
|
*/
|
||||||
|
module test_axis_cobs_encode_zero_frame;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
parameter APPEND_ZERO = 1;
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
reg clk = 0;
|
||||||
|
reg rst = 0;
|
||||||
|
reg [7:0] current_test = 0;
|
||||||
|
|
||||||
|
reg [7:0] input_axis_tdata = 0;
|
||||||
|
reg input_axis_tvalid = 0;
|
||||||
|
reg input_axis_tlast = 0;
|
||||||
|
reg input_axis_tuser = 0;
|
||||||
|
reg output_axis_tready = 0;
|
||||||
|
|
||||||
|
// Outputs
|
||||||
|
wire input_axis_tready;
|
||||||
|
wire [7:0] output_axis_tdata;
|
||||||
|
wire output_axis_tvalid;
|
||||||
|
wire output_axis_tlast;
|
||||||
|
wire output_axis_tuser;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// myhdl integration
|
||||||
|
$from_myhdl(clk,
|
||||||
|
rst,
|
||||||
|
current_test,
|
||||||
|
input_axis_tdata,
|
||||||
|
input_axis_tvalid,
|
||||||
|
input_axis_tlast,
|
||||||
|
input_axis_tuser,
|
||||||
|
output_axis_tready);
|
||||||
|
$to_myhdl(input_axis_tready,
|
||||||
|
output_axis_tdata,
|
||||||
|
output_axis_tvalid,
|
||||||
|
output_axis_tlast,
|
||||||
|
output_axis_tuser);
|
||||||
|
|
||||||
|
// dump file
|
||||||
|
$dumpfile("test_axis_cobs_encode_zero_frame.lxt");
|
||||||
|
$dumpvars(0, test_axis_cobs_encode_zero_frame);
|
||||||
|
end
|
||||||
|
|
||||||
|
axis_cobs_encode #(
|
||||||
|
.APPEND_ZERO(APPEND_ZERO)
|
||||||
|
)
|
||||||
|
UUT (
|
||||||
|
.clk(clk),
|
||||||
|
.rst(rst),
|
||||||
|
.input_axis_tdata(input_axis_tdata),
|
||||||
|
.input_axis_tvalid(input_axis_tvalid),
|
||||||
|
.input_axis_tready(input_axis_tready),
|
||||||
|
.input_axis_tlast(input_axis_tlast),
|
||||||
|
.input_axis_tuser(input_axis_tuser),
|
||||||
|
.output_axis_tdata(output_axis_tdata),
|
||||||
|
.output_axis_tvalid(output_axis_tvalid),
|
||||||
|
.output_axis_tready(output_axis_tready),
|
||||||
|
.output_axis_tlast(output_axis_tlast),
|
||||||
|
.output_axis_tuser(output_axis_tuser)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
Loading…
x
Reference in New Issue
Block a user