Jump to content
    

variable part-select, Verilog

Приветствую!

 

Многие кто пишет на SystemVerilog/Verilog знаком с оператором для динамического выбора нужных кусков вектора/переменной/массива_регистров. 

+: -:

Больше часа ломал голову, как применить его в моем случае, может под вечер устал и не соображаю.  Вот то, что мне нужен сделать (если бы стандарт верилога поддерживал такую запись для варьируемого индекса)

data_o <= {buffer[4+shift_size-1:4],tmp[4:shift_size-1]};

Подскажите, пожалуйста, как описать такую конструкцию? ведь в ней варьируемая ширина вектора, а не фиксированная часть. Поддерживает ли верилог подобные штуки?

Вот весь код. Сразу отвечаю, что пока не симулил, т.к. смысла нет (синтаксическая ошибка range must be bounded by constant expressions), и обычно планирую это делать следующим этапом, пока что я уперся в это.

Если есть желающие, то прошу оставить обратную связь касательно кода. Буду рад любой аргументированной критике. Под Vivado 2018.2

module frame_aligner (
    input              clk_i   , // Clock
    input              arst_n  , // Asynchronous reset active low
    input              sync_i  ,
    input        [3:0] data_i  ,
    output logic [5:0] data_o  ,
    output logic       valid_o , // duty cycle = 2/3
    output logic       synced_o
);
    localparam SYNC_PATT = 12'b111111_000000;
    localparam SYNC_PATT_MR = ~SYNC_PATT;

    /*------------------------------------------------------------------------------
    --  Functions
    ------------------------------------------------------------------------------*/
    function automatic int unsigned clogb2_pure_f( input [31:0] value );
       int unsigned i ;
       int unsigned temp ;
       begin
          temp = 32;
          for (i=31; i>0; i=i-1) begin
              if (2**i >= value) begin
                  temp = i;
             end
          end
          return temp ;
       end
    endfunction

    function automatic logic [11:0] dynamic_shift_f ( input [11:0] data_i, input [clogb2_pure_f(12) - 1:0] ss);
        dynamic_shift_f = data_i;
        for (int i = 0; i < ss; i++) begin
            dynamic_shift_f = {dynamic_shift_f[0],dynamic_shift_f[11:1]};
        end
        return dynamic_shift_f;
    endfunction

    /*------------------------------------------------------------------------------
    --  Signals declaration
    ------------------------------------------------------------------------------*/
    logic sync_ff,sync_fr,sync_cdc;

    typedef enum logic [1:0] {
        INIT, FIND_PATTERN, SYNC_MODE_SHIFT,SYNC_MODE_ZERO
    } fsm_t;
    fsm_t state, state_next;

    logic [ 1:0] cnt         ;
    logic [11:0] buffer      ;
    logic        strb        ;
    logic [11:0] shifted_data;
    logic [ 4:0] tmp         ;

    logic match;
    logic [2:0] shift_size,shift_size_event;


    /*------------------------------------------------------------------------------
    --  Clock Domain crossing
    ------------------------------------------------------------------------------*/
    synchronize_ff #(.FF_CNT(3)) i_synchronize_ff (.clk_i(clk_i), .rstn_i(arst_n), .data_i(sync_i), .data_o(sync_cdc));
    always_ff @(posedge clk_i or negedge arst_n) begin : proc_sync_ff
        if(~arst_n) begin
            sync_ff <= 0;
        end else begin
            sync_ff <= sync_cdc;
        end
    end
    assign sync_fr = !sync_ff && sync_cdc;

    /*------------------------------------------------------------------------------
    --  Functional
    ------------------------------------------------------------------------------*/
    always_ff @(posedge clk_i or negedge arst_n) begin : proc_cnt
        if(~arst_n) begin
            cnt <= 0;
        end else begin
            cnt <= cnt < 2 ? cnt + 1'b1 : '0;
        end
    end

    assign strb = cnt == 2;

    always_ff @(posedge clk_i or negedge arst_n) begin : proc_buffer
        if(~arst_n) begin
            buffer <= 0;
        end else begin
            buffer <= {data_i,buffer[7:4]};
        end
    end

    always_ff @(posedge clk_i or negedge arst_n) begin : proc_shift_size
        if(~arst_n) begin
            shift_size <= 0;
        end else if ( strb ) begin
            if( state == FIND_PATTERN ) begin
                if( !match ) begin
                    shift_size <= shift_size < 5 ? shift_size + 1'b1 : '0 ;
                end else begin
                    shift_size <= shift_size < 5 ? shift_size + 1'b1 : '0 ;
                end
            end
        end
    end
    assign shift_size_event = ( shift_size != 0 ) ? ( 5 ) : ( shift_size - 1 );

    always_ff @(posedge clk_i or negedge arst_n) begin : proc_shifted_data
        if(~arst_n) begin
            shifted_data <= 0;
        end else if (strb) begin
            shifted_data <= dynamic_shift_f(buffer,shift_size);
        end
    end
    assign match = ( shifted_data == SYNC_PATT ) || ( shifted_data == SYNC_PATT );

    /*------------------------------------------------------------------------------
    --  FSM
    ------------------------------------------------------------------------------*/
    always_ff @(posedge clk_i or negedge arst_n) begin : proc_state
        if(~arst_n) begin
            state <= INIT;
        end else begin
            state <= state_next;
        end
    end

    always_comb begin : proc_state_next
        state_next = state;
        case (state)
            INIT              : state_next = ( sync_fr ) ? ( FIND_PATTERN ): ( state );
            FIND_PATTERN      : state_next = ( match ) ?  ((shift_size_event != 0 ) ? (SYNC_MODE_SHIFT) : (SYNC_MODE_ZERO)): ( state ) ;
            SYNC_MODE_SHIFT   : state_next = state;
            SYNC_MODE_ZERO    : state_next = state;
            default      : state_next = INIT ;
        endcase
    end

    /*------------------------------------------------------------------------------
    --  data to output
    ------------------------------------------------------------------------------*/
    always_ff @(posedge clk_i or negedge arst_n) begin : proc_data_o
        if(~arst_n) begin
            data_o <= '0;
            valid_o <= 1'b0;
            tmp    <= '0;
        end else begin
            case (state)
                SYNC_MODE_SHIFT : begin
                    case (cnt)
                        1 : begin
                            data_o <= {buffer[4+shift_size-1:4],tmp[4:shift_size-1]}; // ВОТ ТУТ!
                            valid_o <= 1'b1;
                        end
                        2 : begin
                            data_o <= buffer[shift_size +:6];
                            tmp <= buffer[11:7];
                            valid_o <= 1'b1;
                        end
                        default : begin
                            data_o <= data_o;
                            valid_o <= 1'b0;
                        end
                    endcase
                end

                SYNC_MODE_ZERO : begin
                    case (cnt)
                        1 : begin
                            data_o <= buffer[7:2];
                        end
                        2 : begin
                            data_o <= buffer[5:0];
                        end
                        default : begin
                            data_o  <= data_o;
                            valid_o <= 1'b0;
                        end
                    endcase
                end

                default : data_o <= data_o;
            endcase
        end
    end

    always_ff @(posedge clk_i or negedge arst_n) begin : proc_synced_o
        if(~arst_n) begin
            synced_o <= 1'b0;
        end else if ( match ) begin
            synced_o <= 1'b1;
        end
    end

