[Cryptech-Commits] [user/paul/core] 01/01: Reorganize 'core' source tree.

git at cryptech.is git at cryptech.is
Wed Feb 18 19:21:09 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 user/paul/core.

commit f117851934d38aae0862ec05c10a4c101fc7fbf5
Author: Paul Selkirk <paul at psgd.org>
Date:   Wed Feb 18 14:19:35 2015 -0500

    Reorganize 'core' source tree.
    
    - Promote eim to top level, along with uart and i2c.
    - Put all the Novena specifics in novena repo (eim is generic-ish),
      and build both i2c and eim bitfiles and testers out of novena.
    - Replace coretest_hashes with Pavel's core_selector.
    - Replace Joachim's sha wrappers with my test versions.
---
 core_selector/src/rtl/cipher_selector.v            |  117 ++
 core_selector/src/rtl/core_selector.v              |  182 +++
 core_selector/src/rtl/hash_selector.v              |  264 +++++
 core_selector/src/rtl/rng_selector.v               |  112 ++
 coretest/LICENSE                                   |   24 +
 coretest/README.md                                 |  176 +++
 coretest/src/rtl/coretest.v                        | 1209 ++++++++++++++++++++
 coretest/src/sw/seriedebug.py                      |  118 ++
 coretest/src/tb/tb_coretest.v                      |  492 ++++++++
 coretest/toolruns/Makefile                         |   75 ++
 coretest/toolruns/modelsim/coretest_wave.do        |   80 ++
 eim/src/rtl/cdc_bus_pulse.v                        |  145 +++
 eim/src/rtl/eim.v                                  |   75 ++
 eim/src/rtl/eim_arbiter.v                          |  309 +++++
 eim/src/rtl/eim_arbiter_cdc.v                      |  143 +++
 eim/src/rtl/eim_da_phy.v                           |   77 ++
 eim/src/rtl/eim_indicator.v                        |   69 ++
 i2c/LICENSE                                        |   24 +
 i2c/README.md                                      |    7 +
 i2c/src/rtl/i2c.v                                  |  217 ++++
 i2c/src/rtl/i2c_core.v                             |  580 ++++++++++
 novena/build/.gitignore                            |   52 +
 novena/build/Makefile.eim                          |   39 +
 novena/build/Makefile.i2c                          |   36 +
 novena/build/xilinx.mk                             |  174 +++
 novena/build/xilinx.opt                            |   42 +
 .../novena_reorg_eim/novena_reorg_eim.xise         |  466 ++++++++
 .../novena_reorg_i2c/novena_reorg_i2c.xise         |  438 +++++++
 novena/src/rtl/ipcore/_xmsgs/cg.xmsgs              |   27 +
 novena/src/rtl/ipcore/_xmsgs/pn_parser.xmsgs       |   15 +
 novena/src/rtl/ipcore/clkmgr_dcm.asy               |   25 +
 novena/src/rtl/ipcore/clkmgr_dcm.gise              |   31 +
 novena/src/rtl/ipcore/clkmgr_dcm.ncf               |   60 +
 novena/src/rtl/ipcore/clkmgr_dcm.sym               |   24 +
 novena/src/rtl/ipcore/clkmgr_dcm.ucf               |   59 +
 novena/src/rtl/ipcore/clkmgr_dcm.v                 |  148 +++
 novena/src/rtl/ipcore/clkmgr_dcm.veo               |   79 ++
 novena/src/rtl/ipcore/clkmgr_dcm.xco               |  269 +++++
 novena/src/rtl/ipcore/clkmgr_dcm.xdc               |   67 ++
 novena/src/rtl/ipcore/clkmgr_dcm.xise              |   74 ++
 .../rtl/ipcore/clkmgr_dcm/clk_wiz_v3_6_readme.txt  |  184 +++
 .../ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_readme.txt  |  184 +++
 .../ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_vinfo.html  |  195 ++++
 .../rtl/ipcore/clkmgr_dcm/doc/pg065_clk_wiz.pdf    |  Bin 0 -> 42657 bytes
 .../clkmgr_dcm/example_design/clkmgr_dcm_exdes.ucf |   60 +
 .../clkmgr_dcm/example_design/clkmgr_dcm_exdes.v   |  164 +++
 .../clkmgr_dcm/example_design/clkmgr_dcm_exdes.xdc |   69 ++
 .../rtl/ipcore/clkmgr_dcm/implement/implement.bat  |   90 ++
 .../rtl/ipcore/clkmgr_dcm/implement/implement.sh   |   91 ++
 .../ipcore/clkmgr_dcm/implement/planAhead_ise.bat  |   58 +
 .../ipcore/clkmgr_dcm/implement/planAhead_ise.sh   |   59 +
 .../ipcore/clkmgr_dcm/implement/planAhead_ise.tcl  |   78 ++
 .../ipcore/clkmgr_dcm/implement/planAhead_rdn.bat  |   58 +
 .../ipcore/clkmgr_dcm/implement/planAhead_rdn.sh   |   57 +
 .../ipcore/clkmgr_dcm/implement/planAhead_rdn.tcl  |   69 ++
 novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.prj |    2 +
 novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.scr |    9 +
 .../ipcore/clkmgr_dcm/simulation/clkmgr_dcm_tb.v   |  145 +++
 .../clkmgr_dcm/simulation/functional/simcmds.tcl   |    8 +
 .../simulation/functional/simulate_isim.bat        |   59 +
 .../simulation/functional/simulate_isim.sh         |   61 +
 .../simulation/functional/simulate_mti.bat         |   61 +
 .../simulation/functional/simulate_mti.do          |   65 ++
 .../simulation/functional/simulate_mti.sh          |   61 +
 .../simulation/functional/simulate_ncsim.sh        |   62 +
 .../simulation/functional/simulate_vcs.sh          |   72 ++
 .../simulation/functional/ucli_commands.key        |    5 +
 .../simulation/functional/vcs_session.tcl          |   18 +
 .../clkmgr_dcm/simulation/functional/wave.do       |   60 +
 .../clkmgr_dcm/simulation/functional/wave.sv       |  118 ++
 .../clkmgr_dcm/simulation/timing/clkmgr_dcm_tb.v   |  149 +++
 .../clkmgr_dcm/simulation/timing/sdf_cmd_file      |    2 +
 .../clkmgr_dcm/simulation/timing/simcmds.tcl       |    9 +
 .../clkmgr_dcm/simulation/timing/simulate_isim.sh  |   62 +
 .../clkmgr_dcm/simulation/timing/simulate_mti.bat  |   59 +
 .../clkmgr_dcm/simulation/timing/simulate_mti.do   |   65 ++
 .../clkmgr_dcm/simulation/timing/simulate_mti.sh   |   61 +
 .../clkmgr_dcm/simulation/timing/simulate_ncsim.sh |   64 ++
 .../clkmgr_dcm/simulation/timing/simulate_vcs.sh   |   72 ++
 .../clkmgr_dcm/simulation/timing/ucli_commands.key |    5 +
 .../clkmgr_dcm/simulation/timing/vcs_session.tcl   |    1 +
 .../ipcore/clkmgr_dcm/simulation/timing/wave.do    |   71 ++
 novena/src/rtl/ipcore/clkmgr_dcm_flist.txt         |   54 +
 novena/src/rtl/ipcore/clkmgr_dcm_xmdf.tcl          |  140 +++
 novena/src/rtl/ipcore/coregen.cgp                  |    9 +
 novena/src/rtl/ipcore/create_clkmgr_dcm.tcl        |   37 +
 novena/src/rtl/ipcore/edit_clkmgr_dcm.tcl          |   37 +
 novena/src/rtl/novena_clkmgr.v                     |  143 +++
 novena/src/rtl/novena_eim.v                        |  175 +++
 novena/src/rtl/novena_i2c.v                        |  218 ++++
 novena/src/rtl/novena_regs.v                       |  126 ++
 novena/src/sw/Makefile                             |   17 +
 novena/src/sw/hash_tester_eim.c                    |  876 ++++++++++++++
 novena/src/sw/hash_tester_i2c.c                    | 1013 ++++++++++++++++
 novena/src/sw/novena-eim.c                         |  708 ++++++++++++
 novena/src/sw/novena-eim.h                         |   52 +
 novena/src/ucf/novena_eim.ucf                      |  152 +++
 novena/src/ucf/novena_i2c.ucf                      |   82 ++
 sha1/LICENSE.txt                                   |   24 +
 sha1/README.md                                     |  125 ++
 sha1/src/model/python/sha1.py                      |  269 +++++
 sha1/src/rtl/sha1.v                                |  204 ++++
 sha1/src/rtl/sha1_core.v                           |  443 +++++++
 sha1/src/rtl/sha1_w_mem.v                          |  343 ++++++
 sha1/src/tb/tb_sha1.v                              |  589 ++++++++++
 sha1/src/tb/tb_sha1_core.v                         |  388 +++++++
 sha1/src/tb/tb_sha1_w_mem.v                        |  287 +++++
 sha1/toolruns/Makefile                             |  102 ++
 sha256/LICENSE.txt                                 |   24 +
 sha256/README.md                                   |  113 ++
 sha256/src/model/sha256.py                         |  344 ++++++
 sha256/src/rtl/sha256.v                            |  204 ++++
 sha256/src/rtl/sha256_core.v                       |  519 +++++++++
 sha256/src/rtl/sha256_k_constants.v                |  387 +++++++
 sha256/src/rtl/sha256_w_mem.v                      |  345 ++++++
 sha256/src/rtl/wb_sha256.v                         |  674 +++++++++++
 sha256/src/tb/tb_sha256.v                          |  556 +++++++++
 sha256/src/tb/tb_sha256_core.v                     |  406 +++++++
 sha256/src/tb/tb_sha256_w_mem.v                    |  222 ++++
 sha256/src/tb/tb_wb_sha256.v                       |  556 +++++++++
 sha256/toolruns/Makefile                           |  117 ++
 sha512/LICENSE                                     |   24 +
 sha512/README.md                                   |   41 +
 sha512/src/model/python/sha512.py                  |  345 ++++++
 sha512/src/rtl/sha512.v                            |  241 ++++
 sha512/src/rtl/sha512_core.v                       |  607 ++++++++++
 sha512/src/rtl/sha512_h_constants.v                |  143 +++
 sha512/src/rtl/sha512_k_constants.v                |  472 ++++++++
 sha512/src/rtl/sha512_w_mem.v                      |  346 ++++++
 sha512/src/tb/tb_sha512.v                          |  798 +++++++++++++
 sha512/src/tb/tb_sha512_core.v                     |  535 +++++++++
 sha512/toolruns/Makefile                           |   96 ++
 132 files changed, 24190 insertions(+)

diff --git a/core_selector/src/rtl/cipher_selector.v b/core_selector/src/rtl/cipher_selector.v
new file mode 100644
index 0000000..ea18e14
--- /dev/null
+++ b/core_selector/src/rtl/cipher_selector.v
@@ -0,0 +1,117 @@
+//======================================================================
+//
+// cipher_selector.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of external interface, coretest
+// and the core to be tested. And if more than one core is
+// present the wrapper also includes address and data muxes.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk, Pavel Shatov
+// Copyright (c) 2014-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 cipher_selector
+  (
+   input wire           sys_clk,
+   input wire           sys_rst,
+   input wire           sys_ena,
+
+   input wire [13: 0]   sys_eim_addr,
+   input wire           sys_eim_wr,
+   input wire           sys_eim_rd,
+   output wire [31 : 0] sys_read_data,
+   input wire [31 : 0]  sys_write_data
+   );
+
+
+   //
+   // Output Register
+   //
+   reg [31: 0]          tmp_read_data;
+   assign sys_read_data = tmp_read_data;
+   
+
+   /* So far we have no CIPHER cores, let's make some dummy 32-bit registers here
+    * to prevent ISE from complaining that we don't use input ports.
+    */
+   
+   reg [31: 0]          reg_dummy_first;
+   reg [31: 0]          reg_dummy_second;
+   reg [31: 0]          reg_dummy_third;
+   
+   always @(posedge sys_clk)
+     //
+     if (sys_rst)
+       begin
+          reg_dummy_first  <= {8{4'hD}};
+          reg_dummy_second <= {8{4'hE}};
+          reg_dummy_third  <= {8{4'hF}};
+       end
+     else if (sys_ena)
+       begin
+          //
+          if (sys_eim_wr)
+            begin
+               //
+               // WRITE handler
+               //
+               case (sys_eim_addr)
+                 14'd0: reg_dummy_first  <= sys_write_data;
+                 14'd1: reg_dummy_second <= sys_write_data;
+                 14'd2: reg_dummy_third  <= sys_write_data;
+               endcase
+               //
+            end
+          //
+          if (sys_eim_rd)
+            begin
+               //
+               // READ handler
+               //
+               case (sys_eim_addr)
+                 14'd0: tmp_read_data   <= reg_dummy_first;
+                 14'd1: tmp_read_data   <= reg_dummy_second;
+                 14'd2: tmp_read_data   <= reg_dummy_third;
+                 //
+                 default: tmp_read_data <= {32{1'b0}};  // read non-existent locations as zeroes
+               endcase
+               //
+            end
+          //
+       end
+   
+
+endmodule
+
+//======================================================================
+// EOF core_selector.v
+//======================================================================
diff --git a/core_selector/src/rtl/core_selector.v b/core_selector/src/rtl/core_selector.v
new file mode 100644
index 0000000..4200b15
--- /dev/null
+++ b/core_selector/src/rtl/core_selector.v
@@ -0,0 +1,182 @@
+//======================================================================
+//
+// coretest_hashes.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of external interface, coretest
+// and the core to be tested. And if more than one core is
+// present the wrapper also includes address and data muxes.
+//
+//
+// Author: Pavel Shatov
+// Copyright (c) 2014-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 core_selector
+  (
+   input wire          sys_clk,
+   input wire          sys_rst,
+
+   input wire [16: 0]  sys_eim_addr,
+   input wire          sys_eim_wr,
+   input wire          sys_eim_rd,
+   output wire [31: 0] sys_read_data,
+   input wire [31: 0]  sys_write_data
+   );
+   
+   
+   /* Three upper bits of address [16:14] are used to select memory segment.
+    * There can be eight segments. So far segment 0 is used for hashes,
+    * segment 1 is reserved for random number generators, segment 2 is reserved
+    * for chiphers. Other segments are not used so far.
+    */
+   
+   /* Every segment has its own memory map, take at look at corresponding
+    * selectors for more information.
+    */
+   
+   //----------------------------------------------------------------
+   // Segment Decoder
+   //----------------------------------------------------------------
+   localparam   SEGMENT_ADDR_HASHES     = 3'd0;
+   localparam   SEGMENT_ADDR_RNGS       = 3'd1;
+   localparam   SEGMENT_ADDR_CIPHERS    = 3'd2;
+
+   wire [ 2: 0] addr_segment            = sys_eim_addr[16:14];  //  3 upper bits are decoded here
+   wire [13: 0] addr_segment_int        = sys_eim_addr[13: 0];  // 14 lower bits are decoded individually
+   // in corresponding segment selectors
+   
+   wire [31: 0] segment_hashes_read_data;               // data read from HASHES segment
+   wire [31: 0] segment_rngs_read_data;                 // data read from RNGS segment
+   wire [31: 0] segment_ciphers_read_data;              // data read from CIPHERS segment
+   
+   wire         segment_enable_hashes   = (addr_segment == SEGMENT_ADDR_HASHES)  ? 1'b1 : 1'b0; // HASHES segment is being addressed
+   wire         segment_enable_rngs     = (addr_segment == SEGMENT_ADDR_RNGS)    ? 1'b1 : 1'b0; // RNGS segment is being addressed
+   wire         segment_enable_ciphers  = (addr_segment == SEGMENT_ADDR_CIPHERS) ? 1'b1 : 1'b0; // CIPHERS segment is being addressed
+   
+   
+   //----------------------------------------------------------------
+   // Output (Read Data) Bus
+   //----------------------------------------------------------------
+   reg [31: 0]  sys_read_data_reg;
+   assign sys_read_data = sys_read_data_reg;
+   
+   always @*
+     //
+     case (addr_segment)
+       SEGMENT_ADDR_HASHES:     sys_read_data_reg = segment_hashes_read_data;
+       SEGMENT_ADDR_RNGS:       sys_read_data_reg = segment_rngs_read_data;
+       SEGMENT_ADDR_CIPHERS:    sys_read_data_reg = segment_ciphers_read_data;
+       default:                 sys_read_data_reg = {32{1'b0}};
+     endcase
+   
+   
+   
+   //----------------------------------------------------------------
+   // HASH Core Selector
+   //
+   // This selector is used to map core registers into
+   // EIM address space and select which core to send EIM read and
+   // write operations to.
+   //----------------------------------------------------------------
+   hash_selector segment_hashes
+     (
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .sys_ena(segment_enable_hashes),          // only enable active selector
+
+      .sys_eim_addr(addr_segment_int),          // we only connect 14 lower bits of address here,
+      // because we have already decoded 3 upper bits earlier,
+      // every segment can have its own address decoder.
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),                                          
+
+      .sys_write_data(sys_write_data),
+      .sys_read_data(segment_hashes_read_data)  // output from HASHES segment
+      );
+   
+   
+   //----------------------------------------------------------------
+   // RNG Selector
+   //
+   // This selector is used to map random number generator registers into
+   // EIM address space and select which RNG to send EIM read and
+   // write operations to. So far there are no RNG cores.
+   //----------------------------------------------------------------
+   rng_selector segment_rngs
+     (
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .sys_ena(segment_enable_rngs),            // only enable active selector
+
+      .sys_eim_addr(addr_segment_int),          // we only connect 14 lower bits of address here,
+      // because we have already decoded 3 upper bits earlier,
+      // every segment can have its own address decoder.
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),          
+
+      .sys_write_data(sys_write_data),
+      .sys_read_data(segment_rngs_read_data)    // output from RNGS segment
+      );
+   
+   
+   //----------------------------------------------------------------
+   // CIPHER Selector
+   //
+   // This selector is used to map cipher registers into
+   // EIM address space and select which CIPHER to send EIM read and
+   // write operations to. So far there are no CIPHER cores.
+   //----------------------------------------------------------------
+   cipher_selector segment_ciphers
+     (
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .sys_ena(segment_enable_ciphers),         // only enable active selector
+
+      .sys_eim_addr(addr_segment_int),          // we only connect 14 lower bits of address here,
+      // because we have already decoded 3 upper bits earlier,
+      // every segment can have its own address decoder.
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),          
+
+      .sys_write_data(sys_write_data),
+      .sys_read_data(segment_ciphers_read_data) // output from CIPHERS segment
+      );
+   
+   
+endmodule
+
+
+//======================================================================
+// EOF eim_memory.v
+//======================================================================
diff --git a/core_selector/src/rtl/hash_selector.v b/core_selector/src/rtl/hash_selector.v
new file mode 100644
index 0000000..4698078
--- /dev/null
+++ b/core_selector/src/rtl/hash_selector.v
@@ -0,0 +1,264 @@
+//======================================================================
+//
+// hash_selector.v
+// ---------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of external interface, coretest
+// and the core to be tested. And if more than one core is
+// present the wrapper also includes address and data muxes.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk, Pavel Shatov
+// Copyright (c) 2014-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 hash_selector
+  (
+   input wire           sys_clk,
+   input wire           sys_rst,
+   input wire           sys_ena,
+
+   input wire [13 : 0]  sys_eim_addr,
+   input wire           sys_eim_wr,
+   input wire           sys_eim_rd,
+   output wire [31 : 0] sys_read_data,
+   input wire [31 : 0]  sys_write_data
+   );
+
+   /* In this memory segment (HASHES) we have 14 address bits. Every core has
+    * 8-bit internal address space, so we can have up to 2^(14-8) = 64 cores here.
+    *
+    * Core #0 is not an actual HASH core, but a set of board-level (global)
+    * registers, that can be used to get information about hardware (board
+    * type, bitstream version and so on).
+    *
+    * So far we have three cores: SHA-1, SHA-256 and SHA-512.
+    */
+   
+   /*********************************************************
+    * To add new HASH core named XXX follow the steps below *
+    *********************************************************
+    *
+    * 1. Add corresponding `define under "List of Available Cores", this will
+    *    allow users to exclude your core from implementation to save some
+    *    slices in case they don't need it.
+    *
+    *    `define    USE_CORE_XXX
+XXX define in wrapper core
+    *
+    *
+    * 2. Choose address of your new core and add corresponding line under
+    *    "Core Address Table". Core addresses can be in the range from 1 to 63
+    *    inclusively. Core address 0 is reserved for a page of global
+    *    registers and must not be used.
+    *
+    *    localparam CORE_ADDR_XXX   = 6'dN;
+XXX move to `define in wrapper core??
+    *
+    *
+    * 3. Add instantiation of your new core after all existing cores
+    *    surrounded by conditional synthesis directives.
+    *    You also need a 32-bit output (read data) bus for your core and an
+    *    enable flag. Note that sys_rst in an active-high sync reset signal.
+    *
+    *   `ifdef USE_CORE_XXX
+    *       wire [31: 0]    read_data_xxx;
+    *       wire            enable_xxx = sys_ena && (addr_core_num == CORE_ADDR_XXX);
+    *       xxx xxx_inst
+    *       (
+    *       .clk(sys_clk),
+    *       .reset_n(~sys_rst),
+    *       .cs(enable_xxx & (sys_eim_rd | sys_eim_wr)),
+    *       .we(sys_eim_wr),
+    *       .address(addr_core_reg),
+    *       .write_data(sys_write_data),
+    *       .read_data(read_data_xxx),
+    *       .error()
+    *       );
+    *    `endif
+    *
+    *
+    * 4. Add previously created data bus to "Output (Read Data) Multiplexor"
+    *    in the end of this file.
+    *
+    *   `ifdef USE_CORE_XXX
+    *       CORE_ADDR_XXX:
+    *           sys_read_data_mux = read_data_xxx;
+    *   `endif
+    *
+    */
+
+
+   //----------------------------------------------------------------
+   // Address Decoder
+   //----------------------------------------------------------------
+   wire [ 5: 0]         addr_core_num   = sys_eim_addr[13: 8];  // upper 6 bits specify core being addressed
+   wire [ 7: 0]         addr_core_reg   = sys_eim_addr[ 7: 0];  // lower 8 bits specify register offset in core
+
+
+   /* We can comment following lines to exclude cores from implementation
+    * in case we run out of slices.
+    */
+   
+   //----------------------------------------------------------------
+   // List of Available Cores
+   //----------------------------------------------------------------
+   `define  USE_CORE_SHA1
+   `define  USE_CORE_SHA256
+   `define  USE_CORE_SHA512
+   
+   
+   //----------------------------------------------------------------
+   // Core Address Table
+   //----------------------------------------------------------------
+   localparam   CORE_ADDR_GLOBAL_REGS   = 6'd0;
+   localparam   CORE_ADDR_SHA1          = 6'd1;
+   localparam   CORE_ADDR_SHA256        = 6'd2;
+   localparam   CORE_ADDR_SHA512        = 6'd3;
+   
+   
+   //----------------------------------------------------------------
+   // Global Registers
+   //----------------------------------------------------------------
+   wire [31: 0]         read_data_global;
+   wire                 enable_global = sys_ena && (addr_core_num == CORE_ADDR_GLOBAL_REGS);
+   novena_regs novena_regs_inst
+     (
+      .clk(sys_clk),
+      .rst(sys_rst),
+
+      .cs(enable_global & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_global)
+      );
+   
+   
+   //----------------------------------------------------------------
+   // SHA-1
+   //----------------------------------------------------------------
+   `ifdef USE_CORE_SHA1
+   wire [31: 0]         read_data_sha1;
+   wire                 enable_sha1 = sys_ena && (addr_core_num == CORE_ADDR_SHA1);
+   sha1 sha1_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_sha1 & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_sha1)
+      );
+   `endif
+   
+   
+   //----------------------------------------------------------------
+   // SHA-256
+   //----------------------------------------------------------------
+   `ifdef USE_CORE_SHA256
+   wire [31: 0]         read_data_sha256;
+   wire                 enable_sha256 = sys_ena && (addr_core_num == CORE_ADDR_SHA256);
+   sha256 sha256_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_sha256 & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_sha256)
+      );
+   `endif
+   
+   
+   //----------------------------------------------------------------
+   // SHA-512
+   //----------------------------------------------------------------
+   `ifdef USE_CORE_SHA512
+   wire [31: 0]         read_data_sha512;
+   wire                 enable_sha512 = sys_ena && (addr_core_num == CORE_ADDR_SHA512);
+   sha512 sha512_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_sha512 & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_sha512)
+      );
+   `endif
+   
+   
+   //----------------------------------------------------------------
+   // Output (Read Data) Multiplexor
+   //----------------------------------------------------------------
+   reg [31: 0]          sys_read_data_mux;
+   assign sys_read_data = sys_read_data_mux;
+   
+   always @*
+     //
+     case (addr_core_num)
+       //
+       CORE_ADDR_GLOBAL_REGS:
+         sys_read_data_mux = read_data_global;
+   `ifdef USE_CORE_SHA1
+       CORE_ADDR_SHA1:
+         sys_read_data_mux = read_data_sha1;
+   `endif
+   `ifdef USE_CORE_SHA256
+       CORE_ADDR_SHA256:
+         sys_read_data_mux = read_data_sha256;
+   `endif
+   `ifdef USE_CORE_SHA512
+       CORE_ADDR_SHA512:
+         sys_read_data_mux = read_data_sha512;
+   `endif
+       //
+       default:
+         sys_read_data_mux = {32{1'b0}};
+       //
+     endcase
+
+
+endmodule
+
+//======================================================================
+// EOF hash_selector.v
+//======================================================================
diff --git a/core_selector/src/rtl/rng_selector.v b/core_selector/src/rtl/rng_selector.v
new file mode 100644
index 0000000..f86b3e9
--- /dev/null
+++ b/core_selector/src/rtl/rng_selector.v
@@ -0,0 +1,112 @@
+//======================================================================
+//
+// rng_selector.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of external interface, coretest
+// and the core to be tested. And if more than one core is
+// present the wrapper also includes address and data muxes.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk, Pavel Shatov
+// Copyright (c) 2014-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 rng_selector
+  (
+   input wire           sys_clk,
+   input wire           sys_rst,
+   input wire           sys_ena,
+
+   input wire [13: 0]   sys_eim_addr,
+   input wire           sys_eim_wr,
+   input wire           sys_eim_rd,
+   output wire [31 : 0] sys_read_data,
+   input wire [31 : 0]  sys_write_data
+   );
+
+   
+   //
+   // Output Register
+   //
+   reg [31: 0]          tmp_read_data;
+   assign sys_read_data = tmp_read_data;
+   
+
+   /* So far we have no RNG cores, let's make some dummy 32-bit registers here
+    * to prevent ISE from complaining that we don't use input ports.
+    */
+   
+   reg [31: 0]          reg_dummy_first;
+   reg [31: 0]          reg_dummy_second;
+   reg [31: 0]          reg_dummy_third;
+   
+   always @(posedge sys_clk)
+     //
+     if (sys_rst) begin
+        reg_dummy_first  <= {8{4'hA}};
+        reg_dummy_second <= {8{4'hB}};
+        reg_dummy_third  <= {8{4'hC}};
+     end else if (sys_ena) begin
+        //
+        if (sys_eim_wr) begin
+           //
+           // WRITE handler
+           //
+           case (sys_eim_addr)
+             14'd0: reg_dummy_first     <= sys_write_data;
+             14'd1: reg_dummy_second    <= sys_write_data;
+             14'd2: reg_dummy_third     <= sys_write_data;
+           endcase
+           //
+        end
+        //
+        if (sys_eim_rd) begin
+           //
+           // READ handler
+           //
+           case (sys_eim_addr)
+             14'd0: tmp_read_data       <= reg_dummy_first;
+             14'd1: tmp_read_data       <= reg_dummy_second;
+             14'd2: tmp_read_data       <= reg_dummy_third;
+             //
+             default:
+               tmp_read_data    <= {32{1'b0}};  // read non-existent locations as zeroes
+           endcase
+           //
+        end
+        //
+     end
+
+endmodule
+
+//======================================================================
+// EOF core_selector.v
+//======================================================================
diff --git a/coretest/LICENSE b/coretest/LICENSE
new file mode 100644
index 0000000..9a95faa
--- /dev/null
+++ b/coretest/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2014, SUNET
+Joachim Strömbergson
+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.
+
+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.
diff --git a/coretest/README.md b/coretest/README.md
new file mode 100644
index 0000000..2c38361
--- /dev/null
+++ b/coretest/README.md
@@ -0,0 +1,176 @@
+# coretest #
+Test platform for the [Cryptech Open HSM project](https://cryptech.is/).
+
+(_Note:The Cryptech certificate is by choice not from a CA and therefore
+not in your brower trust store._)
+
+
+## Description ##
+This platform and hardware design is used to functionally verfiy cores
+developed in the Cryptech Open HSM project. The test core itself
+contains just enough functionality to be able to verify that the SW in
+the host computer can talk to the core in the FPGA by reading and
+writing 32 bit data words to given addresses.
+
+This project includes cores in Verilog, a testbench as well as host SW
+to talk to the core.
+
+
+## Architecture ##
+The coretest consists of three state machines:
+
+### rx_engine ###
+Handles receiving command messages from the host. Awaits SYN signals from
+the host interface and reads bytes when SYN is asserted. For each byte
+the rx_engine assetts and ACK and waits for the SYN to be asserted. When
+a EOC byte has been detected the rx_engine signals the test_engine that
+there is a new command available in the rx_buffer.
+
+
+### tx_engine ###
+Handles transmitting response messages to the host. When the test_engine
+signals that there is a new response in the tx_buffer the tx_engine will
+start transmitting all bytes up to and including the EOR byte it is
+expecting in the tx_buffer. The transmission is done by asserting SYN
+awaiting ACK, deasserting SYN and moving to the next byte before
+asserting SYN again. This process is repeated until all bytes has been
+transmitted.
+
+
+### test_engine ###
+Performs the parsing of commands from the host. Known read or write
+commands are used to test the core to be tested. The response from the
+core is collected and the appropriate response is stored in the
+tx_buffer. The test_engine then signals the tx_engine that there is a
+new response message to be transmitted.
+
+## Interfaces ##
+The host communication interface is a byte wide data interface with
+SYN-ACK handshake for each byte.
+
+The interface to the core to be tested is a memory like
+interface with chip select and write enable. The data width is 32-bits
+and the address is 16-bits.
+
+
+## Core under test ##
+The core under test is expected to have a simple memory like interface
+with chip select (cs), write enable (we) signal ports, 16-bit address
+port and separate 32-bit data ports for read and write data. The core is
+also expected to have an error signal port that informs the master if
+any read or write commands given cannot be performed by the core.
+
+***Note:***
+The core reset signal is expected to by active high. The
+core reset signal should be connected to the coretest core_reset
+port, not to system reset.
+
+
+## Protocol ##
+Coretest uses a simple command-response protocol to allow a host to
+control the test functionality.
+
+The command messages are sent as a sequence of bytes with a command byte
+followed by zero or more arguments. The response consists of a response
+code byte followed by zero or more data fields.
+
+The start of a command is signalled by a Start of Command (SOC)
+byte. The end of a command is signalled by a End of Command (EOC)
+byte. These bytes are:
+  - SOC: 0x55
+  - EOC: 0xaa
+
+The start of a response is signalled by a Start of Response (SOR)
+byte. The end of a response is signalled by a End of Respons (EOC)
+byte. These bytes are:
+ - SOR: 0xaa
+ - EOR: 0x55
+
+***The commands accepted are:***
+  - RESET_CMD. Reset the core being tested. Message length is 3 bytes
+    including SOC and EOC.
+    - SOC
+    - 0x01 opcode
+    - EOC
+
+
+  - READ_CMD. Read a 32-bit data word from a given address. Message
+    length is 5 bytes including SOC and EOC.
+    - SOC
+    - 0x10 opcode
+    - 16-bit address in MSB format
+    - EOC
+    
+
+  - WRITE_CMD. Write a given data word to a given address. Message
+    length is 9 bytes including SOC and EOC.
+    - SOC
+    - 0x11 opcode
+    - 16-bit address in MSB format
+    - 32-bit data in MSB format
+    - EOC
+    
+
+***The possible responses are:***
+  - UNKNOWN. Unknown command received. Message length is 4 bytes
+    including SOR and EOR. 
+    - SOR
+    - 0xfe response code
+    - Received command
+    - EOR
+    
+
+  - ERROR. Known but unsuccessful command as signalled by the
+    core. Caused for example by a write command to read only
+    register. Message length is 4 bytes including SOR and EOR.
+    - SOR
+    - 0xfd response code
+    - command received
+    - EOR
+
+
+  - READ_OK. Sent after successful read operation. Message length is 9
+    bytes including SOR and EOR .
+    - SOR
+    - 0x7f response code
+    - 16-bit address in MSB format
+    - 32-bit data in MSB format
+    - EOR
+
+
+  - WRITE_OK. Sent after successful write operation. Message length is 5
+    bytes including SOR and EOR 
+    - SOR
+    - 0x7e response code
+    - 16-bit address in MSB format
+    - EOR
+
+
+  - RESET_OK. Sent after successful reset operation. Message length is 3
+    bytes including SOR and EOR.
+    - SOR
+    - 0x7d response code
+    - EOR
+
+## Status ##
+***(2014-02-11):***
+
+Added information about the architecture and protocols. Updated the
+command and response with explicit read and write ok responses. Some
+cleanup of the description.
+
+Completed first draft of the RTL for coretest. The RTL is not debugged
+and has not been synthesized. We need to add a testbench and a simple
+test core.
+
+Added a simple test core.
+Adding initial version of UART core that will be used for the host
+interface.
+
+
+***(2014-02-10):***
+
+Initial version of the project. Based on previous cttest project but
+renamed and with new (ideas) about the test architecture. Specified
+command and response protocol.
+
diff --git a/coretest/src/rtl/coretest.v b/coretest/src/rtl/coretest.v
new file mode 100644
index 0000000..918312d
--- /dev/null
+++ b/coretest/src/rtl/coretest.v
@@ -0,0 +1,1209 @@
+//======================================================================
+//
+// coretest.v
+// ----------
+// The Cryptech coretest testing module. Combined with an external
+// interface that sends and receives bytes using a SYN-ACK
+// handshake and a core to be tested, coretest can parse read
+// and write commands needed to test the connected core.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014, SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module coretest(
+                input wire           clk,
+                input wire           reset_n,
+
+                // Interface to communication core
+                input wire           rx_syn,
+                input wire [7 : 0]   rx_data,
+                output wire          rx_ack,
+
+                output wire          tx_syn,
+                output wire [7 : 0]  tx_data,
+                input wire           tx_ack,
+
+                // Interface to the core being tested.
+                output wire          core_reset_n,
+                output wire          core_cs,
+                output wire          core_we,
+                output wire [15 : 0] core_address,
+                output wire [31 : 0] core_write_data,
+                input wire  [31 : 0] core_read_data,
+                input wire           core_error
+               );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  // Max elements in read and write buffers.
+  parameter BUFFER_MAX = 4'hf;
+
+  // Command constants.
+  parameter SOC       = 8'h55;
+  parameter EOC       = 8'haa;
+  parameter RESET_CMD = 8'h01;
+  parameter READ_CMD  = 8'h10;
+  parameter WRITE_CMD = 8'h11;
+
+  // Response constants.
+  parameter SOR      = 8'haa;
+  parameter EOR      = 8'h55;
+  parameter UNKNOWN  = 8'hfe;
+  parameter ERROR    = 8'hfd;
+  parameter READ_OK  = 8'h7f;
+  parameter WRITE_OK = 8'h7e;
+  parameter RESET_OK = 8'h7d;
+
+  // rx_engine states.
+  parameter RX_IDLE  = 3'h0;
+  parameter RX_ACK   = 3'h1;
+  parameter RX_NSYN  = 3'h2;
+
+  // tx_engine states.
+  parameter TX_IDLE  = 3'h0;
+  parameter TX_SYN   = 3'h1;
+  parameter TX_NOACK = 3'h2;
+  parameter TX_NEXT  = 3'h3;
+  parameter TX_SENT  = 3'h4;
+  parameter TX_DONE  = 3'h5;
+
+  // test_engine states.
+  parameter TEST_IDLE          = 8'h00;
+  parameter TEST_GET_CMD       = 8'h10;
+  parameter TEST_PARSE_CMD     = 8'h11;
+  parameter TEST_GET_ADDR0     = 8'h20;
+  parameter TEST_GET_ADDR1     = 8'h21;
+  parameter TEST_GET_DATA0     = 8'h24;
+  parameter TEST_GET_DATA1     = 8'h25;
+  parameter TEST_GET_DATA2     = 8'h26;
+  parameter TEST_GET_DATA3     = 8'h27;
+  parameter TEST_GET_EOC       = 8'h28;
+  parameter TEST_RST_START     = 8'h30;
+  parameter TEST_RST_WAIT      = 8'h31;
+  parameter TEST_RST_END       = 8'h32;
+  parameter TEST_RD_START      = 8'h50;
+  parameter TEST_RD_WAIT       = 8'h51;
+  parameter TEST_RD_WAIT2      = 8'h52;
+  parameter TEST_RD_END        = 8'h53;
+  parameter TEST_WR_START      = 8'h60;
+  parameter TEST_WR_WAIT       = 8'h61;
+  parameter TEST_WR_END        = 8'h62;
+  parameter TEST_CMD_UNKNOWN   = 8'h80;
+  parameter TEST_CMD_ERROR     = 8'h81;
+  parameter TEST_SEND_RESPONSE = 8'hc0;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg          rx_syn_reg;
+
+  reg          rx_ack_reg;
+  reg          rx_ack_new;
+  reg          rx_ack_we;
+
+  reg          tx_syn_reg;
+  reg          tx_syn_new;
+  reg          tx_syn_we;
+
+  reg          tx_ack_reg;
+
+  reg          core_reset_n_reg;
+  reg          core_reset_n_new;
+  reg          core_reset_n_we;
+
+  reg          core_cs_reg;
+  reg          core_cs_new;
+  reg          core_cs_we;
+
+  reg          core_we_reg;
+  reg          core_we_new;
+  reg          core_we_we;
+
+  reg          send_response_reg;
+  reg          send_response_new;
+  reg          send_response_we;
+
+  reg          response_sent_reg;
+  reg          response_sent_new;
+  reg          response_sent_we;
+
+  reg [7 : 0]  cmd_reg;
+  reg          cmd_we;
+
+  reg [7 : 0]  core_addr_byte0_reg;
+  reg          core_addr_byte0_we;
+  reg [7 : 0]  core_addr_byte1_reg;
+  reg          core_addr_byte1_we;
+
+  reg [7 : 0]  core_wr_data_byte0_reg;
+  reg          core_wr_data_byte0_we;
+  reg [7 : 0]  core_wr_data_byte1_reg;
+  reg          core_wr_data_byte1_we;
+  reg [7 : 0]  core_wr_data_byte2_reg;
+  reg          core_wr_data_byte2_we;
+  reg [7 : 0]  core_wr_data_byte3_reg;
+  reg          core_wr_data_byte3_we;
+
+  reg [31 : 0] core_read_data_reg;
+  reg          core_error_reg;
+  reg          sample_core_output;
+
+  reg [3 : 0]  rx_buffer_rd_ptr_reg;
+  reg [3 : 0]  rx_buffer_rd_ptr_new;
+  reg          rx_buffer_rd_ptr_we;
+  reg          rx_buffer_rd_ptr_inc;
+
+  reg [3 : 0]  rx_buffer_wr_ptr_reg;
+  reg [3 : 0]  rx_buffer_wr_ptr_new;
+  reg          rx_buffer_wr_ptr_we;
+  reg          rx_buffer_wr_ptr_inc;
+
+  reg [3 : 0]  rx_buffer_ctr_reg;
+  reg [3 : 0]  rx_buffer_ctr_new;
+  reg          rx_buffer_ctr_we;
+  reg          rx_buffer_ctr_inc;
+  reg          rx_buffer_ctr_dec;
+  reg          rx_buffer_full;
+  reg          rx_buffer_empty;
+
+  reg [7 : 0]  rx_buffer [0 : 15];
+  reg          rx_buffer_we;
+
+  reg [3 : 0]  tx_buffer_ptr_reg;
+  reg [3 : 0]  tx_buffer_ptr_new;
+  reg          tx_buffer_ptr_we;
+  reg          tx_buffer_ptr_inc;
+  reg          tx_buffer_ptr_rst;
+
+  reg [7 : 0]  tx_buffer [0 : 8];
+  reg          tx_buffer_we;
+
+  reg [3 : 0]  tx_msg_len_reg;
+  reg [3 : 0]  tx_msg_len_new;
+  reg          tx_msg_len_we;
+
+  reg [2 : 0]  rx_engine_reg;
+  reg [2 : 0]  rx_engine_new;
+  reg          rx_engine_we;
+
+  reg [2 : 0]  tx_engine_reg;
+  reg [2 : 0]  tx_engine_new;
+  reg          tx_engine_we;
+
+  reg [7 : 0]  test_engine_reg;
+  reg [7 : 0]  test_engine_new;
+  reg          test_engine_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [7 : 0] tx_buffer_muxed0;
+  reg [7 : 0] tx_buffer_muxed1;
+  reg [7 : 0] tx_buffer_muxed2;
+  reg [7 : 0] tx_buffer_muxed3;
+  reg [7 : 0] tx_buffer_muxed4;
+  reg [7 : 0] tx_buffer_muxed5;
+  reg [7 : 0] tx_buffer_muxed6;
+  reg [7 : 0] tx_buffer_muxed7;
+  reg [7 : 0] tx_buffer_muxed8;
+
+  reg         update_tx_buffer;
+  reg [7 : 0] response_type;
+
+  reg [7 : 0] rx_byte;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign rx_ack          = rx_ack_reg;
+
+  assign tx_syn          = tx_syn_reg;
+  assign tx_data         = tx_buffer[tx_buffer_ptr_reg];
+
+  assign core_reset_n    = core_reset_n_reg & reset_n;
+  assign core_cs         = core_cs_reg;
+  assign core_we         = core_we_reg;
+  assign core_address    = {core_addr_byte0_reg, core_addr_byte1_reg};
+  assign core_write_data = {core_wr_data_byte0_reg, core_wr_data_byte1_reg,
+                            core_wr_data_byte2_reg, core_wr_data_byte3_reg};
+
+
+  //----------------------------------------------------------------
+  // reg_update
+  // Update functionality for all registers in the core.
+  // All registers are positive edge triggered with synchronous
+  // active low reset. All registers have write enable.
+  //----------------------------------------------------------------
+  always @ (posedge clk)
+    begin: reg_update
+      if (!reset_n)
+        begin
+          rx_buffer[0]           <= 8'h00;
+          rx_buffer[1]           <= 8'h00;
+          rx_buffer[2]           <= 8'h00;
+          rx_buffer[3]           <= 8'h00;
+          rx_buffer[4]           <= 8'h00;
+          rx_buffer[5]           <= 8'h00;
+          rx_buffer[6]           <= 8'h00;
+          rx_buffer[7]           <= 8'h00;
+          rx_buffer[8]           <= 8'h00;
+          rx_buffer[9]           <= 8'h00;
+          rx_buffer[10]          <= 8'h00;
+          rx_buffer[11]          <= 8'h00;
+          rx_buffer[12]          <= 8'h00;
+          rx_buffer[13]          <= 8'h00;
+          rx_buffer[14]          <= 8'h00;
+          rx_buffer[15]          <= 8'h00;
+
+          tx_buffer[0]           <= 8'h00;
+          tx_buffer[1]           <= 8'h00;
+          tx_buffer[2]           <= 8'h00;
+          tx_buffer[3]           <= 8'h00;
+          tx_buffer[4]           <= 8'h00;
+          tx_buffer[5]           <= 8'h00;
+          tx_buffer[6]           <= 8'h00;
+          tx_buffer[7]           <= 8'h00;
+          tx_buffer[8]           <= 8'h00;
+
+          rx_syn_reg             <= 0;
+          rx_ack_reg             <= 0;
+          tx_ack_reg             <= 0;
+          tx_syn_reg             <= 0;
+
+          rx_buffer_rd_ptr_reg   <= 4'h0;
+          rx_buffer_wr_ptr_reg   <= 4'h0;
+          rx_buffer_ctr_reg      <= 4'h0;
+
+          tx_buffer_ptr_reg      <= 4'h0;
+          tx_msg_len_reg         <= 4'h0;
+
+          send_response_reg      <= 0;
+          response_sent_reg      <= 0;
+
+          cmd_reg                <= 8'h00;
+          core_addr_byte0_reg    <= 8'h00;
+          core_addr_byte1_reg    <= 8'h00;
+          core_wr_data_byte0_reg <= 8'h00;
+          core_wr_data_byte1_reg <= 8'h00;
+          core_wr_data_byte2_reg <= 8'h00;
+          core_wr_data_byte3_reg <= 8'h00;
+
+          core_reset_n_reg       <= 1;
+          core_cs_reg            <= 0;
+          core_we_reg            <= 0;
+          core_error_reg         <= 0;
+          core_read_data_reg     <= 32'h00000000;
+
+          rx_engine_reg          <= RX_IDLE;
+          tx_engine_reg          <= TX_IDLE;
+          test_engine_reg        <= TEST_IDLE;
+        end
+      else
+        begin
+          rx_syn_reg <= rx_syn;
+          tx_ack_reg <= tx_ack;
+
+          if (rx_ack_we)
+            begin
+              rx_ack_reg <= rx_ack_new;
+            end
+
+          if (tx_syn_we)
+            begin
+              tx_syn_reg <= tx_syn_new;
+            end
+
+          if (rx_buffer_we)
+            begin
+              rx_buffer[rx_buffer_wr_ptr_reg] <= rx_data;
+            end
+
+          if (tx_buffer_we)
+            begin
+              tx_buffer[0] <= tx_buffer_muxed0;
+              tx_buffer[1] <= tx_buffer_muxed1;
+              tx_buffer[2] <= tx_buffer_muxed2;
+              tx_buffer[3] <= tx_buffer_muxed3;
+              tx_buffer[4] <= tx_buffer_muxed4;
+              tx_buffer[5] <= tx_buffer_muxed5;
+              tx_buffer[6] <= tx_buffer_muxed6;
+              tx_buffer[7] <= tx_buffer_muxed7;
+              tx_buffer[8] <= tx_buffer_muxed8;
+            end
+
+          if (cmd_we)
+            begin
+              cmd_reg <= rx_byte;
+            end
+
+          if (core_addr_byte0_we)
+            begin
+              core_addr_byte0_reg <= rx_byte;
+            end
+
+          if (core_addr_byte1_we)
+            begin
+              core_addr_byte1_reg <= rx_byte;
+            end
+
+          if (core_wr_data_byte0_we)
+            begin
+              core_wr_data_byte0_reg <= rx_byte;
+            end
+
+          if (core_wr_data_byte1_we)
+            begin
+              core_wr_data_byte1_reg <= rx_byte;
+            end
+
+          if (core_wr_data_byte2_we)
+            begin
+              core_wr_data_byte2_reg <= rx_byte;
+            end
+
+          if (core_wr_data_byte3_we)
+            begin
+              core_wr_data_byte3_reg <= rx_byte;
+            end
+
+          if (rx_buffer_rd_ptr_we)
+            begin
+              rx_buffer_rd_ptr_reg <= rx_buffer_rd_ptr_new;
+            end
+
+          if (rx_buffer_wr_ptr_we)
+            begin
+              rx_buffer_wr_ptr_reg <= rx_buffer_wr_ptr_new;
+            end
+
+          if (rx_buffer_ctr_we)
+            begin
+              rx_buffer_ctr_reg <= rx_buffer_ctr_new;
+            end
+
+          if (tx_buffer_ptr_we)
+            begin
+              tx_buffer_ptr_reg <= tx_buffer_ptr_new;
+            end
+
+          if (tx_msg_len_we)
+            begin
+              tx_msg_len_reg <= tx_msg_len_new;
+            end
+
+          if (core_reset_n_we)
+            begin
+              core_reset_n_reg <= core_reset_n_new;
+            end
+
+          if (core_cs_we)
+            begin
+              core_cs_reg <= core_cs_new;
+            end
+
+          if (core_we_we)
+            begin
+              core_we_reg <= core_we_new;
+            end
+
+          if (send_response_we)
+            begin
+              send_response_reg <= send_response_new;
+            end
+
+          if (response_sent_we)
+            begin
+              response_sent_reg <= response_sent_new;
+            end
+
+          if (sample_core_output)
+            begin
+              core_error_reg     <= core_error;
+              core_read_data_reg <= core_read_data;
+            end
+
+          if (rx_engine_we)
+            begin
+              rx_engine_reg <= rx_engine_new;
+            end
+
+          if (tx_engine_we)
+            begin
+              tx_engine_reg <= tx_engine_new;
+            end
+
+          if (test_engine_we)
+            begin
+              test_engine_reg <= test_engine_new;
+            end
+        end
+    end // reg_update
+
+
+  //---------------------------------------------------------------
+  // read_rx_buffer
+  // Combinatinal read mux for the rx_buffer.
+  //---------------------------------------------------------------
+  always @*
+    begin : read_rx_buffer
+      rx_byte = rx_buffer[rx_buffer_rd_ptr_reg];
+    end // read_rx_buffer
+
+
+  //---------------------------------------------------------------
+  // tx_buffer_logic
+  //
+  // Update logic for the tx-buffer. Given the response type and
+  // the correct contents of the tx_buffer is assembled when
+  // and update is signalled by the test engine.
+  //---------------------------------------------------------------
+  always @*
+    begin: tx_buffer_logic
+      // Defafult assignments
+      tx_buffer_muxed0 = 8'h00;
+      tx_buffer_muxed1 = 8'h00;
+      tx_buffer_muxed2 = 8'h00;
+      tx_buffer_muxed3 = 8'h00;
+      tx_buffer_muxed4 = 8'h00;
+      tx_buffer_muxed5 = 8'h00;
+      tx_buffer_muxed6 = 8'h00;
+      tx_buffer_muxed7 = 8'h00;
+      tx_buffer_muxed8 = 8'h00;
+      tx_msg_len_new   = 4'h0;
+      tx_msg_len_we    = 0;
+      tx_buffer_we     = 0;
+
+      if (update_tx_buffer)
+        begin
+          tx_buffer_we = 1;
+          tx_buffer_muxed0 = SOR;
+
+          case (response_type)
+            READ_OK:
+              begin
+                tx_buffer_muxed1 = READ_OK;
+                tx_buffer_muxed2 = core_addr_byte0_reg;
+                tx_buffer_muxed3 = core_addr_byte1_reg;
+                tx_buffer_muxed4 = core_read_data_reg[31 : 24];
+                tx_buffer_muxed5 = core_read_data_reg[23 : 16];
+                tx_buffer_muxed6 = core_read_data_reg[15 :  8];
+                tx_buffer_muxed7 = core_read_data_reg[7  :  0];
+                tx_buffer_muxed8 = EOR;
+                tx_msg_len_new   = 4'h8;
+                tx_msg_len_we    = 1;
+              end
+
+            WRITE_OK:
+              begin
+                tx_buffer_muxed1 = WRITE_OK;
+                tx_buffer_muxed2 = core_addr_byte0_reg;
+                tx_buffer_muxed3 = core_addr_byte1_reg;
+                tx_buffer_muxed4 = EOR;
+                tx_msg_len_new   = 4'h4;
+                tx_msg_len_we    = 1;
+              end
+
+            RESET_OK:
+              begin
+                tx_buffer_muxed1 = RESET_OK;
+                tx_buffer_muxed2 = EOR;
+                tx_msg_len_new   = 4'h2;
+                tx_msg_len_we    = 1;
+              end
+
+            ERROR:
+              begin
+                tx_buffer_muxed1 = ERROR;
+                tx_buffer_muxed2 = cmd_reg;
+                tx_buffer_muxed3 = EOR;
+                tx_msg_len_new   = 4'h3;
+                tx_msg_len_we    = 1;
+              end
+
+            default:
+              begin
+                // Any response type not explicitly defined is treated as UNKNOWN.
+                tx_buffer_muxed1 = UNKNOWN;
+                tx_buffer_muxed2 = cmd_reg;
+                tx_buffer_muxed3 = EOR;
+                tx_msg_len_new   = 4'h3;
+                tx_msg_len_we    = 1;
+              end
+          endcase // case (response_type)
+        end
+    end // tx_buffer_logic
+
+
+  //----------------------------------------------------------------
+  // rx_buffer_rd_ptr
+  //
+  // Logic for the rx buffer read pointer.
+  //----------------------------------------------------------------
+  always @*
+    begin: rx_buffer_rd_ptr
+      // Default assignments
+      rx_buffer_rd_ptr_new = 4'h0;
+      rx_buffer_rd_ptr_we  = 1'b0;
+      rx_buffer_ctr_dec    = 0;
+
+      if (rx_buffer_rd_ptr_inc)
+        begin
+          rx_buffer_ctr_dec    = 1;
+          rx_buffer_rd_ptr_new = rx_buffer_rd_ptr_reg + 1'b1;
+          rx_buffer_rd_ptr_we  = 1'b1;
+        end
+    end // rx_buffer_rd_ptr
+
+
+  //----------------------------------------------------------------
+  // rx_buffer_wr_ptr
+  //
+  // Logic for the rx buffer write pointer.
+  //----------------------------------------------------------------
+  always @*
+    begin: rx_buffer_wr_ptr
+      // Default assignments
+      rx_buffer_wr_ptr_new = 4'h0;
+      rx_buffer_wr_ptr_we  = 1'b0;
+      rx_buffer_ctr_inc    = 0;
+
+      if (rx_buffer_wr_ptr_inc)
+        begin
+          rx_buffer_ctr_inc    = 1;
+          rx_buffer_wr_ptr_new = rx_buffer_wr_ptr_reg + 1'b1;
+          rx_buffer_wr_ptr_we  = 1'b1;
+        end
+    end // rx_buffer_wr_ptr
+
+
+  //----------------------------------------------------------------
+  // rx_buffer_ctr
+  //
+  // Logic for the rx buffer element counter.
+  //----------------------------------------------------------------
+  always @*
+    begin: rx_buffer_ctr
+      // Default assignments
+      rx_buffer_ctr_new = 4'h0;
+      rx_buffer_ctr_we  = 1'b0;
+      rx_buffer_empty   = 1'b0;
+      rx_buffer_full    = 1'b0;
+
+      if (rx_buffer_ctr_inc)
+        begin
+          rx_buffer_ctr_new = rx_buffer_ctr_reg + 1'b1;
+          rx_buffer_ctr_we  = 1'b1;
+        end
+      else if (rx_buffer_ctr_dec)
+        begin
+          rx_buffer_ctr_new = rx_buffer_ctr_reg - 1'b1;
+          rx_buffer_ctr_we  = 1'b1;
+        end
+
+      if (rx_buffer_ctr_reg == 4'h0)
+        begin
+          rx_buffer_empty = 1'b1;
+        end
+
+      if (rx_buffer_ctr_reg == BUFFER_MAX)
+        begin
+          rx_buffer_full = 1'b1;
+        end
+    end // rx_buffer_ctr
+
+
+  //----------------------------------------------------------------
+  // tx_buffer_ptr
+  //
+  // Logic for the tx buffer pointer. Supports reset and
+  // incremental updates.
+  //----------------------------------------------------------------
+  always @*
+    begin: tx_buffer_ptr
+      // Default assignments
+      tx_buffer_ptr_new = 4'h0;
+      tx_buffer_ptr_we  = 1'b0;
+
+      if (tx_buffer_ptr_inc)
+        begin
+          tx_buffer_ptr_new = tx_buffer_ptr_reg + 1'b1;
+          tx_buffer_ptr_we  = 1'b1;
+        end
+
+      else if (tx_buffer_ptr_rst)
+        begin
+          tx_buffer_ptr_new = 4'h0;
+          tx_buffer_ptr_we  = 1'b1;
+        end
+    end // tx_buffer_ptr
+
+
+  //----------------------------------------------------------------
+  // rx_engine
+  //
+  // FSM responsible for handling receiving message bytes from the
+  // host interface and storing them in the receive buffer.
+  //----------------------------------------------------------------
+  always @*
+    begin: rx_engine
+      // Default assignments
+      rx_ack_new           = 1'b0;
+      rx_ack_we            = 1'b0;
+      rx_buffer_we         = 1'b0;
+      rx_buffer_wr_ptr_inc = 1'b0;
+      rx_engine_new        = RX_IDLE;
+      rx_engine_we         = 1'b0;
+
+      case (rx_engine_reg)
+        RX_IDLE:
+          begin
+            if (rx_syn_reg)
+              begin
+                if (!rx_buffer_full)
+                  begin
+                    rx_buffer_we  = 1'b1;
+                    rx_engine_new = RX_ACK;
+                    rx_engine_we  = 1'b1;
+                  end
+              end
+          end
+
+        RX_ACK:
+          begin
+            rx_ack_new           = 1'b1;
+            rx_ack_we            = 1'b1;
+            rx_buffer_wr_ptr_inc = 1'b1;
+            rx_engine_new        = RX_NSYN;
+            rx_engine_we         = 1'b1;
+          end
+
+        RX_NSYN:
+          begin
+            if (!rx_syn_reg)
+              begin
+                rx_ack_new    = 1'b0;
+                rx_ack_we     = 1'b1;
+                rx_engine_new = RX_IDLE;
+                rx_engine_we  = 1;
+              end
+          end
+
+        default:
+          begin
+
+          end
+      endcase // case (rx_engine_reg)
+    end // rx_engine
+
+
+  //----------------------------------------------------------------
+  // tx_engine
+  //
+  // FSM responsible for handling transmitting message bytes
+  // to the host interface.
+  //----------------------------------------------------------------
+  always @*
+    begin: tx_engine
+      // Default assignments
+      tx_buffer_ptr_inc = 0;
+      tx_buffer_ptr_rst = 0;
+      response_sent_new = 0;
+      response_sent_we  = 0;
+      tx_syn_new        = 0;
+      tx_syn_we         = 0;
+
+      tx_engine_new     = TX_IDLE;
+      tx_engine_we      = 0;
+
+      case (tx_engine_reg)
+        TX_IDLE:
+          begin
+            if (send_response_reg)
+              begin
+                tx_syn_new    = 1;
+                tx_syn_we     = 1;
+                tx_engine_new = TX_SYN;
+                tx_engine_we  = 1;
+              end
+          end
+
+        TX_SYN:
+          begin
+            if (tx_ack_reg)
+              begin
+                tx_syn_new    = 0;
+                tx_syn_we     = 1;
+                tx_engine_new = TX_NOACK;
+                tx_engine_we  = 1;
+              end
+          end
+
+        TX_NOACK:
+          begin
+            if (!tx_ack_reg)
+              begin
+                tx_engine_new = TX_NEXT;
+                tx_engine_we  = 1;
+              end
+          end
+
+        TX_NEXT:
+          begin
+            if (tx_buffer_ptr_reg == tx_msg_len_reg)
+              begin
+                tx_engine_new = TX_SENT;
+                tx_engine_we  = 1;
+              end
+            else
+              begin
+                tx_buffer_ptr_inc = 1;
+                tx_syn_new        = 1;
+                tx_syn_we         = 1;
+                tx_engine_new     = TX_SYN;
+                tx_engine_we      = 1;
+              end
+          end
+
+        TX_SENT:
+          begin
+            response_sent_new = 1;
+            response_sent_we  = 1;
+            tx_engine_new     = TX_DONE;
+            tx_engine_we      = 1;
+          end
+
+        TX_DONE:
+          begin
+            response_sent_new = 0;
+            response_sent_we  = 1;
+            tx_buffer_ptr_rst = 1;
+            tx_engine_new     = TX_IDLE;
+            tx_engine_we      = 1;
+          end
+
+        default:
+          begin
+            tx_engine_new = TX_IDLE;
+            tx_engine_we  = 1;
+          end
+      endcase // case (tx_engine_reg)
+    end // tx_engine
+
+
+  //----------------------------------------------------------------
+  // test_engine
+  //
+  // Test engine FSM logic. Parses received commands, tries to
+  // execute the commands and assmbles the response to the
+  // given commands.
+  //----------------------------------------------------------------
+  always @*
+    begin: test_engine
+      // Default assignments.
+      core_reset_n_new      = 1;
+      core_reset_n_we       = 0;
+      core_cs_new           = 0;
+      core_cs_we            = 0;
+      core_we_new           = 0;
+      core_we_we            = 0;
+      sample_core_output    = 0;
+      update_tx_buffer      = 0;
+      response_type         = 8'h00;
+      rx_buffer_rd_ptr_inc  = 0;
+      cmd_we                = 0;
+      core_addr_byte0_we    = 0;
+      core_addr_byte1_we    = 0;
+      core_wr_data_byte0_we = 0;
+      core_wr_data_byte1_we = 0;
+      core_wr_data_byte2_we = 0;
+      core_wr_data_byte3_we = 0;
+      send_response_new     = 0;
+      send_response_we      = 0;
+      test_engine_new       = TEST_IDLE;
+      test_engine_we        = 0;
+
+
+      case (test_engine_reg)
+        TEST_IDLE:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc = 1;
+                if (rx_byte == SOC)
+                  begin
+                    test_engine_new = TEST_GET_CMD;
+                    test_engine_we  = 1;
+                  end
+              end
+          end
+
+        TEST_GET_CMD:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc = 1;
+                cmd_we               = 1;
+                test_engine_new      = TEST_PARSE_CMD;
+                test_engine_we       = 1;
+              end
+          end
+
+        TEST_PARSE_CMD:
+          begin
+            case (cmd_reg)
+              RESET_CMD:
+                begin
+                  test_engine_new = TEST_GET_EOC;
+                  test_engine_we  = 1;
+                end
+
+              READ_CMD:
+                begin
+                  test_engine_new = TEST_GET_ADDR0;
+                  test_engine_we  = 1;
+                end
+
+              WRITE_CMD:
+                begin
+                  test_engine_new = TEST_GET_ADDR0;
+                  test_engine_we  = 1;
+                end
+
+              default:
+                begin
+                  test_engine_new = TEST_CMD_UNKNOWN;
+                  test_engine_we  = 1;
+                end
+            endcase // case (cmd_reg)
+          end
+
+
+        TEST_GET_ADDR0:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc = 1;
+                core_addr_byte0_we   = 1;
+                test_engine_new      = TEST_GET_ADDR1;
+                test_engine_we       = 1;
+              end
+          end
+
+
+        TEST_GET_ADDR1:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc = 1;
+                core_addr_byte1_we   = 1;
+
+                case (cmd_reg)
+                  READ_CMD:
+                    begin
+                      test_engine_new = TEST_GET_EOC;
+                      test_engine_we  = 1;
+                    end
+
+                  WRITE_CMD:
+                    begin
+                      test_engine_new = TEST_GET_DATA0;
+                      test_engine_we  = 1;
+                    end
+
+                  default:
+                    begin
+                      test_engine_new = TEST_CMD_UNKNOWN;
+                      test_engine_we  = 1;
+                    end
+                endcase // case (cmd_reg)
+              end
+          end
+
+
+        TEST_GET_DATA0:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc  = 1;
+                core_wr_data_byte0_we = 1;
+                test_engine_new       = TEST_GET_DATA1;
+                test_engine_we        = 1;
+              end
+          end
+
+
+        TEST_GET_DATA1:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc  = 1;
+                core_wr_data_byte1_we = 1;
+                test_engine_new       = TEST_GET_DATA2;
+                test_engine_we        = 1;
+              end
+          end
+
+
+        TEST_GET_DATA2:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc  = 1;
+                core_wr_data_byte2_we = 1;
+                test_engine_new       = TEST_GET_DATA3;
+                test_engine_we        = 1;
+              end
+          end
+
+
+        TEST_GET_DATA3:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc  = 1;
+                core_wr_data_byte3_we = 1;
+                test_engine_new       = TEST_GET_EOC;
+                test_engine_we        = 1;
+              end
+          end
+
+
+        TEST_GET_EOC:
+          begin
+            if (!rx_buffer_empty)
+              begin
+                rx_buffer_rd_ptr_inc = 1;
+                if (rx_byte == EOC)
+                  begin
+                    case (cmd_reg)
+                      RESET_CMD:
+                        begin
+                          test_engine_new = TEST_RST_START;
+                          test_engine_we  = 1;
+                        end
+
+                      READ_CMD:
+                        begin
+                          test_engine_new = TEST_RD_START;
+                          test_engine_we  = 1;
+                        end
+
+                      WRITE_CMD:
+                        begin
+                          test_engine_new = TEST_WR_START;
+                          test_engine_we  = 1;
+                        end
+
+                      default:
+                        begin
+                          test_engine_new = TEST_CMD_UNKNOWN;
+                          test_engine_we  = 1;
+                        end
+                    endcase // case (cmd_reg)
+                  end
+                else
+                  begin
+                    test_engine_new  = TEST_CMD_ERROR;
+                    test_engine_we   = 1;
+                  end
+              end
+          end
+
+
+        TEST_RST_START:
+          begin
+            core_reset_n_new = 0;
+            core_reset_n_we  = 1;
+            test_engine_new  = TEST_RST_WAIT;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_RST_WAIT:
+          begin
+            test_engine_new = TEST_RST_END;
+            test_engine_we  = 1;
+          end
+
+
+        TEST_RST_END:
+          begin
+            core_reset_n_new = 1;
+            core_reset_n_we  = 1;
+            update_tx_buffer = 1;
+            response_type    = RESET_OK;
+            test_engine_new  = TEST_SEND_RESPONSE;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_RD_START:
+          begin
+            core_cs_new     = 1;
+            core_cs_we      = 1;
+            test_engine_new = TEST_RD_WAIT;
+            test_engine_we  = 1;
+          end
+
+
+        TEST_RD_WAIT:
+          begin
+            test_engine_new    = TEST_RD_WAIT2;
+            test_engine_we     = 1;
+          end
+
+
+        TEST_RD_WAIT2:
+          begin
+            sample_core_output = 1;
+            test_engine_new    = TEST_RD_END;
+            test_engine_we     = 1;
+          end
+
+
+        TEST_RD_END:
+          begin
+            core_cs_new        = 0;
+            core_cs_we         = 1;
+            sample_core_output = 0;
+
+            if (core_error_reg)
+              begin
+                update_tx_buffer = 1;
+                response_type    = ERROR;
+              end
+            else
+              begin
+                update_tx_buffer = 1;
+                response_type    = READ_OK;
+              end
+
+            test_engine_new = TEST_SEND_RESPONSE;
+            test_engine_we  = 1;
+          end
+
+
+        TEST_WR_START:
+          begin
+            core_cs_new = 1;
+            core_cs_we  = 1;
+            core_we_new = 1;
+            core_we_we  = 1;
+
+            test_engine_new = TEST_WR_WAIT;
+            test_engine_we  = 1;
+          end
+
+
+        TEST_WR_WAIT:
+          begin
+            sample_core_output = 1;
+            test_engine_new  = TEST_WR_END;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_WR_END:
+          begin
+            core_cs_new        = 0;
+            core_cs_we         = 1;
+            core_we_new        = 0;
+            core_we_we         = 1;
+            sample_core_output = 0;
+
+            if (core_error_reg)
+              begin
+                update_tx_buffer = 1;
+                response_type    = ERROR;
+              end
+            else
+              begin
+                update_tx_buffer = 1;
+                response_type    = WRITE_OK;
+              end
+
+            test_engine_new  = TEST_SEND_RESPONSE;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_CMD_UNKNOWN:
+          begin
+            update_tx_buffer = 1;
+            response_type    = UNKNOWN;
+            test_engine_new  = TEST_SEND_RESPONSE;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_CMD_ERROR:
+          begin
+            update_tx_buffer = 1;
+            response_type    = ERROR;
+            test_engine_new  = TEST_SEND_RESPONSE;
+            test_engine_we   = 1;
+          end
+
+
+        TEST_SEND_RESPONSE:
+          begin
+            send_response_new = 1;
+            send_response_we  = 1;
+            if (response_sent_reg)
+              begin
+                send_response_new = 0;
+                send_response_we  = 1;
+                test_engine_new   = TEST_IDLE;
+                test_engine_we    = 1;
+              end
+          end
+
+
+        default:
+          begin
+            // If we encounter an unknown state we move
+            // back to idle.
+            test_engine_new = TEST_IDLE;
+            test_engine_we  = 1;
+          end
+      endcase // case (test_engine_reg)
+    end // test_engine
+
+endmodule // coretest
+
+//======================================================================
+// EOF coretest.v
+//======================================================================
diff --git a/coretest/src/sw/seriedebug.py b/coretest/src/sw/seriedebug.py
new file mode 100755
index 0000000..2062116
--- /dev/null
+++ b/coretest/src/sw/seriedebug.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#=======================================================================
+#
+# seriedebug.py
+# -------------
+# Program that sends test bytes onto the serial link and print out
+# any response.
+#
+# Note: This proram requires the PySerial module.
+# http://pyserial.sourceforge.net/
+#
+# 
+# Author: Joachim Strömbergson
+# Copyright (c) 2014 SUNET
+# 
+# Redistribution and use in source and binary forms, with or 
+# without modification, are permitted provided that the following 
+# conditions are met: 
+# 
+# 1. Redistributions of source code must retain the above copyright 
+#    notice, this list of conditions and the following disclaimer. 
+# 
+# 2. Redistributions in binary form must reproduce the above copyright 
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution. 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#=======================================================================
+
+#-------------------------------------------------------------------
+# Python module imports.
+#-------------------------------------------------------------------
+import sys
+import serial
+
+    
+#-------------------------------------------------------------------
+# main()
+#
+# Parse arguments.
+#-------------------------------------------------------------------
+def main():
+    print "Seriedebug started..."
+    print
+
+    verbose = True
+    
+    # Create a serial devce and configure it.
+    # Should be:
+    # 1200 Baud
+    # 1 start bit
+    # 8 data bits
+    # 1 even parity bit
+    # 2 stop bits
+    # No RTS/CTS
+    # Note: You need to update to the correct device in your system.
+    ser = serial.Serial()
+    ser.port='/dev/cu.usbserial-A5020LKF'
+    ser.baudrate=1200
+    ser.bytesize=8
+    ser.parity='E'
+    ser.stopbits=2
+    ser.timeout=1
+    ser.writeTimeout=0
+
+    # Open the interface.
+    ser.open()
+    if verbose:
+        print "Opening device."
+        
+    # Send a byte and try to get the response.
+    test_byte = '\xaa'
+    ser.write(test_byte)
+    if verbose:
+        print "transmitting byte 0x%0x" % ord(test_byte)
+
+    
+    if verbose:
+        print "Waiting for response..."
+
+    response = ""
+    while not len(response):
+        response = ser.read()
+        if len(response):
+            print "received response: 0x%0x" % ord(response)
+
+    # Exit nicely.
+    if verbose:
+        print "Done. Closing device."
+    ser.close()
+
+
+#-------------------------------------------------------------------
+# __name__
+# Python thingy which allows the file to be run standalone as
+# well as parsed from within a Python interpreter.
+#-------------------------------------------------------------------
+if __name__=="__main__": 
+    # Run the main function.
+    sys.exit(main())
+
+#=======================================================================
+# EOF seriedebug.py
+#=======================================================================
diff --git a/coretest/src/tb/tb_coretest.v b/coretest/src/tb/tb_coretest.v
new file mode 100644
index 0000000..e70770d
--- /dev/null
+++ b/coretest/src/tb/tb_coretest.v
@@ -0,0 +1,492 @@
+//======================================================================
+//
+// tb_coretest.v
+// -------------
+// Testbench for coretest. Generates commands and observes responses.
+//
+//
+// 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, 
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+module tb_coretest();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG           = 0;
+  parameter VERBOSE         = 0;
+  parameter CMD_MONITOR     = 1;
+  parameter REC_MONITOR     = 0;
+
+  parameter CLK_HALF_PERIOD = 1;
+  parameter CLK_PERIOD      = CLK_HALF_PERIOD * 2;
+
+  // Command and response constants.
+  parameter SOC       = 8'h55;
+  parameter EOC       = 8'haa;
+  parameter RESET_CMD = 8'h01;
+  parameter READ_CMD  = 8'h10; 
+  parameter WRITE_CMD = 8'h11; 
+
+  parameter SOR      = 8'haa;
+  parameter EOR      = 8'h55;
+  parameter UNKNOWN  = 8'hfe;
+  parameter ERROR    = 8'hfd;
+  parameter READ_OK  = 8'h7f;
+  parameter WRITE_OK = 8'h7e;
+  parameter RESET_OK = 8'h7d;
+  
+  parameter MAX_MEM  = 16'h00ff;
+
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0]  cycle_ctr;
+  reg [31 : 0]  error_ctr;
+  reg [31 : 0]  tc_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+
+  reg           tb_rx_syn;
+  reg [7 : 0]   tb_rx_data;
+  wire          tb_rx_ack;
+  wire          tb_tx_syn;
+  wire [7 : 0]  tb_tx_data;
+  reg           tb_tx_ack;
+
+  wire          tb_core_reset_;
+  wire          tb_core_cs;
+  wire          tb_core_we;
+  wire [15 : 0] tb_core_address;
+  wire [31 : 0] tb_core_write_data;
+  reg [31 : 0]  tb_core_read_data;
+  reg           tb_core_error;
+
+  reg [7 : 0]   received_tx_data;
+  
+  reg [31 : 0]  test_mem [0 : (MAX_MEM - 1'b1)];
+
+
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  coretest dut(
+               .clk(tb_clk),
+               .reset_n(tb_reset_n),
+                
+               // Interface to communication core
+               .rx_syn(tb_rx_syn),
+               .rx_data(tb_rx_data),
+               .rx_ack(tb_rx_ack),
+               
+               .tx_syn(tb_tx_syn),
+               .tx_data(tb_tx_data),
+               .tx_ack(tb_tx_ack),
+                
+               // Interface to the core being tested.
+               .core_reset_n(tb_core_reset_n),
+               .core_cs(tb_core_cs),
+               .core_we(tb_core_we),
+               .core_address(tb_core_address),
+               .core_write_data(tb_core_write_data),
+               .core_read_data(tb_core_read_data),
+               .core_error(tb_core_error)
+              );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+  
+  //----------------------------------------------------------------
+  // sys_monitor
+  //
+  // System monitor. Can display status about the dut and TB
+  // every cycle.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      #(CLK_PERIOD);      
+      if (DEBUG)
+        begin
+          dump_dut_state();
+          $display("");
+        end
+
+      if (VERBOSE)
+        begin
+          $display("cycle: 0x%016x", cycle_ctr);
+        end
+      cycle_ctr = cycle_ctr + 1;
+    end
+  
+
+  //----------------------------------------------------------------
+  // command_monitor
+  //
+  // Observes any read/write or reset commands generated
+  // by the DUT.
+  //----------------------------------------------------------------
+  always
+    begin : command_monitor
+      #(CLK_PERIOD);      
+      if (CMD_MONITOR)
+        begin
+          if (!tb_core_reset_n)
+            begin
+              $display("Core is being reset by coretest.");
+            end
+
+          if (tb_core_cs)
+            begin
+              if (tb_core_we)
+                begin
+                  $display("Core is being written to: address 0x%08x = 0x%08x",
+                           tb_core_address, tb_core_write_data);
+                end
+              else
+                begin
+                  $display("Core is being read from: address 0x%08x = 0x%08x",
+                           tb_core_address, tb_core_read_data);
+                end
+            end
+        end
+    end
+
+
+  //----------------------------------------------------------------
+  // receive_logic
+  //
+  // The logic needed to the correct handshake expected by the DUT
+  // when it is sending bytes.
+  //----------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : receive_logic
+      if (tb_tx_syn)
+        begin
+          if (REC_MONITOR)
+            begin
+              $display("Receiving byte 0x%02x from the DUT.", tb_tx_data);
+            end
+          #(2 * CLK_PERIOD);
+          tb_tx_ack = 1;
+
+          #(2 * CLK_PERIOD);
+          tb_tx_ack = 0;
+        end
+    end // receive_logic
+
+
+  //----------------------------------------------------------------
+  // test_mem_logic
+  //
+  // The logic needed to implement the test memory. We basically
+  // implement a simple memory to allow read and write operations
+  // via commands to the DUT to really be executed.
+  //----------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : test_mem_logic
+      if (tb_core_cs)
+        begin
+          if (tb_core_we)
+            begin
+              if (tb_core_address < MAX_MEM)
+                begin
+                  $display("Writing to test_mem[0x%08x] = 0x%08x",
+                           tb_core_address, tb_core_write_data);
+                  test_mem[tb_core_address] = tb_core_write_data;
+                end
+              else
+                begin
+                  $display("Writing to incorrect address 0x%08x",
+                           tb_core_address);
+                  tb_core_error = 1;
+                end
+            end
+          else
+            begin
+              if (tb_core_address < MAX_MEM)
+                begin
+                  $display("Reading from test_mem[0x%08x] = 0x%08x",
+                           tb_core_address, tb_core_read_data);
+                  tb_core_read_data = test_mem[tb_core_address];
+                end
+              else
+                begin
+                  $display("Reading from incorrect address 0x%08x",
+                           tb_core_address);
+                  tb_core_error = 1;
+                end
+            end
+        end
+      else
+        begin
+          tb_core_read_data = 32'h00000000;
+          tb_core_error     = 0;
+        end
+    end
+  
+  
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dut when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $display("rx_syn = 0x%01x, rx_data = 0x%02x, rx_ack = 0x%01x",
+               dut.rx_syn, dut.rx_data, dut.rx_ack);
+      $display("tx_syn = 0x%01x, tx_data = 0x%02x, tx_ack = 0x%01x",
+               dut.tx_syn, dut.tx_data, dut.tx_ack);
+      $display("cs = 0x%01x, we = 0x%01x, address = 0x%04x, write_data = 0x%08x, read_data = 0x%08x, error = 0x%01x",
+               dut.core_cs, dut.core_we, dut.core_address, dut.core_write_data, dut.core_read_data, dut.core_error);
+      $display("");
+
+      $display("RX chain signals:");
+      $display("rx_buffer_wr_ptr = 0x%02x, rx_buffer_rd_ptr = 0x%02x, rx_buffer_ctr = 0x%02x, rx_buffer_empty = 0x%01x,  rx_buffer_full = 0x%01x",
+               dut.rx_buffer_wr_ptr_reg, dut.rx_buffer_rd_ptr_reg,  dut.rx_buffer_ctr_reg, dut.rx_buffer_empty, dut.rx_buffer_full);
+      $display("");
+
+      $display("Control signals and FSM state:");
+      $display("test_engine_reg = 0x%02x, cmd_reg = 0x%02x",
+               dut.test_engine_reg, dut.cmd_reg);
+      $display("");
+    end
+  endtask // dump_dut_state
+
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(2 * CLK_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    reg [8 : 0] i;
+    
+    begin
+      cycle_ctr         = 0;
+      error_ctr         = 0;
+      tc_ctr            = 0;
+      
+      tb_clk            = 0;
+      tb_reset_n        = 1;
+      tb_rx_syn         = 0;
+      tb_rx_data        = 8'h00;
+      tb_tx_ack         = 0;
+
+      for (i = 0 ; i < 256 ; i = i + 1)
+        begin
+          test_mem[i[7 : 0]] = {4{i[7 : 0]}};
+        end
+    end
+  endtask // init_sim
+
+
+  //----------------------------------------------------------------
+  // send_byte
+  //
+  // Send a byte of data to the DUT.
+  //----------------------------------------------------------------
+  task send_byte(input [7 : 0] data);
+    integer i;
+    begin
+
+      if (VERBOSE)
+        begin
+          $display("*** Sending byte 0x%02x to the dut.", data);
+          $display("*** Setting RX data and RX SYN.");
+        end
+      tb_rx_data = data;
+      tb_rx_syn  = 1;
+
+      while (!tb_rx_ack)
+        begin
+          #CLK_PERIOD;
+          if (VERBOSE)
+            begin
+              $display("*** Waiting for RX ACK.");
+            end
+        end
+
+      if (VERBOSE)
+        begin
+          $display("*** RX ACK seen. Dropping SYN.");
+        end
+      tb_rx_syn  = 0;
+
+      #(2 * CLK_PERIOD);
+    end
+  endtask // send_byte
+
+  
+  //----------------------------------------------------------------
+  // send_reset_command
+  //
+  // Generates a reset command to the dut.
+  //----------------------------------------------------------------
+  task send_reset_command();
+    begin
+      $display("*** Sending reset command.");
+      send_byte(SOC);
+      send_byte(RESET_CMD);
+      send_byte(EOC);
+      $display("*** Sending reset command done.");
+    end
+  endtask // send_write_command
+
+  
+  //----------------------------------------------------------------
+  // send_read_command
+  //
+  // Generates a read command to the dut.
+  //----------------------------------------------------------------
+  task send_read_command(input [15 : 0] addr);
+    begin
+      $display("*** Sending read command: address 0x%04x.", addr);
+      send_byte(SOC);
+      send_byte(READ_CMD);
+      send_byte(addr[15 : 8]);
+      send_byte(addr[7 : 0]);
+      send_byte(EOC);
+      $display("*** Sending read command done.");
+    end
+  endtask // send_write_command
+
+  
+  //----------------------------------------------------------------
+  // send_write_command
+  //
+  // Generates a write command to the dut.
+  //----------------------------------------------------------------
+  task send_write_command(input [15 : 0] addr, input [31 : 0] data);
+    begin
+      $display("*** Sending write command: address 0x%04x = 0x%08x.", addr, data);
+      send_byte(SOC);
+      send_byte(WRITE_CMD);
+      send_byte(addr[15 : 8]);
+      send_byte(addr[7 : 0]);
+      send_byte(data[31 : 24]);
+      send_byte(data[23 : 16]);
+      send_byte(data[15 : 8]);
+      send_byte(data[7 : 0]);
+      send_byte(EOC);
+      $display("*** Sending write command done.");
+    end
+  endtask // send_write_command
+  
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases did not complete successfully.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+                         
+    
+  //----------------------------------------------------------------
+  // coretest_test
+  // The main test functionality. 
+  //----------------------------------------------------------------
+  initial
+    begin : coretest_test
+      $display("   -- Testbench for coretest started --");
+
+      init_sim();
+      dump_dut_state();
+      reset_dut();
+      dump_dut_state();
+
+      #(64 * CLK_PERIOD);
+
+      send_reset_command();
+
+      send_read_command(16'h0023);
+      send_read_command(16'h0055);
+
+      send_write_command(16'h00aa, 32'h1337beef);
+      send_read_command(16'h00aa);
+      send_write_command(16'h0010, 32'h55aa55aa);
+      send_read_command(16'h0010);
+
+      #(200 * CLK_PERIOD);
+
+      display_test_result();
+      $display("*** Simulation done.");
+      $finish;
+    end // coretest_test
+endmodule // tb_coretest
+
+//======================================================================
+// EOF tb_coretest.v
+//======================================================================
diff --git a/coretest/toolruns/Makefile b/coretest/toolruns/Makefile
new file mode 100755
index 0000000..4a5d5d1
--- /dev/null
+++ b/coretest/toolruns/Makefile
@@ -0,0 +1,75 @@
+#===================================================================
+#
+# Makefile
+# --------
+# Makefile for building and simulating coretest.
+#
+#
+# Author: Joachim Strombergson
+# Copyright (c) 2014 SUNET
+# 
+# Redistribution and use in source and binary forms, with or 
+# without modification, are permitted provided that the following 
+# conditions are met: 
+# 
+# 1. Redistributions of source code must retain the above copyright 
+#    notice, this list of conditions and the following disclaimer. 
+# 
+# 2. Redistributions in binary form must reproduce the above copyright 
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution. 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#===================================================================
+
+CORETEST_SRC=../src/rtl/coretest.v
+CORETEST_TB_SRC=../src/tb/tb_coretest.v
+CORETEST_TARGET = coretest.sim
+
+CC=iverilog
+
+
+all: coretest
+
+
+coretest: $(CORETEST_TB_SRC) $(CORETEST_SRC)
+	$(CC) -o $(CORETEST_TARGET) $(CORETEST_TB_SRC) $(CORETEST_SRC)
+
+
+sim-coretest: $(CORETEST_TARGET)
+	./$(CORETEST_TARGET)
+
+
+debug:
+	@echo "No debug available."
+
+
+clean:
+	rm -f $(CORETEST_TARGET)
+
+
+help:
+	@echo "Supported targets:"
+	@echo "------------------"
+	@echo "coretest:      Build coretest simulation target."
+	@echo "sim-coretest:  Run coretest simulation."
+	@echo "debug:         Print the internal varibles."
+	@echo "clean:         Delete all built files."
+
+#===================================================================
+# EOF Makefile
+#===================================================================
+
diff --git a/coretest/toolruns/modelsim/coretest_wave.do b/coretest/toolruns/modelsim/coretest_wave.do
new file mode 100644
index 0000000..d7abc8e
--- /dev/null
+++ b/coretest/toolruns/modelsim/coretest_wave.do
@@ -0,0 +1,80 @@
+onerror {resume}
+quietly WaveActivateNextPane {} 0
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/clk
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/reset_n
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_syn
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_data
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_ack
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_syn
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_data
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_ack
+add wave -noupdate -divider <NULL>
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_reset_n
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_cs
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_we
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_address
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_write_data
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_read_data
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_error
+add wave -noupdate -divider <NULL>
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_reset_n_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_cs_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_we_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/send_response_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/response_sent_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/cmd_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_addr_byte0_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_addr_byte1_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_wr_data_byte0_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_wr_data_byte1_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_wr_data_byte2_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_wr_data_byte3_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_read_data_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/core_error_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/sample_core_output
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_rd_ptr_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_rd_ptr_inc
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_wr_ptr_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_wr_ptr_inc
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_ctr_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_ctr_inc
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_ctr_dec
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_full
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer_empty
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_buffer
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_ptr_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_ptr_inc
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_engine_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_engine_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/test_engine_reg
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed0
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed1
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed2
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed3
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed4
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed5
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed6
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed7
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/tx_buffer_muxed8
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/update_tx_buffer
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/response_type
+add wave -noupdate -radix hexadecimal /tb_coretest/dut/rx_byte
+TreeUpdate [SetDefaultTree]
+WaveRestoreCursors {{Cursor 1} {361000 ps} 0}
+quietly wave cursor active 1
+configure wave -namecolwidth 290
+configure wave -valuecolwidth 203
+configure wave -justifyvalue left
+configure wave -signalnamewidth 0
+configure wave -snapdistance 10
+configure wave -datasetprefix 0
+configure wave -rowmargin 4
+configure wave -childrowmargin 2
+configure wave -gridoffset 0
+configure wave -gridperiod 1
+configure wave -griddelta 40
+configure wave -timeline 0
+configure wave -timelineunits ps
+update
+WaveRestoreZoom {0 ps} {451500 ps}
diff --git a/eim/src/rtl/cdc_bus_pulse.v b/eim/src/rtl/cdc_bus_pulse.v
new file mode 100644
index 0000000..cc2d8db
--- /dev/null
+++ b/eim/src/rtl/cdc_bus_pulse.v
@@ -0,0 +1,145 @@
+//======================================================================
+//
+// cdc_bus_pulse.v
+// ---------------
+// Clock Domain Crossing handler for the Cryptech Novena
+// FPGA framework design.
+//
+// This module is based on design suggested on page 27 of the
+// paper 'Clock Domain Crossing (CDC) Design & Verification Techniques
+// Using SystemVerilog' by Clifford E. Cummings (Sunburst Design, Inc.)
+//
+//
+// Author: Pavel Shatov
+// 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 cdc_bus_pulse
+  #(parameter   DATA_WIDTH      = 32)     // width of data bus
+   (
+    input wire                   src_clk, // source domain clock
+    input wire [DATA_WIDTH-1:0]  src_din, // data from source clock domain
+    input wire                   src_req, // start transfer pulse from source clock domain
+
+    input wire                   dst_clk, // destination domain clock
+    output wire [DATA_WIDTH-1:0] dst_dout, // data to destination clock domain
+    output wire                  dst_pulse // transfer done pulse to destination clock domain
+    );
+
+   //
+   // Source Side Registers
+   //
+   reg                           src_ff         = 1'b0;                 // transfer request flag
+   reg [DATA_WIDTH-1:0]          src_latch      = {DATA_WIDTH{1'bX}};   // source data buffer
+
+
+   //
+   // Source Request Handler
+   //
+   always @(posedge src_clk)
+     //
+     if (src_req) begin                         // transfer request pulse?
+        src_ff          <= ~src_ff;             // toggle transfer request flag...
+        src_latch       <= src_din;             // ... and capture data in source buffer
+     end
+
+
+   //
+   // Source -> Destination Flag Sync Logic
+   //
+
+   /* ISE may decide to infer SRL here, so we explicitly instantiate slice registers. */
+
+   wire flag_sync_first;        // first FF output
+   wire flag_sync_second;       // second FF output
+   wire flag_sync_third;        // third FF output
+   wire flag_sync_pulse;        // flag toggle detector output
+
+   FDCE ff_sync_first
+     (
+      .C(dst_clk),
+      .D(src_ff),               // capture flag from another clock domain
+      .Q(flag_sync_first),      // metastability can occur here
+      .CLR(1'b0),
+      .CE(1'b1)
+      );
+   FDCE ff_sync_second
+     (
+      .C(dst_clk),
+      .D(flag_sync_first),      // synchronize captured flag to remove metastability
+      .Q(flag_sync_second),     // and pass it to another flip-flop
+      .CLR(1'b0),
+      .CE(1'b1)
+      );
+   FDCE ff_sync_third
+     (
+      .C(dst_clk),
+      .D(flag_sync_second),     // delay synchronized flag in another flip-flip, because we need
+      .Q(flag_sync_third),      // two synchronized flag values (current and delayed) to detect its change
+      .CLR(1'b0),
+      .CE(1'b1)
+      );
+
+   // when delayed flag value differs from its current value, it was changed
+   // by the source side, so there must have been a transfer request
+   assign flag_sync_pulse = flag_sync_second ^ flag_sync_third;
+
+
+   //
+   // Destination Side Registers
+   //
+   reg  dst_pulse_reg   = 1'b0;                         // transfer done flag
+   reg [DATA_WIDTH-1:0] dst_latch = {DATA_WIDTH{1'bX}}; // destination data buffer
+
+   assign dst_pulse     = dst_pulse_reg;
+   assign dst_dout      = dst_latch;
+
+   //
+   // Destination Request Handler
+   //
+   always @(posedge dst_clk) begin
+      //
+      dst_pulse_reg <= flag_sync_pulse; // generate pulse if flag change was detected
+      //
+      if (flag_sync_pulse)
+        dst_latch <= src_latch;
+      /* By the time destination side receives synchronized flag
+       * value, data should be stable, we can safely capture and store
+       * it in the destination buffer.
+       */
+
+   end
+
+
+endmodule
+
+//======================================================================
+// EOF cdc_bus_pulse.v
+//======================================================================
diff --git a/eim/src/rtl/eim.v b/eim/src/rtl/eim.v
new file mode 100644
index 0000000..dcbd226
--- /dev/null
+++ b/eim/src/rtl/eim.v
@@ -0,0 +1,75 @@
+`define USE_EIM
+
+module eim
+  (
+   // EIM interface pins from CPU
+   input wire 	       eim_bclk, // EIM burst clock. Started by the CPU.
+   input wire 	       eim_cs0_n, // Chip select (active low).
+   inout wire [15 : 0] eim_da, // Bidirectional address and data port.
+   input wire [18: 16] eim_a, // MSB part of address port.                     
+   input wire 	       eim_lba_n, // Latch address signal (active low).
+   input wire 	       eim_wr_n, // write enable signal (active low).
+   input wire 	       eim_oe_n, // output enable signal (active low).
+   output wire 	       eim_wait_n, // Data wait signal (active low).
+
+   // system clock and reset
+   input wire 	       sys_clk,
+   input wire 	       sys_rst,
+
+   // EIM interface to cores
+   output wire [16: 0] sys_eim_addr,
+   output wire 	       sys_eim_wr,
+   output wire 	       sys_eim_rd,
+   output wire [31: 0] sys_eim_dout,
+   input wire [31: 0]  sys_eim_din,
+
+   // Novena utility ports
+   output wire 	       led_pin		// LED on edge close to the FPGA.
+   );
+
+   // XXX add NAME0/NAME1/VERSION
+
+   //----------------------------------------------------------------
+   // EIM Arbiter
+   //
+   // EIM arbiter handles EIM access and transfers it into
+   // `sys_clk' clock domain.
+   //----------------------------------------------------------------
+
+   eim_arbiter eim
+     (
+      .eim_bclk(eim_bclk),
+      .eim_cs0_n(eim_cs0_n),
+      .eim_da(eim_da),
+      .eim_a(eim_a),
+      .eim_lba_n(eim_lba_n),
+      .eim_wr_n(eim_wr_n),
+      .eim_oe_n(eim_oe_n),
+      .eim_wait_n(eim_wait_n),
+
+      .sys_clk(sys_clk),
+
+      .sys_addr(sys_eim_addr),
+      .sys_wren(sys_eim_wr),
+      .sys_data_out(sys_eim_dout),
+      .sys_rden(sys_eim_rd),
+      .sys_data_in(sys_eim_din)
+      );
+
+
+   //----------------------------------------------------------------
+   // LED Driver
+   //
+   // A simple utility LED driver that turns on the Novena
+   // board LED when the EIM interface is active.
+   //----------------------------------------------------------------
+   eim_indicator led
+     (
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+      .eim_active(sys_eim_wr | sys_eim_rd),
+      .led_out(led_pin)
+      );
+
+
+endmodule // eim
diff --git a/eim/src/rtl/eim_arbiter.v b/eim/src/rtl/eim_arbiter.v
new file mode 100644
index 0000000..e9b2c76
--- /dev/null
+++ b/eim/src/rtl/eim_arbiter.v
@@ -0,0 +1,309 @@
+//======================================================================
+//
+// eim_arbiter.v
+// -------------
+// Port arbiter for the EIM interface for the Cryptech
+// Novena FPGA framework.
+//
+//
+// Author: Pavel Shatov
+// 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 eim_arbiter
+  (
+   // eim bus
+   input wire          eim_bclk, 
+   input wire          eim_cs0_n,
+   inout wire [15: 0]  eim_da,
+   input wire [18:16]  eim_a,
+   input wire          eim_lba_n,
+   input wire          eim_wr_n,
+   input wire          eim_oe_n,
+   output wire         eim_wait_n,
+
+   // system clock
+   input wire          sys_clk,
+
+   // user bus
+   output wire [16: 0] sys_addr, 
+   output wire         sys_wren,
+   output wire [31: 0] sys_data_out,
+   output wire         sys_rden,
+   input wire [31: 0]  sys_data_in
+   );
+
+
+   //
+   // Data/Address PHY
+   //
+
+   /* PHY is needed to control bi-directional address/data bus. */
+
+   wire [15: 0]        da_ro;   // value read from pins
+   reg [15: 0]         da_di;   // value drives onto pins
+
+   eim_da_phy da_phy
+     (
+      .buf_io(eim_da),          // <-- connect directly top-level port
+      .buf_di(da_di),
+      .buf_ro(da_ro),
+      .buf_t(eim_oe_n)          // <-- driven by EIM directly
+      );
+
+
+   //
+   // FSM
+   //
+   localparam   EIM_FSM_STATE_INIT        = 5'b0_0_000; // arbiter is idle
+
+   localparam   EIM_FSM_STATE_WRITE_START = 5'b1_1_000; // got address to write at
+   localparam   EIM_FSM_STATE_WRITE_LSB   = 5'b1_1_001; // got lower 16 bits of data to write
+   localparam   EIM_FSM_STATE_WRITE_MSB   = 5'b1_1_010; // got upper 16 bits of data to write
+   localparam   EIM_FSM_STATE_WRITE_WAIT  = 5'b1_1_100; // request to user-side logic sent
+   localparam   EIM_FSM_STATE_WRITE_DONE  = 5'b1_1_111; // user-side logic acknowledged transaction
+
+   localparam   EIM_FSM_STATE_READ_START  = 5'b1_0_000; // got address to read from
+   localparam   EIM_FSM_STATE_READ_WAIT   = 5'b1_0_100; // request to user-side logic sent
+   localparam   EIM_FSM_STATE_READ_READY  = 5'b1_0_011; // got acknowledge from user logic
+   localparam   EIM_FSM_STATE_READ_LSB    = 5'b1_0_001; // returned lower 16 bits to master
+   localparam   EIM_FSM_STATE_READ_MSB    = 5'b1_0_010; // returned upper 16 bits to master
+   localparam   EIM_FSM_STATE_READ_DONE   = 5'b1_0_111; // transaction complete
+
+   reg [ 4: 0]  eim_fsm_state   = EIM_FSM_STATE_INIT;   // fsm state
+   reg [16: 0]  eim_addr_latch  = {17{1'bX}};           // transaction address
+   reg [15: 0]  eim_write_lsb_latch = {16{1'bX}};       // lower 16 bits of data to write
+
+   /* These flags are used to wake up from INIT state. */
+   wire         eim_write_start_flag = (eim_lba_n == 1'b0) && (eim_wr_n == 1'b0) && (da_ro[1:0] == 2'b00);
+   wire         eim_read_start_flag  = (eim_lba_n == 1'b0) && (eim_wr_n == 1'b1) && (da_ro[1:0] == 2'b00);
+
+   /* These are transaction response flag and data from user-side logic. */
+   wire         eim_user_ack;
+   wire [31: 0] eim_user_data;
+
+   /* FSM is reset whenever Chip Select is de-asserted. */
+
+   //
+   // FSM Transition Logic
+   //
+   always @(posedge eim_bclk or posedge eim_cs0_n)
+     begin
+        //
+        if (eim_cs0_n == 1'b1)
+          eim_fsm_state <= EIM_FSM_STATE_INIT;
+        //
+        else
+          begin
+             //
+             case (eim_fsm_state)
+               //
+               // INIT -> WRITE, INIT -> READ
+               //
+               EIM_FSM_STATE_INIT:
+                 begin
+                    if (eim_write_start_flag)
+                      eim_fsm_state     <= EIM_FSM_STATE_WRITE_START;
+                    if (eim_read_start_flag)
+                      eim_fsm_state     <= EIM_FSM_STATE_READ_START;
+                 end
+               //
+               // WRITE
+               //
+               EIM_FSM_STATE_WRITE_START:
+                 eim_fsm_state  <= EIM_FSM_STATE_WRITE_LSB;
+               //
+               EIM_FSM_STATE_WRITE_LSB:
+                 eim_fsm_state  <= EIM_FSM_STATE_WRITE_MSB;
+               //
+               EIM_FSM_STATE_WRITE_MSB:
+                 eim_fsm_state  <= EIM_FSM_STATE_WRITE_WAIT;
+               //
+               EIM_FSM_STATE_WRITE_WAIT:
+                 if (eim_user_ack)
+                   eim_fsm_state <= EIM_FSM_STATE_WRITE_DONE;
+               //
+               EIM_FSM_STATE_WRITE_DONE:
+                 eim_fsm_state  <= EIM_FSM_STATE_INIT;
+               //
+               // READ
+               //
+               EIM_FSM_STATE_READ_START:
+                 eim_fsm_state  <= EIM_FSM_STATE_READ_WAIT;
+               //
+               EIM_FSM_STATE_READ_WAIT:
+                 if (eim_user_ack)
+                   eim_fsm_state <= EIM_FSM_STATE_READ_READY;
+               //
+               EIM_FSM_STATE_READ_READY:
+                 eim_fsm_state <= EIM_FSM_STATE_READ_LSB;
+               //
+               EIM_FSM_STATE_READ_LSB:
+                 eim_fsm_state  <= EIM_FSM_STATE_READ_MSB;
+               //
+               EIM_FSM_STATE_READ_MSB:
+                 eim_fsm_state  <= EIM_FSM_STATE_READ_DONE;
+               //
+               EIM_FSM_STATE_READ_DONE:
+                 eim_fsm_state  <= EIM_FSM_STATE_INIT;
+               //
+               //
+               //
+               default:
+                 eim_fsm_state  <= EIM_FSM_STATE_INIT;
+               //
+             endcase
+             //
+          end
+        //
+     end
+
+
+   //
+   // Address Latch
+   //
+   always @(posedge eim_bclk)
+     //
+     if ((eim_fsm_state == EIM_FSM_STATE_INIT) && (eim_write_start_flag || eim_read_start_flag))
+       eim_addr_latch <= {eim_a[18:16], da_ro[15:2]};
+
+
+   //
+   // Additional Write Logic
+   //
+   always @(posedge eim_bclk)
+     //
+     if (eim_fsm_state == EIM_FSM_STATE_WRITE_START)
+       eim_write_lsb_latch <= da_ro;
+
+
+   //
+   // Additional Read Logic
+   //
+
+   /* Note that this stuff operates on falling clock edge, because the cpu
+    * samples our bi-directional data bus on rising clock edge.
+    */
+
+   always @(negedge eim_bclk or posedge eim_cs0_n)
+     //
+     if (eim_cs0_n == 1'b1)                                                                             da_di <= {16{1'bX}};                    // don't care what to drive
+     else begin
+        //
+        if (eim_fsm_state == EIM_FSM_STATE_READ_LSB)
+          da_di <= eim_user_data[15: 0];        // drive lower 16 bits at first...
+        if (eim_fsm_state == EIM_FSM_STATE_READ_MSB)
+          da_di <= eim_user_data[31:16];        // ...then drive upper 16 bits
+        //
+     end
+
+
+   //
+   // Wait Logic
+   //
+
+   /* Note that this stuff operates on falling clock edge, because the cpu
+    *  samples our WAIT_N flag on rising clock edge.
+    */
+
+   reg  eim_wait_reg    = 1'b0;
+
+   always @(negedge eim_bclk or posedge eim_cs0_n)
+     //
+     if (eim_cs0_n == 1'b1)
+       eim_wait_reg     <= 1'b0;                // clear wait
+     else begin
+        //
+        if (eim_fsm_state == EIM_FSM_STATE_WRITE_START)
+          eim_wait_reg  <= 1'b1;                // start waiting for write to complete
+        if (eim_fsm_state == EIM_FSM_STATE_READ_START)
+          eim_wait_reg  <= 1'b1;                // start waiting for read to complete
+        //
+        if (eim_fsm_state == EIM_FSM_STATE_WRITE_DONE)
+          eim_wait_reg  <= 1'b0;                // write transaction done
+        if (eim_fsm_state == EIM_FSM_STATE_READ_READY)
+          eim_wait_reg  <= 1'b0;                // read transaction done
+        //
+        if (eim_fsm_state == EIM_FSM_STATE_INIT)
+          eim_wait_reg  <= 1'b0;                // fsm is idle, no need to wait any more
+        //
+     end
+
+   assign eim_wait_n = ~eim_wait_reg;
+
+
+   /* These flags are used to generate 1-cycle pulses to trigger CDC
+    * transaction.  Note that FSM goes from WRITE_LSB to WRITE_MSB and from
+    * READ_START to READ_WAIT unconditionally, so these flags will always be
+    * active for 1 cycle only, which is exactly what we need.
+    */
+
+   wire arbiter_write_req_pulse = (eim_fsm_state == EIM_FSM_STATE_WRITE_LSB)  ? 1'b1 : 1'b0;
+   wire arbiter_read_req_pulse  = (eim_fsm_state == EIM_FSM_STATE_READ_START) ? 1'b1 : 1'b0;
+
+   //
+   // CDC Block
+   //
+
+   /* This block is used to transfer request data from BCLK clock domain to
+    * SYS_CLK clock domain and then transfer acknowledge from SYS_CLK to BCLK
+    * clock domain in return. Af first 1+1+3+14+32 = 51 bits are transfered,
+    * these are: write flag, read flag, msb part of address, lsb part of address,
+    * write data. During read transaction some bogus write data is passed,
+    * which is not used later anyway. During read requests 32 bits of data are
+    * returned, during write requests 32 bits of bogus data are returned, that
+    * are never used later.
+    */
+
+   eim_arbiter_cdc eim_cdc
+     (
+      .eim_clk(eim_bclk),
+
+      .eim_req(arbiter_write_req_pulse | arbiter_read_req_pulse),
+      .eim_ack(eim_user_ack),
+
+      .eim_din({arbiter_write_req_pulse, arbiter_read_req_pulse,
+                eim_addr_latch, da_ro, eim_write_lsb_latch}),
+      .eim_dout(eim_user_data),
+
+      .sys_clk(sys_clk),
+      .sys_addr(sys_addr),
+      .sys_wren(sys_wren),
+      .sys_data_out(sys_data_out),
+      .sys_rden(sys_rden),
+      .sys_data_in(sys_data_in)
+      );
+
+
+endmodule
+
+//======================================================================
+// EOF eim_arbiter.v
+//======================================================================
diff --git a/eim/src/rtl/eim_arbiter_cdc.v b/eim/src/rtl/eim_arbiter_cdc.v
new file mode 100644
index 0000000..15dc433
--- /dev/null
+++ b/eim/src/rtl/eim_arbiter_cdc.v
@@ -0,0 +1,143 @@
+//======================================================================
+//
+// eim_arbiter_cdc.v
+// -----------------
+// The actual clock domain crossing handler od the EIM arbiter
+// for the Cryptech Novena FPGA framework.
+//
+//
+// Author: Pavel Shatov
+// 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 eim_arbiter_cdc
+  (
+   input wire          eim_clk, // eim clock
+   input wire          eim_req, // eim transaction request
+   output wire         eim_ack, // eim transaction acknowledge
+   input wire [50: 0]  eim_din, // data from cpu to fpga (write access)
+   output wire [31: 0] eim_dout, // data from fpga to cpu (read access)
+
+   input wire          sys_clk, // user internal clock
+   output wire [16: 0] sys_addr, // user access address
+   output wire         sys_wren, // user write flag
+   output wire [31: 0] sys_data_out, // user write data
+   output wire         sys_rden, // user read flag
+   input wire [31: 0]  sys_data_in   // user read data
+   );
+
+
+   //
+   // EIM_CLK -> SYS_CLK Request
+   //
+   wire                sys_req;         // request pulse in sys_clk clock domain
+   wire [50: 0]        sys_dout;        // transaction data in sys_clk clock domain
+
+   cdc_bus_pulse #
+     (
+      .DATA_WIDTH(51)   // {write, read, msb addr, lsb addr, data}
+      )
+   cdc_eim_sys
+     (
+      .src_clk(eim_clk),
+      .src_din(eim_din),
+      .src_req(eim_req),
+
+      .dst_clk(sys_clk),
+      .dst_dout(sys_dout),
+      .dst_pulse(sys_req)
+      );
+
+
+   //
+   // Output Registers
+   //
+   reg                 sys_wren_reg     = 1'b0;
+   reg                 sys_rden_reg     = 1'b0;
+   reg [16: 0]         sys_addr_reg     = {17{1'bX}};
+   reg [31: 0]         sys_data_out_reg = {32{1'bX}};
+   
+   assign sys_wren      = sys_wren_reg;
+   assign sys_rden      = sys_rden_reg;
+   assign sys_addr      = sys_addr_reg;
+   assign sys_data_out  = sys_data_out_reg;
+   
+
+   //
+   // System (User) Clock Access Handler
+   //
+   always @(posedge sys_clk)
+     //
+     if (sys_req)                               // request detected?
+       begin
+          sys_wren_reg     <= sys_dout[50];     // set write flag if needed
+          sys_rden_reg     <= sys_dout[49];     // set read flag if needed
+          sys_addr_reg     <= sys_dout[48:32];  // set operation address
+          sys_data_out_reg <= sys_dout[31: 0];  // set data to write
+       end
+     else                                       // no request active
+       begin
+          sys_wren_reg  <=  1'b0;               // clear write flag
+          sys_rden_reg  <=  1'b0;               // clear read flag
+       end
+
+
+   //
+   // System Request 2-cycle delay to compensate registered mux delay in user-side logic
+   //
+   reg  [ 1: 0] sys_req_dly     = 2'b00;
+
+   always @(posedge sys_clk)
+     sys_req_dly <= {sys_req_dly[0], sys_req};
+
+
+   //
+   // SYS_CLK -> EIM_CLK Acknowledge
+   //
+   cdc_bus_pulse #
+     (
+      .DATA_WIDTH(32)
+      )
+   cdc_sys_eim
+     (
+      .src_clk(sys_clk),
+      .src_din(sys_data_in),
+      .src_req(sys_req_dly[1]),
+
+      .dst_clk(eim_clk),
+      .dst_dout(eim_dout),
+      .dst_pulse(eim_ack)
+      );
+
+endmodule
+
+//======================================================================
+// EOF eim_arbiter_cdc.v
+//======================================================================
diff --git a/eim/src/rtl/eim_da_phy.v b/eim/src/rtl/eim_da_phy.v
new file mode 100644
index 0000000..8a4a8d7
--- /dev/null
+++ b/eim/src/rtl/eim_da_phy.v
@@ -0,0 +1,77 @@
+//======================================================================
+//
+// eim_da_phy.v
+// ------------
+// IO buffer module for the EIM DA port.
+//
+//
+// Author: Pavel Shatov
+// 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 eim_da_phy
+  #(parameter BUS_WIDTH = 16)
+   (
+    inout wire [BUS_WIDTH-1:0]  buf_io, // connect directly to top-level pins
+    input wire [BUS_WIDTH-1:0]  buf_di, // drive input (value driven onto pins)
+    output wire [BUS_WIDTH-1:0] buf_ro, // receiver output (value read from pins)
+    input wire                  buf_t   // tristate control (driver is disabled during tristate)
+    );
+
+   //
+   // IOBUFs
+   //
+   genvar                       i;
+   generate
+      for (i = 0; i < BUS_WIDTH; i = i+1)
+        begin: eim_da
+           //
+           IOBUF #
+               (
+                .IOSTANDARD("LVCMOS33"),
+                .DRIVE(12),
+                .SLEW("FAST")
+                )
+           IOBUF_inst
+               (
+                .IO(buf_io[i]),
+                .O(buf_ro[i]),
+                .I(buf_di[i]),
+                .T(buf_t)
+                );
+           //
+        end
+   endgenerate
+
+endmodule
+
+//======================================================================
+// EOF eim_da_phy.v
+//======================================================================
diff --git a/eim/src/rtl/eim_indicator.v b/eim/src/rtl/eim_indicator.v
new file mode 100644
index 0000000..cf9751d
--- /dev/null
+++ b/eim/src/rtl/eim_indicator.v
@@ -0,0 +1,69 @@
+//======================================================================
+//
+// eim_indicator.v
+// ---------------
+// A simple LED indicator to show that the EIM is alive.
+//
+//
+// Author: Pavel Shatov
+// 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 eim_indicator
+  (
+   input wire  sys_clk,
+   input wire  sys_rst,
+   input wire  eim_active,
+   output wire led_out
+   );
+
+   //
+   // Parameters
+   //
+   localparam   CNT_BITS                = 24;   // led will be dim for 2**(24-1) = 8388608 ticks, which is ~100 ms @ 80 MHz.
+
+   //
+   // Counter
+   //
+   reg [CNT_BITS-1:0] cnt;
+
+   always @(posedge sys_clk)
+     //
+     if (sys_rst)                       cnt <= {CNT_BITS{1'b0}};
+     else if (cnt > {CNT_BITS{1'b0}})   cnt <= cnt - 1'b1;
+     else if (eim_active)               cnt <= {CNT_BITS{1'b1}};
+
+   assign led_out = ~cnt[CNT_BITS-1];
+
+endmodule
+
+//======================================================================
+// EOF eim_indicator.v
+//======================================================================
diff --git a/i2c/LICENSE b/i2c/LICENSE
new file mode 100644
index 0000000..0fb159c
--- /dev/null
+++ b/i2c/LICENSE
@@ -0,0 +1,24 @@
+Author: Joachim Strömbergson
+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:
+
+* 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.
+
+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.
diff --git a/i2c/README.md b/i2c/README.md
new file mode 100644
index 0000000..24edcbb
--- /dev/null
+++ b/i2c/README.md
@@ -0,0 +1,7 @@
+i2c
+===
+
+An I2C slave implemented in Verilog.
+
+The core i2c functionality is based on Bunnie Huang's i2c_slave.v from the
+novena-ws2312b-fpga project (https://github.com/xobs/novena-ws2812b-fpga).
diff --git a/i2c/src/rtl/i2c.v b/i2c/src/rtl/i2c.v
new file mode 100644
index 0000000..4a3bc5d
--- /dev/null
+++ b/i2c/src/rtl/i2c.v
@@ -0,0 +1,217 @@
+//======================================================================
+//
+// i2c.v
+// ------
+// Top level wrapper for the i2c core.
+//
+// A simple I2C interface.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014, SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module i2c(
+            input wire 		 clk,
+            input wire 		 reset_n,
+
+            // External interface.
+	    input wire 		 SCL,
+	    input wire 		 SDA,
+	    output wire 	 SDA_pd,
+	    output wire [6:0] 	 i2c_device_addr,
+
+            // Internal receive interface.
+            output wire 	 rxd_syn,
+            output [7 : 0] 	 rxd_data,
+            input wire 		 rxd_ack,
+
+            // Internal transmit interface.
+            input wire 		 txd_syn,
+            input wire [7 : 0] 	 txd_data,
+            output wire 	 txd_ack,
+            
+            // API interface.
+            input wire 		 cs,
+            input wire 		 we,
+            input wire [7 : 0] 	 address,
+            input wire [31 : 0]  write_data,
+            output wire [31 : 0] read_data,
+            output wire 	 error,
+
+            // Debug output.
+            output wire [7 : 0]  debug
+           );
+
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  // API addresses.
+  parameter ADDR_CORE_NAME0   = 8'h00;
+  parameter ADDR_CORE_NAME1   = 8'h01;
+  parameter ADDR_CORE_TYPE    = 8'h02;
+  parameter ADDR_CORE_VERSION = 8'h03;
+
+  // Core ID constants.
+  parameter CORE_NAME0   = 32'h69326320;  // "i2c "
+  parameter CORE_NAME1   = 32'h20202020;  // "    "
+  parameter CORE_TYPE    = 32'h20202031;  // "   1"
+  parameter CORE_VERSION = 32'h302e3031;  // "0.01"
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+
+  wire 	        core_SCL;
+  wire 	        core_SDA;
+  wire 		core_SDA_pd;
+
+  wire          core_rxd_syn;
+  wire [7 : 0]  core_rxd_data;
+  wire          core_rxd_ack;
+
+  wire          core_txd_syn;
+  wire [7 : 0]  core_txd_data;
+  wire          core_txd_ack;
+
+  reg [31 : 0]  tmp_read_data;
+  reg           tmp_error;
+
+  
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign core_SCL      = SCL;
+  assign core_SDA      = SDA;
+  assign SDA_pd        = core_SDA_pd;
+
+  assign rxd_syn       = core_rxd_syn;
+  assign rxd_data      = core_rxd_data;
+  assign core_rxd_ack  = rxd_ack;
+  
+  assign core_txd_syn  = txd_syn;
+  assign core_txd_data = txd_data;
+  assign txd_ack       = core_txd_ack;
+  
+  assign read_data     = tmp_read_data;
+  assign error         = tmp_error;
+
+  assign debug         = core_rxd_data;
+  
+
+  //----------------------------------------------------------------
+  // core
+  //
+  // Instantiation of the i2c core.
+  //----------------------------------------------------------------
+  i2c_core core(
+                 .clk(clk),
+                 .reset(reset_n),
+
+                 // External data interface
+		.SCL(core_SCL),
+		.SDA(core_SDA),
+		.SDA_pd(core_SDA_pd),
+		.i2c_device_addr(i2c_device_addr),
+
+                 // Internal receive interface.
+                 .rxd_syn(core_rxd_syn),
+                 .rxd_data(core_rxd_data),
+                 .rxd_ack(core_rxd_ack),
+                 
+                 // Internal transmit interface.
+                 .txd_syn(core_txd_syn),
+                 .txd_data(core_txd_data),
+                 .txd_ack(core_txd_ack)
+                );
+
+  
+  //----------------------------------------------------------------
+  // api
+  //
+  // The core API that allows an internal host to control the
+  // core functionality.
+  //----------------------------------------------------------------
+  always @*
+    begin: api
+      // Default assignments.
+      tmp_read_data = 32'h00000000;
+      tmp_error     = 0;
+      
+      if (cs)
+        begin
+          if (we)
+            begin
+              // Write operations.
+              case (address)
+                default:
+                  begin
+                    tmp_error = 1;
+                  end
+              endcase // case (address)
+            end
+          else
+            begin
+              // Read operations.
+              case (address)
+                ADDR_CORE_NAME0:
+                  begin
+                    tmp_read_data = CORE_NAME0;
+                  end
+
+                ADDR_CORE_NAME1:
+                  begin
+                    tmp_read_data = CORE_NAME1;
+                  end
+
+                ADDR_CORE_TYPE:
+                  begin
+                    tmp_read_data = CORE_TYPE;
+                  end
+
+                ADDR_CORE_VERSION:
+                  begin
+                    tmp_read_data = CORE_VERSION;
+                  end
+                
+                default:
+                  begin
+                    tmp_error = 1;
+                  end
+              endcase // case (address)
+            end
+        end
+    end
+  
+endmodule // i2c
+
+//======================================================================
+// EOF i2c.v
+//======================================================================
diff --git a/i2c/src/rtl/i2c_core.v b/i2c/src/rtl/i2c_core.v
new file mode 100644
index 0000000..798c105
--- /dev/null
+++ b/i2c/src/rtl/i2c_core.v
@@ -0,0 +1,580 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011, Andrew "bunnie" Huang
+// 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.
+//
+//    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.
+//
+//////////////////////////////////////////////////////////////////////////////
+// A simple I2C slave implementation. Oversampled for robustness.
+// The slave is extended into the snoop & surpress version for the DDC bus;
+// this is just a starting point for basic testing and also simple comms
+// with the CPU.
+//
+// i2c slave module requires the top level module to implement the IOBs
+// This is just to keep the tri-state easy to implemen across the hierarchy
+//
+// The code required on the top level is:
+//   IOBUF #(.DRIVE(12), .SLEW("SLOW")) IOBUF_sda (.IO(SDA), .I(1'b0), .T(!SDA_pd));
+//
+///////////
+`timescale 1 ns / 1 ps
+
+// This file is based on https://github.com/bunnie/novena-gpbb-fpga/blob/master/novena-gpbb.srcs/sources_1/imports/imports/i2c_slave.v
+//
+// For Cryptech, we replaced the register interface with the rxd/txd
+// interface to coretest, and changed i2c_device_addr from an 8-bit
+// input to a 7-bit output.
+
+module i2c_core (
+                 input wire 	    clk,
+                 input wire 	    reset,
+
+                 // External data interface
+		 input wire 	    SCL,
+		 input wire 	    SDA,
+		 output reg 	    SDA_pd,
+		 output wire [6:0]  i2c_device_addr,
+
+                 // Internal receive interface.
+                 output wire 	    rxd_syn,
+                 output [7 : 0]     rxd_data,
+                 input wire 	    rxd_ack,
+
+                 // Internal transmit interface.
+                 input wire 	    txd_syn,
+                 input wire [7 : 0] txd_data,
+                 output wire 	    txd_ack
+		 );
+
+   /////// I2C physical layer components
+   /// SDA is stable when SCL is high.
+   /// If SDA moves while SCL is high, this is considered a start or stop condition.
+   ///
+   /// Otherwise, SDA can move around when SCL is low (this is where we suppress bits or 
+   /// overdrive as needed). SDA is a wired-AND bus, so you only "drive" zero.
+   ///
+   /// In an oversampled implementation, a rising and falling edge de-glitcher is needed
+   /// for SCL and SDA.
+   ///
+
+   // rise fall time cycles computation:
+   // At 400kHz operation, 2.5us is a cycle. "chatter" from transition should be about
+   // 5% of total cycle time max (just rule of thumb), so 0.125us should be the equiv
+   // number of cycles.
+   // For the demo board, a 25 MHz clock is provided, and 0.125us ~ 4 cycles
+   // At 100kHz operation, 10us is a cycle, so 0.5us ~ 12 cycles
+   parameter TRF_CYCLES = 5'd4;  // number of cycles for rise/fall time
+   
+   ////////////////
+   ///// protocol-level state machine
+   ////////////////
+   parameter I2C_START     = 16'b1 << 0; // should only pass through this state for one cycle
+   parameter I2C_RESTART   = 16'b1 << 1;
+   parameter I2C_DADDR     = 16'b1 << 2;
+   parameter I2C_ACK_DADDR = 16'b1 << 3;
+   parameter I2C_WR_DATA   = 16'b1 << 4;
+   parameter I2C_ACK_WR    = 16'b1 << 5;
+   parameter I2C_END_WR    = 16'b1 << 6;
+   parameter I2C_RD_DATA   = 16'b1 << 7;
+   parameter I2C_ACK_RD    = 16'b1 << 8;
+   parameter I2C_END_RD    = 16'b1 << 9;
+   parameter I2C_END_RD2   = 16'b1 << 10;
+   parameter I2C_WAITSTOP  = 16'b1 << 11;
+   parameter I2C_RXD_SYN   = 16'b1 << 12;
+   parameter I2C_RXD_ACK   = 16'b1 << 13;
+   parameter I2C_TXD_SYN   = 16'b1 << 14;
+   parameter I2C_TXD_ACK   = 16'b1 << 15;
+
+   parameter I2C_nSTATES = 16;
+
+   reg [(I2C_nSTATES-1):0]     I2C_cstate = {{(I2C_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(I2C_nSTATES-1):0]     I2C_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                    I2C_state_ascii = "I2C_START          ";
+   always @(I2C_cstate) begin
+      if      (I2C_cstate == I2C_START)     I2C_state_ascii <= "I2C_START          ";
+      else if (I2C_cstate == I2C_RESTART)   I2C_state_ascii <= "I2C_RESTART        ";
+      else if (I2C_cstate == I2C_DADDR)     I2C_state_ascii <= "I2C_DADDR          ";
+      else if (I2C_cstate == I2C_ACK_DADDR) I2C_state_ascii <= "I2C_ACK_DADDR      ";
+      else if (I2C_cstate == I2C_WR_DATA)   I2C_state_ascii <= "I2C_WR_DATA        ";
+      else if (I2C_cstate == I2C_ACK_WR)    I2C_state_ascii <= "I2C_ACK_WR         ";
+      else if (I2C_cstate == I2C_END_WR)    I2C_state_ascii <= "I2C_END_WR         ";
+      else if (I2C_cstate == I2C_RD_DATA)   I2C_state_ascii <= "I2C_RD_DATA        ";
+      else if (I2C_cstate == I2C_ACK_RD)    I2C_state_ascii <= "I2C_ACK_RD         ";
+      else if (I2C_cstate == I2C_END_RD)    I2C_state_ascii <= "I2C_END_RD         ";
+      else if (I2C_cstate == I2C_END_RD2)   I2C_state_ascii <= "I2C_END_RD2        ";
+      else if (I2C_cstate == I2C_WAITSTOP)  I2C_state_ascii <= "I2C_WAITSTOP       ";
+      else if (I2C_cstate == I2C_RXD_SYN)   I2C_state_ascii <= "I2C_RXD_SYN        ";
+      else if (I2C_cstate == I2C_RXD_ACK)   I2C_state_ascii <= "I2C_RXD_ACK        ";
+      else if (I2C_cstate == I2C_TXD_SYN)   I2C_state_ascii <= "I2C_TXD_SYN        ";
+      else if (I2C_cstate == I2C_TXD_ACK)   I2C_state_ascii <= "I2C_TXD_ACK        ";
+      else                                  I2C_state_ascii <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+   
+   reg [3:0] 		       I2C_bitcnt;
+   reg [7:0] 		       I2C_daddr;
+   reg [7:0] 		       I2C_wdata;
+   reg [7:0] 		       I2C_rdata;
+
+   reg 			       rxd_syn_reg;
+   reg 			       txd_ack_reg;
+
+   assign rxd_data = I2C_wdata;
+   assign rxd_syn  = rxd_syn_reg;
+   assign txd_ack  = txd_ack_reg;
+   assign i2c_device_addr = I2C_daddr[7:1];
+
+   ////////// code begins here
+   always @ (posedge clk) begin
+      if (reset || ((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) // stop condition always resets
+	I2C_cstate <= I2C_START; 
+      else
+	I2C_cstate <= I2C_nstate;
+   end
+
+   always @ (*) begin
+      case (I2C_cstate)
+	I2C_START: begin // wait for the start condition
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_DADDR : I2C_START;
+	end
+	I2C_RESTART: begin // repeated start moves immediately to DADDR
+	   I2C_nstate = I2C_DADDR;
+	end
+
+	// device address branch
+	I2C_DADDR: begin // 8 bits to get the address
+	   I2C_nstate = ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_DADDR : I2C_DADDR;
+	end
+	I2C_ACK_DADDR: begin // depending upon W/R bit state, go to one of two branches
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ?
+			(I2C_daddr[0] == 1'b0 ? I2C_WR_DATA : I2C_TXD_SYN) :
+			I2C_ACK_DADDR; // !SCL_FALL
+	end
+
+	// write branch
+	I2C_WR_DATA: begin // 8 bits to get the write data
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+			((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_RXD_SYN : I2C_WR_DATA;
+	end
+	I2C_RXD_SYN: begin // put data on the coretest bus
+	   I2C_nstate = I2C_RXD_ACK;
+	end
+	I2C_RXD_ACK: begin // wait for coretest ack
+           I2C_nstate = rxd_ack ? I2C_ACK_WR : I2C_RXD_ACK;
+	end
+	I2C_ACK_WR: begin // trigger the ack response (pull SDA low until next falling edge)
+	   // and stay in this state until the next falling edge of SCL
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_END_WR : I2C_ACK_WR;
+	end
+	I2C_END_WR: begin // one-cycle state to update address+1, reset SDA pulldown
+	   I2C_nstate = I2C_WR_DATA; // SCL is now low
+	end
+
+	// read branch
+	I2C_TXD_SYN: begin // get data from the coretest bus 
+	   // if data isn't available (txd_syn isn't asserted) by the time we
+	   // get to this state, it probably never will be, so skip it
+           I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_RD_DATA;
+	end
+	I2C_TXD_ACK: begin // send coretest ack
+	   // hold ack high until syn is lowered
+	   I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_RD_DATA;
+	end
+	I2C_RD_DATA: begin // 8 bits to get the read data
+	   I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+			((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_RD : I2C_RD_DATA;
+	end
+	I2C_ACK_RD: begin // wait for an (n)ack response
+	   // need to sample (n)ack on a rising edge
+	   I2C_nstate = (SCL_cstate == SCL_RISE) ? I2C_END_RD : I2C_ACK_RD;
+	end
+	I2C_END_RD: begin // if nack, just go to start state (don't explicitly check stop event)
+	   // single cycle state for adr+1 update
+	   I2C_nstate = (SDA_cstate == SDA_LOW) ? I2C_END_RD2 : I2C_START;
+	end
+	I2C_END_RD2: begin // before entering I2C_RD_DATA, we need to have seen a falling edge.
+	   I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_RD_DATA : I2C_END_RD2;
+	end
+
+	// we're not the addressed device, so we just idle until we see a stop
+	I2C_WAITSTOP: begin
+	   I2C_nstate = (((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) ? // stop
+			I2C_START : 
+			(((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_FALL))) ? // or start
+			I2C_RESTART :
+			I2C_WAITSTOP;
+	end
+      endcase // case (cstate)
+   end
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 I2C_bitcnt <= 4'b0;
+	 I2C_daddr <= 8'b0;
+	 I2C_wdata <= 8'b0;
+	 SDA_pd <= 1'b0;
+	 I2C_rdata <= 8'b0;
+      end else begin
+	 case (I2C_cstate)
+	   I2C_START: begin // everything in reset
+	      I2C_bitcnt <= 4'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	      SDA_pd <= 1'b0;
+	   end
+
+	   I2C_RESTART: begin
+	      I2C_bitcnt <= 4'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	      SDA_pd <= 1'b0;
+	   end
+
+	   // get my i2c device address (am I being talked to?)
+	   I2C_DADDR: begin // shift in the address on rising edges of clock
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+		 I2C_daddr[7] <= I2C_daddr[6];
+		 I2C_daddr[6] <= I2C_daddr[5];
+		 I2C_daddr[5] <= I2C_daddr[4];
+		 I2C_daddr[4] <= I2C_daddr[3];
+		 I2C_daddr[3] <= I2C_daddr[2];
+		 I2C_daddr[2] <= I2C_daddr[1];
+		 I2C_daddr[1] <= I2C_daddr[0];
+		 I2C_daddr[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+	      end else begin // we're oversampled so we need a hold-state gutter
+		 I2C_bitcnt <= I2C_bitcnt;
+		 I2C_daddr <= I2C_daddr;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      SDA_pd <= 1'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	   end // case: I2C_DADDR
+	   I2C_ACK_DADDR: begin
+	      SDA_pd <= 1'b1;  // active pull down ACK
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= 8'b0;
+	   end
+
+	   // write branch
+	   I2C_WR_DATA: begin // shift in data on rising edges of clock
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+		 I2C_wdata[7] <= I2C_wdata[6];
+		 I2C_wdata[6] <= I2C_wdata[5];
+		 I2C_wdata[5] <= I2C_wdata[4];
+		 I2C_wdata[4] <= I2C_wdata[3];
+		 I2C_wdata[3] <= I2C_wdata[2];
+		 I2C_wdata[2] <= I2C_wdata[1];
+		 I2C_wdata[1] <= I2C_wdata[0];
+		 I2C_wdata[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+	      end else begin
+		 I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+		 I2C_wdata <= I2C_wdata;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= I2C_daddr;
+	      I2C_rdata <= I2C_rdata;
+	   end // case: I2C_WR_DATA
+	   I2C_RXD_SYN: begin // put data on the coretest bus and raise syn
+              rxd_syn_reg <= 1;
+	   end
+	   I2C_RXD_ACK: begin // wait for coretest ack
+              if (rxd_ack)
+		 rxd_syn_reg <= 0;
+	   end
+	   I2C_ACK_WR: begin
+	      SDA_pd <= 1'b1;  // active pull down ACK
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= I2C_wdata;
+	      I2C_rdata <= I2C_rdata;
+	   end
+	   I2C_END_WR: begin
+	      SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+	      I2C_bitcnt <= 4'b0;
+	      I2C_wdata <= 8'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_daddr <= I2C_daddr;
+	   end
+
+	   // read branch
+	   I2C_TXD_SYN: begin // get data from the coretest bus
+              if (txd_syn) begin
+		 I2C_rdata <= txd_data;
+		 txd_ack_reg <= 1;
+	      end
+	   end
+	   I2C_TXD_ACK: begin // send coretest ack
+              if (!txd_syn)
+		 txd_ack_reg <= 0;
+	   end
+	   I2C_RD_DATA: begin // shift out data on falling edges of clock
+	      SDA_pd <= I2C_rdata[7] ? 1'b0 : 1'b1;
+	      if( SCL_cstate == SCL_RISE ) begin
+		 I2C_bitcnt <= I2C_bitcnt + 4'b1;
+	      end else begin
+		 I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+	      end
+	      
+	      if( SCL_cstate == SCL_FALL ) begin
+		 I2C_rdata[7] <= I2C_rdata[6];
+		 I2C_rdata[6] <= I2C_rdata[5];
+		 I2C_rdata[5] <= I2C_rdata[4];
+		 I2C_rdata[4] <= I2C_rdata[3];
+		 I2C_rdata[3] <= I2C_rdata[2];
+		 I2C_rdata[2] <= I2C_rdata[1];
+		 I2C_rdata[1] <= I2C_rdata[0];
+		 I2C_rdata[0] <= 1'b0;
+	      end else begin
+		 I2C_rdata <= I2C_rdata;
+	      end // else: !if( SCL_cstate == SCL_RISE )
+	      I2C_daddr <= I2C_daddr;
+	      I2C_wdata <= I2C_wdata;
+	   end // case: I2C_RD_DATA
+	   I2C_ACK_RD: begin
+	      SDA_pd <= 1'b0;  // in ack state don't pull down, we are listening to host
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	   I2C_END_RD: begin
+	      SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+	      I2C_daddr <= I2C_daddr;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	   I2C_END_RD2: begin
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+
+	   I2C_WAITSTOP: begin
+	      SDA_pd <= 1'b0;
+	      I2C_daddr <= 8'b0;
+	      I2C_bitcnt <= 4'b0;
+	      I2C_rdata <= I2C_rdata;
+	      I2C_wdata <= I2C_wdata;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+
+   ///////////////////////////////////////////////////////////////
+   /////////// low level state machines //////////////////////////
+   ///////////////////////////////////////////////////////////////
+   
+   
+   ////////////////
+   ///// SCL low-level sampling state machine
+   ////////////////
+   parameter SCL_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+   parameter SCL_FALL = 4'b1 << 1;
+   parameter SCL_LOW  = 4'b1 << 2;
+   parameter SCL_RISE = 4'b1 << 3;
+   parameter SCL_nSTATES = 4;
+
+   reg [(SCL_nSTATES-1):0]     SCL_cstate = {{(SCL_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(SCL_nSTATES-1):0]     SCL_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                 SCL_state_ascii = "SCL_HIGH           ";
+
+   always @(SCL_cstate) begin
+      if      (SCL_cstate == SCL_HIGH)     SCL_state_ascii <= "SCL_HIGH           ";
+      else if (SCL_cstate == SCL_FALL)     SCL_state_ascii <= "SCL_FALL           ";
+      else if (SCL_cstate == SCL_LOW )     SCL_state_ascii <= "SCL_LOW            ";
+      else if (SCL_cstate == SCL_RISE)     SCL_state_ascii <= "SCL_RISE           ";
+      else SCL_state_ascii                                 <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+
+   reg [4:0] 		       SCL_rfcnt;
+   reg 			       SCL_s, SCL_sync;
+   reg 			       SDA_s, SDA_sync;
+
+   always @ (posedge clk) begin
+      if (reset)
+	SCL_cstate <= SCL_HIGH; // always start here even if it's wrong -- easier to test
+      else
+	SCL_cstate <= SCL_nstate;
+   end
+
+   always @ (*) begin
+      case (SCL_cstate)
+	SCL_HIGH: begin
+	   SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b0)) ? SCL_FALL : SCL_HIGH;
+	end
+	SCL_FALL: begin
+	   SCL_nstate = SCL_LOW;
+	end
+	SCL_LOW: begin
+	   SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b1)) ? SCL_RISE : SCL_LOW;
+	end
+	SCL_RISE: begin
+	   SCL_nstate = SCL_HIGH;
+	end
+      endcase // case (cstate)
+   end // always @ (*)
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 SCL_rfcnt <= 5'b0;
+      end else begin
+	 case (SCL_cstate)
+	   SCL_HIGH: begin
+	      if( SCL_sync == 1'b1 ) begin
+		 SCL_rfcnt <= 5'b0;
+	      end else begin
+		 SCL_rfcnt <= SCL_rfcnt + 5'b1;
+	      end
+	   end
+	   SCL_FALL: begin
+	      SCL_rfcnt <= 5'b0;
+	   end
+	   SCL_LOW: begin
+	      if( SCL_sync == 1'b0 ) begin
+		 SCL_rfcnt <= 5'b0;
+	      end else begin
+		 SCL_rfcnt <= SCL_rfcnt + 5'b1;
+	      end
+	   end
+	   SCL_RISE: begin
+	      SCL_rfcnt <= 5'b0;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+
+   ////////////////
+   ///// SDA low-level sampling state machine
+   ////////////////
+   parameter SDA_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+   parameter SDA_FALL = 4'b1 << 1;
+   parameter SDA_LOW  = 4'b1 << 2;
+   parameter SDA_RISE = 4'b1 << 3;
+   parameter SDA_nSTATES = 4;
+
+   reg [(SDA_nSTATES-1):0]     SDA_cstate = {{(SDA_nSTATES-1){1'b0}}, 1'b1};  //current and next states
+   reg [(SDA_nSTATES-1):0]     SDA_nstate;
+
+//`define SIMULATION  
+`ifdef SIMULATION
+   // synthesis translate_off
+   reg [8*20:1] 	                 SDA_state_ascii = "SDA_HIGH           ";
+
+   always @(SDA_cstate) begin
+      if      (SDA_cstate == SDA_HIGH)     SDA_state_ascii <= "SDA_HIGH           ";
+      else if (SDA_cstate == SDA_FALL)     SDA_state_ascii <= "SDA_FALL           ";
+      else if (SDA_cstate == SDA_LOW )     SDA_state_ascii <= "SDA_LOW            ";
+      else if (SDA_cstate == SDA_RISE)     SDA_state_ascii <= "SDA_RISE           ";
+      else SDA_state_ascii                                 <= "WTF                ";
+   end
+   // synthesis translate_on
+`endif
+
+   reg [4:0] 		       SDA_rfcnt;
+
+   always @ (posedge clk) begin
+      if (reset)
+	SDA_cstate <= SDA_HIGH; // always start here even if it's wrong -- easier to test
+      else
+	SDA_cstate <= SDA_nstate;
+   end
+
+   always @ (*) begin
+      case (SDA_cstate)
+	SDA_HIGH: begin
+	   SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b0)) ? SDA_FALL : SDA_HIGH;
+	end
+	SDA_FALL: begin
+	   SDA_nstate = SDA_LOW;
+	end
+	SDA_LOW: begin
+	   SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b1)) ? SDA_RISE : SDA_LOW;
+	end
+	SDA_RISE: begin
+	   SDA_nstate = SDA_HIGH;
+	end
+      endcase // case (cstate)
+   end // always @ (*)
+
+   always @ (posedge clk) begin
+      if( reset ) begin
+	 SDA_rfcnt <= 5'b0;
+      end else begin
+	 case (SDA_cstate)
+	   SDA_HIGH: begin
+	      if( SDA_sync == 1'b1 ) begin
+		 SDA_rfcnt <= 5'b0;
+	      end else begin
+		 SDA_rfcnt <= SDA_rfcnt + 5'b1;
+	      end
+	   end
+	   SDA_FALL: begin
+	      SDA_rfcnt <= 5'b0;
+	   end
+	   SDA_LOW: begin
+	      if( SDA_sync == 1'b0 ) begin
+		 SDA_rfcnt <= 5'b0;
+	      end else begin
+		 SDA_rfcnt <= SDA_rfcnt + 5'b1;
+	      end
+	   end
+	   SDA_RISE: begin
+	      SDA_rfcnt <= 5'b0;
+	   end
+	 endcase // case (cstate)
+      end // else: !if( reset )
+   end // always @ (posedge clk or posedge reset)
+
+   
+   
+   /////////////////////
+   /////// synchronizers
+   /////////////////////
+   always @ (posedge clk) begin
+      SCL_s <= SCL;
+      SCL_sync <= SCL_s;
+      SDA_s <= SDA;
+      SDA_sync <= SDA_s;
+   end // always @ (posedge clk or posedge reset)
+   
+endmodule // i2c_slave
diff --git a/novena/build/.gitignore b/novena/build/.gitignore
new file mode 100644
index 0000000..01d7e9c
--- /dev/null
+++ b/novena/build/.gitignore
@@ -0,0 +1,52 @@
+*.xrpt
+_xmsgs
+default.xreport
+netlist.lst
+*.bgn
+*.bit
+*.bld
+*.cfi
+*.drc
+*.lso
+*.lso
+*.map
+*.mcs
+*.mrp
+*.ncd
+*.ngc
+*.ngd
+*.ngm
+*.pcf
+*.post_map.twr
+*.post_map.twx
+*.prj
+*.prm
+*.psr
+*.scr
+*.srp
+*.twr
+*.twx
+*_bd.bmm
+*_bitgen.xwb
+*_bitgen.xwbt
+*_err.twr
+*_err.twx
+*_par.grf
+*_par.ncd
+*_par.pad
+*_par.par
+*_par.ptwx
+*_par.unroutes
+*_par.xpi
+*_par_pad.csv
+*_par_pad.txt
+*_summary.xml
+*_usage.xml
+par_usage_statistics.html
+smartguide.ncd
+smartpreview.twr
+smartpreview.twr
+usage_statistics_webtalk.html
+webtalk.log
+xlnx_auto*
+xst
diff --git a/novena/build/Makefile.eim b/novena/build/Makefile.eim
new file mode 100644
index 0000000..6544fdd
--- /dev/null
+++ b/novena/build/Makefile.eim
@@ -0,0 +1,39 @@
+project = novena_reorg_eim
+vendor = xilinx
+family = spartan6
+part = xc6slx45csg324-3
+top_module = novena_baseline_top
+isedir = /opt/Xilinx/14.7/ISE_DS
+xil_env = . $(isedir)/settings64.sh
+ucf = ../src/ucf/novena_eim.ucf
+
+vfiles = \
+	../src/rtl/novena_eim.v \
+	../src/rtl/novena_clkmgr.v \
+	../src/rtl/ipcore/clkmgr_dcm.v \
+	../src/rtl/novena_regs.v \
+	../../eim/src/rtl/eim.v \
+	../../eim/src/rtl/eim_arbiter.v \
+	../../eim/src/rtl/eim_arbiter_cdc.v \
+	../../eim/src/rtl/cdc_bus_pulse.v \
+	../../eim/src/rtl/eim_da_phy.v \
+	../../eim/src/rtl/eim_indicator.v \
+	../../core_selector/src/rtl/core_selector.v \
+	../../core_selector/src/rtl/hash_selector.v \
+	../../core_selector/src/rtl/rng_selector.v \
+	../../core_selector/src/rtl/cipher_selector.v \
+	../../sha1/src/rtl/sha1.v \
+	../../sha1/src/rtl/sha1_core.v \
+	../../sha1/src/rtl/sha1_w_mem.v \
+	../../sha256/src/rtl/sha256.v \
+	../../sha256/src/rtl/sha256_core.v \
+	../../sha256/src/rtl/sha256_k_constants.v \
+	../../sha256/src/rtl/sha256_w_mem.v \
+	../../sha256/src/rtl/wb_sha256.v \
+	../../sha512/src/rtl/sha512.v \
+	../../sha512/src/rtl/sha512_core.v \
+	../../sha512/src/rtl/sha512_h_constants.v \
+	../../sha512/src/rtl/sha512_k_constants.v \
+	../../sha512/src/rtl/sha512_w_mem.v
+
+include xilinx.mk
diff --git a/novena/build/Makefile.i2c b/novena/build/Makefile.i2c
new file mode 100644
index 0000000..267e33b
--- /dev/null
+++ b/novena/build/Makefile.i2c
@@ -0,0 +1,36 @@
+project = novena_reorg_i2c
+vendor = xilinx
+family = spartan6
+part = xc6slx45csg324-3
+top_module = novena_baseline_top
+isedir = /opt/Xilinx/14.7/ISE_DS
+xil_env = . $(isedir)/settings64.sh
+ucf = ../src/ucf/novena_i2c.ucf
+
+vfiles = \
+	../src/rtl/novena_i2c.v \
+	../src/rtl/novena_clkmgr.v \
+	../src/rtl/ipcore/clkmgr_dcm.v \
+	../src/rtl/novena_regs.v \
+	../../i2c/src/rtl/i2c.v \
+	../../i2c/src/rtl/i2c_core.v \
+	../../coretest/src/rtl/coretest.v \
+	../../core_selector/src/rtl/core_selector.v \
+	../../core_selector/src/rtl/hash_selector.v \
+	../../core_selector/src/rtl/rng_selector.v \
+	../../core_selector/src/rtl/cipher_selector.v \
+	../../sha1/src/rtl/sha1.v \
+	../../sha1/src/rtl/sha1_core.v \
+	../../sha1/src/rtl/sha1_w_mem.v \
+	../../sha256/src/rtl/sha256.v \
+	../../sha256/src/rtl/sha256_core.v \
+	../../sha256/src/rtl/sha256_k_constants.v \
+	../../sha256/src/rtl/sha256_w_mem.v \
+	../../sha256/src/rtl/wb_sha256.v \
+	../../sha512/src/rtl/sha512.v \
+	../../sha512/src/rtl/sha512_core.v \
+	../../sha512/src/rtl/sha512_h_constants.v \
+	../../sha512/src/rtl/sha512_k_constants.v \
+	../../sha512/src/rtl/sha512_w_mem.v
+
+include xilinx.mk
diff --git a/novena/build/xilinx.mk b/novena/build/xilinx.mk
new file mode 100644
index 0000000..f35cc98
--- /dev/null
+++ b/novena/build/xilinx.mk
@@ -0,0 +1,174 @@
+# The top level module should define the variables below then include
+# this file.  The files listed should be in the same directory as the
+# Makefile.  
+#
+#   variable	description
+#   ----------  -------------
+#   project	project name (top level module should match this name)
+#   top_module  top level module of the project
+#   libdir	path to library directory
+#   libs	library modules used
+#   vfiles	all local .v files
+#   xilinx_cores  all local .xco files
+#   vendor      vendor of FPGA (xilinx, altera, etc.)
+#   family      FPGA device family (spartan3e) 
+#   part        FPGA part name (xc4vfx12-10-sf363)
+#   flashsize   size of flash for mcs file (16384)
+#   optfile     (optional) xst extra opttions file to put in .scr
+#   map_opts    (optional) options to give to map
+#   par_opts    (optional) options to give to par
+#   intstyle    (optional) intstyle option to all tools
+#   ucf         constraint file, defaults to $(project).ucf
+#
+# Library modules should have a modules.mk in their root directory,
+# namely $(libdir)/<libname>/module.mk, that simply adds to the vfiles
+# and xilinx_cores variable.
+#
+# all the .xco files listed in xilinx_cores will be generated with core, with
+# the resulting .v and .ngc files placed back in the same directory as
+# the .xco file.
+#
+# TODO: .xco files are device dependant, should use a template based system
+
+coregen_work_dir ?= ./coregen-tmp
+map_opts ?= -timing -ol high -detail -pr b -register_duplication -w
+par_opts ?= -ol high
+isedir ?= /opt/Xilinx/13.3/ISE_DS
+xil_env ?= . $(isedir)/settings32.sh
+flashsize ?= 8192
+ucf ?= $(project).ucf
+
+libmks = $(patsubst %,$(libdir)/%/module.mk,$(libs)) 
+mkfiles = $(libmks) xilinx.mk
+include $(libmks)
+
+corengcs = $(foreach core,$(xilinx_cores),$(core:.xco=.ngc))
+local_corengcs = $(foreach ngc,$(corengcs),$(notdir $(ngc)))
+vfiles += $(foreach core,$(xilinx_cores),$(core:.xco=.v))
+junk += $(local_corengcs)
+
+.PHONY: default xilinx_cores clean twr etwr
+default: $(project).bit $(project).mcs
+xilinx_cores: $(corengcs)
+twr: $(project).twr
+etwr: $(project)_err.twr
+
+define cp_template
+$(2): $(1)
+	cp $(1) $(2)
+endef
+$(foreach ngc,$(corengcs),$(eval $(call cp_template,$(ngc),$(notdir $(ngc)))))
+
+%.ngc %.v: %.xco
+	@echo "=== rebuilding $@"
+	if [ -d $(coregen_work_dir) ]; then \
+		rm -rf $(coregen_work_dir)/*; \
+	else \
+		mkdir -p $(coregen_work_dir); \
+	fi
+	cd $(coregen_work_dir); \
+	$(xil_env); \
+	coregen -b $$OLDPWD/$<; \
+	cd -
+	xcodir=`dirname $<`; \
+	basename=`basename $< .xco`; \
+	if [ ! -r $(coregen_work_dir/$$basename.ngc) ]; then \
+		echo "'$@' wasn't created."; \
+		exit 1; \
+	else \
+		cp $(coregen_work_dir)/$$basename.v $(coregen_work_dir)/$$basename.ngc $$xcodir; \
+	fi
+junk += $(coregen_work_dir)
+
+date = $(shell date +%F-%H-%M)
+
+# some common junk
+junk += *.xrpt
+
+programming_files: $(project).bit $(project).mcs
+	mkdir -p $@/$(date)
+	mkdir -p $@/latest
+	for x in .bit .mcs .cfi _bd.bmm; do cp $(project)$$x $@/$(date)/$(project)$$x; cp $(project)$$x $@/latest/$(project)$$x; done
+	$(xil_env); xst -help | head -1 | sed 's/^/#/' | cat - $(project).scr > $@/$(date)/$(project).scr
+
+$(project).mcs: $(project).bit
+	$(xil_env); \
+	promgen -w -s $(flashsize) -p mcs -o $@ -u 0 $^
+junk += $(project).mcs $(project).cfi $(project).prm
+
+$(project).bit: $(project)_par.ncd
+	$(xil_env); \
+	bitgen $(intstyle) -g UnusedPin:Pullnone -g DriveDone:yes -g StartupClk:Cclk -w $(project)_par.ncd $(project).bit
+junk += $(project).bgn $(project).bit $(project).drc $(project)_bd.bmm
+
+
+$(project)_par.ncd: $(project).ncd
+	$(xil_env); \
+	if par $(intstyle) $(par_opts) -w $(project).ncd $(project)_par.ncd; then \
+		:; \
+	else \
+		$(MAKE) etwr; \
+	fi 
+junk += $(project)_par.ncd $(project)_par.par $(project)_par.pad 
+junk += $(project)_par_pad.csv $(project)_par_pad.txt 
+junk += $(project)_par.grf $(project)_par.ptwx
+junk += $(project)_par.unroutes $(project)_par.xpi
+
+$(project).ncd: $(project).ngd
+	if [ -r $(project)_par.ncd ]; then \
+		cp $(project)_par.ncd smartguide.ncd; \
+		smartguide="-smartguide smartguide.ncd"; \
+	else \
+		smartguide=""; \
+	fi; \
+	$(xil_env); \
+	map $(intstyle) $(map_opts) $$smartguide $<
+junk += $(project).ncd $(project).pcf $(project).ngm $(project).mrp $(project).map
+junk += smartguide.ncd $(project).psr 
+junk += $(project)_summary.xml $(project)_usage.xml
+
+$(project).ngd: $(project).ngc $(ucf)
+	$(xil_env); ngdbuild $(intstyle) $(project).ngc -uc $(ucf)
+junk += $(project).ngd $(project).bld
+
+$(project).ngc: $(vfiles) $(local_corengcs) $(project).scr $(project).prj
+	$(xil_env); xst $(intstyle) -ifn $(project).scr
+junk += xlnx_auto* $(top_module).lso $(project).srp 
+junk += netlist.lst xst $(project).ngc
+
+$(project).prj: $(vfiles) $(mkfiles)
+	for src in $(vfiles); do echo "verilog work $$src" >> $(project).tmpprj; done
+	sort -u $(project).tmpprj > $(project).prj
+	rm -f $(project).tmpprj
+junk += $(project).prj
+
+optfile += $(wildcard $(project).opt)
+top_module ?= $(project)
+$(project).scr: $(optfile) $(mkfiles) ./xilinx.opt
+	echo "run" > $@
+	echo "-p $(part)" >> $@
+	echo "-top $(top_module)" >> $@
+	echo "-ifn $(project).prj" >> $@
+	echo "-ofn $(project).ngc" >> $@
+	cat ./xilinx.opt $(optfile) >> $@
+junk += $(project).scr
+
+$(project).post_map.twr: $(project).ncd
+	$(xil_env); trce -e 10 $< $(project).pcf -o $@
+junk += $(project).post_map.twr $(project).post_map.twx smartpreview.twr
+
+$(project).twr: $(project)_par.ncd
+	$(xil_env); trce $< $(project).pcf -o $(project).twr
+junk += $(project).twr $(project).twx smartpreview.twr
+
+$(project)_err.twr: $(project)_par.ncd
+	$(xil_env); trce -e 10 $< $(project).pcf -o $(project)_err.twr
+junk += $(project)_err.twr $(project)_err.twx
+junk += $(project).lso $(project)_bitgen.xwb $(project)_bitgen.xwbt
+junk += usage_statistics_webtalk.html par_usage_statistics.html webtalk.log _xmsgs default.xreport
+
+.gitignore: $(mkfiles)
+	echo programming_files $(junk) | sed 's, ,\n,g' > .gitignore
+
+clean::
+	rm -rf $(junk)
diff --git a/novena/build/xilinx.opt b/novena/build/xilinx.opt
new file mode 100644
index 0000000..7fe9d8b
--- /dev/null
+++ b/novena/build/xilinx.opt
@@ -0,0 +1,42 @@
+-ifmt mixed
+-ofmt NGC
+-opt_mode speed
+-opt_level 1
+-iuc NO
+-keep_hierarchy no
+-netlist_hierarchy as_optimized
+-rtlview no
+-glob_opt AllClockNets
+-read_cores yes
+-write_timing_constraints NO
+-cross_clock_analysis NO
+-hierarchy_separator /
+-bus_delimiter <>
+-case maintain
+-slice_utilization_ratio 100
+-bram_utilization_ratio 100
+#-dsp_utilization_ratio 100
+-safe_implementation No
+-fsm_extract YES
+-fsm_encoding Auto
+-fsm_style lut
+-ram_extract Yes
+-ram_style Auto
+-rom_extract Yes
+-rom_style Auto
+-shreg_extract YES
+-auto_bram_packing NO
+-resource_sharing YES
+-async_to_sync NO
+#-use_dsp48 auto
+-iobuf YES
+-max_fanout 500
+-register_duplication YES
+-register_balancing No
+-optimize_primitives NO
+-use_clock_enable Auto
+-use_sync_set Auto
+-use_sync_reset Auto
+-iob auto
+-equivalent_register_removal YES
+-slice_utilization_ratio_maxmargin 5
diff --git a/novena/iseconfig/novena_reorg_eim/novena_reorg_eim.xise b/novena/iseconfig/novena_reorg_eim/novena_reorg_eim.xise
new file mode 100644
index 0000000..d09db95
--- /dev/null
+++ b/novena/iseconfig/novena_reorg_eim/novena_reorg_eim.xise
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+
+  <header>
+    <!-- ISE source project file created by Project Navigator.             -->
+    <!--                                                                   -->
+    <!-- This file contains project source information including a list of -->
+    <!-- project source files, project and process properties.  This file, -->
+    <!-- along with the project source files, is sufficient to open and    -->
+    <!-- implement in ISE Project Navigator.                               -->
+    <!--                                                                   -->
+    <!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved. -->
+  </header>
+
+  <version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
+
+  <files>
+    <file xil_pn:name="../../src/rtl/novena_clkmgr.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="23"/>
+    </file>
+    <file xil_pn:name="../../src/rtl/novena_eim.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="2"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="26"/>
+    </file>
+    <file xil_pn:name="../../src/rtl/novena_regs.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="4"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="14"/>
+    </file>
+    <file xil_pn:name="../../src/rtl/ipcore/clkmgr_dcm.xco" xil_pn:type="FILE_COREGEN">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="5"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="17"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/cipher_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="11"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="22"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/core_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="12"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="25"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/hash_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="13"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="21"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/rng_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="14"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="20"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/cdc_bus_pulse.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="16"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="10"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/eim_arbiter_cdc.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="17"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="16"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/eim_arbiter.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="18"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="19"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/eim_da_phy.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="19"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="15"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/eim_indicator.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="20"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="18"/>
+    </file>
+    <file xil_pn:name="../../../eim/src/rtl/eim.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="21"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="24"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="22"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="9"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="23"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="6"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="24"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="13"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="25"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="8"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_k_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="26"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="5"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="27"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="4"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="28"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="12"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="30"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="7"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_h_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="31"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="3"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_k_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="32"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="33"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="1"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="34"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="11"/>
+    </file>
+    <file xil_pn:name="../../src/ucf/novena_eim.ucf" xil_pn:type="FILE_UCF">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+    <file xil_pn:name="../../src/rtl/ipcore/clkmgr_dcm.xise" xil_pn:type="FILE_COREGENISE">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+  </files>
+
+  <properties>
+    <property xil_pn:name="AES Initial Vector spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="AES Key (Hex String) spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Logic Optimization Across Hierarchy" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow SelectMAP Pins to Persist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unexpanded Blocks" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Analysis Effort Level" xil_pn:value="Standard" xil_pn:valueState="default"/>
+    <property xil_pn:name="Asynchronous To Synchronous" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatic BRAM Packing" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Run Generate Target PROM/ACE File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="BRAM Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Tristate Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bus Delimiter" xil_pn:value="<>" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Clk (Configuration Pins)" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Done" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M0" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M1" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M2" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Program" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Rate spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Correlate Output to Input Design" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ASCII Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Binary Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Bit File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create I/O Pads from Ports" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create IEEE 1532 Configuration File spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Logic Allocation File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Mask File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ReadBack Data Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Cross Clock Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="DSP Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
+    <property xil_pn:name="Device" xil_pn:value="xc6slx45" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Disable Detailed Package Model Insertion" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Done (Output Events)" xil_pn:value="Default (4)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Awake Pin During Suspend/Wake Sequence spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Done Pin High" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable BitStream Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Cyclic Redundancy Checking (CRC) spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Debugging of Serial Mode BitStream" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable External Master Clock spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Hardware Co-Simulation" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Threading" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Threading par spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Outputs (Output Events)" xil_pn:value="Default (5)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Suspend/Wake Global Set/Reset spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Key Select spartan6" xil_pn:value="BBRAM" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Essential Bits" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of Deprecated EDK Cores" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of EDK Sub-Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Cost Tables Map" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="FPGA Start-Up Clock" xil_pn:value="CCLK" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Flatten Output Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language ArchWiz" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Coregen" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="GTS Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="GWE Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="5" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Asynchronous Delay Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Clock Region Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Detailed MAP Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place & Route Power Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place & Route Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization Goal" xil_pn:value="AllClockNets" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Tristate Port Name" xil_pn:value="GTS_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
+    <property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Implementation Top" xil_pn:value="Module|novena_baseline_top" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top File" xil_pn:value="../../src/rtl/novena_eim.v" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/novena_baseline_top" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include UNISIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Insert Buffers to Prevent Pulse Swallowing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TCK" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDI" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDO" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TMS" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Xst" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Applied Goal" xil_pn:value="Balanced" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Applied Strategy" xil_pn:value="Xilinx Default (unlocked)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Map Slice Logic into Unused Block RAMs" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Mask Pins for Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="0x00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Max Fanout" xil_pn:value="100000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move First Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move Last Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Insert IPROG CMD in the Bitfile spartan6" xil_pn:value="Enable" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Next Configuration Mode spartan6" xil_pn:value="001" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Golden Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Next Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Use New Mode for Next Configuration spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: User-Defined Register for Failsafe Scheme spartan6" xil_pn:value="0x0000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Translation Type" xil_pn:value="Timestamp" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Clock Buffers" xil_pn:value="16" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimization Effort spartan6" xil_pn:value="Normal" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimization Goal" xil_pn:value="Speed" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Par" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Map Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Place & Route Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output File Name" xil_pn:value="novena_baseline_top" xil_pn:valueState="default"/>
+    <property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers into IOBs" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers/Latches into IOBs" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Package" xil_pn:value="csg324" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Perform Advanced Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Advanced Analysis Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Timing-Driven Packing and Placement" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place & Route Effort Level (Overall)" xil_pn:value="High" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place And Route Mode" xil_pn:value="Normal Place and Route" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place MultiBoot Settings into Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Placer Effort Level Map" xil_pn:value="High" xil_pn:valueState="default"/>
+    <property xil_pn:name="Placer Extra Effort Map" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Map Simulation Model Name" xil_pn:value="novena_baseline_top_map.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Place & Route Simulation Model Name" xil_pn:value="novena_baseline_top_timesim.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Synthesis Simulation Model Name" xil_pn:value="novena_baseline_top_synthesis.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Translate Simulation Model Name" xil_pn:value="novena_baseline_top_translate.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Xst" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Read Cores" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Reduce Control Sets" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Regenerate Core" xil_pn:value="Under Current Project Setting" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Balancing" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Xst" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Ordering spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="Default (6)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Entity to" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type Post Trace" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths Post Trace" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retry Configuration if CRC Error Occurs spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select" xil_pn:value="00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select Tristate" xil_pn:value="Disable" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run Design Rules Checker (DRC)" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Translate" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Security" xil_pn:value="Enable Readback and Reconfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Set SPI Configuration Bus Width spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Setup External Master Clock Division spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Minimum Size spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time ISim" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Map" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Translate" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Slice Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Map" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Speed Grade" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
+    <property xil_pn:name="Timing Mode Map" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Timing Mode Par" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Module Name in Output Netlist" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Trim Unconnected Signals" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Tristate On Configuration Pulse Width" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Unused IOB Pins" xil_pn:value="Pull Down" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use 64-bit PlanAhead on 64-bit Systems" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Clock Enable" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Route" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use DSP Block spartan6" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use LOC Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use RLOC Constraints" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Reset" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Set" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="UserID Code (8 Digit Hexadecimal)" xil_pn:value="0xFFFFFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="VCCAUX Voltage Level spartan6" xil_pn:value="2.5V" xil_pn:valueState="default"/>
+    <property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
+    <property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wait for DCM and PLL Lock (Output Events) spartan6" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wakeup Clock spartan6" xil_pn:value="Startup Clock" xil_pn:valueState="default"/>
+    <property xil_pn:name="Watchdog Timer Value spartan6" xil_pn:value="0xFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Write Timing Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <!--                                                                                  -->
+    <!-- The following properties are for internal use only. These should not be modified.-->
+    <!--                                                                                  -->
+    <property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_DesignName" xil_pn:value="novena_reorg_eim" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_FPGAConfiguration" xil_pn:value="FPGAConfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostMapSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostParSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostSynthSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostXlateSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2015-02-18T12:52:31" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="864F45CE2D69580E9CD3CF97C2CAF083" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
+  </properties>
+
+  <bindings/>
+
+  <libraries/>
+
+  <autoManagedFiles>
+    <!-- The following files are identified by `include statements in verilog -->
+    <!-- source files and are automatically managed by Project Navigator.     -->
+    <!--                                                                      -->
+    <!-- Do not hand-edit this section, as it will be overwritten when the    -->
+    <!-- project is analyzed based on files automatically identified as       -->
+    <!-- include files.                                                       -->
+  </autoManagedFiles>
+
+</project>
diff --git a/novena/iseconfig/novena_reorg_i2c/novena_reorg_i2c.xise b/novena/iseconfig/novena_reorg_i2c/novena_reorg_i2c.xise
new file mode 100644
index 0000000..e7666bb
--- /dev/null
+++ b/novena/iseconfig/novena_reorg_i2c/novena_reorg_i2c.xise
@@ -0,0 +1,438 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+
+  <header>
+    <!-- ISE source project file created by Project Navigator.             -->
+    <!--                                                                   -->
+    <!-- This file contains project source information including a list of -->
+    <!-- project source files, project and process properties.  This file, -->
+    <!-- along with the project source files, is sufficient to open and    -->
+    <!-- implement in ISE Project Navigator.                               -->
+    <!--                                                                   -->
+    <!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved. -->
+  </header>
+
+  <version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
+
+  <files>
+    <file xil_pn:name="../../src/rtl/novena_i2c.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="20"/>
+    </file>
+    <file xil_pn:name="../../src/ucf/novena_i2c.ucf" xil_pn:type="FILE_UCF">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/cipher_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="3"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="16"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/core_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="4"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="18"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/hash_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="5"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="15"/>
+    </file>
+    <file xil_pn:name="../../../core_selector/src/rtl/rng_selector.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="6"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="14"/>
+    </file>
+    <file xil_pn:name="../../../coretest/src/rtl/coretest.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="7"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="19"/>
+    </file>
+    <file xil_pn:name="../../../i2c/src/rtl/i2c_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="8"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="17"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="9"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="8"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="10"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="3"/>
+    </file>
+    <file xil_pn:name="../../../sha1/src/rtl/sha1.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="11"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="11"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="12"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="7"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_k_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="13"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="14"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="1"/>
+    </file>
+    <file xil_pn:name="../../../sha256/src/rtl/sha256.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="15"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="10"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_core.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="16"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="9"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_h_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="17"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="6"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_k_constants.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="18"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="5"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512_w_mem.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="19"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="4"/>
+    </file>
+    <file xil_pn:name="../../../sha512/src/rtl/sha512.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="20"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="13"/>
+    </file>
+    <file xil_pn:name="../../src/rtl/novena_regs.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="21"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="12"/>
+    </file>
+  </files>
+
+  <properties>
+    <property xil_pn:name="AES Initial Vector spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="AES Key (Hex String) spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Logic Optimization Across Hierarchy" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow SelectMAP Pins to Persist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unexpanded Blocks" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Analysis Effort Level" xil_pn:value="Standard" xil_pn:valueState="default"/>
+    <property xil_pn:name="Asynchronous To Synchronous" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatic BRAM Packing" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Run Generate Target PROM/ACE File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="BRAM Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Tristate Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bus Delimiter" xil_pn:value="<>" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Clk (Configuration Pins)" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Done" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M0" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M1" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M2" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Program" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Rate spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Correlate Output to Input Design" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ASCII Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Binary Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Bit File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create I/O Pads from Ports" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create IEEE 1532 Configuration File spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Logic Allocation File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Mask File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ReadBack Data Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Cross Clock Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="DSP Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
+    <property xil_pn:name="Device" xil_pn:value="xc6slx45" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Disable Detailed Package Model Insertion" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Done (Output Events)" xil_pn:value="Default (4)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Awake Pin During Suspend/Wake Sequence spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Done Pin High" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable BitStream Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Cyclic Redundancy Checking (CRC) spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Debugging of Serial Mode BitStream" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable External Master Clock spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Threading" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Threading par spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Outputs (Output Events)" xil_pn:value="Default (5)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Suspend/Wake Global Set/Reset spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Key Select spartan6" xil_pn:value="BBRAM" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Essential Bits" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of Deprecated EDK Cores" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of EDK Sub-Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Cost Tables Map" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="FPGA Start-Up Clock" xil_pn:value="CCLK" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Flatten Output Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language ArchWiz" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Coregen" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="GTS Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="GWE Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="5" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Asynchronous Delay Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Clock Region Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Detailed MAP Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place & Route Power Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place & Route Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization Goal" xil_pn:value="AllClockNets" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Tristate Port Name" xil_pn:value="GTS_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
+    <property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Implementation Top" xil_pn:value="Module|novena_baseline_top" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top File" xil_pn:value="../../src/rtl/novena_i2c.v" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/novena_baseline_top" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include UNISIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Insert Buffers to Prevent Pulse Swallowing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TCK" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDI" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDO" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TMS" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Xst" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Applied Goal" xil_pn:value="Balanced" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Applied Strategy" xil_pn:value="Xilinx Default (unlocked)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Map Slice Logic into Unused Block RAMs" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Mask Pins for Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="0x00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Max Fanout" xil_pn:value="100000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move First Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move Last Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Insert IPROG CMD in the Bitfile spartan6" xil_pn:value="Enable" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Next Configuration Mode spartan6" xil_pn:value="001" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Golden Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Next Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Use New Mode for Next Configuration spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: User-Defined Register for Failsafe Scheme spartan6" xil_pn:value="0x0000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Translation Type" xil_pn:value="Timestamp" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Clock Buffers" xil_pn:value="16" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimization Effort spartan6" xil_pn:value="Normal" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimization Goal" xil_pn:value="Speed" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Par" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Map Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Place & Route Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output File Name" xil_pn:value="novena_baseline_top" xil_pn:valueState="default"/>
+    <property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers into IOBs" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers/Latches into IOBs" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Package" xil_pn:value="csg324" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Perform Advanced Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Advanced Analysis Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Timing-Driven Packing and Placement" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place & Route Effort Level (Overall)" xil_pn:value="High" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place And Route Mode" xil_pn:value="Normal Place and Route" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place MultiBoot Settings into Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Placer Effort Level Map" xil_pn:value="High" xil_pn:valueState="default"/>
+    <property xil_pn:name="Placer Extra Effort Map" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Map Simulation Model Name" xil_pn:value="novena_baseline_top_map.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Place & Route Simulation Model Name" xil_pn:value="novena_baseline_top_timesim.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Synthesis Simulation Model Name" xil_pn:value="novena_baseline_top_synthesis.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Translate Simulation Model Name" xil_pn:value="novena_baseline_top_translate.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Xst" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Read Cores" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Reduce Control Sets" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Regenerate Core" xil_pn:value="Under Current Project Setting" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Balancing" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Xst" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Ordering spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="Default (6)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Entity to" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type Post Trace" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths Post Trace" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retry Configuration if CRC Error Occurs spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select" xil_pn:value="00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select Tristate" xil_pn:value="Disable" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run Design Rules Checker (DRC)" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Translate" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Security" xil_pn:value="Enable Readback and Reconfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Set SPI Configuration Bus Width spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Setup External Master Clock Division spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Minimum Size spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time ISim" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Map" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Translate" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Slice Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Map" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Speed Grade" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
+    <property xil_pn:name="Timing Mode Map" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Timing Mode Par" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Module Name in Output Netlist" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Trim Unconnected Signals" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Tristate On Configuration Pulse Width" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Unused IOB Pins" xil_pn:value="Pull Down" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use 64-bit PlanAhead on 64-bit Systems" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Clock Enable" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Route" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use DSP Block spartan6" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use LOC Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use RLOC Constraints" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Reset" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Set" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="UserID Code (8 Digit Hexadecimal)" xil_pn:value="0xFFFFFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="VCCAUX Voltage Level spartan6" xil_pn:value="2.5V" xil_pn:valueState="default"/>
+    <property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
+    <property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wait for DCM and PLL Lock (Output Events) spartan6" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wakeup Clock spartan6" xil_pn:value="Startup Clock" xil_pn:valueState="default"/>
+    <property xil_pn:name="Watchdog Timer Value spartan6" xil_pn:value="0xFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Write Timing Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <!--                                                                                  -->
+    <!-- The following properties are for internal use only. These should not be modified.-->
+    <!--                                                                                  -->
+    <property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_DesignName" xil_pn:value="novena_reorg_i2c" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_FPGAConfiguration" xil_pn:value="FPGAConfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostMapSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostParSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostSynthSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostXlateSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2015-02-18T13:38:00" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="884D55DDED613BF5E3BBF7BC051A0A88" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
+  </properties>
+
+  <bindings/>
+
+  <libraries/>
+
+  <autoManagedFiles>
+    <!-- The following files are identified by `include statements in verilog -->
+    <!-- source files and are automatically managed by Project Navigator.     -->
+    <!--                                                                      -->
+    <!-- Do not hand-edit this section, as it will be overwritten when the    -->
+    <!-- project is analyzed based on files automatically identified as       -->
+    <!-- include files.                                                       -->
+  </autoManagedFiles>
+
+</project>
diff --git a/novena/src/rtl/ipcore/_xmsgs/cg.xmsgs b/novena/src/rtl/ipcore/_xmsgs/cg.xmsgs
new file mode 100644
index 0000000..985e6e3
--- /dev/null
+++ b/novena/src/rtl/ipcore/_xmsgs/cg.xmsgs
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- IMPORTANT: This is an internal file that has been generated
+     by the Xilinx ISE software.  Any direct editing or
+     changes made to this file may result in unpredictable
+     behavior or data corruption.  It is strongly advised that
+     users do not edit the contents of this file. -->
+<messages>
+<msg type="info" file="sim" num="172" delta="old" >Generating IP...
+</msg>
+
+<msg type="warning" file="sim" num="0" delta="new" ><arg fmt="%s" index="1">A core named 'clkmgr_dcm' already exists in the project. Output products for this core may be overwritten.</arg>
+</msg>
+
+<msg type="warning" file="sim" num="0" delta="new" ><arg fmt="%s" index="1">A core named 'clkmgr_dcm' already exists in the project. Output products for this core may be overwritten.</arg>
+</msg>
+
+<msg type="warning" file="sim" num="0" delta="new" ><arg fmt="%s" index="1">Component clk_wiz_v3_6 does not have a valid model name for Verilog synthesis</arg>
+</msg>
+
+<msg type="info" file="sim" num="949" delta="old" >Finished generation of ASY schematic symbol.
+</msg>
+
+<msg type="info" file="sim" num="948" delta="old" >Finished FLIST file generation.
+</msg>
+
+</messages>
+
diff --git a/novena/src/rtl/ipcore/_xmsgs/pn_parser.xmsgs b/novena/src/rtl/ipcore/_xmsgs/pn_parser.xmsgs
new file mode 100644
index 0000000..f69d969
--- /dev/null
+++ b/novena/src/rtl/ipcore/_xmsgs/pn_parser.xmsgs
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- IMPORTANT: This is an internal file that has been generated   -->
+<!--     by the Xilinx ISE software.  Any direct editing or        -->
+<!--     changes made to this file may result in unpredictable     -->
+<!--     behavior or data corruption.  It is strongly advised that -->
+<!--     users do not edit the contents of this file.              -->
+<!--                                                               -->
+<!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved.    -->
+
+<messages>
+<msg type="info" file="ProjectMgmt" num="1845" ><arg fmt="%s" index="1">Analyzing Verilog file "/home/pselkirk/cryptech/user/paul/core/novena/src/rtl/ipcore/clkmgr_dcm.v" into library work</arg>
+</msg>
+
+</messages>
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.asy b/novena/src/rtl/ipcore/clkmgr_dcm.asy
new file mode 100644
index 0000000..016d02a
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.asy
@@ -0,0 +1,25 @@
+Version 4
+SymbolType BLOCK
+TEXT 32 32 LEFT 4 clkmgr_dcm
+RECTANGLE Normal 32 32 576 1088
+LINE Normal 0 80 32 80
+PIN 0 80 LEFT 36
+PINATTR PinName clk_in1
+PINATTR Polarity IN
+LINE Normal 0 432 32 432
+PIN 0 432 LEFT 36
+PINATTR PinName reset
+PINATTR Polarity IN
+LINE Normal 608 80 576 80
+PIN 608 80 RIGHT 36
+PINATTR PinName clk_out1
+PINATTR Polarity OUT
+LINE Normal 608 880 576 880
+PIN 608 880 RIGHT 36
+PINATTR PinName input_clk_stopped
+PINATTR Polarity OUT
+LINE Normal 608 1008 576 1008
+PIN 608 1008 RIGHT 36
+PINATTR PinName clk_valid
+PINATTR Polarity OUT
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.gise b/novena/src/rtl/ipcore/clkmgr_dcm.gise
new file mode 100644
index 0000000..ed6d0f7
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.gise
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<generated_project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+
+  <!--                                                          -->
+
+  <!--             For tool use only. Do not edit.              -->
+
+  <!--                                                          -->
+
+  <!-- ProjectNavigator created generated project file.         -->
+
+  <!-- For use in tracking generated file and other information -->
+
+  <!-- allowing preservation of process status.                 -->
+
+  <!--                                                          -->
+
+  <!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved. -->
+
+  <version xmlns="http://www.xilinx.com/XMLSchema">11.1</version>
+
+  <sourceproject xmlns="http://www.xilinx.com/XMLSchema" xil_pn:fileType="FILE_XISE" xil_pn:name="clkmgr_dcm.xise"/>
+
+  <files xmlns="http://www.xilinx.com/XMLSchema">
+    <file xil_pn:fileType="FILE_ASY" xil_pn:name="clkmgr_dcm.asy" xil_pn:origination="imported"/>
+    <file xil_pn:fileType="FILE_VEO" xil_pn:name="clkmgr_dcm.veo" xil_pn:origination="imported"/>
+  </files>
+
+  <transforms xmlns="http://www.xilinx.com/XMLSchema"/>
+
+</generated_project>
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.ncf b/novena/src/rtl/ipcore/clkmgr_dcm.ncf
new file mode 100644
index 0000000..ef4e259
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.ncf
@@ -0,0 +1,60 @@
+# file: clkmgr_dcm.ucf
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# Input clock periods. These duplicate the values entered for the
+#  input clocks. You can use these to time your system
+#----------------------------------------------------------------
+NET "CLK_IN1" TNM_NET = "CLK_IN1";
+TIMESPEC "TS_CLK_IN1" = PERIOD "CLK_IN1" 20.0 ns HIGH 50% INPUT_JITTER 200.0ps;
+
+
+# FALSE PATH constraints 
+PIN "RESET" TIG;
+
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.sym b/novena/src/rtl/ipcore/clkmgr_dcm.sym
new file mode 100644
index 0000000..7d178b8
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.sym
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<symbol version="7" name="clkmgr_dcm">
+    <symboltype>BLOCK</symboltype>
+    <timestamp>2015-1-28T21:56:19</timestamp>
+    <pin polarity="Input" x="0" y="80" name="clk_in1" />
+    <pin polarity="Input" x="0" y="432" name="reset" />
+    <pin polarity="Output" x="608" y="80" name="clk_out1" />
+    <pin polarity="Output" x="608" y="880" name="input_clk_stopped" />
+    <pin polarity="Output" x="608" y="1008" name="clk_valid" />
+    <graph>
+        <text style="fontsize:40;fontname:Arial" x="32" y="32">clkmgr_dcm</text>
+        <rect width="544" x="32" y="32" height="1056" />
+        <line x2="32" y1="80" y2="80" x1="0" />
+        <attrtext style="fontsize:24;fontname:Arial" attrname="PinName" x="36" y="80" type="pin clk_in1" />
+        <line x2="32" y1="432" y2="432" x1="0" />
+        <attrtext style="fontsize:24;fontname:Arial" attrname="PinName" x="36" y="432" type="pin reset" />
+        <line x2="576" y1="80" y2="80" x1="608" />
+        <attrtext style="alignment:RIGHT;fontsize:24;fontname:Arial" attrname="PinName" x="572" y="80" type="pin clk_out1" />
+        <line x2="576" y1="880" y2="880" x1="608" />
+        <attrtext style="alignment:RIGHT;fontsize:24;fontname:Arial" attrname="PinName" x="572" y="880" type="pin input_clk_stopped" />
+        <line x2="576" y1="1008" y2="1008" x1="608" />
+        <attrtext style="alignment:RIGHT;fontsize:24;fontname:Arial" attrname="PinName" x="572" y="1008" type="pin clk_valid" />
+    </graph>
+</symbol>
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.ucf b/novena/src/rtl/ipcore/clkmgr_dcm.ucf
new file mode 100644
index 0000000..658fdb4
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.ucf
@@ -0,0 +1,59 @@
+# file: clkmgr_dcm.ucf
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# Input clock periods. These duplicate the values entered for the
+#  input clocks. You can use these to time your system
+#----------------------------------------------------------------
+NET "CLK_IN1" TNM_NET = "CLK_IN1";
+TIMESPEC "TS_CLK_IN1" = PERIOD "CLK_IN1" 20.0 ns HIGH 50% INPUT_JITTER 200.0ps;
+
+
+# FALSE PATH constraints 
+PIN "RESET" TIG;
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.v b/novena/src/rtl/ipcore/clkmgr_dcm.v
new file mode 100644
index 0000000..71477a8
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.v
@@ -0,0 +1,148 @@
+// file: clkmgr_dcm.v
+// 
+// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+// 
+// This file contains confidential and proprietary information
+// of Xilinx, Inc. and is protected under U.S. and
+// international copyright and other intellectual property
+// laws.
+// 
+// DISCLAIMER
+// This disclaimer is not a license and does not grant any
+// rights to the materials distributed herewith. Except as
+// otherwise provided in a valid license issued to you by
+// Xilinx, and to the maximum extent permitted by applicable
+// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+// (2) Xilinx shall not be liable (whether in contract or tort,
+// including negligence, or under any other theory of
+// liability) for any loss or damage of any kind or nature
+// related to, arising under or in connection with these
+// materials, including for any direct, or any indirect,
+// special, incidental, or consequential loss or damage
+// (including loss of data, profits, goodwill, or any type of
+// loss or damage suffered as a result of any action brought
+// by a third party) even if such damage or loss was
+// reasonably foreseeable or Xilinx had been advised of the
+// possibility of the same.
+// 
+// CRITICAL APPLICATIONS
+// Xilinx products are not designed or intended to be fail-
+// safe, or for use in any application requiring fail-safe
+// performance, such as life-support or safety devices or
+// systems, Class III medical devices, nuclear facilities,
+// applications related to the deployment of airbags, or any
+// other applications that could lead to death, personal
+// injury, or severe property or environmental damage
+// (individually and collectively, "Critical
+// Applications"). Customer assumes the sole risk and
+// liability of any use of Xilinx products in Critical
+// Applications, subject only to applicable laws and
+// regulations governing limitations on product liability.
+// 
+// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+// PART OF THIS FILE AT ALL TIMES.
+// 
+//----------------------------------------------------------------------------
+// User entered comments
+//----------------------------------------------------------------------------
+// None
+//
+//----------------------------------------------------------------------------
+// "Output    Output      Phase     Duty      Pk-to-Pk        Phase"
+// "Clock    Freq (MHz) (degrees) Cycle (%) Jitter (ps)  Error (ps)"
+//----------------------------------------------------------------------------
+// CLK_OUT1____50.000______0.000______50.0______200.000____150.000
+//
+//----------------------------------------------------------------------------
+// "Input Clock   Freq (MHz)    Input Jitter (UI)"
+//----------------------------------------------------------------------------
+// __primary______________50____________0.010
+
+`timescale 1ps/1ps
+
+(* CORE_GENERATION_INFO = "clkmgr_dcm,clk_wiz_v3_6,{component_name=clkmgr_dcm,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=DCM_SP,num_out_clk=1,clkin1_period=20.0,clkin2_period=20.0,use_power_down=false,use_reset=true,use_locked=false,use_inclk_stopped=true,use_status=false,use_freeze=false,use_clk_valid=true,feedback_type=SINGLE,clock_mgr_type=MANU [...]
+module clkmgr_dcm
+ (// Clock in ports
+  input         CLK_IN1,
+  // Clock out ports
+  output        CLK_OUT1,
+  // Status and control signals
+  input         RESET,
+  output        INPUT_CLK_STOPPED,
+  output        CLK_VALID
+ );
+
+  // Input buffering
+  //------------------------------------
+  assign clkin1 = CLK_IN1;
+
+
+  // Clocking primitive
+  //------------------------------------
+
+  // Instantiation of the DCM primitive
+  //    * Unused inputs are tied off
+  //    * Unused outputs are labeled unused
+  wire        psdone_unused;
+  wire        locked_int;
+  wire [7:0]  status_int;
+  wire clkfb;
+  wire clk0;
+
+  DCM_SP
+  #(.CLKDV_DIVIDE          (2.000),
+    .CLKFX_DIVIDE          (1),
+    .CLKFX_MULTIPLY        (4),
+    .CLKIN_DIVIDE_BY_2     ("FALSE"),
+    .CLKIN_PERIOD          (20.0),
+    .CLKOUT_PHASE_SHIFT    ("NONE"),
+    .CLK_FEEDBACK          ("1X"),
+    .DESKEW_ADJUST         ("SYSTEM_SYNCHRONOUS"),
+    .PHASE_SHIFT           (0),
+    .STARTUP_WAIT          ("FALSE"))
+  dcm_sp_inst
+    // Input clock
+   (.CLKIN                 (clkin1),
+    .CLKFB                 (clkfb),
+    // Output clocks
+    .CLK0                  (clk0),
+    .CLK90                 (),
+    .CLK180                (),
+    .CLK270                (),
+    .CLK2X                 (),
+    .CLK2X180              (),
+    .CLKFX                 (),
+    .CLKFX180              (),
+    .CLKDV                 (),
+    // Ports for dynamic phase shift
+    .PSCLK                 (1'b0),
+    .PSEN                  (1'b0),
+    .PSINCDEC              (1'b0),
+    .PSDONE                (),
+    // Other control and status signals
+    .LOCKED                (locked_int),
+    .STATUS                (status_int),
+ 
+    .RST                   (RESET),
+    // Unused pin- tie low
+    .DSSEN                 (1'b0));
+
+    assign INPUT_CLK_STOPPED = status_int[1];
+    assign CLK_VALID = ( ( locked_int == 1'b 1 ) && ( status_int[1] == 1'b 0 ) );
+
+  // Output buffering
+  //-----------------------------------
+  assign clkfb = CLK_OUT1;
+
+  BUFG clkout1_buf
+   (.O   (CLK_OUT1),
+    .I   (clk0));
+
+
+
+
+endmodule
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.veo b/novena/src/rtl/ipcore/clkmgr_dcm.veo
new file mode 100644
index 0000000..c4e1d31
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.veo
@@ -0,0 +1,79 @@
+// 
+// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+// 
+// This file contains confidential and proprietary information
+// of Xilinx, Inc. and is protected under U.S. and
+// international copyright and other intellectual property
+// laws.
+// 
+// DISCLAIMER
+// This disclaimer is not a license and does not grant any
+// rights to the materials distributed herewith. Except as
+// otherwise provided in a valid license issued to you by
+// Xilinx, and to the maximum extent permitted by applicable
+// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+// (2) Xilinx shall not be liable (whether in contract or tort,
+// including negligence, or under any other theory of
+// liability) for any loss or damage of any kind or nature
+// related to, arising under or in connection with these
+// materials, including for any direct, or any indirect,
+// special, incidental, or consequential loss or damage
+// (including loss of data, profits, goodwill, or any type of
+// loss or damage suffered as a result of any action brought
+// by a third party) even if such damage or loss was
+// reasonably foreseeable or Xilinx had been advised of the
+// possibility of the same.
+// 
+// CRITICAL APPLICATIONS
+// Xilinx products are not designed or intended to be fail-
+// safe, or for use in any application requiring fail-safe
+// performance, such as life-support or safety devices or
+// systems, Class III medical devices, nuclear facilities,
+// applications related to the deployment of airbags, or any
+// other applications that could lead to death, personal
+// injury, or severe property or environmental damage
+// (individually and collectively, "Critical
+// Applications"). Customer assumes the sole risk and
+// liability of any use of Xilinx products in Critical
+// Applications, subject only to applicable laws and
+// regulations governing limitations on product liability.
+// 
+// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+// PART OF THIS FILE AT ALL TIMES.
+// 
+//----------------------------------------------------------------------------
+// User entered comments
+//----------------------------------------------------------------------------
+// None
+//
+//----------------------------------------------------------------------------
+// "Output    Output      Phase     Duty      Pk-to-Pk        Phase"
+// "Clock    Freq (MHz) (degrees) Cycle (%) Jitter (ps)  Error (ps)"
+//----------------------------------------------------------------------------
+// CLK_OUT1____50.000______0.000______50.0______200.000____150.000
+//
+//----------------------------------------------------------------------------
+// "Input Clock   Freq (MHz)    Input Jitter (UI)"
+//----------------------------------------------------------------------------
+// __primary______________50____________0.010
+
+// The following must be inserted into your Verilog file for this
+// core to be instantiated. Change the instance name and port connections
+// (in parentheses) to your own signal names.
+
+//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
+
+  clkmgr_dcm instance_name
+   (// Clock in ports
+    .CLK_IN1(CLK_IN1),      // IN
+    // Clock out ports
+    .CLK_OUT1(CLK_OUT1),     // OUT
+    // Status and control signals
+    .RESET(RESET),// IN
+    .INPUT_CLK_STOPPED(INPUT_CLK_STOPPED), // OUT
+    .CLK_VALID(CLK_VALID));   // OUT
+// INST_TAG_END ------ End INSTANTIATION Template ---------
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.xco b/novena/src/rtl/ipcore/clkmgr_dcm.xco
new file mode 100644
index 0000000..37f1a1d
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.xco
@@ -0,0 +1,269 @@
+##############################################################
+#
+# Xilinx Core Generator version 14.7
+# Date: Sun Feb 01 07:49:40 2015
+#
+##############################################################
+#
+#  This file contains the customisation parameters for a
+#  Xilinx CORE Generator IP GUI. It is strongly recommended
+#  that you do not manually alter this file as it may cause
+#  unexpected and unsupported behavior.
+#
+##############################################################
+#
+#  Generated from component: xilinx.com:ip:clk_wiz:3.6
+#
+##############################################################
+#
+# BEGIN Project Options
+SET addpads = false
+SET asysymbol = true
+SET busformat = BusFormatAngleBracketNotRipped
+SET createndf = false
+SET designentry = Verilog
+SET device = xc6slx45
+SET devicefamily = spartan6
+SET flowvendor = Other
+SET formalverification = false
+SET foundationsym = false
+SET implementationfiletype = Ngc
+SET package = csg324
+SET removerpms = false
+SET simulationfiles = Behavioral
+SET speedgrade = -3
+SET verilogsim = true
+SET vhdlsim = false
+# END Project Options
+# BEGIN Select
+SELECT Clocking_Wizard xilinx.com:ip:clk_wiz:3.6
+# END Select
+# BEGIN Parameters
+CSET calc_done=DONE
+CSET clk_in_sel_port=CLK_IN_SEL
+CSET clk_out1_port=CLK_OUT1
+CSET clk_out1_use_fine_ps_gui=false
+CSET clk_out2_port=CLK_OUT2
+CSET clk_out2_use_fine_ps_gui=false
+CSET clk_out3_port=CLK_OUT3
+CSET clk_out3_use_fine_ps_gui=false
+CSET clk_out4_port=CLK_OUT4
+CSET clk_out4_use_fine_ps_gui=false
+CSET clk_out5_port=CLK_OUT5
+CSET clk_out5_use_fine_ps_gui=false
+CSET clk_out6_port=CLK_OUT6
+CSET clk_out6_use_fine_ps_gui=false
+CSET clk_out7_port=CLK_OUT7
+CSET clk_out7_use_fine_ps_gui=false
+CSET clk_valid_port=CLK_VALID
+CSET clkfb_in_n_port=CLKFB_IN_N
+CSET clkfb_in_p_port=CLKFB_IN_P
+CSET clkfb_in_port=CLKFB_IN
+CSET clkfb_in_signaling=SINGLE
+CSET clkfb_out_n_port=CLKFB_OUT_N
+CSET clkfb_out_p_port=CLKFB_OUT_P
+CSET clkfb_out_port=CLKFB_OUT
+CSET clkfb_stopped_port=CLKFB_STOPPED
+CSET clkin1_jitter_ps=200.0
+CSET clkin1_ui_jitter=0.010
+CSET clkin2_jitter_ps=100.0
+CSET clkin2_ui_jitter=0.010
+CSET clkout1_drives=BUFG
+CSET clkout1_requested_duty_cycle=50.0
+CSET clkout1_requested_out_freq=50
+CSET clkout1_requested_phase=0.000
+CSET clkout2_drives=BUFG
+CSET clkout2_requested_duty_cycle=50.0
+CSET clkout2_requested_out_freq=50
+CSET clkout2_requested_phase=0
+CSET clkout2_used=false
+CSET clkout3_drives=BUFG
+CSET clkout3_requested_duty_cycle=50.0
+CSET clkout3_requested_out_freq=100.000
+CSET clkout3_requested_phase=0.000
+CSET clkout3_used=false
+CSET clkout4_drives=BUFG
+CSET clkout4_requested_duty_cycle=50.0
+CSET clkout4_requested_out_freq=100.000
+CSET clkout4_requested_phase=0.000
+CSET clkout4_used=false
+CSET clkout5_drives=BUFG
+CSET clkout5_requested_duty_cycle=50.0
+CSET clkout5_requested_out_freq=100.000
+CSET clkout5_requested_phase=0.000
+CSET clkout5_used=false
+CSET clkout6_drives=BUFG
+CSET clkout6_requested_duty_cycle=50.0
+CSET clkout6_requested_out_freq=100.000
+CSET clkout6_requested_phase=0.000
+CSET clkout6_used=false
+CSET clkout7_drives=BUFG
+CSET clkout7_requested_duty_cycle=50.0
+CSET clkout7_requested_out_freq=100.000
+CSET clkout7_requested_phase=0.000
+CSET clkout7_used=false
+CSET clock_mgr_type=MANUAL
+CSET component_name=clkmgr_dcm
+CSET daddr_port=DADDR
+CSET dclk_port=DCLK
+CSET dcm_clk_feedback=1X
+CSET dcm_clk_out1_port=CLK0
+CSET dcm_clk_out2_port=CLK0
+CSET dcm_clk_out3_port=CLK0
+CSET dcm_clk_out4_port=CLK0
+CSET dcm_clk_out5_port=CLK0
+CSET dcm_clk_out6_port=CLK0
+CSET dcm_clkdv_divide=2.0
+CSET dcm_clkfx_divide=1
+CSET dcm_clkfx_multiply=4
+CSET dcm_clkgen_clk_out1_port=CLKFX
+CSET dcm_clkgen_clk_out2_port=CLKFX
+CSET dcm_clkgen_clk_out3_port=CLKFX
+CSET dcm_clkgen_clkfx_divide=1
+CSET dcm_clkgen_clkfx_md_max=0.000
+CSET dcm_clkgen_clkfx_multiply=4
+CSET dcm_clkgen_clkfxdv_divide=2
+CSET dcm_clkgen_clkin_period=10.000
+CSET dcm_clkgen_notes=None
+CSET dcm_clkgen_spread_spectrum=NONE
+CSET dcm_clkgen_startup_wait=false
+CSET dcm_clkin_divide_by_2=false
+CSET dcm_clkin_period=20.000
+CSET dcm_clkout_phase_shift=NONE
+CSET dcm_deskew_adjust=SYSTEM_SYNCHRONOUS
+CSET dcm_notes=None
+CSET dcm_phase_shift=0
+CSET dcm_pll_cascade=NONE
+CSET dcm_startup_wait=false
+CSET den_port=DEN
+CSET din_port=DIN
+CSET dout_port=DOUT
+CSET drdy_port=DRDY
+CSET dwe_port=DWE
+CSET feedback_source=FDBK_AUTO
+CSET in_freq_units=Units_MHz
+CSET in_jitter_units=Units_UI
+CSET input_clk_stopped_port=INPUT_CLK_STOPPED
+CSET jitter_options=UI
+CSET jitter_sel=No_Jitter
+CSET locked_port=LOCKED
+CSET mmcm_bandwidth=OPTIMIZED
+CSET mmcm_clkfbout_mult_f=4.000
+CSET mmcm_clkfbout_phase=0.000
+CSET mmcm_clkfbout_use_fine_ps=false
+CSET mmcm_clkin1_period=10.000
+CSET mmcm_clkin2_period=10.000
+CSET mmcm_clkout0_divide_f=4.000
+CSET mmcm_clkout0_duty_cycle=0.500
+CSET mmcm_clkout0_phase=0.000
+CSET mmcm_clkout0_use_fine_ps=false
+CSET mmcm_clkout1_divide=1
+CSET mmcm_clkout1_duty_cycle=0.500
+CSET mmcm_clkout1_phase=0.000
+CSET mmcm_clkout1_use_fine_ps=false
+CSET mmcm_clkout2_divide=1
+CSET mmcm_clkout2_duty_cycle=0.500
+CSET mmcm_clkout2_phase=0.000
+CSET mmcm_clkout2_use_fine_ps=false
+CSET mmcm_clkout3_divide=1
+CSET mmcm_clkout3_duty_cycle=0.500
+CSET mmcm_clkout3_phase=0.000
+CSET mmcm_clkout3_use_fine_ps=false
+CSET mmcm_clkout4_cascade=false
+CSET mmcm_clkout4_divide=1
+CSET mmcm_clkout4_duty_cycle=0.500
+CSET mmcm_clkout4_phase=0.000
+CSET mmcm_clkout4_use_fine_ps=false
+CSET mmcm_clkout5_divide=1
+CSET mmcm_clkout5_duty_cycle=0.500
+CSET mmcm_clkout5_phase=0.000
+CSET mmcm_clkout5_use_fine_ps=false
+CSET mmcm_clkout6_divide=1
+CSET mmcm_clkout6_duty_cycle=0.500
+CSET mmcm_clkout6_phase=0.000
+CSET mmcm_clkout6_use_fine_ps=false
+CSET mmcm_clock_hold=false
+CSET mmcm_compensation=ZHOLD
+CSET mmcm_divclk_divide=1
+CSET mmcm_notes=None
+CSET mmcm_ref_jitter1=0.010
+CSET mmcm_ref_jitter2=0.010
+CSET mmcm_startup_wait=false
+CSET num_out_clks=1
+CSET override_dcm=false
+CSET override_dcm_clkgen=false
+CSET override_mmcm=false
+CSET override_pll=false
+CSET platform=nt
+CSET pll_bandwidth=OPTIMIZED
+CSET pll_clk_feedback=CLKFBOUT
+CSET pll_clkfbout_mult=8
+CSET pll_clkfbout_phase=0.000
+CSET pll_clkin_period=20.0
+CSET pll_clkout0_divide=2
+CSET pll_clkout0_duty_cycle=0.500
+CSET pll_clkout0_phase=0.000
+CSET pll_clkout1_divide=10
+CSET pll_clkout1_duty_cycle=0.500
+CSET pll_clkout1_phase=0.000
+CSET pll_clkout2_divide=1
+CSET pll_clkout2_duty_cycle=0.500
+CSET pll_clkout2_phase=0.000
+CSET pll_clkout3_divide=1
+CSET pll_clkout3_duty_cycle=0.500
+CSET pll_clkout3_phase=0.000
+CSET pll_clkout4_divide=1
+CSET pll_clkout4_duty_cycle=0.500
+CSET pll_clkout4_phase=0.000
+CSET pll_clkout5_divide=1
+CSET pll_clkout5_duty_cycle=0.500
+CSET pll_clkout5_phase=0.000
+CSET pll_compensation=SYSTEM_SYNCHRONOUS
+CSET pll_divclk_divide=1
+CSET pll_notes=None
+CSET pll_ref_jitter=0.010
+CSET power_down_port=POWER_DOWN
+CSET prim_in_freq=50
+CSET prim_in_jitter=0.010
+CSET prim_source=No_buffer
+CSET primary_port=CLK_IN1
+CSET primitive=MMCM
+CSET primtype_sel=DCM_SP
+CSET psclk_port=PSCLK
+CSET psdone_port=PSDONE
+CSET psen_port=PSEN
+CSET psincdec_port=PSINCDEC
+CSET relative_inclk=REL_PRIMARY
+CSET reset_port=RESET
+CSET secondary_in_freq=100.000
+CSET secondary_in_jitter=0.010
+CSET secondary_port=CLK_IN2
+CSET secondary_source=Single_ended_clock_capable_pin
+CSET ss_mod_freq=250
+CSET ss_mode=CENTER_HIGH
+CSET status_port=STATUS
+CSET summary_strings=empty
+CSET use_clk_valid=true
+CSET use_clkfb_stopped=false
+CSET use_dyn_phase_shift=false
+CSET use_dyn_reconfig=false
+CSET use_freeze=false
+CSET use_freq_synth=true
+CSET use_inclk_stopped=true
+CSET use_inclk_switchover=false
+CSET use_locked=false
+CSET use_max_i_jitter=false
+CSET use_min_o_jitter=false
+CSET use_min_power=false
+CSET use_phase_alignment=true
+CSET use_power_down=false
+CSET use_reset=true
+CSET use_spread_spectrum=false
+CSET use_spread_spectrum_1=false
+CSET use_status=false
+# END Parameters
+# BEGIN Extra information
+MISC pkg_timestamp=2012-05-10T12:44:55Z
+# END Extra information
+GENERATE
+# CRC: d6857c2d
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.xdc b/novena/src/rtl/ipcore/clkmgr_dcm.xdc
new file mode 100644
index 0000000..9ecc102
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.xdc
@@ -0,0 +1,67 @@
+# file: clkmgr_dcm.xdc
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# Input clock periods. These duplicate the values entered for the
+#  input clocks. You can use these to time your system
+#----------------------------------------------------------------
+create_clock -name CLK_IN1 -period 20.0 [get_ports CLK_IN1]
+set_propagated_clock CLK_IN1
+set_input_jitter CLK_IN1 0.2
+
+set_false_path -from [get_ports "RESET"]
+
+# Derived clock periods. These are commented out because they are 
+#   automatically propogated by the tools
+# However, if you'd like to use them for module level testing, you 
+#   can copy them into your module level timing checks
+#-----------------------------------------------------------------
+
+#-----------------------------------------------------------------
+
+#-----------------------------------------------------------------
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm.xise b/novena/src/rtl/ipcore/clkmgr_dcm.xise
new file mode 100644
index 0000000..7369d3b
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm.xise
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+
+  <header>
+    <!-- ISE source project file created by Project Navigator.             -->
+    <!--                                                                   -->
+    <!-- This file contains project source information including a list of -->
+    <!-- project source files, project and process properties.  This file, -->
+    <!-- along with the project source files, is sufficient to open and    -->
+    <!-- implement in ISE Project Navigator.                               -->
+    <!--                                                                   -->
+    <!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved. -->
+  </header>
+
+  <version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
+
+  <files>
+    <file xil_pn:name="clkmgr_dcm.ucf" xil_pn:type="FILE_UCF">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+    <file xil_pn:name="clkmgr_dcm.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="1"/>
+      <association xil_pn:name="PostMapSimulation" xil_pn:seqID="3"/>
+      <association xil_pn:name="PostRouteSimulation" xil_pn:seqID="3"/>
+      <association xil_pn:name="PostTranslateSimulation" xil_pn:seqID="3"/>
+    </file>
+  </files>
+
+  <properties>
+    <property xil_pn:name="Auto Implementation Top" xil_pn:value="false" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device" xil_pn:value="xc6slx45" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Stop View" xil_pn:value="PreSynthesis" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top" xil_pn:value="Module|clkmgr_dcm" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top File" xil_pn:value="clkmgr_dcm.v" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/clkmgr_dcm" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Package" xil_pn:value="csg324" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Project Generator" xil_pn:value="CoreGen" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Speed Grade" xil_pn:value="-3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
+    <!--                                                                                  -->
+    <!-- The following properties are for internal use only. These should not be modified.-->
+    <!--                                                                                  -->
+    <property xil_pn:name="PROP_DesignName" xil_pn:value="clkmgr_dcm" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2015-02-01T08:50:04" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="67BEB73269CA45ADBC7997434CEC13CB" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
+  </properties>
+
+  <bindings>
+    <binding xil_pn:location="/clkmgr_dcm" xil_pn:name="clkmgr_dcm.ucf"/>
+  </bindings>
+
+  <libraries/>
+
+  <autoManagedFiles>
+    <!-- The following files are identified by `include statements in verilog -->
+    <!-- source files and are automatically managed by Project Navigator.     -->
+    <!--                                                                      -->
+    <!-- Do not hand-edit this section, as it will be overwritten when the    -->
+    <!-- project is analyzed based on files automatically identified as       -->
+    <!-- include files.                                                       -->
+  </autoManagedFiles>
+
+</project>
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/clk_wiz_v3_6_readme.txt b/novena/src/rtl/ipcore/clkmgr_dcm/clk_wiz_v3_6_readme.txt
new file mode 100644
index 0000000..91dcdd0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/clk_wiz_v3_6_readme.txt
@@ -0,0 +1,184 @@
+CHANGE LOG for LogiCORE Clocking Wizard V3.6 
+
+                    Release Date: June 19, 2013
+--------------------------------------------------------------------------------
+
+Table of Contents
+
+1. INTRODUCTION 
+2. DEVICE SUPPORT    
+3. NEW FEATURE HISTORY   
+4. RESOLVED ISSUES 
+5. KNOWN ISSUES & LIMITATIONS 
+6. TECHNICAL SUPPORT & FEEDBACK
+7. CORE RELEASE HISTORY 
+8. LEGAL DISCLAIMER 
+
+--------------------------------------------------------------------------------
+
+
+1. INTRODUCTION
+
+For installation instructions for this release, please go to:
+
+  http://www.xilinx.com/ipcenter/coregen/ip_update_install_instructions.htm
+
+For system requirements:
+
+   http://www.xilinx.com/ipcenter/coregen/ip_update_system_requirements.htm
+
+This file contains release notes for the Xilinx LogiCORE IP Clocking Wizard v3.6
+solution. For the latest core updates, see the product page at:
+
+   http://www.xilinx.com/products/design_resources/conn_central/solution_kits/wizards/
+
+................................................................................
+
+2. DEVICE SUPPORT
+
+
+  2.1 ISE 
+   
+  
+  The following device families are supported by the core for this release.
+  
+  All 7 Series devices
+
+
+  Zynq-7000 devices
+    Zynq-7000
+    Defense Grade Zynq-7000Q (XQ)
+
+
+  All Virtex-6 devices
+  
+  
+  All Spartan-6 devices
+  
+  
+................................................................................
+
+3. NEW FEATURE HISTORY 
+
+
+  3.1 ISE 
+  
+    - Spread Spectrum support for 7 series MMCME2
+
+    - ISE 14.2 software support
+
+................................................................................
+
+4. RESOLVED ISSUES
+
+
+  4.1 ISE 
+  
+      Resolved issue with example design becoming core top in planAhead
+
+      Resolved issue with Virtex6 MMCM instantiation for VHDL project
+      Please refer to AR 50719 - http://www.xilinx.com/support/answers/50719.htm
+
+................................................................................
+
+5. KNOWN ISSUES & LIMITATIONS
+
+
+  5.1 ISE 
+  
+  
+  The most recent information, including known issues, workarounds, and
+  resolutions for this version is provided in the IP Release Notes Guide
+  located at
+
+   www.xilinx.com/support/documentation/user_guides/xtp025.pdf
+  
+  
+................................................................................
+
+6. TECHNICAL SUPPORT & FEEDBACK
+
+
+To obtain technical support, create a WebCase at www.xilinx.com/support.
+Questions are routed to a team with expertise using this product.
+
+Xilinx provides technical support for use of this product when used
+according to the guidelines described in the core documentation, and
+cannot guarantee timing, functionality, or support of this product for
+designs that do not follow specified guidelines.
+
+
+................................................................................
+
+7. CORE RELEASE HISTORY
+
+
+Date        By            Version      Description
+================================================================================
+06/19/2013  Xilinx, Inc.  3.6(Rev3)    ISE 14.6 support
+10/16/2012  Xilinx, Inc.  3.6(Rev2)    ISE 14.3 support
+07/25/2012  Xilinx, Inc.  3.6          ISE 14.2 support
+04/24/2012  Xilinx, Inc.  3.5          ISE 14.1 support
+01/18/2012  Xilinx, Inc.  3.3          ISE 13.4 support
+06/22/2011  Xilinx, Inc.  3.2          ISE 13.2 support
+03/01/2011  Xilinx, Inc.  3.1          ISE 13.1 support
+12/14/2010  Xilinx, Inc.  1.8          ISE 12.4 support
+09/21/2010  Xilinx, Inc.  1.7          ISE 12.3 support
+07/23/2010  Xilinx, Inc.  1.6          ISE 12.2 support
+04/19/2010  Xilinx, Inc.  1.5          ISE 12.1 support
+12/02/2009  Xilinx, Inc.  1.4          ISE 11.4 support
+09/16/2009  Xilinx, Inc.  1.3          ISE 11.3 support
+06/24/2009  Xilinx, Inc.  1.2          ISE 11.2 support
+04/24/2009  Xilinx, Inc.  1.1          Initial release; 11.1 support
+================================================================================
+                          
+................................................................................
+
+8. LEGAL DISCLAIMER
+
+(c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
+
+This file contains confidential and proprietary information
+of Xilinx, Inc. and is protected under U.S. and
+international copyright and other intellectual property
+laws.
+
+DISCLAIMER
+This disclaimer is not a license and does not grant any
+rights to the materials distributed herewith. Except as
+otherwise provided in a valid license issued to you by
+Xilinx, and to the maximum extent permitted by applicable
+law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+(2) Xilinx shall not be liable (whether in contract or tort,
+including negligence, or under any other theory of
+liability) for any loss or damage of any kind or nature
+related to, arising under or in connection with these
+materials, including for any direct, or any indirect,
+special, incidental, or consequential loss or damage
+(including loss of data, profits, goodwill, or any type of
+loss or damage suffered as a result of any action brought
+by a third party) even if such damage or loss was
+reasonably foreseeable or Xilinx had been advised of the
+possibility of the same.
+
+CRITICAL APPLICATIONS
+Xilinx products are not designed or intended to be fail-
+safe, or for use in any application requiring fail-safe
+performance, such as life-support or safety devices or
+systems, Class III medical devices, nuclear facilities,
+applications related to the deployment of airbags, or any
+other applications that could lead to death, personal
+injury, or severe property or environmental damage
+(individually and collectively, "Critical
+Applications"). Customer assumes the sole risk and
+liability of any use of Xilinx products in Critical
+Applications, subject only to applicable laws and
+regulations governing limitations on product liability.
+
+THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+PART OF THIS FILE AT ALL TIMES.
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_readme.txt b/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_readme.txt
new file mode 100644
index 0000000..91dcdd0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_readme.txt
@@ -0,0 +1,184 @@
+CHANGE LOG for LogiCORE Clocking Wizard V3.6 
+
+                    Release Date: June 19, 2013
+--------------------------------------------------------------------------------
+
+Table of Contents
+
+1. INTRODUCTION 
+2. DEVICE SUPPORT    
+3. NEW FEATURE HISTORY   
+4. RESOLVED ISSUES 
+5. KNOWN ISSUES & LIMITATIONS 
+6. TECHNICAL SUPPORT & FEEDBACK
+7. CORE RELEASE HISTORY 
+8. LEGAL DISCLAIMER 
+
+--------------------------------------------------------------------------------
+
+
+1. INTRODUCTION
+
+For installation instructions for this release, please go to:
+
+  http://www.xilinx.com/ipcenter/coregen/ip_update_install_instructions.htm
+
+For system requirements:
+
+   http://www.xilinx.com/ipcenter/coregen/ip_update_system_requirements.htm
+
+This file contains release notes for the Xilinx LogiCORE IP Clocking Wizard v3.6
+solution. For the latest core updates, see the product page at:
+
+   http://www.xilinx.com/products/design_resources/conn_central/solution_kits/wizards/
+
+................................................................................
+
+2. DEVICE SUPPORT
+
+
+  2.1 ISE 
+   
+  
+  The following device families are supported by the core for this release.
+  
+  All 7 Series devices
+
+
+  Zynq-7000 devices
+    Zynq-7000
+    Defense Grade Zynq-7000Q (XQ)
+
+
+  All Virtex-6 devices
+  
+  
+  All Spartan-6 devices
+  
+  
+................................................................................
+
+3. NEW FEATURE HISTORY 
+
+
+  3.1 ISE 
+  
+    - Spread Spectrum support for 7 series MMCME2
+
+    - ISE 14.2 software support
+
+................................................................................
+
+4. RESOLVED ISSUES
+
+
+  4.1 ISE 
+  
+      Resolved issue with example design becoming core top in planAhead
+
+      Resolved issue with Virtex6 MMCM instantiation for VHDL project
+      Please refer to AR 50719 - http://www.xilinx.com/support/answers/50719.htm
+
+................................................................................
+
+5. KNOWN ISSUES & LIMITATIONS
+
+
+  5.1 ISE 
+  
+  
+  The most recent information, including known issues, workarounds, and
+  resolutions for this version is provided in the IP Release Notes Guide
+  located at
+
+   www.xilinx.com/support/documentation/user_guides/xtp025.pdf
+  
+  
+................................................................................
+
+6. TECHNICAL SUPPORT & FEEDBACK
+
+
+To obtain technical support, create a WebCase at www.xilinx.com/support.
+Questions are routed to a team with expertise using this product.
+
+Xilinx provides technical support for use of this product when used
+according to the guidelines described in the core documentation, and
+cannot guarantee timing, functionality, or support of this product for
+designs that do not follow specified guidelines.
+
+
+................................................................................
+
+7. CORE RELEASE HISTORY
+
+
+Date        By            Version      Description
+================================================================================
+06/19/2013  Xilinx, Inc.  3.6(Rev3)    ISE 14.6 support
+10/16/2012  Xilinx, Inc.  3.6(Rev2)    ISE 14.3 support
+07/25/2012  Xilinx, Inc.  3.6          ISE 14.2 support
+04/24/2012  Xilinx, Inc.  3.5          ISE 14.1 support
+01/18/2012  Xilinx, Inc.  3.3          ISE 13.4 support
+06/22/2011  Xilinx, Inc.  3.2          ISE 13.2 support
+03/01/2011  Xilinx, Inc.  3.1          ISE 13.1 support
+12/14/2010  Xilinx, Inc.  1.8          ISE 12.4 support
+09/21/2010  Xilinx, Inc.  1.7          ISE 12.3 support
+07/23/2010  Xilinx, Inc.  1.6          ISE 12.2 support
+04/19/2010  Xilinx, Inc.  1.5          ISE 12.1 support
+12/02/2009  Xilinx, Inc.  1.4          ISE 11.4 support
+09/16/2009  Xilinx, Inc.  1.3          ISE 11.3 support
+06/24/2009  Xilinx, Inc.  1.2          ISE 11.2 support
+04/24/2009  Xilinx, Inc.  1.1          Initial release; 11.1 support
+================================================================================
+                          
+................................................................................
+
+8. LEGAL DISCLAIMER
+
+(c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
+
+This file contains confidential and proprietary information
+of Xilinx, Inc. and is protected under U.S. and
+international copyright and other intellectual property
+laws.
+
+DISCLAIMER
+This disclaimer is not a license and does not grant any
+rights to the materials distributed herewith. Except as
+otherwise provided in a valid license issued to you by
+Xilinx, and to the maximum extent permitted by applicable
+law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+(2) Xilinx shall not be liable (whether in contract or tort,
+including negligence, or under any other theory of
+liability) for any loss or damage of any kind or nature
+related to, arising under or in connection with these
+materials, including for any direct, or any indirect,
+special, incidental, or consequential loss or damage
+(including loss of data, profits, goodwill, or any type of
+loss or damage suffered as a result of any action brought
+by a third party) even if such damage or loss was
+reasonably foreseeable or Xilinx had been advised of the
+possibility of the same.
+
+CRITICAL APPLICATIONS
+Xilinx products are not designed or intended to be fail-
+safe, or for use in any application requiring fail-safe
+performance, such as life-support or safety devices or
+systems, Class III medical devices, nuclear facilities,
+applications related to the deployment of airbags, or any
+other applications that could lead to death, personal
+injury, or severe property or environmental damage
+(individually and collectively, "Critical
+Applications"). Customer assumes the sole risk and
+liability of any use of Xilinx products in Critical
+Applications, subject only to applicable laws and
+regulations governing limitations on product liability.
+
+THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+PART OF THIS FILE AT ALL TIMES.
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_vinfo.html b/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_vinfo.html
new file mode 100644
index 0000000..d6deba0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/doc/clk_wiz_v3_6_vinfo.html
@@ -0,0 +1,195 @@
+<HTML>
+<HEAD>
+<TITLE>clk_wiz_v3_6_vinfo</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/plain;CHARSET=iso-8859-1">
+</HEAD>
+<BODY>
+<PRE><FONT face="Arial, Helvetica, sans-serif" size="-1">
+CHANGE LOG for LogiCORE Clocking Wizard V3.6 
+
+                    Release Date: June 19, 2013
+--------------------------------------------------------------------------------
+
+Table of Contents
+
+1. INTRODUCTION 
+2. DEVICE SUPPORT    
+3. NEW FEATURE HISTORY   
+4. RESOLVED ISSUES 
+5. KNOWN ISSUES & LIMITATIONS 
+6. TECHNICAL SUPPORT & FEEDBACK
+7. CORE RELEASE HISTORY 
+8. LEGAL DISCLAIMER 
+
+--------------------------------------------------------------------------------
+
+
+1. INTRODUCTION
+
+For installation instructions for this release, please go to:
+
+  <A HREF="http://www.xilinx.com/ipcenter/coregen/ip_update_install_instructions.htm">www.xilinx.com/ipcenter/coregen/ip_update_install_instructions.htm</A>
+
+For system requirements:
+
+   <A HREF="http://www.xilinx.com/ipcenter/coregen/ip_update_system_requirements.htm">www.xilinx.com/ipcenter/coregen/ip_update_system_requirements.htm</A>
+
+This file contains release notes for the Xilinx LogiCORE IP Clocking Wizard v3.6
+solution. For the latest core updates, see the product page at:
+
+   <A HREF="http://www.xilinx.com/products/design_resources/conn_central/solution_kits/wizards/">www.xilinx.com/products/design_resources/conn_central/solution_kits/wizards/</A>
+
+................................................................................
+
+2. DEVICE SUPPORT
+
+
+  2.1 ISE 
+   
+  
+  The following device families are supported by the core for this release.
+  
+  All 7 Series devices
+
+
+  Zynq-7000 devices
+    Zynq-7000
+    Defense Grade Zynq-7000Q (XQ)
+
+
+  All Virtex-6 devices
+  
+  
+  All Spartan-6 devices
+  
+  
+................................................................................
+
+3. NEW FEATURE HISTORY 
+
+
+  3.1 ISE 
+  
+    - Spread Spectrum support for 7 series MMCME2
+
+    - ISE 14.2 software support
+
+................................................................................
+
+4. RESOLVED ISSUES
+
+
+  4.1 ISE 
+  
+      Resolved issue with example design becoming core top in planAhead
+
+      Resolved issue with Virtex6 MMCM instantiation for VHDL project
+      Please refer to AR 50719 - <A HREF="http://www.xilinx.com/support/answers/50719.htm">www.xilinx.com/support/answers/50719.htm</A>
+
+................................................................................
+
+5. KNOWN ISSUES & LIMITATIONS
+
+
+  5.1 ISE 
+  
+  
+  The most recent information, including known issues, workarounds, and
+  resolutions for this version is provided in the IP Release Notes Guide
+  located at
+
+   <A HREF="http://www.xilinx.com/support/documentation/user_guides/xtp025.pdf">www.xilinx.com/support/documentation/user_guides/xtp025.pdf</A>
+  
+  
+................................................................................
+
+6. TECHNICAL SUPPORT & FEEDBACK
+
+
+To obtain technical support, create a WebCase at <A HREF="http://www.xilinx.com/support.">www.xilinx.com/support.</A>
+Questions are routed to a team with expertise using this product.
+
+Xilinx provides technical support for use of this product when used
+according to the guidelines described in the core documentation, and
+cannot guarantee timing, functionality, or support of this product for
+designs that do not follow specified guidelines.
+
+
+................................................................................
+
+7. CORE RELEASE HISTORY
+
+
+Date        By            Version      Description
+================================================================================
+06/19/2013  Xilinx, Inc.  3.6(Rev3)    ISE 14.6 support
+10/16/2012  Xilinx, Inc.  3.6(Rev2)    ISE 14.3 support
+07/25/2012  Xilinx, Inc.  3.6          ISE 14.2 support
+04/24/2012  Xilinx, Inc.  3.5          ISE 14.1 support
+01/18/2012  Xilinx, Inc.  3.3          ISE 13.4 support
+06/22/2011  Xilinx, Inc.  3.2          ISE 13.2 support
+03/01/2011  Xilinx, Inc.  3.1          ISE 13.1 support
+12/14/2010  Xilinx, Inc.  1.8          ISE 12.4 support
+09/21/2010  Xilinx, Inc.  1.7          ISE 12.3 support
+07/23/2010  Xilinx, Inc.  1.6          ISE 12.2 support
+04/19/2010  Xilinx, Inc.  1.5          ISE 12.1 support
+12/02/2009  Xilinx, Inc.  1.4          ISE 11.4 support
+09/16/2009  Xilinx, Inc.  1.3          ISE 11.3 support
+06/24/2009  Xilinx, Inc.  1.2          ISE 11.2 support
+04/24/2009  Xilinx, Inc.  1.1          Initial release; 11.1 support
+================================================================================
+                          
+................................................................................
+
+8. LEGAL DISCLAIMER
+
+(c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
+
+This file contains confidential and proprietary information
+of Xilinx, Inc. and is protected under U.S. and
+international copyright and other intellectual property
+laws.
+
+DISCLAIMER
+This disclaimer is not a license and does not grant any
+rights to the materials distributed herewith. Except as
+otherwise provided in a valid license issued to you by
+Xilinx, and to the maximum extent permitted by applicable
+law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+(2) Xilinx shall not be liable (whether in contract or tort,
+including negligence, or under any other theory of
+liability) for any loss or damage of any kind or nature
+related to, arising under or in connection with these
+materials, including for any direct, or any indirect,
+special, incidental, or consequential loss or damage
+(including loss of data, profits, goodwill, or any type of
+loss or damage suffered as a result of any action brought
+by a third party) even if such damage or loss was
+reasonably foreseeable or Xilinx had been advised of the
+possibility of the same.
+
+CRITICAL APPLICATIONS
+Xilinx products are not designed or intended to be fail-
+safe, or for use in any application requiring fail-safe
+performance, such as life-support or safety devices or
+systems, Class III medical devices, nuclear facilities,
+applications related to the deployment of airbags, or any
+other applications that could lead to death, personal
+injury, or severe property or environmental damage
+(individually and collectively, "Critical
+Applications"). Customer assumes the sole risk and
+liability of any use of Xilinx products in Critical
+Applications, subject only to applicable laws and
+regulations governing limitations on product liability.
+
+THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+PART OF THIS FILE AT ALL TIMES.
+
+</FONT>
+</PRE>
+</BODY>
+</HTML>
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/doc/pg065_clk_wiz.pdf b/novena/src/rtl/ipcore/clkmgr_dcm/doc/pg065_clk_wiz.pdf
new file mode 100644
index 0000000..a7daa60
Binary files /dev/null and b/novena/src/rtl/ipcore/clkmgr_dcm/doc/pg065_clk_wiz.pdf differ
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.ucf b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.ucf
new file mode 100644
index 0000000..dffb528
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.ucf
@@ -0,0 +1,60 @@
+# file: clkmgr_dcm_exdes.ucf
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# Input clock periods. These duplicate the values entered for the
+#  input clocks. You can use these to time your system
+#----------------------------------------------------------------
+NET "CLK_IN1" TNM_NET = "CLK_IN1";
+TIMESPEC "TS_CLK_IN1" = PERIOD "CLK_IN1" 20.0 ns HIGH 50% INPUT_JITTER 200.0ps;
+
+
+# FALSE PATH constraints 
+PIN "COUNTER_RESET" TIG;
+PIN "RESET" TIG;
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.v b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.v
new file mode 100644
index 0000000..10627b3
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.v
@@ -0,0 +1,164 @@
+// file: clkmgr_dcm_exdes.v
+// 
+// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+// 
+// This file contains confidential and proprietary information
+// of Xilinx, Inc. and is protected under U.S. and
+// international copyright and other intellectual property
+// laws.
+// 
+// DISCLAIMER
+// This disclaimer is not a license and does not grant any
+// rights to the materials distributed herewith. Except as
+// otherwise provided in a valid license issued to you by
+// Xilinx, and to the maximum extent permitted by applicable
+// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+// (2) Xilinx shall not be liable (whether in contract or tort,
+// including negligence, or under any other theory of
+// liability) for any loss or damage of any kind or nature
+// related to, arising under or in connection with these
+// materials, including for any direct, or any indirect,
+// special, incidental, or consequential loss or damage
+// (including loss of data, profits, goodwill, or any type of
+// loss or damage suffered as a result of any action brought
+// by a third party) even if such damage or loss was
+// reasonably foreseeable or Xilinx had been advised of the
+// possibility of the same.
+// 
+// CRITICAL APPLICATIONS
+// Xilinx products are not designed or intended to be fail-
+// safe, or for use in any application requiring fail-safe
+// performance, such as life-support or safety devices or
+// systems, Class III medical devices, nuclear facilities,
+// applications related to the deployment of airbags, or any
+// other applications that could lead to death, personal
+// injury, or severe property or environmental damage
+// (individually and collectively, "Critical
+// Applications"). Customer assumes the sole risk and
+// liability of any use of Xilinx products in Critical
+// Applications, subject only to applicable laws and
+// regulations governing limitations on product liability.
+// 
+// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+// PART OF THIS FILE AT ALL TIMES.
+// 
+
+//----------------------------------------------------------------------------
+// Clocking wizard example design
+//----------------------------------------------------------------------------
+// This example design instantiates the created clocking network, where each
+//   output clock drives a counter. The high bit of each counter is ported.
+//----------------------------------------------------------------------------
+
+`timescale 1ps/1ps
+
+module clkmgr_dcm_exdes 
+ #( 
+  parameter TCQ = 100
+  )
+ (// Clock in ports
+  input         CLK_IN1,
+  // Reset that only drives logic in example design
+  input         COUNTER_RESET,
+  output [1:1]  CLK_OUT,
+  // High bits of counters driven by clocks
+  output        COUNT,
+  // Status and control signals
+  input         RESET,
+  output        INPUT_CLK_STOPPED,
+  output        CLK_VALID
+ );
+
+  // Parameters for the counters
+  //-------------------------------
+  // Counter width
+  localparam    C_W       = 16;
+  // Create reset for the counters
+  wire          reset_int = RESET || COUNTER_RESET;
+
+   reg rst_sync;
+   reg rst_sync_int;
+   reg rst_sync_int1;
+   reg rst_sync_int2;
+
+
+
+  // Declare the clocks and counter
+  wire           clk_int;
+  wire           clk_n;
+  wire           clk;
+  reg  [C_W-1:0] counter;
+
+  // Insert BUFGs on all input clocks that don't already have them
+  //--------------------------------------------------------------
+  BUFG clkin1_buf
+   (.O (clk_in1_buf),
+    .I (CLK_IN1));
+
+  // Instantiation of the clocking network
+  //--------------------------------------
+  clkmgr_dcm clknetwork
+   (// Clock in ports
+    .CLK_IN1            (clk_in1_buf),
+    // Clock out ports
+    .CLK_OUT1           (clk_int),
+    // Status and control signals
+    .RESET              (RESET),
+    .INPUT_CLK_STOPPED  (INPUT_CLK_STOPPED),
+    .CLK_VALID          (CLK_VALID));
+
+  assign clk_n = ~clk;
+
+  ODDR2 clkout_oddr
+   (.Q  (CLK_OUT[1]),
+    .C0 (clk),
+    .C1 (clk_n),
+    .CE (1'b1),
+    .D0 (1'b1),
+    .D1 (1'b0),
+    .R  (1'b0),
+    .S  (1'b0));
+
+  // Connect the output clocks to the design
+  //-----------------------------------------
+  assign clk = clk_int;
+
+
+  // Reset synchronizer
+  //-----------------------------------
+    always @(posedge reset_int or posedge clk) begin
+       if (reset_int) begin
+            rst_sync <= 1'b1;
+            rst_sync_int <= 1'b1;
+            rst_sync_int1 <= 1'b1;
+            rst_sync_int2 <= 1'b1;
+       end
+       else begin
+            rst_sync <= 1'b0;
+            rst_sync_int <= rst_sync;     
+            rst_sync_int1 <= rst_sync_int; 
+            rst_sync_int2 <= rst_sync_int1;
+       end
+    end
+
+
+  // Output clock sampling
+  //-----------------------------------
+  always @(posedge clk or posedge rst_sync_int2) begin
+    if (rst_sync_int2) begin
+      counter <= #TCQ { C_W { 1'b 0 } };
+    end else begin
+      counter <= #TCQ counter + 1'b 1;
+    end
+  end
+
+  // alias the high bit to the output
+  assign COUNT = counter[C_W-1];
+
+
+
+endmodule
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.xdc b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.xdc
new file mode 100644
index 0000000..787023d
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/example_design/clkmgr_dcm_exdes.xdc
@@ -0,0 +1,69 @@
+# file: clkmgr_dcm_exdes.xdc
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# Input clock periods. These duplicate the values entered for the
+#  input clocks. You can use these to time your system
+#----------------------------------------------------------------
+create_clock -name CLK_IN1 -period 20.0 [get_ports CLK_IN1]
+set_propagated_clock CLK_IN1
+set_input_jitter CLK_IN1 0.2
+
+# FALSE PATH constraint added on COUNTER_RESET 
+set_false_path -from [get_ports "COUNTER_RESET"]
+set_false_path -from [get_ports "RESET"]
+
+# Derived clock periods. These are commented out because they are 
+#   automatically propogated by the tools
+# However, if you'd like to use them for module level testing, you 
+#   can copy them into your module level timing checks
+#-----------------------------------------------------------------
+
+#-----------------------------------------------------------------
+
+#-----------------------------------------------------------------
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.bat b/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.bat
new file mode 100644
index 0000000..3d313d5
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.bat
@@ -0,0 +1,90 @@
+REM file: implement.bat
+REM 
+REM (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM 
+REM This file contains confidential and proprietary information
+REM of Xilinx, Inc. and is protected under U.S. and
+REM international copyright and other intellectual property
+REM laws.
+REM 
+REM DISCLAIMER
+REM This disclaimer is not a license and does not grant any
+REM rights to the materials distributed herewith. Except as
+REM otherwise provided in a valid license issued to you by
+REM Xilinx, and to the maximum extent permitted by applicable
+REM law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM (2) Xilinx shall not be liable (whether in contract or tort,
+REM including negligence, or under any other theory of
+REM liability) for any loss or damage of any kind or nature
+REM related to, arising under or in connection with these
+REM materials, including for any direct, or any indirect,
+REM special, incidental, or consequential loss or damage
+REM (including loss of data, profits, goodwill, or any type of
+REM loss or damage suffered as a result of any action brought
+REM by a third party) even if such damage or loss was
+REM reasonably foreseeable or Xilinx had been advised of the
+REM possibility of the same.
+REM 
+REM CRITICAL APPLICATIONS
+REM Xilinx products are not designed or intended to be fail-
+REM safe, or for use in any application requiring fail-safe
+REM performance, such as life-support or safety devices or
+REM systems, Class III medical devices, nuclear facilities,
+REM applications related to the deployment of airbags, or any
+REM other applications that could lead to death, personal
+REM injury, or severe property or environmental damage
+REM (individually and collectively, "Critical
+REM Applications"). Customer assumes the sole risk and
+REM liability of any use of Xilinx products in Critical
+REM Applications, subject only to applicable laws and
+REM regulations governing limitations on product liability.
+REM 
+REM THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM PART OF THIS FILE AT ALL TIMES.
+REM 
+
+REM -----------------------------------------------------------------------------
+REM  Script to synthesize and implement the RTL provided for the clocking wizard
+REM -----------------------------------------------------------------------------
+
+REM Clean up the results directory
+rmdir /S /Q results
+mkdir results
+
+REM Copy unisim_comp.v file to results directory
+copy %XILINX%\verilog\src\iSE\unisim_comp.v .\results\
+
+REM Synthesize the Verilog Wrapper Files
+echo 'Synthesizing Clocking Wizard design with XST'
+xst -ifn xst.scr
+move clkmgr_dcm_exdes.ngc results\
+
+REM  Copy the constraints files generated by Coregen
+echo 'Copying files from constraints directory to results directory'
+copy ..\example_design\clkmgr_dcm_exdes.ucf results\
+
+cd results
+
+echo 'Running ngdbuild'
+ngdbuild -uc clkmgr_dcm_exdes.ucf clkmgr_dcm_exdes
+
+echo 'Running map'
+map -timing -pr b clkmgr_dcm_exdes -o mapped.ncd
+
+echo 'Running par'
+par -w mapped.ncd routed mapped.pcf
+
+echo 'Running trce'
+trce -e 10 routed -o routed mapped.pcf
+
+echo 'Running design through bitgen'
+bitgen -w routed
+
+echo 'Running netgen to create gate level model for the clocking wizard example design'
+netgen -ofmt verilog -sim -sdf_anno false -tm clkmgr_dcm_exdes -w routed.ncd routed.v
+cd ..
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.sh b/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.sh
new file mode 100644
index 0000000..2c64bee
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/implement.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# file: implement.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+#-----------------------------------------------------------------------------
+# Script to synthesize and implement the RTL provided for the clocking wizard
+#-----------------------------------------------------------------------------
+
+# Clean up the results directory
+rm -rf results
+mkdir results
+
+# Copy unisim_comp.v file to results directory
+cp $XILINX/verilog/src/iSE/unisim_comp.v ./results/
+
+# Synthesize the Verilog Wrapper Files
+echo 'Synthesizing Clocking Wizard design with XST'
+xst -ifn xst.scr
+mv clkmgr_dcm_exdes.ngc results/
+
+#  Copy the constraints files generated by Coregen
+echo 'Copying files from constraints directory to results directory'
+cp ../example_design/clkmgr_dcm_exdes.ucf results/
+
+cd results
+
+echo 'Running ngdbuild'
+ngdbuild -uc clkmgr_dcm_exdes.ucf clkmgr_dcm_exdes
+
+echo 'Running map'
+map -timing clkmgr_dcm_exdes -o mapped.ncd
+
+echo 'Running par'
+par -w mapped.ncd routed mapped.pcf
+
+echo 'Running trce'
+trce -e 10 routed -o routed mapped.pcf
+
+echo 'Running design through bitgen'
+bitgen -w routed
+
+echo 'Running netgen to create gate level model for the clocking wizard example design'
+netgen -ofmt verilog -sim -sdf_anno false -tm clkmgr_dcm_exdes -w routed.ncd routed.v
+
+cd ..
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.bat b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.bat
new file mode 100644
index 0000000..9782028
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.bat
@@ -0,0 +1,58 @@
+REM file: planAhead_ise.bat
+REM 
+REM (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM 
+REM This file contains confidential and proprietary information
+REM of Xilinx, Inc. and is protected under U.S. and
+REM international copyright and other intellectual property
+REM laws.
+REM 
+REM DISCLAIMER
+REM This disclaimer is not a license and does not grant any
+REM rights to the materials distributed herewith. Except as
+REM otherwise provided in a valid license issued to you by
+REM Xilinx, and to the maximum extent permitted by applicable
+REM law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM (2) Xilinx shall not be liable (whether in contract or tort,
+REM including negligence, or under any other theory of
+REM liability) for any loss or damage of any kind or nature
+REM related to, arising under or in connection with these
+REM materials, including for any direct, or any indirect,
+REM special, incidental, or consequential loss or damage
+REM (including loss of data, profits, goodwill, or any type of
+REM loss or damage suffered as a result of any action brought
+REM by a third party) even if such damage or loss was
+REM reasonably foreseeable or Xilinx had been advised of the
+REM possibility of the same.
+REM 
+REM CRITICAL APPLICATIONS
+REM Xilinx products are not designed or intended to be fail-
+REM safe, or for use in any application requiring fail-safe
+REM performance, such as life-support or safety devices or
+REM systems, Class III medical devices, nuclear facilities,
+REM applications related to the deployment of airbags, or any
+REM other applications that could lead to death, personal
+REM injury, or severe property or environmental damage
+REM (individually and collectively, "Critical
+REM Applications"). Customer assumes the sole risk and
+REM liability of any use of Xilinx products in Critical
+REM Applications, subject only to applicable laws and
+REM regulations governing limitations on product liability.
+REM 
+REM THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM PART OF THIS FILE AT ALL TIMES.
+REM 
+
+REM-----------------------------------------------------------------------------
+REM Script to synthesize and implement the RTL provided for the clocking wizard
+REM-----------------------------------------------------------------------------
+
+del \f results
+mkdir results
+cd results
+
+planAhead -mode batch -source ..\planAhead_ise.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.sh b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.sh
new file mode 100644
index 0000000..7f436b6
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# file: planAhead_ise.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+#-----------------------------------------------------------------------------
+# Script to synthesize and implement the RTL provided for the clocking wizard
+#-----------------------------------------------------------------------------
+
+rm -rf results
+mkdir results
+cd results
+
+planAhead -mode batch -source ../planAhead_ise.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.tcl
new file mode 100644
index 0000000..ab77638
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_ise.tcl
@@ -0,0 +1,78 @@
+# file: planAhead_ise.tcl
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+set projDir [file dirname [info script]]
+set projName clkmgr_dcm
+set topName clkmgr_dcm_exdes
+set device xc6slx45csg324-3
+
+create_project $projName $projDir/results/$projName -part $device
+
+set_property design_mode RTL [get_filesets sources_1]
+
+## Source files
+#set verilogSources [glob $srcDir/*.v]
+import_files -fileset [get_filesets sources_1] -force -norecurse ../../example_design/clkmgr_dcm_exdes.v
+import_files -fileset [get_filesets sources_1] -force -norecurse ../../../clkmgr_dcm.v
+
+
+#UCF file
+import_files -fileset [get_filesets constrs_1] -force -norecurse ../../example_design/clkmgr_dcm_exdes.ucf
+
+set_property top $topName [get_property srcset [current_run]]
+
+launch_runs -runs synth_1
+wait_on_run synth_1
+
+set_property add_step Bitgen [get_runs impl_1]
+launch_runs -runs impl_1
+wait_on_run impl_1
+
+
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.bat b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.bat
new file mode 100644
index 0000000..3e1e03b
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.bat
@@ -0,0 +1,58 @@
+REM file: planAhead_rdn.sh
+REM 
+REM (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM 
+REM This file contains confidential and proprietary information
+REM of Xilinx, Inc. and is protected under U.S. and
+REM international copyright and other intellectual property
+REM laws.
+REM 
+REM DISCLAIMER
+REM This disclaimer is not a license and does not grant any
+REM rights to the materials distributed herewith. Except as
+REM otherwise provided in a valid license issued to you by
+REM Xilinx, and to the maximum extent permitted by applicable
+REM law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM (2) Xilinx shall not be liable (whether in contract or tort,
+REM including negligence, or under any other theory of
+REM liability) for any loss or damage of any kind or nature
+REM related to, arising under or in connection with these
+REM materials, including for any direct, or any indirect,
+REM special, incidental, or consequential loss or damage
+REM (including loss of data, profits, goodwill, or any type of
+REM loss or damage suffered as a result of any action brought
+REM by a third party) even if such damage or loss was
+REM reasonably foreseeable or Xilinx had been advised of the
+REM possibility of the same.
+REM 
+REM CRITICAL APPLICATIONS
+REM Xilinx products are not designed or intended to be fail-
+REM safe, or for use in any application requiring fail-safe
+REM performance, such as life-support or safety devices or
+REM systems, Class III medical devices, nuclear facilities,
+REM applications related to the deployment of airbags, or any
+REM other applications that could lead to death, personal
+REM injury, or severe property or environmental damage
+REM (individually and collectively, "Critical
+REM Applications"). Customer assumes the sole risk and
+REM liability of any use of Xilinx products in Critical
+REM Applications, subject only to applicable laws and
+REM regulations governing limitations on product liability.
+REM 
+REM THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM PART OF THIS FILE AT ALL TIMES.
+REM 
+
+REM-----------------------------------------------------------------------------
+REM Script to synthesize and implement the RTL provided for the XADC wizard
+REM-----------------------------------------------------------------------------
+
+del \f results
+mkdir results
+cd results
+
+planAhead -mode batch -source ..\planAhead_rdn.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.sh b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.sh
new file mode 100644
index 0000000..a5adee8
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# file: planAhead_rdn.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+#-----------------------------------------------------------------------------
+# Script to synthesize and implement the RTL provided for the XADC wizard
+#-----------------------------------------------------------------------------
+rm -rf results
+mkdir results
+cd results
+planAhead -mode batch -source ../planAhead_rdn.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.tcl
new file mode 100644
index 0000000..e8c0fdf
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/planAhead_rdn.tcl
@@ -0,0 +1,69 @@
+# file : planAhead_rdn.tcl
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+set device xc6slx45csg324-3
+set projName clkmgr_dcm
+set design clkmgr_dcm
+set projDir [file dirname [info script]]
+create_project $projName $projDir/results/$projName -part $device -force
+set_property design_mode RTL [current_fileset -srcset]
+set top_module clkmgr_dcm_exdes
+set_property top clkmgr_dcm_exdes [get_property srcset [current_run]]
+add_files -norecurse {../../../clkmgr_dcm.v}
+add_files -norecurse {../../example_design/clkmgr_dcm_exdes.v}
+import_files -fileset [get_filesets constrs_1 ] -force -norecurse {../../example_design/clkmgr_dcm_exdes.xdc}
+synth_design
+opt_design 
+place_design 
+route_design 
+write_sdf -rename_top_module clkmgr_dcm_exdes -file routed.sdf 
+write_verilog -nolib -mode timesim -sdf_anno false -rename_top_module clkmgr_dcm_exdes -file routed.v
+report_timing -nworst 30 -path_type full -file routed.twr
+report_drc -file report.drc
+write_bitstream -bitgen_options {-g UnconstrainedPins:Allow} -file routed.bit
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.prj b/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.prj
new file mode 100644
index 0000000..cd0e0e6
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.prj
@@ -0,0 +1,2 @@
+verilog work ../../clkmgr_dcm.v
+verilog work ../example_design/clkmgr_dcm_exdes.v
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.scr b/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.scr
new file mode 100644
index 0000000..20d09f4
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/implement/xst.scr
@@ -0,0 +1,9 @@
+run
+-ifmt MIXED
+-top clkmgr_dcm_exdes
+-p xc6slx45-csg324-3
+-ifn xst.prj
+-ofn clkmgr_dcm_exdes
+-keep_hierarchy soft 
+-equivalent_register_removal no 
+-max_fanout 65535
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/clkmgr_dcm_tb.v b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/clkmgr_dcm_tb.v
new file mode 100644
index 0000000..ee24750
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/clkmgr_dcm_tb.v
@@ -0,0 +1,145 @@
+// file: clkmgr_dcm_tb.v
+// 
+// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+// 
+// This file contains confidential and proprietary information
+// of Xilinx, Inc. and is protected under U.S. and
+// international copyright and other intellectual property
+// laws.
+// 
+// DISCLAIMER
+// This disclaimer is not a license and does not grant any
+// rights to the materials distributed herewith. Except as
+// otherwise provided in a valid license issued to you by
+// Xilinx, and to the maximum extent permitted by applicable
+// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+// (2) Xilinx shall not be liable (whether in contract or tort,
+// including negligence, or under any other theory of
+// liability) for any loss or damage of any kind or nature
+// related to, arising under or in connection with these
+// materials, including for any direct, or any indirect,
+// special, incidental, or consequential loss or damage
+// (including loss of data, profits, goodwill, or any type of
+// loss or damage suffered as a result of any action brought
+// by a third party) even if such damage or loss was
+// reasonably foreseeable or Xilinx had been advised of the
+// possibility of the same.
+// 
+// CRITICAL APPLICATIONS
+// Xilinx products are not designed or intended to be fail-
+// safe, or for use in any application requiring fail-safe
+// performance, such as life-support or safety devices or
+// systems, Class III medical devices, nuclear facilities,
+// applications related to the deployment of airbags, or any
+// other applications that could lead to death, personal
+// injury, or severe property or environmental damage
+// (individually and collectively, "Critical
+// Applications"). Customer assumes the sole risk and
+// liability of any use of Xilinx products in Critical
+// Applications, subject only to applicable laws and
+// regulations governing limitations on product liability.
+// 
+// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+// PART OF THIS FILE AT ALL TIMES.
+// 
+
+//----------------------------------------------------------------------------
+// Clocking wizard demonstration testbench
+//----------------------------------------------------------------------------
+// This demonstration testbench instantiates the example design for the 
+//   clocking wizard. Input clocks are toggled, which cause the clocking
+//   network to lock and the counters to increment.
+//----------------------------------------------------------------------------
+
+`timescale 1ps/1ps
+
+`define wait_lock @(posedge CLK_VALID)
+
+module clkmgr_dcm_tb ();
+
+  // Clock to Q delay of 100ps
+  localparam  TCQ              = 100;
+
+
+  // timescale is 1ps/1ps
+  localparam  ONE_NS      = 1000;
+  localparam  PHASE_ERR_MARGIN   = 100; // 100ps
+  // how many cycles to run
+  localparam  COUNT_PHASE = 1024;
+  // we'll be using the period in many locations
+  localparam time PER1    = 20.0*ONE_NS;
+  localparam time PER1_1  = PER1/2;
+  localparam time PER1_2  = PER1 - PER1/2;
+
+  // Declare the input clock signals
+  reg         CLK_IN1     = 1;
+
+  // The high bit of the sampling counter
+  wire        COUNT;
+  // Status and control signals
+  reg         RESET      = 0;
+  wire        INPUT_CLK_STOPPED;
+  wire        CLK_VALID;
+  reg         COUNTER_RESET = 0;
+wire [1:1] CLK_OUT;
+//Freq Check using the M & D values setting and actual Frequency generated
+
+
+  // Input clock generation
+  //------------------------------------
+  always begin
+    CLK_IN1 = #PER1_1 ~CLK_IN1;
+    CLK_IN1 = #PER1_2 ~CLK_IN1;
+  end
+
+  // Test sequence
+  reg [15*8-1:0] test_phase = "";
+  initial begin
+    // Set up any display statements using time to be readable
+    $timeformat(-12, 2, "ps", 10);
+    COUNTER_RESET = 0;
+    test_phase = "reset";
+    RESET = 1;
+    #(PER1*6);
+    RESET = 0;
+    test_phase = "wait lock";
+    `wait_lock;
+    #(PER1*6);
+    COUNTER_RESET = 1;
+    #(PER1*20)
+    COUNTER_RESET = 0;
+
+    test_phase = "counting";
+    #(PER1*COUNT_PHASE);
+
+    $display("SIMULATION PASSED");
+    $display("SYSTEM_CLOCK_COUNTER : %0d\n",$time/PER1);
+    $finish;
+  end
+
+  // Instantiation of the example design containing the clock
+  //    network and sampling counters
+  //---------------------------------------------------------
+  clkmgr_dcm_exdes 
+  #(
+    .TCQ (TCQ)
+   ) dut
+   (// Clock in ports
+    .CLK_IN1            (CLK_IN1),
+    // Reset for logic in example design
+    .COUNTER_RESET      (COUNTER_RESET),
+    .CLK_OUT            (CLK_OUT),
+    // High bits of the counters
+    .COUNT              (COUNT),
+    // Status and control signals
+    .RESET              (RESET),
+    .INPUT_CLK_STOPPED  (INPUT_CLK_STOPPED),
+    .CLK_VALID          (CLK_VALID));
+
+// Freq Check 
+
+endmodule
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simcmds.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simcmds.tcl
new file mode 100644
index 0000000..e19ead8
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simcmds.tcl
@@ -0,0 +1,8 @@
+# file: simcmds.tcl
+
+# create the simulation script
+vcd dumpfile isim.vcd
+vcd dumpvars -m /clkmgr_dcm_tb -l 0
+wave add /
+run 50000ns
+quit
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.bat b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.bat
new file mode 100644
index 0000000..80904cb
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.bat
@@ -0,0 +1,59 @@
+REM file: simulate_isim.bat
+REM  
+REM  (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM  
+REM  This file contains confidential and proprietary information
+REM  of Xilinx, Inc. and is protected under U.S. and
+REM  international copyright and other intellectual property
+REM  laws.
+REM  
+REM  DISCLAIMER
+REM  This disclaimer is not a license and does not grant any
+REM  rights to the materials distributed herewith. Except as
+REM  otherwise provided in a valid license issued to you by
+REM  Xilinx, and to the maximum extent permitted by applicable
+REM  law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM  WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM  AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM  BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM  INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM  (2) Xilinx shall not be liable (whether in contract or tort,
+REM  including negligence, or under any other theory of
+REM  liability) for any loss or damage of any kind or nature
+REM  related to, arising under or in connection with these
+REM  materials, including for any direct, or any indirect,
+REM  special, incidental, or consequential loss or damage
+REM  (including loss of data, profits, goodwill, or any type of
+REM  loss or damage suffered as a result of any action brought
+REM  by a third party) even if such damage or loss was
+REM  reasonably foreseeable or Xilinx had been advised of the
+REM  possibility of the same.
+REM  
+REM  CRITICAL APPLICATIONS
+REM  Xilinx products are not designed or intended to be fail-
+REM  safe, or for use in any application requiring fail-safe
+REM  performance, such as life-support or safety devices or
+REM  systems, Class III medical devices, nuclear facilities,
+REM  applications related to the deployment of airbags, or any
+REM  other applications that could lead to death, personal
+REM  injury, or severe property or environmental damage
+REM  (individually and collectively, "Critical
+REM  Applications"). Customer assumes the sole risk and
+REM  liability of any use of Xilinx products in Critical
+REM  Applications, subject only to applicable laws and
+REM  regulations governing limitations on product liability.
+REM  
+REM  THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM  PART OF THIS FILE AT ALL TIMES.
+REM  
+
+vlogcomp -work work %XILINX%\verilog\src\glbl.v
+vlogcomp -work work ..\..\..\clkmgr_dcm.v
+vlogcomp -work work ..\..\example_design\clkmgr_dcm_exdes.v
+vlogcomp -work work ..\clkmgr_dcm_tb.v
+
+REM compile the project
+fuse work.clkmgr_dcm_tb work.glbl -L unisims_ver -o clkmgr_dcm_isim.exe
+
+REM run the simulation script
+.\clkmgr_dcm_isim.exe -gui -tclbatch simcmds.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.sh
new file mode 100644
index 0000000..9fb5029
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_isim.sh
@@ -0,0 +1,61 @@
+# file: simulate_isim.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# nt
+# create the project
+vlogcomp -work work ${XILINX}/verilog/src/glbl.v
+vlogcomp -work work ../../../clkmgr_dcm.v
+vlogcomp -work work ../../example_design/clkmgr_dcm_exdes.v
+vlogcomp -work work ../clkmgr_dcm_tb.v
+
+# compile the project
+fuse work.clkmgr_dcm_tb work.glbl -L unisims_ver -o clkmgr_dcm_isim.exe
+
+# run the simulation script
+./clkmgr_dcm_isim.exe -gui -tclbatch simcmds.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.bat b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.bat
new file mode 100644
index 0000000..7497cd9
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.bat
@@ -0,0 +1,61 @@
+REM file: simulate_mti.bat
+REM  
+REM  (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM  
+REM  This file contains confidential and proprietary information
+REM  of Xilinx, Inc. and is protected under U.S. and
+REM  international copyright and other intellectual property
+REM  laws.
+REM  
+REM  DISCLAIMER
+REM  This disclaimer is not a license and does not grant any
+REM  rights to the materials distributed herewith. Except as
+REM  otherwise provided in a valid license issued to you by
+REM  Xilinx, and to the maximum extent permitted by applicable
+REM  law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM  WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM  AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM  BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM  INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM  (2) Xilinx shall not be liable (whether in contract or tort,
+REM  including negligence, or under any other theory of
+REM  liability) for any loss or damage of any kind or nature
+REM  related to, arising under or in connection with these
+REM  materials, including for any direct, or any indirect,
+REM  special, incidental, or consequential loss or damage
+REM  (including loss of data, profits, goodwill, or any type of
+REM  loss or damage suffered as a result of any action brought
+REM  by a third party) even if such damage or loss was
+REM  reasonably foreseeable or Xilinx had been advised of the
+REM  possibility of the same.
+REM  
+REM  CRITICAL APPLICATIONS
+REM  Xilinx products are not designed or intended to be fail-
+REM  safe, or for use in any application requiring fail-safe
+REM  performance, such as life-support or safety devices or
+REM  systems, Class III medical devices, nuclear facilities,
+REM  applications related to the deployment of airbags, or any
+REM  other applications that could lead to death, personal
+REM  injury, or severe property or environmental damage
+REM  (individually and collectively, "Critical
+REM  Applications"). Customer assumes the sole risk and
+REM  liability of any use of Xilinx products in Critical
+REM  Applications, subject only to applicable laws and
+REM  regulations governing limitations on product liability.
+REM  
+REM  THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM  PART OF THIS FILE AT ALL TIMES.
+REM  
+
+REM set up the working directory
+vlib work
+
+REM compile all of the files
+vlog -work work %XILINX%\verilog\src\glbl.v
+vlog -work work ..\..\..\clkmgr_dcm.v
+vlog -work work ..\..\example_design\clkmgr_dcm_exdes.v
+vlog -work work ..\clkmgr_dcm_tb.v
+
+REM run the simulation
+vsim -c -t ps -voptargs="+acc" -L secureip -L unisims_ver work.clkmgr_dcm_tb work.glbl
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.do b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.do
new file mode 100644
index 0000000..b0e526f
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.do
@@ -0,0 +1,65 @@
+# file: simulate_mti.do
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# set up the working directory
+set work work
+vlib work
+
+# compile all of the files
+vlog -work work $env(XILINX)/verilog/src/glbl.v
+vlog -work work ../../../clkmgr_dcm.v
+vlog -work work ../../example_design/clkmgr_dcm_exdes.v
+vlog -work work ../clkmgr_dcm_tb.v
+
+# run the simulation
+vsim  -t ps -voptargs="+acc" -L unisims_ver work.clkmgr_dcm_tb work.glbl
+do wave.do
+log clkmgr_dcm_tb/dut/counter
+log -r /*
+run 50000ns
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.sh
new file mode 100644
index 0000000..66099e0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_mti.sh
@@ -0,0 +1,61 @@
+#/bin/sh
+# file: simulate_mti.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+# set up the working directory
+set work work
+vlib work
+
+# compile all of the files
+vlog -work work $XILINX/verilog/src/glbl.v
+vlog -work work ../../../clkmgr_dcm.v
+vlog -work work ../../example_design/clkmgr_dcm_exdes.v
+vlog -work work ../clkmgr_dcm_tb.v
+
+# run the simulation
+vsim -c -t ps -voptargs="+acc" -L secureip -L unisims_ver work.clkmgr_dcm_tb work.glbl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_ncsim.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_ncsim.sh
new file mode 100644
index 0000000..01b0412
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_ncsim.sh
@@ -0,0 +1,62 @@
+#/bin/sh
+# file: simulate_ncsim.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# set up the working directory
+mkdir work
+
+# compile all of the files
+ncvlog -work work ${XILINX}/verilog/src/glbl.v
+ncvlog -work work ../../../clkmgr_dcm.v
+ncvlog -work work ../../example_design/clkmgr_dcm_exdes.v
+ncvlog -work work ../clkmgr_dcm_tb.v
+
+# elaborate and run the simulation
+ncelab -work work -access +wc work.clkmgr_dcm_tb work.glbl
+ncsim -input  "@database -open -shm nc; probe -create -database nc -all -depth all; probe dut.counter; run 50000ns; exit" work.clkmgr_dcm_tb
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_vcs.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_vcs.sh
new file mode 100644
index 0000000..39668df
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/simulate_vcs.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# file: simulate_vcs.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# remove old files
+rm -rf simv* csrc DVEfiles AN.DB
+
+# compile all of the files
+# Note that -sverilog is not strictly required- You can
+#   remove the -sverilog if you change the type of the
+#   localparam for the periods in the testbench file to 
+#   [63:0] from time
+vlogan -sverilog \
+      ${XILINX}/verilog/src/glbl.v \
+      ../../../clkmgr_dcm.v \
+      ../../example_design/clkmgr_dcm_exdes.v \
+      ../clkmgr_dcm_tb.v
+
+# prepare the simulation 
+vcs +vcs+lic+wait -debug clkmgr_dcm_tb glbl
+
+# run the simulation
+./simv -ucli -i ucli_commands.key
+
+# launch the viewer
+dve -vpd vcdplus.vpd -session vcs_session.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/ucli_commands.key b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/ucli_commands.key
new file mode 100644
index 0000000..2bbdd0f
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/ucli_commands.key
@@ -0,0 +1,5 @@
+call {$vcdpluson}
+call {$vcdplusmemon(clkmgr_dcm_tb.dut.counter)}
+run
+call {$vcdplusclose}
+quit
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/vcs_session.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/vcs_session.tcl
new file mode 100644
index 0000000..628e55a
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/vcs_session.tcl
@@ -0,0 +1,18 @@
+gui_open_window Wave
+gui_sg_create clkmgr_dcm_group
+gui_list_add_group -id Wave.1 {clkmgr_dcm_group}
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.test_phase}
+gui_set_radix -radix {ascii} -signals {clkmgr_dcm_tb.test_phase}
+gui_sg_addsignal -group clkmgr_dcm_group {{Input_clocks}} -divider
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.CLK_IN1}
+gui_sg_addsignal -group clkmgr_dcm_group {{Output_clocks}} -divider
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.dut.clk}
+gui_list_expand -id Wave.1 clkmgr_dcm_tb.dut.clk
+gui_sg_addsignal -group clkmgr_dcm_group {{Status_control}} -divider
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.RESET}
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.USE_INCLK_STOPPED}
+gui_sg_addsignal -group clkmgr_dcm_group {{Counters}} -divider
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.COUNT}
+gui_sg_addsignal -group clkmgr_dcm_group {clkmgr_dcm_tb.dut.counter}
+gui_list_expand -id Wave.1 clkmgr_dcm_tb.dut.counter
+gui_zoom -window Wave.1 -full
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.do b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.do
new file mode 100644
index 0000000..eee7422
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.do
@@ -0,0 +1,60 @@
+# file: wave.do
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+add wave -noupdate -format Literal -radix ascii /clkmgr_dcm_tb/test_phase
+add wave -noupdate -divider {Input clocks}
+add wave -noupdate -format Logic /clkmgr_dcm_tb/CLK_IN1
+add wave -noupdate -divider {Output clocks}
+add wave -noupdate -format Logic /clkmgr_dcm_tb/dut/clk
+add wave -noupdate -divider Status/control
+add wave -noupdate -format Logic /clkmgr_dcm_tb/RESET
+add wave -noupdate -format Logic /clkmgr_dcm_tb/INPUT_CLK_STOPPED
+add wave -noupdate -divider Counters
+add wave -noupdate -format Literal -radix hexadecimal /clkmgr_dcm_tb/COUNT
+add wave -noupdate -format Literal -radix hexadecimal /clkmgr_dcm_tb/dut/counter
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.sv b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.sv
new file mode 100644
index 0000000..c3c3eef
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/functional/wave.sv
@@ -0,0 +1,118 @@
+# file: wave.sv
+# 
+# (c) Copyright 2008 - 2010 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+#
+# Get the windows set up
+#
+if {[catch {window new WatchList -name "Design Browser 1" -geometry 1054x819+536+322}] != ""} {
+    window geometry "Design Browser 1" 1054x819+536+322
+}
+window target "Design Browser 1" on
+browser using {Design Browser 1}
+browser set \
+    -scope nc::clkmgr_dcm_tb
+browser yview see nc::clkmgr_dcm_tb
+browser timecontrol set -lock 0
+
+if {[catch {window new WaveWindow -name "Waveform 1" -geometry 1010x600+0+541}] != ""} {
+    window geometry "Waveform 1" 1010x600+0+541
+}
+window target "Waveform 1" on
+waveform using {Waveform 1}
+waveform sidebar visibility partial
+waveform set \
+    -primarycursor TimeA \
+    -signalnames name \
+    -signalwidth 175 \
+    -units ns \
+    -valuewidth 75
+cursor set -using TimeA -time 0
+waveform baseline set -time 0
+waveform xview limits 0 20000n
+
+#
+# Define signal groups
+#
+catch {group new -name {Output clocks} -overlay 0}
+catch {group new -name {Status/control} -overlay 0}
+catch {group new -name {Counters} -overlay 0}
+
+set id [waveform add -signals [list {nc::clkmgr_dcm_tb.CLK_IN1}]]
+
+group using {Output clocks}
+group set -overlay 0
+group set -comment {}
+group clear 0 end
+
+group insert \
+    {clkmgr_dcm_tb.dut.clk} \
+
+group using {Counters}
+group set -overlay 0
+group set -comment {}
+group clear 0 end
+
+group insert \
+    {clkmgr_dcm_tb.dut.counter} \
+
+group using {Status/control}
+group set -overlay 0
+group set -comment {}
+group clear 0 end
+
+group insert \
+   {nc::clkmgr_dcm_tb.RESET}    {nc::clkmgr_dcm_tb.INPUT_CLK_STOPPED} 
+
+set id [waveform add -signals [list {nc::clkmgr_dcm_tb.COUNT} ]]
+
+set id [waveform add -signals [list {nc::clkmgr_dcm_tb.test_phase} ]]
+waveform format $id -radix %a
+
+set groupId [waveform add -groups {{Input clocks}}]
+set groupId [waveform add -groups {{Output clocks}}]
+set groupId [waveform add -groups {{Status/control}}]
+set groupId [waveform add -groups {{Counters}}]
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/clkmgr_dcm_tb.v b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/clkmgr_dcm_tb.v
new file mode 100644
index 0000000..9618253
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/clkmgr_dcm_tb.v
@@ -0,0 +1,149 @@
+// file: clkmgr_dcm_tb.v
+// 
+// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+// 
+// This file contains confidential and proprietary information
+// of Xilinx, Inc. and is protected under U.S. and
+// international copyright and other intellectual property
+// laws.
+// 
+// DISCLAIMER
+// This disclaimer is not a license and does not grant any
+// rights to the materials distributed herewith. Except as
+// otherwise provided in a valid license issued to you by
+// Xilinx, and to the maximum extent permitted by applicable
+// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+// (2) Xilinx shall not be liable (whether in contract or tort,
+// including negligence, or under any other theory of
+// liability) for any loss or damage of any kind or nature
+// related to, arising under or in connection with these
+// materials, including for any direct, or any indirect,
+// special, incidental, or consequential loss or damage
+// (including loss of data, profits, goodwill, or any type of
+// loss or damage suffered as a result of any action brought
+// by a third party) even if such damage or loss was
+// reasonably foreseeable or Xilinx had been advised of the
+// possibility of the same.
+// 
+// CRITICAL APPLICATIONS
+// Xilinx products are not designed or intended to be fail-
+// safe, or for use in any application requiring fail-safe
+// performance, such as life-support or safety devices or
+// systems, Class III medical devices, nuclear facilities,
+// applications related to the deployment of airbags, or any
+// other applications that could lead to death, personal
+// injury, or severe property or environmental damage
+// (individually and collectively, "Critical
+// Applications"). Customer assumes the sole risk and
+// liability of any use of Xilinx products in Critical
+// Applications, subject only to applicable laws and
+// regulations governing limitations on product liability.
+// 
+// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+// PART OF THIS FILE AT ALL TIMES.
+// 
+
+//----------------------------------------------------------------------------
+// Clocking wizard demonstration testbench
+//----------------------------------------------------------------------------
+// This demonstration testbench instantiates the example design for the 
+//   clocking wizard. Input clocks are toggled, which cause the clocking
+//   network to lock and the counters to increment.
+//----------------------------------------------------------------------------
+
+`timescale 1ps/1ps
+
+`define wait_lock @(posedge CLK_VALID)
+
+module clkmgr_dcm_tb ();
+
+  // Clock to Q delay of 100ps
+  localparam  TCQ              = 100;
+
+
+  // timescale is 1ps/1ps
+  localparam  ONE_NS      = 1000;
+  localparam  PHASE_ERR_MARGIN   = 100; // 100ps
+  // how many cycles to run
+  localparam  COUNT_PHASE = 1024;
+  // we'll be using the period in many locations
+  localparam time PER1    = 20.0*ONE_NS;
+  localparam time PER1_1  = PER1/2;
+  localparam time PER1_2  = PER1 - PER1/2;
+
+  // Declare the input clock signals
+  reg         CLK_IN1     = 1;
+
+  // The high bit of the sampling counter
+  wire        COUNT;
+  // Status and control signals
+  reg         RESET      = 0;
+  wire        INPUT_CLK_STOPPED;
+  wire        CLK_VALID;
+  reg         COUNTER_RESET = 0;
+wire [1:1] CLK_OUT;
+//Freq Check using the M & D values setting and actual Frequency generated 
+
+  reg [13:0]  timeout_counter = 14'b00000000000000;
+
+  // Input clock generation
+  //------------------------------------
+  always begin
+    CLK_IN1 = #PER1_1 ~CLK_IN1;
+    CLK_IN1 = #PER1_2 ~CLK_IN1;
+  end
+
+  // Test sequence
+  reg [15*8-1:0] test_phase = "";
+  initial begin
+    // Set up any display statements using time to be readable
+    $timeformat(-12, 2, "ps", 10);
+    $display ("Timing checks are not valid");
+    COUNTER_RESET = 0;
+    test_phase = "reset";
+    RESET = 1;
+    #(PER1*6);
+    RESET = 0;
+    test_phase = "wait lock";
+    `wait_lock;
+    #(PER1*6);
+    COUNTER_RESET = 1;
+    #(PER1*19.5)
+    COUNTER_RESET = 0;
+    #(PER1*1)
+    $display ("Timing checks are valid");
+    test_phase = "counting";
+    #(PER1*COUNT_PHASE);
+
+    $display("SIMULATION PASSED");
+    $display("SYSTEM_CLOCK_COUNTER : %0d\n",$time/PER1);
+    $finish;
+  end
+
+
+
+  // Instantiation of the example design containing the clock
+  //    network and sampling counters
+  //---------------------------------------------------------
+  clkmgr_dcm_exdes 
+    dut
+   (// Clock in ports
+    .CLK_IN1            (CLK_IN1),
+    // Reset for logic in example design
+    .COUNTER_RESET      (COUNTER_RESET),
+    .CLK_OUT            (CLK_OUT),
+    // High bits of the counters
+    .COUNT              (COUNT),
+    // Status and control signals
+    .RESET              (RESET),
+    .INPUT_CLK_STOPPED  (INPUT_CLK_STOPPED),
+    .CLK_VALID          (CLK_VALID));
+
+
+// Freq Check 
+
+endmodule
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/sdf_cmd_file b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/sdf_cmd_file
new file mode 100644
index 0000000..d59e315
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/sdf_cmd_file
@@ -0,0 +1,2 @@
+COMPILED_SDF_FILE = "../../implement/results/routed.sdf.X",
+SCOPE = clkmgr_dcm_tb.dut;
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simcmds.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simcmds.tcl
new file mode 100644
index 0000000..14523af
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simcmds.tcl
@@ -0,0 +1,9 @@
+# file: simcmds.tcl
+
+# create the simulation script
+vcd dumpfile isim.vcd
+vcd dumpvars -m /clkmgr_dcm_tb -l 0
+wave add /
+run 50000ns
+quit
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_isim.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_isim.sh
new file mode 100644
index 0000000..0152cb0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_isim.sh
@@ -0,0 +1,62 @@
+# file: simulate_isim.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# create the project
+vlogcomp -work work ${XILINX}/verilog/src/glbl.v
+vlogcomp -work work ../../implement/results/routed.v
+vlogcomp -work work clkmgr_dcm_tb.v
+
+# compile the project
+fuse work.clkmgr_dcm_tb work.glbl -L secureip -L simprims_ver -o clkmgr_dcm_isim.exe
+
+# run the simulation script
+./clkmgr_dcm_isim.exe -tclbatch simcmds.tcl -sdfmax /clkmgr_dcm_tb/dut=../../implement/results/routed.sdf
+
+# run the simulation script
+#./clkmgr_dcm_isim.exe -gui -tclbatch simcmds.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.bat b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.bat
new file mode 100644
index 0000000..8a08dc0
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.bat
@@ -0,0 +1,59 @@
+REM file: simulate_mti.bat
+REM  
+REM  (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+REM  
+REM  This file contains confidential and proprietary information
+REM  of Xilinx, Inc. and is protected under U.S. and
+REM  international copyright and other intellectual property
+REM  laws.
+REM  
+REM  DISCLAIMER
+REM  This disclaimer is not a license and does not grant any
+REM  rights to the materials distributed herewith. Except as
+REM  otherwise provided in a valid license issued to you by
+REM  Xilinx, and to the maximum extent permitted by applicable
+REM  law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+REM  WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+REM  AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+REM  BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+REM  INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+REM  (2) Xilinx shall not be liable (whether in contract or tort,
+REM  including negligence, or under any other theory of
+REM  liability) for any loss or damage of any kind or nature
+REM  related to, arising under or in connection with these
+REM  materials, including for any direct, or any indirect,
+REM  special, incidental, or consequential loss or damage
+REM  (including loss of data, profits, goodwill, or any type of
+REM  loss or damage suffered as a result of any action brought
+REM  by a third party) even if such damage or loss was
+REM  reasonably foreseeable or Xilinx had been advised of the
+REM  possibility of the same.
+REM  
+REM  CRITICAL APPLICATIONS
+REM  Xilinx products are not designed or intended to be fail-
+REM  safe, or for use in any application requiring fail-safe
+REM  performance, such as life-support or safety devices or
+REM  systems, Class III medical devices, nuclear facilities,
+REM  applications related to the deployment of airbags, or any
+REM  other applications that could lead to death, personal
+REM  injury, or severe property or environmental damage
+REM  (individually and collectively, "Critical
+REM  Applications"). Customer assumes the sole risk and
+REM  liability of any use of Xilinx products in Critical
+REM  Applications, subject only to applicable laws and
+REM  regulations governing limitations on product liability.
+REM  
+REM  THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+REM  PART OF THIS FILE AT ALL TIMES.
+REM  
+# set up the working directory
+set work work
+vlib work
+
+REM compile all of the files
+vlog -work work %XILINX%\verilog\src\glbl.v
+vlog -work work ..\..\implement\results\routed.v
+vlog -work work clkmgr_dcm_tb.v
+
+REM run the simulation
+vsim -c -t ps +transport_int_delays -voptargs="+acc" -L secureip -L simprims_ver -sdfmax clkmgr_dcm_tb\dut=..\..\implement\results\routed.sdf +no_notifier work.clkmgr_dcm_tb work.glbl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.do b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.do
new file mode 100644
index 0000000..bfeb9c5
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.do
@@ -0,0 +1,65 @@
+# file: simulate_mti.do
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# set up the working directory
+set work work
+vlib work
+
+# compile all of the files
+vlog -work work $env(XILINX)/verilog/src/glbl.v
+vlog -work work ../../implement/results/routed.v
+vlog -work work clkmgr_dcm_tb.v
+
+# run the simulation
+vsim -t ps +transport_int_delays -voptargs="+acc" -L secureip -L simprims_ver -sdfmax clkmgr_dcm_tb/dut=../../implement/results/routed.sdf +no_notifier work.clkmgr_dcm_tb work.glbl
+#do wave.do
+#log -r /*
+run 50000ns
+
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.sh
new file mode 100644
index 0000000..b842adc
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_mti.sh
@@ -0,0 +1,61 @@
+#/bin/sh
+# file: simulate_mti.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# set up the working directory
+set work work
+vlib work
+
+# compile all of the files
+vlog -work work $XILINX/verilog/src/glbl.v
+vlog -work work ../../implement/results/routed.v
+vlog -work work clkmgr_dcm_tb.v
+
+# run the simulation
+vsim -c -t ps +transport_int_delays -voptargs="+acc" -L secureip -L simprims_ver -sdfmax clkmgr_dcm_tb/dut=../../implement/results/routed.sdf +no_notifier work.clkmgr_dcm_tb work.glbl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_ncsim.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_ncsim.sh
new file mode 100644
index 0000000..fd18dde
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_ncsim.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# file: simulate_ncsim.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# set up the working directory
+mkdir work
+
+# compile all of the files
+ncvlog -work work ${XILINX}/verilog/src/glbl.v
+ncvlog -work work ../../implement/results/routed.v
+ncvlog -work work clkmgr_dcm_tb.v
+
+# elaborate and run the simulation
+ncsdfc ../../implement/results/routed.sdf
+
+ncelab -work work -access +wc -pulse_r 10 -nonotifier work.clkmgr_dcm_tb work.glbl -sdf_cmd_file sdf_cmd_file
+ncsim -input  "@database -open -shm nc; probe -create -database nc -all -depth all; run 50000ns; exit" work.clkmgr_dcm_tb
+
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_vcs.sh b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_vcs.sh
new file mode 100644
index 0000000..26a8c27
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/simulate_vcs.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# file: simulate_vcs.sh
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+# remove old files
+rm -rf simv* csrc DVEfiles AN.DB
+
+# compile all of the files
+# Note that -sverilog is not strictly required- You can
+#   remove the -sverilog if you change the type of the
+#   localparam for the periods in the testbench file to 
+#   [63:0] from time
+  vlogan -sverilog \
+           clkmgr_dcm_tb.v \
+           ../../implement/results/routed.v
+
+
+# prepare the simulation
+vcs -sdf max:clkmgr_dcm_exdes:../../implement/results/routed.sdf +v2k -y $XILINX/verilog/src/simprims \
+        +libext+.v -debug clkmgr_dcm_tb.v ../../implement/results/routed.v
+
+# run the simulation
+./simv -ucli -i ucli_commands.key
+
+# launch the viewer
+#dve -vpd vcdplus.vpd -session vcs_session.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/ucli_commands.key b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/ucli_commands.key
new file mode 100644
index 0000000..b32669e
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/ucli_commands.key
@@ -0,0 +1,5 @@
+
+call {$vcdpluson}
+run 50000ns
+call {$vcdplusclose}
+quit
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/vcs_session.tcl b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/vcs_session.tcl
new file mode 100644
index 0000000..6cc6e24
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/vcs_session.tcl
@@ -0,0 +1 @@
+gui_open_window Wave
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/wave.do b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/wave.do
new file mode 100644
index 0000000..7cc804b
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm/simulation/timing/wave.do
@@ -0,0 +1,71 @@
+# file: wave.do
+# 
+# (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved.
+# 
+# This file contains confidential and proprietary information
+# of Xilinx, Inc. and is protected under U.S. and
+# international copyright and other intellectual property
+# laws.
+# 
+# DISCLAIMER
+# This disclaimer is not a license and does not grant any
+# rights to the materials distributed herewith. Except as
+# otherwise provided in a valid license issued to you by
+# Xilinx, and to the maximum extent permitted by applicable
+# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
+# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
+# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
+# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
+# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
+# (2) Xilinx shall not be liable (whether in contract or tort,
+# including negligence, or under any other theory of
+# liability) for any loss or damage of any kind or nature
+# related to, arising under or in connection with these
+# materials, including for any direct, or any indirect,
+# special, incidental, or consequential loss or damage
+# (including loss of data, profits, goodwill, or any type of
+# loss or damage suffered as a result of any action brought
+# by a third party) even if such damage or loss was
+# reasonably foreseeable or Xilinx had been advised of the
+# possibility of the same.
+# 
+# CRITICAL APPLICATIONS
+# Xilinx products are not designed or intended to be fail-
+# safe, or for use in any application requiring fail-safe
+# performance, such as life-support or safety devices or
+# systems, Class III medical devices, nuclear facilities,
+# applications related to the deployment of airbags, or any
+# other applications that could lead to death, personal
+# injury, or severe property or environmental damage
+# (individually and collectively, "Critical
+# Applications"). Customer assumes the sole risk and
+# liability of any use of Xilinx products in Critical
+# Applications, subject only to applicable laws and
+# regulations governing limitations on product liability.
+# 
+# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
+# PART OF THIS FILE AT ALL TIMES.
+# 
+
+onerror {resume}
+quietly WaveActivateNextPane {} 0
+add wave -noupdate /clkmgr_dcm_tb/CLK_IN1
+add wave -noupdate /clkmgr_dcm_tb/COUNT
+add wave -noupdate /clkmgr_dcm_tb/RESET
+TreeUpdate [SetDefaultTree]
+WaveRestoreCursors {{Cursor 1} {3223025 ps} 0}
+configure wave -namecolwidth 238
+configure wave -valuecolwidth 107
+configure wave -justifyvalue left
+configure wave -signalnamewidth 0
+configure wave -snapdistance 10
+configure wave -datasetprefix 0
+configure wave -rowmargin 4
+configure wave -childrowmargin 2
+configure wave -gridoffset 0
+configure wave -gridperiod 1
+configure wave -griddelta 40
+configure wave -timeline 0
+configure wave -timelineunits ps
+update
+WaveRestoreZoom {0 ps} {74848022 ps}
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm_flist.txt b/novena/src/rtl/ipcore/clkmgr_dcm_flist.txt
new file mode 100644
index 0000000..bd1b2cd
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm_flist.txt
@@ -0,0 +1,54 @@
+# Output products list for <clkmgr_dcm>
+_xmsgs\pn_parser.xmsgs
+clkmgr_dcm.asy
+clkmgr_dcm.gise
+clkmgr_dcm.ucf
+clkmgr_dcm.v
+clkmgr_dcm.veo
+clkmgr_dcm.xco
+clkmgr_dcm.xdc
+clkmgr_dcm.xise
+clkmgr_dcm\clk_wiz_v3_6_readme.txt
+clkmgr_dcm\doc\clk_wiz_v3_6_readme.txt
+clkmgr_dcm\doc\clk_wiz_v3_6_vinfo.html
+clkmgr_dcm\doc\pg065_clk_wiz.pdf
+clkmgr_dcm\example_design\clkmgr_dcm_exdes.ucf
+clkmgr_dcm\example_design\clkmgr_dcm_exdes.v
+clkmgr_dcm\example_design\clkmgr_dcm_exdes.xdc
+clkmgr_dcm\implement\implement.bat
+clkmgr_dcm\implement\implement.sh
+clkmgr_dcm\implement\planAhead_ise.bat
+clkmgr_dcm\implement\planAhead_ise.sh
+clkmgr_dcm\implement\planAhead_ise.tcl
+clkmgr_dcm\implement\planAhead_rdn.bat
+clkmgr_dcm\implement\planAhead_rdn.sh
+clkmgr_dcm\implement\planAhead_rdn.tcl
+clkmgr_dcm\implement\xst.prj
+clkmgr_dcm\implement\xst.scr
+clkmgr_dcm\simulation\clkmgr_dcm_tb.v
+clkmgr_dcm\simulation\functional\simcmds.tcl
+clkmgr_dcm\simulation\functional\simulate_isim.bat
+clkmgr_dcm\simulation\functional\simulate_isim.sh
+clkmgr_dcm\simulation\functional\simulate_mti.bat
+clkmgr_dcm\simulation\functional\simulate_mti.do
+clkmgr_dcm\simulation\functional\simulate_mti.sh
+clkmgr_dcm\simulation\functional\simulate_ncsim.sh
+clkmgr_dcm\simulation\functional\simulate_vcs.sh
+clkmgr_dcm\simulation\functional\ucli_commands.key
+clkmgr_dcm\simulation\functional\vcs_session.tcl
+clkmgr_dcm\simulation\functional\wave.do
+clkmgr_dcm\simulation\functional\wave.sv
+clkmgr_dcm\simulation\timing\clkmgr_dcm_tb.v
+clkmgr_dcm\simulation\timing\sdf_cmd_file
+clkmgr_dcm\simulation\timing\simcmds.tcl
+clkmgr_dcm\simulation\timing\simulate_isim.sh
+clkmgr_dcm\simulation\timing\simulate_mti.bat
+clkmgr_dcm\simulation\timing\simulate_mti.do
+clkmgr_dcm\simulation\timing\simulate_mti.sh
+clkmgr_dcm\simulation\timing\simulate_ncsim.sh
+clkmgr_dcm\simulation\timing\simulate_vcs.sh
+clkmgr_dcm\simulation\timing\ucli_commands.key
+clkmgr_dcm\simulation\timing\vcs_session.tcl
+clkmgr_dcm\simulation\timing\wave.do
+clkmgr_dcm_flist.txt
+clkmgr_dcm_xmdf.tcl
diff --git a/novena/src/rtl/ipcore/clkmgr_dcm_xmdf.tcl b/novena/src/rtl/ipcore/clkmgr_dcm_xmdf.tcl
new file mode 100644
index 0000000..307029b
--- /dev/null
+++ b/novena/src/rtl/ipcore/clkmgr_dcm_xmdf.tcl
@@ -0,0 +1,140 @@
+# The package naming convention is <core_name>_xmdf
+package provide clkmgr_dcm_xmdf 1.0
+
+# This includes some utilities that support common XMDF operations
+package require utilities_xmdf
+
+# Define a namespace for this package. The name of the name space
+# is <core_name>_xmdf
+namespace eval ::clkmgr_dcm_xmdf {
+# Use this to define any statics
+}
+
+# Function called by client to rebuild the params and port arrays
+# Optional when the use context does not require the param or ports
+# arrays to be available.
+proc ::clkmgr_dcm_xmdf::xmdfInit { instance } {
+# Variable containg name of library into which module is compiled
+# Recommendation: <module_name>
+# Required
+utilities_xmdf::xmdfSetData $instance Module Attributes Name clkmgr_dcm
+}
+# ::clkmgr_dcm_xmdf::xmdfInit
+
+# Function called by client to fill in all the xmdf* data variables
+# based on the current settings of the parameters
+proc ::clkmgr_dcm_xmdf::xmdfApplyParams { instance } {
+
+set fcount 0
+# Array containing libraries that are assumed to exist
+# Examples include unisim and xilinxcorelib
+# Optional
+# In this example, we assume that the unisim library will
+# be magically
+# available to the simulation and synthesis tool
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type logical_library
+utilities_xmdf::xmdfSetData $instance FileSet $fcount logical_library unisim
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/clk_wiz_readme.txt
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/doc/clk_wiz_ds709.pdf
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/doc/clk_wiz_gsg521.pdf
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/implement/implement.bat
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/implement/implement.sh
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/implement/xst.prj
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/implement/xst.scr
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/clkmgr_dcm_tb.v
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/simcmds.tcl
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/simulate_isim.sh
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/simulate_mti.do
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/simulate_ncsim.sh
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/simulate_vcs.sh
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/ucli_commands.key
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/vcs_session.tcl
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/wave.do
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm/simulation/functional/wave.sv
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type Ignore
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.asy
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type asy
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.ejp
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.ucf
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type ucf
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.v
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.veo
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type verilog_template
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm.xco
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type coregen_ip
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount relative_path clkmgr_dcm_xmdf.tcl
+utilities_xmdf::xmdfSetData $instance FileSet $fcount type AnyView
+incr fcount
+
+utilities_xmdf::xmdfSetData $instance FileSet $fcount associated_module clkmgr_dcm
+incr fcount
+
+}
+
+# ::gen_comp_name_xmdf::xmdfApplyParams
diff --git a/novena/src/rtl/ipcore/coregen.cgp b/novena/src/rtl/ipcore/coregen.cgp
new file mode 100644
index 0000000..8bc2e70
--- /dev/null
+++ b/novena/src/rtl/ipcore/coregen.cgp
@@ -0,0 +1,9 @@
+SET busformat = BusFormatAngleBracketNotRipped
+SET designentry = Verilog
+SET device = xc6slx45
+SET devicefamily = spartan6
+SET flowvendor = Other
+SET package = csg324
+SET speedgrade = -3
+SET verilogsim = true
+SET vhdlsim = false
diff --git a/novena/src/rtl/ipcore/create_clkmgr_dcm.tcl b/novena/src/rtl/ipcore/create_clkmgr_dcm.tcl
new file mode 100644
index 0000000..fec8dec
--- /dev/null
+++ b/novena/src/rtl/ipcore/create_clkmgr_dcm.tcl
@@ -0,0 +1,37 @@
+##
+## Core Generator Run Script, generator for Project Navigator create command
+##
+
+proc findRtfPath { relativePath } {
+   set xilenv ""
+   if { [info exists ::env(XILINX) ] } {
+      if { [info exists ::env(MYXILINX)] } {
+         set xilenv [join [list $::env(MYXILINX) $::env(XILINX)] $::xilinx::path_sep ]
+      } else {
+         set xilenv $::env(XILINX)
+      }
+   }
+   foreach path [ split $xilenv $::xilinx::path_sep ] {
+      set fullPath [ file join $path $relativePath ]
+      if { [ file exists $fullPath ] } {
+         return $fullPath
+      }
+   }
+   return ""
+}
+
+source [ findRtfPath "data/projnav/scripts/dpm_cgUtils.tcl" ]
+
+set result [ run_cg_create "xilinx.com:ip:clk_wiz:3.6" "clkmgr_dcm" "Clocking Wizard" "Clocking Wizard (xilinx.com:ip:clk_wiz:3.6) generated by Project Navigator" xc6slx45-3csg324 Verilog ]
+
+if { $result == 0 } {
+   puts "Core Generator create command completed successfully."
+} elseif { $result == 1 } {
+   puts "Core Generator create command failed."
+} elseif { $result == 3 || $result == 4 } {
+   # convert 'version check' result to real return range, bypassing any messages.
+   set result [ expr $result - 3 ]
+} else {
+   puts "Core Generator create cancelled."
+}
+exit $result
diff --git a/novena/src/rtl/ipcore/edit_clkmgr_dcm.tcl b/novena/src/rtl/ipcore/edit_clkmgr_dcm.tcl
new file mode 100644
index 0000000..4992eb1
--- /dev/null
+++ b/novena/src/rtl/ipcore/edit_clkmgr_dcm.tcl
@@ -0,0 +1,37 @@
+##
+## Core Generator Run Script, generator for Project Navigator edit command
+##
+
+proc findRtfPath { relativePath } {
+   set xilenv ""
+   if { [info exists ::env(XILINX) ] } {
+      if { [info exists ::env(MYXILINX)] } {
+         set xilenv [join [list $::env(MYXILINX) $::env(XILINX)] $::xilinx::path_sep ]
+      } else {
+         set xilenv $::env(XILINX)
+      }
+   }
+   foreach path [ split $xilenv $::xilinx::path_sep ] {
+      set fullPath [ file join $path $relativePath ]
+      if { [ file exists $fullPath ] } {
+         return $fullPath
+      }
+   }
+   return ""
+}
+
+source [ findRtfPath "data/projnav/scripts/dpm_cgUtils.tcl" ]
+
+set result [ run_cg_edit "clkmgr_dcm" xc6slx45-3csg324 Verilog ]
+
+if { $result == 0 } {
+   puts "Core Generator edit command completed successfully."
+} elseif { $result == 1 } {
+   puts "Core Generator edit command failed."
+} elseif { $result == 3 || $result == 4 } {
+   # convert 'version check' result to real return range, bypassing any messages.
+   set result [ expr $result - 3 ]
+} else {
+   puts "Core Generator edit cancelled."
+}
+exit $result
diff --git a/novena/src/rtl/novena_clkmgr.v b/novena/src/rtl/novena_clkmgr.v
new file mode 100644
index 0000000..00b2e5b
--- /dev/null
+++ b/novena/src/rtl/novena_clkmgr.v
@@ -0,0 +1,143 @@
+//======================================================================
+//
+// novena_clkmgr.v
+// ---------------
+// Clock and reset implementation for the Cryptech Novena
+// FPGA framework.
+//
+//
+// Author: Pavel Shatov
+// 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 novena_clkmgr
+  (
+   input wire  gclk_p, // signal from clock pins
+   input wire  gclk_n, //
+
+   input wire  reset_mcu_b, // cpu reset (async)
+
+   output wire sys_clk, // buffered system clock output
+   output wire sys_rst, // system reset output (sync)
+
+   input wire  bclk_in, // signal from clock pin
+   output wire bclk_out         // buffered clock output
+   );
+
+   //
+   // Ports
+   //
+
+
+   //
+   // IBUFGDS
+   //
+   (* BUFFER_TYPE="NONE" *)
+   wire        gclk;
+
+   IBUFGDS IBUFGDS_gclk
+     (
+      .I(gclk_p),
+      .IB(gclk_n),
+      .O(gclk)
+      );
+
+
+   //
+   // DCM
+   //
+   wire        dcm_reset;               // dcm reset
+   wire        dcm_locked;              // output clock valid
+   wire        gclk_missing;    // no input clock
+
+   clkmgr_dcm dcm
+     (
+      .CLK_IN1(gclk),
+      .RESET(dcm_reset),
+      .INPUT_CLK_STOPPED(gclk_missing),
+
+      .CLK_OUT1(sys_clk),
+      .CLK_VALID(dcm_locked)
+      );
+
+
+   //
+   // DCM Reset Logic
+   //
+
+   /* DCM should be reset on power-up, when input clock is stopped or when the
+    * CPU gets reset.
+    */
+
+   reg [15: 0] dcm_rst_shreg    = {16{1'b1}};   // 16-bit shift register
+
+   always @(posedge gclk or negedge reset_mcu_b or posedge gclk_missing)
+     //
+     if ((reset_mcu_b == 1'b0) || (gclk_missing == 1'b1))
+       dcm_rst_shreg    <= {16{1'b1}};
+     else
+       dcm_rst_shreg    <= {dcm_rst_shreg[14:0], 1'b0};
+
+   assign dcm_reset = dcm_rst_shreg[15];
+
+
+   //
+   // System Reset Logic
+   //
+
+   /* System reset is asserted for 16 cycles whenever DCM aquires lock. */
+
+   reg [15: 0] sys_rst_shreg    = {16{1'b1}};   // 16-bit shift register
+
+   always @(posedge sys_clk or negedge reset_mcu_b or posedge gclk_missing or negedge dcm_locked)
+     //
+     if ((reset_mcu_b == 1'b0) || (gclk_missing == 1'b1) || (dcm_locked == 1'b0))
+       sys_rst_shreg    <= {16{1'b1}};
+     else if (dcm_locked == 1'b1)
+       sys_rst_shreg    <= {sys_rst_shreg[14:0], 1'b0};
+
+   assign sys_rst = sys_rst_shreg[15];
+
+
+   //
+   // BCLK BUFG
+   //
+   BUFG BUFG_BCLK
+     (
+      .I(bclk_in),
+      .O(bclk_out)
+      );
+
+
+endmodule
+
+//======================================================================
+// EOF novena_clkmgr.v
+//======================================================================
diff --git a/novena/src/rtl/novena_eim.v b/novena/src/rtl/novena_eim.v
new file mode 100644
index 0000000..8778291
--- /dev/null
+++ b/novena/src/rtl/novena_eim.v
@@ -0,0 +1,175 @@
+//======================================================================
+//
+// novena_baseline_top.v
+// ---------------------
+// Top module for the Cryptech Novena FPGA framework. This design
+// allow us to run the EIM interface at one clock and cores including
+// core selector with the always present global clock.
+//
+//
+// Author: Pavel Shatov
+// 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 novena_baseline_top
+  (
+   // Differential input for 50 MHz general clock.
+   input wire 	       gclk_p_pin,
+   input wire 	       gclk_n_pin,
+
+   // Reset controlled by the CPU.
+   // this must be configured as input w/pullup
+   input wire 	       reset_mcu_b_pin,
+
+   // Cryptech avalanche noise board input and LED outputs
+   input wire 	       ct_noise,
+   output wire [7 : 0] ct_led,
+
+   // EIM interface
+   input wire 	       eim_bclk, // EIM burst clock. Started by the CPU.
+   input wire 	       eim_cs0_n, // Chip select (active low).
+   inout wire [15 : 0] eim_da, // Bidirectional address and data port.
+   input wire [18: 16] eim_a, // MSB part of address port.                     
+   input wire 	       eim_lba_n, // Latch address signal (active low).
+   input wire 	       eim_wr_n, // write enable signal (active low).
+   input wire 	       eim_oe_n, // output enable signal (active low).
+   output wire 	       eim_wait_n, // Data wait signal (active low).
+
+   // Novena utility ports
+   output wire 	       apoptosis_pin, // Hold low to not restart after config.
+   output wire 	       led_pin		// LED on edge close to the FPGA.
+   );
+
+
+   //----------------------------------------------------------------
+   // Clock Manager
+   //
+   // Clock manager is used to buffer BCLK, generate SYS_CLK
+   // from GCLK and implement the reset logic.
+   //----------------------------------------------------------------
+   wire                 sys_clk;
+   wire                 sys_rst;
+   wire                 eim_bclk_buf;
+
+   novena_clkmgr clkmgr
+     (
+      .gclk_p(gclk_p_pin),
+      .gclk_n(gclk_n_pin),
+
+      .reset_mcu_b(reset_mcu_b_pin),
+
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .bclk_in(eim_bclk),
+      .bclk_out(eim_bclk_buf)
+      );
+
+
+   //----------------------------------------------------------------
+   // EIM Interface
+   //
+   // EIM subsystem handles all data transfer to/from CPU via EIM bus.
+   //----------------------------------------------------------------
+   wire [16: 0]         sys_eim_addr;
+   wire                 sys_eim_wr;
+   wire                 sys_eim_rd;
+   wire [31: 0]         sys_eim_dout;
+   wire [31: 0]         sys_eim_din;
+
+   eim eim
+     (
+      .eim_bclk(eim_bclk_buf),
+      .eim_cs0_n(eim_cs0_n),
+      .eim_da(eim_da),
+      .eim_a(eim_a),
+      .eim_lba_n(eim_lba_n),
+      .eim_wr_n(eim_wr_n),
+      .eim_oe_n(eim_oe_n),
+      .eim_wait_n(eim_wait_n),
+
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .sys_eim_addr(sys_eim_addr),
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),
+      .sys_eim_dout(sys_eim_dout),
+      .sys_eim_din(sys_eim_din),
+
+      .led_pin(led_pin)
+      );
+
+
+   //----------------------------------------------------------------
+   // Core Selector
+   //
+   // This multiplexer is used to map different types of cores, such as
+   // hashes, RNGs and ciphers to different regions (segments) of memory.
+   //----------------------------------------------------------------
+   core_selector cores
+     (
+      .sys_clk(sys_clk),
+      .sys_rst(sys_rst),
+
+      .sys_eim_addr(sys_eim_addr),
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),
+
+      .sys_write_data(sys_eim_dout),
+      .sys_read_data(sys_eim_din)
+      );  
+
+
+   //----------------------------------------------------------------
+   // Cryptech Logic
+   //
+   // Logic specific to the Cryptech use of the Novena.
+   // Currently we just hard wire the LED outputs.
+   //----------------------------------------------------------------
+   assign ct_led = {8{ct_noise}};
+
+
+   //----------------------------------------------------------------
+   // Novena Patch
+   //
+   // Patch logic to keep the Novena board happy.
+   // The apoptosis_pin pin must be kept low or the whole board
+   // (more exactly the CPU) will be reset after the FPGA has
+   // been configured.
+   //----------------------------------------------------------------
+   assign apoptosis_pin = 1'b0;
+
+
+endmodule
+
+//======================================================================
+// EOF novena_baseline_top.v
+//======================================================================
diff --git a/novena/src/rtl/novena_i2c.v b/novena/src/rtl/novena_i2c.v
new file mode 100644
index 0000000..23ce3d2
--- /dev/null
+++ b/novena/src/rtl/novena_i2c.v
@@ -0,0 +1,218 @@
+//======================================================================
+//
+// novena_baseline_top.v
+// ---------------------
+// Top module for the Cryptech Novena FPGA framework. This design
+// allow us to run the EIM interface at one clock and cores including
+// core selector with the always present global clock.
+//
+//
+// Author: Pavel Shatov
+// 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 novena_baseline_top
+  (
+   // Differential input for 50 MHz general clock.
+   input wire 	       gclk_p_pin,
+   input wire 	       gclk_n_pin,
+
+   // Reset controlled by the CPU.
+   // this must be configured as input w/pullup
+   input wire 	       reset_mcu_b_pin,
+
+   // Cryptech avalanche noise board input and LED outputs
+   input wire 	       ct_noise,
+   output wire [7 : 0] ct_led,
+
+   // I2C interface
+   input wire 	       i2c_scl,
+   inout wire 	       i2c_sda,
+                       
+   // Novena utility ports
+   output wire 	       apoptosis_pin, // Hold low to not restart after config.
+   output wire 	       led_pin		// LED on edge close to the FPGA.
+   );
+
+
+   //----------------------------------------------------------------
+   // Clock Manager
+   //
+   // Clock manager is used to buffer BCLK, generate SYS_CLK
+   // from GCLK and implement the reset logic.
+   //----------------------------------------------------------------
+   wire                 sys_clk;
+   wire                 sys_rst = 0;
+
+   IBUFGDS clkibufgds(
+		      .I(gclk_p_pin),
+		      .IB(gclk_n_pin),
+		      .O(sys_clk)
+		      );
+
+
+   //----------------------------------------------------------------
+   // I2C Interface
+   //
+   // I2C subsystem handles all data transfer to/from CPU via I2C bus.
+   //----------------------------------------------------------------
+   parameter I2C_DEVICE_ADDR    = 7'h0f;
+
+   wire [16: 0]         sys_eim_addr;
+   wire                 sys_eim_wr;
+   wire                 sys_eim_rd;
+
+   wire 		sda_pd;
+   wire 		sda_int;
+   
+   wire 		clk = sys_clk;
+   wire 		reset_n = ~sys_rst;
+
+   // Coretest connections.
+   wire 		coretest_reset_n;
+   wire 		coretest_cs;
+   wire 		coretest_we;
+   wire [15 : 0] 	coretest_address;
+   wire [31 : 0] 	coretest_write_data;
+   wire [31 : 0] 	coretest_read_data;
+
+   // I2C connections
+   wire [6:0] 		i2c_device_addr;
+   wire 		i2c_rxd_syn;
+   wire [7 : 0] 	i2c_rxd_data;
+   wire 		i2c_rxd_ack;
+   wire 		i2c_txd_syn;
+   wire [7 : 0] 	i2c_txd_data;
+   wire 		i2c_txd_ack;
+
+   IOBUF #(.DRIVE(8), .SLEW("SLOW"))
+   IOBUF_sda (
+	      .IO(i2c_sda),
+	      .I(1'b0),
+	      .T(!sda_pd),
+	      .O(sda_int)
+	      );
+
+   i2c_core i2c_core
+     (
+      .clk(clk),
+      .reset(sys_rst),
+
+      // External data interface
+      .SCL(i2c_scl),
+      .SDA(sda_int),
+      .SDA_pd(sda_pd),
+      .i2c_device_addr(i2c_device_addr),
+
+      // Internal receive interface.
+      .rxd_syn(i2c_rxd_syn),
+      .rxd_data(i2c_rxd_data),
+      .rxd_ack(i2c_rxd_ack),
+      
+      // Internal transmit interface.
+      .txd_syn(i2c_txd_syn),
+      .txd_data(i2c_txd_data),
+      .txd_ack(i2c_txd_ack)
+      );
+
+   coretest coretest
+     (
+      .clk(clk),
+      .reset_n(reset_n),
+      
+      .rx_syn(i2c_rxd_syn),
+      .rx_data(i2c_rxd_data),
+      .rx_ack(i2c_rxd_ack),
+      
+      .tx_syn(i2c_txd_syn),
+      .tx_data(i2c_txd_data),
+      .tx_ack(i2c_txd_ack),
+      
+      // Interface to the core being tested.
+      .core_reset_n(coretest_reset_n),
+      .core_cs(coretest_cs),
+      .core_we(coretest_we),
+      .core_address(coretest_address),
+      .core_write_data(coretest_write_data),
+      .core_read_data(coretest_read_data)
+      );
+
+   wire 		select = (i2c_device_addr == I2C_DEVICE_ADDR);
+   assign sys_eim_addr = { coretest_address[15:13], 1'b0, coretest_address[12:0] };
+   assign sys_eim_wr = select & coretest_cs & coretest_we;
+   assign sys_eim_rd = select & coretest_cs & ~coretest_we;
+
+
+   //----------------------------------------------------------------
+   // Core Selector
+   //
+   // This multiplexer is used to map different types of cores, such as
+   // hashes, RNGs and ciphers to different regions (segments) of memory.
+   //----------------------------------------------------------------
+   core_selector cores
+     (
+      .sys_clk(clk),
+      .sys_rst(sys_rst),
+
+      .sys_eim_addr(sys_eim_addr),
+      .sys_eim_wr(sys_eim_wr),
+      .sys_eim_rd(sys_eim_rd),
+
+      .sys_write_data(coretest_write_data),
+      .sys_read_data(coretest_read_data)
+      );  
+
+
+   //----------------------------------------------------------------
+   // Cryptech Logic
+   //
+   // Logic specific to the Cryptech use of the Novena.
+   // Currently we just hard wire the LED outputs.
+   //----------------------------------------------------------------
+   assign ct_led = {8{ct_noise}};
+
+
+   //----------------------------------------------------------------
+   // Novena Patch
+   //
+   // Patch logic to keep the Novena board happy.
+   // The apoptosis_pin pin must be kept low or the whole board
+   // (more exactly the CPU) will be reset after the FPGA has
+   // been configured.
+   //----------------------------------------------------------------
+   assign apoptosis_pin = 1'b0;
+
+   assign led_pin = 1'b1;
+
+endmodule
+
+//======================================================================
+// EOF novena_baseline_top.v
+//======================================================================
diff --git a/novena/src/rtl/novena_regs.v b/novena/src/rtl/novena_regs.v
new file mode 100644
index 0000000..7341092
--- /dev/null
+++ b/novena/src/rtl/novena_regs.v
@@ -0,0 +1,126 @@
+//======================================================================
+//
+// novena_regs.v
+// -------------
+// Global registers for the Cryptech Novena FPGA framework.
+//
+//
+// Author: Pavel Shatov
+// 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.
+//
+//======================================================================
+
+`timescale 1ns / 1ps
+
+module novena_regs
+  (
+   input wire           clk,
+   input wire           rst,
+
+   input wire           cs,
+   input wire           we,
+
+   input wire [ 7 : 0]  address,
+   input wire [31 : 0]  write_data,
+   output wire [31 : 0] read_data
+   );
+
+
+   //----------------------------------------------------------------
+   // Board-Level Registers
+   //----------------------------------------------------------------
+   localparam   ADDR_BOARD_TYPE         = 8'h00;        // board id
+   localparam   ADDR_FIRMWARE_VER       = 8'h01;        // bitstream version
+   localparam   ADDR_DUMMY_REG          = 8'hFF;        // general-purpose register
+
+
+   //----------------------------------------------------------------
+   // Constants
+   //----------------------------------------------------------------
+   localparam   NOVENA_BOARD_TYPE       = 32'h50565431;         // PVT1
+   localparam   NOVENA_DESIGN_VER       = 32'h00_01_00_0b;      // v0.1.0b
+
+
+   //
+   // Output Register
+   //
+   reg [31: 0]          tmp_read_data;
+   assign read_data = tmp_read_data;
+   
+
+   /* This dummy register can be used by users to check that they can actually
+    * write something.
+    */
+   
+   reg [31: 0]          reg_dummy;
+   
+   
+   //
+   // Access Handler
+   //
+   always @(posedge clk)
+     //
+     if (rst)
+       reg_dummy <= {32{1'b0}};
+     else if (cs) begin
+        //
+        if (we) begin
+           //
+           // WRITE handler
+           //
+           case (address)
+             ADDR_DUMMY_REG:
+               reg_dummy        <= write_data;
+           endcase
+           //
+        end else begin
+           //
+           // READ handler
+           //
+           case (address)
+             ADDR_BOARD_TYPE:
+               tmp_read_data    <= NOVENA_BOARD_TYPE;
+             ADDR_FIRMWARE_VER:
+               tmp_read_data    <= NOVENA_DESIGN_VER;
+             ADDR_DUMMY_REG:
+               tmp_read_data    <= reg_dummy;
+             //
+             default:
+               tmp_read_data    <= {32{1'b0}};  // read non-existent locations as zeroes
+           endcase
+           //
+        end
+        //
+     end
+
+endmodule
+
+//======================================================================
+// EOF novena_regs.v
+//======================================================================
diff --git a/novena/src/sw/Makefile b/novena/src/sw/Makefile
new file mode 100755
index 0000000..8580a1a
--- /dev/null
+++ b/novena/src/sw/Makefile
@@ -0,0 +1,17 @@
+all: hash_tester_eim hash_tester_i2c
+
+.c.o:
+	gcc -c -Wall -o $@ $<
+
+hash_tester_eim: hash_tester_eim.o novena-eim.o
+	gcc -o $@ $^
+
+hash_tester_eim.o: hash_tester_eim.c novena-eim.h
+
+novena-eim.o: novena-eim.c novena-eim.h
+
+hash_tester_i2c: hash_tester_i2c.c
+	gcc -o $@ $^
+
+clean:
+	rm -f *.o hash_tester_eim hash_tester_i2c
diff --git a/novena/src/sw/hash_tester_eim.c b/novena/src/sw/hash_tester_eim.c
new file mode 100644
index 0000000..a0ab0f1
--- /dev/null
+++ b/novena/src/sw/hash_tester_eim.c
@@ -0,0 +1,876 @@
+/* 
+ * hash_tester.c
+ * --------------
+ * This program sends several commands to the coretest_hashes subsystem
+ * in order to verify the SHA-1, SHA-256 and SHA-512/x hash function
+ * cores.
+ *
+ * Note: This version of the program talks to the FPGA over an EIM bus.
+ *
+ * The single and dual block test cases are taken from the
+ * NIST KAT document:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ *
+ * 
+ * Authors: Joachim Strömbergson, Paul Selkirk
+ * Copyright (c) 2014-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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include "novena-eim.h"
+
+int debug = 0;
+int quiet = 0;
+int repeat = 0;
+
+/* instead of core number 0 we have a page of global registers */
+#define ADDR_GLOBAL_BOARD_TYPE          EIM_BASE_ADDR + (0x00 << 2)
+#define ADDR_GLOBAL_BITSTREAM_VER       EIM_BASE_ADDR + (0x01 << 2)
+#define ADDR_GLOBAL_DUMMY_REG           EIM_BASE_ADDR + (0xFF << 2)
+
+#define SEGMENT_OFFSET_HASHES   EIM_BASE_ADDR + 0x000000
+#define SEGMENT_OFFSET_RNGS     EIM_BASE_ADDR + 0x010000
+#define SEGMENT_OFFSET_CIPHERS  EIM_BASE_ADDR + 0x020000
+
+
+/* addresses and codes common to all hash cores */
+#define ADDR_NAME0              0x00
+#define ADDR_NAME1              0x04
+#define ADDR_VERSION            0x08
+#define ADDR_CTRL               0x20
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             0x24
+#define STATUS_READY_BIT        1
+#define STATUS_VALID_BIT        2
+#define ADDR_BLOCK              0x40
+#define ADDR_DIGEST             0x80
+
+#define HASH_CORE_SIZE          0x400
+
+/* addresses and codes for the specific hash cores */
+#define SHA1_ADDR_BASE          SEGMENT_OFFSET_HASHES + (1*HASH_CORE_SIZE)
+#define SHA1_ADDR_NAME0         SHA1_ADDR_BASE + ADDR_NAME0
+#define SHA1_ADDR_NAME1         SHA1_ADDR_BASE + ADDR_NAME1
+#define SHA1_ADDR_VERSION       SHA1_ADDR_BASE + ADDR_VERSION
+#define SHA1_ADDR_CTRL          SHA1_ADDR_BASE + ADDR_CTRL
+#define SHA1_ADDR_STATUS        SHA1_ADDR_BASE + ADDR_STATUS
+#define SHA1_ADDR_BLOCK         SHA1_ADDR_BASE + ADDR_BLOCK
+#define SHA1_ADDR_DIGEST        SHA1_ADDR_BASE + ADDR_DIGEST
+#define SHA1_BLOCK_LEN          512 / 8
+#define SHA1_DIGEST_LEN         160 / 8
+
+#define SHA256_ADDR_BASE        SEGMENT_OFFSET_HASHES + (2*HASH_CORE_SIZE)
+#define SHA256_ADDR_NAME0       SHA256_ADDR_BASE + ADDR_NAME0
+#define SHA256_ADDR_NAME1       SHA256_ADDR_BASE + ADDR_NAME1
+#define SHA256_ADDR_VERSION     SHA256_ADDR_BASE + ADDR_VERSION
+#define SHA256_ADDR_CTRL        SHA256_ADDR_BASE + ADDR_CTRL
+#define SHA256_ADDR_STATUS      SHA256_ADDR_BASE + ADDR_STATUS
+#define SHA256_ADDR_BLOCK       SHA256_ADDR_BASE + ADDR_BLOCK
+#define SHA256_ADDR_DIGEST      SHA256_ADDR_BASE + ADDR_DIGEST
+#define SHA256_BLOCK_LEN        512 / 8
+#define SHA256_DIGEST_LEN       256 / 8
+
+#define SHA512_ADDR_BASE        SEGMENT_OFFSET_HASHES + (3*HASH_CORE_SIZE)
+#define SHA512_ADDR_NAME0       SHA512_ADDR_BASE + ADDR_NAME0
+#define SHA512_ADDR_NAME1       SHA512_ADDR_BASE + ADDR_NAME1
+#define SHA512_ADDR_VERSION     SHA512_ADDR_BASE + ADDR_VERSION
+#define SHA512_ADDR_CTRL        SHA512_ADDR_BASE + ADDR_CTRL
+#define SHA512_ADDR_STATUS      SHA512_ADDR_BASE + ADDR_STATUS
+#define SHA512_ADDR_BLOCK       SHA512_ADDR_BASE + ADDR_BLOCK
+#define SHA512_ADDR_DIGEST      SHA512_ADDR_BASE + 0x100
+#define SHA512_BLOCK_LEN        1024 / 8
+#define SHA512_224_DIGEST_LEN   224 / 8
+#define SHA512_256_DIGEST_LEN   256 / 8
+#define SHA384_DIGEST_LEN       384 / 8
+#define SHA512_DIGEST_LEN       512 / 8
+#define MODE_SHA_512_224        0 << 2
+#define MODE_SHA_512_256        1 << 2
+#define MODE_SHA_384            2 << 2
+#define MODE_SHA_512            3 << 2
+
+/* SHA-1/SHA-256 One Block Message Sample
+   Input Message: "abc" */
+const uint8_t NIST_512_SINGLE[] =
+{ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 };
+
+const uint8_t SHA1_SINGLE_DIGEST[] =
+{ 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+  0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+  0x9c, 0xd0, 0xd8, 0x9d };
+
+const uint8_t SHA256_SINGLE_DIGEST[] =
+{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+  0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+  0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+  0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD };
+
+/* SHA-1/SHA-256 Two Block Message Sample
+   Input Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */
+const uint8_t NIST_512_DOUBLE0[] =
+{ 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
+  0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
+  0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
+  0x67, 0x68, 0x69, 0x6A, 0x68, 0x69, 0x6A, 0x6B,
+  0x69, 0x6A, 0x6B, 0x6C, 0x6A, 0x6B, 0x6C, 0x6D,
+  0x6B, 0x6C, 0x6D, 0x6E, 0x6C, 0x6D, 0x6E, 0x6F,
+  0x6D, 0x6E, 0x6F, 0x70, 0x6E, 0x6F, 0x70, 0x71,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+const uint8_t NIST_512_DOUBLE1[] =
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0 };
+
+const uint8_t SHA1_DOUBLE_DIGEST[] =
+{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+  0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+  0xE5, 0x46, 0x70, 0xF1 };
+
+const uint8_t SHA256_DOUBLE_DIGEST[] =
+{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+  0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+  0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+  0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 };
+
+/* SHA-512 One Block Message Sample
+   Input Message: "abc" */
+const uint8_t NIST_1024_SINGLE[] =
+{ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 };
+
+const uint8_t SHA512_224_SINGLE_DIGEST[] =
+{ 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54,
+  0xda, 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2,
+  0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4,
+  0x3e, 0x89, 0x24, 0xaa };
+const uint8_t SHA512_256_SINGLE_DIGEST[] =
+{ 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9,
+  0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab,
+  0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46,
+  0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23 };
+const uint8_t SHA384_SINGLE_DIGEST[] =
+{ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
+  0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
+  0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+  0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
+  0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
+  0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 };
+const uint8_t SHA512_SINGLE_DIGEST[] =
+{ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
+  0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
+  0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+  0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
+  0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
+  0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+  0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
+  0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f };
+
+/* SHA-512 Two Block Message Sample
+   Input Message: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" */
+const uint8_t NIST_1024_DOUBLE0[] =
+{ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+  0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+  0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+  0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+  0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+  0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+  0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+  0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+  0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
+  0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+  0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
+  0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+  0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+const uint8_t NIST_1024_DOUBLE1[] =
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80 };
+
+const uint8_t SHA512_224_DOUBLE_DIGEST[] = 
+{ 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23,
+  0x30, 0x81, 0x92, 0x64, 0x0b, 0x0c, 0x45, 0x33,
+  0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72,
+  0x68, 0x67, 0x4a, 0xf9 };
+const uint8_t SHA512_256_DOUBLE_DIGEST[] =
+{ 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8,
+  0x40, 0xda, 0x39, 0x88, 0x12, 0x1d, 0x31, 0xbe,
+  0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14,
+  0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a };
+const uint8_t SHA384_DOUBLE_DIGEST[] =
+{ 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8,
+  0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47,
+  0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2,
+  0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12,
+  0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9,
+  0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 };
+const uint8_t SHA512_DOUBLE_DIGEST[] =
+{ 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
+  0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
+  0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
+  0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
+  0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
+  0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
+  0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
+  0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 };
+
+/* ---------------- test-case low-level code ---------------- */
+
+void dump(char *label, const uint8_t *buf, int len)
+{
+    if (debug) {
+        int i;
+        printf("%s [", label);
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+}
+
+int tc_write(off_t offset, const uint8_t *buf, int len)
+{
+    dump("write ", buf, len);
+
+    for (; len > 0; offset += 4, buf += 4, len -= 4) {
+        uint32_t val;
+        val = htonl(*(uint32_t *)buf);
+        eim_write_32(offset, &val);
+    }
+
+    return 0;
+}
+
+int tc_read(off_t offset, uint8_t *buf, int len)
+{
+    uint8_t *rbuf = buf;
+    int rlen = len;
+
+    for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) {
+        uint32_t val;
+        eim_read_32(offset, &val);
+        *(uint32_t *)rbuf = ntohl(val);
+    }
+
+    dump("read  ", buf, len);
+
+    return 0;
+}
+
+int tc_expected(off_t offset, const uint8_t *expected, int len)
+{
+    uint8_t *buf;
+    int i;
+
+    buf = malloc(len);
+    if (buf == NULL) {
+        perror("malloc");
+        return 1;
+    }
+    dump("expect", expected, len);
+
+    if (tc_read(offset, buf, len) != 0)
+        goto errout;
+
+    for (i = 0; i < len; ++i)
+        if (buf[i] != expected[i]) {
+            fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+                    i, expected[i], buf[i]);
+            goto errout;
+        }
+
+    free(buf);
+    return 0;
+errout:
+    free(buf);
+    return 1;
+}
+
+int tc_init(off_t offset)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_INIT_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_next(off_t offset)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT_CMD };
+
+    return tc_write(offset, buf, 4);
+}
+
+int tc_wait(off_t offset, uint8_t status)
+{
+    uint8_t buf[4];
+
+#if 0
+    do {
+        if (tc_read(offset, buf, 4) != 0)
+            return 1;
+    } while (!(buf[3] & status));
+
+    return 0;
+#else
+    int i;
+    for (i = 0; i < 10; ++i) {
+        if (tc_read(offset, buf, 4) != 0)
+            return 1;
+        if (buf[3] & status)
+            return 0;
+    }
+    fprintf(stderr, "tc_wait timed out\n");
+    return 1;
+#endif
+}
+
+int tc_wait_ready(off_t offset)
+{
+    return tc_wait(offset, STATUS_READY_BIT);
+}
+
+int tc_wait_valid(off_t offset)
+{
+    return tc_wait(offset, STATUS_VALID_BIT);
+}
+
+/* ---------------- sanity test case ---------------- */
+
+int TC0()
+{
+    uint8_t board_type[4]       = { 'P', 'V', 'T', '1'};        /* "PVT1" */
+    uint8_t bitstream_ver[4]    = { 0x00, 0x01, 0x00, 0x0B };   /* v0.1.0b */
+    uint8_t t[4];
+
+    uint8_t seg_rngs_reg_first[4]       = { 0xAA, 0xAA, 0xAA, 0xAA};
+    uint8_t seg_rngs_reg_second[4]      = { 0xBB, 0xBB, 0xBB, 0xBB};
+    uint8_t seg_rngs_reg_third[4]       = { 0xCC, 0xCC, 0xCC, 0xCC};
+
+    uint8_t seg_ciphers_reg_first[4]    = { 0xDD, 0xDD, 0xDD, 0xDD};
+    uint8_t seg_ciphers_reg_second[4]   = { 0xEE, 0xEE, 0xEE, 0xEE};
+    uint8_t seg_ciphers_reg_third[4]    = { 0xFF, 0xFF, 0xFF, 0xFF};
+
+    if (!quiet)
+        printf("TC0: Reading board type, version, and dummy reg from global registers.\n");
+
+    /* write current time into dummy register, then try to read it back
+     * to make sure that we can actually write something into EIM
+     */
+    (void)time((time_t *)t);
+    tc_write(ADDR_GLOBAL_DUMMY_REG, (void *)&t, 4);
+
+    return
+        tc_expected(ADDR_GLOBAL_BOARD_TYPE,    board_type,    4) ||
+        tc_expected(ADDR_GLOBAL_BITSTREAM_VER, bitstream_ver, 4) || 
+        tc_expected(ADDR_GLOBAL_DUMMY_REG,     (void *)t,     4) ||
+
+        tc_expected(SEGMENT_OFFSET_RNGS + (0 << 2), seg_rngs_reg_first,  4) ||
+        tc_expected(SEGMENT_OFFSET_RNGS + (1 << 2), seg_rngs_reg_second, 4) ||
+        tc_expected(SEGMENT_OFFSET_RNGS + (2 << 2), seg_rngs_reg_third,  4) ||
+
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (0 << 2), seg_ciphers_reg_first,  4) ||
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (1 << 2), seg_ciphers_reg_second, 4) ||
+        tc_expected(SEGMENT_OFFSET_CIPHERS + (2 << 2), seg_ciphers_reg_third,  4);
+}
+
+/* ---------------- SHA-1 test cases ---------------- */
+
+/* TC1: Read name and version from SHA-1 core. */
+int TC1(void)
+{
+    uint8_t name0[4]   = { 0x73, 0x68, 0x61, 0x31 };    /* "sha1" */
+    uint8_t name1[4]   = { 0x20, 0x20, 0x20, 0x20 };    /* "    " */
+    uint8_t version[4] = { 0x30, 0x2e, 0x35, 0x30 };    /* "0.50" */
+
+    if (!quiet)
+        printf("TC1: Reading name, type and version words from SHA-1 core.\n");
+
+    return
+        tc_expected(SHA1_ADDR_NAME0, name0, 4) ||
+        tc_expected(SHA1_ADDR_NAME1, name1, 4) ||
+        tc_expected(SHA1_ADDR_VERSION, version, 4);
+}
+
+/* TC2: SHA-1 Single block message test as specified by NIST. */
+int TC2(void)
+{
+    const uint8_t *block = NIST_512_SINGLE;
+    const uint8_t *expected = SHA1_SINGLE_DIGEST;
+    int ret;
+
+    if (!quiet)
+        printf("TC2: Single block message test for SHA-1.\n");
+
+    /* Write block to SHA-1. */
+    tc_write(SHA1_ADDR_BLOCK, block, SHA1_BLOCK_LEN);
+    /* Start initial block hashing, wait and check status. */
+    tc_init(SHA1_ADDR_CTRL);
+    tc_wait_valid(SHA1_ADDR_STATUS);
+    /* Extract the digest. */
+    ret = tc_expected(SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
+    return ret;
+}
+
+/* TC3: SHA-1 Double block message test as specified by NIST. */
+int TC3(void)
+{
+    const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint8_t block0_expected[] =
+        { 0xF4, 0x28, 0x68, 0x18, 0xC3, 0x7B, 0x27, 0xAE,
+          0x04, 0x08, 0xF5, 0x81, 0x84, 0x67, 0x71, 0x48,
+          0x4A, 0x56, 0x65, 0x72 };
+    const uint8_t *expected = SHA1_DOUBLE_DIGEST;
+    int ret;
+
+    if (!quiet)
+        printf("TC3: Double block message test for SHA-1.\n");
+
+    /* Write first block to SHA-1. */
+    tc_write(SHA1_ADDR_BLOCK, block[0], SHA1_BLOCK_LEN);
+    /* Start initial block hashing, wait and check status. */
+    tc_init(SHA1_ADDR_CTRL);
+    tc_wait_valid(SHA1_ADDR_STATUS);
+    /* Extract the first digest. */
+    tc_expected(SHA1_ADDR_DIGEST, block0_expected, SHA1_DIGEST_LEN);
+    /* Write second block to SHA-1. */
+    tc_write(SHA1_ADDR_BLOCK, block[1], SHA1_BLOCK_LEN);
+    /* Start next block hashing, wait and check status. */
+    tc_next(SHA1_ADDR_CTRL);
+    tc_wait_valid(SHA1_ADDR_STATUS);
+    /* Extract the second digest. */
+    ret = tc_expected(SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
+    return ret;
+}
+
+/* ---------------- SHA-256 test cases ---------------- */
+
+/* TC4: Read name and version from SHA-256 core. */
+int TC4(void)
+{
+    uint8_t name0[4]   = { 0x73, 0x68, 0x61, 0x32 };    /* "sha2" */
+    uint8_t name1[4]   = { 0x2d, 0x32, 0x35, 0x36 };    /* "-256" */
+    uint8_t version[4] = { 0x30, 0x2e, 0x38, 0x30 };    /* "0.80" */
+
+    if (!quiet)
+        printf("TC4: Reading name, type and version words from SHA-256 core.\n");
+
+    return
+        tc_expected(SHA256_ADDR_NAME0, name0, 4) ||
+        tc_expected(SHA256_ADDR_NAME1, name1, 4) ||
+        tc_expected(SHA256_ADDR_VERSION, version, 4);
+}
+
+/* TC5: SHA-256 Single block message test as specified by NIST. */
+int TC5()
+{
+    const uint8_t *block = NIST_512_SINGLE;
+    const uint8_t *expected = SHA256_SINGLE_DIGEST;
+
+    if (!quiet)
+        printf("TC5: Single block message test for SHA-256.\n");
+
+    return
+        /* Write block to SHA-256. */
+        tc_write(SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN) ||
+        /* Start initial block hashing, wait and check status. */
+        tc_init(SHA256_ADDR_CTRL) ||
+        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        /* Extract the digest. */
+        tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+}
+
+/* TC6: SHA-256 Double block message test as specified by NIST. */
+int TC6()
+{
+    const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint8_t block0_expected[] = 
+        { 0x85, 0xE6, 0x55, 0xD6, 0x41, 0x7A, 0x17, 0x95,
+          0x33, 0x63, 0x37, 0x6A, 0x62, 0x4C, 0xDE, 0x5C,
+          0x76, 0xE0, 0x95, 0x89, 0xCA, 0xC5, 0xF8, 0x11,
+          0xCC, 0x4B, 0x32, 0xC1, 0xF2, 0x0E, 0x53, 0x3A };
+    const uint8_t *expected = SHA256_DOUBLE_DIGEST;
+
+    if (!quiet)
+        printf("TC6: Double block message test for SHA-256.\n");
+
+    return
+        /* Write first block to SHA-256. */
+        tc_write(SHA256_ADDR_BLOCK, block[0], SHA256_BLOCK_LEN) ||
+        /* Start initial block hashing, wait and check status. */
+        tc_init(SHA256_ADDR_CTRL) ||
+        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        /* Extract the first digest. */
+        tc_expected(SHA256_ADDR_DIGEST, block0_expected, SHA256_DIGEST_LEN) ||
+        /* Write second block to SHA-256. */
+        tc_write(SHA256_ADDR_BLOCK, block[1], SHA256_BLOCK_LEN) ||
+        /* Start next block hashing, wait and check status. */
+        tc_next(SHA256_ADDR_CTRL) ||
+        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        /* Extract the second digest. */
+        tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+}
+
+/* TC7: SHA-256 Huge message test. */
+int TC7()
+{
+    static const uint8_t block[] =
+        { 0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+          0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+          0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+          0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+          0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+          0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+          0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+          0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f };
+
+    /* final digest after 1000 iterations */
+    static const uint8_t expected[] = 
+        { 0x76, 0x38, 0xf3, 0xbc, 0x50, 0x0d, 0xd1, 0xa6,
+          0x58, 0x6d, 0xd4, 0xd0, 0x1a, 0x15, 0x51, 0xaf,
+          0xd8, 0x21, 0xd2, 0x35, 0x2f, 0x91, 0x9e, 0x28,
+          0xd5, 0x84, 0x2f, 0xab, 0x03, 0xa4, 0x0f, 0x2a };
+
+    int i, n = 1000;
+
+    if (!quiet)
+        printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+
+    /* Write block data to SHA-256. */
+    if (tc_write(SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN))
+        return 1;
+
+    /* Start initial block hashing, wait and check status. */
+    if (tc_init(SHA256_ADDR_CTRL) ||
+        tc_wait_ready(SHA256_ADDR_STATUS))
+        return 1;
+
+    /* First block done. Do the rest. */
+    for (i = 1; i < n; ++i) {
+        /* Start next block hashing, wait and check status. */
+        if (tc_next(SHA256_ADDR_CTRL) ||
+            tc_wait_ready(SHA256_ADDR_STATUS))
+            return 1;
+    }
+
+    /* XXX valid is probably set at the same time as ready */
+    if (tc_wait_valid(SHA256_ADDR_STATUS))
+        return 1;
+    /* Extract the final digest. */
+    return tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+}
+
+/* ---------------- SHA-512 test cases ---------------- */
+
+/* TC8: Read name and version from SHA-512 core. */
+int TC8()
+{
+    uint8_t name0[4]   = { 0x73, 0x68, 0x61, 0x32 };    /* "sha2" */
+    uint8_t name1[4]   = { 0x2d, 0x35, 0x31, 0x32 };    /* "-512" */
+    uint8_t version[4] = { 0x30, 0x2e, 0x38, 0x30 };    /* "0.80" */
+
+    if (!quiet)
+        printf("TC8: Reading name, type and version words from SHA-512 core.\n");
+
+    return
+        tc_expected(SHA512_ADDR_NAME0, name0, 4) ||
+        tc_expected(SHA512_ADDR_NAME1, name1, 4) ||
+        tc_expected(SHA512_ADDR_VERSION, version, 4);
+}
+
+/* TC9: SHA-512 Single block message test as specified by NIST.
+   We do this for all modes. */
+int tc9(int mode, const uint8_t *expected, int digest_len)
+{
+    const uint8_t *block = NIST_1024_SINGLE;
+    uint8_t init[4] = { 0, 0, 0, CTRL_INIT_CMD + mode };
+
+    return
+        /* Write block to SHA-512. */
+        tc_write(SHA512_ADDR_BLOCK, block, SHA512_BLOCK_LEN) ||
+        /* Start initial block hashing, wait and check status. */
+        tc_write(SHA512_ADDR_CTRL, init, 4) ||
+        tc_wait_valid(SHA512_ADDR_STATUS) ||
+        /* Extract the digest. */
+        tc_expected(SHA512_ADDR_DIGEST, expected, digest_len);
+}
+
+int TC9()
+{
+    if (!quiet)
+        printf("TC9-1: Single block message test for SHA-512/224.\n");
+    if (tc9(MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC9-2: Single block message test for SHA-512/256.\n");
+    if (tc9(MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST, SHA512_256_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC9-3: Single block message test for SHA-384.\n");
+    if (tc9(MODE_SHA_384, SHA384_SINGLE_DIGEST, SHA384_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC9-4: Single block message test for SHA-512.\n");
+    if (tc9(MODE_SHA_512, SHA512_SINGLE_DIGEST, SHA512_DIGEST_LEN) != 0)
+        return 1;
+
+    return 0;
+}
+
+/* TC10: SHA-512 Double block message test as specified by NIST.
+   We do this for all modes. */
+int tc10(int mode, const uint8_t *expected, int digest_len)
+{
+    const uint8_t *block[2] = { NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 };
+    uint8_t init[4] = { 0, 0, 0, CTRL_INIT_CMD + mode };
+    uint8_t next[4] = { 0, 0, 0, CTRL_NEXT_CMD + mode };
+
+    return
+        /* Write first block to SHA-512. */
+        tc_write(SHA512_ADDR_BLOCK, block[0], SHA512_BLOCK_LEN) ||
+        /* Start initial block hashing, wait and check status. */
+        tc_write(SHA512_ADDR_CTRL, init, 4) ||
+        tc_wait_ready(SHA512_ADDR_STATUS) ||
+        /* Write second block to SHA-512. */
+        tc_write(SHA512_ADDR_BLOCK, block[1], SHA512_BLOCK_LEN) ||
+        /* Start next block hashing, wait and check status. */
+        tc_write(SHA512_ADDR_CTRL, next, 4) ||
+        tc_wait_valid(SHA512_ADDR_STATUS) ||
+        /* Extract the digest. */
+        tc_expected(SHA512_ADDR_DIGEST, expected, digest_len);
+}
+
+int TC10()
+{
+    if (!quiet)
+        printf("TC10-1: Double block message test for SHA-512/224.\n");
+    if (tc10(MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC10-2: Double block message test for SHA-512/256.\n");
+    if (tc10(MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST, SHA512_256_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC10-3: Double block message test for SHA-384.\n");
+    if (tc10(MODE_SHA_384, SHA384_DOUBLE_DIGEST, SHA384_DIGEST_LEN) != 0)
+        return 1;
+
+    if (!quiet)
+        printf("TC10-4: Double block message test for SHA-512.\n");
+    if (tc10(MODE_SHA_512, SHA512_DOUBLE_DIGEST, SHA512_DIGEST_LEN) != 0)
+        return 1;
+
+    return 0;
+}
+
+/* ---------------- main ---------------- */
+
+/* signal handler for ctrl-c to end repeat testing */
+unsigned long iter = 0;
+struct timeval tv_start, tv_end;
+void sighandler(int unused)
+{
+    double tv_diff;
+
+    gettimeofday(&tv_end, NULL);
+    tv_diff = (double)(tv_end.tv_sec - tv_start.tv_sec) +
+        (double)(tv_end.tv_usec - tv_start.tv_usec)/1000000;
+    printf("\n%lu iterations in %.3f seconds (%.3f iterations/sec)\n",
+           iter, tv_diff, (double)iter/tv_diff);
+    exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+    typedef int (*tcfp)(void);
+    tcfp all_tests[] = { TC0, TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10 };
+    tcfp sha1_tests[] = { TC1, TC2, TC3 };
+    tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
+    tcfp sha512_tests[] = { TC8, TC9, TC10 };
+
+    char *usage = "Usage: %s [-h] [-d] [-q] [-r] tc...\n";
+    int i, j, opt;
+
+    while ((opt = getopt(argc, argv, "h?dqr")) != -1) {
+        switch (opt) {
+        case 'h':
+        case '?':
+            printf(usage, argv[0]);
+            return EXIT_SUCCESS;
+        case 'd':
+            debug = 1;
+            break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'r':
+            repeat = 1;
+            break;
+        default:
+            fprintf(stderr, usage, argv[0]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    /* set up EIM */
+    if (eim_setup() != 0) {
+        fprintf(stderr, "EIM setup failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* repeat one test until interrupted */
+    if (repeat) {
+        tcfp tc;
+        if (optind != argc - 1) {
+            fprintf(stderr, "only one test case can be repeated\n");
+            return EXIT_FAILURE;
+        }
+        j = atoi(argv[optind]);
+        if (j < 0 || j >= sizeof(all_tests)/sizeof(all_tests[0])) {
+            fprintf(stderr, "invalid test number %s\n", argv[optind]);
+            return EXIT_FAILURE;
+        }
+        tc = (all_tests[j]);
+        srand(time(NULL));
+        signal(SIGINT, sighandler);
+        gettimeofday(&tv_start, NULL);
+        while (1) {
+            ++iter;
+            if ((iter & 0xffff) == 0) {
+                printf(".");
+                fflush(stdout);
+            }
+            if (tc() != 0)
+                sighandler(0);
+        }
+        return EXIT_SUCCESS;    /*NOTREACHED*/
+    }
+
+    /* no args == run all tests */
+    if (optind >= argc) {
+        for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+            if (all_tests[j]() != 0)
+                return EXIT_FAILURE;
+        return EXIT_SUCCESS;
+    }
+
+    /* run one or more tests (by number) or groups of tests (by name) */
+    for (i = optind; i < argc; ++i) {
+        if (strcmp(argv[i], "all") == 0) {
+            for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+                if (all_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (strcmp(argv[i], "sha1") == 0) {
+            for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
+                if (sha1_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (strcmp(argv[i], "sha256") == 0) {
+            for (j = 0; j < sizeof(sha256_tests)/sizeof(sha256_tests[0]); ++j)
+                if (sha256_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (strcmp(argv[i], "sha512") == 0) {
+            for (j = 0; j < sizeof(sha512_tests)/sizeof(sha512_tests[0]); ++j)
+                if (sha512_tests[j]() != 0)
+                    return EXIT_FAILURE;
+        }
+        else if (isdigit(argv[i][0]) &&
+                 (((j = atoi(argv[i])) >= 0) &&
+                  (j < sizeof(all_tests)/sizeof(all_tests[0])))) {
+            if (all_tests[j]() != 0)
+                return EXIT_FAILURE;
+        }
+        else {
+            fprintf(stderr, "unknown test case %s\n", argv[i]);
+            return EXIT_FAILURE;
+        }
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/novena/src/sw/hash_tester_i2c.c b/novena/src/sw/hash_tester_i2c.c
new file mode 100644
index 0000000..70b98c2
--- /dev/null
+++ b/novena/src/sw/hash_tester_i2c.c
@@ -0,0 +1,1013 @@
+/* 
+ * hash_tester.c
+ * --------------
+ * This program sends several commands to the coretest_hashes subsystem
+ * in order to verify the SHA-1, SHA-256 and SHA-512/x hash function
+ * cores.
+ *
+ * Note: This version of the program talks to the FPGA over an I2C bus.
+ *
+ * The single and dual block test cases are taken from the
+ * NIST KAT document:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ *
+ * 
+ * Authors: Joachim Strömbergson, Paul Selkirk
+ * Copyright (c) 2014, SUNET
+ * 
+ * Redistribution and use in source and binary forms, with or 
+ * without modification, are permitted provided that the following 
+ * conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+/* I2C configuration */
+#define I2C_dev  "/dev/i2c-2"
+#define I2C_addr 0x0f
+
+/* command codes */
+#define SOC       0x55
+#define EOC       0xaa
+#define READ_CMD  0x10
+#define WRITE_CMD 0x11
+#define RESET_CMD 0x01
+
+/* response codes */
+#define SOR       0xaa
+#define EOR       0x55
+#define READ_OK   0x7f
+#define WRITE_OK  0x7e
+#define RESET_OK  0x7d
+#define UNKNOWN   0xfe
+#define ERROR     0xfd
+
+/* instead of core number 0 we have a page of global registers */
+#define GLOBAL_ADDR_PREFIX	0x00
+#define ADDR_GLOBAL_BOARD_TYPE  0x00
+#define ADDR_GLOBAL_BITSTREAM_VER 0x01
+#define ADDR_GLOBAL_DUMMY_REG   0xff
+
+#define SEGMENT_OFFSET_HASHES   0x00
+#define SEGMENT_OFFSET_RNGS     0x20
+#define SEGMENT_OFFSET_CIPHERS  0x40
+
+/* addresses and codes common to all hash cores */
+#define ADDR_NAME0              0x00
+#define ADDR_NAME1              0x01
+#define ADDR_VERSION            0x02
+#define ADDR_CTRL               0x08
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             0x09
+#define STATUS_READY_BIT        1
+#define STATUS_VALID_BIT        2
+
+/* addresses and codes for the specific hash cores */
+#define SHA1_ADDR_PREFIX        0x01
+#define SHA1_ADDR_BLOCK         0x10
+#define SHA1_BLOCK_LEN          16
+#define SHA1_ADDR_DIGEST        0x20
+#define SHA1_DIGEST_LEN         5
+
+#define SHA256_ADDR_PREFIX      0x02
+#define SHA256_ADDR_BLOCK       0x10
+#define SHA256_BLOCK_LEN        16
+#define SHA256_ADDR_DIGEST      0x20
+#define SHA256_DIGEST_LEN       8
+
+#define SHA512_ADDR_PREFIX      0x03
+#define SHA512_CTRL_MODE_LOW    2
+#define SHA512_CTRL_MODE_HIGH   3
+#define SHA512_ADDR_BLOCK       0x10
+#define SHA512_BLOCK_LEN        32
+#define SHA512_ADDR_DIGEST      0x40
+#define SHA512_DIGEST_LEN       16
+#define MODE_SHA_512_224        0
+#define MODE_SHA_512_256        1
+#define MODE_SHA_384            2
+#define MODE_SHA_512            3
+
+int i2cfd;
+int debug = 0;
+
+/* SHA-1/SHA-256 One Block Message Sample
+   Input Message: "abc" */
+const uint32_t NIST_512_SINGLE[] =
+{ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000018 };
+
+const uint32_t SHA1_SINGLE_DIGEST[] =
+{ 0xa9993e36, 0x4706816a, 0xba3e2571, 0x7850c26c,
+  0x9cd0d89d };
+
+const uint32_t SHA256_SINGLE_DIGEST[] =
+{ 0xBA7816BF, 0x8F01CFEA, 0x414140DE, 0x5DAE2223,
+  0xB00361A3, 0x96177A9C, 0xB410FF61, 0xF20015AD };
+
+/* SHA-1/SHA-256 Two Block Message Sample
+   Input Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */
+const uint32_t NIST_512_DOUBLE0[] =
+{ 0x61626364, 0x62636465, 0x63646566, 0x64656667,
+  0x65666768, 0x66676869, 0x6768696A, 0x68696A6B,
+  0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F,
+  0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000 };
+const uint32_t NIST_512_DOUBLE1[] =
+{ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x000001C0 };
+
+const uint32_t SHA1_DOUBLE_DIGEST[] =
+{ 0x84983E44, 0x1C3BD26E, 0xBAAE4AA1, 0xF95129E5,
+  0xE54670F1 };
+
+const uint32_t SHA256_DOUBLE_DIGEST[] =
+{ 0x248D6A61, 0xD20638B8, 0xE5C02693, 0x0C3E6039,
+  0xA33CE459, 0x64FF2167, 0xF6ECEDD4, 0x19DB06C1 };
+
+/* SHA-512 One Block Message Sample
+   Input Message: "abc" */
+const uint32_t NIST_1024_SINGLE[] =
+{ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000018 };
+
+const uint32_t SHA512_224_SINGLE_DIGEST[] =
+{ 0x4634270f, 0x707b6a54, 0xdaae7530, 0x460842e2,
+  0x0e37ed26, 0x5ceee9a4, 0x3e8924aa };
+const uint32_t SHA512_256_SINGLE_DIGEST[] =
+{ 0x53048e26, 0x81941ef9, 0x9b2e29b7, 0x6b4c7dab,
+  0xe4c2d0c6, 0x34fc6d46, 0xe0e2f131, 0x07e7af23 };
+const uint32_t SHA384_SINGLE_DIGEST[] =
+{ 0xcb00753f, 0x45a35e8b, 0xb5a03d69, 0x9ac65007,
+  0x272c32ab, 0x0eded163, 0x1a8b605a, 0x43ff5bed,
+  0x8086072b, 0xa1e7cc23, 0x58baeca1, 0x34c825a7 };
+const uint32_t SHA512_SINGLE_DIGEST[] =
+{ 0xddaf35a1, 0x93617aba, 0xcc417349, 0xae204131,
+  0x12e6fa4e, 0x89a97ea2, 0x0a9eeee6, 0x4b55d39a,
+  0x2192992a, 0x274fc1a8, 0x36ba3c23, 0xa3feebbd,
+  0x454d4423, 0x643ce80e, 0x2a9ac94f, 0xa54ca49f };
+
+/* SHA-512 Two Block Message Sample
+   Input Message: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" */
+const uint32_t NIST_1024_DOUBLE0[] =
+{ 0x61626364, 0x65666768, 0x62636465, 0x66676869,
+  0x63646566, 0x6768696a, 0x64656667, 0x68696a6b,
+  0x65666768, 0x696a6b6c, 0x66676869, 0x6a6b6c6d,
+  0x6768696a, 0x6b6c6d6e, 0x68696a6b, 0x6c6d6e6f,
+  0x696a6b6c, 0x6d6e6f70, 0x6a6b6c6d, 0x6e6f7071,
+  0x6b6c6d6e, 0x6f707172, 0x6c6d6e6f, 0x70717273,
+  0x6d6e6f70, 0x71727374, 0x6e6f7071, 0x72737475,
+  0x80000000, 0x00000000, 0x00000000, 0x00000000 };
+const uint32_t NIST_1024_DOUBLE1[] =
+{ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000380 };
+
+const uint32_t SHA512_224_DOUBLE_DIGEST[] = 
+{ 0x23fec5bb, 0x94d60b23, 0x30819264, 0x0b0c4533,
+  0x35d66473, 0x4fe40e72, 0x68674af9 };
+const uint32_t SHA512_256_DOUBLE_DIGEST[] =
+{ 0x3928e184, 0xfb8690f8, 0x40da3988, 0x121d31be,
+  0x65cb9d3e, 0xf83ee614, 0x6feac861, 0xe19b563a };
+const uint32_t SHA384_DOUBLE_DIGEST[] =
+{ 0x09330c33, 0xf71147e8, 0x3d192fc7, 0x82cd1b47,
+  0x53111b17, 0x3b3b05d2, 0x2fa08086, 0xe3b0f712,
+  0xfcc7c71a, 0x557e2db9, 0x66c3e9fa, 0x91746039 };
+const uint32_t SHA512_DOUBLE_DIGEST[] =
+{ 0x8e959b75, 0xdae313da, 0x8cf4f728, 0x14fc143f,
+  0x8f7779c6, 0xeb9f7fa1, 0x7299aead, 0xb6889018,
+  0x501d289e, 0x4900f7e4, 0x331b99de, 0xc4b5433a,
+  0xc7d329ee, 0xb6dd2654, 0x5e96e55b, 0x874be909 };
+
+/* ---------------- I2C low-level code ---------------- */
+int i2c_setup(char *dev, int addr)
+{
+    i2cfd = open(dev, O_RDWR);
+    if (i2cfd < 0) {
+	fprintf(stderr, "Unable to open %s: ", dev);
+	perror("");
+	i2cfd = 0;
+	return 1;
+    }
+
+    if (ioctl(i2cfd, I2C_SLAVE, addr) < 0) {
+	fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+	perror("");
+	return 1;
+    }
+
+    return 0;
+}
+
+int i2c_write(uint8_t *buf, int len)
+{
+    if (debug) {
+	int i;
+	printf("write [");
+	for (i = 0; i < len; ++i)
+	    printf(" %02x", buf[i]);
+	printf(" ]\n");
+    }
+
+    if (write(i2cfd, buf, len) != len) {
+	perror("i2c write failed");
+	return 1;
+    }
+
+    return 0;
+}
+
+int i2c_read(uint8_t *b)
+{
+    /* read() on the i2c device only returns one byte at a time,
+     * and tc_get_resp() needs to parse the response one byte at a time
+     */
+    if (read(i2cfd, b, 1) != 1) {
+	perror("i2c read failed");
+	return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+int tc_send_write_cmd(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    uint8_t buf[9];
+
+    buf[0] = SOC;
+    buf[1] = WRITE_CMD;
+    buf[2] = addr0;
+    buf[3] = addr1;
+    buf[4] = (data >> 24) & 0xff;
+    buf[5] = (data >> 16) & 0xff;
+    buf[6] = (data >> 8) & 0xff;
+    buf[7] = data & 0xff;
+    buf[8] = EOC;
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_send_read_cmd(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t buf[5];
+
+    buf[0] = SOC;
+    buf[1] = READ_CMD;
+    buf[2] = addr0;
+    buf[3] = addr1;
+    buf[4] = EOC;
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_get_resp(uint8_t *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; ++i) {
+	if (i2c_read(&buf[i]) != 0)
+	    return 1;
+	if ((i == 0) && (buf[i] != SOR)) {
+	    /* we've gotten out of sync, and there's probably nothing we can do */
+	    fprintf(stderr, "response byte 0: expected 0x%02x (SOR), got 0x%02x\n",
+		    SOR, buf[0]);
+	    return 1;
+	}
+	else if (i == 1) {	/* response code */
+	    switch (buf[i]) {
+	    case READ_OK:
+		len = 9;
+		break;
+	    case WRITE_OK:
+		len = 5;
+		break;
+	    case RESET_OK:
+		len = 3;
+		break;
+	    case ERROR:
+	    case UNKNOWN:
+		len = 4;
+		break;
+	    default:
+		/* we've gotten out of sync, and there's probably nothing we can do */
+		fprintf(stderr, "unknown response code 0x%02x\n", buf[i]);
+		return 1;
+	    }
+	}
+    }
+
+    if (debug) {
+	printf("read  [");
+	for (i = 0; i < len; ++i)
+	    printf(" %02x", buf[i]);
+	printf(" ]\n");
+    }
+
+    return 0;
+}
+
+int tc_get_expected(uint8_t *expected, int len)
+{
+    uint8_t buf[9];
+    int i;
+
+    if (tc_get_resp(buf, sizeof(buf)) != 0)
+	return 1;
+
+    for (i = 0; i < len; ++i) {
+	if (buf[i] != expected[i]) {
+	    fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+		    i, expected[i], buf[i]);
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
+int tc_get_write_resp(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t expected[5];
+
+    expected[0] = SOR;
+    expected[1] = WRITE_OK;
+    expected[2] = addr0;
+    expected[3] = addr1;
+    expected[4] = EOR;
+
+    return tc_get_expected(expected, sizeof(expected));
+}
+
+int tc_get_read_resp(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    uint8_t expected[9];
+
+    expected[0] = SOR;
+    expected[1] = READ_OK;
+    expected[2] = addr0;
+    expected[3] = addr1;
+    expected[4] = (data >> 24) & 0xff;
+    expected[5] = (data >> 16) & 0xff;
+    expected[6] = (data >> 8) & 0xff;
+    expected[7] = data & 0xff;
+    expected[8] = EOR;
+
+    return tc_get_expected(expected, sizeof(expected));
+}
+
+int tc_write(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    return (tc_send_write_cmd(addr0, addr1, data) ||
+	    tc_get_write_resp(addr0, addr1));
+}
+
+int tc_read(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    return (tc_send_read_cmd(addr0, addr1) ||
+	    tc_get_read_resp(addr0, addr1, data));
+}
+
+int tc_init(uint8_t addr0)
+{
+    return tc_write(addr0, ADDR_CTRL, CTRL_INIT_CMD);
+}
+
+int tc_next(uint8_t addr0)
+{
+    return tc_write(addr0, ADDR_CTRL, CTRL_NEXT_CMD);
+}
+
+int tc_wait(uint8_t addr0, uint8_t status)
+{
+    uint8_t buf[9];
+
+    do {
+	if (tc_send_read_cmd(addr0, ADDR_STATUS) != 0)
+	    return 1;
+	if (tc_get_resp(buf, 9) != 0)
+	    return 1;
+	if (buf[1] != READ_OK)
+	    return 1;
+    } while ((buf[7] & status) != status);
+
+    return 0;
+}
+
+int tc_wait_ready(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_READY_BIT);
+}
+
+int tc_wait_valid(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_VALID_BIT);
+}
+
+/* ---------------- sanity test case ---------------- */
+
+int TC0()
+{
+    uint32_t board_type = 0x50565431;		/* "PVT1" */
+    uint32_t bitstream_ver = 0x0001000B;	/* v0.1.0b */
+    uint32_t t;
+
+    printf("TC0: Reading board type, version, and dummy reg from global registers.\n");
+
+    /* write current time into dummy register, then try to read it back
+     * to make sure that we can actually write something into EIM
+     */
+    t = time(NULL);
+    tc_write(GLOBAL_ADDR_PREFIX, ADDR_GLOBAL_DUMMY_REG, t);
+
+    return
+        tc_read(GLOBAL_ADDR_PREFIX, ADDR_GLOBAL_BOARD_TYPE,    board_type) ||
+        tc_read(GLOBAL_ADDR_PREFIX, ADDR_GLOBAL_BITSTREAM_VER, bitstream_ver) || 
+        tc_read(GLOBAL_ADDR_PREFIX, ADDR_GLOBAL_DUMMY_REG,     t);
+}
+
+/* ---------------- SHA-1 test cases ---------------- */
+
+int sha1_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA1_ADDR_PREFIX, addr, data);
+}
+
+int sha1_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA1_ADDR_PREFIX, addr, data);
+}
+
+int sha1_init(void)
+{
+    return tc_init(SHA1_ADDR_PREFIX);
+}
+
+int sha1_next(void)
+{
+    return tc_next(SHA1_ADDR_PREFIX);
+}
+
+int sha1_wait_ready(void)
+{
+    return tc_wait_ready(SHA1_ADDR_PREFIX);
+}
+
+int sha1_wait_valid(void)
+{
+    return tc_wait_valid(SHA1_ADDR_PREFIX);
+}
+
+/* TC1: Read name and version from SHA-1 core. */
+int TC1(void)
+{
+    uint32_t name0   = 0x73686131;	/* "sha1" */
+    uint32_t name1   = 0x20202020;	/* "    " */
+    uint32_t version = 0x302e3530;	/* "0.50" */
+
+    printf("TC1: Reading name, type and version words from SHA-1 core.\n");
+
+    return 
+	sha1_read(ADDR_NAME0, name0) ||
+	sha1_read(ADDR_NAME1, name1) ||
+	sha1_read(ADDR_VERSION, version);
+}
+
+/* TC2: SHA-1 Single block message test as specified by NIST. */
+int TC2(void)
+{
+    const uint32_t *block = NIST_512_SINGLE;
+    const uint32_t *expected = SHA1_SINGLE_DIGEST;
+    int i;
+
+    printf("TC2: Single block message test for SHA-1.\n");
+
+    /* Write block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha1_init() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* TC3: SHA-1 Double block message test as specified by NIST. */
+int TC3(void)
+{
+    const uint32_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint32_t block0_expected[] =
+	{ 0xF4286818, 0xC37B27AE, 0x0408F581, 0x84677148, 0x4A566572 };
+    const uint32_t *expected = SHA1_DOUBLE_DIGEST;
+    int i;
+
+    printf("TC3: Double block message test for SHA-1.\n");
+
+    /* Write first block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha1_init() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the first digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, block0_expected[i]) != 0)
+	    return 1;
+    }
+
+    /* Write second block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha1_next() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the second digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- SHA-256 test cases ---------------- */
+
+int sha256_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA256_ADDR_PREFIX, addr, data);
+}
+
+int sha256_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA256_ADDR_PREFIX, addr, data);
+}
+
+int sha256_init(void)
+{
+    return tc_init(SHA256_ADDR_PREFIX);
+}
+
+int sha256_next(void)
+{
+    return tc_next(SHA256_ADDR_PREFIX);
+}
+
+int sha256_wait_ready(void)
+{
+    return tc_wait_ready(SHA256_ADDR_PREFIX);
+}
+
+int sha256_wait_valid(void)
+{
+    return tc_wait_valid(SHA256_ADDR_PREFIX);
+}
+
+/* TC4: Read name and version from SHA-256 core. */
+int TC4(void)
+{
+    uint32_t name0     = 0x73686132;	/* "sha2" */
+    uint32_t name1     = 0x2d323536;	/* "-256" */
+    uint32_t version   = 0x302e3830;	/* "0.80" */
+
+    printf("TC4: Reading name, type and version words from SHA-256 core.\n");
+
+    return
+	sha256_read(ADDR_NAME0, name0) ||
+	sha256_read(ADDR_NAME1, name1) ||
+	sha256_read(ADDR_VERSION, version);
+}
+
+/* TC5: SHA-256 Single block message test as specified by NIST. */
+int TC5(void)
+{
+    const uint32_t *block = NIST_512_SINGLE;
+    const uint32_t *expected = SHA256_SINGLE_DIGEST;
+    int i;
+
+    printf("TC5: Single block message test for SHA-256.\n");
+
+    /* Write block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+
+    return 0;
+}
+
+/* TC6: SHA-1 Double block message test as specified by NIST. */
+int TC6(void)
+{
+    const uint32_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint32_t block0_expected[] = 
+	{ 0x85E655D6, 0x417A1795, 0x3363376A, 0x624CDE5C,
+	  0x76E09589, 0xCAC5F811, 0xCC4B32C1, 0xF20E533A };
+    const uint32_t *expected = SHA256_DOUBLE_DIGEST;
+    int i;
+
+    printf("TC6: Double block message test for SHA-256.\n");
+
+    /* Write first block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the first digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, block0_expected[i]) != 0)
+	    return 1;
+    }
+
+    /* Write second block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha256_next() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the second digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* TC7: SHA-256 Huge message test. */
+int TC7(void)
+{
+    static const uint32_t block[] =
+	{ 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f };
+
+    /* final digest after 1000 iterations */
+    static const uint32_t expected[] = 
+	{ 0x7638f3bc, 0x500dd1a6, 0x586dd4d0, 0x1a1551af,
+	  0xd821d235, 0x2f919e28, 0xd5842fab, 0x03a40f2a };
+
+    int i, n = 1000;
+
+    printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+
+    /* Write first block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write( SHA256_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_ready() != 0))
+	return 1;
+
+    /* First block done. Do the rest. */
+    for (i = 1; i < n; ++i) {
+	/* Start next block hashing, wait and check status. */
+	if ((sha256_next() != 0) || (sha256_wait_ready() != 0))
+	    return 1;
+    }
+
+    /* XXX valid is probably set at the same time as ready */
+    if (sha256_wait_valid() != 0)
+	return 1;
+    /* Extract the final digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- SHA-512 test cases ---------------- */
+
+int sha512_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA512_ADDR_PREFIX, addr, data);
+}
+
+int sha512_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA512_ADDR_PREFIX, addr, data);
+}
+
+int sha512_init(uint8_t mode)
+{
+    return tc_write(SHA512_ADDR_PREFIX, ADDR_CTRL,
+		    CTRL_INIT_CMD + (mode << SHA512_CTRL_MODE_LOW));
+}
+
+int sha512_next(uint8_t mode)
+{
+    return tc_write(SHA512_ADDR_PREFIX, ADDR_CTRL,
+		    CTRL_NEXT_CMD + (mode << SHA512_CTRL_MODE_LOW));
+}
+
+int sha512_wait_ready(void)
+{
+    return tc_wait_ready(SHA512_ADDR_PREFIX);
+}
+
+int sha512_wait_valid(void)
+{
+    return tc_wait_valid(SHA512_ADDR_PREFIX);
+}
+
+/* TC8: Read name and version from SHA-512 core. */
+int TC8(void)
+{
+    uint32_t name0         = 0x73686132;	/* "sha2" */
+    uint32_t name1         = 0x2d353132;	/* "-512" */
+    uint32_t version       = 0x302e3830;	/* "0.80" */
+
+    printf("TC8: Reading name, type and version words from SHA-512 core.\n");
+
+    return 
+	sha512_read(ADDR_NAME0, name0) ||
+	sha512_read(ADDR_NAME1, name1) ||
+	sha512_read(ADDR_VERSION, version);
+}
+
+/* TC9: SHA-512 Single block message test as specified by NIST.
+   We do this for all modes. */
+int tc9(uint8_t mode, const uint32_t *expected, int len)
+{
+    const uint32_t *block = NIST_1024_SINGLE;
+    int i;
+
+    /* Write block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha512_init(mode) != 0) || (sha512_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < len/4; ++i) {
+	if (sha512_read(SHA512_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+int TC9(void)
+{
+    printf("TC9-1: Single block message test for SHA-512/224.\n");
+    if (tc9(MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST,
+	    sizeof(SHA512_224_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-2: Single block message test for SHA-512/256.\n");
+    if (tc9(MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST,
+	    sizeof(SHA512_256_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-3: Single block message test for SHA-384.\n");
+    if (tc9(MODE_SHA_384, SHA384_SINGLE_DIGEST,
+	    sizeof(SHA384_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-4: Single block message test for SHA-512.\n");
+    if (tc9(MODE_SHA_512, SHA512_SINGLE_DIGEST,
+	    sizeof(SHA512_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    return 0;
+}
+
+/* TC10: SHA-512 Double block message test as specified by NIST.
+   We do this for all modes. */
+int tc10(uint8_t mode, const uint32_t *expected, int len)
+{
+    const uint32_t *block[2] = { NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 };
+    int i;
+
+    /* Write first block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha512_init(mode) != 0) || (sha512_wait_ready() != 0))
+	return 1;
+
+    /* Write second block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha512_next(mode) != 0) || (sha512_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < len/4; ++i) {
+	if (sha512_read(SHA512_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+int TC10(void)
+{
+    printf("TC10-1: Double block message test for SHA-512/224.\n");
+    if (tc10(MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST,
+	     sizeof(SHA512_224_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-2: Double block message test for SHA-512/256.\n");
+    if (tc10(MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST,
+	     sizeof(SHA512_256_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-3: Double block message test for SHA-384.\n");
+    if (tc10(MODE_SHA_384, SHA384_DOUBLE_DIGEST,
+	     sizeof(SHA384_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-4: Double block message test for SHA-512.\n");
+    if (tc10(MODE_SHA_512, SHA512_DOUBLE_DIGEST,
+	     sizeof(SHA512_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    return 0;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+    typedef int (*tcfp)(void);
+    tcfp all_tests[] = { TC0, TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10 };
+    tcfp sha1_tests[] = { TC1, TC2, TC3 };
+    tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
+    tcfp sha512_tests[] = { TC8, TC9, TC10 };
+
+    char *usage = "Usage: %s [-d] [-i I2C_device] [-a I2C_addr] tc...\n";
+    char *dev = I2C_dev;
+    int addr = I2C_addr;
+    int i, j, opt;
+
+    while ((opt = getopt(argc, argv, "h?di:a:")) != -1) {
+	switch (opt) {
+	case 'h':
+	case '?':
+	    printf(usage, argv[0]);
+	    return 0;
+	case 'd':
+	    debug = 1;
+	    break;
+	case 'i':
+	    dev = optarg;
+	    break;
+	case 'a':
+	    addr = (int)strtol(optarg, NULL, 0);
+	    if ((addr < 0x03) || (addr > 0x77)) {
+		fprintf(stderr, "addr must be between 0x03 and 0x77\n");
+		return 1;
+	    }
+	    break;
+	default:
+	    fprintf(stderr, usage, argv[0]);
+	    return 1;
+	}
+    }
+
+    if (i2c_setup(dev, addr) != 0)
+	return 1;
+
+    /* no args == run all tests */
+    if (optind >= argc) {
+	for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+	    if (all_tests[j]() != 0)
+		return 1;
+	return 0;
+    }
+
+    for (i = optind; i < argc; ++i) {
+	if (strcmp(argv[i], "all") == 0) {
+	    for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+		if (all_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "sha1") == 0) {
+	    for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
+		if (sha1_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "sha256") == 0) {
+	    for (j = 0; j < sizeof(sha256_tests)/sizeof(sha256_tests[0]); ++j)
+		if (sha256_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "sha512") == 0) {
+	    for (j = 0; j < sizeof(sha512_tests)/sizeof(sha512_tests[0]); ++j)
+		if (sha512_tests[j]() != 0)
+		    return 1;
+	}
+	else if (isdigit(argv[i][0]) &&
+		 (((j = atoi(argv[i])) >= 0) &&
+		  (j < sizeof(all_tests)/sizeof(all_tests[0])))) {
+	    if (all_tests[j]() != 0)
+		return 1;
+	}
+	else {
+	    fprintf(stderr, "unknown test case %s\n", argv[i]);
+	    return 1;
+	}
+    }
+
+    return 0;
+}
diff --git a/novena/src/sw/novena-eim.c b/novena/src/sw/novena-eim.c
new file mode 100644
index 0000000..85bfac0
--- /dev/null
+++ b/novena/src/sw/novena-eim.c
@@ -0,0 +1,708 @@
+/* 
+ * novena-eim.c
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-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.
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include "novena-eim.h"
+
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+#define MEMORY_DEVICE   "/dev/mem"
+
+#define IOMUXC_MUX_MODE_ALT0                    0       // 000
+
+#define IOMUXC_PAD_CTL_SRE_FAST                 1       // 1
+#define IOMUXC_PAD_CTL_DSE_33_OHM               7       // 111
+#define IOMUXC_PAD_CTL_SPEED_MEDIUM_10          2       // 10
+#define IOMUXC_PAD_CTL_ODE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PKE_DISABLED             0       // 0
+#define IOMUXC_PAD_CTL_PUE_PULL                 1       // 1
+#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU          2       // 10
+#define IOMUXC_PAD_CTL_HYS_DISABLED             0       // 0
+
+#define CCM_CGR_OFF                             0       // 00
+#define CCM_CGR_ON_EXCEPT_STOP                  3       // 11
+
+
+//------------------------------------------------------------------------------
+// CPU Registers
+//------------------------------------------------------------------------------
+enum IMX6DQ_REGISTER_OFFSET
+{
+        IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B         = 0x020E00F8,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B          = 0x020E0100,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_RW            = 0x020E0104,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B         = 0x020E0108,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD00          = 0x020E0114,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD01          = 0x020E0118,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD02          = 0x020E011C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD03          = 0x020E0120,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD04          = 0x020E0124,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD05          = 0x020E0128,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD06          = 0x020E012C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD07          = 0x020E0130,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD08          = 0x020E0134,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD09          = 0x020E0138,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD10          = 0x020E013C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD11          = 0x020E0140,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD12          = 0x020E0144,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD13          = 0x020E0148,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD14          = 0x020E014C,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_AD15          = 0x020E0150,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B        = 0x020E0154,
+        IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK          = 0x020E0158,
+
+        IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B         = 0x020E040C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B          = 0x020E0414,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_RW            = 0x020E0418,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B         = 0x020E041C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD00          = 0x020E0428,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD01          = 0x020E042C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD02          = 0x020E0430,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD03          = 0x020E0434,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD04          = 0x020E0438,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD05          = 0x020E043C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD06          = 0x020E0440,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD07          = 0x020E0444,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD08          = 0x020E0448,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD09          = 0x020E044C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD10          = 0x020E0450,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD11          = 0x020E0454,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD12          = 0x020E0458,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD13          = 0x020E045C,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD14          = 0x020E0460,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_AD15          = 0x020E0464,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B        = 0x020E0468,
+        IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK          = 0x020E046C,
+        
+        CCM_CCGR6                               = 0x020C4080,
+        
+        EIM_CS0GCR1                             = 0x021B8000,
+        EIM_CS0GCR2                             = 0x021B8004,
+        EIM_CS0RCR1                             = 0x021B8008,
+        EIM_CS0RCR2                             = 0x021B800C,
+        EIM_CS0WCR1                             = 0x021B8010,
+        EIM_CS0WCR2                             = 0x021B8014,
+
+        EIM_WCR                                 = 0x021B8090,
+        EIM_WIAR                                = 0x021B8094,
+        EIM_EAR                                 = 0x021B8098,
+};
+
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+struct IOMUXC_SW_MUX_CTL_PAD_EIM
+{
+        unsigned int    mux_mode                :  3;
+        unsigned int    reserved_3              :  1;
+        unsigned int    sion                    :  1;
+        unsigned int    reserved_31_5           : 27;
+};
+
+struct IOMUXC_SW_PAD_CTL_PAD_EIM
+{
+        unsigned int    sre                     : 1;
+        unsigned int    reserved_2_1            : 2;
+        unsigned int    dse                     : 3;
+        unsigned int    speed                   : 2;
+        unsigned int    reserved_10_8           : 3;
+        unsigned int    ode                     : 1;
+        unsigned int    pke                     : 1;
+        unsigned int    pue                     : 1;
+        unsigned int    pus                     : 2;
+        unsigned int    hys                     : 1;
+        unsigned int    reserved_31_17          : 15;
+};
+
+struct CCM_CCGR6
+{
+        unsigned int    cg0_usboh3              : 2;
+        unsigned int    cg1_usdhc1              : 2;
+        unsigned int    cg2_usdhc2              : 2;
+        unsigned int    cg3_usdhc3              : 2;
+        
+        unsigned int    cg3_usdhc4              : 2;
+        unsigned int    cg5_eim_slow            : 2;
+        unsigned int    cg6_vdoaxiclk           : 2;
+        unsigned int    cg7_vpu                 : 2;
+        
+        unsigned int    cg8_reserved            : 2;
+        unsigned int    cg9_reserved            : 2;
+        unsigned int    cg10_reserved           : 2;
+        unsigned int    cg11_reserved           : 2;
+        
+        unsigned int    cg12_reserved           : 2;
+        unsigned int    cg13_reserved           : 2;
+        unsigned int    cg14_reserved           : 2;
+        unsigned int    cg15_reserved           : 2;
+};
+
+struct EIM_CS_GCR1
+{
+        unsigned int    csen                    : 1;
+        unsigned int    swr                     : 1;
+        unsigned int    srd                     : 1;
+        unsigned int    mum                     : 1;
+        unsigned int    wfl                     : 1;
+        unsigned int    rfl                     : 1;
+        unsigned int    cre                     : 1;
+        unsigned int    crep                    : 1;
+        unsigned int    bl                      : 3;
+        unsigned int    wc                      : 1;
+        unsigned int    bcd                     : 2;
+        unsigned int    bcs                     : 2;
+        unsigned int    dsz                     : 3;
+        unsigned int    sp                      : 1;
+        unsigned int    csrec                   : 3;
+        unsigned int    aus                     : 1;
+        unsigned int    gbc                     : 3;
+        unsigned int    wp                      : 1;
+        unsigned int    psz                     : 4;
+};
+
+struct EIM_CS_GCR2
+{
+        unsigned int    adh                     :  2;
+        unsigned int    reserved_3_2            :  2;
+        unsigned int    daps                    :  4;
+        unsigned int    dae                     :  1;
+        unsigned int    dap                     :  1;
+        unsigned int    reserved_11_10          :  2;
+        unsigned int    mux16_byp_grant         :  1;
+        unsigned int    reserved_31_13          : 19;
+};
+
+struct EIM_CS_RCR1
+{
+        unsigned int    rcsn                    : 3;
+        unsigned int    reserved_3              : 1;
+        unsigned int    rcsa                    : 3;
+        unsigned int    reserved_7              : 1;
+        unsigned int    oen                     : 3;
+        unsigned int    reserved_11             : 1;
+        unsigned int    oea                     : 3;
+        unsigned int    reserved_15             : 1;
+        unsigned int    radvn                   : 3;
+        unsigned int    ral                     : 1;
+        unsigned int    radva                   : 3;
+        unsigned int    reserved_23             : 1;
+        unsigned int    rwsc                    : 6;
+        unsigned int    reserved_31_30          : 2;
+};
+
+struct EIM_CS_RCR2
+{
+        unsigned int    rben                    :  3;
+        unsigned int    rbe                     :  1;
+        unsigned int    rbea                    :  3;
+        unsigned int    reserved_7              :  1;
+        unsigned int    rl                      :  2;
+        unsigned int    reserved_11_10          :  2;
+        unsigned int    pat                     :  3;
+        unsigned int    apr                     :  1;
+        unsigned int    reserved_31_16          : 16;
+};
+
+struct EIM_CS_WCR1
+{
+        unsigned int    wcsn                    : 3;
+        unsigned int    wcsa                    : 3;
+        unsigned int    wen                     : 3;
+        unsigned int    wea                     : 3;
+        unsigned int    wben                    : 3;
+        unsigned int    wbea                    : 3;
+        unsigned int    wadvn                   : 3;
+        unsigned int    wadva                   : 3;
+        unsigned int    wwsc                    : 6;
+        unsigned int    wbed                    : 1;
+        unsigned int    wal                     : 1;
+};
+
+struct EIM_CS_WCR2
+{
+        unsigned int    wbcdd                   :  1;
+        unsigned int    reserved_31_1           : 31;
+};
+
+struct EIM_WCR
+{
+        unsigned int    bcm                     :  1;
+        unsigned int    gbcd                    :  2;
+        unsigned int    reserved_3              :  1;
+        unsigned int    inten                   :  1;
+        unsigned int    intpol                  :  1;
+        unsigned int    reserved_7_6            :  2;
+        unsigned int    wdog_en                 :  1;
+        unsigned int    wdog_limit              :  2;
+        unsigned int    reserved_31_11          : 21;
+};
+
+struct EIM_WIAR
+{
+        unsigned int    ips_req                 :  1;
+        unsigned int    ips_ack                 :  1;
+        unsigned int    irq                     :  1;
+        unsigned int    errst                   :  1;
+        unsigned int    aclk_en                 :  1;
+        unsigned int    reserved_31_5           : 27;
+};
+
+struct EIM_EAR
+{
+        unsigned int    error_addr              : 32;
+};
+
+
+//------------------------------------------------------------------------------
+// Variables
+//------------------------------------------------------------------------------
+static long     mem_page_size   = 0;
+static int      mem_dev_fd      = -1;
+static void *   mem_map_ptr     = MAP_FAILED;
+static off_t    mem_base_addr   = 0;
+
+
+//------------------------------------------------------------------------------
+// Prototypes
+//------------------------------------------------------------------------------
+static void     _eim_setup_iomuxc       (void);
+static void     _eim_setup_ccm          (void);
+static void     _eim_setup_eim          (void);
+static void     _eim_cleanup            (void);
+static off_t    _eim_calc_offset        (off_t);
+static void     _eim_remap_mem          (off_t);
+
+
+//------------------------------------------------------------------------------
+// Set up EIM bus. Returns 0 on success, -1 on failure.
+//------------------------------------------------------------------------------
+int eim_setup(void)
+{
+    // register cleanup function
+    if (atexit(_eim_cleanup) != 0) {
+        fprintf(stderr, "ERROR: atexit() failed.\n");
+        return -1;
+    }
+
+    // determine memory page size to use in mmap()
+    mem_page_size = sysconf(_SC_PAGESIZE);
+    if (mem_page_size < 1) {
+        fprintf(stderr, "ERROR: sysconf(_SC_PAGESIZE) == %ld\n", mem_page_size);
+        return -1;
+    }
+
+    // try to open memory device
+    mem_dev_fd = open(MEMORY_DEVICE, O_RDWR | O_SYNC);
+    if (mem_dev_fd == -1) {
+        fprintf(stderr, "ERROR: open(%s) failed.\n", MEMORY_DEVICE);
+        return -1;
+    }
+
+    // configure IOMUXC
+    _eim_setup_iomuxc();
+
+    // configure Clock Controller Module
+    _eim_setup_ccm();
+
+    /* We need to properly configure EIM mode and all the corresponding parameters.
+     * That's a lot of code, let's do it now.
+     */
+    _eim_setup_eim();
+
+    // done
+    return 0;
+}
+
+
+//------------------------------------------------------------------------------
+// Shut down EIM bus. This is called automatically on exit().
+//------------------------------------------------------------------------------
+static void _eim_cleanup(void)
+{
+    // unmap memory if needed
+    if (mem_map_ptr != MAP_FAILED)
+        if (munmap(mem_map_ptr, mem_page_size) != 0)
+            fprintf(stderr, "WARNING: munmap() failed.\n");
+
+    // close memory device if needed
+    if (mem_dev_fd != -1)
+        if (close(mem_dev_fd) != 0)
+            fprintf(stderr, "WARNING: close() failed.\n");
+}
+
+
+//------------------------------------------------------------------------------
+// Several blocks in the CPU have common pins. We use the I/O MUX Controller
+// to configure what block will actually use I/O pins. We wait for the EIM
+// module to be able to communicate with the on-board FPGA.
+//------------------------------------------------------------------------------
+static void _eim_setup_iomuxc(void)
+{
+    // create structures
+    struct IOMUXC_SW_MUX_CTL_PAD_EIM    reg_mux;                        // mux control register
+    struct IOMUXC_SW_PAD_CTL_PAD_EIM    reg_pad;                        // pad control register
+
+    // setup mux control register
+    reg_mux.mux_mode            = IOMUXC_MUX_MODE_ALT0;                 // ALT0 mode must be used for EIM
+    reg_mux.sion                = 0;                                    // forced input not needed
+    reg_mux.reserved_3          = 0;                                    // must be 0
+    reg_mux.reserved_31_5       = 0;                                    // must be 0
+
+    // setup pad control register
+    reg_pad.sre                 = IOMUXC_PAD_CTL_SRE_FAST;              // fast slew rate
+    reg_pad.dse                 = IOMUXC_PAD_CTL_DSE_33_OHM;            // highest drive strength
+    reg_pad.speed               = IOMUXC_PAD_CTL_SPEED_MEDIUM_10;       // medium speed
+    reg_pad.ode                 = IOMUXC_PAD_CTL_ODE_DISABLED;          // open drain not needed
+    reg_pad.pke                 = IOMUXC_PAD_CTL_PKE_DISABLED;          // neither pull nor keeper are needed
+    reg_pad.pue                 = IOMUXC_PAD_CTL_PUE_PULL;              // doesn't matter actually, because PKE is disabled
+    reg_pad.pus                 = IOMUXC_PAD_CTL_PUS_100K_OHM_PU;       // doesn't matter actually, because PKE is disabled
+    reg_pad.hys                 = IOMUXC_PAD_CTL_HYS_DISABLED;          // use CMOS, not Schmitt trigger input
+    reg_pad.reserved_2_1        = 0;                                    // must be 0
+    reg_pad.reserved_10_8       = 0;                                    // must be 0
+    reg_pad.reserved_31_17      = 0;                                    // must be 0
+
+    // all the pins must be configured to use the same ALT0 mode
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_RW,          (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_mux);
+    eim_write_32(IOMUXC_SW_MUX_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_mux);
+
+    // we need to configure all the I/O pads too
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_CS0_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_OE_B,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_RW,          (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_LBA_B,       (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD00,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD01,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD02,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD03,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD04,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD05,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD06,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD07,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD08,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD09,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD10,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD11,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD12,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD13,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD14,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_AD15,        (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_WAIT_B,      (uint32_t *)&reg_pad);
+    eim_write_32(IOMUXC_SW_PAD_CTL_PAD_EIM_BCLK,        (uint32_t *)&reg_pad);
+}
+
+
+//------------------------------------------------------------------------------
+// Configure Clock Controller Module to enable clocking of EIM block.
+//------------------------------------------------------------------------------
+static void _eim_setup_ccm(void)
+{
+    // create structure
+    struct CCM_CCGR6 ccm_ccgr6;
+
+    // read register
+    eim_read_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+
+    // modify register
+    ccm_ccgr6.cg0_usboh3                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg1_usdhc1                = CCM_CGR_OFF;
+    ccm_ccgr6.cg2_usdhc2                = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg3_usdhc3                = CCM_CGR_ON_EXCEPT_STOP;
+
+    ccm_ccgr6.cg3_usdhc4                = CCM_CGR_OFF;
+    ccm_ccgr6.cg5_eim_slow              = CCM_CGR_ON_EXCEPT_STOP;
+    ccm_ccgr6.cg6_vdoaxiclk             = CCM_CGR_OFF;
+    ccm_ccgr6.cg7_vpu                   = CCM_CGR_OFF;
+
+    ccm_ccgr6.cg8_reserved              = 0;
+    ccm_ccgr6.cg9_reserved              = 0;
+    ccm_ccgr6.cg10_reserved             = 0;
+    ccm_ccgr6.cg11_reserved             = 0;
+    ccm_ccgr6.cg12_reserved             = 0;
+    ccm_ccgr6.cg13_reserved             = 0;
+    ccm_ccgr6.cg14_reserved             = 0;
+    ccm_ccgr6.cg15_reserved             = 0;
+
+    // write register
+    eim_write_32(CCM_CCGR6, (uint32_t *)&ccm_ccgr6);
+}
+
+
+//------------------------------------------------------------------------------
+// Configure EIM mode and all the corresponding parameters. That's a lot of code.
+//------------------------------------------------------------------------------
+static void _eim_setup_eim(void)
+{
+    // create structures
+    struct EIM_CS_GCR1  gcr1;
+    struct EIM_CS_GCR2  gcr2;
+    struct EIM_CS_RCR1  rcr1;
+    struct EIM_CS_RCR2  rcr2;
+    struct EIM_CS_WCR1  wcr1;
+    struct EIM_CS_WCR2  wcr2;
+
+    struct EIM_WCR              wcr;
+    struct EIM_WIAR             wiar;
+    struct EIM_EAR              ear;
+
+    // read all the registers
+    eim_read_32(EIM_CS0GCR1, (uint32_t *)&gcr1);
+    eim_read_32(EIM_CS0GCR2, (uint32_t *)&gcr2);
+    eim_read_32(EIM_CS0RCR1, (uint32_t *)&rcr1);
+    eim_read_32(EIM_CS0RCR2, (uint32_t *)&rcr2);
+    eim_read_32(EIM_CS0WCR1, (uint32_t *)&wcr1);
+    eim_read_32(EIM_CS0WCR2, (uint32_t *)&wcr2);
+
+    eim_read_32(EIM_WCR,        (uint32_t *)&wcr);
+    eim_read_32(EIM_WIAR,       (uint32_t *)&wiar);
+    eim_read_32(EIM_EAR,        (uint32_t *)&ear);
+
+    // manipulate registers as needed
+    gcr1.csen           = 1;    // chip select is enabled
+    gcr1.swr            = 1;    // write is sync
+    gcr1.srd            = 1;    // read is sync
+    gcr1.mum            = 1;    // address and data are multiplexed
+    gcr1.wfl            = 0;    // write latency is not fixed
+    gcr1.rfl            = 0;    // read latency is not fixed
+    gcr1.cre            = 0;    // CRE signal not needed
+    //gcr1.crep         = x;    // don't care, CRE not used
+    gcr1.bl             = 4;    // burst length
+    gcr1.wc             = 0;    // write is not continuous
+    gcr1.bcd            = 3;    // BCLK divisor is 3+1=4
+    gcr1.bcs            = 1;    // delay from ~CS to BCLK is 1 cycle
+    gcr1.dsz            = 1;    // 16 bits per databeat at DATA[15:0]
+    gcr1.sp             = 0;    // supervisor protection is disabled
+    gcr1.csrec          = 1;    // ~CS recovery is 1 cycle
+    gcr1.aus            = 1;    // address is not shifted
+    gcr1.gbc            = 1;    // ~CS gap is 1 cycle
+    gcr1.wp             = 0;    // write protection is not enabled
+    //gcr1.psz          = x;    // don't care, page mode is not used
+
+    gcr2.adh            = 0;    // address hold duration is 1 cycle
+    //gcr2.daps         = x;    // don't care, DTACK is not used
+    gcr2.dae            = 0;    // DTACK is not used
+    //gcr2.dap          = x;    // don't care, DTACK is not used
+    gcr2.mux16_byp_grant= 1;    // enable grant mechanism
+    gcr2.reserved_3_2   = 0;    // must be 0
+    gcr2.reserved_11_10 = 0;    // must be 0
+    gcr2.reserved_31_13 = 0;    // must be 0
+
+    //rcr1.rcsn         = x;    // don't care in sync mode
+    rcr1.rcsa           = 0;    // no delay for ~CS needed
+    //rcr1.oen          = x;    // don't care in sync mode
+    rcr1.oea            = 0;    // no delay for ~OE needed
+    rcr1.radvn          = 0;    // no delay for ~LBA needed
+    rcr1.ral            = 0;    // clear ~LBA when needed
+    rcr1.radva          = 0;    // no delay for ~LBA needed
+    rcr1.rwsc           = 1;    // one wait state
+    rcr1.reserved_3     = 0;    // must be 0
+    rcr1.reserved_7     = 0;    // must be 0
+    rcr1.reserved_11    = 0;    // must be 0
+    rcr1.reserved_15    = 0;    // must be 0
+    rcr1.reserved_23    = 0;    // must be 0
+    rcr1.reserved_31_30 = 0;    // must be 0
+
+    //rcr2.rben         = x;    // don't care in sync mode
+    rcr2.rbe            = 0;    // BE is disabled
+    //rcr2.rbea         = x;    // don't care when BE is not used
+    rcr2.rl             = 0;    // read latency is 0
+    //rcr2.pat          = x;    // don't care when page read is not used
+    rcr2.apr            = 0;    // page read mode is not used
+    rcr2.reserved_7     = 0;    // must be 0
+    rcr2.reserved_11_10 = 0;    // must be 0
+    rcr2.reserved_31_16 = 0;    // must be 0
+
+    //wcr1.wcsn         = x;    // don't care in sync mode
+    wcr1.wcsa           = 0;    // no delay for ~CS needed
+    //wcr1.wen          = x;    // don't care in sync mode
+    wcr1.wea            = 0;    // no delay for ~WR_N needed
+    //wcr1.wben         = x;    // don't care in sync mode
+    //wcr1.wbea         = x;    // don't care in sync mode
+    wcr1.wadvn          = 0;    // no delay for ~LBA needed
+    wcr1.wadva          = 0;    // no delay for ~LBA needed
+    wcr1.wwsc           = 1;    // no wait state in needed
+    wcr1.wbed           = 1;    // BE is disabled
+    wcr1.wal            = 0;    // clear ~LBA when needed
+
+    wcr2.wbcdd          = 0;    // write clock division is not needed
+    wcr2.reserved_31_1  = 0;    // must be 0
+
+    wcr.bcm             = 0;    // clock is only active during access
+    //wcr.gbcd          = x;    // don't care when BCM=0
+    wcr.inten           = 0;    // interrupt is not used
+    //wcr.intpol        = x;    // don't care when interrupt is not used
+    wcr.wdog_en         = 1;    // watchdog is enabled
+    wcr.wdog_limit      = 00;   // timeout is 128 BCLK cycles
+    wcr.reserved_3      = 0;    // must be 0
+    wcr.reserved_7_6    = 0;    // must be 0
+    wcr.reserved_31_11  = 0;    // must be 0
+
+    wiar.ips_req        = 0;    // IPS not needed
+    wiar.ips_ack        = 0;    // IPS not needed
+    //wiar.irq          = x;    // don't touch
+    //wiar.errst        = x;    // don't touch
+    wiar.aclk_en        = 1;    // clock is enabled
+    wiar.reserved_31_5  = 0;    // must be 0
+
+    //ear.error_addr    = x;    // read-only
+
+    // write modified registers
+    eim_write_32(EIM_CS0GCR1,   (uint32_t *)&gcr1);
+    eim_write_32(EIM_CS0GCR2,   (uint32_t *)&gcr2);
+    eim_write_32(EIM_CS0RCR1,   (uint32_t *)&rcr1);
+    eim_write_32(EIM_CS0RCR2,   (uint32_t *)&rcr2);
+    eim_write_32(EIM_CS0WCR1,   (uint32_t *)&wcr1);
+    eim_write_32(EIM_CS0WCR2,   (uint32_t *)&wcr2);
+    eim_write_32(EIM_WCR,               (uint32_t *)&wcr);
+    eim_write_32(EIM_WIAR,      (uint32_t *)&wiar);
+/*  eim_write_32(EIM_EAR,       (uint32_t *)&ear);*/
+}
+
+
+//------------------------------------------------------------------------------
+// Write a 32-bit word to EIM.
+// If EIM is not set up correctly, this will abort with a bus error.
+//------------------------------------------------------------------------------
+void eim_write_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // write data to memory
+    memcpy(ptr, pvalue, sizeof(uint32_t));
+}
+
+//------------------------------------------------------------------------------
+// Read a 32-bit word from EIM.
+// If EIM is not set up correctly, this will abort with a bus error.
+//------------------------------------------------------------------------------
+void eim_read_32(off_t offset, uint32_t *pvalue)
+{
+    // calculate memory offset
+    uint32_t *ptr = (uint32_t *)_eim_calc_offset(offset);
+
+    // read data from memory
+    memcpy(pvalue, ptr, sizeof(uint32_t));
+}
+
+
+//------------------------------------------------------------------------------
+// Calculate an offset into the currently-mapped EIM page.
+//------------------------------------------------------------------------------
+static off_t _eim_calc_offset(off_t offset)
+{
+    // make sure that memory is mapped
+    if (mem_map_ptr == MAP_FAILED)
+        _eim_remap_mem(offset);
+
+    // calculate starting and ending addresses of currently mapped page
+    off_t offset_low    = mem_base_addr;
+    off_t offset_high   = mem_base_addr + (mem_page_size - 1);
+
+    // check that offset is in currently mapped page, remap new page otherwise
+    if ((offset < offset_low) || (offset > offset_high))
+        _eim_remap_mem(offset);
+
+    // calculate pointer
+    return (off_t)mem_map_ptr + (offset - mem_base_addr);
+}
+
+
+//------------------------------------------------------------------------------
+// Map in a new EIM page.
+//------------------------------------------------------------------------------
+static void _eim_remap_mem(off_t offset)
+{
+    // unmap old memory page if needed
+    if (mem_map_ptr != MAP_FAILED) {
+        if (munmap(mem_map_ptr, mem_page_size) != 0) {
+            fprintf(stderr, "ERROR: munmap() failed.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    // calculate starting address of new page
+    while (offset % mem_page_size)
+        offset--;
+
+    // try to map new memory page
+    mem_map_ptr = mmap(NULL, mem_page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                       mem_dev_fd, offset);
+    if (mem_map_ptr == MAP_FAILED) {
+        fprintf(stderr, "ERROR: mmap() failed.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // save last mapped page address
+    mem_base_addr = offset;
+}
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/novena/src/sw/novena-eim.h b/novena/src/sw/novena-eim.h
new file mode 100644
index 0000000..75613bf
--- /dev/null
+++ b/novena/src/sw/novena-eim.h
@@ -0,0 +1,52 @@
+/* 
+ * novena-eim.h
+ * ------------
+ * This module contains the userland magic to set up and use the EIM bus.
+ *
+ * 
+ * Author: Pavel Shatov
+ * Copyright (c) 2014-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.
+ */
+
+#define EIM_BASE_ADDR 0x08000000
+
+/* Set up EIM bus.
+ * Returns 0 on success, -1 on failure.
+ */
+int  eim_setup(void);
+
+/* Write a 32-bit word to EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_write_32(off_t, uint32_t *);
+
+/* Read a 32-bit word from EIM.
+ * If EIM is not set up correctly, this will abort with a bus error.
+ */
+void eim_read_32(off_t, uint32_t *);
diff --git a/novena/src/ucf/novena_eim.ucf b/novena/src/ucf/novena_eim.ucf
new file mode 100644
index 0000000..160b8d9
--- /dev/null
+++ b/novena/src/ucf/novena_eim.ucf
@@ -0,0 +1,152 @@
+#======================================================================
+#
+# novena_baseline.ucf
+# -------------------
+# Constraint file for implementing the Cryptech Novena base
+# for the Xilinx Spartan6 LX45 on the Novena.
+#
+#
+# Author: Pavel Shatov
+# Copyright (c) 2014, 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.
+#
+#======================================================================
+
+#-------------------------------------------------------------------------------
+CONFIG  VCCAUX = 3.3;
+#-------------------------------------------------------------------------------
+
+
+#--------------------------------------------------------------------------------
+# GCLK Timing
+#--------------------------------------------------------------------------------
+NET  "gclk_p_pin" TNM_NET = TNM_gclk;
+TIMESPEC  TS_gclk = PERIOD TNM_gclk 20 ns HIGH 50%;
+
+
+#-------------------------------------------------------------------------------
+# BCLK Timing
+#-------------------------------------------------------------------------------
+NET  "eim_bclk" TNM_NET = TNM_bclk;
+TIMESPEC  TS_bclk = PERIOD TNM_bclk 30 ns HIGH 50%;
+
+
+#-------------------------------------------------------------------------------
+# FPGA Pinout
+#-------------------------------------------------------------------------------
+NET  "led_pin"         LOC = "A16" | IOSTANDARD = "LVCMOS33" | SLEW = "SLOW" | DRIVE = 12;
+NET  "apoptosis_pin"   LOC = "K1"  | IOSTANDARD = "LVCMOS33" | SLEW = "SLOW" | DRIVE = 12;
+NET  "reset_mcu_b_pin" LOC = "F1"  | IOSTANDARD = "LVCMOS33" | PULLUP;
+
+NET  "gclk_p_pin"      LOC = "H2"  | IOSTANDARD = "LVDS_33"  | DIFF_TERM = "TRUE";
+NET  "gclk_n_pin"      LOC = "H1"  | IOSTANDARD = "LVDS_33"  | DIFF_TERM = "TRUE";
+
+NET  "eim_bclk"        LOC = "C9"  | IOSTANDARD = "LVCMOS33";
+NET  "eim_cs0_n"       LOC = "B11" | IOSTANDARD = "LVCMOS33";
+
+NET  "eim_da<0>"       LOC = "G9"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<1>"       LOC = "A10" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<2>"       LOC = "F9"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<3>"       LOC = "B9"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<4>"       LOC = "E13" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<5>"       LOC = "F13" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<6>"       LOC = "A9"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<7>"       LOC = "A8"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<8>"       LOC = "B8"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<9>"       LOC = "D8"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<10>"      LOC = "D11" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<11>"      LOC = "C8"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<12>"      LOC = "C7"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<13>"      LOC = "C11" | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<14>"      LOC = "C4"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+NET  "eim_da<15>"      LOC = "B6"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+
+NET  "eim_a<16>"       LOC = "A11" | IOSTANDARD = "LVCMOS33";
+NET  "eim_a<17>"       LOC = "B12" | IOSTANDARD = "LVCMOS33";
+NET  "eim_a<18>"       LOC = "D14" | IOSTANDARD = "LVCMOS33";
+
+NET  "eim_lba_n"       LOC = "B14" | IOSTANDARD = "LVCMOS33";
+NET  "eim_wr_n"        LOC = "C14" | IOSTANDARD = "LVCMOS33";
+NET  "eim_oe_n"        LOC = "C10" | IOSTANDARD = "LVCMOS33";
+NET  "eim_wait_n"      LOC = "A7"  | IOSTANDARD = "LVCMOS33" | SLEW = "FAST" | DRIVE = 12;
+
+# Pins to the header where the LEDs on the Cryptech
+# Avalanche Noise Board are connected.
+NET  "ct_led<0>" LOC = K6 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<1>" LOC = H4 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<2>" LOC = H3 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<3>" LOC = M1 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<4>" LOC = L7 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<5>" LOC = G1 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<6>" LOC = T2 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<7>" LOC = H7 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+# Pins to the header where the noise sources on the
+# Cryptech Avalanche Noise Board are connected.
+NET  "ct_noise"  LOC = L4 | IOSTANDARD = LVCMOS33;
+
+#-------------------------------------------------------------------------------
+# EIM Input Timing
+#-------------------------------------------------------------------------------
+NET  "eim_cs0_n" TNM = "TNM_EIM_IN";
+NET  "eim_da<*>" TNM = "TNM_EIM_IN";
+NET  "eim_lba_n" TNM = "TNM_EIM_IN";
+NET  "eim_wr_n"  TNM = "TNM_EIM_IN";
+NET  "eim_oe_n"  TNM = "TNM_EIM_IN";
+
+TIMEGRP  "TNM_EIM_IN" OFFSET = IN 9.75 ns VALID 16.0 ns BEFORE "eim_bclk" RISING;
+
+
+#-------------------------------------------------------------------------------
+# EIM Output Timing
+#-------------------------------------------------------------------------------
+NET  "eim_da<*>"  TNM = "TNM_EIM_OUT";
+NET  "eim_wait_n" TNM = "TNM_EIM_OUT";
+
+TIMEGRP  "TNM_EIM_OUT" OFFSET = OUT 13.0 ns AFTER "eim_bclk" FALLING;
+
+
+#-------------------------------------------------------------------------------
+# CDC Paths
+#-------------------------------------------------------------------------------
+INST  "eim/eim/eim_cdc/cdc_eim_sys/src_ff"     TNM = "TNM_from_bclk";
+INST  "eim/eim/eim_cdc/cdc_eim_sys/src_latch*" TNM = "TNM_from_bclk";
+INST  "eim/eim/eim_cdc/cdc_eim_sys/ff_sync*"   TNM = "TNM_to_sys_clk";
+INST  "eim/eim/eim_cdc/cdc_eim_sys/dst_latch*" TNM = "TNM_to_sys_clk";
+
+INST  "eim/eim/eim_cdc/cdc_sys_eim/src_ff"     TNM = "TNM_from_sys_clk";
+INST  "eim/eim/eim_cdc/cdc_sys_eim/src_latch*" TNM = "TNM_from_sys_clk";
+INST  "eim/eim/eim_cdc/cdc_sys_eim/ff_sync*"   TNM = "TNM_to_bclk";
+INST  "eim/eim/eim_cdc/cdc_sys_eim/dst_latch*" TNM = "TNM_to_bclk";
+
+TIMESPEC  "TS_bclk_2_sys_clk" = FROM "TNM_from_bclk"    TO "TNM_to_sys_clk" TIG;
+TIMESPEC  "TS_sys_clk_2_bclk" = FROM "TNM_from_sys_clk" TO "TNM_to_bclk"    TIG;
+
+#======================================================================
+# EOF novena_baseline.ucf
+#======================================================================
diff --git a/novena/src/ucf/novena_i2c.ucf b/novena/src/ucf/novena_i2c.ucf
new file mode 100644
index 0000000..4f6f1f2
--- /dev/null
+++ b/novena/src/ucf/novena_i2c.ucf
@@ -0,0 +1,82 @@
+#======================================================================
+#
+# novena_baseline.ucf
+# -------------------
+# Constraint file for implementing the Cryptech Novena base
+# for the Xilinx Spartan6 LX45 on the Novena.
+#
+#
+# Author: Pavel Shatov
+# Copyright (c) 2014, 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.
+#
+#======================================================================
+
+#-------------------------------------------------------------------------------
+CONFIG  VCCAUX = 3.3;
+#-------------------------------------------------------------------------------
+
+
+#--------------------------------------------------------------------------------
+# GCLK Timing
+#--------------------------------------------------------------------------------
+NET  "gclk_p_pin" TNM_NET = TNM_gclk;
+TIMESPEC  TS_gclk = PERIOD TNM_gclk 20 ns HIGH 50%;
+
+
+#-------------------------------------------------------------------------------
+# FPGA Pinout
+#-------------------------------------------------------------------------------
+NET  "led_pin"         LOC = "A16" | IOSTANDARD = "LVCMOS33" | SLEW = "SLOW" | DRIVE = 12;
+NET  "apoptosis_pin"   LOC = "K1"  | IOSTANDARD = "LVCMOS33" | SLEW = "SLOW" | DRIVE = 12;
+NET  "reset_mcu_b_pin" LOC = "F1"  | IOSTANDARD = "LVCMOS33" | PULLUP;
+
+NET  "gclk_p_pin"      LOC = "H2"  | IOSTANDARD = "LVDS_33"  | DIFF_TERM = "TRUE";
+NET  "gclk_n_pin"      LOC = "H1"  | IOSTANDARD = "LVDS_33"  | DIFF_TERM = "TRUE";
+
+NET  "i2c_scl"         LOC = "P4"  | IOSTANDARD = LVCMOS33;
+NET  "i2c_sda"         LOC = "P3"  | IOSTANDARD = LVCMOS33;
+
+# Pins to the header where the LEDs on the Cryptech
+# Avalanche Noise Board are connected.
+NET  "ct_led<0>" LOC = K6 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<1>" LOC = H4 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<2>" LOC = H3 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<3>" LOC = M1 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<4>" LOC = L7 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<5>" LOC = G1 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<6>" LOC = T2 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+NET  "ct_led<7>" LOC = H7 | IOSTANDARD = LVCMOS33 | SLEW = SLOW;
+
+# Pins to the header where the noise sources on the
+# Cryptech Avalanche Noise Board are connected.
+NET  "ct_noise"  LOC = L4 | IOSTANDARD = LVCMOS33;
+
+#======================================================================
+# EOF novena_baseline.ucf
+#======================================================================
diff --git a/sha1/LICENSE.txt b/sha1/LICENSE.txt
new file mode 100644
index 0000000..2acf230
--- /dev/null
+++ b/sha1/LICENSE.txt
@@ -0,0 +1,24 @@
+
+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:
+
+* 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.
+
+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.
diff --git a/sha1/README.md b/sha1/README.md
new file mode 100644
index 0000000..f7eac7f
--- /dev/null
+++ b/sha1/README.md
@@ -0,0 +1,125 @@
+sha1
+====
+
+## Introduction ##
+Verilog implementation of the SHA-1 cryptgraphic hash function. The
+functionality follows the specification in NIST FIPS 180-4.
+
+The sha1 design is divided into the following sections.
+ - src/rtl - RTL source files
+ - src/tb  - Testbenches for the RTL files
+ - src/model/python - Functional model written in python
+ - doc/ - documentation (currently not done.)
+ - toolruns/ - Where tools are supposed to be run. Includes a Makefile
+   for building and simulating the design using [Icarus
+   Verilog](http://iverilog.icarus.com/).
+
+The actual core consists of the following RTL files:
+ - sha1.v
+ - sha1_core.v
+ - sha1_w_mem.v
+
+The main core functionality is in the sha1_core file. The file
+sha1_w_mem contains the message block memory W (see FIPS 180-4).
+The top level entity is called sha1_core. The sha1_core module has wide
+interfaces (512 bit block input, 160 bit digest). In order to make it
+usable you probably want to wrap the core with a bus interface.
+
+The file sha1.v contains a top level wrapper that provides a simple
+interface with 32-bit data access . This interface contains mesage block
+and digest registers to allow a host to load the next block while the
+current block is being processed.
+
+## API ##
+The following list contains the address map for all registers
+implemented by the sha1 top level wrapper:
+
+| address | name     | access | description                                     |
+|---------|----------|--------|-------------                                    |
+| 0x00    | name0    |   R    |  "SHA1"                                         |
+| 0x01    | name1    |   R    |  "    "                                         |
+| 0x02    | version  |   R    |  "0.50"                                         |
+|         |          |        |                                                 |
+| 0x08    | control  |  R/W   | Control of core. Bit 0: init, Bit 1: next       |
+| 0x09    | status   |  R/W   | Status of core. Bit 0: Ready, Bit 1: valid data |
+|         |          |        |                                                 |
+| 0x10    | block0   |  R/W   | data block register                             |
+| 0x11    | block1   |  R/W   | data block register                             |
+| 0x12    | block2   |  R/W   | data block register                             |
+| 0x13    | block3   |  R/W   | data block register                             |
+| 0x14    | block4   |  R/W   | data block register                             |
+| 0x15    | block5   |  R/W   | data block register                             |
+| 0x16    | block6   |  R/W   | data block register                             |
+| 0x17    | block7   |  R/W   | data block register                             |
+| 0x18    | block8   |  R/W   | data block register                             |
+| 0x19    | block9   |  R/W   | data block register                             |
+| 0x1a    | block10  |  R/W   | data block register                             |
+| 0x1b    | block11  |  R/W   | data block register                             |
+| 0x1c    | block12  |  R/W   | data block register                             |
+| 0x1d    | block13  |  R/W   | data block register                             |
+| 0x1e    | block14  |  R/W   | data block register                             |
+| 0x1f    | block15  |  R/W   | data block register                             |
+|         |          |        |                                                 |
+| 0x20    | digest0  |  R/W   | digest register                                 |
+| 0x21    | digest1  |  R/W   | digest register                                 |
+| 0x22    | digest2  |  R/W   | digest register                                 |
+| 0x23    | digest3  |  R/W   | digest register                                 |
+| 0x24    | digest4  |  R/W   | digest register                                 |
+
+
+## Implementation details ##
+The implementation is iterative with one cycle/round. The initialization
+takes one cycle. The W memory is based around a sliding window of 16
+32-bit registers that are updated in sync with the round processing. The
+total latency/message block is 82 cycles.
+
+All registers have asynchronous reset.
+
+The design has been implemented and tested on TerasIC DE0-Nano and C5G
+FPGA boards.
+
+
+## Status ##
+The design has been implemented and extensively been tested on TerasIC
+DE0-Nano and C5G FPGA boards. The core has also been tested using SW
+running on The Novena CPU talking to the core in the Xilinx Spartan-6
+FPGA.
+
+
+## FPGA-results ##
+
+### Altera Cyclone FPGAs ###
+Implementation results using Altera Quartus-II 13.1.
+
+***Altera Cyclone IV E***
+- EP4CE6F17C6
+- 2913 LEs
+- 1527 regs
+- 107 MHz
+
+***Altera Cyclone IV GX***
+- EP4CGX22CF19C6
+- 2814 LEs
+- 1527 regs
+- 105 MHz
+
+***Altera Cyclone V***
+- 5CGXFC7C7F23C8
+- 1124 ALMs
+- 1527 regs
+- 104 MHz
+
+
+### Xilinx FPGAs ###
+Implementation results using ISE 14.7.
+
+** Xilinx Spartan-6 **
+- xc6slx45-3csg324
+- 1589 LUTs
+- 564 Slices
+- 1592 regs
+- 100 MHz
+
+
+## TODO ##
+* Documentation
diff --git a/sha1/src/model/python/sha1.py b/sha1/src/model/python/sha1.py
new file mode 100755
index 0000000..9bae18a
--- /dev/null
+++ b/sha1/src/model/python/sha1.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#=======================================================================
+#
+# sha1.py
+# ---------
+# Simple, pure Python model of the SHA-1 function. Used as a
+# reference for the HW implementation. The code follows the structure
+# of the HW implementation as much as possible.
+#
+#
+# Author: Joachim Strömbergson
+# (c) 2014, SUNET
+# 
+# Redistribution and use in source and binary forms, with or 
+# without modification, are permitted provided that the following 
+# conditions are met: 
+# 
+# 1. Redistributions of source code must retain the above copyright 
+#    notice, this list of conditions and the following disclaimer. 
+# 
+# 2. Redistributions in binary form must reproduce the above copyright 
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution. 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#=======================================================================
+
+#-------------------------------------------------------------------
+# Python module imports.
+#-------------------------------------------------------------------
+import sys
+
+
+#-------------------------------------------------------------------
+# Constants.
+#-------------------------------------------------------------------
+
+
+#-------------------------------------------------------------------
+# ChaCha()
+#-------------------------------------------------------------------
+class SHA1():
+    def __init__(self, verbose = 0):
+        self.verbose = verbose
+        self.H = [0] * 5
+        self.T = 0
+        self.a = 0
+        self.b = 0
+        self.c = 0
+        self.d = 0
+        self.e = 0
+        self.W = [0] * 80
+        self.k = 0
+
+        
+    def init(self):
+        self.H = [0x67452301, 0xefcdab89, 0x98badcfe,
+                  0x10325476, 0xc3d2e1f0]
+        
+
+    def next(self, block):
+        self._W_schedule(block)
+        self._copy_digest()
+        for i in range(80):
+            self._sha1_round(i)
+        self._update_digest()
+
+
+    def get_digest(self):
+        return self.H
+
+
+    def _copy_digest(self):
+        self.a = self.H[0] 
+        self.b = self.H[1] 
+        self.c = self.H[2] 
+        self.d = self.H[3] 
+        self.e = self.H[4] 
+    
+    
+    def _update_digest(self):
+        self.H[0] = (self.H[0] + self.a) & 0xffffffff 
+        self.H[1] = (self.H[1] + self.b) & 0xffffffff 
+        self.H[2] = (self.H[2] + self.c) & 0xffffffff 
+        self.H[3] = (self.H[3] + self.d) & 0xffffffff 
+        self.H[4] = (self.H[4] + self.e) & 0xffffffff 
+
+
+    def _sha1_round(self, round):
+        if round <= 19:
+            self.k = 0x5a827999        
+            self.f = self._Ch(self.b, self.c, self.d)
+
+        elif 20 <= round <= 39:
+            self.k = 0x6ed9eba1
+            self.f = self._Parity(self.b, self.c, self.d)
+
+        elif 40 <= round <= 59:
+            self.k = 0x8f1bbcdc
+            self.f = self._Maj(self.b, self.c, self.d)
+
+        elif 60 <= round <= 79:
+            self.k = 0xca62c1d6
+            self.f = self._Parity(self.b, self.c, self.d)
+
+        if self.verbose:
+            print("Round %0d" % round)
+            print("Round input values:")
+            print("a = 0x%08x, b = 0x%08x, c = 0x%08x" % (self.a, self.b, self.c))
+            print("d = 0x%08x, e = 0x%08x" % (self.d, self.e))
+            print("f = 0x%08x, k = 0x%08x, w = 0x%08x" % (self.f, self.k, self.W[round]))
+            
+        
+        self.T = (self._rotl32(self.a, 5) + self.f + self.e + self.k + self.W[round]) & 0xffffffff
+        self.e = self.d
+        self.d = self.c
+        self.c = self._rotl32(self.b, 30)
+        self.b = self.a
+        self.a = self.T
+
+        if self.verbose:
+            print("Round output values:")
+            print("a = 0x%08x, b = 0x%08x, c = 0x%08x" % (self.a, self.b, self.c))
+            print("d = 0x%08x, e = 0x%08x" % (self.d, self.e))
+            print("")
+
+
+    def _W_schedule(self, block):
+        # Expand the block into 80 words before round operations.
+        for i in range(80):
+            if (i < 16):
+                self.W[i] = block[i]
+            else:
+                self.W[i] = self._rotl32((self.W[(i - 3)] ^ self.W[(i - 8)] ^
+                                          self.W[(i - 14)] ^ self.W[(i - 16)]), 1)
+        if (self.verbose):
+            print("W after schedule:")
+            for i in range(80):
+                print("W[%02d] = 0x%08x" % (i, self.W[i]))
+            print("")
+
+
+    def _Ch(self, x, y, z):
+        return (x & y) ^ (~x & z)
+
+
+    def _Maj(self, x, y, z):
+        return (x & y) ^ (x & z) ^ (y & z)
+
+
+    def _Parity(self, x, y, z):
+        return (x ^ y ^ z)
+
+    def _rotl32(self, n, r):
+        return ((n << r) | (n >> (32 - r))) & 0xffffffff
+
+
+def compare_digests(digest, expected):
+    if (digest != expected):
+        print("Error:")
+        print("Got:")
+        print(digest)
+        print("Expected:")
+        print(expected)
+    else:
+        print("Test case ok.")
+        
+    
+#-------------------------------------------------------------------
+# main()
+#
+# If executed tests the ChaCha class using known test vectors.
+#-------------------------------------------------------------------
+def main():
+    print("Testing the SHA-1 Python model.")
+    print("-------------------------------")
+    print
+
+    my_sha1 = SHA1(verbose=0);
+
+    # TC1: NIST testcase with message "abc"
+    print("TC1: Single block NIST test case.")
+    TC1_block = [0x61626380, 0x00000000, 0x00000000, 0x00000000, 
+                 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                 0x00000000, 0x00000000, 0x00000000, 0x00000018]
+    
+    TC1_expected = [0xa9993e36, 0x4706816a, 0xba3e2571,
+                    0x7850c26c, 0x9cd0d89d]
+    my_sha1.init()
+    my_sha1.next(TC1_block)
+    my_digest = my_sha1.get_digest()
+    compare_digests(my_digest, TC1_expected)
+    print("")
+
+
+    # TC2: NIST testcase with message two block message.
+    print("TC2: Dual block NIST test case.")
+    TC2_1_block = [0x61626364, 0x62636465, 0x63646566, 0x64656667,
+                   0x65666768, 0x66676869, 0x6768696A, 0x68696A6B,
+                   0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F,
+                   0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000]
+
+
+    TC2_2_block = [0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x000001C0]
+
+    TC2_1_expected = [0xF4286818, 0xC37B27AE, 0x0408F581,
+                      0x84677148, 0x4A566572]
+
+    TC2_2_expected = [0x84983E44, 0x1C3BD26E, 0xBAAE4AA1,
+                      0xF95129E5, 0xE54670F1]
+
+    my_sha1.init()
+    my_sha1.next(TC2_1_block)
+    my_digest = my_sha1.get_digest()
+    compare_digests(my_digest, TC2_1_expected)
+    my_sha1.next(TC2_2_block)
+    my_digest = my_sha1.get_digest()
+    compare_digests(my_digest, TC2_2_expected)
+    print("")
+
+
+    # TC3: Huge message with n blocks
+    n = 10000
+    print("TC3: Huge message with %d blocks test case." % n)
+    TC3_block = [0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f]
+
+    TC3_expected = [0xea2ebc79, 0x35516705, 0xde1e1467,
+                    0x31e55587, 0xa0038725]
+
+    my_sha1.init()
+    for i in range(n):
+        my_sha1.next(TC3_block)
+    my_digest = my_sha1.get_digest()
+    compare_digests(my_digest, TC3_expected)
+    
+
+#-------------------------------------------------------------------
+# __name__
+# Python thingy which allows the file to be run standalone as
+# well as parsed from within a Python interpreter.
+#-------------------------------------------------------------------
+if __name__=="__main__": 
+    # Run the main function.
+    sys.exit(main())
+
+#=======================================================================
+# EOF sha1.py
+#=======================================================================
diff --git a/sha1/src/rtl/sha1.v b/sha1/src/rtl/sha1.v
new file mode 100644
index 0000000..d0b4a4e
--- /dev/null
+++ b/sha1/src/rtl/sha1.v
@@ -0,0 +1,204 @@
+//======================================================================
+//
+// sha1.v
+// ------
+// Top level wrapper for the SHA-1 hash function providing
+// a simple memory like interface with 32 bit data access.
+//
+// Authors: Joachim Strömbergson, Paul Selkirk
+// Copyright (c) 2014-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 sha1(
+            // 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
+            );
+
+   //----------------------------------------------------------------
+   // 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 ADDR_STATUS      = 8'h09;
+   parameter STATUS_READY_BIT = 0;
+   parameter STATUS_VALID_BIT = 1;
+
+   parameter ADDR_BLOCK       = 8'h10;
+
+   parameter ADDR_DIGEST      = 8'h20;
+
+   parameter CORE_NAME0       = 32'h73686131; // "sha1"
+   parameter CORE_NAME1       = 32'h20202020; // "    "
+   parameter CORE_VERSION     = 32'h302e3530; // "0.50"
+
+   parameter BLOCK_BITS       = 512;
+   parameter DIGEST_BITS      = 160;
+   parameter BLOCK_WORDS      = BLOCK_BITS / 32;
+   parameter DIGEST_WORDS     = DIGEST_BITS / 32;
+
+   //----------------------------------------------------------------
+   // Registers.
+   //----------------------------------------------------------------
+   reg [0 : BLOCK_BITS - 1]    block_reg;
+   reg [0 : DIGEST_BITS - 1]   digest_reg;
+   reg                         init_reg;
+   reg                         next_reg;
+
+   reg [31 : 0]                tmp_read_data;
+   reg [31 : 0]                tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                        core_init;
+   wire                        core_next;
+   wire                        core_ready;
+   wire [0 : BLOCK_BITS - 1]   core_block;
+   wire [0 : DIGEST_BITS - 1]  core_digest;
+   wire                        core_digest_valid;
+
+   wire [31 : 0]               core_name0   = CORE_NAME0;
+   wire [31 : 0]               core_name1   = CORE_NAME1;
+   wire [31 : 0]               core_version = CORE_VERSION;
+   wire [31 : 0]               core_ctrl;
+   wire [31 : 0]               core_status;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init   = init_reg;
+   assign core_next   = next_reg;
+   assign core_ctrl   = { 30'b0, next_reg, init_reg };
+   assign core_status = { 30'b0, core_digest_valid, core_ready };
+   assign core_block  = block_reg;
+
+   assign read_data   = tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // core instantiation.
+   //----------------------------------------------------------------
+   sha1_core core(
+                  .clk(clk),
+                  .reset_n(reset_n),
+
+                  .init(core_init),
+                  .next(core_next),
+
+                  .block(core_block),
+
+                  .ready(core_ready),
+
+                  .digest(core_digest),
+                  .digest_valid(core_digest_valid)
+                  );
+
+
+   //----------------------------------------------------------------
+   // latch in digest when ready
+   //----------------------------------------------------------------
+   always @(posedge clk)
+      begin
+         if (core_digest_valid)
+           digest_reg <= core_digest;
+      end
+
+   //----------------------------------------------------------------
+   // storage registers for mapping memory to core interface
+   //----------------------------------------------------------------
+   always @(posedge clk)
+     begin
+        init_reg <= 0;
+        next_reg <= 0;
+
+        if (cs && we)
+          begin
+             // write operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               block_reg[((address - ADDR_BLOCK) * 32)+:32] <= write_data;
+             else if (address == ADDR_CTRL)
+               begin
+                  init_reg <= write_data[CTRL_INIT_BIT];
+                  next_reg <= write_data[CTRL_NEXT_BIT];
+               end
+          end
+     end
+
+   always @*
+     begin
+        tmp_read_data = 32'h00000000;
+
+        if (cs && !we)
+          begin
+             // read operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               tmp_read_data = block_reg[((address - ADDR_BLOCK) * 32)+:32];
+             else if ((address >= ADDR_DIGEST) &&
+                      (address < ADDR_DIGEST + DIGEST_WORDS))
+               tmp_read_data = digest_reg[((address - ADDR_DIGEST) * 32)+:32];
+             else
+               case (address)
+                 ADDR_NAME0:
+                   tmp_read_data = core_name0;
+                 ADDR_NAME1:
+                   tmp_read_data = core_name1;
+                 ADDR_VERSION:
+                   tmp_read_data = core_version;
+                 ADDR_CTRL:
+                   tmp_read_data = core_ctrl;
+                 ADDR_STATUS:
+                   tmp_read_data = core_status;
+               endcase
+          end
+     end
+
+   always @(posedge clk)
+     begin
+        tmp_read_data_reg <= tmp_read_data;
+     end
+
+endmodule // sha1
diff --git a/sha1/src/rtl/sha1_core.v b/sha1/src/rtl/sha1_core.v
new file mode 100644
index 0000000..78fe2b9
--- /dev/null
+++ b/sha1/src/rtl/sha1_core.v
@@ -0,0 +1,443 @@
+//======================================================================
+//
+// sha1_core.v
+// -----------
+// Verilog 2001 implementation of the SHA-1 hash function.
+// This is the internal core with wide interfaces.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha1_core(
+                 input wire            clk,
+                 input wire            reset_n,
+
+                 input wire            init,
+                 input wire            next,
+
+                 input wire [511 : 0]  block,
+
+                 output wire           ready,
+
+                 output wire [159 : 0] digest,
+                 output wire           digest_valid
+                );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter H0_0 = 32'h67452301;
+  parameter H0_1 = 32'hefcdab89;
+  parameter H0_2 = 32'h98badcfe;
+  parameter H0_3 = 32'h10325476;
+  parameter H0_4 = 32'hc3d2e1f0;
+
+  parameter SHA1_ROUNDS = 79;
+
+  parameter CTRL_IDLE   = 0;
+  parameter CTRL_ROUNDS = 1;
+  parameter CTRL_DIGEST = 2;
+  parameter CTRL_DONE   = 3;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [31 : 0] a_reg;
+  reg [31 : 0] a_new;
+  reg [31 : 0] b_reg;
+  reg [31 : 0] b_new;
+  reg [31 : 0] c_reg;
+  reg [31 : 0] c_new;
+  reg [31 : 0] d_reg;
+  reg [31 : 0] d_new;
+  reg [31 : 0] e_reg;
+  reg [31 : 0] e_new;
+  reg          a_e_we;
+
+  reg [31 : 0] H0_reg;
+  reg [31 : 0] H0_new;
+  reg [31 : 0] H1_reg;
+  reg [31 : 0] H1_new;
+  reg [31 : 0] H2_reg;
+  reg [31 : 0] H2_new;
+  reg [31 : 0] H3_reg;
+  reg [31 : 0] H3_new;
+  reg [31 : 0] H4_reg;
+  reg [31 : 0] H4_new;
+  reg          H_we;
+
+  reg [6 : 0] round_ctr_reg;
+  reg [6 : 0] round_ctr_new;
+  reg         round_ctr_we;
+  reg         round_ctr_inc;
+  reg         round_ctr_rst;
+
+  reg digest_valid_reg;
+  reg digest_valid_new;
+  reg digest_valid_we;
+
+  reg [1 : 0] sha1_ctrl_reg;
+  reg [1 : 0] sha1_ctrl_new;
+  reg         sha1_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg           digest_init;
+  reg           digest_update;
+  reg           state_init;
+  reg           state_update;
+  reg           first_block;
+  reg           ready_flag;
+  reg           w_init;
+  reg           w_next;
+  wire [31 : 0] w;
+
+
+  //----------------------------------------------------------------
+  // Module instantiantions.
+  //----------------------------------------------------------------
+  sha1_w_mem w_mem_inst(
+                        .clk(clk),
+                        .reset_n(reset_n),
+
+                        .block(block),
+
+                        .init(w_init),
+                        .next(w_next),
+
+                        .w(w)
+                       );
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign ready        = ready_flag;
+  assign digest       = {H0_reg, H1_reg, H2_reg, H3_reg, H4_reg};
+  assign digest_valid = digest_valid_reg;
+
+
+  //----------------------------------------------------------------
+  // 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 : reg_update
+      if (!reset_n)
+        begin
+          a_reg            <= 32'h00000000;
+          b_reg            <= 32'h00000000;
+          c_reg            <= 32'h00000000;
+          d_reg            <= 32'h00000000;
+          e_reg            <= 32'h00000000;
+          H0_reg           <= 32'h00000000;
+          H1_reg           <= 32'h00000000;
+          H2_reg           <= 32'h00000000;
+          H3_reg           <= 32'h00000000;
+          H4_reg           <= 32'h00000000;
+          digest_valid_reg <= 0;
+          round_ctr_reg    <= 7'b0000000;
+          sha1_ctrl_reg    <= CTRL_IDLE;
+        end
+      else
+        begin
+          if (a_e_we)
+            begin
+              a_reg <= a_new;
+              b_reg <= b_new;
+              c_reg <= c_new;
+              d_reg <= d_new;
+              e_reg <= e_new;
+            end
+
+          if (H_we)
+            begin
+              H0_reg <= H0_new;
+              H1_reg <= H1_new;
+              H2_reg <= H2_new;
+              H3_reg <= H3_new;
+              H4_reg <= H4_new;
+            end
+
+          if (round_ctr_we)
+            begin
+              round_ctr_reg <= round_ctr_new;
+            end
+
+          if (digest_valid_we)
+            begin
+              digest_valid_reg <= digest_valid_new;
+            end
+
+          if (sha1_ctrl_we)
+            begin
+              sha1_ctrl_reg <= sha1_ctrl_new;
+            end
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // digest_logic
+  //
+  // The logic needed to init as well as update the digest.
+  //----------------------------------------------------------------
+  always @*
+    begin : digest_logic
+      H0_new = 32'h00000000;
+      H1_new = 32'h00000000;
+      H2_new = 32'h00000000;
+      H3_new = 32'h00000000;
+      H4_new = 32'h00000000;
+      H_we = 0;
+
+      if (digest_init)
+        begin
+          H0_new = H0_0;
+          H1_new = H0_1;
+          H2_new = H0_2;
+          H3_new = H0_3;
+          H4_new = H0_4;
+          H_we = 1;
+        end
+
+      if (digest_update)
+        begin
+          H0_new = H0_reg + a_reg;
+          H1_new = H1_reg + b_reg;
+          H2_new = H2_reg + c_reg;
+          H3_new = H3_reg + d_reg;
+          H4_new = H4_reg + e_reg;
+          H_we = 1;
+        end
+    end // digest_logic
+
+
+  //----------------------------------------------------------------
+  // state_logic
+  //
+  // The logic needed to init as well as update the state during
+  // round processing.
+  //----------------------------------------------------------------
+  always @*
+    begin : state_logic
+      reg [31 : 0] a5;
+      reg [31 : 0] f;
+      reg [31 : 0] k;
+      reg [31 : 0] t;
+
+      a5     = 32'h00000000;
+      f      = 32'h00000000;
+      k      = 32'h00000000;
+      t      = 32'h00000000;
+      a_new  = 32'h00000000;
+      b_new  = 32'h00000000;
+      c_new  = 32'h00000000;
+      d_new  = 32'h00000000;
+      e_new  = 32'h00000000;
+      a_e_we = 0;
+
+      if (state_init)
+        begin
+          if (first_block)
+            begin
+              a_new  = H0_0;
+              b_new  = H0_1;
+              c_new  = H0_2;
+              d_new  = H0_3;
+              e_new  = H0_4;
+              a_e_we = 1;
+            end
+          else
+            begin
+              a_new  = H0_reg;
+              b_new  = H1_reg;
+              c_new  = H2_reg;
+              d_new  = H3_reg;
+              e_new  = H4_reg;
+              a_e_we = 1;
+            end
+        end
+
+      if (state_update)
+        begin
+          if (round_ctr_reg <= 19)
+            begin
+              k = 32'h5a827999;
+              f =  ((b_reg & c_reg) ^ (~b_reg & d_reg));
+            end
+          else if ((round_ctr_reg >= 20) && (round_ctr_reg <= 39))
+            begin
+              k = 32'h6ed9eba1;
+              f = b_reg ^ c_reg ^ d_reg;
+            end
+          else if ((round_ctr_reg >= 40) && (round_ctr_reg <= 59))
+            begin
+              k = 32'h8f1bbcdc;
+              f = ((b_reg | c_reg) ^ (b_reg | d_reg) ^ (c_reg | d_reg));
+            end
+          else if (round_ctr_reg >= 60)
+            begin
+              k = 32'hca62c1d6;
+              f = b_reg ^ c_reg ^ d_reg;
+            end
+
+          a5 = {a_reg[26 : 0], a_reg[31 : 27]};
+          t = a5 + e_reg + f + k + w;
+
+          a_new  = t;
+          b_new  = a_reg;
+          c_new  = {b_reg[1 : 0], b_reg[31 : 2]};
+          d_new  = c_reg;
+          e_new  = d_reg;
+          a_e_we = 1;
+        end
+    end // state_logic
+
+
+  //----------------------------------------------------------------
+  // round_ctr
+  //
+  // Update logic for the round counter, a monotonically
+  // increasing counter with reset.
+  //----------------------------------------------------------------
+  always @*
+    begin : round_ctr
+      round_ctr_new = 0;
+      round_ctr_we  = 0;
+
+      if (round_ctr_rst)
+        begin
+          round_ctr_new = 0;
+          round_ctr_we  = 1;
+        end
+
+      if (round_ctr_inc)
+        begin
+          round_ctr_new = round_ctr_reg + 1'b1;
+          round_ctr_we  = 1;
+        end
+    end // round_ctr
+
+
+  //----------------------------------------------------------------
+  // sha1_ctrl_fsm
+  // Logic for the state machine controlling the core behaviour.
+  //----------------------------------------------------------------
+  always @*
+    begin : sha1_ctrl_fsm
+      digest_init      = 0;
+      digest_update    = 0;
+      state_init       = 0;
+      state_update     = 0;
+      first_block      = 0;
+      ready_flag       = 0;
+      w_init           = 0;
+      w_next           = 0;
+      round_ctr_inc    = 0;
+      round_ctr_rst    = 0;
+      digest_valid_new = 0;
+      digest_valid_we  = 0;
+      sha1_ctrl_new    = CTRL_IDLE;
+      sha1_ctrl_we     = 0;
+
+      case (sha1_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            ready_flag = 1;
+
+            if (init)
+              begin
+                digest_init      = 1;
+                w_init           = 1;
+                state_init       = 1;
+                first_block      = 1;
+                round_ctr_rst    = 1;
+                digest_valid_new = 0;
+                digest_valid_we  = 1;
+                sha1_ctrl_new    = CTRL_ROUNDS;
+                sha1_ctrl_we     = 1;
+              end
+
+            if (next)
+              begin
+                w_init           = 1;
+                state_init       = 1;
+                round_ctr_rst    = 1;
+                digest_valid_new = 0;
+                digest_valid_we  = 1;
+                sha1_ctrl_new    = CTRL_ROUNDS;
+                sha1_ctrl_we     = 1;
+              end
+          end
+
+
+        CTRL_ROUNDS:
+          begin
+            state_update  = 1;
+            round_ctr_inc = 1;
+            w_next        = 1;
+
+            if (round_ctr_reg == SHA1_ROUNDS)
+              begin
+                sha1_ctrl_new = CTRL_DIGEST;
+                sha1_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_DIGEST:
+          begin
+            digest_update = 1;
+            sha1_ctrl_new = CTRL_DONE;
+            sha1_ctrl_we  = 1;
+          end
+
+        CTRL_DONE:
+          begin
+            digest_valid_new = 1;
+            digest_valid_we  = 1;
+            sha1_ctrl_new    = CTRL_IDLE;
+            sha1_ctrl_we     = 1;
+          end
+      endcase // case (sha1_ctrl_reg)
+    end // sha1_ctrl_fsm
+
+endmodule // sha1_core
+
+//======================================================================
+// EOF sha1_core.v
+//======================================================================
diff --git a/sha1/src/rtl/sha1_w_mem.v b/sha1/src/rtl/sha1_w_mem.v
new file mode 100644
index 0000000..cafb35c
--- /dev/null
+++ b/sha1/src/rtl/sha1_w_mem.v
@@ -0,0 +1,343 @@
+//======================================================================
+//
+// sha1_w_mem_reg.v
+// -----------------
+// The SHA-1 W memory. This memory is based around a sliding window
+// of 16 32-bit registers that are used to create the w words
+// needed by the core during the 80 rounds.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha1_w_mem(
+                  input wire           clk,
+                  input wire           reset_n,
+
+                  input wire [511 : 0] block,
+
+                  input wire           init,
+                  input wire           next,
+
+                  output wire [31 : 0] w
+                 );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter SHA1_ROUNDS = 79;
+
+  parameter CTRL_IDLE   = 1'b0;
+  parameter CTRL_UPDATE = 1'b1;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [31 : 0] w_mem [0 : 15];
+  reg [31 : 0] w_mem00_new;
+  reg [31 : 0] w_mem01_new;
+  reg [31 : 0] w_mem02_new;
+  reg [31 : 0] w_mem03_new;
+  reg [31 : 0] w_mem04_new;
+  reg [31 : 0] w_mem05_new;
+  reg [31 : 0] w_mem06_new;
+  reg [31 : 0] w_mem07_new;
+  reg [31 : 0] w_mem08_new;
+  reg [31 : 0] w_mem09_new;
+  reg [31 : 0] w_mem10_new;
+  reg [31 : 0] w_mem11_new;
+  reg [31 : 0] w_mem12_new;
+  reg [31 : 0] w_mem13_new;
+  reg [31 : 0] w_mem14_new;
+  reg [31 : 0] w_mem15_new;
+  reg          w_mem_we;
+
+  reg [6 : 0] w_ctr_reg;
+  reg [6 : 0] w_ctr_new;
+  reg         w_ctr_we;
+  reg         w_ctr_inc;
+  reg         w_ctr_rst;
+
+  reg         sha1_w_mem_ctrl_reg;
+  reg         sha1_w_mem_ctrl_new;
+  reg         sha1_w_mem_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [31 : 0] w_tmp;
+  reg [31 : 0] w_new;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign w = w_tmp;
+
+
+  //----------------------------------------------------------------
+  // 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 : reg_update
+      if (!reset_n)
+        begin
+          w_mem[00]           <= 32'h00000000;
+          w_mem[01]           <= 32'h00000000;
+          w_mem[02]           <= 32'h00000000;
+          w_mem[03]           <= 32'h00000000;
+          w_mem[04]           <= 32'h00000000;
+          w_mem[05]           <= 32'h00000000;
+          w_mem[06]           <= 32'h00000000;
+          w_mem[07]           <= 32'h00000000;
+          w_mem[08]           <= 32'h00000000;
+          w_mem[09]           <= 32'h00000000;
+          w_mem[10]           <= 32'h00000000;
+          w_mem[11]           <= 32'h00000000;
+          w_mem[12]           <= 32'h00000000;
+          w_mem[13]           <= 32'h00000000;
+          w_mem[14]           <= 32'h00000000;
+          w_mem[15]           <= 32'h00000000;
+          w_ctr_reg           <= 7'h00;
+          sha1_w_mem_ctrl_reg <= CTRL_IDLE;
+        end
+      else
+        begin
+          if (w_mem_we)
+            begin
+              w_mem[00] <= w_mem00_new;
+              w_mem[01] <= w_mem01_new;
+              w_mem[02] <= w_mem02_new;
+              w_mem[03] <= w_mem03_new;
+              w_mem[04] <= w_mem04_new;
+              w_mem[05] <= w_mem05_new;
+              w_mem[06] <= w_mem06_new;
+              w_mem[07] <= w_mem07_new;
+              w_mem[08] <= w_mem08_new;
+              w_mem[09] <= w_mem09_new;
+              w_mem[10] <= w_mem10_new;
+              w_mem[11] <= w_mem11_new;
+              w_mem[12] <= w_mem12_new;
+              w_mem[13] <= w_mem13_new;
+              w_mem[14] <= w_mem14_new;
+              w_mem[15] <= w_mem15_new;
+            end
+
+          if (w_ctr_we)
+            begin
+              w_ctr_reg <= w_ctr_new;
+            end
+
+          if (sha1_w_mem_ctrl_we)
+            begin
+              sha1_w_mem_ctrl_reg <= sha1_w_mem_ctrl_new;
+            end
+
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // select_w
+  //
+  // W word selection logic. Returns either directly from the
+  // memory or the next w value calculated.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_schedule
+      if (w_ctr_reg < 16)
+        begin
+          w_tmp = w_mem[w_ctr_reg[3 : 0]];
+        end
+      else
+        begin
+          w_tmp = w_new;
+        end
+    end // w_schedule
+
+
+  //----------------------------------------------------------------
+  // w_mem_update_logic
+  //
+  // Update logic for the W memory. This is where the scheduling
+  // based on a sliding window is implemented.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_mem_update_logic
+      reg [31 : 0] w_0;
+      reg [31 : 0] w_2;
+      reg [31 : 0] w_8;
+      reg [31 : 0] w_13;
+      reg [31 : 0] w_16;
+
+      w_mem00_new = 32'h00000000;
+      w_mem01_new = 32'h00000000;
+      w_mem02_new = 32'h00000000;
+      w_mem03_new = 32'h00000000;
+      w_mem04_new = 32'h00000000;
+      w_mem05_new = 32'h00000000;
+      w_mem06_new = 32'h00000000;
+      w_mem07_new = 32'h00000000;
+      w_mem08_new = 32'h00000000;
+      w_mem09_new = 32'h00000000;
+      w_mem10_new = 32'h00000000;
+      w_mem11_new = 32'h00000000;
+      w_mem12_new = 32'h00000000;
+      w_mem13_new = 32'h00000000;
+      w_mem14_new = 32'h00000000;
+      w_mem15_new = 32'h00000000;
+      w_mem_we    = 0;
+
+      w_0   = w_mem[0];
+      w_2   = w_mem[2];
+      w_8   = w_mem[8];
+      w_13  = w_mem[13];
+      w_16  = w_13 ^ w_8 ^ w_2 ^ w_0;
+      w_new = {w_16[30 : 0], w_16[31]};
+
+      if (init)
+        begin
+          w_mem00_new = block[511 : 480];
+          w_mem01_new = block[479 : 448];
+          w_mem02_new = block[447 : 416];
+          w_mem03_new = block[415 : 384];
+          w_mem04_new = block[383 : 352];
+          w_mem05_new = block[351 : 320];
+          w_mem06_new = block[319 : 288];
+          w_mem07_new = block[287 : 256];
+          w_mem08_new = block[255 : 224];
+          w_mem09_new = block[223 : 192];
+          w_mem10_new = block[191 : 160];
+          w_mem11_new = block[159 : 128];
+          w_mem12_new = block[127 :  96];
+          w_mem13_new = block[95  :  64];
+          w_mem14_new = block[63  :  32];
+          w_mem15_new = block[31  :   0];
+          w_mem_we    = 1;
+        end
+
+      else if (w_ctr_reg > 15)
+        begin
+          w_mem00_new = w_mem[01];
+          w_mem01_new = w_mem[02];
+          w_mem02_new = w_mem[03];
+          w_mem03_new = w_mem[04];
+          w_mem04_new = w_mem[05];
+          w_mem05_new = w_mem[06];
+          w_mem06_new = w_mem[07];
+          w_mem07_new = w_mem[08];
+          w_mem08_new = w_mem[09];
+          w_mem09_new = w_mem[10];
+          w_mem10_new = w_mem[11];
+          w_mem11_new = w_mem[12];
+          w_mem12_new = w_mem[13];
+          w_mem13_new = w_mem[14];
+          w_mem14_new = w_mem[15];
+          w_mem15_new = w_new;
+          w_mem_we    = 1;
+        end
+    end // w_mem_update_logic
+
+
+  //----------------------------------------------------------------
+  // w_ctr
+  //
+  // W schedule adress counter. Counts from 0x10 to 0x3f and
+  // is used to expand the block into words.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_ctr
+      w_ctr_new = 7'h00;
+      w_ctr_we  = 0;
+
+      if (w_ctr_rst)
+        begin
+          w_ctr_new = 7'h00;
+          w_ctr_we  = 1;
+        end
+
+      if (w_ctr_inc)
+        begin
+          w_ctr_new = w_ctr_reg + 7'h01;
+          w_ctr_we  = 1;
+        end
+    end // w_ctr
+
+
+  //----------------------------------------------------------------
+  // sha1_w_mem_fsm
+  //
+  // Logic for the w shedule FSM.
+  //----------------------------------------------------------------
+  always @*
+    begin : sha1_w_mem_fsm
+      w_ctr_rst           = 0;
+      w_ctr_inc           = 0;
+      sha1_w_mem_ctrl_new = CTRL_IDLE;
+      sha1_w_mem_ctrl_we  = 0;
+
+      case (sha1_w_mem_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            if (init)
+              begin
+                w_ctr_rst           = 1;
+                sha1_w_mem_ctrl_new = CTRL_UPDATE;
+                sha1_w_mem_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_UPDATE:
+          begin
+            if (next)
+              begin
+                w_ctr_inc = 1;
+              end
+
+            if (w_ctr_reg == SHA1_ROUNDS)
+              begin
+                sha1_w_mem_ctrl_new = CTRL_IDLE;
+                sha1_w_mem_ctrl_we  = 1;
+              end
+          end
+      endcase // case (sha1_ctrl_reg)
+    end // sha1_ctrl_fsm
+endmodule // sha1_w_mem
+
+//======================================================================
+// sha1_w_mem.v
+//======================================================================
diff --git a/sha1/src/tb/tb_sha1.v b/sha1/src/tb/tb_sha1.v
new file mode 100644
index 0000000..abf25d2
--- /dev/null
+++ b/sha1/src/tb/tb_sha1.v
@@ -0,0 +1,589 @@
+//======================================================================
+//
+// tb_sha1.v
+// ---------
+// Testbench for the SHA-1 top level wrapper.
+//
+//
+// 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, 
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+module tb_sha1();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG_CORE = 0;
+  parameter DEBUG_TOP  = 0;
+
+  parameter CLK_HALF_PERIOD = 1;
+  parameter CLK_PERIOD = CLK_HALF_PERIOD * 2;
+  
+  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_INIT_VALUE  = 8'h01;
+  parameter CTRL_NEXT_VALUE  = 8'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_DIGEST0   = 8'h20;
+  parameter ADDR_DIGEST1   = 8'h21;
+  parameter ADDR_DIGEST2   = 8'h22;
+  parameter ADDR_DIGEST3   = 8'h23;
+  parameter ADDR_DIGEST4   = 8'h24;
+
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+  reg           tb_cs;
+  reg           tb_write_read;
+  reg [7 : 0]   tb_address;
+  reg [31 : 0]  tb_data_in;
+  wire [31 : 0] tb_data_out;
+
+  reg [31 : 0]  read_data;
+  reg [159 : 0] digest_data;
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha1 dut(
+           .clk(tb_clk),
+           .reset_n(tb_reset_n),
+             
+           .cs(tb_cs),
+           .we(tb_write_read),
+             
+           .address(tb_address),
+           .write_data(tb_data_in),
+           .read_data(tb_data_out),
+           .error(tb_error)   
+          );
+  
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+    
+
+  //----------------------------------------------------------------
+  // sys_monitor
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      if (DEBUG_CORE)
+        begin
+          dump_core_state();
+        end
+      
+      if (DEBUG_TOP)
+        begin
+          dump_top_state();
+        end
+
+      #(CLK_PERIOD);
+      cycle_ctr = cycle_ctr + 1;
+    end
+
+  
+  //----------------------------------------------------------------
+  // dump_top_state()
+  //
+  // Dump state of the the top of the dut.
+  //----------------------------------------------------------------
+  task dump_top_state();
+    begin
+      $display("State of top");
+      $display("-------------");
+      $display("Inputs and outputs:");
+      $display("cs      = 0x%01x,  we         = 0x%01x", dut.cs, dut.we);
+      $display("address = 0x%02x, write_data = 0x%08x", dut.address, dut.write_data);
+      $display("error   = 0x%01x,  read_data  = 0x%08x", dut.error, dut.read_data);
+      $display("");
+      
+      $display("Control and status flags:");
+      $display("init = 0x%01x, next = 0x%01x, ready = 0x%01x", 
+               dut.init_reg, dut.next_reg, dut.ready_reg);
+      $display("");
+
+      $display("block registers:");
+      $display("block0_reg  = 0x%08x, block1_reg  = 0x%08x, block2_reg  = 0x%08x, block3_reg  = 0x%08x",
+               dut.block0_reg, dut.block1_reg, dut.block2_reg, dut.block3_reg);
+
+      $display("block4_reg  = 0x%08x, block5_reg  = 0x%08x, block6_reg  = 0x%08x, block7_reg  = 0x%08x",
+               dut.block4_reg, dut.block5_reg, dut.block6_reg, dut.block7_reg);
+
+      $display("block8_reg  = 0x%08x, block9_reg  = 0x%08x, block10_reg = 0x%08x, block11_reg = 0x%08x",
+               dut.block8_reg, dut.block9_reg, dut.block10_reg, dut.block11_reg);
+
+      $display("block12_reg = 0x%08x, block13_reg = 0x%08x, block14_reg = 0x%08x, block15_reg = 0x%08x",
+               dut.block12_reg, dut.block13_reg, dut.block14_reg, dut.block15_reg);
+      $display("");
+
+      $display("Digest registers:");
+      $display("digest_reg  = 0x%040x", dut.digest_reg);
+      $display("");
+    end
+  endtask // dump_top_state
+
+  
+  //----------------------------------------------------------------
+  // dump_core_state()
+  //
+  // Dump the state of the core inside the dut.
+  //----------------------------------------------------------------
+  task dump_core_state();
+    begin
+      $display("State of core");
+      $display("-------------");
+      $display("Inputs and outputs:");
+      $display("init   = 0x%01x, next  = 0x%01x", 
+               dut.core.init, dut.core.next);
+      $display("block  = 0x%0128x", dut.core.block);
+
+      $display("ready  = 0x%01x, valid = 0x%01x", 
+               dut.core.ready, dut.core.digest_valid);
+      $display("digest = 0x%040x", dut.core.digest);
+      $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x, H4_reg = 0x%08x", 
+               dut.core.H0_reg, dut.core.H1_reg, dut.core.H2_reg, dut.core.H3_reg, dut.core.H4_reg);
+      $display("");
+      
+      $display("Control signals and counter:");
+      $display("sha1_ctrl_reg = 0x%01x", dut.core.sha1_ctrl_reg);
+      $display("digest_init   = 0x%01x, digest_update = 0x%01x", 
+               dut.core.digest_init, dut.core.digest_update);
+      $display("state_init    = 0x%01x, state_update  = 0x%01x", 
+               dut.core.state_init, dut.core.state_update);
+      $display("first_block   = 0x%01x, ready_flag    = 0x%01x, w_init        = 0x%01x", 
+               dut.core.first_block, dut.core.ready_flag, dut.core.w_init);
+      $display("round_ctr_inc = 0x%01x, round_ctr_rst = 0x%01x, round_ctr_reg = 0x%02x", 
+               dut.core.round_ctr_inc, dut.core.round_ctr_rst, dut.core.round_ctr_reg);
+      $display("");
+
+      $display("State registers:");
+      $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x, e_reg = 0x%08x", 
+               dut.core.a_reg, dut.core.b_reg, dut.core.c_reg, dut.core.d_reg,  dut.core.e_reg);
+      $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x, e_new = 0x%08x", 
+               dut.core.a_new, dut.core.b_new, dut.core.c_new, dut.core.d_new, dut.core.e_new);
+      $display("");
+
+      $display("State update values:");
+      $display("f = 0x%08x, k = 0x%08x, t = 0x%08x, w = 0x%08x,", 
+               dut.core.state_logic.f, dut.core.state_logic.k, dut.core.state_logic.t, dut.core.w);
+      $display("");
+    end
+  endtask // dump_core_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 32'h00000000;
+      error_ctr = 32'h00000000;
+      tc_ctr    = 32'h00000000;
+      
+      tb_clk        = 0;
+      tb_reset_n    = 0;
+      tb_cs         = 0;
+      tb_write_read = 0;
+      tb_address    = 6'h00;
+      tb_data_in    = 32'h00000000;
+    end
+  endtask // init_dut
+
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully.", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases completed.", tc_ctr);
+          $display("*** %02d errors detected during testing.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+  
+  
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  // (Actually we wait for either ready or valid to be set.)
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      read_data = 0;
+      
+      while (read_data == 0)
+        begin
+          read_word(ADDR_STATUS);
+        end
+    end
+  endtask // wait_ready
+  
+
+  //----------------------------------------------------------------
+  // read_word()
+  //
+  // Read a data word from the given address in the DUT.
+  // the word read will be available in the global variable
+  // read_data.
+  //----------------------------------------------------------------
+  task read_word(input [7 : 0] address);
+    begin
+      tb_address = address;
+      tb_cs = 1;
+      tb_write_read = 0;
+      #(CLK_PERIOD);
+      read_data = tb_data_out;
+      tb_cs = 0;
+
+      if (DEBUG_TOP)
+        begin
+          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
+          $display("");
+        end
+    end
+  endtask // read_word
+  
+
+  //----------------------------------------------------------------
+  // write_word()
+  //
+  // Write the given word to the DUT using the DUT interface.
+  //----------------------------------------------------------------
+  task write_word(input [7 : 0]  address,
+                  input [31 : 0] word);
+    begin
+      if (DEBUG_TOP)
+        begin
+          $display("*** Writing 0x%08x to 0x%02x.", word, address);
+          $display("");
+        end
+         
+      tb_address = address;
+      tb_data_in = word;
+      tb_cs = 1;
+      tb_write_read = 1;
+      #(CLK_PERIOD);
+      tb_cs = 0;
+      tb_write_read = 0;
+    end
+  endtask // write_word
+
+  
+  //----------------------------------------------------------------
+  // write_block()
+  //
+  // Write the given block to the dut.
+  //----------------------------------------------------------------
+  task write_block(input [511 : 0] block);
+    begin
+      write_word(ADDR_BLOCK0,  block[511 : 480]);
+      write_word(ADDR_BLOCK1,  block[479 : 448]);
+      write_word(ADDR_BLOCK2,  block[447 : 416]);
+      write_word(ADDR_BLOCK3,  block[415 : 384]);
+      write_word(ADDR_BLOCK4,  block[383 : 352]);
+      write_word(ADDR_BLOCK5,  block[351 : 320]);
+      write_word(ADDR_BLOCK6,  block[319 : 288]);
+      write_word(ADDR_BLOCK7,  block[287 : 256]);
+      write_word(ADDR_BLOCK8,  block[255 : 224]);
+      write_word(ADDR_BLOCK9,  block[223 : 192]);
+      write_word(ADDR_BLOCK10, block[191 : 160]);
+      write_word(ADDR_BLOCK11, block[159 : 128]);
+      write_word(ADDR_BLOCK12, block[127 :  96]);
+      write_word(ADDR_BLOCK13, block[95  :  64]);
+      write_word(ADDR_BLOCK14, block[63  :  32]);
+      write_word(ADDR_BLOCK15, block[31  :   0]);
+    end
+  endtask // write_block
+
+  
+  //----------------------------------------------------------------
+  // check_name_version()
+  //
+  // Read the name and version from the DUT.
+  //----------------------------------------------------------------
+  task check_name_version();
+    reg [31 : 0] name0;
+    reg [31 : 0] name1;
+    reg [31 : 0] version;
+    begin
+
+      read_word(ADDR_NAME0);
+      name0 = read_data;
+      read_word(ADDR_NAME1);
+      name1 = read_data;
+      read_word(ADDR_VERSION);
+      version = read_data;
+
+      $display("DUT name: %c%c%c%c%c%c%c%c",
+               name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0],
+               name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]);
+      $display("DUT version: %c%c%c%c",
+               version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]);
+    end
+  endtask // check_name_version
+  
+
+  //----------------------------------------------------------------
+  // read_digest()
+  //
+  // Read the digest in the dut. The resulting digest will be
+  // available in the global variable digest_data.
+  //----------------------------------------------------------------
+  task read_digest();
+    begin
+      read_word(ADDR_DIGEST0);
+      digest_data[159 : 128] = read_data;
+      read_word(ADDR_DIGEST1);
+      digest_data[127 :  96] = read_data;
+      read_word(ADDR_DIGEST2);
+      digest_data[95  :  64] = read_data;
+      read_word(ADDR_DIGEST3);
+      digest_data[63  :  32] = read_data;
+      read_word(ADDR_DIGEST4);
+      digest_data[31  :   0] = read_data;
+    end
+  endtask // read_digest
+    
+  
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  //
+  // Perform test of a single block digest.
+  //----------------------------------------------------------------
+  task single_block_test(input [511 : 0] block,
+                         input [159 : 0] expected
+                         );
+    begin
+      $display("*** TC%01d - Single block test started.", tc_ctr); 
+     
+      write_block(block);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected)
+        begin
+          $display("TC%01d: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR.", tc_ctr);
+          $display("TC%01d: Expected: 0x%040x", tc_ctr, expected);
+          $display("TC%01d: Got:      0x%040x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+      $display("*** TC%01d - Single block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // single_block_test
+    
+  
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  //
+  // Perform test of a double block digest. Note that we check
+  // the digests for both the first and final block.
+  //----------------------------------------------------------------
+  task double_block_test(input [511 : 0] block0,
+                         input [159 : 0] expected0,
+                         input [511 : 0] block1,
+                         input [159 : 0] expected1
+                        );
+    begin
+      $display("*** TC%01d - Double block test started.", tc_ctr); 
+
+      // First block
+      write_block(block0);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected0)
+        begin
+          $display("TC%01d first block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in first digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%040x", tc_ctr, expected0);
+          $display("TC%01d: Got:      0x%040x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      // Final block
+      write_block(block1);
+      write_word(ADDR_CTRL, CTRL_NEXT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+      
+      if (digest_data == expected1)
+        begin
+          $display("TC%01d final block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in final digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%040x", tc_ctr, expected1);
+          $display("TC%01d: Got:      0x%040x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      $display("*** TC%01d - Double block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // double_block_test
+
+    
+  //----------------------------------------------------------------
+  // sha1_test
+  // The main test functionality. 
+  //----------------------------------------------------------------
+  initial
+    begin : sha1_test
+      reg [511 : 0] tc1;
+      reg [159 : 0] res1;
+
+      reg [511 : 0] tc2_1;
+      reg [159 : 0] res2_1;
+      reg [511 : 0] tc2_2;
+      reg [159 : 0] res2_2;
+
+      $display("   -- Testbench for sha1 started --");
+
+      init_sim();
+      reset_dut();
+      check_name_version();
+        
+      // TC1: Single block message: "abc".
+      tc1 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      res1 = 160'ha9993e364706816aba3e25717850c26c9cd0d89d;
+      single_block_test(tc1, res1);
+
+      // TC2: Double block message.
+      // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+      tc2_1 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000;
+      res2_1 = 160'hf4286818c37b27ae0408f581846771484a566572;
+      
+      tc2_2 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0;
+      res2_2 = 160'h84983e441c3bd26ebaae4aa1f95129e5e54670f1;
+      double_block_test(tc2_1, res2_1, tc2_2, res2_2);
+      
+      display_test_result();
+      $display("*** Simulation done. ***");
+      $finish;
+    end // sha1_test
+endmodule // tb_sha1
+
+//======================================================================
+// EOF tb_sha1.v
+//======================================================================
+
diff --git a/sha1/src/tb/tb_sha1_core.v b/sha1/src/tb/tb_sha1_core.v
new file mode 100644
index 0000000..0ae592d
--- /dev/null
+++ b/sha1/src/tb/tb_sha1_core.v
@@ -0,0 +1,388 @@
+//======================================================================
+//
+// tb_sha1_core.v
+// ----------------
+// Testbench for the SHA-1 core.
+//
+//
+// 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, 
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+module tb_sha1_core();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  parameter CLK_HALF_PERIOD = 1;
+  parameter CLK_PERIOD = CLK_HALF_PERIOD * 2;
+  
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg            tb_clk;
+  reg            tb_reset_n;
+  reg            tb_init;
+  reg            tb_next;
+  reg [511 : 0]  tb_block;
+  wire           tb_ready;
+  wire [159 : 0] tb_digest;
+  wire           tb_digest_valid;
+  
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha1_core dut(
+                   .clk(tb_clk),
+                   .reset_n(tb_reset_n),
+                 
+                   .init(tb_init),
+                   .next(tb_next),
+
+                   .block(tb_block),
+                   
+                   .ready(tb_ready),
+                   
+                   .digest(tb_digest),
+                   .digest_valid(tb_digest_valid)
+                 );
+  
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+    
+
+  //----------------------------------------------------------------
+  // sys_monitor
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      #(CLK_PERIOD);
+      if (DEBUG)
+        begin
+          dump_dut_state();
+        end
+    end
+
+  
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dump when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $display("init   = 0x%01x, next  = 0x%01x", 
+               dut.init, dut.next);
+      $display("block  = 0x%0128x", dut.block);
+
+      $display("ready  = 0x%01x, valid = 0x%01x", 
+               dut.ready, dut.digest_valid);
+      $display("digest = 0x%040x", dut.digest);
+      $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x, H4_reg = 0x%08x", 
+               dut.H0_reg, dut.H1_reg, dut.H2_reg, dut.H3_reg, dut.H4_reg);
+      $display("");
+      
+      $display("Control signals and counter:");
+      $display("sha1_ctrl_reg = 0x%01x", dut.sha1_ctrl_reg);
+      $display("digest_init   = 0x%01x, digest_update = 0x%01x", 
+               dut.digest_init, dut.digest_update);
+      $display("state_init    = 0x%01x, state_update  = 0x%01x", 
+               dut.state_init, dut.state_update);
+      $display("first_block   = 0x%01x, ready_flag    = 0x%01x, w_init        = 0x%01x", 
+               dut.first_block, dut.ready_flag, dut.w_init);
+      $display("round_ctr_inc = 0x%01x, round_ctr_rst = 0x%01x, round_ctr_reg = 0x%02x", 
+               dut.round_ctr_inc, dut.round_ctr_rst, dut.round_ctr_reg);
+      $display("");
+
+      $display("State registers:");
+      $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x, e_reg = 0x%08x", 
+               dut.a_reg, dut.b_reg, dut.c_reg, dut.d_reg,  dut.e_reg);
+      $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x, e_new = 0x%08x", 
+               dut.a_new, dut.b_new, dut.c_new, dut.d_new, dut.e_new);
+      $display("");
+
+      $display("State update values:");
+      $display("f = 0x%08x, k = 0x%08x, t = 0x%08x, w = 0x%08x,", 
+               dut.state_logic.f, dut.state_logic.k, dut.state_logic.t, dut.w);
+      $display("");
+    end
+  endtask // dump_dut_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      error_ctr = 0;
+      tc_ctr = 0;
+      
+      tb_clk = 0;
+      tb_reset_n = 1;
+
+      tb_init = 0;
+      tb_next = 0;
+      tb_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
+    end
+  endtask // init_dut
+
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases did not complete successfully.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+  
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      while (!tb_ready)
+        begin
+          #(CLK_PERIOD);
+          
+        end
+    end
+  endtask // wait_ready
+
+  
+  //----------------------------------------------------------------
+  // single_block_test
+  //
+  // Test a message of at most one block.
+  //----------------------------------------------------------------
+  task single_block_test(input [7 : 0]   tc_number,
+                         input [511 : 0] block,
+                         input [159 : 0] expected);
+   begin
+     $display("*** TC %0d single block test case started.", tc_number);
+     tc_ctr = tc_ctr + 1;
+
+     tb_block = block;
+     tb_init = 1;
+     #(CLK_PERIOD);
+     tb_init = 0;
+     wait_ready();
+
+      
+     if (tb_digest == expected)
+       begin
+         $display("*** TC %0d successful.", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d NOT successful.", tc_number);
+         $display("Expected: 0x%040x", expected);
+         $display("Got:      0x%040x", tb_digest);
+         $display("");
+         
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // single_block_test
+
+  
+  //----------------------------------------------------------------
+  // double_block_test
+  //
+  // Test message consisting of two blocks.
+  //----------------------------------------------------------------
+  task double_block_test(input [7 : 0]   tc_number,
+                         input [511 : 0] block1,
+                         input [159 : 0] expected1,
+                         input [511 : 0] block2,
+                         input [159 : 0] expected2);
+
+     reg [159 : 0] db_digest1;
+     reg           db_error;
+   begin
+     $display("*** TC %0d double block test case started.", tc_number);
+     db_error = 0;
+     tc_ctr = tc_ctr + 1;
+
+     $display("*** TC %0d first block started.", tc_number);
+     tb_block = block1;
+     tb_init = 1;
+     #(CLK_PERIOD);
+     tb_init = 0;
+     wait_ready();
+     db_digest1 = tb_digest;
+     $display("*** TC %0d first block done.", tc_number);
+     
+     $display("*** TC %0d second block started.", tc_number);
+     tb_block = block2;
+     tb_next = 1;
+     #(CLK_PERIOD);
+     tb_next = 0;
+     wait_ready();
+     $display("*** TC %0d second block done.", tc_number);
+      
+     if (db_digest1 == expected1)
+       begin
+         $display("*** TC %0d first block successful", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d first block NOT successful", tc_number);
+         $display("Expected: 0x%040x", expected1);
+         $display("Got:      0x%040x", db_digest1);
+         $display("");
+         db_error = 1;
+       end
+      
+     if (db_digest1 == expected1)
+       begin
+         $display("*** TC %0d second block successful", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d second block NOT successful", tc_number);
+         $display("Expected: 0x%040x", expected2);
+         $display("Got:      0x%040x", tb_digest);
+         $display("");
+         db_error = 1;
+       end
+
+     if (db_error)
+       begin
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // double_block_test
+                         
+    
+  //----------------------------------------------------------------
+  // sha1_core_test
+  // The main test functionality. 
+  //----------------------------------------------------------------
+  initial
+    begin : sha1_core_test
+      reg [511 : 0] tc1;
+      reg [159 : 0] res1;
+
+      reg [511 : 0] tc2_1;
+      reg [159 : 0] res2_1;
+      reg [511 : 0] tc2_2;
+      reg [159 : 0] res2_2;
+      
+      $display("   -- Testbench for sha1 core started --");
+
+      init_sim();
+      dump_dut_state();
+      reset_dut();
+      dump_dut_state();
+        
+      // TC1: Single block message: "abc".
+      tc1 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      res1 = 160'ha9993e364706816aba3e25717850c26c9cd0d89d;
+      single_block_test(1, tc1, res1);
+
+      // TC2: Double block message.
+      // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+      tc2_1 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000;
+      res2_1 = 160'hf4286818c37b27ae0408f581846771484a566572;
+      
+      tc2_2 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0;
+      res2_2 = 160'h84983e441c3bd26ebaae4aa1f95129e5e54670f1;
+      double_block_test(2, tc2_1, res2_1, tc2_2, res2_2);
+      
+      display_test_result();
+      $display("*** Simulation done.");
+      $finish;
+    end // sha1_core_test
+endmodule // tb_sha1_core
+
+//======================================================================
+// EOF tb_sha1_core.v
+//======================================================================
diff --git a/sha1/src/tb/tb_sha1_w_mem.v b/sha1/src/tb/tb_sha1_w_mem.v
new file mode 100644
index 0000000..7426bcd
--- /dev/null
+++ b/sha1/src/tb/tb_sha1_w_mem.v
@@ -0,0 +1,287 @@
+//======================================================================
+//
+// Tb_sha1_w_mem.v
+// ---------------
+// Testbench for the SHA-1 W memory module.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+module tb_sha1_w_mem();
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG          = 1;
+  parameter DISPLAY_CYCLES = 0;
+
+  parameter CLK_HALF_PERIOD = 2;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg           tb_clk;
+  reg           tb_reset_n;
+  reg           tb_init;
+  reg           tb_next;
+  reg [511 : 0] tb_block;
+  wire [31 : 0] tb_w;
+
+  reg [63 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha1_w_mem dut(
+                 .clk(tb_clk),
+                 .reset_n(tb_reset_n),
+
+                 .block(tb_block),
+
+                 .init(tb_init),
+                 .next(tb_next),
+
+                 .w(tb_w)
+                );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //--------------------------------------------------------------------
+  // dut_monitor
+  //
+  // Monitor displaying information every cycle.
+  // Includes the cycle counter.
+  //--------------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : dut_monitor
+      cycle_ctr = cycle_ctr + 1;
+
+      if (DISPLAY_CYCLES)
+        begin
+          $display("cycle = %016x:", cycle_ctr);
+        end
+
+      if (DEBUG)
+        begin
+          dump_w_state();
+        end
+    end // dut_monitor
+
+
+  //----------------------------------------------------------------
+  // dump_w_state()
+  //
+  // Dump the current state of all W registers.
+  //----------------------------------------------------------------
+  task dump_w_state();
+    begin
+      $display("W state:");
+
+
+      $display("ctrl_reg = %01x, w_ctr_reg = %02x, init = %01x, next = %01x",
+               dut.sha1_w_mem_ctrl_reg, dut.w_ctr_reg, dut.init, dut.next);
+
+      $display("w_tmp   = %08x, w_new   = %08x", dut.w_tmp, dut.w_new);
+
+      $display("w0_reg  = %08x, w1_reg  = %08x, w2_reg  = %08x, w3_reg  = %08x",
+               dut.w_mem[00], dut.w_mem[01], dut.w_mem[02], dut.w_mem[03]);
+
+      $display("w4_reg  = %08x, w5_reg  = %08x, w6_reg  = %08x, w7_reg  = %08x",
+               dut.w_mem[04], dut.w_mem[05], dut.w_mem[06], dut.w_mem[07]);
+
+      $display("w8_reg  = %08x, w9_reg  = %08x, w10_reg = %08x, w11_reg = %08x",
+               dut.w_mem[08], dut.w_mem[09], dut.w_mem[10], dut.w_mem[11]);
+
+      $display("w12_reg = %08x, w13_reg = %08x, w14_reg = %08x, w15_reg = %08x",
+               dut.w_mem[12], dut.w_mem[13], dut.w_mem[14], dut.w_mem[15]);
+
+      $display("");
+    end
+  endtask // dump_state
+
+
+  //----------------------------------------------------------------
+  // reset_dut
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+
+  //----------------------------------------------------------------
+  // init_sim
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      $display("*** Simulation init.");
+      tb_clk     = 0;
+      tb_reset_n = 1;
+      cycle_ctr  = 0;
+      tb_init    = 0;
+      tb_next    = 0;
+      tb_block   = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
+    end
+  endtask // reset_dut
+
+
+  //----------------------------------------------------------------
+  // dump_mem()
+  //
+  // Dump the contents of the memory by directly reading from
+  // the registers in the dut, not via the read port.
+  //----------------------------------------------------------------
+  task dump_mem();
+    begin
+      $display("*** Dumping memory:");
+      $display("W[00] = 0x%08x", dut.w_mem[00]);
+      $display("W[01] = 0x%08x", dut.w_mem[01]);
+      $display("W[02] = 0x%08x", dut.w_mem[02]);
+      $display("W[03] = 0x%08x", dut.w_mem[03]);
+      $display("W[04] = 0x%08x", dut.w_mem[04]);
+      $display("W[05] = 0x%08x", dut.w_mem[05]);
+      $display("W[06] = 0x%08x", dut.w_mem[06]);
+      $display("W[07] = 0x%08x", dut.w_mem[07]);
+      $display("W[08] = 0x%08x", dut.w_mem[08]);
+      $display("W[09] = 0x%08x", dut.w_mem[09]);
+      $display("W[10] = 0x%08x", dut.w_mem[10]);
+      $display("W[11] = 0x%08x", dut.w_mem[11]);
+      $display("W[12] = 0x%08x", dut.w_mem[12]);
+      $display("W[13] = 0x%08x", dut.w_mem[13]);
+      $display("W[14] = 0x%08x", dut.w_mem[14]);
+      $display("W[15] = 0x%08x", dut.w_mem[15]);
+      $display("");
+    end
+  endtask // dump_mem
+
+
+  //----------------------------------------------------------------
+  // test_w_schedule()
+  //
+  // Test that W scheduling happens and work correctly.
+  // Note: Currently not a self checking test case.
+  //----------------------------------------------------------------
+  task test_w_schedule();
+    begin
+      $display("*** Test of W schedule processing. --");
+      tb_block = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      tb_init = 1;
+      #(4 * CLK_HALF_PERIOD);
+      tb_init = 0;
+
+      tb_next = 1;
+      #(200 * CLK_HALF_PERIOD);
+
+      dump_w_state();
+    end
+  endtask // test_w_schedule
+
+
+  //----------------------------------------------------------------
+  // test_read_w/(
+  //
+  // Test that we can read data from all W registers.
+  // Note: Currently not a self checking test case.
+  //----------------------------------------------------------------
+  task test_read_w();
+    reg [7 : 0] i;
+    begin
+      $display("*** Test of W read operations. --");
+      i = 0;
+      tb_init = 1;
+      #(2 * CLK_HALF_PERIOD);
+      tb_init = 0;
+
+      while (i < 80)
+        begin
+          tb_next = i;
+          $display("API: w%02x = 0x%02x", i, dut.w_tmp);
+          i = i + 1;
+          #(2 * CLK_HALF_PERIOD);
+        end
+    end
+  endtask // read_w
+
+
+  //----------------------------------------------------------------
+  // The main test functionality.
+  //----------------------------------------------------------------
+  initial
+    begin : w_mem_test
+      $display("   -- Testbench for sha1 w memory started --");
+      init_sim();
+
+      dump_mem();
+      reset_dut();
+      dump_mem();
+
+      test_w_schedule();
+
+      test_read_w();
+
+      $display("*** Simulation done.");
+      $finish;
+    end
+
+endmodule // w_mem_test
+
+//======================================================================
+// EOF tb_sha1_w_mem.v
+//======================================================================
diff --git a/sha1/toolruns/Makefile b/sha1/toolruns/Makefile
new file mode 100755
index 0000000..16dc069
--- /dev/null
+++ b/sha1/toolruns/Makefile
@@ -0,0 +1,102 @@
+#===================================================================
+#
+# Makefile
+# --------
+# Makefile for building sha1 core and top simulation files.
+#
+#
+# Author: Joachim Strombergson
+# Copyright (c) 2014, SUNET
+# 
+# Redistribution and use in source and binary forms, with or 
+# without modification, are permitted provided that the following 
+# conditions are met: 
+# 
+# 1. Redistributions of source code must retain the above copyright 
+#    notice, this list of conditions and the following disclaimer. 
+# 
+# 2. Redistributions in binary form must reproduce the above copyright 
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution. 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#===================================================================
+
+WMEM_SRC=../src/rtl/sha1_w_mem.v
+WMEM_TB_SRC=../src/tb/tb_sha1_w_mem.v
+
+CORE_SRC=../src/rtl/sha1_core.v ../src/rtl/sha1_w_mem.v
+CORE_TB_SRC=../src/tb/tb_sha1_core.v
+
+TOP_SRC=../src/rtl/sha1.v $(CORE_SRC)
+TOP_TB_SRC=../src/tb/tb_sha1.v
+
+CC=iverilog
+
+
+all: top core wmem
+
+
+top: $(TOP_TB_SRC) $(TOP_SRC)
+	$(CC) -o top.sim $(TOP_TB_SRC) $(TOP_SRC)
+
+
+core: $(CORE_TB_SRC) $(CORE_SRC)
+	$(CC) -o core.sim $(CORE_SRC) $(CORE_TB_SRC)
+
+
+wmem: $(WMEM_SRC) $(WMEM_TB_SRC)
+	$(CC) -o wmem.sim $(WMEM_SRC) $(WMEM_TB_SRC)
+
+
+sim-top: top.sim
+	./top.sim
+
+
+sim-core: core.sim
+	./core.sim
+
+
+sim-wmem: wmem.sim
+	./wmem.sim
+
+
+debug:
+	@echo "No debug available."
+
+
+clean:
+	rm -f top.sim
+	rm -f core.sim
+	rm -f wmem.sim
+
+
+help:
+	@echo "Supported targets:"
+	@echo "------------------"
+	@echo "all:      Build all simulation targets."
+	@echo "top:      Build the top simulation target."
+	@echo "core:     Build the core simulation target."
+	@echo "wmem:     Build the wmem simulation target."
+	@echo "sim-top:  Run top level simulation."
+	@echo "sim-core: Run core level simulation."
+	@echo "sim-wmem: Run wmem level simulation."
+	@echo "debug:    Print the internal varibles."
+	@echo "clean:    Delete all built files."
+
+#===================================================================
+# EOF Makefile
+#===================================================================
diff --git a/sha256/LICENSE.txt b/sha256/LICENSE.txt
new file mode 100644
index 0000000..2acf230
--- /dev/null
+++ b/sha256/LICENSE.txt
@@ -0,0 +1,24 @@
+
+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:
+
+* 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.
+
+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.
diff --git a/sha256/README.md b/sha256/README.md
new file mode 100644
index 0000000..10150df
--- /dev/null
+++ b/sha256/README.md
@@ -0,0 +1,113 @@
+# sha256 #
+Hardware implementation of the SHA-256 cryptographic hash function. The
+implementation is written in Verilog 2001 compliant code. The
+implementation includes a core and a wrapper that provides a 32-bit
+interface for simple integration. There is also an alternative wrapper
+that implements a Wishbone compliant interface.
+
+This is a low area implementation that iterates over the rounds but
+there is no sharing of operations such as adders.
+
+The hardware implementation is complemented by a functional model
+written in Python.
+
+## Implementation details ##
+The sha256 is divided into the following sections.
+- src/rtl - RTL source files
+- src/tb  - Testbenches for the RTL files
+- src/model/python - Functional model written in python
+- doc - documentation (currently not done.)
+- toolruns - Where tools are supposed to be run. Includes a Makefile for
+building and simulating the design using [Icarus Verilog](http://iverilog.icarus.com/)
+
+The actual core consists of the following files:
+- sha256_core.v - The core itself with wide interfaces.
+- sha256_w_mem.v - W message block memort and expansion logic.
+- sha256_k_constants.v - K constants ROM memory.
+
+The top level entity is called sha256_core. This entity has wide
+interfaces (512 bit block input, 256 bit digest). In order to make it
+usable you probably want to wrap the core with a bus interface.
+
+Unless you want to provide your own interface you therefore also need to
+select one top level wrapper. There are two wrappers provided:
+- sha256.v - A wrapper with a 32-bit memory like interface.
+- wb_sha256.v - A wrapper that implements a [Wishbone](http://opencores.org/opencores,wishbone) interface.
+
+***Do not include both wrappers in the same project.***
+
+The core (sha256_core) will sample all data inputs when given the init
+or next signal. the wrappers provided contains additional data
+registers. This allows you to load a new block while the core is
+processing the previous block.
+
+The W-memory scheduler is based on 16 32-bit registers. Thee registers
+are loaded with the current block. After 16 rounds the contents of the
+registers slide through the registers r5..r0 while the new W word is
+inserted at r15 as well as being returned to the core.
+
+
+## FPGA-results ##
+
+### Altera Cyclone FPGAs ###
+Implementation results using Altera Quartus-II 13.1.
+
+***Cyclone IV E***
+- EP4CE6F17C6
+- 3882 LEs
+- 1813 registers
+- 74 MHz
+- 66 cycles latency
+
+***Cyclone IV GX***
+- EP4CGX22CF19C6
+- 3773 LEs
+- 1813 registers
+- 76 MHz
+- 66 cycles latency
+
+***Cyclone V***
+- 5CGXFC7C7F23C8
+- 1469 ALMs
+- 1813 registers
+- 79 MHz
+- 66 cycles latency
+
+
+## TODO ##
+- Extensive verification in physical device.
+- Complete documentation.
+
+
+## Status ##
+***(2013-02-23)***
+
+Cleanup, more results etc. Move all wmem update logic to a separate
+process for a cleaner code.
+
+
+**(2014-02-22)**
+
+Redesigned the W-memory into a sliding window solution. This not only
+removed 48 32-registers but also several muxes and address decoders.
+
+The old implementation resources and performance:
+- 9587 LEs
+- 3349 registers
+- 73 MHz
+- 66 cycles latency
+
+The new implementation resources and performance:
+- 3765 LEs
+- 1813 registers
+- 76 MHz
+- 66 cycles latency
+
+
+
+**(2014-02-19)**
+- The core has been added to the Cryptech repo. The core comes from
+  https://github.com/secworks/sha256
+
+
+
diff --git a/sha256/src/model/sha256.py b/sha256/src/model/sha256.py
new file mode 100755
index 0000000..3b16e1f
--- /dev/null
+++ b/sha256/src/model/sha256.py
@@ -0,0 +1,344 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#=======================================================================
+#
+# sha256.py
+# ---------
+# Simple, pure Python model of the SHA-256 hash function. Used as a
+# reference for the HW implementation. The code follows the structure
+# of the HW implementation as much as possible.
+#
+#
+# Author: Joachim Strömbergson
+# Copyright (c) 2013, 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, 
+# 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.
+#
+#=======================================================================
+
+#-------------------------------------------------------------------
+# Python module imports.
+#-------------------------------------------------------------------
+import sys
+
+
+#-------------------------------------------------------------------
+# Constants.
+#-------------------------------------------------------------------
+VERBOSE = True
+
+
+#-------------------------------------------------------------------
+# ChaCha()
+#-------------------------------------------------------------------
+class SHA256():
+    def __init__(self, verbose = 0):
+        self.verbose = verbose
+        self.H = [0] * 8
+        self.t1 = 0
+        self.t2 = 0
+        self.a = 0
+        self.b = 0
+        self.c = 0
+        self.d = 0
+        self.e = 0
+        self.f = 0
+        self.g = 0
+        self.h = 0
+        self.w = 0
+        self.W = [0] * 16
+        self.k = 0
+        self.K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+                  0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+                  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+                  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+                  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+                  0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+                  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+                  0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+                  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+                  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+                  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+                  0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+                  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+                  0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+                  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+                  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
+        
+        
+    def init(self):
+        self.H = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+                  0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]
+        
+
+    def next(self, block):
+        self._W_schedule(block)
+        self._copy_digest()
+        if self.verbose:
+            print("State after init:")
+            self._print_state(0)
+
+        for i in range(64):
+            self._sha256_round(i)
+            if self.verbose:
+                self._print_state(i)
+
+        self._update_digest()
+
+
+    def get_digest(self):
+        return self.H
+
+
+    def _copy_digest(self):
+        self.a = self.H[0] 
+        self.b = self.H[1] 
+        self.c = self.H[2] 
+        self.d = self.H[3] 
+        self.e = self.H[4] 
+        self.f = self.H[5] 
+        self.g = self.H[6] 
+        self.h = self.H[7]
+    
+    
+    def _update_digest(self):
+        self.H[0] = (self.H[0] + self.a) & 0xffffffff 
+        self.H[1] = (self.H[1] + self.b) & 0xffffffff 
+        self.H[2] = (self.H[2] + self.c) & 0xffffffff 
+        self.H[3] = (self.H[3] + self.d) & 0xffffffff 
+        self.H[4] = (self.H[4] + self.e) & 0xffffffff 
+        self.H[5] = (self.H[5] + self.f) & 0xffffffff 
+        self.H[6] = (self.H[6] + self.g) & 0xffffffff 
+        self.H[7] = (self.H[7] + self.h) & 0xffffffff 
+
+
+    def _print_state(self, round):
+        print("State at round 0x%02x:" % round)
+        print("t1 = 0x%08x, t2 = 0x%08x" % (self.t1, self.t2))
+        print("k  = 0x%08x, w  = 0x%08x" % (self.k, self.w))
+        print("a  = 0x%08x, b  = 0x%08x" % (self.a, self.b))
+        print("c  = 0x%08x, d  = 0x%08x" % (self.c, self.d))
+        print("e  = 0x%08x, f  = 0x%08x" % (self.e, self.f))
+        print("g  = 0x%08x, h  = 0x%08x" % (self.g, self.h))
+        print("")
+
+
+    def _sha256_round(self, round):
+        self.k = self.K[round]
+        self.w = self._next_w(round)
+        self.t1 = self._T1(self.e, self.f, self.g, self.h, self.k, self.w)
+        self.t2 = self._T2(self.a, self.b, self.c)
+        self.h = self.g
+        self.g = self.f
+        self.f = self.e
+        self.e = (self.d + self.t1) & 0xffffffff
+        self.d = self.c
+        self.c = self.b
+        self.b = self.a
+        self.a = (self.t1 + self.t2) & 0xffffffff
+
+
+    def _next_w(self, round):
+        if (round < 16):
+            return self.W[round]
+
+        else:
+            tmp_w = (self._delta1(self.W[14]) +
+                     self.W[9] + 
+                     self._delta0(self.W[1]) +
+                     self.W[0]) & 0xffffffff
+            for i in range(15):
+                self.W[i] = self.W[(i+1)]
+            self.W[15] = tmp_w
+            return tmp_w
+
+
+    def _W_schedule(self, block):
+        for i in range(16):
+            self.W[i] = block[i]
+
+
+    def _Ch(self, x, y, z):
+        return (x & y) ^ (~x & z)
+
+
+    def _Maj(self, x, y, z):
+        return (x & y) ^ (x & z) ^ (y & z)
+
+    def _sigma0(self, x):
+        return (self._rotr32(x, 2) ^ self._rotr32(x, 13) ^ self._rotr32(x, 22))
+
+
+    def _sigma1(self, x):
+        return (self._rotr32(x, 6) ^ self._rotr32(x, 11) ^ self._rotr32(x, 25))
+
+
+    def _delta0(self, x):
+        return (self._rotr32(x, 7) ^ self._rotr32(x, 18) ^ self._shr32(x, 3))
+
+
+    def _delta1(self, x):
+        return (self._rotr32(x, 17) ^ self._rotr32(x, 19) ^ self._shr32(x, 10))
+    
+
+    def _T1(self, e, f, g, h, k, w):
+        return (h + self._sigma1(e) + self._Ch(e, f, g) + k + w) & 0xffffffff
+
+
+    def _T2(self, a, b, c):
+        return (self._sigma0(a) + self._Maj(a, b, c)) & 0xffffffff
+
+
+    def _rotr32(self, n, r):
+        return ((n >> r) | (n << (32 - r))) & 0xffffffff
+
+    
+    def _shr32(self, n, r):
+        return (n >> r)
+
+
+#-------------------------------------------------------------------
+# print_digest()
+#
+# Print the given digest.
+#-------------------------------------------------------------------
+def print_digest(digest):
+    print("0x%08x, 0x%08x, 0x%08x, 0x%08x" %\
+          (digest[0], digest[1], digest[2], digest[3]))
+    print("0x%08x, 0x%08x, 0x%08x, 0x%08x" %\
+          (digest[4], digest[5], digest[6], digest[7]))
+    print("")
+
+
+#-------------------------------------------------------------------
+# compare_digests()
+#
+# Check that the given digest matches the expected digest.
+#-------------------------------------------------------------------
+def compare_digests(digest, expected):
+    if (digest != expected):
+        print("Error:")
+        print("Got:")
+        print_digest(digest)
+        print("Expected:")
+        print_digest(expected)
+    else:
+        print("Test case ok.")
+        
+    
+#-------------------------------------------------------------------
+# main()
+#
+# If executed tests the ChaCha class using known test vectors.
+#-------------------------------------------------------------------
+def main():
+    print("Testing the SHA-256 Python model.")
+    print("---------------------------------")
+    print
+
+    my_sha256 = SHA256(verbose=0);
+
+    # TC1: NIST testcase with message "abc"
+    print("TC1: Single block message test specified by NIST.")
+    TC1_block = [0x61626380, 0x00000000, 0x00000000, 0x00000000, 
+                 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                 0x00000000, 0x00000000, 0x00000000, 0x00000018]
+    
+    TC1_expected = [0xBA7816BF, 0x8F01CFEA, 0x414140DE, 0x5DAE2223,
+                    0xB00361A3, 0x96177A9C, 0xB410FF61, 0xF20015AD]
+    
+    my_sha256.init()
+    my_sha256.next(TC1_block)
+    my_digest = my_sha256.get_digest()
+    compare_digests(my_digest, TC1_expected)
+    print("")
+
+
+    # TC2: NIST testcase with double block message."
+    print("TC2: Double block message test specified by NIST.")
+    TC2_1_block = [0x61626364, 0x62636465, 0x63646566, 0x64656667,
+                   0x65666768, 0x66676869, 0x6768696A, 0x68696A6B,
+                   0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F,
+                   0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000]
+
+
+    TC2_2_block = [0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                   0x00000000, 0x00000000, 0x00000000, 0x000001C0]
+
+    TC2_1_expected = [0x85E655D6, 0x417A1795, 0x3363376A, 0x624CDE5C,
+                      0x76E09589, 0xCAC5F811, 0xCC4B32C1, 0xF20E533A]
+
+    TC2_2_expected = [0x248D6A61, 0xD20638B8, 0xE5C02693, 0x0C3E6039,
+                      0xA33CE459, 0x64FF2167, 0xF6ECEDD4, 0x19DB06C1]
+
+    my_sha256.init()
+    my_sha256.next(TC2_1_block)
+    my_digest = my_sha256.get_digest()
+    compare_digests(my_digest, TC2_1_expected)
+
+    my_sha256.next(TC2_2_block)
+    my_digest = my_sha256.get_digest()
+    compare_digests(my_digest, TC2_2_expected)
+    print("")
+
+
+    # TC3: Huge message with n blocks
+    n = 1000
+    print("TC3: Huge message with %d blocks test case." % n)
+    TC3_block = [0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+                 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f]
+
+    TC3_expected = [0x7638f3bc, 0x500dd1a6, 0x586dd4d0, 0x1a1551af,
+                    0xd821d235, 0x2f919e28, 0xd5842fab, 0x03a40f2a]
+
+    my_sha256.init()
+    for i in range(n):
+        my_sha256.next(TC3_block)
+        my_digest = my_sha256.get_digest()
+        if (VERBOSE):
+            print("Digest for block %d:" % i)
+            print_digest(my_digest)
+    compare_digests(my_digest, TC3_expected)
+    
+
+#-------------------------------------------------------------------
+# __name__
+# Python thingy which allows the file to be run standalone as
+# well as parsed from within a Python interpreter.
+#-------------------------------------------------------------------
+if __name__=="__main__": 
+    # Run the main function.
+    sys.exit(main())
+
+#=======================================================================
+# EOF sha256.py
+#=======================================================================
diff --git a/sha256/src/rtl/sha256.v b/sha256/src/rtl/sha256.v
new file mode 100644
index 0000000..04048b1
--- /dev/null
+++ b/sha256/src/rtl/sha256.v
@@ -0,0 +1,204 @@
+//======================================================================
+//
+// sha256.v
+// ------
+// Top level wrapper for the SHA-256 hash function providing
+// a simple memory like interface with 32 bit data access.
+//
+// Authors: Joachim Strömbergson, Paul Selkirk
+// Copyright (c) 2014-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 sha256(
+            // 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
+            );
+
+   //----------------------------------------------------------------
+   // 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 ADDR_STATUS      = 8'h09;
+   parameter STATUS_READY_BIT = 0;
+   parameter STATUS_VALID_BIT = 1;
+
+   parameter ADDR_BLOCK       = 8'h10;
+
+   parameter ADDR_DIGEST      = 8'h20;
+
+   parameter CORE_NAME0       = 32'h73686132; // "sha2"
+   parameter CORE_NAME1       = 32'h2d323536; // "-256"
+   parameter CORE_VERSION     = 32'h302e3830; // "0.80"
+
+   parameter BLOCK_BITS       = 512;
+   parameter DIGEST_BITS      = 256;
+   parameter BLOCK_WORDS      = BLOCK_BITS / 32;
+   parameter DIGEST_WORDS     = DIGEST_BITS / 32;
+
+   //----------------------------------------------------------------
+   // Registers.
+   //----------------------------------------------------------------
+   reg [0 : BLOCK_BITS - 1]    block_reg;
+   reg [0 : DIGEST_BITS - 1]   digest_reg;
+   reg                         init_reg;
+   reg                         next_reg;
+
+   reg [31 : 0]                tmp_read_data;
+   reg [31 : 0]                tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                        core_init;
+   wire                        core_next;
+   wire                        core_ready;
+   wire [0 : BLOCK_BITS - 1]   core_block;
+   wire [0 : DIGEST_BITS - 1]  core_digest;
+   wire                        core_digest_valid;
+
+   wire [31 : 0]               core_name0   = CORE_NAME0;
+   wire [31 : 0]               core_name1   = CORE_NAME1;
+   wire [31 : 0]               core_version = CORE_VERSION;
+   wire [31 : 0]               core_ctrl;
+   wire [31 : 0]               core_status;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init   = init_reg;
+   assign core_next   = next_reg;
+   assign core_ctrl   = { 30'b0, next_reg, init_reg };
+   assign core_status = { 30'b0, core_digest_valid, core_ready };
+   assign core_block  = block_reg;
+
+   assign read_data   = tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // core instantiation.
+   //----------------------------------------------------------------
+   sha256_core core(
+                  .clk(clk),
+                  .reset_n(reset_n),
+
+                  .init(core_init),
+                  .next(core_next),
+
+                  .block(core_block),
+
+                  .ready(core_ready),
+
+                  .digest(core_digest),
+                  .digest_valid(core_digest_valid)
+                  );
+
+
+   //----------------------------------------------------------------
+   // latch in digest when ready
+   //----------------------------------------------------------------
+   always @(posedge clk)
+      begin
+         if (core_digest_valid)
+           digest_reg <= core_digest;
+      end
+
+   //----------------------------------------------------------------
+   // storage registers for mapping memory to core interface
+   //----------------------------------------------------------------
+   always @(posedge clk)
+     begin
+        init_reg <= 0;
+        next_reg <= 0;
+
+        if (cs && we)
+          begin
+             // write operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               block_reg[((address - ADDR_BLOCK) * 32)+:32] <= write_data;
+             else if (address == ADDR_CTRL)
+               begin
+                  init_reg <= write_data[CTRL_INIT_BIT];
+                  next_reg <= write_data[CTRL_NEXT_BIT];
+               end
+          end
+     end
+
+   always @*
+     begin
+        tmp_read_data = 32'h00000000;
+
+        if (cs && !we)
+          begin
+             // read operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               tmp_read_data = block_reg[((address - ADDR_BLOCK) * 32)+:32];
+             else if ((address >= ADDR_DIGEST) &&
+                      (address < ADDR_DIGEST + DIGEST_WORDS))
+               tmp_read_data = digest_reg[((address - ADDR_DIGEST) * 32)+:32];
+             else
+               case (address)
+                 ADDR_NAME0:
+                   tmp_read_data = core_name0;
+                 ADDR_NAME1:
+                   tmp_read_data = core_name1;
+                 ADDR_VERSION:
+                   tmp_read_data = core_version;
+                 ADDR_CTRL:
+                   tmp_read_data = core_ctrl;
+                 ADDR_STATUS:
+                   tmp_read_data = core_status;
+               endcase
+          end
+     end
+
+   always @(posedge clk)
+     begin
+        tmp_read_data_reg <= tmp_read_data;
+     end
+
+endmodule // sha256
diff --git a/sha256/src/rtl/sha256_core.v b/sha256/src/rtl/sha256_core.v
new file mode 100644
index 0000000..a88a359
--- /dev/null
+++ b/sha256/src/rtl/sha256_core.v
@@ -0,0 +1,519 @@
+//======================================================================
+//
+// sha256_core.v
+// -------------
+// Verilog 2001 implementation of the SHA-256 hash function.
+// This is the internal core with wide interfaces.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha256_core(
+                   input wire            clk,
+                   input wire            reset_n,
+
+                   input wire            init,
+                   input wire            next,
+
+                   input wire [511 : 0]  block,
+
+                   output wire           ready,
+
+                   output wire [255 : 0] digest,
+                   output wire           digest_valid
+                  );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter H0_0 = 32'h6a09e667;
+  parameter H0_1 = 32'hbb67ae85;
+  parameter H0_2 = 32'h3c6ef372;
+  parameter H0_3 = 32'ha54ff53a;
+  parameter H0_4 = 32'h510e527f;
+  parameter H0_5 = 32'h9b05688c;
+  parameter H0_6 = 32'h1f83d9ab;
+  parameter H0_7 = 32'h5be0cd19;
+
+  parameter SHA256_ROUNDS = 63;
+
+  parameter CTRL_IDLE   = 0;
+  parameter CTRL_ROUNDS = 1;
+  parameter CTRL_DONE   = 2;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [31 : 0] a_reg;
+  reg [31 : 0] a_new;
+  reg [31 : 0] b_reg;
+  reg [31 : 0] b_new;
+  reg [31 : 0] c_reg;
+  reg [31 : 0] c_new;
+  reg [31 : 0] d_reg;
+  reg [31 : 0] d_new;
+  reg [31 : 0] e_reg;
+  reg [31 : 0] e_new;
+  reg [31 : 0] f_reg;
+  reg [31 : 0] f_new;
+  reg [31 : 0] g_reg;
+  reg [31 : 0] g_new;
+  reg [31 : 0] h_reg;
+  reg [31 : 0] h_new;
+  reg          a_h_we;
+
+  reg [31 : 0] H0_reg;
+  reg [31 : 0] H0_new;
+  reg [31 : 0] H1_reg;
+  reg [31 : 0] H1_new;
+  reg [31 : 0] H2_reg;
+  reg [31 : 0] H2_new;
+  reg [31 : 0] H3_reg;
+  reg [31 : 0] H3_new;
+  reg [31 : 0] H4_reg;
+  reg [31 : 0] H4_new;
+  reg [31 : 0] H5_reg;
+  reg [31 : 0] H5_new;
+  reg [31 : 0] H6_reg;
+  reg [31 : 0] H6_new;
+  reg [31 : 0] H7_reg;
+  reg [31 : 0] H7_new;
+  reg          H_we;
+
+  reg [5 : 0] t_ctr_reg;
+  reg [5 : 0] t_ctr_new;
+  reg         t_ctr_we;
+  reg         t_ctr_inc;
+  reg         t_ctr_rst;
+
+  reg digest_valid_reg;
+  reg digest_valid_new;
+  reg digest_valid_we;
+
+  reg [1 : 0] sha256_ctrl_reg;
+  reg [1 : 0] sha256_ctrl_new;
+  reg         sha256_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg digest_init;
+  reg digest_update;
+
+  reg state_init;
+  reg state_update;
+
+  reg first_block;
+
+  reg ready_flag;
+
+  reg [31 : 0] t1;
+  reg [31 : 0] t2;
+
+  wire [31 : 0] k_data;
+
+  reg           w_init;
+  reg           w_next;
+  wire [31 : 0] w_data;
+
+
+  //----------------------------------------------------------------
+  // Module instantiantions.
+  //----------------------------------------------------------------
+  sha256_k_constants k_constants_inst(
+                                      .addr(t_ctr_reg),
+                                      .K(k_data)
+                                     );
+
+
+  sha256_w_mem w_mem_inst(
+                          .clk(clk),
+                          .reset_n(reset_n),
+
+                          .block(block),
+
+                          .init(w_init),
+                          .next(w_next),
+                          .w(w_data)
+                         );
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign ready = ready_flag;
+
+  assign digest = {H0_reg, H1_reg, H2_reg, H3_reg,
+                   H4_reg, H5_reg, H6_reg, H7_reg};
+
+  assign digest_valid = digest_valid_reg;
+
+
+  //----------------------------------------------------------------
+  // 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 : reg_update
+      if (!reset_n)
+        begin
+          a_reg            <= 32'h00000000;
+          b_reg            <= 32'h00000000;
+          c_reg            <= 32'h00000000;
+          d_reg            <= 32'h00000000;
+          e_reg            <= 32'h00000000;
+          f_reg            <= 32'h00000000;
+          g_reg            <= 32'h00000000;
+          h_reg            <= 32'h00000000;
+          H0_reg           <= 32'h00000000;
+          H1_reg           <= 32'h00000000;
+          H2_reg           <= 32'h00000000;
+          H3_reg           <= 32'h00000000;
+          H4_reg           <= 32'h00000000;
+          H5_reg           <= 32'h00000000;
+          H6_reg           <= 32'h00000000;
+          H7_reg           <= 32'h00000000;
+          digest_valid_reg <= 0;
+          t_ctr_reg        <= 6'b000000;
+          sha256_ctrl_reg  <= CTRL_IDLE;
+        end
+      else
+        begin
+
+          if (a_h_we)
+            begin
+              a_reg <= a_new;
+              b_reg <= b_new;
+              c_reg <= c_new;
+              d_reg <= d_new;
+              e_reg <= e_new;
+              f_reg <= f_new;
+              g_reg <= g_new;
+              h_reg <= h_new;
+            end
+
+          if (H_we)
+            begin
+              H0_reg <= H0_new;
+              H1_reg <= H1_new;
+              H2_reg <= H2_new;
+              H3_reg <= H3_new;
+              H4_reg <= H4_new;
+              H5_reg <= H5_new;
+              H6_reg <= H6_new;
+              H7_reg <= H7_new;
+            end
+
+          if (t_ctr_we)
+            begin
+              t_ctr_reg <= t_ctr_new;
+            end
+
+          if (digest_valid_we)
+            begin
+              digest_valid_reg <= digest_valid_new;
+            end
+
+          if (sha256_ctrl_we)
+            begin
+              sha256_ctrl_reg <= sha256_ctrl_new;
+            end
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // digest_logic
+  //
+  // The logic needed to init as well as update the digest.
+  //----------------------------------------------------------------
+  always @*
+    begin : digest_logic
+      H0_new = 32'h00000000;
+      H1_new = 32'h00000000;
+      H2_new = 32'h00000000;
+      H3_new = 32'h00000000;
+      H4_new = 32'h00000000;
+      H5_new = 32'h00000000;
+      H6_new = 32'h00000000;
+      H7_new = 32'h00000000;
+      H_we = 0;
+
+      if (digest_init)
+        begin
+          H0_new = H0_0;
+          H1_new = H0_1;
+          H2_new = H0_2;
+          H3_new = H0_3;
+          H4_new = H0_4;
+          H5_new = H0_5;
+          H6_new = H0_6;
+          H7_new = H0_7;
+          H_we = 1;
+        end
+
+      if (digest_update)
+        begin
+          H0_new = H0_reg + a_reg;
+          H1_new = H1_reg + b_reg;
+          H2_new = H2_reg + c_reg;
+          H3_new = H3_reg + d_reg;
+          H4_new = H4_reg + e_reg;
+          H5_new = H5_reg + f_reg;
+          H6_new = H6_reg + g_reg;
+          H7_new = H7_reg + h_reg;
+          H_we = 1;
+        end
+    end // digest_logic
+
+
+  //----------------------------------------------------------------
+  // t1_logic
+  //
+  // The logic for the T1 function.
+  //----------------------------------------------------------------
+  always @*
+    begin : t1_logic
+      reg [31 : 0] sum1;
+      reg [31 : 0] ch;
+
+      sum1 = {e_reg[5  : 0], e_reg[31 :  6]} ^
+             {e_reg[10 : 0], e_reg[31 : 11]} ^
+             {e_reg[24 : 0], e_reg[31 : 25]};
+
+      ch = (e_reg & f_reg) ^ ((~e_reg) & g_reg);
+
+      t1 = h_reg + sum1 + ch + w_data + k_data;
+    end // t1_logic
+
+
+  //----------------------------------------------------------------
+  // t2_logic
+  //
+  // The logic for the T2 function
+  //----------------------------------------------------------------
+  always @*
+    begin : t2_logic
+      reg [31 : 0] sum0;
+      reg [31 : 0] maj;
+
+      sum0 = {a_reg[1  : 0], a_reg[31 :  2]} ^
+             {a_reg[12 : 0], a_reg[31 : 13]} ^
+             {a_reg[21 : 0], a_reg[31 : 22]};
+
+      maj = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
+
+      t2 = sum0 + maj;
+    end // t2_logic
+
+
+  //----------------------------------------------------------------
+  // state_logic
+  //
+  // The logic needed to init as well as update the state during
+  // round processing.
+  //----------------------------------------------------------------
+  always @*
+    begin : state_logic
+      a_new  = 32'h00000000;
+      b_new  = 32'h00000000;
+      c_new  = 32'h00000000;
+      d_new  = 32'h00000000;
+      e_new  = 32'h00000000;
+      f_new  = 32'h00000000;
+      g_new  = 32'h00000000;
+      h_new  = 32'h00000000;
+      a_h_we = 0;
+
+      if (state_init)
+        begin
+          if (first_block)
+            begin
+              a_new  = H0_0;
+              b_new  = H0_1;
+              c_new  = H0_2;
+              d_new  = H0_3;
+              e_new  = H0_4;
+              f_new  = H0_5;
+              g_new  = H0_6;
+              h_new  = H0_7;
+              a_h_we = 1;
+            end
+          else
+            begin
+              a_new  = H0_reg;
+              b_new  = H1_reg;
+              c_new  = H2_reg;
+              d_new  = H3_reg;
+              e_new  = H4_reg;
+              f_new  = H5_reg;
+              g_new  = H6_reg;
+              h_new  = H7_reg;
+              a_h_we = 1;
+            end
+        end
+
+      if (state_update)
+        begin
+          a_new  = t1 + t2;
+          b_new  = a_reg;
+          c_new  = b_reg;
+          d_new  = c_reg;
+          e_new  = d_reg + t1;
+          f_new  = e_reg;
+          g_new  = f_reg;
+          h_new  = g_reg;
+          a_h_we = 1;
+        end
+    end // state_logic
+
+
+  //----------------------------------------------------------------
+  // t_ctr
+  //
+  // Update logic for the round counter, a monotonically
+  // increasing counter with reset.
+  //----------------------------------------------------------------
+  always @*
+    begin : t_ctr
+      t_ctr_new = 0;
+      t_ctr_we  = 0;
+
+      if (t_ctr_rst)
+        begin
+          t_ctr_new = 0;
+          t_ctr_we  = 1;
+        end
+
+      if (t_ctr_inc)
+        begin
+          t_ctr_new = t_ctr_reg + 1'b1;
+          t_ctr_we  = 1;
+        end
+    end // t_ctr
+
+
+  //----------------------------------------------------------------
+  // sha256_ctrl_fsm
+  //
+  // Logic for the state machine controlling the core behaviour.
+  //----------------------------------------------------------------
+  always @*
+    begin : sha256_ctrl_fsm
+      digest_init      = 0;
+      digest_update    = 0;
+
+      state_init       = 0;
+      state_update     = 0;
+
+      first_block      = 0;
+      ready_flag       = 0;
+
+      w_init           = 0;
+      w_next           = 0;
+
+      t_ctr_inc        = 0;
+      t_ctr_rst        = 0;
+
+      digest_valid_new = 0;
+      digest_valid_we  = 0;
+
+      sha256_ctrl_new  = CTRL_IDLE;
+      sha256_ctrl_we   = 0;
+
+
+      case (sha256_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            ready_flag = 1;
+
+            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;
+                sha256_ctrl_new  = CTRL_ROUNDS;
+                sha256_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;
+                sha256_ctrl_new  = CTRL_ROUNDS;
+                sha256_ctrl_we   = 1;
+              end
+          end
+
+
+        CTRL_ROUNDS:
+          begin
+            w_next       = 1;
+            state_update = 1;
+            t_ctr_inc    = 1;
+
+            if (t_ctr_reg == SHA256_ROUNDS)
+              begin
+                sha256_ctrl_new = CTRL_DONE;
+                sha256_ctrl_we  = 1;
+              end
+          end
+
+
+        CTRL_DONE:
+          begin
+            digest_update    = 1;
+            digest_valid_new = 1;
+            digest_valid_we  = 1;
+
+            sha256_ctrl_new  = CTRL_IDLE;
+            sha256_ctrl_we   = 1;
+          end
+      endcase // case (sha256_ctrl_reg)
+    end // sha256_ctrl_fsm
+
+endmodule // sha256_core
+
+//======================================================================
+// EOF sha256_core.v
+//======================================================================
diff --git a/sha256/src/rtl/sha256_k_constants.v b/sha256/src/rtl/sha256_k_constants.v
new file mode 100644
index 0000000..2acd3a6
--- /dev/null
+++ b/sha256/src/rtl/sha256_k_constants.v
@@ -0,0 +1,387 @@
+//======================================================================
+//
+// sha256_k_constants.v
+// --------------------
+// The table K with constants in the SHA-256 hash function.
+// A simple combinational ROM basically.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha256_k_constants(
+                          input wire  [5 : 0] addr,
+                          output wire [31 : 0] K
+                         );
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [31 : 0] tmp_K;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign K = tmp_K;
+  
+  
+  //----------------------------------------------------------------
+  // addr_mux
+  //----------------------------------------------------------------
+  always @*
+    begin : addr_mux
+      case(addr)
+        0:
+          begin
+            tmp_K = 32'h428a2f98;
+          end
+
+        1:
+          begin
+            tmp_K = 32'h71374491;
+          end
+
+        2:
+          begin
+            tmp_K = 32'hb5c0fbcf;
+          end
+        
+        3:
+          begin
+            tmp_K = 32'he9b5dba5;
+          end
+        
+        4:
+          begin
+            tmp_K = 32'h3956c25b;
+          end
+        
+        5:
+          begin
+            tmp_K = 32'h59f111f1;
+          end
+        
+        6:
+          begin
+            tmp_K = 32'h923f82a4;
+          end
+        
+        7:
+          begin
+            tmp_K = 32'hab1c5ed5;
+          end
+        
+        8:
+          begin
+            tmp_K = 32'hd807aa98;
+          end
+        
+        9:
+          begin
+            tmp_K = 32'h12835b01;
+          end
+        
+        10:
+          begin
+            tmp_K = 32'h243185be;
+          end
+        
+        11:
+          begin
+            tmp_K = 32'h550c7dc3;
+          end
+        
+        12:
+          begin
+            tmp_K = 32'h72be5d74;
+          end
+        
+        13:
+          begin
+            tmp_K = 32'h80deb1fe;
+          end
+        
+        14:
+          begin
+            tmp_K = 32'h9bdc06a7;
+          end
+        
+        15:
+          begin
+            tmp_K = 32'hc19bf174;
+          end
+        
+        16:
+          begin
+            tmp_K = 32'he49b69c1;
+          end
+        
+        17:
+          begin
+            tmp_K = 32'hefbe4786;
+          end
+        
+        18:
+          begin
+            tmp_K = 32'h0fc19dc6;
+          end
+        
+        19:
+          begin
+            tmp_K = 32'h240ca1cc;
+          end
+        
+        20:
+          begin
+            tmp_K = 32'h2de92c6f;
+          end
+        
+        21:
+          begin
+            tmp_K = 32'h4a7484aa;
+          end
+        
+        22:
+          begin
+            tmp_K = 32'h5cb0a9dc;
+          end
+        
+        23:
+          begin
+            tmp_K = 32'h76f988da;
+          end
+        
+        24:
+          begin
+            tmp_K = 32'h983e5152;
+          end
+        
+        25:
+          begin
+            tmp_K = 32'ha831c66d;
+          end
+        
+        26:
+          begin
+            tmp_K = 32'hb00327c8;
+          end
+        
+        27:
+          begin
+            tmp_K = 32'hbf597fc7;
+          end
+        
+        28:
+          begin
+            tmp_K = 32'hc6e00bf3;
+          end
+        
+        29:
+          begin
+            tmp_K = 32'hd5a79147;
+          end
+        
+        30:
+          begin
+            tmp_K = 32'h06ca6351;
+          end
+        
+        31:
+          begin
+            tmp_K = 32'h14292967;
+          end
+        
+        32:
+          begin
+            tmp_K = 32'h27b70a85;
+          end
+        
+        33:
+          begin
+            tmp_K = 32'h2e1b2138;
+          end
+        
+        34:
+          begin
+            tmp_K = 32'h4d2c6dfc;
+          end
+        
+        35:
+          begin
+            tmp_K = 32'h53380d13;
+          end
+        
+        36:
+          begin
+            tmp_K = 32'h650a7354;
+          end
+        
+        37:
+          begin
+            tmp_K = 32'h766a0abb;
+          end
+        
+        38:
+          begin
+            tmp_K = 32'h81c2c92e;
+          end
+        
+        39:
+          begin
+            tmp_K = 32'h92722c85;
+          end
+        
+        40:
+          begin
+            tmp_K = 32'ha2bfe8a1;
+          end
+        
+        41:
+          begin
+            tmp_K = 32'ha81a664b;
+          end
+        
+        42:
+          begin
+            tmp_K = 32'hc24b8b70;
+          end
+        
+        43:
+          begin
+            tmp_K = 32'hc76c51a3;
+          end
+        
+        44:
+          begin
+            tmp_K = 32'hd192e819;
+          end
+        
+        45:
+          begin
+            tmp_K = 32'hd6990624;
+          end
+        
+        46:
+          begin
+            tmp_K = 32'hf40e3585;
+          end
+        
+        47:
+          begin
+            tmp_K = 32'h106aa070;
+          end
+        
+        48:
+          begin
+            tmp_K = 32'h19a4c116;
+          end
+        
+        49:
+          begin
+            tmp_K = 32'h1e376c08;
+          end
+        
+        50:
+          begin
+            tmp_K = 32'h2748774c;
+          end
+        
+        51:
+          begin
+            tmp_K = 32'h34b0bcb5;
+          end
+        
+        52:
+          begin
+            tmp_K = 32'h391c0cb3;
+          end
+        
+        53:
+          begin
+            tmp_K = 32'h4ed8aa4a;
+          end
+        
+        54:
+          begin
+            tmp_K = 32'h5b9cca4f;
+          end
+        
+        55:
+          begin
+            tmp_K = 32'h682e6ff3;
+          end
+        
+        56:
+          begin
+            tmp_K = 32'h748f82ee;
+          end
+        
+        57:
+          begin
+            tmp_K = 32'h78a5636f;
+          end
+        
+        58:
+          begin
+            tmp_K = 32'h84c87814;
+          end
+        
+        59:
+          begin
+            tmp_K = 32'h8cc70208;
+          end
+        
+        60:
+          begin
+            tmp_K = 32'h90befffa;
+          end
+        
+        61:
+          begin
+            tmp_K = 32'ha4506ceb;
+          end
+        
+        62:
+          begin
+            tmp_K = 32'hbef9a3f7;
+          end
+        
+        63:
+          begin
+            tmp_K = 32'hc67178f2;
+          end
+      endcase // case (addr)
+    end // block: addr_mux
+endmodule // sha256_k_constants
+
+//======================================================================
+// EOF sha256_k_constants.v
+//======================================================================
diff --git a/sha256/src/rtl/sha256_w_mem.v b/sha256/src/rtl/sha256_w_mem.v
new file mode 100644
index 0000000..f58c428
--- /dev/null
+++ b/sha256/src/rtl/sha256_w_mem.v
@@ -0,0 +1,345 @@
+//======================================================================
+//
+// sha256_w_mem_regs.v
+// -------------------
+// The W memory. This version uses 16 32-bit registers as a sliding
+// window to generate the 64 words.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha256_w_mem(
+                    input wire           clk,
+                    input wire           reset_n,
+
+                    input wire [511 : 0] block,
+
+                    input wire           init,
+                    input wire           next,
+                    output wire [31 : 0] w
+                   );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter CTRL_IDLE   = 0;
+  parameter CTRL_UPDATE = 1;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [31 : 0] w_mem [0 : 15];
+  reg [31 : 0] w_mem00_new;
+  reg [31 : 0] w_mem01_new;
+  reg [31 : 0] w_mem02_new;
+  reg [31 : 0] w_mem03_new;
+  reg [31 : 0] w_mem04_new;
+  reg [31 : 0] w_mem05_new;
+  reg [31 : 0] w_mem06_new;
+  reg [31 : 0] w_mem07_new;
+  reg [31 : 0] w_mem08_new;
+  reg [31 : 0] w_mem09_new;
+  reg [31 : 0] w_mem10_new;
+  reg [31 : 0] w_mem11_new;
+  reg [31 : 0] w_mem12_new;
+  reg [31 : 0] w_mem13_new;
+  reg [31 : 0] w_mem14_new;
+  reg [31 : 0] w_mem15_new;
+  reg          w_mem_we;
+
+  reg [5 : 0] w_ctr_reg;
+  reg [5 : 0] w_ctr_new;
+  reg         w_ctr_we;
+  reg         w_ctr_inc;
+  reg         w_ctr_rst;
+
+  reg [1 : 0]  sha256_w_mem_ctrl_reg;
+  reg [1 : 0]  sha256_w_mem_ctrl_new;
+  reg          sha256_w_mem_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [31 : 0] w_tmp;
+  reg [31 : 0] w_new;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign w = w_tmp;
+
+
+  //----------------------------------------------------------------
+  // 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 : reg_update
+      if (!reset_n)
+        begin
+          w_mem[00]             <= 32'h00000000;
+          w_mem[01]             <= 32'h00000000;
+          w_mem[02]             <= 32'h00000000;
+          w_mem[03]             <= 32'h00000000;
+          w_mem[04]             <= 32'h00000000;
+          w_mem[05]             <= 32'h00000000;
+          w_mem[06]             <= 32'h00000000;
+          w_mem[07]             <= 32'h00000000;
+          w_mem[08]             <= 32'h00000000;
+          w_mem[09]             <= 32'h00000000;
+          w_mem[10]             <= 32'h00000000;
+          w_mem[11]             <= 32'h00000000;
+          w_mem[12]             <= 32'h00000000;
+          w_mem[13]             <= 32'h00000000;
+          w_mem[14]             <= 32'h00000000;
+          w_mem[15]             <= 32'h00000000;
+          w_ctr_reg             <= 6'h00;
+          sha256_w_mem_ctrl_reg <= CTRL_IDLE;
+        end
+      else
+        begin
+          if (w_mem_we)
+            begin
+              w_mem[00] <= w_mem00_new;
+              w_mem[01] <= w_mem01_new;
+              w_mem[02] <= w_mem02_new;
+              w_mem[03] <= w_mem03_new;
+              w_mem[04] <= w_mem04_new;
+              w_mem[05] <= w_mem05_new;
+              w_mem[06] <= w_mem06_new;
+              w_mem[07] <= w_mem07_new;
+              w_mem[08] <= w_mem08_new;
+              w_mem[09] <= w_mem09_new;
+              w_mem[10] <= w_mem10_new;
+              w_mem[11] <= w_mem11_new;
+              w_mem[12] <= w_mem12_new;
+              w_mem[13] <= w_mem13_new;
+              w_mem[14] <= w_mem14_new;
+              w_mem[15] <= w_mem15_new;
+            end
+
+          if (w_ctr_we)
+            begin
+              w_ctr_reg <= w_ctr_new;
+            end
+
+          if (sha256_w_mem_ctrl_we)
+            begin
+              sha256_w_mem_ctrl_reg <= sha256_w_mem_ctrl_new;
+            end
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // select_w
+  //
+  // Mux for the external read operation. This is where we exract
+  // the W variable.
+  //----------------------------------------------------------------
+  always @*
+    begin : select_w
+      if (w_ctr_reg < 16)
+        begin
+          w_tmp = w_mem[w_ctr_reg[3 : 0]];
+        end
+      else
+        begin
+          w_tmp = w_new;
+        end
+    end // select_w
+
+
+  //----------------------------------------------------------------
+  // w_new_logic
+  //
+  // Logic that calculates the next value to be inserted into
+  // the sliding window of the memory.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_mem_update_logic
+      reg [31 : 0] w_0;
+      reg [31 : 0] w_1;
+      reg [31 : 0] w_9;
+      reg [31 : 0] w_14;
+      reg [31 : 0] d0;
+      reg [31 : 0] d1;
+
+      w_mem00_new = 32'h00000000;
+      w_mem01_new = 32'h00000000;
+      w_mem02_new = 32'h00000000;
+      w_mem03_new = 32'h00000000;
+      w_mem04_new = 32'h00000000;
+      w_mem05_new = 32'h00000000;
+      w_mem06_new = 32'h00000000;
+      w_mem07_new = 32'h00000000;
+      w_mem08_new = 32'h00000000;
+      w_mem09_new = 32'h00000000;
+      w_mem10_new = 32'h00000000;
+      w_mem11_new = 32'h00000000;
+      w_mem12_new = 32'h00000000;
+      w_mem13_new = 32'h00000000;
+      w_mem14_new = 32'h00000000;
+      w_mem15_new = 32'h00000000;
+      w_mem_we    = 0;
+
+      w_0  = w_mem[0];
+      w_1  = w_mem[1];
+      w_9  = w_mem[9];
+      w_14 = w_mem[14];
+
+      d0 = {w_1[6  : 0], w_1[31 :  7]} ^
+           {w_1[17 : 0], w_1[31 : 18]} ^
+           {3'b000, w_1[31 : 3]};
+
+      d1 = {w_14[16 : 0], w_14[31 : 17]} ^
+           {w_14[18 : 0], w_14[31 : 19]} ^
+           {10'b0000000000, w_14[31 : 10]};
+
+      w_new = d1 + w_9 + d0 + w_0;
+
+      if (init)
+        begin
+          w_mem00_new = block[511 : 480];
+          w_mem01_new = block[479 : 448];
+          w_mem02_new = block[447 : 416];
+          w_mem03_new = block[415 : 384];
+          w_mem04_new = block[383 : 352];
+          w_mem05_new = block[351 : 320];
+          w_mem06_new = block[319 : 288];
+          w_mem07_new = block[287 : 256];
+          w_mem08_new = block[255 : 224];
+          w_mem09_new = block[223 : 192];
+          w_mem10_new = block[191 : 160];
+          w_mem11_new = block[159 : 128];
+          w_mem12_new = block[127 :  96];
+          w_mem13_new = block[95  :  64];
+          w_mem14_new = block[63  :  32];
+          w_mem15_new = block[31  :   0];
+          w_mem_we    = 1;
+        end
+      else if (w_ctr_reg > 15)
+        begin
+          w_mem00_new = w_mem[01];
+          w_mem01_new = w_mem[02];
+          w_mem02_new = w_mem[03];
+          w_mem03_new = w_mem[04];
+          w_mem04_new = w_mem[05];
+          w_mem05_new = w_mem[06];
+          w_mem06_new = w_mem[07];
+          w_mem07_new = w_mem[08];
+          w_mem08_new = w_mem[09];
+          w_mem09_new = w_mem[10];
+          w_mem10_new = w_mem[11];
+          w_mem11_new = w_mem[12];
+          w_mem12_new = w_mem[13];
+          w_mem13_new = w_mem[14];
+          w_mem14_new = w_mem[15];
+          w_mem15_new = w_new;
+          w_mem_we    = 1;
+        end
+    end // w_mem_update_logic
+
+
+  //----------------------------------------------------------------
+  // w_ctr
+  // W schedule adress counter. Counts from 0x10 to 0x3f and
+  // is used to expand the block into words.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_ctr
+      w_ctr_new = 0;
+      w_ctr_we  = 0;
+
+      if (w_ctr_rst)
+        begin
+          w_ctr_new = 6'h00;
+          w_ctr_we  = 1;
+        end
+
+      if (w_ctr_inc)
+        begin
+          w_ctr_new = w_ctr_reg + 6'h01;
+          w_ctr_we  = 1;
+        end
+    end // w_ctr
+
+
+  //----------------------------------------------------------------
+  // sha256_w_mem_fsm
+  // Logic for the w shedule FSM.
+  //----------------------------------------------------------------
+  always @*
+    begin : sha256_w_mem_fsm
+      w_ctr_rst = 0;
+      w_ctr_inc = 0;
+
+      sha256_w_mem_ctrl_new = CTRL_IDLE;
+      sha256_w_mem_ctrl_we  = 0;
+
+      case (sha256_w_mem_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            if (init)
+              begin
+                w_ctr_rst             = 1;
+                sha256_w_mem_ctrl_new = CTRL_UPDATE;
+                sha256_w_mem_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_UPDATE:
+          begin
+            if (next)
+              begin
+                w_ctr_inc = 1;
+              end
+
+            if (w_ctr_reg == 6'h3f)
+              begin
+                sha256_w_mem_ctrl_new = CTRL_IDLE;
+                sha256_w_mem_ctrl_we  = 1;
+              end
+          end
+      endcase // case (sha256_ctrl_reg)
+    end // sha256_ctrl_fsm
+
+endmodule // sha256_w_mem
+
+//======================================================================
+// sha256_w_mem.v
+//======================================================================
diff --git a/sha256/src/rtl/wb_sha256.v b/sha256/src/rtl/wb_sha256.v
new file mode 100644
index 0000000..024d0b9
--- /dev/null
+++ b/sha256/src/rtl/wb_sha256.v
@@ -0,0 +1,674 @@
+//======================================================================
+//
+// wb_sha256.v
+// -----------
+// Wisbone compliant top level wrapper for the SHA-256 hash core.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module wb_sha256(
+                 // Clock and reset.
+                 input wire           CLK_I,
+                 input wire           RST_I,
+                 
+                 // Control and status.
+                 input wire           STB_I,
+                 input wire           WE_I,
+                 output wire          ACK_O,
+                 output wire          ERR_O,
+              
+                 // Address and data.
+                 input wire  [7 : 0]  ADR_I,
+                 input wire  [31 : 0] DAT_I,              
+                 output wire [31 : 0] DAT_O
+                );
+
+  
+  //----------------------------------------------------------------
+  // 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_INIT_VALUE    = 8'h01;
+  parameter CTRL_NEXT_BIT      = 1;
+  parameter CTRL_NEXT_VALUE    = 8'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_DIGEST0       = 8'h20;
+  parameter ADDR_DIGEST1       = 8'h21;
+  parameter ADDR_DIGEST2       = 8'h22;
+  parameter ADDR_DIGEST3       = 8'h23;
+  parameter ADDR_DIGEST4       = 8'h24;
+  parameter ADDR_DIGEST5       = 8'h25;
+  parameter ADDR_DIGEST6       = 8'h26;
+  parameter ADDR_DIGEST7       = 8'h27;
+
+  parameter CORE_NAME0   = 32'h73686132; // "sha2"
+  parameter CORE_NAME1   = 32'h2d323536; // "-256"
+  parameter CORE_VERSION = 32'h302e3830; // "0.80"
+
+  
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg init_reg;
+  reg next_reg;
+  reg ctrl_we;
+  
+  reg ready_reg;
+
+  reg [31 : 0] block0_reg;
+  reg          block0_we;
+  reg [31 : 0] block1_reg;
+  reg          block1_we;
+  reg [31 : 0] block2_reg;
+  reg          block2_we;
+  reg [31 : 0] block3_reg;
+  reg          block3_we;
+  reg [31 : 0] block4_reg;
+  reg          block4_we;
+  reg [31 : 0] block5_reg;
+  reg          block5_we;
+  reg [31 : 0] block6_reg;
+  reg          block6_we;
+  reg [31 : 0] block7_reg;
+  reg          block7_we;
+  reg [31 : 0] block8_reg;
+  reg          block8_we;
+  reg [31 : 0] block9_reg;
+  reg          block9_we;
+  reg [31 : 0] block10_reg;
+  reg          block10_we;
+  reg [31 : 0] block11_reg;
+  reg          block11_we;
+  reg [31 : 0] block12_reg;
+  reg          block12_we;
+  reg [31 : 0] block13_reg;
+  reg          block13_we;
+  reg [31 : 0] block14_reg;
+  reg          block14_we;
+  reg [31 : 0] block15_reg;
+  reg          block15_we;
+
+  reg [255 : 0] digest_reg;
+
+  reg digest_valid_reg;
+
+  
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  wire           core_init;
+  wire           core_next;
+  wire           core_ready;
+  wire [511 : 0] core_block;
+  wire [255 : 0] core_digest;
+  wire           core_digest_valid;
+
+  reg [31 : 0]   tmp_data_out;
+  reg            tmp_ACK_O;
+  reg            tmp_ERR_O;
+
+  wire reset_n;
+  
+  
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign core_init = init_reg;
+
+  assign core_next = next_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};
+
+  assign DAT_O = tmp_data_out;
+
+  assign ACK_O = tmp_ACK_O;
+  assign ERR_O = tmp_ERR_O;
+
+  assign reset_n = ~RST_I;
+    
+             
+  //----------------------------------------------------------------
+  // core instantiation.
+  //----------------------------------------------------------------
+  sha256_core core(
+                   .clk(CLK_I),
+                   .reset_n(reset_n),
+                   
+                   .init(core_init),
+                   .next(core_next),
+                  
+                   .block(core_block),
+                   
+                   .ready(core_ready),
+                   
+                   .digest(core_digest),
+                   .digest_valid(core_digest_valid)
+                  );
+  
+  
+  //----------------------------------------------------------------
+  // reg_update
+  //
+  // Update functionality for all registers in the core.
+  // All registers are positive edge triggered with synchronous
+  // active low reset. All registers have write enable.
+  //----------------------------------------------------------------
+  always @ (posedge CLK_I)
+    begin
+      if (!reset_n)
+        begin
+          init_reg         <= 0;
+          next_reg         <= 0;
+          ready_reg        <= 0;
+          digest_reg       <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
+          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;
+        end
+      else
+        begin
+          ready_reg        <= core_ready;
+          digest_valid_reg <= core_digest_valid;
+
+          if (ctrl_we)
+            begin
+              init_reg <= DAT_I[CTRL_INIT_BIT];
+              next_reg <= DAT_I[CTRL_NEXT_BIT];
+            end
+          
+          if (core_digest_valid)
+            begin
+              digest_reg <= core_digest;
+            end
+
+          if (block0_we)
+            begin
+              block0_reg <= DAT_I;
+            end
+
+          if (block1_we)
+            begin
+              block1_reg <= DAT_I;
+            end
+
+          if (block2_we)
+            begin
+              block2_reg <= DAT_I;
+            end
+
+          if (block3_we)
+            begin
+              block3_reg <= DAT_I;
+            end
+
+          if (block4_we)
+            begin
+              block4_reg <= DAT_I;
+            end
+
+          if (block5_we)
+            begin
+              block5_reg <= DAT_I;
+            end
+
+          if (block6_we)
+            begin
+              block6_reg <= DAT_I;
+            end
+
+          if (block7_we)
+            begin
+              block7_reg <= DAT_I;
+            end
+
+          if (block8_we)
+            begin
+              block8_reg <= DAT_I;
+            end
+
+          if (block9_we)
+            begin
+              block9_reg <= DAT_I;
+            end
+
+          if (block10_we)
+            begin
+              block10_reg <= DAT_I;
+            end
+
+          if (block11_we)
+            begin
+              block11_reg <= DAT_I;
+            end
+
+          if (block12_we)
+            begin
+              block12_reg <= DAT_I;
+            end
+
+          if (block13_we)
+            begin
+              block13_reg <= DAT_I;
+            end
+
+          if (block14_we)
+            begin
+              block14_reg <= DAT_I;
+            end
+
+          if (block15_we)
+            begin
+              block15_reg <= DAT_I;
+            end
+          
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // addr_decoder
+  //
+  // IF SEL_I is enabled will either try to write to or read
+  // from the internal registers.
+  //----------------------------------------------------------------
+  always @*
+    begin : addr_decoder
+      ctrl_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;
+      tmp_data_out = 32'h00000000;
+      tmp_ERR_O    = 0;
+      tmp_ACK_O    = 0;
+      
+      if (STB_I)
+        begin
+          if (WE_I)
+            begin
+              case (ADR_I)
+                // Write operations.
+                ADDR_CTRL:
+                  begin
+                    ctrl_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+                
+                ADDR_BLOCK0:
+                  begin
+                    block0_we = 1;
+                    tmp_ACK_O = 1;
+                   end
+
+                ADDR_BLOCK1:
+                  begin
+                    block1_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK2:
+                  begin
+                    block2_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK3:
+                  begin
+                    block3_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK4:
+                  begin
+                    block4_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK5:
+                  begin
+                    block5_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK6:
+                  begin
+                    block6_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK7:
+                  begin
+                    block7_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK8:
+                  begin
+                    block8_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK9:
+                  begin
+                    block9_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK10:
+                  begin
+                    block10_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK11:
+                  begin
+                    block11_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK12:
+                  begin
+                    block12_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK13:
+                  begin
+                    block13_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK14:
+                  begin
+                    block14_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK15:
+                  begin
+                    block15_we = 1;
+                    tmp_ACK_O = 1;
+                  end
+                
+                default:
+                  begin
+                    tmp_ERR_O = 1;
+                  end
+              endcase // case (ADR_I)
+            end // if (WE_I)
+
+          else
+            begin
+              case (ADR_I)
+                // Read operations.
+                ADDR_NAME0:
+                  begin
+                    tmp_data_out = CORE_NAME0;
+                    tmp_ACK_O = 1;
+                  end
+                
+                ADDR_NAME1:
+                  begin
+                    tmp_data_out = CORE_NAME1;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_VERSION:
+                  begin
+                    tmp_data_out = CORE_VERSION;
+                    tmp_ACK_O = 1;
+                  end
+                
+                ADDR_CTRL:
+                  begin
+                    tmp_data_out = {28'h0000000, 2'b00, next_reg, init_reg};
+                    tmp_ACK_O = 1;
+                  end
+                
+                ADDR_STATUS:
+                  begin
+                    tmp_data_out = {28'h0000000, 2'b00, digest_valid_reg, ready_reg};
+                    tmp_ACK_O = 1;
+                  end
+                
+                ADDR_BLOCK0:
+                  begin
+                    tmp_data_out = block0_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK1:
+                  begin
+                    tmp_data_out = block1_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK2:
+                  begin
+                    tmp_data_out = block2_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK3:
+                  begin
+                    tmp_data_out = block3_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK4:
+                  begin
+                    tmp_data_out = block4_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK5:
+                  begin
+                    tmp_data_out = block5_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK6:
+                  begin
+                    tmp_data_out = block6_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK7:
+                  begin
+                    tmp_data_out = block7_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK8:
+                  begin
+                    tmp_data_out = block8_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK9:
+                  begin
+                    tmp_data_out = block9_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK10:
+                  begin
+                    tmp_data_out = block10_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK11:
+                  begin
+                    tmp_data_out = block11_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK12:
+                  begin
+                    tmp_data_out = block12_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK13:
+                  begin
+                    tmp_data_out = block13_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK14:
+                  begin
+                    tmp_data_out = block14_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_BLOCK15:
+                  begin
+                    tmp_data_out = block15_reg;
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST0:
+                  begin
+                    tmp_data_out = digest_reg[255 : 224];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST1:
+                  begin
+                    tmp_data_out = digest_reg[223 : 192];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST2:
+                  begin
+                    tmp_data_out = digest_reg[191 : 160];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST3:
+                  begin
+                    tmp_data_out = digest_reg[159 : 128];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST4:
+                  begin
+                    tmp_data_out = digest_reg[127 :  96];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST5:
+                  begin
+                    tmp_data_out = digest_reg[95  :  64];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST6:
+                  begin
+                    tmp_data_out = digest_reg[63  :  32];
+                    tmp_ACK_O = 1;
+                  end
+
+                ADDR_DIGEST7:
+                  begin
+                    tmp_data_out = digest_reg[31  :   0];
+                    tmp_ACK_O = 1;
+                  end
+                
+                default:
+                  begin
+                    tmp_ERR_O = 1;
+                  end
+              endcase // case (ADR_I)
+            end
+        end
+    end // addr_decoder
+endmodule // wb_sha256
+
+//======================================================================
+// EOF wb_sha256.v
+//======================================================================
diff --git a/sha256/src/tb/tb_sha256.v b/sha256/src/tb/tb_sha256.v
new file mode 100644
index 0000000..72e7d21
--- /dev/null
+++ b/sha256/src/tb/tb_sha256.v
@@ -0,0 +1,556 @@
+//======================================================================
+//
+// tb_sha256.v
+// -----------
+// Testbench for the SHA-256 top level wrapper.
+//
+//
+// 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, 
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+//------------------------------------------------------------------
+// Test module.
+//------------------------------------------------------------------
+module tb_sha256();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  parameter CLK_HALF_PERIOD = 2;
+  parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
+
+  // 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_VALUE  = 8'h01;
+  parameter CTRL_NEXT_VALUE  = 8'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_DIGEST0   = 8'h20;
+  parameter ADDR_DIGEST1   = 8'h21;
+  parameter ADDR_DIGEST2   = 8'h22;
+  parameter ADDR_DIGEST3   = 8'h23;
+  parameter ADDR_DIGEST4   = 8'h24;
+  parameter ADDR_DIGEST5   = 8'h25;
+  parameter ADDR_DIGEST6   = 8'h26;
+  parameter ADDR_DIGEST7   = 8'h27;
+
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+  reg           tb_cs;
+  reg           tb_we;
+  reg [7 : 0]   tb_address;
+  reg [31 : 0]  tb_write_data;
+  wire [31 : 0] tb_read_data;
+  wire          tb_error;
+
+  reg [31 : 0]  read_data;
+  reg [255 : 0] digest_data;
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha256 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. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+    
+
+  //----------------------------------------------------------------
+  // sys_monitor
+  //
+  // Generates a cycle counter and displays information about
+  // the dut as needed.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      #(2 * CLK_HALF_PERIOD);
+      cycle_ctr = cycle_ctr + 1;
+    end
+
+  
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dump when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $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", 
+               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}, 
+               {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);
+      $display("block4  = 0x%08x, block5  = 0x%08x, block6  = 0x%08x,  block7  = 0x%08x",
+               dut.block4_reg, dut.block5_reg, dut.block6_reg, dut.block7_reg);
+
+      $display("block8  = 0x%08x, block9  = 0x%08x, block10 = 0x%08x,  block11 = 0x%08x",
+               dut.block8_reg, dut.block9_reg, dut.block10_reg, dut.block11_reg);
+     $display("block12 = 0x%08x, block13 = 0x%08x, block14 = 0x%08x,  block15 = 0x%08x",
+               dut.block12_reg, dut.block13_reg, dut.block14_reg, dut.block15_reg);
+      $display("");
+      
+      $display("Digest:");
+      $display("digest = 0x%064x", dut.digest_reg);
+      $display("");
+      
+    end
+  endtask // dump_dut_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //
+  // Toggles reset to force the DUT into a well defined state.
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 32'h00000000;
+      error_ctr = 32'h00000000;
+      tc_ctr = 32'h00000000;
+      
+      tb_clk = 0;
+      tb_reset_n = 0;
+      tb_cs = 0;
+      tb_we = 0;
+      tb_address = 6'h00;
+      tb_write_data = 32'h00000000;
+    end
+  endtask // init_dut
+
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully.", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases completed.", tc_ctr);
+          $display("*** %02d errors detected during testing.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+  
+  
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  // (Actually we wait for either ready or valid to be set.)
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      read_data = 0;
+      
+      while (read_data == 0)
+        begin
+          read_word(ADDR_STATUS);
+        end
+    end
+  endtask // wait_ready
+  
+
+  //----------------------------------------------------------------
+  // write_word()
+  //
+  // Write the given word to the DUT using the DUT interface.
+  //----------------------------------------------------------------
+  task write_word(input [7 : 0]  address,
+                  input [31 : 0] word);
+    begin
+      if (DEBUG)
+        begin
+          $display("*** Writing 0x%08x to 0x%02x.", word, address);
+          $display("");
+        end
+         
+      tb_address = address;
+      tb_write_data = word;
+      tb_cs = 1;
+      tb_we = 1;
+      #(CLK_PERIOD);
+      tb_cs = 0;
+      tb_we = 0;
+    end
+  endtask // write_word
+
+
+  //----------------------------------------------------------------
+  // write_block()
+  //
+  // Write the given block to the dut.
+  //----------------------------------------------------------------
+  task write_block(input [511 : 0] block);
+    begin
+      write_word(ADDR_BLOCK0,  block[511 : 480]);
+      write_word(ADDR_BLOCK1,  block[479 : 448]);
+      write_word(ADDR_BLOCK2,  block[447 : 416]);
+      write_word(ADDR_BLOCK3,  block[415 : 384]);
+      write_word(ADDR_BLOCK4,  block[383 : 352]);
+      write_word(ADDR_BLOCK5,  block[351 : 320]);
+      write_word(ADDR_BLOCK6,  block[319 : 288]);
+      write_word(ADDR_BLOCK7,  block[287 : 256]);
+      write_word(ADDR_BLOCK8,  block[255 : 224]);
+      write_word(ADDR_BLOCK9,  block[223 : 192]);
+      write_word(ADDR_BLOCK10, block[191 : 160]);
+      write_word(ADDR_BLOCK11, block[159 : 128]);
+      write_word(ADDR_BLOCK12, block[127 :  96]);
+      write_word(ADDR_BLOCK13, block[95  :  64]);
+      write_word(ADDR_BLOCK14, block[63  :  32]);
+      write_word(ADDR_BLOCK15, block[31  :   0]);
+    end
+  endtask // write_block
+  
+
+  //----------------------------------------------------------------
+  // read_word()
+  //
+  // Read a data word from the given address in the DUT.
+  // the word read will be available in the global variable
+  // read_data.
+  //----------------------------------------------------------------
+  task read_word(input [7 : 0]  address);
+    begin
+      tb_address = address;
+      tb_cs = 1;
+      tb_we = 0;
+      #(CLK_PERIOD);
+      read_data = tb_read_data;
+      tb_cs = 0;
+
+      if (DEBUG)
+        begin
+          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
+          $display("");
+        end
+    end
+  endtask // read_word
+
+  
+  //----------------------------------------------------------------
+  // check_name_version()
+  //
+  // Read the name and version from the DUT.
+  //----------------------------------------------------------------
+  task check_name_version();
+    reg [31 : 0] name0;
+    reg [31 : 0] name1;
+    reg [31 : 0] version;
+    begin
+
+      read_word(ADDR_NAME0);
+      name0 = read_data;
+      read_word(ADDR_NAME1);
+      name1 = read_data;
+      read_word(ADDR_VERSION);
+      version = read_data;
+
+      $display("DUT name: %c%c%c%c%c%c%c%c",
+               name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0],
+               name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]);
+      $display("DUT version: %c%c%c%c",
+               version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]);
+    end
+  endtask // check_name_version
+  
+
+  //----------------------------------------------------------------
+  // read_digest()
+  //
+  // Read the digest in the dut. The resulting digest will be
+  // available in the global variable digest_data.
+  //----------------------------------------------------------------
+  task read_digest();
+    begin
+      read_word(ADDR_DIGEST0);
+      digest_data[255 : 224] = read_data;
+      read_word(ADDR_DIGEST1);
+      digest_data[223 : 192] = read_data;
+      read_word(ADDR_DIGEST2);
+      digest_data[191 : 160] = read_data;
+      read_word(ADDR_DIGEST3);
+      digest_data[159 : 128] = read_data;
+      read_word(ADDR_DIGEST4);
+      digest_data[127 :  96] = read_data;
+      read_word(ADDR_DIGEST5);
+      digest_data[95  :  64] = read_data;
+      read_word(ADDR_DIGEST6);
+      digest_data[63  :  32] = read_data;
+      read_word(ADDR_DIGEST7);
+      digest_data[31  :   0] = read_data;
+    end
+  endtask // read_digest
+    
+  
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  //
+  // Perform test of a single block digest.
+  //----------------------------------------------------------------
+  task single_block_test(input [511 : 0] block,
+                         input [255 : 0] expected);
+    begin
+      $display("*** TC%01d - Single block test started.", tc_ctr); 
+     
+      write_block(block);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected)
+        begin
+          $display("TC%01d: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR.", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+      $display("*** TC%01d - Single block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // single_block_test
+    
+  
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  //
+  // Perform test of a double block digest. Note that we check
+  // the digests for both the first and final block.
+  //----------------------------------------------------------------
+  task double_block_test(input [511 : 0] block0,
+                         input [255 : 0] expected0,
+                         input [511 : 0] block1,
+                         input [255 : 0] expected1
+                        );
+    begin
+      $display("*** TC%01d - Double block test started.", tc_ctr); 
+
+      // First block
+      write_block(block0);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected0)
+        begin
+          $display("TC%01d first block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in first digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected0);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      // Final block
+      write_block(block1);
+      write_word(ADDR_CTRL, CTRL_NEXT_VALUE);
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+      
+      if (digest_data == expected1)
+        begin
+          $display("TC%01d final block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in final digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected1);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      $display("*** TC%01d - Double block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // double_block_test
+
+    
+  //----------------------------------------------------------------
+  // sha256_test
+  // The main test functionality. 
+  //
+  // Test cases taken from:
+  // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
+  //----------------------------------------------------------------
+  initial
+    begin : sha256_test
+      reg [511 : 0] tc0;
+      reg [255 : 0] res0;
+
+      reg [511 : 0] tc1_0;
+      reg [255 : 0] res1_0;
+      reg [511 : 0] tc1_1;
+      reg [255 : 0] res1_1;
+      
+      $display("   -- Testbench for sha256 started --");
+
+      init_sim();
+      reset_dut();
+      check_name_version();
+
+      // dump_dut_state();
+      // write_word(ADDR_BLOCK0, 32'hdeadbeef);
+      // dump_dut_state();
+      // read_word(ADDR_BLOCK0);
+      // dump_dut_state();
+
+      tc0 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      res0 = 256'hBA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD;
+      single_block_test(tc0, res0);
+
+      tc1_0 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000;
+      res1_0 = 256'h85E655D6417A17953363376A624CDE5C76E09589CAC5F811CC4B32C1F20E533A;
+      tc1_1 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0;
+      res1_1 = 256'h248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1;
+      double_block_test(tc1_0, res1_0, tc1_1, res1_1);
+      
+      display_test_result();
+      
+      $display("   -- Testbench for sha256 done. --");
+      $finish;
+    end // sha256_test
+endmodule // tb_sha256
+
+//======================================================================
+// EOF tb_sha256.v
+//======================================================================
diff --git a/sha256/src/tb/tb_sha256_core.v b/sha256/src/tb/tb_sha256_core.v
new file mode 100644
index 0000000..df0cafc
--- /dev/null
+++ b/sha256/src/tb/tb_sha256_core.v
@@ -0,0 +1,406 @@
+//======================================================================
+//
+// tb_sha256_core.v
+// ----------------
+// Testbench for the SHA-256 core.
+//
+//
+// 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, 
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+//------------------------------------------------------------------
+// Test module.
+//------------------------------------------------------------------
+module tb_sha256_core();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  parameter CLK_HALF_PERIOD = 2;
+  parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
+  
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg            tb_clk;
+  reg            tb_reset_n;
+  reg            tb_init;
+  reg            tb_next;
+  reg [511 : 0]  tb_block;
+  wire           tb_ready;
+  wire [255 : 0] tb_digest;
+  wire           tb_digest_valid;
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha256_core dut(
+                   .clk(tb_clk),
+                   .reset_n(tb_reset_n),
+                 
+                   .init(tb_init),
+                   .next(tb_next),
+
+                   .block(tb_block),
+                   
+                   .ready(tb_ready),
+                   
+                   .digest(tb_digest),
+                   .digest_valid(tb_digest_valid)
+                 );
+  
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Always running clock generator process.
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD;
+      tb_clk = !tb_clk;
+    end // clk_gen
+    
+
+  //----------------------------------------------------------------
+  // sys_monitor()
+  //
+  // An always running process that creates a cycle counter and
+  // conditionally displays information about the DUT.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      cycle_ctr = cycle_ctr + 1;
+      #(2 * CLK_HALF_PERIOD);
+      if (DEBUG)
+        begin
+          dump_dut_state();
+        end
+    end
+
+  
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dump when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $display("init   = 0x%01x, next  = 0x%01x", 
+               dut.init, dut.next);
+      $display("block  = 0x%0128x", dut.block);
+
+      $display("ready  = 0x%01x, valid = 0x%01x", 
+               dut.ready, dut.digest_valid);
+      $display("digest = 0x%064x", dut.digest);
+      $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x", 
+               dut.H0_reg, dut.H1_reg, dut.H2_reg, dut.H3_reg);
+      $display("H4_reg = 0x%08x, H5_reg = 0x%08x, H6_reg = 0x%08x, H7_reg = 0x%08x", 
+               dut.H4_reg, dut.H5_reg, dut.H6_reg, dut.H7_reg);
+      $display("");
+      
+      $display("Control signals and counter:");
+      $display("sha256_ctrl_reg = 0x%02x", dut.sha256_ctrl_reg);
+      $display("digest_init     = 0x%01x, digest_update = 0x%01x", 
+               dut.digest_init, dut.digest_update);
+      $display("state_init      = 0x%01x, state_update  = 0x%01x", 
+               dut.state_init, dut.state_update);
+      $display("first_block     = 0x%01x, ready_flag    = 0x%01x, w_init    = 0x%01x", 
+               dut.first_block, dut.ready_flag, dut.w_init);
+      $display("t_ctr_inc       = 0x%01x, t_ctr_rst     = 0x%01x, t_ctr_reg = 0x%02x", 
+               dut.t_ctr_inc, dut.t_ctr_rst, dut.t_ctr_reg);
+      $display("");
+
+      $display("State registers:");
+      $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x", 
+               dut.a_reg, dut.b_reg, dut.c_reg, dut.d_reg);
+      $display("e_reg = 0x%08x, f_reg = 0x%08x, g_reg = 0x%08x, h_reg = 0x%08x", 
+               dut.e_reg, dut.f_reg, dut.g_reg, dut.h_reg);
+      $display("");
+      $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x", 
+               dut.a_new, dut.b_new, dut.c_new, dut.d_new);
+      $display("e_new = 0x%08x, f_new = 0x%08x, g_new = 0x%08x, h_new = 0x%08x", 
+               dut.e_new, dut.f_new, dut.g_new, dut.h_new);
+      $display("");
+
+      $display("State update values:");
+      $display("w  = 0x%08x, k  = 0x%08x", dut.w_data, dut.k_data);
+      $display("t1 = 0x%08x, t2 = 0x%08x", dut.t1, dut.t2);
+      $display("");
+    end
+  endtask // dump_dut_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //
+  // Toggle reset to put the DUT into a well known state.
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 0;
+      error_ctr = 0;
+      tc_ctr = 0;
+      
+      tb_clk = 0;
+      tb_reset_n = 1;
+
+      tb_init = 0;
+      tb_next = 0;
+      tb_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
+    end
+  endtask // init_dut
+
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases did not complete successfully.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+  
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      while (!tb_ready)
+        begin
+          #(CLK_PERIOD);
+        end
+    end
+  endtask // wait_ready
+
+  
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  // Run a test case spanning a single data block.
+  //----------------------------------------------------------------
+  task single_block_test(input [7 : 0]   tc_number,
+                         input [511 : 0] block,
+                         input [255 : 0] expected);
+   begin
+     $display("*** TC %0d single block test case started.", tc_number);
+     tc_ctr = tc_ctr + 1;
+
+     tb_block = block;
+     tb_init = 1;
+     #(CLK_PERIOD);
+     wait_ready();
+
+      
+     if (tb_digest == expected)
+       begin
+         $display("*** TC %0d successful.", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d NOT successful.", tc_number);
+         $display("Expected: 0x%064x", expected);
+         $display("Got:      0x%064x", tb_digest);
+         $display("");
+         
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // single_block_test
+
+  
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  // Run a test case spanning two data blocks. We check both
+  // intermediate and final digest.
+  //----------------------------------------------------------------
+  task double_block_test(input [7 : 0]   tc_number,
+                         input [511 : 0] block1,
+                         input [255 : 0] expected1,
+                         input [511 : 0] block2,
+                         input [255 : 0] expected2);
+
+     reg [255 : 0] db_digest1;
+     reg           db_error;
+   begin
+     $display("*** TC %0d double block test case started.", tc_number);
+     db_error = 0;
+     tc_ctr = tc_ctr + 1;
+
+     $display("*** TC %0d first block started.", tc_number);
+     tb_block = block1;
+     tb_init = 1;
+     #(CLK_PERIOD);
+     wait_ready();
+     db_digest1 = tb_digest;
+     $display("*** TC %0d first block done.", tc_number);
+     
+     $display("*** TC %0d second block started.", tc_number);
+     tb_block = block2;
+     tb_next = 1;
+     #(CLK_PERIOD);
+     wait_ready();
+     $display("*** TC %0d second block done.", tc_number);
+      
+     if (db_digest1 == expected1)
+       begin
+         $display("*** TC %0d first block successful", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d first block NOT successful", tc_number);
+         $display("Expected: 0x%064x", expected1);
+         $display("Got:      0x%064x", db_digest1);
+         $display("");
+         db_error = 1;
+       end
+      
+     if (db_digest1 == expected1)
+       begin
+         $display("*** TC %0d second block successful", tc_number);
+         $display("");
+       end 
+     else
+       begin
+         $display("*** ERROR: TC %0d second block NOT successful", tc_number);
+         $display("Expected: 0x%064x", expected2);
+         $display("Got:      0x%064x", tb_digest);
+         $display("");
+         db_error = 1;
+       end
+
+     if (db_error)
+       begin
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // single_block_test
+                         
+    
+  //----------------------------------------------------------------
+  // sha256_core_test
+  // The main test functionality. 
+  //
+  // Test cases taken from:
+  // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
+  //----------------------------------------------------------------
+  initial
+    begin : sha256_core_test
+      reg [511 : 0] tc1;
+      reg [255 : 0] res1;
+
+      reg [511 : 0] tc2_1;
+      reg [255 : 0] res2_1;
+      reg [511 : 0] tc2_2;
+      reg [255 : 0] res2_2;
+      
+      $display("   -- Testbench for sha256 core started --");
+
+      init_sim();
+      dump_dut_state();
+      reset_dut();
+      dump_dut_state();
+        
+      // TC1: Single block message: "abc".
+      tc1 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      res1 = 256'hBA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD;
+      single_block_test(1, tc1, res1);
+
+      // TC2: Double block message.
+      // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+      tc2_1 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000;
+      res2_1 = 256'h85E655D6417A17953363376A624CDE5C76E09589CAC5F811CC4B32C1F20E533A;
+      
+      tc2_2 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0;
+      res2_2 = 256'h248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1;
+      double_block_test(2, tc2_1, res2_1, tc2_2, res2_2);
+      
+      display_test_result();
+      $display("*** Simulation done.");
+      $finish;
+    end // sha256_core_test
+endmodule // tb_sha256_core
+
+//======================================================================
+// EOF tb_sha256_core.v
+//======================================================================
diff --git a/sha256/src/tb/tb_sha256_w_mem.v b/sha256/src/tb/tb_sha256_w_mem.v
new file mode 100644
index 0000000..c95317d
--- /dev/null
+++ b/sha256/src/tb/tb_sha256_w_mem.v
@@ -0,0 +1,222 @@
+//======================================================================
+//
+// tb_sha256_w_mem.v
+// -----------------
+// Testbench for the SHA-256 W memory module.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+module tb_sha256_w_mem();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG          = 1;
+  parameter DISPLAY_CYCLES = 0;
+
+  parameter CLK_HALF_PERIOD = 2;
+
+  
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+
+  
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg            tb_clk;
+  reg            tb_reset_n;
+
+  reg           tb_init;
+  reg           tb_next;
+  reg [511 : 0] tb_block;
+  wire [31 : 0] tb_w;
+
+  reg [63 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha256_w_mem dut(
+                   .clk(tb_clk),
+                   .reset_n(tb_reset_n),
+                   
+                   .block(tb_block),
+                   
+                   .init(tb_init),
+                   .next(tb_next),
+
+                   .w(tb_w)
+                  );
+  
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+  
+  //--------------------------------------------------------------------
+  // dut_monitor
+  //
+  // Monitor displaying information every cycle.
+  // Includes the cycle counter.
+  //--------------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : dut_monitor
+      cycle_ctr = cycle_ctr + 1;
+
+      if (DISPLAY_CYCLES)
+        begin
+          $display("cycle = %016x:", cycle_ctr);
+        end
+      
+      if (DEBUG)
+        begin
+          $display("dut ctrl_state = %02x:", dut.sha256_w_mem_ctrl_reg);
+          $display("dut w_ctr      = %02x:", dut.w_ctr_reg);
+          $display("dut w_tmp      = %02x:", dut.w_tmp);
+          dump_w_state();
+        end
+    end // dut_monitor
+      
+  
+  //----------------------------------------------------------------
+  // dump_w_state()
+  //
+  // Dump the current state of all W registers.
+  //----------------------------------------------------------------
+  task dump_w_state();
+    begin
+      $display("W state:");
+      
+      $display("w0_reg  = %08x, w1_reg  = %08x, w2_reg  = %08x, w3_reg  = %08x", 
+               dut.w_mem[00], dut.w_mem[01], dut.w_mem[02], dut.w_mem[03]);
+
+      $display("w4_reg  = %08x, w5_reg  = %08x, w6_reg  = %08x, w7_reg  = %08x", 
+               dut.w_mem[04], dut.w_mem[05], dut.w_mem[06], dut.w_mem[07]);
+
+      $display("w8_reg  = %08x, w9_reg  = %08x, w10_reg = %08x, w11_reg = %08x", 
+               dut.w_mem[08], dut.w_mem[09], dut.w_mem[10], dut.w_mem[11]);
+
+      $display("w12_reg = %08x, w13_reg = %08x, w14_reg = %08x, w15_reg = %08x", 
+               dut.w_mem[12], dut.w_mem[13], dut.w_mem[14], dut.w_mem[15]);
+
+      $display("w_new = %08x", dut.w_new);
+      $display("");
+    end
+  endtask // dump_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+  
+  
+  //----------------------------------------------------------------
+  // init_sim
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      $display("*** Simulation init.");
+      tb_clk = 0;
+      tb_reset_n = 1;
+      cycle_ctr = 0;
+      
+      tb_init = 0;
+      tb_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
+    end
+  endtask // reset_dut
+  
+  
+  //----------------------------------------------------------------
+  // test_w_schedule()
+  //
+  // Test that W scheduling happens and work correctly.
+  // Note: Currently not a self checking test case.
+  //----------------------------------------------------------------
+  task test_w_schedule();
+    begin
+      $display("*** Test of W schedule processing. --");
+      tb_block = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      tb_init = 1;
+      #(4 * CLK_HALF_PERIOD);
+      tb_init = 0;
+      dump_w_state();
+
+      tb_next = 1;
+      #(150 * CLK_HALF_PERIOD);
+    end
+  endtask // test_w_schedule
+  
+    
+  //----------------------------------------------------------------
+  // The main test functionality. 
+  //----------------------------------------------------------------
+  initial
+    begin : w_mem_test
+      $display("   -- Testbench for sha256 w memory started --");
+      init_sim();
+      reset_dut();
+      test_w_schedule();
+
+      $display("*** Simulation done.");
+      $finish;
+    end
+  
+endmodule // w_mem_test
+  
+//======================================================================
+// EOF tb_sha256_w_mem.v
+//======================================================================
diff --git a/sha256/src/tb/tb_wb_sha256.v b/sha256/src/tb/tb_wb_sha256.v
new file mode 100644
index 0000000..6d5fe08
--- /dev/null
+++ b/sha256/src/tb/tb_wb_sha256.v
@@ -0,0 +1,556 @@
+//======================================================================
+//
+// tb_wb_sha256.v
+// --------------
+// Testbench for the SHA-256 top level Wishbone wrapper.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014, SUNET
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+//------------------------------------------------------------------
+// Test module.
+//------------------------------------------------------------------
+module tb_wb_sha256();
+  
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  parameter CLK_HALF_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_INIT_VALUE    = 8'h01;
+  parameter CTRL_NEXT_BIT      = 1;
+  parameter CTRL_NEXT_VALUE    = 8'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_DIGEST0       = 8'h20;
+  parameter ADDR_DIGEST1       = 8'h21;
+  parameter ADDR_DIGEST2       = 8'h22;
+  parameter ADDR_DIGEST3       = 8'h23;
+  parameter ADDR_DIGEST4       = 8'h24;
+  parameter ADDR_DIGEST5       = 8'h25;
+  parameter ADDR_DIGEST6       = 8'h26;
+  parameter ADDR_DIGEST7       = 8'h27;
+
+  
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset;
+  reg           tb_cs;
+  reg           tb_write_read;
+  reg [7 : 0]   tb_address;
+  reg [31 : 0]  tb_data_in;
+  wire [31 : 0] tb_data_out;
+
+  reg [31 : 0]  read_data;
+  reg [255 : 0] digest_data;
+  
+  
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  wb_sha256 dut(
+                .CLK_I(tb_clk),
+                .RST_I(tb_reset),
+                
+                .STB_I(tb_cs),
+                .WE_I(tb_write_read),
+                .ACK_O(tb_ack),
+                .ERR_O(tb_err),
+                
+                .ADR_I(tb_address),
+                .DAT_I(tb_data_in),              
+                .DAT_O(tb_data_out)
+               );
+  
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Clock generator process. 
+  //----------------------------------------------------------------
+  always 
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+    
+
+  //----------------------------------------------------------------
+  // sys_monitor
+  //
+  // Generates a cycle counter and displays information about
+  // the dut as needed.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      #(2 * CLK_HALF_PERIOD);
+      cycle_ctr = cycle_ctr + 1;
+    end
+
+  
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dump when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $display("STB_I = 0x%01x, WE_I = 0x%01x", 
+               dut.STB_I, dut.WE_I);
+      $display("ADR_I = 0x%02x", dut.ADR_I);
+      $display("DAT_I = 0x%08x, DAT_O = 0x%08x", 
+               dut.DAT_I, dut.DAT_O);
+      $display("tmp_data_out = 0x%08x", dut.tmp_data_out);
+      $display("");
+
+      $display("Control and status:");
+      $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);
+      $display("block4  = 0x%08x, block5  = 0x%08x, block6  = 0x%08x,  block7  = 0x%08x",
+               dut.block4_reg, dut.block5_reg, dut.block6_reg, dut.block7_reg);
+
+      $display("block8  = 0x%08x, block9  = 0x%08x, block10 = 0x%08x,  block11 = 0x%08x",
+               dut.block8_reg, dut.block9_reg, dut.block10_reg, dut.block11_reg);
+      $display("block12 = 0x%08x, block13 = 0x%08x, block14 = 0x%08x,  block15 = 0x%08x",
+               dut.block12_reg, dut.block13_reg, dut.block14_reg, dut.block15_reg);
+      $display("");
+      
+      $display("Digest:");
+      $display("digest = 0x%064x", dut.digest_reg);
+      $display("");
+      
+    end
+  endtask // dump_dut_state
+  
+  
+  //----------------------------------------------------------------
+  // reset_dut()
+  //
+  // Toggles reset to force the DUT into a well defined state.
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset = 1;
+      #(4 * CLK_HALF_PERIOD);
+      tb_reset = 0;
+    end
+  endtask // reset_dut
+
+  
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 32'h00000000;
+      error_ctr = 32'h00000000;
+      tc_ctr = 32'h00000000;
+      
+      tb_clk = 0;
+      tb_reset = 0;
+      tb_cs = 0;
+      tb_write_read = 0;
+      tb_address = 6'h00;
+      tb_data_in = 32'h00000000;
+    end
+  endtask // init_dut
+
+  
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully.", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases completed.", tc_ctr);
+          $display("*** %02d errors detected during testing.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+  
+  
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  // (Actually we wait for either ready or valid to be set.)
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      read_data = 0;
+      
+      while (read_data == 0)
+        begin
+          read_word(ADDR_STATUS);
+        end
+    end
+  endtask // wait_ready
+  
+
+  //----------------------------------------------------------------
+  // write_word()
+  //
+  // Write the given word to the DUT using the DUT interface.
+  //----------------------------------------------------------------
+  task write_word(input [7 : 0]  address,
+                  input [31 : 0] word);
+    begin
+      if (DEBUG)
+        begin
+          $display("*** Writing 0x%08x to 0x%02x.", word, address);
+          $display("");
+        end
+         
+      tb_address = address;
+      tb_data_in = word;
+      tb_cs = 1;
+      tb_write_read = 1;
+      #(2 * CLK_HALF_PERIOD);
+      tb_cs = 0;
+      tb_write_read = 0;
+    end
+  endtask // write_word
+
+
+  //----------------------------------------------------------------
+  // write_block()
+  //
+  // Write the given block to the dut.
+  //----------------------------------------------------------------
+  task write_block(input [511 : 0] block);
+    begin
+      write_word(ADDR_BLOCK0,  block[511 : 480]);
+      write_word(ADDR_BLOCK1,  block[479 : 448]);
+      write_word(ADDR_BLOCK2,  block[447 : 416]);
+      write_word(ADDR_BLOCK3,  block[415 : 384]);
+      write_word(ADDR_BLOCK4,  block[383 : 352]);
+      write_word(ADDR_BLOCK5,  block[351 : 320]);
+      write_word(ADDR_BLOCK6,  block[319 : 288]);
+      write_word(ADDR_BLOCK7,  block[287 : 256]);
+      write_word(ADDR_BLOCK8,  block[255 : 224]);
+      write_word(ADDR_BLOCK9,  block[223 : 192]);
+      write_word(ADDR_BLOCK10, block[191 : 160]);
+      write_word(ADDR_BLOCK11, block[159 : 128]);
+      write_word(ADDR_BLOCK12, block[127 :  96]);
+      write_word(ADDR_BLOCK13, block[95  :  64]);
+      write_word(ADDR_BLOCK14, block[63  :  32]);
+      write_word(ADDR_BLOCK15, block[31  :   0]);
+    end
+  endtask // write_block
+  
+
+  //----------------------------------------------------------------
+  // read_word()
+  //
+  // Read a data word from the given address in the DUT.
+  // the word read will be available in the global variable
+  // read_data.
+  //----------------------------------------------------------------
+  task read_word(input [7 : 0]  address);
+    begin
+      tb_address = address;
+      tb_cs = 1;
+      tb_write_read = 0;
+      #(2 * CLK_HALF_PERIOD);
+      read_data = tb_data_out;
+      tb_cs = 0;
+
+      if (DEBUG)
+        begin
+          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
+          $display("");
+        end
+    end
+  endtask // read_word
+
+  
+  //----------------------------------------------------------------
+  // check_name_version()
+  //
+  // Read the name and version from the DUT.
+  //----------------------------------------------------------------
+  task check_name_version();
+    reg [31 : 0] name0;
+    reg [31 : 0] name1;
+    reg [31 : 0] version;
+    begin
+
+      read_word(ADDR_NAME0);
+      name0 = read_data;
+      read_word(ADDR_NAME1);
+      name1 = read_data;
+      read_word(ADDR_VERSION);
+      version = read_data;
+
+      $display("DUT name: %c%c%c%c%c%c%c%c",
+               name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0],
+               name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]);
+      $display("DUT version: %c%c%c%c",
+               version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]);
+    end
+  endtask // check_name_version
+
+  
+  //----------------------------------------------------------------
+  // read_digest()
+  //
+  // Read the digest in the dut. The resulting digest will be
+  // available in the global variable digest_data.
+  //----------------------------------------------------------------
+  task read_digest();
+    begin
+      read_word(ADDR_DIGEST0);
+      digest_data[255 : 224] = read_data;
+      read_word(ADDR_DIGEST1);
+      digest_data[223 : 192] = read_data;
+      read_word(ADDR_DIGEST2);
+      digest_data[191 : 160] = read_data;
+      read_word(ADDR_DIGEST3);
+      digest_data[159 : 128] = read_data;
+      read_word(ADDR_DIGEST4);
+      digest_data[127 :  96] = read_data;
+      read_word(ADDR_DIGEST5);
+      digest_data[95  :  64] = read_data;
+      read_word(ADDR_DIGEST6);
+      digest_data[63  :  32] = read_data;
+      read_word(ADDR_DIGEST7);
+      digest_data[31  :   0] = read_data;
+    end
+  endtask // read_digest
+    
+  
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  //
+  // Perform test of a single block digest.
+  //----------------------------------------------------------------
+  task single_block_test([511 : 0] block,
+                         [255 : 0] expected);
+    begin
+      $display("*** TC%01d - Single block test started.", tc_ctr); 
+     
+      write_block(block);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      write_word(ADDR_CTRL, 8'h00);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected)
+        begin
+          $display("TC%01d: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR.", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+      $display("*** TC%01d - Single block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // single_block_test
+    
+  
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  //
+  // Perform test of a double block digest. Note that we check
+  // the digests for both the first and final block.
+  //----------------------------------------------------------------
+  task double_block_test([511 : 0] block0,
+                         [255 : 0] expected0,
+                         [511 : 0] block1,
+                         [255 : 0] expected1
+                        );
+    begin
+      $display("*** TC%01d - Double block test started.", tc_ctr); 
+
+      // First block
+      write_block(block0);
+      write_word(ADDR_CTRL, CTRL_INIT_VALUE);
+      write_word(ADDR_CTRL, 8'h00);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected0)
+        begin
+          $display("TC%01d first block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in first digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected0);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      // Final block
+      write_block(block1);
+      write_word(ADDR_CTRL, CTRL_NEXT_VALUE);
+      write_word(ADDR_CTRL, 8'h00);
+      wait_ready();
+      read_digest();
+      
+      if (digest_data == expected1)
+        begin
+          $display("TC%01d final block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in final digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected1);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      $display("*** TC%01d - Double block test done.", tc_ctr); 
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // double_block_test
+
+    
+  //----------------------------------------------------------------
+  // wb_sha256_test
+  //
+  // The main test functionality. 
+  //
+  // Test cases taken from:
+  // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
+  //----------------------------------------------------------------
+  initial
+    begin : wb_sha256_test
+      reg [511 : 0] tc0;
+      reg [255 : 0] res0;
+
+      reg [511 : 0] tc1_0;
+      reg [255 : 0] res1_0;
+      reg [511 : 0] tc1_1;
+      reg [255 : 0] res1_1;
+      
+      $display("   -- Testbench for wb_sha256 started --");
+
+      init_sim();
+      reset_dut();
+      check_name_version();
+      
+      // dump_dut_state();
+      // write_word(ADDR_BLOCK0, 32'hdeadbeef);
+      // dump_dut_state();
+      // read_word(ADDR_BLOCK0);
+      // dump_dut_state();
+
+      tc0 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+      res0 = 256'hBA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD;
+      single_block_test(tc0, res0);
+
+      tc1_0 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000;
+      res1_0 = 256'h85E655D6417A17953363376A624CDE5C76E09589CAC5F811CC4B32C1F20E533A;
+      tc1_1 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0;
+      res1_1 = 256'h248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1;
+      double_block_test(tc1_0, res1_0, tc1_1, res1_1);
+      
+      display_test_result();
+      
+      $display("   -- Testbench for wb_sha256 done. --");
+      $finish;
+    end // wb_sha256_test
+endmodule // tb_wb_sha256
+
+//======================================================================
+// EOF tb_wb_sha256.v
+//======================================================================
diff --git a/sha256/toolruns/Makefile b/sha256/toolruns/Makefile
new file mode 100755
index 0000000..4ac5f46
--- /dev/null
+++ b/sha256/toolruns/Makefile
@@ -0,0 +1,117 @@
+#===================================================================
+#
+# Makefile
+# --------
+# Makefile for building sha256 wmem, core top and wishbone
+# simulations.
+#
+#
+# Author: Joachim Strombergson
+# Copyright (c) 2014, SUNET
+# 
+# Redistribution and use in source and binary forms, with or 
+# without modification, are permitted provided that the following 
+# conditions are met: 
+# 
+# 1. Redistributions of source code must retain the above copyright 
+#    notice, this list of conditions and the following disclaimer. 
+# 
+# 2. Redistributions in binary form must reproduce the above copyright 
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution. 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#===================================================================
+
+WMEM_SRC=../src/rtl/sha256_w_mem.v
+WMEM_TB_SRC=../src/tb/tb_sha256_w_mem.v
+
+CORE_SRC=../src/rtl/sha256_core.v ../src/rtl/sha256_k_constants.v ../src/rtl/sha256_w_mem.v
+CORE_TB_SRC=../src/tb/tb_sha256_core.v
+
+TOP_SRC=../src/rtl/sha256.v $(CORE_SRC)
+TOP_TB_SRC=../src/tb/tb_sha256.v
+
+WB_SRC=../src/rtl/wb_sha256.v $(CORE_SRC)
+WB_TB_SRC=../src/tb/tb_wb_sha256.v
+
+CC=iverilog
+
+
+all: wb top core wmem
+
+
+wb:  $(WB_TB_SRC) $(WB_SRC)
+	$(CC) -o wb.sim $(WB_TB_SRC) $(WB_SRC)
+
+
+top: $(TOP_TB_SRC) $(TOP_SRC)
+	$(CC) -o top.sim $(TOP_TB_SRC) $(TOP_SRC)
+
+
+core: $(CORE_TB_SRC) $(CORE_SRC)
+	$(CC) -o core.sim $(CORE_SRC) $(CORE_TB_SRC)
+
+
+wmem: $(WMEM_SRC) $(WMEM_TB_SRC)
+	$(CC) -o wmem.sim $(WMEM_SRC) $(WMEM_TB_SRC)
+
+
+sim-wb: wb.sim
+	./wb.sim
+
+
+sim-top: top.sim
+	./top.sim
+
+
+sim-core: core.sim
+	./core.sim
+
+
+sim-wmem: wmem.sim
+	./wmem.sim
+
+
+debug:
+	@echo "No debug available."
+
+
+clean:
+	rm -f top.sim
+	rm -f core.sim
+	rm -f wmem.sim
+
+
+help:
+	@echo "Supported targets:"
+	@echo "------------------"
+	@echo "all:      Build all simulation targets."
+	@echo "wb:       Build the Wishbone simulation target."
+	@echo "top:      Build the top simulation target."
+	@echo "core:     Build the core simulation target."
+	@echo "wmem:     Build the wmem simulation target."
+	@echo "sim-wb:   Run top Wishbone simulation."
+	@echo "sim-top:  Run top level simulation."
+	@echo "sim-core: Run core level simulation."
+	@echo "sim-wmem: Run wmem level simulation."
+	@echo "debug:    Print the internal varibles."
+	@echo "clean:    Delete all built files."
+
+#===================================================================
+# EOF Makefile
+#===================================================================
+
diff --git a/sha512/LICENSE b/sha512/LICENSE
new file mode 100644
index 0000000..0fb159c
--- /dev/null
+++ b/sha512/LICENSE
@@ -0,0 +1,24 @@
+Author: Joachim Strömbergson
+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:
+
+* 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.
+
+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.
diff --git a/sha512/README.md b/sha512/README.md
new file mode 100644
index 0000000..d6f4d92
--- /dev/null
+++ b/sha512/README.md
@@ -0,0 +1,41 @@
+sha512
+======
+
+Verilog implementation of the SHA-512 hash function. This implementation
+complies with the functionality in NIST FIPS 180-4. The supports the
+SHA-512 variants SHA-512/224, SHA-512/256, SHA-384 and SHA-512.
+
+
+## Implementation details ##
+The core uses a sliding window with 16 64-bit registers for the W
+memory. The top level wrapper contains flag control registers for init
+and next that automatically resets. This means that the flags must be
+set for every block to be processed.
+
+
+## Status ##
+***(2014-04-05)***
+
+RTL for the core and top is completed Testbenches for core and top
+completed. All single block and dual block test cases works. Results
+after building the complete design for Altera Cyclone V GX:
+
+- 2919 ALMs
+- 3609 Registers
+- 77 MHz max clock frequency
+
+
+***(2014-03-24)***
+
+Core works for the SHA-512 mode case. Added top level wrapper and built
+the design for Altera Cyclone V GX:
+
+- 2923 ALMs
+- 3609 Registers
+- 80 MHz max clock frequency
+
+
+
+***(2014-02-23)***
+
+Initial version. Based on the SHA-256 core. Nothing really to see yet.
diff --git a/sha512/src/model/python/sha512.py b/sha512/src/model/python/sha512.py
new file mode 100755
index 0000000..844c9ef
--- /dev/null
+++ b/sha512/src/model/python/sha512.py
@@ -0,0 +1,345 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#=======================================================================
+#
+# sha512.py
+# ---------
+# Simple, pure Python model of the SHA-512 hash function. Used as a
+# reference for the HW implementation. The code follows the structure
+# of the HW implementation as much as possible.
+#
+#
+# Author: Joachim Strömbergson
+# 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, 
+# 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.
+#
+#=======================================================================
+
+#-------------------------------------------------------------------
+# Python module imports.
+#-------------------------------------------------------------------
+import sys
+
+
+#-------------------------------------------------------------------
+# Constants.
+#-------------------------------------------------------------------
+MAX_64BIT = 0xffffffffffffffff
+
+
+#-------------------------------------------------------------------
+# ChaCha()
+#-------------------------------------------------------------------
+class SHA512():
+    def __init__(self, mode = 'MODE_SHA_512', verbose = 0):
+        assert mode in ['MODE_SHA_512_224', 'MODE_SHA_512_256',
+                        'MODE_SHA_384', 'MODE_SHA_512']
+        self.mode = mode
+        self.verbose = verbose
+        self.mode 
+        self.NUM_ROUNDS = 80
+        self.H = [0] * 8
+        self.t1 = 0
+        self.t2 = 0
+        self.a = 0
+        self.b = 0
+        self.c = 0
+        self.d = 0
+        self.e = 0
+        self.f = 0
+        self.g = 0
+        self.h = 0
+        self.w = 0
+        self.W = [0] * 16
+        self.k = 0
+        self.K = [0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 
+                  0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
+                  0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
+                  0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+                  0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
+                  0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
+                  0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
+                  0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+                  0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
+                  0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
+                  0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
+                  0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+                  0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
+                  0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
+                  0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
+                  0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+                  0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
+                  0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
+                  0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
+                  0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+                  0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
+                  0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
+                  0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
+                  0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+                  0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
+                  0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
+                  0x5fcb6fab3ad6faec, 0x6c44198c4a475817]
+
+        
+    def init(self):
+        if self.mode == 'MODE_SHA_512_224':
+            self.H = [0x8c3d37c819544da2, 0x73e1996689dcd4d6,
+                      0x1dfab7ae32ff9c82, 0x679dd514582f9fcf,
+                      0x0f6d2b697bd44da8, 0x77e36f7304c48942,
+                      0x3f9d85a86a1d36c8, 0x1112e6ad91d692a1]
+
+        elif self.mode == 'MODE_SHA_512_256':
+            self.H = [0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 
+                      0x2393b86b6f53b151, 0x963877195940eabd, 
+                      0x96283ee2a88effe3, 0xbe5e1e2553863992, 
+                      0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2]
+                      
+        elif self.mode == 'MODE_SHA_384':
+            self.H = [0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
+                      0x9159015a3070dd17, 0x152fecd8f70e5939, 
+                      0x67332667ffc00b31, 0x8eb44a8768581511, 
+                      0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4]
+
+        elif self.mode == 'MODE_SHA_512':
+            self.H = [0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
+                      0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 
+                      0x510e527fade682d1, 0x9b05688c2b3e6c1f, 
+                      0x1f83d9abfb41bd6b, 0x5be0cd19137e2179]
+        
+
+    def next(self, block):
+        self._W_schedule(block)
+        self._copy_digest()
+        if self.verbose:
+            print("State after init:")
+            self._print_state(0)
+
+        for i in range(self.NUM_ROUNDS):
+            self._sha512_round(i)
+            if self.verbose:
+                self._print_state(i)
+
+        self._update_digest()
+
+
+    def get_digest(self):
+        if self.mode == 'MODE_SHA_512_224':
+            return self.H[0:3] # FIX THIS!
+
+        elif self.mode == 'MODE_SHA_512_256':
+            return self.H[0:4]
+
+        elif self.mode == 'MODE_SHA_384':
+            return self.H[0:6]
+
+        elif self.mode == 'MODE_SHA_512':
+            return self.H
+
+
+    def _copy_digest(self):
+        self.a = self.H[0] 
+        self.b = self.H[1] 
+        self.c = self.H[2] 
+        self.d = self.H[3] 
+        self.e = self.H[4] 
+        self.f = self.H[5] 
+        self.g = self.H[6] 
+        self.h = self.H[7]
+    
+    
+    def _update_digest(self):
+        self.H[0] = (self.H[0] + self.a) & MAX_64BIT
+        self.H[1] = (self.H[1] + self.b) & MAX_64BIT
+        self.H[2] = (self.H[2] + self.c) & MAX_64BIT
+        self.H[3] = (self.H[3] + self.d) & MAX_64BIT
+        self.H[4] = (self.H[4] + self.e) & MAX_64BIT
+        self.H[5] = (self.H[5] + self.f) & MAX_64BIT
+        self.H[6] = (self.H[6] + self.g) & MAX_64BIT
+        self.H[7] = (self.H[7] + self.h) & MAX_64BIT
+
+
+    def _print_state(self, round):
+        print("State at round 0x%02x:" % round)
+        print("t1 = 0x%016x, t2 = 0x%016x" % (self.t1, self.t2))
+        print("k  = 0x%016x, w  = 0x%016x" % (self.k,  self.w))
+        print("a  = 0x%016x, b  = 0x%016x" % (self.a,  self.b))
+        print("c  = 0x%016x, d  = 0x%016x" % (self.c,  self.d))
+        print("e  = 0x%016x, f  = 0x%016x" % (self.e,  self.f))
+        print("g  = 0x%016x, h  = 0x%016x" % (self.g,  self.h))
+        print("")
+
+
+    def _sha512_round(self, round):
+        self.k = self.K[round]
+        self.w = self._next_w(round)
+        self.t1 = self._T1(self.e, self.f, self.g, self.h, self.k, self.w)
+        self.t2 = self._T2(self.a, self.b, self.c)
+        self.h = self.g
+        self.g = self.f
+        self.f = self.e
+        self.e = (self.d + self.t1) & MAX_64BIT
+        self.d = self.c
+        self.c = self.b
+        self.b = self.a
+        self.a = (self.t1 + self.t2) & MAX_64BIT
+
+
+    def _next_w(self, round):
+        if (round < 16):
+            return self.W[round]
+
+        else:
+            tmp_w = (self._delta1(self.W[14]) +
+                     self.W[9] + 
+                     self._delta0(self.W[1]) +
+                     self.W[0]) & MAX_64BIT
+            for i in range(15):
+                self.W[i] = self.W[(i+1)]
+            self.W[15] = tmp_w
+            return tmp_w
+
+
+    def _W_schedule(self, block):
+        for i in range(16):
+            self.W[i] = block[i]
+
+
+    def _Ch(self, x, y, z):
+        return (x & y) ^ (~x & z)
+
+
+    def _Maj(self, x, y, z):
+        return (x & y) ^ (x & z) ^ (y & z)
+
+    def _sigma0(self, x):
+        return (self._rotr64(x, 28) ^ self._rotr64(x, 34) ^ self._rotr64(x, 39))
+
+
+    def _sigma1(self, x):
+        return (self._rotr64(x, 14) ^ self._rotr64(x, 18) ^ self._rotr64(x, 41))
+
+
+    def _delta0(self, x):
+        return (self._rotr64(x, 1) ^ self._rotr64(x, 8) ^ self._shr64(x, 7))
+
+
+    def _delta1(self, x):
+        return (self._rotr64(x, 19) ^ self._rotr64(x, 61) ^ self._shr64(x, 6))
+    
+
+    def _T1(self, e, f, g, h, k, w):
+        return (h + self._sigma1(e) + self._Ch(e, f, g) + k + w) & MAX_64BIT
+
+
+    def _T2(self, a, b, c):
+        return (self._sigma0(a) + self._Maj(a, b, c)) & MAX_64BIT
+
+
+    def _rotr64(self, n, r):
+        return ((n >> r) | (n << (64 - r))) & MAX_64BIT
+
+    
+    def _shr64(self, n, r):
+        return (n >> r)
+
+
+def compare_digests(digest, expected):
+    if (digest != expected):
+        print("Error:")
+        print("Got:")
+        print(digest)
+        print("Expected:")
+        print(expected)
+    else:
+        print("Test case ok.")
+        
+    
+#-------------------------------------------------------------------
+# main()
+#
+# If executed tests the ChaCha class using known test vectors.
+#-------------------------------------------------------------------
+def main():
+    print("Testing the SHA-512 Python model.")
+    print("---------------------------------")
+    print
+
+    # Single block message.
+    TC1_block = [0x6162638000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+                 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+                 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+                 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000018]
+
+    
+    my_sha512 = SHA512(mode = 'MODE_SHA_512', verbose=1);
+    TC1_expected = [0xDDAF35A193617ABA, 0xCC417349AE204131, 0x12E6FA4E89A97EA2, 0x0A9EEEE64B55D39A,
+                    0x2192992A274FC1A8, 0x36BA3C23A3FEEBBD, 0x454D4423643CE80E, 0x2A9AC94FA54CA49F]
+    my_sha512.init()
+    my_sha512.next(TC1_block)
+    my_digest = my_sha512.get_digest()
+    compare_digests(my_digest, TC1_expected)
+
+
+    my_sha512 = SHA512(mode = 'MODE_SHA_512_224', verbose=1);
+    TC2_expected = [0x4634270F707B6A54, 0xDAAE7530460842E2, 0x0E37ED265CEEE9A4, 0x3E8924AA00000000]
+    my_sha512.init()
+    my_sha512.next(TC1_block)
+    my_digest = my_sha512.get_digest()
+    compare_digests(my_digest, TC2_expected)
+
+
+    my_sha512 = SHA512(mode = 'MODE_SHA_512_256', verbose=1);
+    TC3_expected = [0x53048E2681941EF9, 0x9B2E29B76B4C7DAB, 0xE4C2D0C634FC6D46, 0xE0E2F13107E7AF23]
+    my_sha512.init()
+    my_sha512.next(TC1_block)
+    my_digest = my_sha512.get_digest()
+    compare_digests(my_digest, TC3_expected)
+
+
+    my_sha512 = SHA512(mode = 'MODE_SHA_384', verbose=1);
+    TC4_expected = [0xCB00753F45A35E8B, 0xB5A03D699AC65007, 0x272C32AB0EDED163, 0x1A8B605A43FF5BED,
+                    0x8086072BA1E7CC23, 0x58BAECA134C825A7]
+    my_sha512.init()
+    my_sha512.next(TC1_block)
+    my_digest = my_sha512.get_digest()
+    compare_digests(my_digest, TC4_expected)
+
+    
+
+#-------------------------------------------------------------------
+# __name__
+# Python thingy which allows the file to be run standalone as
+# well as parsed from within a Python interpreter.
+#-------------------------------------------------------------------
+if __name__=="__main__": 
+    # Run the main function.
+    sys.exit(main())
+
+#=======================================================================
+# EOF sha512.py
+#=======================================================================
diff --git a/sha512/src/rtl/sha512.v b/sha512/src/rtl/sha512.v
new file mode 100644
index 0000000..8826782
--- /dev/null
+++ b/sha512/src/rtl/sha512.v
@@ -0,0 +1,241 @@
+//======================================================================
+//
+// sha512.v
+// ------
+// Top level wrapper for the SHA-512 hash function providing
+// a simple memory like interface with 32 bit data access.
+//
+// Authors: Joachim Strömbergson, Paul Selkirk
+// Copyright (c) 2014-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 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,
+            output wire [31 : 0] read_data
+            );
+
+   //----------------------------------------------------------------
+   // 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 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_BLOCK           = 8'h10;
+
+   parameter ADDR_DIGEST          = 8'h40;
+
+   parameter CORE_NAME0           = 32'h73686132; // "sha2"
+   parameter CORE_NAME1           = 32'h2d353132; // "-512"
+   parameter CORE_VERSION         = 32'h302e3830; // "0.80"
+
+   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 DEFAULT_WORK_FACTOR_NUM = 32'h000f0000;
+
+   parameter BLOCK_BITS           = 1024;
+   parameter DIGEST_BITS          = 512;
+   parameter BLOCK_WORDS          = BLOCK_BITS / 32;
+   parameter DIGEST_WORDS         = DIGEST_BITS / 32;
+
+   //----------------------------------------------------------------
+   // Registers.
+   //----------------------------------------------------------------
+   reg [0 : BLOCK_BITS - 1]    block_reg;
+   reg [0 : DIGEST_BITS - 1]   digest_reg;
+   reg                         init_reg;
+   reg                         next_reg;
+   reg [1 : 0]                 mode_reg;
+   reg                         work_factor_reg;
+   reg [31 : 0]                work_factor_num_reg;
+
+   reg [31 : 0]                tmp_read_data;
+   reg [31 : 0]                tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                        core_init;
+   wire                        core_next;
+   wire                        core_ready;
+   wire [1 : 0]                core_mode;
+   wire                        core_work_factor;
+   wire [31 : 0]               core_work_factor_num;
+   wire [0 : BLOCK_BITS - 1]   core_block;
+   wire [0 : DIGEST_BITS - 1]  core_digest;
+   wire                        core_digest_valid;
+
+   wire [31 : 0]               core_name0   = CORE_NAME0;
+   wire [31 : 0]               core_name1   = CORE_NAME1;
+   wire [31 : 0]               core_version = CORE_VERSION;
+   wire [31 : 0]               core_ctrl;
+   wire [31 : 0]               core_status;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init   = init_reg;
+   assign core_next   = next_reg;
+   assign core_mode = mode_reg;
+   assign core_work_factor = work_factor_reg;
+   assign core_work_factor_num = work_factor_num_reg;
+   assign core_ctrl   = {24'h000000, work_factor_reg, 3'b000,
+                         mode_reg, next_reg, init_reg};
+   assign core_status = { 30'b0, core_digest_valid, core_ready };
+   assign core_block  = block_reg;
+
+   assign read_data   = tmp_read_data_reg;
+
+   //----------------------------------------------------------------
+   // 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)
+                  );
+
+
+   //----------------------------------------------------------------
+   // latch in digest when ready
+   //----------------------------------------------------------------
+   always @(posedge clk)
+      begin
+         if (core_digest_valid)
+           digest_reg <= core_digest;
+      end
+
+   //----------------------------------------------------------------
+   // storage registers for mapping memory to core interface
+   //----------------------------------------------------------------
+   always @(posedge clk)
+     begin
+        init_reg <= 0;
+        next_reg <= 0;
+        mode_reg            <= MODE_SHA_512;
+        work_factor_reg     <= 0;
+        work_factor_num_reg <= DEFAULT_WORK_FACTOR_NUM;
+
+        if (cs && we)
+          begin
+             // write operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               block_reg[((address - ADDR_BLOCK) * 32)+:32] <= write_data;
+             else if (address == ADDR_CTRL)
+               begin
+                  init_reg <= write_data[CTRL_INIT_BIT];
+                  next_reg <= write_data[CTRL_NEXT_BIT];
+                  mode_reg        <= write_data[CTRL_MODE_HIGH_BIT : CTRL_MODE_LOW_BIT];
+                  work_factor_reg <= write_data[CTRL_WORK_FACTOR_BIT];
+               end
+             else if (address == ADDR_WORK_FACTOR_NUM)
+               begin
+                  work_factor_num_reg <= write_data;
+               end
+          end
+     end
+
+   always @*
+     begin
+        tmp_read_data = 32'h00000000;
+
+        if (cs && !we)
+          begin
+             // read operations
+             if ((address >= ADDR_BLOCK) &&
+                 (address < ADDR_BLOCK + BLOCK_WORDS))
+               tmp_read_data = block_reg[((address - ADDR_BLOCK) * 32)+:32];
+             else if ((address >= ADDR_DIGEST) &&
+                      (address < ADDR_DIGEST + DIGEST_WORDS))
+               tmp_read_data = digest_reg[((address - ADDR_DIGEST) * 32)+:32];
+             else
+               case (address)
+                 ADDR_NAME0:
+                   tmp_read_data = core_name0;
+                 ADDR_NAME1:
+                   tmp_read_data = core_name1;
+                 ADDR_VERSION:
+                   tmp_read_data = core_version;
+                 ADDR_CTRL:
+                   tmp_read_data = core_ctrl;
+                 ADDR_STATUS:
+                   tmp_read_data = core_status;
+                 ADDR_WORK_FACTOR_NUM:
+                   tmp_read_data = work_factor_num_reg;
+               endcase
+          end
+     end
+
+   always @(posedge clk)
+     begin
+        tmp_read_data_reg <= tmp_read_data;
+     end
+
+endmodule // sha512
diff --git a/sha512/src/rtl/sha512_core.v b/sha512/src/rtl/sha512_core.v
new file mode 100644
index 0000000..12742a8
--- /dev/null
+++ b/sha512/src/rtl/sha512_core.v
@@ -0,0 +1,607 @@
+//======================================================================
+//
+// sha512_core.v
+// -------------
+// Verilog 2001 implementation of the SHA-512 hash function.
+// This is the internal core with wide interfaces.
+//
+//
+// 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,
+// 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 sha512_core(
+                   input wire            clk,
+                   input wire            reset_n,
+
+                   input wire            init,
+                   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,
+                   output wire [511 : 0] digest,
+                   output wire           digest_valid
+                  );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter SHA512_ROUNDS = 79;
+
+  parameter CTRL_IDLE   = 0;
+  parameter CTRL_ROUNDS = 1;
+  parameter CTRL_DONE   = 2;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [63 : 0] a_reg;
+  reg [63 : 0] a_new;
+  reg [63 : 0] b_reg;
+  reg [63 : 0] b_new;
+  reg [63 : 0] c_reg;
+  reg [63 : 0] c_new;
+  reg [63 : 0] d_reg;
+  reg [63 : 0] d_new;
+  reg [63 : 0] e_reg;
+  reg [63 : 0] e_new;
+  reg [63 : 0] f_reg;
+  reg [63 : 0] f_new;
+  reg [63 : 0] g_reg;
+  reg [63 : 0] g_new;
+  reg [63 : 0] h_reg;
+  reg [63 : 0] h_new;
+  reg          a_h_we;
+
+  reg [63 : 0] H0_reg;
+  reg [63 : 0] H0_new;
+  reg [63 : 0] H1_reg;
+  reg [63 : 0] H1_new;
+  reg [63 : 0] H2_reg;
+  reg [63 : 0] H2_new;
+  reg [63 : 0] H3_reg;
+  reg [63 : 0] H3_new;
+  reg [63 : 0] H4_reg;
+  reg [63 : 0] H4_new;
+  reg [63 : 0] H5_reg;
+  reg [63 : 0] H5_new;
+  reg [63 : 0] H6_reg;
+  reg [63 : 0] H6_new;
+  reg [63 : 0] H7_reg;
+  reg [63 : 0] H7_new;
+  reg          H_we;
+
+  reg [6 : 0] t_ctr_reg;
+  reg [6 : 0] t_ctr_new;
+  reg         t_ctr_we;
+  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;
+
+  reg [1 : 0] sha512_ctrl_reg;
+  reg [1 : 0] sha512_ctrl_new;
+  reg         sha512_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg digest_init;
+  reg digest_update;
+
+  reg state_init;
+  reg state_update;
+
+  reg first_block;
+
+  reg ready_flag;
+
+  reg [63 : 0] t1;
+  reg [63 : 0] t2;
+
+  wire [63 : 0] k_data;
+
+  reg           w_init;
+  reg           w_next;
+  wire [63 : 0] w_data;
+
+  wire [63 : 0] H0_0;
+  wire [63 : 0] H0_1;
+  wire [63 : 0] H0_2;
+  wire [63 : 0] H0_3;
+  wire [63 : 0] H0_4;
+  wire [63 : 0] H0_5;
+  wire [63 : 0] H0_6;
+  wire [63 : 0] H0_7;
+
+
+  //----------------------------------------------------------------
+  // Module instantiantions.
+  //----------------------------------------------------------------
+  sha512_k_constants k_constants_inst(
+                                      .addr(t_ctr_reg),
+                                      .K(k_data)
+                                     );
+
+
+  sha512_h_constants h_constants_inst(
+                                      .mode(mode),
+
+                                      .H0(H0_0),
+                                      .H1(H0_1),
+                                      .H2(H0_2),
+                                      .H3(H0_3),
+                                      .H4(H0_4),
+                                      .H5(H0_5),
+                                      .H6(H0_6),
+                                      .H7(H0_7)
+                                     );
+
+
+  sha512_w_mem w_mem_inst(
+                          .clk(clk),
+                          .reset_n(reset_n),
+
+                          .block(block),
+
+                          .init(w_init),
+                          .next(w_next),
+                          .w(w_data)
+                         );
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign ready = ready_flag;
+
+  assign digest = {H0_reg, H1_reg, H2_reg, H3_reg,
+                   H4_reg, H5_reg, H6_reg, H7_reg};
+
+  assign digest_valid = digest_valid_reg;
+
+
+  //----------------------------------------------------------------
+  // 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
+          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
+
+          if (a_h_we)
+            begin
+              a_reg <= a_new;
+              b_reg <= b_new;
+              c_reg <= c_new;
+              d_reg <= d_new;
+              e_reg <= e_new;
+              f_reg <= f_new;
+              g_reg <= g_new;
+              h_reg <= h_new;
+            end
+
+          if (H_we)
+            begin
+              H0_reg <= H0_new;
+              H1_reg <= H1_new;
+              H2_reg <= H2_new;
+              H3_reg <= H3_new;
+              H4_reg <= H4_new;
+              H5_reg <= H5_new;
+              H6_reg <= H6_new;
+              H7_reg <= H7_new;
+            end
+
+          if (t_ctr_we)
+            begin
+              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;
+            end
+
+          if (sha512_ctrl_we)
+            begin
+              sha512_ctrl_reg <= sha512_ctrl_new;
+            end
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // digest_logic
+  //
+  // The logic needed to init as well as update the digest.
+  //----------------------------------------------------------------
+  always @*
+    begin : digest_logic
+      H0_new = 64'h00000000;
+      H1_new = 64'h00000000;
+      H2_new = 64'h00000000;
+      H3_new = 64'h00000000;
+      H4_new = 64'h00000000;
+      H5_new = 64'h00000000;
+      H6_new = 64'h00000000;
+      H7_new = 64'h00000000;
+      H_we = 0;
+
+      if (digest_init)
+        begin
+          H0_new = H0_0;
+          H1_new = H0_1;
+          H2_new = H0_2;
+          H3_new = H0_3;
+          H4_new = H0_4;
+          H5_new = H0_5;
+          H6_new = H0_6;
+          H7_new = H0_7;
+          H_we = 1;
+        end
+
+      if (digest_update)
+        begin
+          H0_new = H0_reg + a_reg;
+          H1_new = H1_reg + b_reg;
+          H2_new = H2_reg + c_reg;
+          H3_new = H3_reg + d_reg;
+          H4_new = H4_reg + e_reg;
+          H5_new = H5_reg + f_reg;
+          H6_new = H6_reg + g_reg;
+          H7_new = H7_reg + h_reg;
+          H_we = 1;
+        end
+    end // digest_logic
+
+
+  //----------------------------------------------------------------
+  // t1_logic
+  //
+  // The logic for the T1 function.
+  //----------------------------------------------------------------
+  always @*
+    begin : t1_logic
+      reg [63 : 0] sum1;
+      reg [63 : 0] ch;
+
+      sum1 = {e_reg[13 : 0], e_reg[63 : 14]} ^
+             {e_reg[17 : 0], e_reg[63 : 18]} ^
+             {e_reg[40 : 0], e_reg[63 : 41]};
+
+      ch = (e_reg & f_reg) ^ ((~e_reg) & g_reg);
+
+      t1 = h_reg + sum1 + ch + k_data + w_data;
+    end // t1_logic
+
+
+  //----------------------------------------------------------------
+  // t2_logic
+  //
+  // The logic for the T2 function
+  //----------------------------------------------------------------
+  always @*
+    begin : t2_logic
+      reg [63 : 0] sum0;
+      reg [63 : 0] maj;
+
+      sum0 = {a_reg[27 : 0], a_reg[63 : 28]} ^
+             {a_reg[33 : 0], a_reg[63 : 34]} ^
+             {a_reg[38 : 0], a_reg[63 : 39]};
+
+      maj = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
+
+      t2 = sum0 + maj;
+    end // t2_logic
+
+
+  //----------------------------------------------------------------
+  // state_logic
+  //
+  // The logic needed to init as well as update the state during
+  // round processing.
+  //----------------------------------------------------------------
+  always @*
+    begin : state_logic
+      a_new  = 64'h00000000;
+      b_new  = 64'h00000000;
+      c_new  = 64'h00000000;
+      d_new  = 64'h00000000;
+      e_new  = 64'h00000000;
+      f_new  = 64'h00000000;
+      g_new  = 64'h00000000;
+      h_new  = 64'h00000000;
+      a_h_we = 0;
+
+      if (state_init)
+        begin
+          if (first_block)
+            begin
+              a_new  = H0_0;
+              b_new  = H0_1;
+              c_new  = H0_2;
+              d_new  = H0_3;
+              e_new  = H0_4;
+              f_new  = H0_5;
+              g_new  = H0_6;
+              h_new  = H0_7;
+              a_h_we = 1;
+            end
+          else
+            begin
+              a_new  = H0_reg;
+              b_new  = H1_reg;
+              c_new  = H2_reg;
+              d_new  = H3_reg;
+              e_new  = H4_reg;
+              f_new  = H5_reg;
+              g_new  = H6_reg;
+              h_new  = H7_reg;
+              a_h_we = 1;
+            end
+        end
+
+      if (state_update)
+        begin
+          a_new  = t1 + t2;
+          b_new  = a_reg;
+          c_new  = b_reg;
+          d_new  = c_reg;
+          e_new  = d_reg + t1;
+          f_new  = e_reg;
+          g_new  = f_reg;
+          h_new  = g_reg;
+          a_h_we = 1;
+        end
+    end // state_logic
+
+
+  //----------------------------------------------------------------
+  // t_ctr
+  //
+  // Update logic for the round counter, a monotonically
+  // increasing counter with reset.
+  //----------------------------------------------------------------
+  always @*
+    begin : t_ctr
+      t_ctr_new = 7'h00;
+      t_ctr_we  = 0;
+
+      if (t_ctr_rst)
+        begin
+          t_ctr_new = 7'h00;
+          t_ctr_we  = 1;
+        end
+
+      if (t_ctr_inc)
+        begin
+          t_ctr_new = t_ctr_reg + 1'b1;
+          t_ctr_we  = 1;
+        end
+    end // t_ctr
+
+
+  //----------------------------------------------------------------
+  // 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;
+
+      state_init          = 0;
+      state_update        = 0;
+
+      first_block         = 0;
+      ready_flag          = 0;
+
+      w_init              = 0;
+      w_next              = 0;
+
+      t_ctr_inc           = 0;
+      t_ctr_rst           = 0;
+
+      digest_valid_new    = 0;
+      digest_valid_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)
+        CTRL_IDLE:
+          begin
+            ready_flag = 1;
+
+            if (init)
+              begin
+                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
+                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
+
+
+        CTRL_ROUNDS:
+          begin
+            w_next       = 1;
+            state_update = 1;
+            t_ctr_inc    = 1;
+
+            if (t_ctr_reg == SHA512_ROUNDS)
+              begin
+                work_factor_ctr_inc = 1;
+                sha512_ctrl_new     = CTRL_DONE;
+                sha512_ctrl_we      = 1;
+              end
+          end
+
+
+        CTRL_DONE:
+          begin
+            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
+
+endmodule // sha512_core
+
+//======================================================================
+// EOF sha512_core.v
+//======================================================================
diff --git a/sha512/src/rtl/sha512_h_constants.v b/sha512/src/rtl/sha512_h_constants.v
new file mode 100644
index 0000000..3a38712
--- /dev/null
+++ b/sha512/src/rtl/sha512_h_constants.v
@@ -0,0 +1,143 @@
+//======================================================================
+//
+// sha512_h_constants.v
+// ---------------------
+// The H initial constants for the different modes in SHA-512.
+//
+//
+// 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, 
+// 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 sha512_h_constants(
+                          input wire  [1 : 0]  mode,
+
+                          output wire [63 : 0] H0,
+                          output wire [63 : 0] H1,
+                          output wire [63 : 0] H2,
+                          output wire [63 : 0] H3,
+                          output wire [63 : 0] H4,
+                          output wire [63 : 0] H5,
+                          output wire [63 : 0] H6,
+                          output wire [63 : 0] H7
+                         );
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [63 : 0] tmp_H0;
+  reg [63 : 0] tmp_H1;
+  reg [63 : 0] tmp_H2;
+  reg [63 : 0] tmp_H3;
+  reg [63 : 0] tmp_H4;
+  reg [63 : 0] tmp_H5;
+  reg [63 : 0] tmp_H6;
+  reg [63 : 0] tmp_H7;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign H0 = tmp_H0;
+  assign H1 = tmp_H1;
+  assign H2 = tmp_H2;
+  assign H3 = tmp_H3;
+  assign H4 = tmp_H4;
+  assign H5 = tmp_H5;
+  assign H6 = tmp_H6;
+  assign H7 = tmp_H7;
+
+  
+  //----------------------------------------------------------------
+  // mode_mux
+  //
+  // Based on the given mode, the correct H constants are selected.
+  //----------------------------------------------------------------
+  always @*
+    begin : mode_mux
+      case(mode)
+        0:
+          begin
+            // SHA-512/224
+            tmp_H0 = 64'h8c3d37c819544da2;
+            tmp_H1 = 64'h73e1996689dcd4d6;
+            tmp_H2 = 64'h1dfab7ae32ff9c82;
+            tmp_H3 = 64'h679dd514582f9fcf;
+            tmp_H4 = 64'h0f6d2b697bd44da8;
+            tmp_H5 = 64'h77e36f7304c48942;
+            tmp_H6 = 64'h3f9d85a86a1d36c8;
+            tmp_H7 = 64'h1112e6ad91d692a1;
+          end
+
+        1:
+          begin
+            // SHA-512/256
+            tmp_H0 = 64'h22312194fc2bf72c; 
+            tmp_H1 = 64'h9f555fa3c84c64c2; 
+            tmp_H2 = 64'h2393b86b6f53b151; 
+            tmp_H3 = 64'h963877195940eabd; 
+            tmp_H4 = 64'h96283ee2a88effe3; 
+            tmp_H5 = 64'hbe5e1e2553863992; 
+            tmp_H6 = 64'h2b0199fc2c85b8aa; 
+            tmp_H7 = 64'h0eb72ddc81c52ca2;
+          end
+        
+        2:
+          begin
+            // SHA-384
+            tmp_H0 = 64'hcbbb9d5dc1059ed8;
+            tmp_H1 = 64'h629a292a367cd507;
+            tmp_H2 = 64'h9159015a3070dd17; 
+            tmp_H3 = 64'h152fecd8f70e5939; 
+            tmp_H4 = 64'h67332667ffc00b31; 
+            tmp_H5 = 64'h8eb44a8768581511; 
+            tmp_H6 = 64'hdb0c2e0d64f98fa7; 
+            tmp_H7 = 64'h47b5481dbefa4fa4;
+          end
+        
+        3:
+          begin
+            // SHA-512
+            tmp_H0 = 64'h6a09e667f3bcc908;
+            tmp_H1 = 64'hbb67ae8584caa73b;
+            tmp_H2 = 64'h3c6ef372fe94f82b; 
+            tmp_H3 = 64'ha54ff53a5f1d36f1; 
+            tmp_H4 = 64'h510e527fade682d1; 
+            tmp_H5 = 64'h9b05688c2b3e6c1f; 
+            tmp_H6 = 64'h1f83d9abfb41bd6b; 
+            tmp_H7 = 64'h5be0cd19137e2179;  
+          end
+      endcase // case (addr)
+    end // block: mode_mux
+endmodule // sha512_h_constants
+
+//======================================================================
+// sha512_h_constants.v
+//======================================================================
diff --git a/sha512/src/rtl/sha512_k_constants.v b/sha512/src/rtl/sha512_k_constants.v
new file mode 100644
index 0000000..61cfb6d
--- /dev/null
+++ b/sha512/src/rtl/sha512_k_constants.v
@@ -0,0 +1,472 @@
+//======================================================================
+//
+// sha512_k_constants.v
+// --------------------
+// The table K with constants in the SHA-512 hash function.
+//
+//
+// 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, 
+// 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 sha512_k_constants(
+                          input wire  [6 : 0]  addr,
+                          output wire [63 : 0] K
+                         );
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [63 : 0] tmp_K;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign K = tmp_K;
+  
+  
+  //----------------------------------------------------------------
+  // addr_mux
+  //----------------------------------------------------------------
+  always @*
+    begin : addr_mux
+      case(addr)
+        0:
+          begin
+            tmp_K = 64'h428a2f98d728ae22;
+          end
+        
+        1:
+          begin
+            tmp_K = 64'h7137449123ef65cd;
+          end
+
+        2:
+          begin
+            tmp_K = 64'hb5c0fbcfec4d3b2f;
+          end
+
+        3:
+          begin
+            tmp_K = 64'he9b5dba58189dbbc;
+          end
+
+        4:
+          begin
+            tmp_K = 64'h3956c25bf348b538;
+          end
+
+        5:
+          begin
+            tmp_K = 64'h59f111f1b605d019;
+          end
+
+        6:
+          begin
+            tmp_K = 64'h923f82a4af194f9b;
+          end
+
+        7:
+          begin
+            tmp_K = 64'hab1c5ed5da6d8118;
+          end
+
+        8:
+          begin
+            tmp_K = 64'hd807aa98a3030242;
+          end
+
+        9:
+          begin
+            tmp_K = 64'h12835b0145706fbe;
+          end
+
+        10:
+          begin
+            tmp_K = 64'h243185be4ee4b28c;
+          end
+
+        11:
+          begin
+            tmp_K = 64'h550c7dc3d5ffb4e2;
+          end
+
+        12:
+          begin
+            tmp_K = 64'h72be5d74f27b896f;
+          end
+
+        13:
+          begin
+            tmp_K = 64'h80deb1fe3b1696b1;
+          end
+
+        14:
+          begin
+            tmp_K = 64'h9bdc06a725c71235;
+          end
+        
+        15:
+          begin
+            tmp_K = 64'hc19bf174cf692694;
+          end
+        
+        16:
+          begin
+            tmp_K = 64'he49b69c19ef14ad2;
+          end
+
+        17:
+          begin
+            tmp_K = 64'hefbe4786384f25e3;
+          end
+
+        18:
+          begin
+            tmp_K = 64'h0fc19dc68b8cd5b5;
+          end
+        
+        19:
+          begin
+            tmp_K = 64'h240ca1cc77ac9c65;
+          end
+        
+        20:
+          begin
+            tmp_K = 64'h2de92c6f592b0275;
+          end
+
+        21:
+          begin
+            tmp_K = 64'h4a7484aa6ea6e483;
+          end
+
+        22:
+          begin
+            tmp_K = 64'h5cb0a9dcbd41fbd4;
+          end
+
+        23:
+          begin
+            tmp_K = 64'h76f988da831153b5;
+          end
+
+        24:
+          begin
+            tmp_K = 64'h983e5152ee66dfab;
+          end
+        
+        25:
+          begin
+            tmp_K = 64'ha831c66d2db43210;
+          end
+
+        26:
+          begin
+            tmp_K = 64'hb00327c898fb213f;
+          end
+        
+        27:
+          begin
+            tmp_K = 64'hbf597fc7beef0ee4;
+          end
+
+        28:
+          begin
+            tmp_K = 64'hc6e00bf33da88fc2;
+          end
+
+        29:
+          begin
+            tmp_K = 64'hd5a79147930aa725;
+          end
+
+        30:
+          begin
+            tmp_K = 64'h06ca6351e003826f;
+          end
+
+        31:
+          begin
+            tmp_K = 64'h142929670a0e6e70;
+          end
+
+        32:
+          begin
+            tmp_K = 64'h27b70a8546d22ffc;
+          end
+
+        33:
+          begin
+            tmp_K = 64'h2e1b21385c26c926;
+          end
+
+        34:
+          begin
+            tmp_K = 64'h4d2c6dfc5ac42aed;
+          end
+
+        35:
+          begin
+            tmp_K = 64'h53380d139d95b3df;
+          end
+
+        36:
+          begin
+            tmp_K = 64'h650a73548baf63de;
+          end
+
+        37:
+          begin
+            tmp_K = 64'h766a0abb3c77b2a8;
+          end
+
+        38:
+          begin
+            tmp_K = 64'h81c2c92e47edaee6;
+          end
+
+        39:
+          begin
+            tmp_K = 64'h92722c851482353b;
+          end
+
+        40:
+          begin
+            tmp_K = 64'ha2bfe8a14cf10364;
+          end
+
+        41:
+          begin
+            tmp_K = 64'ha81a664bbc423001;
+          end
+
+        42:
+          begin
+            tmp_K = 64'hc24b8b70d0f89791;
+          end
+        
+        43:
+          begin
+            tmp_K = 64'hc76c51a30654be30;
+          end
+        
+        44:
+          begin
+            tmp_K = 64'hd192e819d6ef5218;
+          end
+
+        45:
+          begin
+            tmp_K = 64'hd69906245565a910;
+          end
+        
+        46:
+          begin
+            tmp_K = 64'hf40e35855771202a;
+          end
+        
+        47:
+          begin
+            tmp_K = 64'h106aa07032bbd1b8;
+          end
+        
+        48:
+          begin
+            tmp_K = 64'h19a4c116b8d2d0c8;
+          end
+        
+        49:
+          begin
+            tmp_K = 64'h1e376c085141ab53;
+          end
+
+        50:
+          begin
+            tmp_K = 64'h2748774cdf8eeb99;
+          end
+
+        51:
+          begin
+            tmp_K = 64'h34b0bcb5e19b48a8;
+          end
+
+        52:
+          begin
+            tmp_K = 64'h391c0cb3c5c95a63;
+          end
+
+        53:
+          begin
+            tmp_K = 64'h4ed8aa4ae3418acb;
+          end
+
+        54:
+          begin
+            tmp_K = 64'h5b9cca4f7763e373;
+          end
+
+        55:
+          begin
+            tmp_K = 64'h682e6ff3d6b2b8a3;
+          end
+
+        56:
+          begin
+            tmp_K = 64'h748f82ee5defb2fc;
+          end
+        
+        57:
+          begin
+            tmp_K = 64'h78a5636f43172f60;
+          end
+        
+        58:
+          begin
+            tmp_K = 64'h84c87814a1f0ab72;
+          end
+        
+        59:
+          begin
+            tmp_K = 64'h8cc702081a6439ec;
+          end
+
+        60:
+          begin
+            tmp_K = 64'h90befffa23631e28;
+          end
+
+        61:
+          begin
+            tmp_K = 64'ha4506cebde82bde9;
+          end
+
+        62:
+          begin
+            tmp_K = 64'hbef9a3f7b2c67915;
+          end
+
+        63:
+          begin
+            tmp_K = 64'hc67178f2e372532b;
+          end
+
+        64:
+          begin
+            tmp_K = 64'hca273eceea26619c;
+          end
+
+        65:
+          begin
+            tmp_K = 64'hd186b8c721c0c207;
+          end
+
+        66:
+          begin
+            tmp_K = 64'heada7dd6cde0eb1e;
+          end
+
+        67:
+          begin
+            tmp_K = 64'hf57d4f7fee6ed178;
+          end
+
+        68:
+          begin
+            tmp_K = 64'h06f067aa72176fba;
+          end
+
+        69:
+          begin
+            tmp_K = 64'h0a637dc5a2c898a6;
+          end
+
+        70:
+          begin
+            tmp_K = 64'h113f9804bef90dae;
+          end
+
+        71:
+          begin
+            tmp_K = 64'h1b710b35131c471b;
+          end
+
+        72:
+          begin
+            tmp_K = 64'h28db77f523047d84;
+          end
+
+        73:
+          begin
+            tmp_K = 64'h32caab7b40c72493;
+          end
+
+        74:
+          begin
+            tmp_K = 64'h3c9ebe0a15c9bebc;
+          end
+
+        75:
+          begin
+            tmp_K = 64'h431d67c49c100d4c;
+          end
+        
+        76:
+          begin
+            tmp_K = 64'h4cc5d4becb3e42b6;
+          end
+
+        77:
+          begin
+            tmp_K = 64'h597f299cfc657e2a;
+          end
+
+        78:
+          begin
+            tmp_K = 64'h5fcb6fab3ad6faec;
+          end
+        
+        79:
+          begin
+            tmp_K = 64'h6c44198c4a475817;
+          end
+
+        default:
+          begin
+            tmp_K = 64'h0000000000000000;
+          end
+      endcase // case (addr)
+    end // block: addr_mux
+endmodule // sha512_k_constants
+
+//======================================================================
+// sha512_k_constants.v
+//======================================================================
diff --git a/sha512/src/rtl/sha512_w_mem.v b/sha512/src/rtl/sha512_w_mem.v
new file mode 100644
index 0000000..824316d
--- /dev/null
+++ b/sha512/src/rtl/sha512_w_mem.v
@@ -0,0 +1,346 @@
+//======================================================================
+//
+// sha512_w_mem_regs.v
+// -------------------
+// The W memory for the SHA-512 core. This version uses 16
+// 32-bit registers as a sliding window to generate the 64 words.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014 Secworks Sweden AB
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in
+//    the documentation and/or other materials provided with the
+//    distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha512_w_mem(
+                    input wire            clk,
+                    input wire            reset_n,
+
+                    input wire [1023 : 0] block,
+
+                    input wire            init,
+                    input wire            next,
+                    output wire [63 : 0]  w
+                   );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter CTRL_IDLE   = 1'b0;
+  parameter CTRL_UPDATE = 1'b1;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg [63 : 0] w_mem [0 : 15];
+  reg [63 : 0] w_mem00_new;
+  reg [63 : 0] w_mem01_new;
+  reg [63 : 0] w_mem02_new;
+  reg [63 : 0] w_mem03_new;
+  reg [63 : 0] w_mem04_new;
+  reg [63 : 0] w_mem05_new;
+  reg [63 : 0] w_mem06_new;
+  reg [63 : 0] w_mem07_new;
+  reg [63 : 0] w_mem08_new;
+  reg [63 : 0] w_mem09_new;
+  reg [63 : 0] w_mem10_new;
+  reg [63 : 0] w_mem11_new;
+  reg [63 : 0] w_mem12_new;
+  reg [63 : 0] w_mem13_new;
+  reg [63 : 0] w_mem14_new;
+  reg [63 : 0] w_mem15_new;
+  reg          w_mem_we;
+
+  reg [6 : 0] w_ctr_reg;
+  reg [6 : 0] w_ctr_new;
+  reg         w_ctr_we;
+  reg         w_ctr_inc;
+  reg         w_ctr_rst;
+
+  reg         sha512_w_mem_ctrl_reg;
+  reg         sha512_w_mem_ctrl_new;
+  reg         sha512_w_mem_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  reg [63 : 0] w_tmp;
+  reg [63 : 0] w_new;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign w = w_tmp;
+
+
+  //----------------------------------------------------------------
+  // 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
+          w_mem[00]             <= 64'h0000000000000000;
+          w_mem[01]             <= 64'h0000000000000000;
+          w_mem[02]             <= 64'h0000000000000000;
+          w_mem[03]             <= 64'h0000000000000000;
+          w_mem[04]             <= 64'h0000000000000000;
+          w_mem[05]             <= 64'h0000000000000000;
+          w_mem[06]             <= 64'h0000000000000000;
+          w_mem[07]             <= 64'h0000000000000000;
+          w_mem[08]             <= 64'h0000000000000000;
+          w_mem[09]             <= 64'h0000000000000000;
+          w_mem[10]             <= 64'h0000000000000000;
+          w_mem[11]             <= 64'h0000000000000000;
+          w_mem[12]             <= 64'h0000000000000000;
+          w_mem[13]             <= 64'h0000000000000000;
+          w_mem[14]             <= 64'h0000000000000000;
+          w_mem[15]             <= 64'h0000000000000000;
+          w_ctr_reg             <= 7'h00;
+          sha512_w_mem_ctrl_reg <= CTRL_IDLE;
+        end
+      else
+        begin
+          if (w_mem_we)
+            begin
+              w_mem[00] <= w_mem00_new;
+              w_mem[01] <= w_mem01_new;
+              w_mem[02] <= w_mem02_new;
+              w_mem[03] <= w_mem03_new;
+              w_mem[04] <= w_mem04_new;
+              w_mem[05] <= w_mem05_new;
+              w_mem[06] <= w_mem06_new;
+              w_mem[07] <= w_mem07_new;
+              w_mem[08] <= w_mem08_new;
+              w_mem[09] <= w_mem09_new;
+              w_mem[10] <= w_mem10_new;
+              w_mem[11] <= w_mem11_new;
+              w_mem[12] <= w_mem12_new;
+              w_mem[13] <= w_mem13_new;
+              w_mem[14] <= w_mem14_new;
+              w_mem[15] <= w_mem15_new;
+            end
+
+          if (w_ctr_we)
+            begin
+              w_ctr_reg <= w_ctr_new;
+            end
+
+          if (sha512_w_mem_ctrl_we)
+            begin
+              sha512_w_mem_ctrl_reg <= sha512_w_mem_ctrl_new;
+            end
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // select_w
+  //
+  // Mux for the external read operation. This is where we exract
+  // the W variable.
+  //----------------------------------------------------------------
+  always @*
+    begin : select_w
+      if (w_ctr_reg < 16)
+        begin
+          w_tmp = w_mem[w_ctr_reg[3 : 0]];
+        end
+      else
+        begin
+          w_tmp = w_new;
+        end
+    end // select_w
+
+
+  //----------------------------------------------------------------
+  // w_new_logic
+  //
+  // Logic that calculates the next value to be inserted into
+  // the sliding window of the memory.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_mem_update_logic
+      reg [63 : 0] w_0;
+      reg [63 : 0] w_1;
+      reg [63 : 0] w_9;
+      reg [63 : 0] w_14;
+      reg [63 : 0] d0;
+      reg [63 : 0] d1;
+
+      w_mem00_new = 64'h0000000000000000;
+      w_mem01_new = 64'h0000000000000000;
+      w_mem02_new = 64'h0000000000000000;
+      w_mem03_new = 64'h0000000000000000;
+      w_mem04_new = 64'h0000000000000000;
+      w_mem05_new = 64'h0000000000000000;
+      w_mem06_new = 64'h0000000000000000;
+      w_mem07_new = 64'h0000000000000000;
+      w_mem08_new = 64'h0000000000000000;
+      w_mem09_new = 64'h0000000000000000;
+      w_mem10_new = 64'h0000000000000000;
+      w_mem11_new = 64'h0000000000000000;
+      w_mem12_new = 64'h0000000000000000;
+      w_mem13_new = 64'h0000000000000000;
+      w_mem14_new = 64'h0000000000000000;
+      w_mem15_new = 64'h0000000000000000;
+      w_mem_we    = 0;
+
+      w_0  = w_mem[0];
+      w_1  = w_mem[1];
+      w_9  = w_mem[9];
+      w_14 = w_mem[14];
+
+      d0 = {w_1[0],     w_1[63 : 1]} ^ // ROTR1
+           {w_1[7 : 0], w_1[63 : 8]} ^ // ROTR8
+           {7'b0000000, w_1[63 : 7]};  // SHR7
+
+      d1 = {w_14[18 : 0], w_14[63 : 19]} ^ // ROTR19
+           {w_14[60 : 0], w_14[63 : 61]} ^ // ROTR61
+           {6'b000000,    w_14[63 : 6]};   // SHR6
+
+      w_new = w_0 + d0 + w_9 + d1;
+
+      if (init)
+        begin
+          w_mem00_new = block[1023 : 960];
+          w_mem01_new = block[959  : 896];
+          w_mem02_new = block[895  : 832];
+          w_mem03_new = block[831  : 768];
+          w_mem04_new = block[767  : 704];
+          w_mem05_new = block[703  : 640];
+          w_mem06_new = block[639  : 576];
+          w_mem07_new = block[575  : 512];
+          w_mem08_new = block[511  : 448];
+          w_mem09_new = block[447  : 384];
+          w_mem10_new = block[383  : 320];
+          w_mem11_new = block[319  : 256];
+          w_mem12_new = block[255  : 192];
+          w_mem13_new = block[191  : 128];
+          w_mem14_new = block[127  :  64];
+          w_mem15_new = block[63   :   0];
+          w_mem_we    = 1;
+        end
+      else if (w_ctr_reg > 15)
+        begin
+          w_mem00_new = w_mem[01];
+          w_mem01_new = w_mem[02];
+          w_mem02_new = w_mem[03];
+          w_mem03_new = w_mem[04];
+          w_mem04_new = w_mem[05];
+          w_mem05_new = w_mem[06];
+          w_mem06_new = w_mem[07];
+          w_mem07_new = w_mem[08];
+          w_mem08_new = w_mem[09];
+          w_mem09_new = w_mem[10];
+          w_mem10_new = w_mem[11];
+          w_mem11_new = w_mem[12];
+          w_mem12_new = w_mem[13];
+          w_mem13_new = w_mem[14];
+          w_mem14_new = w_mem[15];
+          w_mem15_new = w_new;
+          w_mem_we    = 1;
+        end
+    end // w_mem_update_logic
+
+
+  //----------------------------------------------------------------
+  // w_ctr
+  // W schedule adress counter. Counts from 0x10 to 0x3f and
+  // is used to expand the block into words.
+  //----------------------------------------------------------------
+  always @*
+    begin : w_ctr
+      w_ctr_new = 0;
+      w_ctr_we  = 0;
+
+      if (w_ctr_rst)
+        begin
+          w_ctr_new = 7'h00;
+          w_ctr_we  = 1;
+        end
+
+      if (w_ctr_inc)
+        begin
+          w_ctr_new = w_ctr_reg + 7'h01;
+          w_ctr_we  = 1;
+        end
+    end // w_ctr
+
+
+  //----------------------------------------------------------------
+  // sha512_w_mem_fsm
+  // Logic for the w shedule FSM.
+  //----------------------------------------------------------------
+  always @*
+    begin : sha512_w_mem_fsm
+      w_ctr_rst = 0;
+      w_ctr_inc = 0;
+
+      sha512_w_mem_ctrl_new = CTRL_IDLE;
+      sha512_w_mem_ctrl_we  = 0;
+
+      case (sha512_w_mem_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            if (init)
+              begin
+                w_ctr_rst             = 1;
+                sha512_w_mem_ctrl_new = CTRL_UPDATE;
+                sha512_w_mem_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_UPDATE:
+          begin
+            if (next)
+              begin
+                w_ctr_inc = 1;
+              end
+
+            if (w_ctr_reg == 7'h3f)
+              begin
+                sha512_w_mem_ctrl_new = CTRL_IDLE;
+                sha512_w_mem_ctrl_we  = 1;
+              end
+          end
+      endcase // case (sha512_ctrl_reg)
+    end // sha512_ctrl_fsm
+
+endmodule // sha512_w_mem
+
+//======================================================================
+// sha512_w_mem.v
+//======================================================================
diff --git a/sha512/src/tb/tb_sha512.v b/sha512/src/tb/tb_sha512.v
new file mode 100644
index 0000000..c993cfc
--- /dev/null
+++ b/sha512/src/tb/tb_sha512.v
@@ -0,0 +1,798 @@
+//======================================================================
+//
+// tb_sha512.v
+// -----------
+// Testbench for the SHA-512 top level wrapper.
+//
+//
+// 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,
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+//------------------------------------------------------------------
+// Test module.
+//------------------------------------------------------------------
+module tb_sha512();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  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_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           tb_clk;
+  reg           tb_reset_n;
+  reg           tb_cs;
+  reg           tb_we;
+  reg [7 : 0]   tb_address;
+  reg [31 : 0]  tb_write_data;
+  wire [31 : 0] tb_read_data;
+  wire          tb_error;
+
+  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.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //----------------------------------------------------------------
+  // sys_monitor
+  //
+  // Generates a cycle counter and displays information about
+  // the dut as needed.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      #(2 * CLK_HALF_PERIOD);
+      cycle_ctr = cycle_ctr + 1;
+    end
+
+
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dump when needed.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $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",
+               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},
+               {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);
+      $display("block4  = 0x%08x, block5  = 0x%08x, block6  = 0x%08x,  block7  = 0x%08x",
+               dut.block4_reg, dut.block5_reg, dut.block6_reg, dut.block7_reg);
+
+      $display("block8  = 0x%08x, block9  = 0x%08x, block10 = 0x%08x,  block11 = 0x%08x",
+               dut.block8_reg, dut.block9_reg, dut.block10_reg, dut.block11_reg);
+      $display("block12 = 0x%08x, block13 = 0x%08x, block14 = 0x%08x,  block15 = 0x%08x",
+               dut.block12_reg, dut.block13_reg, dut.block14_reg, dut.block15_reg);
+
+      $display("block16 = 0x%08x, block17 = 0x%08x, block18 = 0x%08x,  block19 = 0x%08x",
+               dut.block16_reg, dut.block17_reg, dut.block18_reg, dut.block19_reg);
+      $display("block20 = 0x%08x, block21 = 0x%08x, block22 = 0x%08x,  block23 = 0x%08x",
+               dut.block20_reg, dut.block21_reg, dut.block22_reg, dut.block23_reg);
+
+      $display("block24 = 0x%08x, block25 = 0x%08x, block26 = 0x%08x,  block27 = 0x%08x",
+               dut.block24_reg, dut.block25_reg, dut.block26_reg, dut.block27_reg);
+      $display("block28 = 0x%08x, block29 = 0x%08x, block30 = 0x%08x,  block31 = 0x%08x",
+               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()
+  //
+  // Toggles reset to force the DUT into a well defined state.
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+
+      #(4 * CLK_HALF_PERIOD);
+
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 32'h00000000;
+      error_ctr = 32'h00000000;
+      tc_ctr    = 32'h00000000;
+
+      tb_clk        = 0;
+      tb_reset_n    = 0;
+      tb_cs         = 0;
+      tb_we         = 0;
+      tb_address    = 6'h00;
+      tb_write_data = 32'h00000000;
+    end
+  endtask // init_dut
+
+
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully.", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases completed.", tc_ctr);
+          $display("*** %02d errors detected during testing.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  // (Actually we wait for either ready or valid to be set.)
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      read_data = 0;
+
+      while (read_data == 0)
+        begin
+          read_word(ADDR_STATUS);
+        end
+    end
+  endtask // wait_ready
+
+
+  //----------------------------------------------------------------
+  // write_word()
+  //
+  // Write the given word to the DUT using the DUT interface.
+  //----------------------------------------------------------------
+  task write_word(input [7 : 0]  address,
+                  input [31 : 0] word);
+    begin
+      if (DEBUG)
+        begin
+          $display("*** Writing 0x%08x to 0x%02x.", word, address);
+          $display("");
+        end
+
+      tb_address = address;
+      tb_write_data = word;
+      tb_cs = 1;
+      tb_we = 1;
+      #(2 * CLK_HALF_PERIOD);
+      tb_cs = 0;
+      tb_we = 0;
+    end
+  endtask // write_word
+
+
+  //----------------------------------------------------------------
+  // write_block()
+  //
+  // Write the given block to the dut.
+  //----------------------------------------------------------------
+  task write_block(input [1023 : 0] block);
+    begin
+      write_word(ADDR_BLOCK0,  block[1023 : 992]);
+      write_word(ADDR_BLOCK1,  block[991  : 960]);
+      write_word(ADDR_BLOCK2,  block[959  : 928]);
+      write_word(ADDR_BLOCK3,  block[927  : 896]);
+      write_word(ADDR_BLOCK4,  block[895  : 864]);
+      write_word(ADDR_BLOCK5,  block[863  : 832]);
+      write_word(ADDR_BLOCK6,  block[831  : 800]);
+      write_word(ADDR_BLOCK7,  block[799  : 768]);
+      write_word(ADDR_BLOCK8,  block[767  : 736]);
+      write_word(ADDR_BLOCK9,  block[735  : 704]);
+      write_word(ADDR_BLOCK10, block[703  : 672]);
+      write_word(ADDR_BLOCK11, block[671  : 640]);
+      write_word(ADDR_BLOCK12, block[639  : 608]);
+      write_word(ADDR_BLOCK13, block[607  : 576]);
+      write_word(ADDR_BLOCK14, block[575  : 544]);
+      write_word(ADDR_BLOCK15, block[543  : 512]);
+      write_word(ADDR_BLOCK16, block[511  : 480]);
+      write_word(ADDR_BLOCK17, block[479  : 448]);
+      write_word(ADDR_BLOCK18, block[447  : 416]);
+      write_word(ADDR_BLOCK19, block[415  : 384]);
+      write_word(ADDR_BLOCK20, block[383  : 352]);
+      write_word(ADDR_BLOCK21, block[351  : 320]);
+      write_word(ADDR_BLOCK22, block[319  : 288]);
+      write_word(ADDR_BLOCK23, block[287  : 256]);
+      write_word(ADDR_BLOCK24, block[255  : 224]);
+      write_word(ADDR_BLOCK25, block[223  : 192]);
+      write_word(ADDR_BLOCK26, block[191  : 160]);
+      write_word(ADDR_BLOCK27, block[159  : 128]);
+      write_word(ADDR_BLOCK28, block[127  :  96]);
+      write_word(ADDR_BLOCK29, block[95   :  64]);
+      write_word(ADDR_BLOCK30, block[63   :  32]);
+      write_word(ADDR_BLOCK31, block[31   :   0]);
+    end
+  endtask // write_block
+
+
+  //----------------------------------------------------------------
+  // read_word()
+  //
+  // Read a data word from the given address in the DUT.
+  // the word read will be available in the global variable
+  // read_data.
+  //----------------------------------------------------------------
+  task read_word(input [7 : 0]  address);
+    begin
+      tb_address = address;
+      tb_cs = 1;
+      tb_we = 0;
+      #(CLK_PERIOD);
+      read_data = tb_read_data;
+      tb_cs = 0;
+
+      if (DEBUG)
+        begin
+          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
+          $display("");
+        end
+    end
+  endtask // read_word
+
+
+  //----------------------------------------------------------------
+  // check_name_version()
+  //
+  // Read the name and version from the DUT.
+  //----------------------------------------------------------------
+  task check_name_version();
+    reg [31 : 0] name0;
+    reg [31 : 0] name1;
+    reg [31 : 0] version;
+    begin
+
+      read_word(ADDR_NAME0);
+      name0 = read_data;
+      read_word(ADDR_NAME1);
+      name1 = read_data;
+      read_word(ADDR_VERSION);
+      version = read_data;
+
+      $display("DUT name: %c%c%c%c%c%c%c%c",
+               name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0],
+               name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]);
+      $display("DUT version: %c%c%c%c",
+               version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]);
+    end
+  endtask // check_name_version
+
+
+  //----------------------------------------------------------------
+  // read_digest()
+  //
+  // Read the digest in the dut. The resulting digest will be
+  // available in the global variable digest_data.
+  //----------------------------------------------------------------
+  task read_digest();
+    begin
+      read_word(ADDR_DIGEST0);
+      digest_data[511 : 480] = read_data;
+      read_word(ADDR_DIGEST1);
+      digest_data[479 : 448] = read_data;
+      read_word(ADDR_DIGEST2);
+      digest_data[447 : 416] = read_data;
+      read_word(ADDR_DIGEST3);
+      digest_data[415 : 384] = read_data;
+      read_word(ADDR_DIGEST4);
+      digest_data[383 : 352] = read_data;
+      read_word(ADDR_DIGEST5);
+      digest_data[351 : 320] = read_data;
+      read_word(ADDR_DIGEST6);
+      digest_data[319 : 288] = read_data;
+      read_word(ADDR_DIGEST7);
+      digest_data[287 : 256] = read_data;
+
+      read_word(ADDR_DIGEST8);
+      digest_data[255 : 224] = read_data;
+      read_word(ADDR_DIGEST9);
+      digest_data[223 : 192] = read_data;
+      read_word(ADDR_DIGEST10);
+      digest_data[191 : 160] = read_data;
+      read_word(ADDR_DIGEST11);
+      digest_data[159 : 128] = read_data;
+      read_word(ADDR_DIGEST12);
+      digest_data[127 :  96] = read_data;
+      read_word(ADDR_DIGEST13);
+      digest_data[95  :  64] = read_data;
+      read_word(ADDR_DIGEST14);
+      digest_data[63  :  32] = read_data;
+      read_word(ADDR_DIGEST15);
+      digest_data[31  :   0] = read_data;
+    end
+  endtask // read_digest
+
+
+  //----------------------------------------------------------------
+  // get_mask()
+  //
+  // Create the mask needed for a given mode.
+  //----------------------------------------------------------------
+  function [511 : 0] get_mask(input [1 : 0] mode);
+    begin
+      case (mode)
+        MODE_SHA_512_224:
+          begin
+            if (DEBUG)
+              begin
+                $display("Mode MODE_SHA_512_224");
+              end
+            get_mask = {{7{32'hffffffff}}, {9{32'h00000000}}};
+          end
+
+        MODE_SHA_512_256:
+          begin
+            if (DEBUG)
+              begin
+                $display("Mode MODE_SHA_512_256");
+              end
+            get_mask = {{8{32'hffffffff}}, {8{32'h00000000}}};
+          end
+
+        MODE_SHA_384:
+          begin
+            if (DEBUG)
+              begin
+                $display("Mode MODE_SHA_512_384");
+              end
+            get_mask = {{12{32'hffffffff}}, {4{32'h00000000}}};
+          end
+
+        MODE_SHA_512:
+          begin
+            if (DEBUG)
+              begin
+                $display("Mode MODE_SHA_512");
+              end
+            get_mask = {16{32'hffffffff}};
+          end
+      endcase // case (mode)
+    end
+  endfunction // get_mask
+
+
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  //
+  // Perform test of a single block digest.
+  //----------------------------------------------------------------
+  task single_block_test(input [7 : 0]    tc_number,
+                         input [1 : 0]    mode,
+                         input [1023 : 0] block,
+                         input [511 : 0]  expected);
+
+    reg [511 : 0] mask;
+    reg [511 : 0] masked_data;
+
+    begin
+      $display("*** TC%01d - Single block test started.", tc_ctr);
+
+      write_block(block);
+      write_word(ADDR_CTRL, {28'h0000000, mode, CTRL_INIT_VALUE});
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      mask = get_mask(mode);
+      masked_data = digest_data & mask;
+
+      if (DEBUG)
+        begin
+          $display("masked_data = 0x%0128x", masked_data);
+        end
+
+      if (masked_data == expected)
+        begin
+          $display("TC%01d: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR.", tc_ctr);
+          $display("TC%01d: Expected: 0x%0128x", tc_ctr, expected);
+          $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);
+      tc_ctr = tc_ctr + 1;
+    end
+  endtask // single_block_test
+
+
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  //
+  // Perform test of a double block digest. Note that we check
+  // the digests for both the first and final block.
+  //----------------------------------------------------------------
+  task double_block_test(input [7 : 0]    tc_number,
+                         input [1 : 0]    mode,
+                         input [1023 : 0] block0,
+                         input [1023 : 0] block1,
+                         input [511 : 0]  expected0,
+                         input [511 : 0]  expected1
+                        );
+    reg [511 : 0] mask;
+    reg [511 : 0] masked_data1;
+    reg [31 :  0] ctrl_cmd;
+
+    begin
+      $display("*** TC%01d - Double block test started.", tc_ctr);
+
+      // First block
+      write_block(block0);
+      write_word(ADDR_CTRL, {28'h0000000, mode, CTRL_INIT_VALUE});
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      if (digest_data == expected0)
+        begin
+          $display("TC%01d first block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in first digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%064x", tc_ctr, expected0);
+          $display("TC%01d: Got:      0x%064x", tc_ctr, digest_data);
+          error_ctr = error_ctr + 1;
+        end
+
+      // Final block
+      write_block(block1);
+      write_word(ADDR_CTRL, {28'h0000000, mode, CTRL_NEXT_VALUE});
+      #(CLK_PERIOD);
+      wait_ready();
+      read_digest();
+
+      mask = get_mask(mode);
+      masked_data1 = digest_data & mask;
+
+      if (masked_data1 == expected1)
+        begin
+          $display("TC%01d final block: OK.", tc_ctr);
+        end
+      else
+        begin
+          $display("TC%01d: ERROR in final digest", tc_ctr);
+          $display("TC%01d: Expected: 0x%0128x", tc_ctr, expected1);
+          $display("TC%01d: Got:      0x%0128x", tc_ctr, masked_data1);
+          error_ctr = error_ctr + 1;
+        end
+
+      $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.
+  //
+  // Test cases taken from:
+  // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+  //----------------------------------------------------------------
+  initial
+    begin : sha512_test
+      reg [1024 : 0] single_block;
+      reg [511 : 0]  tc1_expected;
+      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;
+      reg [511 : 0]  tc6_expected;
+      reg [511 : 0]  tc7_expected;
+      reg [511 : 0]  tc8_expected;
+      reg [511 : 0]  tc9_expected;
+      reg [511 : 0]  tc10_expected;
+      reg [511 : 0]  tc11_expected;
+      reg [511 : 0]  tc12_expected;
+
+      $display("   -- Testbench for sha512 started --");
+
+      init_sim();
+      reset_dut();
+      check_name_version();
+
+      // dump_dut_state();
+      // write_word(ADDR_BLOCK0, 32'hdeadbeef);
+      dump_dut_state();
+      // read_word(ADDR_BLOCK0);
+      // dump_dut_state();
+
+      // Single block test mesage.
+      single_block = 1024'h6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+
+      // 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);
+
+      // SHA-512_256 single block digest and test.
+      tc3_expected = {256'h53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23, {8{32'h00000000}}};
+      single_block_test(8'h03, MODE_SHA_512_256, single_block, tc3_expected);
+
+      // SHA-384 single block digest and test.
+      tc4_expected = {384'hCB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7, {4{32'h00000000}}};
+      single_block_test(8'h04, MODE_SHA_384, single_block, tc4_expected);
+
+
+      // Two block test message.
+      double_block_one = 1024'h61626364656667686263646566676869636465666768696A6465666768696A6B65666768696A6B6C666768696A6B6C6D6768696A6B6C6D6E68696A6B6C6D6E6F696A6B6C6D6E6F706A6B6C6D6E6F70716B6C6D6E6F7071726C6D6E6F707172736D6E6F70717273746E6F70717273747580000000000000000000000000000000;
+      double_block_two = 1024'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380;
+
+      // SHA-512 two block digests and test.
+      tc5_expected = 512'h4319017A2B706E69CD4B05938BAE5E890186BF199F30AA956EF8B71D2F810585D787D6764B20BDA2A26014470973692000EC057F37D14B8E06ADD5B50E671C72;
+      tc6_expected = 512'h8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909;
+      double_block_test(8'h05, MODE_SHA_512, double_block_one, double_block_two, tc5_expected, tc6_expected);
+
+      // SHA-512_224 two block digests and test.
+      tc7_expected = 512'h9606CB2DB7823CE75FE35E2674A8F9EF1417ED9E89C412BB54EA29664586108625852563EED495096DEBAAE2F4737FD75319224B135486F8E6C0F55E700C35B3;
+      tc8_expected = {224'h23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9, {9{32'h00000000}}};
+      double_block_test(8'h06, MODE_SHA_512_224, double_block_one, double_block_two, tc7_expected, tc8_expected);
+
+      // SHA-512_256 two block digests and test.
+      tc9_expected = 512'h8DD99EB081311F8BCBBBC42CC7AFB288E8E9408730419D1E953FF7A2B194048DAE24175483C44C7C809B348E8E88E3ECBF2EA614CEED9C5B51807937F11867E1;
+      tc10_expected = {256'h3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A, {8{32'h00000000}}};
+      double_block_test(8'h07, MODE_SHA_512_256, double_block_one, double_block_two, tc9_expected, tc10_expected);
+
+      // SHA-384 two block digests and test.
+      tc11_expected = 512'h2A7F1D895FD58E0BEAAE96D1A673C741015A2173796C1A88F6352CA156ACAFF7C662113E9EBB4D6417B61A85E2CCF0A937EB9A6660FEB5198F2EBE9A81E6A2C5;
+      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
+endmodule // tb_sha512
+
+//======================================================================
+// EOF tb_sha512.v
+//======================================================================
diff --git a/sha512/src/tb/tb_sha512_core.v b/sha512/src/tb/tb_sha512_core.v
new file mode 100644
index 0000000..e4d3bb8
--- /dev/null
+++ b/sha512/src/tb/tb_sha512_core.v
@@ -0,0 +1,535 @@
+//======================================================================
+//
+// tb_sha512_core.v
+// ----------------
+// Testbench for the SHA-512 core.
+//
+//
+// 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,
+// 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Simulator directives.
+//------------------------------------------------------------------
+`timescale 1ns/10ps
+
+
+//------------------------------------------------------------------
+// Test module.
+//------------------------------------------------------------------
+module tb_sha512_core();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 0;
+
+  parameter CLK_PERIOD      = 2;
+  parameter CLK_HALF_PERIOD = CLK_PERIOD / 2;
+
+  parameter MODE_SHA_512_224 = 0;
+  parameter MODE_SHA_512_256 = 1;
+  parameter MODE_SHA_384     = 2;
+  parameter MODE_SHA_512     = 3;
+
+
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] error_ctr;
+  reg [31 : 0] tc_ctr;
+
+  reg            tb_clk;
+  reg            tb_reset_n;
+  reg            tb_init;
+  reg            tb_next;
+  reg    [1 : 0] tb_mode;
+  reg [1023 : 0] tb_block;
+  wire           tb_ready;
+  wire [511 : 0] tb_digest;
+  wire           tb_digest_valid;
+
+
+  //----------------------------------------------------------------
+  // Device Under Test.
+  //----------------------------------------------------------------
+  sha512_core dut(
+                   .clk(tb_clk),
+                   .reset_n(tb_reset_n),
+
+                   .init(tb_init),
+                   .next(tb_next),
+                   .mode(tb_mode),
+
+                   .block(tb_block),
+
+                   .ready(tb_ready),
+
+                   .digest(tb_digest),
+                   .digest_valid(tb_digest_valid)
+                 );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  //
+  // Always running clock generator process.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD;
+      tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //----------------------------------------------------------------
+  // sys_monitor()
+  //
+  // An always running process that creates a cycle counter and
+  // conditionally displays information about the DUT.
+  //----------------------------------------------------------------
+  always
+    begin : sys_monitor
+      cycle_ctr = cycle_ctr + 1;
+      #(CLK_PERIOD);
+      if (DEBUG)
+        begin
+          dump_dut_state();
+        end
+    end
+
+
+  //----------------------------------------------------------------
+  // dump_dut_state()
+  //
+  // Dump the state of the dut.
+  //----------------------------------------------------------------
+  task dump_dut_state();
+    begin
+      $display("State of DUT");
+      $display("------------");
+      $display("Inputs and outputs:");
+      $display("init   = 0x%01x, next  = 0x%01x. mode = 0x%01x",
+               dut.init, dut.next, dut.mode);
+      $display("block  = 0x%0128x", dut.block);
+
+      $display("ready  = 0x%01x, valid = 0x%01x",
+               dut.ready, dut.digest_valid);
+      $display("digest = 0x%064x", dut.digest);
+      $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x",
+               dut.H0_reg, dut.H1_reg, dut.H2_reg, dut.H3_reg);
+      $display("H4_reg = 0x%08x, H5_reg = 0x%08x, H6_reg = 0x%08x, H7_reg = 0x%08x",
+               dut.H4_reg, dut.H5_reg, dut.H6_reg, dut.H7_reg);
+      $display("");
+
+      $display("Control signals and counter:");
+      $display("sha512_ctrl_reg = 0x%02x", dut.sha512_ctrl_reg);
+      $display("digest_init     = 0x%01x, digest_update = 0x%01x",
+               dut.digest_init, dut.digest_update);
+      $display("state_init      = 0x%01x, state_update  = 0x%01x",
+               dut.state_init, dut.state_update);
+      $display("first_block     = 0x%01x, ready_flag    = 0x%01x, w_init    = 0x%01x",
+               dut.first_block, dut.ready_flag, dut.w_init);
+      $display("t_ctr_inc       = 0x%01x, t_ctr_rst     = 0x%01x, t_ctr_reg = 0x%02x",
+               dut.t_ctr_inc, dut.t_ctr_rst, dut.t_ctr_reg);
+      $display("");
+
+      $display("State registers:");
+      $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x",
+               dut.a_reg, dut.b_reg, dut.c_reg, dut.d_reg);
+      $display("e_reg = 0x%08x, f_reg = 0x%08x, g_reg = 0x%08x, h_reg = 0x%08x",
+               dut.e_reg, dut.f_reg, dut.g_reg, dut.h_reg);
+      $display("");
+      $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x",
+               dut.a_new, dut.b_new, dut.c_new, dut.d_new);
+      $display("e_new = 0x%08x, f_new = 0x%08x, g_new = 0x%08x, h_new = 0x%08x",
+               dut.e_new, dut.f_new, dut.g_new, dut.h_new);
+      $display("");
+
+      $display("State update values:");
+      $display("w  = 0x%08x, k  = 0x%08x", dut.w_data, dut.k_data);
+      $display("t1 = 0x%08x, t2 = 0x%08x", dut.t1, dut.t2);
+      $display("");
+    end
+  endtask // dump_dut_state
+
+
+  //----------------------------------------------------------------
+  // dump_dut_wmem()
+  //
+  // Dump the state of the dut wmem.
+  //----------------------------------------------------------------
+  task dump_dut_wmem();
+    begin
+      $display("State of DUT WMEM");
+      $display("-----------------");
+      $display("W[00] = 0x%016x, W[01] = 0x%016x, W[02] = 0x%016x, W[03] = 0x%016x",
+               dut.w_mem_inst.w_mem[00], dut.w_mem_inst.w_mem[01],
+               dut.w_mem_inst.w_mem[02], dut.w_mem_inst.w_mem[03]);
+      $display("W[04] = 0x%016x, W[05] = 0x%016x, W[06] = 0x%016x, W[07] = 0x%016x",
+               dut.w_mem_inst.w_mem[04], dut.w_mem_inst.w_mem[05],
+               dut.w_mem_inst.w_mem[06], dut.w_mem_inst.w_mem[07]);
+      $display("W[08] = 0x%016x, W[09] = 0x%016x, W[10] = 0x%016x, W[11] = 0x%016x",
+               dut.w_mem_inst.w_mem[08], dut.w_mem_inst.w_mem[09],
+               dut.w_mem_inst.w_mem[10], dut.w_mem_inst.w_mem[11]);
+      $display("W[12] = 0x%016x, W[13] = 0x%016x, W[14] = 0x%016x, W[15] = 0x%016x",
+               dut.w_mem_inst.w_mem[12], dut.w_mem_inst.w_mem[13],
+               dut.w_mem_inst.w_mem[14], dut.w_mem_inst.w_mem[15]);
+      $display("");
+    end
+  endtask // dump_dut_wmem
+
+
+  //----------------------------------------------------------------
+  // reset_dut()
+  //
+  // Toggle reset to put the DUT into a well known state.
+  //----------------------------------------------------------------
+  task reset_dut();
+    begin
+      $display("*** Toggle reset.");
+      tb_reset_n = 0;
+      #(2 * CLK_PERIOD);
+      tb_reset_n = 1;
+    end
+  endtask // reset_dut
+
+
+  //----------------------------------------------------------------
+  // init_sim()
+  //
+  // Initialize all counters and testbed functionality as well
+  // as setting the DUT inputs to defined values.
+  //----------------------------------------------------------------
+  task init_sim();
+    begin
+      cycle_ctr = 0;
+      error_ctr = 0;
+      tc_ctr = 0;
+
+      tb_clk = 0;
+      tb_reset_n = 1;
+
+      tb_init = 0;
+      tb_next = 0;
+      tb_next = 2'b00;
+      tb_mode = 2'b00;
+      tb_block = {32{32'h00000000}};
+    end
+  endtask // init_dut
+
+
+  //----------------------------------------------------------------
+  // display_test_result()
+  //
+  // Display the accumulated test results.
+  //----------------------------------------------------------------
+  task display_test_result();
+    begin
+      if (error_ctr == 0)
+        begin
+          $display("*** All %02d test cases completed successfully", tc_ctr);
+        end
+      else
+        begin
+          $display("*** %02d test cases did not complete successfully.", error_ctr);
+        end
+    end
+  endtask // display_test_result
+
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for the ready flag in the dut to be set.
+  //
+  // Note: It is the callers responsibility to call the function
+  // when the dut is actively processing and will in fact at some
+  // point set the flag.
+  //----------------------------------------------------------------
+  task wait_ready();
+    begin
+      while (!tb_ready)
+        begin
+          #(2 * CLK_PERIOD);
+        end
+    end
+  endtask // wait_ready
+
+
+  //----------------------------------------------------------------
+  // single_block_test()
+  //
+  // Run a test case spanning a single data block.
+  //----------------------------------------------------------------
+  task single_block_test(input [7 : 0]    tc_number,
+                         input [1 : 0]    mode,
+                         input [1023 : 0] block,
+                         input [511 : 0]  expected);
+    reg [511 : 0] mask;
+
+   begin
+     $display("*** TC %0d single block test case started.", tc_number);
+     tc_ctr = tc_ctr + 1;
+
+     tb_block = block;
+     tb_mode  = mode;
+     tb_init = 1;
+     #(2 * CLK_PERIOD);
+     tb_init = 0;
+
+     wait_ready();
+
+     case (mode)
+       MODE_SHA_512_224:
+         begin
+           mask = {{7{32'hffffffff}}, {9{32'h00000000}}};
+         end
+
+       MODE_SHA_512_256:
+         begin
+           mask = {{8{32'hffffffff}}, {8{32'h00000000}}};
+         end
+
+       MODE_SHA_384:
+         begin
+           mask = {{12{32'hffffffff}}, {4{32'h00000000}}};
+         end
+
+       MODE_SHA_512:
+         begin
+           mask = {16{32'hffffffff}};
+         end
+     endcase // case (mode)
+
+     if ((tb_digest & mask) == expected)
+       begin
+         $display("*** TC %0d successful.", tc_number);
+         $display("");
+       end
+     else
+       begin
+         $display("*** ERROR: TC %0d NOT successful.", tc_number);
+         $display("Expected: 0x%064x", expected);
+         $display("Got:      0x%064x", tb_digest);
+         $display("");
+
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // single_block_test
+
+
+  //----------------------------------------------------------------
+  // double_block_test()
+  //
+  // Run a test case spanning two data blocks. We check both
+  // intermediate and final digest.
+  //----------------------------------------------------------------
+  task double_block_test(input [7 : 0]    tc_number,
+                         input [1 : 0]    mode,
+                         input [1023 : 0] block1,
+                         input [1023 : 0] block2,
+                         input [511 : 0]  expected1,
+                         input [511 : 0]  expected2);
+
+    reg [511 : 0] mask;
+    reg [511 : 0] db_digest1;
+    reg           db_error;
+   begin
+     $display("*** TC %0d double block test case started.", tc_number);
+     db_error = 0;
+     tc_ctr = tc_ctr + 1;
+
+     $display("*** TC %0d first block started.", tc_number);
+     tb_mode  = mode;
+     tb_block = block1;
+     tb_init = 1;
+     #(2 * CLK_PERIOD);
+     tb_init = 0;
+     wait_ready();
+     db_digest1 = tb_digest;
+     $display("*** TC %0d first block done.", tc_number);
+
+     $display("*** TC %0d second block started.", tc_number);
+     tb_block = block2;
+     tb_next = 1;
+     #(2 * CLK_PERIOD);
+     tb_next = 0;
+     wait_ready();
+     $display("*** TC %0d second block done.", tc_number);
+
+     if (db_digest1 == expected1)
+       begin
+         $display("*** TC %0d first block successful", tc_number);
+         $display("");
+       end
+     else
+       begin
+         $display("*** ERROR: TC %0d first block NOT successful", tc_number);
+         $display("Expected: 0x%064x", expected1);
+         $display("Got:      0x%064x", db_digest1);
+         $display("");
+         db_error = 1;
+       end
+
+     case (mode)
+       MODE_SHA_512_224:
+         begin
+           mask = {{7{32'hffffffff}}, {9{32'h00000000}}};
+         end
+
+       MODE_SHA_512_256:
+         begin
+           mask = {{8{32'hffffffff}}, {8{32'h00000000}}};
+         end
+
+       MODE_SHA_384:
+         begin
+           mask = {{12{32'hffffffff}}, {4{32'h00000000}}};
+         end
+
+       MODE_SHA_512:
+         begin
+           mask = {16{32'hffffffff}};
+         end
+     endcase // case (mode)
+
+     if ((tb_digest & mask) == expected2)
+       begin
+         $display("*** TC %0d second block successful", tc_number);
+         $display("");
+       end
+     else
+       begin
+         $display("*** ERROR: TC %0d second block NOT successful", tc_number);
+         $display("Expected: 0x%064x", expected2);
+         $display("Got:      0x%064x", tb_digest);
+         $display("");
+         db_error = 1;
+       end
+
+     if (db_error)
+       begin
+         error_ctr = error_ctr + 1;
+       end
+   end
+  endtask // double_block_test
+
+
+  //----------------------------------------------------------------
+  // sha512_core_test
+  // The main test functionality.
+  //
+  // Test cases taken from:
+  // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+  //----------------------------------------------------------------
+  initial
+    begin : sha512_core_test
+      reg [1024 : 0] single_block;
+      reg [511 : 0]  tc1_expected;
+      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;
+      reg [511 : 0]  tc6_expected;
+      reg [511 : 0]  tc7_expected;
+      reg [511 : 0]  tc8_expected;
+      reg [511 : 0]  tc9_expected;
+      reg [511 : 0]  tc10_expected;
+      reg [511 : 0]  tc11_expected;
+      reg [511 : 0]  tc12_expected;
+
+      $display("   -- Testbench for sha512 core started --");
+
+      init_sim();
+      dump_dut_state();
+      reset_dut();
+      dump_dut_state();
+
+      // Single block test mesage.
+      single_block = 1024'h6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018;
+
+      // 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);
+
+      // SHA-512_256 single block digest and test.
+      tc3_expected = {256'h53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23, {8{32'h00000000}}};
+      single_block_test(8'h03, MODE_SHA_512_256, single_block, tc3_expected);
+
+      // SHA-384 single block digest and test.
+      tc4_expected = {384'hCB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7, {4{32'h00000000}}};
+      single_block_test(8'h04, MODE_SHA_384, single_block, tc4_expected);
+
+
+      // Two block test message.
+      double_block_one = 1024'h61626364656667686263646566676869636465666768696A6465666768696A6B65666768696A6B6C666768696A6B6C6D6768696A6B6C6D6E68696A6B6C6D6E6F696A6B6C6D6E6F706A6B6C6D6E6F70716B6C6D6E6F7071726C6D6E6F707172736D6E6F70717273746E6F70717273747580000000000000000000000000000000;
+      double_block_two = 1024'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380;
+
+      // SHA-512 two block digests and test.
+      tc5_expected = 512'h4319017A2B706E69CD4B05938BAE5E890186BF199F30AA956EF8B71D2F810585D787D6764B20BDA2A26014470973692000EC057F37D14B8E06ADD5B50E671C72;
+      tc6_expected = 512'h8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909;
+      double_block_test(8'h05, MODE_SHA_512, double_block_one, double_block_two, tc5_expected, tc6_expected);
+
+      // SHA-512_224 two block digests and test.
+      tc7_expected = 512'h9606CB2DB7823CE75FE35E2674A8F9EF1417ED9E89C412BB54EA29664586108625852563EED495096DEBAAE2F4737FD75319224B135486F8E6C0F55E700C35B3;
+      tc8_expected = {224'h23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9, {9{32'h00000000}}};
+      double_block_test(8'h06, MODE_SHA_512_224, double_block_one, double_block_two, tc7_expected, tc8_expected);
+
+      // SHA-512_256 two block digests and test.
+      tc9_expected = 512'h8DD99EB081311F8BCBBBC42CC7AFB288E8E9408730419D1E953FF7A2B194048DAE24175483C44C7C809B348E8E88E3ECBF2EA614CEED9C5B51807937F11867E1;
+      tc10_expected = {256'h3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A, {8{32'h00000000}}};
+      double_block_test(8'h07, MODE_SHA_512_256, double_block_one, double_block_two, tc9_expected, tc10_expected);
+
+      // SHA-384 two block digests and test.
+      tc11_expected = 512'h2A7F1D895FD58E0BEAAE96D1A673C741015A2173796C1A88F6352CA156ACAFF7C662113E9EBB4D6417B61A85E2CCF0A937EB9A6660FEB5198F2EBE9A81E6A2C5;
+      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);
+
+
+      display_test_result();
+      $display("*** Simulation done.");
+      $finish;
+    end // sha512_core_test
+endmodule // tb_sha512_core
+
+//======================================================================
+// EOF tb_sha512_core.v
+//======================================================================
diff --git a/sha512/toolruns/Makefile b/sha512/toolruns/Makefile
new file mode 100755
index 0000000..03073ca
--- /dev/null
+++ b/sha512/toolruns/Makefile
@@ -0,0 +1,96 @@
+#===================================================================
+#
+# Makefile
+# --------
+# Makefile for building sha512 wmem, core and top simulations.
+#
+#
+# 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, 
+# 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.
+#
+#===================================================================
+
+#WMEM_SRC=../src/rtl/sha256_w_mem.v
+#WMEM_TB_SRC=../src/tb/tb_sha256_w_mem.v
+
+CORE_SRC=../src/rtl/sha512_core.v ../src/rtl/sha512_h_constants.v ../src/rtl/sha512_k_constants.v ../src/rtl/sha512_w_mem.v
+CORE_TB_SRC=../src/tb/tb_sha512_core.v
+
+TOP_SRC=../src/rtl/sha512.v
+TOP_TB_SRC=../src/tb/tb_sha512.v
+
+#WB_SRC=../src/rtl/wb_sha256.v $(CORE_SRC)
+#WB_TB_SRC=../src/tb/tb_wb_sha256.v
+
+CC=iverilog
+
+
+all: top core 
+
+
+#wb:  $(WB_TB_SRC) $(WB_SRC)
+#	$(CC) -o wb.sim $(WB_TB_SRC) $(WB_SRC)
+
+
+top: $(TOP_TB_SRC) $(TOP_SRC)
+	$(CC) -o top.sim $(TOP_TB_SRC) $(TOP_SRC) $(CORE_SRC)
+
+
+core: $(CORE_TB_SRC) $(CORE_SRC)
+	$(CC) -o core.sim $(CORE_SRC) $(CORE_TB_SRC)
+
+
+sim-top: top.sim
+	./top.sim
+
+
+sim-core: core.sim
+	./core.sim
+
+
+clean:
+	rm -f top.sim
+	rm -f core.sim
+	rm -f wmem.sim
+
+
+help:
+	@echo "Supported targets:"
+	@echo "------------------"
+	@echo "all:      Build all simulation targets."
+	@echo "top:      Build the top simulation target."
+	@echo "core:     Build the core simulation target."
+	@echo "sim-top:  Run top level simulation."
+	@echo "sim-core: Run core level simulation."
+	@echo "clean:    Delete all built files."
+
+#===================================================================
+# EOF Makefile
+#===================================================================
+



More information about the Commits mailing list