Commit cba3ebb3 authored by Peter Jansweijer's avatar Peter Jansweijer

Merge remote-tracking branch 'remotes/origin/jdgarcia_pcie_gw_upgrade' into proposed_master

parents a612dd92 50a05ff6
This diff is collapsed.
This diff is collapsed.
/.Xil
/work
/*.bak
/*.jou
/*.log
/*.prm
/*.mcs
/*.bin
/*.bit
/revisiondate_log.txt
/hdl_version.xdc
board = "spec7"
target = "xilinx"
action = "synthesis"
syn_device = "xc7z035"
syn_grade = "-1"
syn_package = "fbg676"
syn_top = "spec7_tandem_boot_top"
syn_project = "spec7_tandem_boot_top.xpr"
syn_tool = "vivado"
modules = { "local" : "../../top/spec7_tandem_boot/"}
Synthesis and Place&Route README.TXT January 25, 2018
--------------------------------------------------------
Scripts:
--------
1) do_vivado.cmd start vivado (calling viv_do_all.tcl)
2) do_vivado_tcl.cmd start vivado tcl console.
You may want to type:
a) "start_gui" to start the vivado gui
b) "source proj_properties.tcl" to find the path to the scripts and next
"source $script_dir/viv_do_all.tcl"
3) do_elf.cmd combines the software and the empty "%DesName%.bit" file. Uses "software.elf", "%DesName%.bit"
and "%DesName%_bd.bmm" and merges them into "%DesName%_elf.bit"
4) do_vivado_prog.cmd download the configuration ("%DesName%_elf.bit") into the Evaluation board via the USB
download cable.
Project info and sources:
--------
proj_properties.tcl contains the project properties (name, device etc.)
proj_file_list.txt a text file with all project sources. Remember that the wr-cores files are listed
using "hdlmake list-files > proj_file_list.txt" in
directory "../../wr-cores/syn/clbv3_ref_design"
Scripts that are called by the scripts above or can be executed separately on the tcl command line:
--------
viv_do_synt.tcl sourced by viv_do_all.tcl, starts vivado synthesis run
viv_do_impl.tcl sourced by viv_do_all.tcl, starts vivado implementation run
viv_do_program.tcl sourced by do_vivado_prog.cmd
rem do_vivado.cmd PeterJ, 19-Jan-2018.
@prompt $$$s
rem ### Cleanup old log files and stuff
del *.log
del *.jou
rem ### note that environment variable "VIVADO" must be set to something like "E:\Xilinx\Vivado\2017.1\bin\"
rem ### in your (User) Environment Variables
"%VIVADO%\vivado.bat" -mode batch -source ..\..\..\sw\scripts\viv_do_all.tcl
rem prog.cmd PeterJ, 23-JUl-2018.
@prompt $$$s
rem ### Clean up old log files and stuff
del vivado_gen_bin_mcs.log
rem ### note that environment variable "VIVADO" must be set to something like "E:\Xilinx\Vivado\2017.1\bin\"
rem ### in your (User) Environment Variables
"%VIVADO%\vivado.bat" -mode batch -source ..\..\..\sw\scripts\viv_gen_bin_mcs.tcl -log vivado_gen_bin_mcs.log
rem prog.cmd PeterJ, 23-Jan-2018.
@prompt $$$s
rem ### Cleanup old log files and stuff
del vivado_prog.log
rem ### note that environment variable "VIVADO" must be set to something like "E:\Xilinx\Vivado\2017.1\bin\"
rem ### in your (User) Environment Variables
"%VIVADO%\vivado.bat" -mode batch -source ..\..\..\sw\scripts\viv_do_program.tcl -log vivado_prog.log
rem do_vivado_tcl.cmd PeterJ, 19-Jan-2018.
@prompt $$$s
rem ### Usually one wants to start Vivado in tcl mode to inspect an existing design,
rem ### therefore don't delete log files and setting. Else remove "rem" statements in the lines below.
rem set DesName=clbv3_wr_ref_top
rem set LogName=%DesName%-vivado
rem ### Cleanup old log files and stuff (
rem del vivado*.log
rem del vivado*.jou
rem ### note that environment variable "VIVADO" must be set to something like "E:\Xilinx\Vivado\2017.1\bin\"
rem ### in your (User) Environment Variables
"%VIVADO%\vivado.bat" -mode tcl
# From directory ....spec7/hdl/syn/spec7_tandem_boot
# hdlmake list-files > proj_file_list.txt
../../top/spec7_tandem_boot/spec7_tandem_boot_top.vhd
../../top/spec7_tandem_boot/spec7_tandem_boot_top.xdc
# bmm not supported by hdlmake? Need to add it manually...
../../ip/ps_pci_tandem.bd
# include hardware version ID un FPGA USER_ID register:
hdl_version.xdc
#
# projetc_properties.tcl
# This file contains the general project properties such as the project name and
# the directory where Vivado is doing it's job
#
# ====================================================
# ====================================================
# SELECT DESIGN TO BUILD:
# ====================================================
set spec7_design spec7_tandem_boot_top
# ====================================================
# ====================================================
# SELECT DEVICE TO BUILD:
# ====================================================
# SPEC7 equipped with ZYNQ XC7Z035FBG676-1 (speed grade -1 has lowest performance)
set device xc7z035fbg676-1
#set device xc7z030fbg676-1
# ====================================================
set proj_name spec7_tandem_boot_top
set proj_dir work
set script_dir [pwd]/../../../sw/scripts
# update revision except when argument "no_update_revison" is passed (as for example by viv_do_programm.tcl)
if {$argc == 0 || $argv != "no_update_revision"} {
source $script_dir/revisiondate.tcl
set generics "g_design=$spec7_design"
}
files = [
"spec7_tandem_boot_top.vhd",
"spec7_tandem_boot_top.xdc",
]
-------------------------------------------------------------------------------
-- Title : Tandem Boot for SPEC7
-- : based on ZYNQ Z030/Z035/Z045
-- Project : WR PTP Core and EMPIR 17IND14 WRITE
-- URL : http://www.ohwr.org/projects/wr-cores/wiki/Wrpc_core
-- : http://empir.npl.co.uk/write/
-------------------------------------------------------------------------------
-- File : spec7_tandem_boot_top.vhd
-- Author(s) : Peter Jansweijer <peterj@nikhef.nl>
-- : Mamta Ramendra Shukla <mamta.ramendra.shukla@cern.ch>
-- : Javier D. Garcia <jgarcia@gl-research.com>
-- Company : Nikhef, CERN
-- Created : 2021-06-27
-- Last update: 2021-06-27
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Top-level file for Tandem Boot for SPEC7.
-- See also EMPIR 17IND14 WRITE Project (http://empir.npl.co.uk/write/)
--
-- This Tandem Boot design is a bare minimal PCIe core that enables early
-- PCIe enumeration for the SPEC7 by providing a Tandem PROM mode boot design
-- that reserves the appropriated BAR sizes for SPEC7 designs based on the
-- non Tandem capable Xilinx XDMA core that are loaded afterwards.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2021 Nikhef, CERN
-------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source 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 Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity spec7_tandem_boot_top is
port (
DDR_addr : inout STD_LOGIC_VECTOR ( 14 downto 0 );
DDR_ba : inout STD_LOGIC_VECTOR ( 2 downto 0 );
DDR_cas_n : inout STD_LOGIC;
DDR_ck_n : inout STD_LOGIC;
DDR_ck_p : inout STD_LOGIC;
DDR_cke : inout STD_LOGIC;
DDR_cs_n : inout STD_LOGIC;
DDR_dm : inout STD_LOGIC_VECTOR ( 3 downto 0 );
DDR_dq : inout STD_LOGIC_VECTOR ( 31 downto 0 );
DDR_dqs_n : inout STD_LOGIC_VECTOR ( 3 downto 0 );
DDR_dqs_p : inout STD_LOGIC_VECTOR ( 3 downto 0 );
DDR_odt : inout STD_LOGIC;
DDR_ras_n : inout STD_LOGIC;
DDR_reset_n : inout STD_LOGIC;
DDR_we_n : inout STD_LOGIC;
FIXED_IO_ddr_vrn : inout STD_LOGIC;
FIXED_IO_ddr_vrp : inout STD_LOGIC;
FIXED_IO_mio : inout STD_LOGIC_VECTOR ( 53 downto 0 );
FIXED_IO_ps_clk : inout STD_LOGIC;
FIXED_IO_ps_porb : inout STD_LOGIC;
FIXED_IO_ps_srstb : inout STD_LOGIC;
pci_clk_n : in STD_LOGIC_VECTOR ( 0 to 0 );
pci_clk_p : in STD_LOGIC_VECTOR ( 0 to 0 );
perst_n : in STD_LOGIC;
rxn : in STD_LOGIC_VECTOR ( 1 downto 0 );
rxp : in STD_LOGIC_VECTOR ( 1 downto 0 );
txn : out STD_LOGIC_VECTOR ( 1 downto 0 );
txp : out STD_LOGIC_VECTOR ( 1 downto 0 )
);
end spec7_tandem_boot_top;
architecture STRUCTURE of spec7_tandem_boot_top is
component ps_pci_tandem_wrapper is
port (
pci_clk_n : in STD_LOGIC_VECTOR ( 0 to 0 );
pci_clk_p : in STD_LOGIC_VECTOR ( 0 to 0 );
perst_n : in STD_LOGIC;
rxn : in STD_LOGIC_VECTOR ( 1 downto 0 );
rxp : in STD_LOGIC_VECTOR ( 1 downto 0 );
txn : out STD_LOGIC_VECTOR ( 1 downto 0 );
txp : out STD_LOGIC_VECTOR ( 1 downto 0 );
DDR_cas_n : inout STD_LOGIC;
DDR_cke : inout STD_LOGIC;
DDR_ck_n : inout STD_LOGIC;
DDR_ck_p : inout STD_LOGIC;
DDR_cs_n : inout STD_LOGIC;
DDR_reset_n : inout STD_LOGIC;
DDR_odt : inout STD_LOGIC;
DDR_ras_n : inout STD_LOGIC;
DDR_we_n : inout STD_LOGIC;
DDR_ba : inout STD_LOGIC_VECTOR ( 2 downto 0 );
DDR_addr : inout STD_LOGIC_VECTOR ( 14 downto 0 );
DDR_dm : inout STD_LOGIC_VECTOR ( 3 downto 0 );
DDR_dq : inout STD_LOGIC_VECTOR ( 31 downto 0 );
DDR_dqs_n : inout STD_LOGIC_VECTOR ( 3 downto 0 );
DDR_dqs_p : inout STD_LOGIC_VECTOR ( 3 downto 0 );
FIXED_IO_mio : inout STD_LOGIC_VECTOR ( 53 downto 0 );
FIXED_IO_ddr_vrn : inout STD_LOGIC;
FIXED_IO_ddr_vrp : inout STD_LOGIC;
FIXED_IO_ps_srstb : inout STD_LOGIC;
FIXED_IO_ps_clk : inout STD_LOGIC;
FIXED_IO_ps_porb : inout STD_LOGIC
);
end component ps_pci_tandem_wrapper;
begin
ps_pci_tandem_wrapper_i: component ps_pci_tandem_wrapper
port map (
DDR_addr(14 downto 0) => DDR_addr(14 downto 0),
DDR_ba(2 downto 0) => DDR_ba(2 downto 0),
DDR_cas_n => DDR_cas_n,
DDR_ck_n => DDR_ck_n,
DDR_ck_p => DDR_ck_p,
DDR_cke => DDR_cke,
DDR_cs_n => DDR_cs_n,
DDR_dm(3 downto 0) => DDR_dm(3 downto 0),
DDR_dq(31 downto 0) => DDR_dq(31 downto 0),
DDR_dqs_n(3 downto 0) => DDR_dqs_n(3 downto 0),
DDR_dqs_p(3 downto 0) => DDR_dqs_p(3 downto 0),
DDR_odt => DDR_odt,
DDR_ras_n => DDR_ras_n,
DDR_reset_n => DDR_reset_n,
DDR_we_n => DDR_we_n,
FIXED_IO_ddr_vrn => FIXED_IO_ddr_vrn,
FIXED_IO_ddr_vrp => FIXED_IO_ddr_vrp,
FIXED_IO_mio(53 downto 0) => FIXED_IO_mio(53 downto 0),
FIXED_IO_ps_clk => FIXED_IO_ps_clk,
FIXED_IO_ps_porb => FIXED_IO_ps_porb,
FIXED_IO_ps_srstb => FIXED_IO_ps_srstb,
pci_clk_n(0) => pci_clk_n(0),
pci_clk_p(0) => pci_clk_p(0),
perst_n => perst_n,
rxn(1 downto 0) => rxn(1 downto 0),
rxp(1 downto 0) => rxp(1 downto 0),
txn(1 downto 0) => txn(1 downto 0),
txp(1 downto 0) => txp(1 downto 0)
);
end STRUCTURE;
# ---------------------------------------------------------------------------`
# -- Clocks/resets
# ---------------------------------------------------------------------------
# Set BMM_INFO_DESIGN property to avoid ERROR during "Write Bitstream"
#set_property BMM_INFO_DESIGN spec7_wr_ref_top.bmm [current_design]
# ---------------------------------------------------------------------------
# -- PCIe
# ---------------------------------------------------------------------------
# Bank 112 (GTX2)
set_property PACKAGE_PIN AB3 [get_ports {rxn[0]}]
set_property PACKAGE_PIN AB4 [get_ports {rxp[0]}]
set_property PACKAGE_PIN AA1 [get_ports {txn[0]}]
set_property PACKAGE_PIN AA2 [get_ports {txp[0]}]
set_property PACKAGE_PIN Y3 [get_ports {rxn[1]}]
set_property PACKAGE_PIN Y4 [get_ports {rxp[1]}]
set_property PACKAGE_PIN W1 [get_ports {txn[1]}]
set_property PACKAGE_PIN W2 [get_ports {txp[1]}]
set_property PACKAGE_PIN R6 [get_ports pci_clk_p]
set_property PACKAGE_PIN R5 [get_ports pci_clk_n]
create_clock -period 10.000 -name pci_clk_p [get_ports pci_clk_p]
set_property PACKAGE_PIN D13 [get_ports perst_n]
set_property IOSTANDARD LVCMOS18 [get_ports perst_n]
libspec.a
libspec.so
spec-cl
specmem
spec-fwloader
spec-vuart
# 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:
/*
* 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