text: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  #include <cassert>
  #include <chrono>
  #include <thread>
  #include <vta/dpi/tsim.h>
  #include <verilated.h>
  
  #if VM_TRACE
  #ifdef VM_TRACE_FST
  #include <verilated_fst_c.h>
  #else
  #include <verilated_vcd_c.h>
  #endif
  #endif
  
  #if VM_TRACE
  #define STRINGIZE(x) #x
  #define STRINGIZE_VALUE_OF(x) STRINGIZE(x)
  #endif
  
  static VTAContextHandle _ctx = nullptr;
  static VTASimDPIFunc _sim_dpi = nullptr;
  static VTAHostDPIFunc _host_dpi = nullptr;
  static VTAMemDPIFunc _mem_dpi = nullptr;
  
  void VTASimDPI(dpi8_t* wait,
                 dpi8_t* exit) {
    assert(_sim_dpi != nullptr);
    (*_sim_dpi)(_ctx, wait, exit);
  }
  
  void VTAHostDPI(dpi8_t* req_valid,
                  dpi8_t* req_opcode,
                  dpi8_t* req_addr,
                  dpi32_t* req_value,
                  dpi8_t req_deq,
                  dpi8_t resp_valid,
                  dpi32_t resp_value) {
    assert(_host_dpi != nullptr);
    (*_host_dpi)(_ctx, req_valid, req_opcode,
                 req_addr, req_value, req_deq,
                 resp_valid, resp_value);
  }
  
  void VTAMemDPI(dpi8_t rd_req_valid,
                 dpi8_t rd_req_len,
                 dpi8_t rd_req_id,
                 dpi64_t rd_req_addr,
                 dpi8_t wr_req_valid,
                 dpi8_t wr_req_len,
                 dpi64_t wr_req_addr,
                 dpi8_t wr_valid,
                 const svOpenArrayHandle wr_value,
                 dpi64_t wr_strb,
                 dpi8_t* rd_valid,
                 dpi8_t* rd_id,
                 const svOpenArrayHandle  rd_value,
                 dpi8_t rd_ready) {
    assert(_mem_dpi != nullptr);
    (*_mem_dpi)(_ctx, rd_req_valid, rd_req_len, rd_req_id,
                rd_req_addr, wr_req_valid, wr_req_len, wr_req_addr, 
                wr_valid, wr_value, wr_strb,
                rd_valid, rd_id,rd_value, rd_ready);
  
  }
  
  void VTADPIInit(VTAContextHandle handle,
                  VTASimDPIFunc sim_dpi,
                  VTAHostDPIFunc host_dpi,
                  VTAMemDPIFunc mem_dpi) {
    _ctx = handle;
    _sim_dpi = sim_dpi;
    _host_dpi = host_dpi;
    _mem_dpi = mem_dpi;
  }
  
  
  // Override Verilator finish definition
  // VL_USER_FINISH needs to be defined when compiling Verilator code
  void vl_finish(const char* filename, int linenum, const char* hier) {
    Verilated::gotFinish(true);
  }
  
  int VTADPISim() {
    uint64_t trace_count = 0;
    Verilated::flushCall();
    Verilated::gotFinish(false);
  
  #if VM_TRACE
    uint64_t start = 0;
  #endif
  
    VL_TSIM_NAME* top = new VL_TSIM_NAME;
  
  #if VM_TRACE
    Verilated::traceEverOn(true);
  #ifdef VM_TRACE_FST
    VerilatedFstC* tfp = new VerilatedFstC;
  #else
    VerilatedVcdC* tfp = new VerilatedVcdC;
  #endif // VM_TRACE_FST
    top->trace(tfp, 99);
    tfp->open(STRINGIZE_VALUE_OF(TSIM_TRACE_FILE));
  #endif
  
    // reset
    for (int i = 0; i < 10; i++) {
      top->reset = 1;
      top->clock = 0;
      top->eval();
  #if VM_TRACE
      if (trace_count >= start)
        tfp->dump(static_cast<vluint64_t>(trace_count * 2));
  #endif
      top->clock = 1;
      top->eval();
  #if VM_TRACE
      if (trace_count >= start)
        tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
  #endif
      trace_count++;
    }
    top->reset = 0;
  
    // start simulation
    while (!Verilated::gotFinish()) {
      top->sim_clock = 0;
      top->clock = 0;
      top->eval();
  #if VM_TRACE
      if (trace_count >= start)
        tfp->dump(static_cast<vluint64_t>(trace_count * 2));
  #endif
      top->sim_clock = 1;
      top->clock = 1;
      top->eval();
  #if VM_TRACE
      if (trace_count >= start)
        tfp->dump(static_cast<vluint64_t>(trace_count * 2 + 1));
  #endif
      trace_count++;
      if ((trace_count % 1000000) == 1)
        fprintf(stderr, "[traced %luM cycles]\n", trace_count / 1000000);
      while (top->sim_wait) {
        top->clock = 0;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        top->sim_clock = 0;
        top->eval();
        top->sim_clock = 1;
        top->eval();
      }
    }
  
  #if VM_TRACE
    tfp->close();
  #endif
  
    delete top;
  
    return 0;
  }
  