You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/piklab-test/base/generator_check.cpp

289 lines
9.8 KiB

/***************************************************************************
* Copyright (C) 2007 Nicolas Hadacek <hadacek@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "generator_check.h"
#include "devices/base/device_group.h"
#include "devices/pic/pic/pic_memory.h"
#include "tools/gputils/gputils.h"
#include "tools/gputils/gputils_generator.h"
#include "tools/sdcc/sdcc.h"
#include "tools/sdcc/sdcc_generator.h"
#include "devices/list/device_list.h"
//----------------------------------------------------------------------------
GeneratorCheckHelper::GeneratorCheckHelper()
: _cprocess(0), _lprocess(0), _generator(0)
{}
GeneratorCheckHelper::~GeneratorCheckHelper()
{
delete _generator;
}
void GeneratorCheckHelper::cleanup()
{
delete _lprocess;
_lprocess = 0;
delete _cprocess;
_cprocess = 0;
}
//----------------------------------------------------------------------------
GeneratorCheck::GeneratorCheck(GeneratorCheckHelper *helper)
: _helper(helper), _fdest(0), _fhex(0), _memory1(0)
{
_view = new CLI::View;
}
GeneratorCheck::~GeneratorCheck()
{
delete _view;
delete _helper;
}
void GeneratorCheck::runTest()
{
_helper->initSupported();
DeviceTest::runTest();
}
bool GeneratorCheck::init(const Device::Data &data)
{
PURL::Url dest(PURL::Directory::current(), "test.xxx");
dest = dest.toFileType(_helper->sourceFileType());
_fdest = new PURL::File(dest, *_view);
_helper->init(data);
PURL::Url hex(PURL::Directory::current(), "test.hex");
_fhex = new PURL::File(hex, *_view);
_memory1 = static_cast<Pic::Memory *>(data.group().createMemory(data));
return true;
}
bool GeneratorCheck::skip(const Device::Data &data) const
{
return !_helper->isSupported(data);
}
void GeneratorCheck::cleanup(const Device::Data &)
{
delete _memory1;
_memory1 = 0;
delete _fhex;
_fhex = 0;
// _fdest->remove();
delete _fdest;
_fdest = 0;
_helper->cleanup();
}
bool GeneratorCheck::execute(const Device::Data &data)
{
// create asm file from template source code
if ( !_fdest->openForWrite() ) TEST_FAILED_RETURN("");
_fdest->appendText(_source);
_fdest->close();
// run compiler
Process::State state = Process::runSynchronously(*_helper->_cprocess, Process::Start, 2000); // 2s timeout
if ( state!=Process::Exited ) TEST_FAILED_RETURN("Error while running compilation")
if ( _helper->_cprocess->exitCode()!=0 ) TEST_FAILED_RETURN(TQString("Error in compilation for %1:\n%2%3").tqarg(data.name()).tqarg(_helper->_cprocess->sout()+_helper->_cprocess->serr()).tqarg(TQString()))
// run linker
if (_helper->_lprocess) {
state = Process::runSynchronously(*_helper->_lprocess, Process::Start, 2000); // 2s timeout
if ( state!=Process::Exited ) TEST_FAILED_RETURN("Error while running linking")
if ( _helper->_lprocess->exitCode()!=0 ) TEST_FAILED_RETURN(TQString("Error in linking for %1:\n%2%3").tqarg(data.name()).tqarg(_helper->_lprocess->sout()+_helper->_lprocess->serr()).tqarg(TQString()))
}
// load hex file
if ( !_fhex->openForRead() ) TEST_FAILED_RETURN("")
TQStringList errors, warnings;
Device::Memory::WarningTypes warningTypes;
if ( !_memory1->load(_fhex->stream(), errors, warningTypes, warnings) ) TEST_FAILED_RETURN(TQString("Error loading hex into memory: %1").tqarg(errors.join(" ")))
//if ( warningTypes!=Device::Memory::NoWarning ) TEST_FAILED(TQString("Warning loading hex into memory: %1").tqarg(warnings.join(" ")))
TEST_PASSED
return true;
}
//----------------------------------------------------------------------------
bool ConfigGeneratorCheck::init(const Device::Data &data)
{
if ( !GeneratorCheck::init(data) ) return false;
_memory2 = static_cast<Pic::Memory *>(data.group().createMemory(data));
return true;
}
bool ConfigGeneratorCheck::execute(const Device::Data &data)
{
// create configuration
const Pic::Config &config = static_cast<const Pic::Data &>(data).config();
for (uint l=0; ; l++) {
// set config bits
bool ok = false;
for (uint i=0; i<config._words.count(); i++) {
const Pic::Config::Word &cword = config._words[i];
for (uint k=0; k<cword.masks.count(); k++) {
const Pic::Config::Mask &cmask = cword.masks[k];
if ( l<cmask.values.count() ) {
ok = true;
if ( !cmask.values[l].name.isEmpty() ) _memory2->setConfigValue(cmask.name, cmask.values[l].name);
}
}
}
if ( !ok ) break;
// create source code
PURL::SourceFamily sfamily = _helper->sourceFileType().data().sourceFamily;
PURL::ToolType ttype = sfamily.data().toolType;
SourceLine::List lines = _helper->generator()->includeLines(ttype, data);
lines += _helper->generator()->configLines(ttype, *_memory2, ok);
lines += _helper->configEndLines();
_source = SourceLine::text(sfamily, lines, 2);
if (!ok) TEST_FAILED_RETURN("Config lines generation incomplete")
if ( !GeneratorCheck::execute(data) ) return false;
// check that config bits are the same
uint nbChars = static_cast<const Pic::Data &>(data).nbCharsWord(Pic::MemoryRangeType::Config);
for (uint i=0; i<config._words.count(); i++) {
const Pic::Config::Word &cword = config._words[i];
BitValue word1 = _memory1->word(Pic::MemoryRangeType::Config, i);
BitValue word2 = _memory2->word(Pic::MemoryRangeType::Config, i);
if ( word1==word2 ) continue;
for (uint k=0; k<cword.masks.count(); k++) {
const Pic::Config::Mask &cmask = cword.masks[k];
if ( cmask.value.isInside(cword.pmask) ) continue;
BitValue value1 = word1.maskWith(cmask.value);
BitValue value2 = word2.maskWith(cmask.value);
if ( value1==value2 ) continue;
TQString name1, name2;
uint l1, l2;
for (uint l=0; l<cmask.values.count(); l++) {
const Pic::Config::Value &value = cmask.values[l];
if ( value.value==value1 ) { name1 = value.name; l1 = l; }
if ( value.value==value2 ) { name2 = value.name; l2 = l; }
}
if ( name1==name2 ) continue;
TEST_FAILED_RETURN(TQString("Config bits are different in %1: set\"%2\"=(%3) != compiled=%4)")
.tqarg(cmask.name).tqarg(cmask.values[l2].name)
.tqarg(toHexLabel(word2.maskWith(cmask.value), nbChars)).tqarg(toHexLabel(word1.maskWith(cmask.value), nbChars)))
}
}
}
TEST_PASSED
return true;
}
void ConfigGeneratorCheck::cleanup(const Device::Data &data)
{
GeneratorCheck::cleanup(data);
delete _memory2;
_memory2 = 0;
}
//----------------------------------------------------------------------------
bool TemplateGeneratorCheck::init(const Device::Data &data)
{
if ( !GeneratorCheck::init(data) ) return false;
bool ok;
PURL::SourceFamily sfamily = _helper->sourceFileType().data().sourceFamily;
PURL::ToolType ttype = sfamily.data().toolType;
SourceLine::List lines = _helper->generator()->templateSourceFile(ttype, data, ok);
_source = SourceLine::text(sfamily, lines, 2);
if (!ok) TEST_FAILED_RETURN(TQString("Incomplete template generator for %1").tqarg(data.name()))
return true;
}
//----------------------------------------------------------------------------
GPUtilsGeneratorCheckHelper::GPUtilsGeneratorCheckHelper()
{
_generator = new GPUtils::SourceGenerator;
}
void GPUtilsGeneratorCheckHelper::initSupported()
{
Process::StringOutput p;
TQStringList options;
options += "-l";
p.setup("gpasm", options, false);
Process::runSynchronously(p, Process::Start, 2000); // 2s timeout
_supported = GPUtils::getSupportedDevices(p.sout());
}
bool GPUtilsGeneratorCheckHelper::init(const Device::Data &data)
{
_cprocess = new Process::StringOutput;
TQStringList options;
options = "-c";
options += "-p" + GPUtils::toDeviceName(data.name());
options += "test.asm";
_cprocess->setup("gpasm", options, false);
_lprocess = new Process::StringOutput;
options = "-o";
options += "test.hex";
options += "test.o";
_lprocess->setup("gplink", options, false);
return true;
}
SourceLine::List GPUtilsGeneratorCheckHelper::configEndLines() const
{
SourceLine::List lines;
lines.appendIndentedCode("end");
return lines;
}
//----------------------------------------------------------------------------
SDCCGeneratorCheckHelper::SDCCGeneratorCheckHelper()
{
_generator = new SDCC::SourceGenerator;
}
void SDCCGeneratorCheckHelper::initSupported()
{
PURL::Url url(PURL::Directory::current(), "test.c");
Log::StringView view;
PURL::File file(url, view);
if ( file.openForWrite() ) file.appendText("void main(void) {}\n");
file.close();
_supported.clear();
for (uint i=0; i<SDCC::Nb_Families; i++) {
Process::StringOutput p;
TQStringList options;
options += TQString("-m") + SDCC::FAMILY_DATA[i].name;
options += "-phelp";
options += "test.c";
p.setup("sdcc", options, false);
Process::runSynchronously(p, Process::Start, 2000); // 2s timeout
_supported += SDCC::getSupportedDevices(p.serr());
}
}
bool SDCCGeneratorCheckHelper::init(const Device::Data &data)
{
_cprocess = new Process::StringOutput;
TQStringList options;
options += TQString("-m") + SDCC::FAMILY_DATA[SDCC::family(data.name())].name;
options += "-" + SDCC::toDeviceName(data.name());
options += "test.c";
options += "-I/usr/share/gputils/header";
options += "-Wl-otext.hex";
_cprocess->setup("sdcc", options, false);
return true;
}
SourceLine::List SDCCGeneratorCheckHelper::configEndLines() const
{
SourceLine::List lines;
lines.appendIndentedCode("void main() {}");
return lines;
}