Darky777 0 July 3, 2019 Posted July 3, 2019 (edited) · Report post Приветствую! Многие кто пишет на 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 July 3, 2019 by Darky777 Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 10 July 3, 2019 Posted July 3, 2019 · Report post Приветствую! Работу с частью вектора с динамической шириной в verilog можно делать используя битовые маски, битовые операции, и сдвиги например в вашем случае (если я правильно понял логику) все просто data_o <= ({buffer[11:4],tmp[4:0]}<<1) >> shift_size; Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
Darky777 0 July 3, 2019 Posted July 3, 2019 (edited) · Report post 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 July 3, 2019 by Darky777 Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 10 July 3, 2019 Posted July 3, 2019 · Report post Приветствую! 7 hours ago, Darky777 said: ... Я попробую.. Мне когда-то сказали, что оператор логического сдвига не всегда корректно интерпретируется синтезатором, поэтому если необходимо польоваться сдвигом, я использую конструкцию data <= {data[$bits(data) - 2:0],1'b0}; что думаете об этом? Ох, эти рассказчики - наговорят всякого а народ верит Если не уверенны во что это синтезируется вам никто не мешает слепить тестовый модулек Удачи! Rob. Quote Share this post Link to post Share on other sites More sharing options...
Nick_K 0 July 4, 2019 Posted July 4, 2019 · Report post 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'' но если сделать те же манипуляции через нэт, тогда всё отлично работает. Хотелось узнать в чём специфика? Индексы вроде как обозначаются через простые интеджеры. Quote Share this post Link to post Share on other sites More sharing options...
RobFPGA 10 July 4, 2019 Posted July 4, 2019 · Report post Приветствую! 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. Quote Share this post Link to post Share on other sites More sharing options...
Nick_K 0 July 4, 2019 Posted July 4, 2019 · Report post 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}; и работать с ней, тогда всё отлично синтезится. Что собственно и удивило. Quote Share this post Link to post Share on other sites More sharing options...
Darky777 0 July 5, 2019 Posted July 5, 2019 · Report post Забыл отписаться. Еще раз благодарю за помощь! 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]; //... Quote Share this post Link to post Share on other sites More sharing options...