[Cryptech-Commits] [core/platform/novena] 01/01: generate core_selector, probe FPGA for cores at software startup

git at cryptech.is git at cryptech.is
Wed Jun 10 16:40:38 UTC 2015


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

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

commit f141a79d805acbab07876d9f007e8809603718b5
Author: Paul Selkirk <paul at psgd.org>
Date:   Wed Jun 10 12:30:58 2015 -0400

    generate core_selector, probe FPGA for cores at software startup
---
 config/config.cfg      |  19 +++
 config/config.py       | 212 +++++++++++++++++++++++++++
 config/core_selector.v | 250 ++++++++++++++++++++++++++++++++
 eim/build/Makefile     |   7 +-
 sw/Makefile            |   2 +-
 sw/Makefile.i2c        |   2 +-
 sw/aes_tester.c        | 102 +++++++------
 sw/capability.c        | 145 +++++++++++++++++++
 sw/cryptech.h          | 381 ++++++++++++++++++++++++-------------------------
 sw/hash.c              |  84 ++++++++---
 sw/hash_tester.c       | 206 ++++++++++++++++++--------
 sw/modexp_tester.c     | 333 ++++++++++++++++++++----------------------
 sw/tc_eim.c            |  22 +--
 sw/trng_extractor.c    |  58 +++-----
 sw/trng_tester.c       | 119 ++++++++++++---
 15 files changed, 1363 insertions(+), 579 deletions(-)

diff --git a/config/config.cfg b/config/config.cfg
new file mode 100644
index 0000000..360988e
--- /dev/null
+++ b/config/config.cfg
@@ -0,0 +1,19 @@
+# Config file for the Cryptech Novena FPGA framework.
+
+[default]
+default = rsa
+
+[hash-only]
+cores = sha1, sha256, sha512
+
+[trng-only]
+cores = trng
+
+[modexp-only]
+cores = modexp
+
+[rsa]
+cores = sha256, aes, trng, modexp
+
+[multi-test]
+cores = sha256, aes, aes, chacha, aes
diff --git a/config/config.py b/config/config.py
new file mode 100755
index 0000000..86c8615
--- /dev/null
+++ b/config/config.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+#
+# Generate core_selector.v for a set of cores
+
+import argparse
+import re
+import sys
+if sys.version > '3':
+    import configparser
+else:
+    import ConfigParser as configparser
+
+# defaults
+config = 'config.cfg'
+outfile = 'core_selector.v'
+section = ''
+cores = []
+
+# added cores for TRNG, muxed through trng.v
+trng_cores = ['avalanche_entropy', 'rosc_entropy', 'trng_mixer', 'trng_csprng']
+
+# parse the command line
+def cmdParse():
+    global config, outfile, section, cores
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--cores', help='comma-delimited list of cores')
+    parser.add_argument('-c', '--config', default=config,
+                        help='config file (default "%s")' % config)
+    parser.add_argument('-s', '--section', help='config file section')
+    parser.add_argument('-o', '--outfile',
+                        help='output file (default "%s")' % outfile)
+    args = parser.parse_args()
+
+    if args.cores:
+        cores = re.split(',\s*', args.cores)
+    if args.config:
+        config = args.config
+    if args.outfile:
+        outfile = args.outfile
+    if args.section:
+        section = args.section
+
+# parse the config file
+def configParse(section):
+    cfg = configparser.ConfigParser()
+    try:
+        with open(config, 'r') as f:
+            cfg.readfp(f)
+    except (IOError, configparser.MissingSectionHeaderError) as e:
+        print e
+        exit(1);
+
+    try:
+        if not section:
+            section = cfg.get('default', 'default')
+        cores = cfg.get(section, 'cores')
+    except (configparser.NoSectionError, configparser.NoOptionError) as e:
+        print e
+        exit(1);
+
+    return re.split(r',\s*', cores)
+
+# create an entry in the Core Address Table
+def createAddr(core, corenum):
+    return "   localparam   CORE_ADDR_{:21s} = 9'h{:02x};\n".format(core.upper(), corenum)
+
+# create an instantiation of the core
+# This is complicated because TRNG is a mux for 5 cores.
+def createInstance(core):
+    core_stripped = re.sub('_\d+$', '', core)
+    if core_stripped == 'trng':
+        s3 = "(addr_core_num >= CORE_ADDR_TRNG) && (addr_core_num <= CORE_ADDR_TRNG_CSPRNG)"
+        s4 = "   wire [3:0]           trng_prefix = addr_core_num[3:0] - CORE_ADDR_TRNG;\n"
+        s5 = "{trng_prefix, addr_core_reg}"
+        s6 = ",\n\n      .avalanche_noise(noise),\n      .debug(debug)"
+    else:
+        s3 = "(addr_core_num == CORE_ADDR_{0})".format(core.upper())
+        s4 = ""
+        s5 = "addr_core_reg"
+        s6 = ""
+    
+    return "\
+   //----------------------------------------------------------------\n\
+   // {1}\n\
+   //----------------------------------------------------------------\n\
+   wire                 enable_{0} = {3};\n\
+   wire [31: 0]         read_data_{0};\n\
+   wire                 error_{0};\n\
+{4}\n\
+   {2} {0}_inst\n\
+     (\n\
+      .clk(sys_clk),\n\
+      .reset_n(~sys_rst),\n\
+\n\
+      .cs(enable_{0} & (sys_eim_rd | sys_eim_wr)),\n\
+      .we(sys_eim_wr),\n\
+\n\
+      .address({5}),\n\
+      .write_data(sys_write_data),\n\
+      .read_data(read_data_{0}){6}\n\
+      );\n\n\n".format(core, core.upper(), core_stripped, s3, s4, s5, s6)
+
+# create an entry in the Output (Read Data) Multiplexer
+def createMux(core, core0):
+    return "\
+       CORE_ADDR_{0}:\n\
+         begin\n\
+            sys_read_data_mux = read_data_{1};\n\
+            sys_error_mux = error_{1};\n\
+         end\n".format(core.upper(), core0)
+
+# create the core_selector module
+def createModule(cores):
+    cores = ['board_regs', 'comm_regs'] + cores
+
+    # if multiple instances of a core, number them
+    for a in set([x for x in cores if cores.count(x) > 1]):
+      i = 0
+      j = 0
+      while (1):
+        try:
+          j = cores.index(a, j)
+        except ValueError:
+          break
+        cores[j] += '_' + str(i)
+        i += 1
+        j += 1
+    
+    addrs = ""
+    insts = ""
+    muxs = ""
+    corenum = 0
+    for core in cores:
+        addrs += createAddr(core, corenum)
+        insts += createInstance(core)
+        muxs += createMux(core, core)
+        corenum += 1
+        if core == 'trng':
+            for tcore in trng_cores:
+                addrs += createAddr(tcore, corenum)
+                muxs += createMux(tcore, core)
+                corenum += 1
+
+    # write the boilerplate and all per-core bits
+    with open(outfile, 'w') as f:
+        f.write("\
+// NOTE: This file is generated; do not edit by hand.\n\
+\n\
+module core_selector\n\
+  (\n\
+   input wire          sys_clk,\n\
+   input wire          sys_rst,\n\
+\n\
+   input wire [16: 0]  sys_eim_addr,\n\
+   input wire          sys_eim_wr,\n\
+   input wire          sys_eim_rd,\n\
+   output wire [31: 0] sys_read_data,\n\
+   input wire [31: 0]  sys_write_data,\n\
+   output wire         sys_error,\n\
+\n\
+   input wire          noise,\n\
+   output wire [7 : 0] debug\n\
+   );\n\
+\n\
+\n\
+   //----------------------------------------------------------------\n\
+   // Address Decoder\n\
+   //----------------------------------------------------------------\n\
+   // upper 9 bits specify core being addressed\n\
+   wire [ 8: 0]         addr_core_num   = sys_eim_addr[16: 8];\n\
+   // lower 8 bits specify register offset in core\n\
+   wire [ 7: 0]         addr_core_reg   = sys_eim_addr[ 7: 0];\n\
+\n\n\
+   //----------------------------------------------------------------\n\
+   // Core Address Table\n\
+   //----------------------------------------------------------------\n\
+{0}\n\
+\n\
+{1}\n\
+   //----------------------------------------------------------------\n\
+   // Output (Read Data) Multiplexer\n\
+   //----------------------------------------------------------------\n\
+   reg [31: 0]          sys_read_data_mux;\n\
+   assign               sys_read_data = sys_read_data_mux;\n\
+   reg                  sys_error_mux;\n\
+   assign               sys_error = sys_error_mux;\n\
+\n\
+   always @*\n\
+\n\
+     case (addr_core_num)\n\
+{2}\n\
+       default:\n\
+         begin\n\
+            sys_read_data_mux = {{32{{1'b0}}}};\n\
+            sys_error_mux = 1;\n\
+         end\n\
+     endcase\n\
+\n\
+\n\
+endmodule\n\
+\n\
+\n\
+//======================================================================\n\
+// EOF core_selector.v\n\
+//======================================================================\n".format(addrs, insts, muxs))
+
+# main
+cmdParse()
+if not cores:
+    cores = configParse(section)
+createModule(cores)
diff --git a/config/core_selector.v b/config/core_selector.v
new file mode 100644
index 0000000..4debd60
--- /dev/null
+++ b/config/core_selector.v
@@ -0,0 +1,250 @@
+// NOTE: This file is generated; do not edit by hand.
+
+module core_selector
+  (
+   input wire          sys_clk,
+   input wire          sys_rst,
+
+   input wire [16: 0]  sys_eim_addr,
+   input wire          sys_eim_wr,
+   input wire          sys_eim_rd,
+   output wire [31: 0] sys_read_data,
+   input wire [31: 0]  sys_write_data,
+   output wire         sys_error,
+
+   input wire          noise,
+   output wire [7 : 0] debug
+   );
+
+
+   //----------------------------------------------------------------
+   // Address Decoder
+   //----------------------------------------------------------------
+   // upper 9 bits specify core being addressed
+   wire [ 8: 0]         addr_core_num   = sys_eim_addr[16: 8];
+   // lower 8 bits specify register offset in core
+   wire [ 7: 0]         addr_core_reg   = sys_eim_addr[ 7: 0];
+
+
+   //----------------------------------------------------------------
+   // Core Address Table
+   //----------------------------------------------------------------
+   localparam   CORE_ADDR_BOARD_REGS            = 9'h00;
+   localparam   CORE_ADDR_COMM_REGS             = 9'h01;
+   localparam   CORE_ADDR_SHA256                = 9'h02;
+   localparam   CORE_ADDR_AES                   = 9'h03;
+   localparam   CORE_ADDR_TRNG                  = 9'h04;
+   localparam   CORE_ADDR_AVALANCHE_ENTROPY     = 9'h05;
+   localparam   CORE_ADDR_ROSC_ENTROPY          = 9'h06;
+   localparam   CORE_ADDR_TRNG_MIXER            = 9'h07;
+   localparam   CORE_ADDR_TRNG_CSPRNG           = 9'h08;
+   localparam   CORE_ADDR_MODEXP                = 9'h09;
+
+
+   //----------------------------------------------------------------
+   // BOARD_REGS
+   //----------------------------------------------------------------
+   wire                 enable_board_regs = (addr_core_num == CORE_ADDR_BOARD_REGS);
+   wire [31: 0]         read_data_board_regs;
+   wire                 error_board_regs;
+
+   board_regs board_regs_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_board_regs & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_board_regs)
+      );
+
+
+   //----------------------------------------------------------------
+   // COMM_REGS
+   //----------------------------------------------------------------
+   wire                 enable_comm_regs = (addr_core_num == CORE_ADDR_COMM_REGS);
+   wire [31: 0]         read_data_comm_regs;
+   wire                 error_comm_regs;
+
+   comm_regs comm_regs_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_comm_regs & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_comm_regs)
+      );
+
+
+   //----------------------------------------------------------------
+   // SHA256
+   //----------------------------------------------------------------
+   wire                 enable_sha256 = (addr_core_num == CORE_ADDR_SHA256);
+   wire [31: 0]         read_data_sha256;
+   wire                 error_sha256;
+
+   sha256 sha256_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_sha256 & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_sha256)
+      );
+
+
+   //----------------------------------------------------------------
+   // AES
+   //----------------------------------------------------------------
+   wire                 enable_aes = (addr_core_num == CORE_ADDR_AES);
+   wire [31: 0]         read_data_aes;
+   wire                 error_aes;
+
+   aes aes_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_aes & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_aes)
+      );
+
+
+   //----------------------------------------------------------------
+   // TRNG
+   //----------------------------------------------------------------
+   wire                 enable_trng = (addr_core_num >= CORE_ADDR_TRNG) && (addr_core_num <= CORE_ADDR_TRNG_CSPRNG);
+   wire [31: 0]         read_data_trng;
+   wire                 error_trng;
+   wire [3:0]           trng_prefix = addr_core_num[3:0] - CORE_ADDR_TRNG;
+
+   trng trng_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_trng & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address({trng_prefix, addr_core_reg}),
+      .write_data(sys_write_data),
+      .read_data(read_data_trng),
+
+      .avalanche_noise(noise),
+      .debug(debug)
+      );
+
+
+   //----------------------------------------------------------------
+   // MODEXP
+   //----------------------------------------------------------------
+   wire                 enable_modexp = (addr_core_num == CORE_ADDR_MODEXP);
+   wire [31: 0]         read_data_modexp;
+   wire                 error_modexp;
+
+   modexp modexp_inst
+     (
+      .clk(sys_clk),
+      .reset_n(~sys_rst),
+
+      .cs(enable_modexp & (sys_eim_rd | sys_eim_wr)),
+      .we(sys_eim_wr),
+
+      .address(addr_core_reg),
+      .write_data(sys_write_data),
+      .read_data(read_data_modexp)
+      );
+
+
+
+   //----------------------------------------------------------------
+   // Output (Read Data) Multiplexer
+   //----------------------------------------------------------------
+   reg [31: 0]          sys_read_data_mux;
+   assign               sys_read_data = sys_read_data_mux;
+   reg                  sys_error_mux;
+   assign               sys_error = sys_error_mux;
+
+   always @*
+
+     case (addr_core_num)
+       CORE_ADDR_BOARD_REGS:
+         begin
+            sys_read_data_mux = read_data_board_regs;
+            sys_error_mux = error_board_regs;
+         end
+       CORE_ADDR_COMM_REGS:
+         begin
+            sys_read_data_mux = read_data_comm_regs;
+            sys_error_mux = error_comm_regs;
+         end
+       CORE_ADDR_SHA256:
+         begin
+            sys_read_data_mux = read_data_sha256;
+            sys_error_mux = error_sha256;
+         end
+       CORE_ADDR_AES:
+         begin
+            sys_read_data_mux = read_data_aes;
+            sys_error_mux = error_aes;
+         end
+       CORE_ADDR_TRNG:
+         begin
+            sys_read_data_mux = read_data_trng;
+            sys_error_mux = error_trng;
+         end
+       CORE_ADDR_AVALANCHE_ENTROPY:
+         begin
+            sys_read_data_mux = read_data_trng;
+            sys_error_mux = error_trng;
+         end
+       CORE_ADDR_ROSC_ENTROPY:
+         begin
+            sys_read_data_mux = read_data_trng;
+            sys_error_mux = error_trng;
+         end
+       CORE_ADDR_TRNG_MIXER:
+         begin
+            sys_read_data_mux = read_data_trng;
+            sys_error_mux = error_trng;
+         end
+       CORE_ADDR_TRNG_CSPRNG:
+         begin
+            sys_read_data_mux = read_data_trng;
+            sys_error_mux = error_trng;
+         end
+       CORE_ADDR_MODEXP:
+         begin
+            sys_read_data_mux = read_data_modexp;
+            sys_error_mux = error_modexp;
+         end
+
+       default:
+         begin
+            sys_read_data_mux = {32{1'b0}};
+            sys_error_mux = 1;
+         end
+     endcase
+
+
+endmodule
+
+
+//======================================================================
+// EOF core_selector.v
+//======================================================================
diff --git a/eim/build/Makefile b/eim/build/Makefile
index 7bb4ffd..d598126 100644
--- a/eim/build/Makefile
+++ b/eim/build/Makefile
@@ -12,12 +12,7 @@ vfiles = \
 	../../common/rtl/novena_regs.v \
 	../../common/rtl/novena_clkmgr.v \
 	../../common/rtl/ipcore/clkmgr_dcm.v \
-	../../../common/core_selector/src/rtl/core_selector.v \
-	../../../common/core_selector/src/rtl/global_selector.v \
-	../../../common/core_selector/src/rtl/hash_selector.v \
-	../../../common/core_selector/src/rtl/rng_selector.v \
-	../../../common/core_selector/src/rtl/cipher_selector.v \
-	../../../common/core_selector/src/rtl/math_selector.v \
+	../../config/core_selector.v \
 	../../../../comm/eim/src/rtl/cdc_bus_pulse.v \
 	../../../../comm/eim/src/rtl/eim_arbiter_cdc.v \
 	../../../../comm/eim/src/rtl/eim_arbiter.v \
diff --git a/sw/Makefile b/sw/Makefile
index 2aa4927..d1f33f2 100755
--- a/sw/Makefile
+++ b/sw/Makefile
@@ -15,7 +15,7 @@ all: $(LIB) $(BIN)
 %.o: %.c $(INC)
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-libcryptech.a: tc_eim.o novena-eim.o
+libcryptech.a: tc_eim.o novena-eim.o capability.o
 	ar rcs $@ $^
 
 hash_tester: hash_tester.o $(LIB)
diff --git a/sw/Makefile.i2c b/sw/Makefile.i2c
index 98cd541..1294360 100755
--- a/sw/Makefile.i2c
+++ b/sw/Makefile.i2c
@@ -15,7 +15,7 @@ all: $(LIB) $(BIN)
 %.o: %.c $(INC)
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-libcryptech_i2c.a: tc_i2c.o
+libcryptech_i2c.a: tc_i2c.o capability.o
 	ar rcs $@ $^
 
 hash_tester_i2c: hash_tester.o $(LIB)
diff --git a/sw/aes_tester.c b/sw/aes_tester.c
index 36a3e0d..497f334 100644
--- a/sw/aes_tester.c
+++ b/sw/aes_tester.c
@@ -69,16 +69,12 @@
 
 //------------------------------------------------------------------
 //------------------------------------------------------------------
+static off_t aes_addr_base;
+
 static void check_aes_access(void)
 {
-  uint8_t name0[4], name1[4], version[4];
-
-  printf("Trying to read the aes core name\n");
-
-  check(tc_read(AES_ADDR_NAME0,   name0,    sizeof(name0)));
-  check(tc_read(AES_ADDR_NAME1,   name1,    sizeof(name1)));
-  check(tc_read(AES_ADDR_VERSION, version, sizeof(version)));
-  printf("%4.4s%4.4s %4.4s\n\n", name0, name1, version);
+    aes_addr_base = tc_core_base("aes");
+    assert(aes_addr_base != 0);
 }
 
 
@@ -126,24 +122,24 @@ static void single_block_test(const uint32_t keylength, const uint32_t *key,
 	     key[0], key[1], key[2], key[3]);
   }
 
-  tc_w32(AES_ADDR_KEY0, key[0]);
-  tc_w32(AES_ADDR_KEY1, key[1]);
-  tc_w32(AES_ADDR_KEY2, key[2]);
-  tc_w32(AES_ADDR_KEY3, key[3]);
+  tc_w32(aes_addr_base + AES_ADDR_KEY0, key[0]);
+  tc_w32(aes_addr_base + AES_ADDR_KEY1, key[1]);
+  tc_w32(aes_addr_base + AES_ADDR_KEY2, key[2]);
+  tc_w32(aes_addr_base + AES_ADDR_KEY3, key[3]);
 
   if (keylength == 256) {
-    tc_w32(AES_ADDR_KEY4, key[4]);
-    tc_w32(AES_ADDR_KEY5, key[5]);
-    tc_w32(AES_ADDR_KEY6, key[6]);
-    tc_w32(AES_ADDR_KEY7, key[7]);
+    tc_w32(aes_addr_base + AES_ADDR_KEY4, key[4]);
+    tc_w32(aes_addr_base + AES_ADDR_KEY5, key[5]);
+    tc_w32(aes_addr_base + AES_ADDR_KEY6, key[6]);
+    tc_w32(aes_addr_base + AES_ADDR_KEY7, key[7]);
   }
 
   if (CHECK_WRITE) {
     const uint32_t
-      k0 = tc_r32(AES_ADDR_KEY0), k1 = tc_r32(AES_ADDR_KEY1),
-      k2 = tc_r32(AES_ADDR_KEY2), k3 = tc_r32(AES_ADDR_KEY3),
-      k4 = tc_r32(AES_ADDR_KEY4), k5 = tc_r32(AES_ADDR_KEY5),
-      k6 = tc_r32(AES_ADDR_KEY6), k7 = tc_r32(AES_ADDR_KEY7);
+      k0 = tc_r32(aes_addr_base + AES_ADDR_KEY0), k1 = tc_r32(aes_addr_base + AES_ADDR_KEY1),
+      k2 = tc_r32(aes_addr_base + AES_ADDR_KEY2), k3 = tc_r32(aes_addr_base + AES_ADDR_KEY3),
+      k4 = tc_r32(aes_addr_base + AES_ADDR_KEY4), k5 = tc_r32(aes_addr_base + AES_ADDR_KEY5),
+      k6 = tc_r32(aes_addr_base + AES_ADDR_KEY6), k7 = tc_r32(aes_addr_base + AES_ADDR_KEY7);
     const int
       ok1 = k0 == key[0] && k1 == key[1] && k2 == key[2] && k3 == key[3],
       ok2 = k4 == key[4] && k5 == key[5] && k6 == key[6] && k7 == key[7];
@@ -158,26 +154,26 @@ static void single_block_test(const uint32_t keylength, const uint32_t *key,
   // Performing init i.e. key expansion,
   printf("Doing key init\n");
   if (keylength == 256)
-    tc_w32(AES_ADDR_CONFIG, 0x00000002);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000002);
   else
-    tc_w32(AES_ADDR_CONFIG, 0x00000000);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000000);
 
-  tc_w32(AES_ADDR_CTRL,   0x00000001);
+  tc_w32(aes_addr_base + AES_ADDR_CTRL,   0x00000001);
 
 
   if (VERBOSE)
     printf("Writing block 0x%08x 0x%08x 0x%08x 0x%08x\n",
 	   block[0], block[1], block[2], block[3]);
 
-  tc_w32(AES_ADDR_BLOCK0, block[0]);
-  tc_w32(AES_ADDR_BLOCK1, block[1]);
-  tc_w32(AES_ADDR_BLOCK2, block[2]);
-  tc_w32(AES_ADDR_BLOCK3, block[3]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK0, block[0]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK1, block[1]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK2, block[2]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK3, block[3]);
 
   if (CHECK_WRITE) {
     const uint32_t
-      b0 = tc_r32(AES_ADDR_BLOCK0), b1 = tc_r32(AES_ADDR_BLOCK1),
-      b2 = tc_r32(AES_ADDR_BLOCK2), b3 = tc_r32(AES_ADDR_BLOCK3);
+      b0 = tc_r32(aes_addr_base + AES_ADDR_BLOCK0), b1 = tc_r32(aes_addr_base + AES_ADDR_BLOCK1),
+      b2 = tc_r32(aes_addr_base + AES_ADDR_BLOCK2), b3 = tc_r32(aes_addr_base + AES_ADDR_BLOCK3);
     const int
       ok = b0 == block[0] && b1 == block[1] && b2 == block[2] && b3 == block[3];
     printf("Reading back block: 0x%08x  0x%08x 0x%08x 0x%08x %s\n",
@@ -188,46 +184,46 @@ static void single_block_test(const uint32_t keylength, const uint32_t *key,
     printf("Starting single block encipher operation\n");
 
   if (keylength == 256)
-    tc_w32(AES_ADDR_CONFIG, 0x00000003);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000003);
   else
-    tc_w32(AES_ADDR_CONFIG, 0x00000001);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000001);
 
-  tc_w32(AES_ADDR_CTRL,   0x00000002);
+  tc_w32(aes_addr_base + AES_ADDR_CTRL,   0x00000002);
 
   if (VERBOSE)
       printf("Checking ready: 0x%08x\n",
-	     tc_r32(AES_ADDR_STATUS));
+	     tc_r32(aes_addr_base + AES_ADDR_STATUS));
 
-  check(tc_wait_ready(AES_ADDR_STATUS));
+  check(tc_wait_ready(aes_addr_base + AES_ADDR_STATUS));
 
   if (VERBOSE)
     printf("Ready seen. Result: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-	   tc_r32(AES_ADDR_RESULT0), tc_r32(AES_ADDR_RESULT1),
-	   tc_r32(AES_ADDR_RESULT2), tc_r32(AES_ADDR_RESULT3));
+	   tc_r32(aes_addr_base + AES_ADDR_RESULT0), tc_r32(aes_addr_base + AES_ADDR_RESULT1),
+	   tc_r32(aes_addr_base + AES_ADDR_RESULT2), tc_r32(aes_addr_base + AES_ADDR_RESULT3));
 
