Commit 89fd8cf9 authored by Pascal Bos's avatar Pascal Bos

Merge branch 'Pascal_tooling_fix' into proposed_master

parents 78acf1e0 7dd57950
Pipeline #2217 failed with stage
in 1 minute and 41 seconds
# If it exists includes Makefile.specific. In this Makefile, you should put
# specific Makefile code that you want to run before this. For example,
# build a particular environment.
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
#REPO_PARENT=../..
#-include $(REPO_PARENT)/parent_common.mk
GIT_VERSION ?= $(shell git describe --dirty --long --tags)
CFLAGS += -ggdb -Wall -fPIC -I../kernel $(EXTRACFLAGS)
CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
INSTALL = install
DESTDIR =
PREFIX = /usr/local
BINDIR = $(PREFIX)/sbin
LIBDIR = $(PREFIX)/lib
LIB = libspec.a
LIBOBJ = speclib.o
LIBSHARED = libspec.so
PROGS = spec-fwloader spec-vuart spec-cl specmem
all: $(LIB) $(PROGS) $(LIBSHARED)
$(PROGS): $(LIB)
$(LIB): $(LIBOBJ)
$(AR) r $@ $^
$(LIBSHARED): $(LIB)
$(CC) -shared -o $@ -Wl,--whole-archive $^ -Wl,--no-whole-archive
install:
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -m 0755 -t $(DESTDIR)$(BINDIR) $(PROGS)
$(INSTALL) -d $(DESTDIR)$(LIBDIR)
$(INSTALL) -m 0755 -t $(DESTDIR)$(LIBDIR) $(LIB)
$(INSTALL) -m 0755 -t $(DESTDIR)$(LIBDIR) $(LIBOBJ)
$(INSTALL) -m 0755 -t $(DESTDIR)$(LIBDIR) $(LIBSHARED)
clean:
rm -f *.o $(LIB) $(PROGS) $(LIBSHARED) *~
# add the other unused targets, so the rule in ../Makefile works
modules modules_install:
#! /bin/bash
if [ "$1" = "-h" ]; then
echo "Copies and loads a bitfile to the spec7 over PCIe. Must be run as root"
echo "usage:
$0 NAME_OF_BITFILE.bit"
exit 1
fi
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
ID=$(lspci | grep "Xilinx Corporation Device 7022" | awk '{print $1}')
echo "removing Pcie entry."
echo 1 > /sys/bus/pci/devices/0000\:$ID/remove
sleep 0.2
echo "rescanning Pcie entries."
echo 1 > /sys/bus/pci/rescan
sleep 0.2
echo "Pcie entry loaded."
sleep 1
echo "dcache off" >/dev/ttyUSB1
echo "copying $1 to Spec7."
cp $1 /dev/spec7_bar4
echo "loading bitfile into pCap."
echo "fpga loadb 0 0x1000000 0x1000000" >/dev/ttyUSB1
echo "done"
......@@ -11,7 +11,7 @@ import sys
import argparse
parser = argparse.ArgumentParser(description='Spec7 tool to access the memory mapped area', epilog='A number with prefix "0x" is interpreted as hex value')
parser.add_argument('--device', '-d', default='/dev/xdma0_user', help = 'device path name, default is /dev/xdma0_user')
parser.add_argument('--device', '-d', default='/dev/spec7_bar0', help = 'device path name, default is /dev/spec7')
parser.add_argument('--address', '-a', default='0', help='address to access (0x prefix for hex)')
parser.add_argument('--is-pipe', '-p', dest='is_pipe', action="store_true", help='register is a pipe')
parser.add_argument('--count', '-n', dest='count', help='number of reads/writes')
......
#! /bin/bash
ID=$(lspci | grep "Xilinx Corporation Device 7022" | awk '{print $1}')
echo "removing Pcie entry...."
echo 1 > /sys/bus/pci/devices/0000\:$ID/remove
sleep 1
echo "rescanning Pcie entries...."
echo 1 > /sys/bus/pci/rescan
sleep 1
echo "done"
......@@ -22,7 +22,7 @@ vuart_addr = 0x40500
xmda_user_fd = 0;
parser = argparse.ArgumentParser(description='Terminal interface to the uart of the wr core on the SPEC card')
parser.add_argument('--device', '-d', default='/dev/xdma0_user', help = 'device path name, default is /dev/xdma0_user')
parser.add_argument('--device', '-d', default='/dev/spec7_bar0', help = 'device path name, default is /dev/spec7')
args = parser.parse_args()
......
SPEC7 Tools
-------------------
This is a software collection a various tools related to the SPEC7. Currently it holds 6 items
- PCIe_mm, A debug to quickly read and write memory in one of the BARs of the SPEC7.
- PCIe_rescan, A simple script to reload the PCIe entry. Mandatory after each programming.
- PCIe_vuart, A terminal interface to the uart of the WR core (BAR0).
- SMBus_reset, A simple script to Hard-reset (POR) the SPEC7 over the PCIe SMBus.
- PCIE_load_bitfile, A script to load and flash a bitfile over PCIe (WIP).
- spec7-kernel-module, Provides /dev/spec7_barX entries, and other userspace options.
PCIe_mm
--------------
This tool can be used to read and write to a certain adress. For example:
./spec7-tools/Pcie_mm/spec7_mm.py -a 0x0004
Will read address 0x0004.
./spec7-tools/Pcie_mm/spec7_mm.py -a 0x0004 -w 0xABBA
Will write 0xABBA to adress 0x0004
PCIe_rescan
------------
This scripts automaticly removes and rescans the SPEC7 PCIe device.
./spec7-tools/Pcie_rescan/Pcie_rescan.sh
Must be run as root.
PCIe_vuart
------------
A python script to emulate a termios terminal to utilize an uart connection on the White Rabbit ref design.
./spec7-tools/Pcie_vuart/spec7_vuart.py
SMBus_reset
------------
This script triggers a POR event on the SPEC7 via the PCIe's SMBus.
./spec7-tools/SMBus_reset/spec7_reset.sh
It uses i2c-tools so make sure you've probed i2c_dev beforehand.
./modprobe i2c_dev
PCIE_load_bitfile
------------
This script automatticly loads and flashes a new bitfile to the SPEC7.
./spec7-tools/Pcie_load_bitfile/Pcie_load_bitfile.sh ./spec7_wr_ref_top.bit
Must be run as root.
spec7-kernel-module
------------
The Kernel module written by the one and only Ton Damen. See that specific readme.md for more info.
It's mandatory to have installed to use all the previous tools (except the SMBus_reset).
Pascal Bos, bosp@nikhef.nl
Ton Damen, tond@nikhef.nl
September 2021
obj-m += spec7.o
spec7-objs := spec7_mod.o sysfs.o misc_dev.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) clean
install:
make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) modules_install
KERNEL MODULE spec7
-------------------
This kernel module supports the access of the PCI Axi4 memory of the SPEC7 card.
Currently the IP of the SPEC7 presents two bars: bar0 (1MB) and bar4 (16MB).
When the kernel module (spec7.ko) is loaded, the following should be seen among the kernel messages:
spec7:probe_one: PCI device id: [10ee:7022], address: 0000:01:00.0
spec7:probe_one: size bar0 = 1048576, bar4 = 16777216
spec7:spec7_module_init: loaded
The PCI address is here "0000:01:00.0" which gives the following sysfs entries:
- /sys/bus/pci/devices/0000:01:00.0/deadbe
Writing either '0' or '1' will write this values into the SYSCON register of the LM32.
- /sys/bus/pci/devices/0000:01:00.0/lm32_mem
Gives file based access to the LM32 memory.
BAR interfaces
--------------
The module creates to file entries in /dev:
/dev/spec7_bar0
/dev/spec7_bar4
These character devices supports access to the memory regions of each bar in a stream-like fashion through systems calls read() and write(). The region boundaries are protected by returning EOF when reading and EFAULT (invalid address) when writing beyond.
Both cp(3) and dd(3) can be used to transfer files to and from the bar memory regions.
The system call ioctl() can be used to query the size of the bar regions:
ioctl(fd, 0xdc01, 0)
returns the size in bytes.
Both devices implements also the mmap(2) system call, which enables the mapping of the BAR regions to user-space memory.
PERMISSIONS
------------
The default permissions for the device files are granted for root only. To customize this, an udev rules file must be created in /usr/lib/udev/rules.d.
This example gives users who are member of group “spec7” read-write access and others only read access:
file 60-spec7.rules contents:
KERNEL=="spec7_*", MODE="0664", GROUP="spec7"
To reload the udev config:
# udevadm control --reload
To add the group “spec7”
# addgroup spec7
To add a groups membership to an existing user the following command is given:
# usermod -a -G spec7 username
Nb. reload the driver to effectuate the new configuration.
Ton Damen, tond@nilhef.nl
September 2021
/*
* Copyright (C) 2021 NIKHEF Amsterdam
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* File: misc_dev.c
* Author: Ton Damen <tond@nikhef.nl>
*
* Created on April 27, 2020, 7:46 PM
*/
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include "spec7.h"
#include "misc_dev.h"
#define VMEM_FLAGS (VM_IO | VM_DONTEXPAND | VM_DONTDUMP)
static int miscdev_open(struct inode *inode, struct file *filep)
{
struct miscdevice *mdev_ptr = filep->private_data;
filep->private_data = container_of(mdev_ptr, struct spec7_bar, mdev);
return 0;
}
/*
* character device file operations for control bus (through control bridge)
*/
static ssize_t miscdev_read(struct file *filep, char __user *buf, size_t count,
loff_t *pos)
{
void *addr;
u32 w;
int rv;
struct spec7_bar *bar = filep->private_data;
/* only 32-bit aligned and 32-bit multiples */
if (*pos & 3)
return -EPROTO;
/* first address is BAR base plus file position offset */
addr = bar->base + *pos;
if (addr >= (bar->base + bar->size))
return 0;
//w = read_register(reg);
w = ioread32(addr);
rv = copy_to_user(buf, &w, 4);
if (rv)
pr_info("Copy to userspace failed but continuing\n");
*pos += 4;
return 4;
}
static ssize_t miscdev_write(struct file *filep, const char __user *buf,
size_t count, loff_t *pos)
{
void *addr;
u32 w;
int rv;
struct spec7_bar *bar = filep->private_data;
/* only 32-bit aligned and 32-bit multiples */
if (*pos & 3)
return -EPROTO;
/* first address is BAR base plus file position offset */
addr = bar->base + *pos;
if (addr >= (bar->base + bar->size))
return -EFAULT;
rv = copy_from_user(&w, buf, 4);
if (rv) {
pr_info("copy from user failed %d/4, but continuing.\n", rv);
}
iowrite32(w, addr);
*pos += 4;
return 4;
}
/* maps the PCIe BAR into user space for memory-like access using mmap() */
static int miscdev_mmap(struct file *filep, struct vm_area_struct *vma)
{
unsigned long offs, vsize, psize, phys;
struct spec7_bar *bar = filep->private_data;
offs = vma->vm_pgoff << PAGE_SHIFT;
// physical address
phys = bar->phys + offs;
vsize = vma->vm_end - vma->vm_start;
/* complete resource */
psize = bar->size - offs;
if (vsize > psize)
return -EINVAL;
/*
* pages must not be cached as this would result in cache line sized
* accesses to the end point
*/
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/*
* prevent touching the pages (byte access) for swap-in,
* and prevent the pages from being swapped out
*/
vma->vm_flags |= VMEM_FLAGS;
/* make MMIO accessible to user space */
if (io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
vsize, vma->vm_page_prot) != 0)
return -EAGAIN;
return 0;
}
static long miscdev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
struct spec7_bar *bar = filep->private_data;
switch(cmd){
case SPEC7_IOCQSIZE:
return bar->size;
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations spec7_fops = {
.owner = THIS_MODULE,
.open = miscdev_open,
.read = miscdev_read,
.write = miscdev_write,
.unlocked_ioctl = miscdev_ioctl,
.mmap = miscdev_mmap
};
int miscdev_init(const char *name, struct miscdevice *mdev)
{
int rc;
mdev->minor = MISC_DYNAMIC_MINOR;
mdev->fops = &spec7_fops;
mdev->name = name;
rc = misc_register(mdev);
if (rc == 0)
return mdev->minor;
return rc;
}
\ No newline at end of file
/*
* Copyright (C) 2021 NIKHEF Amsterdam
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* File: misc_dev.h
* Author: Ton Damen <tond@nikhef.nl>
*
* Created on April 27, 2020, 7:38 PM
*/
#ifndef MISC_DEV_H
#define MISC_DEV_H
int miscdev_init(const char *, struct miscdevice *mdev);
#endif /* MISC_DEV_H */
/*
* Copyright (C) 2021 NIKHEF Amsterdam
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* File: spec7.h
* Author: Ton Damen <tond@nikhef.nl>
*
* Created on 24 april 2020, 15:19
*
*/
#ifndef SPEC7_H
#define SPEC7_H
#include <linux/pci.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#define BAR_0 0
#define BAR_4 4
#define BAR0_FNAME "spec7_bar0"
#define BAR4_FNAME "spec7_bar4"
#define PCI_VENDOR_ID_CERN 0x10dc
#define PCI_VENDOR_ID_XILINX 0x10ee
#define LM32_MEM_SIZE (128*1024)
#define SYSCON_REG_ADDR 0x20400
#define SPEC7_IOC_MAGIC 0xdc
#define SPEC7_IOCQSIZE _IO(SPEC7_IOC_MAGIC, 1)
struct spec7_bar {
int idx, inode_minor;
void *__iomem base;
struct miscdevice mdev;
ulong size, phys;
};
struct spec7_dev {
struct pci_dev *pdev;
struct spec7_bar bar0, bar4;
u32 *lm32_mem;
u32 *syscon_reg_addr;
};
#endif /* SPEC7_H */
/*
* Copyright (C) 2021 NIKHEF Amsterdam
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* File: spec7_mod.c
* Author: Ton Damen <tond@nikhef.nl>
*
* Created on April 23, 2020, 13:14 AM
* Modified on September 14, 2021, Added BAR4
*/
#define DEBUG
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include "spec7.h"
#include "sysfs.h"
#include "misc_dev.h"
#define MODULE_NAME "spec7"
#define MODULE_DESC "SPEC7 experimental Driver"
#define MODULE_RELDATE "September 2021"
MODULE_AUTHOR("<Ton Damen>tond@nikhef.nl");
MODULE_DESCRIPTION(MODULE_DESC);
MODULE_VERSION("0.2");
MODULE_LICENSE("GPL");
//pci_device_id=0x18d pci_vendor_id=0x10dc
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(0x10ee, 0x7022),},
{ PCI_DEVICE(0x10dc, 0x18d),},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id) {
struct spec7_dev *spec;
int rc;
//pr_info("Buid %s %s\n", __DATE__, __TIME__);
pr_info("PCI device id: [%x:%x], address: %s\n", pdev->vendor, pdev->device, dev_name(&pdev->dev));
if (pci_enable_device(pdev) < 0)
return -EINVAL;
if ((spec = kzalloc(sizeof (struct spec7_dev), GFP_KERNEL)) == NULL)
return -ENOMEM;
spec->pdev = pdev;
spec->bar0.size = pci_resource_len(pdev, BAR_0);
spec->bar4.size = pci_resource_len(pdev, BAR_4);
spec->bar0.phys = pci_resource_start(pdev, BAR_0);
spec->bar4.phys = pci_resource_start(pdev, BAR_4);
spec->bar0.base = pci_iomap(pdev, BAR_0, spec->bar0.size);
spec->bar4.base = pci_iomap(pdev, BAR_4, spec->bar4.size);
spec->bar0.idx = BAR_0;
spec->bar4.idx = BAR_4;
spec->lm32_mem = spec->bar0.base;
spec->syscon_reg_addr = spec->bar0.base + SYSCON_REG_ADDR;
pci_set_drvdata(pdev, spec);
populate_sysfs(spec);
rc = miscdev_init(BAR0_FNAME, &spec->bar0.mdev);
if (rc > 0)
spec->bar0.inode_minor = rc;
else
return rc;
rc = miscdev_init(BAR4_FNAME, &spec->bar4.mdev);
if (rc > 0)
spec->bar4.inode_minor = rc;
else
return rc;
pr_info("size bar0 = %lu, bar4 = %lu\n", spec->bar0.size, spec->bar4.size);
return 0;
}
static void remove_one(struct pci_dev *pdev) {
struct spec7_dev *spec = pci_get_drvdata(pdev);
misc_deregister(&spec->bar0.mdev);
misc_deregister(&spec->bar4.mdev);
cleanup_sysfs(spec);
pci_set_drvdata(pdev, NULL);
kfree(spec);
}
static struct pci_driver pci_driver = {
.name = MODULE_NAME,
.id_table = pci_ids,
.probe = probe_one,
.remove = remove_one
};
static int __init spec7_module_init(void) {
int rc = pci_register_driver(&pci_driver);
if (rc == 0)
pr_info("loaded\n"); // (compiled at %s %s)\n", __DATE__, __TIME__);
else
pr_alert("failed. Could not register pci driver.");
return rc;
}
static void __exit spec7_module_exit(void) {
pci_unregister_driver(&pci_driver);
pr_info("removed\n");
}
module_init(spec7_module_init);
module_exit(spec7_module_exit);
/*
* Copyright (C) 2021 NIKHEF Amsterdam
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/device.h>
#include "spec7.h"
static ssize_t show_deadbee(struct device *dev, struct device_attribute *attr, char *buf)
{
struct spec7_dev *spec = dev_get_drvdata(dev);
u32 reg = ioread32(spec->syscon_reg_addr);
return scnprintf(buf, PAGE_SIZE, "%x", ((reg & 0x10000000) != 0) ? 1 : 0);
}
static ssize_t store_deadbee(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
unsigned val;
struct spec7_dev *spec = dev_get_drvdata(dev);
if (sscanf(buf, "%u", &val) != 1)
return -EINVAL;
if (val == 0)
iowrite32(0x0deadbee, spec->syscon_reg_addr);
else if (val == 1)
iowrite32(0x1deadbee, spec->syscon_reg_addr);
else
return -EINVAL;
return count;
}
static DEVICE_ATTR(deadbee, S_IRUSR | S_IWUSR, show_deadbee, store_deadbee);
ssize_t lm32_mem_read(struct file *filep, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct spec7_dev *spec = dev_get_drvdata(dev);
u32 *src_addr = spec->lm32_mem + (pos >> 2);
unsigned n;
pr_debug("pos = %llu, size = %lu\n", pos, size);
/* only 32-bit aligned and 32-bit multiples */
if (pos & 3)
return -EPROTO;
for (n = (size >> 2); n > 0; n--) {
u32 data = ioread32be(src_addr++); // present the data as big-endian
memcpy(buf, &data, 4);
buf += 4;
}
return size;
}
ssize_t lm32_mem_write(struct file *filep, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct spec7_dev *spec = dev_get_drvdata(dev);
u32 *dest_addr = spec->lm32_mem + (pos >> 2);
unsigned n;
pr_debug("pos = %llu, size = %lu\n", pos, size);
/* only 32-bit aligned and 32-bit multiples */
if (pos & 3)
return -EPROTO;
for (n = (size >> 2); n > 0; n--) {
u32 data;
memcpy(&data, buf, 4);
iowrite32be(data, dest_addr++); // expect the data to be big-endian
buf += 4;
}
return size;
}
static BIN_ATTR(lm32_mem, S_IRUSR | S_IWUSR, lm32_mem_read, lm32_mem_write, LM32_MEM_SIZE);
int populate_sysfs(struct spec7_dev *spec)
{
if (device_create_file(&spec->pdev->dev, &dev_attr_deadbee) < 0 ||
device_create_bin_file(&spec->pdev->dev, &bin_attr_lm32_mem) < 0)
return -1;
return 0;
}
void cleanup_sysfs(struct spec7_dev *spec)
{
device_remove_file(&spec->pdev->dev, &dev_attr_deadbee);
device_remove_bin_file(&spec->pdev->dev, &bin_attr_lm32_mem);
}
/*
* Copyright (C) 2021 Ton damen, tond@nikhef.nl
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* File: sysfs.h
* Author: Ton Damen, tond@nikhef.nl
*
* Created on 15 september 2021, 10:11
*/
#ifndef SYSFS_H
#define SYSFS_H
int populate_sysfs(struct spec7_dev *dev);
void cleanup_sysfs(struct spec7_dev *dev);
#endif /* SYSFS_H */
/*
* A tool to program our soft-core (LM32) within the SPEC.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include "speclib.h"
static char git_version[] = "version: " GIT_VERSION;
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s\n", libspec_version_s);
}
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, c;
uint32_t lm32_base = 0x80000;
void *card;
while ((c = getopt (argc, argv, "b:d:c:V")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
case 'c':
sscanf(optarg, "%i", &lm32_base);
break;
case 'V':
print_version(argv[0]);
exit(0);
default:
fprintf(stderr,
"Use: \"%s [-V] [-b bus] [-d devfn] "
"[-c lm32 base address] <lm32_program.bin>\"\n",
argv[0]);
fprintf(stderr,
"By default, the first available SPEC is used "
"and the LM32 is assumed at 0x%x.\n",
lm32_base);
exit(1);
}
}
if (optind >= argc) {
fprintf(stderr, "%s: Expected binary name after options.\n",
argv[0]);
exit(1);
}
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "%s: Can't detect a SPEC card under the given "
"adress.\nMake sure a SPEC card is present in your PC, "
"the driver is loaded and you run the program as root.\n", argv[0]);
exit(1);
}
if(spec_load_lm32(card, argv[optind], lm32_base) < 0)
{
fprintf(stderr, "%s: Loader failure.\n", argv[0]);
exit(1);
}
spec_close(card);
exit (0);
}
/*
* A tool to program the FPGA within the SPEC.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include "speclib.h"
static char git_version[] = "version: " GIT_VERSION;
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s\n", libspec_version_s);
}
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, c;
void *card;
while ((c = getopt (argc, argv, "b:d:V")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
case 'V':
print_version(argv[0]);
exit(0);
default:
fprintf(stderr,
"Use: \"%s [-V] [-b bus] [-d devfn] "
"<fpga_bitstream.bin>\"\n", argv[0]);
fprintf(stderr, "By default, the first available SPEC "
"is used.\n");
exit(1);
}
}
if (optind >= argc) {
fprintf(stderr, "Expected binary name after options.\n");
exit(1);
}
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "Can't detect a SPEC card under the given "
"adress.\nMake sure a SPEC card is present in your PC, "
"the driver is loaded and you run the program as root.\n");
exit(1);
}
if(spec_load_bitstream(card, argv[optind]) < 0)
{
fprintf(stderr, "Loader failure.\n");
exit(1);
}
spec_close(card);
exit (0);
}
/* A simple console for accessing the SPEC virtual UART (i.e. for communicating with the WR Core shell
from a Linux terminal. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <getopt.h>
#include <errno.h>
#include "speclib.h"
#define VUART_BASE_WRC 0x20500
#define VUART_BASE_ZYNQ 0x80000
static char git_version[] = "version: " GIT_VERSION;
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s\n", libspec_version_s);
}
static void *card;
static int transfer_byte(int from, int is_control, int vuart_zynq) {
char c;
int ret;
do {
ret = read(from, &c, 1);
} while (ret < 0 && errno == EINTR);
if(ret == 1) {
if(is_control) {
if(c == '\x01') { // C-a
return -1;
}
}
spec_vuart_tx(card, &c, 1, vuart_zynq);
} else {
fprintf(stderr, "nothing to read. Port disconnected?\n");
return -2;
}
return 0;
}
void term_main(int keep_term, int vuart_zynq)
{
struct termios oldkey, newkey;
//above is place for old and new port settings for keyboard teletype
int need_exit = 0;
fprintf(stderr, "[press C-a to exit]\n");
if(!keep_term) {
tcgetattr(STDIN_FILENO,&oldkey);
if(vuart_zynq) {
newkey.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
} else {
newkey.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
}
newkey.c_iflag = IGNPAR;
newkey.c_oflag = 0;
newkey.c_lflag = 0;
newkey.c_cc[VMIN]=1;
newkey.c_cc[VTIME]=0;
tcflush(STDIN_FILENO, TCIFLUSH);
tcsetattr(STDIN_FILENO,TCSANOW,&newkey);
}
while(!need_exit) {
fd_set fds;
int ret;
char rx;
int period;
if(vuart_zynq) {
period = 1000;
} else {
period = 10000;
}
struct timeval tv = {0, period};
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
ret = select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
if(ret == -1) {
perror("select");
} else if (ret > 0) {
if(FD_ISSET(STDIN_FILENO, &fds)) {
need_exit = transfer_byte(STDIN_FILENO, 1, vuart_zynq);
}
}
while((spec_vuart_rx(card, &rx, 1, vuart_zynq)) == 1)
fprintf(stderr,"%c", rx);
}
if(!keep_term)
tcsetattr(STDIN_FILENO,TCSANOW,&oldkey);
}
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, c;
uint32_t vuart_base;
int vuart_base_override = 0;
int keep_term = 0;
int vuart_zynq = 0;
while ((c = getopt (argc, argv, "b:d:u:zkV")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
case 'z':
vuart_zynq = 1;
break;
case 'u':
sscanf(optarg, "%i", &vuart_base);
vuart_base_override = 1;
break;
case 'k':
keep_term = 1;
break;
case 'V':
print_version(argv[0]);
exit(0);
default:
fprintf(stderr,
"Use: \"%s [-V] [-b bus] [-d devfn] [-z] "
"[-u VUART base] [-k]\"\n", argv[0]);
fprintf(stderr,
"By default, the first available SPEC is used.\n"
"-z option connects to the Zynq UART, WRC otherwise.\n"
"-u overrides the VUART base address, default:\n"
" default base address for WRC UART: 0x%x\n"
" default base address for Zynq UART: 0x%x\n"
"-k option keeps the prev terminal config\n",
VUART_BASE_WRC, VUART_BASE_ZYNQ);
exit(1);
}
}
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "Can't detect a SPEC card under the given "
"adress.\nMake sure a SPEC card is present in your PC, "
"the driver is loaded and you run the program as root.\n");
exit(1);
}
if(!vuart_base_override) {
if(vuart_zynq)
vuart_base = VUART_BASE_ZYNQ;
else
vuart_base = VUART_BASE_WRC;
}
spec_vuart_init(card, vuart_base);
if(vuart_zynq) {
spec_vuart_clear(card);
}
term_main(keep_term, vuart_zynq);
spec_close(card);
return 0;
}
/*
* Trivial library function to return one of the spec memory addresses
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/signal.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include "speclib.h"
#include "wb_uart.h"
const char * const libspec_version_s = "libspec version: " GIT_VERSION;
struct spec_private {
/* BAR0 maps the local bus (i.e. we can access FGPA register) */
void *bar0;
/* BAR4 maps the XDMA Bypass zone */
void *bar4;
uint32_t vuart_base;
};
/*
* Check if the PCI device at bus/def_fn is a SPEC board.
* Return 1 if the device is a SPEC and 0 if it is not.
* If there is an error accessing the files, return -1
*/
static int spec_check_id(int bus, int dev)
{
unsigned int vendor, device;
char buf[128];
FILE *f;
// check device
snprintf(buf, sizeof buf,
"/sys/bus/pci/devices/0000:%02x:%02x.0/device",
bus, dev);
f=fopen(buf,"r");
if (f==NULL){
fprintf(stderr,"error accessing to file\n");
return -1;
}
fscanf(f, "%x", &device);
fclose(f);
// check vendor
snprintf(buf, sizeof buf,
"/sys/bus/pci/devices/0000:%02x:%02x.0/vendor",
bus, dev);
f=fopen(buf,"r");
if (f==NULL){
fprintf(stderr,"error accessing to file\n");
return -1;
}
fscanf(f, "%x", &vendor);
fclose(f);
//fprintf(stderr, "Detected: device: %x, vendor: %x\n", device, vendor);
//fprintf(stderr, "Hardcoded: device: %x, vendor: %x\n", PCI_DEVICE_ID_SPEC7, PCI_VENDOR_ID_SPEC7);
if (device== PCI_DEVICE_ID_SPEC7 && vendor== PCI_VENDOR_ID_SPEC7)
return 1;
return 0;
}
/*
* Checks if there's a SPEC card at bus/def_fn.
* If one (or both) parameters are < 0, takes first available card
* and returns 0. If no cards have been detected, returns -1
*/
static int spec_scan(int *bus, int *devfn)
{
struct dirent **namelist;
int n, i, found = 0, ret;
int my_bus, my_devfn;
// Automatic search for the first availabe card
n = scandir("/sys/bus/pci/devices/", &namelist, 0, 0);
if (n < 0)
{
perror("scandir");
exit(-1);
}
for (i = 0; i < n; i++)
{
ret = sscanf(namelist[i]->d_name, "0000:%02x:%02x.0",
&my_bus, &my_devfn);
if(!found && ret == 2)
{
if (*bus >= 0)
my_bus = *bus;
if (*devfn >= 0)
my_devfn = *devfn;
if (spec_check_id(my_bus, my_devfn) > 0)
{
*bus = my_bus;
*devfn = my_devfn;
found = 1;
}
}
free(namelist[i]);
}
free(namelist);
if(!found)
{
fprintf(stderr,"Can't detect any SPEC card :(\n");
return -1;
}
return 0;
}
/* Maps a particular BAR of given SPEC card and returns its virtual address
(or NULL in case of failure) */
static void *spec_map_area(int bus, int dev, int bar, size_t size)
{
char path[1024];
int fd;
void *ptr;
snprintf(path, sizeof(path), "/sys/bus/pci/devices/"
"/0000:%02x:%02x.0/resource%d", bus, dev, bar);
fd = open(path, O_RDWR | O_SYNC);
if(fd <= 0)
return NULL;
ptr = mmap(NULL, size & ~(getpagesize()-1), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
close(fd);
if((long)ptr == -1)
return NULL;
return ptr;
}
void *spec_open(int bus, int dev)
{
struct spec_private *card = malloc(sizeof(struct spec_private));
if(!card || spec_scan(&bus, &dev) < 0)
return NULL;
card->bar0 = spec_map_area(bus, dev, BASE_BAR0, 0x100000);
card->bar4 = spec_map_area(bus, dev, BASE_BAR4, 0x1000000);
if(!card->bar0 && !card->bar4)
{
free(card);
card = NULL;
}
return card;
}
void *spec_get_base(void *card, int basenr)
{
struct spec_private *p = card;
if (basenr == BASE_BAR0)
return p->bar0;
if (basenr == BASE_BAR4)
return p->bar4;
return NULL;
}
void spec_close(void *card)
{
struct spec_private *p = (struct spec_private *) card;
if(!card)
return;
munmap(p->bar0, 0x100000);
munmap(p->bar4, 0x1000000);
free(card);
}
void spec_writel(void *card, uint32_t data, uint32_t addr)
{
struct spec_private *p = (struct spec_private *) card;
*(volatile uint32_t *) (p->bar0 + addr) = data;
}
uint32_t spec_readl(void *card, uint32_t addr)
{
struct spec_private *p = (struct spec_private *) card;
return *(volatile uint32_t *) (p->bar0 + addr);
}
static int vuart_wb_rx(void *card)
{
struct spec_private *p = (struct spec_private *) card;
int rdr = spec_readl(card, p->vuart_base + UART_REG_HOST_RDR);
if(rdr & UART_HOST_RDR_RDY)
return UART_HOST_RDR_DATA_R(rdr);
else
return -1;
}
static int vuart_lite_rx(void *card)
{
struct spec_private *p = (struct spec_private *) card;
int rx_status = spec_readl(card, p->vuart_base + UARTLITE_REG_SR);
int rx_data;
if(rx_status & UARTLITE_SR_RX_RDY)
{
rx_data = spec_readl(card, p->vuart_base + UARTLITE_REG_HOST_RDR);
return UART_HOST_RDR_DATA_R(rx_data);
}
else
return -1;
}
static int vuart_rx(void *card, int vuart_zynq)
{
if(vuart_zynq)
return vuart_lite_rx(card);
else
return vuart_wb_rx(card);
}
static void vuart_wb_tx(void *card, int c)
{
struct spec_private *p = (struct spec_private *) card;
while( spec_readl(card, p->vuart_base + UART_REG_SR) & UART_SR_RX_RDY);
spec_writel(card, UART_HOST_TDR_DATA_W(c),
p->vuart_base + UART_REG_HOST_TDR);
}
static void vuart_lite_tx(void *card, int c)
{
struct spec_private *p = (struct spec_private *) card;
while( spec_readl(card, p->vuart_base + UARTLITE_REG_SR) & UARTLITE_SR_TX_BUSY);
spec_writel(card, UART_HOST_TDR_DATA_W(c),
p->vuart_base + UARTLITE_REG_HOST_TDR);
}
static void vuart_tx(void *card, int c, int vuart_zynq)
{
if(vuart_zynq)
vuart_lite_tx(card, c);
else
vuart_wb_tx(card, c);
}
static char *load_binary_file(const char *filename, size_t *size)
{
int i;
struct stat stbuf;
char *buf;
FILE *f;
f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return NULL;
}
if (fstat(fileno(f), &stbuf) < 0) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
fclose(f);
return NULL;
}
if (!S_ISREG(stbuf.st_mode)) {
fprintf(stderr, "%s: not a regular file\n", filename);
fclose(f);
return NULL;
}
buf = malloc(stbuf.st_size);
if (!buf) {
fprintf(stderr, "loading %s: %s\n", filename, strerror(errno));
fclose(f);
return NULL;
}
i = fread(buf, 1, stbuf.st_size, f);
fclose(f);
if (i < 0) {
fprintf(stderr, "reading %s: %s\n", filename, strerror(errno));
free(buf);
return NULL;
}
if (i != stbuf.st_size) {
fprintf(stderr, "%s: short read\n", filename);
free(buf);
return NULL;
}
*size = stbuf.st_size;
return buf;
}
int spec_load_bitstream(void *card, const char *filename)
{
char *buf;
uint32_t *ibuf;
size_t size;
int i;
struct spec_private *p = (struct spec_private *) card;
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
ibuf = (uint32_t *) buf;
for (i = 0; i < (size + 3) / 4; i++)
*(volatile uint32_t *) (p->bar4 + i*4) = ibuf[i];
sync();
for (i = 0; i < (size + 3) / 4; i++) {
uint32_t r = *(volatile uint32_t *) (p->bar4 + i*4);
if (r != ibuf[i])
{
fprintf(stderr, "programming error at %x "
"(expected %08x, found %08x)\n", i*4,
ibuf[i], r);
return -1;
}
}
sync();
free(buf);
return 0;
}
int spec_load_lm32(void *card, const char *filename, uint32_t base_addr)
{
char *buf;
uint32_t *ibuf;
size_t size;
int i;
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
/* Phew... we are there, finally */
spec_writel(card, 0x1deadbee, base_addr + 0x20400);
while ( ! (spec_readl(card, base_addr + 0x20400) & (1<<28)) );
ibuf = (uint32_t *) buf;
for (i = 0; i < (size + 3) / 4; i++)
spec_writel(card, htonl(ibuf[i]), base_addr + i*4);
sync();
for (i = 0; i < (size + 3) / 4; i++) {
uint32_t r = spec_readl(card, base_addr + i * 4);
if (r != htonl(ibuf[i]))
{
fprintf(stderr, "programming error at %x "
"(expected %08x, found %08x)\n", i*4,
htonl(ibuf[i]), r);
return -1;
}
}
sync();
spec_writel(card, 0x0deadbee, base_addr + 0x20400);
return 0;
}
int spec_vuart_init(void *card, uint32_t base_addr)
{
struct spec_private *p = (struct spec_private *) card;
p->vuart_base = base_addr;
return 0;
}
int spec_vuart_clear(void *card)
{
// Clear TX and RX buffers in UARTLite
struct spec_private *p = (struct spec_private *) card;
spec_writel(card, 0x3,
p->vuart_base + UARTLITE_REG_CR);
return 0;
}
size_t spec_vuart_rx(void *card, char *buffer, size_t size, int vuart_zynq)
{
size_t s = size, n_rx = 0;
while(s--)
{
int c = vuart_rx(card, vuart_zynq);
if(c < 0)
return n_rx;
*buffer++ = c;
n_rx ++;
}
return n_rx;
}
size_t spec_vuart_tx(void *card, char *buffer, size_t size, int vuart_zynq)
{
size_t s = size;
while(s--)
vuart_tx(card, *buffer++, vuart_zynq);
return size;
}
#ifndef __SPECLIB_H
#define __SPECLIB_H
#include <stdint.h>
/* Vendor/Device ID to identify the SPEC */
#define PCI_VENDOR_ID_CERN 0x10dc
#define PCI_DEVICE_ID_SPEC_45T 0x018d
#define PCI_DEVICE_ID_SPEC_100T 0x01a2
#define PCI_VENDOR_ID_GENNUM 0x1a39
#define PCI_DEVICE_ID_GN4124 0x0004
#define PCI_VENDOR_ID_SPEC7 0x10ee
#define PCI_DEVICE_ID_SPEC7 0x7022
/* For compatibility */
#define PCI_DEVICE_ID_SPEC PCI_DEVICE_ID_SPEC_45T
/* 'Opens' the SPEC card at PCI bus [bus], device/function [dev].
Returns a handle to the card or NULL in case of failure. */
void *spec_open(int bus, int dev);
/* Closes the SPEC handle [card] */
void spec_close(void *card);
/* Loads the FPGA bitstream into card [card] from file [filename].
Returns 0 on success. */
int spec_load_bitstream(void *card, const char *filename);
/* Load the FPGA bitstram into car [card] from a given buffer [buf]
of size [size] */
int spec_load_bitstream_buffer(void *card, void *buf, size_t size);
/* Loads the WRC LM32 firmware into card [card] from file [filename]. starting at
address [base_addr]. Returns 0 on success.
WARNING: using improper base address/FPGA firmware will freeze the computer. */
int spec_load_lm32(void *card, const char *filename, uint32_t base_addr);
/* Raw I/O to BAR4 (Wishbone) */
void spec_writel(void *card, uint32_t data, uint32_t addr);
uint32_t spec_readl(void *card, uint32_t addr);
/* Initializes a virtual UART at base address [base_addr]. */
int spec_vuart_init(void *card, uint32_t base_addr);
/* Clear the TX/RX buffers of a virtual UART. */
int spec_vuart_clear(void *card);
/* Virtual uart Rx (VUART->Host) and Tx (Host->VUART) functions */
size_t spec_vuart_rx(void *card, char *buffer, size_t size, int vuart_zynq);
size_t spec_vuart_tx(void *card, char *buffer, size_t size, int vuart_zynq);
/* Get the pointer to access SPEC memory directly */
void *spec_get_base(void *card, int basenr);
enum {
BASE_BAR0 = 0, /* for wrpc etc (but lm32 is at 0x80000 offset) */
BASE_BAR2 = 2,
BASE_BAR4 = 4 /* for DMA Bypass access */
};
/* libspec version string */
extern const char * const libspec_version_s;
#endif
/*
* A tool to read SPEC-internal memory (only BAR0)
*
* Alessandro Rubini and Tomasz Wlostowski 2012 for CERN, GPLv2 or later.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "speclib.h"
static char git_version[] = "version: " GIT_VERSION;
void help(char *name)
{
fprintf(stderr,
"Use: \"%s [-V] [-b bus] [-d devfn] [-g] <offset> [<value>]\"\n",
name);
fprintf(stderr, "By default, the first available SPEC is used.\n");
exit(1);
}
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
printf("%s\n", libspec_version_s);
}
int main(int argc, char **argv)
{
int i, bar = BASE_BAR0;
int bus = -1, dev_fn = -1, c;
uint32_t *ptr;
uint32_t uarg[2];
int do_write;
void *card;
void *map_base;
char *end;
while ((c = getopt (argc, argv, "b:d:gV")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
case 'V':
print_version(argv[0]);
exit(0);
default:
help(argv[0]);
}
}
if (optind >= argc || optind < argc - 2)
help(argv[0]);
do_write = (optind == argc - 2);
/* convert the trailing hex number or numbers */
for (i = 0; i <= do_write; i++) {
uarg[i] = strtol(argv[optind + i], &end, 16);
if (end && *end) {
fprintf(stderr, "%s: \"%s\" is not an hex number\n",
argv[0], argv[optind + i]);
exit(1);
}
}
if (uarg[0] & 3) {
fprintf(stderr, "%s: address \"%s\" not multiple of 4\n",
argv[0], argv[optind + 0]);
exit(1);
}
card = spec_open(bus, dev_fn);
if (!card) {
fprintf(stderr, "%s: No SPEC card at bus %i, devfn %i\n",
argv[0], bus, dev_fn);
fprintf(stderr, " please make sure the address is correct,\n"
" spec.ko is loaded and you run as superuser.\n");
exit(1);
}
map_base = spec_get_base(card, bar);
if(!map_base || map_base == (void *) -1) {
fprintf(stderr, "%s: mmap(/dev/mem): %s\n", argv[0],
strerror(errno));
exit(1);
}
ptr = map_base + uarg[0];
/* by default, operate quietly (only report read value) */
if (!do_write) {
uarg[1] = *ptr;
if (!getenv("VERBOSE"))
printf("%08x\n", uarg[1]);
} else {
*ptr = uarg[1];
}
/* be verbose, if so requested */
if (getenv("VERBOSE")) {
if (argc == 2)
printf("%08x == %08x\n", uarg[0], uarg[1]);
else
printf("%08x := %08x\n", uarg[0], uarg[1]);
}
spec_close(card);
exit (0);
}
/*
Register definitions for slave core: Simple Wishbone UART
* File : wb_uart.h
* Author : auto-generated by wbgen2 from simple_uart_wb.wb
* Created : Thu May 3 17:36:38 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE simple_uart_wb.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_SIMPLE_UART_WB_WB
#define __WBGEN2_REGDEFS_SIMPLE_UART_WB_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Status Register */
/* definitions for field: TX busy in reg: Status Register */
#define UART_SR_TX_BUSY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX ready in reg: Status Register */
#define UART_SR_RX_RDY WBGEN2_GEN_MASK(1, 1)
/* definitions for register: Baudrate control register */
/* definitions for register: Transmit data regsiter */
/* definitions for field: Transmit data in reg: Transmit data regsiter */
#define UART_TDR_TX_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_TDR_TX_DATA_SHIFT 0
#define UART_TDR_TX_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_TDR_TX_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: Receive data regsiter */
/* definitions for field: Received data in reg: Receive data regsiter */
#define UART_RDR_RX_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_RDR_RX_DATA_SHIFT 0
#define UART_RDR_RX_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_RDR_RX_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: Host VUART Tx register */
/* definitions for field: TX Data in reg: Host VUART Tx register */
#define UART_HOST_TDR_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_HOST_TDR_DATA_SHIFT 0
#define UART_HOST_TDR_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_HOST_TDR_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for field: TX Ready in reg: Host VUART Tx register */
#define UART_HOST_TDR_RDY WBGEN2_GEN_MASK(8, 1)
/* definitions for register: Host VUART Rx register */
/* definitions for field: RX Data in reg: Host VUART Rx register */
#define UART_HOST_RDR_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_HOST_RDR_DATA_SHIFT 0
#define UART_HOST_RDR_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_HOST_RDR_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for field: RX Ready in reg: Host VUART Rx register */
#define UART_HOST_RDR_RDY WBGEN2_GEN_MASK(8, 1)
/* definitions for field: RX FIFO Count in reg: Host VUART Rx register */
#define UART_HOST_RDR_COUNT_MASK WBGEN2_GEN_MASK(9, 16)
#define UART_HOST_RDR_COUNT_SHIFT 9
#define UART_HOST_RDR_COUNT_W(value) WBGEN2_GEN_WRITE(value, 9, 16)
#define UART_HOST_RDR_COUNT_R(reg) WBGEN2_GEN_READ(reg, 9, 16)
#define UART_REG_SR 0x0
#define UART_REG_HOST_TDR 0x10
#define UART_REG_HOST_RDR 0x14
/* Xilinx UARTLite stuff */
/* definitions for field: TX busy in reg: Status Register */
#define UARTLITE_SR_TX_BUSY WBGEN2_GEN_MASK(3, 1)
/* definitions for field: RX ready in reg: Status Register */
#define UARTLITE_SR_RX_RDY WBGEN2_GEN_MASK(0, 1)
#define UARTLITE_REG_CR 0xc
#define UARTLITE_REG_SR 0x8
#define UARTLITE_REG_HOST_TDR 0x4
#define UARTLITE_REG_HOST_RDR 0x0
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment