<|start_filename|>simmem.cpp<|end_filename|>
// 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 <assert.h>
#include "simmem.h"

simmem_t::simmem_t(int argc, char** argv, size_t b, size_t w, size_t d)
  : htif_t(argc, argv), base(b), width(w), depth(d) {

}
simmem_t::simmem_t(const std::vector<std::string>& args, size_t b, size_t w, size_t d)
  : htif_t(args), base(b), width(w), depth(d) {

}

void sim_thread_main(void* arg) {
  ((simmem_t*)arg)->main();
}

void simmem_t::main() {

    std::unique_ptr<Variane_wrapped> top(new Variane_wrapped);
    std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC);

    if (this->vcd_file != NULL) {
      Verilated::traceEverOn(true);
      top->trace (tfp.get(), 99);
      tfp->open (this->vcd_file);
    }

    if (this->label != NULL) {
        fprintf(stderr, "%s\n", label);
    }

    top->core_id_i = 0;
    top->cluster_id_i = 0;
    top->rst_ni = 0;
    top->fetch_enable_i = 0;
    top->boot_addr_i = 0x80000000;
    top->flush_req_i = 0;

    while (!Verilated::gotFinish()) {

      if (this->vcd_file != NULL) {
        tfp->dump(main_time);
      }

      if (main_time > 40) {
          top->rst_ni = 1; // de-assert reset
          top->fetch_enable_i = 1;
      }

      if ((main_time % 10) == 0) {
          top->clk_i = 1; // toggle clock
      }

      // Apply
      if ((main_time % 10) == 8) {
        if (!flush_req.empty() && !top->flushing_o) {
          flush_req.pop();
          flushing.push(true);
          top->flush_req_i = 1;
        }
      }

      // Test
      if ((main_time % 10) == 1) {
        if (!flushing.empty()) {
          flushing.pop();
          top->flush_req_i = 0;
        }
      }

      if ((main_time % 10) == 6) {
          top->clk_i = 0;
      }

      if ((main_time % 10) == 0) {
        host->switch_to();
      }


      top->eval();
      main_time++;

    }

    if (this->vcd_file != NULL) {
      tfp->close ();
    }
}

addr_t simmem_t::get_tohost_address() {
  return htif_t::tohost_addr;
}

addr_t simmem_t::get_fromhost_address() {
  return htif_t::fromhost_addr;
}

void simmem_t::flush_dcache() {
  flush_req.push(true);
}

void simmem_t::idle()
{
  target.switch_to();
}

int simmem_t::run()
{
  host = context_t::current();
  target.init(sim_thread_main, this);
  return htif_t::run();
}

void simmem_t::read_chunk(addr_t taddr, size_t len, void* vdst)
{
  taddr -= base;

  assert(len % chunk_align() == 0);
  if (taddr >= width*depth) {
    return;
  }

  uint8_t* dst = (uint8_t*)vdst;
  while(len)
  {
    if(mem[taddr/width].size() == 0)
      mem[taddr/width].resize(width,0);

    for(size_t j = 0; j < width; j++)
      dst[j] = mem[taddr/width][j];

    len -= width;
    taddr += width;
    dst += width;
  }
}

void simmem_t::write_chunk(addr_t taddr, size_t len, const void* vsrc)
{
  if (taddr == fromhost_addr) {
    flush_dcache();
  }

  taddr -= base;

  assert(len % chunk_align() == 0);
  if (taddr >= width*depth) {
    return;
  }

  const uint8_t* src = (const uint8_t*)vsrc;
  while(len)
  {
    if(mem[taddr/width].size() == 0)
      mem[taddr/width].resize(width,0);

    for(size_t j = 0; j < width; j++)
      mem[taddr/width][j] = src[j];

    len -= width;
    taddr += width;
  }
}


<|start_filename|>ariane_tb.cpp<|end_filename|>
// 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 "svdpi.h"
#include "Variane_wrapped__Dpi.h"

#include <stdio.h>
#include "simmem.h"
#include <fesvr/htif.h>
#include <fesvr/memif.h>
#include <fesvr/htif_hexwriter.h>
#include <time.h>
#include <iostream>
#include <string>
#include <fesvr/option_parser.h>

std::unique_ptr<simmem_t> htif;
bool stop_sim = false;

extern unsigned long long read_uint64 (unsigned long long address) {

  // as we do not have physical memory protection at the moment check here for invalid accesses
  // in the soc this is done by the AXI bus
  if (address < 0x80000000) {
    return 0xdeadbeafdeadbeef;
  }

  return htif->memif().read_uint64(address);
}

extern void write_uint64 (unsigned long long address, unsigned long long data) {
  htif->memif().write_uint64(address, data);
}

extern unsigned long long get_tohost_address() {
  return htif->get_tohost_address();
}

extern unsigned long long get_fromhost_address() {
  return htif->get_fromhost_address();
}

static void help()
{
  fprintf(stderr, "usage: ariane C verilator simulator [host options] <target program> [target options]\n");
  fprintf(stderr, "Host Options:\n");
  fprintf(stderr, "  --vcd=<file>              Dump VCD trace to file\n");
  fprintf(stderr, "  --label=<label>           Pass a label to the program\n");
  fprintf(stderr, "  -p                        Show simulation performance counters\n");
  fprintf(stderr, "  -v                        Verbose\n");
  exit(1);
}

// This is a 64-bit integer to reduce wrap over issues and
// allow modulus.  You can also use a double, if you wish.

double sc_time_stamp () {       // Called by $time in Verilog
    return htif->main_time;     // converts to double, to match
                                // what SystemC does
}

int main(int argc, char **argv) {

  const char *vcd_file = NULL, *label = NULL;
  bool dump_perf = false, verbose= false;

  option_parser_t parser;
  parser.help(&help);
  parser.option('h', 0, 0, [&](const char* s){help();});
  parser.option('p', 0, 0, [&](const char* s){dump_perf = true;});
  parser.option('v', 0, 0, [&](const char* s){verbose = true;});
  parser.option(0, "vcd", 1, [&](const char* s){vcd_file = s;});
  parser.option(0, "label", 1, [&](const char* s){label = s;});

  auto argv1 = parser.parse(argv);
  std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);

  htif.reset(new simmem_t(htif_args, 0x80000000, 8, 2097152));

  htif->set_vcd(vcd_file);
  htif->set_label(label);
  htif->start();

  clock_t t;
  t = clock();

  htif->run();

  t = clock() - t;

  if (dump_perf) {
    fprintf(stderr, "Elapsed Time: %f seconds\n", t*1.0/CLOCKS_PER_SEC);
    fprintf(stderr, "Cycles: %2.f \n", htif->main_time/10.0);
    fprintf(stderr, "Cycles/s: %2.f\n", (htif->main_time*1.0)/(t*10.0/CLOCKS_PER_SEC));
  }
  exit(0);
}


<|start_filename|>dpi/elfdpi.cc<|end_filename|>
// Copyright (c) 2013, The Regents of the University of California (Regents).
// All Rights Reserved.

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the name of the Regents nor the
//    names of its contributors may be used to endorse or promote products
//    derived from this software without specific prior written permission.

// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
// OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
// BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

#include "vpi_user.h"
#include "elfdpi.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include "elf.h"
#include <map>
#include <string>
#include <vpi_user.h>

std::map<std::string, uint64_t> symbols;
std::map<std::string, uint64_t> sections;
std::map<std::string, uint64_t> section_length;

uint64_t get_section_address (const char* symb) {
  return sections[symb];
}

uint64_t get_symbol_address (const char* symb) {
  return symbols[symb];
}

uint64_t get_section_size (const char* symb) {
  return section_length[symb];
}