-  enc_result[0] = tc_r32(AES_ADDR_RESULT0);
-  enc_result[1] = tc_r32(AES_ADDR_RESULT1);
-  enc_result[2] = tc_r32(AES_ADDR_RESULT2);
-  enc_result[3] = tc_r32(AES_ADDR_RESULT3);
+  enc_result[0] = tc_r32(aes_addr_base + AES_ADDR_RESULT0);
+  enc_result[1] = tc_r32(aes_addr_base + AES_ADDR_RESULT1);
+  enc_result[2] = tc_r32(aes_addr_base + AES_ADDR_RESULT2);
+  enc_result[3] = tc_r32(aes_addr_base + AES_ADDR_RESULT3);
 
-  tc_w32(AES_ADDR_BLOCK0, enc_result[0]);
-  tc_w32(AES_ADDR_BLOCK1, enc_result[1]);
-  tc_w32(AES_ADDR_BLOCK2, enc_result[2]);
-  tc_w32(AES_ADDR_BLOCK3, enc_result[3]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK0, enc_result[0]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK1, enc_result[1]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK2, enc_result[2]);
+  tc_w32(aes_addr_base + AES_ADDR_BLOCK3, enc_result[3]);
 
   // Single block decipher operation.
   if (keylength == 256)
-    tc_w32(AES_ADDR_CONFIG, 0x00000002);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000002);
   else
-    tc_w32(AES_ADDR_CONFIG, 0x00000000);
-  tc_w32(AES_ADDR_CTRL,   0x00000002);
+    tc_w32(aes_addr_base + AES_ADDR_CONFIG, 0x00000000);
+  tc_w32(aes_addr_base + AES_ADDR_CTRL,   0x00000002);
 
-  check(tc_wait_ready(AES_ADDR_STATUS));
+  check(tc_wait_ready(aes_addr_base + AES_ADDR_STATUS));
 
-  dec_result[0] = tc_r32(AES_ADDR_RESULT0);
-  dec_result[1] = tc_r32(AES_ADDR_RESULT1);
-  dec_result[2] = tc_r32(AES_ADDR_RESULT2);
-  dec_result[3] = tc_r32(AES_ADDR_RESULT3);
+  dec_result[0] = tc_r32(aes_addr_base + AES_ADDR_RESULT0);
+  dec_result[1] = tc_r32(aes_addr_base + AES_ADDR_RESULT1);
+  dec_result[2] = tc_r32(aes_addr_base + AES_ADDR_RESULT2);
+  dec_result[3] = tc_r32(aes_addr_base + AES_ADDR_RESULT3);
 
   printf("Generated cipher block: 0x%08x 0x%08x 0x%08x 0x%08x\n",
          enc_result[0], enc_result[1], enc_result[2], enc_result[3]);
@@ -298,7 +294,7 @@ static void run_nist_tests()
 int main(int argc, char *argv[])
 {
   check_aes_access();
-  tc_set_debug(1);
+//  tc_set_debug(1);
   run_nist_tests();
 
   return 0;
diff --git a/sw/capability.c b/sw/capability.c
new file mode 100644
index 0000000..9b29c98
--- /dev/null
+++ b/sw/capability.c
@@ -0,0 +1,145 @@
+/* 
+ * capability.c
+ * ------------
+ * This module contains code to probe the FPGA for its installed cores.
+ * 
+ * Author: Paul Selkirk
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "cryptech.h"
+
+static struct core_info *tc_probe_cores(void)
+{
+    static struct core_info *head = NULL;
+    struct core_info *tail = NULL, *node;
+    off_t offset;
+
+    if (head != NULL)
+	return head;
+
+    /* XXX could use unix linked-list macros */
+    for (offset = 0; offset < 0x10000; offset += CORE_SIZE) {
+        node = calloc(1, sizeof(struct core_info));
+        if (node == NULL) {
+            perror("malloc");
+            goto fail;
+        }
+
+        if (tc_read(offset, (uint8_t *)&node->name[0], 8) ||
+            tc_read(offset + 2, (uint8_t *)&node->version[0], 4)) {
+            fprintf(stderr, "tc_read(%04x) error\n", (unsigned int)offset);
+            free(node);
+            goto fail;
+        }
+        if (node->name[0] == 0) {
+            free(node);
+            break;
+        }
+
+        node->base = offset;
+
+        if (head == NULL) {
+            head = tail = node;
+        }
+        else {
+            tail->next = node;
+            tail = node;
+        }
+    }
+
+    return head;
+
+fail:
+    while (head) {
+        node = head;
+        head = node->next;
+        free(node);
+    }
+    return NULL;
+}
+
+static struct core_info *tc_core_find(struct core_info *node, char *name)
+{
+    struct core_info *core;
+    size_t len;
+
+    if ((name == NULL) || (*name == '\0'))
+	return node;
+
+    len = strlen(name);
+    for (core = node->next; core != NULL; core = core->next) {
+	if (strncmp(core->name, name, len) == 0)
+	    return core;
+    }
+
+    return NULL;
+}
+
+struct core_info *tc_core_first(char *name)
+{
+    struct core_info *head;
+
+    head = tc_probe_cores();
+    if (head == NULL)
+	return NULL;
+
+    return tc_core_find(head, name);
+}
+
+struct core_info *tc_core_next(struct core_info *node, char *name)
+{
+    if (node == NULL) {
+	node = tc_core_first(name);
+	if (node == NULL)
+	    return NULL;
+    }
+
+    return tc_core_find(node->next, name);
+}
+
+off_t tc_core_base(char *name)
+{
+    struct core_info *node;
+
+    node = tc_core_first(name);
+    if (node == NULL)
+	return 0;
+    /* 0 is the base address for the "board-regs" core, installed
+     * unconditionally at that address. Probing for any other core,
+     * and getting 0, should be considered an error.
+     */
+
+    return node->base;
+}
diff --git a/sw/cryptech.h b/sw/cryptech.h
index 5b01bc9..9535061 100644
--- a/sw/cryptech.h
+++ b/sw/cryptech.h
@@ -70,17 +70,6 @@ in order to map it into a 16-bit address space.
 // Default sizes
 //------------------------------------------------------------------
 #define CORE_SIZE               0x100
-#define SEGMENT_SIZE            0x20 * CORE_SIZE
-
-
-//------------------------------------------------------------------
-// Segments
-//------------------------------------------------------------------
-#define SEGMENT_OFFSET_GLOBALS  0 * SEGMENT_SIZE
-#define SEGMENT_OFFSET_HASHES   1 * SEGMENT_SIZE
-#define SEGMENT_OFFSET_RNGS     2 * SEGMENT_SIZE
-#define SEGMENT_OFFSET_CIPHERS  3 * SEGMENT_SIZE
-#define SEGMENT_OFFSET_MATH     4 * SEGMENT_SIZE
 
 
 //------------------------------------------------------------------
