Skip to content

Commit

Permalink
Starting AxiDMA class, cleanup interrupts in UIO
Browse files Browse the repository at this point in the history
Changed the way interrupts are enabled in UIO class, can enable before
waiting now. Starting AxiDMA class, still in the notebook.
  • Loading branch information
Kirill888 committed Jan 11, 2016
1 parent 768d251 commit f7addcc
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 138 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ vivado.log
*.backup.log
*.backup.jou
*~
*.pyc
/sample/webtalk.jou
/sample/webtalk.log
/sample/.Xil/
/sample/parallella.bit
/sample/test_app/uio_mult_test
.ipynb_checkpoints
229 changes: 101 additions & 128 deletions sample/test_app/axi-dma.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,30 @@
"worksheet-0"
]
},
"outputs": [],
"source": [
"def to_bin(x):\n",
" vv = [ (x>>(32-(i+1)*4))&0xF for i in range(8)]\n",
" return '{0:04b}_{1:04b}|{2:04b}_{3:04b}|{4:04b}_{5:04b}|{6:04b}_{7:04b}'.format( *vv )"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"UIO: dma (uio2) sz:0x10000 @0x40400000"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import uio\n",
"reload(uio)\n",
"import numpy as np\n",
"\n",
"reload(uio)\n",
"\n",
"\n",
"def to_bin(x):\n",
" vv = [ (x>>(32-(i+1)*4))&0xF for i in range(8)]\n",
" return '{0:04b}_{1:04b}|{2:04b}_{3:04b}|{4:04b}_{5:04b}|{6:04b}_{7:04b}'.format( *vv )\n",
"\n",
"\n",
"axi_dma_direct_dtype = np.dtype([\n",
" ('cr' , '<u4'),\n",
" ('st' , '<u4'),\n",
Expand All @@ -62,12 +67,72 @@
" return (dma.st&2) == 2\n",
"\n",
"def dma_halted(dma):\n",
" return (dma.st&1) == 1"
" return (dma.st&1) == 1\n",
"\n",
"\n",
"class AxiDMA:\n",
" def __init__(self, name_or_idx='dma'):\n",
" dma_uio = uio.UIO(name_or_idx)\n",
" mm2s, s2mm = dma_uio.as_recarray(2, dtype=axi_dma_direct_dtype)\n",
" \n",
" self._dma_uio = dma_uio\n",
" self.mm2s = mm2s\n",
" self.s2mm = s2mm\n",
" self._streams = (mm2s, s2mm)\n",
"\n",
" if self.halted() == False:\n",
" self.reset()\n",
"\n",
" def __repr__(self):\n",
" #TODO: dump state instead\n",
" return self._dma_uio.__repr__()\n",
" \n",
" def reset(self):\n",
" map(dma_reset, self._streams)\n",
"\n",
" def idle(self):\n",
" return dma_idle(self.s2mm) and dma_idle(self.mm2s)\n",
"\n",
" def halted(self):\n",
" return dma_halted(self.s2mm) and dma_halted(self.mm2s)\n",
"\n",
" def _launch_stream(self, ss, buf, irq_flags = 0x1):\n",
" phy_addr, sz = buf\n",
" ss.addr_lo = phy_addr\n",
" ss.cr = (irq_flags<<12)|1\n",
" ss.length = sz\n",
"\n",
" def launch(self, src_buf, dst_buf, enable_interrupts = True):\n",
" irq_flags = 0x1 if enable_interrupts else 0\n",
" \n",
" if enable_interrupts:\n",
" self._dma_uio.enable_interrupts()\n",
" \n",
" self._launch_stream(self.s2mm, dst_buf, irq_flags)\n",
" self._launch_stream(self.mm2s, src_buf, irq_flags)\n",
" \n",
" \n",
" def wait(self, n_iter=2):\n",
" x = self._dma_uio.wait_for_interrupt(reenable=True)\n",
" if x < n_iter: #wait for second interrupt\n",
" x = self._dma_uio.wait_for_interrupt()\n",
" \n",
" result = self.idle()\n",
" self.reset()\n",
" \n",
" return result\n",
"\n",
" \n",
" \n",
"\n",
"dma = AxiDMA('dma')\n",
"\n",
"dma"
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 3,
"metadata": {
"collapsed": false
},
Expand All @@ -81,40 +146,15 @@
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n"
]
},
{
"data": {
"text/plain": [
"(UIO: dma (uio2) sz:0x10000 @0x40400000,\n",
" UIO: scratch_mem (uio0) sz:0x2000000 @0x3e000000,\n",
" (65538L, 1L, array([0, 0, 0, 0], dtype=uint32), 0L, 0L, array([0, 0], dtype=uint32), 0L, 0L),\n",
" (65538L, 1L, array([0, 0, 0, 0], dtype=uint32), 0L, 0L, array([0, 0], dtype=uint32), 0L, 0L),\n",
" False)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mem_uio = uio.UIO('scratch_mem')\n",
"\n",
"dma_uio = uio.UIO('dma')\n",
"mm2s, s2mm = dma_uio.as_recarray(2, dtype=axi_dma_direct_dtype)\n",
"\n",
"#reset dma streams\n",
"dma_reset(mm2s)\n",
"dma_reset(s2mm)\n",
"\n",
"print('\\n'.join([to_bin(x) for x in [mm2s.cr, s2mm.cr, mm2s.st,s2mm.st]]))\n",
"\n",
"dma_uio, mem_uio, mm2s, s2mm, dma_idle(s2mm)"
"print('\\n'.join([to_bin(x) for x in [dma.mm2s.cr, dma.s2mm.cr, dma.mm2s.st,dma.s2mm.st]]))"
]
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 7,
"metadata": {
"collapsed": false
},
Expand All @@ -123,16 +163,15 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0000_0000|0000_0001|0000_0000|0000_0010\n",
"0000_0000|0000_0001|0000_0000|0000_0010\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"SRC: [197 175 200 37]\n",
"SRC: [191 166 174 183]\n",
"DST: [255 255 255 255]\n"
]
}
],
"source": [
"reload(uio)\n",
"mem_uio = uio.UIO('scratch_mem')\n",
"\n",
"SZ=(1<<19)\n",
"\n",
"data = mem_uio.as_ndarray()\n",
Expand All @@ -143,16 +182,13 @@
"src_data[:] = np.random.randint(0,256,SZ)\n",
"dst_data[:] = 0xFF\n",
"\n",
"[hex(x) for x in [mem_uio.phy(), mem_uio.phy(src_data), mem_uio.phy(dst_data)]]\n",
"\n",
"print('\\n'.join([to_bin(x) for x in [mm2s.cr, s2mm.cr, mm2s.st,s2mm.st]]))\n",
"print(\"SRC:\",src_data[:4])\n",
"print(\"DST:\",dst_data[:4])"
]
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 10,
"metadata": {
"collapsed": false
},
Expand All @@ -161,61 +197,22 @@
"name": "stdout",
"output_type": "stream",
"text": [
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"int: 1\n",
"int: 1\n",
" done\n",
"0000_0000|0000_0000|0001_0000|0000_0010\n",
"0000_0000|0000_0000|0001_0000|0000_0010\n",
" resetting\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n",
"0000_0000|0000_0000|0000_0000|0000_0001\n"
"DMA Completed Succesfully\n"
]
}
],
"source": [
"map(dma_reset, [s2mm,mm2s])\n",
"map(lambda dma: print(to_bin(dma.st)), [s2mm,mm2s])\n",
"\n",
"#set up stream to memory transfer first\n",
"s2mm.addr_lo = mem_uio.phy(dst_data)\n",
"s2mm.cr = (0x1<<12)|1 #on completion interrupt\n",
"s2mm.length = SZ\n",
"\n",
"assert dma_idle(s2mm) == False\n",
"\n",
"#now do memory to stream\n",
"mm2s.addr_lo = mem_uio.phy(src_data)\n",
"mm2s.cr = (0x1<<12)|1 #on completion interrupt\n",
"mm2s.length = SZ\n",
"\n",
"x = dma_uio.wait_for_interrupt()\n",
"print('int:',x)\n",
"if x < 2: #wait for second interrupt\n",
" x = dma_uio.wait_for_interrupt()\n",
" print('int:',x)\n",
"\n",
"\n",
"#poll until 'idle' bit is flipped on the PL->PS dma channel\n",
"while dma_idle(s2mm) == False:\n",
" print('.', end='')\n",
"print(' done')\n",
"assert dma_idle(s2mm)\n",
"\n",
"map(lambda dma: print(to_bin(dma.st)), [s2mm,mm2s])\n",
"\n",
"print(' resetting')\n",
"dma_reset(s2mm)\n",
"dma_reset(mm2s)\n",
"\n",
"map(lambda dma: print(to_bin(dma.st)), [s2mm,mm2s])\n",
"pass"
"dma.launch(mem_uio.phy_buf(src_data), mem_uio.phy_buf(dst_data), enable_interrupts=True)\n",
"if dma.wait():\n",
" print('DMA Completed Succesfully')\n",
"else:\n",
" print('DMA FAILED')\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 12,
"metadata": {
"collapsed": false
},
Expand All @@ -225,8 +222,8 @@
"output_type": "stream",
"text": [
"SUCCESS: Data copied as expected\n",
"SRC: [197 175 200 37]\n",
"DST: [197 175 200 37]\n"
"SRC: [191 166 174 183] ...\n",
"DST: [191 166 174 183] ...\n"
]
}
],
Expand All @@ -236,32 +233,8 @@
"else:\n",
" print('FAILED: dst and src do not match up')\n",
"\n",
"print(\"SRC:\",src_data[:4])\n",
"print(\"DST:\",dst_data[:4])"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "KeyboardInterrupt",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-10-78ff8e683e61>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mdma_uio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwait_for_interrupt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m/home/parallella/kk/notebooks/uio.pyc\u001b[0m in \u001b[0;36mwait_for_interrupt\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 140\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 141\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_fd\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstruct\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpack\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'@I'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 142\u001b[1;33m \u001b[0me_count\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mstruct\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0munpack\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'@I'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_fd\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 143\u001b[0m \u001b[0me_diff\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0me_count\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_event_count\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 144\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_event_count\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0me_count\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mKeyboardInterrupt\u001b[0m: "
]
}
],
"source": [
"dma_uio.wait_for_interrupt()"
"print(\"SRC:\",src_data[:4],'...')\n",
"print(\"DST:\",dst_data[:4],'...')"
]
},
{
Expand Down
35 changes: 25 additions & 10 deletions sample/test_app/uio.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ def _ptr(x):
return None




def __init__(self, idx):
import mmap
import os
Expand Down Expand Up @@ -110,7 +108,7 @@ def virt2phy(self, addr):


def phy(self, arg=None):
""" Return physical memory value
""" Return physical memory address
no-args -> base address of the device
integer argument -> base address plus byte offset
Expand All @@ -128,21 +126,38 @@ def phy(self, arg=None):

raise TypeError('Supported types: None, int,long, and numpy.ndarray')

def phy_buf(self, a):
""" Returns (phy_addr, sz) tuple from ndarray
"""
return ( self.virt2phy( UIO._ptr(a) ) , a.nbytes )

def wait_for_interrupt(self):
""" Blocking, returns number of interrupts that happened since last
time this function was called, or since creation time in
case of the first call.

"""
def _write(self, v):
import os
import struct

os.write(self._fd, struct.pack('@I',1))
e_count = struct.unpack('@I', os.read(self._fd,4) )[0]
os.write(self._fd, struct.pack('@I',v))

def _read(self):
import os
import struct
return struct.unpack('@I', os.read(self._fd, 4) )[0]

def enable_interrupts(self):
self._write(1)

def wait_for_interrupt(self, reenable=True):
""" Blocking, returns number of interrupts that happened since last
time this function was called, or since creation time in
case of the very first call.
"""
e_count = self._read()
e_diff = e_count - self._event_count
self._event_count = e_count

if reenable:
self.enable_interrupts()

return e_diff


Expand Down

0 comments on commit f7addcc

Please sign in to comment.