//====================================================================== // // chacha.v // -------- // Top level wrapper for the ChaCha stream, cipher core providing // a simple memory like interface with 32 bit data access. // // // Author: Joachim Strombergson // Copyright (c) 2011, 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 chacha( // Clock and reset. input wire clk, input wire reset_n, // Control. input wire cs, input wire we, // Data ports. input wire [7 : 0] address, input wire [31 : 0] write_data, output wire [31 : 0] read_data, output wire error ); //---------------------------------------------------------------- // Internal constant and parameter definitions. //---------------------------------------------------------------- parameter ADDR_CTRL = 8'h00; parameter CTRL_INIT_BIT = 0; parameter CTRL_NEXT_BIT = 1; parameter ADDR_STATUS = 8'h01; parameter STATUS_READY_BIT = 0; parameter ADDR_KEYLEN = 8'h08; parameter KEYLEN_BIT = 0; parameter ADDR_ROUNDS = 8'h09; parameter ROUNDS_HIGH_BIT = 4; parameter ROUNDS_LOW_BIT = 0; parameter ADDR_KEY0 = 8'h10; parameter ADDR_KEY1 = 8'h11; parameter ADDR_KEY2 = 8'h12; parameter ADDR_KEY3 = 8'h13; parameter ADDR_KEY4 = 8'h14; parameter ADDR_KEY5 = 8'h15; parameter ADDR_KEY6 = 8'h16; parameter ADDR_KEY7 = 8'h17; parameter ADDR_IV0 = 8'h20; parameter ADDR_IV1 = 8'h21; parameter ADDR_DATA_IN0 = 8'h40; parameter ADDR_DATA_IN1 = 8'h41; parameter ADDR_DATA_IN2 = 8'h42; parameter ADDR_DATA_IN3 = 8'h43; parameter ADDR_DATA_IN4 = 8'h44; parameter ADDR_DATA_IN5 = 8'h45; parameter ADDR_DATA_IN6 = 8'h46; parameter ADDR_DATA_IN7 = 8'h47; parameter ADDR_DATA_IN8 = 8'h48; parameter ADDR_DATA_IN9 = 8'h49; parameter ADDR_DATA_IN10 = 8'h4a; parameter ADDR_DATA_IN11 = 8'h4b; parameter ADDR_DATA_IN12 = 8'h4c; parameter ADDR_DATA_IN13 = 8'h4d; parameter ADDR_DATA_IN14 = 8'h4e; parameter ADDR_DATA_IN15 = 8'h4f; parameter ADDR_DATA_OUT0 = 8'h80; parameter ADDR_DATA_OUT1 = 8'h81; parameter ADDR_DATA_OUT2 = 8'h82; parameter ADDR_DATA_OUT3 = 8'h83; parameter ADDR_DATA_OUT4 = 8'h84; parameter ADDR_DATA_OUT5 = 8'h85; parameter ADDR_DATA_OUT6 = 8'h86; parameter ADDR_DATA_OUT7 = 8'h87; parameter ADDR_DATA_OUT8 = 8'h88; parameter ADDR_DATA_OUT9 = 8'h89; parameter ADDR_DATA_OUT10 = 8'h8a; parameter ADDR_DATA_OUT11 = 8'h8b; parameter ADDR_DATA_OUT12 = 8'h8c; parameter ADDR_DATA_OUT13 = 8'h8d; parameter ADDR_DATA_OUT14 = 8'h8e; parameter ADDR_DATA_OUT15 = 8'h8f; parameter DEFAULT_CTR_INIT = 64'h0000000000000000; //---------------------------------------------------------------- // Registers including update variables and write enable. //---------------------------------------------------------------- reg init_reg; reg next_reg; reg ctrl_we; reg ready_reg; reg keylen_reg; reg keylen_we; reg [4 : 0] rounds_reg; reg rounds_we; reg data_out_valid_reg; reg [31 : 0] key0_reg; reg key0_we; reg [31 : 0] key1_reg; reg key1_we; reg [31 : 0] key2_reg; reg key2_we; reg [31 : 0] key3_reg; reg key3_we; reg [31 : 0] key4_reg; reg key4_we; reg [31 : 0] key5_reg; reg key5_we; reg [31 : 0] key6_reg; reg key6_we; reg [31 : 0] key7_reg; reg key7_we; reg [31 : 0] iv0_reg; reg iv0_we; reg [31 : 0] iv1_reg; reg iv1_we; reg [31 : 0] data_in0_reg; reg data_in0_we; reg [31 : 0] data_in1_reg; reg data_in1_we; reg [31 : 0] data_in2_reg; reg data_in2_we; reg [31 : 0] data_in3_reg; reg data_in3_we; reg [31 : 0] data_in4_reg; reg data_in4_we; reg [31 : 0] data_in5_reg; reg data_in5_we; reg [31 : 0] data_in6_reg; reg data_in6_we; reg [31 : 0] data_in7_reg; reg data_in7_we; reg [31 : 0] data_in8_reg; reg data_in8_we; reg [31 : 0] data_in9_reg; reg data_in9_we; reg [31 : 0] data_in10_reg; reg data_in10_we; reg [31 : 0] data_in11_reg; reg data_in11_we; reg [31 : 0] data_in12_reg; reg data_in12_we; reg [31 : 0] data_in13_reg; reg data_in13_we; reg [31 : 0] data_in14_reg; reg data_in14_we; reg [31 : 0] data_in15_reg; reg data_in15_we; reg [31 : 0] data_out0_reg; reg [31 : 0] data_out0_new; reg [31 : 0] data_out1_reg; reg [31 : 0] data_out1_new; reg [31 : 0] data_out2_reg; reg [31 : 0] data_out2_new; reg [31 : 0] data_out3_reg; reg [31 : 0] data_out3_new; reg [31 : 0] data_out4_reg; reg [31 : 0] data_out4_new; reg [31 : 0] data_out5_reg; reg [31 : 0] data_out5_new; reg [31 : 0] data_out6_reg; reg [31 : 0] data_out6_new; reg [31 : 0] data_out7_reg; reg [31 : 0] data_out7_new; reg [31 : 0] data_out8_reg; reg [31 : 0] data_out8_new; reg [31 : 0] data_out9_reg; reg [31 : 0] data_out9_new; reg [31 : 0] data_out10_reg; reg [31 : 0] data_out10_new; reg [31 : 0] data_out11_reg; reg [31 : 0] data_out11_new; reg [31 : 0] data_out12_reg; reg [31 : 0] data_out12_new; reg [31 : 0] data_out13_reg; reg [31 : 0] data_out13_new; reg [31 : 0] data_out14_reg; reg [31 : 0] data_out14_new; reg [31 : 0] data_out15_reg; reg [31 : 0] data_out15_new; //---------------------------------------------------------------- // Wires. //---------------------------------------------------------------- wire core_init; wire core_next; wire [255 : 0] core_key; wire core_keylen; wire [4 : 0] core_rounds; wire [63 : 0] core_iv; wire core_ready; wire [511 : 0] core_data_in; wire [511 : 0] core_data_out; wire core_data_out_valid; reg [31 : 0] tmp_read_data; reg tmp_error; //---------------------------------------------------------------- // Concurrent connectivity for ports etc. //---------------------------------------------------------------- assign core_init = init_reg; assign core_next = next_reg; assign core_keylen = keylen_reg; assign core_rounds = rounds_reg; assign core_key = {key0_reg, key1_reg, key2_reg, key3_reg, key4_reg, key5_reg, key6_reg, key7_reg}; assign core_iv = {iv0_reg, iv1_reg}; assign core_data_in = {data_in0_reg, data_in1_reg, data_in2_reg, data_in3_reg, data_in4_reg, data_in5_reg, data_in6_reg, data_in7_reg, data_in8_reg, data_in9_reg, data_in10_reg, data_in11_reg, data_in12_reg, data_in13_reg, data_in14_reg, data_in15_reg}; assign read_data = tmp_read_data; assign error = tmp_error; //---------------------------------------------------------------- // core instantiation. //---------------------------------------------------------------- chacha_core core ( .clk(clk), .reset_n(reset_n), .init(core_init), .next(core_next), .key(core_key), .keylen(core_keylen), .iv(core_iv), .ctr(DEFAULT_CTR_INIT), .rounds(core_rounds), .data_in(core_data_in), .ready(core_ready), .data_out(core_data_out), .data_out_valid(core_data_out_valid) ); //---------------------------------------------------------------- // reg_update // Update functionality for all registers in the core. // All registers are positive edge triggered with asynchronous // active low reset. //---------------------------------------------------------------- always @ (posedge clk or negedge reset_n) begin if (!reset_n) begin init_reg <= 0; next_reg <= 0; ready_reg <= 0; keylen_reg <= 0; rounds_reg <= 5'b00000; data_out_valid_reg <= 0; key0_reg <= 32'h00000000; key1_reg <= 32'h00000000; key2_reg <= 32'h00000000; key3_reg <= 32'h00000000; key4_reg <= 32'h00000000; key5_reg <= 32'h00000000; key6_reg <= 32'h00000000; key7_reg <= 32'h00000000; iv0_reg <= 32'h00000000; iv1_reg <= 32'h00000000; data_in0_reg <= 32'h00000000; data_in1_reg <= 32'h00000000; data_in2_reg <= 32'h00000000; data_in3_reg <= 32'h00000000; data_in4_reg <= 32'h00000000; data_in5_reg <= 32'h00000000; data_in6_reg <= 32'h00000000; data_in7_reg <= 32'h00000000; data_in8_reg <= 32'h00000000; data_in9_reg <= 32'h00000000; data_in10_reg <= 32'h00000000; data_in11_reg <= 32'h00000000; data_in12_reg <= 32'h00000000; data_in13_reg <= 32'h00000000; data_in14_reg <= 32'h00000000; data_in15_reg <= 32'h00000000; data_out0_reg <= 32'h00000000; data_out1_reg <= 32'h00000000; data_out2_reg <= 32'h00000000; data_out3_reg <= 32'h00000000; data_out4_reg <= 32'h00000000; data_out5_reg <= 32'h00000000; data_out6_reg <= 32'h00000000; data_out7_reg <= 32'h00000000; data_out8_reg <= 32'h00000000; data_out9_reg <= 32'h00000000; data_out10_reg <= 32'h00000000; data_out11_reg <= 32'h00000000; data_out12_reg <= 32'h00000000; data_out13_reg <= 32'h00000000; data_out14_reg <= 32'h00000000; data_out15_reg <= 32'h00000000; end else begin ready_reg <= core_ready; data_out_valid_reg <= core_data_out_valid; if (ctrl_we) begin init_reg <= write_data[CTRL_INIT_BIT]; next_reg <= write_data[CTRL_NEXT_BIT]; end if (keylen_we) begin keylen_reg <= write_data[KEYLEN_BIT]; end if (rounds_we) begin rounds_reg <= write_data[ROUNDS_HIGH_BIT : ROUNDS_LOW_BIT]; end if (key0_we) begin key0_reg <= write_data; end if (key1_we) begin key1_reg <= write_data; end if (key2_we) begin key2_reg <= write_data; end if (key3_we) begin key3_reg <= write_data; end if (key4_we) begin key4_reg <= write_data; end if (key5_we) begin key5_reg <= write_data; end if (key6_we) begin key6_reg <= write_data; end if (key7_we) begin key7_reg <= write_data; end if (iv0_we) begin iv0_reg <= write_data; end if (iv1_we) begin iv1_reg <= write_data; end if (data_in0_we) begin data_in0_reg <= write_data; end if (data_in1_we) begin data_in1_reg <= write_data; end if (data_in2_we) begin data_in2_reg <= write_data; end if (data_in3_we) begin data_in3_reg <= write_data; end if (data_in4_we) begin data_in4_reg <= write_data; end if (data_in5_we) begin data_in5_reg <= write_data; end if (data_in6_we) begin data_in6_reg <= write_data; end if (data_in7_we) begin data_in7_reg <= write_data; end if (data_in8_we) begin data_in8_reg <= write_data; end if (data_in9_we) begin data_in9_reg <= write_data; end if (data_in10_we) begin data_in10_reg <= write_data; end if (data_in11_we) begin data_in11_reg <= write_data; end if (data_in12_we) begin data_in12_reg <= write_data; end if (data_in13_we) begin data_in13_reg <= write_data; end if (data_in14_we) begin data_in14_reg <= write_data; end if (data_in15_we) begin data_in15_reg <= write_data; end if (core_data_out_valid) begin data_out0_reg <= core_data_out[511 : 480]; data_out1_reg <= core_data_out[479 : 448]; data_out2_reg <= core_data_out[447 : 416]; data_out3_reg <= core_data_out[415 : 384]; data_out4_reg <= core_data_out[383 : 352]; data_out5_reg <= core_data_out[351 : 320]; data_out6_reg <= core_data_out[319 : 288]; data_out7_reg <= core_data_out[287 : 256]; data_out8_reg <= core_data_out[255 : 224]; data_out9_reg <= core_data_out[223 : 192]; data_out10_reg <= core_data_out[191 : 160]; data_out11_reg <= core_data_out[159 : 128]; data_out12_reg <= core_data_out[127 : 96]; data_out13_reg <= core_data_out[95 : 64]; data_out14_reg <= core_data_out[63 : 32]; data_out15_reg <= core_data_out[31 : 0]; end end end // reg_update //---------------------------------------------------------------- // Address decoder logic. //---------------------------------------------------------------- always @* begin : addr_decoder ctrl_we = 0; keylen_we = 0; rounds_we = 0; key0_we = 0; key1_we = 0; key2_we = 0; key3_we = 0; key4_we = 0; key5_we = 0; key6_we = 0; key7_we = 0; iv0_we = 0; iv1_we = 0; data_in0_we = 0; data_in1_we = 0; data_in2_we = 0; data_in3_we = 0; data_in4_we = 0; data_in5_we = 0; data_in6_we = 0; data_in7_we = 0; data_in8_we = 0; data_in9_we = 0; data_in10_we = 0; data_in11_we = 0; data_in12_we = 0; data_in13_we = 0; data_in14_we = 0; data_in15_we = 0; tmp_read_data = 32'h00000000; tmp_error = 0; if (cs) begin if (we) begin case (address) ADDR_CTRL: begin ctrl_we = 1; end ADDR_KEYLEN: begin keylen_we = 1; end ADDR_ROUNDS: begin rounds_we = 1; end ADDR_KEY0: begin key0_we = 1; end ADDR_KEY1: begin key1_we = 1; end ADDR_KEY2: begin key2_we = 1; end ADDR_KEY3: begin key3_we = 1; end ADDR_KEY4: begin key4_we = 1; end ADDR_KEY5: begin key5_we = 1; end ADDR_KEY6: begin key6_we = 1; end ADDR_KEY7: begin key7_we = 1; end ADDR_IV0: begin iv0_we = 1; end ADDR_IV1: begin iv1_we = 1; end ADDR_DATA_IN0: begin data_in0_we = 1; end ADDR_DATA_IN1: begin data_in1_we = 1; end ADDR_DATA_IN2: begin data_in2_we = 1; end ADDR_DATA_IN3: begin data_in3_we = 1; end ADDR_DATA_IN4: begin data_in4_we = 1; end ADDR_DATA_IN5: begin data_in5_we = 1; end ADDR_DATA_IN6: begin data_in6_we = 1; end ADDR_DATA_IN7: begin data_in7_we = 1; end ADDR_DATA_IN8: begin data_in8_we = 1; end ADDR_DATA_IN9: begin data_in9_we = 1; end ADDR_DATA_IN10: begin data_in10_we = 1; end ADDR_DATA_IN11: begin data_in11_we = 1; end ADDR_DATA_IN12: begin data_in12_we = 1; end ADDR_DATA_IN13: begin data_in13_we = 1; end ADDR_DATA_IN14: begin data_in14_we = 1; end ADDR_DATA_IN15: begin data_in15_we = 1; end default: begin tmp_error = 1; end endcase // case (address) end // if (we) else begin case (address) ADDR_CTRL: begin tmp_read_data = {28'h0000000, 2'b00, next_reg, init_reg}; end ADDR_STATUS: begin tmp_read_data = {28'h0000000, 2'b00, {data_out_valid_reg, ready_reg}}; end ADDR_KEYLEN: begin tmp_read_data = {28'h0000000, 3'b000, keylen_reg}; end ADDR_ROUNDS: begin tmp_read_data = {24'h000000, 3'b000, rounds_reg}; end ADDR_KEY0: begin tmp_read_data = key0_reg; end ADDR_KEY1: begin tmp_read_data = key1_reg; end ADDR_KEY2: begin tmp_read_data = key2_reg; end ADDR_KEY3: begin tmp_read_data = key3_reg; end ADDR_KEY4: begin tmp_read_data = key4_reg; end ADDR_KEY5: begin tmp_read_data = key5_reg; end ADDR_KEY6: begin tmp_read_data = key6_reg; end ADDR_KEY7: begin tmp_read_data = key7_reg; end ADDR_IV0: begin tmp_read_data = iv0_reg; end ADDR_IV1: begin tmp_read_data = iv1_reg; end ADDR_DATA_OUT0: begin tmp_read_data = data_out0_reg; end ADDR_DATA_OUT1: begin tmp_read_data = data_out1_reg; end ADDR_DATA_OUT2: begin tmp_read_data = data_out2_reg; end ADDR_DATA_OUT3: begin tmp_read_data = data_out3_reg; end ADDR_DATA_OUT4: begin tmp_read_data = data_out4_reg; end ADDR_DATA_OUT5: begin tmp_read_data = data_out5_reg; end ADDR_DATA_OUT6: begin tmp_read_data = data_out6_reg; end ADDR_DATA_OUT7: begin tmp_read_data = data_out7_reg; end ADDR_DATA_OUT8: begin tmp_read_data = data_out8_reg; end ADDR_DATA_OUT9: begin tmp_read_data = data_out9_reg; end ADDR_DATA_OUT10: begin tmp_read_data = data_out10_reg; end ADDR_DATA_OUT11: begin tmp_read_data = data_out11_reg; end ADDR_DATA_OUT12: begin tmp_read_data = data_out12_reg; end ADDR_DATA_OUT13: begin tmp_read_data = data_out13_reg; end ADDR_DATA_OUT14: begin tmp_read_data = data_out14_reg; end ADDR_DATA_OUT15: begin tmp_read_data = data_out15_reg; end default: begin tmp_error = 1; end endcase // case (address) end end end // addr_decoder endmodule // chacha //====================================================================== // EOF chacha.v //======================================================================