"""Python interface for AXI IP blocks on the FPGA"""
from __future__ import absolute_import, division, print_function
import logging
import os
import math
import mmap
import struct
import wni.config as config
logger = logging.getLogger(__name__)
[docs]def float_to_int12(x):
"""
Change a float (between between -1 and 1) to an int12.
"""
import numpy as np
f64 = np.asarray(x, dtype='float64')
if not ((-1 <= f64) & (f64 <= 1)).all():
import warnings
warnings.warn('All values must be between -1 and 1 (inclusive)')
rounded = np.round(f64 * 0x7ff)
int12 = rounded.astype('int32')
return int12
[docs]def int12_to_float(x):
import numpy as np
i16 = np.asarray(x, dtype='int16')
if not ((-0x7ff <= i16) & (i16 <= 0x7ff)).all():
import warnings
warnings.warn("All values must be representable by an int12")
f32 = i16.astype('float32')
scaled = f32 / 0x7ff
return scaled
[docs]class MmapRegion(object):
def __init__(self, base, size):
"""
base (int): The base address where the memory map is opened.
size (int): The number of bytes the memory should be mapped.
"""
self.base = base
self.size = size
self._fd = os.open('/dev/mem', os.O_RDWR)
self._map = mmap.mmap(
self._fd,
length=size,
flags=mmap.MAP_SHARED,
prot=mmap.PROT_READ | mmap.PROT_WRITE,
offset=base
)
def _seek(self, offset):
self._map.seek(offset, os.SEEK_SET)
[docs] def write_bytes(self, addr, bytes):
self._seek(addr)
return self._map.write(bytes)
[docs] def read_bytes(self, addr, size):
self._seek(addr)
return self._map.read(size)
# integer read methods
[docs] def read_int8(self, addr):
"""Returns an 8-bit signed integer at addr."""
bytes = self.read_bytes(addr, 1)
integer, = struct.unpack('b', bytes)
return integer
[docs] def read_int16(self, addr):
"""Returns a 16-bit signed integer at addr."""
bytes = self.read_bytes(addr, 2)
integer, = struct.unpack('h', bytes)
return integer
[docs] def read_int32(self, addr):
"""Returns a 32-bit signed integer at addr."""
bytes = self.read_bytes(addr, 4)
integer, = struct.unpack('i', bytes)
return integer
# unsigned integer read methods
[docs] def read_uint8(self, addr):
"""Returns an 8-bit unsigned integer at addr."""
bytes = self.read_bytes(addr, 1)
integer, = struct.unpack('B', bytes)
return integer
[docs] def read_uint16(self, addr):
"""Returns a 16-bit unsigned integer at addr."""
bytes = self.read_bytes(addr, 2)
integer, = struct.unpack('H', bytes)
return integer
[docs] def read_uint32(self, addr):
"""Returns a 32-bit unsigned integer at addr."""
bytes = self.read_bytes(addr, 4)
integer, = struct.unpack('I', bytes)
return integer
# signed integer write methods
[docs] def write_int8(self, addr, value):
"""Writes an 8-bit signed integer `value` to `addr`"""
bytes = struct.pack('b', value)
return self.write_bytes(addr, bytes)
[docs] def write_int16(self, addr, value):
"""Writes a 16-bit signed integer `value` to `addr`"""
bytes = struct.pack('h', value)
return self.write_bytes(addr, bytes)
[docs] def write_int32(self, addr, value):
"""Writes a 32-bit signed integer `value` to `addr`"""
bytes = struct.pack('i', value)
return self.write_bytes(addr, bytes)
# unsigned integer write methods
[docs] def write_uint8(self, addr, value):
"""Writes an 8-bit unsigned integer `value` to `addr`"""
bytes = struct.pack('B', value)
return self.write_bytes(addr, bytes)
[docs] def write_uint16(self, addr, value):
"""Writes a 16-bit unsigned integer `value` to `addr`"""
bytes = struct.pack('H', value)
return self.write_bytes(addr, bytes)
[docs] def write_uint32(self, addr, value):
"""Writes a 32-bit unsigned integer `value` to `addr`"""
bytes = struct.pack('I', value)
return self.write_bytes(addr, bytes)
read_int = read_int32
read_uint = read_uint32
write_int = write_int32
write_uint = write_uint32
def __repr__(self):
return '{}({}, {})'.format(
self.__class__.__name__,
hex(self.base),
hex(self.size))