Division en virgule flottante complexe de noyau Vivado IP Virgule flottante
Table des matières
1. Exemple de division complexe en virgule flottante
2. Étapes de configuration du noyau IP à virgule flottante
avant-propos
Avec le développement continu du processus de fabrication, le réseau de portes logiques programmables sur le terrain (FPGA) devient de plus en plus intégré et son application devient de plus en plus étendue.Parmi eux, certains IP de traitement mathématique doivent être utilisés lors du traitement des signaux numériques. nucléaire. Récemment, j'étudie l'implémentation matérielle FPGA de la recherche sur la technologie anti-brouillage adaptative de l'espace aérien, qui utilise inévitablement certains cœurs IP.Aujourd'hui, je vais vous présenter comment utiliser le cœur IP à virgule flottante dans vivado pour réaliser une division complexe en virgule flottante.à certains mesure utile.
Astuce : Ce qui suit est le texte de cet article, qui sont tous originaux par l'auteur lui-même. Il n'est pas facile d'écrire un article. J'espère que vous joindrez un lien vers cet article lors de la publication.
1. Exemple de division complexe en virgule flottante
Afin de faciliter l'analyse des résultats dans la simulation suivante, nous énumérons ici l'exemple de division de nombres à virgule flottante complexe. Pendant la simulation, utilisez directement l'exemple suivant pour la simulation afin de vérifier si le résultat de la simulation est correct.
exemple : Soit le nombre flottant a=32'h4057AE14+j32'h400F5C29, soit a=3.37+j2.24, le nombre flottant b=32'h3FE51EB8+j32'hC039999A, soit b=1.79-j2 .9, puis a/b= 32'hBD236E2F+32'h3F97E5C9, soit a/b=-0.0399+j1.1867, notez que le résultat ne conserve que quatre décimales.
2. Étapes de configuration du noyau IP à virgule flottante
Comment configurer l'addition, la soustraction, la multiplication et la division du noyau IP à virgule flottante a été expliqué dans l'article précédent. Les étudiants qui ne le savent pas peuvent lire mon article précédent, donc je ne le répéterai pas ici.
3. Réflexion globale
Selon la formule , nous utilisons d'abord six multiplicateurs parallèles pour calculer les résultats de ac, bd, ad, bc, cc, dd, puis utilisons un soustracteur et deux additionneurs pour calculer bc-ad et ac+bd, cc+dd dans parallèle , et enfin utiliser deux diviseurs pour calculer la somme en parallèle . Dans ma configuration de cœur IP, le retard du cœur IP multiplicateur est de 8 horloges, le retard du cœur IP additionneur et soustracteur est de 11 horloges et le retard du cœur IP diviseur est de 28 horloges.Dans le code, un ou deux de plus des horloges sont données au signal de données valides Valid. Dans l'ensemble du code de niveau supérieur, le comptage de cnt est particulièrement important, et les changements de nombreuses variables intermédiaires dépendent de la valeur de cnt. J'ai aussi beaucoup commenté dans le code, et l'idée de conception cette fois n'est pas difficile, je pense que tout le monde peut la comprendre.
4. Simuler
1. Code de niveau supérieur
Créez un module de niveau supérieur nommé float_complex_div .
code afficher comme ci-dessous:
`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/07/26 12:30:21
// Design Name:
// Module Name: float_complex_div
// Project Name:
// Target Devices:
// Tool Versions: 2017.4
// Description:
// Dependencies:
// Revision:1.0
// Revision 0.01 - File Created
// Additional Comments:
//
//计算公式: (a+bi)/(c+di)=( ac+bd+(bc-ad)i )/(c^2+b^2)
module float_complex_div(
input clk, // 输入时钟信号
input rst_n, //输入复位信号
input start, //输入开始信号
input [31:0] re_a, //输入被除数a的实部
input [31:0] im_a, //输入被除数a的虚部
input [31:0] re_b, //输入除数b的实部
input [31:0] im_b, //输入除数b的虚部
output reg over, //输出计算完成信号
output reg [31:0] re_res, //输出计算结果的实部
output reg [31:0] im_res //输出计算结果的虚部
);
//reg define
reg [5:0] cnt; //过程计数标志
reg valid1; //乘有效信号
reg valid2; //加减有效信号
reg valid3; //除有效信号
//wire define
wire [31:0] result1; //结果1
wire [31:0] result2; //结果2
wire [31:0] result3; //结果3
wire [31:0] result4; //结果4
wire [31:0] result5; //结果5
wire [31:0] result6; //结果6
wire [31:0] result7; //结果7
wire [31:0] result8; //结果8
wire [31:0] result9; //结果9
wire [31:0] result10; //结果10
wire [31:0] result11; //结果11
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=0;
else if(start==1)
begin
if(cnt<6'd56)
cnt<=cnt+1;
else
cnt<=0;
end
else if(start==0)
cnt<=0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
valid1<=0;
else if(6'd0<cnt<=6'd9)
valid1<=1;
else
valid1<=0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
valid2<=0;
else if(6'd12<cnt<=6'd24)
valid2<=1;
else
valid2<=0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
valid3<=0;
else if(6'd24<cnt<=6'd53)
valid3<=1;
else
valid3<=0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin over<=0;re_res<=0;im_res<=0; end
else if(cnt==6'd55)
begin over<=1;re_res<=result10;im_res<=result11; end
else
begin over<=0;re_res<=0;im_res<=0; end
float_mul_ip u1_float_mul_ip( //乘法器1 计算ac
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(re_a),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(re_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result1)
);
float_mul_ip u2_float_mul_ip( //乘法器2 计算bd
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(im_a),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(im_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result2)
);
float_mul_ip u3_float_mul_ip( //乘法器3 计算ad
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(re_a),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(im_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result3)
);
float_mul_ip u4_float_mul_ip( //乘法器4 计算bc
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(im_a),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(re_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result4)
);
float_mul_ip u5_float_mul_ip( //乘法器5 计算c*c
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(re_b),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(re_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result5)
);
float_mul_ip u6_float_mul_ip( //乘法器6 计算d*d
.aclk(clk),
.s_axis_a_tvalid(valid1),
.s_axis_a_tdata(im_b),
.s_axis_b_tvalid(valid1),
.s_axis_b_tdata(im_b),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result6)
);
float_sub_ip u1_float_sub_ip( //减法器 计算bc-ad
.aclk(clk),
.s_axis_a_tvalid(valid2),
.s_axis_a_tdata(result4),
.s_axis_b_tvalid(valid2),
.s_axis_b_tdata(result3),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result7)
);
float_add_ip u1_float_add_ip( //加法器1 计算ac+bd
.aclk(clk),
.s_axis_a_tvalid(valid2),
.s_axis_a_tdata(result1),
.s_axis_b_tvalid(valid2),
.s_axis_b_tdata(result2),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result8)
);
float_add_ip u2_float_add_ip( //加法器2 计算cc+dd
.aclk(clk),
.s_axis_a_tvalid(valid2),
.s_axis_a_tdata(result5),
.s_axis_b_tvalid(valid2),
.s_axis_b_tdata(result6),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result9)
);
float_div_ip u1_float_div_ip( //除法器1 计算(ac+bd)/(cc+dd)
.aclk(clk),
.s_axis_a_tvalid(valid3),
.s_axis_a_tdata(result8),
.s_axis_b_tvalid(valid3),
.s_axis_b_tdata(result9),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result10)
);
float_div_ip u2_float_div_ip( //除法器2 计算(bc-ad)/(cc+dd)
.aclk(clk),
.s_axis_a_tvalid(valid3),
.s_axis_a_tdata(result7),
.s_axis_b_tvalid(valid3),
.s_axis_b_tdata(result9),
.m_axis_result_tvalid(),
.m_axis_result_tdata(result11)
);
endmodule
2. Code de simulation
Créez un module de simulation nommé float_complex_div_tb pour simuler le module de niveau supérieur.
code afficher comme ci-dessous:
`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/07/26 13:32:30
// Design Name:
// Module Name: float_complex_div_tb
// Project Name:
// Target Devices:
// Tool Versions: 2017.4
// Description:
// Dependencies:
// Revision:1.0
// Revision 0.01 - File Created
// Additional Comments:
//
module float_complex_div_tb();
reg clk; // 输入时钟信号
reg rst_n; //输入复位信号
reg start; //输入开始信号
reg [31:0] re_a; //输入因数a的实部
reg [31:0] im_a; //输入因数a的虚部
reg [31:0] re_b; //输入因数b的实部
reg [31:0] im_b; //输入因数b的虚部
wire over; //输出计算完成信号
wire [31:0] re_res; //输出计算结果的实部
wire [31:0] im_res; //输出计算结果的虚部
float_complex_div u1_float_complex_div( //例化顶层模块
.clk(clk),
.rst_n(rst_n),
.start(start),
.re_a(re_a),
.im_a(im_a),
.re_b(re_b),
.im_b(im_b),
.over(over),
.re_res(re_res),
.im_res(im_res)
);
always #5 clk=~clk;
initial begin
clk=1'b0;rst_n=1'b1;start=1'b0;
#5; rst_n=1'b0;
#10; rst_n=1'b1;
start=1'b1;
re_a=32'h4057ae14;
im_a=32'h400f5c29;
re_b=32'h3fe51eb8;
im_b=32'hc039999a;
#560 start=1'b0;
end
endmodule
5. Analyse des résultats de la simulation
Les résultats de la simulation sont présentés sur la figure 1. Par rapport aux exemples de division complexe en virgule flottante mentionnés ci-dessus, on peut voir que le module a réalisé avec succès la division de nombres complexes en virgule flottante. Le résultat est 32'hBD23891A+j32'h3F97E634, soit -0,039925672+j1,1867127. Si quatre décimales sont conservées, il est -0,0399+j1,1867, ce qui est cohérent avec l'exemple présenté au début de cet article.
Résumer
Cette fois, nous allons introduire la division des nombres complexes à virgule flottante.