aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rtl/adder32.v54
-rw-r--r--src/rtl/blockmem1r1w.v70
-rw-r--r--src/rtl/blockmem2r1w.v76
-rw-r--r--src/rtl/modexp.v807
-rw-r--r--src/rtl/montprod.v590
-rw-r--r--src/rtl/residue.v224
-rw-r--r--src/rtl/shr32.v53
7 files changed, 1874 insertions, 0 deletions
diff --git a/src/rtl/adder32.v b/src/rtl/adder32.v
new file mode 100644
index 0000000..d9cac45
--- /dev/null
+++ b/src/rtl/adder32.v
@@ -0,0 +1,54 @@
+//======================================================================
+//
+// adder32.v
+// ---------
+// 32bit adder with carry in / carry out
+//
+//
+// Author: Peter Magnusson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 adder32(
+ input [31 : 0] a,
+ input [31 : 0] b,
+ input carry_in,
+ output wire [31 : 0] sum,
+ output wire carry_out);
+
+ reg [32 : 0] adder_result;
+
+ assign sum = adder_result[31:0];
+ assign carry_out = adder_result[32];
+
+ always @(a, b, carry_in)
+ adder_result = {1'b0, a} + {1'b0, b} + {32'b0, carry_in};
+endmodule
diff --git a/src/rtl/blockmem1r1w.v b/src/rtl/blockmem1r1w.v
new file mode 100644
index 0000000..1d84369
--- /dev/null
+++ b/src/rtl/blockmem1r1w.v
@@ -0,0 +1,70 @@
+//======================================================================
+//
+// blockmem1rw1.v
+// --------------
+// Synchronous block memory with one read and one write port.
+// The data size is the same for both read and write operations.
+//
+// The memory is used in the modexp core.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 blockmem1r1w(
+ input wire clk,
+
+ input wire [07 : 0] read_addr,
+ output wire [31 : 0] read_data,
+
+ input wire wr,
+ input wire [07 : 0] write_addr,
+ input wire [31 : 0] write_data
+ );
+
+ reg [31 : 0] mem [0 : 255];
+ reg [31 : 0] tmp_read_data;
+
+ assign read_data = tmp_read_data;
+
+ always @ (posedge clk)
+ begin : reg_mem
+ if (wr)
+ mem[write_addr] <= write_data;
+
+ tmp_read_data <= mem[read_addr];
+ end
+
+endmodule // blockmem1r1w
+
+//======================================================================
+// EOF blockmem1r1w.v
+//======================================================================
diff --git a/src/rtl/blockmem2r1w.v b/src/rtl/blockmem2r1w.v
new file mode 100644
index 0000000..252764f
--- /dev/null
+++ b/src/rtl/blockmem2r1w.v
@@ -0,0 +1,76 @@
+//======================================================================
+//
+// blockmem2r1w.v
+// --------------
+// Synchronous block memory with two read ports and one write port.
+// The data size is the same for both read and write operations.
+//
+// The memory is used in the modexp core.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 blockmem2r1w(
+ input wire clk,
+
+ input wire [07 : 0] read_addr0,
+ output wire [31 : 0] read_data0,
+
+ input wire [07 : 0] read_addr1,
+ output wire [31 : 0] read_data1,
+
+ input wire wr,
+ input wire [07 : 0] write_addr,
+ input wire [31 : 0] write_data
+ );
+
+ reg [31 : 0] mem [0 : 255];
+ reg [31 : 0] tmp_read_data0;
+ reg [31 : 0] tmp_read_data1;
+
+ assign read_data0 = tmp_read_data0;
+ assign read_data1 = tmp_read_data1;
+
+ always @ (posedge clk)
+ begin : reg_mem
+ if (wr)
+ mem[write_addr] <= write_data;
+
+ tmp_read_data0 <= mem[read_addr0];
+ tmp_read_data1 <= mem[read_addr1];
+ end
+
+endmodule // blockmem2r1w
+
+//======================================================================
+// EOF blockmem2r1w.v
+//======================================================================
diff --git a/src/rtl/modexp.v b/src/rtl/modexp.v
new file mode 100644
index 0000000..b0e8aa3
--- /dev/null
+++ b/src/rtl/modexp.v
@@ -0,0 +1,807 @@
+//======================================================================
+//
+// modexp.v
+// --------
+// Modular exponentiation core for implementing 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 at most 32 bits
+// N is the modulus with a length of n bits
+// n is can be 32 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: Peter Magnusson, Joachim Strombergson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 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.
+ //----------------------------------------------------------------
+ localparam GENERAL_PREFIX = 4'h0;
+ localparam ADDR_NAME0 = 8'h00;
+ localparam ADDR_NAME1 = 8'h01;
+ localparam ADDR_VERSION = 8'h02;
+
+ localparam ADDR_MODSIZE = 8'h10;
+ localparam ADDR_EXPONENT = 8'h20;
+
+ localparam MODULUS_PREFIX = 4'h1;
+ localparam ADDR_MODULUS_START = 8'h00;
+ localparam ADDR_MODULUS_END = 8'hff;
+
+ localparam EXPONENT_PREFIX = 4'h2;
+ localparam ADDR_EXPONENT_START = 8'h00;
+ localparam ADDR_EXPONENT_END = 8'hff;
+
+ localparam MESSAGE_PREFIX = 4'h3;
+ localparam MESSAGE_START = 8'h00;
+ localparam MESSAGE_END = 8'hff;
+
+ localparam RESULT_PREFIX = 4'h4;
+ localparam RESULT_START = 8'h00;
+ localparam RESULT_END = 8'hff;
+
+ localparam LENGTH_PREFIX = 4'h5;
+
+ localparam DEFAULT_MODLENGTH = 8'h80;
+ localparam DEFAULT_EXPLENGTH = 8'h80;
+
+ localparam MONTPROD_SELECT_ONE_NR = 3'h0;
+ localparam MONTPROD_SELECT_X_NR = 3'h1;
+ localparam MONTPROD_SELECT_Z_P = 3'h2;
+ localparam MONTPROD_SELECT_P_P = 3'h3;
+ localparam MONTPROD_SELECT_ONE_Z = 3'h4;
+
+ localparam MONTPROD_DEST_Z = 2'b00;
+ localparam MONTPROD_DEST_P = 2'b01;
+ localparam MONTPROD_DEST_NOWHERE = 2'b10;
+
+ localparam CTRL_IDLE = 4'h0;
+ localparam CTRL_RESIDUE = 4'h1;
+ localparam CTRL_CALCULATE_Z0 = 4'h2;
+ localparam CTRL_CALCULATE_P0 = 4'h3;
+ localparam CTRL_ITERATE = 4'h4;
+ localparam CTRL_ITERATE_Z_P = 4'h5;
+ localparam CTRL_ITERATE_P_P = 4'h6;
+ localparam CTRL_ITERATE_END = 4'h7;
+ localparam CTRL_CALCULATE_ZN = 4'h8;
+ localparam CTRL_DONE = 4'h9;
+
+ localparam CORE_NAME0 = 32'h72736120; // "rsa "
+ localparam CORE_NAME1 = 32'h38313932; // "8192"
+ localparam CORE_VERSION = 32'h302e3031; // "0.01"
+
+
+ //----------------------------------------------------------------
+ // Registers including update variables and write enable.
+ //----------------------------------------------------------------
+ reg [07 : 0] modulus_mem_int_rd_addr;
+ wire [31 : 0] modulus_mem_int_rd_data;
+ wire [31 : 0] modulus_mem_api_rd_data;
+ reg modulus_mem_api_we;
+
+ reg [07 : 0] message_mem_int_rd_addr;
+ wire [31 : 0] message_mem_int_rd_data;
+ wire [31 : 0] message_mem_api_rd_data;
+ reg message_mem_api_we;
+
+ reg [07 : 0] exponent_mem_int_rd_addr;
+ wire [31 : 0] exponent_mem_int_rd_data;
+ wire [31 : 0] exponent_mem_api_rd_data;
+ reg exponent_mem_api_we;
+
+ wire [31 : 0] result_mem_api_rd_data;
+ reg [07 : 0] result_mem_int_rd_addr;
+ wire [31 : 0] result_mem_int_rd_data;
+ reg [07 : 0] result_mem_int_wr_addr;
+ reg [31 : 0] result_mem_int_wr_data;
+ reg result_mem_int_we;
+
+ reg residue_calculator_start; //TODO not implemented yet
+ reg residue_calculator_ready; //TODO not implemented yet
+
+ reg [31 : 0] residue_mem [0 : 255];
+ reg [07 : 0] residue_mem_rd_addr;
+ wire [31 : 0] residue_mem_rd_data;
+ reg [07 : 0] residue_mem_wr_addr;
+ reg [31 : 0] residue_mem_wr_data;
+ reg residue_mem_we;
+
+
+ reg [07 : 0] p_mem_rd0_addr;
+ wire [31 : 0] p_mem_rd0_data;
+ reg [07 : 0] p_mem_rd1_addr;
+ wire [31 : 0] p_mem_rd1_data;
+ reg [07 : 0] p_mem_wr_addr;
+ reg [31 : 0] p_mem_wr_data;
+ reg p_mem_we;
+
+ reg [07 : 0] length_reg;
+ reg [07 : 0] length_m1_reg;
+ reg [07 : 0] length_new;
+ reg [07 : 0] length_m1_new;
+ reg length_we;
+
+ reg start_reg;
+ reg start_new;
+ reg start_we;
+
+ reg ready_reg;
+ reg ready_new;
+ reg ready_we;
+
+ reg [2 : 0] montprod_select_reg;
+ reg [2 : 0] montprod_select_new;
+ reg montprod_select_we;
+ reg [1 : 0] montprod_dest_reg;
+ reg [1 : 0] montprod_dest_new;
+ reg [1 : 0] montprod_dest_we;
+
+ reg [3 : 0] modexp_ctrl_reg;
+ reg [3 : 0] modexp_ctrl_new;
+ reg modexp_ctrl_we;
+
+ reg [31 : 0] one;
+ reg [31 : 0] one_new;
+
+ reg [12 : 0] loop_counter_reg;
+ reg [12 : 0] loop_counter_new;
+ reg [12 : 0] loop_counter_we;
+ reg [07 : 0] E_word_index;
+ reg [04 : 0] E_bit_index;
+ reg last_iteration;
+ reg ei_reg;
+ reg ei_new;
+ reg ei_we;
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ reg [31 : 0] tmp_read_data;
+ reg tmp_error;
+
+ reg montprod_calc;
+ wire montprod_ready;
+ reg [07 : 0] montprod_length;
+
+ wire [07 : 0] montprod_opa_addr;
+ reg [31 : 0] montprod_opa_data;
+
+ wire [07 : 0] montprod_opb_addr;
+ reg [31 : 0] montprod_opb_data;
+
+ wire [07 : 0] montprod_opm_addr;
+ reg [31 : 0] montprod_opm_data;
+
+ wire [07 : 0] montprod_result_addr;
+ wire [31 : 0] montprod_result_data;
+ wire montprod_result_we;
+
+
+ //----------------------------------------------------------------
+ // Concurrent connectivity for ports etc.
+ //----------------------------------------------------------------
+ assign read_data = tmp_read_data;
+
+
+ //----------------------------------------------------------------
+ // core instantiations.
+ //----------------------------------------------------------------
+ montprod montprod_inst(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .calculate(montprod_calc),
+ .ready(montprod_ready),
+
+ .length(montprod_length),
+
+ .opa_addr(montprod_opa_addr),
+ .opa_data(montprod_opa_data),
+
+ .opb_addr(montprod_opb_addr),
+ .opb_data(montprod_opb_data),
+
+ .opm_addr(montprod_opm_addr),
+ .opm_data(message_mem_int_rd_data),
+
+ .result_addr(montprod_result_addr),
+ .result_data(montprod_result_data),
+ .result_we(montprod_result_we)
+ );
+
+
+ blockmem2r1w modulus_mem(
+ .clk(clk),
+ .read_addr0(modulus_mem_int_rd_addr),
+ .read_data0(modulus_mem_int_rd_data),
+ .read_addr1(address[7 : 0]),
+ .read_data1(modulus_mem_api_rd_data),
+ .wr(modulus_mem_api_we),
+ .write_addr(address[7 : 0]),
+ .write_data(write_data)
+ );
+
+
+ blockmem2r1w message_mem(
+ .clk(clk),
+ .read_addr0(message_mem_int_rd_addr),
+ .read_data0(message_mem_int_rd_data),
+ .read_addr1(address[7 : 0]),
+ .read_data1(message_mem_api_rd_data),
+ .wr(message_mem_api_we),
+ .write_addr(address[7 : 0]),
+ .write_data(write_data)
+ );
+
+
+ blockmem2r1w exponent_mem(
+ .clk(clk),
+ .read_addr0(exponent_mem_int_rd_addr),
+ .read_data0(exponent_mem_int_rd_data),
+ .read_addr1(address[7 : 0]),
+ .read_data1(exponent_mem_api_rd_data),
+ .wr(exponent_mem_api_we),
+ .write_addr(address[7 : 0]),
+ .write_data(write_data)
+ );
+
+
+ blockmem2r1w result_mem(
+ .clk(clk),
+ .read_addr0(result_mem_int_rd_addr[7 : 0]),
+ .read_data0(result_mem_int_rd_data),
+ .read_addr1(address[7 : 0]),
+ .read_data1(result_mem_api_rd_data),
+ .wr(result_mem_int_we),
+ .write_addr(result_mem_int_wr_addr),
+ .write_data(result_mem_int_wr_data)
+ );
+
+ blockmem2r1w p_mem(
+ .clk(clk),
+ .read_addr0(p_mem_rd0_addr),
+ .read_data0(p_mem_rd0_data),
+ .read_addr1(p_mem_rd1_addr),
+ .read_data1(p_mem_rd1_data),
+ .wr(p_mem_we),
+ .write_addr(p_mem_wr_addr),
+ .write_data(p_mem_wr_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
+ ready_reg <= 1'b1;
+ montprod_select_reg <= MONTPROD_SELECT_ONE_NR;
+ montprod_dest_reg <= MONTPROD_DEST_NOWHERE;
+ modexp_ctrl_reg <= CTRL_IDLE;
+ one <= 32'h0;
+ length_reg <= 8'h0;
+ length_m1_reg <= 8'h0;
+ loop_counter_reg <= 13'b0;
+ ei_reg <= 1'b0;
+ end
+ else
+ begin
+ if (ready_we)
+ ready_reg <= ready_new;
+
+ if (montprod_select_we)
+ montprod_select_reg <= montprod_select_new;
+
+ if (montprod_dest_we)
+ montprod_dest_reg <= montprod_dest_new;
+
+ if (modexp_ctrl_we)
+ modexp_ctrl_reg <= modexp_ctrl_new;
+
+ if (length_we)
+ begin
+ length_reg <= length_new;
+ length_m1_reg <= length_m1_new;
+ end
+
+ if (loop_counter_we)
+ loop_counter_reg <= loop_counter_new;
+
+ if (ei_we)
+ ei_reg <= ei_new;
+
+ one <= one_new;
+ end
+ end // reg_update
+
+
+ //----------------------------------------------------------------
+ // api
+ //
+ // The interface command decoding logic.
+ //----------------------------------------------------------------
+ always @*
+ begin : api
+ modulus_mem_api_we = 1'b0;
+ exponent_mem_api_we = 1'b0;
+ message_mem_api_we = 1'b0;
+ tmp_read_data = 32'h00000000;
+
+ length_new = write_data[7 : 0];
+ length_m1_new = write_data[7 : 0] - 8'h1;
+ length_we = 1'b0;
+
+ if (cs)
+ begin
+ case (address[11 : 8])
+ GENERAL_PREFIX:
+ begin
+// if (we)
+// begin
+// case (address)
+// // Write operations.
+// ADDR_MODSIZE:
+// begin
+// modsize_we = 1;
+// end
+//
+// ADDR_EXPONENT:
+// begin
+// exponent_we = 1;
+// end
+//
+// default:
+// begin
+// tmp_error = 1;
+// end
+// endcase // case (addr)
+// end // if (write_read)
+// else
+// begin
+// case (address)
+// // Read operations.
+// ADDR_NAME0:
+// begin
+// tmp_read_data = CORE_NAME0;
+// end
+//
+// ADDR_NAME1:
+// begin
+// tmp_read_data = CORE_NAME1;
+// end
+//
+// ADDR_VERSION:
+// begin
+// tmp_read_data = CORE_VERSION;
+// end
+//
+// ADDR_MODSIZE:
+// begin
+// tmp_read_data = {28'h0000000, modsize_reg};
+// end
+//
+// default:
+// begin
+// tmp_error = 1;
+// end
+// endcase // case (addr)
+// end
+ end
+
+ MODULUS_PREFIX:
+ begin
+ if (we)
+ begin
+ modulus_mem_api_we = 1'b1;
+ end
+ else
+ begin
+ tmp_read_data = modulus_mem_api_rd_data;
+ end
+ end
+
+ EXPONENT_PREFIX:
+ begin
+ if (we)
+ begin
+ exponent_mem_api_we = 1'b1;
+ end
+ else
+ begin
+ tmp_read_data = exponent_mem_api_rd_data;
+ end
+ end
+
+ MESSAGE_PREFIX:
+ begin
+ if (we)
+ begin
+ message_mem_api_we = 1'b1;
+ end
+ else
+ begin
+ tmp_read_data = message_mem_api_rd_data;
+ end
+ end
+
+ RESULT_PREFIX:
+ begin
+ tmp_read_data = result_mem_api_rd_data;
+ end
+
+ LENGTH_PREFIX:
+ begin
+ if (we)
+ length_we = 1'b1;
+ end
+
+// RESULT_PREFIX:
+// begin
+// if (we)
+// begin
+// modulus_mem_api_we = 1'b1;
+// end
+// else
+// begin
+// tmp_read_data = modulus_mem_int_rd_data;
+// end
+// end
+
+ default:
+ begin
+
+ end
+ endcase // case (address[11 : 8])
+ end // if (cs)
+ end // api
+
+
+ //----------------------------------------------------------------
+ // montprod_op_select
+ //
+ // Select operands used during montprod calculations depending
+ // on what operation we want to do
+ //----------------------------------------------------------------
+ always @*
+ begin : montprod_op_select
+ message_mem_int_rd_addr = montprod_opa_addr;
+ p_mem_rd0_addr = montprod_opa_addr;
+
+ residue_mem_rd_addr = montprod_opb_addr;
+ p_mem_rd1_addr = montprod_opb_addr;
+
+ modulus_mem_int_rd_addr = montprod_opm_addr;
+
+ montprod_opa_data = 32'h00000000;
+ montprod_opb_data = 32'h00000000;
+
+ if (montprod_opa_addr == length_m1_reg)
+ one_new = 32'h00000001;
+ else
+ one_new = 32'h00000000;
+
+ case (montprod_select_reg)
+ MONTPROD_SELECT_ONE_NR:
+ begin
+ montprod_opa_data = one;
+ montprod_opb_data = residue_mem_rd_data;
+ end
+
+ MONTPROD_SELECT_X_NR:
+ begin
+ montprod_opa_data = message_mem_int_rd_data;
+ montprod_opb_data = residue_mem_rd_data;
+ end
+
+ MONTPROD_SELECT_Z_P:
+ begin
+ montprod_opa_data = result_mem_int_rd_data;
+ montprod_opb_data = p_mem_rd1_data;
+ end
+
+ MONTPROD_SELECT_P_P:
+ begin
+ montprod_opa_data = p_mem_rd0_data;
+ montprod_opb_data = p_mem_rd1_data;
+ end
+
+ MONTPROD_SELECT_ONE_Z:
+ begin
+ montprod_opa_data = one;
+ montprod_opb_data = result_mem_int_rd_data;
+ end
+
+ default:
+ begin
+ end
+ endcase // case (montprod_selcect_reg)
+ end
+
+ //----------------------------------------------------------------
+ // memory write mux
+ //
+ // direct memory write signals to correct memory
+ //----------------------------------------------------------------
+ always @*
+ begin : memory_write_process
+ result_mem_int_wr_addr = montprod_result_addr;
+ result_mem_int_wr_data = montprod_result_data;
+ result_mem_int_we = 1'b0;
+
+ p_mem_wr_addr = montprod_result_addr;
+ p_mem_wr_data = montprod_result_data;
+ p_mem_we = 1'b0;
+
+ case (montprod_dest_reg)
+ MONTPROD_DEST_Z:
+ result_mem_int_we = montprod_result_we;
+ MONTPROD_DEST_P:
+ p_mem_we = montprod_result_we;
+ default:
+ begin
+ end
+ endcase
+
+ // inhibit Z=Z*P when ei = 0
+ if (modexp_ctrl_reg == CTRL_ITERATE_Z_P)
+ result_mem_int_we = result_mem_int_we & ei_reg;
+ end
+
+ //----------------------------------------------------------------
+ // loop_counter
+ //
+ // Calculate the loop counter and related variables
+ //----------------------------------------------------------------
+ always @*
+ begin : loop_counters_process
+ E_bit_index = loop_counter_reg[ 04 : 0 ];
+
+ if (loop_counter_reg == { length_m1_reg, 5'b11111 })
+ last_iteration = 1'b1;
+ else
+ last_iteration = 1'b0;
+
+ case (modexp_ctrl_reg)
+ CTRL_CALCULATE_P0:
+ begin
+ loop_counter_new = 13'b0;
+ loop_counter_we = 1'b1;
+ end
+
+ CTRL_ITERATE_END:
+ begin
+ loop_counter_new = loop_counter_reg + 1'b1;
+ loop_counter_we = 1'b1;
+ end
+
+ default:
+ begin
+ loop_counter_new = 13'b0;
+ loop_counter_we = 1'b0;
+ end
+
+ endcase
+ end
+
+ //----------------------------------------------------------------
+ // exponent
+ //
+ // reads the exponent
+ //----------------------------------------------------------------
+ always @*
+ begin : exponent_process
+ // accessing new instead of reg - pick up update at CTRL_ITERATE_NEW to remove a pipeline stall
+ E_word_index = loop_counter_new[ 12 : 5 ];
+
+ exponent_mem_int_rd_addr = E_word_index;
+
+ ei_new = exponent_mem_int_rd_data[ E_bit_index ];
+
+ if (modexp_ctrl_reg == CTRL_ITERATE)
+ ei_we = 1'b1;
+ else
+ ei_we = 1'b0;
+ end
+
+ //----------------------------------------------------------------
+ // modexp_ctrl
+ //
+ // Control FSM logic needed to perform the modexp operation.
+ //----------------------------------------------------------------
+ always @*
+ begin
+ ready_new = 0;
+ ready_we = 0;
+ montprod_select_new = MONTPROD_SELECT_ONE_NR;
+ montprod_select_we = 0;
+ montprod_dest_new = MONTPROD_DEST_NOWHERE;
+ montprod_dest_we = 0;
+ montprod_calc = 0;
+ modexp_ctrl_new = CTRL_IDLE;
+ modexp_ctrl_we = 0;
+
+ residue_calculator_start = 1'b0;
+
+ case (modexp_ctrl_reg)
+ CTRL_IDLE:
+ begin
+ ready_new = 0;
+ ready_we = 1;
+ if (start_reg == 1'b1)
+ begin
+ modexp_ctrl_new = CTRL_RESIDUE;
+ modexp_ctrl_we = 1;
+ residue_calculator_start = 1'b1;
+ end
+ end
+
+ CTRL_RESIDUE:
+ begin
+ if (residue_calculator_ready == 1'b1)
+ begin
+ montprod_select_new = MONTPROD_SELECT_ONE_NR;
+ montprod_select_we = 1;
+ montprod_dest_new = MONTPROD_DEST_Z;
+ montprod_dest_we = 1;
+ montprod_calc = 1;
+ modexp_ctrl_new = CTRL_CALCULATE_Z0;
+ modexp_ctrl_we = 1;
+ end
+ end
+
+ CTRL_CALCULATE_Z0:
+ begin
+ if (montprod_ready == 1'b1)
+ begin
+ montprod_select_new = MONTPROD_SELECT_X_NR;
+ montprod_select_we = 1;
+ montprod_dest_new = MONTPROD_DEST_P;
+ montprod_dest_we = 1;
+ montprod_calc = 1;
+ modexp_ctrl_new = CTRL_CALCULATE_P0;
+ modexp_ctrl_we = 1;
+ end
+ end
+
+ CTRL_CALCULATE_P0:
+ begin
+ if (montprod_ready == 1'b1)
+ begin
+ modexp_ctrl_new = CTRL_ITERATE;
+ modexp_ctrl_we = 1;
+ end
+ end
+
+ CTRL_ITERATE:
+ begin
+ montprod_select_new = MONTPROD_SELECT_Z_P;
+ montprod_select_we = 1;
+ montprod_dest_new = MONTPROD_DEST_Z;
+ montprod_dest_we = 1;
+ montprod_calc = 1;
+ modexp_ctrl_new = CTRL_ITERATE_Z_P;
+ modexp_ctrl_we = 1;
+ end
+
+ CTRL_ITERATE_Z_P:
+ if (montprod_ready == 1'b1)
+ begin
+ montprod_select_new = MONTPROD_SELECT_P_P;
+ montprod_select_we = 1;
+ montprod_dest_new = MONTPROD_DEST_P;
+ montprod_dest_we = 1;
+ montprod_calc = 1;
+ modexp_ctrl_new = CTRL_ITERATE_P_P;
+ modexp_ctrl_we = 1;
+ end
+
+ CTRL_ITERATE_P_P:
+ if (montprod_ready == 1'b1)
+ begin
+ modexp_ctrl_new = CTRL_ITERATE_END;
+ modexp_ctrl_we = 1;
+ end
+
+ CTRL_ITERATE_END:
+ begin
+ if (last_iteration == 1'b0)
+ begin
+ modexp_ctrl_new = CTRL_ITERATE;
+ modexp_ctrl_we = 1;
+ end
+ else
+ begin
+ montprod_select_new = MONTPROD_SELECT_ONE_Z;
+ montprod_select_we = 1;
+ montprod_calc = 1;
+ modexp_ctrl_new = CTRL_CALCULATE_ZN;
+ modexp_ctrl_we = 1;
+ end
+ end
+
+ CTRL_CALCULATE_ZN:
+ begin
+ if (montprod_ready == 1'b1)
+ begin
+ modexp_ctrl_new = CTRL_DONE;
+ modexp_ctrl_we = 1;
+ end
+ end
+
+ CTRL_DONE:
+ begin
+ ready_new = 1;
+ ready_we = 1;
+ modexp_ctrl_new = CTRL_IDLE;
+ modexp_ctrl_we = 1;
+ end
+
+ default:
+ begin
+ end
+
+ endcase // case (modexp_ctrl_reg)
+ end
+
+endmodule // modexp
+
+//======================================================================
+// EOF modexp.v
+//======================================================================
diff --git a/src/rtl/montprod.v b/src/rtl/montprod.v
new file mode 100644
index 0000000..32bbdec
--- /dev/null
+++ b/src/rtl/montprod.v
@@ -0,0 +1,590 @@
+//======================================================================
+//
+// montprod.v
+// ---------
+// Montgomery product calculator for the modular exponentiantion core.
+//
+//
+// Author: Peter Magnusson, Joachim Strombergson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 montprod(
+ input wire clk,
+ input wire reset_n,
+
+ input wire calculate,
+ output wire ready,
+
+ input [7 : 0] length,
+
+ output wire [7 : 0] opa_addr,
+ input wire [31 : 0] opa_data,
+
+ output wire [7 : 0] opb_addr,
+ input wire [31 : 0] opb_data,
+
+ output wire [7 : 0] opm_addr,
+ input wire [31 : 0] opm_data,
+
+ output wire [7 : 0] result_addr,
+ output wire [31 : 0] result_data,
+ output wire result_we
+ );
+
+
+ //----------------------------------------------------------------
+ // Internal constant and parameter definitions.
+ //----------------------------------------------------------------
+ localparam CTRL_IDLE = 4'h0;
+ localparam CTRL_INIT_S = 4'h1;
+ localparam CTRL_LOOP_INIT = 4'h2;
+ localparam CTRL_LOOP_ITER = 4'h3;
+ localparam CTRL_LOOP_BQ = 4'h4;
+ localparam CTRL_L_CALC_SM = 4'h5;
+ localparam CTRL_L_STALLPIPE_SM = 4'h6;
+ localparam CTRL_L_CALC_SA = 4'h7;
+ localparam CTRL_L_STALLPIPE_SA = 4'h8;
+ localparam CTRL_L_CALC_SDIV2 = 4'h9;
+ localparam CTRL_L_STALLPIPE_D2 = 4'hA;
+ localparam CTRL_L_STALLPIPE_ES = 4'hB;
+ localparam CTRL_EMIT_S = 4'hC;
+ localparam CTRL_DONE = 4'hD;
+
+ localparam SMUX_0 = 2'h0;
+ localparam SMUX_ADD_SM = 2'h1;
+ localparam SMUX_ADD_SA = 2'h2;
+ localparam SMUX_SHR = 2'h3;
+
+ //----------------------------------------------------------------
+ // Registers including update variables and write enable.
+ //----------------------------------------------------------------
+
+ reg [07 : 0] opa_addr_reg;
+ reg [07 : 0] opb_addr_reg;
+ reg [07 : 0] opm_addr_reg;
+
+ reg [07 : 0] result_addr_reg;
+ reg [31 : 0] result_data_reg;
+
+ reg ready_reg;
+ reg ready_new;
+ reg ready_we;
+
+ reg [3 : 0] montprod_ctrl_reg;
+ reg [3 : 0] montprod_ctrl_new;
+ reg montprod_ctrl_we;
+
+ reg [1 : 0] s_mux_new;
+ reg [1 : 0] s_mux_reg;
+
+ reg [31 : 0] s_mem_new;
+ reg s_mem_we;
+ reg s_mem_we_new;
+ reg [07 : 0] s_mem_addr;
+ reg [07 : 0] s_mem_wr_addr;
+ wire [31 : 0] s_mem_read_data;
+
+ reg q; //q = (s - b * A) & 1
+ reg q_reg;
+ reg b; //b: bit of B
+ reg b_reg;
+
+ reg [12 : 0] loop_counter;
+ reg [12 : 0] loop_counter_new;
+ reg [12 : 0] loop_counter_dec;
+ reg [07 : 0] B_word_index; //loop counter as a word index
+ reg [04 : 0] B_bit_index; //loop counter as a bit index
+ reg [04 : 0] B_bit_index_reg; //loop counter as a bit index
+
+ reg [07 : 0] word_index; //register of what word is being read
+ reg [07 : 0] word_index_new; //calculation of what word to be read
+ reg [07 : 0] word_index_prev; //register of what word was read previously (result address to emit)
+ reg [07 : 0] length_m1;
+
+ reg add_carry_in_sa;
+ reg add_carry_new_sa;
+ reg add_carry_in_sm;
+ reg add_carry_new_sm;
+
+ reg shr_carry_in;
+ reg shr_carry_new;
+
+ reg reset_word_index_LSW;
+ reg reset_word_index_MSW;
+
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ reg tmp_result_we;
+ wire [31 : 0] add_result_sa;
+ wire add_carry_out_sa;
+ wire [31 : 0] add_result_sm;
+ wire add_carry_out_sm;
+
+ wire shr_carry_out;
+ wire [31 : 0] shr_adiv2;
+
+
+ //----------------------------------------------------------------
+ // Concurrent connectivity for ports etc.
+ //----------------------------------------------------------------
+ assign opa_addr = opa_addr_reg;
+ assign opb_addr = opb_addr_reg;
+ assign opm_addr = opm_addr_reg;
+
+ assign result_addr = result_addr_reg;
+ assign result_data = result_data_reg;
+ assign result_we = tmp_result_we;
+
+ assign ready = ready_reg;
+
+
+ //----------------------------------------------------------------
+ // Instantions
+ //----------------------------------------------------------------
+
+ blockmem1r1w s_mem(
+ .clk(clk),
+ .read_addr(s_mem_addr),
+ .read_data(s_mem_read_data),
+ .wr(s_mem_we),
+ .write_addr(s_mem_wr_addr),
+ .write_data(s_mem_new)
+ );
+
+
+ adder32 s_adder_sa(
+ .a(s_mem_read_data),
+ .b(opa_data),
+ .carry_in(add_carry_in_sa),
+ .sum(add_result_sa),
+ .carry_out(add_carry_out_sa)
+ );
+
+ adder32 s_adder_sm(
+ .a(s_mem_read_data),
+ .b(opm_data),
+ .carry_in(add_carry_in_sm),
+ .sum(add_result_sm),
+ .carry_out(add_carry_out_sm)
+ );
+
+ shr32 shifter(
+ .a( s_mem_read_data ),
+ .carry_in( shr_carry_in ),
+ .adiv2( shr_adiv2 ),
+ .carry_out( shr_carry_out )
+ );
+
+ always @*
+ begin : s_mux
+ case (s_mux_reg)
+ SMUX_0:
+ s_mem_new = 32'b0;
+ SMUX_ADD_SA:
+ s_mem_new = add_result_sa;
+ SMUX_ADD_SM:
+ s_mem_new = add_result_sm;
+ SMUX_SHR:
+ s_mem_new = shr_adiv2;
+ endcase
+ $display("SMUX%x: %x", s_mux_reg, s_mem_new);
+ end
+
+ //----------------------------------------------------------------
+ // 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 : reg_update
+ if (!reset_n)
+ begin
+ ready_reg <= 1'b0;
+ loop_counter <= 13'h0;
+ word_index <= 8'h0;
+ word_index_prev <= 8'h0;
+ add_carry_in_sa <= 1'b0;
+ add_carry_in_sm <= 1'b0;
+ shr_carry_in <= 1'b0;
+ montprod_ctrl_reg <= CTRL_IDLE;
+ b_reg <= 1'b0;
+ q_reg <= 1'b0;
+ s_mux_reg <= SMUX_0;
+ s_mem_we <= 1'b0;
+ s_mem_wr_addr <= 8'h0;
+ B_bit_index_reg <= 5'h0;
+ end
+ else
+ begin
+ if (ready_we)
+ ready_reg <= ready_new;
+
+ if (montprod_ctrl_we)
+ begin
+ montprod_ctrl_reg <= montprod_ctrl_new;
+ end
+
+ s_mem_wr_addr <= s_mem_addr;
+
+ s_mem_we <= s_mem_we_new;
+
+ word_index <= word_index_new;
+ word_index_prev <= word_index;
+
+ loop_counter <= loop_counter_new;
+ shr_carry_in <= shr_carry_new;
+ add_carry_in_sa <= add_carry_new_sa;
+ add_carry_in_sm <= add_carry_new_sm;
+
+ B_bit_index_reg <= B_bit_index;
+ q_reg <= q;
+ b_reg <= b;
+
+ s_mux_reg <= s_mux_new;
+ end
+ end // reg_update
+
+ always @*
+ begin : bq_process
+ b = b_reg;
+ q = q_reg;
+ if (montprod_ctrl_reg == CTRL_LOOP_BQ)
+ begin
+ b = opb_data[ B_bit_index_reg ];
+ //opa_addr will point to length-1 to get A LSB.
+ //s_read_addr will point to length-1
+ q = s_mem_read_data[0] ^ (opa_data[0] & b);
+ $display("s_mem_read_data: %x opa_data %x b %x q %x B_bit_index_reg %x", s_mem_read_data, opa_data, b, q, B_bit_index_reg);
+ end
+ end
+
+
+ //----------------------------------------------------------------
+ // Process for iterating the loop counter and setting related B indexes
+ //----------------------------------------------------------------
+ always @*
+ begin : loop_counter_process
+ length_m1 = length - 1'b1;
+ loop_counter_dec = loop_counter - 1'b1;
+ B_word_index = loop_counter[12:5];
+ B_bit_index = B_bit_index_reg;
+
+ case (montprod_ctrl_reg)
+ CTRL_LOOP_INIT:
+ loop_counter_new = {length, 5'b00000}-1;
+
+ CTRL_LOOP_ITER:
+ begin
+ B_word_index = loop_counter[12:5];
+ B_bit_index = 5'h1f - loop_counter[4:0];
+ end
+
+ CTRL_L_STALLPIPE_D2:
+ loop_counter_new = loop_counter_dec;
+
+ default:
+ loop_counter_new = loop_counter;
+ endcase
+ end
+
+
+ //----------------------------------------------------------------
+ // prodcalc
+ //----------------------------------------------------------------
+ always @*
+ begin : prodcalc
+
+ case (montprod_ctrl_reg)
+ CTRL_LOOP_ITER:
+ //q = (s[length-1] ^ A[length-1]) & 1;
+ opa_addr_reg = length_m1;
+
+ default:
+ opa_addr_reg = word_index;
+ endcase
+
+ opb_addr_reg = B_word_index;
+ opm_addr_reg = word_index;
+
+ case (montprod_ctrl_reg)
+ CTRL_LOOP_ITER:
+ s_mem_addr = length_m1;
+ default:
+ s_mem_addr = word_index;
+ endcase
+
+
+
+
+ result_addr_reg = word_index_prev;
+ result_data_reg = s_mem_read_data;
+
+ case (montprod_ctrl_reg)
+ CTRL_EMIT_S:
+ tmp_result_we = 1'b1;
+ default:
+ tmp_result_we = 1'b0;
+ endcase
+
+
+ if (reset_word_index_LSW == 1'b1)
+ word_index_new = length_m1;
+ else if (reset_word_index_MSW == 1'b1)
+ word_index_new = 8'h0;
+ else if (montprod_ctrl_reg == CTRL_L_CALC_SDIV2)
+ word_index_new = word_index + 1'b1;
+ else
+ word_index_new = word_index - 1'b1;
+ end // prodcalc
+
+
+ always @*
+ begin : s_writer_process
+ shr_carry_new = 1'b0;
+ s_mux_new = SMUX_0;
+
+ s_mem_we_new = 1'b0;
+ case (montprod_ctrl_reg)
+ CTRL_INIT_S:
+ begin
+ s_mem_we_new = 1'b1;
+ s_mux_new = SMUX_0; // write 0
+ end
+
+ CTRL_L_CALC_SM:
+ begin
+ //s = (s + q*M + b*A) >>> 1;, if(q==1) S+= M. Takes (1..length) cycles.
+ s_mem_we_new = q_reg;
+ s_mux_new = SMUX_ADD_SM;
+ end
+
+ CTRL_L_CALC_SA:
+ begin
+ //s = (s + q*M + b*A) >>> 1;, if(b==1) S+= A. Takes (1..length) cycles.
+ s_mem_we_new = b_reg;
+ s_mux_new = SMUX_ADD_SA;
+ end
+
+ CTRL_L_CALC_SDIV2:
+ begin
+ //s = (s + q*M + b*A) >>> 1; s>>=1. Takes (1..length) cycles.
+ s_mux_new = SMUX_SHR;
+ s_mem_we_new = 1'b1;
+ end
+
+ default:
+ begin
+ end
+ endcase
+
+ add_carry_new_sa = 1'b0;
+ add_carry_new_sm = 1'b0;
+
+ case (s_mux_reg)
+ SMUX_ADD_SM:
+ add_carry_new_sm = add_carry_out_sm;
+
+ SMUX_ADD_SA:
+ add_carry_new_sa = add_carry_out_sa;
+
+ SMUX_SHR:
+ shr_carry_new = shr_carry_out;
+
+ default:
+ begin
+ end
+ endcase
+
+ end // prodcalc
+
+
+ //----------------------------------------------------------------
+ // montprod_ctrl
+ //
+ // Control FSM for the montgomery product calculator.
+ //----------------------------------------------------------------
+ always @*
+ begin : montprod_ctrl
+ ready_new = 1'b0;
+ ready_we = 1'b0;
+ montprod_ctrl_new = CTRL_IDLE;
+ montprod_ctrl_we = 1'b0;
+
+ reset_word_index_LSW = 1'b0;
+ reset_word_index_MSW = 1'b0;
+
+ case (montprod_ctrl_reg)
+ CTRL_IDLE:
+ begin
+ if (calculate)
+ begin
+ ready_new = 1'b0;
+ ready_we = 1'b1;
+ montprod_ctrl_new = CTRL_INIT_S;
+ montprod_ctrl_we = 1'b1;
+ reset_word_index_LSW = 1'b1;
+ end
+ else
+ begin
+ ready_new = 1'b1;
+ ready_we = 1'b1;
+ end
+ end
+
+ CTRL_INIT_S:
+ begin
+ if (word_index == 8'h0)
+ begin
+ montprod_ctrl_new = CTRL_LOOP_INIT;
+ montprod_ctrl_we = 1'b1;
+ end
+ end
+
+
+ CTRL_LOOP_INIT:
+ begin
+ montprod_ctrl_new = CTRL_LOOP_ITER;
+ montprod_ctrl_we = 1'b1;
+ end
+
+ //calculate q = (s - b * A) & 1;.
+ // Also abort loop if done.
+ CTRL_LOOP_ITER:
+ begin
+ reset_word_index_LSW = 1'b1;
+ montprod_ctrl_new = CTRL_LOOP_BQ;
+ montprod_ctrl_we = 1'b1;
+ end
+
+ CTRL_LOOP_BQ:
+ begin
+ reset_word_index_LSW = 1'b1;
+ montprod_ctrl_new = CTRL_L_CALC_SM;
+ montprod_ctrl_we = 1'b1;
+ end
+
+ CTRL_L_CALC_SM:
+ begin
+ if (word_index == 8'h0)
+ begin
+ reset_word_index_LSW = 1'b1;
+ montprod_ctrl_we = 1'b1;
+ montprod_ctrl_new = CTRL_L_STALLPIPE_SM;
+ end
+ end
+
+ CTRL_L_STALLPIPE_SM:
+ begin
+ montprod_ctrl_new = CTRL_L_CALC_SA;
+ montprod_ctrl_we = 1'b1;
+ reset_word_index_LSW = 1'b1;
+ end
+
+ CTRL_L_CALC_SA:
+ begin
+ if (word_index == 8'h0)
+ begin
+ reset_word_index_LSW = 1'b1;
+ montprod_ctrl_new = CTRL_L_STALLPIPE_SA;
+ montprod_ctrl_we = 1'b1;
+ end
+ end
+
+ CTRL_L_STALLPIPE_SA:
+ begin
+ montprod_ctrl_new = CTRL_L_CALC_SDIV2;
+ montprod_ctrl_we = 1'b1;
+ reset_word_index_MSW = 1'b1;
+ end
+
+ CTRL_L_CALC_SDIV2:
+ begin
+ if (word_index == length_m1)
+ begin
+ montprod_ctrl_new = CTRL_L_STALLPIPE_D2;
+ montprod_ctrl_we = 1'b1;
+ //reset_word_index = 1'b1;
+ end
+ end
+
+ CTRL_L_STALLPIPE_D2:
+ begin
+ montprod_ctrl_new = CTRL_LOOP_ITER; //loop
+ montprod_ctrl_we = 1'b1;
+ reset_word_index_LSW = 1'b1;
+ if (loop_counter == 0)
+ begin
+ montprod_ctrl_new = CTRL_L_STALLPIPE_ES;
+ montprod_ctrl_we = 1'b1;
+ end
+ end
+
+ CTRL_L_STALLPIPE_ES:
+ begin
+ montprod_ctrl_new = CTRL_EMIT_S;
+ montprod_ctrl_we = 1'b1;
+ //reset_word_index_LSW = 1'b1;
+ end
+
+ CTRL_EMIT_S:
+ begin
+ $display("EMIT_S word_index: %d", word_index);
+ if (word_index_prev == 8'h0)
+ begin
+ montprod_ctrl_new = CTRL_DONE;
+ montprod_ctrl_we = 1'b1;
+ end
+ end
+
+ CTRL_DONE:
+ begin
+ ready_new = 1'b1;
+ ready_we = 1'b1;
+ montprod_ctrl_new = CTRL_IDLE;
+ montprod_ctrl_we = 1'b1;
+ end
+
+ default:
+ begin
+ end
+
+ endcase // case (montprod_ctrl_reg)
+ end // montprod_ctrl
+
+endmodule // montprod
+
+//======================================================================
+// EOF montprod.v
+//======================================================================
diff --git a/src/rtl/residue.v b/src/rtl/residue.v
new file mode 100644
index 0000000..2991dd6
--- /dev/null
+++ b/src/rtl/residue.v
@@ -0,0 +1,224 @@
+//======================================================================
+//
+// residue.v
+// ---------
+// Modulus 2**2N residue calculator for montgomery calculations.
+//
+// m_residue_2_2N_array( N, M, Nr)
+// Nr = 00...01 ; Nr = 1 == 2**(2N-2N)
+// for (int i = 0; i < 2 * N; i++)
+// Nr = Nr shift left 1
+// if (Nr less than M) continue;
+// Nr = Nr - M
+// return Nr
+//
+//
+//
+// Author: Peter Magnusson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 residue(
+ input wire clk,
+ input wire reset_n,
+
+ input wire calculate,
+ output wire ready,
+
+ input wire [07 : 0] nn,
+ input wire [07 : 0] length,
+
+ output wire [07 : 0] opa_rd_addr,
+ input wire [31 : 0] opa_rd_data,
+ output wire [07 : 0] opa_wr_addr,
+ output wire [31 : 0] opa_wr_data,
+ output wire opa_wr_we,
+
+ output wire [07 : 0] opm_addr,
+ input wire [31 : 0] opm_data
+
+);
+
+//----------------------------------------------------------------
+// Internal constant and parameter definitions.
+//----------------------------------------------------------------
+
+
+localparam CTRL_IDLE = 4'h0;
+localparam CTRL_INIT = 4'h1;
+localparam CTRL_INIT_STALL = 4'h2;
+localparam CTRL_SHL = 4'h3;
+localparam CTRL_SHL_STALL = 4'h4;
+localparam CTRL_COMPARE = 4'h5;
+localparam CTRL_COMPARE_STALL = 4'h6;
+localparam CTRL_SUB = 4'h7;
+localparam CTRL_SUB_STALL = 4'h8;
+localparam CTRL_LOOP = 4'h9;
+
+//----------------------------------------------------------------
+// Registers including update variables and write enable.
+//----------------------------------------------------------------
+
+reg [07 : 0] opa_rd_addr_reg;
+reg [07 : 0] opa_wr_addr_reg;
+reg [31 : 0] opa_wr_data_reg;
+reg opa_wr_we_reg;
+reg [07 : 0] opm_addr_reg;
+reg ready_reg;
+reg ready_new;
+reg ready_we;
+reg [03 : 0] residue_ctrl_reg;
+reg [03 : 0] residue_ctrl_new;
+reg residue_ctrl_we;
+reg reset_word_index;
+reg reset_n_counter;
+reg [07 : 0] word_index;
+
+//----------------------------------------------------------------
+// Concurrent connectivity for ports etc.
+//----------------------------------------------------------------
+assign opa_rd_addr = opa_rd_addr_reg;
+assign opa_wr_addr = opa_wr_addr_reg;
+assign opa_wr_data = opa_wr_data_reg;
+assign opm_addr = opm_addr_reg;
+assign ready = ready_reg;
+
+
+
+
+ //----------------------------------------------------------------
+ // reg_update
+ //----------------------------------------------------------------
+ always @ (posedge clk or negedge reset_n)
+ begin
+ if (!reset_n)
+ begin
+ residue_ctrl_reg <= CTRL_IDLE;
+ end
+ else
+ begin
+ if (residue_ctrl_we)
+ residue_ctrl_reg <= residue_ctrl_new;
+ end
+ end // reg_update
+
+
+ //----------------------------------------------------------------
+ //----------------------------------------------------------------
+ always @*
+ begin : process_1_to_2n
+ end
+
+ //----------------------------------------------------------------
+ //----------------------------------------------------------------
+ always @*
+ begin : word_index_process
+ end
+
+//----------------------------------------------------------------
+// residue_ctrl
+//
+// Control FSM for residue
+//----------------------------------------------------------------
+always @*
+ begin : residue_ctrl
+ ready_new = 1'b0;
+ ready_we = 1'b0;
+ residue_ctrl_new = CTRL_IDLE;
+ residue_ctrl_we = 1'b0;
+ reset_word_index = 1'b0;
+ reset_n_counter = 1'b0;
+
+ case (residue_ctrl_reg)
+ CTRL_IDLE:
+ if (calculate)
+ begin
+ ready_new = 1'b0;
+ ready_we = 1'b1;
+ residue_ctrl_new = CTRL_INIT;
+ residue_ctrl_we = 1'b1;
+ reset_word_index = 1'b1;
+ end
+
+ CTRL_INIT:
+ if (word_index == 8'h0)
+ begin
+ residue_ctrl_new = CTRL_INIT_STALL;
+ residue_ctrl_we = 1'b1;
+ end
+
+ CTRL_INIT_STALL:
+ begin
+ reset_word_index = 1'b1;
+ reset_n_counter = 1'b1;
+ residue_ctrl_new = CTRL_COMPARE;
+ residue_ctrl_we = 1'b1;
+ end
+
+ CTRL_COMPARE:
+ begin
+ end
+
+ CTRL_COMPARE_STALL:
+ begin
+ end
+
+ CTRL_SUB:
+ begin
+ end
+
+ CTRL_SUB_STALL:
+ begin
+ end
+
+ CTRL_SHL:
+ begin
+ end
+
+ CTRL_SHL_STALL:
+ begin
+ end
+
+ CTRL_LOOP:
+ begin
+ end
+
+ default:
+ begin
+ end
+
+ endcase
+ end
+
+endmodule // residue
+
+//======================================================================
+// EOF residue.v
+//======================================================================
diff --git a/src/rtl/shr32.v b/src/rtl/shr32.v
new file mode 100644
index 0000000..840f9df
--- /dev/null
+++ b/src/rtl/shr32.v
@@ -0,0 +1,53 @@
+//======================================================================
+//
+// shr32.v
+// ---------
+// 32bit shifter with carry in / carry out
+//
+//
+// Author: Peter Magnusson
+// Copyright (c) 2015, NORDUnet A/S All rights reserved.
+//
+// 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 NORDUnet 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 shr32(
+ input [31 : 0] a,
+ input carry_in,
+ output wire [31 : 0] adiv2,
+ output wire carry_out);
+
+ reg [32 : 0] shr_result;
+
+ assign adiv2 = shr_result[32:1];
+ assign carry_out = shr_result[0];
+
+ always @(a, carry_in)
+ shr_result = { carry_in, a };
+endmodule