Готовое рукопожатие в Verilog - PullRequest
       86

Готовое рукопожатие в Verilog

0 голосов
/ 02 декабря 2018

Я пытаюсь выучить правильное / готовое рукопожатие в verilog.В частности, мне интересно использовать флаг ready в качестве флага, который указывает на успешную транзакцию данных (т. Е. ready_in становится высоким после того, как valid_out становится высоким).Я хотел бы объяснить мою проблему на очень простом примере Verilog.Я написал сверточный кодер (код ниже)

module Conv_Encoder_Core(
    input wire clk,                 
    input wire reset,        
    input wire in_bit,
    output reg out_A,
    output reg out_B,
    input wire sleep,          
    input wire valid_in,
    input wire ready_in,
    output reg valid_out,
    output reg ready_out);

reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;

always @(posedge clkON)begin
    if (reset) begin
        S <=0;
        valid_out <=0; 
        ready_out <=0;
    end else if (valid_in) begin
        out_A <= in_bit ^ S_A;
        out_B <= in_bit ^ S_B;
        valid_out <=1;
        if (ready_in)begin
            S<= S<<1;
            S[0] <=in_bit;
            ready_out <=1;
        end else begin
            ready_out <=0;
        end

    end else begin
        valid_out <=0;
        ready_out <=0;
    end


end 
endmodule

Мне интересно использовать флаг ready_in в качестве индикатора того, что данные out_A и out_B получены следующим блоком, поэтому мой блокможете принять новые данные, установив флаг ready_out.Я написал тестовый стенд для этого блока, однако я не получаю ожидаемых результатов

`timescale 1 ns/1 ns
module TB_Conv();
reg  clk;
//---------------clock generator-----------------------
initial begin
    clk = 1'b0; 
    #5; 
    clk = 1'b1; 
    forever    begin
        #5 clk = ~clk;      
    end
end
//------------------ dump -----------------------
initial begin
    $dumpfile("dumpVCD.vcd");
    $dumpvars(10);  
end

localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
    in_bits_vec[0] = 1'b1;
    in_bits_vec[1] = 1'b0; 
    in_bits_vec[2] = 1'b0; 
    in_bits_vec[3] = 1'b0; 
    in_bits_vec[4] = 1'b0;
    in_bits_vec[5] = 1'b0;
    in_bits_vec[6] = 1'b0;
    in_bits_vec[7] = 1'b0;
    in_bits_vec[8] = 1'b0;
    in_bits_vec[9] = 1'b1;
end
reg in_bit, ready_in,reset, valid_in;
Conv_Encoder_Core UUT(.clk(clk),
                        .reset(reset),
                        .in_bit(in_bit),
                        .out_A(out_A),
                        .out_B(out_B),
                        .sleep(1'b0),
                        .valid_in(valid_in),
                        .ready_in(ready_in),
                        .valid_out(valid_out),
                        .ready_out(ready_out));

//---------------- code starts here -------------------//
reg [3:0] addr;
always @(posedge clk) begin
    if (reset)begin
        addr<=0;
        valid_in <=0;
        in_bit <=0;
    end else if (addr < 10) begin
        in_bit <= in_bits_vec[addr];
        valid_in <=1'b1;
        if (ready_out) begin
            addr <= addr+1'b1;
        end

    end else  begin
        in_bit <=0;
        valid_in <=0;
    end

    if (valid_out==1) ready_in <= 1;
    else              ready_in <= 0;

end 
// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always @(negedge clk)begin
    if (cnt<5) begin
        reset = 1;
        cnt=cnt+1;
    end else  reset =0;
end

initial begin
 #1000;
$finish;
end
endmodule

Если вы посмотрите на входные данные (в тестовом бекче), вы увидите, что это 1000000000,Я ожидаю увидеть, как 1 будет проходить через регистр S следующим образом:

S = 000000 //at beginning
S = 000001 // after ready_out=1
S = 000010
S = 000100

однако результаты, которые я получаю, совершенно другие (см. Снимок экрана).Другая проблема, с которой я столкнулся, заключается в том, что inbit=1 продолжает на два такта больше, чем я ожидаю.на самом деле, когда ready_out=1, я ожидаю увидеть, что in_bit станет равным нулю, но это происходит через два такта (желтый курсор на снимке).

Я был бы очень признателен, если бы кто-то мог объяснить, что я делаюнеправильно в этом примере.

enter image description here

1 Ответ

0 голосов
/ 25 декабря 2018

Conv_Encoder_Core

module Conv_Encoder_Core
(
    input wire clk,
    input wire reset,
    input wire in_bit,
    output reg out_A,
    output reg out_B,
    input wire sleep,
    // input channel
    input  wire inp_valid_i,
    output wire inp_ready_o,
    // output channel
    output reg out_valid_o,
    input  reg out_ready_i
);

reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;


// -- Changes start here -- //
wire wr_en;
reg full_r;

assign wr_en = ~full_r | out_ready_i;
always @(posedge clkON)begin
    if (reset) begin
        S <=0;
        full_r <=0;
    end else begin
        if (wr_en) begin
            if (inp_valid_i) begin
                full_r  <= 1;
                out_A   <= in_bit ^ S_A;
                out_B   <= in_bit ^ S_B;
                S       <= S<<1;
                S[0]    <=in_bit;
            end else begin
                full_r  <= 0;
            end
        end
    end
end

assign inp_ready_o = wr_en;
assign out_valid_o = full_r;

endmodule

tb

`timescale 1 ns/1 ns
module tb();
reg  clk;
//---------------clock generator-----------------------
initial begin
    clk = 1'b0; 
    #5; 
    clk = 1'b1; 
    forever    begin
        #5 clk = ~clk;      
    end