@@ -104,19 +93,16 @@ in order to map it into a 16-bit address space.
 
 
 //------------------------------------------------------------------
-// Board segment.
 // Board-level registers and communication channel registers
 //------------------------------------------------------------------
-#define BOARD_ADDR_BASE         SEGMENT_OFFSET_GLOBALS + (0 * CORE_SIZE)
-#define BOARD_ADDR_NAME0        BOARD_ADDR_BASE + ADDR_NAME0
-#define BOARD_ADDR_NAME1        BOARD_ADDR_BASE + ADDR_NAME1
-#define BOARD_ADDR_VERSION      BOARD_ADDR_BASE + ADDR_VERSION
-#define BOARD_ADDR_DUMMY        BOARD_ADDR_BASE + 0xFF
+#define BOARD_ADDR_NAME0        ADDR_NAME0
+#define BOARD_ADDR_NAME1        ADDR_NAME1
+#define BOARD_ADDR_VERSION      ADDR_VERSION
+#define BOARD_ADDR_DUMMY        0xFF
 
-#define COMM_ADDR_BASE          SEGMENT_OFFSET_GLOBALS + (1 * CORE_SIZE)
-#define COMM_ADDR_NAME0         COMM_ADDR_BASE + ADDR_NAME0
-#define COMM_ADDR_NAME1         COMM_ADDR_BASE + ADDR_NAME1
-#define COMM_ADDR_VERSION       COMM_ADDR_BASE + ADDR_VERSION
+#define COMM_ADDR_NAME0         ADDR_NAME0
+#define COMM_ADDR_NAME1         ADDR_NAME1
+#define COMM_ADDR_VERSION       ADDR_VERSION
 
 // current name and version values
 #define NOVENA_BOARD_NAME0      "PVT1"
@@ -133,45 +119,42 @@ in order to map it into a 16-bit address space.
 
 
 //------------------------------------------------------------------
-// Hashes segment.
+// Hash cores
 //------------------------------------------------------------------
 // addresses common to all hash cores
 #define ADDR_BLOCK              0x10
 #define ADDR_DIGEST             0x20      // except SHA512
 
-// addresses and codes for the specific hash cores.
-#define SHA1_ADDR_BASE          SEGMENT_OFFSET_HASHES + (0 * CORE_SIZE)
-#define SHA1_ADDR_NAME0         SHA1_ADDR_BASE + ADDR_NAME0
-#define SHA1_ADDR_NAME1         SHA1_ADDR_BASE + ADDR_NAME1
-#define SHA1_ADDR_VERSION       SHA1_ADDR_BASE + ADDR_VERSION
-#define SHA1_ADDR_CTRL          SHA1_ADDR_BASE + ADDR_CTRL
-#define SHA1_ADDR_STATUS        SHA1_ADDR_BASE + ADDR_STATUS
-#define SHA1_ADDR_BLOCK         SHA1_ADDR_BASE + ADDR_BLOCK
-#define SHA1_ADDR_DIGEST        SHA1_ADDR_BASE + ADDR_DIGEST
+// SHA-1 core
+#define SHA1_ADDR_NAME0         ADDR_NAME0
+#define SHA1_ADDR_NAME1         ADDR_NAME1
+#define SHA1_ADDR_VERSION       ADDR_VERSION
+#define SHA1_ADDR_CTRL          ADDR_CTRL
+#define SHA1_ADDR_STATUS        ADDR_STATUS
+#define SHA1_ADDR_BLOCK         ADDR_BLOCK
+#define SHA1_ADDR_DIGEST        ADDR_DIGEST
 #define SHA1_BLOCK_LEN          bitsToBytes(512)
 #define SHA1_LENGTH_LEN         bitsToBytes(64)
 #define SHA1_DIGEST_LEN         bitsToBytes(160)
 
-#define SHA256_ADDR_BASE        SEGMENT_OFFSET_HASHES + (1 * CORE_SIZE)
-#define SHA256_ADDR_NAME0       SHA256_ADDR_BASE + ADDR_NAME0
-#define SHA256_ADDR_NAME1       SHA256_ADDR_BASE + ADDR_NAME1
-#define SHA256_ADDR_VERSION     SHA256_ADDR_BASE + ADDR_VERSION
-#define SHA256_ADDR_CTRL        SHA256_ADDR_BASE + ADDR_CTRL
-#define SHA256_ADDR_STATUS      SHA256_ADDR_BASE + ADDR_STATUS
-#define SHA256_ADDR_BLOCK       SHA256_ADDR_BASE + ADDR_BLOCK
-#define SHA256_ADDR_DIGEST      SHA256_ADDR_BASE + ADDR_DIGEST
+#define SHA256_ADDR_NAME0       ADDR_NAME0
+#define SHA256_ADDR_NAME1       ADDR_NAME1
+#define SHA256_ADDR_VERSION     ADDR_VERSION
+#define SHA256_ADDR_CTRL        ADDR_CTRL
+#define SHA256_ADDR_STATUS      ADDR_STATUS
+#define SHA256_ADDR_BLOCK       ADDR_BLOCK
+#define SHA256_ADDR_DIGEST      ADDR_DIGEST
 #define SHA256_BLOCK_LEN        bitsToBytes(512)
 #define SHA256_LENGTH_LEN       bitsToBytes(64)
 #define SHA256_DIGEST_LEN       bitsToBytes(256)
 
-#define SHA512_ADDR_BASE        SEGMENT_OFFSET_HASHES + (2 * CORE_SIZE)
-#define SHA512_ADDR_NAME0       SHA512_ADDR_BASE + ADDR_NAME0
-#define SHA512_ADDR_NAME1       SHA512_ADDR_BASE + ADDR_NAME1
-#define SHA512_ADDR_VERSION     SHA512_ADDR_BASE + ADDR_VERSION
-#define SHA512_ADDR_CTRL        SHA512_ADDR_BASE + ADDR_CTRL
-#define SHA512_ADDR_STATUS      SHA512_ADDR_BASE + ADDR_STATUS
-#define SHA512_ADDR_BLOCK       SHA512_ADDR_BASE + ADDR_BLOCK
-#define SHA512_ADDR_DIGEST      SHA512_ADDR_BASE + 0x40
+#define SHA512_ADDR_NAME0       ADDR_NAME0
+#define SHA512_ADDR_NAME1       ADDR_NAME1
+#define SHA512_ADDR_VERSION     ADDR_VERSION
+#define SHA512_ADDR_CTRL        ADDR_CTRL
+#define SHA512_ADDR_STATUS      ADDR_STATUS
+#define SHA512_ADDR_BLOCK       ADDR_BLOCK
+#define SHA512_ADDR_DIGEST      0x40
 #define SHA512_BLOCK_LEN        bitsToBytes(1024)
 #define SHA512_LENGTH_LEN       bitsToBytes(128)
 #define SHA512_224_DIGEST_LEN   bitsToBytes(224)
@@ -198,69 +181,64 @@ in order to map it into a 16-bit address space.
 
 
 //-----------------------------------------------------------------
-// TRNG segment.
+// TRNG cores
 //-----------------------------------------------------------------
 // addresses and codes for the TRNG cores */
-#define TRNG_ADDR_BASE          SEGMENT_OFFSET_RNGS + (0x00 * CORE_SIZE)
-#define TRNG_ADDR_NAME0         TRNG_ADDR_BASE + ADDR_NAME0
-#define TRNG_ADDR_NAME1         TRNG_ADDR_BASE + ADDR_NAME1
-#define TRNG_ADDR_VERSION       TRNG_ADDR_BASE + ADDR_VERSION
-#define TRNG_ADDR_CTRL          TRNG_ADDR_BASE + 0x10
+#define TRNG_ADDR_NAME0         ADDR_NAME0
+#define TRNG_ADDR_NAME1         ADDR_NAME1
+#define TRNG_ADDR_VERSION       ADDR_VERSION
+#define TRNG_ADDR_CTRL          0x10
 #define TRNG_CTRL_DISCARD       1
 #define TRNG_CTRL_TEST_MODE     2
-#define TRNG_ADDR_STATUS        TRNG_ADDR_BASE + 0x11
+#define TRNG_ADDR_STATUS        0x11
 // no status bits defined (yet)
-#define TRNG_ADDR_DELAY         TRNG_ADDR_BASE + 0x13
+#define TRNG_ADDR_DELAY         0x13
 
-#define ENTROPY1_ADDR_BASE      SEGMENT_OFFSET_RNGS + (0x05 * CORE_SIZE)
-#define ENTROPY1_ADDR_NAME0     ENTROPY1_ADDR_BASE + ADDR_NAME0
-#define ENTROPY1_ADDR_NAME1     ENTROPY1_ADDR_BASE + ADDR_NAME1
-#define ENTROPY1_ADDR_VERSION   ENTROPY1_ADDR_BASE + ADDR_VERSION
-#define ENTROPY1_ADDR_CTRL      ENTROPY1_ADDR_BASE + 0x10
+#define ENTROPY1_ADDR_NAME0     ADDR_NAME0
+#define ENTROPY1_ADDR_NAME1     ADDR_NAME1
+#define ENTROPY1_ADDR_VERSION   ADDR_VERSION
+#define ENTROPY1_ADDR_CTRL      0x10
 #define ENTROPY1_CTRL_ENABLE    1
-#define ENTROPY1_ADDR_STATUS    ENTROPY1_ADDR_BASE + 0x11
+#define ENTROPY1_ADDR_STATUS    0x11
 #define ENTROPY1_STATUS_VALID   1
-#define ENTROPY1_ADDR_ENTROPY   ENTROPY1_ADDR_BASE + 0x20
-#define ENTROPY1_ADDR_DELTA     ENTROPY1_ADDR_BASE + 0x30
-
-#define ENTROPY2_ADDR_BASE      SEGMENT_OFFSET_RNGS + (0x06 * CORE_SIZE)
-#define ENTROPY2_ADDR_NAME0     ENTROPY2_ADDR_BASE + ADDR_NAME0
-#define ENTROPY2_ADDR_NAME1     ENTROPY2_ADDR_BASE + ADDR_NAME1
-#define ENTROPY2_ADDR_VERSION   ENTROPY2_ADDR_BASE + ADDR_VERSION
-#define ENTROPY2_ADDR_CTRL      ENTROPY2_ADDR_BASE + 0x10
+#define ENTROPY1_ADDR_ENTROPY   0x20
+#define ENTROPY1_ADDR_DELTA     0x30
+
+#define ENTROPY2_ADDR_NAME0     ADDR_NAME0
+#define ENTROPY2_ADDR_NAME1     ADDR_NAME1
+#define ENTROPY2_ADDR_VERSION   ADDR_VERSION
+#define ENTROPY2_ADDR_CTRL      0x10
 #define ENTROPY2_CTRL_ENABLE    1
-#define ENTROPY2_ADDR_STATUS    ENTROPY2_ADDR_BASE + 0x11
+#define ENTROPY2_ADDR_STATUS    0x11
 #define ENTROPY2_STATUS_VALID   1
-#define ENTROPY2_ADDR_OPA       ENTROPY2_ADDR_BASE + 0x18
-#define ENTROPY2_ADDR_OPB       ENTROPY2_ADDR_BASE + 0x19
-#define ENTROPY2_ADDR_ENTROPY   ENTROPY2_ADDR_BASE + 0x20
-#define ENTROPY2_ADDR_RAW       ENTROPY2_ADDR_BASE + 0x21
-#define ENTROPY2_ADDR_ROSC      ENTROPY2_ADDR_BASE + 0x22
-
-#define MIXER_ADDR_BASE         SEGMENT_OFFSET_RNGS + (0x0a * CORE_SIZE)
-#define MIXER_ADDR_NAME0        MIXER_ADDR_BASE + ADDR_NAME0
-#define MIXER_ADDR_NAME1        MIXER_ADDR_BASE + ADDR_NAME1
-#define MIXER_ADDR_VERSION      MIXER_ADDR_BASE + ADDR_VERSION
-#define MIXER_ADDR_CTRL         MIXER_ADDR_BASE + 0x10
+#define ENTROPY2_ADDR_OPA       0x18
+#define ENTROPY2_ADDR_OPB       0x19
+#define ENTROPY2_ADDR_ENTROPY   0x20
+#define ENTROPY2_ADDR_RAW       0x21
+#define ENTROPY2_ADDR_ROSC      0x22
+
+#define MIXER_ADDR_NAME0        ADDR_NAME0
+#define MIXER_ADDR_NAME1        ADDR_NAME1
+#define MIXER_ADDR_VERSION      ADDR_VERSION
+#define MIXER_ADDR_CTRL         0x10
 #define MIXER_CTRL_ENABLE       1
 #define MIXER_CTRL_RESTART      2
-#define MIXER_ADDR_STATUS       MIXER_ADDR_BASE + 0x11
+#define MIXER_ADDR_STATUS       0x11
 // no status bits defined (yet)
-#define MIXER_ADDR_TIMEOUT      MIXER_ADDR_BASE + 0x20
+#define MIXER_ADDR_TIMEOUT      0x20
 
-#define CSPRNG_ADDR_BASE        SEGMENT_OFFSET_RNGS + (0x0b * CORE_SIZE)
-#define CSPRNG_ADDR_NAME0       CSPRNG_ADDR_BASE + ADDR_NAME0
-#define CSPRNG_ADDR_NAME1       CSPRNG_ADDR_BASE + ADDR_NAME1
-#define CSPRNG_ADDR_VERSION     CSPRNG_ADDR_BASE + ADDR_VERSION
-#define CSPRNG_ADDR_CTRL        CSPRNG_ADDR_BASE + 0x10
+#define CSPRNG_ADDR_NAME0       ADDR_NAME0
+#define CSPRNG_ADDR_NAME1       ADDR_NAME1
+#define CSPRNG_ADDR_VERSION     ADDR_VERSION
+#define CSPRNG_ADDR_CTRL        0x10
 #define CSPRNG_CTRL_ENABLE      1
 #define CSPRNG_CTRL_SEED        2
-#define CSPRNG_ADDR_STATUS      CSPRNG_ADDR_BASE + 0x11
+#define CSPRNG_ADDR_STATUS      0x11
 #define CSPRNG_STATUS_VALID     1
-#define CSPRNG_ADDR_RANDOM      CSPRNG_ADDR_BASE + 0x20
-#define CSPRNG_ADDR_NROUNDS     CSPRNG_ADDR_BASE + 0x40
-#define CSPRNG_ADDR_NBLOCKS_LO  CSPRNG_ADDR_BASE + 0x41
-#define CSPRNG_ADDR_NBLOCKS_HI  CSPRNG_ADDR_BASE + 0x42
+#define CSPRNG_ADDR_RANDOM      0x20
+#define CSPRNG_ADDR_NROUNDS     0x40
+#define CSPRNG_ADDR_NBLOCKS_LO  0x41
+#define CSPRNG_ADDR_NBLOCKS_HI  0x42
 
 // current name and version values
 #define TRNG_NAME0              "trng"
@@ -275,44 +253,47 @@ in order to map it into a 16-bit address space.
 #define ROSC_ENTROPY_NAME1      " ent"
 #define ROSC_ENTROPY_VERSION    "0.10"
 
+#define MIXER_NAME0             "rngm"
+#define MIXER_NAME1             "ixer"
+#define MIXER_VERSION           "0.50"
+
 #define CSPRNG_NAME0            "cspr"
 #define CSPRNG_NAME1            "ng  "
 #define CSPRNG_VERSION          "0.50"
 
 
 // -----------------------------------------------------------------
-// CIPHERS segment.
+// Cipher cores
 // -----------------------------------------------------------------
