Układy mnoŝące 1
MnoŜenie w układzie sekwencyjnym P = A X = N 1 k = 0 k a k 2 X MnoŜenie szeregowo-równoległe równoległe Czynnik X jest przesuwany o k pozycji: jeŝeli a k 0 to X*2 k jest dodawane i zapisywane w rejestrze (akumulatorze), jeŝeli a k = 0 to dodawanie jest pomijane. 2
Układ mnoŝący sekwencyjny V WAIT UNTI clk = '1'; width := n-1; PACKAGE const IS CASE state IS CONSTANT n : integer := 4; WEN s0 => EN PACKAGE const; state <= s1; IBRARY work; count := 0; USE work.const.a; p := 0; IBRARY ieee; t := b; USE ieee.std_logic_1164.a; WEN s1 => USE ieee.std_logic_arith.a; IF a(count) = '1' TEN p := p + t; ENTITY mul_reg IS EN IF; PORT (clk : IN ST_OGIC; t := t * 2; a : IN ST_OGIC_VECTOR(n-1 OWNTO 0); IF count = width TEN b : IN INTEGER RANGE 0 TO (2**n)-1; state <= s2; y : OUT INTEGER RANGE 0 TO (2**(2*n))-1); ESE EN mul_reg; count := count + 1; state <= s1; ARCITECTURE arch_mult OF mul_reg IS EN IF; TYPE STATE_TYPE IS (s0, s1, s2); WEN s2 => SIGNA state : STATE_TYPE; y <= p; BEGIN state <= s0; States: PROCESS EN CASE; VARIABE p, t : INTEGER RANGE 0 TO (2**(2*n))-1; EN PROCESS States; VARIABE count, width : INTEGER RANGE 0 TO n+1; EN arch_mult; BEGIN 3
Układ mnoŝący sekwencyjny Verilog // serial multiplication module mul_reg(clk, a, b, y); parameter n = 8; input clk; input [n-1:0] a,b; output [2*n-1:0] y; s1: begin if (a[count]==1) p <= p + t; reg [2*n-1:0] y; t <= t<<1; if (count == n-1) always@(posedge clk) begin : fsm parameter s0=0,s1=1,s2=2; reg [1:0] state; reg [2*n-1:0] p, t; reg [3:0] count; case(state) s0: begin state <= s1; count <= 0; p <= 0; t <= b; end state <= s2; else begin count <= count + 1; state <= s1; end end s2: begin y <= p; state <= s0; end endcase end endmodule 4
MnoŜenie w układzie sekwencyjnym - symulacja Realizacja w FPGA: Altera Flex10K70 EPF10K70RC240-4 komórek f [Mz] t_clk [ns] (przerzutników) 4 bit 50 (29) 53,19 18,8 8 bit 105 (55) 38,91 25,7 5
MnoŜenie w układzie macierzowym (kombinacyjnym) a 3 a 2 a 1 a 0 b 3 b 2 b 1 b 0 0 0 0 0 a 3 b 0 a 2 b 0 a 1 b 0 a 0 b 0 M 0 0 0 0 a 3 b 1 a 2 b 1 a 1 b 1 a 0 b 1 0 M 1 0 0 a 3 b 2 a 2 b 2 a 1 b 2 a 0 b 2 0 0 M 2 0 a 3 b 3 a 2 b 3 a 1 b 3 a 0 b 3 0 0 0 M 3 p 7 p 6 p 5 p 4 p 3 p 2 p 1 p 0 P = A B, n = 4 M i = A b i 2 i 6
MnoŜenie macierzowe 4-bitowe MnoŜenie równoległo-równoległe 7
IBRARY work; USE work.fa_package.a; IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY mul_fa IS GENERIC (n : INTEGER := 4); MnoŜenie macierzowe MnoŜenie 4-bitowe - realizacja macierzowe 4-bitowe V PORT ( a_in, b_in : IN ST_OGIC_VECTOR(n-1 OWNTO 0); clk : IN ST_OGIC; p_out : OUT ST_OGIC_VECTOR(2*n-1 OWNTO 0)); EN mul_fa; ARCITECTURE mul_arch OF mul_fa IS SIGNA a : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA b : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA p : ST_OGIC_VECTOR(2*n-1 OWNTO 0); SIGNA s0 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA s1 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA s2 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA s3 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA c0 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA c1 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA c2 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA c3 : ST_OGIC_VECTOR(n-2 OWNTO 0); SIGNA m0 : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA m1 : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA m2 : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA m3 : ST_OGIC_VECTOR(n-1 OWNTO 0); 8
MnoŜenie macierzowe 4-bitowe realizacja V BEGIN Reg: PROCESS (clk) BEGIN IF clk'event AN (clk = '1') TEN a <= a_in; b <= b_in; p_out <= p; EN IF; EN PROCESS Reg; m_0: FOR i IN n-1 OWNTO 0 GENERATE m0(i) <= a(i) AN b(0); EN GENERATE; m_1: FOR i IN n-1 OWNTO 0 GENERATE m1(i) <= a(i) AN b(1); EN GENERATE; m_2: FOR i IN n-1 OWNTO 0 GENERATE m2(i) <= a(i) AN b(2); EN GENERATE; m_3: FOR i IN n-1 OWNTO 0 GENERATE m3(i) <= a(i) AN b(3); EN GENERATE; 9
MnoŜenie macierzowe 4-bitowe - realizacja ha0_0: ha PORT MAP (a => m0(1), b => m1(0), s => s0(0), cout => c0(0)); ha0_1: ha PORT MAP (a => m0(2), b => m1(1), s => s0(1), cout => c0(1)); ha0_2: ha PORT MAP (a => m0(3), b => m1(2), s => s0(2), cout => c0(2)); fa1_0: fa PORT MAP (a => s0(1), b => m2(0), cin => c0(0), s => s1(0), cout => c1(0)); fa1_1: fa PORT MAP (a => s0(2), b => m2(1), cin => c0(1), s => s1(1), cout => c1(1)); fa1_2: fa PORT MAP (a => m1(3), b => m2(2), cin => c0(2), s => s1(2), cout => c1(2)); fa2_0: fa PORT MAP (a => s1(1), b => m3(0), cin => c1(0), s => s2(0), cout => c2(0)); fa2_1: fa PORT MAP (a => s1(2), b => m3(1), cin => c1(1), s => s2(1), cout => c2(1)); fa2_2: fa PORT MAP (a => m2(3), b => m3(2), cin => c1(2), s => s2(2), cout => c2(2)); ha3_0: ha PORT MAP (a => c2(0), b => s2(1), s => s3(0), cout => c3(0)); fa3_1: fa PORT MAP (a => c2(1), b => s2(2), cin => c3(0), s => s3(1), cout => c3(1)); fa3_2: fa PORT MAP (a => c2(2), b => m3(3), cin => c3(1), s => s3(2), cout => c3(2)); p(0) <= m0(0); p(1) <= s0(0); p(2) <= s1(0); p(3) <= s2(0); p(4) <= s3(0); p(5) <= s3(1); p(6) <= s3(2); p(7) <= c3(2); EN mul_arch; 10
MnoŜenie macierzowe 4-bitowe Verilog // 4-bit multiplier (fa) //'include "fa.v"; //'include "ha.v"; module mul_fa(clk,a_in,b_in,p_out); parameter n=4; input clk; input [n-1:0] a_in, b_in; output [2*n-1:0] p_out; genvar i; generate for (i = 0; i < n; i=i+1) begin : m_i assign m0[i] = a[i] & b[0]; assign m1[i] = a[i] & b[1]; assign m2[i] = a[i] & b[2]; assign m3[i] = a[i] & b[3]; end endgenerate reg [2*n-1:0] p_out; reg [n-1:0] a, b; wire [2*n-1:0] p; wire [n-2:0] s0,s1,s2,s3; wire [n-2:0] c0,c1,c2,c3; wire [n-1:0] m0,m1,m2,m3; always@(posedge clk) begin a <= a_in; b <= b_in; p_out <= p; end 11
MnoŜenie macierzowe 4-bitowe Verilog ha ha_0 (.a(m0[1]),.b(m1[0]),.s(s0[0]),.cout(c0[0])); ha ha_1 (.a(m0[2]),.b(m1[1]),.s(s0[1]),.cout(c0[1])); ha ha_2 (.a(m0[3]),.b(m1[2]),.s(s0[2]),.cout(c0[2])); fa fa1_0 (.a(s0[1]),.b(m2[0]),.cin(c0[0]),.s(s1[0]),.cout(c1[0])); fa fa1_1 (.a(s0[2]),.b(m2[1]),.cin(c0[1]),.s(s1[1]),.cout(c1[1])); fa fa1_2 (.a(m1[3]),.b(m2[2]),.cin(c0[2]),.s(s1[2]),.cout(c1[2])); fa fa2_0 (.a(s1[1]),.b(m3[0]),.cin(c1[0]),.s(s2[0]),.cout(c2[0])); fa fa2_1 (.a(s1[2]),.b(m3[1]),.cin(c1[1]),.s(s2[1]),.cout(c2[1])); fa fa2_2 (.a(m2[3]),.b(m3[2]),.cin(c1[2]),.s(s2[2]),.cout(c2[2])); ha ha3_0 (.a(c2[0]),.b(s2[1]),.s(s3[0]),.cout(c3[0])); fa fa3_1 (.a(c2[1]),.b(s2[2]),.cin(c3[0]),.s(s3[1]),.cout(c3[1])); fa fa3_2 (.a(c2[2]),.b(m3[3]),.cin(c3[1]),.s(s3[2]),.cout(c3[2])); endmodule assign p = {c3[2],s3[2],s3[1],s3[0],s2[0],s1[0],s0[0],m0[0]}; 12
MnoŜenie macierzowe - symulacja komórek przerzutników f [Mz] t_clk [ns] 39 16 36,5 24,7 13
MnoŜenie macierzowe sumator równoległy CSA Sumator równoległy bez propagacji przeniesienia Carry-Save Adder MnoŜenie jest rozłoŝone na operacje sumowania, więc moŝna wykorzystać bloki CSA sumowanie bez uwzględniania przeniesienia 14
MnoŜenie macierzowe sumator równoległy CSA V -- Carry Save Adder IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY csa IS GENERIC (n : INTEGER := 4); PORT ( a, b, cin : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s, cout : OUT ST_OGIC_VECTOR(n-1 OWNTO 0)); EN csa; ARCITECTURE csa_arch OF csa IS BEGIN csa: FOR i IN n-1 OWNTO 0 GENERATE s(i) <= a(i) XOR b(i) XOR cin(i); cout(i) <= (a(i) AN b(i)) OR (a(i) AN cin(i)) OR (b(i) AN cin(i)); EN GENERATE; EN csa_arch; 15
MnoŜenie macierzowe sumator równoległy CSA Verilog // Carry Save Adder module csa(a, b, cin, s, cout); parameter n = 4; input [n-1:0] a, b, cin; output [n-1:0] s, cout; genvar i; generate for (i = 0; i < n; i=i+1) begin : csa assign s[i] = a[i] ^ b[i] ^ cin[i]; assign cout[i] = a[i] & b[i] a[i] & cin[i] b[i] & cin[i]; end endgenerate endmodule 16
MnoŜenie CSA 4-bitowe n-2 poziomów CSA C* przesunięte o 1 bit w lewo CPA Carry Propagate Adder 17
MnoŜenie CSA 4-bitowe sumator CPA V ENTITY cpa IS --- Carry Propagate Adder GENERIC(n : INTEGER := 8); PORT(s: IN ST_OGIC_VECTOR(n-1 OWNTO 0); EN cpa; c :IN ST_OGIC_VECTOR(n-1 OWNTO 0); p: OUT ST_OGIC_VECTOR(n-1 OWNTO 0)); ARCITECTURE cpa_arch OF cpa IS SIGNA cout_cin : ST_OGIC_VECTOR(n-2 OWNTO 1); BEGIN p(0) <= s(0); EN cpa_arch; Blok potrzebny do wyznaczenia sumy na ostatnim poziomie ha1: ha PORT MAP(a => s(1), b => c(0), s => p(1), cout => cout_cin(1)); fa_n: FOR i IN 2 TO n-2 GENERATE fa_n: fa PORT MAP(a => s(i), b => c(i-1), cin => cout_cin(i-1), s => p(i), cout => cout_cin(i)); EN GENERATE; p(n-1) <= cout_cin(n-2) XOR s(n-1) XOR c(n-2); 18
MnoŜenie CSA 4-bitowe sumator CPA Verilog // Carry Propagate Adder module cpa(s,c,p); parameter n = 8; input [n-1:0] s, c; output [n-1:0] p; Blok potrzebny do wyznaczenia sumy na ostatnim poziomie wire [n-2:0] cout_cin; assign p[0] = s[0]; ha ha1(.a(s[1]),.b(c[0]),.s(p[1]),.cout(cout_cin[1])); genvar i; generate for (i = 2; i <= n-2; i=i+1) begin : fa_i fa fa_n(.a(s[i]),.b(c[i-1]),.cin(cout_cin[i-1]),.s(p[i]),.cout(cout_cin[i])); end endgenerate assign p[n-1] = cout_cin[n-2] ^ s[n-1] ^ c[n-2]; endmodule 19
MnoŜenie CSA 4-bitowe V IBRARY ieee; USE ieee.std_logic_1164.a; PACKAGE csa_package IS... EN csa_package; IBRARY work; USE work.csa_package.a; IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY mul_csa IS GENERIC (n : INTEGER := 4); PORT (a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); clk : IN ST_OGIC; p : OUT ST_OGIC_VECTOR(2*n-1 OWNTO 0)); EN mul_csa; ARCITECTURE mul_arch OF mul_csa IS SIGNA a_r, b_r : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA p_r : ST_OGIC_VECTOR(2*n-1 OWNTO 0); SIGNA s0, s1 : ST_OGIC_VECTOR(2*n-1 OWNTO 0); SIGNA c0, c0_out, c1 : ST_OGIC_VECTOR(2*n-1 OWNTO 0); SIGNA m0, m1, m2, m3 : ST_OGIC_VECTOR(2*n-1 OWNTO 0); 20
MnoŜenie CSA 4-bitowe V m2(1 OWNTO 0) <= "00"; m_2: FOR i IN 5 OWNTO 2 GENERATE BEGIN m2(i) <= a_r(i-2) AN b_r(2); Reg: PROCESS (clk) EN GENERATE; BEGIN m_2msb: FOR i IN 2*n-1 OWNTO 6 GENERATE IF clk'event AN (clk = '1') TEN m2(i) <= '0'; a_r <= a; EN GENERATE; b_r <= b; m3(2 OWNTO 0) <= "000"; p <= p_r; m_3: FOR i IN 6 OWNTO 3 GENERATE EN IF; m3(i) <= a_r(i-3) AN b_r(3); EN PROCESS Reg; EN GENERATE; m_3msb: FOR i IN 2*n-1 OWNTO 7 GENERATE m_0: FOR i IN 3 OWNTO 0 GENERATE m3(i) <= '0'; m0(i) <= a_r(i) AN b_r(0); EN GENERATE; EN GENERATE; m_0msb: FOR i IN 2*n-1 OWNTO 4 GENERATE csa0: csa m0(i) <= '0'; PORT MAP (a => m2, b => m1, cin => m0, EN GENERATE; s => s0, cout => c0); m1(0) <= '0'; c0_out <= c0(2*n-2 OWNTO 0) & '0'; m_1: FOR i IN 4 OWNTO 1 GENERATE csa1: csa m1(i) <= a_r(i-1) AN b_r(1); PORT MAP (a => m3, b => c0_out, cin => s0, EN GENERATE; s => s1, cout => c1); m_1msb: FOR i IN 2*n-1 OWNTO 5 GENERATE cpa_end: cpa m1(i) <= '0'; PORT MAP (s => s1, c => c1, p => p_r); EN GENERATE; EN mul_arch; 21
MnoŜenie CSA 4-bitowe Verilog // 4-bit multiplier (csa) module mul_csa(a,b,clk,p); parameter n=4; input clk; input [n-1:0] a,b; output [2*n-1:0] p; reg [2*n-1:0] p; reg [n-1:0] a_r, b_r; wire [2*n-1:0] p_r; wire [2*n-1:0] s0, s1; wire [2*n-1:0] c0, c0_out, c1; wire [2*n-1:0] m0, m1, m2, m3; always@(posedge clk) begin a_r <= a; b_r <= b; p <= p_r; end assign m0 = {4'b0000,a_r[3] & b_r[0],a_r[2] & b_r[0],a_r[1] & b_r[0],a_r[0] & b_r[0]}; assign m1 = {3'b000,a_r[3] & b_r[1],a_r[2] & b_r[1],a_r[1] & b_r[1],a_r[0] & b_r[1],1'b0}; assign m2 = {2'b00,a_r[3] & b_r[2],a_r[2] & b_r[2],a_r[1] & b_r[2],a_r[0] & b_r[2],2'b00}; assign m3 = {1'b0,a_r[3] & b_r[3],a_r[2] & b_r[3],a_r[1] & b_r[3],a_r[0] & b_r[3],3'b000}; csa csa0(.a(m2),.b(m1),.cin(m0),.s(s0),.cout(c0)); defparam csa0.n=2*n; assign c0_out = {c0[2*n-2:0],1'b0}; csa csa1(.a(m3),.b(c0_out),.cin(s0),.s(s1),.cout(c1)); defparam csa1.n=2*n; cpa cpa_end(.s(s1),.c(c1),.p(p_r)); endmodule 22
MnoŜenie CSA 4-bitowe Verilog always@(posedge clk) begin a_r <= a; b_r <= b; p <= p_r; end assign m0 = {4'b0000,a_r[3] & b_r[0],a_r[2] & b_r[0],a_r[1] & b_r[0],a_r[0] & b_r[0]}; assign m1 = {3'b000,a_r[3] & b_r[1],a_r[2] & b_r[1],a_r[1] & b_r[1],a_r[0] & b_r[1],1'b0}; assign m2 = {2'b00,a_r[3] & b_r[2],a_r[2] & b_r[2],a_r[1] & b_r[2],a_r[0] & b_r[2],2'b00}; assign m3 = {1'b0,a_r[3] & b_r[3],a_r[2] & b_r[3],a_r[1] & b_r[3],a_r[0] & b_r[3],3'b000}; csa csa0(.a(m2),.b(m1),.cin(m0),.s(s0),.cout(c0)); defparam csa0.n=2*n; assign c0_out = {c0[2*n-2:0],1'b0}; csa csa1(.a(m3),.b(c0_out),.cin(s0),.s(s1),.cout(c1)); defparam csa1.n=2*n; cpa cpa_end(.s(s1),.c(c1),.p(p_r)); endmodule 23
MnoŜenie CSA 4-bitowe komórek przerzutników f [Mz] t_clk [ns] 40 16 35,46 28,2 24
MnoŜenie UT 4-bitowe MnoŜenie z wykorzystaniem pamięci UT (A(4 bity), B(4 bity)) * słowo P (8 bitów) = 2048 bitów latego pamięci EAB w Flex10K mają rozmiar 2048 bitów 25
MnoŜenie UT 4-bitowe -- 4x4 bit multiplication depth= 256; width = 8; address_radix = bin; data_radix = dec; content begin 00000000 : 000 ; 00000001 : 000 ; 00000010 : 000 ; 00000011 : 000 ; 00000100 : 000 ; 00000101 : 000 ;.. 11111010 : 150 ; 11111011 : 165 ; 11111100 : 180 ; 11111101 : 195 ; 11111110 : 210 ; 11111111 : 225 ; end; Plik konfiguracyjny pamięci UT: 4x4_mult.mif 26
MnoŜenie UT 4-bitowe V IBRARY ieee; USE ieee.std_logic_1164.a; PACKAGE ram_constants IS CONSTANT ATA_WIT : INTEGER := 8; CONSTANT AR_WIT : INTEGER := 8; EN ram_constants; IBRARY ieee; USE ieee.std_logic_1164.a; IBRARY lpm; USE lpm.lpm_components.a; IBRARY work; USE work.ram_constants.a; ENTITY mul_rom4b IS GENERIC (n : INTEGER := 4); PORT (a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); clk : IN ST_OGIC; p : OUT ST_OGIC_VECTOR(2*n-1 OWNTO 0)); EN mul_rom4b; ARCITECTURE mul_arch OF mul_rom4b IS SIGNA address : ST_OGIC_VECTOR(2*n-1 OWNTO 0); BEGIN address <= a & b; rom4b: lpm_rom GENERIC MAP (PM_WIT => ATA_WIT, PM_WITA => AR_WIT, PM_FIE => "4x4_mult.mif", PM_ARESS_CONTRO => "REGISTERE", PM_OUTATA => "REGISTERE") PORT MAP (address => address, inclock => clk, outclock => clk, q => p); EN mul_arch; 27
MnoŜenie UT 4-bitowe Verilog // 4bit ROM-based multiplier module mul_rom4b(a,b,clk,p); parameter n=4; parameter data_width=2*n; parameter addr_width=2*n; input clk; input [n-1:0] a,b; output [2*n-1:0] p; reg [2*n-1:0] p; wire [2*n-1:0] address; assign address = {a, b}; lpm_rom rom4b(.address(address),.inclock(clk),.outclock(clk),.q(p)); defparam rom4b.lpm_width=data_width; defparam rom4b.lpm_widthad=addr_width; defparam rom4b.lpm_file="4x4_mult.mif"; defparam rom4b.lpm_address_control="registere"; defparam rom4b.lpm_outdata="registere"; endmodule; 28
MnoŜenie UT 4-bitowe pamięci EAB komórek przerzutników f [Mz] t_clk [ns] 1 (2048 bitów) 0 0 76,34 13,1 29
MnoŜenie UT 8-bitowe MnoŜenie z wykorzystaniem pamięci UT 2kbit: P = A B = (A 1 2 n + A 0 ) (B 1 2 n + B 0 ) = A 1 B 1 2 2n + (A 1 B 0 + A 0 B 1 ) 2 n + A 0 B 0 30
MnoŜenie UT 8-bitowe V IBRARY ieee; USE ieee.std_logic_1164.a; PACKAGE ram_constants IS CONSTANT ATA_WIT : INTEGER := 8; CONSTANT AR_WIT : INTEGER := 8; EN ram_constants; IBRARY ieee; USE ieee.std_logic_1164.a; IBRARY lpm; USE lpm.lpm_components.a; IBRARY work; USE work.ram_constants.a; ENTITY mul_rom8b IS GENERIC (n : INTEGER := 8); PORT (a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); clk : IN ST_OGIC; p : OUT ST_OGIC_VECTOR(2*n-1 OWNTO 0)); EN mul_rom8b; ARCITECTURE mul_arch OF mul_rom8b IS SIGNA address0, address1, address2, address3 : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA p0, p1, p2, p3 : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA s0, s1, s2, s3, s4, s5 : ST_OGIC_VECTOR((n+n/2-1) OWNTO 0); SIGNA s6, s7, p_r : ST_OGIC_VECTOR(2*n-1 OWNTO 0); 31
MnoŜenie UT 8-bitowe V BEGIN Reg: PROCESS (clk) BEGIN IF clk'event AN (clk = '1') TEN p <= p_r; EN IF; EN PROCESS Reg; address0 <= a(n/2-1 OWNTO 0) & b(n/2-1 OWNTO 0); address1 <= a(n/2-1 OWNTO 0) & b(n-1 OWNTO n/2); address2 <= a(n-1 OWNTO n/2) & b(n/2-1 OWNTO 0); address3 <= a(n-1 OWNTO n/2) & b(n-1 OWNTO n/2); rom4b_0: lpm_rom GENERIC MAP (PM_WIT => ATA_WIT, PM_WITA => AR_WIT, PM_FIE => "4x4_mult.mif", PM_ARESS_CONTRO => "REGISTERE", PM_OUTATA => "REGISTERE") PORT MAP (address => address0, inclock => clk, outclock => clk, q => p0); rom4b_1: lpm_rom GENERIC MAP (PM_WIT => ATA_WIT, PM_WITA => AR_WIT, PM_FIE => "4x4_mult.mif", PM_ARESS_CONTRO => "REGISTERE", PM_OUTATA => "REGISTERE") PORT MAP (address => address1, inclock => clk, outclock => clk, q => p1); rom4b_2: lpm_rom GENERIC MAP (PM_WIT => ATA_WIT, PM_WITA => AR_WIT, PM_FIE => "4x4_mult.mif", PM_ARESS_CONTRO => "REGISTERE", PM_OUTATA => "REGISTERE") dr inŝ. Paweł PORT Tomaszewicz MAP (address => address2, inclock => clk, outclock => clk, q => p2); 32
MnoŜenie UT 8-bitowe V rom4b_3: lpm_rom GENERIC MAP (PM_WIT => ATA_WIT, PM_WITA => AR_WIT, PM_FIE => "4x4_mult.mif", PM_ARESS_CONTRO => "REGISTERE", PM_OUTATA => "REGISTERE") PORT MAP (address => address3, inclock => clk, outclock => clk, q => p3); s0 <= "0000" & p0; s1 <= p1 & "0000"; sum0: lpm_add_sub GENERIC MAP (PM_WIT => 12, PM_REPRESENTATION => "UNSIGNE", PM_IRECTION => "A") PORT MAP (dataa => s0, datab => s1, result => s4); s2 <= "0000" & p2; s3 <= p3 & "0000"; sum1: lpm_add_sub GENERIC MAP (PM_WIT => 12, PM_REPRESENTATION => "UNSIGNE", PM_IRECTION => "A") PORT MAP (dataa => s2, datab => s3, result => s5); s6 <= "0000" & s4; s7 <= s5 & "0000"; sum2: lpm_add_sub GENERIC MAP (PM_WIT => 16, PM_REPRESENTATION => "UNSIGNE", PM_IRECTION => "A") PORT MAP (dataa => s6, datab => s7, result => p_r); EN mul_arch; 33
MnoŜenie UT 8-bitowe Verilog // 4bit ROM-based multiplier // P = X * Y = (Y2 * 2^N + Y1)*(X2 * 2^N + X1) // = Y2X2 * 2^2N + (Y2X1 + Y1X2)*2^N + Y1X1 module mul_rom8b(a,b,clk,p); parameter n=8; parameter data_width=8; parameter addr_width=8; input clk; input [n-1:0] a,b; output [2*n-1:0] p; reg [2*n-1:0] p; wire [n-1:0] address0,address1,address2,address3; wire [n-1:0] p0, p1, p2, p3; wire [n+n/2-1:0] s0, s1, s2, s3, s4, s5; wire [2*n-1:0] s6, s7, p_r; always@(posedge clk) begin p <= p_r; end 34
MnoŜenie UT 8-bitowe Verilog assign address0 = {a[n/2-1:0], b[n/2-1:0]}; assign address1 = {a[n/2-1:0], b[n-1:n/2]}; assign address2 = {a[n-1:n/2], b[n/2-1:0]}; assign address3 = {a[n-1:n/2], b[n-1:n/2]}; lpm_rom rom4b_0(.address(address0),.inclock(clk),.outclock(clk),.q(p0)); defparam rom4b_0.lpm_width=data_width; defparam rom4b_0.lpm_widthad=addr_width; defparam rom4b_0.lpm_file="4x4_mult.mif"; defparam rom4b_0.lpm_address_control="registere"; defparam rom4b_0.lpm_outdata="registere"; lpm_rom rom4b_1(.address(address1),.inclock(clk),.outclock(clk),.q(p1)); defparam rom4b_1.lpm_width=data_width; defparam rom4b_1.lpm_widthad=addr_width; defparam rom4b_1.lpm_file="4x4_mult.mif"; defparam rom4b_1.lpm_address_control="registere"; defparam rom4b_1.lpm_outdata="registere"; lpm_rom rom4b_2(.address(address2),.inclock(clk),.outclock(clk),.q(p2)); defparam rom4b_2.lpm_width=data_width; defparam rom4b_2.lpm_widthad=addr_width; defparam rom4b_2.lpm_file="4x4_mult.mif"; defparam rom4b_2.lpm_address_control="registere"; defparam rom4b_2.lpm_outdata="registere"; lpm_rom rom4b_3(.address(address3),.inclock(clk),.outclock(clk),.q(p3)); defparam rom4b_3.lpm_width=data_width; defparam rom4b_3.lpm_widthad=addr_width; defparam rom4b_3.lpm_file="4x4_mult.mif"; defparam rom4b_3.lpm_address_control="registere"; defparam rom4b_3.lpm_outdata="registere"; 35
MnoŜenie UT 8-bitowe Verilog assign s0 = {4'b0000, p0}; assign s1 = {p1, 4'b0000}; lpm_add_sub sum0(.dataa(s0),.datab(s1),.result(s4)); defparam sum0.lpm_width=12; defparam sum0.lpm_representation="unsigned"; defparam sum0.lpm_direction="add"; assign s2 = {4'b0000, p2}; assign s3 = {p3, 4'b0000}; lpm_add_sub sum1(.dataa(s2),.datab(s3),.result(s5)); defparam sum1.lpm_width=12; defparam sum1.lpm_representation="unsigned"; defparam sum1.lpm_direction="add"; assign s6 = {4'b0000, s4}; assign s7 = {s5, 4'b0000}; lpm_add_sub sum2(.dataa(s6),.datab(s7),.result(p_r)); defparam sum2.lpm_width=16; defparam sum2.lpm_representation="unsigned"; defparam sum2.lpm_direction="add"; endmodule 36
MnoŜenie UT 8-bitowe opcje kompilatora pamięci EAB komórek przerzutników f [Mz] t_clk [ns] pamięć UT z we/wy rejestrowymi z CarryChain 4 (8192 bity) 44 16 38,31 26,1 bez CarryChain 4 (8192 bity) 42 16 21,69 46,1 pamięć UT tylko z we rejestrowymi z CarryChain 4 (8192 bity) 44 16 26,04 38,4 bez CarryChain 4 (8192 bity) 42 16 17,06 58,6 Widać na tym przykładzie jaki wpływ ma stosowanie CARRY Chain! 37
Szybkie mnoŝenie FastArray macierzowe 8-bitowe W pierwszym kroku dodać dwa sąsiadujące czynniki a n B 2 n + a n+1 B 2 n+1 cpa_1shl.vhd cpa_2shl.vhd cpa_2.vhd cpa_4.vhd log 2 (N) poziomów N=8, 3 poziomy 38
MnoŜenie macierzowe 8-bitowe N-2 poziomów CSA N=8, 6+1 poziomów 39
MnoŜenie macierzowe 8bit drzewo Wallace a N=8, 4+1 poziomów Architektury typu Wallacetree, Booth są rzadko spotykane w FPGA (często uŝywane w układach ASIC) 40
MnoŜenie 8-bitowe potokowe vs kombinacyjne model komórek przerzutników stopni f [Mz] t_clk [ns] potoku fast 189 96 3 29,5 33,9 CSA 299 275 7 34,97 28,6 Wallace 226 182 5 29,07 34,4 fast 174 32 1 15,2 65,8 CSA 151 32 1 15,06 66,4 Wallace 183 32 1 16,23 61,6 W układzie Szybkiego MnoŜenia (Fast Array) dodanie potokowości nie kosztuje prawie Ŝadnych dodatkowych zasobów a przepustowość wzrosła dwukrotnie Układy moŝna by zoptymalizować (a szczególnie CSA) jeŝeli uwzględnimy fakt, Ŝe w cząstkowych iloczynach M połowa wektora wejściowego to są zera 41
IBRARY ieee; USE ieee.std_logic_1164.a; IBRARY lpm; USE lpm.lpm_components.a; ENTITY mul_lpm IS GENERIC (n : INTEGER := 8); PORT (a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); clk EN mul_lpm; MnoŜenie 8-bitowe PM V : IN ST_OGIC; p : OUT ST_OGIC_VECTOR(2*n-1 OWNTO 0)); ARCITECTURE mul_arch OF mul_lpm IS BEGIN SIGNA a_r, b_r : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA p_r : ST_OGIC_VECTOR(2*n-1 OWNTO 0); Reg: PROCESS (clk) BEGIN IF clk'event AN (clk = '1') TEN EN IF; EN PROCESS Reg; mul: lpm_mult a_r <= a; b_r <= b; p <= p_r; GENERIC MAP (PM_WITA => n, PM_WITB => n, PM_WITS => n, PM_WITP => 2*n, PM_PIPEINE => 3) PORT MAP (dataa => a_r, datab => b_r, result => p_r, clock => clk); EN mul_arch; 42
MnoŜenie 8-bitowe PM Verilog // 8-bit PM multiplier module mul_lpm(a,b,clk,p); parameter n=8; input clk; input [n-1:0] a,b; output [2*n-1:0] p; reg [n-1:0] a_r,b_r; reg [2*n-1:0] p; reg [2*n-1:0] p_r; always@(posedge clk) begin a_r <= a; b_r <= b; p <= p_r; end lpm_mult mult(.dataa(a_r),.datab(b_r),.result(p_r),.clock(clk)); defparam mult.lpm_widtha=n; defparam mult.lpm_widthb=n; defparam mult.lpm_widths=1; defparam mult.lpm_widthp=2*n; defparam mult.lpm_pipeline=1; endmodule 43
MnoŜenie 8-bitowe PM_MUT stopni potoku komórek przerzutników f [Mz] t_clk [ns] -* 194 32 14,77 67,7 1 168 72 40,49 24,7 2 198 120 18,98 52,7 3 172 160 56,18 17,8 4 188 176 56,5 17,7 5 204 192 55,56 18,0 * wejścia/wyjścia rejestrowe Najlepsza realizacja (szybkość/zajętość) jest dla 3 stopni potoku. 44