Commit cf571844 authored by Benoit Rat's avatar Benoit Rat

all: improve EWBReg and EWBPeriph

* add sdb vendor & device ID
* Improve checking when appending registers or fields
* Append fields with a specific index
* Create test unit for EWBReg and EWBPeriph
parent 5c217a8e
......@@ -28,7 +28,7 @@ int EWBPeriph::sCount=0;
* \param[in] addr The absolute wishbone address of this peripheral on the device
* \param[in] desc A description of this peripheral (optional)
*/
EWBPeriph::EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint32_t ID, const std::string &desc)
EWBPeriph::EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint64_t venID, uint32_t devID, const std::string &desc)
: EWBSync(EWB_AM_RW)
{
this->bus=bus;
......@@ -37,11 +37,12 @@ EWBPeriph::EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint3
this->offset=offset;
this->ID=ID;
this->venID=venID;
this->devID=devID;
this->index=sCount++;
TRACE_P_INFO("%s (%d) => @0x%08X",name.c_str(),ID,offset);
TRACE_P_INFO("%s (%4x:%08x) => @0x%08X",name.c_str(),(uint32_t)venID,devID,offset);
}
/**
......@@ -62,9 +63,16 @@ EWBPeriph::~EWBPeriph() {
/**
* Simply add a EWBReg to the EWBPeriph structure
*/
void EWBPeriph::appendReg(EWBReg *pReg)
bool EWBPeriph::appendReg(EWBReg *pReg)
{
if(pReg) registers.insert(std::pair<uint32_t,EWBReg*>(pReg->getOffset(),pReg));
if(pReg) {
std::pair<std::map<uint32_t,EWBReg*>::iterator,bool> ret;
ret = registers.insert(std::pair<uint32_t,EWBReg*>(pReg->getOffset(),pReg));
TRACE_CHECK_VA(ret.second,false,"Could not append '%s' because offset @x%0x is already used by '%s'",
pReg->getCName(),pReg->getOffset(),ret.first->second->getCName());
return ret.second;
}
return false;
}
/**
......@@ -307,7 +315,7 @@ void EWBPeriph::print(std::ostream & o, int level) const
for(i=0;i<level;i++) pre[i]='\t';
pre[i]='\0';
o << pre << "Node: " << this->name << EWBTrace::string_format(" @0x%08X (ID=%d)",this->offset,this->index) << std::endl;
o << pre << "Periph: " << this->name << EWBTrace::string_format(" @0x%08X (%4x:%08x #%d)",this->offset,(uint32_t)this->venID,this->devID,this->index) << std::endl;
EWBReg * reg=NULL;
for(std::map<uint32_t,EWBReg*>::const_iterator ii=this->registers.begin(); ii!=this->registers.end(); ++ii)
......
......@@ -19,6 +19,14 @@ class EWBReg;
#define EWB_NODE_MEMBCK_OWNADDR 0xFFFFFFFF //!< Used by WBNode::sync()
#define WB2_PRH_ARGS(pname,offset) \
WB2_##pname##_PERIPH_PREFIX, \
offset, \
WB2_##pname##_PERIPH_VENID, \
WB2_##pname##_PERIPH_DEVID, \
WB2_##pname##_PERIPH_DESC
/**
* Class that represent a WB peripheral in a tree structure.
*
......@@ -26,20 +34,23 @@ class EWBReg;
*/
class EWBPeriph: public EWBSync {
public:
EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint32_t ID, const std::string &desc="");
EWBPeriph(EWBBus *bus,const std::string &name, uint32_t offset, uint64_t venID, uint32_t devID, const std::string &desc="");
virtual ~EWBPeriph();
void appendReg(EWBReg *pReg);
bool 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.
EWBReg* getLastReg() const { return (registers.size()>0)?registers.rbegin()->second:NULL; } //!< 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
bool isValid(int level=-1) const { return (level!=0)?(bus && bus->isValid(level-1)):bus!=NULL; } //!< Return true when all pointers are defined
bool isID(uint64_t venID, uint32_t devID) const { return (venID==this->venID && devID==this->devID); }
uint32_t getDeviceID() const { return this->devID; } //!< Get the Device ID of this WBPeriph
uint64_t getVendorID() const { return this->venID; } //!< Get the Device ID of this 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
......@@ -55,7 +66,8 @@ 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
uint32_t devID; //!< Device ID (SDB) of this peripheral
uint64_t venID; //!< Vendor ID (SDB) of this peripheral
private:
......
......@@ -32,9 +32,10 @@
* \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] nfields Tell that this register is already set with a specific number of field
* \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)
EWBReg::EWBReg(EWBPeriph *pPrtPeriph,const std::string &name, uint32_t offset, int nfields, const std::string &desc)
:EWBSync(EWB_AM_RW)
{
this->pPeriph=pPrtPeriph;
......@@ -45,8 +46,14 @@ EWBReg::EWBReg(EWBPeriph *pPrtPeriph,const std::string &name, uint32_t offset, c
this->used_mask=0;
this->data=0;
this->toSync=false;
this->nfields=nfields;
pPrtPeriph->appendReg(this);
if(nfields>0) fields.resize(nfields,NULL);
bool added=false;
if(this->pPeriph) added=this->pPeriph->appendReg(this);
if(added==false) {
this->pPeriph=NULL; //Remove linking
}
//TRACE_DEBUG("EWBNode::EWBNode() %s (%x, %x)\n",this->name.c_str(),&this->name,this);
}
......@@ -75,7 +82,7 @@ EWBReg::~EWBReg()
* \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)
bool EWBReg::addField(EWBField *fld, int index, bool toSyncInit)
{
const EWBReg* fld_reg=fld->getReg();
if(fld==NULL || fld_reg==NULL || this!=fld_reg)
......@@ -90,9 +97,22 @@ bool EWBReg::addField(EWBField *fld, bool toSyncInit)
fld->getCName(), fld->getMask(),this->getCName(),this->used_mask);
return false;
}
if(index>0 && nfields>0 && (size_t)index>=fields.size())
{
TRACE_P_WARNING("This field index %s (%d) >= nfields %d\n",
fld->getCName(),index,fields.size());
return false;
}
if(index>0 && nfields>0 && fields[index]!=NULL)
{
TRACE_P_WARNING("This field index already exists %s. It can not be replaced by %s\n",
fields[index]->getCName(),fld->getCName());
return false;
}
//Append the field to the vector
fields.push_back(fld);
if(index>=0 && nfields>0) fields[index]=fld;
else fields.push_back(fld); //Append the field to the vector
//append field mask to used mask of the whole register
used_mask|=fld->getMask();
......
......@@ -28,13 +28,13 @@ public:
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="");
EWBReg(EWBPeriph *pPrtNode,const std::string &name, uint32_t offset, int nfields = -1, 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);
bool addField(EWBField *fld, int index=-1, bool toSyncInit=false);
const EWBField* getField(const std::string& name) const;
const EWBField* operator[](const std::string& name) const { return this->getField(name); }
......@@ -60,6 +60,7 @@ protected:
uint32_t offset; //!< The offset relative to EWBNode
uint32_t data; //!< The corresponding data
uint32_t used_mask; //!< The mask used by other EWBField
int nfields; //!< The number of field defined
bool toSync; //!< Boolean that tell if this register need to be sync ASAP
private:
......
......@@ -6,8 +6,3 @@
*/
#include "EWBBus.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
......@@ -7,3 +7,116 @@
#include "EWBPeriph.h"
#include "EWBReg.h"
#include "EWBField.h"
#include "gtest/gtest.h"
#include "files/wbtest.h"
TEST(EWBPeriph,SimpleConstructor)
{
EWBPeriph p(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
EXPECT_FALSE(p.isValid());
EXPECT_EQ(NULL,p.getBridge());
EXPECT_EQ(0x1234567,p.getVendorID());
EXPECT_EQ(0xABCDEF,p.getDeviceID());
EXPECT_EQ(EWBSync::EWB_AM_RW,p.getAccessMode());
EXPECT_STREQ(WB2_TEST_PERIPH_PREFIX,p.getCName());
EXPECT_STREQ("",p.getDesc().c_str());
EXPECT_EQ(0x40000000,p.getOffset(false));
EXPECT_EQ(NULL,p.getReg(0x0000));
EXPECT_EQ(NULL,p.getReg(0x0004));
EXPECT_EQ(NULL,p.getNextReg(NULL));
EXPECT_EQ(NULL,p.getLastReg());
}
TEST(EWBPeriph,IndexConstructor)
{
EWBPeriph p0(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
int idx_p0=p0.getIndex();
EWBPeriph *pP1 = new EWBPeriph(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
EXPECT_EQ(idx_p0+1,pP1->getIndex());
EWBPeriph p2(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
EXPECT_EQ(idx_p0+2,p2.getIndex());
delete pP1;
EWBPeriph p3(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
EXPECT_EQ(idx_p0+3,p3.getIndex());
}
TEST(EWBPeriph,BadRegOffset)
{
EWBPeriph p(NULL,WB2_TEST_PERIPH_PREFIX,0x40000000,0x1234567,0xABCDEF);
EWBReg *pR1 = new EWBReg(&p,"reg1",0x0004);
EWBReg *pR2 = new EWBReg(&p,"reg2",0x0004);
EXPECT_EQ(pR1,p.getReg(0x0004));
EXPECT_TRUE(pR1->isValid(0));
EXPECT_FALSE(pR2->isValid(0));
}
TEST(EWBPeriph,TreeStructure)
{
EWBPeriph *pP = new EWBPeriph(NULL,WB2_PRH_ARGS(TEST,0x60000000));
EWBReg *pRFix = new EWBReg(pP,WB2_REG_ARGS(TEST,BFIXED));
EWBField *pRFixF2 = new EWBField(pRFix,WB2_FIELD_ARGS(TEST,BFIXED,SIGN1));
EWBField *pRFixF3 = new EWBField(pRFix,WB2_FIELD_ARGS(TEST,BFIXED,SIGN2));
EWBField *pRFixF1 = new EWBField(pRFix,WB2_FIELD_ARGS(TEST,BFIXED,U));
EWBField *pRFixF4 = new EWBField(pRFix,WB2_FIELD_ARGS(TEST,BFIXED,DEFAULT));
EWBReg *pRSig = new EWBReg(pP,WB2_REG_ARGS(TEST,BSIGN));
EWBField *pRSigF3 = new EWBField(pRSig,WB2_FIELD_ARGS(TEST,BSIGN,SIGN2));
EWBField *pRSigF2 = new EWBField(pRSig,WB2_FIELD_ARGS(TEST,BSIGN,SIGN1));
EWBField *pRSigF1 = new EWBField(pRSig,WB2_FIELD_ARGS(TEST,BSIGN,U));
EWBReg *pRAdc = new EWBReg(pP,WB2_REG_ARGS(TEST,ADC));
//Check recursive valid
EXPECT_FALSE(pRFix->isValid());
EXPECT_TRUE(pRFix->isValid(0));
EXPECT_FALSE(pRFix->isValid(1));
EXPECT_TRUE(pRFixF1->isValid(1));
EXPECT_TRUE(pRFixF2->isValid(1));
EXPECT_TRUE(pRFixF3->isValid(1));
EXPECT_TRUE(pRFixF4->isValid(1));
EXPECT_FALSE(pRFixF4->isValid(2));
EXPECT_EQ(pRFix,pP->getLastReg());
EWBReg *pRTmp=NULL;
pRTmp=pP->getNextReg(pRTmp);
EXPECT_EQ(pRAdc,pRTmp);
pRTmp=pP->getNextReg(pRTmp);
EXPECT_EQ(pRSig,pRTmp);
pRTmp=pP->getNextReg(pRTmp);
EXPECT_EQ(pRFix,pRTmp);
pRTmp=pP->getNextReg(pRTmp);
EXPECT_EQ(NULL,pRTmp);
EXPECT_EQ(pRSig,pP->getReg(WB2_TEST_REG_BSIGN));
EXPECT_EQ(pRFix,pP->getReg(WB2_TEST_REG_BFIXED));
EXPECT_EQ(NULL,pP->getReg(WB2_TEST_REG_DAC));
EXPECT_EQ(pRAdc,pP->getReg(WB2_TEST_REG_ADC));
float val=-0.125, valRdbk;
pRFixF3->convert(&val,false);
EXPECT_NE(0,pRFix->getData());
pRFixF3->convert(&valRdbk,true);
EXPECT_EQ(val,valRdbk);
EXPECT_EQ(val,pRFixF3->getFloat());
std::cout << *pP << std::endl;
delete pP;
}
......@@ -7,3 +7,125 @@
#include "EWBReg.h"
#include "EWBField.h"
#include "gtest/gtest.h"
#include "files/wbtest.h"
TEST(EWBReg,SimpleConstructor)
{
EWBReg r(NULL,WB2_REG_ARGS(TEST,CSR));
EXPECT_FALSE(r.isValid());
EXPECT_EQ(NULL,r.getPrtNode());
EXPECT_EQ(EWBSync::EWB_AM_RW,r.getAccessMode());
EXPECT_STREQ(WB2_TEST_REG_CSR_PREFIX,r.getCName());
EXPECT_STREQ(WB2_TEST_REG_CSR_NAME,r.getDesc().c_str());
EXPECT_EQ(WB2_TEST_REG_CSR,r.getOffset(false));
EXPECT_EQ(WB2_TEST_REG_CSR_NFIELDS,r.getFields().size());
EXPECT_EQ(0,r.getData());
}
TEST(EWBReg,NFldConstructor)
{
EWBField *pF;
EWBReg *pR0 = new EWBReg(NULL,"regtest0",0x12345670);
EXPECT_EQ(0x12345670,pR0->getOffset(false));
EXPECT_EQ(0,pR0->getFields().size());
pF = new EWBField(pR0,WB2_FIELD_ARGS(TEST,BFIXED,SIGN1));
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR0,WB2_FIELD_ARGS(TEST,BFIXED,SIGN2));
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR0,WB2_FIELD_ARGS(TEST,BFIXED,U));
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR0,WB2_FIELD_ARGS(TEST,BFIXED,DEFAULT));
EXPECT_TRUE(pF->isValid(0));
delete pR0;
//--------------------------------------------------------
EWBReg *pR1 = new EWBReg(NULL,"regtest1",0x76543210,3);
EXPECT_EQ(0x76543210,pR1->getOffset(false));
EXPECT_EQ(3,pR1->getFields().size());
pF = new EWBField(pR1,WB2_FIELD_ARGS(TEST,BFIXED,SIGN1));
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR1,WB2_FIELD_ARGS(TEST,BFIXED,SIGN2));
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR1,WB2_FIELD_ARGS(TEST,BFIXED,U));
EXPECT_TRUE(pF->isValid(0));
//Try to add a fourth field to a pre-defined register of 3 fields.
pF = new EWBField(pR1,WB2_FIELD_ARGS(TEST,BFIXED,DEFAULT));
EXPECT_FALSE(pF->isValid(0));
EXPECT_EQ(NULL,pF->getReg());
delete pR1;
}
TEST(EWBReg,FieldConstructor)
{
EWBReg *pR = new EWBReg(NULL,WB2_REG_ARGS(TEST,BFIXED));
EWBField *pF2 = new EWBField(pR,WB2_FIELD_ARGS(TEST,BFIXED,SIGN1));
EWBField *pF3 = new EWBField(pR,WB2_FIELD_ARGS(TEST,BFIXED,SIGN2));
EWBField *pF1 = new EWBField(pR,WB2_FIELD_ARGS(TEST,BFIXED,U));
EWBField *pF4 = new EWBField(pR,WB2_FIELD_ARGS(TEST,BFIXED,DEFAULT));
EXPECT_FALSE(pR->isValid());
EXPECT_EQ(NULL,pR->getPrtNode());
EXPECT_EQ(WB2_TEST_REG_BFIXED_NFIELDS,pR->getFields().size());
EXPECT_EQ(0,pR->getData());
EXPECT_TRUE(pF1->isValid(0));
EXPECT_TRUE(pF2->isValid(0));
EXPECT_TRUE(pF3->isValid(0));
EXPECT_TRUE(pF4->isValid(0));
EXPECT_EQ(pF2,pR->getField(WB2_TEST_BFIXED_SIGN1_PREFIX));
EXPECT_EQ(pF2,(*pR)[WB2_TEST_BFIXED_SIGN1_PREFIX]);
EXPECT_EQ(pF2,(*pR)[WB2_TEST_BFIXED_SIGN1_PREFIX]);
std::vector<EWBField*> fVec=pR->getFields();
EXPECT_EQ(pF1,fVec[WB2_TEST_BFIXED_U_INDEX]);
EXPECT_EQ(pF2,fVec[WB2_TEST_BFIXED_SIGN1_INDEX]);
EXPECT_EQ(pF3,fVec[WB2_TEST_BFIXED_SIGN2_INDEX]);
EXPECT_EQ(pF4,fVec[WB2_TEST_BFIXED_DEFAULT_INDEX]);
delete pR;
}
TEST(EWBReg,BadFieldConstructor)
{
EWBReg *pR;
EWBField *pF;
pR = new EWBReg(NULL,"n",0x4);
EWBField *pF1 = new EWBField(pR,"f1",5,0);
EWBField *pF2 = new EWBField(pR,"f2",3,4);
EXPECT_TRUE(pF1->isValid(0));
EXPECT_FALSE(pF2->isValid(0));
EXPECT_EQ(NULL,pF2->getReg());
delete pR;
pR = new EWBReg(NULL,"n",0x4,3);
pF = new EWBField(pR,"f1",5,0,EWBSync::EWB_AM_RW,"",0,0,0);
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR,"f2",2,5,EWBSync::EWB_AM_RW,"",0,0,1);
EXPECT_TRUE(pF->isValid(0));
pF = new EWBField(pR,"f3",4,8,EWBSync::EWB_AM_RW,"",0,0,1); //Retry same index
EXPECT_FALSE(pF->isValid(0));
EXPECT_EQ(NULL,pF->getReg());
delete pR;
EXPECT_STREQ("f3",pF->getCName());
delete pF; //Don't belong to pR so we delete it
}
......@@ -40,7 +40,9 @@ LFLAGS=-L$(GTEST_DIR)/lib/ -L../src/output/ -lpthread
ODIR=../src/output/
OBJ_MAIN=EWBParamStrCmd_test.o \
EWBField_test.o
EWBField_test.o \
EWBReg_test.o \
EWBPeriph_test.o \
# All Google Test headers. Usually you shouldn't change this
......
......@@ -5,6 +5,9 @@
* Author: Benoit Rat (benoit<AT>sevensols.com)
*/
#include "gtest/gtest.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
......@@ -15,7 +15,6 @@ clean:
%.db: %.wb
wbgen2 --epicsdb=$@ $<
./meldepicsdb.sh $(@:.db=)
%.html: %.wb
wbgen2 -f html --doco=$@ $<
......
......@@ -329,5 +329,7 @@
#define WB2_TEST_PERIPH_PREFIX "WB2_test"
#define WB2_TEST_PERIPH_NAME "TestWB"
#define WB2_TEST_PERIPH_DESC WBGEN2_DESC("Fake peripheral to test all possibilities")
#define WB2_TEST_PERIPH_VENID 0x0000000000007501
#define WB2_TEST_PERIPH_DEVID 0xc1fb2535
#endif
......@@ -4,6 +4,8 @@ top = peripheral {
hdl_entity = "wb_test";
c_prefix = "WB2_test";
hdl_prefix = "WB2Test";
sdb_vendor=0x7501;
reg {
name = "Control Statut Register";
......@@ -57,6 +59,7 @@ top = peripheral {
nbfp = 14;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
epicsdb_prec = "4";
};
field {
......@@ -86,6 +89,8 @@ top = peripheral {
nbfp = 14;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
epicsdb_egu = "V";
epicsdb_hopr = "1.5";
};
field {
......
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