• [^] # Re: Pourquoi en faire une dépêche ?

    Posté par (site web personnel) . En réponse à la dépêche k1g1 : le premier FPGA Libre.... Évalué à 6. Dernière modification le 06 novembre 2019 à 09:33.

    Dans l'absolu, il a pas tord. C'est effectivement plus bas niveau que l'assembleur au sens où on manipule directement des portes logiques.

    Freem<, pour l'exemple, là je décris un simple additionneur 32 bits en verilog :

    module Adder(s, a, b);
     input [3:0] a, b;
     output [3:0] s;
     assign s = a + b;
    endmodule

    Ici, c'est ce que j'obtiens après un passage dans un outil de synthèse. Il m'a tout converti en portes logiques abstraites

    module Adder(s, a, b);
     wire _00_;
     wire _01_;
     wire _02_;
     wire _03_;
     wire _04_;
     wire _05_;
     wire _06_;
     wire _07_;
     wire _08_;
     wire _09_;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] a;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] b;
     (* src = "rtl/Adder.v:3" *)
     output [3:0] s;
     assign _00_ = a[1] ^ b[1];
     assign _01_ = ~(a[0] & b[0]);
     assign s[1] = ~(_01_ ^ _00_);
     assign _02_ = a[2] ^ b[2];
     assign _03_ = ~(a[1] & b[1]);
     assign _04_ = _00_ & ~(_01_);
     assign _05_ = _03_ & ~(_04_);
     assign s[2] = ~(_05_ ^ _02_);
     assign _06_ = ~(a[3] ^ b[3]);
     assign _07_ = ~(a[2] & b[2]);
     assign _08_ = _02_ & ~(_05_);
     assign _09_ = _07_ & ~(_08_);
     assign s[3] = _09_ ^ _06_;
     assign s[0] = a[0] ^ b[0];
    endmodule

    À partir de là, je peux lui demander de transformer cette logique en LUT pour cibler un FPGA (ici un ICE40 de chez Lattice)

    module Adder(s, a, b);
     wire _0_;
     wire _1_;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] a;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] b;
     (* src = "rtl/Adder.v:3" *)
     output [3:0] s;
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:56" *)
     SB_LUT4 #(
     .LUT_INIT(16'h9666)
     ) _2_ (
     .I0(b[1]),
     .I1(a[1]),
     .I2(b[0]),
     .I3(a[0]),
     .O(s[1])
     );
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:51" *)
     SB_LUT4 #(
     .LUT_INIT(16'h3cc3)
     ) _3_ (
     .I0(1'h0),
     .I1(b[2]),
     .I2(a[2]),
     .I3(_0_),
     .O(s[2])
     );
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:56" *)
     SB_LUT4 #(
     .LUT_INIT(16'h077f)
     ) _4_ (
     .I0(b[0]),
     .I1(a[0]),
     .I2(b[1]),
     .I3(a[1]),
     .O(_0_)
     );
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:56" *)
     SB_LUT4 #(
     .LUT_INIT(16'h6a56)
     ) _5_ (
     .I0(_1_),
     .I1(b[2]),
     .I2(a[2]),
     .I3(_0_),
     .O(s[3])
     );
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:46" *)
     SB_LUT4 #(
     .LUT_INIT(16'h0ff0)
     ) _6_ (
     .I0(1'h0),
     .I1(1'h0),
     .I2(b[3]),
     .I3(a[3]),
     .O(_1_)
     );
     (* module_not_derived = 32'd1 *)
     (* src = "/home/killruana/opt/eda/yosys/usr/local/bin/../share/yosys/ice40/cells_map.v:46" *)
     SB_LUT4 #(
     .LUT_INIT(16'h0ff0)
     ) _7_ (
     .I0(1'h0),
     .I1(1'h0),
     .I2(b[0]),
     .I3(a[0]),
     .O(s[0])
     );
    endmodule

    Ou alors de cibler une véritable bibliothèques de portes logiques (ici des standard cell OSU 035) pour ensuite fabriquer un circuit intégré

    module Adder(s, a, b);
     wire _00_;
     wire _01_;
     wire _02_;
     wire _03_;
     wire _04_;
     wire _05_;
     wire _06_;
     wire _07_;
     wire _08_;
     wire _09_;
     wire _10_;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] a;
     (* src = "rtl/Adder.v:2" *)
     input [3:0] b;
     (* src = "rtl/Adder.v:3" *)
     output [3:0] s;
     NAND2X1 _11_ (
     .A(b[0]),
     .B(a[0]),
     .Y(_00_)
     );
     NAND2X1 _12_ (
     .A(b[1]),
     .B(a[1]),
     .Y(_01_)
     );
     INVX1 _13_ (
     .A(_01_),
     .Y(_02_)
     );
     NOR2X1 _14_ (
     .A(b[1]),
     .B(a[1]),
     .Y(_03_)
     );
     NOR2X1 _15_ (
     .A(_03_),
     .B(_02_),
     .Y(_04_)
     );
     XNOR2X1 _16_ (
     .A(_04_),
     .B(_00_),
     .Y(s[1])
     );
     OAI21X1 _17_ (
     .A(_00_),
     .B(_03_),
     .C(_01_),
     .Y(_05_)
     );
     AND2X2 _18_ (
     .A(b[2]),
     .B(a[2]),
     .Y(_06_)
     );
     NOR2X1 _19_ (
     .A(b[2]),
     .B(a[2]),
     .Y(_07_)
     );
     NOR2X1 _20_ (
     .A(_07_),
     .B(_06_),
     .Y(_08_)
     );
     XOR2X1 _21_ (
     .A(_05_),
     .B(_08_),
     .Y(s[2])
     );
     AOI21X1 _22_ (
     .A(_05_),
     .B(_08_),
     .C(_06_),
     .Y(_09_)
     );
     XOR2X1 _23_ (
     .A(b[3]),
     .B(a[3]),
     .Y(_10_)
     );
     XNOR2X1 _24_ (
     .A(_09_),
     .B(_10_),
     .Y(s[3])
     );
     XOR2X1 _25_ (
     .A(b[0]),
     .B(a[0]),
     .Y(s[0])
     );
    endmodule

    Et c'est la que je me rends compte que mon outil de synthèse est bof. Vu que dans ma bibliothèque de porte logique j'ai une porte de type full adder, il aurait pu me générer le résultat suivant :

    module Adder(s, a, b); 
     wire _00_;
     wire _01_;
     wire _02_;
     FAX1 _04_(
     .A(a[3]),
     .B(a[3]),
     .C(_02_)
     .YC(),
     .YS(s[3])
     );
     FAX1 _05_(
     .A(a[2]),
     .B(a[2]),
     .C(_01_)
     .YC(_02_),
     .YS(s[2])
     );
     FAX1 _06_(
     .A(a[1]),
     .B(a[1]),
     .C(_00_)
     .YC(_01_),
     .YS(s[1])
     );
     HAX1 _07_(
     .A(a[0]),
     .B(a[0]),
     .YC(_00_),
     .YS(s[0])
     );
    endmodule

    Dans l'absolu, les deux résultats précédents sont fonctionnellement équivalents. Mais il y a de bonnes chances que la solution à base de full-adder soit plus intéressante au niveau vitesse de fonctionnement et surface utilisée.