top level for the bls12-381 core
This commit is contained in:
parent
4068dec4df
commit
df2ca6fdac
|
@ -44,7 +44,7 @@ interface if_axi_stream # (
|
|||
import task reset_source(),
|
||||
import task copy_if(dat_, val_, sop_, eop_, err_, mod_, ctl_),
|
||||
import task copy_if_comb(dat_, val_, sop_, eop_, err_, mod_, ctl_),
|
||||
import task set_mod_from_keep(keep));
|
||||
import task set_mod_from_keep(keep));
|
||||
|
||||
// Task to reset a source interface signals to all 0
|
||||
task reset_source();
|
||||
|
@ -81,7 +81,7 @@ interface if_axi_stream # (
|
|||
mod = 0;
|
||||
for (int i = 0; i < DAT_BYTS; i++)
|
||||
if (keep[i])
|
||||
mod += 1;
|
||||
mod += 1;
|
||||
endtask
|
||||
|
||||
|
||||
|
@ -244,4 +244,25 @@ interface if_ram # (
|
|||
d <= 0;
|
||||
endtask
|
||||
|
||||
task automatic write_data(input logic [$clog2(RAM_DEPTH)-1:0] addr,
|
||||
input logic [common_pkg::MAX_SIM_BYTS*8-1:0] data);
|
||||
|
||||
integer len_bits = $clog2(data);
|
||||
|
||||
@(posedge i_clk);
|
||||
a = addr;
|
||||
while (len_bits > 0) begin
|
||||
en = 1;
|
||||
we = 1;
|
||||
re = 0;
|
||||
d = data;
|
||||
data = data >> RAM_WIDTH;
|
||||
@(posedge i_clk); // Go to next clock edge
|
||||
len_bits = len_bits > RAM_WIDTH ? len_bits - RAM_WIDTH : 0;
|
||||
a = a + 1;
|
||||
end
|
||||
en = 0;
|
||||
we = 0;
|
||||
endtask
|
||||
|
||||
endinterface
|
||||
|
|
|
@ -34,7 +34,7 @@ end
|
|||
|
||||
always_comb begin
|
||||
if_ram_a.a = reset_done ? a.a : addr;
|
||||
if_ram_a.en = a.en;
|
||||
if_ram_a.en = reset_done ? a.en : 1'd1;
|
||||
if_ram_a.we = reset_done ? a.we : 1'd1;
|
||||
if_ram_a.re = a.re;
|
||||
if_ram_a.d = reset_done ? a.d : {RAM_WIDTH{1'd0}};
|
||||
|
|
|
@ -16,25 +16,24 @@ module uram_reset #(
|
|||
if_ram.sink b
|
||||
);
|
||||
|
||||
if_ram #(.RAM_WIDTH(a.RAM_WIDTH), .RAM_DEPTH(a.RAM_DEPTH)) if_ram_a(.i_clk(a.i_clk), .i_rst(a.i_rst));
|
||||
if_ram #(.RAM_WIDTH(RAM_WIDTH), .RAM_DEPTH(RAM_DEPTH)) if_ram_a(.i_clk(a.i_clk), .i_rst(a.i_rst));
|
||||
|
||||
logic reset_done;
|
||||
logic [$clog2(RAM_WIDTH)-1:0] addr;
|
||||
logic [RAM_DEPTH-1:0] addr;
|
||||
|
||||
always_ff @ (posedge a.i_clk) begin
|
||||
if (a.i_rst) begin
|
||||
reset_done <= 0;
|
||||
addr <= 0;
|
||||
end else begin
|
||||
addr <= addr + 1;
|
||||
if (&addr)
|
||||
reset_done <= 1;
|
||||
if (&addr) reset_done <= 1;
|
||||
if (~reset_done) addr <= addr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
if_ram_a.a = reset_done ? a.a : addr;
|
||||
if_ram_a.en = a.en;
|
||||
if_ram_a.en = reset_done ? a.en : 1'd1;
|
||||
if_ram_a.we = reset_done ? a.we : 1'd1;
|
||||
if_ram_a.re = a.re;
|
||||
if_ram_a.d = reset_done ? a.d : {RAM_WIDTH{1'd0}};
|
||||
|
|
|
@ -24,12 +24,36 @@ package bls12_381_pkg;
|
|||
localparam [DAT_BITS-1:0] Gx = 381'h17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB;
|
||||
localparam [DAT_BITS-1:0] Gy = 381'h08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1;
|
||||
|
||||
// Jacobian coordinates
|
||||
|
||||
|
||||
// Jacobian coordinates for Fp elements
|
||||
typedef struct packed {
|
||||
logic [DAT_BITS-1:0] x, y, z;
|
||||
} jb_point_t;
|
||||
|
||||
jb_point_t g_point = {x:Gx, y:Gy, z:1};
|
||||
// Jacobian coordinates for Fp^2 elements
|
||||
typedef struct packed {
|
||||
jb_point_t fp1_a, fp1_b;
|
||||
} fp2_jb_point_t;
|
||||
|
||||
// Instruction codes
|
||||
typedef enum logic [7:0] {
|
||||
NOOP_WAIT = 8'h0,
|
||||
FP_POINT_MULT = 8'h20
|
||||
} code_t;
|
||||
|
||||
// Instruction format
|
||||
typedef struct packed {
|
||||
logic [15:0] c, b, a;
|
||||
code_t code;
|
||||
} inst_t;
|
||||
|
||||
localparam DATA_RAM_WIDTH = 381;
|
||||
localparam DATA_RAM_DEPTH = $clog2(64);
|
||||
localparam INST_RAM_WIDTH = $bits(inst_t);
|
||||
localparam INST_RAM_DEPTH = $clog2(1024);
|
||||
|
||||
jb_point_t g_point = '{x:Gx, y:Gy, z:1};
|
||||
|
||||
function is_zero(jb_point_t p);
|
||||
is_zero = (p.x == 0 && p.y == 0 && p.z == 1);
|
||||
|
@ -72,11 +96,11 @@ package bls12_381_pkg;
|
|||
if (p1.y == p2.y && p1.x == p2.x)
|
||||
return (dbl_jb_point(p1));
|
||||
|
||||
U1 = p1.x*p2.z % P;
|
||||
U1 = U1*p2.z % P;
|
||||
U1 = (p1.x*p2.z) % P;
|
||||
U1 = (U1*p2.z) % P;
|
||||
|
||||
U2 = p2.x*p1.z % P;
|
||||
U2 = U2 *p1.z % P;
|
||||
U2 = (p2.x*p1.z) % P;
|
||||
U2 = (U2 *p1.z) % P;
|
||||
S1 = p1.y *p2.z % P;
|
||||
S1 = (S1*p2.z % P) *p2.z % P;
|
||||
S2 = p2.y * p1.z % P;
|
||||
|
@ -102,6 +126,20 @@ package bls12_381_pkg;
|
|||
|
||||
endfunction
|
||||
|
||||
function jb_point_t point_mult(logic [DAT_BITS-1:0] c, jb_point_t p);
|
||||
jb_point_t result, addend;
|
||||
result = 0;
|
||||
addend = p;
|
||||
while (c > 0) begin
|
||||
if (c[0]) begin
|
||||
result = add_jb_point(result, addend);
|
||||
end
|
||||
addend = dbl_jb_point(addend);
|
||||
c = c >> 1;
|
||||
end
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
function on_curve(jb_point_t p);
|
||||
return (p.y*p.y - p.x*p.x*p.x - secp256k1_pkg::a*p.x*p.z*p.z*p.z*p.z - secp256k1_pkg::b*p.z*p.z*p.z*p.z*p.z*p.z);
|
||||
endfunction
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
This module is the top level for the BLS12-381 coprocessor.
|
||||
Runs on instruction memory and has access to slot memory.
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module bls12_381_top
|
||||
import bls12_381_pkg::*;
|
||||
#(
|
||||
)(
|
||||
input i_clk, i_rst,
|
||||
// Only tx interface is used to send messages to SW on a SEND-INTERRUPT instruction
|
||||
if_axi_stream.source tx_if,
|
||||
// User access to the instruction and register RAM
|
||||
if_ram.sink inst_ram_usr_if,
|
||||
if_ram.sink data_ram_usr_if,
|
||||
// Configuration memory
|
||||
if_axi_mm.sink cfg_usr_if
|
||||
);
|
||||
|
||||
localparam DAT_BITS = bls12_381_pkg::DAT_BITS;
|
||||
|
||||
// Instruction RAM
|
||||
localparam INST_READ_CYCLE = 3;
|
||||
logic [INST_READ_CYCLE:0] inst_ram_read;
|
||||
localparam DATA_READ_CYCLE = 3;
|
||||
logic [INST_READ_CYCLE:0] data_ram_read;
|
||||
if_ram #(.RAM_WIDTH(bls12_381_pkg::INST_RAM_WIDTH), .RAM_DEPTH(bls12_381_pkg::INST_RAM_DEPTH)) inst_ram_sys_if(.i_clk(i_clk), .i_rst(i_rst));
|
||||
inst_t curr_inst;
|
||||
|
||||
// Data RAM
|
||||
if_ram #(.RAM_WIDTH(bls12_381_pkg::DATA_RAM_WIDTH), .RAM_DEPTH(bls12_381_pkg::DATA_RAM_DEPTH)) data_ram_sys_if(.i_clk(i_clk), .i_rst(i_rst));
|
||||
|
||||
// Fp point multiplication
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS*3)) fp_pt_mult_in_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS*3)) fp_pt_mult_out_if(i_clk);
|
||||
|
||||
logic [DAT_BITS-1:0] k_fp_in;
|
||||
logic [7:0] cnt;
|
||||
|
||||
always_comb begin
|
||||
curr_inst = inst_ram_sys_if.q;
|
||||
end
|
||||
|
||||
code_t inst_state;
|
||||
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
tx_if.reset_source();
|
||||
inst_ram_sys_if.reset_source();
|
||||
data_ram_sys_if.reset_source();
|
||||
fp_pt_mult_out_if.rdy <= 0;
|
||||
fp_pt_mult_in_if.reset_source();
|
||||
inst_ram_read <= 0;
|
||||
data_ram_read <= 0;
|
||||
k_fp_in <= 0;
|
||||
cnt <= 0;
|
||||
inst_state <= NOOP_WAIT;
|
||||
end else begin
|
||||
inst_ram_sys_if.re <= 1;
|
||||
inst_ram_sys_if.en <= 1;
|
||||
inst_ram_read <= inst_ram_read << 1;
|
||||
|
||||
data_ram_sys_if.re <= 1;
|
||||
data_ram_sys_if.en <= 1;
|
||||
data_ram_sys_if.we <= 0;
|
||||
data_ram_read <= data_ram_read << 1;
|
||||
|
||||
if (fp_pt_mult_in_if.val && fp_pt_mult_in_if.rdy) fp_pt_mult_in_if.val <= 0;
|
||||
fp_pt_mult_out_if.rdy <= 1;
|
||||
|
||||
case(inst_state)
|
||||
{NOOP_WAIT}: begin
|
||||
// Wait in this state
|
||||
inst_state <= curr_inst.code;
|
||||
end
|
||||
{FP_POINT_MULT}: begin
|
||||
case(cnt) inside
|
||||
0: begin
|
||||
data_ram_sys_if.a <= curr_inst.a;
|
||||
data_ram_read[0] <= 1;
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
1: begin
|
||||
if (data_ram_read[DATA_READ_CYCLE]) begin
|
||||
data_ram_sys_if.a <= curr_inst.b;
|
||||
k_fp_in <= data_ram_sys_if.q;
|
||||
fp_pt_mult_in_if.dat <= bls12_381_pkg::g_point;
|
||||
fp_pt_mult_in_if.val <= 1;
|
||||
data_ram_read[0] <= 1;
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
end
|
||||
// Wait for result
|
||||
2: begin
|
||||
fp_pt_mult_out_if.rdy <= 0;
|
||||
if (fp_pt_mult_out_if.val) begin
|
||||
data_ram_sys_if.d <= fp_pt_mult_out_if.dat;
|
||||
data_ram_sys_if.we <= 1;
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
end
|
||||
3: begin
|
||||
fp_pt_mult_out_if.rdy <= 0;
|
||||
data_ram_sys_if.d <= fp_pt_mult_out_if.dat >> DAT_BITS;
|
||||
data_ram_sys_if.a <= data_ram_sys_if.a + 1;
|
||||
data_ram_sys_if.we <= 1;
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
4: begin
|
||||
data_ram_sys_if.d <= fp_pt_mult_out_if.dat >> (2*DAT_BITS);
|
||||
data_ram_sys_if.we <= 1;
|
||||
data_ram_sys_if.a <= data_ram_sys_if.a + 1;
|
||||
cnt <= cnt + 1;
|
||||
inst_ram_sys_if.a <= inst_ram_sys_if.a + 1;
|
||||
inst_ram_read[0] <= 1;
|
||||
end
|
||||
5: begin
|
||||
if (inst_ram_read[INST_READ_CYCLE]) begin
|
||||
inst_state <= curr_inst.code;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// Configuration registers
|
||||
always_ff @ (posedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
cfg_usr_if.reset_sink();
|
||||
end else begin
|
||||
cfg_usr_if.rd_dat_val <= 0;
|
||||
if (cfg_usr_if.wr) begin
|
||||
|
||||
end
|
||||
if (cfg_usr_if.rd) begin
|
||||
cfg_usr_if.rd_dat_val <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
uram_reset #(
|
||||
.RAM_WIDTH(bls12_381_pkg::INST_RAM_WIDTH),
|
||||
.RAM_DEPTH(bls12_381_pkg::INST_RAM_DEPTH),
|
||||
.PIPELINES( INST_READ_CYCLE - 2 )
|
||||
)
|
||||
inst_uram_reset (
|
||||
.a ( inst_ram_usr_if ),
|
||||
.b ( inst_ram_sys_if )
|
||||
);
|
||||
|
||||
uram_reset #(
|
||||
.RAM_WIDTH(bls12_381_pkg::DATA_RAM_WIDTH),
|
||||
.RAM_DEPTH(bls12_381_pkg::DATA_RAM_DEPTH),
|
||||
.PIPELINES( DATA_READ_CYCLE - 2 )
|
||||
)
|
||||
data_uram_reset (
|
||||
.a ( data_ram_usr_if ),
|
||||
.b ( data_ram_sys_if )
|
||||
);
|
||||
|
||||
// These interfaces are unused
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS*2), .CTL_BITS(16)) mult_in_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS), .CTL_BITS(16)) mult_out_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS*2), .CTL_BITS(16)) add_in_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS), .CTL_BITS(16)) add_out_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS*2), .CTL_BITS(16)) sub_in_if(i_clk);
|
||||
if_axi_stream #(.DAT_BITS(DAT_BITS), .CTL_BITS(16)) sub_out_if(i_clk);
|
||||
|
||||
|
||||
always_comb begin
|
||||
mult_in_if.rdy = 1;
|
||||
mult_out_if.reset_source();
|
||||
add_in_if.rdy = 1;
|
||||
add_out_if.reset_source();
|
||||
sub_in_if.rdy = 1;
|
||||
sub_out_if.reset_source();
|
||||
end
|
||||
|
||||
ec_fp_point_mult #(
|
||||
.P ( bls12_381_pkg::P ),
|
||||
.POINT_TYPE ( bls12_381_pkg::jb_point_t ),
|
||||
.DAT_BITS ( bls12_381_pkg::DAT_BITS ),
|
||||
.RESOURCE_SHARE ("NO")
|
||||
)
|
||||
ec_fp_point_mult (
|
||||
.i_clk ( i_clk ),
|
||||
.i_rst ( i_rst ),
|
||||
.i_p ( fp_pt_mult_in_if.dat ),
|
||||
.i_k ( k_fp_in ),
|
||||
.i_val ( fp_pt_mult_in_if.val ),
|
||||
.o_rdy ( fp_pt_mult_in_if.rdy ),
|
||||
.o_p ( fp_pt_mult_out_if.dat ),
|
||||
.i_rdy ( fp_pt_mult_out_if.rdy ),
|
||||
.o_val ( fp_pt_mult_out_if.val ),
|
||||
.o_err ( fp_pt_mult_out_if.err ),
|
||||
.o_mult_if ( mult_in_if ),
|
||||
.i_mult_if ( mult_out_if ),
|
||||
.o_add_if ( add_in_if ),
|
||||
.i_add_if ( add_out_if ),
|
||||
.o_sub_if ( sub_in_if ),
|
||||
.i_sub_if ( sub_out_if ),
|
||||
.i_p2_val ( 0 ),
|
||||
.i_p2 ( 0 )
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
`timescale 1ps/1ps
|
||||
|
||||
module bls12_381_top_tb ();
|
||||
|
||||
import common_pkg::*;
|
||||
import bls12_381_pkg::*;
|
||||
|
||||
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 clk = ~clk;
|
||||
end
|
||||
|
||||
if_axi_stream #(.DAT_BYTS(8)) out_if(clk);
|
||||
if_ram #(.RAM_WIDTH(bls12_381_pkg::INST_RAM_WIDTH), .RAM_DEPTH(bls12_381_pkg::INST_RAM_DEPTH)) inst_ram_usr_if(.i_clk(clk), .i_rst(rst));
|
||||
if_ram #(.RAM_WIDTH(bls12_381_pkg::DATA_RAM_WIDTH), .RAM_DEPTH(bls12_381_pkg::DATA_RAM_DEPTH)) data_ram_usr_if(.i_clk(clk), .i_rst(rst));
|
||||
if_axi_mm #(.D_BITS(64), .A_BITS(8)) cfg_usr_if(clk);
|
||||
|
||||
bls12_381_top bls12_381_top (
|
||||
.i_clk ( clk ),
|
||||
.i_rst ( rst ),
|
||||
// Only tx interface is used to send messages to SW on a SEND-INTERRUPT instruction
|
||||
.tx_if ( out_if ),
|
||||
// User access to the instruction and register RAM
|
||||
.inst_ram_usr_if ( inst_ram_usr_if ),
|
||||
.data_ram_usr_if ( data_ram_usr_if ),
|
||||
// Configuration memory
|
||||
.cfg_usr_if ( cfg_usr_if )
|
||||
);
|
||||
|
||||
|
||||
task test_0();
|
||||
begin
|
||||
integer signed get_len;
|
||||
logic [common_pkg::MAX_SIM_BYTS*8-1:0] expected, get_dat;
|
||||
inst_t inst;
|
||||
$display("Running test_0...");
|
||||
|
||||
inst = '{code:FP_POINT_MULT, a:0, b:0, c:0};
|
||||
data_ram_usr_if.write_data(0, 100);
|
||||
inst_ram_usr_if.write_data(0, inst);
|
||||
|
||||
$display("test_0 PASSED");
|
||||
end
|
||||
endtask;
|
||||
|
||||
|
||||
initial begin
|
||||
inst_ram_usr_if.reset_source();
|
||||
data_ram_usr_if.reset_source();
|
||||
cfg_usr_if.reset_source();
|
||||
#100ns;
|
||||
// Wait for memories to reset
|
||||
while(!bls12_381_top.inst_uram_reset.reset_done ||
|
||||
!bls12_381_top.data_uram_reset.reset_done)
|
||||
@(posedge clk);
|
||||
|
||||
test_0();
|
||||
|
||||
#1us $finish();
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue