Есть как программа для обмена порядком с прямым байтовым порядком (малым и большим), так и его тестовая среда. Поток данных поступает в модуль и преобразуется в другой порядок байтов с помощью вычислительной логики.
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 ответ
В коде хорошо используются параметры. Однако я вижу потенциальную проблему.
if (0 == (DATA_WIDTH % 4)) begin
Этот код, кажется, подразумевает, что поддерживается любое кратное 4. Но если я попробую DATA_WIDTH = 20, тогда я вижу z значения на выходе. Возможно, вам следует ограничить значения кратными 8:
if (0 == (DATA_WIDTH % 8)) begin
Обычно слово «проверка» означает, что вы сравниваете фактическое значение с ожидаемым и сообщаете об ошибке, если они не совпадают. В check_swap задача просто отображает значения. Если это все, что вы хотите сделать, я предлагаю переименовать задачу как display_swap или же monitor_swap.
Однако вы можете добавить код в тестовую среду для сравнения. Если ваш набор инструментов поддерживает функции SystemVerilog, следующие дополнения / модификации обеспечат автоматическую проверку:
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
Для создания ожидаемых данных (data_o) Я скопировал generate код из проекта и сделал некоторые упрощения. В {<< 8{counter_dir_value}} синтаксис — еще один способ выполнить обмен байтами. См. IEEE Std 1800-2017, раздел 11.4.14. Операторы потоковой передачи (упаковка / распаковка). В '0 синтаксис — это упрощенный способ присвоения всех битов 0, эквивалентный тому, что у вас уже есть. Если вы планируете синтезировать дизайн и ваша цепочка инструментов поддерживает этот синтаксис, вы даже можете использовать этот код в своем модуле дизайна.
Небольшое примечание: с таким типом task тело, begin/end ключевые слова теперь необязательны.
