Разворот бит в шине на Verilog

Казалось бы простая задача: как развернуть биты в шине так, чтоб младший бит стал старшим, а старший самым младшим? Первое, что приходит на ум: написать вот так:


reg [7:0]src;
//reverse?
wire [0:7]re1; assign re1 = src; //does not work..


Но это так не работает!
Какие есть работающие варианты?

Первый и самый понятный способ - это расписывать каждый бит в отдельности. Вот так:


//method 1
wire [7:0]re2; assign re2 = {src[0],src[1],src[2],src[3],src[4],src[5],src[6],src[7]};


Это отличный метод, который использует оператор конкатенации, объединяет известные сигналы в новом нужном порядке. Этим методом легко пользоваться, когда число сигналов в шине не велико. Если же шина многоразрядная, 64, 128, 1024 бита, то как быть?

Второй метод - это написать и использовать специальную функцию:


function [7:0] fbit_reverse ( input [7:0] data );
integer i;
begin
  for ( i=0; i<8; i=i+1 )
    begin
      fbit_reverse[7-i] = data[i];
    end
  end
endfunction


В эту функцию можно передать восьмибитный сигнал и она выдаст нам другой восьмибитный сигнал, где биты уже развернуты, как нужно. Вот так:


//method 2, use reverse function
wire [7:0]re3; assign re3 = fbit_reverse(src);


Хорошее решение, но не придумал, как сделать его параметризуемым. Что если есть несколько шин которые имеют разную разрядность и каждую нужно развернуть? Тогда можно сделать отдельный параметризуемый модуль. Например, вот так:


module mod_bit_reverse( in, out );
parameter NUM_BITS = 16;
input wire [NUM_BITS-1:0]in;
output wire [NUM_BITS-1:0]out;
genvar i;
generate
  for(i=0; i<NUM_BITS; i=i+1)
  begin
    assign out[NUM_BITS-1-i] = in[i];
  end
endgenerate
endmodule


Этот модуль можно вставлять в другие модули и там и сям и задавать разрядность шин в параметре.
Вставить модуль в другой модуль верилом можно так:


wire [7:0]re4;
mod_bit_reverse // module name
  #(.NUM_BITS(8)) //module parameter, bus width
  my_reverse_module //module instance name
  (
    .in(src), // module signals
    .out(re4)
  );


Есть еще один вариант - использовать SystemVerilog Streaming Operator.


wire [7:0]re5;
assign re5 = {<<{src}};


Это замечательно работает, если симулировать в Modelsim. Для симуляции подходит даже Modelsim Starter Edition Intel v10.5b, который идет в комплекте с 16м квартусом.

Однако, похоже, что сам квартус такое не поддерживает. Увы.
Симулятор icarus verilog так же на эту строку дает ошибку - что-то вроде "sorry, streaming operators are not supported".

Чтобы не быть голословным, объединяю все описанные выше методы в один Verilog Testbench файл и пробую симулировать в Modelsim.

Вот тестбенч:


`timescale 1ns/1ns

module tb();

//source bits which should be reversed
reg [7:0]src;

//this method does not work! no reverse bits!!
wire [0:7]re1; assign re1 = src;

//method 1
wire [7:0]re2; assign re2 = {src[0],src[1],src[2],src[3],src[4],src[5],src[6],src[7]};

//method 2, use reverse function
wire [7:0]re3; assign re3 = fbit_reverse(src);

//method 3, use reversing module
wire [7:0]re4;
mod_bit_reverse #(.NUM_BITS(8)) my_reverse_module( .in(src), .out(re4) );

//method 4
//SystemVerilog streaming operators do not work neither with icarus verilog nor with Quartus Prime
//Modelsim Starter Edition v10.5b supports this
wire [7:0]re5;
assign re5 = {<<{src}};

initial
begin
$dumpfile("out.vcd");
$dumpvars(0,tb);
#10;

src = 8'hA1; #1;
$display("source %X",src);
$display("try1 reverse %X",re1);
$display("try2 reverse %X",re2);
$display("try3 reverse %X",re3);
$display("try4 reverse %X",re4);
$display("try5 reverse %X",re5);
#10;

src = 8'h78; #1;
$display("source %X",src);
$display("try1 reverse %X",re1);
$display("try2 reverse %X",re2);
$display("try3 reverse %X",re3);
$display("try4 reverse %X",re4);
$display("try5 reverse %X",re5);
#10;

src = 8'h1C; #1;
$display("source %X",src);
$display("try1 reverse %X",re1);
$display("try2 reverse %X",re2);
$display("try3 reverse %X",re3);
$display("try4 reverse %X",re4);
$display("try5 reverse %X",re5);
#10;
#10;
$finish();
end

function [7:0] fbit_reverse ( input [7:0] data );
integer i;
begin
  for ( i=0; i<8; i=i+1 )
  begin
    fbit_reverse[7-i] = data[i];
  end
end
endfunction

endmodule

module mod_bit_reverse( in, out );
parameter NUM_BITS = 16;
input wire [NUM_BITS-1:0]in;
output wire [NUM_BITS-1:0]out;
genvar i;
generate
  for(i=0; i<NUM_BITS; i=i+1)
  begin
    assign out[NUM_BITS-1-i] = in[i];
  end
endgenerate
endmodule


Еще напишу вспомогательный файл TB.DO со списоком команд симулятора Modelsim:


vlib work1
vlog -work work1 tb.v
vsim work1.tb
run -all


Запускаю в командной строке Modelsim:

>vsim -c -do tb.do

vsim

В консоли видно, как верилоговская системная функция $display выводит развернутый байт для методов 2, 3, 4 и 5. Метод 1, как я и говорил - не работает.

Кроме того, тестбенч создает файл OUT.VCD, который содержит информацию о сигналах проекта и который можно посмотреть с помощью gtkwave. Вот эти сигналы (скриншот программы gtkwave):

out vcd

Ну и напоследок, пожалуй нужно заметить, что любая логика разворачивающая шину, даже модуль mod_bit_reverse,  в микросхеме FPGA абсолютно не занимает никакого места. И это правильно, ведь фактически, никакой логики там и нет - есть просто переименование сигналов.

 


Добавить комментарий