[Cryptech-Commits] [staging/core/platform/novena] 01/08: initial commit of Novena code for coretest

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


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

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

commit f06583ef515bae8f24d696e0df75a425bc47c2bb
Author: Paul Selkirk <pselkirk at isc.org>
Date:   Thu Aug 28 10:29:48 2014 -0400

    initial commit of Novena code for coretest
---
 LICENSE                   |  24 ++
 README.md                 |  13 +
 src/rtl/coretest_hashes.v | 318 ++++++++++++++++
 src/rtl/novena_fpga.v     | 147 ++++++++
 src/sw/configure.sh       |  15 +
 src/sw/hash_tester.c      | 942 ++++++++++++++++++++++++++++++++++++++++++++++
 src/sw/hash_tester.py     | 669 ++++++++++++++++++++++++++++++++
 synth/Makefile            |  20 +
 synth/coretest-novena.bmm |   0
 synth/coretest-novena.ucf | 594 +++++++++++++++++++++++++++++
 synth/xilinx.mk           | 176 +++++++++
 synth/xilinx.opt          |  42 +++
 12 files changed, 2960 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8d0d6ec
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Author: Joachim Strömbergson
+Copyright (c) 2014, SUNET
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..302a492
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+coretest_hashes
+===============
+
+The coretest system combined with cryptographic hash functions.
+
+## Introduction ##
+This is a HW subsystem that includes the coretest module connected to an
+I2C bus for external access and to hash function cores. This version
+includes the SHA-1, SHA-256, and SHA-512 cores.
+
+## Status ##
+***(2014-08-27)***
+Initial version. Build using Xilinx ISE 14.3.
diff --git a/src/rtl/coretest_hashes.v b/src/rtl/coretest_hashes.v
new file mode 100644
index 0000000..5076047
--- /dev/null
+++ b/src/rtl/coretest_hashes.v
@@ -0,0 +1,318 @@
+//======================================================================
+//
+// coretest_hashes.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of external interface, coretest
+// and the core to be tested. And if more than one core is
+// present the wrapper also includes address and data muxes.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2014, SUNET
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or 
+// without modification, are permitted provided that the following 
+// conditions are met: 
+// 
+// 1. Redistributions of source code must retain the above copyright 
+//    notice, this list of conditions and the following disclaimer. 
+// 
+// 2. Redistributions in binary form must reproduce the above copyright 
+//    notice, this list of conditions and the following disclaimer in 
+//    the documentation and/or other materials provided with the 
+//    distribution. 
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module 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_ADDR_PREFIX    = 8'h00;
+  parameter SHA1_ADDR_PREFIX   = 8'h10;
+  parameter SHA256_ADDR_PREFIX = 8'h20;
+  parameter SHA512_ADDR_PREFIX = 8'h30;
+  
+  
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  // Coretest connections.
+  wire          coretest_reset_n;
+  wire          coretest_cs;
+  wire          coretest_we;
+  wire [15 : 0] coretest_address;
+  wire [31 : 0] coretest_write_data;
+  reg [31 : 0]  coretest_read_data;
+  reg           coretest_error;
+
+  // i2c connections
+  wire          i2c_rxd_syn;
+  wire [7 : 0]  i2c_rxd_data;
+  wire          i2c_rxd_ack;
+  wire          i2c_txd_syn;
+  wire [7 : 0]  i2c_txd_data;
+  wire          i2c_txd_ack;
+  reg           i2c_cs;
+  reg           i2c_we;
+  reg [7 : 0]   i2c_address;
+  reg [31 : 0]  i2c_write_data;
+  wire [31 : 0] i2c_read_data;
+  wire          i2c_error;
+  wire [7 : 0]  i2c_debug;
+
+  // sha1 connections.
+  reg           sha1_cs;
+  reg           sha1_we;
+  reg [7 : 0]   sha1_address;
+  reg [31 : 0]  sha1_write_data;
+  wire [31 : 0] sha1_read_data;
+  wire          sha1_error;
+  wire [7 : 0]  sha1_debug;
+
+  // sha256 connections.
+  reg           sha256_cs;
+  reg           sha256_we;
+  reg [7 : 0]   sha256_address;
+  reg [31 : 0]  sha256_write_data;
+  wire [31 : 0] sha256_read_data;
+  wire          sha256_error;
+  wire [7 : 0]  sha256_debug;
+
+  // sha512 connections.
+  reg           sha512_cs;
+  reg           sha512_we;
+  reg [7 : 0]   sha512_address;
+  reg [31 : 0]  sha512_write_data;
+  wire [31 : 0] sha512_read_data;
+  wire          sha512_error;
+  wire [7 : 0]  sha512_debug;
+  
+  
+  //----------------------------------------------------------------
+  // Concurrent assignment.
+  //----------------------------------------------------------------
+  assign debug = i2c_debug;
+  
+  
+  //----------------------------------------------------------------
+  // Core instantiations.
+  //----------------------------------------------------------------
+  coretest coretest(
+                    .clk(clk),
+                    .reset_n(reset_n),
+                         
+                    .rx_syn(i2c_rxd_syn),
+                    .rx_data(i2c_rxd_data),
+                    .rx_ack(i2c_rxd_ack),
+                    
+                    .tx_syn(i2c_txd_syn),
+                    .tx_data(i2c_txd_data),
+                    .tx_ack(i2c_txd_ack),
+                    
+                    // Interface to the core being tested.
+                    .core_reset_n(coretest_reset_n),
+                    .core_cs(coretest_cs),
+                    .core_we(coretest_we),
+                    .core_address(coretest_address),
+                    .core_write_data(coretest_write_data),
+                    .core_read_data(coretest_read_data),
+                    .core_error(coretest_error)
+                   );
+
+
+  i2c i2c(
+          .clk(clk),
+          .reset_n(!reset_n),	// active high
+          
+          .SCL(SCL),
+          .SDA(SDA),
+          .SDA_pd(SDA_pd),
+          .i2c_device_addr(8'h1E),
+
+          .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),
+     
+          .cs(i2c_cs),
+          .we(i2c_we),
+          .address(i2c_address),
+          .write_data(i2c_write_data),
+          .read_data(i2c_read_data),
+          .error(i2c_error),
+
+          .debug(i2c_debug)
+          );
+
+  
+  sha1 sha1(
+            // Clock and reset.
+            .clk(clk),
+            .reset_n(reset_n),
+            
+            // Control.
+            .cs(sha1_cs),
+            .we(sha1_we),
+              
+            // Data ports.
+            .address(sha1_address),
+            .write_data(sha1_write_data),
+            .read_data(sha1_read_data),
+            .error(sha1_error)
+           );
+
+  
+  sha256 sha256(
+                // Clock and reset.
+                .clk(clk),
+                .reset_n(reset_n),
+                
+                // Control.
+                .cs(sha256_cs),
+                .we(sha256_we),
+              
+                // Data ports.
+                .address(sha256_address),
+                .write_data(sha256_write_data),
+                .read_data(sha256_read_data),
+                .error(sha256_error)
+               );
+
+  
+  sha512 sha512(
+                // Clock and reset.
+                .clk(clk),
+                .reset_n(reset_n),
+
+                // Control.
+                .cs(sha512_cs),
+                .we(sha512_we),
+
+                // Data ports.
+                .address(sha512_address),
+                .write_data(sha512_write_data),
+                .read_data(sha512_read_data),
+                .error(sha512_error)
+               );
+
+
+  //----------------------------------------------------------------
+  // address_mux
+  //
+  // Combinational data mux that handles addressing between
+  // cores using the 32-bit memory like interface.
+  //----------------------------------------------------------------
+  always @*
+    begin : address_mux
+      // Default assignments.
+      coretest_read_data = 32'h00000000;
+      coretest_error     = 0;
+
+      i2c_cs            = 0;
+      i2c_we            = 0;
+      i2c_address       = 8'h00;
+      i2c_write_data    = 32'h00000000;
+
+      sha1_cs            = 0;
+      sha1_we            = 0;
+      sha1_address       = 8'h00;
+      sha1_write_data    = 32'h00000000;
+
+      sha256_cs          = 0;
+      sha256_we          = 0;
+      sha256_address     = 8'h00;
+      sha256_write_data  = 32'h00000000;
+
+      sha512_cs          = 0;
+      sha512_we          = 0;
+      sha512_address     = 8'h00;
+      sha512_write_data  = 32'h00000000;
+
+
+      case (coretest_address[15 : 8])
+        I2C_ADDR_PREFIX:
+          begin
+            i2c_cs             = coretest_cs;
+            i2c_we             = coretest_we;
+            i2c_address        = coretest_address[7 : 0];
+            i2c_write_data     = coretest_write_data;
+            coretest_read_data = i2c_read_data;
+            coretest_error     = i2c_error;
+          end
+
+        
+        SHA1_ADDR_PREFIX:
+          begin
+            sha1_cs            = coretest_cs;
+            sha1_we            = coretest_we;
+            sha1_address       = coretest_address[7 : 0];
+            sha1_write_data    = coretest_write_data;
+            coretest_read_data = sha1_read_data;
+            coretest_error     = sha1_error;
+          end
+
+        
+        SHA256_ADDR_PREFIX:
+          begin
+            sha256_cs          = coretest_cs;
+            sha256_we          = coretest_we;
+            sha256_address     = coretest_address[7 : 0];
+            sha256_write_data  = coretest_write_data;
+            coretest_read_data = sha256_read_data;
+            coretest_error     = sha256_error;
+          end
+
+
+        SHA512_ADDR_PREFIX:
+          begin
+            sha512_cs          = coretest_cs;
+            sha512_we          = coretest_we;
+            sha512_address     = coretest_address[7 : 0];
+            sha512_write_data  = coretest_write_data;
+            coretest_read_data = sha512_read_data;
+            coretest_error     = sha512_error;
+          end
+        
+        
+        default:
+          begin
+          end
+      endcase // case (coretest_address[15 : 8])
+    end // address_mux
+  
+endmodule // coretest_hashes
+
+//======================================================================
+// EOF coretest_hashes.v
+//======================================================================
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/sw/configure.sh b/src/sw/configure.sh
new file mode 100755
index 0000000..b3ed7cf
--- /dev/null
+++ b/src/sw/configure.sh
@@ -0,0 +1,15 @@
+#!/bin/sh -
+# bitbang a configuration to the FPGA on a Novena PVT1
+bitfile="${1-novena_fpga.bit}"
+echo "Setting export of reset pin"
+echo 135 > /sys/class/gpio/export
+echo "setting reset pin to out"
+echo out > /sys/class/gpio/gpio135/direction
+echo "flipping reset"
+echo 0 > /sys/class/gpio/gpio135/value
+echo 1 > /sys/class/gpio/gpio135/value
+echo "configuring FPGA"
+dd if=${bitfile} of=/dev/spidev2.0 bs=128
+echo "turning on clock to FPGA"
+# compile devmem2 from novena-scope-drivers/userspace/devmem2.c
+./devmem2 0x020c8160 w 0x00000D2B
diff --git a/src/sw/hash_tester.c b/src/sw/hash_tester.c
new file mode 100644
index 0000000..d02db41
--- /dev/null
+++ b/src/sw/hash_tester.c
@@ -0,0 +1,942 @@
+/* 
+ * hash_tester.c
+ * --------------
+ * This program sends several commands to the coretest_hashes subsystem
+ * in order to verify the SHA-1, SHA-256 and SHA-512/x hash function
+ * cores.
+ *
+ * Note: This version of the program talks to the FPGA over an I2C bus.
+ *
+ * The single and dual block test cases are taken from the
+ * NIST KAT document:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ *
+ * 
+ * Authors: Joachim Strömbergson, Paul Selkirk
+ * Copyright (c) 2014, SUNET
+ * 
+ * Redistribution and use in source and binary forms, with or 
+ * without modification, are permitted provided that the following 
+ * conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+/* I2C configuration */
+#define I2C_dev  "/dev/i2c-2"
+#define I2C_addr 0x0f
+
+/* command codes */
+#define SOC       0x55
+#define EOC       0xaa
+#define READ_CMD  0x10
+#define WRITE_CMD 0x11
+
+/* response codes */
+#define SOR       0xaa
+#define EOR       0x55
+#define UNKNOWN   0xfe
+#define ERROR     0xfd
+#define READ_OK   0x7f
+#define WRITE_OK  0x7e
+#define RESET_OK  0x7d
+
+/* addresses and codes common to all hash cores */
+#define ADDR_NAME0              0x00
+#define ADDR_NAME1              0x01
+#define ADDR_VERSION            0x02
+#define ADDR_CTRL               0x08
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             0x09
+#define STATUS_READY_BIT        0
+#define STATUS_VALID_BIT        1
+
+/* addresses and codes for the specific hash cores */
+#define SHA1_ADDR_PREFIX        0x10
+#define SHA1_ADDR_BLOCK         0x10
+#define SHA1_BLOCK_LEN          16
+#define SHA1_ADDR_DIGEST        0x20
+#define SHA1_DIGEST_LEN         5
+
+#define SHA256_ADDR_PREFIX      0x20
+#define SHA256_ADDR_BLOCK       0x10
+#define SHA256_BLOCK_LEN        16
+#define SHA256_ADDR_DIGEST      0x20
+#define SHA256_DIGEST_LEN       8
+
+#define SHA512_ADDR_PREFIX      0x30
+#define SHA512_CTRL_MODE_LOW    2
+#define SHA512_CTRL_MODE_HIGH   3
+#define SHA512_ADDR_BLOCK       0x10
+#define SHA512_BLOCK_LEN        32
+#define SHA512_ADDR_DIGEST      0x40
+#define SHA512_DIGEST_LEN       16
+#define MODE_SHA_512_224        0
+#define MODE_SHA_512_256        1
+#define MODE_SHA_384            2
+#define MODE_SHA_512            3
+
+int i2cfd;
+int debug = 0;
+
+/* SHA-1/SHA-256 One Block Message Sample
+   Input Message: "abc" */
+const uint32_t NIST_512_SINGLE[] =
+{ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000018 };
+
+const uint32_t SHA1_SINGLE_DIGEST[] =
+{ 0xa9993e36, 0x4706816a, 0xba3e2571, 0x7850c26c,
+  0x9cd0d89d };
+
+const uint32_t SHA256_SINGLE_DIGEST[] =
+{ 0xBA7816BF, 0x8F01CFEA, 0x414140DE, 0x5DAE2223,
+  0xB00361A3, 0x96177A9C, 0xB410FF61, 0xF20015AD };
+
+/* SHA-1/SHA-256 Two Block Message Sample
+   Input Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */
+const uint32_t NIST_512_DOUBLE0[] =
+{ 0x61626364, 0x62636465, 0x63646566, 0x64656667,
+  0x65666768, 0x66676869, 0x6768696A, 0x68696A6B,
+  0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F,
+  0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000 };
+const uint32_t NIST_512_DOUBLE1[] =
+{ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x000001C0 };
+
+const uint32_t SHA1_DOUBLE_DIGEST[] =
+{ 0x84983E44, 0x1C3BD26E, 0xBAAE4AA1, 0xF95129E5,
+  0xE54670F1 };
+
+const uint32_t SHA256_DOUBLE_DIGEST[] =
+{ 0x248D6A61, 0xD20638B8, 0xE5C02693, 0x0C3E6039,
+  0xA33CE459, 0x64FF2167, 0xF6ECEDD4, 0x19DB06C1 };
+
+/* SHA-512 One Block Message Sample
+   Input Message: "abc" */
+const uint32_t NIST_1024_SINGLE[] =
+{ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000018 };
+
+const uint32_t SHA512_224_SINGLE_DIGEST[] =
+{ 0x4634270f, 0x707b6a54, 0xdaae7530, 0x460842e2,
+  0x0e37ed26, 0x5ceee9a4, 0x3e8924aa };
+const uint32_t SHA512_256_SINGLE_DIGEST[] =
+{ 0x53048e26, 0x81941ef9, 0x9b2e29b7, 0x6b4c7dab,
+  0xe4c2d0c6, 0x34fc6d46, 0xe0e2f131, 0x07e7af23 };
+const uint32_t SHA384_SINGLE_DIGEST[] =
+{ 0xcb00753f, 0x45a35e8b, 0xb5a03d69, 0x9ac65007,
+  0x272c32ab, 0x0eded163, 0x1a8b605a, 0x43ff5bed,
+  0x8086072b, 0xa1e7cc23, 0x58baeca1, 0x34c825a7 };
+const uint32_t SHA512_SINGLE_DIGEST[] =
+{ 0xddaf35a1, 0x93617aba, 0xcc417349, 0xae204131,
+  0x12e6fa4e, 0x89a97ea2, 0x0a9eeee6, 0x4b55d39a,
+  0x2192992a, 0x274fc1a8, 0x36ba3c23, 0xa3feebbd,
+  0x454d4423, 0x643ce80e, 0x2a9ac94f, 0xa54ca49f };
+
+/* SHA-512 Two Block Message Sample
+   Input Message: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+   "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" */
+const uint32_t NIST_1024_DOUBLE0[] =
+{ 0x61626364, 0x65666768, 0x62636465, 0x66676869,
+  0x63646566, 0x6768696a, 0x64656667, 0x68696a6b,
+  0x65666768, 0x696a6b6c, 0x66676869, 0x6a6b6c6d,
+  0x6768696a, 0x6b6c6d6e, 0x68696a6b, 0x6c6d6e6f,
+  0x696a6b6c, 0x6d6e6f70, 0x6a6b6c6d, 0x6e6f7071,
+  0x6b6c6d6e, 0x6f707172, 0x6c6d6e6f, 0x70717273,
+  0x6d6e6f70, 0x71727374, 0x6e6f7071, 0x72737475,
+  0x80000000, 0x00000000, 0x00000000, 0x00000000 };
+const uint32_t NIST_1024_DOUBLE1[] =
+{ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000380 };
+
+const uint32_t SHA512_224_DOUBLE_DIGEST[] = 
+{ 0x23fec5bb, 0x94d60b23, 0x30819264, 0x0b0c4533,
+  0x35d66473, 0x4fe40e72, 0x68674af9 };
+const uint32_t SHA512_256_DOUBLE_DIGEST[] =
+{ 0x3928e184, 0xfb8690f8, 0x40da3988, 0x121d31be,
+  0x65cb9d3e, 0xf83ee614, 0x6feac861, 0xe19b563a };
+const uint32_t SHA384_DOUBLE_DIGEST[] =
+{ 0x09330c33, 0xf71147e8, 0x3d192fc7, 0x82cd1b47,
+  0x53111b17, 0x3b3b05d2, 0x2fa08086, 0xe3b0f712,
+  0xfcc7c71a, 0x557e2db9, 0x66c3e9fa, 0x91746039 };
+const uint32_t SHA512_DOUBLE_DIGEST[] =
+{ 0x8e959b75, 0xdae313da, 0x8cf4f728, 0x14fc143f,
+  0x8f7779c6, 0xeb9f7fa1, 0x7299aead, 0xb6889018,
+  0x501d289e, 0x4900f7e4, 0x331b99de, 0xc4b5433a,
+  0xc7d329ee, 0xb6dd2654, 0x5e96e55b, 0x874be909 };
+
+/* ---------------- I2C low-level code ---------------- */
+int i2c_setup(char *dev, int addr)
+{
+    i2cfd = open(dev, O_RDWR);
+    if (i2cfd < 0) {
+	fprintf(stderr, "Unable to open %s: ", dev);
+	perror("");
+	i2cfd = 0;
+	return 1;
+    }
+
+    if (ioctl(i2cfd, I2C_SLAVE, addr) < 0) {
+	fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+	perror("");
+	return 1;
+    }
+
+    return 0;
+}
+
+int i2c_write(uint8_t *buf, int len)
+{
+    if (debug) {
+	int i;
+	printf("write [");
+	for (i = 0; i < len; ++i)
+	    printf(" %02x", buf[i]);
+	printf(" ]\n");
+    }
+
+    if (write(i2cfd, buf, len) != len) {
+	perror("i2c write failed");
+	return 1;
+    }
+
+    return 0;
+}
+
+int i2c_read(uint8_t *buf, int len)
+{
+    int i;
+
+    if (debug)
+	printf("read  [");
+
+    for (i = 0; i < len; ++i) {
+	if (read(i2cfd, &buf[i], 1) != 1) {
+	    fprintf(stderr, "i2c read failed on byte %d: ", i);
+	    perror("");
+	    return 1;
+	}
+	if (debug)
+	    printf(" %02x", buf[i]);
+    }
+
+    if (debug)
+	printf(" ]\n");
+
+    return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+int tc_send_write_cmd(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    uint8_t buf[9];
+
+    buf[0] = SOC;
+    buf[1] = WRITE_CMD;
+    buf[2] = addr0;
+    buf[3] = addr1;
+    buf[4] = (data >> 24) & 0xff;
+    buf[5] = (data >> 16) & 0xff;
+    buf[6] = (data >> 8) & 0xff;
+    buf[7] = data & 0xff;
+    buf[8] = EOC;
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_send_read_cmd(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t buf[5];
+
+    buf[0] = SOC;
+    buf[1] = READ_CMD;
+    buf[2] = addr0;
+    buf[3] = addr1;
+    buf[4] = EOC;
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_get_resp(uint8_t *expected, int len)
+{
+    uint8_t buf[9];
+    int i;
+
+    if (i2c_read(buf, len) != 0)
+	return 1;
+
+    for (i = 0; i < len; ++i) {
+	if (buf[i] != expected[i]) {
+	    fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+		    i, expected[i], buf[i]);
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
+int tc_get_write_resp(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t expected[5];
+
+    expected[0] = SOR;
+    expected[1] = WRITE_OK;
+    expected[2] = addr0;
+    expected[3] = addr1;
+    expected[4] = EOR;
+
+    return tc_get_resp(expected, sizeof(expected));
+}
+
+int tc_get_read_resp(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    uint8_t expected[9];
+
+    expected[0] = SOR;
+    expected[1] = READ_OK;
+    expected[2] = addr0;
+    expected[3] = addr1;
+    expected[4] = (data >> 24) & 0xff;
+    expected[5] = (data >> 16) & 0xff;
+    expected[6] = (data >> 8) & 0xff;
+    expected[7] = data & 0xff;
+    expected[8] = EOR;
+
+    return tc_get_resp(expected, sizeof(expected));
+}
+
+int tc_write(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    return (tc_send_write_cmd(addr0, addr1, data) ||
+	    tc_get_write_resp(addr0, addr1));
+}
+
+int tc_read(uint8_t addr0, uint8_t addr1, uint32_t data)
+{
+    return (tc_send_read_cmd(addr0, addr1) ||
+	    tc_get_read_resp(addr0, addr1, data));
+}
+
+int tc_init(uint8_t addr0)
+{
+    return tc_write(addr0, ADDR_CTRL, CTRL_INIT_CMD);
+}
+
+int tc_next(uint8_t addr0)
+{
+    return tc_write(addr0, ADDR_CTRL, CTRL_NEXT_CMD);
+}
+
+int tc_wait(uint8_t addr0, uint8_t status)
+{
+    uint8_t buf[9];
+
+    do {
+	if (tc_send_read_cmd(addr0, ADDR_STATUS) != 0)
+	    return 1;
+	if (i2c_read(buf, 9) != 0)
+	    return 1;
+    } while ((buf[7] & status) != status);
+
+    return 0;
+}
+
+int tc_wait_ready(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_READY_BIT);
+}
+
+int tc_wait_valid(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_VALID_BIT);
+}
+
+/* ---------------- SHA-1 test cases ---------------- */
+
+int sha1_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA1_ADDR_PREFIX, addr, data);
+}
+
+int sha1_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA1_ADDR_PREFIX, addr, data);
+}
+
+int sha1_init(void)
+{
+    return tc_init(SHA1_ADDR_PREFIX);
+}
+
+int sha1_next(void)
+{
+    return tc_next(SHA1_ADDR_PREFIX);
+}
+
+int sha1_wait_ready(void)
+{
+    return tc_wait_ready(SHA1_ADDR_PREFIX);
+}
+
+int sha1_wait_valid(void)
+{
+    return tc_wait_valid(SHA1_ADDR_PREFIX);
+}
+
+/* TC1: Read name and version from SHA-1 core. */
+int TC1(void)
+{
+    uint32_t name0   = 0x73686131;	/* "sha1" */
+    uint32_t name1   = 0x20202020;	/* "    " */
+    uint32_t version = 0x302e3530;	/* "0.50" */
+
+    printf("TC1: Reading name, type and version words from SHA-1 core.\n");
+
+    return 
+	sha1_read(ADDR_NAME0, name0) ||
+	sha1_read(ADDR_NAME1, name1) ||
+	sha1_read(ADDR_VERSION, version);
+}
+
+/* TC2: SHA-1 Single block message test as specified by NIST. */
+int TC2(void)
+{
+    const uint32_t *block = NIST_512_SINGLE;
+    const uint32_t *expected = SHA1_SINGLE_DIGEST;
+    int i;
+
+    printf("TC2: Single block message test for SHA-1.\n");
+
+    /* Write block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha1_init() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* TC3: SHA-1 Double block message test as specified by NIST. */
+int TC3(void)
+{
+    const uint32_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint32_t block0_expected[] =
+	{ 0xF4286818, 0xC37B27AE, 0x0408F581, 0x84677148, 0x4A566572 };
+    const uint32_t *expected = SHA1_DOUBLE_DIGEST;
+    int i;
+
+    printf("TC3: Double block message test for SHA-1.\n");
+
+    /* Write first block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha1_init() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the first digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, block0_expected[i]) != 0)
+	    return 1;
+    }
+
+    /* Write second block to SHA-1. */
+    for (i = 0; i < SHA1_BLOCK_LEN; ++i) {
+	if (sha1_write(SHA1_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha1_next() != 0) || (sha1_wait_valid() != 0))
+	return 1;
+
+    /* Extract the second digest. */
+    for (i = 0; i < SHA1_DIGEST_LEN; ++i) {
+	if (sha1_read(SHA1_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- SHA-256 test cases ---------------- */
+
+int sha256_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA256_ADDR_PREFIX, addr, data);
+}
+
+int sha256_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA256_ADDR_PREFIX, addr, data);
+}
+
+int sha256_init(void)
+{
+    return tc_init(SHA256_ADDR_PREFIX);
+}
+
+int sha256_next(void)
+{
+    return tc_next(SHA256_ADDR_PREFIX);
+}
+
+int sha256_wait_ready(void)
+{
+    return tc_wait_ready(SHA256_ADDR_PREFIX);
+}
+
+int sha256_wait_valid(void)
+{
+    return tc_wait_valid(SHA256_ADDR_PREFIX);
+}
+
+/* TC4: Read name and version from SHA-256 core. */
+int TC4(void)
+{
+    uint32_t name0     = 0x73686132;	/* "sha2" */
+    uint32_t name1     = 0x2d323536;	/* "-256" */
+    uint32_t version   = 0x302e3830;	/* "0.80" */
+
+    printf("TC4: Reading name, type and version words from SHA-256 core.\n");
+
+    return
+	sha256_read(ADDR_NAME0, name0) ||
+	sha256_read(ADDR_NAME1, name1) ||
+	sha256_read(ADDR_VERSION, version);
+}
+
+/* TC5: SHA-256 Single block message test as specified by NIST. */
+int TC5(void)
+{
+    const uint32_t *block = NIST_512_SINGLE;
+    const uint32_t *expected = SHA256_SINGLE_DIGEST;
+    int i;
+
+    printf("TC5: Single block message test for SHA-256.\n");
+
+    /* Write block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+
+    return 0;
+}
+
+/* TC6: SHA-1 Double block message test as specified by NIST. */
+int TC6(void)
+{
+    const uint32_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+    static const uint32_t block0_expected[] = 
+	{ 0x85E655D6, 0x417A1795, 0x3363376A, 0x624CDE5C,
+	  0x76E09589, 0xCAC5F811, 0xCC4B32C1, 0xF20E533A };
+    const uint32_t *expected = SHA256_DOUBLE_DIGEST;
+    int i;
+
+    printf("TC6: Double block message test for SHA-256.\n");
+
+    /* Write first block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the first digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, block0_expected[i]) != 0)
+	    return 1;
+    }
+
+    /* Write second block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write(SHA256_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha256_next() != 0) || (sha256_wait_valid() != 0))
+	return 1;
+
+    /* Extract the second digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* TC7: SHA-256 Huge message test. */
+int TC7(void)
+{
+    static const uint32_t block[] =
+	{ 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+	  0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f };
+
+    /* final digest after 1000 iterations */
+    static const uint32_t expected[] = 
+	{ 0x7638f3bc, 0x500dd1a6, 0x586dd4d0, 0x1a1551af,
+	  0xd821d235, 0x2f919e28, 0xd5842fab, 0x03a40f2a };
+
+    int i, n = 1000;
+
+    printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+
+    /* Write first block to SHA-256. */
+    for (i = 0; i < SHA256_BLOCK_LEN; ++i) {
+	if (sha256_write( SHA256_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha256_init() != 0) || (sha256_wait_ready() != 0))
+	return 1;
+
+    /* First block done. Do the rest. */
+    for (i = 1; i < n; ++i) {
+	/* Start next block hashing, wait and check status. */
+	if ((sha256_next() != 0) || (sha256_wait_ready() != 0))
+	    return 1;
+    }
+
+    /* XXX valid is probably set at the same time as ready */
+    if (sha256_wait_valid() != 0)
+	return 1;
+    /* Extract the final digest. */
+    for (i = 0; i < SHA256_DIGEST_LEN; ++i) {
+	if (sha256_read(SHA256_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- SHA-512 test cases ---------------- */
+
+int sha512_read(uint8_t addr, uint32_t data)
+{
+    return tc_read(SHA512_ADDR_PREFIX, addr, data);
+}
+
+int sha512_write(uint8_t addr, uint32_t data)
+{
+    return tc_write(SHA512_ADDR_PREFIX, addr, data);
+}
+
+int sha512_init(uint8_t mode)
+{
+    return tc_write(SHA512_ADDR_PREFIX, ADDR_CTRL,
+		    CTRL_INIT_CMD + (mode << SHA512_CTRL_MODE_LOW));
+}
+
+int sha512_next(uint8_t mode)
+{
+    return tc_write(SHA512_ADDR_PREFIX, ADDR_CTRL,
+		    CTRL_NEXT_CMD + (mode << SHA512_CTRL_MODE_LOW));
+}
+
+int sha512_wait_ready(void)
+{
+    return tc_wait_ready(SHA512_ADDR_PREFIX);
+}
+
+int sha512_wait_valid(void)
+{
+    return tc_wait_valid(SHA512_ADDR_PREFIX);
+}
+
+/* TC8: Read name and version from SHA-512 core. */
+int TC8(void)
+{
+    uint32_t name0         = 0x73686132;	/* "sha2" */
+    uint32_t name1         = 0x2d353132;	/* "-512" */
+    uint32_t version       = 0x302e3830;	/* "0.80" */
+
+    printf("TC8: Reading name, type and version words from SHA-512 core.\n");
+
+    return 
+	sha512_read(ADDR_NAME0, name0) ||
+	sha512_read(ADDR_NAME1, name1) ||
+	sha512_read(ADDR_VERSION, version);
+}
+
+/* TC9: SHA-512 Single block message test as specified by NIST.
+   We do this for all modes. */
+int tc9(uint8_t mode, const uint32_t *expected, int len)
+{
+    const uint32_t *block = NIST_1024_SINGLE;
+    int i;
+
+    /* Write block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha512_init(mode) != 0) || (sha512_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < len/4; ++i) {
+	if (sha512_read(SHA512_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+int TC9(void)
+{
+    printf("TC9-1: Single block message test for SHA-512/224.\n");
+    if (tc9(MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST,
+	    sizeof(SHA512_224_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-2: Single block message test for SHA-512/256.\n");
+    if (tc9(MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST,
+	    sizeof(SHA512_256_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-3: Single block message test for SHA-384.\n");
+    if (tc9(MODE_SHA_384, SHA384_SINGLE_DIGEST,
+	    sizeof(SHA384_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC9-4: Single block message test for SHA-512.\n");
+    if (tc9(MODE_SHA_512, SHA512_SINGLE_DIGEST,
+	    sizeof(SHA512_SINGLE_DIGEST)) != 0)
+	return 1;
+
+    return 0;
+}
+
+/* TC10: SHA-512 Double block message test as specified by NIST.
+   We do this for all modes. */
+int tc10(uint8_t mode, const uint32_t *expected, int len)
+{
+    const uint32_t *block[2] = { NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 };
+    int i;
+
+    /* Write first block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[0][i]) != 0)
+	    return 1;
+    }
+
+    /* Start initial block hashing, wait and check status. */
+    if ((sha512_init(mode) != 0) || (sha512_wait_ready() != 0))
+	return 1;
+
+    /* Write second block to SHA-512. */
+    for (i = 0; i < SHA512_BLOCK_LEN; ++i) {
+	if (sha512_write(SHA512_ADDR_BLOCK + i, block[1][i]) != 0)
+	    return 1;
+    }
+
+    /* Start next block hashing, wait and check status. */
+    if ((sha512_next(mode) != 0) || (sha512_wait_valid() != 0))
+	return 1;
+
+    /* Extract the digest. */
+    for (i = 0; i < len/4; ++i) {
+	if (sha512_read(SHA512_ADDR_DIGEST + i, expected[i]) != 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+int TC10(void)
+{
+    printf("TC10-1: Double block message test for SHA-512/224.\n");
+    if (tc10(MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST,
+	     sizeof(SHA512_224_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-2: Double block message test for SHA-512/256.\n");
+    if (tc10(MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST,
+	     sizeof(SHA512_256_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-3: Double block message test for SHA-384.\n");
+    if (tc10(MODE_SHA_384, SHA384_DOUBLE_DIGEST,
+	     sizeof(SHA384_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    printf("TC10-4: Double block message test for SHA-512.\n");
+    if (tc10(MODE_SHA_512, SHA512_DOUBLE_DIGEST,
+	     sizeof(SHA512_DOUBLE_DIGEST)) != 0)
+	return 1;
+
+    return 0;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+    typedef int (*tcfp)(void);
+    tcfp all_tests[] = { TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10 };
+    tcfp sha1_tests[] = { TC1, TC2, TC3 };
+    tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
+    tcfp sha512_tests[] = { TC8, TC9, TC10 };
+
+    char *usage = "Usage: %s [-d] [-i I2C_device] [-a I2C_addr] tc...\n";
+    char *dev = I2C_dev;
+    int addr = I2C_addr;
+    int i, j, opt;
+
+    while ((opt = getopt(argc, argv, "di:a:")) != -1) {
+	switch (opt) {
+	case 'h':
+	case '?':
+	    printf(usage, argv[0]);
+	    return 0;
+	case 'd':
+	    debug = 1;
+	    break;
+	case 'i':
+	    dev = optarg;
+	    break;
+	case 'a':
+	    addr = (int)strtol(optarg, NULL, 0);
+	    if ((addr < 0x03) || (addr > 0x77)) {
+		fprintf(stderr, "addr must be between 0x03 and 0x77\n");
+		return 1;
+	    }
+	    break;
+	default:
+	    fprintf(stderr, usage, argv[0]);
+	    return 1;
+	}
+    }
+
+    if (i2c_setup(dev, addr) != 0)
+	return 1;
+
+    /* no args == run all tests */
+    if (optind >= argc) {
+	for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+	    if (all_tests[j]() != 0)
+		return 1;
+	return 0;
+    }
+
+    for (i = optind; i < argc; ++i) {
+	if (strcmp(argv[i], "sha1") == 0) {
+	    for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
+		if (sha1_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "sha256") == 0) {
+	    for (j = 0; j < sizeof(sha256_tests)/sizeof(sha256_tests[0]); ++j)
+		if (sha256_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "sha512") == 0) {
+	    for (j = 0; j < sizeof(sha512_tests)/sizeof(sha512_tests[0]); ++j)
+		if (sha512_tests[j]() != 0)
+		    return 1;
+	}
+	else if (strcmp(argv[i], "all") == 0) {
+	    for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+		if (all_tests[j]() != 0)
+		    return 1;
+	}
+	else if (isdigit(argv[i][0]) &&
+		 (((j = atoi(argv[i])) > 0) &&
+		  (j <= sizeof(all_tests)/sizeof(all_tests[0])))) {
+	    if (all_tests[j - 1]() != 0)
+		return 1;
+	}
+	else {
+	    fprintf(stderr, "unknown test case %s\n", argv[i]);
+	    return 1;
+	}
+    }
+
+    return 0;
+}
diff --git a/src/sw/hash_tester.py b/src/sw/hash_tester.py
new file mode 100755
index 0000000..e2b3777
--- /dev/null
+++ b/src/sw/hash_tester.py
@@ -0,0 +1,669 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#=======================================================================
+#
+# hash_tester.py
+# --------------
+# 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. The program will use the built in hash implementations in
+# Python to do functional comparison and validation.
+#
+# This version of the program talks to the FPGA over an I2C bus, but
+# does not require any additional modules.
+#
+# 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.
+#
+#=======================================================================
+ 
+#-------------------------------------------------------------------
+# Python module imports.
+#-------------------------------------------------------------------
+import sys
+import io
+import fcntl
+
+#-------------------------------------------------------------------
+# Defines.
+#-------------------------------------------------------------------
+
+# addresses and codes common to all hash cores
+ADDR_NAME0       = 0x00
+ADDR_NAME1       = 0x01
+ADDR_VERSION     = 0x02
+ADDR_CTRL        = 0x08
+CTRL_INIT_CMD    = 1
+CTRL_NEXT_CMD    = 2
+ADDR_STATUS      = 0x09
+STATUS_READY_BIT = 0
+STATUS_VALID_BIT = 1
+
+#----------------------------------------------------------------
+# NIST sample message blocks and expected digests
+#----------------------------------------------------------------
+
+# SHA-1/SHA-256 One Block Message Sample
+# Input Message: "abc"
+NIST_512_SINGLE = [ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                    0x00000000, 0x00000000, 0x00000000, 0x00000018 ]
+
+SHA1_SINGLE_DIGEST   = [ 0xa9993e36, 0x4706816a, 0xba3e2571, 0x7850c26c,
+                         0x9cd0d89d ]
+
+SHA256_SINGLE_DIGEST = [ 0xBA7816BF, 0x8F01CFEA, 0x414140DE, 0x5DAE2223,
+                         0xB00361A3, 0x96177A9C, 0xB410FF61, 0xF20015AD ]
+
+# SHA-1/SHA-256 Two Block Message Sample
+# Input Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+NIST_512_DOUBLE0 = [ 0x61626364, 0x62636465, 0x63646566, 0x64656667,
+                     0x65666768, 0x66676869, 0x6768696A, 0x68696A6B,
+                     0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F,
+                     0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000 ]
+NIST_512_DOUBLE1 = [ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x000001C0 ]
+
+SHA1_DOUBLE_DIGEST   = [ 0x84983E44, 0x1C3BD26E, 0xBAAE4AA1, 0xF95129E5,
+                         0xE54670F1 ]
+
+SHA256_DOUBLE_DIGEST = [ 0x248D6A61, 0xD20638B8, 0xE5C02693, 0x0C3E6039,
+                         0xA33CE459, 0x64FF2167, 0xF6ECEDD4, 0x19DB06C1 ]
+
+# SHA-512 One Block Message Sample
+# Input Message: "abc"
+NIST_1024_SINGLE = [ 0x61626380, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                     0x00000000, 0x00000000, 0x00000000, 0x00000018 ]
+
+SHA512_224_SINGLE_DIGEST = [0x4634270f, 0x707b6a54, 0xdaae7530, 0x460842e2,
+                            0x0e37ed26, 0x5ceee9a4, 0x3e8924aa]
+SHA512_256_SINGLE_DIGEST = [0x53048e26, 0x81941ef9, 0x9b2e29b7, 0x6b4c7dab,
+                            0xe4c2d0c6, 0x34fc6d46, 0xe0e2f131, 0x07e7af23]
+SHA384_SINGLE_DIGEST     = [0xcb00753f, 0x45a35e8b, 0xb5a03d69, 0x9ac65007,
+                            0x272c32ab, 0x0eded163, 0x1a8b605a, 0x43ff5bed,
+                            0x8086072b, 0xa1e7cc23, 0x58baeca1, 0x34c825a7]
+SHA512_SINGLE_DIGEST     = [0xddaf35a1, 0x93617aba, 0xcc417349, 0xae204131,
+                            0x12e6fa4e, 0x89a97ea2, 0x0a9eeee6, 0x4b55d39a,
+                            0x2192992a, 0x274fc1a8, 0x36ba3c23, 0xa3feebbd,
+                            0x454d4423, 0x643ce80e, 0x2a9ac94f, 0xa54ca49f]
+
+# SHA-512 Two Block Message Sample
+# Input Message: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+# "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+NIST_1024_DOUBLE0 = [ 0x61626364, 0x65666768, 0x62636465, 0x66676869,
+                      0x63646566, 0x6768696a, 0x64656667, 0x68696a6b,
+                      0x65666768, 0x696a6b6c, 0x66676869, 0x6a6b6c6d,
+                      0x6768696a, 0x6b6c6d6e, 0x68696a6b, 0x6c6d6e6f,
+                      0x696a6b6c, 0x6d6e6f70, 0x6a6b6c6d, 0x6e6f7071,
+                      0x6b6c6d6e, 0x6f707172, 0x6c6d6e6f, 0x70717273,
+                      0x6d6e6f70, 0x71727374, 0x6e6f7071, 0x72737475,
+                      0x80000000, 0x00000000, 0x00000000, 0x00000000 ]
+NIST_1024_DOUBLE1 = [ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000380 ]
+
+SHA512_224_DOUBLE_DIGEST = [ 0x23fec5bb, 0x94d60b23, 0x30819264, 0x0b0c4533,
+                             0x35d66473, 0x4fe40e72, 0x68674af9 ]
+SHA512_256_DOUBLE_DIGEST = [ 0x3928e184, 0xfb8690f8, 0x40da3988, 0x121d31be,
+                             0x65cb9d3e, 0xf83ee614, 0x6feac861, 0xe19b563a ]
+SHA384_DOUBLE_DIGEST     = [ 0x09330c33, 0xf71147e8, 0x3d192fc7, 0x82cd1b47,
+                             0x53111b17, 0x3b3b05d2, 0x2fa08086, 0xe3b0f712,
+                             0xfcc7c71a, 0x557e2db9, 0x66c3e9fa, 0x91746039 ]
+SHA512_DOUBLE_DIGEST     = [ 0x8e959b75, 0xdae313da, 0x8cf4f728, 0x14fc143f,
+                             0x8f7779c6, 0xeb9f7fa1, 0x7299aead, 0xb6889018,
+                             0x501d289e, 0x4900f7e4, 0x331b99de, 0xc4b5433a,
+                             0xc7d329ee, 0xb6dd2654, 0x5e96e55b, 0x874be909 ]
+
+def hexlist(list):
+    return "[ " + ' '.join('%02x' % b for b in list) + " ]"
+
+#----------------------------------------------------------------
+# I2C class
+#----------------------------------------------------------------
+
+# default configuration
+I2C_dev = "/dev/i2c-2"
+I2C_addr = 0x0f
+
+# from /usr/include/linux/i2c-dev.h
+I2C_SLAVE = 0x0703
+
+class I2C:
+    # file handle for the i2c device
+    file = None
+
+    # constructor: initialize the i2c communications channel
+    def __init__(self, dev=I2C_dev, addr=I2C_addr):
+        self.dev = dev
+        self.addr = addr
+        try:
+            self.file = io.FileIO(self.dev, 'r+b')
+        except IOError as e:
+            print "Unable to open %s: %s" % (self.dev, e.strerror)
+            sys.exit(1)
+        try:
+            fcntl.ioctl(self.file, I2C_SLAVE, self.addr)
+        except IOError as e:
+            print "Unable to set I2C slave device 0x%02x: %s" % (self.addr, e.strerror)
+            sys.exit(1)
+
+    # destructor: close the i2c communications channel
+    def __del__(self):
+        if (self.file):
+            self.file.close()
+            
+    # write a command to the i2c device
+    def write(self, buf):
+        if DEBUG:
+            print "write %s" % hexlist(buf)
+        self.file.write(bytearray(buf))
+
+    # read 5 or 9 response bytes to a buffer
+    def read(self, len):
+        buf = []
+        # read() on the i2c device will only return 1 byte at a time
+        for i in range(len):
+            buf.append(ord(self.file.read(1)))
+        if DEBUG:
+            print "read  %s" % hexlist(buf)
+        return buf
+
+#----------------------------------------------------------------
+# test-case class
+#----------------------------------------------------------------
+
+# command codes
+SOC                   = 0x55
+EOC                   = 0xaa
+READ_CMD              = 0x10
+WRITE_CMD             = 0x11
+
+# response codes
+SOR                   = 0xaa
+EOR                   = 0x55
+READ_OK               = 0x7f
+WRITE_OK              = 0x7e
+
+class TcError(Exception):
+    pass
+
+class tc:
+    def __init__(self, i2c, addr0, addr1):
+        self.i2c = i2c
+        self.addr0 = addr0
+        self.addr1 = addr1
+
+    def send_write_cmd(self, data):
+        buf = [SOC, WRITE_CMD, self.addr0, self.addr1]
+        for s in (24, 16, 8, 0):
+            buf.append(data >> s & 0xff)
+        buf.append(EOC)
+        self.i2c.write(buf)
+
+    def send_read_cmd(self):
+        buf = [SOC, READ_CMD, self.addr0, self.addr1, EOC]
+        self.i2c.write(buf)
+
+    def get_resp(self, expected):
+        buf = self.i2c.read(len(expected))
+        if (buf != expected):
+            print "expected %s,\nreceived %s" % (hexlist(expected), hexlist(buf))
+            raise TcError()
+
+    def get_write_resp(self):
+        expected = [SOR, WRITE_OK, self.addr0, self.addr1, EOR]
+        self.get_resp(expected)
+
+    def get_read_resp(self, data):
+        expected = [SOR, READ_OK, self.addr0, self.addr1]
+        for s in (24, 16, 8, 0):
+            expected.append(data >> s & 0xff)
+        expected.append(EOR)
+        self.get_resp(expected)
+
+    def write(self, data):
+        self.send_write_cmd(data)
+        self.get_write_resp()
+
+    def read(self, data):
+        self.send_read_cmd()
+        self.get_read_resp(data)
+
+def tc_write(i2c, addr0, addr1, data):
+    tc(i2c, addr0, addr1).write(data)
+
+def tc_read(i2c, addr0, addr1, data):
+    tc(i2c, addr0, addr1).read(data)
+
+def tc_init(i2c, addr0):
+    tc(i2c, addr0, ADDR_CTRL).write(CTRL_INIT_CMD)
+
+def tc_next(i2c, addr0):
+    tc(i2c, addr0, ADDR_CTRL).write(CTRL_NEXT_CMD)
+
+def tc_wait(i2c, addr0, status):
+    t = tc(i2c, addr0, ADDR_STATUS)
+    while 1:
+        t.send_read_cmd()
+        buf = t.i2c.read(9)
+        if ((buf[7] & status) == status):
+            break
+
+def tc_wait_ready(i2c, addr0):
+    tc_wait(i2c, addr0, STATUS_READY_BIT)
+
+def tc_wait_valid(i2c, addr0):
+    tc_wait(i2c, addr0, STATUS_VALID_BIT)
+
+#----------------------------------------------------------------
+# SHA-1 test cases
+#----------------------------------------------------------------
+SHA1_ADDR_PREFIX      = 0x10
+SHA1_ADDR_BLOCK       = 0x10
+SHA1_ADDR_DIGEST      = 0x20
+
+def sha1_read(i2c, addr, data):
+    tc_read(i2c, SHA1_ADDR_PREFIX, addr, data)
+
+def sha1_write(i2c, addr, data):
+    tc_write(i2c, SHA1_ADDR_PREFIX, addr, data)
+
+def sha1_init(i2c):
+    tc_init(i2c, SHA1_ADDR_PREFIX)
+
+def sha1_next(i2c):
+    tc_next(i2c, SHA1_ADDR_PREFIX)
+
+def sha1_wait_ready(i2c):
+    tc_wait_ready(i2c, SHA1_ADDR_PREFIX)
+
+def sha1_wait_valid(i2c):
+    tc_wait_valid(i2c, SHA1_ADDR_PREFIX)
+
+# TC1: Read name and version from SHA-1 core.
+def TC1(i2c):
+    print "TC1: Reading name, type and version words from SHA-1 core."
+
+    sha1_read(i2c, ADDR_NAME0, 0x73686131)	# "sha1"
+    sha1_read(i2c, ADDR_NAME1, 0x20202020)	# "    "
+    sha1_read(i2c, ADDR_VERSION, 0x302e3530)	# "0.50"
+
+# TC2: SHA-1 Single block message test as specified by NIST.
+def TC2(i2c):
+    block = NIST_512_SINGLE
+    expected = SHA1_SINGLE_DIGEST
+
+    print "TC2: Single block message test for SHA-1."
+
+    # Write block to SHA-1.
+    for i in range(len(block)):
+        sha1_write(i2c, SHA1_ADDR_BLOCK + i, block[i])
+
+    # Start initial block hashing, wait and check status.
+    sha1_init(i2c)
+    sha1_wait_valid(i2c)
+
+    # Extract the digest.
+    for i in range(len(expected)):
+        sha1_read(i2c, SHA1_ADDR_DIGEST + i, expected[i])
+
+# TC3: SHA-1 Double block message test as specified by NIST.
+def TC3(i2c):
+    block = [ NIST_512_DOUBLE0, NIST_512_DOUBLE1 ]
+    block0_expected = [ 0xF4286818, 0xC37B27AE, 0x0408F581, 0x84677148,
+                        0x4A566572 ]
+    expected = SHA1_DOUBLE_DIGEST
+
+    print "TC3: Double block message test for SHA-1."
+
+    # Write first block to SHA-1.
+    for i in range(len(block[0])):
+        sha1_write(i2c, SHA1_ADDR_BLOCK + i, block[0][i])
+
+    # Start initial block hashing, wait and check status.
+    sha1_init(i2c)
+    sha1_wait_valid(i2c)
+
+    # Extract the first digest.
+    for i in range(len(block0_expected)):
+        sha1_read(i2c, SHA1_ADDR_DIGEST + i, block0_expected[i])
+
+    # Write second block to SHA-1.
+    for i in range(len(block[1])):
+        sha1_write(i2c, SHA1_ADDR_BLOCK + i, block[1][i])
+
+    # Start next block hashing, wait and check status.
+    sha1_next(i2c)
+    sha1_wait_valid(i2c)
+
+    # Extract the second digest.
+    for i in range(len(expected)):
+        sha1_read(i2c, SHA1_ADDR_DIGEST + i, expected[i])
+
+#----------------------------------------------------------------
+# SHA-256 test cases
+#----------------------------------------------------------------
+SHA256_ADDR_PREFIX      = 0x20
+SHA256_ADDR_BLOCK       = 0x10
+SHA256_ADDR_DIGEST      = 0x20
+
+def sha256_read(i2c, addr, data):
+    tc_read(i2c, SHA256_ADDR_PREFIX, addr, data)
+
+def sha256_write(i2c, addr, data):
+    tc_write(i2c, SHA256_ADDR_PREFIX, addr, data)
+
+def sha256_init(i2c):
+    tc_init(i2c, SHA256_ADDR_PREFIX)
+
+def sha256_next(i2c):
+    tc_next(i2c, SHA256_ADDR_PREFIX)
+
+def sha256_wait_ready(i2c):
+    tc_wait_ready(i2c, SHA256_ADDR_PREFIX)
+
+def sha256_wait_valid(i2c):
+    tc_wait_valid(i2c, SHA256_ADDR_PREFIX)
+
+# TC4: Read name and version from SHA-256 core.
+def TC4(i2c):
+    print "TC4: Reading name, type and version words from SHA-256 core."
+
+    sha256_read(i2c, ADDR_NAME0, 0x73686132)	# "sha2"
+    sha256_read(i2c, ADDR_NAME1, 0x2d323536)	# "-256"
+    sha256_read(i2c, ADDR_VERSION, 0x302e3830)	# "0.80"
+
+# TC5: SHA-256 Single block message test as specified by NIST.
+def TC5(i2c):
+    block = NIST_512_SINGLE
+    expected = SHA256_SINGLE_DIGEST
+
+    print "TC5: Single block message test for SHA-256."
+
+    # Write block to SHA-256.
+    for i in range(len(block)):
+        sha256_write(i2c, SHA256_ADDR_BLOCK + i, block[i])
+
+    # Start initial block hashing, wait and check status.
+    sha256_init(i2c)
+    sha256_wait_valid(i2c)
+
+    # Extract the digest.
+    for i in range(len(expected)):
+        sha256_read(i2c, SHA256_ADDR_DIGEST + i, expected[i])
+
+# TC6: SHA-256 Double block message test as specified by NIST.
+def TC6(i2c):
+    block = [ NIST_512_DOUBLE0, NIST_512_DOUBLE1 ]
+    block0_expected = [ 0x85E655D6, 0x417A1795, 0x3363376A, 0x624CDE5C,
+                        0x76E09589, 0xCAC5F811, 0xCC4B32C1, 0xF20E533A ]
+    expected = SHA256_DOUBLE_DIGEST
+
+    print "TC6: Double block message test for SHA-256."
+
+    # Write first block to SHA-256.
+    for i in range(len(block[0])):
+        sha256_write(i2c, SHA256_ADDR_BLOCK + i, block[0][i])
+
+    # Start initial block hashing, wait and check status.
+    sha256_init(i2c)
+    sha256_wait_valid(i2c)
+
+    # Extract the first digest.
+    for i in range(len(block0_expected)):
+        sha256_read(i2c, SHA256_ADDR_DIGEST + i, block0_expected[i])
+
+    # Write second block to SHA-256.
+    for i in range(len(block[1])):
+        sha256_write(i2c, SHA256_ADDR_BLOCK + i, block[1][i])
+
+    # Start next block hashing, wait and check status.
+    sha256_next(i2c)
+    sha256_wait_valid(i2c)
+
+    # Extract the second digest.
+    for i in range(len(expected)):
+        sha256_read(i2c, SHA256_ADDR_DIGEST + i, expected[i])
+
+# TC7: SHA-256 Huge message test.
+def TC7(i2c):
+    block = [ 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+              0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+              0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f,
+              0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f ]
+    expected = [ 0x7638f3bc, 0x500dd1a6, 0x586dd4d0, 0x1a1551af,
+                 0xd821d235, 0x2f919e28, 0xd5842fab, 0x03a40f2a ]
+    n = 1000
+
+    print "TC7: Message with %d blocks test for SHA-256." % n
+
+    # Write first block to SHA-256.
+    for i in range(len(block)):
+        sha256_write(i2c, SHA256_ADDR_BLOCK + i, block[i])
+
+    # Start initial block hashing, wait and check status.
+    sha256_init(i2c)
+    sha256_wait_ready(i2c)
+
+    # First block done. Do the rest.
+    for i in range(n - 1):
+        # Start next block hashing, wait and check status.
+        sha256_next(i2c)
+        sha256_wait_ready(i2c)
+
+    # XXX valid is probably set at the same time as ready
+    sha256_wait_valid(i2c)
+
+    # Extract the final digest.
+    for i in range(len(expected)):
+        sha256_read(i2c, SHA256_ADDR_DIGEST + i, expected[i])
+
+#----------------------------------------------------------------
+# SHA-512 test cases
+#----------------------------------------------------------------
+SHA512_ADDR_PREFIX      = 0x30
+SHA512_ADDR_BLOCK       = 0x10
+SHA512_ADDR_DIGEST      = 0x40
+SHA512_CTRL_MODE_LOW    = 2
+SHA512_CTRL_MODE_HIGH   = 3
+MODE_SHA_512_224 = 0
+MODE_SHA_512_256 = 1
+MODE_SHA_384     = 2
+MODE_SHA_512     = 3
+
+def sha512_read(i2c, addr, data):
+    tc_read(i2c, SHA512_ADDR_PREFIX, addr, data)
+
+def sha512_write(i2c, addr, data):
+    tc_write(i2c, SHA512_ADDR_PREFIX, addr, data)
+
+def sha512_init(i2c, mode):
+    tc_write(i2c, SHA512_ADDR_PREFIX, ADDR_CTRL,
+             CTRL_INIT_CMD + (mode << SHA512_CTRL_MODE_LOW))
+
+def sha512_next(i2c, mode):
+    tc_write(i2c, SHA512_ADDR_PREFIX, ADDR_CTRL,
+             CTRL_NEXT_CMD + (mode << SHA512_CTRL_MODE_LOW))
+
+def sha512_wait_ready(i2c):
+    tc_wait_ready(i2c, SHA512_ADDR_PREFIX)
+
+def sha512_wait_valid(i2c):
+    tc_wait_valid(i2c, SHA512_ADDR_PREFIX)
+
+# TC8: Read name and version from SHA-512 core.
+def TC8(i2c):
+    print "TC8: Reading name, type and version words from SHA-512 core."
+
+    sha512_read(i2c, ADDR_NAME0, 0x73686132)	# "sha2"
+    sha512_read(i2c, ADDR_NAME1, 0x2d353132)	# "-512"
+    sha512_read(i2c, ADDR_VERSION, 0x302e3830)	# "0.80"
+
+# TC9: SHA-512 Single block message test as specified by NIST.
+# We do this for all modes.
+def TC9(i2c):
+    def tc9(i2c, mode, expected):
+        block = NIST_1024_SINGLE
+
+        # Write block to SHA-512.
+        for i in range(len(block)):
+            sha512_write(i2c, SHA512_ADDR_BLOCK + i, block[i])
+
+        # Start initial block hashing, wait and check status.
+        sha512_init(i2c, mode)
+        sha512_wait_valid(i2c)
+
+        # Extract the digest.
+        for i in range(len(expected)):
+            sha512_read(i2c, SHA512_ADDR_DIGEST + i, expected[i])
+
+    print "TC9-1: Single block message test for SHA-512/224."
+    tc9(i2c, MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST)
+
+    print "TC9-2: Single block message test for SHA-512/256."
+    tc9(i2c, MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST)
+
+    print "TC9-3: Single block message test for SHA-384."
+    tc9(i2c, MODE_SHA_384, SHA384_SINGLE_DIGEST)
+
+    print "TC9-4: Single block message test for SHA-512."
+    tc9(i2c, MODE_SHA_512, SHA512_SINGLE_DIGEST)
+
+# TC10: SHA-512 Single block message test as specified by NIST.
+# We do this for all modes.
+def TC10(i2c):
+    def tc10(i2c, mode, expected):
+        block = [ NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 ]
+
+        # Write first block to SHA-512.
+        for i in range(len(block[0])):
+            sha512_write(i2c, SHA512_ADDR_BLOCK + i, block[0][i])
+
+        # Start initial block hashing, wait and check status.
+        sha512_init(i2c, mode)
+        sha512_wait_ready(i2c)
+
+        # Write second block to SHA-512.
+        for i in range(len(block[1])):
+            sha512_write(i2c, SHA512_ADDR_BLOCK + i, block[1][i])
+
+        # Start next block hashing, wait and check status.
+        sha512_next(i2c, mode)
+        sha512_wait_valid(i2c)
+
+        # Extract the digest.
+        for i in range(len(expected)):
+            sha512_read(i2c, SHA512_ADDR_DIGEST + i, expected[i])
+
+    print "TC10-1: Double block message test for SHA-512/224."
+    tc10(i2c, MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST)
+
+    print "TC10-2: Double block message test for SHA-512/256."
+    tc10(i2c, MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST)
+
+    print "TC10-3: Double block message test for SHA-384."
+    tc10(i2c, MODE_SHA_384, SHA384_DOUBLE_DIGEST)
+
+    print "TC10-4: Double block message test for SHA-512."
+    tc10(i2c, MODE_SHA_512, SHA512_DOUBLE_DIGEST)
+
+
+#----------------------------------------------------------------
+# main
+#----------------------------------------------------------------
+if __name__ == '__main__':
+    import argparse
+
+    all_tests = [ TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC8, TC9, TC10 ]
+    sha1_tests = all_tests[0:3]
+    sha256_tests = all_tests[3:7]
+    sha512_tests = all_tests[7:]
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-d', '--debug', action='store_true',
+                        help='add debugging/trace information')
+    parser.add_argument('-i', dest='dev', default=I2C_dev,
+                        help='I2C device name (default ' + I2C_dev + ')')
+    parser.add_argument('-a', dest='addr', type=lambda x:int(x,0), default=I2C_addr,
+                        help='I2C device address (default ' + hex(I2C_addr) + ')')
+    parser.add_argument('test_cases', metavar='TC', nargs='*',
+                        help='test case number, "sha1", "sha256", "sha512", or "all"')
+    args = parser.parse_args()
+    DEBUG = args.debug
+    i = I2C(args.dev, args.addr)
+
+    if (not args.test_cases):
+        for TC in all_tests:
+            TC(i)
+    else:
+        for t in args.test_cases:
+            if (t == 'sha1'):
+                for TC in sha1_tests:
+                    TC(i)
+            elif (t == 'sha256'):
+                for TC in sha256_tests:
+                    TC(i)
+            elif (t == 'sha512'):
+                for TC in sha512_tests:
+                    TC(i)
+            elif (t == 'all'):
+                for TC in all_tests:
+                    TC(i)
+            else:
+                try:
+                    n = int(t)
+                except:
+                    print 'invalid test case %s' % t
+                else:
+                    if ((n < 1) or (n > len(all_tests))):
+                        print 'invalid test case %d' % n
+                    else:
+                        all_tests[n-1](i)
+
+#=======================================================================
+# EOF hash_tester.py
+#=======================================================================
diff --git a/synth/Makefile b/synth/Makefile
new file mode 100644
index 0000000..d05a056
--- /dev/null
+++ b/synth/Makefile
@@ -0,0 +1,20 @@
+project = coretest-novena
+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 \
+	../../coretest/src/rtl/coretest.v \
+	../../i2c/src/rtl/i2c_core.v ../../i2c/src/rtl/i2c.v \
+	../../sha1/src/rtl/sha1_core.v ../../sha1/src/rtl/sha1.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.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.v \
+	../../sha512/src/rtl/sha512_w_mem.v
+
+include xilinx.mk
diff --git a/synth/coretest-novena.bmm b/synth/coretest-novena.bmm
new file mode 100644
index 0000000..e69de29
diff --git a/synth/coretest-novena.ucf b/synth/coretest-novena.ucf
new file mode 100644
index 0000000..448c692
--- /dev/null
+++ b/synth/coretest-novena.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/synth/xilinx.mk b/synth/xilinx.mk
new file mode 100644
index 0000000..a3a0216
--- /dev/null
+++ b/synth/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/synth/xilinx.opt b/synth/xilinx.opt
new file mode 100644
index 0000000..7fe9d8b
--- /dev/null
+++ b/synth/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



More information about the Commits mailing list