/**************************************************************************************************
 * Apache License, Version 2.0
 * Copyright (c) 2024 chciken/Niko
 * Compile with: g++ -O3 -I$SYSTEMC_PATH/include/ -L${SYSTEMC_PATH}/lib-linux64 \
                 -DSC_DISABLE_API_VERSION_CHECK td_simple_bm.cpp -lsystemc -o td_simple_bm.exe
 **************************************************************************************************/

#include <chrono>
#include <cstdlib>
#include <iostream>
#include <thread>

#include "systemc.h"
#include "tlm.h"
#include "tlm_utils/tlm_quantumkeeper.h"

struct Cpu : public sc_module {
  SC_HAS_PROCESS(Cpu);
  tlm_utils::tlm_quantumkeeper qk;

  void thread() {
    while (true) {
      if (qk.need_sync())
        qk.sync();
      // Do stuff..
      qk.inc(sc_time(1, SC_NS));
    }
  }

  Cpu(sc_module_name name) : sc_module(name) {
    SC_THREAD(thread);
    qk.reset();
  }
};


struct Soc : public sc_module {
  SC_HAS_PROCESS(Soc);
  Cpu cpu0, cpu1;

  Soc(sc_module_name name) : sc_module(name), cpu0("cpu0"), cpu1("cpu1") {
    tlm_utils::tlm_quantumkeeper::set_global_quantum(sc_time(2, SC_NS));
  }
};

constexpr double kSimulationTime = 1 * 5000000;
constexpr int kMaxQuantum = 100;

int sc_main(int argc, char* argv[]) {
  Soc soc("soc");

  if (argc < 2) {
    throw std::runtime_error("No quantum provided!");
  }

  int quantum = std::atoi(argv[1]);
  tlm_utils::tlm_quantumkeeper::set_global_quantum(sc_time(quantum, SC_NS));

  auto begin = std::chrono::steady_clock::now();
  sc_start(kSimulationTime, SC_NS);
  auto end = std::chrono::steady_clock::now();

  auto time_us = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
  float mips = (kSimulationTime * 2) / time_us;
  std::cout << "MIPS = " << mips << std::endl;

  return 0;
}

