diff --git a/fpga/ci_tools/drivers/ADP_PYNQ_driver.py b/fpga/ci_tools/drivers/ADP_PYNQ_driver.py
new file mode 100644
index 0000000000000000000000000000000000000000..256e7493c96c2d674cb8778597684d6f4b499b41
--- /dev/null
+++ b/fpga/ci_tools/drivers/ADP_PYNQ_driver.py
@@ -0,0 +1,112 @@
+from time import sleep, time
+from pynq import MMIO
+
+class ADP:
+    def __init__(self, address):
+        # HARDWARE CONSTANTS
+        self.RX_FIFO = 0x00
+        self.TX_FIFO = 0x04
+        # Status Reg
+        self.STAT_REG = 0x08
+        self.RX_VALID = 0
+        self.RX_FULL = 1
+        self.TX_EMPTY = 2
+        self.TX_FULL = 3
+        self.IS_INTR = 4
+
+        # Ctrl Reg
+        self.CTRL_REG = 0x0C
+        self.RST_TX = 0
+        self.RST_RX = 1
+        self.INTR_EN = 4
+        # Setup axi core
+        self.uart = MMIO(address, 0x10000, debug=False)
+        self.address = address
+
+    def setupCtrlReg(self):
+#        # Reset FIFOs, disable interrupts
+#        self.uart.write(CTRL_REG, 1 << RST_TX | 1 << RST_RX)
+#        sleep(1)
+        self.uart.write(self.CTRL_REG, 0)
+        sleep(1)
+
+    def monitorModeEnter(self):
+        self.uart.write(self.TX_FIFO, 0x1b)
+
+    def monitorModeExit(self):
+        self.uart.write(self.TX_FIFO, 0x04)
+
+    ##################################################################
+    # read: Read a block from the Rx FIFO
+    ##################################################################
+    def read(self, length):
+        # status = currentStatus(uart) bad idea
+        buf = ""
+        timeout=1
+        stop_time = time() + timeout
+        for i in range(length):
+            # Wait till RX fifo has valid data, stop waiting if timeoutpasses
+            while (not (self.uart.read(self.STAT_REG) & 1 << self.RX_VALID)) and (time() < stop_time):
+                pass
+            if time() >= stop_time:
+                break
+            buf += chr(self.uart.read(self.RX_FIFO))
+            stop_time = time() + timeout
+
+        return buf
+
+    ##################################################################
+    # write: Write a block of data to the Tx FIFO
+    ##################################################################
+    def write(self, buf):
+        # Write bytes via UART
+        timeout=1
+        stop_time = time() + timeout
+        wr_count = 0
+        for i in buf:
+            # Wait while TX FIFO is Full, stop waiting if timeout passes
+            while (self.uart.read(self.STAT_REG) & 1 << self.TX_FULL) and (time() < stop_time):
+                pass
+            # Check timeout
+            if time() > stop_time:
+                wr_count = -1
+                break
+            self.uart.write(self.TX_FIFO, ord(i))
+            wr_count += 1
+            stop_time = time() + timeout
+        return wr_count
+    ##################################################################
+    # readLine: Read a block from the Rx FIFO until newline character
+    ##################################################################
+    def readLine(self):
+        buf = ""
+        timeout = 1
+        stop_time = time() + timeout
+        stop=False
+        while(not(stop)):
+            while(not(self.checkReg(self.STAT_REG) & 1 << self.RX_VALID) and (time() < stop_time)):
+                pass
+            if time() > stop_time:
+                break
+            next_chr = chr(self.uart.read(self.RX_FIFO))
+            buf += next_chr
+            stop_time = time() + timeout
+            if (next_chr == '\n'):
+                stop = True
+        return buf
+    def write8(self, buf):
+        # Write bytes via UART
+        timeout=1
+        stop_time = time() + timeout
+        wr_count = 0
+        while (self.uart.read(self.STAT_REG) & 1 << self.TX_FULL) and (time() < stop_time):
+            pass
+        # Check timeout
+        if time() > stop_time:
+            wr_count = -1
+        self.uart.write(self.TX_FIFO, buf)
+        wr_count += 1
+        stop_time = time() + timeout
+        return wr_count
+    
+    
\ No newline at end of file
diff --git a/fpga/ci_tools/drivers/NanoSoC_Verification.py b/fpga/ci_tools/drivers/NanoSoC_Verification.py
index a43f1c1e9ab179924ae3b248d99d52173caa70d3..29afdf91f23312614406f02a77857e62235e8df9 100644
--- a/fpga/ci_tools/drivers/NanoSoC_Verification.py
+++ b/fpga/ci_tools/drivers/NanoSoC_Verification.py
@@ -1,7 +1,9 @@
 import os, sys
 from progress.bar import Bar
-if os.environ["BOARDNAME"] == 'MPS3':
+if os.environ["BOARD"] == 'MPS3':
     from .ADP_UART_driver import ADP
+elif os.environ["BOARD"] == "ZCU104":
+    from .ADP_PYNQ_driver import ADP
 
 class NanoSoC_APD:
     def __init__(self):
diff --git a/fpga/ci_tools/load_bitfile.py b/fpga/ci_tools/load_bitfile.py
index 2e4c01a48344380b10f20a087b6af8f293a00971..ca86e9ddabb27fc079e78655e960622f5228efde 100644
--- a/fpga/ci_tools/load_bitfile.py
+++ b/fpga/ci_tools/load_bitfile.py
@@ -2,7 +2,7 @@ import os, warnings
 from pynq import PL
 from pynq import Overlay
 
-ol = Overlay("/home/xilinx/pynq/overlays/soclabs/design_1.bit")
+ol = Overlay("/home/xilinx/pynq/overlays/soclabs/nanosoc_design.bit")
 
 if not os.path.exists(PL.bitfile_name):
     warnings.warn('There is no overlay loaded after boot.', UserWarning)