-// aes core.
-#define AES_ADDR_BASE           SEGMENT_OFFSET_CIPHERS + (0 * CORE_SIZE)
-#define AES_ADDR_NAME0          AES_ADDR_BASE + ADDR_NAME0
-#define AES_ADDR_NAME1          AES_ADDR_BASE + ADDR_NAME1
-#define AES_ADDR_VERSION        AES_ADDR_BASE + ADDR_VERSION
-#define AES_ADDR_CTRL           AES_ADDR_BASE + ADDR_CTRL
-#define AES_ADDR_STATUS         AES_ADDR_BASE + ADDR_STATUS
-
-#define AES_ADDR_CONFIG         AES_ADDR_BASE + 0x0a
+// AES core
+#define AES_ADDR_NAME0          ADDR_NAME0
+#define AES_ADDR_NAME1          ADDR_NAME1
+#define AES_ADDR_VERSION        ADDR_VERSION
+#define AES_ADDR_CTRL           ADDR_CTRL
+#define AES_ADDR_STATUS         ADDR_STATUS
+
+#define AES_ADDR_CONFIG         0x0a
 #define AES_CONFIG_ENCDEC       1
 #define AES_CONFIG_KEYLEN       2
 
-#define AES_ADDR_KEY0           AES_ADDR_BASE + 0x10
-#define AES_ADDR_KEY1           AES_ADDR_BASE + 0x11
-#define AES_ADDR_KEY2           AES_ADDR_BASE + 0x12
-#define AES_ADDR_KEY3           AES_ADDR_BASE + 0x13
-#define AES_ADDR_KEY4           AES_ADDR_BASE + 0x14
-#define AES_ADDR_KEY5           AES_ADDR_BASE + 0x15
-#define AES_ADDR_KEY6           AES_ADDR_BASE + 0x16
-#define AES_ADDR_KEY7           AES_ADDR_BASE + 0x17
-
-#define AES_ADDR_BLOCK0         AES_ADDR_BASE + 0x20
-#define AES_ADDR_BLOCK1         AES_ADDR_BASE + 0x21
-#define AES_ADDR_BLOCK2         AES_ADDR_BASE + 0x22
-#define AES_ADDR_BLOCK3         AES_ADDR_BASE + 0x23
-
-#define AES_ADDR_RESULT0        AES_ADDR_BASE + 0x30
-#define AES_ADDR_RESULT1        AES_ADDR_BASE + 0x31
-#define AES_ADDR_RESULT2        AES_ADDR_BASE + 0x32
-#define AES_ADDR_RESULT3        AES_ADDR_BASE + 0x33
+#define AES_ADDR_KEY0           0x10
+#define AES_ADDR_KEY1           0x11
+#define AES_ADDR_KEY2           0x12
+#define AES_ADDR_KEY3           0x13
+#define AES_ADDR_KEY4           0x14
+#define AES_ADDR_KEY5           0x15
+#define AES_ADDR_KEY6           0x16
+#define AES_ADDR_KEY7           0x17
+
+#define AES_ADDR_BLOCK0         0x20
+#define AES_ADDR_BLOCK1         0x21
+#define AES_ADDR_BLOCK2         0x22
+#define AES_ADDR_BLOCK3         0x23
+
+#define AES_ADDR_RESULT0        0x30
+#define AES_ADDR_RESULT1        0x31
+#define AES_ADDR_RESULT2        0x32
+#define AES_ADDR_RESULT3        0x33
 
 // current name and version values
 #define AES_CORE_NAME0          "aes "
@@ -321,63 +302,62 @@ in order to map it into a 16-bit address space.
 
 
 // Chacha core
-#define CHACHA_ADDR_BASE        SEGMENT_OFFSET_CIPHERS + (1 * CORE_SIZE)
-#define CHACHA_ADDR_NAME0       CHACHA_ADDR_BASE + ADDR_NAME0
-#define CHACHA_ADDR_NAME1       CHACHA_ADDR_BASE + ADDR_NAME1
-#define CHACHA_ADDR_VERSION     CHACHA_ADDR_BASE + ADDR_VERSION
-#define CHACHA_ADDR_CTRL        CHACHA_ADDR_BASE + ADDR_CTRL
-#define CHACHA_ADDR_STATUS      CHACHA_ADDR_BASE + ADDR_STATUS
-
-#define CHACHA_ADDR_KEYLEN      CHACHA_ADDR_BASE + 0x0a
+#define CHACHA_ADDR_NAME0       ADDR_NAME0
+#define CHACHA_ADDR_NAME1       ADDR_NAME1
+#define CHACHA_ADDR_VERSION     ADDR_VERSION
+#define CHACHA_ADDR_CTRL        ADDR_CTRL
+#define CHACHA_ADDR_STATUS      ADDR_STATUS
+
+#define CHACHA_ADDR_KEYLEN      0x0a
 #define CHACHA_KEYLEN           1
 
-#define CHACHA_ADDR_ROUNDS      CHACHA_ADDR_BASE + 0x0b
-
-#define CHACHA_ADDR_KEY0        CHACHA_ADDR_BASE + 0x10
-#define CHACHA_ADDR_KEY1        CHACHA_ADDR_BASE + 0x11
-#define CHACHA_ADDR_KEY2        CHACHA_ADDR_BASE + 0x12
-#define CHACHA_ADDR_KEY3        CHACHA_ADDR_BASE + 0x13
-#define CHACHA_ADDR_KEY4        CHACHA_ADDR_BASE + 0x14
-#define CHACHA_ADDR_KEY5        CHACHA_ADDR_BASE + 0x15
-#define CHACHA_ADDR_KEY6        CHACHA_ADDR_BASE + 0x16
-#define CHACHA_ADDR_KEY7        CHACHA_ADDR_BASE + 0x17
-
-#define CHACHA_ADDR_IV0         CHACHA_ADDR_BASE + 0x20
-#define CHACHA_ADDR_IV1         CHACHA_ADDR_BASE + 0x21
-
-#define CHACHA_ADDR_DATA_IN0    CHACHA_ADDR_BASE + 0x40
-#define CHACHA_ADDR_DATA_IN1    CHACHA_ADDR_BASE + 0x41
-#define CHACHA_ADDR_DATA_IN2    CHACHA_ADDR_BASE + 0x42
-#define CHACHA_ADDR_DATA_IN3    CHACHA_ADDR_BASE + 0x43
-#define CHACHA_ADDR_DATA_IN4    CHACHA_ADDR_BASE + 0x44
-#define CHACHA_ADDR_DATA_IN5    CHACHA_ADDR_BASE + 0x45
-#define CHACHA_ADDR_DATA_IN6    CHACHA_ADDR_BASE + 0x46
-#define CHACHA_ADDR_DATA_IN7    CHACHA_ADDR_BASE + 0x47
-#define CHACHA_ADDR_DATA_IN8    CHACHA_ADDR_BASE + 0x48
-#define CHACHA_ADDR_DATA_IN9    CHACHA_ADDR_BASE + 0x49
-#define CHACHA_ADDR_DATA_IN10   CHACHA_ADDR_BASE + 0x4a
-#define CHACHA_ADDR_DATA_IN11   CHACHA_ADDR_BASE + 0x4b
-#define CHACHA_ADDR_DATA_IN12   CHACHA_ADDR_BASE + 0x4c
-#define CHACHA_ADDR_DATA_IN13   CHACHA_ADDR_BASE + 0x4d
-#define CHACHA_ADDR_DATA_IN14   CHACHA_ADDR_BASE + 0x4e
-#define CHACHA_ADDR_DATA_IN15   CHACHA_ADDR_BASE + 0x4f
-
-#define CHACHA_ADDR_DATA_OUT0   CHACHA_ADDR_BASE + 0x80
-#define CHACHA_ADDR_DATA_OUT1   CHACHA_ADDR_BASE + 0x81
-#define CHACHA_ADDR_DATA_OUT2   CHACHA_ADDR_BASE + 0x82
-#define CHACHA_ADDR_DATA_OUT3   CHACHA_ADDR_BASE + 0x83
-#define CHACHA_ADDR_DATA_OUT4   CHACHA_ADDR_BASE + 0x84
-#define CHACHA_ADDR_DATA_OUT5   CHACHA_ADDR_BASE + 0x85
-#define CHACHA_ADDR_DATA_OUT6   CHACHA_ADDR_BASE + 0x86
-#define CHACHA_ADDR_DATA_OUT7   CHACHA_ADDR_BASE + 0x87
-#define CHACHA_ADDR_DATA_OUT8   CHACHA_ADDR_BASE + 0x88
-#define CHACHA_ADDR_DATA_OUT9   CHACHA_ADDR_BASE + 0x89
-#define CHACHA_ADDR_DATA_OUT10  CHACHA_ADDR_BASE + 0x8a
-#define CHACHA_ADDR_DATA_OUT11  CHACHA_ADDR_BASE + 0x8b
-#define CHACHA_ADDR_DATA_OUT12  CHACHA_ADDR_BASE + 0x8c
-#define CHACHA_ADDR_DATA_OUT13  CHACHA_ADDR_BASE + 0x8d
-#define CHACHA_ADDR_DATA_OUT14  CHACHA_ADDR_BASE + 0x8e
-#define CHACHA_ADDR_DATA_OUT15  CHACHA_ADDR_BASE + 0x8f
+#define CHACHA_ADDR_ROUNDS      0x0b
+
+#define CHACHA_ADDR_KEY0        0x10
+#define CHACHA_ADDR_KEY1        0x11
+#define CHACHA_ADDR_KEY2        0x12
+#define CHACHA_ADDR_KEY3        0x13
+#define CHACHA_ADDR_KEY4        0x14
+#define CHACHA_ADDR_KEY5        0x15
+#define CHACHA_ADDR_KEY6        0x16
+#define CHACHA_ADDR_KEY7        0x17
+
+#define CHACHA_ADDR_IV0         0x20
+#define CHACHA_ADDR_IV1         0x21
+
+#define CHACHA_ADDR_DATA_IN0    0x40
+#define CHACHA_ADDR_DATA_IN1    0x41
+#define CHACHA_ADDR_DATA_IN2    0x42
+#define CHACHA_ADDR_DATA_IN3    0x43
+#define CHACHA_ADDR_DATA_IN4    0x44
+#define CHACHA_ADDR_DATA_IN5    0x45
+#define CHACHA_ADDR_DATA_IN6    0x46
+#define CHACHA_ADDR_DATA_IN7    0x47
+#define CHACHA_ADDR_DATA_IN8    0x48
+#define CHACHA_ADDR_DATA_IN9    0x49
+#define CHACHA_ADDR_DATA_IN10   0x4a
+#define CHACHA_ADDR_DATA_IN11   0x4b
+#define CHACHA_ADDR_DATA_IN12   0x4c
+#define CHACHA_ADDR_DATA_IN13   0x4d
+#define CHACHA_ADDR_DATA_IN14   0x4e
+#define CHACHA_ADDR_DATA_IN15   0x4f
+
+#define CHACHA_ADDR_DATA_OUT0   0x80
+#define CHACHA_ADDR_DATA_OUT1   0x81
+#define CHACHA_ADDR_DATA_OUT2   0x82
+#define CHACHA_ADDR_DATA_OUT3   0x83
+#define CHACHA_ADDR_DATA_OUT4   0x84
+#define CHACHA_ADDR_DATA_OUT5   0x85
+#define CHACHA_ADDR_DATA_OUT6   0x86
+#define CHACHA_ADDR_DATA_OUT7   0x87
+#define CHACHA_ADDR_DATA_OUT8   0x88
+#define CHACHA_ADDR_DATA_OUT9   0x89
+#define CHACHA_ADDR_DATA_OUT10  0x8a
+#define CHACHA_ADDR_DATA_OUT11  0x8b
+#define CHACHA_ADDR_DATA_OUT12  0x8c
+#define CHACHA_ADDR_DATA_OUT13  0x8d
+#define CHACHA_ADDR_DATA_OUT14  0x8e
+#define CHACHA_ADDR_DATA_OUT15  0x8f
 
 // current name and version values
 #define CHACHA_NAME0            "chac"
@@ -386,36 +366,35 @@ in order to map it into a 16-bit address space.
 
 
 // -----------------------------------------------------------------
-// MATH segment.
+// Math cores
 // -----------------------------------------------------------------
-// Modexp core.
-#define MODEXP_ADDR_BASE        SEGMENT_OFFSET_MATH + (0x00 * CORE_SIZE)
-#define MODEXP_ADDR_NAME0       MODEXP_ADDR_BASE + ADDR_NAME0
-#define MODEXP_ADDR_NAME1       MODEXP_ADDR_BASE + ADDR_NAME1
-#define MODEXP_ADDR_VERSION     MODEXP_ADDR_BASE + ADDR_VERSION
-#define MODEXP_ADDR_CTRL        MODEXP_ADDR_BASE + ADDR_CTRL
+// Modular exponentiation core
+#define MODEXP_ADDR_NAME0       ADDR_NAME0
+#define MODEXP_ADDR_NAME1       ADDR_NAME1
+#define MODEXP_ADDR_VERSION     ADDR_VERSION
+#define MODEXP_ADDR_CTRL        ADDR_CTRL
 #define MODEXP_CTRL_INIT_BIT    1
 #define MODEXP_CTRL_NEXT_BIT    2
-#define MODEXP_ADDR_STATUS      MODEXP_ADDR_BASE + ADDR_STATUS
+#define MODEXP_ADDR_STATUS      ADDR_STATUS
 
-#define MODEXP_ADDR_DELAY       MODEXP_ADDR_BASE + 0x13
+#define MODEXP_ADDR_DELAY       0x13
 #define MODEXP_STATUS_READY     1
 
-#define MODEXP_MODULUS_LENGTH   MODEXP_ADDR_BASE + 0x20
-#define MODEXP_EXPONENT_LENGTH  MODEXP_ADDR_BASE + 0x21
-#define MODEXP_LENGTH           MODEXP_ADDR_BASE + 0x22
+#define MODEXP_MODULUS_LENGTH   0x20
+#define MODEXP_EXPONENT_LENGTH  0x21
+#define MODEXP_LENGTH           0x22
 
-#define MODEXP_MODULUS_PTR_RST  MODEXP_ADDR_BASE + 0x30
-#define MODEXP_MODULUS_DATA     MODEXP_ADDR_BASE + 0x31
+#define MODEXP_MODULUS_PTR_RST  0x30
+#define MODEXP_MODULUS_DATA     0x31
 
-#define MODEXP_EXPONENT_PTR_RST MODEXP_ADDR_BASE + 0x40
-#define MODEXP_EXPONENT_DATA    MODEXP_ADDR_BASE + 0x41
+#define MODEXP_EXPONENT_PTR_RST 0x40
+#define MODEXP_EXPONENT_DATA    0x41
 
-#define MODEXP_MESSAGE_PTR_RST  MODEXP_ADDR_BASE + 0x50
-#define MODEXP_MESSAGE_DATA     MODEXP_ADDR_BASE + 0x51
+#define MODEXP_MESSAGE_PTR_RST  0x50
+#define MODEXP_MESSAGE_DATA     0x51
 
-#define MODEXP_RESULT_PTR_RST   MODEXP_ADDR_BASE + 0x60
-#define MODEXP_RESULT_DATA      MODEXP_ADDR_BASE + 0x61
+#define MODEXP_RESULT_PTR_RST   0x60
+#define MODEXP_RESULT_DATA      0x61
 
 #define MODEXP_NAME0            "mode"
 #define MODEXP_NAME1            "xp  "
@@ -425,6 +404,16 @@ in order to map it into a 16-bit address space.
 //------------------------------------------------------------------
 // Test case public functions
 //------------------------------------------------------------------
+struct core_info {
+    char name[8];
+    char version[4];
+    off_t base;
+    struct core_info *next;
+};
+struct core_info *tc_core_first(char *name);
+struct core_info *tc_core_next(struct core_info *node, char *name);
+off_t tc_core_base(char *name);
+
 void tc_set_debug(int onoff);
 int tc_write(off_t offset, const uint8_t *buf, size_t len);
 int tc_read(off_t offset, uint8_t *buf, size_t len);
