Skip to content
Snippets Groups Projects
Commit ca25d828 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski Committed by Alessandro Rubini
Browse files

spec-tools: moved the core functionality into a small library

parent ddec2e35
Branches
Tags
No related merge requests found
......@@ -7,31 +7,16 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "spec-tools.h"
#include "speclib.h"
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, i, c;
struct stat stbuf;
unsigned char *buf;
unsigned int *ibuf;
volatile uint32_t *p;
void *map_base;
char *fname;
int bus = -1, dev_fn = -1, c;
uint32_t lm32_base = 0x80000;
FILE *f;
void *card;
while ((c = getopt (argc, argv, "b:d:c:")) != -1)
{
......@@ -48,9 +33,9 @@ int main(int argc, char **argv)
break;
default:
fprintf(stderr,
"Use: \"%s [-b bus] [-d devfn] <fpga_bitstream.bin>\"\n", argv[0]);
"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 assumet at 0x%x.\n", lm32_base);
"By default, the first available SPEC is used and the LM32 is assumed at 0x%x.\n", lm32_base);
exit(1);
}
}
......@@ -60,76 +45,20 @@ int main(int argc, char **argv)
exit(1);
}
fname = argv[optind];
f = fopen(fname, "r");
if (!f) {
fprintf(stderr, "%s: %s: %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (fstat(fileno(f), &stbuf)) {
fprintf(stderr, "%s: stat(%s): %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (!S_ISREG(stbuf.st_mode)) {
fprintf(stderr, "%s: %s: Not a regular file\n", argv[0],
fname);
exit(1);
}
buf = malloc(stbuf.st_size);
if (!buf) {
fprintf(stderr, "%s: Can't allocate buffer (%li bytes): %s\n",
argv[0], (long)stbuf.st_size, strerror(errno));
exit(1);
}
i = fread(buf, 1, stbuf.st_size, f);
if (i < 0) {
fprintf(stderr, "%s: read(%s): %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (i != stbuf.st_size) {
fprintf(stderr, "%s: short read from %s\n", argv[0], fname);
exit(1);
}
map_base = spec_map_area(bus, dev_fn, BASE_BAR0, 0x100000);
if(!map_base)
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "%s: can't map the SPEC @ %02x:%02x\n", argv[0], bus, dev_fn);
exit(1);
}
ibuf = (void *)buf;
/* Phew... we are there, finally */
*(volatile uint32_t *)(map_base + lm32_base + 0x20400) = 0x1deadbee;
while ( !((*(volatile uint32_t *)(map_base + lm32_base + 0x20400)) & (1<<28)) )
;
p = map_base + lm32_base;
for (i = 0; i < (stbuf.st_size + 3) / 4; i++) {
p[i] = htonl(ibuf[i]); /* big endian */
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);
}
sync();
for (i = 0; i < (stbuf.st_size + 3) / 4; i++) {
if (p[i] != htonl(ibuf[i]))
fprintf(stderr, "programming error at %x "
"(expected %08x, found %08x)\n", i*4,
htonl(ibuf[i]), p[i]);
if(spec_load_lm32(card, argv[optind], lm32_base) < 0)
{
fprintf(stderr, "Loader failure.\n");
exit(1);
}
sync();
*(volatile uint32_t *)(map_base + lm32_base + 0x20400) = 0x0deadbee;
if (getenv("VERBOSE"))
printf("%s: Wrote %li bytes at offset 0x%x\n", argv[0],
(long)stbuf.st_size, lm32_base);
spec_close(card);
exit (0);
}
/*
* A tool to program our soft-core (LM32) within the SPEC.
* A tool to program the FPGA within the SPEC.
*
* Alessandro Rubini 2012 for CERN, GPLv2 or later.
*/
......@@ -7,28 +7,14 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "spec-tools.h"
#include "speclib.h"
int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, i, c;
struct stat stbuf;
unsigned char *buf;
void *map_base;
char *fname;
FILE *f;
int bus = -1, dev_fn = -1, c;
void *card;
while ((c = getopt (argc, argv, "b:d:")) != -1)
{
......@@ -54,50 +40,20 @@ int main(int argc, char **argv)
exit(1);
}
fname = argv[optind];
f = fopen(fname, "r");
if (!f) {
fprintf(stderr, "%s: %s: %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (fstat(fileno(f), &stbuf)) {
fprintf(stderr, "%s: stat(%s): %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (!S_ISREG(stbuf.st_mode)) {
fprintf(stderr, "%s: %s: Not a regular file\n", argv[0],
fname);
exit(1);
}
buf = malloc(stbuf.st_size);
if (!buf) {
fprintf(stderr, "%s: Can't allocate buffer (%li bytes): %s\n",
argv[0], (long)stbuf.st_size, strerror(errno));
exit(1);
}
i = fread(buf, 1, stbuf.st_size, f);
if (i < 0) {
fprintf(stderr, "%s: read(%s): %s\n", argv[0], fname,
strerror(errno));
exit(1);
}
if (i != stbuf.st_size) {
fprintf(stderr, "%s: short read from %s\n", argv[0], fname);
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);
}
map_base = spec_map_area(bus, dev_fn, BASE_BAR4, 0x1000);
if(!map_base)
if(spec_load_bitstream(card, argv[optind]) < 0)
{
fprintf(stderr, "%s: can't map the SPEC @ %02x:%02x\n", argv[0], bus, dev_fn);
exit(1);
fprintf(stderr, "Loader failure.\n");
exit(1);
}
loader_low_level(0, map_base, buf, stbuf.st_size);
spec_close(card);
exit (0);
}
#include "loader-userspace.h"
void *spec_map_area(int bus, int dev, int bar, size_t size);
enum {
BASE_BAR0 = 0, /* for wrpc etc (but lm32 is at 0x80000 offset) */
BASE_BAR2 = 2,
BASE_BAR4 = 4 /* for gennum-internal registers */
};
/* 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>
......@@ -9,28 +12,11 @@
#include <getopt.h>
#include <errno.h>
#include "spec-tools.h"
#include "wb_uart.h"
void *vuart_regs;
int vc_rx(void *ptr)
{
int csr ;
csr = *(int *)(ptr + UART_REG_HOST_RDR);
if(csr & UART_HOST_RDR_RDY)
return UART_HOST_RDR_DATA_R(csr);
else
return -1;
}
#include "speclib.h"
void vc_tx(void *ptr, int c)
{
while( *(int *)(ptr + UART_REG_SR) & UART_SR_RX_RDY);
*(int *)(ptr + UART_REG_HOST_TDR) = UART_HOST_TDR_DATA_W(c);
}
static void *card;
int transfer_byte(int from, int is_control, void *ptr) {
static int transfer_byte(int from, int is_control) {
char c;
int ret;
do {
......@@ -42,7 +28,7 @@ int transfer_byte(int from, int is_control, void *ptr) {
return -1;
}
}
vc_tx(ptr, c);
spec_vuart_tx(card, &c, 1);
} else {
fprintf(stderr, "\nnothing to read. probably port disconnected.\n");
return -2;
......@@ -71,7 +57,8 @@ void term_main(int keep_term)
}
while(!need_exit) {
fd_set fds;
int ret, rx;
int ret;
char rx;
struct timeval tv = {0, 10000};
FD_ZERO(&fds);
......@@ -82,12 +69,12 @@ void term_main(int keep_term)
perror("select");
} else if (ret > 0) {
if(FD_ISSET(STDIN_FILENO, &fds)) {
need_exit = transfer_byte(STDIN_FILENO, 1, vuart_regs);
need_exit = transfer_byte(STDIN_FILENO, 1);
}
}
while((rx = vc_rx(vuart_regs)) >= 0)
fprintf(stderr,"%c", (char)rx);
while((spec_vuart_rx(card, &rx, 1)) == 1)
fprintf(stderr,"%c", rx);
}
......@@ -99,7 +86,6 @@ int main(int argc, char **argv)
{
int bus = -1, dev_fn = -1, c;
uint32_t vuart_base = 0xe0500;
void *map_base;
int keep_term = 0;
while ((c = getopt (argc, argv, "b:d:u:k")) != -1)
......@@ -128,14 +114,16 @@ int main(int argc, char **argv)
}
}
map_base = spec_map_area(bus, dev_fn, BASE_BAR0, 0x100000);
if(!map_base)
card = spec_open(bus, dev_fn);
if(!card)
{
fprintf(stderr, "%s: can't map the SPEC @ %02x:%02x\n", argv[0], bus, dev_fn);
exit(1);
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);
}
vuart_regs = map_base + vuart_base;
spec_vuart_init(card, vuart_base);
term_main(keep_term);
spec_close(card);
return 0;
}
......@@ -8,17 +8,29 @@
#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 "spec-tools.h"
#include "speclib.h"
#include "wb_uart.h"
#define BASE_BAR0 0
#define BASE_BAR4 4
/* 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.
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 */
int spec_scan(int *bus, int *devfn)
static int spec_scan(int *bus, int *devfn)
{
struct dirent **namelist;
int n, found = 0;
......@@ -57,16 +69,13 @@ int spec_scan(int *bus, int *devfn)
/* Maps a particular BAR of given SPEC card and returns its virtual address
(or NULL in case of failure) */
void *spec_map_area(int bus, int dev, int bar, size_t size)
static void *spec_map_area(int bus, int dev, int bar, size_t size)
{
char path[1024];
int fd;
void *ptr;
if(spec_scan(&bus, &dev) < 0)
return NULL;
snprintf(path, sizeof(path), "/sys/bus/pci/drivers/spec/0000:%02x:%02x.0/resource%d", bus, dev, bar);
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)
......@@ -82,3 +91,188 @@ void *spec_map_area(int bus, int dev, int bar, size_t size)
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)
{
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_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;
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
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