There are both a simple byte endian (little and big) order swapper and its testbench. A data stream inputs to the module and is converted to the other endianness by computational logic.
byte_order_swap.v
`timescale 1ns / 1ps
module byte_order_swap #
(
parameter integer DATA_WIDTH = 32
)
(
input wire [DATA_WIDTH - 1 : 0] data_i,
input wire [DATA_WIDTH - 1 : 0] data_o
);
localparam integer DATA_BYTE_NUMBER = DATA_WIDTH / 8;
localparam integer DEC_DATA_WIDTH = DATA_WIDTH - 1;
generate
genvar i;
if (0 == (DATA_WIDTH % 4)) begin
for(i = 0; i < DATA_BYTE_NUMBER; i = i + 1) begin
assign data_o[(i * 8) +: 8] = data_i[(DEC_DATA_WIDTH - i * 8) -: 8];
end
end
else begin
assign data_o = {DATA_WIDTH{1'h0}};
end
endgenerate
endmodule
byte_order_swap_tb.v
`timescale 1ns / 1ps
module byte_order_swap_tb;
localparam integer DATA_WIDTH = 32;
localparam integer CLOCK_PERIOD = 100;
localparam integer ITERATION_NUMBER = 1000;
localparam [DATA_WIDTH - 1 : 0] COUNTER_START_VALUE = 32'hAABB1122;
wire [DATA_WIDTH - 1 : 0] counter_swap_value;
reg clk;
reg [DATA_WIDTH - 1 : 0] counter_dir_value;
byte_order_swap #
(
.DATA_WIDTH (DATA_WIDTH)
)
byte_order_swap_dut
(
.data_i (counter_dir_value),
.data_o (counter_swap_value)
);
initial begin
clk = 1'h0;
forever begin
#( CLOCK_PERIOD / 2 ) clk = !clk;
end
end
initial begin
counter_dir_value <= COUNTER_START_VALUE;
repeat(ITERATION_NUMBER) begin
@(posedge clk);
counter_dir_value <= counter_dir_value + 1'h1;
end
end
task check_swap;
begin
repeat(ITERATION_NUMBER) begin
@(posedge clk);
$display("A direction value: %h -> the swap value: %h",counter_dir_value, counter_swap_value, $time);
end
end
endtask
initial begin
check_swap;
$stop();
end
endmodule
1 Answer 1
The code makes good use of parameters. However, I see a potential problem.
if (0 == (DATA_WIDTH % 4)) begin
That code seems to imply that any multiple of 4 is supported. But, if I try DATA_WIDTH
= 20, then I see z
values in the output. Perhaps you should restrict values to be a multiple of 8 instead:
if (0 == (DATA_WIDTH % 8)) begin
Conventionally, the word "check" means that you will compare an actual value to an expected value and report an error if the two do not match. The check_swap
task simply displays the values. If that is all you are looking to do, then I suggest renaming the task as display_swap
or monitor_swap
.
However, you could add code to the testbench to do a comparison. If your tool suite supports SystemVerilog features, then the following additions/modifications would provide automatic checking:
wire [DATA_WIDTH - 1 : 0] data_o;
generate
if (0 == (DATA_WIDTH % 8)) begin
assign data_o = {<< 8{counter_dir_value}};
end else begin
assign data_o = '0;
end
endgenerate
task check_swap;
repeat(ITERATION_NUMBER) begin
@(posedge clk);
$display("A direction value: %h -> the swap value: %h", counter_dir_value, counter_swap_value, $time);
if (data_o !== counter_swap_value) begin
$display("ERROR: data miscompare", $time);
end
end
endtask
To create the expected data (data_o
), I copied the generate
code from the design and made some simplifications. The {<< 8{counter_dir_value}}
syntax is another way to perform the byte swap. Refer to IEEE Std 1800-2017, section 11.4.14 Streaming operators (pack/unpack). The '0
syntax is a simplified way of assigning all bits to 0, equivalent to what you have already. If you plan to synthesize the design, and your tool chain supports this syntax, you could even use this code in your design module.
A minor note: with that type of task
body, the begin/end
keywords are now optional.
-
1\$\begingroup\$ Thank you for the reply. Your criticism and rectification of my code are very important for me. Sorry for the late answer. \$\endgroup\$Drakonof– Drakonof2021年03月18日 07:15:14 +00:00Commented Mar 18, 2021 at 7:15