diff --git a/sw/hash.c b/sw/hash.c
index 8b3bac2..d875225 100644
--- a/sw/hash.c
+++ b/sw/hash.c
@@ -64,23 +64,24 @@ int verbose = 0;
 
 struct ctrl {
     char *name;
+    off_t base_addr;
     off_t block_addr;
     int   block_len;
     off_t digest_addr;
     int   digest_len;
     int   mode;
 } ctrl[] = {
-    { "sha-1",       SHA1_ADDR_BLOCK, SHA1_BLOCK_LEN,
+    { "sha-1",       0, SHA1_ADDR_BLOCK, SHA1_BLOCK_LEN,
                      SHA1_ADDR_DIGEST, SHA1_DIGEST_LEN, 0 },
-    { "sha-256",     SHA256_ADDR_BLOCK, SHA256_BLOCK_LEN,
+    { "sha-256",     0, SHA256_ADDR_BLOCK, SHA256_BLOCK_LEN,
                      SHA256_ADDR_DIGEST, SHA256_DIGEST_LEN, 0 },
-    { "sha-512/224", SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+    { "sha-512/224", 0, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
                      SHA512_ADDR_DIGEST, SHA512_224_DIGEST_LEN, MODE_SHA_512_224 },
-    { "sha-512/256", SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+    { "sha-512/256", 0, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
                      SHA512_ADDR_DIGEST, SHA512_256_DIGEST_LEN, MODE_SHA_512_256 },
-    { "sha-384",     SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+    { "sha-384",     0, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
                      SHA512_ADDR_DIGEST, SHA384_DIGEST_LEN, MODE_SHA_384 },
-    { "sha-512",     SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+    { "sha-512",     0, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
                      SHA512_ADDR_DIGEST, SHA512_DIGEST_LEN, MODE_SHA_512 },
     { NULL, 0, 0, 0 }
 };
@@ -99,24 +100,63 @@ struct ctrl *find_algo(char *algo)
     return NULL;
 }
 
+/* ---------------- startup code ---------------- */
+
+static int patch(char *name, off_t base_addr) {
+    struct ctrl *ctrl;
+
+    ctrl = find_algo(name);
+    if (ctrl == NULL)
+	return -1;
+
+    ctrl->base_addr = base_addr;
+    return 0;
+}
+
+static int inited = 0;
+
+static int init(void)
+{
+    struct core_info *core;
+
+    if (inited)
+        return 0;
+
+    for (core = tc_core_first("sha"); core; core = tc_core_next(core, "sha")) {
+        if (strncmp(core->name, SHA1_NAME0 SHA1_NAME1, 8) == 0)
+            patch("sha-1", core->base);
+        else if (strncmp(core->name, SHA256_NAME0 SHA256_NAME1, 8) == 0)
+            patch("sha-256", core->base);
+        else if (strncmp(core->name, SHA512_NAME0 SHA512_NAME1, 8) == 0) {
+            patch("sha-512/224", core->base);
+            patch("sha-512/256", core->base);
+            patch("sha-384", core->base);
+            patch("sha-512", core->base);
+	}
+    }
+
+    inited = 1;
+    return 0;
+}
+
 /* ---------------- hash ---------------- */
 
-static int transmit(off_t offset, uint8_t *block, int blen, int mode, int first)
+static int transmit(off_t base, uint8_t *block, int blen, int mode, int first)
 {
-    off_t base = offset & ~(0x1ff);
     uint8_t ctrl_cmd[4] = { 0 };
+    int limit = 10;
 
-    if (tc_write(offset, block, blen) != 0)
+    if (tc_write(base + ADDR_BLOCK, block, blen) != 0)
         return 1;
 
     ctrl_cmd[3] = (first ? CTRL_INIT : CTRL_NEXT) | mode;
 
     return
 	tc_write(base + ADDR_CTRL, ctrl_cmd, 4) ||
-	tc_wait_ready(base + ADDR_STATUS);
+	tc_wait(base + ADDR_STATUS, STATUS_READY, &limit);
 }
 
-static int pad_transmit(off_t offset, uint8_t *block, uint8_t flen, uint8_t blen,
+static int pad_transmit(off_t base, uint8_t *block, uint8_t flen, uint8_t blen,
 			uint8_t mode, long long tlen, int first)
 {
     assert(flen < blen);
@@ -125,7 +165,7 @@ static int pad_transmit(off_t offset, uint8_t *block, uint8_t flen, uint8_t blen
     memset(block + flen, 0, blen - flen);
 
     if (blen - flen < ((blen == 64) ? 8 : 16)) {
-        if (transmit(offset, block, blen, mode, first) != 0)
+        if (transmit(base, block, blen, mode, first) != 0)
             return 1;
         first = 0;
         memset(block, 0, blen);
@@ -137,7 +177,7 @@ static int pad_transmit(off_t offset, uint8_t *block, uint8_t flen, uint8_t blen
     ((uint32_t *)block)[blen/4 - 2] = htonl((tlen >> 32) & 0xffff);
     ((uint32_t *)block)[blen/4 - 1] = htonl(tlen & 0xffff);
 
-    return transmit(offset, block, blen, mode, first);
+    return transmit(base, block, blen, mode, first);
 }
 
 /* return number of digest bytes read */
@@ -146,18 +186,26 @@ static int hash(char *algo, char *file, uint8_t *digest)
     uint8_t block[SHA512_BLOCK_LEN];
     struct ctrl *ctrl;
     int in_fd = 0;      /* stdin */
-    off_t baddr, daddr;
+    off_t base, daddr;
     int blen, dlen, mode;
     int nblk, nread, first;
     int ret = -1;
     struct timeval start, stop, difftime;
 
+    if (init() != 0)
+        return -1;
+
     ctrl = find_algo(algo);
     if (ctrl == NULL)
         return -1;
-    baddr = ctrl->block_addr;
+    base = ctrl->base_addr;
+    if (base == 0) {
+	fprintf(stderr, "core for algorithm \"%s\" not installed\n", algo);
+	return -1;
+    }
+
     blen = ctrl->block_len;
-    daddr = ctrl->digest_addr;
+    daddr = ctrl->base_addr + ctrl->digest_addr;
     dlen = ctrl->digest_len;
     mode = ctrl->mode;
 
@@ -185,14 +233,14 @@ static int hash(char *algo, char *file, uint8_t *digest)
         }
         else if (nread < blen) {
             /* partial read = last block */
-            if (pad_transmit(baddr, block, nread, blen, mode,
+            if (pad_transmit(base, block, nread, blen, mode,
                              (nblk * blen + nread) * 8, first) != 0)
                 goto out;
             break;
         }
         else {
             /* full block read */
-            if (transmit(baddr, block, blen, mode, first) != 0)
+            if (transmit(base, block, blen, mode, first) != 0)
                 goto out;
         }
     }
diff --git a/sw/hash_tester.c b/sw/hash_tester.c
index 7e4f2c8..d3a2964 100644
--- a/sw/hash_tester.c
+++ b/sw/hash_tester.c
@@ -225,6 +225,27 @@ const uint8_t SHA512_DOUBLE_DIGEST[] =
   0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
   0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 };
 
+
+/* ---------------- startup code ---------------- */
+
+static off_t board_addr_base = 0;
+static off_t sha1_addr_base, sha256_addr_base, sha512_addr_base;
+
+static int init(void)
+{
+    static int inited = 0;
+
+    if (inited)
+        return 0;
+
+    sha1_addr_base = tc_core_base("sha1");
+    sha256_addr_base = tc_core_base("sha2-256");
+    sha512_addr_base = tc_core_base("sha2-512");
+
+    inited = 1;
+    return 0;
+}
+
 /* ---------------- sanity test case ---------------- */
 
 int TC0()
@@ -234,6 +255,9 @@ int TC0()
     uint8_t board_version[4]    = NOVENA_BOARD_VERSION;
     uint8_t t[4];
 
+    if (init() != 0)
+        return -1;
+
     if (!quiet)
         printf("TC0: Reading board type, version, and dummy reg from global registers.\n");
 
@@ -241,14 +265,14 @@ int TC0()
      * to make sure that we can actually write something into EIM
      */
     (void)time((time_t *)t);
-    if (tc_write(BOARD_ADDR_DUMMY, t, 4) != 0)
+    if (tc_write(board_addr_base + BOARD_ADDR_DUMMY, t, 4) != 0)
         return 1;
 
     return
-	tc_expected(BOARD_ADDR_NAME0,   board_name0,   4) ||
-        tc_expected(BOARD_ADDR_NAME1,   board_name1,   4) ||
-        tc_expected(BOARD_ADDR_VERSION, board_version, 4) ||
-        tc_expected(BOARD_ADDR_DUMMY,   t, 4);
+        tc_expected(board_addr_base + BOARD_ADDR_NAME0,   board_name0,   4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_NAME1,   board_name1,   4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_VERSION, board_version, 4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_DUMMY,   t, 4);
 }
 
 /* ---------------- SHA-1 test cases ---------------- */
@@ -260,13 +284,20 @@ int TC1(void)
     uint8_t name1[4]   = SHA1_NAME1;
     uint8_t version[4] = SHA1_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((sha1_addr_base == 0) && !quiet) {
+        printf("TC1: SHA-1 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC1: Reading name and version words from SHA-1 core.\n");
 
     return
-        tc_expected(SHA1_ADDR_NAME0, name0, 4) ||
-        tc_expected(SHA1_ADDR_NAME1, name1, 4) ||
-        tc_expected(SHA1_ADDR_VERSION, version, 4);
+        tc_expected(sha1_addr_base + SHA1_ADDR_NAME0, name0, 4) ||
+        tc_expected(sha1_addr_base + SHA1_ADDR_NAME1, name1, 4) ||
+        tc_expected(sha1_addr_base + SHA1_ADDR_VERSION, version, 4);
 }
 
 /* TC2: SHA-1 Single block message test as specified by NIST. */
@@ -276,16 +307,23 @@ int TC2(void)
     const uint8_t *expected = SHA1_SINGLE_DIGEST;
     int ret;
 
+    if (init() != 0)
+        return -1;
+    if ((sha1_addr_base == 0) && !quiet) {
+        printf("TC2: SHA-1 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC2: Single block message test for SHA-1.\n");
 
     /* Write block to SHA-1. */
-    tc_write(SHA1_ADDR_BLOCK, block, SHA1_BLOCK_LEN);
+    tc_write(sha1_addr_base + SHA1_ADDR_BLOCK, block, SHA1_BLOCK_LEN);
     /* Start initial block hashing, wait and check status. */
-    tc_init(SHA1_ADDR_CTRL);
-    tc_wait_valid(SHA1_ADDR_STATUS);
+    tc_init(sha1_addr_base + SHA1_ADDR_CTRL);
+    tc_wait_valid(sha1_addr_base + SHA1_ADDR_STATUS);
     /* Extract the digest. */
-    ret = tc_expected(SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
+    ret = tc_expected(sha1_addr_base + SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
     return ret;
 }
 
@@ -300,23 +338,30 @@ int TC3(void)
     const uint8_t *expected = SHA1_DOUBLE_DIGEST;
     int ret;
 
+    if (init() != 0)
+        return -1;
+    if ((sha1_addr_base == 0) && !quiet) {
+        printf("TC3: SHA-1 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC3: Double block message test for SHA-1.\n");
 
     /* Write first block to SHA-1. */
-    tc_write(SHA1_ADDR_BLOCK, block[0], SHA1_BLOCK_LEN);
+    tc_write(sha1_addr_base + SHA1_ADDR_BLOCK, block[0], SHA1_BLOCK_LEN);
     /* Start initial block hashing, wait and check status. */
-    tc_init(SHA1_ADDR_CTRL);
-    tc_wait_valid(SHA1_ADDR_STATUS);
+    tc_init(sha1_addr_base + SHA1_ADDR_CTRL);
+    tc_wait_valid(sha1_addr_base + SHA1_ADDR_STATUS);
     /* Extract the first digest. */
-    tc_expected(SHA1_ADDR_DIGEST, block0_expected, SHA1_DIGEST_LEN);
+    tc_expected(sha1_addr_base + SHA1_ADDR_DIGEST, block0_expected, SHA1_DIGEST_LEN);
     /* Write second block to SHA-1. */
-    tc_write(SHA1_ADDR_BLOCK, block[1], SHA1_BLOCK_LEN);
+    tc_write(sha1_addr_base + SHA1_ADDR_BLOCK, block[1], SHA1_BLOCK_LEN);
     /* Start next block hashing, wait and check status. */
-    tc_next(SHA1_ADDR_CTRL);
-    tc_wait_valid(SHA1_ADDR_STATUS);
+    tc_next(sha1_addr_base + SHA1_ADDR_CTRL);
+    tc_wait_valid(sha1_addr_base + SHA1_ADDR_STATUS);
     /* Extract the second digest. */
-    ret = tc_expected(SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
+    ret = tc_expected(sha1_addr_base + SHA1_ADDR_DIGEST, expected, SHA1_DIGEST_LEN);
     return ret;
 }
 
@@ -329,13 +374,20 @@ int TC4(void)
     uint8_t name1[4]   = SHA256_NAME1;
     uint8_t version[4] = SHA256_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((sha256_addr_base == 0) && !quiet) {
+        printf("TC4: SHA-256 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC4: Reading name and version words from SHA-256 core.\n");
 
     return
-        tc_expected(SHA256_ADDR_NAME0, name0, 4) ||
-        tc_expected(SHA256_ADDR_NAME1, name1, 4) ||
-        tc_expected(SHA256_ADDR_VERSION, version, 4);
+        tc_expected(sha256_addr_base + SHA256_ADDR_NAME0, name0, 4) ||
+        tc_expected(sha256_addr_base + SHA256_ADDR_NAME1, name1, 4) ||
+        tc_expected(sha256_addr_base + SHA256_ADDR_VERSION, version, 4);
 }
 
 /* TC5: SHA-256 Single block message test as specified by NIST. */
@@ -344,17 +396,24 @@ int TC5()
     const uint8_t *block = NIST_512_SINGLE;
     const uint8_t *expected = SHA256_SINGLE_DIGEST;
 
+    if (init() != 0)
+        return -1;
+    if ((sha256_addr_base == 0) && !quiet) {
+        printf("TC5: SHA-256 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC5: Single block message test for SHA-256.\n");
 
     return
         /* Write block to SHA-256. */
-        tc_write(SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN) ||
+        tc_write(sha256_addr_base + SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN) ||
         /* Start initial block hashing, wait and check status. */
-        tc_init(SHA256_ADDR_CTRL) ||
-        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        tc_init(sha256_addr_base + SHA256_ADDR_CTRL) ||
+        tc_wait_valid(sha256_addr_base + SHA256_ADDR_STATUS) ||
         /* Extract the digest. */
-        tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+        tc_expected(sha256_addr_base + SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
 }
 
 /* TC6: SHA-256 Double block message test as specified by NIST. */
@@ -368,24 +427,31 @@ int TC6()
           0xCC, 0x4B, 0x32, 0xC1, 0xF2, 0x0E, 0x53, 0x3A };
     const uint8_t *expected = SHA256_DOUBLE_DIGEST;
 
+    if (init() != 0)
+        return -1;
+    if ((sha256_addr_base == 0) && !quiet) {
+        printf("TC6: SHA-256 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC6: Double block message test for SHA-256.\n");
 
     return
         /* Write first block to SHA-256. */
-        tc_write(SHA256_ADDR_BLOCK, block[0], SHA256_BLOCK_LEN) ||
+        tc_write(sha256_addr_base + SHA256_ADDR_BLOCK, block[0], SHA256_BLOCK_LEN) ||
         /* Start initial block hashing, wait and check status. */
-        tc_init(SHA256_ADDR_CTRL) ||
-        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        tc_init(sha256_addr_base + SHA256_ADDR_CTRL) ||
+        tc_wait_valid(sha256_addr_base + SHA256_ADDR_STATUS) ||
         /* Extract the first digest. */
-        tc_expected(SHA256_ADDR_DIGEST, block0_expected, SHA256_DIGEST_LEN) ||
+        tc_expected(sha256_addr_base + SHA256_ADDR_DIGEST, block0_expected, SHA256_DIGEST_LEN) ||
         /* Write second block to SHA-256. */
-        tc_write(SHA256_ADDR_BLOCK, block[1], SHA256_BLOCK_LEN) ||
+        tc_write(sha256_addr_base + SHA256_ADDR_BLOCK, block[1], SHA256_BLOCK_LEN) ||
         /* Start next block hashing, wait and check status. */
-        tc_next(SHA256_ADDR_CTRL) ||
-        tc_wait_valid(SHA256_ADDR_STATUS) ||
+        tc_next(sha256_addr_base + SHA256_ADDR_CTRL) ||
+        tc_wait_valid(sha256_addr_base + SHA256_ADDR_STATUS) ||
         /* Extract the second digest. */
-        tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+        tc_expected(sha256_addr_base + SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
 }
 
 /* TC7: SHA-256 Huge message test. */
@@ -410,31 +476,38 @@ int TC7()
 
     int i, n = 1000;
 
+    if (init() != 0)
+        return -1;
+    if ((sha256_addr_base == 0) && !quiet) {
+        printf("TC7: SHA-256 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC7: Message with %d blocks test for SHA-256.\n", n);
 
     /* Write block data to SHA-256. */
-    if (tc_write(SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN))
+    if (tc_write(sha256_addr_base + SHA256_ADDR_BLOCK, block, SHA256_BLOCK_LEN))
         return 1;
 
     /* Start initial block hashing, wait and check status. */
-    if (tc_init(SHA256_ADDR_CTRL) ||
-        tc_wait_ready(SHA256_ADDR_STATUS))
+    if (tc_init(sha256_addr_base + SHA256_ADDR_CTRL) ||
+        tc_wait_ready(sha256_addr_base + SHA256_ADDR_STATUS))
         return 1;
 
     /* First block done. Do the rest. */
     for (i = 1; i < n; ++i) {
         /* Start next block hashing, wait and check status. */
-        if (tc_next(SHA256_ADDR_CTRL) ||
-            tc_wait_ready(SHA256_ADDR_STATUS))
+        if (tc_next(sha256_addr_base + SHA256_ADDR_CTRL) ||
+            tc_wait_ready(sha256_addr_base + SHA256_ADDR_STATUS))
             return 1;
     }
 
     /* XXX valid is probably set at the same time as ready */
-    if (tc_wait_valid(SHA256_ADDR_STATUS))
+    if (tc_wait_valid(sha256_addr_base + SHA256_ADDR_STATUS))
         return 1;
     /* Extract the final digest. */
-    return tc_expected(SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
+    return tc_expected(sha256_addr_base + SHA256_ADDR_DIGEST, expected, SHA256_DIGEST_LEN);
 }
 
 /* ---------------- SHA-512 test cases ---------------- */
@@ -446,13 +519,20 @@ int TC8()
     uint8_t name1[4]   = SHA512_NAME1;
     uint8_t version[4] = SHA512_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((sha512_addr_base == 0) && !quiet) {
+        printf("TC8: SHA-512 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC8: Reading name and version words from SHA-512 core.\n");
 
     return
-        tc_expected(SHA512_ADDR_NAME0, name0, 4) ||
-        tc_expected(SHA512_ADDR_NAME1, name1, 4) ||
-        tc_expected(SHA512_ADDR_VERSION, version, 4);
+        tc_expected(sha512_addr_base + SHA512_ADDR_NAME0, name0, 4) ||
+        tc_expected(sha512_addr_base + SHA512_ADDR_NAME1, name1, 4) ||
+        tc_expected(sha512_addr_base + SHA512_ADDR_VERSION, version, 4);
 }
 
 /* TC9: SHA-512 Single block message test as specified by NIST.
@@ -464,16 +544,23 @@ int tc9(int mode, const uint8_t *expected, int digest_len)
 
     return
         /* Write block to SHA-512. */
-        tc_write(SHA512_ADDR_BLOCK, block, SHA512_BLOCK_LEN) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_BLOCK, block, SHA512_BLOCK_LEN) ||
         /* Start initial block hashing, wait and check status. */
-        tc_write(SHA512_ADDR_CTRL, init, 4) ||
-        tc_wait_valid(SHA512_ADDR_STATUS) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_CTRL, init, 4) ||
+        tc_wait_valid(sha512_addr_base + SHA512_ADDR_STATUS) ||
         /* Extract the digest. */
-        tc_expected(SHA512_ADDR_DIGEST, expected, digest_len);
+        tc_expected(sha512_addr_base + SHA512_ADDR_DIGEST, expected, digest_len);
 }
 
 int TC9()
 {
+    if (init() != 0)
+        return -1;
+    if ((sha512_addr_base == 0) && !quiet) {
+        printf("TC9: SHA-512 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC9-1: Single block message test for SHA-512/224.\n");
     if (tc9(MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
@@ -507,21 +594,28 @@ int tc10(int mode, const uint8_t *expected, int digest_len)
 
     return
         /* Write first block to SHA-512. */
-        tc_write(SHA512_ADDR_BLOCK, block[0], SHA512_BLOCK_LEN) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_BLOCK, block[0], SHA512_BLOCK_LEN) ||
         /* Start initial block hashing, wait and check status. */
-        tc_write(SHA512_ADDR_CTRL, init, 4) ||
-        tc_wait_ready(SHA512_ADDR_STATUS) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_CTRL, init, 4) ||
+        tc_wait_ready(sha512_addr_base + SHA512_ADDR_STATUS) ||
         /* Write second block to SHA-512. */
-        tc_write(SHA512_ADDR_BLOCK, block[1], SHA512_BLOCK_LEN) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_BLOCK, block[1], SHA512_BLOCK_LEN) ||
         /* Start next block hashing, wait and check status. */
-        tc_write(SHA512_ADDR_CTRL, next, 4) ||
-        tc_wait_valid(SHA512_ADDR_STATUS) ||
+        tc_write(sha512_addr_base + SHA512_ADDR_CTRL, next, 4) ||
+        tc_wait_valid(sha512_addr_base + SHA512_ADDR_STATUS) ||
         /* Extract the digest. */
-        tc_expected(SHA512_ADDR_DIGEST, expected, digest_len);
+        tc_expected(sha512_addr_base + SHA512_ADDR_DIGEST, expected, digest_len);
 }
 
 int TC10()
 {
+    if (init() != 0)
+        return -1;
+    if ((sha512_addr_base == 0) && !quiet) {
+        printf("TC10: SHA-512 not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC10-1: Double block message test for SHA-512/224.\n");
     if (tc10(MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST, SHA512_224_DIGEST_LEN) != 0)
diff --git a/sw/modexp_tester.c b/sw/modexp_tester.c
index 2288ad5..021c0a9 100644
--- a/sw/modexp_tester.c
+++ b/sw/modexp_tester.c
@@ -99,19 +99,16 @@ static uint32_t tc_r32(const off_t addr)
 // Check that we can read from the modexp core by trying to
 // read out the name and version.
 //------------------------------------------------------------------
+static off_t modexp_addr_base;
+
 static void check_modexp_access(void)
 {
-  uint8_t name0[4], name1[4], version[4];
-
-  printf("Trying to read the modexp core name\n");
-
-  check(tc_read(MODEXP_ADDR_NAME0,   name0,    sizeof(name0)));
-  check(tc_read(MODEXP_ADDR_NAME1,   name1,    sizeof(name1)));
-  check(tc_read(MODEXP_ADDR_VERSION, version, sizeof(version)));
-  printf("%4.4s%4.4s %4.4s\n\n", name0, name1, version);
+    modexp_addr_base = tc_core_base("modexp");
+    assert(modexp_addr_base != 0);
 }
 
 
+#if 0
 //------------------------------------------------------------------
 // check_modulus_mem()
 //
@@ -124,22 +121,22 @@ static void check_modulus_mem(void)
 
   printf("Testing modulus mem access.\n");
 
-  tc_w32(MODEXP_MODULUS_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST, 0x00000000);
   // Write test data to modulus mempory.
   for (i = 0 ; i < 64; i = i + 1) {
     j = ((i * 4 + 3) << 24) + ((i * 4 + 2) << 16) +
       ((i * 4 + 1) << 8) + i * 4;
-    tc_w32(MODEXP_MODULUS_DATA, j);
+    tc_w32(modexp_addr_base + MODEXP_MODULUS_DATA, j);
   }
 
-  tc_w32(MODEXP_MODULUS_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST, 0x00000000);
   // Read out test data from modulus mempory.
   for (i = 0 ; i < 64 ; i = i + 4) {
     printf("modulus mem: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-	   tc_r32(MODEXP_MODULUS_DATA),
-	   tc_r32(MODEXP_MODULUS_DATA),
-	   tc_r32(MODEXP_MODULUS_DATA),
-	   tc_r32(MODEXP_MODULUS_DATA));
+	   tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA));
   }
 }
 
@@ -156,22 +153,22 @@ static void check_exponent_mem(void)
 
   printf("Testing exponent mem access.\n");
 
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
   // Write test data to exponent memory.
   for (i = 0 ; i < 64; i = i + 1) {
     j = ((i * 4 + 3) << 24) + ((i * 4 + 2) << 16) +
       ((i * 4 + 1) << 8) + i * 4;
-    tc_w32(MODEXP_EXPONENT_DATA, j);
+    tc_w32(modexp_addr_base + MODEXP_EXPONENT_DATA, j);
   }
 
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
   // Read out test data from exponent memory.
   for (i = 0 ; i < 64 ; i = i + 4) {
     printf("exponent mem: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-	   tc_r32(MODEXP_EXPONENT_DATA),
-	   tc_r32(MODEXP_EXPONENT_DATA),
-	   tc_r32(MODEXP_EXPONENT_DATA),
-	   tc_r32(MODEXP_EXPONENT_DATA));
+	   tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA));
   }
 }
 
@@ -189,22 +186,22 @@ static void check_message_mem(void)
 
   printf("Testing message mem access.\n");
 
-  tc_w32(MODEXP_MESSAGE_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST, 0x00000000);
   // Write test data to message memory.
   for (i = 0 ; i < 64; i = i + 1) {
     j = ((i * 4 + 3) << 24) + ((i * 4 + 2) << 16) +
       ((i * 4 + 1) << 8) + i * 4;
-    tc_w32(MODEXP_MESSAGE_DATA, j);
+    tc_w32(modexp_addr_base + MODEXP_MESSAGE_DATA, j);
   }
 
-  tc_w32(MODEXP_MESSAGE_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST, 0x00000000);
   // Read out test data from messsage memory.
   for (i = 0 ; i < 64 ; i = i + 4) {
     printf("message mem: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-	   tc_r32(MODEXP_MESSAGE_DATA),
-	   tc_r32(MODEXP_MESSAGE_DATA),
-	   tc_r32(MODEXP_MESSAGE_DATA),
-	   tc_r32(MODEXP_MESSAGE_DATA));
+	   tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA),
+	   tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA));
   }
 }
 
@@ -217,19 +214,19 @@ static void check_message_mem(void)
 static void clear_mems()
 {
   uint32_t i;
-  tc_w32(MODEXP_MESSAGE_PTR_RST,  0x00000000);
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_MODULUS_PTR_RST,  0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST,  0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST,  0x00000000);
 
   for (i = 0 ; i < 256 ; i++) {
-    tc_w32(MODEXP_MESSAGE_DATA,  0x00000000);
-    tc_w32(MODEXP_EXPONENT_DATA, 0x00000000);
-    tc_w32(MODEXP_MODULUS_DATA,  0x00000000);
+    tc_w32(modexp_addr_base + MODEXP_MESSAGE_DATA,  0x00000000);
+    tc_w32(modexp_addr_base + MODEXP_EXPONENT_DATA, 0x00000000);
+    tc_w32(modexp_addr_base + MODEXP_MODULUS_DATA,  0x00000000);
   }
 
-  tc_w32(MODEXP_MESSAGE_PTR_RST,  0x00000000);
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_MODULUS_PTR_RST,  0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST,  0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST,  0x00000000);
 }
 
 
