Commit 7be72cf4 authored by Tristan Gingold's avatar Tristan Gingold

software: update test_vme, add vmedma and vmespy.

parent d2d407bd
VMEBRIDGE=/acc/local/L867/drv/vmebus/1.0.1
CC=gcc
CFLAGS=-O -Wall
CFLAGS=-O -Wall --std=c99 -I$(VMEBRIDGE)/include/vmebus
LDFLAGS=$(VMEBRIDGE)/lib/libvmebus.a -lrt
all: test_vme
all: test_vme vmespy vmedma
test_vme: test_vme.o
$(CC) -o $@ $< $(VMEBRIDGE)/lib/libvmebus.a -lrt
$(CC) -o $@ $< $(LDFLAGS)
test_vme.o: test_vme.c
$(CC) -c -o $@ $< --std=c99 $(CFLAGS) -I$(VMEBRIDGE)/include/vmebus
vmespy: vmespy.o
$(CC) -o $@ $< $(LDFLAGS)
vmespy.o: vmespy.c
vmedma.o: vmedma.c
vmedma: vmedma.o
$(CC) -o $@ $< $(LDFLAGS)
clean:
$(RM) -f test_vme *.o *~ *.pyc
$(RM) -f test_vme vmedma vmespy *.o *~ *.pyc
......@@ -368,7 +368,7 @@ do_test_dma_with_len (uint8_t am, uint32_t off, uint32_t len)
uint32_t r = ((uint32_t *)buf)[j];
uint32_t v;
v = (j + (off >> 2)) & 0xffff;
v = ((j << 2) + off) & 0xffff;
v = v | (~v << 16);
r = swapbe32 (r);
......@@ -474,7 +474,7 @@ static int
do_vme_test (void)
{
// A24
do_test_mem (0x3e);
// do_test_mem (0x3e);
do_test_mem (0x39);
// A32
......@@ -813,13 +813,13 @@ main (int argc, char **argv)
{
if (am == -1)
am = 0x39;
do_test_dma_with_len (am, 0x10000, 0x40000);
do_test_dma_with_len (am, 0x20000, 0x40000);
}
else if (strcmp (action, "mblt") == 0)
{
if (am == -1)
am = 0x38;
do_test_dma_with_len (am, 0x10000, 0x40000);
do_test_dma_with_len (am, 0x20000, 0x40000);
}
else if (strcmp (action, "show-func") == 0)
do_show_functions ();
......
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Tristan Gingold <tristan.gingold@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* test_vme: program to test the vme64xcore (to be used with the
* svec_vmecore_test design).
*/
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <unistd.h>
#include <getopt.h>
#include "libvmebus.h"
#define VME_2eVME 3
static enum vme_dma_block_size vbs = VME_DMA_BSIZE_2048;
static enum vme_dma_block_size pbs = VME_DMA_BSIZE_2048;
static void
rate_start (struct timespec *start_ts)
{
if (clock_gettime (CLOCK_MONOTONIC, start_ts) != 0)
{
fprintf (stderr, "clock_gettime error: %m\n");
exit (4);
}
}
static void
rate_done (struct timespec *start_ts, unsigned int nbr_bytes)
{
struct timespec end_ts;
unsigned long nano;
if (clock_gettime (CLOCK_MONOTONIC, &end_ts) != 0)
{
fprintf (stderr, "clock_gettime error: %m\n");
exit (4);
}
nano = (end_ts.tv_nsec - start_ts->tv_nsec)
+ (end_ts.tv_sec - start_ts->tv_sec) * 1000000000;
printf ("Rate: %f MB/sec\n",
nbr_bytes * 1.0E9 / nano / (1 << 20));
}
static enum vme_dma_block_size
convert_block_size (const char *str)
{
unsigned int num;
num = strtoul (str, NULL, 0);
switch (num)
{
case 32:
return VME_DMA_BSIZE_32;
case 64:
return VME_DMA_BSIZE_64;
case 128:
return VME_DMA_BSIZE_128;
case 256:
return VME_DMA_BSIZE_256;
case 512:
return VME_DMA_BSIZE_512;
case 1024:
return VME_DMA_BSIZE_1024;
case 2048:
return VME_DMA_BSIZE_2048;
case 4096:
return VME_DMA_BSIZE_4096;
default:
fprintf (stderr, "unhandled block size of %u\n", num);
exit (2);
}
}
static void
do_test_dma (uint8_t am, enum vme_2esst_mode vmode,
uint32_t addr, uint32_t len, void *buf)
{
struct vme_dma dma;
int s;
struct timespec start_ts;
memset (&dma, 0, sizeof (dma));
dma.status = 0; // ??
dma.length = len;
dma.novmeinc = 0;
dma.dir = VME_DMA_FROM_DEVICE;
dma.src.data_width = VME_D32;
dma.src.am = am;
dma.src.v2esst_mode = vmode;
dma.src.bcast_select = 0;
dma.src.addru = 0;
dma.src.addrl = addr;
dma.dst.addru = ((uintptr_t)buf) >> 32;
dma.dst.addrl = (uintptr_t)buf;
dma.ctrl.vme_block_size = vbs;
dma.ctrl.vme_backoff_time = VME_DMA_BACKOFF_0;
dma.ctrl.pci_block_size = pbs;
dma.ctrl.pci_backoff_time = VME_DMA_BACKOFF_0;
rate_start (&start_ts);
s = vme_dma_read (&dma);
rate_done (&start_ts, len);
if (s != 0)
printf ("Error: DMA read\n");
}
#define OPT_VBS 128
#define OPT_PBS 129
static const struct option options[] =
{
{ "addr", required_argument, 0, 'a' },
{ "len", required_argument, 0, 'n' },
{ "am", required_argument, 0, 'm' },
{ "2e", required_argument, 0, 'e' },
{ "dump", no_argument, 0, 'd' },
{ "help", no_argument, 0, 'h' },
{ "vbs", required_argument, 0, OPT_VBS },
{ "pbs", required_argument, 0, OPT_PBS },
{ NULL, 0, 0, 0 }
};
int
main (int argc, char **argv)
{
int am = 0x08; /* MBLT */
unsigned addr = 0xffffffff;
unsigned int len = 4096;
int c;
void *buf;
int flag_dump = 0;
enum vme_2esst_mode vmode = VME_2eVME;
while ((c = getopt_long (argc, argv, "a:m:n:e:dh",
options, NULL)) != -1)
switch (c)
{
case 'a':
addr = strtoul (optarg, NULL, 0);
break;
case 'n':
len = strtol (optarg, NULL, 0);
break;
case 'm':
am = strtol (optarg, NULL, 0);
break;
case 'e':
if (strcmp (optarg, "2eVME") == 0)
vmode = VME_2eVME;
else if (strcmp (optarg, "2eSST") == 0
|| strcmp (optarg, "2eSST-160") == 0)
vmode = VME_SST160;
else {
fprintf (stderr, "%s: bad value for -e, expect 2eVME or 2eSST-160\n",
argv[0]);
exit(3);
}
break;
case 'd':
flag_dump = 1;
break;
case OPT_VBS:
vbs = convert_block_size (optarg);
break;
case OPT_PBS:
pbs = convert_block_size (optarg);
break;
case 'h':
printf ("usage: %s -a ADDR [-m AM] [-n LENGTH]\n", argv[0]);
printf ("options:\n"
" --vbs=SZ set VME block size\n"
" --pbs=SZ set PCI block size\n");
return 0;
case '?':
fprintf (stderr, "incorrect option, try %s -h\n", argv[0]);
return 1;
}
if (addr == 0xffffffff)
{
fprintf (stderr, "missing address\n");
return 2;
}
if (am == 0)
{
fprintf (stderr, "bad AM\n");
return 2;
}
printf ("INFO: test DMA for am 0x%02x, mode: %u (addr: 0x%08x, len: 0x%0x)\n",
am, vmode, addr, len);
if (posix_memalign (&buf, 4096, len) != 0)
{
fprintf (stderr, "cannot allocate memory\n");
exit (4);
}
do_test_dma (am, vmode, addr, len, buf);
if (flag_dump)
for (unsigned i = 0; i < len; i += 4)
printf ("%08x: %08x\n", addr + i, ((unsigned int *)buf)[i >> 2]);
free (buf);
return 0;
}
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Tristan Gingold <tristan.gingold@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* test_vme: program to test the vme64xcore (to be used with the
* svec_vmecore_test design).
*/
#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include "libvmebus.h"
#define MAX(A, B) ((A) > (B) ? (A) : (B))
static unsigned slot = 0;
static volatile unsigned char *conf;
static uint32_t
read_conf4 (unsigned int addr)
{
return (conf[addr + 0] << 24)
| (conf[addr + 4] << 16)
| (conf[addr + 8] << 8)
| (conf[addr + 12] << 0);
}
static uint64_t
read_conf8 (unsigned int addr)
{
uint64_t res = 0;
for (int i = 0; i < 8; i++)
res = (res << 8) | conf[addr + i * 4];
return res;
}
struct vme_function
{
uint64_t amcap;
uint32_t adem;
uint32_t ader;
uint8_t am;
};
static void
read_vme_function (struct vme_function *res, int i)
{
res->amcap = read_conf8(0x123 + i * 0x20);
res->adem = read_conf4(0x623 + i * 0x10);
res->ader = read_conf4(0x7ff63 + i * 0x10);
res->am = (res->ader >> 2) & 0x3f;
}
static bool
is_vme_function_enabled (struct vme_function *f)
{
if ((f->ader & 1) || ((f->amcap >> f->am) & 1) == 0)
return false;
else
return true;
}
static struct vme_mapping data_map;
static void *ptr;
static volatile unsigned char *ptr8;
static volatile unsigned short *ptr16;
static volatile unsigned int *ptr32;
/* Setup the board for access mode AM. Return the base + mask. */
static void
setup_am (uint8_t am, uint32_t *base, uint32_t *mask)
{
for (int i = 0; i < 8; i++)
{
struct vme_function fn;
read_vme_function (&fn, i);
if (!((fn.amcap >> am) & 1))
continue;
*mask = fn.adem & 0xffffff00;
*base = (slot << 19) & *mask;
fn.ader = *base | (am << 2);
fn.am = am;
conf[0x7ff63 + i * 0x10 + 0] = (fn.ader >> 24) & 0xff;
conf[0x7ff63 + i * 0x10 + 4] = (fn.ader >> 16) & 0xff;
conf[0x7ff63 + i * 0x10 + 8] = (fn.ader >> 8) & 0xff;
conf[0x7ff63 + i * 0x10 + 12] = (fn.ader >> 0) & 0xff;
return;
}
fprintf (stderr, "am 0x%02x is not supported\n", am);
exit (3);
}
/* Map vme space defined by AM, BASE, MASK to user memory. */
static void
setup_map (uint8_t am, uint32_t base, uint32_t mask)
{
if (ptr != NULL)
{
vme_unmap (&data_map, 1);
ptr = NULL;
}
data_map.am = am;
data_map.data_width = 32;
data_map.sizel = MAX (0x80000, ~mask + 1);
data_map.vme_addrl = base & mask;
printf ("INFO: Map VME 0x%08x AM 0x%02x (base=%08x mask=%08x)\n",
data_map.vme_addrl, data_map.am, base, mask);
/* Do mmap */
ptr = vme_map(&data_map, 1);
if (!ptr)
{
fprintf (stderr, "cannot map vme space\n");
exit (3);
}
ptr8 = (volatile unsigned char *)ptr;
ptr16 = (volatile unsigned short *)ptr;
ptr32 = (volatile unsigned int *)ptr;
}
/* Setup the board for AM and map the address space. */
static uint32_t
map_for_am (uint8_t am)
{
uint32_t base;
uint32_t mask;
setup_am (am, &base, &mask);
setup_map (am, base, mask);
return base;
}
static void
map_crcsr (void)
{
struct vme_mapping conf_map;
/* Map the CR/CSR space of the board. */
memset (&conf_map, 0, sizeof (conf_map));
conf_map.am = VME_CR_CSR;
conf_map.data_width = 32;
conf_map.sizel = 512 << 10;
conf_map.vme_addrl = (slot << 19);
conf = vme_map(&conf_map, 1);
if (!conf)
{
fprintf (stderr, "cannot map vme CR/CSR space\n");
exit (3);
}
}
void
do_show_functions (void)
{
int i;
for (i = 0; i < 8; i++)
{
int j;
struct vme_function fn;
read_vme_function (&fn, i);
printf ("F%d: amcap=%016lx adem=%08x ader=%08x am=%02x\n",
i, fn.amcap, fn.adem, fn.ader, fn.am);
for (j = 0; j < 64; j++)
if ((fn.amcap >> j) & 1)
printf (" %02x", j);
printf ("\n");
}
}
int
main (int argc, char **argv)
{
int am = -1;
int c;
char *action = NULL;
while ((c = getopt (argc, argv, "s:ha:m:")) != -1)
switch (c)
{
case 's':
slot = strtol (optarg, NULL, 0);
break;
case 'm':
am = strtol (optarg, NULL, 0);
break;
case 'a':
action = optarg;
break;
case 'h':
printf ("usage: %s [-h] [-m AM] [-a ACTION] -s SLOT\n", argv[0]);
return 0;
case '?':
fprintf (stderr, "incorrect option, try %s -h\n", argv[0]);
return 1;
}
if (slot == 0 || slot > 0x1f)
{
fprintf (stderr, "incorrect or missing slot value (1 - 0x1f)\n");
return 2;
}
if (strcmp (action, "set-ader") == 0)
{
unsigned int fn;
uint32_t addr;
unsigned int am;
if (optind + 3 != argc)
{
fprintf (stderr, "usage: set-adr FN ADDR AM\n");
exit (2);
}
fn = strtoul (argv[optind + 0], NULL, 0);
addr = strtoul (argv[optind + 1], NULL, 0);
am = strtoul (argv[optind + 2], NULL, 0);
printf ("setting ader %u to %08x %02x\n", fn, addr, am);
map_crcsr ();
addr |= am << 2;
conf[0x7ff63 + fn * 0x10 + 0] = (addr >> 24) & 0xff;
conf[0x7ff63 + fn * 0x10 + 4] = (addr >> 16) & 0xff;
conf[0x7ff63 + fn * 0x10 + 8] = (addr >> 8) & 0xff;
conf[0x7ff63 + fn * 0x10 + 12] = (addr >> 0) & 0xff;
return 0;
}
else if (strcmp (action, "show-ader") == 0)
{
map_crcsr ();
do_show_functions ();
return 0;
}
if (am == -1)
{
/* MAP A24. */
setup_map (0x39, slot << 19, ~((512 << 10) - 1));
}
else
{
map_crcsr ();
/* Set an am if needed. */
if (am != -1)
map_for_am (am);
else
{
/* Find a map. */
memset (&data_map, 0, sizeof (data_map));
for (int i = 0; i < 8; i++)
{
struct vme_function fn;
read_vme_function (&fn, i);
if (!is_vme_function_enabled (&fn))
continue;
uint32_t mask = fn.adem & 0xffffff00;
uint32_t base = fn.ader & mask;
printf ("Func %d: 0x%08x-0x%08x, am=0x%02x\n",
i, base, (base & mask) | ~mask, fn.am);
setup_map (fn.am, base, mask);
break;
}
if (data_map.data_width == 0)
{
printf ("No map found\n");
return 3;
}
}
}
if (action == NULL || strcmp (action, "regs") == 0)
{
printf ("spy status: 0x%08x\n", swapbe32 (ptr32[0x4018 >> 2]));
printf ("spy counters: 0x%08x\n", swapbe32 (ptr32[0x401c >> 2]));
}
else if (strcmp (action, "count") == 0)
{
ptr32[0x401c >> 2] = swapbe32 (20);
}
else if (strcmp (action, "start") == 0)
{
unsigned int count = 10;
if (optind < argc)
count = atoi (argv[optind]);
printf ("Start trigger after %u transfers\n", count);
ptr32[0x401c >> 2] = swapbe32 (count);
ptr32[0x4018 >> 2] = swapbe32 (1);
}
else if (strcmp (action, "dump") == 0)
{
unsigned last;
unsigned addr, prev_addr;
unsigned data, prev_data;
unsigned ctrl, prev_ctrl;
last = swapbe32 (ptr32[0x401c >> 2]) >> 16;
prev_ctrl = 0;
prev_data = 0;
prev_addr = 0;
printf ("cycl: data addr am as wr ds dtack\n");
for (unsigned i = 0; i <= last; i++)
{
data = swapbe32 (ptr32[(0x20000 + (i << 4) + 0) >> 2]);
addr = swapbe32 (ptr32[(0x20000 + (i << 4) + 4) >> 2]);
ctrl = swapbe32 (ptr32[(0x20000 + (i << 4) + 8) >> 2]);
if (ctrl != prev_ctrl || addr != prev_addr || data != prev_data)
{
printf ("%04u: ", i);
printf (" %08x", data);
printf (" %08x", addr ^ 1);
printf (" %02x %x %x %x %x\n",
ctrl & 0x3f, (ctrl >> 10) & 1, (ctrl >> 8) & 1,
(ctrl >> 6) & 3, (ctrl >> 11) & 1);
prev_ctrl = ctrl;
prev_addr = addr;
prev_data = data;
}
}
}
else
printf ("unknown action\n");
return 0;
}
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