summaryrefslogblamecommitdiff
path: root/rtl/ed25519_worker.v
blob: df99f61dbbad922c72e2838a0afe68d0d980d69b (plain) (tree)










































































































































































































































































































                                                                                                            
//------------------------------------------------------------------------------
//
// ed25519_uop_worker.v
// -----------------------------------------------------------------------------
// Ed25519 uOP Worker.
//
// Authors: Pavel Shatov
//
// Copyright (c) 2018, NORDUnet A/S
//
// 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 ed25519_worker
(
    clk, rst_n,
    ena, rdy,
    uop_offset
);


    //
    // Microcode Header
    //
`include "ed25519_uop.v"


    //
    // Ports
    //
    input   clk;    // system clock
    input   rst_n;  // active-low async reset

    input   ena;    // enable input
    output  rdy;    // ready output
    
    input [UOP_ADDR_WIDTH-1:0] uop_offset;  // starting offset

    
    //
    // Constants
    //
    localparam integer OPERAND_NUM_WORDS = 8;   // 256 bits -> 8 x 32-bit words
    localparam integer WORD_COUNTER_WIDTH = 3;  // 0..7 -> 3 bits
    

    //
    // FSM
    //
    localparam [1:0] FSM_STATE_IDLE     = 2'b00;
    localparam [1:0] FSM_STATE_FETCH    = 2'b01;
    localparam [1:0] FSM_STATE_DECODE   = 2'b10;
    localparam [1:0] FSM_STATE_BUSY     = 2'b11;

    reg  [1:0] fsm_state = FSM_STATE_IDLE;
    reg  [1:0] fsm_state_next;

  
    //
    // Microcode
    //
    reg  [UOP_ADDR_WIDTH-1:0] uop_addr;
    wire [UOP_DATA_WIDTH-1:0] uop_data;
    
    wire [4:0] uop_data_opcode        = uop_data[1 + 3*6 +: 5];
    wire       uop_data_banks         = uop_data[0 + 3*6 +: 1];
    wire [5:0] uop_data_operand_src1  = uop_data[0 + 2*6 +: 6];
    wire [5:0] uop_data_operand_src2  = uop_data[0 + 1*6 +: 6];
    wire [5:0] uop_data_operand_dst   = uop_data[0 + 0*6 +: 6];
    
    wire uop_data_opcode_is_stop = uop_data_opcode[4];
    wire uop_data_opcode_is_copy = uop_data_opcode[0];
    
    ed25519_microcode microcode
    (
        .clk    (clk),
        .addr   (uop_addr),
        .data   (uop_data)
    );
    
    
    //
    // Microcode Address Increment Logic
    //
    always @(posedge clk)
        //
        if (fsm_state_next == FSM_STATE_FETCH)
            uop_addr <= (fsm_state == FSM_STATE_IDLE) ? uop_offset : uop_addr + 1'b1;


    //
    // Multi-Word Mover
    //
    reg  mw_mover_ena = 1'b0;
    wire mw_mover_rdy;
    
    wire [WORD_COUNTER_WIDTH-1:0]   mw_mover_x_addr;
    wire [WORD_COUNTER_WIDTH-1:0]   mw_mover_y_addr;
    wire [                32-1:0]   mw_mover_x_din;
    wire [                32-1:0]   mw_mover_y_dout;
    wire                            mw_mover_y_wren;
    
    mw_mover #
    (
        .WORD_COUNTER_WIDTH     (WORD_COUNTER_WIDTH),
        .OPERAND_NUM_WORDS      (OPERAND_NUM_WORDS)
    )
    mw_mover_inst
    (
        .clk        (clk),
        .rst_n      (rst_n),
        .ena        (mw_mover_ena),
        .rdy        (mw_mover_rdy),
        .x_addr     (mw_mover_x_addr),
        .y_addr     (mw_mover_y_addr),
        .y_wren     (mw_mover_y_wren),
        .x_din      (mw_mover_x_din),
        .y_dout     (mw_mover_y_dout)
    );
    
            
    //
    // uOP Trigger Logic
    //
    always @(posedge clk)
        //
        if (fsm_state == FSM_STATE_DECODE) begin
            mw_mover_ena   <= uop_data_opcode_is_copy;
        end else begin
            mw_mover_ena   <= 1'b0;
        end

    
    //
    // uOP Completion Detector
    //
    reg fsm_exit_from_busy;
    
    always @* begin
        //
        fsm_exit_from_busy = 0;
        //
        if (uop_data_opcode_is_copy)    fsm_exit_from_busy = ~mw_mover_ena & mw_mover_rdy;
        //
    end

    
        
        //
        // Banks
        //
    reg     [ 2:0]  banks_src1_addr;
    reg     [ 2:0]  banks_src2_addr;
    reg     [ 2:0]  banks_dst_addr;
    
    reg             banks_dst_wren;
    
    reg     [31:0]  banks_dst_din;

    wire    [31:0]  banks_src1_dout;
    wire    [31:0]  banks_src2_dout;    
    
    ed25519_banks banks
    (
        .clk            (clk),
    
        .banks          (uop_data_banks),
    
        .src1_operand   (uop_data_operand_src1),
        .src2_operand   (uop_data_operand_src2),
        .dst_operand    (uop_data_operand_dst),
    
        .src1_addr      (banks_src1_addr),
        .src2_addr      (banks_src2_addr),
        .dst_addr       (banks_dst_addr),
    
        .dst_wren       (banks_dst_wren),
    
        .src1_dout      (banks_src1_dout),
        .src2_dout      (banks_src2_dout),
    
        .dst_din        (banks_dst_din)
    );
    
    assign mw_mover_x_din = banks_src1_dout;
    
    always @*
        //
        case (uop_data_opcode)
            //
            UOP_OPCODE_COPY: begin
                //
                banks_src1_addr = mw_mover_x_addr;
                banks_src2_addr = 'bX;
                //
                banks_dst_addr  = mw_mover_y_addr;
                //
                banks_dst_wren  = mw_mover_y_wren;
                //
                banks_dst_din   = mw_mover_y_dout;
                //
            end
            //
            //UOP_OPCODE_ADD:     d
            //UOP_OPCODE_SUB:     d
            //UOP_OPCODE_MUL:     d
            //
            default: begin
                //
                banks_src1_addr = 'bX;
                banks_src2_addr = 'bX;
                //
                banks_dst_addr  = 'bX;
                //
                banks_dst_wren  = 'b0;
                //
                banks_dst_din   = 'bX;
            end
            //
        endcase
    
    //addr
    //wren
    //dout
    //din
    
    
    //
    // FSM Process
    //
    always @(posedge clk or negedge rst_n)
        //
        if (rst_n == 1'b0)  fsm_state <= FSM_STATE_IDLE;
        else                fsm_state <= fsm_state_next;
    
    
    //
    // FSM Transition Logic
    //
    always @* begin
        //
        fsm_state_next = FSM_STATE_IDLE;
        //
        case (fsm_state)
            FSM_STATE_IDLE:     fsm_state_next = ena                     ? FSM_STATE_FETCH : FSM_STATE_IDLE;
            FSM_STATE_FETCH:    fsm_state_next = FSM_STATE_DECODE;
            FSM_STATE_DECODE:   fsm_state_next = uop_data_opcode_is_stop ? FSM_STATE_IDLE  : FSM_STATE_BUSY;
            FSM_STATE_BUSY:     fsm_state_next = fsm_exit_from_busy      ? FSM_STATE_FETCH : FSM_STATE_BUSY;
        endcase
        //
    end


    //
    // Ready Flag Logic
    //
    reg rdy_reg = 1'b1;
    assign rdy = rdy_reg;

    always @(posedge clk or negedge rst_n)
        //
        if (rst_n == 1'b0)      rdy_reg <= 1'b1;
        else case (fsm_state)
            FSM_STATE_IDLE:     rdy_reg <= ~ena;
            FSM_STATE_DECODE:   rdy_reg <= uop_data_opcode_is_stop;
        endcase


endmodule


//------------------------------------------------------------------------------
// End-of-File
//------------------------------------------------------------------------------