Перейти к содержанию
    

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

 

Изменено пользователем Darky777

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Удачи! Rob.

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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};

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

Изменено пользователем Darky777

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

7 hours ago, Darky777 said:

...

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


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

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

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

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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''

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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}; и работать с ней, тогда всё отлично синтезится. Что собственно и удивило.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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];
//...

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...