diff --git a/Cortex-M0/nanosoc/software/common/validation/dma_tests.c b/Cortex-M0/nanosoc/software/common/validation/dma_tests.c
index 88e15676ed949e56318f45d6734bb925a0f48a8a..05febb20b47b6815e6bd66adaf78f25f836c7be9 100644
--- a/Cortex-M0/nanosoc/software/common/validation/dma_tests.c
+++ b/Cortex-M0/nanosoc/software/common/validation/dma_tests.c
@@ -67,7 +67,8 @@ void delay(void);
                               /* Maximum to 32 DMA channel */
 #define MAX_NUM_OF_DMA_CHANNELS   32
                               /* SRAM in example system is 64K bytes */
-#define RAM_ADDRESS_MAX       0x3000FFFF
+//#define RAM_ADDRESS_MAX       0x3000FFFF
+#define RAM_ADDRESS_MAX       0x80000FFF
 
 typedef struct /* 4 words */
 {
@@ -110,7 +111,6 @@ int main (void)
   dma_error_irq_occurred = 0;
   dma_data_struct_init();
   dma_pl230_init();
-
   result += dma_simple_test();
   result += dma_interrupt_test();
   result += dma_event_test();
@@ -197,7 +197,8 @@ void dma_data_struct_init(void)
   so we can use this space for putting the DMA data structure.
   */
 
-  ptr     = HW32_REG(0);                     /* Read Top of Stack */
+//  ptr     = HW32_REG(0);                     /* Read Top of Stack */
+  ptr     = 0x80000000;              /* DMA memory bank */
 
   /* the DMA data structure must be aligned to the size of the data structure */
   if ((ptr & blkmask) != 0x0)
diff --git a/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz104/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb b/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz104/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb
new file mode 100755
index 0000000000000000000000000000000000000000..8d000a3dbe36d61a466f5a08c27024291f9fa407
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz104/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb
@@ -0,0 +1,924 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# nanosoc ADP io test\n",
+    "\n",
+    "This notebook demonstrates how to download an FPGA overlay and examine programmable logic state.  \n",
+    "\n",
+    "## 1. Setting up and checking the overlay\n",
+    "With the following overlay bundle present in the `overlays` folder, users can instantiate the overlay easily.\n",
+    "\n",
+    "*  A bitstream file (\\*.bit).\n",
+    "*  An hwh file (\\*.hwh).\n",
+    "*  A python class (\\*.py).\n",
+    "\n",
+    "For example, an overlay called `base` can be loaded by:\n",
+    "```python\n",
+    "from pynq.overlays.base import BaseOverlay\n",
+    "overlay = BaseOverlay(\"base.bit\")\n",
+    "```\n",
+    "Users can also use the absolute file path of the bitstream to instantiate the overlay.\n",
+    "\n",
+    "In this notebook, we get the current bitstream loaded on PL, and try to download it multiple times."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "\n",
+       "try {\n",
+       "require(['notebook/js/codecell'], function(codecell) {\n",
+       "  codecell.CodeCell.options_default.highlight_modes[\n",
+       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
+       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
+       "      Jupyter.notebook.get_cells().map(function(cell){\n",
+       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
+       "  });\n",
+       "});\n",
+       "} catch (e) {};\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/javascript": [
+       "\n",
+       "try {\n",
+       "require(['notebook/js/codecell'], function(codecell) {\n",
+       "  codecell.CodeCell.options_default.highlight_modes[\n",
+       "      'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n",
+       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
+       "      Jupyter.notebook.get_cells().map(function(cell){\n",
+       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
+       "  });\n",
+       "});\n",
+       "} catch (e) {};\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import os, warnings\n",
+    "from pynq import PL\n",
+    "from pynq import Overlay\n",
+    "\n",
+    "ol = Overlay(\"/home/xilinx/pynq/overlays/soclabs/design_1.bit\")\n",
+    "\n",
+    "if not os.path.exists(PL.bitfile_name):\n",
+    "    warnings.warn('There is no overlay loaded after boot.', UserWarning)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Note**: If you see a warning message in the above cell, it means that no overlay\n",
+    "has been loaded after boot, hence the PL server is not aware of the \n",
+    "current status of the PL. In that case you won't be able to run this notebook\n",
+    "until you manually load an overlay at least once using:\n",
+    "\n",
+    "```python\n",
+    "from pynq import Overlay\n",
+    "ol = Overlay('your_overlay.bit')\n",
+    "```\n",
+    "\n",
+    "If you do not see any warning message, you can safely proceed."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ol = Overlay(PL.bitfile_name)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we can check the download timestamp for this overlay."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'2023/3/17 12:2:13 +667853'"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ol.download()\n",
+    "ol.timestamp"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 2. Examining the overlay\n",
+    "Uncomment the #PL.ip_dict command to see the full details"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/home/xilinx/pynq/overlays/soclabs/design_1.bit\n",
+      "2023/3/17 12:2:13 +667853\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(PL.bitfile_name)\n",
+    "print(PL.timestamp)\n",
+    "\n",
+    "#PL.ip_dict"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Interrogate the HWH database for interface addresses"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ADPIO stream interface:  0x80020000\n",
+      "UART(2) interface:  0x80060000\n"
+     ]
+    }
+   ],
+   "source": [
+    "ADP_address = PL.ip_dict['cmsdk_socket/axi_stream_io_0']['phys_addr']\n",
+    "print(\"ADPIO stream interface: \",hex(ADP_address))\n",
+    "UART2_address = PL.ip_dict['cmsdk_socket/axi_uartlite_0']['phys_addr']\n",
+    "print(\"UART(2) interface: \",hex(UART2_address))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Set up interface functions for ADP"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from pynq import Overlay\n",
+    "from pynq import MMIO\n",
+    "import time\n",
+    "from time import sleep, time\n",
+    "\n",
+    "# HARDWARE CONSTANTS\n",
+    "RX_FIFO = 0x00\n",
+    "TX_FIFO = 0x04\n",
+    "# Status Reg\n",
+    "STAT_REG = 0x08\n",
+    "RX_VALID = 0\n",
+    "RX_FULL = 1\n",
+    "TX_EMPTY = 2\n",
+    "TX_FULL = 3\n",
+    "IS_INTR = 4\n",
+    "\n",
+    "# Ctrl Reg\n",
+    "CTRL_REG = 0x0C\n",
+    "RST_TX = 0\n",
+    "RST_RX = 1\n",
+    "INTR_EN = 4\n",
+    "\n",
+    "class ADPIO:\n",
+    "    def __init__(self, address):\n",
+    "        # Setup axi core\n",
+    "        self.uart = MMIO(address, 0x10000, debug=False)\n",
+    "        self.address = address\n",
+    "\n",
+    "    def setupCtrlReg(self):\n",
+    "#        # Reset FIFOs, disable interrupts\n",
+    "#        self.uart.write(CTRL_REG, 1 << RST_TX | 1 << RST_RX)\n",
+    "#        sleep(1)\n",
+    "        self.uart.write(CTRL_REG, 0)\n",
+    "        sleep(1)\n",
+    "\n",
+    "    def monitorModeEnter(self):\n",
+    "        self.uart.write(TX_FIFO, 0x1b)\n",
+    "\n",
+    "    def monitorModeExit(self):\n",
+    "        self.uart.write(TX_FIFO, 0x04)\n",
+    "\n",
+    "    def read(self, count, timeout=1):\n",
+    "        # status = currentStatus(uart) bad idea\n",
+    "        buf = \"\"\n",
+    "        stop_time = time() + timeout\n",
+    "        for i in range(count):\n",
+    "            # Wait till RX fifo has valid data, stop waiting if timeoutpasses\n",
+    "            while (not (self.uart.read(STAT_REG) & 1 << RX_VALID)) and (time() < stop_time):\n",
+    "                pass\n",
+    "            if time() >= stop_time:\n",
+    "                break\n",
+    "            buf += chr(self.uart.read(RX_FIFO))\n",
+    "        return buf\n",
+    "    \n",
+    "    def write(self, buf, timeout=1):\n",
+    "        # Write bytes via UART\n",
+    "        stop_time = time() + timeout\n",
+    "        wr_count = 0\n",
+    "        for i in buf:\n",
+    "            # Wait while TX FIFO is Full, stop waiting if timeout passes\n",
+    "            while (self.uart.read(STAT_REG) & 1 << TX_FULL) and (time() < stop_time):\n",
+    "                pass\n",
+    "            # Check timeout\n",
+    "            if time() > stop_time:\n",
+    "                wr_count = -1\n",
+    "                break\n",
+    "            self.uart.write(TX_FIFO, ord(i))\n",
+    "            wr_count += 1\n",
+    "        return wr_count\n",
+    "\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Inspect the ADP banner after reset (0x50CLAB03 expected)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      " 0x50c1ab03\n",
+      "\r\n",
+      "\n",
+      "\n",
+      "SOCLABS: ARM Cortex-M0 nanosoc\n",
+      "** Remap->RAM2\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp = ADPIO(ADP_address)\n",
+    "# Setup AXI UART register\n",
+    "adp.setupCtrlReg()\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Enter ADP monitor mode ('ESC' char)\n",
+    "And check the ']' prompt appears"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.monitorModeEnter()\n",
+    "print(adp.read(4))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Also check the UART2 RX channel for any boot message"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "''"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "uart = ADPIO(UART2_address)\n",
+    "# Setup AXI UART register\n",
+    "uart.setupCtrlReg()\n",
+    "uart.read(50)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Demonstrate basic ADP console functionality\n",
+    "\"A\" command with no parameter simply prints current Address pointer\n",
+    "\n",
+    "Here, check adp Address pointer resets to zero"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A\\n')\n",
+    "print(adp.read(100))\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Do a sequence of (4) auto-incrementing 32-bit reads from ROM1 space\n",
+    "\n",
+    " * \"A hexparam\" sets adddress pointer\n",
+    " * \"R hexparam\" performs number of 32-bit reads auto-incementing address pointer"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x10000000\n",
+      "\r",
+      "]R 0x30000368\n",
+      "\r",
+      "R 0x10000335\n",
+      "\r",
+      "R 0x1000033d\n",
+      "\r",
+      "R 0x1000033f\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x10000000\\nR 4\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]R 0x05f5e100\n",
+      "\r",
+      "]R 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nR\\nR \\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Write patterns to RAM3 base\n",
+    "\n",
+    " * \"W hexparam\" writes 32-bit data and auto-increments address pointer"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]W!0x11111111\n",
+      "\r",
+      "]W!0x22222222\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nW 0x11111111\\nW22222222\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Read back the patterns from RAM3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]R 0x05f5e100\n",
+      "\r",
+      "R 0x00000000\n",
+      "\r",
+      "R 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nR 3\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Next try writes to map with bus errors\n",
+    "\n",
+    "  get a \"!\" warning on faulting accesses\n",
+    "  \n",
+    "(0x5xxxxxxx address range is illegal and faults in nanosoc address map)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x50000000\n",
+      "\r",
+      "]W!0x11111111\n",
+      "\r",
+      "]W!0x22222222\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x50000000\\nW 0x11111111\\nW22222222\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x50000000\n",
+      "\r",
+      "]R!0x00000000\n",
+      "\r",
+      "R!0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x50000000\\nR 2\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Poll bus address (no auto-incrment)\n",
+    "\n",
+    " * \"M hexparam\"  sets up MASK pattern to use\n",
+    " * \"V hexparam\"  sets up VALUE of masked pattern to match\n",
+    " * \"P hexparam\"  Poll command reads from address and tests <param> times\n",
+    "\n",
+    " * match when (mem[A] & M) == \"V\"\n",
+    "\n",
+    "Run a poll cammand (indicated '!' for failure to match), followed by a poll with match (and returns the number of poll iteration until matched)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x10000000\n",
+      "]M 0xf0000000\n",
+      "]V 0x00000000\n",
+      "]P!0x00004000\n",
+      "]\n",
+      "A 0x10000000\n",
+      "]M 0xf0000000\n",
+      "]V 0x30000000\n",
+      "]P 0x00000001\n",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 10000000\\nM 0xF0000000\\nV 0\\nP 4000\\n')\n",
+    "print(adp.read(100))\n",
+    "adp.write('A 10000000\\nM\\nV 30000000\\nP 2000\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Fill command - set a pattern value from current base address pointer\n",
+    "\n",
+    " * \"V hexparam\"  sets up VALUE of data pattern to write\n",
+    " * \"F hexparam\"  Fill command writes <param> number of 32-bit words\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x90000000\n",
+      "\r",
+      "]V 0x87654321\n",
+      "\r",
+      "]F 0x00000400\n",
+      "\r",
+      "]A 0x90001000\n",
+      "\r",
+      "]W!0xffffffff\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 90000000\\nV 0x87654321\\nF 400\\nA\\nW FFFFFFFF\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x90000000\n",
+      "]R 0x87654321\n",
+      "R 0x87654321\n",
+      "R 0x87654321\n",
+      "]\n",
+      "A 0x90000ffc\n",
+      "]R 0x87654321\n",
+      "R 0x00000000\n",
+      "R 0x00000000\n",
+      "]?\n",
+      "]A 0x90001008\n",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x90000000\\nR 3\\n')\n",
+    "print(adp.read(100))\n",
+    "adp.write('A 0x90000FFC\\nr 0003\\n\\nA\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "S!0x00000031\n",
+      "\r",
+      "]?\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('S 0x31\\n\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.monitorModeExit()\n",
+    "print(adp.read(100))\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "\n",
+    "## ol.download()\n",
+    "ol.timestamp\n",
+    "ol.reset()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ip_info = {'trace_cntrl':\"ft1248tb_i/ila_0\"}\n",
+    "class pynq.logictools.trace_analyzer.TraceAnalyzer(ip_info)\n",
+    "\n",
+    "                "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#PL.ip_dict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "gpio_0.register_map\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 2. Examining the PL state\n",
+    "\n",
+    "While there can be multiple overlay instances in Python, there is only one bitstream that is currently loaded onto the programmable logic (PL). \n",
+    "\n",
+    "This bitstream state is held in the singleton class, PL, and is available for user queries."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "PL.bitfile_name"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "PL.timestamp\n",
+    "\n",
+    "PL.ip_dict\n",
+    "\n",
+    "leds_address = PL.ip_dict['led_4bits']['phys_addr']\n",
+    "                                               \n",
+    "from pynq import MMIO\n",
+    "mmio_buttons = MMIO(0xa0000000, 16)\n",
+    "help (mmio_buttons)\n",
+    "\n",
+    "#print(hex(mmio_buttons))\n",
+    "#print(hex(mmio_buttons.read(0)))\n",
+    "\n",
+    "hex(pl.ip_dict[\"axi_gpio_1\"][\"phys_addr\"])\n",
+    "\n",
+    "\n",
+    "#buttons_address = ssc_dpram.ip_dict['push_button_4bits']['phys_addr']\n",
+    "#switches_address = ssc_dpram.ip_dict['dip_switch_4bits']['phys_addr']\n",
+    "#leds_address = ssc_dpram.ip_dict['led_4bitss']['phys_addr']"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Users can verify whether an overlay instance is currently loaded using the Overlay is_loaded() method"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ol.is_loaded()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 3. Overlay downloading overhead\n",
+    "\n",
+    "Finally, using Python, we can see the bitstream download time over 50 downloads.  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "import matplotlib.pyplot as plt\n",
+    "\n",
+    "length = 50\n",
+    "time_log = []\n",
+    "for i in range(length):\n",
+    "    start = time.time()\n",
+    "    ol.download()\n",
+    "    end = time.time()\n",
+    "    time_log.append((end-start)*1000)\n",
+    "\n",
+    "%matplotlib inline\n",
+    "plt.plot(range(length), time_log, 'ro')\n",
+    "plt.title('Bitstream loading time (ms)')\n",
+    "plt.axis([0, length, 0, 1000])\n",
+    "plt.show()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.6.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz2/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb b/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz2/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb
new file mode 100755
index 0000000000000000000000000000000000000000..8d000a3dbe36d61a466f5a08c27024291f9fa407
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/fpga_imp/pynq_export/pz2/jupyter_notebooks/soclabs/nanosoc-ADPtest.ipynb
@@ -0,0 +1,924 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# nanosoc ADP io test\n",
+    "\n",
+    "This notebook demonstrates how to download an FPGA overlay and examine programmable logic state.  \n",
+    "\n",
+    "## 1. Setting up and checking the overlay\n",
+    "With the following overlay bundle present in the `overlays` folder, users can instantiate the overlay easily.\n",
+    "\n",
+    "*  A bitstream file (\\*.bit).\n",
+    "*  An hwh file (\\*.hwh).\n",
+    "*  A python class (\\*.py).\n",
+    "\n",
+    "For example, an overlay called `base` can be loaded by:\n",
+    "```python\n",
+    "from pynq.overlays.base import BaseOverlay\n",
+    "overlay = BaseOverlay(\"base.bit\")\n",
+    "```\n",
+    "Users can also use the absolute file path of the bitstream to instantiate the overlay.\n",
+    "\n",
+    "In this notebook, we get the current bitstream loaded on PL, and try to download it multiple times."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "\n",
+       "try {\n",
+       "require(['notebook/js/codecell'], function(codecell) {\n",
+       "  codecell.CodeCell.options_default.highlight_modes[\n",
+       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
+       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
+       "      Jupyter.notebook.get_cells().map(function(cell){\n",
+       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
+       "  });\n",
+       "});\n",
+       "} catch (e) {};\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "application/javascript": [
+       "\n",
+       "try {\n",
+       "require(['notebook/js/codecell'], function(codecell) {\n",
+       "  codecell.CodeCell.options_default.highlight_modes[\n",
+       "      'magic_text/x-csrc'] = {'reg':[/^%%pybind11/]};\n",
+       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
+       "      Jupyter.notebook.get_cells().map(function(cell){\n",
+       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
+       "  });\n",
+       "});\n",
+       "} catch (e) {};\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import os, warnings\n",
+    "from pynq import PL\n",
+    "from pynq import Overlay\n",
+    "\n",
+    "ol = Overlay(\"/home/xilinx/pynq/overlays/soclabs/design_1.bit\")\n",
+    "\n",
+    "if not os.path.exists(PL.bitfile_name):\n",
+    "    warnings.warn('There is no overlay loaded after boot.', UserWarning)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "**Note**: If you see a warning message in the above cell, it means that no overlay\n",
+    "has been loaded after boot, hence the PL server is not aware of the \n",
+    "current status of the PL. In that case you won't be able to run this notebook\n",
+    "until you manually load an overlay at least once using:\n",
+    "\n",
+    "```python\n",
+    "from pynq import Overlay\n",
+    "ol = Overlay('your_overlay.bit')\n",
+    "```\n",
+    "\n",
+    "If you do not see any warning message, you can safely proceed."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ol = Overlay(PL.bitfile_name)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Now we can check the download timestamp for this overlay."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'2023/3/17 12:2:13 +667853'"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ol.download()\n",
+    "ol.timestamp"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 2. Examining the overlay\n",
+    "Uncomment the #PL.ip_dict command to see the full details"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/home/xilinx/pynq/overlays/soclabs/design_1.bit\n",
+      "2023/3/17 12:2:13 +667853\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(PL.bitfile_name)\n",
+    "print(PL.timestamp)\n",
+    "\n",
+    "#PL.ip_dict"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Interrogate the HWH database for interface addresses"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ADPIO stream interface:  0x80020000\n",
+      "UART(2) interface:  0x80060000\n"
+     ]
+    }
+   ],
+   "source": [
+    "ADP_address = PL.ip_dict['cmsdk_socket/axi_stream_io_0']['phys_addr']\n",
+    "print(\"ADPIO stream interface: \",hex(ADP_address))\n",
+    "UART2_address = PL.ip_dict['cmsdk_socket/axi_uartlite_0']['phys_addr']\n",
+    "print(\"UART(2) interface: \",hex(UART2_address))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Set up interface functions for ADP"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from pynq import Overlay\n",
+    "from pynq import MMIO\n",
+    "import time\n",
+    "from time import sleep, time\n",
+    "\n",
+    "# HARDWARE CONSTANTS\n",
+    "RX_FIFO = 0x00\n",
+    "TX_FIFO = 0x04\n",
+    "# Status Reg\n",
+    "STAT_REG = 0x08\n",
+    "RX_VALID = 0\n",
+    "RX_FULL = 1\n",
+    "TX_EMPTY = 2\n",
+    "TX_FULL = 3\n",
+    "IS_INTR = 4\n",
+    "\n",
+    "# Ctrl Reg\n",
+    "CTRL_REG = 0x0C\n",
+    "RST_TX = 0\n",
+    "RST_RX = 1\n",
+    "INTR_EN = 4\n",
+    "\n",
+    "class ADPIO:\n",
+    "    def __init__(self, address):\n",
+    "        # Setup axi core\n",
+    "        self.uart = MMIO(address, 0x10000, debug=False)\n",
+    "        self.address = address\n",
+    "\n",
+    "    def setupCtrlReg(self):\n",
+    "#        # Reset FIFOs, disable interrupts\n",
+    "#        self.uart.write(CTRL_REG, 1 << RST_TX | 1 << RST_RX)\n",
+    "#        sleep(1)\n",
+    "        self.uart.write(CTRL_REG, 0)\n",
+    "        sleep(1)\n",
+    "\n",
+    "    def monitorModeEnter(self):\n",
+    "        self.uart.write(TX_FIFO, 0x1b)\n",
+    "\n",
+    "    def monitorModeExit(self):\n",
+    "        self.uart.write(TX_FIFO, 0x04)\n",
+    "\n",
+    "    def read(self, count, timeout=1):\n",
+    "        # status = currentStatus(uart) bad idea\n",
+    "        buf = \"\"\n",
+    "        stop_time = time() + timeout\n",
+    "        for i in range(count):\n",
+    "            # Wait till RX fifo has valid data, stop waiting if timeoutpasses\n",
+    "            while (not (self.uart.read(STAT_REG) & 1 << RX_VALID)) and (time() < stop_time):\n",
+    "                pass\n",
+    "            if time() >= stop_time:\n",
+    "                break\n",
+    "            buf += chr(self.uart.read(RX_FIFO))\n",
+    "        return buf\n",
+    "    \n",
+    "    def write(self, buf, timeout=1):\n",
+    "        # Write bytes via UART\n",
+    "        stop_time = time() + timeout\n",
+    "        wr_count = 0\n",
+    "        for i in buf:\n",
+    "            # Wait while TX FIFO is Full, stop waiting if timeout passes\n",
+    "            while (self.uart.read(STAT_REG) & 1 << TX_FULL) and (time() < stop_time):\n",
+    "                pass\n",
+    "            # Check timeout\n",
+    "            if time() > stop_time:\n",
+    "                wr_count = -1\n",
+    "                break\n",
+    "            self.uart.write(TX_FIFO, ord(i))\n",
+    "            wr_count += 1\n",
+    "        return wr_count\n",
+    "\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Inspect the ADP banner after reset (0x50CLAB03 expected)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      " 0x50c1ab03\n",
+      "\r\n",
+      "\n",
+      "\n",
+      "SOCLABS: ARM Cortex-M0 nanosoc\n",
+      "** Remap->RAM2\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp = ADPIO(ADP_address)\n",
+    "# Setup AXI UART register\n",
+    "adp.setupCtrlReg()\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Enter ADP monitor mode ('ESC' char)\n",
+    "And check the ']' prompt appears"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.monitorModeEnter()\n",
+    "print(adp.read(4))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Also check the UART2 RX channel for any boot message"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "''"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "uart = ADPIO(UART2_address)\n",
+    "# Setup AXI UART register\n",
+    "uart.setupCtrlReg()\n",
+    "uart.read(50)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Demonstrate basic ADP console functionality\n",
+    "\"A\" command with no parameter simply prints current Address pointer\n",
+    "\n",
+    "Here, check adp Address pointer resets to zero"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A\\n')\n",
+    "print(adp.read(100))\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Do a sequence of (4) auto-incrementing 32-bit reads from ROM1 space\n",
+    "\n",
+    " * \"A hexparam\" sets adddress pointer\n",
+    " * \"R hexparam\" performs number of 32-bit reads auto-incementing address pointer"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x10000000\n",
+      "\r",
+      "]R 0x30000368\n",
+      "\r",
+      "R 0x10000335\n",
+      "\r",
+      "R 0x1000033d\n",
+      "\r",
+      "R 0x1000033f\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x10000000\\nR 4\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]R 0x05f5e100\n",
+      "\r",
+      "]R 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nR\\nR \\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Write patterns to RAM3 base\n",
+    "\n",
+    " * \"W hexparam\" writes 32-bit data and auto-increments address pointer"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 13,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]W!0x11111111\n",
+      "\r",
+      "]W!0x22222222\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nW 0x11111111\\nW22222222\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Read back the patterns from RAM3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x30000000\n",
+      "\r",
+      "]R 0x05f5e100\n",
+      "\r",
+      "R 0x00000000\n",
+      "\r",
+      "R 0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x30000000\\nR 3\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Next try writes to map with bus errors\n",
+    "\n",
+    "  get a \"!\" warning on faulting accesses\n",
+    "  \n",
+    "(0x5xxxxxxx address range is illegal and faults in nanosoc address map)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x50000000\n",
+      "\r",
+      "]W!0x11111111\n",
+      "\r",
+      "]W!0x22222222\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x50000000\\nW 0x11111111\\nW22222222\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x50000000\n",
+      "\r",
+      "]R!0x00000000\n",
+      "\r",
+      "R!0x00000000\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x50000000\\nR 2\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Poll bus address (no auto-incrment)\n",
+    "\n",
+    " * \"M hexparam\"  sets up MASK pattern to use\n",
+    " * \"V hexparam\"  sets up VALUE of masked pattern to match\n",
+    " * \"P hexparam\"  Poll command reads from address and tests <param> times\n",
+    "\n",
+    " * match when (mem[A] & M) == \"V\"\n",
+    "\n",
+    "Run a poll cammand (indicated '!' for failure to match), followed by a poll with match (and returns the number of poll iteration until matched)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x10000000\n",
+      "]M 0xf0000000\n",
+      "]V 0x00000000\n",
+      "]P!0x00004000\n",
+      "]\n",
+      "A 0x10000000\n",
+      "]M 0xf0000000\n",
+      "]V 0x30000000\n",
+      "]P 0x00000001\n",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 10000000\\nM 0xF0000000\\nV 0\\nP 4000\\n')\n",
+    "print(adp.read(100))\n",
+    "adp.write('A 10000000\\nM\\nV 30000000\\nP 2000\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Fill command - set a pattern value from current base address pointer\n",
+    "\n",
+    " * \"V hexparam\"  sets up VALUE of data pattern to write\n",
+    " * \"F hexparam\"  Fill command writes <param> number of 32-bit words\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x90000000\n",
+      "\r",
+      "]V 0x87654321\n",
+      "\r",
+      "]F 0x00000400\n",
+      "\r",
+      "]A 0x90001000\n",
+      "\r",
+      "]W!0xffffffff\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 90000000\\nV 0x87654321\\nF 400\\nA\\nW FFFFFFFF\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "A 0x90000000\n",
+      "]R 0x87654321\n",
+      "R 0x87654321\n",
+      "R 0x87654321\n",
+      "]\n",
+      "A 0x90000ffc\n",
+      "]R 0x87654321\n",
+      "R 0x00000000\n",
+      "R 0x00000000\n",
+      "]?\n",
+      "]A 0x90001008\n",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('A 0x90000000\\nR 3\\n')\n",
+    "print(adp.read(100))\n",
+    "adp.write('A 0x90000FFC\\nr 0003\\n\\nA\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "S!0x00000031\n",
+      "\r",
+      "]?\n",
+      "\r",
+      "]\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.write('S 0x31\\n\\n')\n",
+    "print(adp.read(100))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "adp.monitorModeExit()\n",
+    "print(adp.read(100))\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "\n",
+    "## ol.download()\n",
+    "ol.timestamp\n",
+    "ol.reset()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ip_info = {'trace_cntrl':\"ft1248tb_i/ila_0\"}\n",
+    "class pynq.logictools.trace_analyzer.TraceAnalyzer(ip_info)\n",
+    "\n",
+    "                "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "#PL.ip_dict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "gpio_0.register_map\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 2. Examining the PL state\n",
+    "\n",
+    "While there can be multiple overlay instances in Python, there is only one bitstream that is currently loaded onto the programmable logic (PL). \n",
+    "\n",
+    "This bitstream state is held in the singleton class, PL, and is available for user queries."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "PL.bitfile_name"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "PL.timestamp\n",
+    "\n",
+    "PL.ip_dict\n",
+    "\n",
+    "leds_address = PL.ip_dict['led_4bits']['phys_addr']\n",
+    "                                               \n",
+    "from pynq import MMIO\n",
+    "mmio_buttons = MMIO(0xa0000000, 16)\n",
+    "help (mmio_buttons)\n",
+    "\n",
+    "#print(hex(mmio_buttons))\n",
+    "#print(hex(mmio_buttons.read(0)))\n",
+    "\n",
+    "hex(pl.ip_dict[\"axi_gpio_1\"][\"phys_addr\"])\n",
+    "\n",
+    "\n",
+    "#buttons_address = ssc_dpram.ip_dict['push_button_4bits']['phys_addr']\n",
+    "#switches_address = ssc_dpram.ip_dict['dip_switch_4bits']['phys_addr']\n",
+    "#leds_address = ssc_dpram.ip_dict['led_4bitss']['phys_addr']"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Users can verify whether an overlay instance is currently loaded using the Overlay is_loaded() method"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "ol.is_loaded()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## 3. Overlay downloading overhead\n",
+    "\n",
+    "Finally, using Python, we can see the bitstream download time over 50 downloads.  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "import matplotlib.pyplot as plt\n",
+    "\n",
+    "length = 50\n",
+    "time_log = []\n",
+    "for i in range(length):\n",
+    "    start = time.time()\n",
+    "    ol.download()\n",
+    "    end = time.time()\n",
+    "    time_log.append((end-start)*1000)\n",
+    "\n",
+    "%matplotlib inline\n",
+    "plt.plot(range(length), time_log, 'ro')\n",
+    "plt.title('Bitstream loading time (ms)')\n",
+    "plt.axis([0, length, 0, 1000])\n",
+    "plt.show()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.6.5"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/Cortex-M0/nanosoc/systems/mcu/rtl_sim/makefile b/Cortex-M0/nanosoc/systems/mcu/rtl_sim/makefile
index 69b6280dade46c7e5a95b6073fc1ae1742559a27..bafff8790d0ca4524cd0d9d091bbc5d68c2bed49 100644
--- a/Cortex-M0/nanosoc/systems/mcu/rtl_sim/makefile
+++ b/Cortex-M0/nanosoc/systems/mcu/rtl_sim/makefile
@@ -46,7 +46,7 @@ TEST_LIST   = hello dhry sleep_demo interrupt_demo dualtimer_demo \
  self_reset_demo watchdog_demo rtx_demo gpio_tests timer_tests \
  uart_tests debug_tests default_slaves_tests dma_tests \
  gpio_driver_tests uart_driver_tests timer_driver_tests apb_mux_tests \