void* read_elf(const char* fn) {

  int fd = open(fn, O_RDONLY);
  struct stat s;
  // check thtat the file exists
  assert(fd != -1);

  if (fstat(fd, &s) < 0)
    abort();
  size_t size = s.st_size;
  // map the file to memory
  char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
  assert(buf != MAP_FAILED);
  close(fd);
  // check that this is an elf file
  assert(size >= sizeof(Elf64_Ehdr));
  const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf;
  assert(IS_ELF32(*eh64) || IS_ELF64(*eh64) && "This file is not a valid ELF file");

  #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t) do { \
    ehdr_t* eh = (ehdr_t*)buf; \
    phdr_t* ph = (phdr_t*)(buf + eh->e_phoff); \
    assert(size >= eh->e_phoff + eh->e_phnum*sizeof(*ph)); \
    for (unsigned i = 0; i < eh->e_phnum; i++) { \
      if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \
        if (ph[i].p_filesz) { \
          assert(size >= ph[i].p_offset + ph[i].p_filesz); \
        } \
      } \
    } \
    shdr_t* sh = (shdr_t*)(buf + eh->e_shoff); \
    assert(size >= eh->e_shoff + eh->e_shnum*sizeof(*sh)); \
    assert(eh->e_shstrndx < eh->e_shnum); \
    assert(size >= sh[eh->e_shstrndx].sh_offset + sh[eh->e_shstrndx].sh_size); \
    char *shstrtab = buf + sh[eh->e_shstrndx].sh_offset; \
    unsigned strtabidx = 0, symtabidx = 0; \
    for (unsigned i = 0; i < eh->e_shnum; i++) { \
      unsigned max_len = sh[eh->e_shstrndx].sh_size - sh[i].sh_name; \
      assert(sh[i].sh_name < sh[eh->e_shstrndx].sh_size); \
      assert(strnlen(shstrtab + sh[i].sh_name, max_len) < max_len); \
      sections[shstrtab + sh[i].sh_name] = sh[i].sh_addr; \
      section_length[shstrtab + sh[i].sh_name] =  sh[i].sh_size; \
      if (sh[i].sh_type & SHT_NOBITS) continue; \
      assert(size >= sh[i].sh_offset + sh[i].sh_size); \
      if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) \
        strtabidx = i; \
      if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) \
        symtabidx = i; \
    } \
    if (strtabidx && symtabidx) { \
      char* strtab = buf + sh[strtabidx].sh_offset; \
      sym_t* sym = (sym_t*)(buf + sh[symtabidx].sh_offset); \
      for (unsigned i = 0; i < sh[symtabidx].sh_size/sizeof(sym_t); i++) { \
        unsigned max_len = sh[strtabidx].sh_size - sym[i].st_name; \
        symbols[strtab + sym[i].st_name] = sym[i].st_value; \
        assert(sym[i].st_name < sh[strtabidx].sh_size); \
        assert(strnlen(strtab + sym[i].st_name, max_len) < max_len); \
      } \
    } \
  } while(0)

  if (IS_ELF32(*eh64))
    LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym);
  else
    LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym);

  munmap(buf, size);

  return &symbols;
}


<|start_filename|>simmem.h<|end_filename|>
// 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.


#ifndef __HTIF_SIMMEM_H
#define __HTIF_SIMMEM_H
#include "Variane_wrapped.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "svdpi.h"
#include "Variane_wrapped__Dpi.h"

#include <map>
#include <fesvr/htif.h>
#include <vector>
#include <string>
#include <memory>
#include <fesvr/context.h>
#include <stdio.h>
#include <queue>


class simmem_t : public htif_t
{
public:
  simmem_t(int argc, char** argv, size_t b, size_t w, size_t d);
  simmem_t(const std::vector<std::string>& args, size_t b, size_t w, size_t d);

  void set_vcd (const char *vcd_file) { this->vcd_file = vcd_file; }
  void set_label (const char *label) { this->label = label; }
  int run();
  addr_t get_tohost_address();
  addr_t get_fromhost_address();

  vluint64_t main_time;       // Current simulation time

private:
  size_t base;
  size_t width;
  size_t depth;
  std::map<addr_t,std::vector<char> > mem;

  std::queue<bool> flush_req;
  std::queue<bool> flushing;

  void flush_dcache();
  const char * vcd_file;
  const char * label;

  void read_chunk(addr_t taddr, size_t len, void* dst);
  void write_chunk(addr_t taddr, size_t len, const void* src);

  size_t chunk_max_size() { return 8; }
  size_t chunk_align() { return 8; }
  void reset() { }

  context_t* host;
  context_t target;

  // htif
  friend void sim_thread_main(void*);
  void main();
  void idle();

};

#endif // __HTIF_SIMMEM_H
