Andy111 0 3 марта, 2015 Опубликовано 3 марта, 2015 · Жалоба Здравствуйте. В общем стоит задача написать модуль на Verilog, который бы рассчитывал arctg(y/x) с помощью CORDIC алгоритма. Я в veriloge не очень силен, поэтому покопался в интернете и нашел вот такую реализацию: `define activehigh 1 `define procline posedge clk `define proclineg posedge clk `define proclineSlow posedge clkSlow `define proclineFast posedge clkFast module CordicRotator (clk, rst, en, xi, yi, zi, xo, yo, zo); // { parameter smi = 1; parameter bitWidth = 16; parameter angBitWidth = 16; parameter angFracWidth = 16; parameter rotMode = 1; input clk; input rst; input en; input signed [bitWidth-1:0] xi; input signed [bitWidth-1:0] yi; input signed [angBitWidth-1:0] zi; output reg signed [bitWidth-1:0] xo; output reg signed [bitWidth-1:0] yo; output reg signed [angBitWidth-1:0] zo; function signed [angFracWidth-1:0] appr; input signed [53:0] atf; begin if (angFracWidth>54) begin appr = 0; appr[angFracWidth-1:angFracWidth-54] = atf; end else appr = atf[53:54-angFracWidth]; end endfunction // appr wire signed [bitWidth-1:0] sx,sy; assign sx = xi >>> smi; assign sy = yi >>> smi; reg signed [53:0] atf; reg signed [angFracWidth-1:0] at; always @(`procline) begin if (rst==`activehigh) begin xo <= 0; yo <= 0; zo <= 0; end else if (en) begin case (smi) 0: atf = 54'b010000000000000000000000000000000000000000000000000000; //0.25 1: atf = 54'b001001011100100000001010001110110011101111100110000100; 2: atf = 54'b000100111111011001110000101101101011110111000111001111; 3: atf = 54'b000010100010001000100011101010000011101110111011001101; 4: atf = 54'b000001010001011000011010100001100001110010110001001101; 5: atf = 54'b000000101000101110101111110000101011001000001000110001; 6: atf = 54'b000000010100010111101100001111001011100001010000010011; 7: atf = 54'b000000001010001011111000101010100010001110101000100001; 8: atf = 54'b000000000101000101111100101001101000110110100001100001; 9: atf = 54'b000000000010100010111110010111010111011001100001010101; 10: atf = 54'b000000000001010001011111001100000000000100100011011101; 11: atf = 54'b000000000000101000101111100110000010100101010000000110; 12: atf = 54'b000000000000010100010111110011000001100110111111110110; 13: atf = 54'b000000000000001010001011111001100000110110000010111001; 14: atf = 54'b000000000000000101000101111100110000011011010101110100; 15: atf = 54'b000000000000000010100010111110011000001101101101011101; 16: atf = 54'b000000000000000001010001011111001100000110110111000010; 17: atf = 54'b000000000000000000101000101111100110000011011011100100; 18: atf = 54'b000000000000000000010100010111110011000001101101110010; 19: atf = 54'b000000000000000000001010001011111001100000110110111001; 20: atf = 54'b000000000000000000000101000101111100110000011011011100; 21: atf = 54'b000000000000000000000010100010111110011000001101101110; 22: atf = 54'b000000000000000000000001010001011111001100000110110111; 23: atf = 54'b000000000000000000000000101000101111100110000011011011; 24: atf = 54'b000000000000000000000000010100010111110011000001101101; 25: atf = 54'b000000000000000000000000001010001011111001100000110110; 26: atf = 54'b000000000000000000000000000101000101111100110000011011; 27: atf = 54'b000000000000000000000000000010100010111110011000001101; 28: atf = 54'b000000000000000000000000000001010001011111001100000110; 29: atf = 54'b000000000000000000000000000000101000101111100110000011; 30: atf = 54'b000000000000000000000000000000010100010111110011000001; 31: atf = 54'b000000000000000000000000000000001010001011111001100000; 32: atf = 54'b000000000000000000000000000000000101000101111100110000; 33: atf = 54'b000000000000000000000000000000000010100010111110011000; 34: atf = 54'b000000000000000000000000000000000001010001011111001100; 35: atf = 54'b000000000000000000000000000000000000101000101111100110; 36: atf = 54'b000000000000000000000000000000000000010100010111110011; 37: atf = 54'b000000000000000000000000000000000000001010001011111001; 38: atf = 54'b000000000000000000000000000000000000000101000101111100; 39: atf = 54'b000000000000000000000000000000000000000010100010111110; 40: atf = 54'b000000000000000000000000000000000000000001010001011111; 41: atf = 54'b000000000000000000000000000000000000000000101000101111; 42: atf = 54'b000000000000000000000000000000000000000000010100010111; 43: atf = 54'b000000000000000000000000000000000000000000001010001011; 44: atf = 54'b000000000000000000000000000000000000000000000101000101; 45: atf = 54'b000000000000000000000000000000000000000000000010100010; 46: atf = 54'b000000000000000000000000000000000000000000000001010001; 47: atf = 54'b000000000000000000000000000000000000000000000000101000; 48: atf = 54'b000000000000000000000000000000000000000000000000010100; 49: atf = 54'b000000000000000000000000000000000000000000000000001010; 50: atf = 54'b000000000000000000000000000000000000000000000000000101; 51: atf = 54'b000000000000000000000000000000000000000000000000000010; 52: atf = 54'b000000000000000000000000000000000000000000000000000001; default: atf = 0; endcase at = appr(atf); if (rotMode==1) if (zi >= 0) begin xo <= xi - sy; yo <= yi + sx; zo <= zi - at; end else begin xo <= xi + sy; yo <= yi - sx; zo <= zi + at; end // if (zi... else if (yi >=0) begin xo <= xi + sy; yo <= yi - sx; zo <= zi + at; end else begin xo <= xi - sy; yo <= yi + sx; zo <= zi - at; end // if(yi... end // if(en) end // always endmodule // CordicRotator } ///////////////////////////////////////////////////////////////////// module CordicSeq (clk, rst, en, xi, yi, zi, xo, yo, zo); // { parameter depth = 15; parameter bitWidth = 16; parameter angBitWidth = 16; parameter angFracWidth = 16; parameter rotMode = 1; input clk, rst, en; input signed [bitWidth-1:0] xi, yi; input signed [angBitWidth-1:0] zi; output signed [bitWidth-1:0] xo, yo; output signed [angBitWidth-1:0] zo; wire signed [bitWidth-1:0] x [0:depth]; wire signed [bitWidth-1:0] y [0:depth]; wire signed [angBitWidth-1:0] z [0:depth]; assign x[0] = xi; assign y[0] = yi; assign z[0] = zi; generate genvar i; for (i = 0; i < depth; i=i+1) begin : gen_seq CordicRotator #( .smi(i), .bitWidth(bitWidth), .angBitWidth(angBitWidth), .angFracWidth(angFracWidth), .rotMode(rotMode)) cr (clk, rst, en, x[i], y[i], z[i], x[i+1], y[i+1], z[i+1]); end endgenerate //gen_seq assign xo = x[depth]; assign yo = y[depth]; assign zo = z[depth]; endmodule // CordicSeq } module synCordicAtan (clk, rst, en, x, y, atanOut); // { parameter depth=15; parameter bitWidth=16; parameter angBitWidth=16; input clk, rst, en; input [bitWidth-1:0] x, y; output reg [angBitWidth-1:0] atanOut; reg [1:0] quadrant [0:depth-1]; reg signed [bitWidth+1:0] xi=0, yi=0; wire signed [bitWidth-1:0] tmpx, tmpy; reg signed [angBitWidth-1:0] zi=0; wire signed [bitWidth+1:0] xo, yo; wire signed [angBitWidth-1:0] zo; wire signed [angBitWidth-1:0] negzo; wire [angBitWidth-2:0] tmpzero = 0; reg [5:0] rcnt; integer i; assign negzo = -zo; assign tmpx = -x; assign tmpy = -y; CordicSeq #( .depth(depth-1), .bitWidth(bitWidth+2), .angBitWidth(angBitWidth), .angFracWidth(angBitWidth-1), .rotMode(0)) cs (clk, rst, en, xi, yi, zi, xo, yo, zo); always @(`procline) begin if (rst==`activehigh) begin rcnt <= 0; xi <= 0; yi <= 0; atanOut <= 0; for (i=0;i<depth;i=i+1) quadrant[i] <= 2'b00; end else if (en) begin if(rcnt!=depth) rcnt <= rcnt+1; if (x[bitWidth-1] == 0) xi <= {x[bitWidth-1],x[bitWidth-1],x}; else xi <= {tmpx[bitWidth-1],tmpx[bitWidth-1],tmpx}; if (y[bitWidth-1] == 0) yi <= {y[bitWidth-1],y[bitWidth-1],y}; else yi <= {tmpy[bitWidth-1],tmpy[bitWidth-1],tmpy}; quadrant[0][0] <= x[bitWidth-1]; quadrant[0][1] <= y[bitWidth-1]; for (i=0;i<depth-1;i=i+1) quadrant[i+1] <= quadrant[i]; if(rcnt==depth) case (quadrant[depth-1]) 2'b00 : atanOut <= zo; 2'b01 : atanOut <= {1'b1, tmpzero} - $unsigned(zo); 2'b10 : atanOut <= negzo; // use intermediate to force sizing default : atanOut <= {1'b1, tmpzero} + $unsigned(zo); endcase end // if end // always endmodule // } Промоделировал в Quartus. Вроде работает (через 15 тактов выдает результат). Но не могу разобраться в каком формате задавать входные данные x и y (с фиксированной точкой или целое, знаковое или беззнаковое и т. п.). И как интерпретировать результат (т. е. в каком формате выдается результат, в градусах или радианах, сколько разрядов на дробную часть, сколько на целую и т. д.). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ElrondTelvanni 0 3 марта, 2015 Опубликовано 3 марта, 2015 · Жалоба Я тоже где-то с полгода назад разбирался в кордике, в итоге всё написал сам, и разобрался, как оно работает. Если интересно, могу выложить код. Тут реализация похожа на мою, но стиль написания довольно корявый. К тому же, это только ядро CORDIC, а для того чтобы вычислять арктангенс, нужны ещё препроцессор и постпроцессор. На вход должны идти значения синуса и косинуса в формате (s16,15), а на выходе - зависит от реализации постпроцессора. Я сделал выходы в формате u16,16 и для угла, и для фазы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Andy111 0 3 марта, 2015 Опубликовано 3 марта, 2015 · Жалоба Я тоже где-то с полгода назад разбирался в кордике, в итоге всё написал сам, и разобрался, как оно работает. Если интересно, могу выложить код. Тут реализация похожа на мою, но стиль написания довольно корявый. К тому же, это только ядро CORDIC, а для того чтобы вычислять арктангенс, нужны ещё препроцессор и постпроцессор. На вход должны идти значения синуса и косинуса в формате (s16,15), а на выходе - зависит от реализации постпроцессора. Я сделал выходы в формате u16,16 и для угла, и для фазы. Буду премного благодарен если скинете свою версию:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ElrondTelvanni 0 3 марта, 2015 Опубликовано 3 марта, 2015 (изменено) · Жалоба Ядро CORDIC // ================================================================================ ========================== // Project : FPGA DSP Library // File : cordic_core.sv // Title : CORDIC core module // Dependencies : - // // Description : This module implements iterative CORDIC algorhytm with parameterized precision. // Calculation started when request detected. 'rdy' flag asserted when result is ready. // Output data remain valid until the next request. // ================================================================================ ========================== // REVISION HISTORY // Version Date Author Change Description // 1.0 24.11.14 Noskov A.M. Initial creation; // ================================================================================ ========================== module cordic_core #( parameter SIG_W = 18, parameter ACC_W = 20 )( input logic rst_n, input logic clk, input logic req, input logic ccwr, input logic signed [sIG_W:0] x_i, input logic signed [sIG_W:0] y_i, input logic signed [ACC_W+1:0] a_i, output logic rdy, output logic busy, output logic signed [sIG_W:0] x_o, output logic signed [sIG_W:0] y_o, output logic signed [ACC_W+1:0] a_o ); `define ANG_SCALE(s) (ACC_W < 32) ? \ (ACC_W+2)'(unsigned'(``s`` >>> (32-ACC_W)) + unsigned'(1'(``s`` >> (32-ACC_W-1)))) : \ (ACC_W+2)'(``s``) localparam logic signed [ACC_W+1:0] ANG_TABLE[31] = '{ `ANG_SCALE(32'sd536870912), `ANG_SCALE(32'sd316933406), `ANG_SCALE(32'sd167458907), `ANG_SCALE(32'sd85004756), `ANG_SCALE(32'sd42667331), `ANG_SCALE(32'sd21354465), `ANG_SCALE(32'sd10679838), `ANG_SCALE(32'sd5340245), `ANG_SCALE(32'sd2670163), `ANG_SCALE(32'sd1335087), `ANG_SCALE(32'sd667544), `ANG_SCALE(32'sd333772), `ANG_SCALE(32'sd166886), `ANG_SCALE(32'sd83443), `ANG_SCALE(32'sd41722), `ANG_SCALE(32'sd20861), `ANG_SCALE(32'sd10430), `ANG_SCALE(32'sd5215), `ANG_SCALE(32'sd2608), `ANG_SCALE(32'sd1304), `ANG_SCALE(32'sd652), `ANG_SCALE(32'sd326), `ANG_SCALE(32'sd163), `ANG_SCALE(32'sd81), `ANG_SCALE(32'sd41), `ANG_SCALE(32'sd20), `ANG_SCALE(32'sd10), `ANG_SCALE(32'sd5), `ANG_SCALE(32'sd3), `ANG_SCALE(32'sd1), `ANG_SCALE(32'sd1) }; `undef ANG_SCALE localparam CNT_W = $clog2(ACC_W+1); localparam [CNT_W-1:0] LAST_CNT = (CNT_W)'(ACC_W) - 1'b1; logic busy_t1; logic [CNT_W-1:0] i; logic signed [sIG_W:0] x_s, y_s; assign x_s = signed'(x_o >>> i); assign y_s = signed'(y_o >>> i); assign busy = (i < LAST_CNT); assign rdy = (~busy & busy_t1); always_ff @(posedge clk or negedge rst_n) begin if(!rst_n) begin i <= '1; x_o <= 0; y_o <= 0; a_o <= 0; busy_t1 <= 0; end else begin busy_t1 <= busy; if(req & ~busy) begin i <= 0; x_o <= x_i; y_o <= y_i; a_o <= a_i; end if(busy) begin i <= i + 1'b1; x_o <= (ccwr) ? (x_o - y_s) : (x_o + y_s); y_o <= (ccwr) ? (y_o + x_s) : (y_o - x_s); a_o <= (ccwr) ? (a_o + ANG_TABLE[i]) : (a_o - ANG_TABLE[i]); end end end endmodule Пре/пост-процессор для арктангенса // ================================================================================ ========================== // Project : FPGA DSP Library // File : cart2pol.sv // Title : Cartesian-to-Polar Vector Transform // Dependencies : cordic_core.sv // // Description : This module performs transformation of vector from Cartesian to Polar coordinate system. // Transformation is based on the iterative implementation of the CORDIC algorhytm. // Vector precision parameterized for both coordinate systems separately; // Calculation started when request detected. 'rdy' flag asserted when result is ready. // Output data remain valid until the next request. // ================================================================================ ========================== // REVISION HISTORY // Version Date Author Change Description // 1.0 25.11.14 Noskov A.M. Initial creation; // ================================================================================ ========================== module cart2pol #( parameter SIG_W = 16, parameter ACC_W = 16 )( input logic rst_n, input logic clk, input logic req, input logic signed [sIG_W-1:0] cos, input logic signed [sIG_W-1:0] sin, output logic rdy, output logic busy, output logic [ACC_W-1:0] ang, output logic [sIG_W-1:0] hyp ); localparam [sIG_W-1:0] X_SCALE = (2**SIG_W-1) * 0.60723; logic ccwr; logic signed [sIG_W:0] x_i, y_i; logic signed [sIG_W:0] x_o, y_o; logic signed [ACC_W+1:0] a_o, a_i; cordic_core #( .SIG_W (SIG_W), .ACC_W (ACC_W)) dds_core ( .rst_n, .clk, .req, .ccwr, .x_i, .y_i, .a_i, .rdy, .busy, .x_o, .y_o, .a_o ); // Clockwise / Counter-clockwise rotate assign ccwr = y_o[sIG_W]; // Quadrant selector always_comb begin : quadrant_sel x_i = cos; y_i = -sin; a_i = '0; if(cos[sIG_W-1]) begin // X < 0 a_i[ACC_W-:2] = 2'b01; // + 180 deg. x_i = -cos; y_i = sin; end else if(sin[sIG_W-1]) // Y < 0 a_i[ACC_W-:2] = 2'b10; // + 360 deg. end : quadrant_sel function logic [sIG_W-1:0] calc_hyp(logic signed [sIG_W:0] i_x); logic [sIG_W*2+1:0] mult; mult = unsigned'(i_x) * X_SCALE; calc_hyp = mult[sIG_W*2-1:SIG_W]; endfunction // Output assignments assign ang = a_o[ACC_W-1:0]; assign hyp = calc_hyp(x_o); endmodule Изменено 3 марта, 2015 пользователем ~Elrond~ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
serjj1333 0 4 марта, 2015 Опубликовано 4 марта, 2015 · Жалоба Могу свою реализацию подкинуть (под cyclone), может кому пригодится. Способ применения понятен из тестбенча. Перед сборкой нужно поставить флажок __SYNTHESIS__. cordic_light.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Krys 2 5 марта, 2015 Опубликовано 5 марта, 2015 · Жалоба Выложите ещё пожалуйста те доки (или ссылки) по которым удалось разобраться, как это работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
serjj1333 0 5 марта, 2015 Опубликовано 5 марта, 2015 · Жалоба Тысячи их, вот например: cordic____.pdf Matlab1 Matlab2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lerk 0 5 марта, 2015 Опубликовано 5 марта, 2015 (изменено) · Жалоба Выложите ещё пожалуйста те доки (или ссылки) по которым удалось разобраться, как это работает. Если дружить с математикой нет желания, то просто и доступно есть вот такой гайд: CORDIC for dummies Изменено 5 марта, 2015 пользователем Lerk Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ElrondTelvanni 0 5 марта, 2015 Опубликовано 5 марта, 2015 · Жалоба Krys Я разбирался и писал свою версию исключительно по CORDIC for dummies. Крайне полезный и доступный для понимания материал, есть исходники. Оставалось только перевести в HDL и параметризовать. В аттаче моя версия вместе с тестбенчем. atan2.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Krys 2 10 марта, 2015 Опубликовано 10 марта, 2015 · Жалоба Большое спасибо всем отозвавшимся! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abo 0 25 ноября, 2017 Опубликовано 25 ноября, 2017 · Жалоба Krys Я разбирался и писал свою версию исключительно по CORDIC for dummies. Крайне полезный и доступный для понимания материал, есть исходники. Оставалось только перевести в HDL и параметризовать. В аттаче моя версия вместе с тестбенчем. Мне тоже потребовалось сделать кордик для расчета арктангенса. Воспользовался этим кодом. Благодарю автора. Со своей стороны прикладываю немного ускоренный вариант с хранением сдвинутого предыдущего значения в отдельном регистре. До изменения на 10M50 максимальная тактовая была не более 119МГц, после выросла до 137МГц. Мне нужно было чтобы при 120МГц работало. module cordic_core #( parameter SIG_W = 18, parameter ACC_W = 20 )( input rst, input clk, input req, input ccwr, input signed [SIG_W:0] x_i, input signed [SIG_W:0] y_i, input signed [ACC_W+1:0] a_i, output rdy, output busy, output reg signed [SIG_W:0] x_o, output reg signed [SIG_W:0] y_o, output reg signed [ACC_W+1:0] a_o ); `define ANG_SCALE(s) (ACC_W < 32) ? \ (ACC_W+2)'(unsigned'(``s`` >>> (32-ACC_W)) + unsigned'(1'(``s`` >> (32-ACC_W-1)))) : \ (ACC_W+2)'(``s``) localparam logic signed [ACC_W+1:0] ANG_TABLE[31] = '{ `ANG_SCALE(32'sd536870912), `ANG_SCALE(32'sd316933406), `ANG_SCALE(32'sd167458907), `ANG_SCALE(32'sd85004756), `ANG_SCALE(32'sd42667331), `ANG_SCALE(32'sd21354465), `ANG_SCALE(32'sd10679838), `ANG_SCALE(32'sd5340245), `ANG_SCALE(32'sd2670163), `ANG_SCALE(32'sd1335087), `ANG_SCALE(32'sd667544), `ANG_SCALE(32'sd333772), `ANG_SCALE(32'sd166886), `ANG_SCALE(32'sd83443), `ANG_SCALE(32'sd41722), `ANG_SCALE(32'sd20861), `ANG_SCALE(32'sd10430), `ANG_SCALE(32'sd5215), `ANG_SCALE(32'sd2608), `ANG_SCALE(32'sd1304), `ANG_SCALE(32'sd652), `ANG_SCALE(32'sd326), `ANG_SCALE(32'sd163), `ANG_SCALE(32'sd81), `ANG_SCALE(32'sd41), `ANG_SCALE(32'sd20), `ANG_SCALE(32'sd10), `ANG_SCALE(32'sd5), `ANG_SCALE(32'sd3), `ANG_SCALE(32'sd1), `ANG_SCALE(32'sd1) }; `undef ANG_SCALE localparam CNT_W = $clog2(ACC_W+1); localparam [CNT_W-1:0] LAST_CNT = (CNT_W)'(ACC_W) - 1'b1; logic busy_t1; logic [4:0] i; // Изначально разрядность была настраиваемой [CNT_W-1:0], изменил чтобы квартус не предупреждал. logic signed [SIG_W:0] x_s, y_s; assign busy = (i < LAST_CNT); assign rdy = (~busy & busy_t1); wire signed [SIG_W:0] next_x_o = (ccwr) ? (x_o - y_s) : (x_o + y_s); wire signed [SIG_W:0] next_y_o = (ccwr) ? (y_o + x_s) : (y_o - x_s); wire signed [SIG_W:0] next_x_s = signed'(next_x_o >>> (i+1'b1)); wire signed [SIG_W:0] next_y_s = signed'(next_y_o >>> (i+1'b1)); always_ff @(posedge clk, posedge rst) begin if(rst) begin busy_t1 <= 0; i <= '1; x_o <= 0; y_o <= 0; x_s <= 0; y_s <= 0; a_o <= 0; end else begin busy_t1 <= busy; if(req | busy) if(req) begin i <= 0; x_o <= x_i; y_o <= y_i; x_s <= x_i; y_s <= y_i; a_o <= a_i; end else begin i <= i + 1'b1; x_o <= next_x_o; //(ccwr) ? (x_o - y_s) : (x_o + y_s); y_o <= next_y_o; //(ccwr) ? (y_o + x_s) : (y_o - x_s); x_s <= next_x_s; y_s <= next_y_s; a_o <= a_o + (ccwr ? ANG_TABLE[i] : -ANG_TABLE[i]); //(ccwr) ? (a_o + ANG_TABLE[i]) : (a_o - ANG_TABLE[i]); end end end endmodule Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться