#ifdef SYSTEMC
#include "systemc.h"
#endif
#include <iostream>
#include "../include/Data.h"
#include "../../../shared/mapping_memory.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;
  
  const bool test1 = false; // 
  const bool test2 = true; // 

  if (test1)
    {
      // 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;
    }

  if (test2)
    {
      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_STACK_BASE    = 0x40000000;
      // const int DATA_UNCACHED_BASE = 0x80000000;
      
      // const int TEXT_SIZE          = 0x4000;
      // const int DATA_CACHED_SIZE   = 0x4000;
      // const int DATA_STACK_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_stack", DATA_STACK_BASE    , DATA_STACK_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 * filename = "../../../../Softwares/Test/Test_000/bin/soft_NEWLIB_MORPHEO.x";
      const char * sections_text  []  = {".text",NULL}; 
      const char * sections_data  []  = {".data",".rodata",".bss",".sdata",".sbss", NULL}; 

      bool init_ok = true;
      init_ok = init_ok and data->init("text"   , filename, sections_text);
      init_ok = init_ok and data->init("data"   , filename, sections_data);
      
      if (init_ok)
        {
          char * str = new char [8];
          
          data->read(0x100,8,str);
          
          cout << "Read  @100 : " << hex << "0x";
          for (uint32_t i=0; i<8; i++)
            {
              if (i==4)
                cout << endl << "Read  @104 : 0x";
              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;
          
          cout << "Write @104 : 0xdeadbeef" << endl;
          cout << "Write @108 : 0xbabebeef" << endl;
          
          data->write(0x104,8,str);
          
          data->read(0x100,8,str);
          
          cout << "Read  @100 : " << hex << "0x";
          for (uint32_t i=0; i<8; i++)
            {
              if (i==4)
                cout << endl << "Read  @104 : 0x";
              cout << std::setw(2) << std::setfill('0') << ((static_cast<uint32_t>(str [i]))&0xff);
            }
          cout << dec << endl;
          
          data->read(0x108,8,str);
          
          cout << "Read  @108 : " << hex << "0x";
          for (uint32_t i=0; i<8; i++)
            {
              if (i==4)
                cout << endl << "Read  @10C : 0x";
              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;
}
