top level for the bls12-381 core

This commit is contained in:
bsdevlin 2019-05-30 21:37:28 +08:00
parent 4068dec4df
commit df2ca6fdac
6 changed files with 384 additions and 15 deletions

View File

@ -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

View File

@ -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}};

View File

@ -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}};

View File

@ -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

View File

@ -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

View File

@ -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