diff options
-rw-r--r-- | LICENSE | 24 | ||||
-rw-r--r-- | README.md | 29 | ||||
-rw-r--r-- | build/Makefile | 17 | ||||
-rw-r--r-- | build/coretest-novena-simple.bmm | 0 | ||||
-rw-r--r-- | build/coretest-novena-simple.ucf | 594 | ||||
-rw-r--r-- | build/xilinx.mk | 176 | ||||
-rw-r--r-- | build/xilinx.opt | 42 | ||||
-rw-r--r-- | src/rtl/coretest_hashes.v | 273 | ||||
-rw-r--r-- | src/rtl/i2c_core.v | 581 | ||||
-rw-r--r-- | src/rtl/novena_fpga.v | 147 | ||||
-rw-r--r-- | src/rtl/sha1.v | 421 | ||||
-rw-r--r-- | src/rtl/sha256.v | 433 | ||||
-rw-r--r-- | src/rtl/sha512.v | 497 | ||||
-rw-r--r-- | src/sw/hash.c | 310 | ||||
-rw-r--r-- | src/sw/hash_tester.c | 688 |
15 files changed, 4232 insertions, 0 deletions
@@ -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 --- /dev/null +++ b/build/coretest-novena-simple.bmm 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; +} |