Commit 065de6b7 authored by Benoit Rat's avatar Benoit Rat

all: big restructuration for v2.0 (part 1 ...)

* The structure is almost define
* The first unit-tests have been added
* The compatibility with asynWBPortDrvr has been broken.
parent 21bb5eeb
########################################################################
## Makefile to compile C++ object from a folder
##
## References:
##
## Authors:
## - Benoit Rat (Seven Solutions, www.sevensols.com)
##
## GNU Lesser General Public License Usage
## This file may be used under the terms of the GNU Lesser
## General Public License version 2.1 as published by the Free Software
## Foundation and appearing in the file LICENSE.LGPL included in the
## packaging of this file. Please review the following information to
## ensure the GNU Lesser General Public License version 2.1 requirements
## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
########################################################################
## Cross Compile
CC = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
## Config
-include $(CURDIR)/.config
## Obtain the version ($ is replaced by $$)
VERSION = $(shell git describe --always --dirty=+ | sed 's;^.*-\([v0-9\.]*\)\([a-z0-9\-+]*\)$$;\1\2;' )
DATE = $(shell date +"%d %b. %Y")
## Flags
INCLUDE_DIR=-Iewbcore/ -Iewbdrige/ -Iasynwb
CXXFLAGS=-Wall -g -O3 -DTRACE_STDERR -std=c++11
## File processing
ODIR=output/
SRC_MAIN=$(wildcard ewbcore/*.cpp)
OBJ_MAIN=$(addprefix $(ODIR), $(SRC_MAIN:.cpp=.o))
all: main
ODIR_%: $(ODIR)$(subst ODIR_,,$@)
mkdir -p $(ODIR)$(subst ODIR_,,$@)
@echo ""
@echo ":==================================================================================================================>"
@echo ""
main: ODIR_ewbcore $(ODIR)libewbmain.a
@echo "----> libewbmain.a OK"
output/libewbmain.a: $(OBJ_MAIN)
$(AR) rc $@ $^ $(LDFLAGS)
bridge:
asynwb:
output/%.o: %.cpp
${CC} $(CXXFLAGS) $(INCLUDE_DIR) $(LIB_DIR) -c $*.cpp -o $@
clean_%:
rm -Rvf $(ODIR)$(subst clean_,,$@)
clean: clean_ewbcore
This diff is collapsed.
This diff is collapsed.
/*
* EWBBridge.cpp
*
* Created on: Jun 15, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBBridge.h"
/*
* EWBBridge.h
*
* Created on: Jun 15, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBBRIDGE_H_
#define EWBBRIDGE_H_
#include <stdlib.h>
#include <stdint.h>
#include <string>
/**
* Polymorphic & abstract class memory bridge to a EWB device.
*
* The inherited class:
* - must overload single access to the memory
* - might overload DMA access to the memory
*
* The child class will be defined for each type of physical driver used to access to our EWB board.
*/
class EWBBridge {
public:
//! The type of the overridden class
enum Type {
TFILE=0, //!< Connector to a test file
X1052, //!< Connector to the X1052 driver
RAWRABBIT, //!< Connector to the RawRabbit driver
ETHERBONE //!< Connector to the Etherbone driver
};
//! Constructor where we only give the type
EWBBridge(int type,const std::string &name =""): type(type),name(name),block_busy(false) {};
//! Empty destructor
virtual ~EWBBridge() {};
//! Return true if the handler of the overridden class if true, otherwise false.
virtual bool isValid() { return false; }
//! Generic single access to the wishbone memory of the device
virtual bool mem_access(uint32_t addr, uint32_t *data, bool to_dev)=0;
//! Retrieve the internal read/write buffer and its size
virtual uint32_t get_block_buffer(uint32_t **hBuff, bool to_dev) { return 0; };
//! Generic block access to the wishbone memory of the device
virtual bool mem_block_access(uint32_t dev_addr, uint32_t nsize, bool to_dev) { return false; };
//! Return which type of EWBBrdige overridden class we are using (force casting)
int getType() { return type; }
//! Return true if the block access is busy.
bool isBlockBusy() { return block_busy; }
virtual const std::string& getName() const { return name; }
virtual const std::string& getVer() const { return ver; }
virtual const std::string& getDesc() const { return desc; }
protected:
int type; //!< type of the overridden class.
std::string name;
std::string desc;
std::string ver;
bool block_busy;
};
#endif /* EWBBRIDGE_H_ */
/*
* EWBCmdConsole.cpp
*
* Created on: Aug 10, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBCmdConsole.h"
EWBCmdConsole::EWBCmdConsole() {
// TODO Auto-generated constructor stub
}
EWBCmdConsole::~EWBCmdConsole() {
// TODO Auto-generated destructor stub
}
/*
* EWBCmdConsole.h
*
* Created on: Aug 10, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBCMDCONSOLE_H_
#define EWBCMDCONSOLE_H_
#include <EWBSync.h>
class EWBCmdConsole {
public:
enum Type { UNKNOWN=-1, SERIAL, MEMVUART, ETHVUART };
EWBCmdConsole(Type t): _type(t) {};
virtual ~EWBCmdConsole() {};
virtual void writeCmd(std::string cmd, std::string value)=0;
virtual std::string getCmd(std::string cmd)=0;
virtual const std::string& getInfo() const =0;
virtual bool isValid() const =0;
Type getType() const { return _type; }
protected:
Type _type;
};
class SerialPort;
class EWBSerialConsole: public EWBCmdConsole {
EWBSerialConsole(SerialPort tty);
bool sync(EWBSync::AMode mode);
};
/**
* Class that wrap the EWBCmdConsole class to improve parsing of WR consoles
*/
class EWBWRConsole: public EWBCmdConsole {
EWBWRConsole(EWBCmdConsole *term, int rgui_ms);
virtual ~EWBWRConsole();
void writeCmd(std::string cmd, std::string value) { term->writeCmd(cmd,value); }
std::string getCmd(std::string cmd);
const std::string& getInfo() const { return term->getInfo(); }
Type getType() const { return term->getType(); }
private:
EWBCmdConsole *term; //!< This is the real terminal
};
#endif /* EWBCMDCONSOLE_H_ */
/*
* WBMemTestFileCon.cpp
* EWBMemTestFileCon.cpp
*
* Created on: Oct 31, 2013
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "WBMemTestFileCon.h"
#include "EWBMemTestFileCon.h"
#include <cstring>
#include "awbpd_trace.h"
......@@ -18,14 +18,14 @@
/**
* Constructor of the WBMemTestFileCon
* Constructor of the EWBMemTestFileCon
*
* This function will allocate one internal buffer of
* BUFF_MAX_SIZEB for both read and write.
* It will also try to open the file.
*/
WBMemTestFileCon::WBMemTestFileCon(const std::string& fname)
: WBMemCon(WBMemCon::TFILE), fname(fname), lastpos(0)
: EWBMemCon(EWBMemCon::TFILE), fname(fname), lastpos(0)
{
o_file.open(fname.c_str(),std::fstream::out|std::fstream::in);
TRACE_P_INFO("tfile=%d (%s)",o_file.is_open(),fname.c_str());
......@@ -50,7 +50,7 @@ WBMemTestFileCon::~WBMemTestFileCon()
/**
* Function that fill the file with the all the registers in the wishbone structure.
*/
void WBMemTestFileCon::generate(WBNode* node)
void EWBMemTestFileCon::generate(WBNode* node)
{
WBReg *reg=NULL;
uint32_t data;
......@@ -86,7 +86,7 @@ void WBMemTestFileCon::generate(WBNode* node)
* \param[inout] data the read "read from/write to" the file.
* \param[in] to_dev if true we write to the file (aka device).
*/
bool WBMemTestFileCon::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
bool EWBMemTestFileCon::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
{
uint32_t rdata=0xDA1AFEED;
char buff[50];
......@@ -130,7 +130,7 @@ bool WBMemTestFileCon::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
return true;
}
uint32_t WBMemTestFileCon::get_block_buffer(uint32_t** hDma, bool to_dev)
uint32_t EWBMemTestFileCon::get_block_buffer(uint32_t** hDma, bool to_dev)
{
*hDma=pData;
return BUFF_MAX_SIZEB;
......@@ -153,7 +153,7 @@ uint32_t WBMemTestFileCon::get_block_buffer(uint32_t** hDma, bool to_dev)
* \param[in] nsize The size in byte that we want to read/write.
* \param[in] to_dev if true we write to the device.
*/
bool WBMemTestFileCon::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool to_dev)
bool EWBMemTestFileCon::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool to_dev)
{
char buff[50], *p;
std::string line;
......@@ -206,7 +206,7 @@ bool WBMemTestFileCon::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool t
* \param[in] rewind if true we start the search from the beginning, otherwise from the current position.
* \return the position of the line that contains the address or -1 if it was not found.
*/
long WBMemTestFileCon::seek(std::fstream& tfile, uint32_t wb_addr, bool rewind)
long EWBMemTestFileCon::seek(std::fstream& tfile, uint32_t wb_addr, bool rewind)
{
std::string line;
......
/**
* \file
* \brief Contains the class WBMemTestFileCon.
* \brief Contains the class EWBMemTestFileCon.
*
*
* \date Nov 4, 2013
* \author Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef WBMEMTFILECON_H_
#define WBMEMTFILECON_H_
#ifndef EWBMEMTFILECON_H_
#define EWBMEMTFILECON_H_
#include "WBNode.h"
#include EWBNode.h"
#include <iostream>
#include <fstream>
#include <string>
/**
* Fake WB memory connector by testing on a file
* Fake EWB memory connector by testing on a file
*
* The operation will read and write in the test file.
*
......@@ -33,10 +33,10 @@
* \endcode
*
*/
class WBMemTestFileCon: public WBMemCon {
class EWBMemTestFileCon: public EWBMemCon {
public:
WBMemTestFileCon(const std::string& fname);
virtual ~WBMemTestFileCon();
virtual EWBMemTestFileCon();
void generate(WBNode* node);
......@@ -53,4 +53,4 @@ private:
uint32_t *pData;
};
#endif /* WBMEMTFILECON_H_ */
#endif /* EWBMEMTFILECON_H_ */
/*
* WBMemX1052Con.cpp
* EWBMemX1052Con.cpp
*
* Created on: Oct 31, 2013
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "awbpd_trace.h"
#ifndef AWBPD_NO_X1052
#ifndef EWBPD_NO_X1052
#define TRACE_H
#include <x1052_api.h>
......@@ -17,16 +17,16 @@
#define BOOL int
#endif
#include "WBMemX1052Con.h"
#include EWBMemX1052Con.h"
#define TRACE_P_VDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
#define TRACE_P_VVDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
int WBMemX1052Con::nHandles = -1; //!< Initiate static nHandles to count number of PCIe slot opened
int EWBMemX1052Con::nHandles = -1; //!< Initiate static nHandles to count number of PCIe slot opened
/**
* Constructor of the WBMemX1052Con class.
* Constructor of the EWBMemX1052Con class.
*
* The constructor init the X1052 library and open an handler
* on the corresponding device.
......@@ -35,7 +35,7 @@ int WBMemX1052Con::nHandles = -1; //!< Initiate static nHandles to count number
* \param[in] idxPCIe The index of PCIe slot for X1052 Devices
*/
WBMemX1052Con::WBMemX1052Con(int idxPCIe,uint32_t magic_addr, uint32_t magic_val)
: WBMemCon(WBMemCon::X1052,"X1052"), hBiDma(NULL), hDev(NULL)
: EWBMemCon(WBMemCon::X1052,"X1052"), hBiDma(NULL), hDev(NULL)
{
uint32_t dwStatus, tmp;
if(nHandles<0)
......@@ -98,7 +98,7 @@ WBMemX1052Con::WBMemX1052Con(int idxPCIe,uint32_t magic_addr, uint32_t magic_val
}
/**
* Desctructor of the WBMemX1052 class
* Desctructor of the EWBMemX1052 class
*
* It will close the handler on the PCIe device.
*/
......@@ -126,7 +126,7 @@ WBMemX1052Con::~WBMemX1052Con()
/**
* Return true if the handler on the PCIe is valid
*/
bool WBMemX1052Con::isValid()
bool EWBMemX1052Con::isValid()
{
return hDev!=NULL;
}
......@@ -139,7 +139,7 @@ bool WBMemX1052Con::isValid()
* \param[in] to_dev if true we write to the device.
* \see X1052_Wishbone_CSR() function
*/
bool WBMemX1052Con::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
bool EWBMemX1052Con::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
{
int status;
TRACE_CHECK_PTR(hDev,false);
......@@ -163,7 +163,7 @@ bool WBMemX1052Con::mem_access(uint32_t wb_addr, uint32_t* data, bool to_dev)
* \param[in] to_dev if true we write to the device.
* \see X1052_DMAToDev() and X1052_DMAFromDev() function.
*/
bool WBMemX1052Con::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool to_dev)
bool EWBMemX1052Con::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool to_dev)
{
int mbps;
TRACE_CHECK_PTR(hDev,false);
......@@ -199,7 +199,7 @@ bool WBMemX1052Con::mem_block_access(uint32_t dev_addr, uint32_t nsize,bool to_d
* otherwise we return the read to dev buffer.
* \return The size in byte of the retrieved buffer
*/
uint32_t WBMemX1052Con::get_block_buffer(uint32_t** hDma, bool to_dev)
uint32_t EWBMemX1052Con::get_block_buffer(uint32_t** hDma, bool to_dev)
{
(*hDma)=(uint32_t*)X1052_BiDMAGetUserSpaceBuffer(hBiDma,(int)to_dev);
return X1052_DMA_TRANSFER_MAXB;
......
/**
* \file
* \brief Contains the class WBMemX1052Con.
* \brief Contains the class EWBMemX1052Con.
*
*
*
......@@ -13,10 +13,10 @@
* \author Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef WBMEMX1052CON_H_
#define WBMEMX1052CON_H_
#ifndef EWBMEMX1052CON_H_
#define EWBMEMX1052CON_H_
#include "WBNode.h"
#include "EWBBridge.h"
#ifndef _WDC_LIB_H_
typedef void * WDC_DEVICE_HANDLE; //!< Hack to not include all the X1052 api in this header
......@@ -26,19 +26,19 @@ typedef void * X1052_BIDMA_HANDLE; //!< Hack to not include all the X1052 api in
#endif
/**
* WB memory connector using X1052 driver
* EWB memory connector using X1052 driver
*
* \warning
* The x1052_api and Jungo Windriver libraries must be linked
* during the compilation if we want to compile this class.\n
* You might also define the \b AWBPD_NO_X1052 preprocessor variable
* You might also define the \b EWBPD_NO_X1052 preprocessor variable
* if you want to disable the compilation of the cpp file.
*
*/
class WBMemX1052Con: public WBMemCon {
class EWBMemX1052Con: public EWBBridge {
public:
WBMemX1052Con(int idPCIe,uint32_t magic_addr=0xFFFFFFFF, uint32_t magic_val=-1);
virtual ~WBMemX1052Con();
EWBMemX1052Con(int idPCIe,uint32_t magic_addr=0xFFFFFFFF, uint32_t magic_val=-1);
virtual EWBMemX1052Con();
bool isValid();
......@@ -53,4 +53,4 @@ private:
static int nHandles;
};
#endif /* WBMEMX1052CON_H_ */
#endif /* EWBMEMX1052CON_H_ */
/*
* EWBBus.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBBUS_H_
#define EWBBUS_H_
#include "../ewbbridge/EWBBridge.h"
#include <cstdint>
#include <cstddef>
class EWBBridge;
/**
* Simple class that help us connecting different peripheral to a bus or a sub bus.
*/
class EWBBus {
public:
EWBBus(EWBBridge *b, uint32_t base_offset): b(b), base_offset(base_offset) {};
virtual ~EWBBus();
const EWBBridge* getBridge() const { return b; }
EWBBridge* getBridge() { return b; }
uint32_t getOffset() const { return base_offset; }
bool isValid(bool connected=true) const { return (connected? (b && b->isValid()) : (b!=NULL) ); }
protected:
EWBBridge *b;
uint32_t base_offset;
};
#endif /* EWBBUS_H_ */
/*
* EWBField.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBField.h"
#include "EWBReg.h"
#include "EWBPeriph.h"
#include "EWBTrace.h"
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <cstdarg>
#include <ctype.h>
#define TRACE_P_VDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
#define TRACE_P_VVDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
/**
* Default constructor of the EWBField
*
* If pReg is valid it will automatically append this EWBField to a EWBReg only if
* the bit mask of EWBField is not already used in EWBReg.
*
* \param[in] pReg Belonging EWBReg
* \param[in] name Name of the field
* \param[in] mask Bit mask of the field on the register
* \param[in] shift how many bit we need to shift
* \param[in] mode The access mode to the register given by \ref EWBSync::AMode
* \param[in] desc Optional description
* \param[in] signess Which type of signess we want to use EWBField::TMask
* \param[in] nfb Number of fractional bit.
* \param[in] iniVal Value to setup field at creation,
* if set to "inf" we keep 0 as default value. Does nothing when pReg is NULL.
*/
EWBField::EWBField(EWBReg *pReg,
const std::string &name, uint32_t mask,
uint8_t shift, uint8_t mode, const std::string &desc,
uint8_t signess, uint8_t nfb, double iniVal):
EWBParam(name,0,mode,desc)
{
this->pReg=pReg;
this->mask=mask;
this->shift=shift;
this->type=(signess & EWBF_TM_SIGNESS);
if(nfb>0) this->type|=EWBF_TM_FIXED_POINT;
this->nfb=nfb;
this->forceSync=false;
this->checkOverflow=true;
TRACE_P_DEBUG("%s type=0x%0x nfb=%d, dVal=%f",name.c_str(),type,nfb,iniVal);
int i = 1;
for (; mask; mask >>= 1, i++)
this->width=i-shift;
if(pReg)
{
if(isinf(iniVal)) pReg->addField(this);
else
{
float dVal32=(float)iniVal;
this->convert(&dVal32,false);
pReg->addField(this,true);
}
}
}
/**
* Empty destructor
*/
EWBField::~EWBField()
{
}
/**
* Generic function to convert an integer value to/from a reg_data
*
* Simple transformation using the bit mask and the shift to transform the value.
*
* \warning In this transformation the sign is not taken in account.
* \note This is a constant function so we do not modify any internal data of EWBField and we don't need a valid linked EWBReg.
* \param[inout] value pointer to an integer value
* \param[inout] reg_data pointer to a register data
* \param[in] to_value if true, value will be out and reg_data in, when false this is swapped.
* \return true if the operation success, false otherwise.
*/
bool EWBField::regCvt(uint32_t *value, uint32_t *reg_data, bool to_value) const
{
if(to_value)
{
*value=(*reg_data&mask) >> shift;
}
else
{
*reg_data=((*value << shift) & mask) | (*reg_data & ~mask);
}
return true;
}
/**
* Generic function to convert a float value to/from a reg_data
*
* The floating point value can be converted in different way according to the \ref getType()
* - EWBField::EWBF_32U truncate to u32 and use the integer \ref regCvt() function
* - EWBField::EWBF_32FP convert using signed fixed point conversion
* - EWBField::EWBF_32F2C convert using 2 complements fixed point conversion so that
* we only use 1bit for zero. If \ref isOverflowPrevented() we limit the value to out bit width.\n
* More info: http://en.wikipedia.org/wiki/Two%27s_complement
*
*
*
* \note This is a constant function so we do not modify any internal data of EWBField and we don't need a valid linked EWBReg.
* \param[inout] value pointer to an integer value
* \param[inout] reg_data pointer to a register data
* \param[in] to_value if true, value will be out and reg_data in, when false this is swapped.
* \return true if the operation success, false otherwise.
*/
bool EWBField::regCvt(float *value, uint32_t *reg_data, bool to_value) const
{
bool ret=false;
uint32_t fixed, utmp;
float ftmp;
switch(type)
{
case EWBF_32U:
if(to_value)
{
ret=this->regCvt(&fixed,reg_data,to_value);
*value=(float)fixed;
}
else
{
fixed=(uint32_t)round(*value);
ret=this->regCvt(&fixed,reg_data,to_value);
}
break;
case EWBF_TM_FIXED_POINT: //Unsigned Fixed point conversion
case EWBF_32FP: //Signed Fixed point conversion
if(to_value)
{
ret=this->regCvt(&fixed,reg_data,to_value);
*value=(float)(fixed/pow(2,this->nfb));
}
else
{
fixed=(uint32_t)(round(*value * pow(2,this->nfb)));
ret=this->regCvt(&fixed,reg_data,to_value);
}
break;
case EWBF_32F2C: //2 complements fixed point conversion
if(to_value)
{
ret=this->regCvt(&fixed,reg_data,to_value);
if (fixed & (1 << (this->width-1)))
{
fixed=((~fixed)+1) & (this->mask >> this->shift) ; //Convert negative 2C to negative Fixed Point
*value=(-1.f / (float)(1<<this->nfb)) * (float)fixed; // then to floating
}
else
*value= (1.f / (float)(1<<this->nfb)) * (float)fixed; //Convert directly Fixed Point to Floating Point
}
else
{
ftmp=fabs(*value);
if(checkOverflow)
{
utmp=1 << ((this->width-this->nfb)-1);
if(ftmp >= utmp) ftmp=(float)utmp;
}
fixed=round(ftmp * (float)(1 << this->nfb)); //convert to signed fixed point using absolute value
if(*value<0) fixed=(~(fixed))+1; //convert absolute signed fixed point to 2C fixed point when value <0
ret=this->regCvt(&fixed,reg_data,to_value);
}
break;
default:
TRACE_P_WARNING("%s: Type %d not defined",getCName(),getType());
return false;
}
return ret;
}
/**
* Shortcut function for converting from/to float value
*
* This function will use the corresponding bit stored in the associate EWBReg
* and will convert them to/from the given pVal. A valid EWBReg must be linked to
* this object.
*
* \see Call \ref regCvt() method using EWBReg::data as reg_data.
* \param[inout] pVal pointer to a value
* \param[in] to_value if true, value will be out. Otherwise it will be in.
* \return true if the operation success, false otherwise.
*/
bool EWBField::convert(uint32_t *pVal, bool to_value)
{
return (pReg)?regCvt(pVal,&(pReg->data),to_value):false;
}
/**
* Shortcut function for converting from/to float value
*
* This function will use the corresponding bit stored in the associate EWBReg
* and will convert them to/from the given pVal.
*
* \see Call \ref regCvt() method using EWBReg::data as reg_data.
* \param[inout] pVal pointer to a value
* \param[in] to_value if true, value will be out. Otherwise it will be in.
* \return true if the operation success, false otherwise.
*/
bool EWBField::convert(float *pVal, bool to_value)
{
return (pReg)?regCvt(pVal,&(pReg->data),to_value):false;
}
/**
* Shortcut to setup the register to be sync with the device ASAP.
*
* \note Once the corresponding register flag toSync is true it is not possible to reset
* it unless calling to EWBReg::sync() method. Calling to EWBField::sync() will not reset this
* flag.
*
* \return true if everything okay. otherwirse false if pointer on register is unvalid.
*/
bool EWBField::setToSync()
{
TRACE_CHECK_PTR(pReg,false);
pReg->toSync=true;
return true;
}
/**
* Shortcut function to return a float from the data in the field
*/
float EWBField::getFloat() const
{
float val=0;
if(pReg) regCvt(&val,&(pReg->data),true);
return val;
}
/**
* Shortcut function to return a uint32_t from the data in the field
*/
uint32_t EWBField::getU32() const
{
uint32_t val=0;
if(pReg) regCvt(&val,&(pReg->data),true);
return val;
}
/**
* Synchronize only the EWBField bits with memory
*
* This function has a mechanism that only write and read
* on the desired EWBField.
* - Writing: we first need to read the actual value on the device, so that we can keep
* the non-corresponding to the value on the device.
* - Reading: Only update the corresponding bit.
*
* \note in R/W mode we first perform write so that we can check back the value we have wrote.
*
* \param[in] con A pointer to a valid Memory Connector object.
* \param[in] amode Access mode (R, W, R/W)
* \return true if everything is okay, false otherwise
*/
bool EWBField::sync(EWBSync::AMode amode)
{
bool ret=true;
uint32_t oldval, value;
//Perform some check
if(!isValid(true)) return false;
EWBBridge *b=pReg->getPeriph()->getBridge();
//first write to dev
if(amode & EWB_AM_W)
{
//Get current value
ret &=b->mem_access(pReg->getOffset(true),&oldval,false); //Read EWB from dev
value=(pReg->data & mask) | (oldval & ~mask); //Update only our field
TRACE_P_DEBUG("%-10s (@0x%08X) ret=%d old=0x%x new=0x%x",getCName(),pReg->getOffset(true),ret,oldval,value);
if(oldval != value || forceSync)
{
ret &=b->mem_access(pReg->getOffset(true),&value,true); //Write EWB to dev
TRACE_P_DEBUG("%-10s (@0x%08X) ret=%d value=0x%0x",getCName(),pReg->getOffset(true),ret,value);
}
}
//then read from dev
if(amode & EWB_AM_R)
{
ret &=b->mem_access(pReg->getOffset(true),&value,false); //Read EWB from dev
pReg->data = (pReg->data & ~mask) | (value & mask); //update only our field
}
return ret;
}
/**
* operator that print the data of the EWBField in a stream
*/
std::ostream & operator<<(std::ostream & o, const EWBField &f)
{
o << EWBTrace::string_format("0x%08X ",f.mask) << f.name;
o << " (" << ((f.mode & EWBSync::EWB_AM_R)?"R":"") << ((f.mode & EWBSync::EWB_AM_W)?"W":"") << ")";
if(f.type==EWBField::EWBF_32F2C)
o << " FixedPoint with 2comp (nfb=" << std::dec << (int)f.nfb << ")";
return o;
}
/*
* EWBField.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBFIELD_H_
#define EWBFIELD_H_
#include "EWBParam.h"
#include "EWBReg.h"
//! Generate field preprocessor variable name for wbgen2 header
#define WB2_TOKENPASTING_FIELD(periphname,regname,fieldname,type) \
WB2_##periphname##_##regname##_##fieldname##type
//! Generate register preprocessor variable name for wbgen2 header
#define WB2_TOKENPASTING_REG(periphname,regname,type) \
WB2_##periphname##_REG_##regname##type
//! Shortcut for WBReg constructor arguments
#define WB2_REG_ARGS(pname,rname) \
WB2_TOKENPASTING_REG(pname,rname,_PREFIX),\
WB2_TOKENPASTING_REG(pname,rname,)
//! Shortcut for WBField constructor arguments
#define WB2_FIELD_ARGS(pname,rname,fname) \
WB2_TOKENPASTING_FIELD(pname,rname,fname,_PREFIX),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_MASK),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_SHIFT),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_ACCESS),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_DESC), \
WB2_TOKENPASTING_FIELD(pname,rname,fname,_SIGN),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_NBFP)
//! Shortcut for WBField constructor arguments
#define WB2_FIELD_ARGS_VA(pname,rname,fname,...) \
WB2_TOKENPASTING_FIELD(pname,rname,fname,_PREFIX),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_MASK),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_SHIFT),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_ACCESS),\
WB2_TOKENPASTING_FIELD(pname,rname,fname,_DESC),\
__VA_ARGS__
#include <iostream>
/**
* Class that represent a Wishbone field on a EWBReg
*
* The EWBField is a part (or not) of a EWBReg.
* We use a mask to show which bits correspond to this EWBField in
* the linked EWBReg.
*
* \todo Verify the all the combination of regCvt() according to type !!!
*
* \ref EWBReg
*/
class EWBField: public EWBParam {
public:
friend std::ostream & operator<<(std::ostream & output, const EWBField &n);
EWBField(EWBReg *pReg,const std::string &name, uint32_t mask, uint8_t shift,
uint8_t mode=EWB_AM_RW, const std::string &desc="",
uint8_t signess=0, uint8_t nfb=0, double defVal=(1.0/0.0));
virtual ~EWBField();
bool regCvt(uint32_t *value, uint32_t *regdata, bool from_data) const;
bool regCvt(float *value, uint32_t *regdata, bool from_data) const;
bool convert(uint32_t *value, bool to_value);
bool convert(float *value, bool to_value);
float getFloat() const;
uint32_t getU32() const;
bool setToSync();
bool sync(EWBSync::AMode amode=EWB_AM_RW);
uint32_t getMask() const { return mask; } //!< Get the bit mask
uint8_t getNOfFractionBit() const { return nfb; } //!< Get the number of fractional bit (0 for EWBF_32U)
const EWBReg* getReg() const { return pReg; } //!< Get the linked register (RO)
EWBReg* getReg() { return pReg; } //!< Get the linked register
bool isOverflowPrevented() const { return checkOverflow; } //!< When true prevent overflow during FP conversion \ref regCvt(), \ ref convert()
bool isValid() const { return isValid(true); }
bool isValid(bool connected) const { return (pReg && pReg->isValid(connected)); }
protected:
uint32_t mask; //!< Corresponding mask
uint8_t shift; //!< Number of bit to be shift
uint8_t width; //!< Width of the field
uint8_t nfb; //!< Number of fraction bits
bool checkOverflow; //!< Limit overflow during FP conversion
private:
EWBReg *pReg; //! parent register which belong this field
};
#endif /* EWBFIELD_H_ */
/*
* EWBParam.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBParam.h"
/*
* EWBParam.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBPARAM_H_
#define EWBPARAM_H_
#include "EWBSync.h"
#include <string>
/**
* Generic class that represent a parameter that need to
* synchronized with the upper layer.
*
*/
class EWBParam: public EWBSync {
public:
EWBParam(std::string name, uint8_t type, uint8_t mode, std::string desc=""): EWBSync(mode), name(name), type(type), desc(desc) {};
virtual ~EWBParam() {};
//! Type Mask (Used by EWBField)
enum TMask {
EWBF_TM_SIGN_MSB = 0x1,
EWBF_TM_SIGN_2COMP = 0x2,
EWBF_TM_SIGNESS = 0x3,
EWBF_TM_FIXED_POINT = 0x4,
};
//! Type of EWBField available
enum Type {
//! Automatic Type
EWBF_AUTO=0xFF,
//! Unsigned integer field
EWBF_32U=0,
//! Signed integer field
EWBF_32I=1,
//! Fixed point field with highest bit signed
EWBF_32FP = (EWBF_TM_FIXED_POINT | EWBF_TM_SIGN_MSB),
//! Fixed point field with 2'complements signed
EWBF_32F2C =(EWBF_TM_FIXED_POINT | EWBF_TM_SIGN_2COMP),
//! String parameters
EWBF_STRING,
};
const std::string& getName() const { return name; } //!< Get the name
const char *getCName() const { return name.c_str(); } //!< Get the name in "C" format for printf function
const std::string& getDesc() const { return desc; } //!< Get the description
uint8_t getType() const { return type; } //!< Get the type of field
protected:
std::string name; //!< Name of the EWBField
uint8_t type; //!< Type of data
std::string desc; //!< Description
};
/**
* Generic class that represent a string parameter that need to
* synchronized with the upper layer.
*/
class EWBParamStr: public EWBParam {
public:
EWBParamStr(std::string name, uint8_t mode, std::string value, std::string desc=""): EWBParam(name,EWBParam::EWBF_STRING,mode,desc), value(value) {};
virtual ~EWBParamStr() {};
protected:
std::string value;
};
#endif /* EWBPARAM_H_ */
/*
* EWBParamStrCmd.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBParamStrCmd.h"
#include "../ewbbridge/EWBCmdConsole.h"
#include <iostream>
#include <string>
EWBParamStrCmd::EWBParamStrCmd(EWBCmdConsole *pConsole,const std::string& name, const std::string& cmdW, const std::string& cmdR, const std::string& eStrR, const std::string& desc)
:EWBParamStr(name,EWBSync::EWB_AM_RW,"",desc), pConsole(pConsole), cmdW(cmdW), cmdR(cmdR)
{
//Update mode
if(cmdR.empty()) mode=EWBSync::EWB_AM_W;
if(cmdW.empty()) mode=EWBSync::EWB_AM_R;
// try {
// this->rgxpR=std::regex(rgxpR);
// }
// catch(std::regex_error &e)
// {
// std::cout << "ERROR: " << e.what() << "; code: " << parseCode(e.code()) << std::endl;
// }
int reti = regcomp(&rgxpR, eStrR.c_str(), REG_EXTENDED);
if (reti) {
fprintf(stderr, "ERROR: Could not compile regex\n");
}
}
/**
* Empty Destructor
*
*/
EWBParamStrCmd::~EWBParamStrCmd()
{
regfree(&rgxpR);
}
bool EWBParamStrCmd::isValid() const
{
return (pConsole && pConsole->isValid());
}
//std::string EWBParamStrCmd::parseCode(std::regex_constants::error_type etype) {
// switch (etype) {
// case std::regex_constants::error_collate:
// return "error_collate: invalid collating element request";
// case std::regex_constants::error_ctype:
// return "error_ctype: invalid character class";
// case std::regex_constants::error_escape:
// return "error_escape: invalid escape character or trailing escape";
// case std::regex_constants::error_backref:
// return "error_backref: invalid back reference";
// case std::regex_constants::error_brack:
// return "error_brack: mismatched bracket([ or ])";
// case std::regex_constants::error_paren:
// return "error_paren: mismatched parentheses(( or ))";
// case std::regex_constants::error_brace:
// return "error_brace: mismatched brace({ or })";
// case std::regex_constants::error_badbrace:
// return "error_badbrace: invalid range inside a { }";
// case std::regex_constants::error_range:
// return "erro_range: invalid character range(e.g., [z-a])";
// case std::regex_constants::error_space:
// return "error_space: insufficient memory to handle this regular expression";
// case std::regex_constants::error_badrepeat:
// return "error_badrepeat: a repetition character (*, ?, +, or {) was not preceded by a valid regular expression";
// case std::regex_constants::error_complexity:
// return "error_complexity: the requested match is too complex";
// case std::regex_constants::error_stack:
// return "error_stack: insufficient memory to evaluate a match";
// default:
// return "";
// }
//}
bool EWBParamStrCmd::sync(EWBSync::AMode m) {
if(isValid())
{
if(m & EWBSync::EWB_AM_W)
{
pConsole->writeCmd(cmdW,value);
}
if(m & EWBSync::EWB_AM_R)
{
value=pConsole->getCmd(cmdR);
if(rgxpR.re_nsub>0) //Check if we have a compile regex when reading
{
/* Execute regular expression */
regmatch_t pMatch[rgxpR.re_nsub+1];
const char *s=value.c_str();
int reti = regexec(&rgxpR,s,rgxpR.re_nsub+1, pMatch, 0);
if (!reti) {
// printf("%d matched from %d (%c) to %d (%c)\n",rgxpR.re_nsub,
// pMatch[1].rm_so, s[pMatch[1].rm_so],pMatch[1].rm_eo, s[pMatch[1].rm_eo]);
value=value.substr(pMatch[1].rm_so,pMatch[1].rm_eo-pMatch[1].rm_so);
}
else if (reti == REG_NOMATCH) {
puts("No match");
}
else {
char msgbuf[256];
regerror(reti, &rgxpR, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
}
}
// //C++11 (Need at least GCC v4.9)
// if(rgxpR.mark_count()>0)
// {
// std::smatch sm;
//
// std::regex_match(value,sm,rgxpR);
// if(sm.size()>1)
// {
// value=sm[1];
// std::cout << "YEAH="<<sm[1] << "--- ; " << value << std::endl;
// }
// }
}
return true;
}
return false;
}
/*
* EWBParamStrCmd.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBPARAMSTRCMD_H_
#define EWBPARAMSTRCMD_H_
#include "EWBParam.h"
#include <regex.h>
class EWBCmdConsole; //!< Pre-call to improve compilation
/**
* This class is used to handle parameters that can be configured through a command
* interface such as the wrc# console.
*/
class EWBParamStrCmd: public EWBParamStr {
public:
EWBParamStrCmd(EWBCmdConsole *pConsole,const std::string& name, const std::string& cmdW, const std::string& cmdR, const std::string& rgxpR="", const std::string& desc="");
virtual ~EWBParamStrCmd();
const std::string& getValue() const { return value; } //!< Get the name
bool sync(EWBSync::AMode mode);
bool isValid() const;
protected:
EWBCmdConsole *pConsole; //!< Pointer on the cmd console
std::string cmdW; //!< Consoled command corresponding to this parameter
std::string cmdR; //!< Consoled command corresponding to this parameter
regex_t rgxpR; //!< Regular to retrieve the value of this command
};
#endif /* EWBPARAMSTRCMD_H_ */
This diff is collapsed.
/*
* EWBPeriph.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBPERIPH_H_
#define EWBPERIPH_H_
#include "EWBSync.h"
#include "EWBBus.h"
#include <map>
//Forward declaration to improve compilation
class EWBBridge;
class EWBReg;
#define EWB_NODE_MEMBCK_OWNADDR 0xFFFFFFFF //!< Used by WBNode::sync()
/**
* Class that represent a WB peripheral in a tree structure.
*
* - A list EWBReg is also linked to this peripheral
*/
class EWBPeriph: public EWBSync {
public:
EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint32_t ID, const std::string &desc="");
virtual ~EWBPeriph();
void appendReg(EWBReg *pReg);
EWBReg* getReg(uint32_t offset) const;
EWBReg* getNextReg(EWBReg *prev);
EWBReg* getLastReg() const { return registers.rbegin()->second; } //!< Get the highest WBReg in the node.
bool sync(EWBSync::AMode amode=EWB_AM_RW);
// bool sync(EWBSync::AMode amode, uint32_t dma_dev_offset=WB_NODE_MEMBCK_OWNADDR);
// bool sync(uint32_t* pData32, uint32_t length, EWBSync::AMode amode, uint32_t doffset=0);
int getID() const { return this->ID; } //!< Get ID of WBPeriph
int getIndex() const { return this->index; } //!< Get unique index of WBPeriph
const std::string& getName() const { return this->name; } //!< Get the name
const char *getCName() const { return this->name.c_str(); } //!< Get the name in "C" format for printf function
const std::string& getDesc() const { return this->desc; } //!< Get the description
bool isValid(bool connected=true) const { return (bus && bus->isValid(connected)); } //!< Return true when all pointers are defined
const EWBBridge* getBridge() const { return (bus)?bus->getBridge():0; }
EWBBridge* getBridge() { return (bus)?bus->getBridge():0; }
uint32_t getOffset(bool absolute) const;
void print(std::ostream & o, int level=0) const;
friend std::ostream & operator<<(std::ostream & o, const EWBPeriph &p) { p.print(o); return o; } //!< \ref print()
protected:
std::string name; //!< Name of the peripheral node
std::string desc; //!< Description of the peripheral node
uint32_t offset; //!< Address of the peripheral node
uint32_t ID; //!< ID (SDB) of this peripheral
private:
EWBBus *bus;
static int sCount;
int index;
std::map<uint32_t,EWBReg*> registers;
std::map<uint32_t,EWBReg*>::iterator ii_nxtreg;
};
#endif /* EWBPERIPH_H_ */
/*
* EEWBReg.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBReg.h"
#include "EWBField.h"
#include "EWBPeriph.h"
#include "EWBTrace.h"
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <cstdarg>
#include <ctype.h>
#define TRACE_P_VDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
#define TRACE_P_VVDEBUG(...) //TRACE_P_DEBUG( __VA_ARGS__)
/**
* Constructor of a EWBReg
*
* \param[in] pPrtNode if valid, we will append this register to the EWBNode.
* \param[in] name The name of the register
* \param[in] offset The EWB address offset respective to the peripheral (EWBNode)
* \param[in] desc a description of what does this registers in case it is needed.
*/
EWBReg::EWBReg(EWBPeriph *pPrtPeriph,const std::string &name, uint32_t offset, const std::string &desc)
:EWBSync(EWB_AM_RW)
{
this->pPeriph=pPrtPeriph;
this->name=name;
this->desc=desc;
this->offset=offset;
this->used_mask=0;
this->data=0;
this->toSync=false;
pPrtPeriph->appendReg(this);
//TRACE_DEBUG("EWBNode::EWBNode() %s (%x, %x)\n",this->name.c_str(),&this->name,this);
}
/**
* Destructor of EWBReg
*
* It also delete all the fields associate to this EWBReg.
*/
EWBReg::~EWBReg()
{
for(size_t j=0;j<fields.size();j++)
{
if(fields[j]) delete fields[j];
}
}
/**
* Append a field to the register
*
* It will check if the field exist or if some bits of this mask
* is already used.
*
*
* \param[in] fld A pointer
* \param[in] toSyncInit Tell if this field need to be sync at initialization
* \return true if it was possible to add it, false otherwise.
*/
bool EWBReg::addField(EWBField *fld, bool toSyncInit)
{
const EWBReg* fld_reg=fld->getReg();
if(fld==NULL || fld_reg==NULL || this!=fld_reg)
{
TRACE_P_WARNING("Field %s does not belong to this register %s (%s)",
fld->getName().c_str(), this->getName().c_str(),fld_reg->getName().c_str());
return false;
}
if((fld->getMask() & used_mask)!=0)
{
TRACE_P_WARNING("Can not add field %s (0x%08x), mask is already used in register %s (0x%08x)\n",
fld->getCName(), fld->getMask(),this->getCName(),this->used_mask);
return false;
}
//Append the field to the vector
fields.push_back(fld);
//append field mask to used mask of the whole register
used_mask|=fld->getMask();
this->toSync|=toSyncInit;
return true;
}
/**
* Get a pointer on the corresponding field
*
* \return A pointer on EWBField or NULL if it was not found
*/
const EWBField* EWBReg::getField(const std::string& name) const
{
EWBField *f;
for(size_t j=0;j<fields.size();j++)
{
f=fields[j];
if(f && f->getName()==name) return f;
}
return NULL;
}
/**
* Synchronize the 32bits of the EWBReg
*
* \note This method is also the only way to reset the toSync flag
*
* \param[in] con A pointer to a valid Memory Connector object.
* \param[in] amode Access mode (R, W, R/W)
* \return true if everything is okay, false otherwise
*/
bool EWBReg::sync(EWBSync::AMode amode)
{
bool ret=true;
if(!isValid()) return false;
EWBBridge *b=pPeriph->getBridge();
//first write to dev
if(amode & EWB_AM_W)
{
ret &= b->mem_access(this->getOffset(true),&data,true); //Write EWB to dev
}
//then read from dev
if(amode & EWB_AM_R)
{
ret &= b->mem_access(this->getOffset(true),&data,false); //Read EWB from dev
}
if(toSync) toSync=(ret==false); //Keep trying to sync if return was false
return ret;
}
/**
* Return the offset of the register
*
* \param[in] absolute if true the offset is the absolute direction in relation with the EWBNode.
*
*/
uint32_t EWBReg::getOffset(bool absolute) const
{
if(absolute && isValid())
{
return pPeriph->getOffset(absolute)+offset;
}
return offset;
}
/**
* operator that print the data of the EWBReg in a stream
*/
std::ostream & operator<<(std::ostream & o, const EWBReg &r)
{
o << EWBTrace::string_format("@0x%08X (%s) : 0x%x",r.getOffset(true),r.getCName(),r.getData());
return o;
}
/*
* EWBReg.h
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBREG_H_
#define EWBREG_H_
#include "EWBSync.h"
#include "EWBPeriph.h"
class EWBField;
#include <vector>
/**
* Class to manipulate Wishbone register with various EWBField
*
* \ref EWBNode
* \ref EWBField
*/
class EWBReg: public EWBSync {
public:
friend class EWBField;
friend class EWBPeriph;
friend std::ostream & operator<<(std::ostream & output, const EWBReg &r);
EWBReg(EWBPeriph *pPrtNode,const std::string &name, uint32_t offset, const std::string &desc="");
virtual ~EWBReg();
uint32_t getOffset(bool absolute=false) const;
bool sync(EWBSync::AMode amode=EWB_AM_RW);
bool addField(EWBField *fld, bool toSyncInit=false);
const EWBField* getField(const std::string& name) const;
const EWBField* operator[](const std::string& name) const { return this->getField(name); }
std::vector<EWBField*> getFields() { return fields; }
const std::vector<EWBField*> getFields() const { return fields; } //!< Get a vector on the belonging EWBField
const EWBPeriph* getPrtNode() const { return pPeriph; } //!< Get the parent EWBNode
void setToSync() { toSync=true; } //!< Set this register to be sync ASAP
bool isToSync() const { return toSync; } //!< Check if the register need to be sync ASAP
uint32_t getData() const { return data; } //!< Get the data
const std::string& getName() const { return this->name; } //!< Get the name
const char *getCName() const { return this->name.c_str(); } //!< Get the name in "C" format for printf function
const std::string& getDesc() const { return this->desc; } //!< Get the description
bool isValid(bool connected=true) const { return (pPeriph && pPeriph->isValid(connected)); }
protected:
EWBPeriph* getPeriph() { return pPeriph; }
std::vector<EWBField*> fields; //!< A list of the relative EWBFields
std::string name; //!< The name
std::string desc; //!< A description
uint32_t offset; //!< The offset relative to EWBNode
uint32_t data; //!< The corresponding data
uint32_t used_mask; //!< The mask used by other EWBField
bool toSync; //!< Boolean that tell if this register need to be sync ASAP
private:
EWBPeriph *pPeriph; //!< Parent Peripheral
};
#endif /* EWBREG_H_ */
/*
* EWBSync.h
*
* Created on: Jun 15, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBSYNC_H_
#define EWBSYNC_H_
#include <cstdint>
/**
* Abstract interface to implement the sync functionality shared
* by the different classes
*/
class EWBSync {
public:
//! Access mode for a EWB Register or Field
enum AMode { EWB_AM_R=0x1, EWB_AM_W=0x2, EWB_AM_RW=0x3 };
EWBSync(uint8_t mode): mode(mode), forceSync(false), toSync(false) {};
virtual ~EWBSync() {};
virtual bool sync(EWBSync::AMode mode) = 0;
virtual bool isValid() const = 0;
void setForceSync(bool val=true) { this->forceSync=val; };
uint8_t getAccessMode() const { return mode; } //!< Get the mode of access
bool isModeRead() const { return mode==EWB_AM_R; }; //!< Return @true if this parameter can be read from the device.
bool isModeWrite() const { return mode==EWB_AM_W; }; //!< Return @true if this parameter can be written to the device.
protected:
uint8_t mode;
bool forceSync;
bool toSync;
};
//class EWBPVSync {
//
//public:
//
// EWBPVSync();
// virtual void preSync();
// virtual void postSync();
//
//
//protected:
// EWBParam *pPrm;
// EWBSync *pSync;
// int index;
//};
#endif /* EWBSYNC_H_ */
/*
* EWBTrace.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBTrace.h"
#include <string>
#include <vector>
#include <cstdarg>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
std::string EWBTrace::string_format(const std::string &fmt, ...) {
int size = 512;
char* buffer = 0;
buffer = new char[size];
va_list vl;
va_start(vl, fmt);
int nsize = vsnprintf(buffer, size, fmt.c_str(), vl);
if(size<=nsize){ //fail delete buffer and try again
delete[] buffer;
buffer = 0;
buffer = new char[nsize+1]; //+1 for /0
nsize = vsnprintf(buffer, size, fmt.c_str(), vl);
}
std::string ret(buffer);
va_end(vl);
delete[] buffer;
return ret;
}
/*
* awbpd_trace.h
* EWBTrace.h
*
* Created on: Nov 4, 2013
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef AWBPD_TRACE_H_
#define AWBPD_TRACE_H_
#ifndef EWBTRACE_H_
#define EWBTRACE_H_
#if defined(TRACE_STDERR)
#define errlogPrintf(...) fprintf(stderr,__VA_ARGS__)
......@@ -155,4 +157,44 @@
#include <sstream>
#endif /* AWBPD_TRACE_H_ */
/**
* Singleton class to handle trace message
*
* @ref: http://stackoverflow.com/questions/1008019/c-singleton-design-pattern
*/
class EWBTrace {
public:
static EWBTrace& getInstance()
{
static EWBTrace instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
static std::string string_format(const std::string &fmt, ...);
private:
EWBTrace() {}; // Forbidden Constructor
#if __cplusplus <= 199711L
// C++ 11
// =======
// We can use the better technique of deleting the methods
// we don't want.
EWBTrace(EWBTrace const&) = delete;
void operator=(EWBTrace const&) = delete;
#else
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
EWBTrace(EWBTrace const&); // Don't Implement
void operator=(EWBTrace const&); // Don't implement
#endif
};
#endif /* EWBTRACE_H_ */
/*
* EWBBus_test.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBBus.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
/*
* EWBFakeWRConsole.cpp
*
* Created on: Aug 10, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBFakeWRConsole.h"
EWBFakeWRConsole::EWBFakeWRConsole()
:EWBCmdConsole(UNKNOWN), info("Fake Console")
{
addCmd("ver","WR Core build: wrpc-FAKE-v1.0\nBuilt on Apr 7 2015, 19:02:39\nBuilt for 00 kB RAM, stack is 0000 bytes ");
addCmd("mode","slave");
addCmd("mode slave","Locking PLL");
addCmd("ptp stop","");
addCmd("ptp start","Slave Only, clock class set to 255");
addCmd("sfp erase","");
addCmd("sfp detect","AXGE-1254-0531");
addCmd("sfp match","Could not match to DB");
addCmd("sfp add","");
addCmd("gui","WR PTP Core Sync Monitor v 1.0\n\
Esc = exit\n\
\n\
TAI Time: Thu, Jan 1, 1970, 04:26:33\n\
\n\
wru1: Link up (RX: 55761, TX: 15967), mode: WR Slave Locked Calibrated\n\
\n\
PTP status: slave\n\
\n\
Synchronization status:\n\
\n\
Servo state: TRACK_PHASE\n\
Phase tracking: ON\n\
Synchronization source:\n\
Aux clock status:\n\
\n\
Timing parameters:\n\
\n\
Round-trip time (mu): 770929 ps\n\
Master-slave delay: 409632 ps\n\
Master PHY delays: TX: 174900 ps, RX: 255214 ps\n\
Slave PHY delays: TX: 46407 ps, RX: 175043 ps\n\
Total link asymmetry: -48335 ps\n\
Cable rtt delay: 119365 ps\n\
Clock offset: -1 ps\n\
Phase setpoint: 489 ps\n\
Skew: -3 ps\n\
Manual phase adjustment: 0 ps\n\
Update counter: 2486\n\
--");
}
EWBFakeWRConsole::~EWBFakeWRConsole() {
// TODO Auto-generated destructor stub
}
void EWBFakeWRConsole::addCmd(const std::string& cmd, const std::string& ret)
{
cMap.insert(std::pair<std::string,std::string>(cmd,ret));
}
void EWBFakeWRConsole::writeCmd(std::string cmd, std::string value)
{
std::map<std::string,std::string>::const_iterator ii;
ii=cMap.find(cmd);
if(ii!=cMap.end())
{
printf("%s %s\n",cmd.c_str(),value.c_str());
}
}
std::string EWBFakeWRConsole::getCmd(std::string cmd)
{
std::map<std::string,std::string>::const_iterator ii;
ii=cMap.find(cmd);
if(ii!=cMap.end())
{
return ii->second;
}
return "";
}
/*
* EWBFakeWRConsoleConsole.h
*
* Created on: Aug 10, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#ifndef EWBFAKEWRCONSOLE_H_
#define EWBFAKEWRCONSOLE_H_
#include <map>
#include <EWBCmdConsole.h>
/**
* Class to test the #WRC Console
*/
class EWBFakeWRConsole: public EWBCmdConsole {
public:
EWBFakeWRConsole();
virtual ~EWBFakeWRConsole();
void writeCmd(std::string cmd, std::string value);
std::string getCmd(std::string cmd);
bool isValid() const { return true; }
const std::string& getInfo() const { return info; };
private:
void addCmd(const std::string& cmd, const std::string& ret);
std::string info;
std::map<std::string, std::string> cMap;
};
#endif /* EWBFAKEWRCONSOLE_H_ */
/*
* EWBField_test.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBField.h"
#include "gtest/gtest.h"
#include "files/wbtest.h"
//EWBField f(NULL,WB2_FIELD_ARGS(TEST,CSR,RST));
namespace
{
TEST(EWBField,ConstructorRst)
{
EWBField f(NULL,WB2_FIELD_ARGS(TEST,CSR,RST));
EXPECT_FALSE(f.isValid());
EXPECT_EQ(NULL,f.getReg());
EXPECT_EQ(WB2_TEST_CSR_RST_ACCESS,f.getAccessMode());
EXPECT_EQ(WB2_TEST_CSR_RST_MASK,f.getMask());
EXPECT_EQ(EWBParam::EWBF_32U,f.getType());
EXPECT_EQ(WB2_TEST_CSR_RST_NBFP,f.getNOfFractionBit());
EXPECT_EQ(0,f.getFloat());
std::cout << f << std::endl;
}
TEST(EWBField,ConstructorNumber)
{
EWBField f(NULL,WB2_FIELD_ARGS(TEST,CSR,NUMBER));
EXPECT_FALSE(f.isValid());
EXPECT_EQ(NULL,f.getReg());
EXPECT_EQ(WB2_TEST_CSR_NUMBER_ACCESS,f.getAccessMode());
EXPECT_EQ(WB2_TEST_CSR_NUMBER_MASK,f.getMask());
EXPECT_EQ(EWBParam::EWBF_32U,f.getType());
EXPECT_EQ(WB2_TEST_CSR_NUMBER_NBFP,f.getNOfFractionBit());
EXPECT_EQ(0,f.getFloat());
}
//TEST(EWBField,ConstructorNumber)
//{
// EXPECT_NEAR(val1, val2, abs_error);
//}
}
/*
* EWBParamStrCmd_test.cpp *
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBParamStrCmd.h"
#include "EWBFakeWRConsole.h"
#include "gtest/gtest.h"
namespace {
TEST(EWBParamStrCmd,Constructor)
{
EWBParamStrCmd p(NULL,"ip","ip set","","Set the IP");
EXPECT_FALSE(p.isValid());
//EXPECT_STREQ(std::string("ip"),p.getName());
EXPECT_STREQ("ip",p.getCName());
EXPECT_EQ(EWBSync::EWB_AM_W,p.getAccessMode());
EXPECT_STREQ("",p.getValue().c_str());
}
TEST(EWBParamStrCmd,Sync)
{
EWBCmdConsole *pConsole = (EWBCmdConsole*)new EWBFakeWRConsole();
EWBParamStrCmd p(pConsole,"mode","mode %s","mode","","Set/Get the PTP mode");
EXPECT_TRUE(p.isValid());
EXPECT_EQ(EWBSync::EWB_AM_RW,p.getAccessMode());
EXPECT_STREQ("",p.getValue().c_str());
p.sync(EWBSync::EWB_AM_R);
EXPECT_STREQ("slave",p.getValue().c_str());
delete pConsole;
}
TEST(EWBParamStrCmd,Regexp1stLine)
{
EWBCmdConsole *pConsole = (EWBCmdConsole*)new EWBFakeWRConsole();
EWBParamStrCmd p(pConsole,"wrc-version","","ver","[^:]*: (.*-v1.0)","Get the version of wrcore");
EXPECT_TRUE(p.isValid());
EXPECT_EQ(EWBSync::EWB_AM_R,p.getAccessMode());
EXPECT_STREQ("",p.getValue().c_str());
p.sync(EWBSync::EWB_AM_R);
EXPECT_STREQ("wrpc-FAKE-v1.0",p.getValue().c_str());
delete pConsole;
}
TEST(EWBParamStrCmd,Regexp2ndLine)
{
EWBCmdConsole *pConsole = (EWBCmdConsole*)new EWBFakeWRConsole();
EWBParamStrCmd p(pConsole,"wrc-builddate","","ver",".*\n(.*)\n.*","Get build date of wrcore");
ASSERT_TRUE(p.isValid());
EXPECT_EQ(EWBSync::EWB_AM_R,p.getAccessMode());
EXPECT_STREQ("",p.getValue().c_str());
p.sync(EWBSync::EWB_AM_R);
EXPECT_STREQ("Built on Apr 7 2015, 19:02:39",p.getValue().c_str());
delete pConsole;
}
TEST(EWBParamStrCmd,GUIRegexpRTT)
{
EWBCmdConsole *pConsole = (EWBCmdConsole*)new EWBFakeWRConsole();
//printf("%s",pConsole->getCmd("gui").c_str());
EWBParamStrCmd p(pConsole,"rtt-delay","","gui","rtt delay:[ ]*([0-9]*) ps.*\n","Get Round-Trip Cable delay");
ASSERT_TRUE(p.isValid());
EXPECT_EQ(EWBSync::EWB_AM_R,p.getAccessMode());
EXPECT_STREQ("",p.getValue().c_str());
p.sync(EWBSync::EWB_AM_R);
EXPECT_STREQ("119365",p.getValue().c_str());
delete pConsole;
}
}
/*
* EWBPeriph_test.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBPeriph.h"
/*
* EWBReg_test.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBReg.h"
/*
* EWBTrace_test.cpp
*
* Created on: Aug 11, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "EWBTrace.h"
########################################################################
## Makefile to compile C++ object from a folder
##
## References:
##
## Authors:
## - Benoit Rat (Seven Solutions, www.sevensols.com)
##
## GNU Lesser General Public License Usage
## This file may be used under the terms of the GNU Lesser
## General Public License version 2.1 as published by the Free Software
## Foundation and appearing in the file LICENSE.LGPL included in the
## packaging of this file. Please review the following information to
## ensure the GNU Lesser General Public License version 2.1 requirements
## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
########################################################################
## Cross Compile
CC = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
## Config
-include $(CURDIR)/.config
## Obtain the version ($ is replaced by $$)
VERSION = $(shell git describe --always --dirty=+ | sed 's;^.*-\([v0-9\.]*\)\([a-z0-9\-+]*\)$$;\1\2;' )
DATE = $(shell date +"%d %b. %Y")
## Flags
INCLUDE_DIR=-I../src/ewbcore/ -I../src/ewbbridge/ -I../src/asynwb
GTEST_DIR=/home/opt/gtest-1.7.0
CPPFLAGS += -isystem $(GTEST_DIR)/include
CXXFLAGS += -g -Wall -Wextra -pthread -Wno-reorder -DTRACE_STDERR -std=c++11
LFLAGS=-L$(GTEST_DIR)/lib/ -L../src/output/ -lpthread
## File processing
ODIR=../src/output/
OBJ_MAIN=EWBParamStrCmd_test.o \
EWBField_test.o
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
all: ewb_test
main: ../src/output/libewbmain.a $(TESTS_MAIN)
../src/output/libewbmain.a:
make -C $(ODIR)
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
#Compiling objects
%.o: %.cpp
${CC} $(CPPFLAGS) $(CXXFLAGS) $(INCLUDE_DIR) -c $*.cpp -o $@
#Final app
ewb_test: ewb_test.o EWBFakeWRConsole.o $(OBJ_MAIN) ../src/output/libewbmain.a gtest_main.a
${CC} $(CPPFLAGS) $(CXXFLAGS) $(LFLAGS) $^ -o $@
clean:
rm -vf *.o gtest_main.* ewb_test
Unit test of the epics-wb library using Gtest framework
Introduction
=============
In order to ensure a stable/bug-free library to
bridge EPICS-IOC with our FPGA node we have decided to
create a testing procedure that try some aspect of the
software in order to avoid bugs when porting to
another environment or when adding features
Requierements
===============
* GCC >4.7 (C++11)
* Gtest-v1.7.0
Usage
==========
Please first compile using `make` command.
Then you should run the first serie of unit-tests
by executing:
./ewb_test
/*
* ewb_test.cpp
*
* Created on: Aug 12, 2015
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
WBHEADERS = wbtest.h
WBINPUT = $(WBHEADERS:.h=wb)
all: header
html: $(WBHEADERS:.h=.html)
db: $(WBHEADERS:.h=.db)
header: $(WBHEADERS)
clean:
rm $(WBHEADERS)
%.h: %.wb
wbgen2 --cstyle=extended --co=$@ $<
%.db: %.wb
wbgen2 --epicsdb=$@ $<
./meldepicsdb.sh $(@:.db=)
%.html: %.wb
wbgen2 -f html --doco=$@ $<
%.vhdl: %.wb
wbgen2 --vo=$@ $<
R PTP Core Sync Monitor v 1.0
Esc = exit
TAI Time: Thu, Jan 1, 1970, 04:26:33
wru1: Link up (RX: 55761, TX: 15967), mode: WR Slave Locked Calibrated
PTP status: slave
Synchronization status:
Servo state: TRACK_PHASE
Phase tracking: ON
Synchronization source:
Aux clock status:
Timing parameters:
Round-trip time (mu): 770929 ps
Master-slave delay: 409632 ps
Master PHY delays: TX: 174900 ps, RX: 255214 ps
Slave PHY delays: TX: 46407 ps, RX: 175043 ps
Total link asymmetry: -48335 ps
Cable rtt delay: 119365 ps
Clock offset: -1 ps
Phase setpoint: 489 ps
Skew: -3 ps
Manual phase adjustment: 0 ps
Update counter: 2486
--
This diff is collapsed.
top = peripheral {
name = "TestWB";
description = "Fake peripheral to test all possibilities";
hdl_entity = "wb_test";
c_prefix = "WB2_test";
hdl_prefix = "WB2Test";
reg {
name = "Control Statut Register";
description = "Reset";
prefix = "CSR";
field {
name = "Reset bit";
description = "write 1 to reset something";
prefix = "rst";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Enable";
description = "This registers indicates the ADC chip selected";
prefix = "enable";
type = BIT;
align=1;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Number";
description = "This registers indicates a number that need to be read";
prefix = "number";
type = SLV;
size = 8;
align = 8;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "ADC_IQ";
description = "I,Q repreTypicial Amplitude P.";
prefix = "adc";
field {
name = "I";
description = "I Voltage units: 16 bits with 2 bits integer (2'complement)";
prefix = "I";
type = SLV;
size = 16;
nbfp = 14;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Q";
description = "Q Minimum Reference directly [-sqrt(2):sqrt(2)]V. Voltage units: 16 bits with 2 bits integer (2'complement)";
prefix = "Q";
type = SLV;
size = 16;
nbfp = 14;
align = 16;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Full Integer";
description = "Minimun Voltage register until Reset";
prefix = "Full";
field {
name = "U32";
description = "Full field";
prefix = "u32";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Full Fixed Integer";
description = "Minimun Voltage register until Reset";
prefix = "FullFixed";
field {
name = "U32";
description = "Full field";
prefix = "all";
type = SLV;
size = 32;
nbfp = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "TestByteSign";
description = "Test on the 4 bytes";
prefix = "testbsign";
field {
name = "Unsigned";
description = "Unsigned byte";
prefix = "u";
type = SLV;
size = 8;
sign = 0;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Sign1 MSB";
description = "MSB Signess";
prefix = "sign1";
type = SLV;
size = 8;
align = 8;
sign= 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Sign2C";
description = "2Complement's signess";
prefix = "sign2";
type = SLV;
size = 8;
align = 16;
sign= 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "TestByteFixed";
description = "Test full fixed point on the 4 bytes";
prefix = "testbfixed";
field {
name = "Unsigned";
description = "Unsigned byte";
prefix = "u";
type = SLV;
size = 8;
nbfp = 8;
sign = 0;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Sign1 MSB";
description = "MSB Signess";
prefix = "sign1";
type = SLV;
size = 8;
align = 8;
nbfp = 7;
sign = 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Sign2C";
description = "2Complement's signess";
prefix = "sign2";
type = SLV;
size = 8;
align = 16;
nbfp = 8;
sign = 1;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Default";
description = "Default signess (2complements)";
prefix = "default";
type = SLV;
size = 8;
align = 24;
nbfp = 8;
sign = 2;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
};
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