[Cryptech-Commits] [staging/core/hash/sha512] 08/09: Adding work factor processing functionality.

git at cryptech.is git at cryptech.is
Tue Mar 17 13:15:20 UTC 2015


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch master
in repository staging/core/hash/sha512.

commit fa8db082f8f945c87abf808b3b692f367a21d159
Author: Joachim Strömbergson <joachim at secworks.se>
Date:   Thu Nov 20 10:38:46 2014 +0100

    Adding work factor processing functionality.
---
 src/rtl/sha512.v      | 450 ++++++++++++++++++++++++++++----------------------
 src/rtl/sha512_core.v | 187 ++++++++++++++-------
 src/tb/tb_sha512.v    | 334 +++++++++++++++++++++----------------
 3 files changed, 569 insertions(+), 402 deletions(-)

diff --git a/src/rtl/sha512.v b/src/rtl/sha512.v
index c9c388b..0d26b85 100644
--- a/src/rtl/sha512.v
+++ b/src/rtl/sha512.v
@@ -9,30 +9,30 @@
 // Author: Joachim Strombergson
 // Copyright (c) 2014, SUNET
 // 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, 
+//
+// 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 
+// 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.
 //
 //======================================================================
@@ -41,11 +41,11 @@ module sha512(
               // 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,
@@ -56,70 +56,73 @@ module sha512(
   //----------------------------------------------------------------
   // Internal constant and parameter definitions.
   //----------------------------------------------------------------
-  parameter ADDR_NAME0         = 8'h00;
-  parameter ADDR_NAME1         = 8'h01;
-  parameter ADDR_VERSION       = 8'h02;
-  
-  parameter ADDR_CTRL          = 8'h08;
-  parameter CTRL_INIT_BIT      = 0;
-  parameter CTRL_NEXT_BIT      = 1;
-  parameter CTRL_MODE_LOW_BIT  = 2;
-  parameter CTRL_MODE_HIGH_BIT = 3;
-
-  parameter ADDR_STATUS        = 8'h09;
-  parameter STATUS_READY_BIT   = 0;
-  parameter STATUS_VALID_BIT   = 1;
-                             
-  parameter ADDR_BLOCK0        = 8'h10;
-  parameter ADDR_BLOCK1        = 8'h11;
-  parameter ADDR_BLOCK2        = 8'h12;
-  parameter ADDR_BLOCK3        = 8'h13;
-  parameter ADDR_BLOCK4        = 8'h14;
-  parameter ADDR_BLOCK5        = 8'h15;
-  parameter ADDR_BLOCK6        = 8'h16;
-  parameter ADDR_BLOCK7        = 8'h17;
-  parameter ADDR_BLOCK8        = 8'h18;
-  parameter ADDR_BLOCK9        = 8'h19;
-  parameter ADDR_BLOCK10       = 8'h1a;
-  parameter ADDR_BLOCK11       = 8'h1b;
-  parameter ADDR_BLOCK12       = 8'h1c;
-  parameter ADDR_BLOCK13       = 8'h1d;
-  parameter ADDR_BLOCK14       = 8'h1e;
-  parameter ADDR_BLOCK15       = 8'h1f;
-  parameter ADDR_BLOCK16       = 8'h20;
-  parameter ADDR_BLOCK17       = 8'h21;
-  parameter ADDR_BLOCK18       = 8'h22;
-  parameter ADDR_BLOCK19       = 8'h23;
-  parameter ADDR_BLOCK20       = 8'h24;
-  parameter ADDR_BLOCK21       = 8'h25;
-  parameter ADDR_BLOCK22       = 8'h26;
-  parameter ADDR_BLOCK23       = 8'h27;
-  parameter ADDR_BLOCK24       = 8'h28;
-  parameter ADDR_BLOCK25       = 8'h29;
-  parameter ADDR_BLOCK26       = 8'h2a;
-  parameter ADDR_BLOCK27       = 8'h2b;
-  parameter ADDR_BLOCK28       = 8'h2c;
-  parameter ADDR_BLOCK29       = 8'h2d;
-  parameter ADDR_BLOCK30       = 8'h2e;
-  parameter ADDR_BLOCK31       = 8'h2f;
-                             
-  parameter ADDR_DIGEST0       = 8'h40;
-  parameter ADDR_DIGEST1       = 8'h41;
-  parameter ADDR_DIGEST2       = 8'h42;
-  parameter ADDR_DIGEST3       = 8'h43;
-  parameter ADDR_DIGEST4       = 8'h44;
-  parameter ADDR_DIGEST5       = 8'h45;
-  parameter ADDR_DIGEST6       = 8'h46;
-  parameter ADDR_DIGEST7       = 8'h47;
-  parameter ADDR_DIGEST8       = 8'h48;
-  parameter ADDR_DIGEST9       = 8'h49;
-  parameter ADDR_DIGEST10      = 8'h4a;
-  parameter ADDR_DIGEST11      = 8'h4b;
-  parameter ADDR_DIGEST12      = 8'h4c;
-  parameter ADDR_DIGEST13      = 8'h4d;
-  parameter ADDR_DIGEST14      = 8'h4e;
-  parameter ADDR_DIGEST15      = 8'h4f;
-  
+  parameter ADDR_NAME0           = 8'h00;
+  parameter ADDR_NAME1           = 8'h01;
+  parameter ADDR_VERSION         = 8'h02;
+
+  parameter ADDR_CTRL            = 8'h08;
+  parameter CTRL_INIT_BIT        = 0;
+  parameter CTRL_NEXT_BIT        = 1;
+  parameter CTRL_MODE_LOW_BIT    = 2;
+  parameter CTRL_MODE_HIGH_BIT   = 3;
+  parameter CTRL_WORK_FACTOR_BIT = 7;
+
+  parameter ADDR_STATUS          = 8'h09;
+  parameter STATUS_READY_BIT     = 0;
+  parameter STATUS_VALID_BIT     = 1;
+
+  parameter ADDR_WORK_FACTOR_NUM = 8'h0a;
+
+  parameter ADDR_BLOCK0          = 8'h10;
+  parameter ADDR_BLOCK1          = 8'h11;
+  parameter ADDR_BLOCK2          = 8'h12;
+  parameter ADDR_BLOCK3          = 8'h13;
+  parameter ADDR_BLOCK4          = 8'h14;
+  parameter ADDR_BLOCK5          = 8'h15;
+  parameter ADDR_BLOCK6          = 8'h16;
+  parameter ADDR_BLOCK7          = 8'h17;
+  parameter ADDR_BLOCK8          = 8'h18;
+  parameter ADDR_BLOCK9          = 8'h19;
+  parameter ADDR_BLOCK10         = 8'h1a;
+  parameter ADDR_BLOCK11         = 8'h1b;
+  parameter ADDR_BLOCK12         = 8'h1c;
+  parameter ADDR_BLOCK13         = 8'h1d;
+  parameter ADDR_BLOCK14         = 8'h1e;
+  parameter ADDR_BLOCK15         = 8'h1f;
+  parameter ADDR_BLOCK16         = 8'h20;
+  parameter ADDR_BLOCK17         = 8'h21;
+  parameter ADDR_BLOCK18         = 8'h22;
+  parameter ADDR_BLOCK19         = 8'h23;
+  parameter ADDR_BLOCK20         = 8'h24;
+  parameter ADDR_BLOCK21         = 8'h25;
+  parameter ADDR_BLOCK22         = 8'h26;
+  parameter ADDR_BLOCK23         = 8'h27;
+  parameter ADDR_BLOCK24         = 8'h28;
+  parameter ADDR_BLOCK25         = 8'h29;
+  parameter ADDR_BLOCK26         = 8'h2a;
+  parameter ADDR_BLOCK27         = 8'h2b;
+  parameter ADDR_BLOCK28         = 8'h2c;
+  parameter ADDR_BLOCK29         = 8'h2d;
+  parameter ADDR_BLOCK30         = 8'h2e;
+  parameter ADDR_BLOCK31         = 8'h2f;
+
+  parameter ADDR_DIGEST0         = 8'h40;
+  parameter ADDR_DIGEST1         = 8'h41;
+  parameter ADDR_DIGEST2         = 8'h42;
+  parameter ADDR_DIGEST3         = 8'h43;
+  parameter ADDR_DIGEST4         = 8'h44;
+  parameter ADDR_DIGEST5         = 8'h45;
+  parameter ADDR_DIGEST6         = 8'h46;
+  parameter ADDR_DIGEST7         = 8'h47;
+  parameter ADDR_DIGEST8         = 8'h48;
+  parameter ADDR_DIGEST9         = 8'h49;
+  parameter ADDR_DIGEST10        = 8'h4a;
+  parameter ADDR_DIGEST11        = 8'h4b;
+  parameter ADDR_DIGEST12        = 8'h4c;
+  parameter ADDR_DIGEST13        = 8'h4d;
+  parameter ADDR_DIGEST14        = 8'h4e;
+  parameter ADDR_DIGEST15        = 8'h4f;
+
   parameter CORE_NAME0         = 32'h73686132; // "sha2"
   parameter CORE_NAME1         = 32'h2d353132; // "-512"
   parameter CORE_VERSION       = 32'h302e3830; // "0.80"
@@ -129,7 +132,9 @@ module sha512(
   parameter MODE_SHA_384       = 2'h2;
   parameter MODE_SHA_512       = 2'h3;
 
-  
+  parameter DEFAULT_WORK_FACTOR_NUM = 32'h000f0000;
+
+
   //----------------------------------------------------------------
   // Registers including update variables and write enable.
   //----------------------------------------------------------------
@@ -143,10 +148,17 @@ module sha512(
   reg next_we;
   reg next_set;
 
+  reg work_factor_reg;
+  reg work_factor_new;
+  reg work_factor_we;
+
   reg [1 : 0] mode_reg;
   reg [1 : 0] mode_new;
   reg         mode_we;
-  
+
+  reg [31 : 0] work_factor_num_reg;
+  reg          work_factor_num_we;
+
   reg ready_reg;
 
   reg [31 : 0] block0_reg;
@@ -213,17 +225,19 @@ module sha512(
   reg          block30_we;
   reg [31 : 0] block31_reg;
   reg          block31_we;
-  
+
   reg [511 : 0] digest_reg;
   reg           digest_valid_reg;
 
-  
+
   //----------------------------------------------------------------
   // Wires.
   //----------------------------------------------------------------
   wire            core_init;
   wire            core_next;
   wire [1 : 0]    core_mode;
+  wire            core_work_factor;
+  wire [31 : 0]   core_work_factor_num;
   wire            core_ready;
   wire [1023 : 0] core_block;
   wire [511 : 0]  core_digest;
@@ -231,49 +245,55 @@ module sha512(
 
   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_mode = mode_reg;
-  
-  assign core_block = {block0_reg,  block1_reg,  block2_reg,  block3_reg,  block4_reg,  
-                       block5_reg,  block6_reg,  block7_reg,  block8_reg,  block9_reg,  
-                       block10_reg, block11_reg, block12_reg, block13_reg, block14_reg, 
+
+  assign core_work_factor = work_factor_reg;
+  assign core_work_factor_num = work_factor_num_reg;
+
+  assign core_block = {block0_reg,  block1_reg,  block2_reg,  block3_reg,  block4_reg,
+                       block5_reg,  block6_reg,  block7_reg,  block8_reg,  block9_reg,
+                       block10_reg, block11_reg, block12_reg, block13_reg, block14_reg,
                        block15_reg, block16_reg, block17_reg, block18_reg, block19_reg,
-                       block20_reg, block21_reg, block22_reg, block23_reg, block24_reg, 
+                       block20_reg, block21_reg, block22_reg, block23_reg, block24_reg,
                        block25_reg, block26_reg, block27_reg, block28_reg, block29_reg,
                        block30_reg, block31_reg};
 
   assign read_data = tmp_read_data;
   assign error     = tmp_error;
-  
-             
+
+
   //----------------------------------------------------------------
   // core instantiation.
   //----------------------------------------------------------------
   sha512_core core(
                    .clk(clk),
                    .reset_n(reset_n),
-                   
+
                    .init(core_init),
                    .next(core_next),
                    .mode(core_mode),
-                  
+
+                   .work_factor(core_work_factor),
+                   .work_factor_num(core_work_factor_num),
+
                    .block(core_block),
-                   
+
                    .ready(core_ready),
-                   
+
                    .digest(core_digest),
                    .digest_valid(core_digest_valid)
                   );
-  
-  
+
+
   //----------------------------------------------------------------
   // reg_update
   //
@@ -285,44 +305,46 @@ module sha512(
     begin
       if (!reset_n)
         begin
-          init_reg         <= 0;
-          next_reg         <= 0;
-          mode_reg         <= MODE_SHA_512;
-          ready_reg        <= 0;
-          digest_reg       <= {16{32'h00000000}};
-          digest_valid_reg <= 0;
-          block0_reg       <= 32'h00000000;
-          block1_reg       <= 32'h00000000;
-          block2_reg       <= 32'h00000000;
-          block3_reg       <= 32'h00000000;
-          block4_reg       <= 32'h00000000;
-          block5_reg       <= 32'h00000000;
-          block6_reg       <= 32'h00000000;
-          block7_reg       <= 32'h00000000;
-          block8_reg       <= 32'h00000000;
-          block9_reg       <= 32'h00000000;
-          block10_reg      <= 32'h00000000;
-          block11_reg      <= 32'h00000000;
-          block12_reg      <= 32'h00000000;
-          block13_reg      <= 32'h00000000;
-          block14_reg      <= 32'h00000000;
-          block15_reg      <= 32'h00000000;
-          block16_reg      <= 32'h00000000;
-          block17_reg      <= 32'h00000000;
-          block18_reg      <= 32'h00000000;
-          block19_reg      <= 32'h00000000;
-          block20_reg      <= 32'h00000000;
-          block21_reg      <= 32'h00000000;
-          block22_reg      <= 32'h00000000;
-          block23_reg      <= 32'h00000000;
-          block24_reg      <= 32'h00000000;
-          block25_reg      <= 32'h00000000;
-          block26_reg      <= 32'h00000000;
-          block27_reg      <= 32'h00000000;
-          block28_reg      <= 32'h00000000;
-          block29_reg      <= 32'h00000000;
-          block30_reg      <= 32'h00000000;
-          block31_reg      <= 32'h00000000;
+          init_reg            <= 0;
+          next_reg            <= 0;
+          mode_reg            <= MODE_SHA_512;
+          work_factor_reg     <= 0;
+          work_factor_num_reg <= DEFAULT_WORK_FACTOR_NUM;
+          ready_reg           <= 0;
+          digest_reg          <= {16{32'h00000000}};
+          digest_valid_reg    <= 0;
+          block0_reg          <= 32'h00000000;
+          block1_reg          <= 32'h00000000;
+          block2_reg          <= 32'h00000000;
+          block3_reg          <= 32'h00000000;
+          block4_reg          <= 32'h00000000;
+          block5_reg          <= 32'h00000000;
+          block6_reg          <= 32'h00000000;
+          block7_reg          <= 32'h00000000;
+          block8_reg          <= 32'h00000000;
+          block9_reg          <= 32'h00000000;
+          block10_reg         <= 32'h00000000;
+          block11_reg         <= 32'h00000000;
+          block12_reg         <= 32'h00000000;
+          block13_reg         <= 32'h00000000;
+          block14_reg         <= 32'h00000000;
+          block15_reg         <= 32'h00000000;
+          block16_reg         <= 32'h00000000;
+          block17_reg         <= 32'h00000000;
+          block18_reg         <= 32'h00000000;
+          block19_reg         <= 32'h00000000;
+          block20_reg         <= 32'h00000000;
+          block21_reg         <= 32'h00000000;
+          block22_reg         <= 32'h00000000;
+          block23_reg         <= 32'h00000000;
+          block24_reg         <= 32'h00000000;
+          block25_reg         <= 32'h00000000;
+          block26_reg         <= 32'h00000000;
+          block27_reg         <= 32'h00000000;
+          block28_reg         <= 32'h00000000;
+          block29_reg         <= 32'h00000000;
+          block30_reg         <= 32'h00000000;
+          block31_reg         <= 32'h00000000;
         end
       else
         begin
@@ -343,7 +365,17 @@ module sha512(
             begin
               mode_reg <= mode_new;
             end
-          
+
+          if (work_factor_we)
+            begin
+              work_factor_reg <= work_factor_new;
+            end
+
+          if (work_factor_num_we)
+            begin
+              work_factor_num_reg <= write_data;
+            end
+
           if (core_digest_valid)
             begin
               digest_reg <= core_digest;
@@ -551,50 +583,53 @@ module sha512(
   //----------------------------------------------------------------
   // api_logic
   //
-  // Implementation of the api logic. If cs is enabled will either 
+  // Implementation of the api logic. If cs is enabled will either
   // try to write to or read from the internal registers.
   //----------------------------------------------------------------
   always @*
     begin : api_logic
-      init_set      = 0;
-      next_set      = 0;
-      mode_new      = 2'b00;
-      mode_we       = 0;
-      block0_we     = 0;
-      block1_we     = 0;
-      block2_we     = 0;
-      block3_we     = 0;
-      block4_we     = 0;
-      block5_we     = 0;
-      block6_we     = 0;
-      block7_we     = 0;
-      block8_we     = 0;
-      block9_we     = 0;
-      block10_we    = 0;
-      block11_we    = 0;
-      block12_we    = 0;
-      block13_we    = 0;
-      block14_we    = 0;
-      block15_we    = 0;
-      block16_we    = 0;
-      block17_we    = 0;
-      block18_we    = 0;
-      block19_we    = 0;
-      block20_we    = 0;
-      block21_we    = 0;
-      block22_we    = 0;
-      block23_we    = 0;
-      block24_we    = 0;
-      block25_we    = 0;
-      block26_we    = 0;
-      block27_we    = 0;
-      block28_we    = 0;
-      block29_we    = 0;
-      block30_we    = 0;
-      block31_we    = 0;
-      tmp_read_data = 32'h00000000;
-      tmp_error     = 0;
-      
+      init_set           = 0;
+      next_set           = 0;
+      mode_new           = 2'b00;
+      mode_we            = 0;
+      work_factor_new    = 0;
+      work_factor_we     = 0;
+      work_factor_num_we = 0;
+      block0_we          = 0;
+      block1_we          = 0;
+      block2_we          = 0;
+      block3_we          = 0;
+      block4_we          = 0;
+      block5_we          = 0;
+      block6_we          = 0;
+      block7_we          = 0;
+      block8_we          = 0;
+      block9_we          = 0;
+      block10_we         = 0;
+      block11_we         = 0;
+      block12_we         = 0;
+      block13_we         = 0;
+      block14_we         = 0;
+      block15_we         = 0;
+      block16_we         = 0;
+      block17_we         = 0;
+      block18_we         = 0;
+      block19_we         = 0;
+      block20_we         = 0;
+      block21_we         = 0;
+      block22_we         = 0;
+      block23_we         = 0;
+      block24_we         = 0;
+      block25_we         = 0;
+      block26_we         = 0;
+      block27_we         = 0;
+      block28_we         = 0;
+      block29_we         = 0;
+      block30_we         = 0;
+      block31_we         = 0;
+      tmp_read_data      = 32'h00000000;
+      tmp_error          = 0;
+
       if (cs)
         begin
           if (we)
@@ -603,12 +638,19 @@ module sha512(
                 // Write operations.
                 ADDR_CTRL:
                   begin
-                    init_set = write_data[CTRL_INIT_BIT];
-                    next_set = write_data[CTRL_NEXT_BIT];
-                    mode_new = write_data[CTRL_MODE_HIGH_BIT : CTRL_MODE_LOW_BIT];
-                    mode_we  = 1;
+                    init_set        = write_data[CTRL_INIT_BIT];
+                    next_set        = write_data[CTRL_NEXT_BIT];
+                    mode_new        = write_data[CTRL_MODE_HIGH_BIT : CTRL_MODE_LOW_BIT];
+                    work_factor_new = write_data[CTRL_WORK_FACTOR_BIT];
+                    work_factor_we  = 1;
+                    mode_we         = 1;
                   end
-                
+
+                ADDR_WORK_FACTOR_NUM:
+                  begin
+                    work_factor_num_we = 1;
+                  end
+
                 ADDR_BLOCK0:
                   begin
                     block0_we = 1;
@@ -768,7 +810,7 @@ module sha512(
                   begin
                     block31_we = 1;
                   end
-                
+
                 default:
                   begin
                     tmp_error = 1;
@@ -789,7 +831,7 @@ module sha512(
                   begin
                     tmp_read_data = CORE_NAME1;
                   end
-                
+
                 ADDR_VERSION:
                   begin
                     tmp_read_data = CORE_VERSION;
@@ -797,14 +839,20 @@ module sha512(
 
                 ADDR_CTRL:
                   begin
-                    tmp_read_data = {28'h0000000, mode_reg, next_reg, init_reg};
+                    tmp_read_data = {24'h000000, work_factor_reg, 3'b000,
+                                     mode_reg, next_reg, init_reg};
                   end
-                
+
                 ADDR_STATUS:
                   begin
                     tmp_read_data = {28'h0000000, 2'b00, digest_valid_reg, ready_reg};
                   end
-                
+
+                ADDR_WORK_FACTOR_NUM:
+                  begin
+                    tmp_read_data = work_factor_num_reg;
+                  end
+
                 ADDR_BLOCK0:
                   begin
                     tmp_read_data = block0_reg;
@@ -1004,7 +1052,7 @@ module sha512(
                   begin
                     tmp_read_data = digest_reg[287 : 256];
                   end
-                
+
                 ADDR_DIGEST8:
                   begin
                     tmp_read_data = digest_reg[255 : 224];
@@ -1044,7 +1092,7 @@ module sha512(
                   begin
                     tmp_read_data = digest_reg[31  :   0];
                   end
-                
+
                 default:
                   begin
                     tmp_error = 1;
diff --git a/src/rtl/sha512_core.v b/src/rtl/sha512_core.v
index 44af0b1..12742a8 100644
--- a/src/rtl/sha512_core.v
+++ b/src/rtl/sha512_core.v
@@ -45,6 +45,9 @@ module sha512_core(
                    input wire            next,
                    input wire [1 : 0]    mode,
 
+                   input wire            work_factor,
+                   input wire [31 : 0]   work_factor_num,
+
                    input wire [1023 : 0] block,
 
                    output wire           ready,
@@ -108,6 +111,13 @@ module sha512_core(
   reg         t_ctr_inc;
   reg         t_ctr_rst;
 
+  reg [31 : 0] work_factor_ctr_reg;
+  reg [31 : 0] work_factor_ctr_new;
+  reg          work_factor_ctr_rst;
+  reg          work_factor_ctr_inc;
+  reg          work_factor_ctr_done;
+  reg          work_factor_ctr_we;
+
   reg digest_valid_reg;
   reg digest_valid_new;
   reg digest_valid_we;
@@ -205,25 +215,26 @@ module sha512_core(
     begin : reg_update
       if (!reset_n)
         begin
-          a_reg            <= 64'h00000000;
-          b_reg            <= 64'h00000000;
-          c_reg            <= 64'h00000000;
-          d_reg            <= 64'h00000000;
-          e_reg            <= 64'h00000000;
-          f_reg            <= 64'h00000000;
-          g_reg            <= 64'h00000000;
-          h_reg            <= 64'h00000000;
-          H0_reg           <= 64'h00000000;
-          H1_reg           <= 64'h00000000;
-          H2_reg           <= 64'h00000000;
-          H3_reg           <= 64'h00000000;
-          H4_reg           <= 64'h00000000;
-          H5_reg           <= 64'h00000000;
-          H6_reg           <= 64'h00000000;
-          H7_reg           <= 64'h00000000;
-          digest_valid_reg <= 0;
-          t_ctr_reg        <= 7'h00;
-          sha512_ctrl_reg  <= CTRL_IDLE;
+          a_reg               <= 64'h0000000000000000;
+          b_reg               <= 64'h0000000000000000;
+          c_reg               <= 64'h0000000000000000;
+          d_reg               <= 64'h0000000000000000;
+          e_reg               <= 64'h0000000000000000;
+          f_reg               <= 64'h0000000000000000;
+          g_reg               <= 64'h0000000000000000;
+          h_reg               <= 64'h0000000000000000;
+          H0_reg              <= 64'h0000000000000000;
+          H1_reg              <= 64'h0000000000000000;
+          H2_reg              <= 64'h0000000000000000;
+          H3_reg              <= 64'h0000000000000000;
+          H4_reg              <= 64'h0000000000000000;
+          H5_reg              <= 64'h0000000000000000;
+          H6_reg              <= 64'h0000000000000000;
+          H7_reg              <= 64'h0000000000000000;
+          work_factor_ctr_reg <= 32'h00000000;
+          digest_valid_reg    <= 0;
+          t_ctr_reg           <= 7'h00;
+          sha512_ctrl_reg     <= CTRL_IDLE;
         end
       else
         begin
@@ -257,6 +268,11 @@ module sha512_core(
               t_ctr_reg <= t_ctr_new;
             end
 
+          if (work_factor_ctr_we)
+            begin
+              work_factor_ctr_reg <= work_factor_ctr_new;
+            end
+
           if (digest_valid_we)
             begin
               digest_valid_reg <= digest_valid_new;
@@ -442,32 +458,65 @@ module sha512_core(
 
 
   //----------------------------------------------------------------
+  // work_factor_ctr
+  //
+  // Work factor counter logic.
+  //----------------------------------------------------------------
+  always @*
+    begin : work_factor_ctr
+      work_factor_ctr_new  = 32'h00000000;
+      work_factor_ctr_we   = 0;
+      work_factor_ctr_done = 0;
+
+      if (work_factor_ctr_reg == work_factor_num)
+        begin
+          work_factor_ctr_done = 1;
+        end
+
+      if (work_factor_ctr_rst)
+        begin
+          work_factor_ctr_new  = 32'h00000000;
+          work_factor_ctr_we   = 1;
+        end
+
+      if (work_factor_ctr_inc)
+        begin
+          work_factor_ctr_new  = work_factor_ctr_reg + 1'b1;
+          work_factor_ctr_we   = 1;
+        end
+    end // work_factor_ctr
+
+
+  //----------------------------------------------------------------
   // sha512_ctrl_fsm
   //
   // Logic for the state machine controlling the core behaviour.
   //----------------------------------------------------------------
   always @*
     begin : sha512_ctrl_fsm
-      digest_init      = 0;
-      digest_update    = 0;
+      digest_init         = 0;
+      digest_update       = 0;
 
-      state_init       = 0;
-      state_update     = 0;
+      state_init          = 0;
+      state_update        = 0;
 
-      first_block      = 0;
-      ready_flag       = 0;
+      first_block         = 0;
+      ready_flag          = 0;
 
-      w_init           = 0;
-      w_next           = 0;
+      w_init              = 0;
+      w_next              = 0;
 
-      t_ctr_inc        = 0;
-      t_ctr_rst        = 0;
+      t_ctr_inc           = 0;
+      t_ctr_rst           = 0;
 
-      digest_valid_new = 0;
-      digest_valid_we  = 0;
+      digest_valid_new    = 0;
+      digest_valid_we     = 0;
 
-      sha512_ctrl_new  = CTRL_IDLE;
-      sha512_ctrl_we   = 0;
+      work_factor_ctr_rst = 0;
+      work_factor_ctr_inc = 0;
+
+      sha512_ctrl_new     = CTRL_IDLE;
+      sha512_ctrl_we      = 0;
 
 
       case (sha512_ctrl_reg)
@@ -477,26 +526,28 @@ module sha512_core(
 
             if (init)
               begin
-                digest_init      = 1;
-                w_init           = 1;
-                state_init       = 1;
-                first_block      = 1;
-                t_ctr_rst        = 1;
-                digest_valid_new = 0;
-                digest_valid_we  = 1;
-                sha512_ctrl_new  = CTRL_ROUNDS;
-                sha512_ctrl_we   = 1;
+                work_factor_ctr_rst = 1;
+                digest_init         = 1;
+                w_init              = 1;
+                state_init          = 1;
+                first_block         = 1;
+                t_ctr_rst           = 1;
+                digest_valid_new    = 0;
+                digest_valid_we     = 1;
+                sha512_ctrl_new     = CTRL_ROUNDS;
+                sha512_ctrl_we      = 1;
               end
 
             if (next)
               begin
-                w_init           = 1;
-                state_init       = 1;
-                t_ctr_rst        = 1;
-                digest_valid_new = 0;
-                digest_valid_we  = 1;
-                sha512_ctrl_new  = CTRL_ROUNDS;
-                sha512_ctrl_we   = 1;
+                work_factor_ctr_rst = 1;
+                w_init              = 1;
+                state_init          = 1;
+                t_ctr_rst           = 1;
+                digest_valid_new    = 0;
+                digest_valid_we     = 1;
+                sha512_ctrl_new     = CTRL_ROUNDS;
+                sha512_ctrl_we      = 1;
               end
           end
 
@@ -509,20 +560,42 @@ module sha512_core(
 
             if (t_ctr_reg == SHA512_ROUNDS)
               begin
-                sha512_ctrl_new = CTRL_DONE;
-                sha512_ctrl_we  = 1;
+                work_factor_ctr_inc = 1;
+                sha512_ctrl_new     = CTRL_DONE;
+                sha512_ctrl_we      = 1;
               end
           end
 
 
         CTRL_DONE:
           begin
-            digest_update    = 1;
-            digest_valid_new = 1;
-            digest_valid_we  = 1;
-
-            sha512_ctrl_new  = CTRL_IDLE;
-            sha512_ctrl_we   = 1;
+            if (work_factor)
+              begin
+                if (!work_factor_ctr_done)
+                  begin
+                    w_init              = 1;
+                    state_init          = 1;
+                    t_ctr_rst           = 1;
+                    sha512_ctrl_new     = CTRL_ROUNDS;
+                    sha512_ctrl_we      = 1;
+                  end
+                else
+                  begin
+                    digest_update    = 1;
+                    digest_valid_new = 1;
+                    digest_valid_we  = 1;
+                    sha512_ctrl_new  = CTRL_IDLE;
+                    sha512_ctrl_we   = 1;
+                  end
+              end
+            else
+              begin
+                digest_update    = 1;
+                digest_valid_new = 1;
+                digest_valid_we  = 1;
+                sha512_ctrl_new  = CTRL_IDLE;
+                sha512_ctrl_we   = 1;
+              end
           end
       endcase // case (sha512_ctrl_reg)
     end // sha512_ctrl_fsm
diff --git a/src/tb/tb_sha512.v b/src/tb/tb_sha512.v
index f84ef56..c993cfc 100644
--- a/src/tb/tb_sha512.v
+++ b/src/tb/tb_sha512.v
@@ -8,30 +8,30 @@
 // Author: Joachim Strombergson
 // Copyright (c) 2014, SUNET
 // 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, 
+//
+// 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 
+// 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.
 //
 //======================================================================
@@ -46,7 +46,7 @@
 // Test module.
 //------------------------------------------------------------------
 module tb_sha512();
-  
+
   //----------------------------------------------------------------
   // Internal constant and parameter definitions.
   //----------------------------------------------------------------
@@ -55,87 +55,91 @@ module tb_sha512();
   parameter CLK_PERIOD      = 2;
   parameter CLK_HALF_PERIOD = CLK_PERIOD / 2;
 
-  
+
   // The address map.
-  parameter ADDR_NAME0         = 8'h00;
-  parameter ADDR_NAME1         = 8'h01;
-  parameter ADDR_VERSION       = 8'h02;
-
-  parameter ADDR_CTRL          = 8'h08;
-  parameter CTRL_INIT_BIT      = 0;
-  parameter CTRL_NEXT_BIT      = 1;
-  parameter CTRL_MODE_LOW_BIT  = 2;
-  parameter CTRL_MODE_HIGH_BIT = 3;
-  parameter CTRL_INIT_VALUE    = 2'h01;
-  parameter CTRL_NEXT_VALUE    = 2'h02;
-
-  parameter ADDR_STATUS        = 8'h09;
-  parameter STATUS_READY_BIT   = 0;
-  parameter STATUS_VALID_BIT   = 1;
-                             
-  parameter ADDR_BLOCK0        = 8'h10;
-  parameter ADDR_BLOCK1        = 8'h11;
-  parameter ADDR_BLOCK2        = 8'h12;
-  parameter ADDR_BLOCK3        = 8'h13;
-  parameter ADDR_BLOCK4        = 8'h14;
-  parameter ADDR_BLOCK5        = 8'h15;
-  parameter ADDR_BLOCK6        = 8'h16;
-  parameter ADDR_BLOCK7        = 8'h17;
-  parameter ADDR_BLOCK8        = 8'h18;
-  parameter ADDR_BLOCK9        = 8'h19;
-  parameter ADDR_BLOCK10       = 8'h1a;
-  parameter ADDR_BLOCK11       = 8'h1b;
-  parameter ADDR_BLOCK12       = 8'h1c;
-  parameter ADDR_BLOCK13       = 8'h1d;
-  parameter ADDR_BLOCK14       = 8'h1e;
-  parameter ADDR_BLOCK15       = 8'h1f;
-  parameter ADDR_BLOCK16       = 8'h20;
-  parameter ADDR_BLOCK17       = 8'h21;
-  parameter ADDR_BLOCK18       = 8'h22;
-  parameter ADDR_BLOCK19       = 8'h23;
-  parameter ADDR_BLOCK20       = 8'h24;
-  parameter ADDR_BLOCK21       = 8'h25;
-  parameter ADDR_BLOCK22       = 8'h26;
-  parameter ADDR_BLOCK23       = 8'h27;
-  parameter ADDR_BLOCK24       = 8'h28;
-  parameter ADDR_BLOCK25       = 8'h29;
-  parameter ADDR_BLOCK26       = 8'h2a;
-  parameter ADDR_BLOCK27       = 8'h2b;
-  parameter ADDR_BLOCK28       = 8'h2c;
-  parameter ADDR_BLOCK29       = 8'h2d;
-  parameter ADDR_BLOCK30       = 8'h2e;
-  parameter ADDR_BLOCK31       = 8'h2f;
-                             
-  parameter ADDR_DIGEST0       = 8'h40;
-  parameter ADDR_DIGEST1       = 8'h41;
-  parameter ADDR_DIGEST2       = 8'h42;
-  parameter ADDR_DIGEST3       = 8'h43;
-  parameter ADDR_DIGEST4       = 8'h44;
-  parameter ADDR_DIGEST5       = 8'h45;
-  parameter ADDR_DIGEST6       = 8'h46;
-  parameter ADDR_DIGEST7       = 8'h47;
-  parameter ADDR_DIGEST8       = 8'h48;
-  parameter ADDR_DIGEST9       = 8'h49;
-  parameter ADDR_DIGEST10      = 8'h4a;
-  parameter ADDR_DIGEST11      = 8'h4b;
-  parameter ADDR_DIGEST12      = 8'h4c;
-  parameter ADDR_DIGEST13      = 8'h4d;
-  parameter ADDR_DIGEST14      = 8'h4e;
-  parameter ADDR_DIGEST15      = 8'h4f;
-
-
-  parameter MODE_SHA_512_224 = 0;
-  parameter MODE_SHA_512_256 = 1;
-  parameter MODE_SHA_384     = 2;
-  parameter MODE_SHA_512     = 3;
-
-  
+  parameter ADDR_NAME0           = 8'h00;
+  parameter ADDR_NAME1           = 8'h01;
+  parameter ADDR_VERSION         = 8'h02;
+
+  parameter ADDR_CTRL            = 8'h08;
+  parameter CTRL_INIT_BIT        = 0;
+  parameter CTRL_NEXT_BIT        = 1;
+  parameter CTRL_MODE_LOW_BIT    = 2;
+  parameter CTRL_MODE_HIGH_BIT   = 3;
+  parameter CTRL_WORK_FACTOR_BIT = 7;
+
+  parameter ADDR_STATUS          = 8'h09;
+  parameter STATUS_READY_BIT     = 0;
+  parameter STATUS_VALID_BIT     = 1;
+
+  parameter ADDR_WORK_FACTOR_NUM = 8'h0a;
+
+  parameter ADDR_BLOCK0          = 8'h10;
+  parameter ADDR_BLOCK1          = 8'h11;
+  parameter ADDR_BLOCK2          = 8'h12;
+  parameter ADDR_BLOCK3          = 8'h13;
+  parameter ADDR_BLOCK4          = 8'h14;
+  parameter ADDR_BLOCK5          = 8'h15;
+  parameter ADDR_BLOCK6          = 8'h16;
+  parameter ADDR_BLOCK7          = 8'h17;
+  parameter ADDR_BLOCK8          = 8'h18;
+  parameter ADDR_BLOCK9          = 8'h19;
+  parameter ADDR_BLOCK10         = 8'h1a;
+  parameter ADDR_BLOCK11         = 8'h1b;
+  parameter ADDR_BLOCK12         = 8'h1c;
+  parameter ADDR_BLOCK13         = 8'h1d;
+  parameter ADDR_BLOCK14         = 8'h1e;
+  parameter ADDR_BLOCK15         = 8'h1f;
+  parameter ADDR_BLOCK16         = 8'h20;
+  parameter ADDR_BLOCK17         = 8'h21;
+  parameter ADDR_BLOCK18         = 8'h22;
+  parameter ADDR_BLOCK19         = 8'h23;
+  parameter ADDR_BLOCK20         = 8'h24;
+  parameter ADDR_BLOCK21         = 8'h25;
+  parameter ADDR_BLOCK22         = 8'h26;
+  parameter ADDR_BLOCK23         = 8'h27;
+  parameter ADDR_BLOCK24         = 8'h28;
+  parameter ADDR_BLOCK25         = 8'h29;
+  parameter ADDR_BLOCK26         = 8'h2a;
+  parameter ADDR_BLOCK27         = 8'h2b;
+  parameter ADDR_BLOCK28         = 8'h2c;
+  parameter ADDR_BLOCK29         = 8'h2d;
+  parameter ADDR_BLOCK30         = 8'h2e;
+  parameter ADDR_BLOCK31         = 8'h2f;
+
+  parameter ADDR_DIGEST0         = 8'h40;
+  parameter ADDR_DIGEST1         = 8'h41;
+  parameter ADDR_DIGEST2         = 8'h42;
+  parameter ADDR_DIGEST3         = 8'h43;
+  parameter ADDR_DIGEST4         = 8'h44;
+  parameter ADDR_DIGEST5         = 8'h45;
+  parameter ADDR_DIGEST6         = 8'h46;
+  parameter ADDR_DIGEST7         = 8'h47;
+  parameter ADDR_DIGEST8         = 8'h48;
+  parameter ADDR_DIGEST9         = 8'h49;
+  parameter ADDR_DIGEST10        = 8'h4a;
+  parameter ADDR_DIGEST11        = 8'h4b;
+  parameter ADDR_DIGEST12        = 8'h4c;
+  parameter ADDR_DIGEST13        = 8'h4d;
+  parameter ADDR_DIGEST14        = 8'h4e;
+  parameter ADDR_DIGEST15        = 8'h4f;
+
+  parameter MODE_SHA_512_224     = 2'h0;
+  parameter MODE_SHA_512_256     = 2'h1;
+  parameter MODE_SHA_384         = 2'h2;
+  parameter MODE_SHA_512         = 2'h3;
+
+  parameter CTRL_INIT_VALUE        = 2'h1;
+  parameter CTRL_NEXT_VALUE        = 2'h2;
+  parameter CTRL_WORK_FACTOR_VALUE = 1'h1;
+
+
   //----------------------------------------------------------------
   // Register and Wire declarations.
   //----------------------------------------------------------------
-  reg [31 : 0] cycle_ctr;
-  reg [31 : 0] error_ctr;
-  reg [31 : 0] tc_ctr;
+  reg [31 : 0]  cycle_ctr;
+  reg [31 : 0]  error_ctr;
+  reg [31 : 0]  tc_ctr;
 
   reg           tb_clk;
   reg           tb_reset_n;
@@ -148,36 +152,36 @@ module tb_sha512();
 
   reg [31 : 0]  read_data;
   reg [511 : 0] digest_data;
-  
-  
+
+
   //----------------------------------------------------------------
   // Device Under Test.
   //----------------------------------------------------------------
   sha512 dut(
              .clk(tb_clk),
              .reset_n(tb_reset_n),
-             
+
              .cs(tb_cs),
              .we(tb_we),
-             
-             
+
+
              .address(tb_address),
              .write_data(tb_write_data),
              .read_data(tb_read_data),
              .error(tb_error)
             );
-  
+
 
   //----------------------------------------------------------------
   // clk_gen
   //
-  // Clock generator process. 
+  // Clock generator process.
   //----------------------------------------------------------------
-  always 
+  always
     begin : clk_gen
       #CLK_HALF_PERIOD tb_clk = !tb_clk;
     end // clk_gen
-    
+
 
   //----------------------------------------------------------------
   // sys_monitor
@@ -191,7 +195,7 @@ module tb_sha512();
       cycle_ctr = cycle_ctr + 1;
     end
 
-  
+
   //----------------------------------------------------------------
   // dump_dut_state()
   //
@@ -202,20 +206,20 @@ module tb_sha512();
       $display("State of DUT");
       $display("------------");
       $display("Inputs and outputs:");
-      $display("cs = 0x%01x, we = 0x%01x", 
+      $display("cs = 0x%01x, we = 0x%01x",
                dut.cs, dut.we);
       $display("address = 0x%02x", dut.address);
-      $display("write_data = 0x%08x, read_data = 0x%08x", 
+      $display("write_data = 0x%08x, read_data = 0x%08x",
                dut.write_data, dut.read_data);
       $display("tmp_read_data = 0x%08x", dut.tmp_read_data);
       $display("");
 
       $display("Control and status:");
-      $display("ctrl = 0x%02x, status = 0x%02x", 
-               {dut.next_reg, dut.init_reg}, 
+      $display("ctrl = 0x%02x, status = 0x%02x",
+               {dut.next_reg, dut.init_reg},
                {dut.digest_valid_reg, dut.ready_reg});
       $display("");
-      
+
       $display("Message block:");
       $display("block0  = 0x%08x, block1  = 0x%08x, block2  = 0x%08x,  block3  = 0x%08x",
                dut.block0_reg, dut.block1_reg, dut.block2_reg, dut.block3_reg);
@@ -238,15 +242,15 @@ module tb_sha512();
                dut.block28_reg, dut.block29_reg, dut.block30_reg, dut.block31_reg);
 
       $display("");
-      
+
       $display("Digest:");
       $display("digest = 0x%0128x", dut.digest_reg);
       $display("");
-      
+
     end
   endtask // dump_dut_state
-  
-  
+
+
   //----------------------------------------------------------------
   // reset_dut()
   //
@@ -263,7 +267,7 @@ module tb_sha512();
     end
   endtask // reset_dut
 
-  
+
   //----------------------------------------------------------------
   // init_sim()
   //
@@ -275,7 +279,7 @@ module tb_sha512();
       cycle_ctr = 32'h00000000;
       error_ctr = 32'h00000000;
       tc_ctr    = 32'h00000000;
-      
+
       tb_clk        = 0;
       tb_reset_n    = 0;
       tb_cs         = 0;
@@ -285,7 +289,7 @@ module tb_sha512();
     end
   endtask // init_dut
 
-  
+
   //----------------------------------------------------------------
   // display_test_result()
   //
@@ -304,8 +308,8 @@ module tb_sha512();
         end
     end
   endtask // display_test_result
-  
-  
+
+
   //----------------------------------------------------------------
   // wait_ready()
   //
@@ -319,14 +323,14 @@ module tb_sha512();
   task wait_ready();
     begin
       read_data = 0;
-      
+
       while (read_data == 0)
         begin
           read_word(ADDR_STATUS);
         end
     end
   endtask // wait_ready
-  
+
 
   //----------------------------------------------------------------
   // write_word()
@@ -341,7 +345,7 @@ module tb_sha512();
           $display("*** Writing 0x%08x to 0x%02x.", word, address);
           $display("");
         end
-         
+
       tb_address = address;
       tb_write_data = word;
       tb_cs = 1;
@@ -394,7 +398,7 @@ module tb_sha512();
       write_word(ADDR_BLOCK31, block[31   :   0]);
     end
   endtask // write_block
-  
+
 
   //----------------------------------------------------------------
   // read_word()
@@ -420,7 +424,7 @@ module tb_sha512();
     end
   endtask // read_word
 
-  
+
   //----------------------------------------------------------------
   // check_name_version()
   //
@@ -491,7 +495,7 @@ module tb_sha512();
       digest_data[31  :   0] = read_data;
     end
   endtask // read_digest
-  
+
 
   //----------------------------------------------------------------
   // get_mask()
@@ -583,12 +587,12 @@ module tb_sha512();
           $display("TC%01d: Got:      0x%0128x", tc_ctr, masked_data);
           error_ctr = error_ctr + 1;
         end
-      $display("*** TC%01d - Single block test done.", tc_ctr); 
+      $display("*** TC%01d - Single block test done.", tc_ctr);
       tc_ctr = tc_ctr + 1;
     end
   endtask // single_block_test
-    
-  
+
+
   //----------------------------------------------------------------
   // double_block_test()
   //
@@ -605,9 +609,10 @@ module tb_sha512();
                         );
     reg [511 : 0] mask;
     reg [511 : 0] masked_data1;
+    reg [31 :  0] ctrl_cmd;
 
     begin
-      $display("*** TC%01d - Double block test started.", tc_ctr); 
+      $display("*** TC%01d - Double block test started.", tc_ctr);
 
       // First block
       write_block(block0);
@@ -634,7 +639,7 @@ module tb_sha512();
       #(CLK_PERIOD);
       wait_ready();
       read_digest();
-      
+
       mask = get_mask(mode);
       masked_data1 = digest_data & mask;
 
@@ -650,15 +655,53 @@ module tb_sha512();
           error_ctr = error_ctr + 1;
         end
 
-      $display("*** TC%01d - Double block test done.", tc_ctr); 
+      $display("*** TC%01d - Double block test done.", tc_ctr);
       tc_ctr = tc_ctr + 1;
     end
   endtask // double_block_test
 
-    
+
+  //----------------------------------------------------------------
+  // work_factor_test()
+  //
+  // Perform test of the work factor function.
+  //----------------------------------------------------------------
+  task work_factor_test();
+    reg [1023 : 0] my_block;
+    reg [511 :  0] my_digest;
+    reg [31 : 0]   my_ctrl_cmd;
+
+    begin
+      $display("*** TC%01d - Work factor test started.", tc_ctr);
+
+      // Read out work factor number.
+      read_word(ADDR_WORK_FACTOR_NUM);
+
+      // Trying to change the work factor number.
+      write_word(ADDR_WORK_FACTOR_NUM, 32'h00000003);
+      read_word(ADDR_WORK_FACTOR_NUM);
+
+      // Set block to all zero
+      my_block = {16{64'h0000000000000000}};
+      write_block(my_block);
+
+      // Set init+ work factor. We use SHA-512 mode.
+      my_ctrl_cmd = 32'h00000000 + (CTRL_WORK_FACTOR_VALUE << 7) +
+                    (MODE_SHA_512 << 2) + CTRL_INIT_VALUE;
+      write_word(ADDR_CTRL, my_ctrl_cmd);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      $display("*** TC%01d - Work factor test done.", tc_ctr);
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // work_factor_test
+
+
   //----------------------------------------------------------------
   // sha512_test
-  // The main test functionality. 
+  // The main test functionality.
   //
   // Test cases taken from:
   // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
@@ -670,7 +713,7 @@ module tb_sha512();
       reg [511 : 0]  tc2_expected;
       reg [511 : 0]  tc3_expected;
       reg [511 : 0]  tc4_expected;
-      
+
       reg [1024 : 0] double_block_one;
       reg [1024 : 0] double_block_two;
       reg [511 : 0]  tc5_expected;
@@ -681,7 +724,7 @@ module tb_sha512();
       reg [511 : 0]  tc10_expected;
       reg [511 : 0]  tc11_expected;
       reg [511 : 0]  tc12_expected;
-      
+
       $display("   -- Testbench for sha512 started --");
 
       init_sim();
@@ -700,7 +743,7 @@ module tb_sha512();
       // SHA-512 single block digest and test.
       tc1_expected = 512'hDDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F;
       single_block_test(8'h01, MODE_SHA_512, single_block, tc1_expected);
-      
+
       // SHA-512_224 single block digest and test.
       tc2_expected = {224'h4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA, {9{32'h00000000}}};
       single_block_test(8'h02, MODE_SHA_512_224, single_block, tc2_expected);
@@ -738,10 +781,13 @@ module tb_sha512();
       tc12_expected = {384'h09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039, {4{32'h00000000}}};
       double_block_test(8'h08, MODE_SHA_384, double_block_one, double_block_two, tc11_expected, tc12_expected);
 
+      // Work factor test.
+      work_factor_test();
+
       dump_dut_state();
-      
+
       display_test_result();
-      
+
       $display("   -- Testbench for sha512 done. --");
       $finish;
     end // sha512_test



More information about the Commits mailing list