//======================================================================
//
// modexp.v
// --------
// Top level wrapper for the modula exponentiation core. The core
// is used to implement public key algorithms such as RSA,
// DH, ElGamal etc.
//
// The core calculates the following function:
//
// C = M ** e mod N
//
// M is a message with a length of n bits
// e is the exponent with a length of m bits
// N is the modulus with a length of n bits
//
// n can be 32 and up to and including 8192 bits in steps
// of 32 bits.
// m can be one and up to and including 8192 bits in steps
// of 32 bits.
//
// The core has a 32-bit memory like interface, but provides
// status signals to inform the system that a given operation
// has is done. Additionally, any errors will also be asserted.
//
//
// Author: Joachim Strombergson, Peter Magnusson
// Copyright (c) 2015, Assured AB
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 OWNER 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 modexp(
input wire clk,
input wire reset_n,
input wire cs,
input wire we,
input wire [11 : 0] address,
input wire [31 : 0] write_data,
output wire [31 : 0] read_data
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
// The operand width is the internal operand width in bits.
// The address width is the size of the address space used. This
// value must be balances with OPERAND_WIDTH to allow a total
// of 8192 bits of data. OPERAND_WIDTH * (ADDRESS_WIDTH ** 2)
// is the formula. Note that the API data with is always 32 bits.
localparam OPERAND_WIDTH = 32;
localparam ADDRESS_WIDTH = 8;
localparam GENERAL_PREFIX = 4'h0;
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_INIT_BIT = 0;
localparam CTRL_NEXT_BIT = 1;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_CYCLES_HIGH = 8'h10;
localparam ADDR_CYCLES_LOW = 8'h11;
localparam ADDR_MODULUS_LENGTH = 8'h20;
localparam ADDR_EXPONENT_LENGTH = 8'h21;
localparam ADDR_MODULUS_PTR_RST = 8'h30;
localparam ADDR_MODULUS_DATA = 8'h31;
localparam ADDR_EXPONENT_PTR_RST = 8'h40;
localparam ADDR_EXPONENT_DATA = 8'h41;
localparam ADDR_MESSAGE_PTR_RST = 8'h50;
localparam ADDR_MESSAGE_DATA = 8'h51;
localparam ADDR_RESULT_PTR_RST = 8'h60;
localparam ADDR_RESULT_DATA = 8'h61;
localparam DEFAULT_MODLENGTH = 8'h80; // 2048 bits.
localparam DEFAULT_EXPLENGTH = 8'h80;
localparam CORE_NAME0 = 32'h6d6f6465; // "mode"
localparam CORE_NAME1 = 32'h78702020; // "xp "
localparam CORE_VERSION = 32'h302e3532; // "0.52"
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [07 : 0] exponent_length_reg;
reg [07 : 0] exponent_length_new;
reg exponent_length_we;
reg [07 : 0] modulus_length_reg;
reg [07 : 0] modulus_length_new;
reg modulus_length_we;
reg start_reg;
reg start_new;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg exponent_mem_api_rst;
reg exponent_mem_api_cs;
reg exponent_mem_api_wr;
wire [31 : 0] exponent_mem_api_read_data;
reg modulus_mem_api_rst;
reg modulus_mem_api_cs;
reg modulus_mem_api_wr;
wire [31 : 0] modulus_mem_api_read_data;
reg message_mem_api_rst;
reg message_mem_api_cs;
reg message_mem_api_wr;
wire [31 : 0] message_mem_api_read_data;
reg result_mem_api_rst;
reg result_mem_api_cs;
wire [31 : 0] result_mem_api_read_data;
wire ready;
wire [63 : 0] cycles;
reg [31 : 0] tmp_read_data;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign read_data = tmp_read_data;
//----------------------------------------------------------------
// core instantiations.
//----------------------------------------------------------------
modexp_core #(.OPW(OPERAND_WIDTH), .ADW(ADDRESS_WIDTH))
core_inst(
.clk(clk),
.reset_n(reset_n),
.start(start_reg),
.ready(ready),
.exponent_length(exponent_length_reg),
.modulus_length(modulus_length_reg),
.cycles(cycles),
.exponent_mem_api_cs(exponent_mem_api_cs),
.exponent_mem_api_wr(exponent_mem_api_wr),
.exponent_mem_api_rst(exponent_mem_api_rst),
.exponent_mem_api_write_data(write_data),
.exponent_mem_api_read_data(exponent_mem_api_read_data),
.modulus_mem_api_cs(modulus_mem_api_cs),
.modulus_mem_api_wr(modulus_mem_api_wr),
.modulus_mem_api_rst(modulus_mem_api_rst),
.modulus_mem_api_write_data(write_data),
.modulus_mem_api_read_data(modulus_mem_api_read_data),
.message_mem_api_cs(message_mem_api_cs),
.message_mem_api_wr(message_mem_api_wr),
.message_mem_api_rst(message_mem_api_rst),
.message_mem_api_write_data(write_data),
.message_mem_api_read_data(message_mem_api_read_data),
.result_mem_api_cs(result_mem_api_cs),
.result_mem_api_rst(result_mem_api_rst),
.result_mem_api_read_data(result_mem_api_read_data)
);
//----------------------------------------------------------------
// reg_update
//
// Update functionality for all registers in the core.
// All registers are positive edge triggered with asynchronous
// active low reset. All registers have write enable.
//----------------------------------------------------------------
always @ (posedge clk or negedge reset_n)
begin
if (!reset_n)
begin
start_reg <= 1'b0;
exponent_length_reg <= DEFAULT_EXPLENGTH;
modulus_length_reg <= DEFAULT_MODLENGTH;
end
else
begin
start_reg <= start_new;
if (exponent_length_we)
begin
exponent_length_reg <= write_data[7 : 0];
end
if (modulus_length_we)
begin
modulus_length_reg <= write_data[7 : 0];
end
end
end // reg_update
//----------------------------------------------------------------
// api
//
// The interface command decoding logic.
//----------------------------------------------------------------
always @*
begin : api
modulus_length_we = 1'b0;
exponent_length_we = 1'b0;
start_new = 1'b0;
modulus_mem_api_rst = 1'b0;
modulus_mem_api_cs = 1'b0;
modulus_mem_api_wr = 1'b0;
exponent_mem_api_rst = 1'b0;
exponent_mem_api_cs = 1'b0;
exponent_mem_api_wr = 1'b0;
message_mem_api_rst = 1'b0;
message_mem_api_cs = 1'b0;
message_mem_api_wr = 1'b0;
result_mem_api_rst = 1'b0;
result_mem_api_cs = 1'b0;
tmp_read_data = 32'h00000000;
if (cs)
begin
case (address[11 : 8])
GENERAL_PREFIX:
begin
if (we)
begin
case (address[7 : 0])
ADDR_CTRL:
begin
start_new = write_data[0];
end
ADDR_MODULUS_LENGTH:
begin
modulus_length_we = 1'b1;
end
ADDR_EXPONENT_LENGTH:
begin
exponent_length_we = 1'b1;
end
ADDR_MODULUS_PTR_RST:
begin
modulus_mem_api_rst = 1'b1;
end
ADDR_MODULUS_DATA:
begin
modulus_mem_api_cs = 1'b1;
modulus_mem_api_wr = 1'b1;
end
ADDR_EXPONENT_PTR_RST:
begin
exponent_mem_api_rst = 1'b1;
end
ADDR_EXPONENT_DATA:
begin
exponent_mem_api_cs = 1'b1;
exponent_mem_api_wr = 1'b1;
end
ADDR_MESSAGE_PTR_RST:
begin
message_mem_api_rst = 1'b1;
end
ADDR_MESSAGE_DATA:
begin
message_mem_api_cs = 1'b1;
message_mem_api_wr = 1'b1;
end
ADDR_RESULT_PTR_RST:
begin
result_mem_api_rst = 1'b1;
end
default:
begin
end
endcase // case (address[7 : 0])
end
else
begin
case (address[7 : 0])
ADDR_NAME0:
tmp_read_data = CORE_NAME0;
ADDR_NAME1:
tmp_read_data = CORE_NAME1;
ADDR_VERSION:
tmp_read_data = CORE_VERSION;
ADDR_CTRL:
tmp_read_data = {31'h00000000, start_reg};
ADDR_STATUS:
tmp_read_data = {31'h00000000, ready};
ADDR_CYCLES_HIGH:
tmp_read_data = cycles[63 : 32];
ADDR_CYCLES_LOW:
tmp_read_data = cycles[31 : 0];
ADDR_MODULUS_LENGTH:
tmp_read_data = {24'h000000, modulus_length_reg};
ADDR_EXPONENT_LENGTH:
tmp_read_data = {24'h000000, exponent_length_reg};
ADDR_MODULUS_DATA:
begin
modulus_mem_api_cs = 1'b1;
tmp_read_data = modulus_mem_api_read_data;
end
ADDR_EXPONENT_DATA:
begin
exponent_mem_api_cs = 1'b1;
tmp_read_data = exponent_mem_api_read_data;
end
ADDR_MESSAGE_DATA:
begin
message_mem_api_cs = 1'b1;
tmp_read_data = message_mem_api_read_data;
end
ADDR_RESULT_DATA:
begin
result_mem_api_cs = 1'b1;
tmp_read_data = result_mem_api_read_data;
end
default:
begin
end
endcase // case (address[7 : 0])
end
end
default:
begin
end
endcase // case (address[11 : 8])
end // if (cs)
end // api
endmodule // modexp
//======================================================================
// EOF modexp.v
//======================================================================