//======================================================================
//
// Copyright: 2019, The Commons Conservancy Cryptech Project
// SPDX-License-Identifier: BSD-3-Clause
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//======================================================================
module modexpng_wrapper
(
input clk,
input rst_n,
input clk_core,
input cs,
input we,
input [11:0] address,
input [31:0] write_data,
output [31:0] read_data
);
//
// Headers
//
`include "modexpng_parameters.vh"
//
// Address Decoder
//
localparam ADDR_MSB_WRAP = 2'b00;
wire [1:0] addr_msb = address[11:10];
wire [9:0] addr_lsb = address[ 9: 0];
wire addr_msb_is_wrap = addr_msb == ADDR_MSB_WRAP;
//
// Register Addresses
//
localparam ADDR_NAME0 = 10'h000;
localparam ADDR_NAME1 = 10'h001;
localparam ADDR_VERSION = 10'h002;
localparam ADDR_CONTROL = 10'h008; // {next, init}
localparam ADDR_STATUS = 10'h009; // {valid, ready}
localparam ADDR_MODE = 10'h010; // {crt, dummy}
localparam ADDR_MODULUS_BITS = 10'h011; // number of bits in modulus
localparam ADDR_EXPONENT_BITS = 10'h012; // number of bits in exponent
localparam ADDR_BANK_BITS = 10'h013; // largest supported number of bits
localparam ADDR_NUM_MULTS = 10'h014; // number of parallel multipliers
//
// Register Bits
//
// localparam CONTROL_INIT_BIT = 0; -- not used
localparam CONTROL_NEXT_BIT = 1;
// localparam STATUS_READY_BIT = 0; -- hardcoded to always read 1
localparam STATUS_VALID_BIT = 1;
// localparam MODE_FASTUNSAFE_BIT = 0; - not used
localparam MODE_FULLCRT_BIT = 1;
//
// Default Values
//
`define MODEXPNG_DEFAULT_NAME0 32'h6D6F6465 // "mode"
`define MODEXPNG_DEFAULT_NAME1 32'h78706E67 // "xpng"
`define MODEXPNG_DEFAULT_VERSION 32'h302E3231 // "0.21"
`define MODEXPNG_DEFAULT_CONTROL 1'b0
`define MODEXPNG_DEFAULT_MODE 1'b0
`define MODEXPNG_DEFAULT_MODULUS_BITS 13'd1024
`define MODEXPNG_DEFAULT_EXPONENT_BITS 13'd17
//
// Handy Values
//
localparam MIN_OP_W = 2 * NUM_MULTS * WORD_W * 2;
localparam MIN_EXP_W = 2 * 2;
localparam LSB_BIT_INDEX_W = 1 + cryptech_clog2(NUM_MULTS) + cryptech_clog2(WORD_W);
localparam MSB_BIT_INDEX_W = BIT_INDEX_W - LSB_BIT_INDEX_W;
//
// Register Values
//
localparam CORE_NAME0 = `MODEXPNG_DEFAULT_NAME0;
localparam CORE_NAME1 = `MODEXPNG_DEFAULT_NAME1;
localparam CORE_VERSION = `MODEXPNG_DEFAULT_VERSION;
//
// Registers
//
reg wrap_reg_control = `MODEXPNG_DEFAULT_CONTROL;
reg core_reg_control = `MODEXPNG_DEFAULT_CONTROL;
reg wrap_reg_mode = `MODEXPNG_DEFAULT_MODE;
reg sync_reg_mode;
reg core_reg_mode;
reg [BIT_INDEX_W:LSB_BIT_INDEX_W] wrap_modulus_bits_msb;
reg [BIT_INDEX_W: 0] wrap_exponent_bits;
initial update_modulus_bits_user;
initial update_exponent_bits_user;
//wire sync_reg_control_rising = sync_reg_control & ~sync_reg_control_dly;
//
// Wires
//
reg wrap_reg_status = 1'b1;
reg sync_reg_status = 1'b1;
reg sync_reg_status_dly = 1'b1;
wire core_reg_status;
//
// Output Mux
//
reg [31: 0] wrap_read_data;
wire [31: 0] core_read_data;
//
// Reset Resync
//
wire core_rst_n;
reg [15: 0] core_rst_shreg = {16{1'b0}};
always @(posedge clk_core or negedge rst_n)
//
if (!rst_n) core_rst_shreg <= {16{1'b0}};
else core_rst_shreg <= {core_rst_shreg[14:0], 1'b1};
assign core_rst_n = core_rst_shreg[15];
//
// Trigger Logic
//
reg wrap_reg_control_dly = `MODEXPNG_DEFAULT_CONTROL;
reg wrap_reg_control_posedge = 1'b0;
reg sync_reg_control_posedge = 1'b0;
reg core_reg_control_posedge = 1'b0;
reg core_reg_control_posedge_dly = 1'b0;
reg sync_reg_control_posedge_ack = 1'b0;
reg wrap_reg_control_posedge_ack = 1'b0;
always @(posedge clk or negedge rst_n)
if (!rst_n) wrap_reg_control_dly <= `MODEXPNG_DEFAULT_CONTROL;
else wrap_reg_control_dly <= wrap_reg_control;
always @(posedge clk or negedge rst_n)
if (!rst_n) wrap_reg_control_posedge <= 1'b0;
else begin
if (!wrap_reg_control_posedge) begin
if (wrap_reg_control && !wrap_reg_control_dly) wrap_reg_control_posedge <= 1'b1;
end else begin
if (wrap_reg_control_posedge_ack) wrap_reg_control_posedge <= 1'b0;
end
end
always @(posedge clk_core or negedge core_rst_n)
if (!core_rst_n) sync_reg_control_posedge <= 1'b0;
else sync_reg_control_posedge <= wrap_reg_control_posedge;
always @(posedge clk_core or negedge core_rst_n)
if (!core_rst_n) core_reg_control_posedge <= 1'b0;
else core_reg_control_posedge <= sync_reg_control_posedge;
always @(posedge clk_core or negedge core_rst_n)
if (!core_rst_n) core_reg_control_posedge_dly <= 1'b0;
else core_reg_control_posedge_dly <= core_reg_control_posedge;
always @(posedge clk or negedge rst_n)
if (!rst_n) sync_reg_control_posedge_ack <= 1'b0;
else sync_reg_control_posedge_ack <= core_reg_control_posedge;
always @(posedge clk or negedge rst_n)
if (!rst_n) wrap_reg_control_posedge_ack <= 1'b0;
else wrap_reg_control_posedge_ack <= sync_reg_control_posedge_ack;
always @(posedge clk_core or negedge core_rst_n)
if (!core_rst_n) core_reg_control <= `MODEXPNG_DEFAULT_CONTROL;
else core_reg_control <= core_reg_control_posedge && !core_reg_control_posedge_dly;
always @(posedge clk or negedge rst_n)
if (!rst_n) sync_reg_status <= 1'b1;
else sync_reg_status <= core_reg_status;
always @(posedge clk or negedge rst_n)
if (!rst_n) sync_reg_status_dly <= 1'b1;
else sync_reg_status_dly <= sync_reg_status;
always @(posedge clk or negedge rst_n)
if (!rst_n) wrap_reg_status <= 1'b1;
else begin
if (wrap_reg_status) begin
if (wrap_reg_control && !wrap_reg_control_dly) wrap_reg_status <= 1'b0;
end else begin
if (!wrap_reg_control_posedge && !wrap_reg_control_posedge_ack && sync_reg_status_dly) wrap_reg_status <= 1'b1;
end
end
//
// Parameters Resync
//
reg [OP_ADDR_W -1:0] wrap_word_index_last_n;
reg [OP_ADDR_W -1:0] wrap_word_index_last_pq;
reg [BIT_INDEX_W -1:0] wrap_bit_index_last_n;
reg [BIT_INDEX_W -1:0] wrap_bit_index_last_pq;
reg [OP_ADDR_W -1:0] sync_word_index_last_n;
reg [OP_ADDR_W -1:0] sync_word_index_last_pq;
reg [BIT_INDEX_W -1:0] sync_bit_index_last_n;
reg [BIT_INDEX_W -1:0] sync_bit_index_last_pq;
reg [OP_ADDR_W -1:0] core_word_index_last_n;
reg [OP_ADDR_W -1:0] core_word_index_last_pq;
reg [BIT_INDEX_W -1:0] core_bit_index_last_n;
reg [BIT_INDEX_W -1:0] core_bit_index_last_pq;
always @(posedge clk_core) begin
//
sync_reg_mode <= wrap_reg_mode;
//
sync_word_index_last_n <= wrap_word_index_last_n;
sync_word_index_last_pq <= wrap_word_index_last_pq;
//
sync_bit_index_last_n <= wrap_bit_index_last_n;
sync_bit_index_last_pq <= wrap_bit_index_last_pq;
//
end
always @(posedge clk_core)
//
if (core_reg_control_posedge && !core_reg_control_posedge_dly) begin
//
core_reg_mode <= sync_reg_mode;
//
core_word_index_last_n <= sync_word_index_last_n;
core_word_index_last_pq <= sync_word_index_last_pq;
//
core_bit_index_last_n <= sync_bit_index_last_n;
core_bit_index_last_pq <= sync_bit_index_last_pq;
//
end
//
// ModExpNG
//
modexpng_core_top modexpng
(
.clk (clk_core),
.clk_bus (clk),
.rst_n (core_rst_n),
.next (core_reg_control),
.valid (core_reg_status),
.crt_mode (core_reg_mode),
.word_index_last_n (core_word_index_last_n),
.word_index_last_pq (core_word_index_last_pq),
.bit_index_last_n (core_bit_index_last_n),
.bit_index_last_pq (core_bit_index_last_pq),
.bus_cs (cs),
.bus_we (we),
.bus_addr (address),
.bus_data_wr (write_data),
.bus_data_rd (core_read_data)
);
//
// Write Interface
//
wire [ BIT_INDEX_W :0] corrected_modulus_bits_user = correct_modulus_bits(write_data[BIT_INDEX_W:0]);
wire [MSB_BIT_INDEX_W :0] corrected_modulus_bits_msb_user = corrected_modulus_bits_user[BIT_INDEX_W:LSB_BIT_INDEX_W];
wire [ OP_ADDR_W :0] modulus_num_words_n_user = {corrected_modulus_bits_msb_user, {(LSB_BIT_INDEX_W-WORD_MUX_W){1'b0}}} - 1'b1;
wire [ OP_ADDR_W-1:0] modulus_num_words_n_lsb_user = modulus_num_words_n_user[OP_ADDR_W-1:0];
wire [ OP_ADDR_W-1:0] modulus_num_words_pq_user = {corrected_modulus_bits_msb_user, {(LSB_BIT_INDEX_W-WORD_MUX_W-1){1'b0}}} - 1'b1;
wire [ BIT_INDEX_W :0] corrected_modulus_bits_default = `MODEXPNG_DEFAULT_MODULUS_BITS;
wire [MSB_BIT_INDEX_W :0] corrected_modulus_bits_msb_default = corrected_modulus_bits_default[BIT_INDEX_W:LSB_BIT_INDEX_W];
wire [ OP_ADDR_W :0] modulus_num_words_n_default = {corrected_modulus_bits_msb_default, {(LSB_BIT_INDEX_W-WORD_MUX_W){1'b0}}} - 1'b1;
wire [ OP_ADDR_W-1:0] modulus_num_words_n_lsb_default = modulus_num_words_n_default[OP_ADDR_W-1:0];
wire [ OP_ADDR_W-1:0] modulus_num_words_pq_default = {corrected_modulus_bits_msb_default, {(LSB_BIT_INDEX_W-WORD_MUX_W-1){1'b0}}} - 1'b1;
wire [ BIT_INDEX_W :0] corrected_exponent_bits_user = correct_exponent_bits(write_data[BIT_INDEX_W:0]);
wire [ BIT_INDEX_W-1:0] corrected_exponent_bits_msb_user = corrected_exponent_bits_user[BIT_INDEX_W:1];
wire [ BIT_INDEX_W :0] exponent_num_bits_n_user = corrected_exponent_bits_user - 1'b1;
wire [ BIT_INDEX_W-1:0] exponent_num_bits_n_lsb_user = exponent_num_bits_n_user[BIT_INDEX_W-1:0];
wire [ BIT_INDEX_W-1:0] exponent_num_bits_pq_user = corrected_exponent_bits_msb_user - 1'b1;
wire [ BIT_INDEX_W :0] corrected_exponent_bits_default = `MODEXPNG_DEFAULT_EXPONENT_BITS;
wire [ BIT_INDEX_W-1:0] corrected_exponent_bits_msb_default = corrected_exponent_bits_default[BIT_INDEX_W:1];
wire [ BIT_INDEX_W :0] exponent_num_bits_n_default = corrected_exponent_bits_default - 1'b1;
wire [ BIT_INDEX_W-1:0] exponent_num_bits_n_lsb_default = exponent_num_bits_n_default[BIT_INDEX_W-1:0];
wire [ BIT_INDEX_W-1:0] exponent_num_bits_pq_default = corrected_exponent_bits_msb_default - 1'b1;
task update_modulus_bits_user;
begin
wrap_modulus_bits_msb <= corrected_modulus_bits_msb_user;
wrap_word_index_last_n <= modulus_num_words_n_lsb_user;
wrap_word_index_last_pq <= modulus_num_words_pq_user;
end
endtask
task update_modulus_bits_default;
begin
wrap_modulus_bits_msb <= corrected_modulus_bits_msb_default;
wrap_word_index_last_n <= modulus_num_words_n_lsb_default;
wrap_word_index_last_pq <= modulus_num_words_pq_default;
end
endtask
task update_exponent_bits_user;
begin
wrap_exponent_bits <= corrected_exponent_bits_user;
wrap_bit_index_last_n <= exponent_num_bits_n_lsb_user;
wrap_bit_index_last_pq <= exponent_num_bits_pq_user;
end
endtask
task update_exponent_bits_default;
begin
wrap_exponent_bits <= corrected_exponent_bits_default;
wrap_bit_index_last_n <= exponent_num_bits_n_lsb_default;
wrap_bit_index_last_pq <= exponent_num_bits_pq_default;
end
endtask
always @(posedge clk or negedge rst_n)
//
if (!rst_n) begin
//
wrap_reg_control <= `MODEXPNG_DEFAULT_CONTROL;
wrap_reg_mode <= `MODEXPNG_DEFAULT_MODE;
//
update_modulus_bits_default;
update_exponent_bits_default;
//
end else if (cs && we && addr_msb_is_wrap)
//
case (addr_lsb)
ADDR_CONTROL: wrap_reg_control <= write_data[CONTROL_NEXT_BIT];
ADDR_MODE: wrap_reg_mode <= write_data[MODE_FULLCRT_BIT];
ADDR_MODULUS_BITS: update_modulus_bits_user;
ADDR_EXPONENT_BITS: update_exponent_bits_user;
endcase
//
// Only accept correct modulus width
//
function [BIT_INDEX_W:0] correct_modulus_bits;
input [BIT_INDEX_W:0] width;
if (width < MIN_OP_W) correct_modulus_bits = MIN_OP_W;
else if (width > MAX_OP_W) correct_modulus_bits = MAX_OP_W;
else correct_modulus_bits = width;
endfunction
//
// Only accept correct exponent width
//
function [BIT_INDEX_W:0] correct_exponent_bits;
input [BIT_INDEX_W:0] width;
if (width < MIN_EXP_W) correct_exponent_bits = MIN_EXP_W;
else if (width > MAX_OP_W ) correct_exponent_bits = MAX_OP_W;
else correct_exponent_bits = width;
endfunction
//
// Read Interface
//
always @(posedge clk)
//
if (cs && addr_msb_is_wrap)
//
case (address)
//
ADDR_NAME0: wrap_read_data <= CORE_NAME0;
ADDR_NAME1: wrap_read_data <= CORE_NAME1;
ADDR_VERSION: wrap_read_data <= CORE_VERSION;
ADDR_CONTROL: wrap_read_data <= {{30{1'b0}}, wrap_reg_control, 1'b0};
ADDR_STATUS: wrap_read_data <= {{30{1'b0}}, wrap_reg_status, 1'b1};
//
ADDR_MODE: wrap_read_data <= {{30{1'b0}}, wrap_reg_mode, 1'b0};
ADDR_MODULUS_BITS: wrap_read_data <= {{(31-BIT_INDEX_W){1'b0}}, wrap_modulus_bits_msb, {LSB_BIT_INDEX_W{1'b0}}};
ADDR_EXPONENT_BITS: wrap_read_data <= {{(31-BIT_INDEX_W){1'b0}}, wrap_exponent_bits};
ADDR_BANK_BITS: wrap_read_data <= MAX_OP_W;
ADDR_NUM_MULTS: wrap_read_data <= NUM_MULTS;
//
default: wrap_read_data <= 32'h00000000;
//
endcase
//
// Register / Core Memory Selector
//
reg [1:0] addr_msb_last;
wire addr_msb_last_is_wrap = addr_msb_last == ADDR_MSB_WRAP;
always @(posedge clk)
addr_msb_last <= addr_msb;
assign read_data = addr_msb_last_is_wrap ? wrap_read_data : core_read_data;
endmodule