diff --git a/set_env.sh b/set_env.sh
new file mode 100755
index 0000000000000000000000000000000000000000..57af45cb17c9c4a427ee2facf0c29984188f13f6
--- /dev/null
+++ b/set_env.sh
@@ -0,0 +1,50 @@
+#-----------------------------------------------------------------------------
+# SoC Labs Environment Setup Script
+# A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+#
+# Contributors
+#
+# David Mapstone (d.a.mapstone@soton.ac.uk)
+#
+# Copyright  2023, SoC Labs (www.soclabs.org)
+#-----------------------------------------------------------------------------
+#!/bin/bash
+
+# Get Root Location of Design Structure
+if [ -z $DESIGN_ROOT ]; then
+    # If $DESIGN_ROOT hasn't been set yet
+    DESIGN_ROOT=`git rev-parse --show-superproject-working-tree`
+
+    if [ -z $DESIGN_ROOT ]; then
+        # If not in a submodule - at root
+        DESIGN_ROOT=`git rev-parse --show-toplevel`
+    fi
+
+    # Source Top-Level Sourceme
+    source $DESIGN_ROOT/set_env.sh
+else
+    # Set Environment Variable for this Repository
+    export CHIPKIT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+
+    # If this Repo is root of workspace
+    if [ $CHIPKIT_DIR = $DESIGN_ROOT ]; then
+        echo "Design Workspace: $DESIGN_ROOT" 
+        export DESIGN_ROOT
+        # Set Default Simulator
+        export SIMULATOR="ivlog"
+    fi
+     
+    # Source environment variables for all submodules
+    for d in $CHIPKIT_DIR/* ; do
+        if [ -f "$d/.git" ]; then
+            if [ -f "$d/set_env.sh" ]; then
+            # If .git file exists - submodule
+                source $d/set_env.sh
+            fi
+        fi
+    done
+
+    # Add Scripts to Path
+    export PATH="$PATH:/$CHIPKIT_DIR"
+    export PYTHONPATH="$PYTHONPATH:$CHIPKIT_DIR/tools/vgen/bin"
+fi
\ No newline at end of file
diff --git a/tools/vgen/bin/vgen.py b/tools/vgen/bin/vgen.py
index db0300ca22f4bc92e5c9025d9a311335f8fc9ad7..dea53422ca80f14d4b3d7bb2eed7822d5c472b75 100755
--- a/tools/vgen/bin/vgen.py
+++ b/tools/vgen/bin/vgen.py
@@ -60,7 +60,7 @@ def get_verilog_signals(module_file,signal_prefix):
   Read a (system)verilog file and return all signals with a matching prefix, along with some related details 
   """
   fi = open(module_file,"r")
-  print "** Reading file \""+module_file+"\" to get signals with prefix \""+signal_prefix+"\"."
+  print("** Reading file \""+module_file+"\" to get signals with prefix \""+signal_prefix+"\".")
   
   # define some regexs
   re_nb = '(\\b'+re.escape(signal_prefix)+'\w+)\[(\d+)\:(\d+)\]'    # this regex matches multibit signals: e.g. "mysig[7:0]"
@@ -161,17 +161,17 @@ def get_verilog_module_signals(module_file,debug=False):
       if ')' in line:
         break
       elif re.search(re_nb,line): 
-        if d: print 'Found nb signal in module declaration.'
+        if d: print('Found nb signal in module declaration.')
         nbits = int(re.search(re_nb,line).group(2)) - int(re.search(re_nb,line).group(3)) +1
         start = int(re.search(re_nb,line).group(3)) 
         assert start == 0, 'start bit index in slice is not zero: %s' % start
         signal_match = [re.search(re_nb,line).group(4).strip(),re.search(re_nb,line).group(1).strip(),nbits,0]
       elif re.search(re_1b,line): 
-        if d: print 'Found 1b signal in module declaration.'
+        if d: print('Found 1b signal in module declaration.')
         nbits = 1
         signal_match = [re.search(re_1b,line).group(2).strip(),re.search(re_1b,line).group(1).strip(),nbits,0]
       new = dict((key,val) for key,val in zip(keys,signal_match))
-      if d: print new
+      if d: print(new)
       vglist.append(new)
  
   return vglist
@@ -196,42 +196,44 @@ def read_csv(csv_file, debug=False):
   try:
     fi = open(csv_file,"r")
   except IOError:
-    print "** Error: File not found: "+vglist_file
+    print("** Error: File not found: "+vglist_file)
     sys.exit()
   
   # create an empty list to add dictionaries to
   vglist = [] 
  
   # use csv module to iterate over input file
-  reader = csv.reader(fi)
+  reader = csv.reader(fi, delimiter="\t")
   
   # get keys from header on first line
   row = next(reader) 
+  print(row)
   header = [x.strip(' ') for x in row]      # clean up any whitespace
+  print(header)
   header = [header[0].replace('*','').strip()] + header[1:]
-  if d: print "line contains key list: " + str(header)
+  if d: print("line contains key list: " + str(header))
  
   # get the rows
   for row in reader:
-    if d: print row
+    if d: print(row)
     if not row:
-      if d: print "line is empty"
+      if d: print("line is empty")
     elif not row[0].strip(): 
-      if d: print "line is whitespace"
+      if d: print("line is whitespace")
     #elif row[0].strip().startswith('*'):            # header starts with * (store this to generate keys)
     #  header = [x.strip(' ') for x in row]          # clean up any whitespace
     #  header = [header[0].replace('*','').strip()] + header[1:]
     #  if d: print "line contains key list: " + str(header)
     elif row[0].lstrip().startswith("#"):            # comments or whitespace (ignore) 
       pass
-      if d: print "line is comment: "+"-".join(row)
+      if d: print("line is comment: "+"-".join(row))
     else:                                           # Add legit entry to list
       assert len(header) > 0                        # should have already seen the header 
       entry = [x.strip(' ') for x in row[:]]        # clean up any whitespace
       assert len(header) == len(entry)              # check equal number of key/val pairs
-      if d: print "line is CSV row: "+str(entry)
+      if d: print("line is CSV row: "+str(entry))
       new = dict((key,val) for key,val in zip(header,entry))
-      if d: print "new dict is: "+str(new)
+      if d: print("new dict is: "+str(new))
       vglist.append(new)
   
   #print vglist
@@ -251,7 +253,7 @@ def append_csv(csv_file,vglist,keys,unused_str='?',debug=False):
   d = debug
   assert vglist != [], 'empty vglist supplied: %s' %str(vglist)
 
-  print "** Appending new signals to csv file \""+csv_file+"\""
+  print("** Appending new signals to csv file \""+csv_file+"\"")
   if os.path.isfile(csv_file):
     shutil.copy2(csv_file,csv_file+".bak")   # copy2 preserves mod/access info
  
@@ -263,7 +265,7 @@ def append_csv(csv_file,vglist,keys,unused_str='?',debug=False):
   header = [header[0].strip()] + header[1:]
   assert len(header) > 0, 'Header is missing in CSV file: %s' % csv_file
   assert all(x in header for x in keys), 'Header does not contain all keys.  Header: %s, Keys: %s' % (header,keys)
-  if d: print "Header line contains key list: " + str(header)
+  if d: print("Header line contains key list: " + str(header))
   fi.close()
    
   # Now append new rows to CSV, obeying order specified in header.
@@ -278,7 +280,7 @@ def append_csv(csv_file,vglist,keys,unused_str='?',debug=False):
       else:
         line.append(unused_str)
     #line = [row[x] for x in keys]
-    if d: print line
+    if d: print(line)
     writer.writerow(line) 
   fo.close()
 
@@ -333,7 +335,7 @@ def remove_duplicates(vglist,key):
     val = row[key]
     if val in values:
       # duplicate!
-      print "**Found duplicate: "+row
+      print("**Found duplicate: "+row)
     else:
       new_list.append(row)
       values.append(row[key])
@@ -358,7 +360,7 @@ def check_complete(vglist):
     l = row.values()
     for field in l:
       if (field == ""):
-        print "** Warning: Signals list contains incomplete fields!"
+        print("** Warning: Signals list contains incomplete fields!")
         return False 
   return True
 
@@ -370,6 +372,10 @@ def check_keys_exist(vglist,my_keys):
   """
   for d in vglist:
     if not all(key in d for key in my_keys): 
+      print("Key ERROR")
+      for key in d:
+        print(key)
+      print(vglist)
       return False
   return True
 
@@ -389,7 +395,7 @@ def test():
   """
 
   # TODO test of the verilog module reading function
-  print get_verilog_module_signals('../TOP.sv',debug=True)
+  print(get_verilog_module_signals('../TOP.sv',debug=True))
   
   # Test reading in a list from a CSV file
   myvglist = read_csv('test.csv')
@@ -403,9 +409,9 @@ def test():
   #  print x["that"]
 
   # Test check keys
-  print check_keys(myvglist,['this'])
-  print check_keys(myvglist,['this','that'])
-  print check_keys(myvglist,['this','that','other'])
+  print(check_keys(myvglist,['this']))
+  print(check_keys(myvglist,['this','that']))
+  print(check_keys(myvglist,['this','that','other']))
   
   # Test appending to CSV file
   append_csv('test.csv',[{'this':'blah','that':'blaf'}],['this','that'])
diff --git a/tools/vgen/examples/pads/vgen_pads.py b/tools/vgen/examples/pads/vgen_pads.py
index 39b73f8470b32c8830d2eb865c3c5237403d1837..ed856770c9938b76f26b083a8f142997539cdf66 100755
--- a/tools/vgen/examples/pads/vgen_pads.py
+++ b/tools/vgen/examples/pads/vgen_pads.py
@@ -17,7 +17,7 @@ import os;
 import sys;
 import argparse;
 
-from vgen import *;
+from CHIPKIT.tools.vgen.bin.vgen import *;
 
 
 # This is the minimum set of keys required for generating Verilog
diff --git a/tools/vgen/examples/registers/vgen_regs.py b/tools/vgen/examples/registers/vgen_regs.py
index fd4e2373fc5f820d034d72391b7de82de384c781..3dbb65aef978c7d0b66b69fc873043b2bf405d26 100755
--- a/tools/vgen/examples/registers/vgen_regs.py
+++ b/tools/vgen/examples/registers/vgen_regs.py
@@ -12,7 +12,7 @@ import os;
 import sys;
 import argparse;
 
-from vgen import *;
+from CHIPKIT.tools.vgen.bin.vgen import *;
 
 
 # This is the minimum set of keys required for generation.
@@ -49,7 +49,7 @@ def update_regs_csv_from_verilog(csv_file,verilog_file,match_prefix=''):
   Return True if any new signals were added to csv.
   """
   # Read in list of io signals from CSV file
-  print '** Reading csv_file: %s, and Verilog file: %s' % (csv_file,verilog_file)
+  print('** Reading csv_file: %s, and Verilog file: %s' % (csv_file,verilog_file))
   csv_vglist = read_csv(csv_file)
   check_keys_exist(csv_vglist,regs_keys)
 
@@ -62,18 +62,18 @@ def update_regs_csv_from_verilog(csv_file,verilog_file,match_prefix=''):
  
   # debug
   if (True):
-    print 'csv_vglist: '+str([d['name'] for d in csv_vglist])
-    print 'verilog_vglist: '+str([d['name'] for d in verilog_vglist])
+    print('csv_vglist: '+str([d['name'] for d in csv_vglist]))
+    print('verilog_vglist: '+str([d['name'] for d in verilog_vglist]))
 
   # Compare the two lists, keep signals that are in CSV and not in Verilog
   missing_in_verilog = find_new(verilog_vglist,csv_vglist,'name')
   if len(missing_in_verilog) > 0:
-    print 'WARNING: Found signals in CSV (%s) not in Verilog (%s): \n%s' % (csv_file,verilog_file,str([d['name'] for d in missing_in_verilog]))
+    print('WARNING: Found signals in CSV (%s) not in Verilog (%s): \n%s' % (csv_file,verilog_file,str([d['name'] for d in missing_in_verilog])))
 
   # Write any new signals from Verilog back to the CSV.
   if new_in_verilog != []: 
-    print 'Found new signals in Verilog file (not listed in CSV):\n %s' % str([d['name'] for d in new_in_verilog])
-    print 'Updating CSV file: %s' % csv_file
+    print('Found new signals in Verilog file (not listed in CSV):\n %s' % str([d['name'] for d in new_in_verilog]))
+    print('Updating CSV file: %s' % csv_file)
     append_csv(csv_file,new_in_verilog,regs_keys,unused_str='')
 
   # Return true if new signals were added to FE csv
@@ -110,8 +110,8 @@ def gen_regs_module(module_name,module_file,template_file,regs):
   # Open output file 
   if (os.path.isfile(module_file)):                   # if verilog already exists, backup first
     shutil.copy2(module_file,module_file+".bak")      # copy2 preserves mod/access info
-  fo = open(module_file,"wb")
-  print "**Writing module \""+module_name+"\" to file \""+fo.name+"\""
+  fo = open(module_file,"w")
+  print("**Writing module \""+module_name+"\" to file \""+fo.name+"\"")
   fo.write(banner_start())
 
   # Print some header info into the generated file
@@ -198,7 +198,7 @@ def gen_regs_instance(module_name,instance_file,regs,clock='?clk',reset='?rstn')
   """ Generate an instantiation template for the register module """
 
   fo = open(instance_file,"w")
-  print "**Writing module instantiation template to file \""+fo.name+"\""
+  print("**Writing module instantiation template to file \""+fo.name+"\"")
   fo.write(banner_start())
 
   # list of signals
@@ -246,7 +246,7 @@ def gen_regs_docs(module_name,md_file,regs):
   """ Generate markdown documentation for the register module """
 
   fo = open(md_file,"w")
-  print "**Writing module documentation to markdown file \""+fo.name+"\""
+  print("**Writing module documentation to markdown file \""+fo.name+"\"")
   fo.write(banner_start())
   
   # Title for the documentation
@@ -296,7 +296,7 @@ def gen_regs_cheader(module_name,cheader_file,regs):
   """ Generate C header with definitions for the register module """
 
   fo = open(cheader_file,"w")
-  print "**Writing register map to C header file \""+fo.name+"\""
+  print("**Writing register map to C header file \""+fo.name+"\"")
   
   # comment line and header guards
   fo.write(banner_start()) 
@@ -356,7 +356,7 @@ def gen_regs_python(module_name,output_file,regs):
   """ Generate Python module with dictionary containing definitions for the register module """
 
   fo = open(output_file,"w")
-  print "**Writing register map dictionary to python module \""+fo.name+"\""
+  print("**Writing register map dictionary to python module \""+fo.name+"\"")
   
   # comment line and header guards
   fo.write("# "+banner_start())
@@ -404,7 +404,7 @@ def gen_regs_ctest(module_name,output_file,regs):
  
   # Write a header for the test
   fo = open(output_file[0],"w")
-  print "**Writing C test header (.h) file \""+fo.name+"\""
+  print("**Writing C test header (.h) file \""+fo.name+"\"")
   
   # comment line and header guards
   fo.write(banner_start()) 
@@ -439,7 +439,7 @@ def gen_regs_ctest(module_name,output_file,regs):
 
   # Write out the c code for the test
   fo = open(output_file[1],"w")
-  print "**Writing C test (.c) file \""+fo.name+"\""
+  print("**Writing C test (.c) file \""+fo.name+"\"")
   fo.write(banner_end())
 
   # include the header
@@ -528,7 +528,7 @@ def main():
   args = parser.parse_args()
   if not (args.generate or args.update):
     parser.error('No action specified.  Please specify an action: --update or --generate')
-  print 'Command line arguments: %s' + str(args)
+  print('Command line arguments: %s' + str(args))
 
   # Run scripts
   
@@ -538,14 +538,14 @@ def main():
   if (args.generate):
     # Module name is derived from the CSV filename
     module = args.generate.split('.')[0]
-    print module
+    print(module)
     outdir = args.output
 
     # Read in the register list
     regs = read_csv(args.generate,debug=True)
 
     # generate verilog
-    gen_regs_module(module,outdir+'/'+module+'.sv','regs_template.sv',regs)
+    gen_regs_module(module,outdir+'/'+module+'.sv',os.path.dirname(__file__)+'/regs_template.sv',regs)
     gen_regs_instance(module,outdir+'/'+module+'.inst.sv',regs,clock=args.clock,reset=args.reset)
     gen_regs_docs(module,outdir+'/'+module+'.md',regs)
     gen_regs_python(module,outdir+'/'+module+'.py',regs)