- memory_tests romtable_tests
+ memory_tests romtable_tests aes128_tests
 
 # Default to DS-5 tool-chain
 TOOL_CHAIN = ds5
@@ -430,6 +430,15 @@ clean : clean_all_code
 	@if [ -e ft1248_op.log ] ; then \
 	  rm ft1248_op.log ; \
 	fi
+	@if [ -e ft1248_out.log ] ; then \
+	  rm ft1248_out.log ; \
+	fi
+	@if [ -e dma230.log ] ; then \
+	  rm dma230.log ; \
+	fi
+	@if [ -e aes128.log ] ; then \
+	  rm aes128.log ; \
+	fi
 	@if [ -e uart.log ] ; then \
 	  rm uart.log ; \
 	fi
@@ -496,6 +505,9 @@ clean : clean_all_code
 	@if [ -e inter.vpd ] ; then \
 	  rm -rf inter.vpd ; \
 	fi
+	@if [ -e vsim.cmd ] ; then \
+	  rm -rf vsim.cmd ; \
+	fi
 	@if [ -e quit.do ] ; then \
 	  rm -rf quit.do ; \
 	fi
diff --git a/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128.h b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128.h
new file mode 100644
index 0000000000000000000000000000000000000000..601a68c16745165c896c2bbbf6c4b7d15688084c
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128.h
@@ -0,0 +1,68 @@
+#ifndef _AES128_H_
+#define _AES128_H_
+
+#include <stdint.h>
+
+// define the addresses here. 
+
+#define AES128_BASE        (0x60000000)
+
+typedef struct {
+     __I  uint32_t CORE_NAME[2];   /* 0x0000-0007 */
+     __I  uint32_t CORE_VERSION;   /* 0x0008-000B */
+          uint32_t RESRV0C;        /* 0x000C */
+     __IO uint32_t CTRL;           /* 0x0010 */
+     __O  uint32_t CTRL_SET;       /* 0x0014 */
+     __O  uint32_t CTRLL_CLR;      /* 0x0018 */
+     __I  uint32_t STATUS;         /* 0x001c */
+     __IO uint32_t QUAL;           /* 0x0020 */
+          uint32_t RESRV24[3];     /* 0x0024 - 2F*/
+     __IO uint32_t DRQ_MSK;        /* 0x0030 */
+     __O  uint32_t DRQ_MSK_SET;    /* 0x0034 */
+     __O  uint32_t DRQ_MSK_CLR;    /* 0x0038 */
+     __I  uint32_t DRQ_STATUS;     /* 0x003C */
+     __IO uint32_t IRQ_MSK;        /* 0x0040 */
+     __O  uint32_t IRQ_MSK_SET;    /* 0x0044 */
+     __O  uint32_t IRQ_MSK_CLR;    /* 0x0048 */
+     __I  uint32_t IRQ_STATUS;     /* 0x004C */
+          uint32_t RESRV50[4076];  /* 0x0050-0x3FFC (4096-20 words) */
+     __IO uint8_t KEY128[0x4000];   /* 0x4000-7FFF (0x3FFF is last alias) */
+     __IO uint8_t TXTIP128[0x4000]; /* 0x8000-BFFF (0x3FFF is last alias) */
+     __I  uint8_t TXTOP128[0x4000]; /* 0xC000-FFFF (0x3FFF is last alias) */
+} AES128_TypeDef;
+
+#define AES128             ((AES128_TypeDef *) AES128_BASE )
+
+#define AES_BLOCK_SIZE 16
+
+#define AES_KEY_LEN_128 16
+
+#define HW32_REG(ADDRESS)  (*((volatile unsigned long  *)(ADDRESS)))
+
+#define  AES128_CTRL_REG_WIDTH   ( 8)
+#define  AES128_CTRL_BIT_MAX     ( (CTRL_REG_WIDTH-1)
+#define  AES128_CTRL_KEY_REQ_BIT (1<<0)
+#define  AES128_CTRL_IP_REQ_BIT  (1<<1)
+#define  AES128_CTRL_OP_REQ_BIT  (1<<2)
+#define  AES128_CTRL_ERR_REQ_BIT (1<<3)
+#define  AES128_CTRL_BYPASS_BIT  (1<<6)
+#define  AES128_CTRL_ENCODE_BIT  (1<<7)
+#define  AES128_STAT_REG_WIDTH   ( 8)
+#define  AES128_STAT_KEY_REQ_BIT (1<<0)
+#define  AES128_STAT_IP_REQ_BIT  (1<<1)
+#define  AES128_STAT_OP_REQ_BIT  (1<<2)
+#define  AES128_STAT_ERR_REQ_BIT (1<<3)
+#define  AES128_STAT_KEYOK_BIT   (1<<4)
+#define  AES128_STAT_VALID_BIT   (1<<5)
+#define  AES128_STAT_BYPASS_BIT  (1<<6)
+#define  AES128_STAT_ENCODE_BIT  (1<<7)
+#define  AES128_KEY_REQ_BIT (1<<0)
+#define  AES128_IP_REQ_BIT  (1<<1)
+#define  AES128_OP_REQ_BIT  (1<<2)
+#define  AES128_ERR_REQ_BIT (1<<3)
+#define  AES128_KEYOK_BIT   (1<<4)
+#define  AES128_VALID_BIT   (1<<5)
+#define  AES128_BYPASS_BIT  (1<<6)
+#define  AES128_ENCODE_BIT  (1<<7)
+
+#endif // _AES128_H_
diff --git a/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128_tests.c b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128_tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..8df6aee230cb49927b612e3c07e06d075c25a137
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/aes128_tests.c
@@ -0,0 +1,512 @@
+#include "CMSDK_CM0.h"
+#include "aes128.h"
+#include <string.h>
+#include "uart_stdout.h"
+#include <stdio.h>
+// memcopy implememtation
+#define os_memcpy memcpy
+#define os_memset memset
+// PL230DMA implementation
+#include "dma_pl230_driver.h"
+
+
+static volatile dma_pl230_channel_data aes_ip_chain[2];
+static volatile dma_pl230_channel_data aes_op_chain[2];
+
+// associate DMA channel numbers
+#define DMA_CHAN_AES128_IP (0)
+#define DMA_CHAN_AES128_OP (1)
+
+  uint8_t _test_key128[AES_KEY_LEN_128] = {  
+    0x75, 0x46, 0x20, 0x67,
+    0x6e, 0x75, 0x4b, 0x20,
+    0x79, 0x6d, 0x20, 0x73,
+    0x74, 0x61, 0x68, 0x54 };
+
+  uint8_t test_key128[AES_KEY_LEN_128] = {  
+    0x54, 0x68, 0x61, 0x74,
+    0x73, 0x20, 0x6d, 0x79,
+    0x20, 0x4b, 0x75, 0x6e,
+    0x67, 0x20, 0x46, 0x75 };
+	
+  uint8_t buf128[AES_BLOCK_SIZE] = {
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00 };
+
+  uint8_t _test_text128[AES_BLOCK_SIZE] = {
+    0x6f, 0x77, 0x54, 0x20,
+    0x65, 0x6e, 0x69, 0x4e,
+    0x20, 0x65, 0x6e, 0x4f,
+    0x20, 0x6f, 0x77, 0x54 };
+
+  uint8_t test_text128[AES_BLOCK_SIZE] = {
+    0x54, 0x77, 0x6f, 0x20,
+    0x4f, 0x6e, 0x65, 0x20,
+    0x4e, 0x69, 0x6e, 0x65,
+    0x20, 0x54, 0x77, 0x6f };
+
+  uint8_t test_exp128[AES_BLOCK_SIZE] = {
+    0x29, 0xc3, 0x50, 0x5f,
+    0x57, 0x14, 0x20, 0xf6,
+    0x40, 0x22, 0x99, 0xb3,
+    0x1a, 0x02, 0xd7, 0x3a };
+
+// add extra block[128] with all zeros to toggle bits low
+  uint8_t shift_patt[129*16] = {
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//127
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//128
+ };    
+
+  uint8_t shift_buf1[sizeof(shift_patt)];
+  uint8_t shift_buf2[sizeof(shift_patt)];
+
+
+/* Note:  Hardware supports byte, half-word or word accesses
+   So memcpy() can be used to load/save data
+   And memset() can be used to pad out data-in to 128-bits
+   mode =0 (bypass), =1 (encode) or =2 (decode)
+*/
+void aes128_driver_memcpy(uint8_t *key, uint32_t nbytes, uint8_t *input,
+                          uint8_t *result, uint8_t mode)
+{
+    // Reset engine
+    AES128->DRQ_MSK = 0;
+    AES128->IRQ_MSK = 0;
+    AES128->QUAL    = 0;
+    AES128->CTRL    = 0;
+
+    // Set up parameters
+    if (mode == 1)
+      AES128->CTRL_SET = AES128_ENCODE_BIT; // ENCODE mode
+    if (mode == 0)
+      AES128->CTRL_SET = AES128_BYPASS_BIT; // BYPASS mode
+
+    AES128->IRQ_MSK_SET = (AES128_ERR_REQ_BIT | AES128_KEY_REQ_BIT | AES128_IP_REQ_BIT | AES128_OP_REQ_BIT);
+    
+    // Program Key
+    os_memcpy((uint8_t *)AES128->KEY128, key, AES_KEY_LEN_128);
+    while (!(AES128->STATUS & AES128_KEYOK_BIT))
+         ;
+
+    /* payload */
+    while(nbytes) {
+       uint8_t len = (nbytes > AES_BLOCK_SIZE) ? AES_BLOCK_SIZE : nbytes;            
+       /* Align/pad input and load into hardware */
+       os_memcpy((uint8_t *)AES128->TXTIP128, input, len);
+       //patch up any zero-padding
+       if (len < AES_BLOCK_SIZE)
+           os_memset((uint8_t *)&(AES128->TXTIP128[len]), 0, AES_BLOCK_SIZE-len);
+       /* Auto-started! - no need for manual start */
+       /* Poll until completed */
+       while (!(AES128->STATUS & AES128_VALID_BIT))
+         ;
+       os_memcpy(result, (uint8_t *)AES128->TXTOP128, AES_BLOCK_SIZE);
+       /* Accounting */
+       input   += len;
+       result  += len;
+       nbytes -= len;
+    }
+    AES128->CTRL    = 0;
+}
+
+// wrapper functions
+
+void aes128_bypass_memcpy(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result)
+       { aes128_driver_memcpy(key, nbytes, input, result, 0); }
+
+void aes128_encrypt_memcpy(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result)
+       { aes128_driver_memcpy(key, nbytes, input, result, 1); }
+
+void aes128_decrypt_memcpy(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result)
+       { aes128_driver_memcpy(key, nbytes, input, result, 2); }
+
+
+int aes128_buffer_verify(uint32_t buflen, uint8_t *buf_A, uint8_t *buf_B)
+{
+    int i, j, fail = 0;
+        for (i=0 ; i < buflen; i++) {
+            if (buf_A[i] != buf_B[i]){
+                fail = 1;
+                break;
+            }
+        }
+        if (fail) {
+            j=i; // print offending block
+            for (i=(j - (j%16)) ; i < (j-(j%16)+16); i++) {
+               if (i%16==0)
+                   printf(" //%03d\n", (i>>4));
+               printf("0x%02x,", buf_A[i]);
+           }
+        }
+        if (fail){
+            i=j;
+            printf("Verify compare FAIL\n      EXPECTED_RESULT[%2d]= 0x%02x, ACTUAL_RESULT= 0x%02x \n",i, buf_B[i], buf_A[i]);
+            return(-1);
+        }
+        return(0);
+}
+
+void aes128_driver_dma32(uint8_t *key, uint32_t nbytes, uint8_t *input,
+                          uint8_t *result, uint8_t mode)
+{
+    int c;
+    // Reset engine
+    AES128->DRQ_MSK = 0;
+    AES128->IRQ_MSK = 0;
+    AES128->QUAL    = 0;
+    AES128->CTRL    = 0;
+
+    // Set up parameters
+    if (mode == 1)
+      AES128->CTRL_SET = AES128_ENCODE_BIT; // ENCODE mode
+    if (mode == 0)
+      AES128->CTRL_SET = AES128_BYPASS_BIT; // BYPASS mode
+    
+    dma_pl230_data_struct_init(); // initialize
+    
+    // program DMA transfers in multiples of 4 words (nbytes scaled >>2 for words)
+    aes_ip_chain[0].SrcEndPointer = DMA_PL230_PTR_END(key,PL230_XFER_W,4);
+    aes_ip_chain[0].DstEndPointer = DMA_PL230_PTR_END(&(AES128->KEY128[(0x4000)-16]),PL230_XFER_W,4);
+    aes_ip_chain[0].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_DEV_CHAIN_ALT,PL230_XFER_W,4,PL230_CTRL_RPWR_4);
+
+    aes_ip_chain[1].SrcEndPointer = DMA_PL230_PTR_END(input,PL230_XFER_W,(nbytes>>2));
+    aes_ip_chain[1].DstEndPointer = DMA_PL230_PTR_END(&(AES128->TXTIP128[(0x4000)-nbytes]),PL230_XFER_W,(nbytes>>2));
+    aes_ip_chain[1].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_BASIC,PL230_XFER_W,(nbytes>>2),PL230_CTRL_RPWR_4);
+
+    c=DMA_CHAN_AES128_IP;
+    dma_pl230_table->Primary[c].SrcEndPointer  = DMA_PL230_PTR_END(&(aes_ip_chain[0].SrcEndPointer), PL230_XFER_W,(2*4));
+    dma_pl230_table->Primary[c].DstEndPointer  = DMA_PL230_PTR_END(&(dma_pl230_table->Alternate[c]), PL230_XFER_W,(1*4));
+    dma_pl230_table->Primary[c].Control= DMA_PL230_CTRL_DSTFIX(PL230_CTRL_CYCLE_DEV_CHAIN_PRI,PL230_XFER_W,(2*4),PL230_CTRL_RPWR_4);
+
+    aes_op_chain[0].SrcEndPointer = DMA_PL230_PTR_END(&(AES128->TXTOP128[(0x4000)-nbytes]),PL230_XFER_W,(nbytes>>2));
+    aes_op_chain[0].DstEndPointer = DMA_PL230_PTR_END(result,PL230_XFER_W,(nbytes>>2));
+    aes_op_chain[0].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_BASIC,PL230_XFER_W,(nbytes>>2),PL230_CTRL_RPWR_4);
+
+    c=DMA_CHAN_AES128_OP;        
+    dma_pl230_table->Primary[c].SrcEndPointer  = DMA_PL230_PTR_END(&(aes_op_chain[0].SrcEndPointer), PL230_XFER_W,(1*4));
+    dma_pl230_table->Primary[c].DstEndPointer  = DMA_PL230_PTR_END(&(dma_pl230_table->Alternate[c]), PL230_XFER_W,(1*4));
+    dma_pl230_table->Primary[c].Control= DMA_PL230_CTRL_DSTFIX(PL230_CTRL_CYCLE_DEV_CHAIN_PRI,PL230_XFER_W,(1*4),PL230_CTRL_RPWR_4);
+ 
+    // enable DMA controller channels
+    dma_pl230_init((1<<DMA_CHAN_AES128_OP) | (1<<DMA_CHAN_AES128_IP)); // two active
+
+    // and enable DMA requests
+    AES128->DRQ_MSK_SET = (AES128_KEY_REQ_BIT | AES128_IP_REQ_BIT | AES128_OP_REQ_BIT);
+    AES128->IRQ_MSK_SET = (AES128_ERR_REQ_BIT | AES128_KEY_REQ_BIT | AES128_IP_REQ_BIT | AES128_OP_REQ_BIT);
+    // test to ensure output DMA has started                            
+    while (!(dma_pl230_channel_active((1<<DMA_CHAN_AES128_OP))))
+      ;
+    while (dma_pl230_channel_active((1<<DMA_CHAN_AES128_OP)))
+      ;
+    while (dma_pl230_channel_active((1<<DMA_CHAN_AES128_OP)))
+      ;
+    AES128->DRQ_MSK = 0;
+    AES128->IRQ_MSK = 0;
+    CMSDK_DMA->DMA_CFG = 0; /* Disable DMA controller for initialization */
+    dma_pl230_init(0); // none active
+    return;
+}
+
+void aes128_driver_dma8(uint8_t *key, uint32_t nbytes, uint8_t *input,
+                          uint8_t *result, uint8_t mode)
+{
+    int c;
+    // Reset engine
+    AES128->DRQ_MSK = 0;
+    AES128->IRQ_MSK = 0;
+    AES128->QUAL    = 0;
+    AES128->CTRL    = 0;
+
+    // Set up parameters
+    if (mode == 1)
+      AES128->CTRL_SET = AES128_ENCODE_BIT; // ENCODE mode
+    if (mode == 0)
+      AES128->CTRL_SET = AES128_BYPASS_BIT; // BYPASS mode
+    
+    dma_pl230_data_struct_init(); // initialize
+    
+    // program DMA transfers in multiples of 16 bytes
+    aes_ip_chain[0].SrcEndPointer = DMA_PL230_PTR_END(key,PL230_XFER_B,16);
+    aes_ip_chain[0].DstEndPointer = DMA_PL230_PTR_END(&(AES128->KEY128[(0x4000)-16]),PL230_XFER_B,16);
+    aes_ip_chain[0].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_DEV_CHAIN_ALT,PL230_XFER_B,16,PL230_CTRL_RPWR_16);
+
+    aes_ip_chain[1].SrcEndPointer = DMA_PL230_PTR_END(input,PL230_XFER_B,(nbytes));
+    aes_ip_chain[1].DstEndPointer = DMA_PL230_PTR_END(&(AES128->TXTIP128[(0x4000)-nbytes]),PL230_XFER_B,(nbytes));
+    aes_ip_chain[1].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_BASIC,PL230_XFER_B,(nbytes),PL230_CTRL_RPWR_16);
+
+    c=DMA_CHAN_AES128_IP;
+    dma_pl230_table->Primary[c].SrcEndPointer  = DMA_PL230_PTR_END(&(aes_ip_chain[0].SrcEndPointer), PL230_XFER_W, (2*4));
+    dma_pl230_table->Primary[c].DstEndPointer  = DMA_PL230_PTR_END(&(dma_pl230_table->Alternate[c]), PL230_XFER_W, (1*4));
+    dma_pl230_table->Primary[c].Control= DMA_PL230_CTRL_DSTFIX(PL230_CTRL_CYCLE_DEV_CHAIN_PRI,PL230_XFER_W,(2*4),PL230_CTRL_RPWR_4);
+
+    aes_op_chain[0].SrcEndPointer = DMA_PL230_PTR_END(&(AES128->TXTOP128[(0x4000)-nbytes]),PL230_XFER_B,(nbytes));
+    aes_op_chain[0].DstEndPointer = DMA_PL230_PTR_END(result,PL230_XFER_B,(nbytes));
+    aes_op_chain[0].Control = DMA_PL230_CTRL(PL230_CTRL_CYCLE_BASIC,PL230_XFER_B,(nbytes),PL230_CTRL_RPWR_16);
+
+    c=DMA_CHAN_AES128_OP;        
+    dma_pl230_table->Primary[c].SrcEndPointer  = DMA_PL230_PTR_END(&(aes_op_chain[0].SrcEndPointer), PL230_XFER_W,(1*4));
+    dma_pl230_table->Primary[c].DstEndPointer  = DMA_PL230_PTR_END(&(dma_pl230_table->Alternate[c]), PL230_XFER_W,(1*4));
+    dma_pl230_table->Primary[c].Control= DMA_PL230_CTRL_DSTFIX(PL230_CTRL_CYCLE_DEV_CHAIN_PRI,PL230_XFER_W,(1*4),PL230_CTRL_RPWR_4);
+ 
+    // enable DMA controller channels
+    dma_pl230_init((1<<DMA_CHAN_AES128_OP) | (1<<DMA_CHAN_AES128_IP)); // two active
+
+    // and enable DMA requests
+    AES128->DRQ_MSK_SET = (AES128_KEY_REQ_BIT | AES128_IP_REQ_BIT | AES128_OP_REQ_BIT);
+    AES128->IRQ_MSK_SET = (AES128_ERR_REQ_BIT | AES128_KEY_REQ_BIT | AES128_IP_REQ_BIT | AES128_OP_REQ_BIT);
+    // test to ensure output DMA has started                            
+    while (!(dma_pl230_channel_active(1<<DMA_CHAN_AES128_OP)))
+      ;
+    while (dma_pl230_channel_active(1<<DMA_CHAN_AES128_OP))
+      ;
+    while (dma_pl230_channel_active(1<<DMA_CHAN_AES128_OP))
+      ;
+    AES128->DRQ_MSK = 0;
+    AES128->IRQ_MSK = 0;
+    CMSDK_DMA->DMA_CFG = 0; /* Disable DMA controller for initialization */
+    dma_pl230_init(0); // none active
+    return;
+}
+
+// wrapper functions
+
+void aes128_aligned_block_dma(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result, uint8_t mode)
+       { uint32_t dma_max = 1024;
+         if (((((long)key) & 3)==0) && ((((long)input) & 3)==0) && ((((long)result) & 3)==0)) dma_max=4096;
+         while (nbytes >dma_max) {
+            if (dma_max == 1024)
+              aes128_driver_dma8(key, dma_max, input, result, mode);
+            else
+              aes128_driver_dma32(key, dma_max, input, result, mode);
+           nbytes -= dma_max; input  += dma_max; result += dma_max;
+         }
+         if (dma_max == 1024)
+           aes128_driver_dma8(key, nbytes, input, result, mode);
+         else
+           aes128_driver_dma32(key, nbytes, input, result, mode);
+       }
+
+void aes128_bypass_dma(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result) 
+       { aes128_aligned_block_dma (key, nbytes, input, result, 0); }
+
+void aes128_encrypt_dma(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result)
+       { aes128_aligned_block_dma (key, nbytes, input, result, 1); }
+
+void aes128_decrypt_dma(uint8_t *key, uint32_t nbytes, uint8_t *input, uint8_t *result)
+       { aes128_aligned_block_dma (key, nbytes, input, result, 2); }
+
+
+int main(void) {
+	char rx_char [256] = "soclabs AES128v1"; // init to 0
+	unsigned char id_string [16] = {0};
+	int  i, fail=0;
+        unsigned char * p;
+        
+		UartStdOutInit();
+		printf("%s\n",rx_char);
+		printf("AES128 test program\n");
+		printf("  AES128 ID: ");
+ 	        // iterate over 3 32-bit fields
+                p = (unsigned char *)AES128->CORE_NAME;
+	        for (i = 0; i < 12; i++) {
+                  id_string[i^3]=*p; // fix byte ordering per word
+                  p+=1;
+                  }
+                id_string[12] = 0; 
+		printf("%s\n",id_string);
+		printf("AES128 SW (memcpy) tests...\n");
+ 		printf("  AES128 reference pattern test\n");
+
+ 		printf("    AES128 input/output bypass test\n");
+                aes128_bypass_memcpy(test_key128, sizeof(test_text128), test_text128, buf128);
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_text128);
+                
+		printf("    AES128 encrypt test\n");
+                aes128_encrypt_memcpy(test_key128, sizeof(test_text128), test_text128, buf128); 
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_exp128);
+
+ 		printf("    AES128 decrypt test\n");
+                aes128_decrypt_memcpy(test_key128, sizeof(buf128), buf128, buf128);
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_text128);
+
+ 		printf("  AES128 logic toggle test\n");
+		printf("    AES128 input/output pattern test\n");
+                aes128_bypass_memcpy(test_key128, sizeof(shift_patt), shift_patt, shift_buf1); 
+                fail += aes128_buffer_verify(sizeof(shift_patt), shift_buf1, shift_patt);
+		printf("    AES128 pattern encrypt test\n");
+                aes128_encrypt_memcpy(test_key128, sizeof(shift_patt), shift_patt, shift_buf1); 
+ 		printf("    AES128 pattern decrypt test\n");
+                aes128_decrypt_memcpy(test_key128, sizeof(shift_patt), shift_buf1, shift_buf2); 
+                fail += aes128_buffer_verify(sizeof(shift_patt), shift_buf2, shift_patt);
+
+		printf("AES128 DMA tests...\n");
+
+ 		printf("  AES128 dma input/output bypass test\n");
+                aes128_bypass_dma(test_key128, sizeof(test_text128), test_text128, buf128);
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_text128);
+
+		printf("  AES128 dma encrypt test\n");
+                aes128_encrypt_dma(test_key128, sizeof(test_text128), test_text128, buf128); 
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_exp128);
+
+ 		printf("  AES128 dma decrypt test\n");
+                aes128_decrypt_dma(test_key128, sizeof(buf128), buf128, buf128);
+                fail += aes128_buffer_verify(AES_BLOCK_SIZE, buf128, test_text128);
+
+		printf("  AES128 dma unaligned pattern test\n");
+                aes128_bypass_dma(test_key128,(16*63), shift_patt, shift_buf1+3); 
+                fail += aes128_buffer_verify((16*63), shift_buf1+3, shift_patt);
+
+		printf("  AES128 dma input/output pattern test\n");
+                aes128_bypass_dma(test_key128, sizeof(shift_patt), shift_patt, shift_buf1); 
+                fail += aes128_buffer_verify(sizeof(shift_patt), shift_buf1, shift_patt);
+		printf("  AES128 dma pattern encrypt test\n");
+                aes128_encrypt_dma(test_key128, sizeof(shift_patt), shift_patt, shift_buf1); 
+ 		printf("  AES128 dma pattern decrypt test\n");
+                aes128_decrypt_dma(test_key128, sizeof(shift_patt), shift_buf1, shift_buf2); 
+                fail += aes128_buffer_verify(sizeof(shift_patt), shift_buf2, shift_patt);
+
+  		printf ("Data retrieved from the AES is: %s\n", id_string);
+		printf ("Data expected from the AES is: %s\n", rx_char);
+		if (fail >0)
+		  printf("** AES TESTS FAILED (%d)  **\n", fail);
+                else
+		  printf("** AES TEST PASSED **\n");
+		// End simulation
+
+
+  		UartEndSimulation();
+
+  	return 0;
+
+}
+	
diff --git a/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.c b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.c
new file mode 100644
index 0000000000000000000000000000000000000000..878146502e4b9f1d44f686d3f9f0df121ffcfe74
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.c
@@ -0,0 +1,163 @@
+#include <stdio.h>
+#include <string.h>
+#include "dma_pl230_driver.h"
+
+#define DEBUG_PRINTF(...) do {} while(0); 
+//#define cpu_to_be32(__x) __x
+//#define be32_to_cpu(__x) __x
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int g_dma_pl230_initialised = 0;
+
+static dma_pl230_data_structure priv_dma __attribute__((aligned(256)));
+//
+dma_pl230_data_structure *dma_pl230_table = &priv_dma; 
+
+/* --------------------------------------------------------------- */
+/*  Initialize DMA data structure                                  */
+/* --------------------------------------------------------------- */
+void dma_pl230_data_struct_init(void)
+{
+  int          i;   /* loop counter */
+
+//  printf ("dma structure block address = %x\n", dma_pl230_table);
+  for (i=0; i<MAX_NUM_OF_DMA_CHANNELS; i++) {
+    dma_pl230_table->Primary[i].SrcEndPointer   = 0;
+    dma_pl230_table->Primary[i].DstEndPointer   = 0;
+    dma_pl230_table->Primary[i].Control         = 0;
+    dma_pl230_table->Alternate[i].SrcEndPointer = 0;
+    dma_pl230_table->Alternate[i].DstEndPointer = 0;
+    dma_pl230_table->Alternate[i].Control       = 0;
+    }
+  g_dma_pl230_initialised = 1;
+  return;
+}
+
+void dma_pl230_data_struct_init_dbg(void)
+{
+  int          i;   /* loop counter */
+  unsigned int ptr;
+
+  int          ch_num;         /* number of channels */
+  unsigned int blksize;        /* Size of DMA data structure in bytes */
+  unsigned int blkmask;        /* address mask */
+
+
+  ch_num  = (((DMA_PL230_DMAC->DMA_STATUS) >> 16) & 0x1F)+1;
+  blksize = ch_num * 32;
+  if      (ch_num > 16) blkmask = 0x3FF; /* 17 to 32 */
+  else if (ch_num > 8)  blkmask = 0x1FF; /*  9 to 16 */
+  else if (ch_num > 4)  blkmask = 0x0FF; /*  5 to 8 */
+  else if (ch_num > 2)  blkmask = 0x07F; /*  3 to 4 */
+  else if (ch_num > 1)  blkmask = 0x03F; /*       2 */
+  else                  blkmask = 0x01F; /*       1 */
+
+
+  /* Create DMA data structure in RAM after stack
+  In the linker script, a 1KB memory stack above stack is reserved
+  so we can use this space for putting the DMA data structure.
+  */
+
+//  ptr     = HW32_REG(0);                     /* Read Top of Stack */
+  ptr     = (0x80000000); // force for now as no reserved RAM available
+  
+  /* the DMA data structure must be aligned to the size of the data structure */
+  if ((ptr & blkmask) != 0x0)
+    ptr     = (ptr + blksize) & ~blkmask;
+
+///  if ((ptr + blksize) > (RAM_ADDRESS_MAX + 1)) {
+///    puts ("ERROR : Not enough RAM space for DMA data structure.");
+///    UartEndSimulation();
+///    }
+
+  /* Set pointer to the reserved space */
+  dma_pl230_table = (dma_pl230_data_structure *) ptr;
+  ptr = (unsigned long) &(dma_pl230_table->Primary[0].SrcEndPointer);
+
+  printf ("dma structure block address = %x\n", ptr);
+
+  for (i=0; i<MAX_NUM_OF_DMA_CHANNELS; i++) {
+    dma_pl230_table->Primary[i].SrcEndPointer   = 0;
+    dma_pl230_table->Primary[i].DstEndPointer   = 0;
+    dma_pl230_table->Primary[i].Control         = 0;
+    dma_pl230_table->Alternate[i].SrcEndPointer = 0;
+    dma_pl230_table->Alternate[i].DstEndPointer = 0;
+    dma_pl230_table->Alternate[i].Control       = 0;
+    }
+  g_dma_pl230_initialised = 1;
+  return;
+}
+/* --------------------------------------------------------------- */
+/*  Initialize DMA PL230                                           */
+/* --------------------------------------------------------------- */
+void dma_pl230_init_dbg(unsigned int chan_mask)
+{
+  unsigned int current_state;
+  puts ("Initialize PL230");
+  current_state = DMA_PL230_DMAC->DMA_STATUS;
+  printf ("- # of channels allowed : %d\n",(((current_state) >> 16) & 0x1F)+1);
+  /* Debugging printfs: */
+  printf ("- Current status        : %x\n",(((current_state) >> 4)  & 0xF));
+  printf ("- Current master enable : %x\n",(((current_state) >> 0)  & 0x1));
+
+  /* Wait until current DMA complete */
+  current_state = (DMA_PL230_DMAC->DMA_STATUS >> 4)  & 0xF;
+  if (!((current_state==0) || (current_state==0x8) || (current_state==0x9))) {
+    puts ("- wait for DMA IDLE/STALLED/DONE");
+    current_state = (DMA_PL230_DMAC->DMA_STATUS >> 4)  & 0xF;
+    printf ("- Current status        : %x\n",(((current_state) >> 4)  & 0xF));
+
+    }
+  while (!((current_state==0) || (current_state==0x8) || (current_state==0x9))){
+    /* Wait if not IDLE/STALLED/DONE */
+    current_state = (DMA_PL230_DMAC->DMA_STATUS >> 4)  & 0xF;
+    printf ("- Current status        : %x\n",(((current_state) >> 4)  & 0xF));
+    }
+  DMA_PL230_DMAC->DMA_CFG = 0; /* Disable DMA controller for initialization */
+  DMA_PL230_DMAC->CTRL_BASE_PTR = (unsigned long) &(dma_pl230_table->Primary->SrcEndPointer);
+                           /* Set DMA data structure address */
+  DMA_PL230_DMAC->CHNL_ENABLE_CLR = 0xFFFFFFFF; /* Disable all channels */
+  DMA_PL230_DMAC->CHNL_PRI_ALT_CLR = ((1<<MAX_NUM_OF_DMA_CHANNELS)-1); /* Disable all alt channels */
+  DMA_PL230_DMAC->CHNL_ENABLE_SET = (chan_mask & ((1<<MAX_NUM_OF_DMA_CHANNELS)-1)); /* Enable channel */
+  DMA_PL230_DMAC->CHNL_USEBURST_SET = (chan_mask & ((1<<MAX_NUM_OF_DMA_CHANNELS)-1)); /* Enable bursts */
+  if (chan_mask)
+    DMA_PL230_DMAC->DMA_CFG = 1;              /* Enable DMA controller if enabled channel*/
+  return;
+}
+
+void dma_pl230_init(unsigned int chan_mask)
+{
+  unsigned int current_state;
+  if (g_dma_pl230_initialised ==0)
+    dma_pl230_data_struct_init();
+  /* Wait until current DMA complete */
+  current_state = (DMA_PL230_DMAC->DMA_STATUS >> 4)  & 0xF;
+  while (!((current_state==0) || (current_state==0x8) || (current_state==0x9))){
+    /* Wait if not IDLE/STALLED/DONE */
+    puts ("- wait for DMA IDLE/STALLED/DONE");
+    current_state = (DMA_PL230_DMAC->DMA_STATUS >> 4)  & 0xF;
+    }
+  DMA_PL230_DMAC->DMA_CFG = 0; /* Disable DMA controller for initialization */
+  DMA_PL230_DMAC->CTRL_BASE_PTR = (unsigned long) &(dma_pl230_table->Primary->SrcEndPointer);
+                           /* Set DMA data structure address */
+  DMA_PL230_DMAC->CHNL_ENABLE_CLR  = ((1<<MAX_NUM_OF_DMA_CHANNELS)-1); /* Disable all channels */
+  DMA_PL230_DMAC->CHNL_PRI_ALT_CLR = ((1<<MAX_NUM_OF_DMA_CHANNELS)-1); /* Disable all alt channels */
+  DMA_PL230_DMAC->CHNL_ENABLE_SET  = (chan_mask & ((1<<MAX_NUM_OF_DMA_CHANNELS)-1)); /* Enable channel */
+  DMA_PL230_DMAC->CHNL_USEBURST_SET = (chan_mask & ((1<<MAX_NUM_OF_DMA_CHANNELS)-1)); /* Enable bursts */
+  g_dma_pl230_initialised = 2;
+  if (chan_mask)
+    DMA_PL230_DMAC->DMA_CFG = 1;              /* Enable DMA controller if enabled channel*/
+  return;
+}
+
+unsigned int dma_pl230_channel_active(unsigned int chan_mask)
+{
+  return(DMA_PL230_DMAC->CHNL_ENABLE_SET & chan_mask & ((1<<MAX_NUM_OF_DMA_CHANNELS)-1)); /* Enabled channels */
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.h b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.h
new file mode 100644
index 0000000000000000000000000000000000000000..3455c406e5fbc609bec214493932084c358c8fa9
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/dma_pl230_driver.h
@@ -0,0 +1,196 @@
+#ifndef __DMA_PL230_MCU_H
+#define __DMA_PL230_MCU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include  "CMSDK_CM0.h"
+
+#define DMA_PL230_BASE        (CMSDK_APB_BASE + 0xF000UL)
+
+#define MAX_NUM_OF_DMA_CHANNELS   2
+
+/*------------- PL230 uDMA (PL230) --------------------------------------*/
+/** @addtogroup DMA_PL230 CMSDK uDMA controller
+  @{
+*/
+typedef struct
+{
+  __I    uint32_t  DMA_STATUS;           /*!< Offset: 0x000 DMA status Register (R/W) */
+  __O    uint32_t  DMA_CFG;              /*!< Offset: 0x004 DMA configuration Register ( /W) */
+  __IO   uint32_t  CTRL_BASE_PTR;        /*!< Offset: 0x008 Channel Control Data Base Pointer Register  (R/W) */
+  __I    uint32_t  ALT_CTRL_BASE_PTR;    /*!< Offset: 0x00C Channel Alternate Control Data Base Pointer Register  (R/ ) */
+  __I    uint32_t  DMA_WAITONREQ_STATUS; /*!< Offset: 0x010 Channel Wait On Request Status Register  (R/ ) */
+  __O    uint32_t  CHNL_SW_REQUEST;      /*!< Offset: 0x014 Channel Software Request Register  ( /W) */
+  __IO   uint32_t  CHNL_USEBURST_SET;    /*!< Offset: 0x018 Channel UseBurst Set Register  (R/W) */
+  __O    uint32_t  CHNL_USEBURST_CLR;    /*!< Offset: 0x01C Channel UseBurst Clear Register  ( /W) */
+  __IO   uint32_t  CHNL_REQ_MASK_SET;    /*!< Offset: 0x020 Channel Request Mask Set Register  (R/W) */
+  __O    uint32_t  CHNL_REQ_MASK_CLR;    /*!< Offset: 0x024 Channel Request Mask Clear Register  ( /W) */
+  __IO   uint32_t  CHNL_ENABLE_SET;      /*!< Offset: 0x028 Channel Enable Set Register  (R/W) */
+  __O    uint32_t  CHNL_ENABLE_CLR;      /*!< Offset: 0x02C Channel Enable Clear Register  ( /W) */
+  __IO   uint32_t  CHNL_PRI_ALT_SET;     /*!< Offset: 0x030 Channel Primary-Alterante Set Register  (R/W) */
+  __O    uint32_t  CHNL_PRI_ALT_CLR;     /*!< Offset: 0x034 Channel Primary-Alterante Clear Register  ( /W) */
+  __IO   uint32_t  CHNL_PRIORITY_SET;    /*!< Offset: 0x038 Channel Priority Set Register  (R/W) */
+  __O    uint32_t  CHNL_PRIORITY_CLR;    /*!< Offset: 0x03C Channel Priority Clear Register  ( /W) */
+         uint32_t  RESERVED0[3];
+  __IO   uint32_t  ERR_CLR;              /*!< Offset: 0x04C Bus Error Clear Register  (R/W) */
+
+} DMA_PL230_TypeDef;
+
+#define PL230_DMA_CHNL_BITS 0
+
+#define DMA_PL230_DMA_STATUS_MSTREN_Pos          0                                                          /*!< DMA_PL230 DMA STATUS: MSTREN Position */
+#define DMA_PL230_DMA_STATUS_MSTREN_Msk          (0x00000001ul << DMA_PL230_DMA_STATUS_MSTREN_Pos)        /*!< DMA_PL230 DMA STATUS: MSTREN Mask */
+
+#define DMA_PL230_DMA_STATUS_STATE_Pos           0                                                          /*!< DMA_PL230 DMA STATUS: STATE Position */
+#define DMA_PL230_DMA_STATUS_STATE_Msk           (0x0000000Ful << DMA_PL230_DMA_STATUS_STATE_Pos)         /*!< DMA_PL230 DMA STATUS: STATE Mask */
+
+#define DMA_PL230_DMA_STATUS_CHNLS_MINUS1_Pos    0                                                          /*!< DMA_PL230 DMA STATUS: CHNLS_MINUS1 Position */
+#define DMA_PL230_DMA_STATUS_CHNLS_MINUS1_Msk    (0x0000001Ful << DMA_PL230_DMA_STATUS_CHNLS_MINUS1_Pos)  /*!< DMA_PL230 DMA STATUS: CHNLS_MINUS1 Mask */
+
+#define DMA_PL230_DMA_STATUS_TEST_STATUS_Pos     0                                                          /*!< DMA_PL230 DMA STATUS: TEST_STATUS Position */
+#define DMA_PL230_DMA_STATUS_TEST_STATUS_Msk     (0x00000001ul << DMA_PL230_DMA_STATUS_TEST_STATUS_Pos)   /*!< DMA_PL230 DMA STATUS: TEST_STATUS Mask */
+
+#define DMA_PL230_DMA_CFG_MSTREN_Pos             0                                                          /*!< DMA_PL230 DMA CFG: MSTREN Position */
+#define DMA_PL230_DMA_CFG_MSTREN_Msk             (0x00000001ul << DMA_PL230_DMA_CFG_MSTREN_Pos)           /*!< DMA_PL230 DMA CFG: MSTREN Mask */
+
+#define DMA_PL230_DMA_CFG_CPCCACHE_Pos           2                                                          /*!< DMA_PL230 DMA CFG: CPCCACHE Position */
+#define DMA_PL230_DMA_CFG_CPCCACHE_Msk           (0x00000001ul << DMA_PL230_DMA_CFG_CPCCACHE_Pos)         /*!< DMA_PL230 DMA CFG: CPCCACHE Mask */
+
+#define DMA_PL230_DMA_CFG_CPCBUF_Pos             1                                                          /*!< DMA_PL230 DMA CFG: CPCBUF Position */
+#define DMA_PL230_DMA_CFG_CPCBUF_Msk             (0x00000001ul << DMA_PL230_DMA_CFG_CPCBUF_Pos)           /*!< DMA_PL230 DMA CFG: CPCBUF Mask */
+
+#define DMA_PL230_DMA_CFG_CPCPRIV_Pos            0                                                          /*!< DMA_PL230 DMA CFG: CPCPRIV Position */
+#define DMA_PL230_DMA_CFG_CPCPRIV_Msk            (0x00000001ul << DMA_PL230_DMA_CFG_CPCPRIV_Pos)          /*!< DMA_PL230 DMA CFG: CPCPRIV Mask */
+
+#define DMA_PL230_CTRL_BASE_PTR_Pos              PL230_DMA_CHNL_BITS + 5                                    /*!< DMA_PL230 STATUS: BASE_PTR Position */
+#define DMA_PL230_CTRL_BASE_PTR_Msk              (0x0FFFFFFFul << DMA_PL230_CTRL_BASE_PTR_Pos)            /*!< DMA_PL230 STATUS: BASE_PTR Mask */
+
+#define DMA_PL230_ALT_CTRL_BASE_PTR_Pos          0                                                          /*!< DMA_PL230 STATUS: MSTREN Position */
+#define DMA_PL230_ALT_CTRL_BASE_PTR_Msk          (0xFFFFFFFFul << DMA_PL230_ALT_CTRL_BASE_PTR_Pos)        /*!< DMA_PL230 STATUS: MSTREN Mask */
+
+#define DMA_PL230_DMA_WAITONREQ_STATUS_Pos       0                                                          /*!< DMA_PL230 DMA_WAITONREQ_STATUS: DMA_WAITONREQ_STATUS Position */
+#define DMA_PL230_DMA_WAITONREQ_STATUS_Msk       (0xFFFFFFFFul << DMA_PL230_DMA_WAITONREQ_STATUS_Pos)     /*!< DMA_PL230 DMA_WAITONREQ_STATUS: DMA_WAITONREQ_STATUS Mask */
+
+#define DMA_PL230_CHNL_SW_REQUEST_Pos            0                                                          /*!< DMA_PL230 CHNL_SW_REQUEST: CHNL_SW_REQUEST Position */
+#define DMA_PL230_CHNL_SW_REQUEST_Msk            (0xFFFFFFFFul << DMA_PL230_CHNL_SW_REQUEST_Pos)          /*!< DMA_PL230 CHNL_SW_REQUEST: CHNL_SW_REQUEST Mask */
+
+#define DMA_PL230_CHNL_USEBURST_SET_Pos          0                                                          /*!< DMA_PL230 CHNL_USEBURST: SET Position */
+#define DMA_PL230_CHNL_USEBURST_SET_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_USEBURST_SET_Pos)        /*!< DMA_PL230 CHNL_USEBURST: SET Mask */
+
+#define DMA_PL230_CHNL_USEBURST_CLR_Pos          0                                                          /*!< DMA_PL230 CHNL_USEBURST: CLR Position */
+#define DMA_PL230_CHNL_USEBURST_CLR_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_USEBURST_CLR_Pos)        /*!< DMA_PL230 CHNL_USEBURST: CLR Mask */
+
+#define DMA_PL230_CHNL_REQ_MASK_SET_Pos          0                                                          /*!< DMA_PL230 CHNL_REQ_MASK: SET Position */
+#define DMA_PL230_CHNL_REQ_MASK_SET_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_REQ_MASK_SET_Pos)        /*!< DMA_PL230 CHNL_REQ_MASK: SET Mask */
+
+#define DMA_PL230_CHNL_REQ_MASK_CLR_Pos          0                                                          /*!< DMA_PL230 CHNL_REQ_MASK: CLR Position */
+#define DMA_PL230_CHNL_REQ_MASK_CLR_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_REQ_MASK_CLR_Pos)        /*!< DMA_PL230 CHNL_REQ_MASK: CLR Mask */
+
+#define DMA_PL230_CHNL_ENABLE_SET_Pos            0                                                          /*!< DMA_PL230 CHNL_ENABLE: SET Position */
+#define DMA_PL230_CHNL_ENABLE_SET_Msk            (0xFFFFFFFFul << DMA_PL230_CHNL_ENABLE_SET_Pos)          /*!< DMA_PL230 CHNL_ENABLE: SET Mask */
+
+#define DMA_PL230_CHNL_ENABLE_CLR_Pos            0                                                          /*!< DMA_PL230 CHNL_ENABLE: CLR Position */
+#define DMA_PL230_CHNL_ENABLE_CLR_Msk            (0xFFFFFFFFul << DMA_PL230_CHNL_ENABLE_CLR_Pos)          /*!< DMA_PL230 CHNL_ENABLE: CLR Mask */
+
+#define DMA_PL230_CHNL_PRI_ALT_SET_Pos           0                                                          /*!< DMA_PL230 CHNL_PRI_ALT: SET Position */
+#define DMA_PL230_CHNL_PRI_ALT_SET_Msk           (0xFFFFFFFFul << DMA_PL230_CHNL_PRI_ALT_SET_Pos)         /*!< DMA_PL230 CHNL_PRI_ALT: SET Mask */
+
+#define DMA_PL230_CHNL_PRI_ALT_CLR_Pos           0                                                          /*!< DMA_PL230 CHNL_PRI_ALT: CLR Position */
+#define DMA_PL230_CHNL_PRI_ALT_CLR_Msk           (0xFFFFFFFFul << DMA_PL230_CHNL_PRI_ALT_CLR_Pos)         /*!< DMA_PL230 CHNL_PRI_ALT: CLR Mask */
+
+#define DMA_PL230_CHNL_PRIORITY_SET_Pos          0                                                          /*!< DMA_PL230 CHNL_PRIORITY: SET Position */
+#define DMA_PL230_CHNL_PRIORITY_SET_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_PRIORITY_SET_Pos)        /*!< DMA_PL230 CHNL_PRIORITY: SET Mask */
+
+#define DMA_PL230_CHNL_PRIORITY_CLR_Pos          0                                                          /*!< DMA_PL230 CHNL_PRIORITY: CLR Position */
+#define DMA_PL230_CHNL_PRIORITY_CLR_Msk          (0xFFFFFFFFul << DMA_PL230_CHNL_PRIORITY_CLR_Pos)        /*!< DMA_PL230 CHNL_PRIORITY: CLR Mask */
+
+#define DMA_PL230_ERR_CLR_Pos                    0                                                          /*!< DMA_PL230 ERR: CLR Position */
+#define DMA_PL230_ERR_CLR_Msk                    (0x00000001ul << DMA_PL230_ERR_CLR_Pos)                  /*!< DMA_PL230 ERR: CLR Mask */
+
+
+#define HW32_REG(ADDRESS)  (*((volatile unsigned long  *)(ADDRESS)))
+
+                              /* Maximum to 32 DMA channel */
+                              /* SRAM in example system is 64K bytes */
+#define RAM_ADDRESS_MAX       0x80001fff
+
+typedef struct /* 4 words */
+{
+  volatile unsigned char* SrcEndPointer;
+  volatile unsigned char* DstEndPointer;
+  volatile unsigned long Control;
+  volatile unsigned long unused;
+} dma_pl230_channel_data;
+
+
+typedef struct /* 8 words per channel */
+{ /* was one channel in the example uDMA setup */
+  volatile dma_pl230_channel_data Primary[MAX_NUM_OF_DMA_CHANNELS];
+  volatile dma_pl230_channel_data Alternate[MAX_NUM_OF_DMA_CHANNELS];
+} dma_pl230_data_structure;
+
+
+extern dma_pl230_data_structure *dma_pl230_table;
+
+#define DMA_PL230_DMAC   ((DMA_PL230_TypeDef *)  DMA_PL230_BASE)
+
+#define DMA_PL230_PTR_END(__ptr, __siz, __num) \
+	((unsigned char *) __ptr + ((1<<__siz)*(__num-1)))
+
+#define DMA_PL230_CTRL(__cyc, __siz, __num, __rpwr) \
+	(((unsigned long) __siz << 30)|(__siz << 28)|(__siz << 26)|(__siz << 24)| \
+         (1     << 21)|(1     << 18)|(__rpwr << 14)|(((__num-1)&0x3ff)<<4)| \
+         (1     <<  3)|(__cyc <<  0) )
+
+#define DMA_PL230_CTRL_SRCFIX(__cyc, __siz, __num, __rpwr) \
+	(((unsigned long) __siz << 30)|(__siz << 28)|(0x0c000000UL)|(__siz << 24)| \
+         (1     << 21)|(1     << 18)|(__rpwr << 14)|(((__num-1)&0x3ff)<<4)| \
+         (1     <<  3)|(__cyc <<  0) )
+
+#define DMA_PL230_CTRL_DSTFIX(__cyc, __siz, __num, __rpwr) \
+	((0xc0000000UL)|(__siz << 28)|(__siz << 26)|(__siz << 24)| \
+         (1     << 21)|(1     << 18)|(__rpwr << 14)|(((__num-1)&0x3ff)<<4)| \
+         (1     <<  3)|(__cyc <<  0) )
+
+#define PL230_CTRL_CYCLE_STOP    0
+#define PL230_CTRL_CYCLE_BASIC   1
+#define PL230_CTRL_CYCLE_AUTO    2
+#define PL230_CTRL_CYCLE_PPONG   3
+#define PL230_CTRL_CYCLE_MEM_CHAIN_PRI 4
+#define PL230_CTRL_CYCLE_MEM_CHAIN_ALT 5
+#define PL230_CTRL_CYCLE_DEV_CHAIN_PRI 6
+#define PL230_CTRL_CYCLE_DEV_CHAIN_ALT 7
+
+#define PL230_CTRL_RPWR_1  0
+#define PL230_CTRL_RPWR_2  1
+#define PL230_CTRL_RPWR_4  2
+#define PL230_CTRL_RPWR_8  3
+#define PL230_CTRL_RPWR_16 4
+
+#define PL230_XFER_B    0
+#define PL230_XFER_H    1
+#define PL230_XFER_W    2
+
+/* --------------------------------------------------------------- */
+/*  Initialize DMA data structure                                  */
+/* --------------------------------------------------------------- */
+void dma_pl230_data_struct_init(void);
+
+/* --------------------------------------------------------------- */
+/*  Initialize DMA PL230                                           */
+/* --------------------------------------------------------------- */
+void dma_pl230_init_dbg(unsigned int chan_mask);
+void dma_pl230_init(unsigned int chan_mask);
+
+/* --------------------------------------------------------------- */
+/*  Check DMA PL230 DMA channel(s) active (return 0 when finishes) */
+/* --------------------------------------------------------------- */
+unsigned int dma_pl230_channel_active(unsigned int chan_mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DMA_PL230_MCU_H */
+
diff --git a/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/makefile b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e756fd7f50fcf556e424ffd8a464032820bf1a84
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/testcodes/aes128_tests/makefile
@@ -0,0 +1,258 @@
+#-----------------------------------------------------------------------------
+# 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-2013 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
+#-----------------------------------------------------------------------------
+#
+# Cortex-M System Design Kit software compilation make file
+#
+#-----------------------------------------------------------------------------
+#
+#  Configurations
+#
+# Choose the core instantiated, can be
+#  - CORTEX_M0
+#  - CORTEX_M0PLUS
+CPU_PRODUCT = CORTEX_M0
+
+# Shared software directory
+SOFTWARE_DIR = ../../../../software
+CMSIS_DIR    = $(SOFTWARE_DIR)/cmsis
+CORE_DIR     = $(CMSIS_DIR)/CMSIS/Include
+
+ifeq ($(CPU_PRODUCT),CORTEX_M0PLUS)
+  DEVICE_DIR   = $(CMSIS_DIR)/Device/ARM/CMSDK_CM0plus
+else
+  DEVICE_DIR   = $(CMSIS_DIR)/Device/ARM/CMSDK_CM0
+endif
+
+# Program file
+TESTNAME     = aes128_tests
+
+# Endian Option
+COMPILE_BIGEND = 0
+
+# Configuration
+ifeq ($(CPU_PRODUCT),CORTEX_M0PLUS)
+  USER_DEFINE    = -DCORTEX_M0PLUS
+else
+  USER_DEFINE    = -DCORTEX_M0
+endif
+
+DEPS_LIST       = makefile
+
+# Tool chain : ds5 / gcc / keil
+TOOL_CHAIN      = ds5
+
+ifeq ($(TOOL_CHAIN),ds5)
+  ifeq ($(CPU_PRODUCT),CORTEX_M0PLUS)
+    CPU_TYPE        = --cpu Cortex-M0plus
+  else
+    CPU_TYPE        = --cpu Cortex-M0
+  endif
+endif
+
+ifeq ($(TOOL_CHAIN),gcc)
+  ifeq ($(CPU_PRODUCT),CORTEX_M0PLUS)
+    CPU_TYPE        = -mcpu=cortex-m0plus
+  else
+    CPU_TYPE        = -mcpu=cortex-m0
+  endif
+endif
+
+# Startup code directory for DS-5
+ifeq ($(TOOL_CHAIN),ds5)
+ STARTUP_DIR  = $(DEVICE_DIR)/Source/ARM
+endif
+
+# Startup code directory for gcc
+ifeq ($(TOOL_CHAIN),gcc)
+ STARTUP_DIR  = $(DEVICE_DIR)/Source/GCC
+endif
+
+ifeq ($(CPU_PRODUCT),CORTEX_M0PLUS)
+  STARTUP_FILE = startup_CMSDK_CM0plus
+  SYSTEM_FILE  = system_CMSDK_CM0plus
+else
+  STARTUP_FILE = startup_CMSDK_CM0
+  SYSTEM_FILE  = system_CMSDK_CM0
+endif
+
+# ---------------------------------------------------------------------------------------
+# DS-5 options
+
+# MicroLIB option
+COMPILE_MICROLIB = 0
+
+# Small Multiply (Cortex-M0/M0+ has small multiplier option)
+COMPILE_SMALLMUL = 0
+
+#ARM_CC_OPTIONS   = -c -O3 -g -Otime -I $(DEVICE_DIR)/Include  -I $(CORE_DIR) \
+#		   -I $(SOFTWARE_DIR)/common/retarget $(USER_DEFINE)
+#ARM_ASM_OPTIONS  = -g
+#ARM_LINK_OPTIONS = "--keep=$(STARTUP_FILE).o(RESET)" "--first=$(STARTUP_FILE).o(RESET)" \
+#		   --rw_base 0x30000000 --ro_base 0x00000000 --map  --info sizes
+
+ARM_CC_OPTIONS   = -c -O3 -Ospace -I $(DEVICE_DIR)/Include  -I $(CORE_DIR) \
+		   -I $(SOFTWARE_DIR)/common/retarget $(USER_DEFINE)
+ARM_ASM_OPTIONS  = 
+ARM_LINK_OPTIONS = "--keep=$(STARTUP_FILE).o(RESET)" "--first=$(STARTUP_FILE).o(RESET)" \
+		   --no_debug --rw_base 0x30000000 --ro_base 0x00000000 --map  --info sizes
+
+ifeq ($(COMPILE_BIGEND),1)
+ # Big Endian
+ ARM_CC_OPTIONS   += --bigend
+ ARM_ASM_OPTIONS  += --bigend
+ ARM_LINK_OPTIONS += --be8
+endif
+
+ifeq ($(COMPILE_MICROLIB),1)
+ # MicroLIB
+ ARM_CC_OPTIONS   += --library_type=microlib
+ ARM_ASM_OPTIONS  += --library_type=microlib --pd "__MICROLIB SETA 1"
+ ARM_LINK_OPTIONS += --library_type=microlib
+endif
+
+ifeq ($(COMPILE_SMALLMUL),1)
+ # In Cortex-M0, small multiply takes 32 cycles
+ ARM_CC_OPTIONS   += --multiply_latency=32
+endif
+
+# ---------------------------------------------------------------------------------------
+# gcc options
+
+GNG_CC      = arm-none-eabi-gcc
+GNU_OBJDUMP = arm-none-eabi-objdump
+GNU_OBJCOPY = arm-none-eabi-objcopy
+
+LINKER_SCRIPT_PATH = $(SOFTWARE_DIR)/common/scripts
+LINKER_SCRIPT = $(LINKER_SCRIPT_PATH)/cmsdk_cm0.ld
+
+GNU_CC_FLAGS = -g -O3 -mthumb $(CPU_TYPE)
+
+ifeq ($(COMPILE_BIGEND),1)
+ # Big Endian
+ GNU_CC_FLAGS   += -mbig-endian
+endif
+
+# ---------------------------------------------------------------------------------------
+all: all_$(TOOL_CHAIN)
+
+# ---------------------------------------------------------------------------------------
+# DS-5
+all_ds5 : $(TESTNAME).hex $(TESTNAME).lst
+
+$(TESTNAME).o :  $(TESTNAME).c $(DEPS_LIST)
+	armcc $(ARM_CC_OPTIONS) $(CPU_TYPE) $< -o  $@
+
+dma_pl230_driver.o :  dma_pl230_driver.c $(DEPS_LIST)
+	armcc $(ARM_CC_OPTIONS) $(CPU_TYPE) $< -o $@
+
+$(SYSTEM_FILE).o : $(DEVICE_DIR)/Source/$(SYSTEM_FILE).c $(DEPS_LIST)
+	armcc $(ARM_CC_OPTIONS) $(CPU_TYPE) $< -o  $@
+
+retarget.o : $(SOFTWARE_DIR)/common/retarget/retarget.c $(DEPS_LIST)
+	armcc $(ARM_CC_OPTIONS) $(CPU_TYPE) $< -o  $@
+
+uart_stdout.o : $(SOFTWARE_DIR)/common/retarget/uart_stdout.c $(DEPS_LIST)
+	armcc $(ARM_CC_OPTIONS) $(CPU_TYPE) $< -o  $@
+
+$(STARTUP_FILE).o : $(STARTUP_DIR)/$(STARTUP_FILE).s $(DEPS_LIST)
+	armasm $(ARM_ASM_OPTIONS) $(CPU_TYPE) $< -o  $@
+
+$(TESTNAME).ELF : $(TESTNAME).o dma_pl230_driver.o $(SYSTEM_FILE).o $(STARTUP_FILE).o retarget.o uart_stdout.o
+	armlink $(ARM_LINK_OPTIONS) -o $@ $(TESTNAME).o dma_pl230_driver.o $(SYSTEM_FILE).o $(STARTUP_FILE).o retarget.o uart_stdout.o
+
+$(TESTNAME).hex : $(TESTNAME).ELF
+	fromelf --vhx --8x1 $< --output $@
+
+$(TESTNAME).lst : $(TESTNAME).ELF
+	fromelf -c -d -e -s -z -v $< --output $@
+
+# ---------------------------------------------------------------------------------------
+# gcc
+all_gcc:
+	$(GNG_CC) $(GNU_CC_FLAGS) $(STARTUP_DIR)/$(STARTUP_FILE).s \
+		$(TESTNAME).c \
+		$(SOFTWARE_DIR)/common/retarget/retarget.c \
+		$(SOFTWARE_DIR)/common/retarget/uart_stdout.c \
+		$(DEVICE_DIR)/Source/$(SYSTEM_FILE).c \
+		-I $(DEVICE_DIR)/Include -I $(CORE_DIR) \
+                -I $(SOFTWARE_DIR)/common/retarget  \
+		-L $(LINKER_SCRIPT_PATH) \
+		-D__STACK_SIZE=0x200 \
+		-D__HEAP_SIZE=0x1000 \
+		$(USER_DEFINE) -T $(LINKER_SCRIPT) -o $(TESTNAME).o
+	# Generate disassembly code
+	$(GNU_OBJDUMP) -S $(TESTNAME).o > $(TESTNAME).lst
+	# Generate binary file
+	$(GNU_OBJCOPY) -S $(TESTNAME).o -O binary $(TESTNAME).bin
+	# Generate hex file
+	$(GNU_OBJCOPY) -S $(TESTNAME).o -O verilog $(TESTNAME).hex
+
+# Note:
+# If the version of object copy you are using does not support verilog hex file output,
+# you can generate the hex file from binary file using the following command
+#       od -v -A n -t x1 --width=1  $(TESTNAME).bin > $(TESTNAME).hex
+
+
+# ---------------------------------------------------------------------------------------
+# Keil MDK
+
+all_keil:
+	@echo "Please compile your project code and press ENTER when ready"
+	@read dummy
+
+# ---------------------------------------------------------------------------------------
+# Binary
+
+all_bin: $(TESTNAME).bin
+	# Generate hex file from binary
+	od -v -A n -t x1 --width=1  $(TESTNAME).bin > $(TESTNAME).hex
+
+# ---------------------------------------------------------------------------------------
+# Clean
+clean :
+	@rm -rf *.o
+	@if [ -e $(TESTNAME).hex ] ; then \
+	  rm -rf $(TESTNAME).hex ; \
+	fi
+	@if [ -e $(TESTNAME).lst ] ; then \
+	  rm -rf $(TESTNAME).lst ; \
+	fi
+	@if [ -e $(TESTNAME).ELF ] ; then \
+	  rm -rf $(TESTNAME).ELF ; \
+	fi
+	@if [ -e $(TESTNAME).bin ] ; then \
+	  rm -rf $(TESTNAME).bin ; \
+	fi
+	@rm -rf *.crf
+	@rm -rf *.plg
+	@rm -rf *.tra
+	@rm -rf *.htm
+	@rm -rf *.map
+	@rm -rf *.dep
+	@rm -rf *.d
+	@rm -rf *.lnp
+	@rm -rf *.bak
+	@rm -rf *.lst
+	@rm -rf *.axf
+	@rm -rf *.sct
+	@rm -rf *.__i
+	@rm -rf *._ia
diff --git a/Cortex-M0/nanosoc/systems/mcu/v2html_doc.tgz b/Cortex-M0/nanosoc/systems/mcu/v2html_doc.tgz
index d5bfa253f348ce3b67ec8f288e8eefeaf27c051e..a371e317a9e60c2ad3e07ad0bbf81e7dd936cde3 100644
Binary files a/Cortex-M0/nanosoc/systems/mcu/v2html_doc.tgz and b/Cortex-M0/nanosoc/systems/mcu/v2html_doc.tgz differ
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/aes128_log_to_file.v b/Cortex-M0/nanosoc/systems/mcu/verilog/aes128_log_to_file.v
new file mode 100644
index 0000000000000000000000000000000000000000..bc190d8eca21de47cc2d5413ec4f78da1e4487f7
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/aes128_log_to_file.v
@@ -0,0 +1,308 @@
+//-----------------------------------------------------------------------------
+// AHB transaction logger, developed for DMA integration testing
+// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+//
+// Contributors
+//
+// David Flynn (d.w.flynn@soton.ac.uk)
+//
+// Copyright (C) 2023, SoC Labs (www.soclabs.org)
+//-----------------------------------------------------------------------------
+
+module aes128_log_to_file
+  #(parameter FILENAME = "aes128.log",
+    parameter TIMESTAMP = 1)
+  (
+  input  wire        ahb_hclk,      // Clock
+  input  wire        ahb_hresetn,   // Reset
+  input  wire        ahb_hsel,      // Device select
+  input  wire [15:0] ahb_haddr16,   // Address for byte select
+  input  wire  [1:0] ahb_htrans,    // Transfer control
+  input  wire  [2:0] ahb_hsize,     // Transfer size
+  input  wire  [3:0] ahb_hprot,     // Protection control
+  input  wire        ahb_hwrite,    // Write control
+  input  wire        ahb_hready,    // Transfer phase done
+  input  wire [31:0] ahb_hwdata,    // Write data
+  input  wire        ahb_hreadyout, // Device ready
+  input  wire [31:0] ahb_hrdata,    // Read data output
+  input  wire        ahb_hresp,     // Device response
+// stream data
+  input  wire        drq_ipdma128,  // (to) DMAC input burst request
+  input  wire        dlast_ipdma128,// (from) DMAC input burst end (last transfer)
+  input  wire        drq_opdma128,  // (to) DMAC output dma burst request
+  input  wire        dlast_opdma128,// (from) DMAC output burst end (last transfer)
+  input  wire        irq_key128,
+  input  wire        irq_ip128,
+  input  wire        irq_op128,
+  input  wire        irq_error,
+  input  wire        irq_merged     // combined interrrupt request (to CPU)
+  );
+
+
+// CORE ID
+  localparam ADDR_CORE_NAME0  = 16'h0000;
+  localparam ADDR_CORE_NAME1  = 16'h0004;
+  localparam ADDR_CORE_VERSION= 16'h0008;
+  localparam CORE_NAME0       = 32'h61657331; // "aes1"
+  localparam CORE_NAME1       = 32'h32382020; // "28  "
+  localparam CORE_VERSION     = 32'h302e3031; // "0.01"
+
+// CTRL control register with bit-set/bit-clear options
+  localparam ADDR_CTRL        = 16'h0010;
+  localparam ADDR_CTRL_SET    = 16'h0014;
+  localparam ADDR_CTRL_CLR    = 16'h0018;
+  localparam CTRL_REG_WIDTH   = 8;
+  localparam CTRL_BIT_MAX     = (CTRL_REG_WIDTH-1);
+  localparam CTRL_KEY_REQ_BIT = 0;
+  localparam CTRL_IP_REQ_BIT  = 1;
+  localparam CTRL_OP_REQ_BIT  = 2;
+  localparam CTRL_ERR_REQ_BIT = 3;
+  localparam CTRL_KEYOK_BIT   = 4;
+  localparam CTRL_VALID_BIT   = 5;
+  localparam CTRL_BYPASS_BIT  = 6;
+  localparam CTRL_ENCODE_BIT  = 7;
+// STAT status regisyer 
+  localparam ADDR_STAT        = 16'h001c;
+  localparam STAT_REG_WIDTH   = 8;
+  localparam STAT_BIT_MAX     = (STAT_REG_WIDTH-1);
+  localparam STAT_KEYREQ_BIT  = 0;
+  localparam STAT_INPREQ_BIT  = 1;
+  localparam STAT_OUTREQ_BIT  = 2;
+  localparam STAT_ERROR_BIT   = 3;
+  localparam STAT_KEYOK_BIT   = 4;
+  localparam STAT_VALID_BIT   = 5;
+
+// QUAL qualifier field
+  localparam ADDR_QUAL        = 16'h0020;
+  localparam QUAL_REG_WIDTH   = 32;
+  localparam QUAL_BIT_MAX     = (QUAL_REG_WIDTH-1);
+
+// DREQ DMAC request control with bit-set/bit-clear options
+  localparam ADDR_DREQ        = 16'h0030;
+  localparam ADDR_DREQ_SET    = 16'h0034;
+  localparam ADDR_DREQ_CLR    = 16'h0038;
+  localparam ADDR_DREQ_ACT    = 16'h003c;
+  localparam DREQ_REG_WIDTH   = 3;
+  localparam DREQ_BIT_MAX     = (DREQ_REG_WIDTH-1);
+  localparam  REQ_KEYBUF_BIT  = 0;
+  localparam  REQ_IP_BUF_BIT  = 1;
+  localparam  REQ_OP_BUF_BIT  = 2;
+
+// IREQ CPU interrupt request control with bit-set/bit-clear options
+  localparam ADDR_IREQ        = 16'h0040;
+  localparam ADDR_IREQ_SET    = 16'h0044;
+  localparam ADDR_IREQ_CLR    = 16'h0048;
+  localparam ADDR_IREQ_ACT    = 16'h004c;
+  localparam IREQ_REG_WIDTH   = 4;
+  localparam IREQ_BIT_MAX     = (IREQ_REG_WIDTH-1);
+  localparam  REQ_ERROR_BIT   = 3;
+
+  localparam ADDR_KEY_BASE    = 16'h4000;
+  localparam ADDR_KEY0        = 16'h4000;
+  localparam ADDR_KEY3        = 16'h400c;
+  localparam ADDR_KEY7        = 16'h401c;
+
+  localparam ADDR_IBUF_BASE   = 16'h8000;
+  localparam ADDR_IBUF_0      = 16'h8000;
+  localparam ADDR_IBUF_3      = 16'h800c;
+
+  localparam ADDR_OBUF_BASE   = 16'hc000;
+  localparam ADDR_OBUF_3      = 16'hc00c;
+
+ // AHB transction de-pipelining
+ 
+  // --------------------------------------------------------------------------
+  // Internal regs/wires
+  // --------------------------------------------------------------------------
+
+  reg          sel_r;
+  reg   [15:0] addr16_r;
+  reg          wcyc_r;
+  reg          rcyc_r;
+  reg    [3:0] byte4_r;
+  reg    [3:0] dma_ctrl_state_r;
+  
+  // --------------------------------------------------------------------------
+  // AHB slave byte buffer interface, support for unaligned data transfers
+  // --------------------------------------------------------------------------
+
+  wire   [1:0] byte_addr = ahb_haddr16[1:0];
+  // generate next byte enable decodes for Word/Half/Byte CPU/DMA accesses
+  wire   [3:0] byte_nxt;
+  assign byte_nxt[0] = (ahb_hsize[1])|((ahb_hsize[0])&(!byte_addr[1]))|(byte_addr[1:0]==2'b00);
+  assign byte_nxt[1] = (ahb_hsize[1])|((ahb_hsize[0])&(!byte_addr[1]))|(byte_addr[1:0]==2'b01);
+  assign byte_nxt[2] = (ahb_hsize[1])|((ahb_hsize[0])&( byte_addr[1]))|(byte_addr[1:0]==2'b10);
+  assign byte_nxt[3] = (ahb_hsize[1])|((ahb_hsize[0])&( byte_addr[1]))|(byte_addr[1:0]==2'b11);
+
+  // de-pipelined registered access signals
+  always @(posedge ahb_hclk or negedge ahb_hresetn)
+    if (!ahb_hresetn)
+    begin
+      addr16_r <= 16'h0000;
+      sel_r    <= 1'b0;
+      wcyc_r   <= 1'b0;
+      rcyc_r   <= 1'b0;
+      byte4_r  <= 4'b0000;
+    end else if (ahb_hready)
+    begin
+      addr16_r <= (ahb_hsel & ahb_htrans[1]) ?  ahb_haddr16 : addr16_r;
+      sel_r    <= (ahb_hsel & ahb_htrans[1]);
+      wcyc_r   <= (ahb_hsel & ahb_htrans[1]  &  ahb_hwrite);
+      rcyc_r   <= (ahb_hsel & ahb_htrans[1]  & !ahb_hwrite);
+      byte4_r  <= (ahb_hsel & ahb_htrans[1]) ?  byte_nxt[3:0] : 4'b0000;
+    end 
+
+  wire [31:0] ahb_hdata = (wcyc_r)? ahb_hwdata : ahb_hrdata;
+
+ //----------------------------------------------
+ //-- File I/O
+ //----------------------------------------------
+
+   integer        fd;       // channel descriptor for cmd file input
+   integer        ch;
+
+    reg           drq_ipdma128_prev;
+    reg           dlast_ipdma128_prev;
+    reg           drq_opdma128_prev;
+    reg           dlast_opdma128_prev;
+    reg           irq_key128_prev;
+    reg           irq_ip128_prev;
+    reg           irq_op128_prev;
+    reg           irq_error_prev;
+    reg           irq_merged_prev;
+
+    wire          drq_ipdma128_change;
+    wire          dlast_ipdma128_change;
+    wire          drq_opdma128_change;
+    wire          dlast_opdma128_change;
+    wire          irq_key128_change;
+    wire          irq_ip128_change;
+    wire          irq_op128_change;
+    wire          irq_error_change;
+    wire          irq_merged_change;
+    wire          irq_change;
+    wire          drq_change;
+    wire          any_change;
+        
+    reg [31:0]     cyc_count;
+`define EOF -1
+
+  reg [7:0] ctrl_reg;
+  reg [2:0] dreq_reg;
+  reg [2:0] ireq_reg;
+  
+  always @(posedge ahb_hclk or negedge ahb_hresetn)
+    if (!ahb_hresetn)
+    begin
+       drq_ipdma128_prev   <= 1'b0;
+       dlast_ipdma128_prev <= 1'b0;
+       drq_opdma128_prev   <= 1'b0;
+       dlast_opdma128_prev <= 1'b0;
+       irq_key128_prev     <= 1'b0;
+       irq_ip128_prev      <= 1'b0;
+       irq_op128_prev      <= 1'b0;
+       irq_error_prev      <= 1'b0;
+       irq_merged_prev     <= 1'b0;
+    end else if (ahb_hready)
+    begin
+       drq_ipdma128_prev   <= drq_ipdma128  ;
+       dlast_ipdma128_prev <= dlast_ipdma128;
+       drq_opdma128_prev   <= drq_opdma128  ;
+       dlast_opdma128_prev <= dlast_opdma128;
+       irq_key128_prev     <= irq_key128    ;
+       irq_ip128_prev      <= irq_ip128     ;
+       irq_op128_prev      <= irq_op128     ;
+       irq_error_prev      <= irq_error     ;
+       irq_merged_prev     <= irq_merged    ;
+    end 
+
+    assign drq_ipdma128_change   = (drq_ipdma128_prev   ^ drq_ipdma128  );
+    assign dlast_ipdma128_change = (dlast_ipdma128_prev ^ dlast_ipdma128);
+    assign drq_opdma128_change   = (drq_opdma128_prev   ^ drq_opdma128  );
+    assign dlast_opdma128_change = (dlast_opdma128_prev ^ dlast_opdma128);
+    assign drq_change            =   drq_ipdma128_change |   drq_opdma128_change
+                                 | dlast_ipdma128_change | dlast_opdma128_change;
+    assign irq_key128_change     = (irq_key128_prev     ^ irq_key128    );
+    assign irq_ip128_change      = (irq_ip128_prev      ^ irq_ip128     );
+    assign irq_op128_change      = (irq_op128_prev      ^ irq_op128     );
+    assign irq_error_change      = (irq_error_prev      ^ irq_error     );
+    assign irq_change            = irq_key128_change | irq_ip128_change
+                                 | irq_op128_change | irq_error_change;
+
+    assign any_change = drq_ipdma128_change
+                      | dlast_ipdma128_change
+                      | drq_opdma128_change
+                      | dlast_opdma128_change
+                      | irq_key128_change
+                      | irq_ip128_change
+                      | irq_op128_change
+                      | irq_error_change
+                      | irq_merged_change
+                      ;
+                         
+   initial
+     begin
+       fd= $fopen(FILENAME,"w");
+       cyc_count <= 0;
+       if (fd == 0)
+          $write("** %m : output log file failed to open **\n");
+       else begin
+         @(posedge ahb_hresetn);
+         while (1) begin
+           @(posedge ahb_hclk);
+           cyc_count <= cyc_count +1;
+           if (sel_r & ahb_hready) begin
+             $fwrite(fd, "AES-C: ");
+             case ({addr16_r[15:2],2'b00})
+               ADDR_CORE_NAME0   : begin $fwrite(fd, "CORE_NAME0  ");    end
+               ADDR_CORE_NAME1   : begin $fwrite(fd, "CORE_NAME1  ");    end
+               ADDR_CORE_VERSION : begin $fwrite(fd, "CORE_VERSION");  end
+               ADDR_CTRL         : begin $fwrite(fd, "CTRL        ");  if (wcyc_r) ctrl_reg <= ahb_hwdata[7:0];            end
+               ADDR_CTRL_SET     : begin $fwrite(fd, "CTRL_SET    ");  if (wcyc_r) ctrl_reg <= ctrl_reg | ahb_hwdata[7:0]; end
+               ADDR_CTRL_CLR     : begin $fwrite(fd, "CTRL_CLR    ");  if (wcyc_r) ctrl_reg <= ctrl_reg &~ahb_hwdata[7:0]; end
+               ADDR_STAT         : begin $fwrite(fd, "STAT        ");  end
+               ADDR_QUAL         : begin $fwrite(fd, "QUAL        ");  end
+               ADDR_DREQ         : begin $fwrite(fd, "DREQ        ");  if (wcyc_r) dreq_reg <= ahb_hwdata[2:0];            end
+               ADDR_DREQ_SET     : begin $fwrite(fd, "DREQ_SET    ");  if (wcyc_r) dreq_reg <= dreq_reg | ahb_hwdata[2:0]; end
+               ADDR_DREQ_CLR     : begin $fwrite(fd, "DREQ_CLR    ");  if (wcyc_r) dreq_reg <= dreq_reg &~ahb_hwdata[2:0]; end
+               ADDR_DREQ_ACT     : begin $fwrite(fd, "DREQ_ACT    ");  end
+               ADDR_IREQ         : begin $fwrite(fd, "IREQ        ");  end
+               ADDR_IREQ_SET     : begin $fwrite(fd, "IREQ_SET    ");  if (wcyc_r) ireq_reg <= ahb_hwdata[3:0];            end
+               ADDR_IREQ_CLR     : begin $fwrite(fd, "IREQ_CLR    ");  if (wcyc_r) ireq_reg <= ireq_reg | ahb_hwdata[3:0]; end
+               ADDR_IREQ_ACT     : begin $fwrite(fd, "IREQ_ACT    ");  if (wcyc_r) ireq_reg <= ireq_reg &~ahb_hwdata[3:0]; end
+             default:
+               if      (addr16_r[15:14] == 2'b01) $fwrite(fd, "KEYBUF128   ");
+               else if (addr16_r[15:14] == 2'b10) $fwrite(fd, "IPBUF128    ");
+               else if (addr16_r[15:14] == 2'b11) $fwrite(fd, "OPBUF128    ");
+             endcase
+               $fwrite(fd, " A+0x%04x, %s, D=0x",  addr16_r, (wcyc_r) ? "W" : "R");
+               if (byte4_r[3]) $fwrite(fd, "%02x", ahb_hdata[31:24]); else $fwrite(fd, "--");
+               if (byte4_r[2]) $fwrite(fd, "%02x", ahb_hdata[23:16]); else $fwrite(fd, "--");
+               if (byte4_r[1]) $fwrite(fd, "%02x", ahb_hdata[15: 8]); else $fwrite(fd, "--");
+               if (byte4_r[0]) $fwrite(fd, "%02x", ahb_hdata[ 7: 0]); else $fwrite(fd, "--");
+              if (TIMESTAMP) $fwrite(fd, ", CYC=%8d (@%t)\n", cyc_count, $time); else $fwrite(fd, "\n");
+           end
+           if (any_change) begin
+             $fwrite(fd, "AESRQ: ");
+             if (drq_change) begin
+               $fwrite(fd, " drq_ipdma128=%b,",drq_ipdma128);
+               $fwrite(fd, " dlast_ipdma128=%b,",dlast_ipdma128);
+               $fwrite(fd, " drq_opdma128=%b,",drq_opdma128);
+               $fwrite(fd, " dlast_opdma128=%b",dlast_opdma128);
+             end
+             if (irq_change) begin
+               if (drq_change)  $fwrite(fd, ",");
+               $fwrite(fd, " irq_merged=%b,",irq_merged);
+               $fwrite(fd, "irq_key128=%b,",irq_key128);
+               $fwrite(fd, "irq_ip128=%b,",irq_ip128);
+               $fwrite(fd, "irq_op128=%b,",irq_op128);
+               $fwrite(fd, "irq_error=%b",irq_error);
+             end
+             if (TIMESTAMP) $fwrite(fd, ", CYC=%8d (@%t)\n",cyc_count, $time); else $fwrite(fd, "\n");
+           end
+         end
+         $fclose(fd);
+       end
+     end
+
+endmodule
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/dma_log_to_file.v b/Cortex-M0/nanosoc/systems/mcu/verilog/dma_log_to_file.v
new file mode 100644
index 0000000000000000000000000000000000000000..9458671e89b82b9621086e7f223761a6db684987
--- /dev/null
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/dma_log_to_file.v
@@ -0,0 +1,254 @@
+//-----------------------------------------------------------------------------
+// AHB transaction logger, developed for DMA integration testing
+// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+//
+// Contributors
+//
+// David Flynn (d.w.flynn@soton.ac.uk)
+//
+// Copyright (C) 2023, SoC Labs (www.soclabs.org)
+//-----------------------------------------------------------------------------
+
+module dma_log_to_file
+  #(parameter FILENAME = "dma.log",
+    parameter NUM_CHNLS = 2,
+    parameter NUM_CHNL_BITS = 1,
+    parameter TIMESTAMP = 1)
+  (
+  input  wire        hclk,
+  input  wire        hresetn,
+  // AHB manager interface
+  input  wire        hready,
+  input  wire        hresp,
+  input  wire [1:0]  htrans,
+  input  wire [31:0] haddr,
+  input  wire        hwrite,
+  input  wire [3:0]  hprot,
+  input  wire [2:0]  hsize,
+  input  wire [2:0]  hburst,
+  input  wire [31:0] hwdata,
+  input  wire [31:0] hrdata,
+  // APB control interface
+  input  wire        pclken,
+  input  wire        psel,
+  input  wire        pen,
+  input  wire        pwrite,
+  input  wire [11:0] paddr,
+  input  wire [31:0] pwdata,
+  input  wire [31:0] prdata,
+  // DMA state tracking
+  input wire  [NUM_CHNLS-1:0]  dma_req,
+  input wire  [NUM_CHNLS-1:0]  dma_active,
+  input wire  [NUM_CHNLS-1:0]  dma_done,
+  input wire  [NUM_CHNL_BITS-1:0]  dma_chnl,
+  input wire  [3:0]  dma_ctrl_state
+  );
+
+function FN_one_hot_valid;
+input [NUM_CHNLS-1:0] onehot;
+integer b;
+  begin
+    FN_one_hot_valid = |onehot;
+  end
+endfunction
+
+function [NUM_CHNL_BITS:0] FN_one_hot_to_chnl;
+input [NUM_CHNLS-1:0] onehot;
+integer b;
+  begin
+    b=0;
+    while (!onehot[b])
+      b = b+1;
+    FN_one_hot_to_chnl = b;
+  end
+endfunction
+
+wire hsel = 1'b1;
+ // AHB transction de-pipelining
+ 
+  // --------------------------------------------------------------------------
+  // Internal regs/wires
+  // --------------------------------------------------------------------------
+
+  reg          sel_r;
+  reg   [31:0] addr_r;
+  reg          wcyc_r;
+  reg          rcyc_r;
+  reg    [3:0] byte4_r;
+  reg    [3:0] dma_ctrl_state_r;
+  wire  [31:0] hdata;
+  
+  
+  // --------------------------------------------------------------------------
+  // AHB slave byte buffer interface, support for unaligned data transfers
+  // --------------------------------------------------------------------------
+
+  wire   [1:0] byte_addr = haddr[1:0];
+  // generate next byte enable decodes for Word/Half/Byte CPU/DMA accesses
+  wire   [3:0] byte_nxt;
+  assign byte_nxt[0] = (hsize[1])|((hsize[0])&(!byte_addr[1]))|(byte_addr[1:0]==2'b00);
+  assign byte_nxt[1] = (hsize[1])|((hsize[0])&(!byte_addr[1]))|(byte_addr[1:0]==2'b01);
+  assign byte_nxt[2] = (hsize[1])|((hsize[0])&( byte_addr[1]))|(byte_addr[1:0]==2'b10);
+  assign byte_nxt[3] = (hsize[1])|((hsize[0])&( byte_addr[1]))|(byte_addr[1:0]==2'b11);
+
+  // de-pipelined registered access signals
+  always @(posedge hclk or negedge hresetn)
+    if (!hresetn)
+    begin
+      addr_r   <= 32'h0000;
+      sel_r    <= 1'b0;
+      wcyc_r   <= 1'b0;
+      rcyc_r   <= 1'b0;
+      byte4_r  <= 4'b0000;
+    end else if (hready)
+    begin
+      addr_r   <= (hsel & htrans[1]) ?  haddr : addr_r;
+      sel_r    <= (hsel & htrans[1]);
+      wcyc_r   <= (hsel & htrans[1]  &  hwrite);
+      rcyc_r   <= (hsel & htrans[1]  & !hwrite);
+      byte4_r  <= (hsel & htrans[1]) ?  byte_nxt[3:0] : 4'b0000;
+    end 
+
+  assign hdata = (wcyc_r)? hwdata : hrdata;
+  
+  wire dma_ctrl_state_change = |(dma_ctrl_state_r ^ dma_ctrl_state);
+
+  wire dma_control_access = pclken & pen & psel;
+
+  wire state_nowait = (dma_ctrl_state_r == 0) |  (dma_ctrl_state_r == 6)
+                    | (dma_ctrl_state_r == 8) |  (dma_ctrl_state_r == 9)
+                    | (dma_ctrl_state_r == 10) |  (dma_ctrl_state_r == 15)
+                    ;
+                    
+  wire report_cycle = (sel_r & hready) | (dma_ctrl_state_change & state_nowait);
+
+  always @(posedge hclk or negedge hresetn)
+    if (!hresetn)
+    begin
+      dma_ctrl_state_r  <= 4'b0000;
+    end else if (report_cycle)
+    begin
+      dma_ctrl_state_r <= dma_ctrl_state;
+    end 
+
+
+  reg  [NUM_CHNLS-1:0] active_one_hot_r;
+  reg  [NUM_CHNLS-1:0] done_one_hot_r;
+  
+   always @(posedge hclk or negedge hresetn)
+    if (!hresetn) begin
+      active_one_hot_r <= {NUM_CHNLS{1'b0}};
+      done_one_hot_r   <= {NUM_CHNLS{1'b0}};
+    end else begin
+      active_one_hot_r <= dma_active;
+      done_one_hot_r   <= dma_done  ;
+    end 
+ 
+   wire chnl_change = ((active_one_hot_r != dma_active) & |dma_active)
+                    | ((done_one_hot_r != dma_done) & |dma_done);
+   
+ //----------------------------------------------
+ //-- File I/O
+ //----------------------------------------------
+
+
+   integer        fd;       // channel descriptor for cmd file input
+   integer        ch;
+   reg [NUM_CHNLS-1:0] dma_req_last;
+   reg [31:0]     cyc_count;
+`define EOF -1
+
+`define PL230_ST_XC_INI 4'hB
+`define PL230_ST_XC_RDY  4'hC
+`define PL230_ST_XR_SDAT 4'hD
+`define PL230_ST_XW_DDAT 4'hE
+
+   initial
+     begin
+       fd= $fopen(FILENAME,"w");
+       dma_req_last <= 2'b00;
+       cyc_count <= 0;
+       if (fd == 0)
+          $write("** %m : output log file failed to open **\n");
+       else begin
+         @(posedge hresetn);
+         while (1) begin
+           @(posedge hclk);
+           cyc_count <= cyc_count +1;
+           if (report_cycle) begin
+             $fwrite(fd, "DMA-M: C#%02x ", dma_chnl);
+             case (dma_ctrl_state_r)
+             0 : $fwrite(fd, "PL230_ST_IDLE         ");
+             1 : $fwrite(fd, "PL230_ST_RD_CTRL [%s]", (addr_r & (16 << NUM_CHNL_BITS)) ? "ALT" : "PRI");
+             2 : $fwrite(fd, "PL230_ST_RD_SPTR [%s]", (addr_r & (16 << NUM_CHNL_BITS)) ? "ALT" : "PRI");
+             3 : $fwrite(fd, "PL230_ST_RD_DPTR [%s]", (addr_r & (16 << NUM_CHNL_BITS)) ? "ALT" : "PRI");
+             4 : $fwrite(fd, "PL230_ST_RD_SDAT      ");
+             5 : $fwrite(fd, "PL230_ST_WR_DDAT      ");
+             6 : $fwrite(fd, "PL230_ST_WAIT         ");
+             7 : $fwrite(fd, "PL230_ST_WR_CTRL [%s]", (addr_r & (16 << NUM_CHNL_BITS)) ? "ALT" : "PRI");
+             8 : $fwrite(fd, "PL230_ST_STALL        ");
+             9 : $fwrite(fd, "PL230_ST_DONE         ");
+             10: $fwrite(fd, "PL230_ST_PSGP         ");
+             11: $fwrite(fd, "PL230_ST_XC_INI*      ");
+             12: $fwrite(fd, "PL230_ST_XC_RDY*      ");
+             13: $fwrite(fd, "PL230_ST_XR_SDAT*     ");
+             14: $fwrite(fd, "PL230_ST_XW_DDAT*     ");
+             default: $fwrite(fd, "PL230_ST_RESVD   ");
+             endcase
+             case (dma_ctrl_state_r)
+             0, 6, 8, 9, 10, 11, 12, 15 :
+               $fwrite(fd, "                                  ");
+             default: begin
+               $fwrite(fd, "     A=0x%03x, %s, D=0x",  addr_r, (wcyc_r) ? "W" : "R");
+               if (byte4_r[3]) $fwrite(fd, "%02x", hdata[31:24]); else $fwrite(fd, "--");
+               if (byte4_r[2]) $fwrite(fd, "%02x", hdata[23:16]); else $fwrite(fd, "--");
+               if (byte4_r[1]) $fwrite(fd, "%02x", hdata[15: 8]); else $fwrite(fd, "--");
+               if (byte4_r[0]) $fwrite(fd, "%02x", hdata[ 7: 0]); else $fwrite(fd, "--");
+               end
+             endcase
+             if (TIMESTAMP) $fwrite(fd, ", CYC=%8d (@%t)\n", cyc_count, $time); else $fwrite(fd, "\n");
+           end
+           if (dma_control_access) begin
+             $fwrite(fd, "DMA-C:      ");
+             case (paddr[11:2])
+             0 : $fwrite(fd, "PL230_DMA_STATUS          ");
+             1 : $fwrite(fd, "PL230_DMA_CFG             ");
+             2 : $fwrite(fd, "PL230_CTRL_BASE_PTR       ");
+             3 : $fwrite(fd, "PL230_ALT_CTRL_BASE_PTR   ");
+             4 : $fwrite(fd, "PL230_DMA_WAITONREQ_STATUS");
+             5 : $fwrite(fd, "PL230_CHNL_SW_REQUEST     ");
+             6 : $fwrite(fd, "PL230_CHNL_USEBURST_SET   ");
+             7 : $fwrite(fd, "PL230_CHNL_USEBURST_CLR   ");
+             8 : $fwrite(fd, "PL230_CHNL_REQ_MASK_SET   ");
+             9 : $fwrite(fd, "PL230_CHNL_REQ_MASK_CLR   ");
+             10: $fwrite(fd, "PL230_CHNL_ENABLE_SET     ");
+             11: $fwrite(fd, "PL230_CHNL_ENABLE_CLR     ");
+             12: $fwrite(fd, "PL230_CHNL_PRI_ALT_SET    ");
+             13: $fwrite(fd, "PL230_CHNL_PRI_ALT_CLR    ");
+             14: $fwrite(fd, "PL230_CHNL_PRIORITY_SET   ");
+             15: $fwrite(fd, "PL230_CHNL_PRIORITY_CLR   ");
+             default: $fwrite(fd, "PL230_ADDR_RESVD          ");
+             endcase
+              $fwrite(fd, "       A+0x%03x %s, D=0x%08x", paddr, (pwrite) ? "W" : "R", (pwrite)? pwdata : prdata);
+              if (TIMESTAMP) $fwrite(fd, ", CYC=%8d (@%t)\n", cyc_count, $time); else $fwrite(fd, "\n");
+           end
+           if (dma_req != dma_req_last) begin
+              $fwrite(fd, "DMARQ: [%b]", dma_req);
+              if (TIMESTAMP) $fwrite(fd, ", CYC=%8d (@%t)\n",
+                                         cyc_count, $time); else $fwrite(fd, "\n");
+              dma_req_last <= dma_req;
+           end
+           if (chnl_change) begin
+              $fwrite(fd, "DMAIO: ");
+              if (|dma_active) $fwrite(fd, "dma_active[%d], ", FN_one_hot_to_chnl(dma_active)); else $fwrite(fd, "dma_in_active, ");
+              if (|dma_done )  $fwrite(fd, "dma_done[%d], ", FN_one_hot_to_chnl(dma_done));
+              if (TIMESTAMP)   $fwrite(fd, "CYC=%8d (@%t)\n",
+                                         cyc_count, $time); else $fwrite(fd, "\n");
+              dma_req_last <= dma_req;
+           end
+         end
+         $fclose(fd);
+       end
+     end
+
+endmodule
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/nanosoc_chip.v b/Cortex-M0/nanosoc/systems/mcu/verilog/nanosoc_chip.v
index 2474888b5e032a3238fe5045202cbee9c34aa222..1d6ebe974b114be573f9d896977509cdc4735498 100644
--- a/Cortex-M0/nanosoc/systems/mcu/verilog/nanosoc_chip.v
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/nanosoc_chip.v
@@ -73,7 +73,7 @@ module nanosoc_chip
   );
 
 localparam    CLKGATE_PRESENT = 0;
-localparam    DMA_CHANNEL_NUM = 1;
+localparam    DMA_CHANNEL_NUM = 2;
 localparam    INCLUDE_DMA = 1;
 localparam    CORTEX_M0 = 1;
 
@@ -826,6 +826,10 @@ localparam    CORTEX_M0 = 1;
 //
 // ************************************************
 
+  wire   aes128_ip_req;
+  wire   aes128_op_req;
+  wire   aes128_irq;
+   
   soclabs_ahb_aes128_ctrl u_exp_aes128 (
     .ahb_hclk        (HCLK),
     .ahb_hresetn     (HRESETn),
@@ -842,15 +846,15 @@ localparam    CORTEX_M0 = 1;
     .ahb_hrdata      (HRDATA_exp),
     .ahb_hreadyout   (HREADYOUT_exp),
     .ahb_hresp       (HRESP_exp),
-    .drq_ipdma128    ( ),
+    .drq_ipdma128    (aes128_ip_req),
     .dlast_ipdma128  (1'b0),
-    .drq_opdma128    ( ),
+    .drq_opdma128    (aes128_op_req),
     .dlast_opdma128  (1'b0),
     .irq_key128      ( ),
     .irq_ip128       ( ),
     .irq_op128       ( ),
     .irq_error       ( ),
-    .irq_merged      ( )
+    .irq_merged      (aes128_irq)
   );
  
 //  // Default slave
@@ -1145,7 +1149,7 @@ localparam AWRAM9 = ADDR_WIDTH_RAM; // Address width - to match RAM instance siz
   assign adp_gpi8 = adp_gpo8;
   assign ADPRESETREQ = adp_gpo8[0];
 
-  // DMA controller present
+  // ADP debug controller present
   ADPcontrol_v1_0 u_ADP (
   // Clock and Reset
     .ahb_hclk          (HCLK),
@@ -1212,7 +1216,7 @@ localparam AWRAM9 = ADDR_WIDTH_RAM; // Address width - to match RAM instance siz
     .RXOVRINT          ( ),    // Receive  Overrun Interrupt
     .UARTINT           ( ) // Combined Interrupt
   );
-
+  
   wire        [7:0]  ft_clkdiv = 8'd03;
 
   ft1248_streamio_v1_0 #
@@ -1246,9 +1250,12 @@ localparam AWRAM9 = ADDR_WIDTH_RAM; // Address width - to match RAM instance siz
 //----------------------------------------
 
   // DMA interface not used in this example system
-  wire  [DMA_CHANNEL_NUM-1:0] dma230_tie0;  // tie off signal.
+  wire  [DMA_CHANNEL_NUM-1:0] dma230_req;  // tie off signal.
+  wire  [DMA_CHANNEL_NUM-1:0] dma230_tie0 = {DMA_CHANNEL_NUM{1'b0}};
+
+  assign dma230_req[0] = aes128_ip_req;
+  assign dma230_req[1] = aes128_op_req;
 
-  assign dma230_tie0 = {DMA_CHANNEL_NUM{1'b0}};
 
   // DMA done per channel
   wire  [DMA_CHANNEL_NUM-1:0] dma230_done_ch;
@@ -1262,8 +1269,8 @@ localparam AWRAM9 = ADDR_WIDTH_RAM; // Address width - to match RAM instance siz
     .hclk          (HCLK),
     .hresetn       (HRESETn),
   // DMA Control
-    .dma_req       (dma230_tie0),
-    .dma_sreq      (dma230_tie0),
+    .dma_req       (dma230_req),
+    .dma_sreq      (dma230_req),
     .dma_waitonreq (dma230_tie0),
     .dma_stall     (1'b0),
     .dma_active    (),
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/pl230_defs.v b/Cortex-M0/nanosoc/systems/mcu/verilog/pl230_defs.v
index c061b99bcddb90d59d4bd00a4a06094364f70c39..dcf4f1040e44f0b5ead58276a3367e5617e91c4a 100644
--- a/Cortex-M0/nanosoc/systems/mcu/verilog/pl230_defs.v
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/pl230_defs.v
@@ -38,7 +38,7 @@
 `endif
 
 // Set the number of channels implemented
-`define PL230_CHNLS                     1
+`define PL230_CHNLS                     2
 `define PL230_CHNL_BITS                 1
 //`define PL230_ONE_CHNL
 
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/soclabs_ahb_aes128_ctrl.v b/Cortex-M0/nanosoc/systems/mcu/verilog/soclabs_ahb_aes128_ctrl.v
index 57ac73bcb88ad2b782850a5137bb35ce48f18f8f..612dd5caca6accea1c68272ff6afc3be1e42abf9 100644
--- a/Cortex-M0/nanosoc/systems/mcu/verilog/soclabs_ahb_aes128_ctrl.v
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/soclabs_ahb_aes128_ctrl.v
@@ -77,7 +77,7 @@ module soclabs_ahb_aes128_ctrl(
   localparam ADDR_CORE_VERSION= 16'h0008;
   localparam CORE_NAME0       = 32'h61657331; // "aes1"
   localparam CORE_NAME1       = 32'h32382020; // "28  "
-  localparam CORE_VERSION     = 32'h302e3630; // "0.01"
+  localparam CORE_VERSION     = 32'h302e3031; // "0.01"
 
 // CTRL control register with bit-set/bit-clear options
   localparam ADDR_CTRL        = 16'h0010;
@@ -235,7 +235,7 @@ module soclabs_ahb_aes128_ctrl(
      irq_enable <= {IREQ_REG_WIDTH{1'b0}};
      end
    else if (sel_mode & wcyc_r & byte4_r[0])
-     case (addr16_r)
+     case ({addr16_r[15:2],2'b00})
        ADDR_CTRL    : control    <=  ahb_hwdata[CTRL_BIT_MAX:0];              // overwrite ctl reg
        ADDR_CTRL_SET: control    <=  ahb_hwdata[CTRL_BIT_MAX:0] | control;    // bit set ctl mask pattern
        ADDR_CTRL_CLR: control    <= ~ahb_hwdata[CTRL_BIT_MAX:0] & control;    // bit clear ctl mask pattern
@@ -266,7 +266,7 @@ reg [31:0] rdata32; // mux read data
     begin : read_decoder
       rdata32  = 32'hbad0bad;
       if (sel_r & rcyc_r)
-        case (addr16_r)
+        case ({addr16_r[15:2],2'b00})
           ADDR_CORE_NAME0   : rdata32 = CORE_NAME0; 
           ADDR_CORE_NAME1   : rdata32 = CORE_NAME1; 
           ADDR_CORE_VERSION : rdata32 = CORE_VERSION;
@@ -381,6 +381,7 @@ reg  aes_key_busy;
 reg  aes_key_rdy;
 reg  aes_res_busy;
 reg  aes_res_rdy;
+reg  aes_err;
 
   always @(posedge ahb_hclk or negedge ahb_hresetn)
     if (!ahb_hresetn) begin
@@ -391,6 +392,7 @@ reg  aes_res_rdy;
       aes_key_rdy   <= 1'b0;
       aes_res_busy  <= 1'b0;
       aes_res_rdy   <= 1'b0;
+      aes_err       <= 1'b0;
     end else begin
       aes_ready_del <= aes_ready; // delay for rising edge detect
       aes_init      <= aes_keyloaded_pulse;
@@ -401,30 +403,32 @@ reg  aes_res_rdy;
       aes_res_busy  <= (aes_next) | (aes_res_busy & !(aes_ready & !aes_ready_del)); // hold until block processing done
       aes_res_rdy   <= (aes_res_busy & aes_ready & !aes_ready_del) // block ready
                      | (aes_res_rdy & !op128_load_ack);           // hold until output transferred
+      aes_err       <= (!aes_key_rdy & ((sel_ipbuf & wcyc_r) | (sel_opbuf & rcyc_r)))
+                     | (aes_err & !(sel_keybuf & wcyc_r));
     end
 
-  assign drq_active[REQ_KEYBUF_BIT] = control[CTRL_KEY_REQ_BIT] | (!aes_key_busy & !aes_key_rdy & !wlast128);
-  assign drq_active[REQ_IP_BUF_BIT] = control[CTRL_IP_REQ_BIT] | (!aes_res_busy & !aes_res_rdy & aes_key_rdy & !wlast128);
-  assign drq_active[REQ_OP_BUF_BIT] = control[CTRL_OP_REQ_BIT] | (!aes_res_busy &  aes_res_rdy & !rlast128);
+  assign drq_active[REQ_KEYBUF_BIT] = control[CTRL_KEY_REQ_BIT] | (!aes_keyloaded_pulse & !aes_init & !aes_key_busy & !aes_key_rdy);
+  assign drq_active[REQ_IP_BUF_BIT] = control[CTRL_IP_REQ_BIT] | (!aes_dataloaded_pulse & !aes_next & !aes_res_busy & !aes_res_rdy & aes_key_rdy);
+  assign drq_active[REQ_OP_BUF_BIT] = control[CTRL_OP_REQ_BIT] | (!aes_res_busy &  aes_res_rdy);
 
 // input DMA channel shared by Key and Data-In
-  assign drq_ipdma128 = (drq_enable[REQ_KEYBUF_BIT] & drq_active[REQ_KEYBUF_BIT]) // if key DMA enabled
-                      | (drq_enable[REQ_IP_BUF_BIT] & drq_active[REQ_IP_BUF_BIT]) // if ip128 DMA requested
+  assign drq_ipdma128 = (drq_enable[REQ_KEYBUF_BIT] & drq_active[REQ_KEYBUF_BIT] & !wlast128) // if key DMA enabled
+                      | (drq_enable[REQ_IP_BUF_BIT] & drq_active[REQ_IP_BUF_BIT] & !wlast128) // if ip128 DMA requested
                       ;
                       
 // output DMA channel for Data-Out
-  assign drq_opdma128 = (drq_enable[REQ_OP_BUF_BIT]  & drq_active[REQ_OP_BUF_BIT]); // if op128 DMA requested
+  assign drq_opdma128 = (drq_enable[REQ_OP_BUF_BIT]  & drq_active[REQ_OP_BUF_BIT] & !rlast128); // if op128 DMA requested
 
 // and Interrupt requests are masked out if corresponding DMA requests are enabled
   assign irq_active[REQ_KEYBUF_BIT] = drq_active[REQ_KEYBUF_BIT] & !drq_enable[REQ_KEYBUF_BIT];
   assign irq_active[REQ_IP_BUF_BIT] = drq_active[REQ_IP_BUF_BIT] & !drq_enable[REQ_IP_BUF_BIT];
   assign irq_active[REQ_OP_BUF_BIT] = drq_active[REQ_OP_BUF_BIT] & !drq_enable[REQ_OP_BUF_BIT];
-  assign irq_active[REQ_ERROR_BIT ] = control[CTRL_ERR_REQ_BIT] | (!aes_res_busy & !aes_key_rdy); // error raised in SW
+  assign irq_active[REQ_ERROR_BIT ] = control[CTRL_ERR_REQ_BIT] | aes_err; // error raised in SW
 
-  assign irq_key128 = irq_active[REQ_KEYBUF_BIT] & !drq_active[REQ_KEYBUF_BIT];
-  assign irq_ip128  = irq_active[REQ_IP_BUF_BIT] & !drq_active[REQ_IP_BUF_BIT];
-  assign irq_op128  = irq_active[REQ_OP_BUF_BIT] & !drq_active[REQ_OP_BUF_BIT];
-  assign irq_error  = irq_active[REQ_ERROR_BIT ];
+  assign irq_key128 = irq_active[REQ_KEYBUF_BIT] & irq_enable[REQ_KEYBUF_BIT];
+  assign irq_ip128  = irq_active[REQ_IP_BUF_BIT] & irq_enable[REQ_IP_BUF_BIT];
+  assign irq_op128  = irq_active[REQ_OP_BUF_BIT] & irq_enable[REQ_OP_BUF_BIT];
+  assign irq_error  = irq_active[REQ_ERROR_BIT ] & irq_enable[REQ_ERROR_BIT ];
 // merge and mask if not DRQ
   assign irq_merged = irq_key128 | irq_ip128 | irq_op128 | irq_error;
   
diff --git a/Cortex-M0/nanosoc/systems/mcu/verilog/tb_nanosoc.v b/Cortex-M0/nanosoc/systems/mcu/verilog/tb_nanosoc.v
index 3e0e71660feb4528172114ea923566b598e12e63..8cea4e5d2a4d0d678decd13ecba12d9369801dbb 100644
--- a/Cortex-M0/nanosoc/systems/mcu/verilog/tb_nanosoc.v
+++ b/Cortex-M0/nanosoc/systems/mcu/verilog/tb_nanosoc.v
@@ -508,6 +508,77 @@ ft1248x1_track
 `endif // USE_TARMAC
 `endif // CORTEX_M0
 
+ // --------------------------------------------------------------------------------
+ // Tracking DMA logging support
+ // --------------------------------------------------------------------------------
+
+`define DMAC_PATH u_nanosoc_chip_pads.u_nanosoc_chip.u_pl230_udma
+
+  dma_log_to_file #(.FILENAME("dma230.log"),.NUM_CHNLS(2),.NUM_CHNL_BITS(1),.TIMESTAMP(1))
+    u_dma_log_to_file (
+    .hclk          (`DMAC_PATH.hclk),
+    .hresetn       (`DMAC_PATH.hresetn),
+  // AHB-Lite Master Interface
+    .hready        (`DMAC_PATH.hready),
+    .hresp         (`DMAC_PATH.hresp),
+    .hrdata        (`DMAC_PATH.hrdata),
+    .htrans        (`DMAC_PATH.htrans),
+    .hwrite        (`DMAC_PATH.hwrite),
+    .haddr         (`DMAC_PATH.haddr),
+    .hsize         (`DMAC_PATH.hsize),
+    .hburst        (`DMAC_PATH.hburst),
+    .hprot         (`DMAC_PATH.hprot),
+    .hwdata        (`DMAC_PATH.hwdata),
+   // APB control interface
+    .pclken        (`DMAC_PATH.pclken),
+    .psel          (`DMAC_PATH.psel),
+    .pen           (`DMAC_PATH.pen),
+    .pwrite        (`DMAC_PATH.pwrite),
+    .paddr         (`DMAC_PATH.paddr),
+    .pwdata        (`DMAC_PATH.pwdata),
+    .prdata        (`DMAC_PATH.prdata),
+  // DMA Control
+    .dma_req       (`DMAC_PATH.dma_req),
+    .dma_active    (`DMAC_PATH.dma_active),
+    .dma_done      (`DMAC_PATH.dma_done),
+   // DMA state
+    .dma_chnl      (`DMAC_PATH.u_pl230_ahb_ctrl.current_chnl),
+    .dma_ctrl_state(`DMAC_PATH.u_pl230_ahb_ctrl.ctrl_state)
+  );
+
+ // --------------------------------------------------------------------------------
+ // Tracking AES logging support
+ // --------------------------------------------------------------------------------
+
+`define AES_PATH u_nanosoc_chip_pads.u_nanosoc_chip.u_exp_aes128
+
+  aes128_log_to_file #(.FILENAME("aes128.log"),.TIMESTAMP(1))
+    u_aes_log_to_file (
+    .ahb_hclk        (`AES_PATH.ahb_hclk      ),
+    .ahb_hresetn     (`AES_PATH.ahb_hresetn   ),
+    .ahb_hsel        (`AES_PATH.ahb_hsel      ),
+    .ahb_haddr16     (`AES_PATH.ahb_haddr16   ),
+    .ahb_htrans      (`AES_PATH.ahb_htrans    ),
+    .ahb_hwrite      (`AES_PATH.ahb_hwrite    ),
+    .ahb_hsize       (`AES_PATH.ahb_hsize     ),
+    .ahb_hprot       (`AES_PATH.ahb_hprot     ),
+    .ahb_hwdata      (`AES_PATH.ahb_hwdata    ),
+    .ahb_hready      (`AES_PATH.ahb_hready    ),
+    .ahb_hrdata      (`AES_PATH.ahb_hrdata    ),
+    .ahb_hreadyout   (`AES_PATH.ahb_hreadyout ),
+    .ahb_hresp       (`AES_PATH.ahb_hresp     ),
+    .drq_ipdma128    (`AES_PATH.drq_ipdma128  ),
+    .dlast_ipdma128  (`AES_PATH.dlast_ipdma128),
+    .drq_opdma128    (`AES_PATH.drq_opdma128  ),
+    .dlast_opdma128  (`AES_PATH.dlast_opdma128),
+    .irq_key128      (`AES_PATH.irq_key128    ),
+    .irq_ip128       (`AES_PATH.irq_ip128     ),
+    .irq_op128       (`AES_PATH.irq_op128     ),
+    .irq_error       (`AES_PATH.irq_error     ),
+    .irq_merged      (`AES_PATH.irq_merged    )
+  );
+
+
  // --------------------------------------------------------------------------------
  // Debug tester connection -
  // --------------------------------------------------------------------------------