endmodule

 

Edited by Darky777

Share this post


Link to post
Share on other sites

Приветствую!

Работу с частью вектора с динамической шириной в verilog можно делать используя  битовые маски, битовые операции, и сдвиги 

например в вашем случае (если я правильно понял логику)  все просто

data_o <= ({buffer[11:4],tmp[4:0]}<<1) >> shift_size;

Удачи! Rob.

 

 

 

Share this post


Link to post
Share on other sites

1 hour ago, RobFPGA said:

Приветствую!

Работу с частью вектора с динамической шириной в verilog можно делать используя  битовые маски, битовые операции, и сдвиги 

например в вашем случае (если я правильно понял логику)  все просто


data_o <= ({buffer[11:4],tmp[4:0]}<<1) >> shift_size;

Удачи! Rob.

 

 

 

Спасибо за ответ!

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

data <= {data[$bits(data) - 2:0],1'b0};

что думаете об этом?

Edited by Darky777

Share this post


Link to post
Share on other sites

Приветствую!

7 hours ago, Darky777 said:

...

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


data <= {data[$bits(data) - 2:0],1'b0};

что думаете об этом?

Ох, эти рассказчики -  наговорят всякого а народ верит :shok: Если не уверенны во что это синтезируется вам никто не мешает слепить тестовый модулек

Удачи! Rob.

Share this post


Link to post
Share on other sites

11 hours ago, Darky777 said:

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

Вполне справедливо, если говорить про ISE+vhdl. Вивада стала более продвинутой и посему такие приколы происходят реже.

Кстати имеется вопрос по теме. У меня конструкция типа

parameter C_S_AXI_DATA_WIDTH = 32;
parameter C_S_AXI_ADDR_WIDTH = 5;

localparam p_num = 32;
localparam p_word_bits = 32;
localparam p_bits_per = 16;

logic [2**C_S_AXI_ADDR_WIDTH - 1 : 0][C_S_AXI_DATA_WIDTH - 1 : 0] internal_reg;
logic [p_num - 1 : 0][p_bits_per - 1 : 0] r_csr;

always foreach (r_csr[i])
	r_csr[i] <= {internal_reg}[(p_word_bits + (i * p_bits_per)) +: p_bits_per];

Выдаёт ошибку:

[Synth 8-524] part-select [543:528] out of range of prefix ''Undefined''

но если сделать те же манипуляции через нэт, тогда всё отлично работает.

Хотелось узнать в чём специфика? Индексы вроде как обозначаются через простые интеджеры.

Share this post


Link to post
Share on other sites

Приветствую!

7 minutes ago, Nick_K said:

 


...
parameter C_S_AXI_ADDR_WIDTH = 5;

logic [2**C_S_AXI_ADDR_WIDTH - 1 : 0][C_S_AXI_DATA_WIDTH - 1 : 0] internal_reg;
logic [p_num - 1 : 0][p_bits_per - 1 : 0] r_csr;

always foreach (r_csr[i])
	r_csr[i] <= {internal_reg}[(p_word_bits + (i * p_bits_per)) +: p_bits_per];

Выдаёт ошибку:

[Synth 8-524] part-select [543:528] out of range of prefix ''Undefined''

но если сделать те же манипуляции через нэт, тогда всё отлично работает.

Хотелось узнать в чём специфика? Индексы вроде как обозначаются через простые интеджеры.

Странно - а в чем синтезировали?  Может при синтезе  параметр C_S_AXI_ADDR_WIDTH был равен 4 ?

Удачи! Rob.

 

Share this post


Link to post
Share on other sites

25 minutes ago, RobFPGA said:

Странно - а в чем синтезировали?  Может при синтезе  параметр C_S_AXI_ADDR_WIDTH был равен 4 ?

Стандартными средствами: Vivado 2019.1, Linux x64. Особо не разгонишься тут)

Параметр не менялся. Он идёт через порт и везде копипаст одинаковый.

Говорю же, если сделать временную переменную  wire logic [(2**C_S_AXI_ADDR_WIDTH)*C_S_AXI_DATA_WIDTH - 1 : 0] r_vector_internal = {internal_reg}; и работать с ней, тогда всё отлично синтезится. Что собственно и удивило.

Share this post


Link to post
Share on other sites

Забыл отписаться.

Еще раз благодарю за помощь!

On 7/3/2019 at 8:52 PM, RobFPGA said:

Работу с частью вектора с динамической шириной в verilog можно делать используя  битовые маски, битовые операции, и сдвиги 

Решил этот момент следующим образом.

//...
assign tmp_s = {buffer[8:4],tmp} >> (shift_size - 1);
//...
data_o <= tmp_s[5:0];
//...

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...