{"id":39864252,"url":"https://github.com/ikwzm/uiomem","last_synced_at":"2026-01-18T14:05:28.630Z","repository":{"id":146258083,"uuid":"275975611","full_name":"ikwzm/uiomem","owner":"ikwzm","description":"uiomem is a Linux device driver for accessing a memory area outside the Linux Kernel management from user space.","archived":false,"fork":false,"pushed_at":"2025-12-01T03:05:16.000Z","size":151,"stargazers_count":13,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-22T20:06:13.215Z","etag":null,"topics":["arm","arm64","cpu-cache","fpga","fpga-soc-linux","linux-drivers"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ikwzm.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-06-30T02:23:53.000Z","updated_at":"2025-11-29T04:46:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"16d60af0-60f4-471e-bca3-f7c965645fbd","html_url":"https://github.com/ikwzm/uiomem","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/ikwzm/uiomem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fuiomem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fuiomem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fuiomem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fuiomem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ikwzm","download_url":"https://codeload.github.com/ikwzm/uiomem/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikwzm%2Fuiomem/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28537492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T13:04:05.990Z","status":"ssl_error","status_checked_at":"2026-01-18T13:01:44.092Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arm","arm64","cpu-cache","fpga","fpga-soc-linux","linux-drivers"],"created_at":"2026-01-18T14:05:24.434Z","updated_at":"2026-01-18T14:05:28.616Z","avatar_url":"https://github.com/ikwzm.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"uiomem(User space mappable I/O Memory)\n==================================================================================\n\n**This project is under development.**\n\nSee the develop branch for this project for details.\n\nhttps://github.com/ikwzm/uiomem/tree/develop\n\nCurrently 1.0.0-alpha.7 is tentatively released.\n\nhttps://github.com/ikwzm/uiomem/tree/v1.0.0-alpha.7.\n\n# Overview\n\n## Introduction of uiomem\n\nuiomem is a Linux device driver for accessing a memory area outside the Linux\nKernel management from user space.\n\nuiomem has following features.\n\n  * uiomem can enable CPU cache, so it can access memory at high speed.\n  * uiomem can manually invalidiate and flush the CPU cache.\n  * uiomem can be freely attached and detached from Linux Kernel.\n\nIt is possible to access memory from the user space by opneing the device\nfile(e.g. /dev/uiomem0) and mapping to the user memory space, or using\nthe read()/write() functions.\n\nThe start address and size of the allocated memory area can be specified when \nthe device driver is loaded (e.g. when loaded via the `insmod` command).\nSome platforms allow to specify them in the device tree.\n\n\n## Supported platforms\n\n* OS : Linux Kernel Version 4.19, 5.4, 6.1, 6.6, 6.12 (the author tested on 5.4 and 6.1 and 6.12).\n* CPU: ARMv7 Cortex-A9 (Xilinx ZYNQ / Altera CycloneV SoC)\n* CPU: ARM64 Cortex-A53 (Xilinx ZYNQ UltraScale+ MPSoC)\n\n# Usage\n\n## Compile\n\nThe following `Makefile` is included in the repository.\n\n```Makefile:Makefile\n# SPDX-License-Identifier: GPL-2.0 OR MIT\n# Copyright (C) 2015-2023 Ichiro Kawazome\n\n#\n# For in kernel tree variables\n# \nobj-$(CONFIG_UIOMEM) += uiomem.o\n\n#\n# For out of kernel tree variables\n#\nCONFIG_MODULES ?= CONFIG_UIOMEM=m\n\nHOST_ARCH ?= $(shell uname -m | sed -e s/arm.*/arm/ -e s/aarch64.*/arm64/)\nARCH      ?= $(shell uname -m | sed -e s/arm.*/arm/ -e s/aarch64.*/arm64/)\n\nifeq ($(ARCH), arm)\n ifneq ($(HOST_ARCH), arm)\n   CROSS_COMPILE ?= arm-linux-gnueabihf-\n endif\nendif\nifeq ($(ARCH), arm64)\n ifneq ($(HOST_ARCH), arm64)\n   CROSS_COMPILE ?= aarch64-linux-gnu-\n endif\nendif\n\nifdef KERNEL_SRC\n  KERNEL_SRC_DIR := $(KERNEL_SRC)\nelse\n  KERNEL_SRC_DIR ?= /lib/modules/$(shell uname -r)/build\nendif\n\n#\n# For out of kernel tree rules\n#\nall:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) $(CONFIG_MODULES) modules\n\nmodules_install:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) $(CONFIG_MODULES) modules_install\n\nclean:\n\t$(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean\n\n```\n\n## Install\n\nLoad the uiomem kernel driver using `insmod`.\nThe start address and size of the allocated memory area should be provided as an argument as follows.\nThe device driver is created, and allocates memory area with the specified address and size.\nThe memory area that can be specified must be aligned with the page size.\nThe maximum number of memory area that can be allocated using `insmod` is 8 (uiomem0/1/2/3/4/5/6/7).\n\n```console\nshell$ sudo insmod uiomem.ko uiomem0_addr=0x0400000000 uiomem0_size=0x00040000\n[  562.657246] uiomem uiomem0: driver version = 1.0.0-alpha.7\n[  562.657264] uiomem uiomem0: major number   = 238\n[  562.657270] uiomem uiomem0: minor number   = 0\n[  562.657275] uiomem uiomem0: range address  = 0x0000000400000000\n[  562.657282] uiomem uiomem0: range size     = 262144\n[  562.657287] uiomem uiomem.0: driver installed.\nshell$ ls -la /dev/uiomem0\ncrw------- 1 root root 238, 0 Oct 21 17:36 /dev/uiomem0\n```\n\nThe module can be uninstalled by the `rmmod` command.\n\n```console\nshell$ sudo rmmod uiomem\n[  657.672544] uiomem uiomem.0: driver removed.\n```\n\n## Configuration via the device tree file\n\nIn addition to the allocation via the `insmod` command and its arguments,\nmemory area can be allocated by specifying the reg property in the device tree file.\nWhen a device tree file contains an entry like the following, uiomem will allocate\nmemory area and create device drivers when loaded by `insmod`.\n\n```devicetree:devicetree.dts\n\t\t#address-cells = \u003c2\u003e;\n\t\t#size-cells    = \u003c2\u003e;\n\t\tuiomem_plmem {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\tdevice-name = \"uiomem0\";\n\t\t\tminor-number = \u003c0\u003e;\n\t\t\treg = \u003c0x04 0x00000000 0x0 0x00040000\u003e;\n\t\t};\n\n```\n\n```console\nshell$ sudo insmod uiomem.ko\n[  773.889476] uiomem uiomem0: driver version = 1.0.0-alpha.7\n[  773.889496] uiomem uiomem0: major number   = 237\n[  773.889501] uiomem uiomem0: minor number   = 0\n[  773.889506] uiomem uiomem0: range address  = 0x0000000400000000\n[  773.889512] uiomem uiomem0: range size     = 262144\n[  773.889518] uiomem 400000000.uiomem_plbram: driver installed.\nshell$ ls -la /dev/uiomem0\ncrw------- 1 root root 237, 0 Oct 21 17:40 /dev/uiomem0\n```\n\nThe following properties can be set in the device tree.\n\n  *  `compatible`\n  *  `reg`\n  *  `memory-region`\n  *  `shareable`\n  *  `minor-number`\n  *  `device-name`\n  *  `sync-offset`\n  *  `sync-size`\n  *  `sync-direction`\n\n### `compatible`\n\nThe `compatible` property is used to set the corresponding device driver when loading\nuiomem. The `compatible` property is mandatory. Be sure to specify `compatible`\nproperty as \"ikwzm,uiomem\".\n\n### `reg`\n\nThe `reg` property specifies the physical address and size.\nThe `reg` property is used when uiomem allocates a buffer outside the management of Linux Kernel.\nThe memory area that can be specified must be aligned with the page size.\nEither the `reg` property or the `memory-region` property is required.\n\n```devicetree:devicetree.dts\n\t\t#address-cells = \u003c2\u003e;\n\t\t#size-cells = \u003c2\u003e;\n\t\tuiomem@0xFFFC0000 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\treg = \u003c0x0 0xFFFC0000 0x0 0x00040000\u003e;\n\t\t};\n```\n\n### `memory-region`\n\nThe `memory-region` property specifies the memory region allocated for reserved memory.\nThe memory region specified by the `memory-region` property must always have the `no-map` property specified.\nEither the `reg` property or the `memory-region` property is required.\n\n```devicetree:devicetree.dts\n\t\t#address-cells = \u003c2\u003e;\n\t\t#size-cells = \u003c2\u003e;\n\t\treserved_memory {\n\t\t\tranges;\n\t\t\timage_buf0: image_buf@0 {\n\t\t\t\tno-map;\n\t\t\t\treg = \u003c0x0 0x70000000 0x0 0x10000000\u003e;\n\t\t\t\tlabel = \"image_buf0\";\n\t\t\t};\n\t\t};\n\t\tuiomem@image_buf0 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\tmemory-region = \u003c\u0026image_buf0\u003e;\n\t\t};\n```\n\n### `shareable`\n\nThe `shareable` property is specified when multiple uiomem shares the memory space specified by `reg` property.\n\n```devicetree:devicetree.dts\n\t\t#address-cells = \u003c2\u003e;\n\t\t#size-cells = \u003c2\u003e;\n\t\tuiomem0 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\treg = \u003c0x0 0xFFFC0000 0x0 0x00040000\u003e;\n\t\t\tshareable;\n\t\t};\n\t\tuiomem1 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\treg = \u003c0x0 0xFFFC0000 0x0 0x00040000\u003e;\n\t\t\tshareable;\n\t\t};\n```\n\n### `minor-number`\n\nThe `minor-number` property is used to set the minor number.\nThe valid minor number range is 0 to 255. A minor number provided as `insmod`\nargument will has higher precedence, and when definition in the device tree has\ncolliding number, creation of the device defined in the device tree will fail.\n\nThe `minor-number` property is optional. When the `minor-number` property is not\nspecified, uiomem automatically assigns an appropriate one.\n\n```devicetree:devicetree.dts\n\t\tuiomem0 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\tminor-number = \u003c0\u003e;\n\t\t\treg = \u003c0x0 0xFFFC0000 0x0 0x00040000\u003e;\n\t\t};\n\n```\n\n### `device-name`\n\nThe `device-name` property is used to set the name of device.\n\nThe `device-name` property is optional. The device name is determined as follow:\n\n  1. If `device-name` property is specified, the value of `device-name` property is used.\n  2. If `device-name` property is not present, and if `minor-number` property is\n     specified, `sprintf(\"uiomem%d\", minor-number)` is used.\n\n### `sync-offset`\n\nThe `sync-offset` property is used to set the start of the buffer range when manually\ncontrolling the cache of uiomem. \n\nThe `sync-offset` property is optional.\nWhen the `sync-offset` property is not specified, `sync-offset` is set to \u003c0\u003e.\n\n### `sync-size`\n\nThe `sync-size` property is used to set the size of the buffer range when manually\ncontrolling the cache of uiomem.\n\nThe `sync-size` property is optional.\nWhen the `sync-size` property is not specified, `sync-size` is set to ths size specified by the `reg` property.\n\n### `sync-direction`\n\nThe `sync-direction` property is used to set the direction of DMA when manually\ncontrolling the cache of uiomem\n\n  * `sync-direction`=\u003c0\u003e: Read and Write\n  * `sync-direction`=\u003c1\u003e: Write Only\n  * `sync-direction`=\u003c2\u003e: Read Only\n\nThe `sync-direction` property is optional.\nWhen the `sync-direction` property is not specified, `sync-direction` is set to \u003c0\u003e.\n\n```devicetree:devicetree.dts\n\t\tuiomem0 {\n\t\t\tcompatible = \"ikwzm,uiomem\";\n\t\t\treg = \u003c0x0 0xFFFC0000 0x0 0x00040000\u003e;\n\t\t\tsync-offset = \u003c0x00010000\u003e;\n\t\t\tsync-size = \u003c0x000F0000\u003e;\n\t\t\tsync-direction = \u003c2\u003e;\n\t\t};\n\n```\n\n## Device file\n\nWhen uiomem is loaded into the kernel, the following device files are created.\n`\u003cdevice-name\u003e` is a placeholder for the device name described in the previous section.\n\n  * `/dev/\u003cdevice-name\u003e`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/phys_addr`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/size`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_offset`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_size`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_direction`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_owner`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_for_cpu`\n  * `/sys/class/uiomem/\u003cdevice-name\u003e/sync_for_device`\n\n### `/dev/\u003cdevice-name\u003e`\n\n`/dev/\u003cdevice-name\u003e` is used when `mmap()`-ed to the user space or accessed via `read()`/`write()`.\n\n```C:uiomem_test.c\n    if ((fd  = open(\"/dev/uiomem0\", O_RDWR)) != -1) {\n        buf = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n        /* Do some read/write access to buf */\n        close(fd);\n    }\n\n```\n\nThe device file can be directly read/written by specifying the device as the target of `dd` in the shell.\n\n```console\nshell$  dd if=/dev/urandom of=/dev/uiomem0 bs=4096 count=64\n64+0 records in\n64+0 records out\n262144 bytes (262 kB, 256 KiB) copied, 0.00341051 s, 76.9 MB/s\n```\n\n```console\nshell$ dd if=/dev/uiomem0 of=random.bin bs=4096\n64+0 records in\n64+0 records out\n262144 bytes (262 kB, 256 KiB) copied, 0.00192588 s, 136 MB/s\n```\n\n### `phys_addr`\n\nThe physical address of a memory area can be retrieved by reading `/sys/class/uiomem/\u003cdevice-name\u003e/phys_addr`.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  phys_addr;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/phys_addr\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%x\", \u0026phys_addr);\n        close(fd);\n    }\n\n```\n\n### `size`\n\nThe size of a memory area can be retrieved by reading `/sys/class/uiomem/\u003cdevice-name\u003e/size`.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned int   buf_size;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/size\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%d\", \u0026buf_size);\n        close(fd);\n    }\n\n```\n\n### `sync_offset`\n\nThe device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_offset` is used to specify\nthe start address of a memory block of which cache is manually managed.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset = 0x00000000;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_offset\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_offset); /* or sprintf(attr, \"0x%x\", sync_offset); */\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n### `sync_size`\n\nThe device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_size` is used to specify\nthe size of a memory block of which cache is manually managed.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_size = 1024;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_size\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_size); /* or sprintf(attr, \"0x%x\", sync_size); */\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n### `sync_direction`\n\nThe device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_direction` is used to set the\ndirection(Read/Write) of memory area of which cache is manually managed.\n\n  - 0: sets Read and Write\n  - 1: sets Write Only\n  - 2: sets Read Only\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_direction = 1;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_direction\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_direction);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\n### `sync_owner`\n\nThe device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_owner` reports the owner of\nthe memory block in the manual cache management mode.\nIf this value is 1, the buffer is owned by the device.\nIf this value is 0, the buffer is owned by the cpu.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    int sync_owner;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_owner\", O_RDONLY)) != -1) {\n        read(fd, attr, 1024);\n        sscanf(attr, \"%x\", \u0026sync_owner);\n        close(fd);\n    }\n\n```\n\n### `sync_for_cpu`\n\nIn the manual cache management mode, CPU can be the owner of the buffer by writing\nnon-zero to the device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_for_cpu`.\nThis device file is write only.\n\nIf '1' is written to device file, if `sync_direction` is 2(=Read Only) or 0(=Read and Write),\nthe write to the device file invalidates a cache specified by `sync_offset` and `sync_size`.\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_for_cpu = 1;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_for_cpu\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_for_cpu);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\nThe value written to this device file can include sync_offset, sync_size, and sync_direction. \n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset    = 0;\n    unsigned long  sync_size      = 0x10000;\n    unsigned int   sync_direction = 1;\n    unsigned long  sync_for_cpu   = 1;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_for_cpu\", O_WRONLY)) != -1) {\n        sprintf(attr, \"0x%08X%08X\", (sync_offset \u0026 0xFFFFFFFF), (sync_size \u0026 0xFFFFFFF0) | (sync_direction \u003c\u003c 2) | sync_for_cpu);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\nThe sync_offset/sync_size/sync_direction specified by ```sync_for_cpu``` is temporary and does not affect the ```sync_offset``` or ```sync_size``` or ```sync_direction``` device files.\n\n### `sync_for_device`\n\nIn the manual cache management mode, DEVICE can be the owner of the buffer by\nwriting non-zero to the device file `/sys/class/uiomem/\u003cdevice-name\u003e/sync_for_device`.\nThis device file is write only.\n\nIf '1' is written to device file, if `sync_direction` is 1(=Write Only) or 0(=Read and Write),\nthe write to the device file flushes a cache specified by `sync_offset` and `sync_size` (i.e. the\ncached data, if any, will be updated with data on DDR memory).\n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_for_device = 1;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_for_device\", O_WRONLY)) != -1) {\n        sprintf(attr, \"%d\", sync_for_device);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\nThe value written to this device file can include sync_offset, sync_size, and sync_direction. \n\n```C:uiomem_test.c\n    unsigned char  attr[1024];\n    unsigned long  sync_offset     = 0;\n    unsigned long  sync_size       = 0x10000;\n    unsigned int   sync_direction  = 1;\n    unsigned long  sync_for_device = 1;\n    if ((fd  = open(\"/sys/class/uiomem/uiomem0/sync_for_device\", O_WRONLY)) != -1) {\n        sprintf(attr, \"0x%08X%08X\", (sync_offset \u0026 0xFFFFFFFF), (sync_size \u0026 0xFFFFFFF0) | (sync_direction \u003c\u003c 2) | sync_for_device);\n        write(fd, attr, strlen(attr));\n        close(fd);\n    }\n```\n\nThe sync_offset/sync_size/sync_direction specified by ```sync_for_device``` is temporary and does not affect the ```sync_offset``` or ```sync_size``` or ```sync_direction``` device files.\n\n\n\n# Example using uiomem\n\n  * https://github.com/ikwzm/PLBRAM-Ultra96\n  * https://github.com/ikwzm/PLBRAM-ZYBO-Z7\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikwzm%2Fuiomem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fikwzm%2Fuiomem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikwzm%2Fuiomem/lists"}