_Ivan_ 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба Добрый день. Интересует следующий вопрос. Вот есть код, сгенерируемый симулинком из модели.Это просто Cordic ядро для вычисления синуса. `timescale 1 ns / 1 ns module Sine ( clk, reset_n, enb, u, sin_2_pi_u ); input clk; input reset_n; input enb; input [15:0] u; // ufix16_En19 output signed [15:0] sin_2_pi_u; // sfix16_En14 reg [15:0] u_1; // ufix16_En19 wire [15:0] CastU16En16_out1; // ufix16_En16 wire LTEp50_relop1; wire [15:0] Amp50_out1; // ufix16_En16 wire [15:0] QuadHandle1_out1; // ufix16_En16 wire LTEp25_relop1; wire [15:0] p50mA_out1; // ufix16_En16 wire [15:0] QuadHandle2_out1; // ufix16_En16 reg signed [15:0] Look_Up_Table_out1; // sfix16_En14 wire signed [16:0] Negate_cast; // sfix17_En14 wire signed [15:0] Negate_out1; // sfix16_En14 wire signed [15:0] SignCorrected_out1; // sfix16_En14 reg signed [15:0] Sine_out1; // sfix16_En14 reg signed [15:0] Look_Up_Table_dout_low_1; // sfix16_En14 reg [5:0] Look_Up_Table_k_1; // ufix6 reg [31:0] Look_Up_Table_f_1; // ufix32_En31 reg signed [15:0] Look_Up_Table_t_0_0_1 [0:32]; // sfix16_En14 [33] reg [15:0] Look_Up_Table_div_temp_1; // ufix16 reg [46:0] Look_Up_Table_div_temp_0_1; // ufix47_En31 reg [15:0] Look_Up_Table_cast_1; // ufix16_En16 reg [31:0] Look_Up_Table_mul_temp_1; // ufix32_En32 reg [15:0] Look_Up_Table_sub_temp_1; // ufix16_En16 reg signed [48:0] Look_Up_Table_add_cast_2; // sfix49_En45 reg signed [32:0] Look_Up_Table_cast_0_1; // sfix33_En31 reg signed [15:0] Look_Up_Table_sub_temp_0_1; // sfix16_En14 reg signed [48:0] Look_Up_Table_mul_temp_0_1; // sfix49_En45 reg signed [47:0] Look_Up_Table_add_cast_0_1; // sfix48_En45 reg signed [48:0] Look_Up_Table_add_cast_1_1; // sfix49_En45 reg signed [48:0] Look_Up_Table_add_temp_1; // sfix49_En45 always @(posedge clk) begin : in_0_pipe_process if (reset_n == 1'b0) begin u_1 <= 16'b0000000000000000; end else if (enb) begin u_1 <= u; end end // <S7>/CastU16En16 assign CastU16En16_out1 = u_1[15:3]; // <S7>/LTEp50 assign LTEp50_relop1 = (CastU16En16_out1 <= 16'b1000000000000000 ? 1'b1 : 1'b0); // <S7>/Amp50 assign Amp50_out1 = CastU16En16_out1 - 32768; // <S7>/QuadHandle1 assign QuadHandle1_out1 = (LTEp50_relop1 == 1'b0 ? Amp50_out1 : CastU16En16_out1); // <S7>/LTEp25 assign LTEp25_relop1 = (QuadHandle1_out1 <= 16'b0100000000000000 ? 1'b1 : 1'b0); // <S7>/p50mA assign p50mA_out1 = 32768 - QuadHandle1_out1; // <S7>/QuadHandle2 assign QuadHandle2_out1 = (LTEp25_relop1 == 1'b0 ? p50mA_out1 : QuadHandle1_out1); // <S6>/Look-Up Table always @(QuadHandle2_out1) begin Look_Up_Table_t_0_0_1[0] = 16'sb0000000000000000; Look_Up_Table_t_0_0_1[1] = 16'sb0000001100100100; Look_Up_Table_t_0_0_1[2] = 16'sb0000011001000110; Look_Up_Table_t_0_0_1[3] = 16'sb0000100101100100; Look_Up_Table_t_0_0_1[4] = 16'sb0000110001111100; Look_Up_Table_t_0_0_1[5] = 16'sb0000111110001101; Look_Up_Table_t_0_0_1[6] = 16'sb0001001010010100; Look_Up_Table_t_0_0_1[7] = 16'sb0001010110010000; Look_Up_Table_t_0_0_1[8] = 16'sb0001100001111110; Look_Up_Table_t_0_0_1[9] = 16'sb0001101101011101; Look_Up_Table_t_0_0_1[10] = 16'sb0001111000101011; Look_Up_Table_t_0_0_1[11] = 16'sb0010000011100111; Look_Up_Table_t_0_0_1[12] = 16'sb0010001110001110; Look_Up_Table_t_0_0_1[13] = 16'sb0010011000100000; Look_Up_Table_t_0_0_1[14] = 16'sb0010100010011010; Look_Up_Table_t_0_0_1[15] = 16'sb0010101011111011; Look_Up_Table_t_0_0_1[16] = 16'sb0010110101000001; Look_Up_Table_t_0_0_1[17] = 16'sb0010111101101100; Look_Up_Table_t_0_0_1[18] = 16'sb0011000101111001; Look_Up_Table_t_0_0_1[19] = 16'sb0011001101101000; Look_Up_Table_t_0_0_1[20] = 16'sb0011010100110111; Look_Up_Table_t_0_0_1[21] = 16'sb0011011011100101; Look_Up_Table_t_0_0_1[22] = 16'sb0011100001110001; Look_Up_Table_t_0_0_1[23] = 16'sb0011100111011011; Look_Up_Table_t_0_0_1[24] = 16'sb0011101100100001; Look_Up_Table_t_0_0_1[25] = 16'sb0011110001000010; Look_Up_Table_t_0_0_1[26] = 16'sb0011110100111111; Look_Up_Table_t_0_0_1[27] = 16'sb0011111000010101; Look_Up_Table_t_0_0_1[28] = 16'sb0011111011000101; Look_Up_Table_t_0_0_1[29] = 16'sb0011111101001111; Look_Up_Table_t_0_0_1[30] = 16'sb0011111110110001; Look_Up_Table_t_0_0_1[31] = 16'sb0011111111101100; Look_Up_Table_t_0_0_1[32] = 16'sb0100000000000000; if (QuadHandle2_out1 <= 16'b0000000000000000) begin Look_Up_Table_k_1 = 6'b000000; end else if (QuadHandle2_out1 >= 16'b0100000000000000) begin Look_Up_Table_k_1 = 6'b100000; end else begin Look_Up_Table_div_temp_1 = QuadHandle2_out1 / 512; Look_Up_Table_k_1 = Look_Up_Table_div_temp_1[5:0]; end if ((QuadHandle2_out1 <= 16'b0000000000000000) || (QuadHandle2_out1 >= 16'b0100000000000000)) begin Look_Up_Table_f_1 = 32'b00000000000000000000000000000000; end else begin Look_Up_Table_cast_1 = 16'b0000000000000000; // CSD Encoding (512) : 1000000000; Cost (Adders) = 0 Look_Up_Table_mul_temp_1 = {Look_Up_Table_cast_1, 9'b000000000}; Look_Up_Table_sub_temp_1 = QuadHandle2_out1 - Look_Up_Table_mul_temp_1[31:16]; Look_Up_Table_div_temp_0_1 = ({Look_Up_Table_sub_temp_1, 31'b0000000000000000000000000000000}) / 512; Look_Up_Table_f_1 = Look_Up_Table_div_temp_0_1[31:0]; end Look_Up_Table_dout_low_1 = Look_Up_Table_t_0_0_1[Look_Up_Table_k_1]; if (Look_Up_Table_k_1 == 6'b100000) begin end else begin Look_Up_Table_k_1 = Look_Up_Table_k_1 + 1; end Look_Up_Table_add_cast_2 = {{2{Look_Up_Table_dout_low_1[15]}}, {Look_Up_Table_dout_low_1, 31'b0000000000000000000000000000000}}; Look_Up_Table_cast_0_1 = Look_Up_Table_f_1; Look_Up_Table_sub_temp_0_1 = Look_Up_Table_t_0_0_1[Look_Up_Table_k_1] - Look_Up_Table_dout_low_1; Look_Up_Table_mul_temp_0_1 = Look_Up_Table_cast_0_1 * Look_Up_Table_sub_temp_0_1; Look_Up_Table_add_cast_0_1 = Look_Up_Table_mul_temp_0_1[47:0]; Look_Up_Table_add_cast_1_1 = {Look_Up_Table_add_cast_0_1[47], Look_Up_Table_add_cast_0_1}; Look_Up_Table_add_temp_1 = Look_Up_Table_add_cast_2 + Look_Up_Table_add_cast_1_1; Look_Up_Table_out1 = Look_Up_Table_add_temp_1[46:31]; end // <S7>/Negate assign Negate_cast = - ({Look_Up_Table_out1[15], Look_Up_Table_out1}); assign Negate_out1 = Negate_cast[15:0]; // <S7>/SignCorrected assign SignCorrected_out1 = (LTEp50_relop1 == 1'b0 ? Negate_out1 : Look_Up_Table_out1); always @(posedge clk) begin : out_0_pipe_process if (reset_n == 1'b0) begin Sine_out1 <= 16'sb0000000000000000; end else if (enb) begin Sine_out1 <= SignCorrected_out1; end end assign sin_2_pi_u = Sine_out1; endmodule // Sine Я тут вижу 2 регистра, входной - по которому защелкиваются данные и выходной, по которому посчитанные данные защелкиваются. Между ними идет какая-то асинхронщина. Меня смущает вот эта строчка always @(QuadHandle2_out1) . Причем там есть еще счетчик - т.е. по идее это должен быть регистр-защелка для счетчика. Причем синтезатор показывает, что код может работать на частоте в почти 84 МГц. И защелок в проекте нет вообще. Хотя все-таки остается ощущение, что если будут всякие температурные скачки, то возможно появление метастабильного состояния выходного регистра. Можно ли использовать данный код в проекте? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба Где счетчик? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Ivan_ 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба if (Look_Up_Table_k_1 == 6'b100000) begin end else begin Look_Up_Table_k_1 = Look_Up_Table_k_1 + 1; end Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
masics 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба if (Look_Up_Table_k_1 == 6'b100000) begin end else begin Look_Up_Table_k_1 = Look_Up_Table_k_1 + 1; end Это не счетчик, а временная переменная. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба Приветствую! Ну как же - вот же он! always @(posedge clk) begin : in_0_pipe_process if (reset_n == 1'b0) begin u_1 <= 16'b0000000000000000; end else if (enb) begin u_1 <= u; end end из него выгрызают кусок assign CastU16En16_out1 = u_1[15:3]; а затем легким движением рук assign LTEp50_relop1 = (CastU16En16_out1 <= 16'b1000000000000000 ? 1'b1 :1'b0); и бедер assign assign assign Amp50_out1 = CastU16En16_out1 - 32768; assign QuadHandle1_out1 = (LTEp50_relop1 == 1'b0 ? Amp50_out1 :CastU16En16_out1); шорты превращаются в элегантный счетчик :cranky: :) Работать будет - но я бы за такой код убил бы. Увы - это проблема всех кодогенераторов - формальная конверсия логики высокоуровневых языков в железо. Успехов! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Ivan_ 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба ого, даже так! а где почитать про временные переменные? что-то я с таким сталкиваюсь впервые вообщем получается что код работать будет, но нестабильно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба Приветствую! Ну почему же нестабильно - если задать правильные constrain для PR то все будет нормально. Но вот максимальная рабочая частота устройства с таким кодом будет очень далека от возможной. Успехов! Rob. P.S. Жуя обеденный бутерброд и искоса посматривая на это чудо код понял что это не Cordic а похоже вычислительный блок - генерирующий sin от входного аргумента при помощи какойто мате... апроксимации. Так что тут счетчика и не должно было быть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Ivan_ 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба огромное спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 15 сентября, 2014 Опубликовано 15 сентября, 2014 · Жалоба что-то я не понял как тут счетчик образовался... вернее как движения рук и бедер перевели входной регистр защелки в счетчик. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться