[Cryptech-Commits] [core/novena_i2c_simple] 01/01: Initial commit

git at cryptech.is git at cryptech.is
Fri Sep 26 02:10:30 UTC 2014


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

paul at psgd.org pushed a commit to branch master
in repository core/novena_i2c_simple.

commit 4817dd0cffa365bd58fc45e51f89157c36e0691f
Author: Paul Selkirk <paul at psgd.org>
Date:   Thu Sep 25 22:09:34 2014 -0400

    Initial commit
---
 LICENSE                          |  24 ++
 README.md                        |  29 ++
 build/Makefile                   |  17 +
 build/coretest-novena-simple.bmm |   0
 build/coretest-novena-simple.ucf | 594 +++++++++++++++++++++++++++++++++
 build/xilinx.mk                  | 176 ++++++++++
 build/xilinx.opt                 |  42 +++
 src/rtl/coretest_hashes.v        | 273 ++++++++++++++++
 src/rtl/i2c_core.v               | 581 +++++++++++++++++++++++++++++++++
 src/rtl/novena_fpga.v            | 147 +++++++++
 src/rtl/sha1.v                   | 421 ++++++++++++++++++++++++
 src/rtl/sha256.v                 | 433 ++++++++++++++++++++++++
 src/rtl/sha512.v                 | 497 ++++++++++++++++++++++++++++
 src/sw/hash.c                    | 310 ++++++++++++++++++
 src/sw/hash_tester.c             | 688 +++++++++++++++++++++++++++++++++++++++
 15 files changed, 4232 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a53b5f0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Authors: Joachim Strömbergson, Paul Selkirk
+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/README.md b/README.md
new file mode 100644
index 0000000..c8c1827
--- /dev/null
+++ b/README.md
@@ -0,0 +1,29 @@
+novena_i2c_simple
+=================
+
+The coretest system for the Novena PVT1, over I2C, with simplified
+user interface.
+
+## Introduction ##
+
+This variant of novena_i2c provides a more intuitive, more compact,
+and more efficient user interface - just write() the block data, and
+read() the digest. All signalling to/from the hash cores is implicit
+and handled by the SHA wrapper cores.
+
+Repeated writes to the same SHA core will be added to the same digest;
+the act of reading the digest resets the internal state, so that the
+next write will start a new digest.
+
+Each hash algorithm is a separate virtual I2C device on bus 2, with
+the following device addresses:
+  SHA-1         0x1e
+  SHA-256       0x1f
+  SHA-512/224   0x20
+  SHA-512/256   0x21
+  SHA-384       0x22
+  SHA-512       0x23
+
+## Status ##
+***(2014-09-18)***
+Initial version. Built using Xilinx ISE 14.3.
diff --git a/build/Makefile b/build/Makefile
new file mode 100644
index 0000000..4188adb
--- /dev/null
+++ b/build/Makefile
@@ -0,0 +1,17 @@
+project = coretest-novena-simple
+vendor = xilinx
+family = spartan6
+part = xc6slx45csg324-3
+top_module = novena_fpga
+isedir = /opt/Xilinx/14.3/ISE_DS
+xil_env = . $(isedir)/settings64.sh
+
+vfiles = ../src/rtl/novena_fpga.v ../src/rtl/coretest_hashes.v ../src/rtl/i2c_core.v \
+	../src/rtl/sha1.v ../src/rtl/sha256.v ../src/rtl/sha512.v \
+	../../sha1/src/rtl/sha1_core.v ../../sha1/src/rtl/sha1_w_mem.v \
+	../../sha256/src/rtl/sha256_core.v ../../sha256/src/rtl/sha256_k_constants.v \
+	../../sha256/src/rtl/sha256_w_mem.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/build/coretest-novena-simple.bmm b/build/coretest-novena-simple.bmm
new file mode 100644
index 0000000..e69de29
diff --git a/build/coretest-novena-simple.ucf b/build/coretest-novena-simple.ucf
new file mode 100644
index 0000000..448c692
--- /dev/null
+++ b/build/coretest-novena-simple.ucf
@@ -0,0 +1,594 @@
+###  Autogenerated on 2013-May-10 01:38 by edifToUcf.py
+###  Extracting designator U800 from EDIF netlist novena-dvt.EDF
+
+### extended performance annotation
+CONFIG VCCAUX  = 3.3;
+# Valid values are 2.5 and 3.3
+CONFIG MCB_PERFORMANCE  = EXTENDED;
+
+NET "APOPTOSIS" LOC = K1;
+NET "APOPTOSIS" IOSTANDARD = LVCMOS33;
+
+# AUD6_TFS
+# NET "DEL_CONT" LOC = A4;
+# NET "DEL_CONT" IOSTANDARD = LVCMOS33;
+# AUD6_TXC
+# NET "DEL_RST_L" LOC = B4;
+# NET "DEL_RST_L" IOSTANDARD = LVCMOS33;
+# NET "AUD6_TXD" LOC = A6;
+# NET "AUD6_TXD" IOSTANDARD = LVCMOS33;
+# NET "AUD_MCLK" LOC = H6;
+# NET "AUD_MCLK" IOSTANDARD = LVCMOS33;
+# AUD_MIC_CLK
+#NET "ZEROVEN" LOC = G3;
+#NET "ZEROVEN" IOSTANDARD = LVCMOS33;
+# NET "AUD_MIC_DAT" LOC = C5;
+# NET "AUD_MIC_DAT" IOSTANDARD = LVCMOS33;
+
+# NET "BATT_NRST" LOC = N1;
+# NET "BATT_NRST" IOSTANDARD = LVCMOS33;
+# NET "BATT_REFLASH_ALRT" LOC = N2;
+# NET "BATT_REFLASH_ALRT" IOSTANDARD = LVCMOS33;
+
+NET "CLK2_N" LOC = H1;
+NET "CLK2_N" IOSTANDARD = LVDS_33;
+NET "CLK2_N" DIFF_TERM = "TRUE";
+NET "CLK2_P" LOC = H2;
+NET "CLK2_P" IOSTANDARD = LVDS_33;
+NET "CLK2_P" DIFF_TERM = "TRUE";
+
+# NET "DDC_SCL" LOC = J6;
+# NET "DDC_SCL" IOSTANDARD = LVCMOS33;
+# NET "DDC_SDA" LOC = F2;
+# NET "DDC_SDA" IOSTANDARD = LVCMOS33;
+
+# ECSPI3_MISO
+#NET "SPI1_MISO" LOC = A3;
+#NET "SPI1_MISO" IOSTANDARD = LVCMOS33;
+# # R13 
+# ECSPI3_MOSI
+#NET "SPI1_MOSI" LOC = A2;
+#NET "SPI1_MOSI" IOSTANDARD = LVCMOS33;
+# ECSPI3_RDY
+#NET "SPI1_DELI_SEL" LOC = A5;
+#NET "SPI1_DELI_SEL" IOSTANDARD = LVCMOS33;
+# # R15 
+# ECSPI3_SCLK
+#NET "SPI1_SCLK" LOC = D9;
+#NET "SPI1_SCLK" IOSTANDARD = LVCMOS33;
+# ECSPI3_SS2
+#NET "SAMPEN" LOC = B3;
+#NET "SAMPEN" IOSTANDARD = LVCMOS33;
+
+# NET "EIM_BCLK" LOC = C9;
+# NET "EIM_BCLK" IOSTANDARD = LVCMOS33;
+#NET "EIM_CS[0]" LOC = B11;
+#NET "EIM_CS[0]" IOSTANDARD = LVCMOS33;
+#NET "EIM_CS[1]" LOC = A15;
+#NET "EIM_CS[1]" IOSTANDARD = LVCMOS33;
+
+NET "EIM_DA[0]" LOC = G9;
+NET "EIM_DA[0]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[0]" SLEW = SLOW;
+NET "EIM_DA[1]" LOC = A10;
+NET "EIM_DA[1]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[1]" SLEW = SLOW;
+NET "EIM_DA[2]" LOC = F9;
+NET "EIM_DA[2]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[2]" SLEW = SLOW;
+NET "EIM_DA[3]" LOC = B9;
+NET "EIM_DA[3]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[3]" SLEW = SLOW;
+NET "EIM_DA[4]" LOC = E13;
+NET "EIM_DA[4]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[4]" SLEW = SLOW;
+NET "EIM_DA[5]" LOC = F13;
+NET "EIM_DA[5]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[5]" SLEW = SLOW;
+NET "EIM_DA[6]" LOC = A9;
+NET "EIM_DA[6]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[6]" SLEW = SLOW;
+NET "EIM_DA[7]" LOC = A8;
+NET "EIM_DA[7]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[7]" SLEW = SLOW;
+NET "EIM_DA[8]" LOC = B8;
+NET "EIM_DA[8]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[8]" SLEW = SLOW;
+NET "EIM_DA[9]" LOC = D8;
+NET "EIM_DA[9]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[9]" SLEW = SLOW;
+NET "EIM_DA[10]" LOC = D11;
+NET "EIM_DA[10]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[10]" SLEW = SLOW;
+NET "EIM_DA[11]" LOC = C8;
+NET "EIM_DA[11]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[11]" SLEW = SLOW;
+NET "EIM_DA[12]" LOC = C7;
+NET "EIM_DA[12]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[12]" SLEW = SLOW;
+
+NET "EIM_DA[13]" LOC = C11;
+NET "EIM_DA[13]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[13]" SLEW = SLOW;
+
+NET "EIM_DA[14]" LOC = C4;
+NET "EIM_DA[14]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[14]" SLEW = SLOW;
+NET "EIM_DA[15]" LOC = B6;
+NET "EIM_DA[15]" IOSTANDARD = LVCMOS33;
+NET "EIM_DA[15]" SLEW = SLOW;
+
+# EIM_A16
+NET "EIM_A16" LOC = A11;
+NET "EIM_A16" IOSTANDARD = LVCMOS33;
+NET "EIM_A16" SLEW = SLOW;
+
+# EIM_A17
+NET "EIM_A17" LOC = B12;
+NET "EIM_A17" IOSTANDARD = LVCMOS33;
+NET "EIM_A17" SLEW = SLOW;
+# EIM_A18
+#NET "ENC_PBIN" LOC = D14;
+#NET "ENC_PBIN" IOSTANDARD = LVCMOS33;
+
+# EIM_LBA
+#NET "EIM_LBA" LOC = B14;
+#NET "EIM_LBA" IOSTANDARD = LVCMOS33;
+# NET "EIM_OE" LOC = C10;
+# NET "EIM_OE" IOSTANDARD = LVCMOS33;
+# EIM_RW
+#NET "LED3" LOC = C14;
+#NET "LED3" IOSTANDARD = LVCMOS33;
+# NET "EIM_WAIT" LOC = A7;
+# NET "EIM_WAIT" IOSTANDARD = LVCMOS33;
+
+# #NET "FPGA_DONE" LOC = V17;
+# #NET "FPGA_DONE" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_HSWAPEN" LOC = D4;
+# #NET "FPGA_HSWAPEN" IOSTANDARD = LVCMOS33;
+# FPGA_INIT_N
+#NET "LED2" LOC = U3;
+#NET "LED2" IOSTANDARD = LVCMOS33;
+
+NET "FPGA_LED2" LOC = A16;
+NET "FPGA_LED2" IOSTANDARD = LVCMOS33;
+NET "FPGA_LED2" SLEW = SLOW;
+
+# NET "FPGA_LSPI_CLK" LOC = D3;
+# NET "FPGA_LSPI_CLK" IOSTANDARD = LVCMOS33;
+# NET "FPGA_LSPI_CS" LOC = D1;
+# NET "FPGA_LSPI_CS" IOSTANDARD = LVCMOS33;
+# NET "FPGA_LSPI_HOLD" LOC = E3;
+# NET "FPGA_LSPI_HOLD" IOSTANDARD = LVCMOS33;
+# NET "FPGA_LSPI_MISO" LOC = D2;
+# NET "FPGA_LSPI_MISO" IOSTANDARD = LVCMOS33;
+# NET "FPGA_LSPI_MOSI" LOC = C2;
+# NET "FPGA_LSPI_MOSI" IOSTANDARD = LVCMOS33;
+# NET "FPGA_LSPI_WP" LOC = C1;
+# NET "FPGA_LSPI_WP" IOSTANDARD = LVCMOS33;
+
+# #NET "FPGA_M0" LOC = T15;
+# #NET "FPGA_M0" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_M1" LOC = N12;
+# #NET "FPGA_M1" IOSTANDARD = LVCMOS33;
+
+# #NET "FPGA_RESET_N" LOC = V2;
+# #NET "FPGA_RESET_N" IOSTANDARD = TMDS_33;
+# #NET "FPGA_SUSPEND" LOC = R16;
+# #NET "FPGA_SUSPEND" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_TCK" LOC = A17;
+# #NET "FPGA_TCK" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_TDI" LOC = D15;
+# #NET "FPGA_TDI" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_TDO" LOC = D16;
+# #NET "FPGA_TDO" IOSTANDARD = LVCMOS33;
+# #NET "FPGA_TMS" LOC = B18;
+# #NET "FPGA_TMS" IOSTANDARD = LVCMOS33;
+
+# # NET "GND" LOC = A1;# A18 B7 B13 C3 C16 D5 D10 E15 G2 G5 G12 G17 H8 H10 J4 J9 J11 J15 K8 K10 L9 L11 M2 M6 M17 N13 R1 R4 R9 R14 R18 T16 U6 U12 V1 V18 
+# # NET "GND" IOSTANDARD = LVCMOS33;
+
+NET "I2C3_SCL" LOC = P4;
+NET "I2C3_SCL" IOSTANDARD = LVCMOS33;
+NET "I2C3_SDA" LOC = P3;
+NET "I2C3_SDA" IOSTANDARD = LVCMOS33;
+
+# # NET "P1_2V" LOC = G7;# H9 H11 J8 J10 K9 K11 L8 L10 M7 M12 
+# # NET "P1_2V" IOSTANDARD = LVCMOS33;
+# # NET "P3_3V_DELAYED" LOC = B1;# B5 B10 B15 B17 D7 D13 E2 E5 E9 E10 E14 E17 G4 G10 G15 J2 J5 J12 J14 J17 K7 M4 M9 M15 P5 P9 P10 P14 R2 R6 R12 R17 U4 U9 U14 
+# # NET "P3_3V_DELAYED" IOSTANDARD = LVCMOS33;
+
+NET "RESETBMCU" LOC = F1;
+NET "RESETBMCU" IOSTANDARD = LVCMOS33;
+
+# NET "SMB_SCL" LOC = N3;
+# NET "SMB_SCL" IOSTANDARD = LVCMOS33;
+# NET "SMB_SDA" LOC = N4;
+# NET "SMB_SDA" IOSTANDARD = LVCMOS33;
+
+# NET "UART4_CTS" LOC = U1;
+# NET "UART4_CTS" IOSTANDARD = LVCMOS33;
+# NET "UART4_RTS" LOC = U2;
+# NET "UART4_RTS" IOSTANDARD = LVCMOS33;
+# NET "UART4_RXD" LOC = T1;
+# NET "UART4_RXD" IOSTANDARD = LVCMOS33;
+# NET "UART4_TXD" LOC = P1;
+# NET "UART4_TXD" IOSTANDARD = LVCMOS33;
+
+# UIM_CLK
+#NET "MODES" LOC = B16;
+#NET "MODES" IOSTANDARD = LVCMOS33;
+# UIM_DATA
+#NET "ENC_SW" LOC = A12;
+#NET "ENC_SW" IOSTANDARD = LVCMOS33;
+# #NET "UIM_PWR" LOC = C18;
+# #NET "UIM_PWR" IOSTANDARD = SSTL15_II;
+# #NET "UIM_PWRON" LOC = A14;
+# #NET "UIM_PWRON" IOSTANDARD = LVCMOS33;
+# UIM_RESET
+#NET "SW_BACKUP" LOC = C15;
+#NET "SW_BACKUP" IOSTANDARD = LVCMOS33;
+
+##############
+# DDR3
+##############
+
+# NET "F_BA[2]" IOSTANDARD = SSTL15_II;
+# NET "F_BA[1]" IOSTANDARD = SSTL15_II;
+# NET "F_BA[0]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[13]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[12]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[11]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[10]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[9]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[8]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[7]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[6]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[5]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[4]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[3]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[2]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[1]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_A[0]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[15]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[14]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[13]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[12]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[11]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[10]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[9]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[8]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[7]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[6]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[5]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[4]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[3]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[2]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[1]" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_D[0]" IOSTANDARD = SSTL15_II;
+# NET "F_CAS_N" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_CKE" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_ODT" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_RST_N" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_RZQ" IOSTANDARD = SSTL15_II;
+# NET "F_DDR3_ZIO" IOSTANDARD = SSTL15_II;
+# NET "F_LDM" IOSTANDARD = SSTL15_II;
+# NET "F_RAS_N" IOSTANDARD = SSTL15_II;
+# NET "F_UDM" IOSTANDARD = SSTL15_II;
+# NET "F_WE_N" IOSTANDARD = SSTL15_II;
+
+
+# NET "F_BA[0]" LOC = H13;
+# NET "F_BA[1]" LOC = H14;
+# NET "F_BA[2]" LOC = K13;
+# NET "F_BA[0]" OUT_TERM = UNTUNED_50;
+# NET "F_BA[1]" OUT_TERM = UNTUNED_50;
+# NET "F_BA[2]" OUT_TERM = UNTUNED_50;
+
+# NET "F_CAS_N" LOC = K16;
+# NET "F_CAS_N" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_A[0]" LOC = H15;
+# NET "F_DDR3_A[1]" LOC = H16;
+# NET "F_DDR3_A[10]" LOC = E16;
+# NET "F_DDR3_A[11]" LOC = G14;
+# NET "F_DDR3_A[12]" LOC = D18;
+# NET "F_DDR3_A[13]" LOC = C17;
+# NET "F_DDR3_A[2]" LOC = F18;
+# NET "F_DDR3_A[3]" LOC = J13;
+# NET "F_DDR3_A[4]" LOC = E18;
+# NET "F_DDR3_A[5]" LOC = L12;
+# NET "F_DDR3_A[6]" LOC = L13;
+# NET "F_DDR3_A[7]" LOC = F17;
+# NET "F_DDR3_A[8]" LOC = H12;
+# NET "F_DDR3_A[9]" LOC = G13;
+# NET "F_DDR3_A[0]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[10]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[11]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[12]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[13]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[1]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[2]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[3]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[4]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[5]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[6]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[7]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[8]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_A[9]" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_CKE" LOC = D17;
+# NET "F_DDR3_CKE" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_CK_N" LOC = G18;
+# NET "F_DDR3_CK_N" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_DDR3_CK_N" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_CK_P" LOC = G16;
+# NET "F_DDR3_CK_P" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_DDR3_CK_P" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_D[0]" LOC = M16;
+# NET "F_DDR3_D[1]" LOC = M18;
+# NET "F_DDR3_D[10]" LOC = P17;
+# NET "F_DDR3_D[11]" LOC = P18;
+# NET "F_DDR3_D[12]" LOC = T17;
+# NET "F_DDR3_D[13]" LOC = T18;
+# NET "F_DDR3_D[14]" LOC = U17;
+# NET "F_DDR3_D[15]" LOC = U18;
+# NET "F_DDR3_D[2]" LOC = L17;
+# NET "F_DDR3_D[3]" LOC = L18;
+# NET "F_DDR3_D[4]" LOC = H17;
+# NET "F_DDR3_D[5]" LOC = H18;
+# NET "F_DDR3_D[6]" LOC = J16;
+# NET "F_DDR3_D[7]" LOC = J18;
+# NET "F_DDR3_D[8]" LOC = N17;
+# NET "F_DDR3_D[9]" LOC = N18;
+# NET "F_DDR3_D[0]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[10]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[11]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[12]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[13]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[14]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[15]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[1]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[2]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[3]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[4]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[5]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[6]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[7]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[8]" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_D[9]" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_RST_N" LOC = F14;
+# NET "F_DDR3_RST_N" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_ODT" LOC = K14;
+# NET "F_DDR3_ODT" OUT_TERM = UNTUNED_50;
+
+# NET "F_RAS_N" LOC = K15;
+# NET "F_RAS_N" OUT_TERM = UNTUNED_50;
+# NET "F_UDM" LOC = L15;
+# NET "F_UDM" OUT_TERM = UNTUNED_50;
+# NET "F_UDQS_N" LOC = N16;
+# NET "F_UDQS_N" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_UDQS_N" OUT_TERM = UNTUNED_50;
+# NET "F_UDQS_P" LOC = N15;
+# NET "F_UDQS_P" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_UDQS_P" OUT_TERM = UNTUNED_50;
+# NET "F_LDM" LOC = L16;
+# NET "F_LDM" OUT_TERM = UNTUNED_50;
+# NET "F_LDQS_N" LOC = K18;
+# NET "F_LDQS_N" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_LDQS_N" OUT_TERM = UNTUNED_50;
+# NET "F_LDQS_P" LOC = K17;
+# NET "F_LDQS_P" IOSTANDARD = DIFF_SSTL15_II;
+# NET "F_LDQS_P" OUT_TERM = UNTUNED_50;
+# NET "F_WE_N" LOC = K12;
+# NET "F_WE_N" OUT_TERM = UNTUNED_50;
+
+# NET "F_DDR3_RZQ" LOC = F15;
+# NET "F_DDR3_RZQ" OUT_TERM = UNTUNED_50;
+# NET "F_DDR3_ZIO" LOC = M14;
+# NET "F_DDR3_ZIO" OUT_TERM = UNTUNED_50;
+
+#NET "F_BA[*]" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_CAS_N" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_DDR3_A[*]" SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_DDR3_CKE" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+
+#NET "F_DDR3_D[*]" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_DDR3_RST_N" IOSTANDARD = SSTL15_II | OUT_TERM = UNTUNED_50;
+
+#NET "F_DDR3_ODT" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_RAS_N" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+#NET "F_UDM" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+#NET "F_LDM" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+#NET "F_WE_N" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+#NET "F_DDR3_RZQ" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+#NET "F_DDR3_ZIO" IOSTANDARD = SSTL15_II  | OUT_TERM = UNTUNED_50;
+
+
+##############
+# I/O connector
+##############
+#NET "F_DX0" LOC = K6;
+#NET "F_DX0" IOSTANDARD = LVCMOS33;
+#NET "F_DX0" SLEW = SLOW;
+# NET "F_DX0" PULLUP;
+
+NET "F_DX1" LOC = L7;
+NET "F_DX1" IOSTANDARD = LVCMOS33;
+NET "F_DX1" SLEW = SLOW;
+
+#NET "F_DX2" LOC = H3;
+#NET "F_DX2" IOSTANDARD = LVCMOS33;
+#NET "F_DX2" SLEW = SLOW;
+
+#NET "F_DX3" LOC = H4;
+#NET "F_DX3" IOSTANDARD = LVCMOS33;
+#NET "F_DX3" SLEW = SLOW;
+# NET "F_DX3" PULLUP;
+
+# NET "F_DX[4]" LOC = J1;
+# NET "F_DX[5]" LOC = J3;
+# NET "F_DX6" LOC = L3;
+# NET "F_DX6" IOSTANDARD = LVCMOS33;
+# NET "F_DX6" SLEW = SLOW;
+
+# NET "F_DX7" LOC = L4;
+# NET "F_DX7" IOSTANDARD = LVCMOS33;
+# NET "F_DX7" SLEW = SLOW;
+
+# NET "F_DX8" LOC = K2;
+# NET "F_DX8" IOSTANDARD = LVCMOS33;
+# NET "F_DX8" SLEW = SLOW;
+
+#NET "F_DX11" LOC = M1;
+#NET "F_DX11" IOSTANDARD = LVCMOS33;
+#NET "F_DX11" SLEW = SLOW;
+# NET "F_DX12" LOC = M3;
+# NET "F_DX12" IOSTANDARD = LVCMOS33;
+# NET "F_DX12" SLEW = SLOW;
+
+# NET "F_DX13" LOC = P2;
+# NET "F_DX13" IOSTANDARD = LVCMOS33;
+# NET "F_DX13" SLEW = SLOW;
+
+# NET "F_DX14" LOC = T2;
+# NET "F_DX14" IOSTANDARD = LVCMOS33;
+# NET "F_DX14" SLEW = SLOW;
+
+NET "F_DX15" LOC = M5;
+NET "F_DX15" IOSTANDARD = LVCMOS33;
+NET "F_DX15" SLEW = SLOW;
+
+# NET "F_DX[16]" LOC = L6;
+NET "F_DX17" LOC = G1;
+NET "F_DX17" IOSTANDARD = LVCMOS33;
+NET "F_DX17" SLEW = SLOW;
+#NET "F_DX18" LOC = H7;
+#NET "F_DX18" IOSTANDARD = LVCMOS33;
+#NET "F_DX18" SLEW = SLOW;
+
+# NET "F_DX[*]" IOSTANDARD = LVCMOS33;
+
+NET "F_LVDS_N0" LOC = P6;
+NET "F_LVDS_N0" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_N0" SLEW = SLOW;
+NET "F_LVDS_P0" LOC = N5;
+NET "F_LVDS_P0" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_P0" SLEW = SLOW;
+# NET "F_LVDS_N1" LOC = V4;
+# NET "F_LVDS_N1" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N1" SLEW = SLOW;
+# NET "F_LVDS_P1" LOC = T4;
+# NET "F_LVDS_P1" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_P1" SLEW = SLOW;
+# NET "F_LVDS_N2" LOC = T3;
+# NET "F_LVDS_N2" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N2" SLEW = SLOW;
+# NET "F_LVDS_P[2]" LOC = R3;
+
+# NET "F_LVDS_N3" LOC = V5;
+# NET "F_LVDS_N3" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N3" SLEW = SLOW;
+
+# NET "F_LVDS_P[3]" LOC = U5;
+# NET "F_LVDS_N4" LOC = T5;
+# NET "F_LVDS_N4" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N4" SLEW = SLOW;
+NET "F_LVDS_P4" LOC = R5;
+NET "F_LVDS_P4" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_P4" SLEW = SLOW;
+
+# NET "F_LVDS_N5" LOC = T7;
+# NET "F_LVDS_N5" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N5" SLEW = SLOW;
+
+# NET "F_LVDS_P5" LOC = R7;
+# NET "F_LVDS_P5" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_P5" SLEW = SLOW;
+
+# NET "F_LVDS_N[6]" LOC = V6;
+# NET "F_LVDS_P[6]" LOC = T6;
+NET "F_LVDS_N7" LOC = V7;
+NET "F_LVDS_N7" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_N7" SLEW = SLOW;
+
+NET "F_LVDS_P7" LOC = U7;
+NET "F_LVDS_P7" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_P7" SLEW = SLOW;
+
+# NET "F_LVDS_N8" LOC = V8;
+# NET "F_LVDS_N8" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_N8" SLEW = SLOW;
+
+# NET "F_LVDS_P[8]" LOC = U8;
+# NET "F_LVDS_N[9]" LOC = V9;
+#NET "F_LVDS_P9" LOC = T9;
+#NET "F_LVDS_P9" IOSTANDARD = LVCMOS33;
+
+# NET "F_LVDS_N[10]" LOC = V11;
+# NET "F_LVDS_P[10]" LOC = U11;
+NET "F_LVDS_N11" LOC = T11;
+NET "F_LVDS_N11" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_N11" SLEW = SLOW;
+NET "F_LVDS_P11" LOC = R11;
+NET "F_LVDS_P11" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_P11" SLEW = SLOW;
+# NET "F_LVDS_N[12]" LOC = V13;
+# NET "F_LVDS_P[12]" LOC = U13;
+# NET "F_LVDS_N[13]" LOC = V14;
+# NET "F_LVDS_P[13]" LOC = T14;
+# NET "F_LVDS_N[14]" LOC = V16;
+# NET "F_LVDS_P[14]" LOC = U16;
+NET "F_LVDS_N15" LOC = V10;
+NET "F_LVDS_N15" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_N15" SLEW = SLOW;
+NET "F_LVDS_P15" LOC = U10;
+NET "F_LVDS_P15" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_P15" SLEW = SLOW;
+
+# NET "F_LVDS_P[*]" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+# NET "F_LVDS_N[*]" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+
+# NET "F_LVDS_NA" LOC = K3;
+# NET "F_LVDS_NA" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+# NET "F_LVDS_PA" LOC = K4;
+# NET "F_LVDS_PA" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+# NET "F_LVDS_NB" LOC = K5;
+# NET "F_LVDS_NB" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_NB" SLEW = SLOW;
+# NET "F_LVDS_PB" LOC = L5;
+# NET "F_LVDS_PB" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_PB" SLEW = SLOW;
+NET "F_LVDS_NC" LOC = L1;
+NET "F_LVDS_NC" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_NC" SLEW = SLOW;
+# NET "F_LVDS_PC" LOC = L2;
+# NET "F_LVDS_PC" IOSTANDARD = LVCMOS33;
+# NET "F_LVDS_PC" SLEW = SLOW;
+
+#NET "F_LVDS_CK0_N" LOC = T8;
+#NET "F_LVDS_CK0_N" IOSTANDARD = LVCMOS33;
+#NET "F_LVDS_CK0_P" LOC = R8;
+#NET "F_LVDS_CK0_P" IOSTANDARD = LVCMOS33;
+
+NET "F_LVDS_CK1_N" LOC = T10;
+NET "F_LVDS_CK1_N" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_CK1_N" SLEW = SLOW;
+NET "F_LVDS_CK1_P" LOC = R10;
+NET "F_LVDS_CK1_P" IOSTANDARD = LVCMOS33;
+NET "F_LVDS_CK1_P" SLEW = SLOW;
+
+# NET "F_LVDS_CK_N[*]" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+# NET "F_LVDS_CK_P[*]" IOSTANDARD = LVDS_33 | DIFF_TERM = TRUE;
+NET "CLK2_P" PERIOD = 20 ns;
diff --git a/build/xilinx.mk b/build/xilinx.mk
new file mode 100644
index 0000000..a3a0216
--- /dev/null
+++ b/build/xilinx.mk
@@ -0,0 +1,176 @@
+# 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
+#
+#   files 		description
+#   ----------  	------------
+#   $(project).ucf	ucf file
+#
+# 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
+
+libmks = $(patsubst %,$(libdir)/%/module.mk,$(libs)) 
+mkfiles = Makefile $(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 $(project).ucf $(project).bmm
+	$(xil_env); ngdbuild $(intstyle) $(project).ngc -bm $(project).bmm
+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/build/xilinx.opt b/build/xilinx.opt
new file mode 100644
index 0000000..7fe9d8b
--- /dev/null
+++ b/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/src/rtl/coretest_hashes.v b/src/rtl/coretest_hashes.v
new file mode 100644
index 0000000..567d4f7
--- /dev/null
+++ b/src/rtl/coretest_hashes.v
@@ -0,0 +1,273 @@
+//======================================================================
+//
+// coretest_hashes.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of the external interface and the
+// cores to be tested, as well as address and data muxes.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// 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 coretest_hashes(
+                       input wire          clk,
+                       input wire          reset_n,
+
+                       // External interface.
+                       input wire          SCL,
+                       input wire          SDA,
+                       output wire         SDA_pd,
+
+                       output wire [7 : 0] debug
+                      );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter I2C_SHA1_ADDR       = 7'h1e;
+  parameter I2C_SHA256_ADDR     = 7'h1f;
+  parameter I2C_SHA512_224_ADDR = 7'h20;
+  parameter I2C_SHA512_256_ADDR = 7'h21;
+  parameter I2C_SHA384_ADDR     = 7'h22;
+  parameter I2C_SHA512_ADDR     = 7'h23;
+
+  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;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  // i2c connections
+  wire          i2c_rxd_syn;
+  wire [7 : 0]  i2c_rxd_data;
+  reg           i2c_rxd_ack;
+  reg           i2c_txd_syn;
+  reg  [7 : 0]  i2c_txd_data;
+  wire          i2c_txd_ack;
+  wire [6 : 0]  i2c_device_addr;
+
+  // sha1 connections.
+  reg           sha1_rxd_syn;
+  reg  [7 : 0]  sha1_rxd_data;
+  wire          sha1_rxd_ack;
+  wire          sha1_txd_syn;
+  wire [7 : 0]  sha1_txd_data;
+  reg           sha1_txd_ack;
+
+  // sha256 connections.
+  reg           sha256_rxd_syn;
+  reg  [7 : 0]  sha256_rxd_data;
+  wire          sha256_rxd_ack;
+  wire          sha256_txd_syn;
+  wire [7 : 0]  sha256_txd_data;
+  reg           sha256_txd_ack;
+
+  // sha512 connections.
+  reg  [1 : 0]  sha512_mode;
+  reg           sha512_rxd_syn;
+  reg  [7 : 0]  sha512_rxd_data;
+  wire          sha512_rxd_ack;
+  wire          sha512_txd_syn;
+  wire [7 : 0]  sha512_txd_data;
+  reg           sha512_txd_ack;
+
+
+  //----------------------------------------------------------------
+  // Core instantiations.
+  //----------------------------------------------------------------
+  i2c_core i2c(
+               .clk(clk),
+               .reset(!reset_n), // active high
+
+               .SCL(SCL),
+               .SDA(SDA),
+               .SDA_pd(SDA_pd),
+               .i2c_addr_low(I2C_SHA1_ADDR),
+               .i2c_addr_high(I2C_SHA512_ADDR),
+               .i2c_device_addr(i2c_device_addr),
+
+               .rxd_syn(i2c_rxd_syn),
+               .rxd_data(i2c_rxd_data),
+               .rxd_ack(i2c_rxd_ack),
+
+               .txd_syn(i2c_txd_syn),
+               .txd_data(i2c_txd_data),
+               .txd_ack(i2c_txd_ack)
+               );
+
+  sha1 sha1(
+            .clk(clk),
+            .reset_n(reset_n),
+
+            .rx_syn(sha1_rxd_syn),
+            .rx_data(sha1_rxd_data),
+            .rx_ack(sha1_rxd_ack),
+
+            .tx_syn(sha1_txd_syn),
+            .tx_data(sha1_txd_data),
+            .tx_ack(sha1_txd_ack)
+           );
+
+  sha256 sha256(
+                .clk(clk),
+                .reset_n(reset_n),
+
+                .rx_syn(sha256_rxd_syn),
+                .rx_data(sha256_rxd_data),
+                .rx_ack(sha256_rxd_ack),
+
+                .tx_syn(sha256_txd_syn),
+                .tx_data(sha256_txd_data),
+                .tx_ack(sha256_txd_ack)
+                );
+
+  sha512 sha512(
+                .clk(clk),
+                .reset_n(reset_n),
+
+                .mode(sha512_mode),
+
+                .rx_syn(sha512_rxd_syn),
+                .rx_data(sha512_rxd_data),
+                .rx_ack(sha512_rxd_ack),
+
+                .tx_syn(sha512_txd_syn),
+                .tx_data(sha512_txd_data),
+                .tx_ack(sha512_txd_ack)
+                );
+
+  //----------------------------------------------------------------
+  // address_mux
+  //
+  // Combinational data mux that handles addressing between
+  // cores using the I2C device address.
+  //----------------------------------------------------------------
+  always @*
+    begin : address_mux
+      // Default assignments.
+      i2c_rxd_ack     = 0;
+      i2c_txd_syn     = 0;
+      i2c_txd_data    = 8'h00;
+
+      sha1_rxd_syn    = 0;
+      sha1_rxd_data   = 8'h00;
+      sha1_txd_ack    = 0;
+
+      sha256_rxd_syn  = 0;
+      sha256_rxd_data = 8'h00;
+      sha256_txd_ack  = 0;
+
+      sha512_rxd_syn  = 0;
+      sha512_rxd_data = 8'h00;
+      sha512_txd_ack  = 0;
+      sha512_mode     = 2'b00;
+
+      case (i2c_device_addr)
+        I2C_SHA1_ADDR:
+          begin
+            sha1_rxd_syn    = i2c_rxd_syn;
+            sha1_rxd_data   = i2c_rxd_data;
+            i2c_rxd_ack     = sha1_rxd_ack;
+            i2c_txd_syn     = sha1_txd_syn;
+            i2c_txd_data    = sha1_txd_data;
+            sha1_txd_ack    = i2c_txd_ack;
+          end
+
+        I2C_SHA256_ADDR:
+          begin
+            sha256_rxd_syn  = i2c_rxd_syn;
+            sha256_rxd_data = i2c_rxd_data;
+            i2c_rxd_ack     = sha256_rxd_ack;
+            i2c_txd_syn     = sha256_txd_syn;
+            i2c_txd_data    = sha256_txd_data;
+            sha256_txd_ack  = i2c_txd_ack;
+          end
+
+        I2C_SHA512_224_ADDR:
+          begin
+            sha512_rxd_syn  = i2c_rxd_syn;
+            sha512_rxd_data = i2c_rxd_data;
+            i2c_rxd_ack     = sha512_rxd_ack;
+            i2c_txd_syn     = sha512_txd_syn;
+            i2c_txd_data    = sha512_txd_data;
+            sha512_txd_ack  = i2c_txd_ack;
+            sha512_mode     = MODE_SHA_512_224;
+          end
+
+        I2C_SHA512_256_ADDR:
+          begin
+            sha512_rxd_syn  = i2c_rxd_syn;
+            sha512_rxd_data = i2c_rxd_data;
+            i2c_rxd_ack     = sha512_rxd_ack;
+            i2c_txd_syn     = sha512_txd_syn;
+            i2c_txd_data    = sha512_txd_data;
+            sha512_txd_ack  = i2c_txd_ack;
+            sha512_mode     = MODE_SHA_512_256;
+          end
+
+        I2C_SHA384_ADDR:
+          begin
+            sha512_rxd_syn  = i2c_rxd_syn;
+            sha512_rxd_data = i2c_rxd_data;
+            i2c_rxd_ack     = sha512_rxd_ack;
+            i2c_txd_syn     = sha512_txd_syn;
+            i2c_txd_data    = sha512_txd_data;
+            sha512_txd_ack  = i2c_txd_ack;
+            sha512_mode     = MODE_SHA_384;
+          end
+
+        I2C_SHA512_ADDR:
+          begin
+            sha512_rxd_syn  = i2c_rxd_syn;
+            sha512_rxd_data = i2c_rxd_data;
+            i2c_rxd_ack     = sha512_rxd_ack;
+            i2c_txd_syn     = sha512_txd_syn;
+            i2c_txd_data    = sha512_txd_data;
+            sha512_txd_ack  = i2c_txd_ack;
+            sha512_mode     = MODE_SHA_512;
+          end
+
+        default:
+          begin
+          end
+      endcase // case (i2c_device_addr)
+    end // address_mux
+
+endmodule // coretest_hashes
+
+//======================================================================
+// EOF coretest_hashes.v
+//======================================================================
diff --git a/src/rtl/i2c_core.v b/src/rtl/i2c_core.v
new file mode 100644
index 0000000..cbf76c6
--- /dev/null
+++ b/src/rtl/i2c_core.v
@@ -0,0 +1,581 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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
+
+module i2c_core (
+                 input wire 	    clk,
+                 input wire 	    reset,
+
+                 // External data interface
+		 input wire 	    SCL,
+		 input wire 	    SDA,
+		 output reg 	    SDA_pd,
+		 input wire [6:0]   i2c_addr_low,
+		 input wire [6:0]   i2c_addr_high,
+		 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) //synthesis parallel_case full_case
+	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[7:1] >= i2c_addr_low) &&
+			 (I2C_daddr[7:1] <= i2c_addr_high)) ?
+			(I2C_daddr[0] == 1'b0 ? I2C_WR_DATA : I2C_TXD_SYN) :
+			I2C_WAITSTOP : // !I2C_daddr match
+			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) // synthesis parallel_case full_case
+	   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) //synthesis parallel_case full_case
+	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) // synthesis parallel_case full_case
+	   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) //synthesis parallel_case full_case
+	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) // synthesis parallel_case full_case
+	   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/src/rtl/novena_fpga.v b/src/rtl/novena_fpga.v
new file mode 100644
index 0000000..fd0f667
--- /dev/null
+++ b/src/rtl/novena_fpga.v
@@ -0,0 +1,147 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2013, Andrew "bunnie" Huang
+//
+// See the NOTICE file distributed with this work for additional 
+// information regarding copyright ownership.  The copyright holder 
+// licenses this file to you under the Apache License, Version 2.0 
+// (the "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// code distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//////////////////////////////////////////////////////////////////////////////
+
+/// note: must set "-g UnusedPin:Pullnone" to avoid conflicts with unused pins
+
+`timescale 1ns / 1ps
+
+module novena_fpga(
+	// CPU side mapping
+	input wire [15:0] EIM_DA,
+	output reg EIM_A16,  // relay of the trigger output
+	output reg EIM_A17,  // relay of the trigger data (read path)
+
+	// connector side mapping
+	//input wire F_LVDS_N3, // output of trigger
+	//input wire F_DX2,       // output of trigger
+	//output wire F_LVDS_N5, // trigger reset
+	output wire F_LVDS_P4,   // trigger reset
+	//inout wire F_LVDS_P5, // trigger data (bidir)
+	//input wire F_DX18,      // trigger data in from sticker (DUT->CPU)
+	output wire F_LVDS_P11, // trigger data out to sticker (CPU->DUT)
+	//output wire F_LVDS_N8, // trigger clock
+	//output wire F_DX14,      // trigger clock
+
+	output wire F_LVDS_N7, // drive TPI data line
+	output wire F_LVDS_P7, // drive TPI signal lines
+
+	output wire F_DX15,  // 1 = drive 5V, 0 = drive 3V to DUT
+
+	output wire F_LVDS_CK1_N,
+	output wire F_LVDS_CK1_P,
+	output wire F_LVDS_N11,
+
+	output wire F_LVDS_N0,
+	output wire F_LVDS_P0,
+	output wire F_DX1,
+
+	output wire F_LVDS_N15,
+	output wire F_LVDS_P15,
+	output wire F_LVDS_NC,
+
+	//input wire F_DX11,
+	//input wire F_DX3,
+	//input wire F_DX0,
+
+	//input wire F_LVDS_CK0_P,
+	//input wire F_LVDS_CK0_N,
+	//input wire F_LVDS_P9,
+
+	//input wire [1:0] EIM_CS,
+	//input wire EIM_LBA,
+
+	input wire CLK2_N,
+	input wire CLK2_P,
+	output wire FPGA_LED2,
+
+	input wire I2C3_SCL,
+	inout wire I2C3_SDA,
+
+	input wire RESETBMCU,
+	output wire F_DX17,  // dummy
+	output wire APOPTOSIS
+);
+	wire clk;
+
+	IBUFGDS clkibufgds(
+		.I(CLK2_P),
+		.IB(CLK2_N),
+		.O(clk)
+	);
+
+	assign FPGA_LED2 = 1'b1;
+
+	assign APOPTOSIS = 1'b0;
+	assign F_DX15 = 1'b1; //+5V P_DUT
+   
+	// OE on bank to drive signals; signal not inverted in software
+	assign F_LVDS_P7 = !EIM_DA[3];
+	// OE on bank to drive the data; signal not inverted in software
+	assign F_LVDS_N7 = !EIM_DA[4];
+	assign F_LVDS_P4 = 1'b0;
+	assign F_LVDS_P11 = 1'b0;
+	assign F_LVDS_CK1_N = 1'b0;
+	assign F_LVDS_CK1_P = 1'b0;
+	assign F_LVDS_N11 = 1'b0;
+	assign F_LVDS_N0 = 1'b0;
+	assign F_LVDS_P0 = 1'b0;
+	assign F_DX1 = 1'b0;
+	assign F_LVDS_N15 = 1'b0;
+	assign F_LVDS_P15 = 1'b0;
+	assign F_LVDS_NC = 1'b0;
+
+	// reduction and of EIM_DA, dummy-map to keep compiler quiet
+	assign F_DX17 = &EIM_DA | RESETBMCU;
+   
+	////////////////////////////////////
+	///// I2C register set
+	////////////////////////////////////
+	wire       SDA_pd;
+	wire       SDA_int;
+	reg        clk25;
+   
+	initial begin
+		clk25 <= 1'b0;
+	end
+	always @ (posedge clk) begin
+		clk25 <= ~clk25;
+		EIM_A16 <= 1'b0;
+		EIM_A17 <= 1'b0;
+	end
+   
+	IOBUF #(
+		.DRIVE(8),
+		.SLEW("SLOW")
+	) IOBUF_sda (
+		.IO(I2C3_SDA),
+		.I(1'b0),
+		.T(!SDA_pd),
+		.O(SDA_int)
+	);
+
+   coretest_hashes top(
+		       .clk(clk25),
+		       .reset_n(1'b1),
+      
+		       .SCL(I2C3_SCL),
+		       .SDA(SDA_int),
+		       .SDA_pd(SDA_pd)
+		       );
+
+endmodule
diff --git a/src/rtl/sha1.v b/src/rtl/sha1.v
new file mode 100644
index 0000000..2bf0de7
--- /dev/null
+++ b/src/rtl/sha1.v
@@ -0,0 +1,421 @@
+//======================================================================
+//
+// sha1.v
+// ------
+// Top level wrapper for the SHA-1 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// 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 sha1(
+            // Clock and reset.
+            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
+            );
+
+   //----------------------------------------------------------------
+   // Internal constant and parameter definitions.
+   //----------------------------------------------------------------
+   parameter RX_INIT = 0;
+   parameter RX_SYN  = 1;
+   parameter RX_ACK  = 2;
+   parameter RX_WAIT = 3;
+
+   parameter TX_INIT = 0;
+   parameter TX_SYN  = 1;
+   parameter TX_ACK  = 2;
+
+   parameter BLOCK_BITS   = 512;
+   parameter BLOCK_BYTES  = BLOCK_BITS / 8;
+   parameter DIGEST_BITS  = 160;
+   parameter DIGEST_BYTES = DIGEST_BITS / 8;
+
+   //----------------------------------------------------------------
+   // Registers including update variables and write enable.
+   //----------------------------------------------------------------
+   reg                          rx_ack_reg;
+   reg                          rx_ack_new;
+   reg                          rx_ack_we;
+
+   reg [6 : 0]                  rx_ptr_reg;
+   reg [7 : 0]                  rx_ptr_new;
+   reg                          rx_ptr_we;
+
+   reg [1 : 0]                  rx_ctrl_reg;
+   reg [1 : 0]                  rx_ctrl_new;
+   reg                          rx_ctrl_we;
+
+   reg [7 : 0]                  block_reg [0 : BLOCK_BYTES - 1];
+   reg [7 : 0]                  block_new;
+   reg                          block_we;
+
+   reg                          init_reg;
+   reg                          init_new;
+   reg                          init_we;
+
+   reg                          next_reg;
+   reg                          next_new;
+   reg                          next_we;
+
+   reg                          initnext_reg;
+   reg                          initnext_new;
+   reg                          initnext_we;
+
+   reg                          tx_syn_reg;
+   reg                          tx_syn_new;
+   reg                          tx_syn_we;
+
+   reg [6 : 0]                  tx_ptr_reg;
+   reg [7 : 0]                  tx_ptr_new;
+   reg                          tx_ptr_we;
+
+   reg [1 : 0]                  tx_ctrl_reg;
+   reg [1 : 0]                  tx_ctrl_new;
+   reg                          tx_ctrl_we;
+
+   reg                          tx_active_reg;
+   reg                          tx_active_new;
+   reg                          tx_active_we;
+
+   wire [7 : 0]                 digest_reg [0 : DIGEST_BYTES - 1];
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                         core_init;
+   wire                         core_next;
+   wire                         core_ready;
+   wire [BLOCK_BITS - 1 : 0]    core_block;
+   wire [DIGEST_BITS - 1 : 0]   core_digest;
+   wire                         core_digest_valid;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init  = init_reg;
+   assign core_next  = next_reg;
+   assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+                        block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+                        block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+                        block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+                        block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+                        block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+                        block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+                        block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+                        block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+                        block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+                        block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+                        block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+                        block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+                        block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+                        block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+                        block_reg[60], block_reg[61], block_reg[62], block_reg[63]};
+
+   assign rx_ack     = rx_ack_reg;
+   assign tx_syn     = tx_syn_reg;
+   assign tx_data    = digest_reg[tx_ptr_reg];
+
+   assign digest_reg[0]  = core_digest[159 : 152];
+   assign digest_reg[1]  = core_digest[151 : 144];
+   assign digest_reg[2]  = core_digest[143 : 136];
+   assign digest_reg[3]  = core_digest[135 : 128];
+   assign digest_reg[4]  = core_digest[127 : 120];
+   assign digest_reg[5]  = core_digest[119 : 112];
+   assign digest_reg[6]  = core_digest[111 : 104];
+   assign digest_reg[7]  = core_digest[103 : 96];
+   assign digest_reg[8]  = core_digest[95 : 88];
+   assign digest_reg[9]  = core_digest[87 : 80];
+   assign digest_reg[10] = core_digest[79 : 72];
+   assign digest_reg[11] = core_digest[71 : 64];
+   assign digest_reg[12] = core_digest[63 : 56];
+   assign digest_reg[13] = core_digest[55 : 48];
+   assign digest_reg[14] = core_digest[47 : 40];
+   assign digest_reg[15] = core_digest[39 : 32];
+   assign digest_reg[16] = core_digest[31 : 24];
+   assign digest_reg[17] = core_digest[23 : 16];
+   assign digest_reg[18] = core_digest[15 : 8];
+   assign digest_reg[19] = core_digest[7 : 0];
+
+   //----------------------------------------------------------------
+   // 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)
+                  );
+
+   //----------------------------------------------------------------
+   // 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: reset_reg
+             reg[7:0] i;
+             for (i = 0; i < BLOCK_BYTES; i = i + 1)
+               block_reg[i] <= 0;
+             rx_ack_reg   <= 0;
+             rx_ptr_reg   <= 0;
+             rx_ctrl_reg  <= RX_INIT;
+             tx_syn_reg   <= 0;
+             tx_ptr_reg   <= 0;
+             tx_ctrl_reg  <= TX_INIT;
+             initnext_reg <= 0;
+          end
+        else
+          begin
+             if (rx_ack_we)
+               begin
+                  rx_ack_reg <= rx_ack_new;
+               end
+
+             if (rx_ptr_we)
+               begin
+                  rx_ptr_reg <= rx_ptr_new[6:0];
+               end
+
+             if (rx_ctrl_we)
+               begin
+                  rx_ctrl_reg <= rx_ctrl_new;
+               end
+
+             if (block_we)
+               begin
+                  block_reg[rx_ptr_reg] <= block_new;
+               end
+
+             if (init_we)
+               begin
+                  init_reg <= init_new;
+               end
+
+             if (next_we)
+               begin
+                  next_reg <= next_new;
+               end
+
+             if (initnext_we)
+               begin
+                  initnext_reg <= initnext_new;
+               end
+
+             if (tx_syn_we)
+               begin
+                  tx_syn_reg <= tx_syn_new;
+               end
+
+             if (tx_ptr_we)
+               begin
+                  tx_ptr_reg <= tx_ptr_new[6:0];
+               end
+
+             if (tx_ctrl_we)
+               begin
+                  tx_ctrl_reg <= tx_ctrl_new;
+               end
+
+             if (tx_active_we)
+               begin
+                  tx_active_reg <= tx_active_new;
+               end
+          end
+     end // reg_update
+
+   //----------------------------------------------------------------
+   // rx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: rx_engine
+        rx_ack_new = 0;
+        rx_ack_we = 0;
+        rx_ptr_new = 0;
+        rx_ptr_we = 0;
+        rx_ctrl_new = 0;
+        rx_ctrl_we = 0;
+        block_new = 0;
+        block_we = 0;
+        init_new = 0;
+        init_we = 0;
+        next_new = 0;
+        next_we = 0;
+        initnext_new = 0;
+        initnext_we = 0;
+
+        if (tx_active_reg)
+          begin
+             initnext_we = 1;
+          end
+
+        case (rx_ctrl_reg)
+          RX_INIT:
+            if (core_ready)
+              begin
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+              end
+          RX_SYN:
+            if (rx_syn)
+              begin
+                 rx_ack_new = 1;
+                 rx_ack_we = 1;
+                 block_new = rx_data;
+                 block_we = 1;
+                 rx_ctrl_new = RX_ACK;
+                 rx_ctrl_we = 1;
+              end
+          RX_ACK:
+            if (!rx_syn)
+              begin
+                 rx_ack_new = 0;
+                 rx_ack_we = 1;
+                 rx_ptr_new = rx_ptr_reg + 1;
+                 rx_ptr_we = 1;
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+                 if (rx_ptr_new == BLOCK_BYTES)
+                   begin
+                      rx_ptr_new = 0;
+                      rx_ctrl_new = RX_WAIT;
+                      if (initnext_reg == 0)
+                        begin
+                           init_new = 1;
+                           init_we = 1;
+                           initnext_new = 1;
+                           initnext_we = 1;
+                        end
+                      else
+                        begin
+                           next_new = 1;
+                           next_we = 1;
+                        end
+                   end
+              end
+          RX_WAIT:
+            if (!core_ready)
+              begin
+                 init_new = 0;
+                 init_we = 1;
+                 next_new = 0;
+                 next_we = 1;
+                 rx_ctrl_new = RX_INIT;
+                 rx_ctrl_we = 1;
+              end
+        endcase // case (rx_ctrl_reg)
+     end // rx_engine
+
+   //----------------------------------------------------------------
+   // tx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: tx_engine
+        tx_syn_new = 0;
+        tx_syn_we = 0;
+        tx_ptr_new = 0;
+        tx_ptr_we = 0;
+        tx_ctrl_new = 0;
+        tx_ctrl_we = 0;
+        tx_active_new = 0;
+        tx_active_we = 0;
+
+        case (tx_ctrl_reg)
+          TX_INIT:
+            if (core_digest_valid)
+              begin
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+              end
+          TX_SYN:
+            begin
+               tx_syn_new = 1;
+               tx_syn_we = 1;
+               tx_ctrl_new = TX_ACK;
+               tx_ctrl_we = 1;
+            end
+          TX_ACK:
+            if (!core_digest_valid)
+              begin
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = 0;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_INIT;
+                 tx_ctrl_we = 1;
+              end
+            else if (tx_ack)
+              begin
+                 tx_active_new = 1;
+                 tx_active_we = 1;
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = tx_ptr_reg + 1;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+                 if (tx_ptr_new == DIGEST_BYTES)
+                   begin
+                      tx_active_new = 0;
+                      tx_ptr_new = 0;
+                      tx_ctrl_new = TX_INIT;
+                   end
+              end
+        endcase // case (tx_ctrl_reg)
+     end // tx_engine
+
+endmodule // sha1
+
+//======================================================================
+// EOF sha1.v
+//======================================================================
diff --git a/src/rtl/sha256.v b/src/rtl/sha256.v
new file mode 100644
index 0000000..d28a914
--- /dev/null
+++ b/src/rtl/sha256.v
@@ -0,0 +1,433 @@
+//======================================================================
+//
+// sha256.v
+// --------
+// Top level wrapper for the SHA-256 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// 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 sha256(
+              // Clock and reset.
+              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
+              );
+
+   //----------------------------------------------------------------
+   // Internal constant and parameter definitions.
+   //----------------------------------------------------------------
+   parameter RX_INIT = 0;
+   parameter RX_SYN  = 1;
+   parameter RX_ACK  = 2;
+   parameter RX_WAIT = 3;
+
+   parameter TX_INIT = 0;
+   parameter TX_SYN  = 1;
+   parameter TX_ACK  = 2;
+
+   parameter BLOCK_BITS   = 512;
+   parameter BLOCK_BYTES  = BLOCK_BITS / 8;
+   parameter DIGEST_BITS  = 256;
+   parameter DIGEST_BYTES = DIGEST_BITS / 8;
+
+   //----------------------------------------------------------------
+   // Registers including update variables and write enable.
+   //----------------------------------------------------------------
+   reg                          rx_ack_reg;
+   reg                          rx_ack_new;
+   reg                          rx_ack_we;
+
+   reg [6 : 0]                  rx_ptr_reg;
+   reg [7 : 0]                  rx_ptr_new;
+   reg                          rx_ptr_we;
+
+   reg [1 : 0]                  rx_ctrl_reg;
+   reg [1 : 0]                  rx_ctrl_new;
+   reg                          rx_ctrl_we;
+
+   reg [7 : 0]                  block_reg [0 : BLOCK_BYTES - 1];
+   reg [7 : 0]                  block_new;
+   reg                          block_we;
+
+   reg                          init_reg;
+   reg                          init_new;
+   reg                          init_we;
+
+   reg                          next_reg;
+   reg                          next_new;
+   reg                          next_we;
+
+   reg                          initnext_reg;
+   reg                          initnext_new;
+   reg                          initnext_we;
+
+   reg                          tx_syn_reg;
+   reg                          tx_syn_new;
+   reg                          tx_syn_we;
+
+   reg [6 : 0]                  tx_ptr_reg;
+   reg [7 : 0]                  tx_ptr_new;
+   reg                          tx_ptr_we;
+
+   reg [1 : 0]                  tx_ctrl_reg;
+   reg [1 : 0]                  tx_ctrl_new;
+   reg                          tx_ctrl_we;
+
+   reg                          tx_active_reg;
+   reg                          tx_active_new;
+   reg                          tx_active_we;
+
+   wire [7 : 0]                 digest_reg [0 : DIGEST_BYTES - 1];
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                         core_init;
+   wire                         core_next;
+   wire                         core_ready;
+   wire [BLOCK_BITS - 1 : 0]    core_block;
+   wire [DIGEST_BITS - 1 : 0]   core_digest;
+   wire                         core_digest_valid;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init  = init_reg;
+   assign core_next  = next_reg;
+   assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+                        block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+                        block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+                        block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+                        block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+                        block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+                        block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+                        block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+                        block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+                        block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+                        block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+                        block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+                        block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+                        block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+                        block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+                        block_reg[60], block_reg[61], block_reg[62], block_reg[63]};
+
+   assign rx_ack     = rx_ack_reg;
+   assign tx_syn     = tx_syn_reg;
+   assign tx_data    = digest_reg[tx_ptr_reg];
+
+   assign digest_reg[0]  = core_digest[255 : 248];
+   assign digest_reg[1]  = core_digest[247 : 240];
+   assign digest_reg[2]  = core_digest[239 : 232];
+   assign digest_reg[3]  = core_digest[231 : 224];
+   assign digest_reg[4]  = core_digest[223 : 216];
+   assign digest_reg[5]  = core_digest[215 : 208];
+   assign digest_reg[6]  = core_digest[207 : 200];
+   assign digest_reg[7]  = core_digest[199 : 192];
+   assign digest_reg[8]  = core_digest[191 : 184];
+   assign digest_reg[9]  = core_digest[183 : 176];
+   assign digest_reg[10] = core_digest[175 : 168];
+   assign digest_reg[11] = core_digest[167 : 160];
+   assign digest_reg[12] = core_digest[159 : 152];
+   assign digest_reg[13] = core_digest[151 : 144];
+   assign digest_reg[14] = core_digest[143 : 136];
+   assign digest_reg[15] = core_digest[135 : 128];
+   assign digest_reg[16] = core_digest[127 : 120];
+   assign digest_reg[17] = core_digest[119 : 112];
+   assign digest_reg[18] = core_digest[111 : 104];
+   assign digest_reg[19] = core_digest[103 : 96];
+   assign digest_reg[20] = core_digest[95 : 88];
+   assign digest_reg[21] = core_digest[87 : 80];
+   assign digest_reg[22] = core_digest[79 : 72];
+   assign digest_reg[23] = core_digest[71 : 64];
+   assign digest_reg[24] = core_digest[63 : 56];
+   assign digest_reg[25] = core_digest[55 : 48];
+   assign digest_reg[26] = core_digest[47 : 40];
+   assign digest_reg[27] = core_digest[39 : 32];
+   assign digest_reg[28] = core_digest[31 : 24];
+   assign digest_reg[29] = core_digest[23 : 16];
+   assign digest_reg[30] = core_digest[15 : 8];
+   assign digest_reg[31] = core_digest[7 : 0];
+
+   //----------------------------------------------------------------
+   // 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)
+                    );
+
+   //----------------------------------------------------------------
+   // 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: reset_reg
+             reg[7:0] i;
+             for (i = 0; i < BLOCK_BYTES; i = i + 1)
+               block_reg[i] <= 0;
+             rx_ack_reg   <= 0;
+             rx_ptr_reg   <= 0;
+             rx_ctrl_reg  <= RX_INIT;
+             tx_syn_reg   <= 0;
+             tx_ptr_reg   <= 0;
+             tx_ctrl_reg  <= TX_INIT;
+             initnext_reg <= 0;
+          end
+        else
+          begin
+             if (rx_ack_we)
+               begin
+                  rx_ack_reg <= rx_ack_new;
+               end
+
+             if (rx_ptr_we)
+               begin
+                  rx_ptr_reg <= rx_ptr_new[6:0];
+               end
+
+             if (rx_ctrl_we)
+               begin
+                  rx_ctrl_reg <= rx_ctrl_new;
+               end
+
+             if (block_we)
+               begin
+                  block_reg[rx_ptr_reg] <= block_new;
+               end
+
+             if (init_we)
+               begin
+                  init_reg <= init_new;
+               end
+
+             if (next_we)
+               begin
+                  next_reg <= next_new;
+               end
+
+             if (initnext_we)
+               begin
+                  initnext_reg <= initnext_new;
+               end
+
+             if (tx_syn_we)
+               begin
+                  tx_syn_reg <= tx_syn_new;
+               end
+
+             if (tx_ptr_we)
+               begin
+                  tx_ptr_reg <= tx_ptr_new[6:0];
+               end
+
+             if (tx_ctrl_we)
+               begin
+                  tx_ctrl_reg <= tx_ctrl_new;
+               end
+
+             if (tx_active_we)
+               begin
+                  tx_active_reg <= tx_active_new;
+               end
+          end
+     end // reg_update
+
+   //----------------------------------------------------------------
+   // rx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: rx_engine
+        rx_ack_new = 0;
+        rx_ack_we = 0;
+        rx_ptr_new = 0;
+        rx_ptr_we = 0;
+        rx_ctrl_new = 0;
+        rx_ctrl_we = 0;
+        block_new = 0;
+        block_we = 0;
+        init_new = 0;
+        init_we = 0;
+        next_new = 0;
+        next_we = 0;
+        initnext_new = 0;
+        initnext_we = 0;
+
+        if (tx_active_reg)
+          begin
+             initnext_we = 1;
+          end
+
+        case (rx_ctrl_reg)
+          RX_INIT:
+            if (core_ready)
+              begin
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+              end
+          RX_SYN:
+            if (rx_syn)
+              begin
+                 rx_ack_new = 1;
+                 rx_ack_we = 1;
+                 block_new = rx_data;
+                 block_we = 1;
+                 rx_ctrl_new = RX_ACK;
+                 rx_ctrl_we = 1;
+              end
+          RX_ACK:
+            if (!rx_syn)
+              begin
+                 rx_ack_new = 0;
+                 rx_ack_we = 1;
+                 rx_ptr_new = rx_ptr_reg + 1;
+                 rx_ptr_we = 1;
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+                 if (rx_ptr_new == BLOCK_BYTES)
+                   begin
+                      rx_ptr_new = 0;
+                      rx_ctrl_new = RX_WAIT;
+                      if (initnext_reg == 0)
+                        begin
+                           init_new = 1;
+                           init_we = 1;
+                           initnext_new = 1;
+                           initnext_we = 1;
+                        end
+                      else
+                        begin
+                           next_new = 1;
+                           next_we = 1;
+                        end
+                   end
+              end
+          RX_WAIT:
+            if (!core_ready)
+              begin
+                 init_new = 0;
+                 init_we = 1;
+                 next_new = 0;
+                 next_we = 1;
+                 rx_ctrl_new = RX_INIT;
+                 rx_ctrl_we = 1;
+              end
+        endcase // case (rx_ctrl_reg)
+     end // rx_engine
+
+   //----------------------------------------------------------------
+   // tx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: tx_engine
+        tx_syn_new = 0;
+        tx_syn_we = 0;
+        tx_ptr_new = 0;
+        tx_ptr_we = 0;
+        tx_ctrl_new = 0;
+        tx_ctrl_we = 0;
+        tx_active_new = 0;
+        tx_active_we = 0;
+
+        case (tx_ctrl_reg)
+          TX_INIT:
+            if (core_digest_valid)
+              begin
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+              end
+          TX_SYN:
+            begin
+               tx_syn_new = 1;
+               tx_syn_we = 1;
+               tx_ctrl_new = TX_ACK;
+               tx_ctrl_we = 1;
+            end
+          TX_ACK:
+            if (!core_digest_valid)
+              begin
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = 0;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_INIT;
+                 tx_ctrl_we = 1;
+              end
+            else if (tx_ack)
+              begin
+                 tx_active_new = 1;
+                 tx_active_we = 1;
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = tx_ptr_reg + 1;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+                 if (tx_ptr_new == DIGEST_BYTES)
+                   begin
+                      tx_active_new = 0;
+                      tx_ptr_new = 0;
+                      tx_ctrl_new = TX_INIT;
+                   end
+              end
+        endcase // case (tx_ctrl_reg)
+     end // tx_engine
+
+endmodule // sha256
+
+//======================================================================
+// EOF sha256.v
+//======================================================================
diff --git a/src/rtl/sha512.v b/src/rtl/sha512.v
new file mode 100644
index 0000000..9e9b3d5
--- /dev/null
+++ b/src/rtl/sha512.v
@@ -0,0 +1,497 @@
+//======================================================================
+//
+// sha512.v
+// --------
+// Top level wrapper for the SHA-512 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// 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(
+              // Clock and reset.
+              input wire          clk,
+              input wire          reset_n,
+
+              // SHA-512 mode
+              input wire [1 : 0]  mode,
+
+              // 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
+              );
+
+   //----------------------------------------------------------------
+   // Internal constant and parameter definitions.
+   //----------------------------------------------------------------
+   parameter RX_INIT = 0;
+   parameter RX_SYN  = 1;
+   parameter RX_ACK  = 2;
+   parameter RX_WAIT = 3;
+
+   parameter TX_INIT = 0;
+   parameter TX_SYN  = 1;
+   parameter TX_ACK  = 2;
+
+   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 BLOCK_BITS           = 1024;
+   parameter BLOCK_BYTES          = BLOCK_BITS / 8;
+   parameter DIGEST_BITS          = 512;
+   parameter DIGEST_BYTES         = DIGEST_BITS / 8;
+   parameter DIGEST_BYTES_512_224 = 224 / 8;
+   parameter DIGEST_BYTES_512_256 = 256 / 8;
+   parameter DIGEST_BYTES_384     = 384 / 8;
+   parameter DIGEST_BYTES_512     = 512 / 8;
+
+   //----------------------------------------------------------------
+   // Registers including update variables and write enable.
+   //----------------------------------------------------------------
+   reg                          rx_ack_reg;
+   reg                          rx_ack_new;
+   reg                          rx_ack_we;
+
+   reg [6 : 0]                  rx_ptr_reg;
+   reg [7 : 0]                  rx_ptr_new;
+   reg                          rx_ptr_we;
+
+   reg [1 : 0]                  rx_ctrl_reg;
+   reg [1 : 0]                  rx_ctrl_new;
+   reg                          rx_ctrl_we;
+
+   reg [7 : 0]                  block_reg [0 : BLOCK_BYTES - 1];
+   reg [7 : 0]                  block_new;
+   reg                          block_we;
+
+   reg                          init_reg;
+   reg                          init_new;
+   reg                          init_we;
+
+   reg                          next_reg;
+   reg                          next_new;
+   reg                          next_we;
+
+   reg                          initnext_reg;
+   reg                          initnext_new;
+   reg                          initnext_we;
+
+   reg                          tx_syn_reg;
+   reg                          tx_syn_new;
+   reg                          tx_syn_we;
+
+   reg [6 : 0]                  tx_ptr_reg;
+   reg [7 : 0]                  tx_ptr_new;
+   reg                          tx_ptr_we;
+
+   reg [1 : 0]                  tx_ctrl_reg;
+   reg [1 : 0]                  tx_ctrl_new;
+   reg                          tx_ctrl_we;
+
+   reg                          tx_active_reg;
+   reg                          tx_active_new;
+   reg                          tx_active_we;
+
+   wire [7 : 0]                 digest_reg [0 : DIGEST_BYTES - 1];
+
+   //----------------------------------------------------------------
+   // Wires.
+   //----------------------------------------------------------------
+   wire                         core_init;
+   wire                         core_next;
+   wire                         core_ready;
+   wire [BLOCK_BITS - 1 : 0]    core_block;
+   wire [DIGEST_BITS - 1 : 0]   core_digest;
+   wire                         core_digest_valid;
+
+   //----------------------------------------------------------------
+   // Concurrent connectivity for ports etc.
+   //----------------------------------------------------------------
+   assign core_init  = init_reg;
+   assign core_next  = next_reg;
+   assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+                        block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+                        block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+                        block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+                        block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+                        block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+                        block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+                        block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+                        block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+                        block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+                        block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+                        block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+                        block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+                        block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+                        block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+                        block_reg[60], block_reg[61], block_reg[62], block_reg[63],
+                        block_reg[64], block_reg[65], block_reg[66], block_reg[67],
+                        block_reg[68], block_reg[69], block_reg[70], block_reg[71],
+                        block_reg[72], block_reg[73], block_reg[74], block_reg[75],
+                        block_reg[76], block_reg[77], block_reg[78], block_reg[79],
+                        block_reg[80], block_reg[81], block_reg[82], block_reg[83],
+                        block_reg[84], block_reg[85], block_reg[86], block_reg[87],
+                        block_reg[88], block_reg[89], block_reg[90], block_reg[91],
+                        block_reg[92], block_reg[93], block_reg[94], block_reg[95],
+                        block_reg[96], block_reg[97], block_reg[98], block_reg[99],
+                        block_reg[100], block_reg[101], block_reg[102], block_reg[103],
+                        block_reg[104], block_reg[105], block_reg[106], block_reg[107],
+                        block_reg[108], block_reg[109], block_reg[110], block_reg[111],
+                        block_reg[112], block_reg[113], block_reg[114], block_reg[115],
+                        block_reg[116], block_reg[117], block_reg[118], block_reg[119],
+                        block_reg[120], block_reg[121], block_reg[122], block_reg[123],
+                        block_reg[124], block_reg[125], block_reg[126], block_reg[127]};
+
+   assign rx_ack     = rx_ack_reg;
+   assign tx_syn     = tx_syn_reg;
+   assign tx_data    = digest_reg[tx_ptr_reg];
+
+   assign digest_reg[0]  = core_digest[511 : 504];
+   assign digest_reg[1]  = core_digest[503 : 496];
+   assign digest_reg[2]  = core_digest[495 : 488];
+   assign digest_reg[3]  = core_digest[487 : 480];
+   assign digest_reg[4]  = core_digest[479 : 472];
+   assign digest_reg[5]  = core_digest[471 : 464];
+   assign digest_reg[6]  = core_digest[463 : 456];
+   assign digest_reg[7]  = core_digest[455 : 448];
+   assign digest_reg[8]  = core_digest[447 : 440];
+   assign digest_reg[9]  = core_digest[439 : 432];
+   assign digest_reg[10] = core_digest[431 : 424];
+   assign digest_reg[11] = core_digest[423 : 416];
+   assign digest_reg[12] = core_digest[415 : 408];
+   assign digest_reg[13] = core_digest[407 : 400];
+   assign digest_reg[14] = core_digest[399 : 392];
+   assign digest_reg[15] = core_digest[391 : 384];
+   assign digest_reg[16] = core_digest[383 : 376];
+   assign digest_reg[17] = core_digest[375 : 368];
+   assign digest_reg[18] = core_digest[367 : 360];
+   assign digest_reg[19] = core_digest[359 : 352];
+   assign digest_reg[20] = core_digest[351 : 344];
+   assign digest_reg[21] = core_digest[343 : 336];
+   assign digest_reg[22] = core_digest[335 : 328];
+   assign digest_reg[23] = core_digest[327 : 320];
+   assign digest_reg[24] = core_digest[319 : 312];
+   assign digest_reg[25] = core_digest[311 : 304];
+   assign digest_reg[26] = core_digest[303 : 296];
+   assign digest_reg[27] = core_digest[295 : 288];
+   assign digest_reg[28] = core_digest[287 : 280];
+   assign digest_reg[29] = core_digest[279 : 272];
+   assign digest_reg[30] = core_digest[271 : 264];
+   assign digest_reg[31] = core_digest[263 : 256];
+   assign digest_reg[32] = core_digest[255 : 248];
+   assign digest_reg[33] = core_digest[247 : 240];
+   assign digest_reg[34] = core_digest[239 : 232];
+   assign digest_reg[35] = core_digest[231 : 224];
+   assign digest_reg[36] = core_digest[223 : 216];
+   assign digest_reg[37] = core_digest[215 : 208];
+   assign digest_reg[38] = core_digest[207 : 200];
+   assign digest_reg[39] = core_digest[199 : 192];
+   assign digest_reg[40] = core_digest[191 : 184];
+   assign digest_reg[41] = core_digest[183 : 176];
+   assign digest_reg[42] = core_digest[175 : 168];
+   assign digest_reg[43] = core_digest[167 : 160];
+   assign digest_reg[44] = core_digest[159 : 152];
+   assign digest_reg[45] = core_digest[151 : 144];
+   assign digest_reg[46] = core_digest[143 : 136];
+   assign digest_reg[47] = core_digest[135 : 128];
+   assign digest_reg[48] = core_digest[127 : 120];
+   assign digest_reg[49] = core_digest[119 : 112];
+   assign digest_reg[50] = core_digest[111 : 104];
+   assign digest_reg[51] = core_digest[103 : 96];
+   assign digest_reg[52] = core_digest[95 : 88];
+   assign digest_reg[53] = core_digest[87 : 80];
+   assign digest_reg[54] = core_digest[79 : 72];
+   assign digest_reg[55] = core_digest[71 : 64];
+   assign digest_reg[56] = core_digest[63 : 56];
+   assign digest_reg[57] = core_digest[55 : 48];
+   assign digest_reg[58] = core_digest[47 : 40];
+   assign digest_reg[59] = core_digest[39 : 32];
+   assign digest_reg[60] = core_digest[31 : 24];
+   assign digest_reg[61] = core_digest[23 : 16];
+   assign digest_reg[62] = core_digest[15 : 8];
+   assign digest_reg[63] = core_digest[7 : 0];
+
+   //----------------------------------------------------------------
+   // core instantiation.
+   //----------------------------------------------------------------
+   sha512_core core(
+                    .clk(clk),
+                    .reset_n(reset_n),
+
+                    .init(core_init),
+                    .next(core_next),
+                    .mode(mode),
+
+                    .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)
+     begin: reg_update
+        if (!reset_n)
+          begin: reset_reg
+             reg[7:0] i;
+             for (i = 0; i < BLOCK_BYTES; i = i + 1)
+               block_reg[i] <= 0;
+             rx_ack_reg   <= 0;
+             rx_ptr_reg   <= 0;
+             rx_ctrl_reg  <= RX_INIT;
+             tx_syn_reg   <= 0;
+             tx_ptr_reg   <= 0;
+             tx_ctrl_reg  <= TX_INIT;
+             initnext_reg <= 0;
+          end
+        else
+          begin
+             if (rx_ack_we)
+               begin
+                  rx_ack_reg <= rx_ack_new;
+               end
+
+             if (rx_ptr_we)
+               begin
+                  rx_ptr_reg <= rx_ptr_new[6:0];
+               end
+
+             if (rx_ctrl_we)
+               begin
+                  rx_ctrl_reg <= rx_ctrl_new;
+               end
+
+             if (block_we)
+               begin
+                  block_reg[rx_ptr_reg] <= block_new;
+               end
+
+             if (init_we)
+               begin
+                  init_reg <= init_new;
+               end
+
+             if (next_we)
+               begin
+                  next_reg <= next_new;
+               end
+
+             if (initnext_we)
+               begin
+                  initnext_reg <= initnext_new;
+               end
+
+             if (tx_syn_we)
+               begin
+                  tx_syn_reg <= tx_syn_new;
+               end
+
+             if (tx_ptr_we)
+               begin
+                  tx_ptr_reg <= tx_ptr_new[6:0];
+               end
+
+             if (tx_ctrl_we)
+               begin
+                  tx_ctrl_reg <= tx_ctrl_new;
+               end
+
+             if (tx_active_we)
+               begin
+                  tx_active_reg <= tx_active_new;
+               end
+          end
+     end // reg_update
+
+   //----------------------------------------------------------------
+   // rx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: rx_engine
+        rx_ack_new = 0;
+        rx_ack_we = 0;
+        rx_ptr_new = 0;
+        rx_ptr_we = 0;
+        rx_ctrl_new = 0;
+        rx_ctrl_we = 0;
+        block_new = 0;
+        block_we = 0;
+        init_new = 0;
+        init_we = 0;
+        next_new = 0;
+        next_we = 0;
+        initnext_new = 0;
+        initnext_we = 0;
+
+        if (tx_active_reg)
+          begin
+             initnext_we = 1;
+          end
+
+        case (rx_ctrl_reg)
+          RX_INIT:
+            if (core_ready)
+              begin
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+              end
+          RX_SYN:
+            if (rx_syn)
+              begin
+                 rx_ack_new = 1;
+                 rx_ack_we = 1;
+                 block_new = rx_data;
+                 block_we = 1;
+                 rx_ctrl_new = RX_ACK;
+                 rx_ctrl_we = 1;
+              end
+          RX_ACK:
+            if (!rx_syn)
+              begin
+                 rx_ack_new = 0;
+                 rx_ack_we = 1;
+                 rx_ptr_new = rx_ptr_reg + 1;
+                 rx_ptr_we = 1;
+                 rx_ctrl_new = RX_SYN;
+                 rx_ctrl_we = 1;
+                 if (rx_ptr_new == BLOCK_BYTES)
+                   begin
+                      rx_ptr_new = 0;
+                      rx_ctrl_new = RX_WAIT;
+                      if (initnext_reg == 0)
+                        begin
+                           init_new = 1;
+                           init_we = 1;
+                           initnext_new = 1;
+                           initnext_we = 1;
+                        end
+                      else
+                        begin
+                           next_new = 1;
+                           next_we = 1;
+                        end
+                   end
+              end
+          RX_WAIT:
+            if (!core_ready)
+              begin
+                 init_new = 0;
+                 init_we = 1;
+                 next_new = 0;
+                 next_we = 1;
+                 rx_ctrl_new = RX_INIT;
+                 rx_ctrl_we = 1;
+              end
+        endcase // case (rx_ctrl_reg)
+     end // rx_engine
+
+   //----------------------------------------------------------------
+   // tx_engine
+   //----------------------------------------------------------------
+   always @*
+     begin: tx_engine
+        tx_syn_new = 0;
+        tx_syn_we = 0;
+        tx_ptr_new = 0;
+        tx_ptr_we = 0;
+        tx_ctrl_new = 0;
+        tx_ctrl_we = 0;
+        tx_active_new = 0;
+        tx_active_we = 0;
+
+        case (tx_ctrl_reg)
+          TX_INIT:
+            if (core_digest_valid)
+              begin
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+              end
+          TX_SYN:
+            begin
+               tx_syn_new = 1;
+               tx_syn_we = 1;
+               tx_ctrl_new = TX_ACK;
+               tx_ctrl_we = 1;
+            end
+          TX_ACK:
+            if (!core_digest_valid)
+              begin
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = 0;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_INIT;
+                 tx_ctrl_we = 1;
+              end
+            else if (tx_ack)
+              begin
+                 tx_active_new = 1;
+                 tx_active_we = 1;
+                 tx_syn_new = 0;
+                 tx_syn_we = 1;
+                 tx_ptr_new = tx_ptr_reg + 1;
+                 tx_ptr_we = 1;
+                 tx_ctrl_new = TX_SYN;
+                 tx_ctrl_we = 1;
+                 if (((mode == MODE_SHA_512_224) && (tx_ptr_new == DIGEST_BYTES_512_224)) ||
+                     ((mode == MODE_SHA_512_256) && (tx_ptr_new == DIGEST_BYTES_512_256)) ||
+                     ((mode == MODE_SHA_384) && (tx_ptr_new == DIGEST_BYTES_384)) ||
+                     ((mode == MODE_SHA_512) && (tx_ptr_new == DIGEST_BYTES_512)))
+                   begin
+                      tx_active_new = 0;
+                      tx_ptr_new = 0;
+                      tx_ctrl_new = TX_INIT;
+                   end
+              end
+        endcase // case (tx_ctrl_reg)
+     end // tx_engine
+
+endmodule // sha512
+
+//======================================================================
+// EOF sha512.v
+//======================================================================
diff --git a/src/sw/hash.c b/src/sw/hash.c
new file mode 100644
index 0000000..2314fe4
--- /dev/null
+++ b/src/sw/hash.c
@@ -0,0 +1,310 @@
+/* 
+ * hash.c
+ * ------
+ * This program uses the coretest_hashes subsystem to produce a
+ * cryptographic hash of a file or input stream. It is a generalization
+ * of the hash_tester.c test program.
+ * 
+ * Author: 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 <sys/time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+char *usage = 
+"Usage: %s [-d] [-v] [-q] [-i I2C_device] [-a I2C_addr] [algorithm [file]]\n"
+"algorithms: sha-1, sha-256, sha-512/224, sha-512/256, sha-384, sha-512\n";
+
+/* I2C configuration */
+#define I2C_dev  "/dev/i2c-2"
+
+int debug = 0;
+int verbose = 0;
+
+/* block and digest lengths are number of 32-bit words */
+#define SHA1_BLOCK_LEN          16
+#define SHA1_DIGEST_LEN         5
+#define SHA256_BLOCK_LEN        16
+#define SHA256_DIGEST_LEN       8
+#define SHA512_BLOCK_LEN        32
+#define SHA512_224_DIGEST_LEN   7
+#define SHA512_256_DIGEST_LEN   8
+#define SHA384_DIGEST_LEN       12
+#define SHA512_DIGEST_LEN       16
+
+/* ---------------- algorithm lookup code ---------------- */
+
+struct ctrl {
+    char *name;
+    int i2c_addr;
+    int block_len;
+    int digest_len;
+} ctrl[] = {
+    { "sha-1",       0x1e, SHA1_BLOCK_LEN,   SHA1_DIGEST_LEN },
+    { "sha-256",     0x1f, SHA256_BLOCK_LEN, SHA256_DIGEST_LEN },
+    { "sha-512/224", 0x20, SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN },
+    { "sha-512/256", 0x21, SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN },
+    { "sha-384",     0x22, SHA512_BLOCK_LEN, SHA384_DIGEST_LEN },
+    { "sha-512",     0x23, SHA512_BLOCK_LEN, SHA512_DIGEST_LEN },
+    { NULL, 0, 0, 0 }
+};
+
+/* return the control structure for the given algorithm */
+struct ctrl *find_algo(char *algo)
+{
+    int i;
+
+    for (i = 0; ctrl[i].name != NULL; ++i)
+        if (strcmp(ctrl[i].name, algo) == 0)
+            return &ctrl[i];
+
+    fprintf(stderr, "algorithm \"%s\" not found\n", algo);
+    fprintf(stderr, usage, "hash");
+    return NULL;
+}
+
+/* ---------------- I2C low-level code ---------------- */
+
+/* return file descriptor for i2c device */
+int i2c_open(char *dev, int addr)
+{
+    int fd;
+
+    fd = open(dev, O_RDWR);
+    if (fd < 0) {
+        fprintf(stderr, "Unable to open %s: ", dev);
+        perror("");
+        return -1;
+    }
+
+    if (ioctl(fd, I2C_SLAVE, addr) < 0) {
+        fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+        perror("");
+        close(fd);
+        return -1;
+    }
+
+    return fd;
+}
+
+void i2c_close(int ifd)
+{
+    close(ifd);
+}
+
+/* ---------------- hash ---------------- */
+
+/* return number of digest bytes read */
+int hash(char *dev, char *algo, char *file, uint8_t *digest)
+{
+    uint8_t block[SHA512_BLOCK_LEN * 4];
+    struct ctrl *ctrl;
+    int i2c_fd, in_fd = 0;
+    int addr, blen, dlen;
+    int nblk, nread;
+    int i, ret = -1;
+    struct timeval start, stop, difftime;
+
+    if (debug) printf("hash(dev=%s, algo=%s, file=%s, digest=%p)\n", dev, algo, file, digest);
+
+    ctrl = find_algo(algo);
+    if (ctrl == NULL)
+        return -1;
+    addr = ctrl->i2c_addr;
+    blen = ctrl->block_len * 4;
+    dlen = ctrl->digest_len * 4;
+
+    if (debug) printf("algorithm %s, device addr %02x\n", ctrl->name, ctrl->i2c_addr);
+
+    i2c_fd = i2c_open(dev, addr);
+    if (i2c_fd < 0)
+        return -1;
+
+    if (strcmp(file, "-") != 0) {
+        in_fd = open(file, O_RDONLY);
+        if (in_fd < 0) {
+            perror("open");
+            goto out2;
+        }
+    }
+
+    if (verbose) {
+        if (gettimeofday(&start, NULL) < 0) {
+            perror("gettimeofday");
+            goto out;
+        }
+    }
+
+    for (nblk = 0; ; ++nblk) {
+        nread = read(in_fd, block, blen);
+        if (nread != blen) {
+            if (nread < 0) {
+                /* read error */
+                perror("read");
+                goto out;
+            }
+            else if (nread == 0) {
+                /* EOF */
+                break;
+            }
+            else {
+                /* partial read - pad the block with 0 */
+                while (nread < blen) {
+                    block[nread++] = 0;
+                }
+            }
+        }
+        if (debug) {
+            printf("write [");
+            for (i = 0; i < blen; ++i)
+                printf(" %02x", block[i]);
+            printf(" ]\n");
+        }
+        if (write(i2c_fd, block, blen) != blen) {
+            perror("i2c write failed");
+            goto out;
+        }
+    }
+
+    for (i = 0; i < dlen; ++i) {
+        /* read() on the i2c device only returns one byte at a time */
+        if (read(i2c_fd, &digest[i], 1) != 1) {
+            perror("i2c read failed");
+            goto out;
+        }
+    }
+
+    if (verbose) {
+        if (gettimeofday(&stop, NULL) < 0) {
+            perror("gettimeofday");
+            goto out;
+        }
+        timersub(&stop, &start, &difftime);
+        printf("%d blocks written in %d.%03d sec (%.3f blocks/sec)\n",
+               nblk, (int)difftime.tv_sec, (int)difftime.tv_usec/1000,
+               (float)nblk / ((float)difftime.tv_sec + ((float)difftime.tv_usec)/1000000));
+    }
+
+    ret = dlen;
+out:
+    if (in_fd != 0)
+        close(in_fd);
+out2:
+    i2c_close(i2c_fd);
+    return ret;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+    char *dev = I2C_dev;
+    int addr = 0;
+    int i, opt, quiet = 0;
+    char *algo = "sha-1";
+    char *file = "-";
+    uint8_t digest[512/8];
+    int dlen;
+
+    while ((opt = getopt(argc, argv, "h?dvqi:a:")) != -1) {
+        switch (opt) {
+        case 'h':
+        case '?':
+            printf(usage, argv[0]);
+            return 0;
+        case 'd':
+            debug = 1;
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'q':
+            quiet = 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 (optind < argc) {
+        algo = argv[optind];
+        ++optind;
+    }
+    else {
+        if (!quiet)
+            printf("defaulting to algorithm \"%s\"\n", algo);
+    }
+
+    if (optind < argc) {
+        file = argv[optind];
+        ++optind;
+    }
+    else {
+        if (!quiet)
+            printf("reading from stdin\n");
+    }
+
+    dlen = hash(dev, algo, file, digest);
+    if (dlen < 0)
+        return 1;
+
+    for (i = 0; i < dlen; ++i) {
+        printf("%02x", digest[i]);
+        if (i % 16 == 15)
+            printf("\n");
+        else if (i % 4 == 3)
+            printf(" ");
+    }
+    if (dlen % 16 != 0)
+        printf("\n");
+
+    return 0;
+}
diff --git a/src/sw/hash_tester.c b/src/sw/hash_tester.c
new file mode 100644
index 0000000..994c305
--- /dev/null
+++ b/src/sw/hash_tester.c
@@ -0,0 +1,688 @@
+/* 
+ * 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_SHA1_ADDR    0x1e
+#define I2C_SHA256_ADDR  0x1f
+#define I2C_SHA512_ADDR  0x20
+
+#define MODE_SHA_512_224 0x00
+#define MODE_SHA_512_256 0x01
+#define MODE_SHA_384     0x02
+#define MODE_SHA_512     0x03
+
+int i2cfd;
+int debug = 0;
+
+#define SHA1_BLOCK_BITS         512
+#define SHA1_BLOCK_BYTES        SHA1_BLOCK_BITS/8
+#define SHA1_DIGEST_BITS        160
+#define SHA1_DIGEST_BYTES       SHA1_DIGEST_BITS/8
+
+#define SHA256_BLOCK_BITS       512
+#define SHA256_BLOCK_BYTES      SHA256_BLOCK_BITS/8
+#define SHA256_DIGEST_BITS      256
+#define SHA256_DIGEST_BYTES     SHA256_DIGEST_BITS/8
+
+#define SHA512_BLOCK_BITS       1024
+#define SHA512_BLOCK_BYTES      SHA512_BLOCK_BITS/8
+#define SHA512_224_DIGEST_BITS  224
+#define SHA512_224_DIGEST_BYTES SHA512_224_DIGEST_BITS/8
+#define SHA512_256_DIGEST_BITS  256
+#define SHA512_256_DIGEST_BYTES SHA512_256_DIGEST_BITS/8
+#define SHA384_DIGEST_BITS      384
+#define SHA384_DIGEST_BYTES     SHA384_DIGEST_BITS/8
+#define SHA512_DIGEST_BITS      512
+#define SHA512_DIGEST_BYTES     SHA512_DIGEST_BITS/8
+
+/* 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 };
+
+/* ---------------- I2C low-level code ---------------- */
+
+int i2c_open(char *dev)
+{
+    i2cfd = open(dev, O_RDWR);
+    if (i2cfd < 0) {
+        fprintf(stderr, "Unable to open %s: ", dev);
+        perror("");
+        i2cfd = 0;
+        return 1;
+    }
+
+    return 0;
+}
+
+int i2c_addr(int addr)
+{
+    static int cur_addr = 0;
+
+    if (addr != cur_addr) {
+        if (ioctl(i2cfd, I2C_SLAVE, addr) < 0) {
+            fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+            perror("");
+            return 1;
+        }
+        addr = cur_addr;
+    }
+
+    return 0;
+}
+
+int i2c_close(void)
+{
+    return close(i2cfd);
+}
+
+int i2c_write(const uint8_t *buf, int len)
+{
+    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_write(int addr, const uint8_t *buf, int len)
+{
+    /* we only set the i2c device addr on tc_write, because test cases always
+     * write before reading, plus test cases never call tc_read directly
+     */
+    if (i2c_addr(addr) != 0)
+        return 1;
+
+    if (debug) {
+        int i;
+        printf("write [");
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+
+    return i2c_write(buf, len);
+}
+
+int tc_read(uint8_t *buf, int len)
+{
+    int i;
+
+    if (debug) printf("read  [");
+
+    for (i = 0; i < len; ++i) {
+        if (i2c_read(&buf[i]) != 0) {
+            if (debug) printf(" ]\n");
+            return 1;
+        }
+        if (debug) printf(" %02x", buf[i]);
+    }
+
+    if (debug) printf(" ]\n");
+
+    return 0;
+}
+
+int tc_expected(const uint8_t *expected, int len)
+{
+    uint8_t *buf;
+    int i;
+
+    buf = malloc(len);
+    if (buf == NULL) {
+        perror("malloc");
+        return 1;
+    }
+
+    if (tc_read(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;
+}
+
+/* ---------------- SHA-1 test cases ---------------- */
+
+#define BLOCK_LEN  SHA1_BLOCK_BYTES
+#define DIGEST_LEN SHA1_DIGEST_BYTES
+
+/* TC1: Read name and version from SHA-1 core. */
+int TC1(int addr)
+{
+    return 0;
+}
+
+/* TC2: SHA-1 Single block message test as specified by NIST. */
+int TC2(int addr)
+{
+    const uint8_t *block = NIST_512_SINGLE;
+    const uint8_t *expected = SHA1_SINGLE_DIGEST;
+
+    printf("TC2: Single block message test for SHA-1.\n");
+
+    if (addr == 0)
+        addr = I2C_SHA1_ADDR;
+
+    return
+        tc_write(addr, block, BLOCK_LEN) ||
+        tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC3: SHA-1 Double block message test as specified by NIST. */
+int TC3(int addr)
+{
+    const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    const uint8_t *expected = SHA1_DOUBLE_DIGEST;
+
+    printf("TC3: Double block message test for SHA-1.\n");
+
+    if (addr == 0)
+        addr = I2C_SHA1_ADDR;
+
+    return
+        tc_write(addr, block[0], BLOCK_LEN) ||
+        tc_write(addr, block[1], BLOCK_LEN) ||
+        tc_expected(expected, DIGEST_LEN);
+}
+
+/* ---------------- SHA-256 test cases ---------------- */
+
+#undef  BLOCK_LEN
+#define BLOCK_LEN  SHA256_BLOCK_BYTES
+#undef  DIGEST_LEN
+#define DIGEST_LEN SHA256_DIGEST_BYTES
+
+int TC4(int addr)
+{
+    return 0;
+}
+
+/* TC5: SHA-256 Single block message test as specified by NIST. */
+int TC5(int addr)
+{
+    const uint8_t *block = NIST_512_SINGLE;
+    const uint8_t *expected = SHA256_SINGLE_DIGEST;
+
+    printf("TC5: Single block message test for SHA-256.\n");
+
+    if (addr == 0)
+        addr = I2C_SHA256_ADDR;
+
+    return
+        tc_write(addr, block, BLOCK_LEN) ||
+        tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC6: SHA-256 Double block message test as specified by NIST. */
+int TC6(int addr)
+{
+    const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    const uint8_t *expected = SHA256_DOUBLE_DIGEST;
+
+    printf("TC6: Double block message test for SHA-256.\n");
+
+    if (addr == 0)
+        addr = I2C_SHA256_ADDR;
+
+    return
+        tc_write(addr, block[0], BLOCK_LEN) ||
+        tc_write(addr, block[1], BLOCK_LEN) ||
+        tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC7: SHA-256 Huge message test. */
+int TC7(int addr)
+{
+    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;
+
+    printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+
+    if (addr == 0)
+        addr = I2C_SHA256_ADDR;
+
+    /* Write blocks to SHA-256. */
+    for (i = 0; i < n; ++i)
+        if (tc_write(addr, block, BLOCK_LEN) != 0)
+            return 1;
+
+    /* Extract the final digest. */
+    return tc_expected(expected, DIGEST_LEN);
+}
+
+/* ---------------- SHA-512 test cases ---------------- */
+
+#undef  BLOCK_LEN
+#define BLOCK_LEN  SHA512_BLOCK_BYTES
+
+/* TC8: Read name and version from SHA-512 core. */
+int TC8(int addr)
+{
+    return 0;
+}
+
+/* TC9: SHA-512 Single block message test as specified by NIST.
+   We do this for all modes. */
+int tc9(int addr, const uint8_t *expected, int digest_len)
+{
+    const uint8_t *block = NIST_1024_SINGLE;
+
+    return
+        tc_write(addr, block, BLOCK_LEN) ||
+        tc_expected(expected, digest_len);
+}
+
+int TC9(int addr)
+{
+    if (addr == 0)
+        addr = I2C_SHA512_ADDR;
+
+    printf("TC9-1: Single block message test for SHA-512/224.\n");
+    if (tc9(addr + 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(addr + 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(addr + 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(addr + 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(int addr, const uint8_t *expected, int digest_len)
+{
+    const uint8_t *block[2] = { NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 };
+
+    return
+        tc_write(addr, block[0], BLOCK_LEN) ||
+        tc_write(addr, block[1], BLOCK_LEN) ||
+        tc_expected(expected, digest_len);
+}
+
+int TC10(int addr)
+{
+    if (addr == 0)
+        addr = I2C_SHA512_ADDR;
+
+    printf("TC10-1: Double block message test for SHA-512/224.\n");
+    if (tc10(addr + 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(addr + 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(addr + 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(addr + 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)(int);
+    tcfp all_tests[] = { TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC9, TC10
+    };
+    tcfp sha1_tests[] = { TC1, TC2, TC3 };
+    tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
+    tcfp sha512_tests[] = { TC9, TC10 };
+
+    char *usage = "Usage: %s [-h] [-d] [-i I2C_device] [-a I2C_addr] tc...\n";
+    char *dev = I2C_DEV;
+    int addr = 0;
+    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_open(dev) != 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](addr) != 0)
+                return 1;
+        return 0;
+    }
+
+    for (i = optind; i < argc; ++i) {
+        if (strcmp(argv[i], "sha1") == 0) {
+            for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
+                if (sha1_tests[j](addr) != 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](addr) != 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](addr) != 0)
+                    return 1;
+        }
+        else if (strcmp(argv[i], "all") == 0) {
+            for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+                if (all_tests[j](addr) != 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 - 1](addr) != 0)
+                return 1;
+        }
+        else {
+            fprintf(stderr, "unknown test case %s\n", argv[i]);
+            return 1;
+        }
+    }
+
+    return 0;
+}



More information about the Commits mailing list