Commit 03fefdbe authored by root's avatar root Committed by Tomasz Wlostowski

software: initial DDS PLL version, seems to lock to a 10 MHz reference

parent 1bd30289
OBJS = ad9516.o speclib/speclib.o filters.o
CFLAGS = -I../include -g -Imini_bone -Ispeclib -I.
all: $(OBJS)
gcc -o rf-test $(OBJS) -lm
clean:
rm -f $(OBJS) rf-test
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include <math.h>
#include "speclib.h"
#include "regs/dds_regs.h"
#include "filters.h"
void loader_low_level() {};
struct wr_rf_device {
void *card;
uint32_t base;
};
static inline void rf_writel(struct wr_rf_device *dev, uint32_t data, uint32_t addr)
{
spec_writel(dev->card, data, addr + dev->base);
}
static inline uint32_t rf_readl(struct wr_rf_device *dev, uint32_t addr)
{
return spec_readl (dev->card, addr + dev->base);
}
static void gpio_set(struct wr_rf_device *dev, uint32_t pin, int value)
{
uint32_t g = rf_readl(dev, DDS_REG_GPIOR);
if(value)
rf_writel(dev, g | pin, DDS_REG_GPIOR);
else
rf_writel(dev, g & ~pin, DDS_REG_GPIOR);
}
static int gpio_get(struct wr_rf_device *dev, uint32_t pin)
{
return rf_readl(dev, DDS_REG_GPIOR) & pin;
}
/* Returns the numer of microsecond timer ticks */
int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* Microsecond-accurate delay */
void udelay(uint32_t usecs)
{
int64_t ts = get_tics();
while(get_tics() - ts < (int64_t)usecs);
}
static int extra_debug = 1;
void dbg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if(extra_debug)
vfprintf(stderr,fmt,ap);
va_end(ap);
}
void spi_txrx(struct wr_rf_device *dev, uint32_t cs_pin, int n_bits, uint32_t value, uint32_t *rval)
{
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 0);
udelay(10);
gpio_set(dev, cs_pin, 0);
udelay(10);
int i;
uint32_t rv = 0;
for(i = 0; i<n_bits; i++)
{
value <<= 1;
gpio_set(dev, DDS_GPIOR_PLL_SDIO, value & (1<<n_bits));
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 1);
udelay(10);
rv <<= 1;
rv |= gpio_get(dev, DDS_GPIOR_PLL_SDIO) ? 1 : 0;
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_SCLK, 0);
udelay(10);
}
gpio_set(dev, cs_pin, 1);
if(rval)
*rval = rv;
}
/* Reads a register from AD9516 */
static inline uint8_t ad951x_read_reg(struct wr_rf_device *dev, uint32_t cs_pin, uint16_t reg)
{
uint32_t rval;
spi_txrx(dev, cs_pin, 24, ((uint32_t)(reg & 0xfff) << 8) | (1<<23), &rval);
return rval & 0xff;
}
/* Writes an AD9516 register */
static inline void ad951x_write_reg(struct wr_rf_device *dev, uint32_t cs_pin, uint16_t reg, uint8_t val)
{
spi_txrx(dev, cs_pin, 24, ((uint32_t)(reg & 0xfff) << 8) | val, NULL);
// dbg("write %x val %x readback %x\n", reg, val, ad951x_read_reg(dev, cs_pin, reg));
}
static int ad9516_init(struct wr_rf_device *dev)
{
gpio_set(dev, DDS_GPIOR_PLL_SYS_RESET_N, 0);
udelay(1000);
gpio_set(dev, DDS_GPIOR_PLL_SYS_RESET_N, 1);
udelay(1000);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0, 0x99);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
static struct {
int reg;
int val;
} regs [] = {
#include "regs/ad9516_init.h"
};
/* Check if the chip is present by reading its ID register */
dbg("AD9516 PLL ID Register = %x\n", ad951x_read_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x3));
/* Check if the chip is present by reading its ID register */
if(ad951x_read_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x3) != 0xc3)
{
dbg("%s: AD9516 PLL not responding.\n", __FUNCTION__);
return -1;
}
int i;
/* Load the regs */
for(i=0;regs[i].reg >=0 ;i++)
ad951x_write_reg (dev, DDS_GPIOR_PLL_SYS_CS_N, regs[i].reg, regs[i].val);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 0);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
/* Wait until the PLL has locked */
uint64_t start_tics = get_tics();
uint64_t lock_timeout = 1000000ULL;
for(;;)
{
if(ad951x_read_reg(dev,DDS_GPIOR_PLL_SYS_CS_N, 0x1f) & 1)
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: AD9516 PLL does not lock.\n", __FUNCTION__);
return -1;
}
udelay(100);
}
/* Synchronize the phase of all clock outputs (this is critical for the accuracy!) */
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x230, 1);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x230, 0);
ad951x_write_reg(dev, DDS_GPIOR_PLL_SYS_CS_N, 0x232, 1);
dbg("%s: AD9516 locked.\n", __FUNCTION__);
}
void reset_core(struct wr_rf_device *dev)
{
rf_writel(dev, DDS_RSTR_PLL_RST, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, 0, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, DDS_RSTR_SW_RST, DDS_REG_RSTR);
udelay(10);
rf_writel(dev, 0, DDS_REG_RSTR);
udelay(10000);
}
void set_center_freq(struct wr_rf_device *dev, double freq, double sample_rate)
{
uint64_t tune =(uint64_t) ( (double)(1ULL<<42) * (freq / sample_rate) * 8.0 );
dbg("Setting DDS center freq to: %.3f MHz (Fs = %.3f MHz), tune = 0x%llx\n", freq/1e6, sample_rate/1e6, tune);
rf_writel(dev, (tune >> 32) & 0xffffffffULL, DDS_REG_FREQ_HI);
rf_writel(dev, tune & 0xffffffffULL, DDS_REG_FREQ_LO);
// dbg("Freq_Lo 0x%x\n", rf_readl(dev, DDS_REG_FREQ_LO));
// dbg("Freq_Hi 0x%x\n", rf_readl(dev, DDS_REG_FREQ_HI));
}
void adf4002_write(struct wr_rf_device *dev, uint32_t value)
{
gpio_set(dev, DDS_GPIOR_ADF_CLK, 0);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_LE, 0);
udelay(10);
int i;
for(i=0;i<24;i++)
{
value <<= 1;
gpio_set(dev, DDS_GPIOR_ADF_DATA, value & (1<<24) ? 1 : 0);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_CLK, 1);
udelay(10);
gpio_set(dev, DDS_GPIOR_ADF_CLK, 0);
}
gpio_set(dev, DDS_GPIOR_ADF_LE, 1);
udelay(10);
}
void adf4002_configure(struct wr_rf_device *dev, int r_div, int n_div, int mon_output)
{
gpio_set(dev, DDS_GPIOR_ADF_CE, 1); /* enable the PD */
udelay(10);
adf4002_write(dev, 0 | (r_div << 2));
adf4002_write(dev, 1 | (n_div << 8));
adf4002_write(dev, 2 | (0<<7) | ( mon_output << 4)); /* R div -> muxout */
}
void ad9510_init(struct wr_rf_device *dev)
{
gpio_set(dev, DDS_GPIOR_PLL_VCXO_FUNCTION, 0); /* reset AD9510 */
udelay(10);
gpio_set(dev, DDS_GPIOR_PLL_VCXO_FUNCTION, 1); /* reset AD9510 */
udelay(1000);
ad951x_write_reg(dev, DDS_GPIOR_PLL_VCXO_CS_N, 0, 0x10);
}
int read_adc(struct wr_rf_device *dev, int *buffer, int size)
{
int n = size;
while(n--)
{
while(rf_readl(dev, DDS_REG_PD_FIFO_CSR) & DDS_PD_FIFO_CSR_EMPTY);
*buffer++ = rf_readl(dev, DDS_REG_PD_FIFO_R0) & 0xffff;
}
return n;
}
void write_tune(struct wr_rf_device *dev, int tune)
{
while(rf_readl(dev, DDS_REG_TUNE_FIFO_CSR) & DDS_TUNE_FIFO_CSR_FULL);
rf_writel(dev, tune, DDS_REG_TUNE_FIFO_R0);
}
void modulation_test(struct wr_rf_device *dev)
{
rf_writel(dev, 80, DDS_REG_GAIN); /* tuning gain = 0 dB */
double f_test = 1e3;
double f_samp = 125e6/1024.0;
int n;
for(;;)
{
double x = 32767.0 * cos(2.0*M_PI*(double)n * f_test / f_samp);
// printf("S %d\n", (int)x);
write_tune(dev, (int) x);
n++;
}
}
int main(int argc, char *argv[])
{
struct wr_rf_device dev;
dev.card = spec_open(-1, -1);
dev.base = 0x80000;
if(!dev.card)
{
dbg("SPEC open failed\n");
return -1;
}
dbg("SDB signature = 0x%x\n", spec_readl(dev.card, 0));
ad9516_init(&dev);
reset_core(&dev);
set_center_freq(&dev, 10e6, 500e6);
// rf_writel(&dev, DDS_RSTR_SW_RST, DDS_REG_RSTR);
// sleep(2);
// rf_writel(&dev, 0, DDS_REG_RSTR);
adf4002_configure(&dev, 2, 2, 4);
struct fir_filter *flt_comp = fir_load("fir_compensator.dat");
struct iir_1st *flt_loop = lowpass_init(0.03);
rf_writel(&dev, 6000, DDS_REG_GAIN); /* tuning gain = 0 dB */
//for(;;) write_tune(&dev, 15000);
// return 0;
/* for(;;)
{
int i;
dbg("up...\n");
for(i=0;i<1000000;i++)
write_tune(&dev, 30000);
dbg("down...\n");
for(i=0;i<1000000;i++)
write_tune(&dev, -30000);
}*/
int i;
int s;
for(i=0;i<10000;i++)
read_adc(&dev, &s , 1);
for(;;)
{
int s;
read_adc(&dev, &s , 1);
s-=32768;
// s*=-1;
s = lowpass_process(flt_loop, s);
s = fir_process(flt_comp, s);
s/=25;
// printf("%d\n", s);
if(s < -32000) s = -32000;
else if (s > 32000) s = 32000;
// s = 30000;
write_tune(&dev, s);
}
modulation_test(&dev);
spec_close(dev.card);
return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include "fdelay_lib.h"
#include "sveclib/sveclib.h"
#include "speclib/speclib.h"
#include "fdelay_lib.h"
void printk() {};
static void fd_svec_writel(void *priv, uint32_t data, uint32_t addr)
{
svec_writel(priv, data, addr);
}
static uint32_t fd_svec_readl(void *priv, uint32_t addr)
{
return svec_readl(priv, addr);
}
static void fd_spec_writel(void *priv, uint32_t data, uint32_t addr)
{
spec_writel(priv, data, addr);
}
static uint32_t fd_spec_readl(void *priv, uint32_t addr)
{
return spec_readl(priv, addr);
}
#if 0
#endif
#define VENDOR_CERN 0xce42
#define DEVICE_FD_CORE 0xf19ede1a
#define DEVICE_VUART 0xe2d13d04
static int probe_svec(fdelay_device_t *dev, const char *location)
{
uint32_t map_base;
int slot;
void *card;
uint32_t core_base;
printf("probe_svec: loc %s\n", location);
if (!strncmp(location, "svec:", 5)) {
sscanf(location+5, "%d,%x,%x", &slot, &map_base, &core_base);
} else
return -ENODEV;
card = svec_open(slot);
svec_set_map_base(card, map_base, 1);
if(!card)
{
fprintf(stderr,"SVEC probe failed.\n");
return -1;
}
dev->priv_io = card;
dev->writel = fd_svec_writel;
dev->readl = fd_svec_readl;
dev->base_addr = core_base;
dbg("svec: using slot %d, A32/D32 base: 0x%x, core base 0x%x\n", slot, map_base, core_base);
return 0;
}
//void loader_low_level() {};
static int probe_spec(fdelay_device_t *dev, const char *location)
{
uint32_t core_base;
int slot;
if (!strncmp(location, "spec:", 5)) {
sscanf(location+5, "%d,%x", &slot, &core_base);
} else
return -ENODEV;
dev->priv_io = spec_open(slot, -1);
if(!dev->priv_io)
{
fprintf(stderr,"Can't map the SPEC @ slot %d\n", slot);
return -1;
}
dev->writel = fd_spec_writel;
dev->readl = fd_spec_readl;
dev->base_addr = core_base;
dbg("spec: using slot %d, core base 0x%x\n", slot, core_base);
return 0;
}
int fdelay_probe(fdelay_device_t *dev, const char *location)
{
int ret;
ret = probe_svec(dev, location);
if(ret != -ENODEV)
return ret;
ret = probe_spec(dev, location);
if(ret != -ENODEV)
return ret;
}
fdelay_device_t *fdelay_create()
{
return (fdelay_device_t *) malloc(sizeof(fdelay_device_t));
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct fir_filter {
int n_taps;
int pos;
int *delay;
double *coefs;
};
struct iir_1st {
int x0;
double y0, alpha;
};
struct fir_filter * fir_load(const char *coeffs_fname)
{
FILE * f=fopen(coeffs_fname, "r");
double coeffs[1024];
if(!f)
return NULL;
int n = 0, i;
while((fscanf(f, "%lf", &coeffs[n]) == 1) && n < 1024) n++;
printf("Loaded FIR Filter %s: %d taps.\n", coeffs_fname, n);
struct fir_filter *flt = malloc(sizeof(struct fir_filter));
flt->delay = malloc(sizeof(int) * n);
flt->coefs = malloc(sizeof(double) * n);
memcpy(flt->coefs, coeffs, sizeof(double) * n);
flt->n_taps = n;
flt->pos = 0;
memset(flt->delay, 0, sizeof(int) * n);
fclose(f);
return flt;
}
int fir_process(struct fir_filter *flt, int x)
{
double acc = 0.0;
flt->delay[flt->pos] = x;
int i;
for(i = 0; i< flt->n_taps; i++)
{
int idx = flt->pos - flt->n_taps + 1 + i;
if(idx < 0)
idx += flt->n_taps;
else if (idx >= flt->n_taps)
idx -= flt->n_taps;
acc += flt->coefs[i] * (double)flt->delay[idx];
}
flt->pos++;
if(flt->pos == flt->n_taps)
flt->pos = 0;
return (int) acc;
}
struct iir_1st * lowpass_init(double alpha)
{
struct iir_1st *flt = malloc(sizeof(struct iir_1st));
flt->alpha = alpha;
flt->y0 = 0.0;
// flt->x0 = 0;
return flt;
}
int lowpass_process(struct iir_1st *flt, int x)
{
double y = flt->y0 + flt->alpha * ((double) x - flt->y0);
flt->y0 = y;
return (int) y;
}
#ifndef __FILTERS_H
#define __FILTERS_H
#include <math.h>
struct fir_filter {
int n_taps;
int pos;
int *delay;
double *coefs;
};
struct iir_1st {
int x0;
double y0, alpha;
};
struct fir_filter * fir_load(const char *coeffs_fname);
int fir_process(struct fir_filter *flt, int x);
struct iir_1st * lowpass_init(double alpha);
int lowpass_process(struct iir_1st *flt, int x);
#endif
-0.00038385 -0.0013273 -0.0015635 0.00091054 0.0047773 0.0039991 -0.0042284 -0.010424 -0.001365 0.016826 0.01661 -0.013276 -0.036778 -0.0081087 0.051718 0.054753 -0.038602 -0.12613 -0.049535 0.20453 0.43998 0.43998 0.20453 -0.049535 -0.12613 -0.038602 0.054753 0.051718 -0.0081087 -0.036778 -0.013276 0.01661 0.016826 -0.001365 -0.010424 -0.0042284 0.0039991 0.0047773 0.00091054 -0.0015635 -0.0013273 -0.00038385
\ No newline at end of file
#!/bin/bash
insmod /home/user/pts/test/fmcdelay1ns4cha/lib/spec/kernel/spec.ko
spec-fwloader /home/user/rf18.bin
#!/usr/bin/python
import sys
import re
expr = re.compile("^\"([0-9a-fA-F]{4})\"\,\"[0-1]{8}\"\,\"([0-9a-fA-F]{2})\"", re.DOTALL)
lines = open(sys.argv[1],"r").readlines()
for l in lines:
m = re.match(expr, l)
if(m):
print("{0x%s, 0x%s}," % (m.groups(1)[0], (m.groups(1)[1])))
print("{-1, -1}");
\ No newline at end of file
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x08},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x0A},
{0x00F5, 0x0A},
{0x0140, 0x46},
{0x0141, 0x46},
{0x0142, 0x46},
{0x0143, 0x46},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0xBB},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x00},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x11},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x11},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x01},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, -1}
/*
Register definitions for slave core: DDS RF distribution WB Slave
* File : dds_regs.h
* Author : auto-generated by wbgen2 from dds_wb_slave.wb
* Created : Mon May 6 17:52:47 2013
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE dds_wb_slave.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_DDS_WB_SLAVE_WB
#define __WBGEN2_REGDEFS_DDS_WB_SLAVE_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: Control Register */
/* definitions for field: Enable DDS test mode in reg: Control Register */
#define DDS_CR_TEST WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Enable DDS RF slave mode in reg: Control Register */
#define DDS_CR_SLAVE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Enable DDS RF master mode in reg: Control Register */
#define DDS_CR_MASTER WBGEN2_GEN_MASK(2, 1)
/* definitions for field: ADC Bitbanged Access Enable in reg: Control Register */
#define DDS_CR_ADC_BB_ENABLE WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Broadcast Clock ID in reg: Control Register */
#define DDS_CR_CLK_ID_MASK WBGEN2_GEN_MASK(4, 16)
#define DDS_CR_CLK_ID_SHIFT 4
#define DDS_CR_CLK_ID_W(value) WBGEN2_GEN_WRITE(value, 4, 16)
#define DDS_CR_CLK_ID_R(reg) WBGEN2_GEN_READ(reg, 4, 16)
/* definitions for register: GPIO register */
/* definitions for field: System PLL CS in reg: GPIO register */
#define DDS_GPIOR_PLL_SYS_CS_N WBGEN2_GEN_MASK(0, 1)
/* definitions for field: System Reset in reg: GPIO register */
#define DDS_GPIOR_PLL_SYS_RESET_N WBGEN2_GEN_MASK(1, 1)
/* definitions for field: PLL SCLK (shared) in reg: GPIO register */
#define DDS_GPIOR_PLL_SCLK WBGEN2_GEN_MASK(2, 1)
/* definitions for field: PLL SDIO (shared) in reg: GPIO register */
#define DDS_GPIOR_PLL_SDIO WBGEN2_GEN_MASK(3, 1)
/* definitions for field: PLL SDIO direction (shared) in reg: GPIO register */
#define DDS_GPIOR_PLL_SDIO_DIR WBGEN2_GEN_MASK(4, 1)
/* definitions for field: VCXO PLL Reset in reg: GPIO register */
#define DDS_GPIOR_PLL_VCXO_RESET_N WBGEN2_GEN_MASK(5, 1)
/* definitions for field: VCXO PLL Chip Select in reg: GPIO register */
#define DDS_GPIOR_PLL_VCXO_CS_N WBGEN2_GEN_MASK(6, 1)
/* definitions for field: VCXO PLL Function in reg: GPIO register */
#define DDS_GPIOR_PLL_VCXO_FUNCTION WBGEN2_GEN_MASK(7, 1)
/* definitions for field: VCXO PLL SDO in reg: GPIO register */
#define DDS_GPIOR_PLL_VCXO_SDO WBGEN2_GEN_MASK(8, 1)
/* definitions for field: ADF4002 Chip Enable in reg: GPIO register */
#define DDS_GPIOR_ADF_CE WBGEN2_GEN_MASK(9, 1)
/* definitions for field: ADF4002 Clock in reg: GPIO register */
#define DDS_GPIOR_ADF_CLK WBGEN2_GEN_MASK(10, 1)
/* definitions for field: ADF4002 Latch Enable in reg: GPIO register */
#define DDS_GPIOR_ADF_LE WBGEN2_GEN_MASK(11, 1)
/* definitions for field: ADF4002 Data in reg: GPIO register */
#define DDS_GPIOR_ADF_DATA WBGEN2_GEN_MASK(12, 1)
/* definitions for field: AD7980 Bitbanged Data Out in reg: GPIO register */
#define DDS_GPIOR_ADC_SDI WBGEN2_GEN_MASK(13, 1)
/* definitions for field: AD7980 Bitbanged Convert Strobe in reg: GPIO register */
#define DDS_GPIOR_ADC_CNV WBGEN2_GEN_MASK(14, 1)
/* definitions for field: AD7980 Bitbanged Serial Clock in reg: GPIO register */
#define DDS_GPIOR_ADC_SCK WBGEN2_GEN_MASK(15, 1)
/* definitions for field: AD7980 Bitbanged Data In in reg: GPIO register */
#define DDS_GPIOR_ADC_SDO WBGEN2_GEN_MASK(16, 1)
/* definitions for register: DDS Center frequency hi */
/* definitions for register: DDS Center frequency lo */
/* definitions for register: DDS Gain */
/* definitions for register: Reset Register */
/* definitions for field: FPGA REF/Serdes PLL Reset in reg: Reset Register */
#define DDS_RSTR_PLL_RST WBGEN2_GEN_MASK(0, 1)
/* definitions for field: FPGA DDS Logic software reset in reg: Reset Register */
#define DDS_RSTR_SW_RST WBGEN2_GEN_MASK(1, 1)
/* definitions for register: I2C bitbanged IO register */
/* definitions for field: SCL Line out in reg: I2C bitbanged IO register */
#define DDS_I2CR_SCL_OUT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: SDA Line out in reg: I2C bitbanged IO register */
#define DDS_I2CR_SDA_OUT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: SCL Line in in reg: I2C bitbanged IO register */
#define DDS_I2CR_SCL_IN WBGEN2_GEN_MASK(2, 1)
/* definitions for field: SDA Line in in reg: I2C bitbanged IO register */
#define DDS_I2CR_SDA_IN WBGEN2_GEN_MASK(3, 1)
/* definitions for register: FIFO 'PD ADC Test FIFO (test mode)' data output register 0 */
/* definitions for field: ADC data in reg: FIFO 'PD ADC Test FIFO (test mode)' data output register 0 */
#define DDS_PD_FIFO_R0_DATA_MASK WBGEN2_GEN_MASK(0, 16)
#define DDS_PD_FIFO_R0_DATA_SHIFT 0
#define DDS_PD_FIFO_R0_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define DDS_PD_FIFO_R0_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for register: FIFO 'PD ADC Test FIFO (test mode)' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'PD ADC Test FIFO (test mode)' control/status register */
#define DDS_PD_FIFO_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'PD ADC Test FIFO (test mode)' control/status register */
#define DDS_PD_FIFO_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for register: FIFO 'DDS Tuning FIFO (test mode)' data input register 0 */
/* definitions for field: DDS tune word in reg: FIFO 'DDS Tuning FIFO (test mode)' data input register 0 */
#define DDS_TUNE_FIFO_R0_DATA_MASK WBGEN2_GEN_MASK(0, 32)
#define DDS_TUNE_FIFO_R0_DATA_SHIFT 0
#define DDS_TUNE_FIFO_R0_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DDS_TUNE_FIFO_R0_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'DDS Tuning FIFO (test mode)' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'DDS Tuning FIFO (test mode)' control/status register */
#define DDS_TUNE_FIFO_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'DDS Tuning FIFO (test mode)' control/status register */
#define DDS_TUNE_FIFO_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* [0x0]: REG Control Register */
#define DDS_REG_CR 0x00000000
/* [0x4]: REG GPIO register */
#define DDS_REG_GPIOR 0x00000004
/* [0x8]: REG DDS Center frequency hi */
#define DDS_REG_FREQ_HI 0x00000008
/* [0xc]: REG DDS Center frequency lo */
#define DDS_REG_FREQ_LO 0x0000000c
/* [0x10]: REG DDS Gain */
#define DDS_REG_GAIN 0x00000010
/* [0x14]: REG Reset Register */
#define DDS_REG_RSTR 0x00000014
/* [0x18]: REG I2C bitbanged IO register */
#define DDS_REG_I2CR 0x00000018
/* [0x1c]: REG FIFO 'PD ADC Test FIFO (test mode)' data output register 0 */
#define DDS_REG_PD_FIFO_R0 0x0000001c
/* [0x20]: REG FIFO 'PD ADC Test FIFO (test mode)' control/status register */
#define DDS_REG_PD_FIFO_CSR 0x00000020
/* [0x24]: REG FIFO 'DDS Tuning FIFO (test mode)' data input register 0 */
#define DDS_REG_TUNE_FIFO_R0 0x00000024
/* [0x28]: REG FIFO 'DDS Tuning FIFO (test mode)' control/status register */
#define DDS_REG_TUNE_FIFO_CSR 0x00000028
#endif
"AD9516 Setup File"
"Rev.","1.1.0"
""
"Addr(Hex)","Value(Bin)","Value(Hex)"
"0000","00011000","18"
"0001","00000000","00"
"0002","00010000","10"
"0003","11000011","C3"
"0004","00000000","00"
"0010","01111100","7C"
"0011","00000101","05"
"0012","00000000","00"
"0013","00001100","0C"
"0014","00010010","12"
"0015","00000000","00"
"0016","00000101","05"
"0017","00000000","00"
"0018","00000111","07"
"0019","00000000","00"
"001A","00000000","00"
"001B","00000000","00"
"001C","00000010","02"
"001D","00000000","00"
"001E","00000000","00"
"001F","00001110","0E"
"00A0","00000001","01"
"00A1","00000000","00"
"00A2","00000000","00"
"00A3","00000001","01"
"00A4","00000000","00"
"00A5","00000000","00"
"00A6","00000001","01"
"00A7","00000000","00"
"00A8","00000000","00"
"00A9","00000001","01"
"00AA","00000000","00"
"00AB","00000000","00"
"00F0","00001000","08"
"00F1","00001010","0A"
"00F2","00001010","0A"
"00F3","00001010","0A"
"00F4","00001010","0A"
"00F5","00001010","0A"
"0140","01000110","46"
"0141","01000110","46"
"0142","01000110","46"
"0143","01000110","46"
"0190","00000000","00"
"0191","10000000","80"
"0192","00000000","00"
"0193","10111011","BB"
"0194","00000000","00"
"0195","00000000","00"
"0196","00000000","00"
"0197","00000000","00"
"0198","00000000","00"
"0199","00010001","11"
"019A","00000000","00"
"019B","00010001","11"
"019C","00100000","20"
"019D","00000000","00"
"019E","00010001","11"
"019F","00000000","00"
"01A0","00010001","11"
"01A1","00100000","20"
"01A2","00000000","00"
"01A3","00000000","00"
"01E0","00000001","01"
"01E1","00000010","02"
"0230","00000000","00"
"0231","00000000","00"
"0232","00000000","00"
"","",""
"Other Settings..."
"REF 1:",25
"REF 2:",30.72
"VCO:",1500
"CLK:",1200
"CPRSet:",5100
"Auto Update:",1
"Load All Regs:",0
"AD9516 Setup File"
"Rev.","1.1.0"
""
"Addr(Hex)","Value(Bin)","Value(Hex)"
"0000","00011000","18"
"0001","00000000","00"
"0002","00010000","10"
"0003","11000011","C3"
"0004","00000000","00"
"0010","01111100","7C"
"0011","00000101","05"
"0012","00000000","00"
"0013","00010000","10"
"0014","00011000","18"
"0015","00000000","00"
"0016","00000101","05"
"0017","00000001","01"
"0018","00000111","07"
"0019","00000000","00"
"001A","00000000","00"
"001B","00000000","00"
"001C","00000010","02"
"001D","00000000","00"
"001E","00000000","00"
"001F","00001110","0E"
"00A0","00000001","01"
"00A1","00000000","00"
"00A2","00000000","00"
"00A3","00000001","01"
"00A4","00000000","00"
"00A5","00000000","00"
"00A6","00000001","01"
"00A7","00000000","00"
"00A8","00000000","00"
"00A9","00000001","01"
"00AA","00000000","00"
"00AB","00000000","00"
"00F0","00001000","08"
"00F1","00001010","0A"
"00F2","00001010","0A"
"00F3","00001010","0A"
"00F4","00001010","0A"
"00F5","00001010","0A"
"0140","01000010","42"
"0141","01010010","52"
"0142","01000010","42"
"0143","01000010","42"
"0190","00000000","00"
"0191","00000000","00"
"0192","00000000","00"
"0193","10111011","BB"
"0194","00000000","00"
"0195","00000000","00"
"0196","00000000","00"
"0197","00000000","00"
"0198","00000000","00"
"0199","00110011","33"
"019A","00000000","00"
"019B","00010001","11"
"019C","00100000","20"
"019D","00000000","00"
"019E","00110011","33"
"019F","00000000","00"
"01A0","00010001","11"
"01A1","00100000","20"
"01A2","00000000","00"
"01A3","00000000","00"
"01E0","00000000","00"
"01E1","00000010","02"
"0230","00000000","00"
"0231","00000000","00"
"0232","00000000","00"
"","",""
"Other Settings..."
"REF 1:",25
"REF 2:",30.72
"VCO:",2000
"CLK:",1200
"CPRSet:",5100
"Auto Update:",1
"Load All Regs:",0
"AD9516 Setup File"
"Rev.","1.1.0"
""
"Addr(Hex)","Value(Bin)","Value(Hex)"
"0000","00011000","18"
"0001","00000000","00"
"0002","00010000","10"
"0003","11000011","C3"
"0004","00000000","00"
"0010","01111100","7C"
"0011","00000101","05"
"0012","00000000","00"
"0013","00001100","0C"
"0014","00010010","12"
"0015","00000000","00"
"0016","00000101","05"
"0017","00000001","01"
"0018","00000111","07"
"0019","00000000","00"
"001A","00000000","00"
"001B","00000000","00"
"001C","00000010","02"
"001D","00000000","00"
"001E","00000000","00"
"001F","00001110","0E"
"00A0","00000001","01"
"00A1","00000000","00"
"00A2","00000000","00"
"00A3","00000001","01"
"00A4","00000000","00"
"00A5","00000000","00"
"00A6","00000001","01"
"00A7","00000000","00"
"00A8","00000000","00"
"00A9","00000001","01"
"00AA","00000000","00"
"00AB","00000000","00"
"00F0","00001000","08"
"00F1","00001010","0A"
"00F2","00001010","0A"
"00F3","00001010","0A"
"00F4","00001010","0A"
"00F5","00001010","0A"
"0140","01000010","42"
"0141","01000011","43"
"0142","01000010","42"
"0143","01000011","43"
"0190","00010000","10"
"0191","00000000","00"
"0192","00000000","00"
"0193","10111011","BB"
"0194","00000000","00"
"0195","00000000","00"
"0196","00000000","00"
"0197","00000000","00"
"0198","00000000","00"
"0199","00100010","22"
"019A","00000000","00"
"019B","00010001","11"
"019C","00100000","20"
"019D","00000000","00"
"019E","00100010","22"
"019F","00000000","00"
"01A0","00010001","11"
"01A1","00100000","20"
"01A2","00000000","00"
"01A3","00000000","00"
"01E0","00000000","00"
"01E1","00000010","02"
"0230","00000000","00"
"0231","00000000","00"
"0232","00000000","00"
"","",""
"Other Settings..."
"REF 1:",25
"REF 2:",30.72
"VCO:",1500
"CLK:",1200
"CPRSet:",5100
"Auto Update:",1
"Load All Regs:",0
"AD9516 Setup File"
"Rev.","1.1.0"
""
"Addr(Hex)","Value(Bin)","Value(Hex)"
"0000","00011000","18"
"0001","00000000","00"
"0002","00010000","10"
"0003","11000011","C3"
"0004","00000000","00"
"0010","01111100","7C"
"0011","00000101","05"
"0012","00000000","00"
"0013","00001100","0C"
"0014","00010010","12"
"0015","00000000","00"
"0016","00000101","05"
"0017","00000000","00"
"0018","00000111","07"
"0019","00000000","00"
"001A","00000000","00"
"001B","00000000","00"
"001C","00000010","02"
"001D","00000000","00"
"001E","00000000","00"
"001F","00001110","0E"
"00A0","00000001","01"
"00A1","00000000","00"
"00A2","00000000","00"
"00A3","00000001","01"
"00A4","00000000","00"
"00A5","00000000","00"
"00A6","00000001","01"
"00A7","00000000","00"
"00A8","00000000","00"
"00A9","00000001","01"
"00AA","00000000","00"
"00AB","00000000","00"
"00F0","00001000","08"
"00F1","00001010","0A"
"00F2","00001010","0A"
"00F3","00001010","0A"
"00F4","00001010","0A"
"00F5","00001010","0A"
"0140","01000110","46"
"0141","01000110","46"
"0142","01000110","46"
"0143","01000110","46"
"0190","00000000","00"
"0191","00000000","00"
"0192","00000000","00"
"0193","10111011","BB"
"0194","00000000","00"
"0195","00000000","00"
"0196","00000000","00"
"0197","00000000","00"
"0198","00000000","00"
"0199","00010001","11"
"019A","00000000","00"
"019B","00010001","11"
"019C","00100000","20"
"019D","00000000","00"
"019E","00010001","11"
"019F","00000000","00"
"01A0","00010001","11"
"01A1","00100000","20"
"01A2","00000000","00"
"01A3","00000000","00"
"01E0","00000001","01"
"01E1","00000010","02"
"0230","00000000","00"
"0231","00000000","00"
"0232","00000000","00"
"","",""
"Other Settings..."
"REF 1:",25
"REF 2:",30.72
"VCO:",1500
"CLK:",1200
"CPRSet:",5100
"Auto Update:",1
"Load All Regs:",0
CFLAGS = -ggdb -Wall
LDFLAGS = -L. -lspec
LIB = libspec.a
LIBOBJ = speclib.o loader-ll.o
PROGS = spec-cl spec-fwloader spec-vuart # specmem
all: $(LIB) $(PROGS)
$(PROGS): $(LIB)
$(LIB): $(LIBOBJ)
ar r $@ $^
loader-ll.o: ../kernel/loader-ll.c
${CC} -c $^ -I .
clean:
rm -f *.o $(LIB) $(PROGS) *~
\ No newline at end of file
/*
* This header differentiates between kernel-mode and user-mode compilation,
* as loader-ll.c is meant to be used in both contexts.
*/
#ifndef __iomem
#define __iomem /* nothing, for user space */
#endif
extern int loader_low_level(
int fd, /* This is ignored in kernel space */
void __iomem *bar4, /* This is ignored in user space */
const void *data,
int size8);
/* Registers from the gennum header files */
enum {
GNGPIO_BASE = 0xA00,
GNGPIO_DIRECTION_MODE = GNGPIO_BASE + 0x4,
GNGPIO_OUTPUT_ENABLE = GNGPIO_BASE + 0x8,
GNGPIO_OUTPUT_VALUE = GNGPIO_BASE + 0xC,
GNGPIO_INPUT_VALUE = GNGPIO_BASE + 0x10,
FCL_BASE = 0xB00,
FCL_CTRL = FCL_BASE,
FCL_STATUS = FCL_BASE + 0x4,
FCL_IODATA_IN = FCL_BASE + 0x8,
FCL_IODATA_OUT = FCL_BASE + 0xC,
FCL_EN = FCL_BASE + 0x10,
FCL_TIMER_0 = FCL_BASE + 0x14,
FCL_TIMER_1 = FCL_BASE + 0x18,
FCL_CLK_DIV = FCL_BASE + 0x1C,
FCL_IRQ = FCL_BASE + 0x20,
FCL_TIMER_CTRL = FCL_BASE + 0x24,
FCL_IM = FCL_BASE + 0x28,
FCL_TIMER2_0 = FCL_BASE + 0x2C,
FCL_TIMER2_1 = FCL_BASE + 0x30,
FCL_DBG_STS = FCL_BASE + 0x34,
FCL_FIFO = 0xE00,
PCI_SYS_CFG_SYSTEM = 0x800
};
/* The following part implements a different access rule for user and kernel */
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <errno.h>
static inline void lll_write(int fd, void __iomem *bar4, uint32_t val, int reg)
{
*(volatile uint32_t *)(bar4+reg) = val;
}
static inline uint32_t lll_read(int fd, void __iomem *bar4, int reg)
{
return *(volatile uint32_t *)(bar4 + reg);
}
#define KERN_ERR /* nothing */
#define printk(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
/*
* A tool to program our soft-core (LM32) within the SPEC.
*
* Alessandro Rubini 2012 for CERN, GPLv2 or later.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include "speclib.h"
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:")) != -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;
default:
fprintf(stderr,
"Use: \"%s [-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, "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. Make sure a SPEC card is present in your PC and the driver is loaded.\n");
exit(1);
}
if(spec_load_lm32(card, argv[optind], lm32_base) < 0)
{
fprintf(stderr, "Loader failure.\n");
exit(1);
}
spec_close(card);
exit (0);
}
/*
* A tool to program the FPGA within the SPEC.
*
* Alessandro Rubini 2012 for CERN, GPLv2 or later.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include "speclib.h"
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, c;
void *card;
while ((c = getopt (argc, argv, "b:d:")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
default:
fprintf(stderr,
"Use: \"%s [-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. Make sure a SPEC card is present in your PC and the driver is loaded.\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"
static void *card;
static int transfer_byte(int from, int is_control) {
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);
} else {
fprintf(stderr, "\nnothing to read. probably port disconnected.\n");
return -2;
}
return 0;
}
void term_main(int keep_term)
{
struct termios oldkey, newkey; //place tor 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);
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;
struct timeval tv = {0, 10000};
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);
}
}
while((spec_vuart_rx(card, &rx, 1)) == 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 = 0xe0500;
int keep_term = 0;
while ((c = getopt (argc, argv, "b:d:u:k")) != -1)
{
switch(c)
{
case 'b':
sscanf(optarg, "%i", &bus);
break;
case 'd':
sscanf(optarg, "%i", &dev_fn);
break;
case 'u':
sscanf(optarg, "%i", &vuart_base);
break;
case 'k':
keep_term = 1;
break;
default:
fprintf(stderr,
"Use: \"%s [-b bus] [-d devfn] [-u VUART base] [-k]\"\n", argv[0]);
fprintf(stderr,
"By default, the first available SPEC is used and the VUART is assumed at 0x%x.\n \
-k option keeps the terminal config unchanged.", vuart_base);
exit(1);
}
}
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "Can't detect a SPEC card under the given adress. Make sure a SPEC card is present in your PC and the driver is loaded.\n");
exit(1);
}
spec_vuart_init(card, vuart_base);
term_main(keep_term);
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"
#define BASE_BAR0 0
#define BASE_BAR4 4
struct spec_private {
void *bar0;
void *bar4;
uint32_t vuart_base;
};
/* 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, found = 0;
int my_bus, my_devfn;
n = scandir("/sys/bus/pci/drivers/spec", &namelist, 0, 0);
if (n < 0)
{
perror("can't find driver at /sys/bus/pci/drivers/spec = scandir");
return -1;
//exit(-1);
} else {
while (n--)
{
if(!found && sscanf(namelist[n]->d_name, "0000:%02x:%02x.0", &my_bus, &my_devfn) == 2)
{
if(*bus < 0) *bus = my_bus;
if(*devfn < 0) *devfn = my_devfn;
if(*bus == my_bus && *devfn == my_devfn)
found = 1;
}
free(namelist[n]);
}
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/drivers/spec/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);
if((int)ptr == -1)
{
close(fd);
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, 0x1000);
return card;
}
void spec_close(void *card)
{
struct spec_private *p = (struct spec_private *) card;
if(!card)
return;
munmap(p->bar0, 0x100000);
munmap(p->bar4, 0x1000);
free(card);
}
void spec_writel(void *card, uint32_t data, uint32_t addr)
{
// printf("Writel %x %x\n", addr, data);
struct spec_private *p = (struct spec_private *) card;
*(volatile uint32_t *) (p->bar0 + addr) = data;
}
uint32_t spec_readl(void *card, uint32_t addr)
{
// printf("Readl %x\n", addr);
struct spec_private *p = (struct spec_private *) card;
return *(volatile uint32_t *) (p->bar0 + addr);
}
static int vuart_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 void vuart_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 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)
return NULL;
if (fstat(fileno(f), &stbuf))
{
fclose(f);
return NULL;
}
if (!S_ISREG(stbuf.st_mode))
{
fclose(f);
return NULL;
}
buf = malloc(stbuf.st_size);
if (!buf)
{
fclose(f);
return NULL;
}
i = fread(buf, 1, stbuf.st_size, f);
if (i < 0) {
fclose(f);
free(buf);
return NULL;
}
if (i != stbuf.st_size) {
fclose(f);
free(buf);
return NULL;
}
fclose(f);
*size = stbuf.st_size;
return buf;
}
int spec_load_bitstream(void *card, const char *filename)
{
struct spec_private *p = (struct spec_private *) card;
char *buf;
size_t size;
// printf("load-bitstream: %s\n", filename);
buf = load_binary_file(filename, &size);
if(!buf)
return -1;
int rv = loader_low_level(0, p->bar4, buf, size);
free(buf);
return rv;
}
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;
}
size_t spec_vuart_rx(void *card, char *buffer, size_t size)
{
size_t s = size, n_rx = 0;
while(s--)
{
int c = vuart_rx(card);
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)
{
size_t s = size;
while(s--)
vuart_tx(card, *buffer++);
return size;
}
#ifndef __SPECLIB_H
#define __SPECLIB_H
#include <stdint.h>
/* '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);
/* 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);
/* Virtual uart Rx (VUART->Host) and Tx (Host->VUART) functions */
size_t spec_vuart_rx(void *card, char *buffer, size_t size);
size_t spec_vuart_tx(void *card, char *buffer, size_t size);
#endif
/*
* A tool to read SPEC-internal memory (only BAR0)
*
* Alessandro Rubini 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 "spec-tools.h"
int main(int argc, char **argv)
{
int i, fd, bar = BASE_BAR0;
uint32_t base, *ptr;
uint32_t uarg[3];
void *map_base;
char *end;
if (argc > 1 && !strcmp(argv[1], "-g")) {
bar = BASE_BAR4;
argv[1] = argv[0];
argc--; argv++;
}
if (argc < 2 || argc > 3) {
fprintf(stderr,
"Use: \"%s [-g] <offset> [<value>]\" "
"(-g selects gennum memory, I/O is 32 bits)\n",
argv[0]);
exit(1);
}
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
fprintf(stderr, "%s: open(/dev/mem): %s\n", argv[0],
strerror(errno));
exit(1);
}
base = spec_get_base(bar);
if (base == (typeof(base))-1) {
fprintf(stderr, "%s: spec_get_base(): %s\n", argv[0],
strerror(errno));
exit(1);
}
map_base = mmap(0, 1024 * 1024, /* gennum's bar 0 is 1M */
PROT_READ | PROT_WRITE, MAP_SHARED, fd, base);
if(map_base == (void *) -1) {
fprintf(stderr, "%s: mmap(/dev/mem): %s\n", argv[0],
strerror(errno));
exit(1);
}
for (i = 1; i < argc; i++) {
uarg[i] = strtol(argv[i], &end, 16);
if (end && *end) {
fprintf(stderr, "%s: \"%s\" is not an hex number\n",
argv[0], argv[i]);
exit(1);
}
}
if (uarg[1] & 3) {
fprintf(stderr, "%s: address \"%s\" not multiple of 4\n",
argv[0], argv[1]);
exit(1);
}
ptr = map_base + uarg[1];
/* by default, operate quietly (only report read value) */
if (argc == 2) {
uarg[2] = *ptr;
if (!getenv("VERBOSE"))
printf("%08x\n", uarg[2]);
} else {
*ptr = uarg[2];
}
/* be verbose, if so requested */
if (getenv("VERBOSE")) {
if (argc == 2)
printf("%08x == %08x\n", uarg[1], uarg[2]);
else
printf("%08x := %08x\n", uarg[1], uarg[2]);
}
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 Aug 9 10:31:41 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
#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