diff --git a/ip_cores/ec/src/rtl/ec_fe2_mul.sv b/ip_cores/ec/src/rtl/ec_fe2_mul_s.sv similarity index 90% rename from ip_cores/ec/src/rtl/ec_fe2_mul.sv rename to ip_cores/ec/src/rtl/ec_fe2_mul_s.sv index cfb51f0..191c520 100644 --- a/ip_cores/ec/src/rtl/ec_fe2_mul.sv +++ b/ip_cores/ec/src/rtl/ec_fe2_mul_s.sv @@ -1,7 +1,8 @@ /* - This provides the interface to perform Fp2 field element mul. Using karabusta algorithm. + This provides the interface to perform Fp2 field element mul. Inputs must be interleaved starting at c0 (i.e. clock 0 = {b.c0, a.c0}) + _s in the name represents the input is a stream starting at c0. Copyright (C) 2019 Benjamin Devlin and Zcash Foundation @@ -19,13 +20,13 @@ along with this program. If not, see . */ -module ec_fe2_mul +module ec_fe2_mul_s #( parameter type FE_TYPE, // Base field element type parameter CTL_BITS = 12 )( input i_clk, i_rst, - // Interface to FE(P)_TYPE adder (mod P) 2*FE_TYPE data width + // Interface to FE2_TYPE mul (mod P) 2*FE_TYPE data width if_axi_stream.source o_mul_fe2_if, if_axi_stream.sink i_mul_fe2_if, // Interface to FE_TYPE mul (mod P) 2*FE_TYPE data width @@ -46,7 +47,7 @@ logic out_cnt; // Point addtions are simple additions on each of the Fp elements always_comb begin i_mul_fe2_if.rdy = (mul_cnt == 0 || mul_cnt == 1) && (~o_mul_fe_if.val || (o_mul_fe_if.val && o_mul_fe_if.rdy)); - i_mul_fe_if.rdy = (add_sub_cnt == 0 || add_sub_cnt == 1) ? ~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy) : + i_mul_fe_if.rdy = (add_sub_cnt == 0 || add_sub_cnt == 1) ? ~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy) : ~o_add_fe_if.val || (o_add_fe_if.val && o_add_fe_if.rdy); i_add_fe_if.rdy = out_cnt == 1 && (~o_mul_fe2_if.val || (o_mul_fe2_if.val && o_mul_fe2_if.rdy)); i_sub_fe_if.rdy = out_cnt == 0 && (~o_mul_fe2_if.val || (o_mul_fe2_if.val && o_mul_fe2_if.rdy)); @@ -76,14 +77,14 @@ always_ff @ (posedge i_clk) begin o_mul_fe_if.dat <= i_mul_fe2_if.dat; // a0 * b0 o_mul_fe_if.val <= i_mul_fe2_if.val; o_mul_fe_if.ctl <= i_mul_fe2_if.ctl; - {b, a} <= i_mul_fe2_if.dat; + {b, a} <= i_mul_fe2_if.dat; if (i_mul_fe2_if.val) mul_cnt <= mul_cnt + 1; end end 1: begin if (~o_mul_fe_if.val || (o_mul_fe_if.val && o_mul_fe_if.rdy)) begin o_mul_fe_if.dat <= i_mul_fe2_if.dat; // a1 * b1 - o_mul_fe_if.val <= i_mul_fe2_if.val; + o_mul_fe_if.val <= i_mul_fe2_if.val; if (i_mul_fe2_if.val) mul_cnt <= mul_cnt + 1; end end @@ -108,7 +109,7 @@ always_ff @ (posedge i_clk) begin case(add_sub_cnt) 0: begin if (~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy)) begin - o_sub_fe_if.dat[0 +: $bits(FE_TYPE)] <= i_mul_fe_if.dat; + o_sub_fe_if.dat[0 +: $bits(FE_TYPE)] <= i_mul_fe_if.dat; if (i_mul_fe_if.val) add_sub_cnt <= add_sub_cnt + 1; end end @@ -126,7 +127,7 @@ always_ff @ (posedge i_clk) begin if (i_mul_fe_if.val) add_sub_cnt <= add_sub_cnt + 1; end end - 3: begin + 3: begin o_add_fe_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)] <= i_mul_fe_if.dat; o_add_fe_if.ctl <= i_mul_fe_if.ctl; // a1b0 + a0b1 if (i_mul_fe_if.val) begin @@ -135,7 +136,7 @@ always_ff @ (posedge i_clk) begin end end endcase - + case(out_cnt) 0: begin if (~o_mul_fe2_if.val || (o_mul_fe2_if.val && o_mul_fe2_if.rdy)) begin diff --git a/ip_cores/ec/src/rtl/ec_fe6_mul_s.sv b/ip_cores/ec/src/rtl/ec_fe6_mul_s.sv new file mode 100644 index 0000000..6afccb6 --- /dev/null +++ b/ip_cores/ec/src/rtl/ec_fe6_mul_s.sv @@ -0,0 +1,312 @@ +/* + This provides the interface to perform Fp6 field element mul. Using karabusta algorithm. + Because of feedback path we can lockup if there are not enough pipelines for fe2_sub/ fe2_add. + + Inputs must be interleaved starting at c0 (i.e. clock 0 = {b.c0, a.c0}) + _s in the name represents the input is a stream starting at c0. + + Copyright (C) 2019 Benjamin Devlin and Zcash Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +module ec_fe6_mul_s +#( + parameter type FE_TYPE, // Base field element type + parameter type FE2_TYPE, // Fp6 is towered over Fp2 + parameter type FE6_TYPE, // Fp6 is towered over Fp2 + parameter CTL_BITS = 12, + parameter OVR_WRT_BIT = 0 +)( + input i_clk, i_rst, + // Interface to FE2_TYPE multiplier (mod P), 2*FE_TYPE data width + if_axi_stream.source o_mul_fe2_if, + if_axi_stream.sink i_mul_fe2_if, + // Interface to FE_TYPE adder (mod P), 2*FE_TYPE data width + if_axi_stream.source o_add_fe_if, + if_axi_stream.sink i_add_fe_if, + // Interface to FE_TYPE subtractor (mod P), 2*FE_TYPE data width + if_axi_stream.source o_sub_fe_if, + if_axi_stream.sink i_sub_fe_if, + // Interface to FE2_TYPE multiply by non-residue, FE_TYPE data width + if_axi_stream.source o_mnr_fe2_if, + if_axi_stream.sink i_mnr_fe2_if, + // Interface to FE6_TYPE multiplier (mod P), 2*FE_TYPE data width + if_axi_stream.source o_mul_fe6_if, + if_axi_stream.sink i_mul_fe6_if +); + +localparam CNT_BITS = 5; +localparam NUM_OVR_WRT = $clog2((1 << CNT_BITS)/2); // Only need half the bits for control + +// Multiplications are calculated using the formula in bls12_381.pkg::fe6_mul() +// Need storage to latch input stream +// a_a is a[2], b_b is a[1], c_c is a[0] +FE6_TYPE a, b; +FE_TYPE t; + +logic [CNT_BITS-1:0] add_cnt, sub_cnt, mul_cnt, mnr_cnt, out_cnt; +logic start; + +always_comb begin + + i_mul_fe6_if.rdy = (start == 0) && (~o_mul_fe2_if.val || (o_mul_fe2_if.val & o_mul_fe2_if.rdy)); + + case (i_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT]) inside + 0,1,2: i_mul_fe2_if.rdy = 1; + 3,4,5: i_mul_fe2_if.rdy = ~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy); + default: i_mul_fe2_if.rdy = 0; + endcase + + case (i_add_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT]) inside + 0,1,2,3,4,5: i_add_fe_if.rdy = ~o_mul_fe2_if.val || (o_mul_fe2_if.val & o_mul_fe2_if.rdy); + 6: i_add_fe_if.rdy = 1; + 7: i_add_fe_if.rdy = (~o_mul_fe6_if.val || (o_mul_fe6_if.val && o_mul_fe6_if.rdy)); + 8: i_add_fe_if.rdy = (~o_mul_fe6_if.val || (o_mul_fe6_if.val && o_mul_fe6_if.rdy)); + default: i_add_fe_if.rdy = 0; + endcase + + case (i_sub_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT]) inside + 0,1: i_sub_fe_if.rdy = (sub_cnt/2 > 2) && (~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy)); + 2: i_sub_fe_if.rdy = (~o_add_fe_if.val || (o_add_fe_if.val && o_add_fe_if.rdy)); + 3: i_sub_fe_if.rdy = (~o_mnr_fe2_if.val || (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy)); + 4: i_sub_fe_if.rdy = 1; + 5: i_sub_fe_if.rdy = (out_cnt/2 == 2) && (~o_mul_fe6_if.val || (o_mul_fe6_if.val && o_mul_fe6_if.rdy)); + default: i_sub_fe_if.rdy = 0; + endcase + + case (i_mnr_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT]) inside + 0: i_mnr_fe2_if.rdy = (add_cnt/2 == 7) && (~o_add_fe_if.val || (o_add_fe_if.val && o_add_fe_if.rdy)); + 1: i_mnr_fe2_if.rdy = (add_cnt/2 == 8) && (~o_add_fe_if.val || (o_add_fe_if.val && o_add_fe_if.rdy)); + default: i_mnr_fe2_if.rdy = 0; + endcase + + +end + +always_ff @ (posedge i_clk) begin + if (i_rst) begin + o_mul_fe6_if.reset_source(); + o_mnr_fe2_if.reset_source(); + o_mul_fe2_if.reset_source(); + o_sub_fe_if.reset_source(); + o_add_fe_if.reset_source(); + + add_cnt <= 0; + sub_cnt <= 0; + mul_cnt <= 0; + mnr_cnt <= 0; + out_cnt <= 0; + + a <= 0; + b <= 0; + t <= 0; + + start <= 0; + end else begin + + if (o_mul_fe6_if.rdy) o_mul_fe6_if.val <= 0; + if (o_mul_fe2_if.rdy) o_mul_fe2_if.val <= 0; + if (o_sub_fe_if.rdy) o_sub_fe_if.val <= 0; + if (o_add_fe_if.rdy) o_add_fe_if.val <= 0; + if (o_mnr_fe2_if.rdy) o_mnr_fe2_if.val <= 0; + + // Latch some results temp + if (i_add_fe_if.val && i_add_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 6) begin + b[0] <= {i_add_fe_if.dat, b[0][1]}; + end + + if (i_sub_fe_if.val && i_sub_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 4) begin + b[1] <= {i_sub_fe_if.dat, b[1][1]}; + end + + // Latch multiplier results of a_a, b_b, c_c + if (i_mul_fe2_if.val && i_mul_fe2_if.rdy && i_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] < 3) begin + a <= {i_mul_fe2_if.dat, {a[2], a[1], a[0][1]}}; + end + + if (i_mul_fe6_if.rdy && i_mul_fe6_if.eop && i_mul_fe6_if.val) + start <= 1; + + // Multiplier input flow + case (mul_cnt) inside + 0,1,2,3,4,5: begin // Calculates a_a, b_b, c_c + fe2_mul(i_mul_fe6_if.val, i_mul_fe6_if.dat[0 +: $bits(FE_TYPE)], + i_mul_fe6_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)], mul_cnt); + + if (i_mul_fe6_if.val && i_mul_fe6_if.rdy) begin + a <= {i_mul_fe6_if.dat[0 +: $bits(FE_TYPE)], a[2], a[1], a[0][1]}; + b <= {i_mul_fe6_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)], b[2], b[1], b[0][1]}; + end + end + 6,10,14: begin + // Store result into multiplier and temp - calculates fe6_mul[0] / fe6_mul[1] / fe6_mul[2] + if (i_add_fe_if.val && i_add_fe_if.rdy) begin + o_mul_fe2_if.dat[0 +: $bits(FE_TYPE)] <= i_add_fe_if.dat; + o_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= o_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] + 1; + mul_cnt <= mul_cnt + 1; + end + end + 7,11,15: begin + if (i_add_fe_if.val && i_add_fe_if.rdy) begin + t <= i_add_fe_if.dat; + mul_cnt <= mul_cnt + 1; + end + end + 8,12,16: begin + if (i_add_fe_if.val && i_add_fe_if.rdy) begin // .rdy takes into account the multiplier output state + o_mul_fe2_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)] <= i_add_fe_if.dat; + o_mul_fe2_if.sop <= 1; + o_mul_fe2_if.eop <= 0; + o_mul_fe2_if.val <= 1; + mul_cnt <= mul_cnt + 1; + end + end + 9,13,17: begin + if (i_add_fe_if.val && i_add_fe_if.rdy) begin + o_mul_fe2_if.dat <= {i_add_fe_if.dat, t}; + o_mul_fe2_if.sop <= 0; + o_mul_fe2_if.eop <= 1; + o_mul_fe2_if.val <= 1; + mul_cnt <= mul_cnt + 1; + end + end + default: if (start==0) mul_cnt <= 0; + endcase + + // Adder input flow + case (add_cnt) inside + 0,1: fe2_add(start, a[1][add_cnt%2], a[2][add_cnt%2], add_cnt); + 2,3: fe2_add(start, b[1][add_cnt%2], b[2][add_cnt%2], add_cnt); + 4,5: fe2_add(start, b[0][add_cnt%2], b[1][add_cnt%2], add_cnt); + 6,7: fe2_add(start, a[0][add_cnt%2], a[1][add_cnt%2], add_cnt); + 8,9: fe2_add(start, b[0][add_cnt%2], b[2][add_cnt%2], add_cnt); + 10,11: fe2_add(start, a[0][add_cnt%2], a[2][add_cnt%2], add_cnt); + 12,13: fe2_add(i_sub_fe_if.val && i_sub_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 2 , i_sub_fe_if.dat, a[1][add_cnt%2], add_cnt); + 14,15: fe2_add(i_mnr_fe2_if.val, i_mnr_fe2_if.dat, a[0][add_cnt%2], add_cnt); + 16,17: fe2_add(i_mnr_fe2_if.val, b[1][add_cnt%2], i_mnr_fe2_if.dat, add_cnt); + default: if (start==0) add_cnt <= 0; + endcase + + // Sub input flow + case (sub_cnt) inside + 0,1: fe2_sub(i_mul_fe2_if.val && i_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 3, i_mul_fe2_if.dat, a[1][sub_cnt%2], sub_cnt); + 2,3: fe2_sub(i_mul_fe2_if.val, i_mul_fe2_if.dat, a[1][sub_cnt%2], sub_cnt); + 4,5: fe2_sub(i_mul_fe2_if.val, i_mul_fe2_if.dat, a[0][sub_cnt%2], sub_cnt); + 6,7: fe2_sub(i_sub_fe_if.val, i_sub_fe_if.dat, a[2][sub_cnt%2], sub_cnt); + 8,9: fe2_sub(i_sub_fe_if.val, i_sub_fe_if.dat, a[0][sub_cnt%2], sub_cnt); + 10,11: fe2_sub(add_cnt >= 18, b[0][sub_cnt%2], a[2][sub_cnt%2], sub_cnt); + default: if (start==0) sub_cnt <= 0; + endcase + + // mnr flow + case (mnr_cnt) inside + 0,1: fe2_mnr(i_sub_fe_if.val && i_sub_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 3, i_sub_fe_if.dat, mnr_cnt); + 2,3: fe2_mnr(1, a[2][mnr_cnt%2], mnr_cnt); + default: if (start==0) mnr_cnt <= 0; + endcase + + // Final output flow + if (~o_mul_fe6_if.val || (o_mul_fe6_if.val && o_mul_fe6_if.rdy)) begin + case (out_cnt) inside + 0,1: begin + o_mul_fe6_if.dat <= i_add_fe_if.dat; + o_mul_fe6_if.ctl <= i_add_fe_if.ctl; + o_mul_fe6_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= 0; + o_mul_fe6_if.sop <= out_cnt == 0; + o_mul_fe6_if.eop <= 0; + if (i_add_fe_if.val && i_add_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] == 7) begin + o_mul_fe6_if.val <= 1; + out_cnt <= out_cnt + 1; + end + end + 2,3: begin + o_mul_fe6_if.dat <= i_add_fe_if.dat; + o_mul_fe6_if.sop <= 0; + o_mul_fe6_if.eop <= 0; + if (i_add_fe_if.val) begin + o_mul_fe6_if.val <= 1; + out_cnt <= out_cnt + 1; + end + end + 4,5: begin + o_mul_fe6_if.dat <= i_sub_fe_if.dat; + o_mul_fe6_if.sop <= 0; + o_mul_fe6_if.eop <= out_cnt == 5; + if (i_sub_fe_if.val) begin + o_mul_fe6_if.val <= 1; + out_cnt <= out_cnt + 1; + end + end + default: begin + out_cnt <= 0; + start <= 0; + end + endcase + end + + + end +end + +// Task for fe2_mul +task automatic fe2_mul(input logic val, input logic [$bits(FE_TYPE)-1:0] a, b, ref [CNT_BITS-1:0] cnt); + if (~o_mul_fe2_if.val || (o_mul_fe2_if.val && o_mul_fe2_if.rdy)) begin + o_mul_fe2_if.sop <= val ? ~o_mul_fe2_if.sop : o_mul_fe2_if.sop; + o_mul_fe2_if.eop <= val ? o_mul_fe2_if.sop : o_mul_fe2_if.eop; + o_mul_fe2_if.dat <= {b, a}; + o_mul_fe2_if.val <= val; + o_mul_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= cnt / 2; + if (val) cnt = cnt + 1; + end +endtask + +// Task for fe2_add +task automatic fe2_add(input logic val, input logic [$bits(FE_TYPE)-1:0] a, b, ref [CNT_BITS-1:0] cnt); + if (~o_add_fe_if.val || (o_add_fe_if.val && o_add_fe_if.rdy)) begin + o_add_fe_if.sop <= val ? ~o_add_fe_if.sop : o_add_fe_if.sop; + o_add_fe_if.eop <= val ? o_add_fe_if.sop : o_add_fe_if.eop; + o_add_fe_if.dat <= {b, a}; + o_add_fe_if.val <= val; + o_add_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= cnt / 2; + if (val) cnt = cnt + 1; + end +endtask + +// Task for fe2_sub +task automatic fe2_sub(input logic val, input logic [$bits(FE_TYPE)-1:0] a, b, ref [CNT_BITS-1:0] cnt); + if (~o_sub_fe_if.val || (o_sub_fe_if.val && o_sub_fe_if.rdy)) begin + o_sub_fe_if.sop <= val ? ~o_sub_fe_if.sop : o_sub_fe_if.sop; + o_sub_fe_if.eop <= val ? o_sub_fe_if.sop : o_sub_fe_if.eop; + o_sub_fe_if.dat <= {b, a}; + o_sub_fe_if.val <= val; + o_sub_fe_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= cnt / 2; + if (val) cnt = cnt + 1; + end +endtask + +// Task for fe2_mnr +task automatic fe2_mnr(input logic val, input logic [$bits(FE_TYPE)-1:0] a, ref [CNT_BITS-1:0] cnt); + if (~o_mnr_fe2_if.val || (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy)) begin + o_mnr_fe2_if.sop <= val ? ~o_mnr_fe2_if.sop : o_mnr_fe2_if.sop; + o_mnr_fe2_if.eop <= val ? o_mnr_fe2_if.sop : o_mnr_fe2_if.eop; + o_mnr_fe2_if.dat <= {b, a}; + o_mnr_fe2_if.val <= val; + o_mnr_fe2_if.ctl[OVR_WRT_BIT +: NUM_OVR_WRT] <= cnt / 2; + if (val) cnt = cnt + 1; + end +endtask + + +endmodule \ No newline at end of file diff --git a/ip_cores/ec/src/rtl/fe2_mul_by_nonresidue_s.sv b/ip_cores/ec/src/rtl/fe2_mul_by_nonresidue_s.sv new file mode 100644 index 0000000..dd6f4cc --- /dev/null +++ b/ip_cores/ec/src/rtl/fe2_mul_by_nonresidue_s.sv @@ -0,0 +1,89 @@ +/* + Multiplies by non-residue for Fp2 towering. + _s in the name represents the input is a stream starting at c0. + + Copyright (C) 2019 Benjamin Devlin and Zcash Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +module fe2_mul_by_nonresidue_s +#( + parameter type FE_TYPE +)( + input i_clk, i_rst, + if_axi_stream.source o_mnr_fe2_if, + if_axi_stream.sink i_mnr_fe2_if, // Input is multiplied by non residue + if_axi_stream.source o_add_fe_if, + if_axi_stream.sink i_add_fe_if, + if_axi_stream.source o_sub_fe_if, + if_axi_stream.sink i_sub_fe_if +); + +logic add_sub_cnt; +always_comb begin + i_mnr_fe2_if.rdy = (~o_add_fe_if.val || (o_add_fe_if.rdy && o_add_fe_if.val)) && (~o_sub_fe_if.val || (o_sub_fe_if.rdy && o_sub_fe_if.val)); + i_add_fe_if.rdy = add_sub_cnt == 1 && (~o_mnr_fe2_if.val || (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy)); + i_sub_fe_if.rdy = add_sub_cnt == 0 && (~o_mnr_fe2_if.val || (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy)); +end + +always_ff @ (posedge i_clk) begin + if (i_rst) begin + o_mnr_fe2_if.reset_source(); + o_add_fe_if.copy_if(0, 0, 1, 1, 0, 0, 0); + o_sub_fe_if.copy_if(0, 0, 1, 1, 0, 0, 0); + add_sub_cnt <= 0; + end else begin + + if (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy) o_mnr_fe2_if.val <= 0; + + if (i_mnr_fe2_if.rdy) begin + if (i_mnr_fe2_if.sop) begin + o_add_fe_if.dat[0 +: $bits(FE_TYPE)] <= i_mnr_fe2_if.dat; + o_sub_fe_if.dat[0 +: $bits(FE_TYPE)] <= i_mnr_fe2_if.dat; + end else begin + o_add_fe_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)] <= i_mnr_fe2_if.dat; + o_sub_fe_if.dat[$bits(FE_TYPE) +: $bits(FE_TYPE)] <= i_mnr_fe2_if.dat; + end + o_add_fe_if.val <= i_mnr_fe2_if.val && i_mnr_fe2_if.rdy && i_mnr_fe2_if.eop; + o_add_fe_if.ctl <= i_mnr_fe2_if.ctl; + o_sub_fe_if.val <= i_mnr_fe2_if.val && i_mnr_fe2_if.rdy && i_mnr_fe2_if.eop; + o_sub_fe_if.ctl <= i_mnr_fe2_if.ctl; + end + + if (~o_mnr_fe2_if.val || (o_mnr_fe2_if.val && o_mnr_fe2_if.rdy)) begin + case(add_sub_cnt) + 0: begin + o_mnr_fe2_if.dat <= i_sub_fe_if.dat; + o_mnr_fe2_if.ctl <= i_sub_fe_if.ctl; + o_mnr_fe2_if.val <= i_sub_fe_if.val; + o_mnr_fe2_if.sop <= 1; + o_mnr_fe2_if.eop <= 0; + if (i_sub_fe_if.val) + add_sub_cnt <= add_sub_cnt + 1; + end + 1: begin + o_mnr_fe2_if.dat <= i_add_fe_if.dat; + o_mnr_fe2_if.ctl <= i_add_fe_if.ctl; + o_mnr_fe2_if.val <= i_add_fe_if.val; + o_mnr_fe2_if.sop <= 0; + o_mnr_fe2_if.eop <= 1; + if (i_add_fe_if.val) + add_sub_cnt <= add_sub_cnt + 1; + end + endcase + end + end +end +endmodule \ No newline at end of file diff --git a/ip_cores/ec/src/tb/ec_fe6_mul_s_tb.sv b/ip_cores/ec/src/tb/ec_fe6_mul_s_tb.sv new file mode 100644 index 0000000..b3f565d --- /dev/null +++ b/ip_cores/ec/src/tb/ec_fe6_mul_s_tb.sv @@ -0,0 +1,246 @@ +/* + Copyright (C) 2019 Benjamin Devlin and Zcash Foundation + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +`timescale 1ps/1ps + +module ec_fe6_mul_tb (); + +import common_pkg::*; +import bls12_381_pkg::*; + +parameter type FE_TYPE = bls12_381_pkg::fe_t; +parameter type FE2_TYPE = bls12_381_pkg::fe2_t; +parameter type FE6_TYPE = bls12_381_pkg::fe6_t; +parameter P = bls12_381_pkg::P; + + +localparam CTL_BITS = 32; + +localparam CLK_PERIOD = 100; + +logic clk, rst; + +initial begin + rst = 0; + repeat(2) #(20*CLK_PERIOD) rst = ~rst; +end + +initial begin + clk = 0; + forever #(CLK_PERIOD/2) clk = ~clk; +end + +if_axi_stream #(.DAT_BITS(2*$bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mul_fe_o_if (clk); +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mul_fe_i_if (clk); +if_axi_stream #(.DAT_BITS(2*$bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) add_fe_o_if [3:0] (clk); +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) add_fe_i_if [3:0] (clk); +if_axi_stream #(.DAT_BITS(2*$bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) sub_fe_o_if [3:0] (clk); +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) sub_fe_i_if [3:0] (clk); + +if_axi_stream #(.DAT_BITS(2*$bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mul_fe2_o_if (clk); +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mul_fe2_i_if (clk); + +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mnr_fe2_o_if (clk); +if_axi_stream #(.DAT_BITS($bits(FE_TYPE)), .CTL_BITS(CTL_BITS)) mnr_fe2_i_if (clk); + +if_axi_stream #(.DAT_BYTS(($bits(FE_TYPE)+7)/8), .CTL_BITS(CTL_BITS)) o_mul_fe6_if (clk); +if_axi_stream #(.DAT_BYTS((2*$bits(FE_TYPE)+7)/8), .CTL_BITS(CTL_BITS)) i_mul_fe6_if (clk); + +ec_fp_mult_mod #( + .P ( P ), + .KARATSUBA_LVL ( 3 ), + .CTL_BITS ( CTL_BITS ) +) +ec_fp_mult_mod ( + .i_clk( clk ), + .i_rst( rst ), + .i_mul ( mul_fe_o_if ), + .o_mul ( mul_fe_i_if ) +); + +adder_pipe # ( + .BITS ( bls12_381_pkg::DAT_BITS ), + .P ( P ), + .CTL_BITS ( CTL_BITS ), + .LEVEL ( 2 ) +) +adder_pipe ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_add ( add_fe_o_if[3] ), + .o_add ( add_fe_i_if[3] ) +); + +subtractor_pipe # ( + .BITS ( bls12_381_pkg::DAT_BITS ), + .P ( P ), + .CTL_BITS ( CTL_BITS ), + .LEVEL ( 2 ) +) +subtractor_pipe ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_sub ( sub_fe_o_if[3] ), + .o_sub ( sub_fe_i_if[3] ) +); + +ec_fe2_mul_s #( + .FE_TYPE ( FE_TYPE ), + .CTL_BITS ( CTL_BITS ) +) +ec_fe2_mul_s ( + .i_clk ( clk ), + .i_rst ( rst ), + .o_mul_fe2_if ( mul_fe2_i_if ), + .i_mul_fe2_if ( mul_fe2_o_if ), + .o_add_fe_if ( add_fe_o_if[0] ), + .i_add_fe_if ( add_fe_i_if[0] ), + .o_sub_fe_if ( sub_fe_o_if[0] ), + .i_sub_fe_if ( sub_fe_i_if[0] ), + .o_mul_fe_if ( mul_fe_o_if ), + .i_mul_fe_if ( mul_fe_i_if ) +); + +fe2_mul_by_nonresidue_s #( + .FE_TYPE ( FE_TYPE ) +) +fe2_mul_by_nonresidue_s ( + .i_clk ( clk ), + .i_rst ( rst ), + .o_mnr_fe2_if ( mnr_fe2_i_if ), + .i_mnr_fe2_if ( mnr_fe2_o_if ), + .o_add_fe_if ( add_fe_o_if[1] ), + .i_add_fe_if ( add_fe_i_if[1] ), + .o_sub_fe_if ( sub_fe_o_if[1] ), + .i_sub_fe_if ( sub_fe_i_if[1] ) +); + +ec_fe6_mul_s #( + .FE_TYPE ( FE_TYPE ), + .FE2_TYPE ( FE2_TYPE ), + .FE6_TYPE ( FE6_TYPE ), + .CTL_BITS ( CTL_BITS ), + .OVR_WRT_BIT ( 0 ) +) +ec_fe6_mul_s ( + .i_clk ( clk ), + .i_rst ( rst ), + .o_mul_fe2_if ( mul_fe2_o_if ), + .i_mul_fe2_if ( mul_fe2_i_if ), + .o_add_fe_if ( add_fe_o_if[2] ), + .i_add_fe_if ( add_fe_i_if[2] ), + .o_sub_fe_if ( sub_fe_o_if[2] ), + .i_sub_fe_if ( sub_fe_i_if[2] ), + .o_mnr_fe2_if ( mnr_fe2_o_if ), + .i_mnr_fe2_if ( mnr_fe2_i_if), + .o_mul_fe6_if ( o_mul_fe6_if ), + .i_mul_fe6_if ( i_mul_fe6_if ) +); + +resource_share # ( + .NUM_IN ( 3 ), + .DAT_BITS ( 2*$bits(FE_TYPE) ), + .CTL_BITS ( CTL_BITS ), + .OVR_WRT_BIT ( 8 ), + .PIPELINE_IN ( 2 ), + .PIPELINE_OUT ( 2 ) +) +resource_share_fe_add ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_axi ( add_fe_o_if[2:0] ), + .o_res ( add_fe_o_if[3] ), + .i_res ( add_fe_i_if[3] ), + .o_axi ( add_fe_i_if[2:0] ) +); + +resource_share # ( + .NUM_IN ( 3 ), + .DAT_BITS ( 2*$bits(FE_TYPE) ), + .CTL_BITS ( CTL_BITS ), + .OVR_WRT_BIT ( 8 ), + .PIPELINE_IN ( 2 ), + .PIPELINE_OUT ( 2 ) +) +resource_share_fe_sub ( + .i_clk ( clk ), + .i_rst ( rst ), + .i_axi ( sub_fe_o_if[2:0] ), + .o_res ( sub_fe_o_if[3] ), + .i_res ( sub_fe_i_if[3] ), + .o_axi ( sub_fe_i_if[2:0] ) +); + +task test(); + fe6_t a, b, f_exp, f_exp2, f_out; + integer signed get_len; + integer start_time, finish_time; + logic [common_pkg::MAX_SIM_BYTS*8-1:0] get_dat, dat_in; + + $display("Running test ..."); + for (int i = 0; i < 10; i++) begin + $display("Loop %d", i); + dat_in = 0; + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) begin + a[j][k] = random_vector(384/8) % P; + b[j][k] = random_vector(384/8) % P; + dat_in[(j*2+k)*768 +: 2*$bits(FE_TYPE)] = {b[j][k], a[j][k]}; + end + + f_exp = fe6_mul(a, b); + + start_time = $time; + fork + i_mul_fe6_if.put_stream(dat_in, 6*768/8); + o_mul_fe6_if.get_stream(get_dat, get_len); + join + finish_time = $time; + + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + f_out[j][k] = get_dat[(j*2+k)*384 +: $bits(FE_TYPE)]; + + if (f_exp != f_out) begin + $display("Input a was:"); + print_fe6(a); + $display("Input b was:"); + print_fe6(b); + $display("Output was:"); + print_fe6(f_out); + $display("Output Expected:"); + print_fe6(f_exp); + $fatal(1, "%m %t ERROR: output was wrong", $time); + end + + $display("test PASSED in %d clocks", (finish_time-start_time)/CLK_PERIOD); + end + +endtask + + + +initial begin + i_mul_fe6_if.reset_source(); + o_mul_fe6_if.rdy = 0; + #10ns; + + test(); + + #50ns $finish(); +end + +endmodule \ No newline at end of file diff --git a/ip_cores/ec/src/tb/ec_fp6_arithmetic_tb.sv b/ip_cores/ec/src/tb/ec_fp6_arithmetic_tb.sv index 7f6f90c..7c0be93 100644 --- a/ip_cores/ec/src/tb/ec_fp6_arithmetic_tb.sv +++ b/ip_cores/ec/src/tb/ec_fp6_arithmetic_tb.sv @@ -65,7 +65,7 @@ end initial begin clk = 0; - forever #CLK_PERIOD clk = ~clk; + forever #(CLK_PERIOD/2) clk = ~clk; end ec_fe2_arithmetic #(