#include <iostream>
#include "../include/Data.h"

using namespace std;
using namespace environment;
using namespace environment::data;

#define TEST(x,y)				\
  {						\
    cout << "Line " << __LINE__ << " : ";	\
    if (x==y)					\
      {						\
	cout << "Test OK" << endl;		\
      }						\
    else					\
      {						\
	cout << "Test KO" << endl;		\
	exit (EXIT_FAILURE);			\
      }						\
  } while (0)
    


#ifdef SYSTEMC
int sc_main (int argc, char * argv[])
#else
int    main (int argc, char * argv[])
#endif
{
  cout << "<main> Begin" << endl;

  {
    Segment * seg1 = new Segment ();
    
    TEST(seg1->getType     (), TYPE_TARGET_MEMORY);
    TEST(seg1->getIndex    (), 0);
    TEST(seg1->getBase     (), 0);
    TEST(seg1->getSize     (), 0);
    TEST(seg1->getUncached (), false);
    
    seg1->define_target(TYPE_TARGET_SIM2OS,4);
    TEST(seg1->getType     (), TYPE_TARGET_SIM2OS);
    TEST(seg1->getIndex    (), 4);
    
    cout << *seg1 << endl;
    
    SEGMENT_TABLE_ENTRY * entry = new SEGMENT_TABLE_ENTRY("entry", 0x100, 0x1024, 21, 7, true);
    
    Segment * seg2 = new Segment (entry);
    
    cout << *seg2 << endl;
    
    TEST(seg2->test(0x100, 0x0   ), true);
    TEST(seg2->test(0x100, 0x1024), true);
    TEST(seg2->test(0x100, 0x1025), false);
    
    char * str = new char [10];
    
    str [0] = 'k';
    str [1] = 'a';
    str [2] = 'n';
    str [3] = 'e';
    str [4] = 'd';
    str [5] = 'e';
    str [6] = 'a';
    str [7] = 'd';
    
    seg2->write(0x200,8,str);
    
    for (uint32_t i=0; i<10; i++)
      str [i] = '.';
    
    for (uint32_t i=0; i<10; i++)
      cout << str [i];
    cout << endl;
    
    str [0] = 'i';
    str [1] = 's';
    str [2] = 'b';
    str [3] = 'a';
    str [4] = 'c';
    str [5] = 'k';
    
    seg2->write(0x204,6,str);

    for (uint32_t i=0; i<10; i++)
      str [i] = '.';
    
    seg2->read(0x200,10,str);
    
    for (uint32_t i=0; i<10; i++)
      cout << str [i];
    cout << endl;
  
    Entity * entity1 = new Entity (false);
    Entity * entity2 = new Entity (true, seg2);
    
    cout << *entity1 << endl;
    cout << *entity2 << endl;  
    
    delete    entity2;
    delete    entity1;
    delete [] str;
    delete    seg2;
    delete    entry;
    delete    seg1;
  }

  {
    SOCLIB_SEGMENT_TABLE * segtable = new SOCLIB_SEGMENT_TABLE;
    segtable->setMSBNumber    (8);
    segtable->setDefaultTarget(0,0);
    
    //shared data segment
    
    const int TEXT_BASE          = 0x0;
    const int DATA_CACHED_BASE   = 0x10000000;
    const int DATA_UNCACHED_BASE = 0x40000000;
    
    const int TEXT_SIZE          = 0x4000;
    const int DATA_CACHED_SIZE   = 0x4000;
    const int DATA_UNCACHED_SIZE = 0x4000;
    
    // Add a segment   :name        , address of base    , size               , global index , local index, uncache
    segtable->addSegment("text"      , TEXT_BASE          , TEXT_SIZE          , 0            ,0           , false);
    segtable->addSegment("data"      , DATA_CACHED_BASE   , DATA_CACHED_SIZE   , 0            ,0           , false);
    segtable->addSegment("data_unc"  , DATA_UNCACHED_BASE , DATA_UNCACHED_SIZE , 0            ,0           , true );
    
    segtable->print();

    Parameters * param = new Parameters (16,0,0,segtable);
    
    Data * data = new Data ("my_data", param);

    cout << *data << endl;
    
    const char * filename = "selftest/data/soft.x";
    const char * sections_text  []  = {".text",NULL}; 
    const char * sections_data  []  = {".data",".rodata",".bss",".sdata",".sbss", NULL}; 

    data->init("text"   , filename, sections_text);
    data->init("data"   , filename, sections_data);

    char * str = new char [8];
    
    data->read(0x100,8,str);
    
    cout << hex;
    for (uint32_t i=0; i<8; i++)
      {
	if (i==4)
	  cout << endl;
	cout << std::setw(2) << std::setfill('0') << ((static_cast<uint32_t>(str [i]))&0xff);
      }
    cout << dec << endl;

    str [0] = 0xde;
    str [1] = 0xad;
    str [2] = 0xbe;
    str [3] = 0xef;
    str [4] = 0xba;
    str [5] = 0xbe;
    str [6] = 0xbe;
    str [7] = 0xef;

    data->write(0x104,8,str);

    data->read(0x100,8,str);
    
    cout << hex;
    for (uint32_t i=0; i<8; i++)
      {
	if (i==4)
	  cout << endl;
	cout << std::setw(2) << std::setfill('0') << ((static_cast<uint32_t>(str [i]))&0xff);
      }
    cout << dec << endl;

    data->read(0x108,8,str);
    
    cout << hex;
    for (uint32_t i=0; i<8; i++)
      {
	if (i==4)
	  cout << endl;
	cout << std::setw(2) << std::setfill('0') << ((static_cast<uint32_t>(str [i]))&0xff);
      }
    cout << dec << endl;

    delete [] str;
    delete data;
    delete param;
    delete segtable;
  }
  cout << "<main> End" << endl;
  
  return EXIT_SUCCESS;
}