@@ -240,35 +237,36 @@ static void clear_mems()
 //------------------------------------------------------------------
 static void dump_mems()
 {
-  tc_w32(MODEXP_MESSAGE_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST, 0x00000000);
   printf("First words in messagee mem:\n");
   printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
-	 tc_r32(MODEXP_MESSAGE_DATA), tc_r32(MODEXP_MESSAGE_DATA),
-	 tc_r32(MODEXP_MESSAGE_DATA), tc_r32(MODEXP_MESSAGE_DATA));
+	 tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA), tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA),
+	 tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA), tc_r32(modexp_addr_base + MODEXP_MESSAGE_DATA));
 
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
   printf("First words in exponent mem:\n");
   printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
-	 tc_r32(MODEXP_EXPONENT_DATA), tc_r32(MODEXP_EXPONENT_DATA),
-	 tc_r32(MODEXP_EXPONENT_DATA), tc_r32(MODEXP_EXPONENT_DATA));
+	 tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA), tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA),
+	 tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA), tc_r32(modexp_addr_base + MODEXP_EXPONENT_DATA));
 
-  tc_w32(MODEXP_MODULUS_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST, 0x00000000);
   printf("First words in modulus mem:\n");
   printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
-	 tc_r32(MODEXP_MODULUS_DATA), tc_r32(MODEXP_MODULUS_DATA),
-	 tc_r32(MODEXP_MODULUS_DATA), tc_r32(MODEXP_MODULUS_DATA));
+	 tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA), tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA),
+	 tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA), tc_r32(modexp_addr_base + MODEXP_MODULUS_DATA));
 
-  tc_w32(MODEXP_RESULT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_RESULT_PTR_RST, 0x00000000);
   printf("First words in result mem:\n");
   printf("0x%08x 0x%08x 0x%08x 0x%08x\n",
-	 tc_r32(MODEXP_RESULT_DATA), tc_r32(MODEXP_RESULT_DATA),
-	 tc_r32(MODEXP_RESULT_DATA), tc_r32(MODEXP_RESULT_DATA));
+	 tc_r32(modexp_addr_base + MODEXP_RESULT_DATA), tc_r32(modexp_addr_base + MODEXP_RESULT_DATA),
+	 tc_r32(modexp_addr_base + MODEXP_RESULT_DATA), tc_r32(modexp_addr_base + MODEXP_RESULT_DATA));
 
-  tc_w32(MODEXP_MESSAGE_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_MODULUS_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_RESULT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_RESULT_PTR_RST, 0x00000000);
 }
+#endif /* #if 0 */
 
 
 //------------------------------------------------------------------
