
#include <QApplication>
#include <QMainWindow>
#include <QThread>
#include <QTableView>

#include "history.hh"
#include "memchecker_events.h"
#include "mem_view.hh"

#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <iostream>

static History<uint32_t, uint32_t> *_hist;

class FifoThread : public QThread
{
public:

  FifoThread(const char *fifo)
  {
    _fd = open(fifo, O_RDWR);
    assert(_fd >= 0);
  }

private:

  void rd(void *buf, size_t size)
  {
    int r;

    do {
      r = read(_fd, buf, size);

      assert(r > 0);

      size -= r;
      buf = (uint8_t*)buf + r;
	
    } while (size > 0);
  }

  void run()
  {
    while (1)
      {
	IssMemcheckerEventPacket p;
	rd(&p, sizeof(p));

	if (p._magic != 0x477569677569)
	  continue;

	switch (p._type)
	  {
	  case ISS_MCEVENT_NONE: {
	    std::cerr << "init\n";
	    _hist->init();
	    break;
	  }

	  case ISS_MCEVENT_RESET: {
	    std::cerr << "reset cpu " << p._cpu_id << "\n";
	    char reg_names[p._reset._regs_count][8];
	    rd(reg_names, sizeof(reg_names));
	    _hist->cpuReset(p._cpu_id, p._reset._regs_count,
			    p._reset._pc_reg, p._reset._sp_reg, reg_names);
	    break;
	  }

	  case ISS_MCEVENT_PRELOAD: {
	    uint8_t data[p._state._size];
	    rd(data, p._state._size);
	    _hist->setData(p._state._addr, data, p._state._size);
	    break;
	  }

	  case ISS_MCEVENT_READ_START:
	  case ISS_MCEVENT_READ_DONE:
	  case ISS_MCEVENT_WRITE_START:
	  case ISS_MCEVENT_WRITE_DONE:
	  case ISS_MCEVENT_LL_START:
	  case ISS_MCEVENT_LL_DONE:
	  case ISS_MCEVENT_SC_START:
	  case ISS_MCEVENT_SC_DONE:
	  case ISS_MCEVENT_SC_FAILED:
	    _hist->memAccess(p._type, p._access._addr, p._access._data, p._access._be, p._cpu_id, p._cycles);
	    //	    std::cerr << "access " << p._access._addr << " " << p._access._data << "\n";
	    break;

	  case ISS_MCEVENT_MEM_DECLARE:
	    std::cerr << "mem declare\n";

	  case ISS_MCEVENT_TYPE_GLOBAL:
	  case ISS_MCEVENT_TYPE_GLOBAL_RO:
	  case ISS_MCEVENT_TYPE_ALLOC:
	  case ISS_MCEVENT_TYPE_FREE:
	  case ISS_MCEVENT_TYPE_SPECIAL:

	  case ISS_MCEVENT_LOCK_ENABLE:
	  case ISS_MCEVENT_LOCK_DISABLE:

	  case ISS_MCEVENT_STACK_ENABLE:
	  case ISS_MCEVENT_STACK_DISABLE:

	  case ISS_MCEVENT_VALUE_INVALID:
	  case ISS_MCEVENT_VALUE_UNDEFINED:
	  case ISS_MCEVENT_VALUE_INIT:

	    _hist->memState(p._type, p._state._addr, p._state._size, p._cpu_id, p._cycles);
	    //	    std::cerr << "state " << p._state._addr << " " << p._state._size << "\n";
	    break;

	  case ISS_MCEVENT_REG_CHANGE:
	    _hist->regWrite(p._reg._id, p._reg._data, p._cpu_id, p._cycles);
	    break;
	  }
      }
  }

  int _fd;
};

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  //  QMainWindow mainWin;

  _hist = new History<uint32_t, uint32_t>();

  QThread *t = new FifoThread("iss_viewer.fifo");
  t->start();

  MemView view1(_hist, 0x7f000000, 0x01000000);
  MemView view2(_hist, 0x60000000, 0x00100000);

  view1.setWindowTitle("ram");
  view2.setWindowTitle("load");

  view1.show();
  view2.show();

  //  mainWin.show();
  return app.exec();
}