diff --git a/fpga/ci_tools/romtable_test.py b/fpga/ci_tools/romtable_test.py
index b4b98575a0ac3d74ae64e7cf1f83752fc9b7c8df..852cccef59ecd99fad5aceb8125bea509b4cc4ba 100644
--- a/fpga/ci_tools/romtable_test.py
+++ b/fpga/ci_tools/romtable_test.py
@@ -4,7 +4,7 @@ from drivers.NanoSoC_Verification import NanoSoC_APD
 
 
 NanoSoC = NanoSoC_APD()
-NanoSoC.writeHex('uart_tests.hex')
+NanoSoC.writeHex('binaries/uart_tests.hex')
 print(NanoSoC.adp.read(500))
 NanoSoC.adp.write('C 0x200\n')
 NanoSoC.adp.write('C 0x201\n')
diff --git a/fpga/ci_tools/run_full_verification.py b/fpga/ci_tools/run_full_verification.py
index ad1403940945f48fed62da82041303bd004720bc..b61928c1a73738a8aa373c0052b69ef3b6a1ca2c 100644
--- a/fpga/ci_tools/run_full_verification.py
+++ b/fpga/ci_tools/run_full_verification.py
@@ -1,8 +1,12 @@
 import os, warnings
 from pynq import PL
 from pynq import Overlay
+import os
+from drivers.NanoSoC_Verification import NanoSoC_APD
 
-ol = Overlay("/home/xilinx/pynq/overlays/soclabs/design_1.bit")
+log = open("verification_log",'w')
+tests = open("fpga_tests",'r')
+ol = Overlay("/home/xilinx/pynq/overlays/soclabs/nanosoc_design.bit")
 
 if not os.path.exists(PL.bitfile_name):
     warnings.warn('There is no overlay loaded after boot.', UserWarning)
@@ -13,7 +17,34 @@ ol.download()
 
 if ol.is_loaded():
 	print("Overlay Loaded")
+	log.write("Overlay Load Test: PASSED\n")
+	NanoSoC = NanoSoC_APD()
+	for lines in tests:
+		ol.download()
+		NanoSoC = NanoSoC_APD()
+		li=lines.strip()
+		li=li.lstrip('nanosoc_tech/testcodes/')
+		li = li.split('/')
+		testname = li[0]
+		testfile = li[1]
+		print("Running test: " + testfile)
+		NanoSoC.writeHex("binaries/" + testfile)
+		print(NanoSoC.adp.read(500))
+		NanoSoC.adp.write('C 0x200\n')
+		NanoSoC.adp.write('C 0x201\n')
+		buf = (NanoSoC.adp.read(1000000))
+		print(buf)
+		if "PASSED" in buf:
+			log.write(testfile + ": PASSED\n")
+		elif "SKIPPED" in buf:
+			log.write(testfile + ": SKIPPED\n")
+		else:
+			log.write(testfile + ": FAILED\n")
 else:
 	print("Overlay failed to load")
+	log.write("Overlay Load Test: FAILED\n")
+print("ALL TESTS FINISHED")
+log.close()
+
 
 
diff --git a/nanosoc/nanosoc_subsystems/dma/verilog/nanosoc_ss_dma.v b/nanosoc/nanosoc_subsystems/dma/verilog/nanosoc_ss_dma.v
index 213521fe0ce57a0ae6c71a00aacf7dd0cc4a74f0..f30a4655697333a882a2457f8e473a3678bc07e7 100644
--- a/nanosoc/nanosoc_subsystems/dma/verilog/nanosoc_ss_dma.v
+++ b/nanosoc/nanosoc_subsystems/dma/verilog/nanosoc_ss_dma.v
@@ -9,6 +9,7 @@
 //
 // Copyright 2021-3, SoC Labs (www.soclabs.org)
 //-----------------------------------------------------------------------------
+`include "gen_defines.v"
 
 module nanosoc_ss_dma #(
     parameter    SYS_ADDR_W         = 32,  // System Address Width
diff --git a/software/common/demos/watchdog_demo.c b/software/common/demos/watchdog_demo.c
index 3dcf0a60fd8c5e5491f2ac3d273ed64f2d78c168..817847da8e7bba790a54e899a4730e48dafd8df0 100644
--- a/software/common/demos/watchdog_demo.c
+++ b/software/common/demos/watchdog_demo.c
@@ -308,21 +308,22 @@ void NMI_Handler(void)
 /* Watchdog initialization */
 void watchdog_init(unsigned int cycle, int type)
 {
-  puts   ("  Unlocking watchdog...");
+  //puts   ("  Unlocking watchdog...");
   watchdog_unlock();
   CMSDK_WATCHDOG->LOAD = cycle;
   if (type==0) {
-    puts   ("  Set to no action");
+    //puts   ("  Set to no action");
     CMSDK_WATCHDOG->CTRL = 0;
   } else if (type==1) {
-    puts   ("  Set to NMI generation");
+    //puts   ("  Set to NMI generation");
     CMSDK_WATCHDOG->CTRL = CMSDK_Watchdog_CTRL_INTEN_Msk;
   } else {
-    puts   ("  Set to reset generation");
+    //puts   ("  Set to reset generation");
     CMSDK_WATCHDOG->CTRL = CMSDK_Watchdog_CTRL_RESEN_Msk|CMSDK_Watchdog_CTRL_INTEN_Msk;
   }
-  puts   ("  Locking watchdog...");
   watchdog_lock();
+  //puts   ("  Locking watchdog...");
+
 }
 /* ----------------------------------------------------------------- */
 /* Update watchdog counter */