@@ -282,28 +280,28 @@ uint8_t testrunner(uint32_t exp_len, uint32_t *exponent,
   uint32_t result;
   uint8_t correct;
 
-  tc_w32(MODEXP_EXPONENT_LENGTH, exp_len);
-  tc_w32(MODEXP_EXPONENT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_LENGTH, exp_len);
+  tc_w32(modexp_addr_base + MODEXP_EXPONENT_PTR_RST, 0x00000000);
   for (i = 0 ; i < mod_len ; i++) {
-    tc_w32(MODEXP_EXPONENT_DATA, exponent[i]);
+    tc_w32(modexp_addr_base + MODEXP_EXPONENT_DATA, exponent[i]);
   }
 
-  tc_w32(MODEXP_MODULUS_LENGTH, mod_len);
-  tc_w32(MODEXP_MESSAGE_PTR_RST, 0x00000000);
-  tc_w32(MODEXP_MODULUS_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_LENGTH, mod_len);
+  tc_w32(modexp_addr_base + MODEXP_MESSAGE_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_MODULUS_PTR_RST, 0x00000000);
   for (i = 0 ; i < mod_len ; i++) {
-    tc_w32(MODEXP_MESSAGE_DATA, message[i]);
-    tc_w32(MODEXP_MODULUS_DATA, modulus[i]);
+    tc_w32(modexp_addr_base + MODEXP_MESSAGE_DATA, message[i]);
+    tc_w32(modexp_addr_base + MODEXP_MODULUS_DATA, modulus[i]);
   }
 
-  tc_w32(MODEXP_ADDR_CTRL, 0x00000001);
-  check(tc_wait_ready(MODEXP_ADDR_STATUS));
+  tc_w32(modexp_addr_base + MODEXP_ADDR_CTRL, 0x00000001);
+  check(tc_wait_ready(modexp_addr_base + MODEXP_ADDR_STATUS));
 
   correct = 1;
 
-  tc_w32(MODEXP_RESULT_PTR_RST, 0x00000000);
+  tc_w32(modexp_addr_base + MODEXP_RESULT_PTR_RST, 0x00000000);
   for (i = 0 ; i < mod_len ; i++) {
-    result = tc_r32(MODEXP_RESULT_DATA);
+    result = tc_r32(modexp_addr_base + MODEXP_RESULT_DATA);
     if (result != expected[i]) {
       printf("Error. Expected 0x%08x, got 0x%08x\n", expected[i], result);
       correct = 0;
@@ -514,7 +512,7 @@ static void tc7()
 //------------------------------------------------------------------
 // tc8()
 //
-// Testcase with 1024 bit operands.
+// Testcase with 2048 bit operands.
 //------------------------------------------------------------------
 static void tc8()
 {
@@ -591,7 +589,7 @@ static void tc8()
                          0xd5535329 };
   uint8_t result;
 
-  printf("Running TC8: 1024 bit operands...\n");
+  printf("Running TC8: 2048 bit operands.s\n");
 
   result = testrunner(65, exponent, 65, modulus, message, expected);
 
@@ -602,112 +600,94 @@ static void tc8()
 }
 
 
-void rob_dec_1024(void)
-{
-  uint32_t exponent[] = {0x00000000, 0x3ff26c9e, 0x32685b93, 0x66570228, 0xf0603c4e,
-                         0x04a717c1, 0x8038b116, 0xeb48325e, 0xcada992a,
-                         0x920bb241, 0x5aee4afe, 0xe2a37e87, 0xb35b9519,
-                         0xb335775d, 0x989553e9, 0x1326f46e, 0x2cdf6b7b,
-                         0x84aabfa9, 0xef24c600, 0xb56872ad, 0x5edb9041,
-                         0xe8ecd7f8, 0x535133fb, 0xdefc92c7, 0x42384226,
-                         0x7d40e5f5, 0xc91bd745, 0x9578e460, 0xfc858374,
-                         0x3172bed3, 0x73b6957c, 0xc0d6a68e, 0x33156a61};
-
-
-  uint32_t modulus[] = {0x00000000, 0xd075ec0a, 0x95048ef8, 0xcaa69073, 0x8d9d58e9,
-                        0x1764b437, 0x50b58cad, 0x8a6e3199, 0x135f80ee,
-                        0x84eb2bde, 0x58d38ee3, 0x5825e91e, 0xafdeb1ba,
-                        0xa15a160b, 0x0057c47c, 0xc7765e31, 0x868a3e15,
-                        0x5ee57cef, 0xb008c4dd, 0x6a0a89ee, 0x98a4ee9c,
-                        0x971a07de, 0x61e5b0d3, 0xcf70e1cd, 0xc6a0de5b,
-                        0x451f2fb9, 0xdb995196, 0x9f2f884b, 0x4b09749a,
-                        0xe6c4ddbe, 0x7ee61f79, 0x265c6adf, 0xb16b3015};
-
-
-  uint32_t message[] = {0x00000000, 0x0001ffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0x00303130,
-                        0x0d060960, 0x86480165, 0x03040201, 0x05000420,
-                        0x8e36fc9a, 0xa31724c3, 0x2416263c, 0x0366a175,
-                        0xfabbb92b, 0x741ca649, 0x6107074d, 0x0343b597};
-
-
-  uint32_t expected[] = {0x00000000, 0x06339a64, 0x367db02a, 0xf41158cc, 0x95e76049,
-                         0x4519c165, 0x111184be, 0xe41d8ee2, 0x2ae5f5d1,
-                         0x1da7f962, 0xac93ac88, 0x915eee13, 0xa3350c22,
-                         0xf0dfa62e, 0xfdfc2b62, 0x29f26e27, 0xbebdc84e,
-                         0x4746df79, 0x7b387ad2, 0x13423c9f, 0x98e8a146,
-                         0xff486b6c, 0x1a85414e, 0x73117121, 0xb700e547,
-                         0xab4e07b2, 0x21b988b8, 0x24dd77c2, 0x046b0a20,
-                         0xcddb986a, 0xac75c2f2, 0xb044ed59, 0xea565879};
-
-  uint8_t result;
-
-  printf("=== Running 1024 bit decipher/sign test from Robs RSA code. ===\n");
-
-  result = testrunner(33, exponent, 33, modulus, message, expected);
-
-  if (result)
-    printf("Rob 1024 dec/sign test OK\n");
-  else
-    printf("Rob 1024 dec/sign test NOT OK\n");
-
-}
-
-
-void rob_enc_1024(void)
+//------------------------------------------------------------------
+// tc9()
+//
+// Testcase with 2048 bit operands.
+//------------------------------------------------------------------
+static void tc9()
 {
-  uint32_t exponent[] = {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, 0x00000000, 0x00010001};
-
-
-  uint32_t modulus[] = {0x00000000, 0xd075ec0a, 0x95048ef8, 0xcaa69073, 0x8d9d58e9,
-                        0x1764b437, 0x50b58cad, 0x8a6e3199, 0x135f80ee,
-                        0x84eb2bde, 0x58d38ee3, 0x5825e91e, 0xafdeb1ba,
-                        0xa15a160b, 0x0057c47c, 0xc7765e31, 0x868a3e15,
-                        0x5ee57cef, 0xb008c4dd, 0x6a0a89ee, 0x98a4ee9c,
-                        0x971a07de, 0x61e5b0d3, 0xcf70e1cd, 0xc6a0de5b,
-                        0x451f2fb9, 0xdb995196, 0x9f2f884b, 0x4b09749a,
-                        0xe6c4ddbe, 0x7ee61f79, 0x265c6adf, 0xb16b3015};
-
-
-  uint32_t message[] = {0x00000000, 0x0001ffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
-                        0xffffffff, 0xffffffff, 0xffffffff, 0x00303130,
-                        0x0d060960, 0x86480165, 0x03040201, 0x05000420,
-                        0x8e36fc9a, 0xa31724c3, 0x2416263c, 0x0366a175,
-                        0xfabbb92b, 0x741ca649, 0x6107074d, 0x0343b597};
-
-
-  uint32_t expected[] = {0x00000000, 0x06339a64, 0x367db02a, 0xf41158cc, 0x95e76049,
-                         0x4519c165, 0x111184be, 0xe41d8ee2, 0x2ae5f5d1,
-                         0x1da7f962, 0xac93ac88, 0x915eee13, 0xa3350c22,
-                         0xf0dfa62e, 0xfdfc2b62, 0x29f26e27, 0xbebdc84e,
-                         0x4746df79, 0x7b387ad2, 0x13423c9f, 0x98e8a146,
-                         0xff486b6c, 0x1a85414e, 0x73117121, 0xb700e547,
-                         0xab4e07b2, 0x21b988b8, 0x24dd77c2, 0x046b0a20,
-                         0xcddb986a, 0xac75c2f2, 0xb044ed59, 0xea565879};
+  uint32_t message[] = {0x21558179, 0x3e2914b1, 0xefe95957, 0x965fdead,
+                        0xe766d8fc, 0x136eadf4, 0xa6106a2a, 0x88b2df7e,
+                        0xe0b0eaae, 0x2c17946a, 0x6f5b5563, 0x228052ae,
+                        0x7fc40d80, 0xf81354db, 0xfceecd1a, 0xa5e4c97d,
+                        0x433ecfcd, 0xc20d1e4d, 0x2a748fe3, 0x1d9e63f0,
+                        0xdc6c25d6, 0xdae5c8be, 0x1d8c5431, 0xb1d7d270,
+                        0xed5b2566, 0x1463b0fd, 0xa9e26cf7, 0x3dd6fbd7,
+                        0x1347c8f7, 0x76c2cc37, 0xf382b786, 0x1d5ac517,
+                        0x26b96692, 0x2c1fe6f8, 0x5852dbf8, 0x4bcabda2,
+                        0xbedb2f5f, 0xbfe58158, 0x8cd5d15f, 0xac7c7f4c,
+                        0xf8ba47d2, 0x86c6571d, 0x06a4760b, 0xa6afa0e1,
+                        0x7a819f62, 0x5cdbfe15, 0x9b2d10b5, 0xf508b1fd,
+                        0xb3f0462a, 0x92f45a64, 0x69b6ec58, 0xbfad8fab,
+                        0x6799260f, 0x27415db5, 0xf6ac7832, 0xe547826d,
+                        0x6a9806a5, 0x36c62a88, 0x98bee14d, 0x9b8c2648,
+                        0xabdbbd3d, 0xaf59eea1, 0x164eacb5, 0x3a18e427};
+
+
+  uint32_t exponent[] = {0x2519837b, 0xe73a9031, 0xe241606d, 0x21e70fa2,
+                         0x7881f254, 0x4e60831d, 0x266f408e, 0x4a83e6ed,
+                         0xa7741995, 0x32b477ba, 0x91bdf5d0, 0x4acd7a06,
+                         0x51e344b9, 0xdf376e4e, 0x8494e625, 0xa0cc9697,
+                         0x817a0c93, 0x3b68cefb, 0x46de14c1, 0x52229965,
+                         0x329645bd, 0xf4176adc, 0x29a8bc50, 0x44900fec,
+                         0x1558d492, 0xf838a8e7, 0xea207abd, 0xcd21a28c,
+                         0x91e6b02f, 0x2a490ea8, 0x5d99663b, 0x87c92fb6,
+                         0x0a185325, 0x5256a7a3, 0x496b7288, 0x6688b6c8,
+                         0x650e1776, 0x54cd429f, 0x90ea3b18, 0x0b72ae61,
+                         0xcc8651b3, 0xa488742d, 0x93c401ef, 0x5a2220ff,
+                         0xaee1f257, 0xf9d1e29a, 0xd47151fe, 0x4978342b,
+                         0x0927048a, 0x404b0689, 0xdc9df8cc, 0xfba9845f,
+                         0xeb8a39b0, 0xd3f24ae2, 0x5ea9ca0a, 0x0c064f94,
+                         0x35368ae2, 0xeab6c035, 0x9baa39c6, 0x2ef6259d,
+                         0xa2577555, 0x514c7d98, 0x0890d44f, 0xf416fbdd};
+
+
+  uint32_t modulus[] = {0x2c5337a9, 0x3f2e1ca6, 0x91de65ea, 0xc3f9a3c2,
+                        0xdc9099e0, 0x64ebe412, 0xf4583fae, 0x1fc8e8dd,
+                        0x92dcbbfb, 0x9159239e, 0xdbbec456, 0x8735a660,
+                        0x8248dbbc, 0x76f01415, 0x3cb8a897, 0x7cc09280,
+                        0x6cc6db51, 0x9c2544da, 0x316564ce, 0x4b6d9b3b,
+                        0x3e0e123f, 0x942a4a3c, 0x1f128873, 0x5ad14862,
+                        0xdde8e6dd, 0x73da31fb, 0x1a8a2046, 0xc3ff18c6,
+                        0x24e31d54, 0x7d8a1796, 0x88ab346c, 0x262bb321,
+                        0x2cada5dc, 0x1fb2284c, 0x042375fd, 0xba10d309,
+                        0xcda978ec, 0x229ee156, 0x8470728a, 0xa58017fd,
+                        0x65727801, 0x1ea396a6, 0xbd9a4bc1, 0x8e97c08f,
+                        0xd7529796, 0x2c8339e9, 0xc5340a83, 0x6f7d1f9c,
+                        0xd6014fec, 0xdffa2265, 0xfa9906a9, 0xafbd424a,
+                        0x631994ae, 0x73a9b3f1, 0x2284f999, 0x6f8c87f6,
+                        0x93136a66, 0x47c81e45, 0xd35f0e41, 0x238d6960,
+                        0x96cf337d, 0x8865e4cc, 0x15039c40, 0x65ee7211};
+
+
+  uint32_t expected[] = {0x24665860, 0x4b150493, 0xc0834602, 0xc0b99ab5,
+                         0xbe649545, 0xa7d8b1ca, 0x55c1b98a, 0x1dce374b,
+                         0x65750415, 0x573dfed7, 0x95df9943, 0x58a4aea0,
+                         0x5fb40a92, 0x1408d9c2, 0xb5e23fc9, 0x225eb60b,
+                         0x41d33a41, 0xbf958f7f, 0x619f5ac1, 0x207647f3,
+                         0x223e56f8, 0x26afd4ae, 0x6a297840, 0x830947db,
+                         0xbc5af940, 0x4c97ebb1, 0xca38b220, 0x04c9a26d,
+                         0x49a16b72, 0x0882c658, 0x2dbc50e0, 0x67e2d057,
+                         0x4b8ef356, 0x4ba5eac3, 0x17237d9f, 0x27c111a8,
+                         0xc1b1944e, 0xe91fd6b6, 0xa78d9747, 0x61e946d3,
+                         0x0078fe23, 0x7770a088, 0x6d5762af, 0x435ac5f9,
+                         0x36cde9d5, 0xc313804d, 0xa4623760, 0xb1c37572,
+                         0x2b22486d, 0x8af131e3, 0x3e5fc3ea, 0x0d9c9ba0,
+                         0x218bcc8f, 0x8bcdfea2, 0xcf55a599, 0x57b9fcbc,
+                         0x5c087f62, 0xec130a15, 0x7e8bd1f5, 0x60eaaa51,
+                         0x020dd89b, 0x890cc6ea, 0x042d0054, 0x74055863};
 
   uint8_t result;
 
-  printf("=== Running 1024 bit enc/verify test from Robs RSA code. ===\n");
+  printf("Running TC9: 2048 bit operands.s\n");
 
-  result = testrunner(33, exponent, 33, modulus, expected, message);
+  result = testrunner(64, exponent, 64, modulus, message, expected);
 
   if (result)
-    printf("Rob 1024 enc/verify test OK\n");
+    printf("TC9: OK\n");
   else
-    printf("Rob 1024 enc/verify test NOT OK\n");
+    printf("TC9: NOT OK\n");
 }
 
 
@@ -717,22 +697,21 @@ void rob_enc_1024(void)
 int main(void)
 {
   check_modexp_access();
-  //  tc_set_debug(1);
+//  tc_set_debug(1);
 
 //  check_modulus_mem();
 //  check_exponent_mem();
 //  check_message_mem();
 
-//  tc1();
-//  tc2();
-//  tc3();
-//  tc4();
-//  tc5();
-//  tc6();
-//  tc7();
-//  tc8();
-  rob_dec_1024();
-  rob_enc_1024();
+  tc1();
+  tc2();
+  tc3();
+  tc4();
+  tc5();
+  tc6();
+  tc7();
+  tc8();
+  tc9();
 
   return 0;
 }
diff --git a/sw/tc_eim.c b/sw/tc_eim.c
index 8ef4f06..87e90d1 100644
--- a/sw/tc_eim.c
+++ b/sw/tc_eim.c
@@ -45,12 +45,13 @@
 #include "cryptech.h"
 
 static int debug = 0;
-static int inited = 0;
 
 /* ---------------- EIM low-level code ---------------- */
 
 static int init(void)
 {
+    static int inited = 0;
+
     if (inited)
         return 0;
 
@@ -84,11 +85,11 @@ void tc_set_debug(int onoff)
     debug = onoff;
 }
 
-static void dump(char *label, const uint8_t *buf, size_t len)
+static void dump(char *label, off_t addr, const uint8_t *buf, size_t len)
 {
     if (debug) {
         int i;
-        printf("%s [", label);
+        printf("%s %04x [", label, (unsigned int)addr);
         for (i = 0; i < len; ++i)
             printf(" %02x", buf[i]);
         printf(" ]\n");
@@ -100,10 +101,9 @@ int tc_write(off_t offset, const uint8_t *buf, size_t len)
     if (init() != 0)
         return -1;
 
-    dump("write ", buf, len);
+    dump("write ", offset, buf, len);
 
-    offset = eim_offset(offset);
-    for (; len > 0; offset += 4, buf += 4, len -= 4) {
+    for (offset = eim_offset(offset); len > 0; offset += 4, buf += 4, len -= 4) {
         uint32_t val;
         val = htonl(*(uint32_t *)buf);
         eim_write_32(offset, &val);
@@ -114,20 +114,20 @@ int tc_write(off_t offset, const uint8_t *buf, size_t len)
 
 int tc_read(off_t offset, uint8_t *buf, size_t len)
 {
+    off_t off;
     uint8_t *rbuf = buf;
     int rlen = len;
 
     if (init() != 0)
         return -1;
 
-    offset = eim_offset(offset);
-    for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) {
+    for (off = eim_offset(offset); rlen > 0; off += 4, rbuf += 4, rlen -= 4) {
         uint32_t val;
-        eim_read_32(offset, &val);
+        eim_read_32(off, &val);
         *(uint32_t *)rbuf = ntohl(val);
     }
 
-    dump("read  ", buf, len);
+    dump("read  ", offset, buf, len);
 
     return 0;
 }
@@ -142,7 +142,7 @@ int tc_expected(off_t offset, const uint8_t *expected, size_t len)
         perror("malloc");
         return 1;
     }
-    dump("expect", expected, len);
+    dump("expect", offset, expected, len);
 
     if (tc_read(offset, buf, len) != 0)
         goto errout;
diff --git a/sw/trng_extractor.c b/sw/trng_extractor.c
index e25ebf0..c0ff227 100644
--- a/sw/trng_extractor.c
+++ b/sw/trng_extractor.c
@@ -53,31 +53,18 @@ char *usage =
 -v      verbose operation\n\
 ";
 
-/* check availability of avalanche entropy core by reading core name and version */
-static int avalanche_check(void)
-{
-    return
-        tc_expected(ENTROPY1_ADDR_NAME0, (const uint8_t *)AVALANCHE_ENTROPY_NAME0, 4) ||
-        tc_expected(ENTROPY1_ADDR_NAME1, (const uint8_t *)AVALANCHE_ENTROPY_NAME1, 4);
-}
+/* ---------------- startup code ---------------- */
 
-/* check availability of rosc core by reading the core name and version */
-static int rosc_check(void)
-{
-    return
-        tc_expected(ENTROPY2_ADDR_NAME0, (const uint8_t *)ROSC_ENTROPY_NAME0, 4) ||
-        tc_expected(ENTROPY2_ADDR_NAME1, (const uint8_t *)ROSC_ENTROPY_NAME1, 4);
-}
+static off_t entropy1_addr_base, entropy2_addr_base, csprng_addr_base;
 
-/* check availability of csprng core by reading the core name and version */
-static int csprng_check(void)
+static void init(void)
 {
-    return
-        tc_expected(CSPRNG_ADDR_NAME0, (const uint8_t *)CSPRNG_NAME0, 4) ||
-        tc_expected(CSPRNG_ADDR_NAME1, (const uint8_t *)CSPRNG_NAME1, 4);
+    entropy1_addr_base = tc_core_base("extnoise");
+    entropy2_addr_base = tc_core_base("rosc ent");
+    csprng_addr_base = tc_core_base("csprng");
 }
 
-/* extract one data sample */
+/* ---------------- extract one data sample ---------------- */
 static int extract(off_t status_addr, off_t data_addr, uint32_t *data)
 {
     if (tc_wait(status_addr, ENTROPY1_STATUS_VALID, NULL) != 0) {
@@ -93,18 +80,20 @@ static int extract(off_t status_addr, off_t data_addr, uint32_t *data)
     return 0;
 }
 
-/* main */
+/* ---------------- main ---------------- */
 int main(int argc, char *argv[])
 {
     int opt;
     unsigned long num_words = 1, i;
     char *endptr;
-    off_t status_addr = CSPRNG_ADDR_STATUS;
-    off_t data_addr = CSPRNG_ADDR_RANDOM;
+    off_t status_addr = 0;
+    off_t data_addr = 0;
     FILE *output = stdout;
     uint32_t data;
     int verbose = 0;
 
+    init();
+
     /* parse command line */
     while ((opt = getopt(argc, argv, "h?varcn:o:")) != -1) {
         switch (opt) {
@@ -113,16 +102,16 @@ int main(int argc, char *argv[])
             printf(usage, argv[0]);
             return EXIT_SUCCESS;
         case 'a':
-            status_addr = ENTROPY1_ADDR_STATUS;
-            data_addr = ENTROPY1_ADDR_ENTROPY;
+            status_addr = entropy1_addr_base + ENTROPY1_ADDR_STATUS;
+            data_addr = entropy1_addr_base + ENTROPY1_ADDR_ENTROPY;
             break;
         case 'r':
-            status_addr = ENTROPY2_ADDR_STATUS;
-            data_addr = ENTROPY2_ADDR_ENTROPY;
+            status_addr = entropy2_addr_base + ENTROPY2_ADDR_STATUS;
+            data_addr = entropy2_addr_base + ENTROPY2_ADDR_ENTROPY;
             break;
         case 'c':
-            status_addr = CSPRNG_ADDR_STATUS;
-            data_addr = CSPRNG_ADDR_RANDOM;
+            status_addr = csprng_addr_base + CSPRNG_ADDR_STATUS;
+            data_addr = csprng_addr_base + CSPRNG_ADDR_RANDOM;
             break;
         case 'v':
             verbose = 1;
@@ -171,15 +160,10 @@ int main(int argc, char *argv[])
         goto errout;
     }
 
-    // Check that we can talk to the trng.
-    if (verbose)
-        printf("Checking that we can access the TRNG...\n");
-    if (avalanche_check() || rosc_check() || csprng_check()) {
-        fprintf(stderr, "Can't properly access the trng.\n");
-        return EXIT_FAILURE;
+    if (status_addr == 0) {
+	status_addr = csprng_addr_base + CSPRNG_ADDR_STATUS;
+	data_addr = csprng_addr_base + CSPRNG_ADDR_RANDOM;
     }
-    if (verbose)
-        printf("TRNG access ok..\n");
 
     /* get the data */
     for (i = 0; i < num_words; ++i) {
diff --git a/sw/trng_tester.c b/sw/trng_tester.c
index 715a20c..6243544 100644
--- a/sw/trng_tester.c
+++ b/sw/trng_tester.c
@@ -57,6 +57,27 @@ int repeat = 0;
 int num_words = 10;
 int wait_stats = 0;
 
+/* ---------------- startup code ---------------- */
+
+static off_t board_addr_base = 0;
+static off_t trng_addr_base, entropy1_addr_base, entropy2_addr_base, csprng_addr_base;
+
+static int init(void)
+{
+    static int inited = 0;
+
+    if (inited)
+        return 0;
+
+    trng_addr_base = tc_core_base("trng");
+    entropy1_addr_base = tc_core_base("extnoise");
+    entropy2_addr_base = tc_core_base("rosc ent");
+    csprng_addr_base = tc_core_base("csprng");
+
+    inited = 1;
+    return 0;
+}
+
 /* ---------------- sanity test case ---------------- */
 
 int TC0()
@@ -66,6 +87,9 @@ int TC0()
     uint8_t version[4] = NOVENA_BOARD_VERSION;
     uint8_t t[4];
 
+    if (init() != 0)
+        return -1;
+
     if (!quiet)
         printf("TC0: Reading board type, version, and dummy reg from global registers.\n");
 
@@ -73,14 +97,14 @@ int TC0()
      * to make sure that we can actually write something into EIM
      */
     (void)time((time_t *)t);
-    if (tc_write(BOARD_ADDR_DUMMY, t, 4) != 0)
+    if (tc_write(board_addr_base + BOARD_ADDR_DUMMY, t, 4) != 0)
         return 1;
 
     return
-	tc_expected(BOARD_ADDR_NAME0,   name0,   4) ||
-        tc_expected(BOARD_ADDR_NAME1,   name1,   4) ||
-        tc_expected(BOARD_ADDR_VERSION, version, 4) ||
-        tc_expected(BOARD_ADDR_DUMMY,   t, 4);
+	tc_expected(board_addr_base + BOARD_ADDR_NAME0,   name0,   4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_NAME1,   name1,   4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_VERSION, version, 4) ||
+        tc_expected(board_addr_base + BOARD_ADDR_DUMMY,   t, 4);
 }
 
 /* ---------------- trng test cases ---------------- */
@@ -92,13 +116,20 @@ int TC1(void)
     uint8_t name1[4]   = TRNG_NAME1;
     uint8_t version[4] = TRNG_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((trng_addr_base == 0) && !quiet) {
+        printf("TC1: TRNG not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC1: Reading name and version words from trng core.\n");
 
     return
-        tc_expected(TRNG_ADDR_NAME0, name0, 4) ||
-        tc_expected(TRNG_ADDR_NAME1, name1, 4) ||
-        tc_expected(TRNG_ADDR_VERSION, version, 4);
+        tc_expected(trng_addr_base + TRNG_ADDR_NAME0, name0, 4) ||
+        tc_expected(trng_addr_base + TRNG_ADDR_NAME1, name1, 4) ||
+        tc_expected(trng_addr_base + TRNG_ADDR_VERSION, version, 4);
 }
 
 /* XXX test cases for setting blinkenlights? */
@@ -113,13 +144,20 @@ int TC2(void)
     uint8_t name1[4]   = AVALANCHE_ENTROPY_NAME1;
     uint8_t version[4] = AVALANCHE_ENTROPY_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((entropy1_addr_base == 0) && !quiet) {
+        printf("TC2: AVALANCHE_ENTROPY not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC2: Reading name and version words from avalanche_entropy core.\n");
 
     return
-        tc_expected(ENTROPY1_ADDR_NAME0, name0, 4) ||
-        tc_expected(ENTROPY1_ADDR_NAME1, name1, 4) ||
-        tc_expected(ENTROPY1_ADDR_VERSION, version, 4);
+        tc_expected(entropy1_addr_base + ENTROPY1_ADDR_NAME0, name0, 4) ||
+        tc_expected(entropy1_addr_base + ENTROPY1_ADDR_NAME1, name1, 4) ||
+        tc_expected(entropy1_addr_base + ENTROPY1_ADDR_VERSION, version, 4);
 }
 
 /* XXX clear 'enable' control bit, see if we read the same value */
@@ -130,16 +168,23 @@ int TC3(void)
     int i, n;
     uint32_t entropy;
 
+    if (init() != 0)
+        return -1;
+    if ((entropy1_addr_base == 0) && !quiet) {
+        printf("TC3: AVALANCHE_ENTROPY not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC3: Read random data from avalanche_entropy.\n");
 
     for (i = 0; i < num_words; ++i) {
         /* check status */
         n = 0;
-        if (tc_wait(ENTROPY1_ADDR_STATUS, ENTROPY1_STATUS_VALID, &n) != 0)
+        if (tc_wait(entropy1_addr_base + ENTROPY1_ADDR_STATUS, ENTROPY1_STATUS_VALID, &n) != 0)
             return 1;
         /* read entropy data */
-        if (tc_read(ENTROPY1_ADDR_ENTROPY, (uint8_t *)&entropy, 4) != 0)
+        if (tc_read(entropy1_addr_base + ENTROPY1_ADDR_ENTROPY, (uint8_t *)&entropy, 4) != 0)
             return 1;
         /* display entropy data */
         if (!debug) {
@@ -162,13 +207,20 @@ int TC4(void)
     uint8_t name1[4]   = ROSC_ENTROPY_NAME1;
     uint8_t version[4] = ROSC_ENTROPY_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((entropy2_addr_base == 0) && !quiet) {
+        printf("TC4: ROSC_ENTROPY not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC4: Reading name and version words from rosc_entropy core.\n");
 
     return
-        tc_expected(ENTROPY2_ADDR_NAME0, name0, 4) ||
-        tc_expected(ENTROPY2_ADDR_NAME1, name1, 4) ||
-        tc_expected(ENTROPY2_ADDR_VERSION, version, 4);
+        tc_expected(entropy2_addr_base + ENTROPY2_ADDR_NAME0, name0, 4) ||
+        tc_expected(entropy2_addr_base + ENTROPY2_ADDR_NAME1, name1, 4) ||
+        tc_expected(entropy2_addr_base + ENTROPY2_ADDR_VERSION, version, 4);
 }
 
 /* XXX clear 'enable' control bit, see if we read the same value */
@@ -179,16 +231,23 @@ int TC5(void)
     int i, n;
     uint32_t entropy;
 
+    if (init() != 0)
+        return -1;
+    if ((entropy2_addr_base == 0) && !quiet) {
+        printf("TC5: ROSC_ENTROPY not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC5: Read random data from rosc_entropy.\n");
 
     for (i = 0; i < num_words; ++i) {
         /* check status */
         n = 0;
-        if (tc_wait(ENTROPY2_ADDR_STATUS, ENTROPY2_STATUS_VALID, &n) != 0)
+        if (tc_wait(entropy2_addr_base + ENTROPY2_ADDR_STATUS, ENTROPY2_STATUS_VALID, &n) != 0)
             return 1;
         /* read entropy data */
-        if (tc_read(ENTROPY2_ADDR_ENTROPY, (uint8_t *)&entropy, 4) != 0)
+        if (tc_read(entropy2_addr_base + ENTROPY2_ADDR_ENTROPY, (uint8_t *)&entropy, 4) != 0)
             return 1;
         /* display entropy data */
         if (!debug) {
@@ -211,13 +270,20 @@ int TC6(void)
     uint8_t name1[4]   = CSPRNG_NAME1;
     uint8_t version[4] = CSPRNG_VERSION;
 
+    if (init() != 0)
+        return -1;
+    if ((csprng_addr_base == 0) && !quiet) {
+        printf("TC6: CSPRNG not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC6: Reading name and version words from trng_csprng core.\n");
 
     return
-        tc_expected(CSPRNG_ADDR_NAME0, name0, 4) ||
-        tc_expected(CSPRNG_ADDR_NAME1, name1, 4) ||
-        tc_expected(CSPRNG_ADDR_VERSION, version, 4);
+        tc_expected(csprng_addr_base + CSPRNG_ADDR_NAME0, name0, 4) ||
+        tc_expected(csprng_addr_base + CSPRNG_ADDR_NAME1, name1, 4) ||
+        tc_expected(csprng_addr_base + CSPRNG_ADDR_VERSION, version, 4);
 }
 
 /* XXX clear 'enable' control bit, see if we read the same value */
@@ -229,16 +295,23 @@ int TC7(void)
     int i, n;
     uint32_t random;
 
+    if (init() != 0)
+        return -1;
+    if ((csprng_addr_base == 0) && !quiet) {
+        printf("TC7: CSPRNG not present\n");
+        return 0;
+    }
+
     if (!quiet)
         printf("TC7: Read random data from trng_csprng.\n");
 
     for (i = 0; i < num_words; ++i) {
         /* check status */
         n = 0;
-        if (tc_wait(CSPRNG_ADDR_STATUS, CSPRNG_STATUS_VALID, &n) != 0)
+        if (tc_wait(csprng_addr_base + CSPRNG_ADDR_STATUS, CSPRNG_STATUS_VALID, &n) != 0)
             return 1;
         /* read random data */
-        if (tc_read(CSPRNG_ADDR_RANDOM, (uint8_t *)&random, 4) != 0)
+        if (tc_read(csprng_addr_base + CSPRNG_ADDR_RANDOM, (uint8_t *)&random, 4) != 0)
             return 1;
         /* display random data */
         if (!debug) {



More information about the Commits mailing list