Sumatory 1
Sumator 1-bitowy full adder Równanie boolowskie sumy: s k = a k XOR b k XOR c k = a k b k c k Równanie boolowskie przeniesienia: c k+1 = (a k AN b k ) OR (a k AN c k ) OR (b k AN c k ) = (a k b k ) + (a k c k ) + (b k c k ) 2
Układ Flex10K - schemat 3
Układ Flex10K komórka logiczna 4
Sumator 1-bitowy realizacja w FPGA Realizacja w FPGA: Altera Flex10K70 EPF10K70RC240-4; Quartus2 v4.1 SP2 WebEdition -- 1 bit full adder IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY fa IS PORT ( a, b, cin : IN ST_OGIC; s, cout : OUT ST_OGIC); EN fa; ARCITECTURE fa_arch OF fa IS BEGIN s <= a XOR b XOR cin; cout <= (a AN b) OR (a AN cin) OR (b AN cin); EN fa_arch; 5
Sumator 1-bitowy realizacja w FPGA // 1 bit full adder module fa(a, b, cin, s, cout); input a, b, cin; output s, cout; assign s = a ^ b ^ cin; assign cout = a & b a & cin b & cin; endmodule 6
Sumator 1-bitowy realizacja w FPGA 7
Sumator 1-bitowy realizacja w FPGA Opóźnienia w komórce Opóźnienia w ścieŝkach bardzo duŝe w fpga 8
Sumator 1-bitowy realizacja w FPGA 9
Sumator 1-bitowy realizacja w FPGA 10
Sumator 1-bitowy realizacja funkcją PM -- 1 bit full adder using PM_A_SUB IBRARY ieee; USE ieee.std_logic_1164.a; IBRARY lpm; USE lpm.lpm_components.a; ENTITY fa_lpm IS GENERIC (n : INTEGER := 1); Realizacja w FPGA: Altera Flex10K20 EPF10K70RC240-4 z parametryzowaną funkcją PM_A_SUB 2 C; t pd =20,5ns PORT (a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); cin : IN ST_OGIC; s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); EN fa_lpm; ARCITECTURE fa_arch OF fa_lpm IS BEGIN fa_lpm: lpm_add_sub GENERIC MAP (PM_WIT => n, PM_REPRESENTATION => "UNSIGNE", PM_IRECTION => "A") PORT MAP (dataa => a, datab => b, cin => cin, result => s, cout => cout); EN fa_arch; 11
Sumator 1-bitowy realizacja funkcją PM Nagłówek parametryzowanej funkcji PM_A_SUB (V Component eclaration): COMPONENT lpm_add_sub GENERIC (PM_WIT: POSITIVE; PM_IRECTION: STRING := "UNUSE"; PM_REPRESENTATION: STRING := "SIGNE"; PM_PIPEINE: INTEGER := 0; PM_TYPE: STRING := "PM_A_SUB"; PM_INT: STRING := "UNUSE" ONE_INPUT_IS_CONSTANT: STRING := "NO"; MAXIMIZE_SPEE: INTEGER; USE_WYS: STRING := "OFF"); PORT (dataa, datab: IN ST_OGIC_VECTOR(PM_WIT-1 OWNTO 0); aclr, clock, cin: IN ST_OGIC := '0'; clken, add_sub: IN ST_OGIC := '1'; result: OUT ST_OGIC_VECTOR(PM_WIT-1 OWNTO 0); cout, overflow: OUT ST_OGIC); EN COMPONENT; 12
Sumator 7-bitowy ripple-carry adder 13
Sumator 7-bitowy realizacja V -- n-bit adder Ripple Carry Adder IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY rca IS GENERIC (n : INTEGER := 7); EN rca; PORT ( a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); ARCITECTURE rca_arch OF rca IS BEGIN SIGNA c : ST_OGIC_VECTOR(n-1 OWNTO 0); s(0) <= a(0) XOR b(0); c(0) <= (a(0) AN b(0)); add: FOR i IN n-1 OWNTO 1 GENERATE s(i) <= a(i) XOR b(i) XOR c(i-1); Realizacja bez sygnału Carry-In c(i) <= (a(i) AN b(i)) OR (a(i) AN c(i-1)) OR (b(i) AN c(i-1)); EN GENERATE; cout <= c(n-1); EN rca_arch; 7-bitowy RCA C (carry) * 8 f [Mz] / tmax [ns] 34, 01 / 29,4 C (bez carry) ** 13 f [Mz] / tmax [ns] 22,27 / 44,9 * Z komponentem CARRY_SUM ** Bez 14
Sumator 7-bitowy realizacja Verilog // n-bit adder Ripple-Carry Adder module rca (a, b, s, cout); parameter n=7; input [n-1:0] a, b; output [n-1:0] s; output cout; wire [n-1:0] c; assign s[0] = a[0] ^ b[0]; assign c[0] = a[0] & b[0]; genvar i; generate for (i = 1; i < n; i=i+1) begin : rca_adder assign s[i] = a[i] ^ b[i] ^ c[i-1]; assign c[i] = a[i] & b[i] a[i] & c[i-1] b[i] & c[i-1]; end endgenerate assign cout = c[n-1]; endmodule; 15
Komponent carry_sum 16
Sumator 7-bitowy z komponentem carry_sum V ARCITECTURE rca_arch OF rca IS SIGNA cin : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA co : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA sin : ST_OGIC_VECTOR(n-1 OWNTO 0); COMPONENT CARRY_SUM IS PORT (sin, cin : IN ST_OGIC; sout, cout : OUT ST_OGIC); EN COMPONENT; BEGIN sin(0) <= a(0) XOR b(0); cin(0) <= a(0) AN b(0); c_0: CARRY_SUM PORT MAP (sin => sin(0), cin => cin(0), sout => s(0), cout => co(0)); add: FOR i IN n-1 OWNTO 1 GENERATE sin(i) <= a(i) XOR b(i) XOR co(i-1); cin(i) <= (a(i) AN b(i)) OR (a(i) AN co(i-1)) OR (b(i) AN co(i-1)); c_i: CARRY_SUM PORT MAP (sin => sin(i), cin => cin(i), sout => s(i), cout => co(i)); EN GENERATE; cout <= co(n-1); dr inŝ. Paweł EN rca_arch; Tomaszewicz 17
Sumator 7-bitowy z carry_sum Verilog // n-bit adder Ripple-Carry Adder module rca (a, b, s, cout); parameter n=7; input [n-1:0] a, b; output [n-1:0] s; output cout; wire [n-1:0] cin, co, sin; assign sin[0] = a[0] ^ b[0]; assign cin[0] = a[0] & b[0]; carry_sum c_0 (.sin(sin[0]),.cin(cin[0]),.sout(s[0]),.cout(co[0])); genvar i; generate for (i = 1; i < n; i=i+1) begin : rca_adder assign sin[i] = a[i] ^ b[i] ^ co[i-1]; assign cin[i] = a[i] & b[i] a[i] & co[i-1] b[i] & co[i-1]; carry_sum c_i (.sin(sin[i]),.cin(cin[i]),.sout(s[i]),.cout(co[i])); end endgenerate assign cout = co[n-1]; endmodule 18
Sumator 7-bitowy symulacja 19
Sumator 7-bitowy realizacja w fpga 20
Sumator 7-bitowy realizacja z komponenem fa V IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY rca_fa IS GENERIC (n : INTEGER := 7); PORT ( a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); EN rca_fa; ARCITECTURE rca_arch OF rca_fa IS COMPONENT fa IS PORT ( a, b, cin : IN ST_OGIC; s, cout : OUT ST_OGIC); EN COMPONENT fa; SIGNA c : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA cin : ST_OGIC; BEGIN cin <= '0'; fa0: fa PORT MAP (a => a(0), b => b(0), cin => cin, s => s(0), cout => c(0)); fa_n: FOR i IN n-1 OWNTO 1 GENERATE fa_i: fa PORT MAP (a => a(i), b => b(i), cin => c(i-1), s => s(i), cout => c(i)); EN GENERATE; cout <= c(n-1); dr inŝ. Paweł EN rca_arch; Tomaszewicz 21
Sumator 7-bitowy realizacja z komponenem fa V IBRARY ieee; USE ieee.std_logic_1164.a; PACKAGE fa_package IS COMPONENT fa IS PORT ( a, b, cin : IN ST_OGIC; s, cout : OUT ST_OGIC); EN COMPONENT fa; EN fa_package; IBRARY work; USE work.fa_package.a; IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY rca_fa IS GENERIC (n : INTEGER := 7); PORT ( a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); EN rca_fa; ARCITECTURE rca_arch OF rca_fa IS SIGNA c : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA cin : ST_OGIC; BEGIN dr inŝ. Paweł... Tomaszewicz 22
Sumator 7-bitowy realizacja z komponenem fa Verilog // n-bit adder Ripple-Carry Adder // using FA component //'include "fa.v" module rca_fa (a, b, s, cout); parameter n=7; input [n-1:0] a, b; output [n-1:0] s; output cout; wire [n-1:0] c; fa fa_0 (.a(a[0]),.b(b[0]),.cin(0),.s(s[0]),.cout(c[0])); genvar i; generate for (i = 1; i < n; i=i+1) begin : rca_adder fa fa_i (.a(a[i]),.b(b[i]),.cin(c[i-1]),.s(s[i]),.cout(c[i])); end endgenerate endmodule assign cout = c[n-1]; 23
Sumator 7-bitowy z rejestrami na we/wy V ENTITY rca_r IS... ARCITECTURE rca_arch OF rca_r IS BEGIN SIGNA c : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA a_r, b_r, s_r : ST_OGIC_VECTOR(n-1 OWNTO 0); Reg: PROCESS (clk) BEGIN EN rca_arch; IF clk'event AN (clk = '1') TEN EN IF; a_r <= a; b_r <= b; s <= s_r; EN PROCESS Reg; cout <= c(n-1); s_r(0) <= a_r(0) XOR b_r(0); c(0) <= (a_r(0) AN b_r(0)); cra_n: FOR i IN n-1 OWNTO 1 GENERATE s_r(i) <= a_r(i) XOR b_r(i) XOR c(i-1); 7-bitowy RCA c(i) <= (a_r(i) AN b_r(i)) OR (a_r(i) AN c(i-1)) OR (b_r(i) AN c(i-1)); EN GENERATE; C (carry) * 29 f [Mz] / t_clk [ns] 65,36 / 15,3 C (bez carry) ** 27 f [Mz] / t_clk [ns] 42,55 / 23,5 * Z komponentem CARRY_SUM ** Bez Rejestry na wejściu i wyjściu bloku pozwalają na oszacowanie szybkości działania bloku wewnątrz układu FPGA, bez opóźnień związanych z logiką we/wy 24
Sumator 7-bitowy parameter n=7; input z [n-1:0] rejestrami a, b; na we/wy Verilog // n-bit adder Ripple-Carry Adder module rca_r_1 (a, b, s, cout, clk); input clk; output [n-1:0] s; output cout; reg [n-1:0] a_r, b_r, s; reg cout; wire [n-1:0] s_r; wire [n-1:0] c; always @(posedge clk) begin a_r <= a; b_r <= b; s <= s_r; cout <= c[n-1]; end assign s_r[0] = a_r[0] ^ b_r[0]; assign c[0] = a_r[0] & b_r[0]; genvar i; generate for (i = 1; i < n; i=i+1) begin : rca_adder assign s_r[i] = a_r[i] ^ b_r[i] ^ c[i-1]; assign c[i] = a_r[i] & b_r[i] a_r[i] & c[i-1] b_r[i] & c[i-1]; end endgenerate endmodule 25
Sumator 8n+7- bitowy Opóźnienia liniowo związane z długością sumatora komórek f [Mz] t_clk [ns] 15bit 61 53,19 18,8 23bit 93 45,05 22,2 31bit 125 38,91 25,7 39bit 157 34,25 29,2 47bit 189 30,58 32,7 55bit 221 27,62 36,2 la układu FEX10K70RC240 moŝna zbudować maks. sumator 55-bitowy, poniewaŝ uŝyty układ ma dostępnych 183 nóŝki dla uŝytkownika (55+55+56=166); la sumatora 63-bitowego mamy 63+63+64=190 + 1 bit zegara i juŝ się nie zmieścił ze względu na liczbę nóŝek; Teoretycznie moŝna zbudować łańcuch Carry o długości 13x8=104, bo 52 kolumny, w połówce układu jest 26 kolumn, uŝyta co druga kolumna, czyli dostępnych13, stąd moŝliwy do zbudowania sumator 8 x n+7=103 bity) 26
Sumator potokowy A + B = S 27
Sumator 15-bitowy potokowy V (1) IBRARY work; USE work.rca_package.a; IBRARY ieee; USE ieee.std_logic_1164.a; ENTITY rca_pipe IS GENERIC (n : INTEGER := 15; n7 : INTEGER := 7; n8 : INTEGER := 8); PORT (clk : IN ST_OGIC; a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); EN rca_pipe; ARCITECTURE rca_arch OF rca_pipe IS SIGNA r0_00, r0_01, r1_0, r2_0, s0 : ST_OGIC_VECTOR(n8-1 OWNTO 0); SIGNA r0_10, r0_11, r1_10, r1_11, r2_1, s1: ST_OGIC_VECTOR(n7-1 OWNTO 0); SIGNA c0, c1, cr0, cr1 : ST_OGIC; 28
BEGIN PROCESS BEGIN Sumator 15-bitowy potokowy V (2) WAIT UNTI clk='1'; FOR k IN n8-1 OWNTO 0 OOP r0_00(k) <= a(k); r0_01(k) <= b(k); EN OOP; FOR k IN n7-1 OWNTO 0 OOP -- 1st level add_lsb: rca GENERIC MAP (n => n8) PORT MAP (a => r0_00, b => r0_01, s => s0, cout => c0); r0_10(k) <= a(k+n8); -- 2nd level r0_11(k) <= b(k+n8); EN OOP; add_msb: rca_in GENERIC MAP (n => n7) PORT MAP (a => r1_10, b => r1_11, EN PROCESS; cin => cr0, s => s1, cout => c1); Reg: PROCESS (clk) s(n8-1 OWNTO 0) <= r2_0(n8-1 OWNTO 0); BEGIN s(n7-1+n8 OWNTO n8) <= r2_1(n7-1 OWNTO 0); IF clk'event AN (clk = '1') TEN cout <= cr1; r1_10 <= r0_10; EN rca_arch; r1_11 <= r0_11; r2_0 <= r1_0; r1_0 <= s0; r2_1 <= s1; cr0 <= c0; cr1 <= c1; EN IF; EN PROCESS Reg; 29
Sumator 15-bitowy potokowy Verilog // 15-bit pipeline adder //'include "rca.v" //'include "rca_in.v" module rca_pipe (clk, a, b, s, cout); parameter n=15; parameter n7=7; parameter n8=8; input clk; input [n-1:0] a, b; output [n-1:0] s; output cout; reg [n8-1:0] r0_00, r0_01, r1_0, r2_0, s0; reg [n7-1:0] r0_10, r0_11, r1_10, r1_11, r2_1, s1; reg c0, c1, cr0, cr1; always @(posedge clk) begin r0_00 <= a[n8-1:0]; r0_01 <= b[n8-1:0]; r0_10 <= a[n7-1+n8:n8]; r0_11 <= b[n7-1+n8:n8]; end Przykład przekazania parametru przez konkretyzację // 1st level always @(posedge clk) // registers begin end r1_0 <= s0; r1_10 <= r0_10; r1_11 <= r0_11; cr0 <= c0; r2_0 <= r1_0; r2_1 <= s1; cr1 <= c1; //rca add_lsb (.a(r0_00),.b(r0_01),.s(s0),.cout(c0)); // defparam add_lsb.n=n8; rca #(n8) add_lsb (.a(r0_00),.b(r0_01),.s(s0),.cout(c0)); // 2nd level //rca_in add_msb (.a(r1_10),.b(r1_11),.cin(cr0),.s(s1),.cout(c1)); // defparam add_msb.n=n7; rca_in #(n7) add_msb (.a(r1_10),.b(r1_11),.cin(cr0),.s(s1),.cout(c1)); // output endmodule assign s[n8-1:0] = r2_0[n8-1:0]; assign s[n7-1+n8:n8] = r2_1[n7-1:0]; assign cout = cr1; 30
Sumator 15-bitowy potokowy - symulacja C 86 FF 69 f [Mz] 49,02 t_clk [ns] 20,4 31
Sumator 8n+7 potokowy N = 47 W = 8 Potokowość: zyskujemy na przepustowości, tracimy na uŝytych zasobach 32
Sumator 8n+7 RCA potokowy vs kombinacyjny stopni potoku komórek przerzutników f [Mz] t_clk [ns] 15bit 2 86 69 49,02 20,4 23bit 3 167 140 48,78 20,5 31bit 4 272 235 48,08 20,8 39bit 5 401 354 48,54 20,6 47bit 6 554 497 47,17 21,2 15bit - 61 46 53,19 18,8 23bit - 93 70 45,05 22,2 31bit - 125 94 38,91 25,7 39bit - 157 118 34,25 29,2 47bit - 189 142 30,58 32,7 Wyniki uzyskane dla układów z rejestrami na wejściu i wyjściu Wyniki uzyskane dla układów z rejestrami na wejściu i wyjściu oraz oraz z z wykorzystaniem wykorzystaniem szybkich szybkich łańcuchów łańcuchów Carry Carry 33
Sumator 15-bitowy potokowy PM V -- n-bit adder using PM IBRARY ieee; USE ieee.std_logic_1164.a; IBRARY lpm; USE lpm.lpm_components.a; ENTITY rca_lpm IS GENERIC (n : INTEGER := 15); PORT (clk : IN ST_OGIC; a, b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); cout : OUT ST_OGIC); EN rca_lpm; ARCITECTURE rca_arch OF cra_lpm IS SIGNA a_r, b_r : ST_OGIC_VECTOR(n-1 OWNTO 0); BEGIN Reg: PROCESS (clk) BEGIN IF clk'event AN (clk = '1') TEN a_r <= a; b_r <= b; EN IF; EN PROCESS Reg; add: lpm_add_sub GENERIC MAP (PM_WIT => n, PM_REPRESENTATION => "UNSIGNE", PM_IRECTION => "A", PM_PIPEINE => 2) PORT MAP (dataa => a_r, datab => b_r, result => s, cout => cout, clock => clk); EN rca_arch; 34
Sumator 15-bitowy potokowy PM Verilog // n-bit adder using PM module rca_lpm (clk, a, b, s, cout); parameter n = 47; input clk; input [n-1:0] a, b; output [n-1:0] s; output cout; reg [n-1:0] a_r, b_r; always @(posedge clk) // registers begin a_r <= a; b_r <= b; end lpm_add_sub fa_lpm (.dataa(a_r),.datab(b_r),.result(s),.cout(cout),.clock(clk)); defparam fa_lpm.lpm_width=n; defparam fa_lpm.lpm_representtion="unsigned"; defparam fa_lpm.lpm_direction="add"; defparam fa_lpm.lpm_pipeline=6; endmodule 35
Sumator 15-bitowy potokowy PM - symulacja C 71 FF 65 f [Mz] 99,01 t_clk [s] 10,1 36
Sumator potokowy PM - koszt stopni potoku komórek przerzutników f [Mz] t_clk [ns] 15bit 1 55 47 84,75 11,8 2 71 65 99,01 10,01 23bit 1 83 71 76,92 13,0 2 105 97 84,03 11,9 3 130 124 84,75 11,8 31bit 1 111 95 65,36 15,3 2 140 129 68,49 14,6 3 172 164 84,03 11,9 4 207 200 82,64 12,1 39 bit 1 139 119 60,61 16,5 2 175 161 64,52 15,5 3 214 204 79,37 12,6 4 256 248 74,07 13,5 5 300 293 78,74 12,7 47 bit 6 410 403 75,19 13,3 37
Sumator Carry ook-ahead Adder W sumatorze z przeniesieniami równoległymi wszystkie przeniesienia są wytwarzane jednocześnie na podstawie bitów sumowanych składników. s i = a i b i c i c i+1 = a i b i + a i c i + b i c i = a i b i + c i (a i + b i ) G i = a i b i (generacja przeniesienia) P i = a i + b i (propagacja przeniesienia) Wtedy: c i+1 = G i + c i P i 38
Realizacja sumatora Carry ook-ahead Adder V (1) IBRARY ieee; USE ieee.std_logic_1164.a; Argorytm CA nie jest stosowany w układach fpga, poniewaŝ są zaimplementowane specjalne linie szybkiego przeniesienia Carry ENTITY c_l_addr IS GENERIC (n : INTEGER := 7); PORT ( a : IN ST_OGIC_VECTOR(n-1 OWNTO 0); b : IN ST_OGIC_VECTOR(n-1 OWNTO 0); carry_in : IN ST_OGIC; s : OUT ST_OGIC_VECTOR(n-1 OWNTO 0); carry_out : OUT ST_OGIC ); EN c_l_addr; 39
Realizacja sumatora Carry ook-ahead Adder V (2) ARCITECTURE behavioral OF c_l_addr IS SIGNA h_sum : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA carry_generate : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA carry_propagate : ST_OGIC_VECTOR(n-1 OWNTO 0); SIGNA carry_in_internal : ST_OGIC_VECTOR(n-1 OWNTO 1); BEGIN h_sum <= a XOR b; carry_generate <= a AN b; carry_propagate <= a OR b; PROCESS (carry_generate,carry_propagate,carry_in_internal,carry_in) BEGIN carry_in_internal(1) <= carry_generate(0) OR (carry_propagate(0) AN carry_in); inst: FOR i IN 1 TO n-2 OOP carry_in_internal(i+1) <= carry_generate(i) OR (carry_propagate(i) AN carry_in_internal(i)); EN OOP; carry_out <= carry_generate(n-1) OR (carry_propagate(n-1) AN carry_in_internal(n-1)); EN PROCESS; s(0) <= h_sum(0) XOR carry_in; s(n-1 OWNTO 1) <= h_sum(n-1 OWNTO 1) XOR carry_in_internal(n-1 OWNTO 1); EN behavioral; 40
Realizacja sumatora Carry ook-ahead Adder Verilog // carry look-ahead adder module c_l_addr (a, b, carry_in, s, carry_out); parameter n=7; input [n-1:0] a,b; input carry_in; output [n-1:0] s; output carry_out; wire [n-1:0] h_sum; wire [n-1:0] carry_generate; wire [n-1:0] carry_propagate; wire [n-1:0] carry_in_internal; assign h_sum = a ^ b; assign carry_generate = a & b; assign carry_propagate = a b; assign carry_in_internal[1] = carry_generate[0] (carry_propagate[0] & carry_in); genvar i; generate for (i = 1; i <= n-2; i=i+1) begin : l_a_adder assign carry_in_internal[i+1] = carry_generate[i] (carry_propagate[i] & carry_in_internal[i]); end endgenerate assign carry_out = carry_generate[n-1] (carry_propagate[n-1] & carry_in_internal[n-1]); assign s[0] = h_sum[0] ^ carry_in; assign s[n-1:1] = h_sum[n-1:1] ^ carry_in_internal[n-1:1]; dr inŝ. endmodule Paweł Tomaszewicz 41