diff --git a/flow/vgen_apb_regs b/flow/vgen_apb_regs
new file mode 100755
index 0000000000000000000000000000000000000000..85dfdd410eca09297c919b1fbcac0267cd46cac3
--- /dev/null
+++ b/flow/vgen_apb_regs
@@ -0,0 +1,16 @@
+#-----------------------------------------------------------------------------
+# SoC Labs Register Generation 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  2022, SoC Labs (www.soclabs.org)
+#-----------------------------------------------------------------------------
+
+#!/usr/bin/env bash
+
+mkdir -p $1
+# TODO: Choose a template for verilog
+python3 $CHIPKIT_DIR/tools/vgen/examples/registers/vgen_regs.py --generate $1.csv --clock pclk --reset presetn --output $1
\ No newline at end of file
diff --git a/flow/vgen_regs b/flow/vgen_regs
new file mode 100755
index 0000000000000000000000000000000000000000..406e0db4b09f6bd613e205db899dab8d6d08ec92
--- /dev/null
+++ b/flow/vgen_regs
@@ -0,0 +1,15 @@
+#-----------------------------------------------------------------------------
+# SoC Labs Register Generation 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  2022, SoC Labs (www.soclabs.org)
+#-----------------------------------------------------------------------------
+
+#!/usr/bin/env bash
+
+mkdir -p $1
+python3 $CHIPKIT_DIR/tools/vgen/examples/registers/vgen_regs.py --generate $1.csv --clock pclk --reset presetn --output $1
\ No newline at end of file
diff --git a/ip/apb/apb3_target_interface.sv b/ip/apb/apb3_target_interface.sv
new file mode 100644
index 0000000000000000000000000000000000000000..b5630fe6e26b98a272961d5232d70184c1bd7fcf
--- /dev/null
+++ b/ip/apb/apb3_target_interface.sv
@@ -0,0 +1,104 @@
+//-----------------------------------------------------------------------------
+// The confidential and proprietary information contained in this file may
+// only be used by a person authorised under and to the extent permitted
+// by a subsisting licensing agreement from Arm Limited or its affiliates.
+//
+//            (C) COPYRIGHT 2010-2011 Arm Limited or its affiliates.
+//                ALL RIGHTS RESERVED
+//
+// This entire notice must be reproduced on all copies of this file
+// and copies of this file may only be made by a person if such person is
+// permitted to do so under the terms of a subsisting license agreement
+// from Arm Limited or its affiliates.
+//
+//      SVN Information
+//
+//      Checked In          : $Date: 2017-10-10 15:55:38 +0100 (Tue, 10 Oct 2017) $
+//
+//      Revision            : $Revision: 371321 $
+//
+//      Release Information : Cortex-M System Design Kit-r1p1-00rel0
+//
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Abstract : AMBA APB3 example Target interface module.
+//            Convert APB BUS protocol to simple register read write protocol
+//-----------------------------------------------------------------------------
+module apb3_target_interface #(
+  // parameter for address width
+  parameter ADDRWIDTH = 12)
+ (
+  // IO declaration
+
+  input  wire                    pclk,     // pclk
+  input  wire                    presetn,  // reset
+
+  // apb interface inputs
+  input  wire                    psel,
+  input  wire [ADDRWIDTH-1:0]    paddr,
+  input  wire                    penable,
+  input  wire                    pwrite,
+  input  wire [31:0]             pwdata,
+
+  // apb interface outputs
+  output wire [31:0]             prdata,
+  output wire                    pready,
+  output wire                    pslverr,
+
+  // Data register read/write interface
+  output wire [ADDRWIDTH-1:0]    addr,
+  output wire                    read_en,
+  output wire                    write_en,
+  output wire [31:0]             wdata,
+  input  wire [31:0]             rdata
+ );
+
+ //------------------------------------------------------------------------------
+ // module logic start
+ //------------------------------------------------------------------------------
+
+// APB interface
+assign   pready  = 1'b1; //always ready. Can be customized to support waitstate if required.
+assign   pslverr = 1'b0; //always OKAY. Can be customized to support error response if required.
+
+
+// register read and write signal
+assign  addr = paddr;
+assign  read_en  = psel & (~pwrite); // assert for whole apb read transfer
+assign  write_en = psel & (~penable) & pwrite; // assert for 1st cycle of write transfer
+        // It is also possible to change the design to perform the write in the 2nd
+        // APB cycle.   E.g.
+        //   assign write_en = psel & penable & pwrite;
+        // However, if the design generate waitstate, this expression will result
+        // in write_en being asserted for multiple cycles.
+assign  wdata       = pwdata;
+assign  prdata      = rdata;
+
+
+`ifdef ARM_APB_ASSERT_ON
+
+ `include "std_ovl_defines.h"
+  // ------------------------------------------------------------
+  // Assertions
+  // ------------------------------------------------------------
+
+  // Check error response should not be generated if not selected
+    assert_never
+     #(`OVL_ERROR,
+       `OVL_ASSERT,
+       "Error! Should not generate error response if not selected")
+     u_ovl_apb3_eg_slave_response_illegal
+     (.clk        (pclk),
+      .reset_n    (presetn),
+      .test_expr  (pslverr & pready & (~psel))
+      );
+
+`endif
+
+ //------------------------------------------------------------------------------
+ // module logic end
+ //------------------------------------------------------------------------------
+
+endmodule
+
+
diff --git a/tools/vgen/examples/registers/regs_apb.tmpl.sv b/tools/vgen/examples/registers/regs_apb.tmpl.sv
new file mode 100644
index 0000000000000000000000000000000000000000..22fbe3828b1f7ab8cf9d1daf2f7ff2ccaba1dd1d
--- /dev/null
+++ b/tools/vgen/examples/registers/regs_apb.tmpl.sv
@@ -0,0 +1,103 @@
+//-----------------------------------------------------------------------------
+// SoC Labs APB register Template
+// 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)
+//-----------------------------------------------------------------------------
+// VGEN: HEADER 
+// VGEN: MODULE NAME
+(
+// clocks and resets
+  input logic     clk,           
+  input logic     rstn,
+
+// APB inteface
+  input logic psel,
+	input logic [ADDRWIDTH:0] paddr,
+	input logic penable,
+	input logic pwrite,
+	input logic [31:0] pwdata,
+
+	output logic [31:0] prdata,
+	output logic pready,
+	output logic pslverr,
+
+// VGEN: INPUTS TO REGS
+
+
+// VGEN: OUTPUTS FROM REGS
+
+
+);
+
+//------------------------------------------------------------------------------
+// APB Interface
+//------------------------------------------------------------------------------
+
+logic [ADDRWIDTH-1:0]    addr;
+logic                    read_en;
+logic                    write_en;
+logic [31:0]             wdata;
+logic [31:0]             rdata;
+
+// APB interface
+assign   pready  = 1'b1; //always ready. Can be customized to support waitstate if required.
+assign   pslverr = 1'b0; //always OKAY. Can be customized to support error response if required.
+
+
+// register read and write signal
+assign  addr = paddr;
+assign  read_en  = psel & (~pwrite); // assert for whole apb read transfer
+assign  write_en = psel & (~penable) & pwrite; // assert for 1st cycle of write transfer
+        // It is also possible to change the design to perform the write in the 2nd
+        // APB cycle.   E.g.
+        //   assign write_en = psel & penable & pwrite;
+        // However, if the design generate waitstate, this expression will result
+        // in write_en being asserted for multiple cycles.
+assign  wdata       = pwdata;
+assign  prdata      = rdata;
+
+//------------------------------------------------------------------------------
+// Regsiter write
+//------------------------------------------------------------------------------
+
+// VGEN: REG WRITE
+
+
+//------------------------------------------------------------------------------
+// Regsiter read
+//------------------------------------------------------------------------------
+
+
+logic [31:0] rdata_o;
+
+always @*
+begin
+  if (read_en)
+  begin
+    rdata_o[31:0] = 32'h00000000;
+
+    // VGEN: REG READ
+
+  end
+  else 
+  begin
+    rdata_o[31:0] = {32'h00000000};
+  end	
+end
+
+assign rdata[31:0] = rdata_o[31:0];
+
+
+//------------------------------------------------------------------------------
+// 
+//------------------------------------------------------------------------------
+
+
+
+
+endmodule
diff --git a/tools/vgen/examples/registers/vgen_regs.py b/tools/vgen/examples/registers/vgen_regs.py
index 3dbb65aef978c7d0b66b69fc873043b2bf405d26..06fc0b148cf9f7cca4d7dfe581369e819de13cfc 100755
--- a/tools/vgen/examples/registers/vgen_regs.py
+++ b/tools/vgen/examples/registers/vgen_regs.py
@@ -11,6 +11,7 @@ import shutil;
 import os;
 import sys;
 import argparse;
+from enum import Enum
 
 from CHIPKIT.tools.vgen.bin.vgen import *;
 
@@ -26,6 +27,43 @@ regs_keys = [
   'rval'
   ]
 
+class Port_direction(Enum):
+  INPUT  = 1
+  OUTPUT = 2
+
+class Port():
+  def __init__(self,name,width,direction):
+    self.name      = name
+    self.width     = width
+    self.direction = direction
+
+class Interface():
+  def __init__(self,ports):
+    self.ports = ports
+
+ADDRW = 12
+
+apb_psel    = Port("psel",      1, Port_direction.INPUT)
+apb_paddr   = Port("paddr", ADDRW, Port_direction.INPUT)
+apb_penable = Port("penable",   1, Port_direction.INPUT)
+apb_pwrite  = Port("pwrite",    1, Port_direction.INPUT)
+apb_pwdata  = Port("pwdata",   32, Port_direction.INPUT)
+
+apb_prdata  = Port("prdata",   32, Port_direction.OUTPUT)
+apb_pready  = Port("pready",    1, Port_direction.OUTPUT)
+apb_pslverr = Port("pslverr",   1, Port_direction.OUTPUT)
+
+apb_inf = Interface([
+  apb_psel,   
+  apb_paddr,  
+  apb_penable,
+  apb_pwrite, 
+  apb_pwdata, 
+  apb_prdata, 
+  apb_pready,
+  apb_pslverr
+])
+    
 # TODO
 # Update command line arg parsing - setup the same as pads version.
 # Might make sense to put the command line arg parsing into vgen.py?
@@ -88,7 +126,7 @@ def update_regs_csv_from_verilog(csv_file,verilog_file,match_prefix=''):
 ###############################################################################
 
 
-def gen_regs_module(module_name,module_file,template_file,regs):
+def gen_regs_module(module_name,module_file,template_file,regs,ext_inf=apb_inf):
   """ Generate a CSR module from a template file and a signal list """
 
   # Check the required keys are present (others will be ignored)
@@ -128,13 +166,27 @@ def gen_regs_module(module_name,module_file,template_file,regs):
 
   # Module name
   fo.write(read_to_tag(fi_template,"VGEN: MODULE NAME"))
-  fo.write(module_name+"\n")
+  fo.write("module "+module_name+" ")
   
+  # # Interface
+  # fo.write(read_to_tag(fi_template,"VGEN: EXTERNAL INTERFACE"))
+  # for port in ext_inf.ports:
+  #   if port.direction == Port_direction.INPUT:
+  #     fo.write("\tinput logic ")
+  #   elif port.direction == Port_direction.OUTPUT:
+  #     fo.write("\toutput logic ")
+    
+  #   if port.width > 1:
+  #     fo.write(f"[{port.width-1}:0] ")
+    
+  #   fo.write(port.name + ",\n")
+      
+
   # Port list inputs
   fo.write(read_to_tag(fi_template,"VGEN: INPUTS TO REGS"))
   for n, row in enumerate(regs):
     if (row['access'] == "r"):
-      l = "input  logic "+reg_dims(row)+" "+row['name']+",\t"
+      l = "\tinput logic "+reg_dims(row)+" "+row['name']+",\t"
       l += "/* idx #"+str(n)+": "+row['desc']+" */" + "\n"
       fo.write(l)
   
@@ -148,9 +200,11 @@ def gen_regs_module(module_name,module_file,template_file,regs):
         first = False
       else:
         l += ",\n"
-      l += "output logic " + reg_dims(row) + " " + row['name'] + "\t"
+      l += "\toutput logic " + reg_dims(row) + " " + row['name'] + "\t"
       l += " /* idx #"+str(n)+": "+row['desc']+" */"
       fo.write(l)
+  
+  #
  
   # Register write 
   fo.write(read_to_tag(fi_template,"VGEN: REG WRITE"))
@@ -166,8 +220,8 @@ def gen_regs_module(module_name,module_file,template_file,regs):
       else:   # TODO really should get the correct number of digits for the reset value
         l += " <= " + row['nbits'] + "\'h" + row['rval'].rsplit("0x")[1] + ";\n"
       l += "  end else begin\n"
-      l += "    if(regbus.write_en & (regbus.addr[9:2]==8'h"+(hex(int(row['idx'])).lstrip("0x") or "0")+")) "
-      l += row['name'] + "_reg" + reg_dims(row) + " <= regbus.wdata" + reg_dims(row)
+      l += "    if(write_en & (addr[9:2]==8'h"+(hex(int(row['idx'])).lstrip("0x") or "0")+")) "
+      l += row['name'] + "_reg" + reg_dims(row) + " <= wdata" + reg_dims(row)
       l += ";\n  end\nend\n"
       l += "assign "+row['name']+reg_dims(row)+" = "+row['name']+"_reg"+reg_dims(row)+";\n\n"
       fo.write(l)
@@ -175,7 +229,7 @@ def gen_regs_module(module_name,module_file,template_file,regs):
   # Register read
   fo.write(read_to_tag(fi_template,"VGEN: REG READ"))
   for n, row in enumerate(regs):
-    l = "    if(regbus.addr[9:2]==8'h"+(hex(int(row['idx'])).lstrip("0x") or "0")+") "
+    l = "    if(addr[9:2]==8'h"+(hex(int(row['idx'])).lstrip("0x") or "0")+") "
     l += l + "rdata_o"+reg_dims(row)+" = "+row['name']+reg_dims(row)+";\t"
     l = l +" // idx #"+str(n)+"\n"
     fo.write(l)
@@ -537,15 +591,15 @@ def main():
  
   if (args.generate):
     # Module name is derived from the CSV filename
-    module = args.generate.split('.')[0]
-    print(module)
+    module = os.path.basename(args.generate.split('.')[0])
+    print("module is "+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',os.path.dirname(__file__)+'/regs_template.sv',regs)
+    gen_regs_module(module,outdir+'/'+module+'.sv',os.path.dirname(__file__)+'/regs_apb.tmpl.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)