end
//------------------ dump -----------------------
initial begin
    $dumpfile("dumpVCD.vcd");
    $dumpvars(10);  
end

localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
    in_bits_vec[0] = 1'b1;
    in_bits_vec[1] = 1'b0; 
    in_bits_vec[2] = 1'b0; 
    in_bits_vec[3] = 1'b0; 
    in_bits_vec[4] = 1'b0;
    in_bits_vec[5] = 1'b0;
    in_bits_vec[6] = 1'b0;
    in_bits_vec[7] = 1'b0;
    in_bits_vec[8] = 1'b0;
    in_bits_vec[9] = 1'b1;
end
reg in_bit, reset, inp_valid, inp_ready, out_valid, out_ready;
Conv_Encoder_Core UUT(.clk(clk),
                        .reset(reset),
                        .in_bit(in_bit),
                        .out_A(out_A),
                        .out_B(out_B),
                        .sleep(1'b0),
                        // input channel
                        .inp_valid_i(inp_valid),
                        .inp_ready_o(inp_ready),
                        // output channel
                        .out_valid_o(out_valid),
                        .out_ready_i(out_ready));

//---------------- code starts here -------------------//
reg [3:0] addr;

// -- Transmitter Side -- //
always @(posedge clk) begin: ff_addr
    if (reset)begin
        addr <= 0;
    end else begin
        if (addr < 10) begin
            if (inp_valid && inp_ready) begin
                addr <= addr + 1;
            end
        end else begin
            addr <= 0;
        end
    end
end

assign inp_valid = (addr < 10) ? 1'b1 : 1'b0;

assign in_bit = in_bits_vec[addr];

// -- Receiver Side -- //
always @(posedge clk) begin: ff_ready_in
    if (reset) begin
        out_ready <= 0;
    end else begin
        out_ready <= $urandom_range(0, 1); // some randomness on the receiver, otherwise, we won't see if our DUT behaves correctly in case of ready=0
    end
end

// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always @(negedge clk)begin
    if (cnt<5) begin
        reset = 1;
        cnt=cnt+1;
    end else  reset =0;
end

initial begin
 #1000;
$finish;
end
endmodule

Проблемы с вашей реализацией

Неверное определение и реализация протокола

Вы определяете протокол, который больше похож на "запрос / подтверждение", чем на "готов / действителен", поскольку передачи данных в вашем протоколе подтверждаются после однократной задержки .Что вам нужно, это подтверждение одновременной передачи в том же цикле 1017 *, что-то вроде следующего:

enter image description here

Указана действительная передача данныхпередатчиком через valid=1 и подтверждены получателем через ready=1.Итак, передача данных действительна только тогда, когда valid && ready в том же цикле.Обратите внимание, что вход data эквивалентен in_bit в вашем случае, в то время как выход data равен out_A и out_B.

Вход / выход готов / допустимая путаница канала

Если вы добавите блок обработки / буферизации между передатчиком и приемником вышеуказанного канала, то вы получите что-то вроде этого:

enter image description here

В этом случае ваш буфер является модулем Conv_Encoder_Core и, кроме внутренней логики ядра, он должен предоставлять входной готовый / действительный канал, из которого он получает входные данные, и вывод один, из которого он выводит свои данные.Также обратите внимание, что передатчик и приемник реализованы с помощью кода тестового стенда (модуль tb).См. Комментарии «Сторона передатчика» и «Сторона приемника» в коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...