vpi_session.cc 6.87 KB
Newer Older
1 2 3 4 5 6
/*!
 *  Copyright (c) 2017 by Contributors
 * \file vpi_session.cc
 * \brief IPC session call to verilog simulator via VPI.
 */
#include <tvm/api_registry.h>
7
#include <memory>
8
#include "vpi_session.h"
9 10 11 12 13 14

namespace tvm {
namespace codegen {

using namespace vpi;

15 16
// helper class to get the node.
class VPISessionEntry {
17 18 19 20 21 22 23
 public:
  // Whether in control.
  bool in_control{false};
  // Internal reader and writer.
  common::Pipe reader;
  common::Pipe writer;
  // internal constructor
24
  VPISessionEntry(int h_pipe_read, int h_pipe_write)
25 26
      : reader(h_pipe_read), writer(h_pipe_write) {
  }
27
  ~VPISessionEntry() {
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
    if (in_control) {
      VPIReturnCode cd;
      writer.Write(kShutDown);
      reader.Read(&cd);
    }
    reader.Close();
    writer.Close();
  }
  void ReadExpect(VPIReturnCode rcode) {
    VPIReturnCode code;
    CHECK(reader.Read(&code));
    CHECK_EQ(code, rcode) << "Error in simulation";
  }
};

// Inline implementations
inline VPISessionNode* VPISession::get() const {
  return static_cast<VPISessionNode*>(node_.get());
}
inline VPIHandleNode* VPIHandle::get() const {
  return static_cast<VPIHandleNode*>(node_.get());
}

51 52 53
VPIHandle VPIHandleCreate(
    const std::shared_ptr<VPISessionEntry>& sess,
    VPIRawHandle handle) {
54
  auto n = make_node<VPIHandleNode>();
55 56 57
  n->sess = sess;
  n->handle = handle;
  return VPIHandle(n);
58 59
}

60 61 62 63 64 65
VPIHandle GetHandleByName(
    const std::shared_ptr<VPISessionEntry>& sess,
    const std::string& name,
    VPIRawHandle handle,
    bool allow_undefined) {
  VPISessionEntry* n = sess.get();
66 67 68 69 70 71
  CHECK(n->in_control);
  n->writer.Write(kGetHandleByName);
  n->writer.Write(name);
  n->writer.Write(handle);
  n->ReadExpect(kSuccess);
  CHECK(n->reader.Read(&handle));
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  if (handle != nullptr) {
    return VPIHandleCreate(sess, handle);
  } else {
    CHECK(allow_undefined)
        << "Cannot find handle with name=" << name;
    return VPIHandle();
  }
}

std::string VPIGetStrProp(VPIHandleNode* h, int code) {
  VPISessionEntry* n = h->sess.get();
  CHECK(n->in_control);
  n->writer.Write(kGetStrProp);
  n->writer.Write(code);
  n->writer.Write(h->handle);
  n->ReadExpect(kSuccess);
  std::string str;
  CHECK(n->reader.Read(&str));
  return str;
}

int VPIGetIntProp(VPIHandleNode* h, int code) {
  VPISessionEntry* n = h->sess.get();
  CHECK(n->in_control);
  n->writer.Write(kGetIntProp);
  n->writer.Write(code);
  n->writer.Write(h->handle);
  n->ReadExpect(kSuccess);
  int value;
  CHECK(n->reader.Read(&value));
  return value;
}

VPISession VPISession::make(int h_pipe_read, int h_pipe_write) {
106
  auto n = make_node<VPISessionNode>();
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
  n->sess = std::make_shared<VPISessionEntry>(h_pipe_read, h_pipe_write);
  n->sess->in_control = true;
  VPISession sess(n);
  // The custom module handles
  std::vector<VPIRawHandle> mod_handles;
  n->sess->reader.Read(&mod_handles);
  n->sess->ReadExpect(kPosEdgeTrigger);
  // start Initialize the callbacks
  for (VPIRawHandle raw_h : mod_handles) {
    VPIHandle h = VPIHandleCreate(n->sess, raw_h);
    CHECK_EQ(VPIGetIntProp(h.get(), kVPIType), kVPIModule)
        << "Expect pass modules to $tvm_session after clk";
    std::string def = VPIGetStrProp(h.get(), kVPIDefName);
    std::string callback_name = "_vpi_module_" + def;
    const PackedFunc* f = runtime::Registry::Get(callback_name);
    CHECK(f != nullptr)
        << "Cannot find definition for tvm vpi module " << def;
    PackedFunc cb = (*f)(h);
    n->posedge_end_callbacks.push_back(cb);
  }
  return sess;
}

VPIHandle VPISession::operator[](const std::string& name) const {
  return GetHandleByName(get()->sess, name, nullptr, false);
}
VPIHandle VPISession::GetByName(const std::string& name,
                                bool allow_undefined) const {
  return GetHandleByName(get()->sess, name, nullptr, true);
136 137 138
}

void VPISession::yield() {
139
  VPISessionEntry* n = get()->sess.get();
140
  CHECK(n->in_control);
141 142 143
  for (const PackedFunc& f : get()->posedge_end_callbacks) {
    f();
  }
144 145 146 147 148 149 150 151
  n->writer.Write(kYield);
  n->ReadExpect(kSuccess);
  n->in_control = false;
  n->ReadExpect(kPosEdgeTrigger);
  n->in_control = true;
}

void VPISession::shutdown() {
152
  VPISessionEntry* n = get()->sess.get();
153 154 155 156 157 158 159 160
  if (n->in_control) {
    n->writer.Write(kShutDown);
    n->ReadExpect(kSuccess);
    n->in_control = false;
  }
}

int VPIHandle::size() const {
161
  return VPIGetIntProp(get(), kVPISize);
162 163 164 165
}

void VPIHandle::put_int(int value) {
  VPIHandleNode* h = get();
166
  VPISessionEntry* n = h->sess.get();
167 168 169 170 171 172 173 174 175
  CHECK(n->in_control);
  n->writer.Write(kPutInt32);
  n->writer.Write(h->handle);
  n->writer.Write(value);
  n->ReadExpect(kSuccess);
}

int VPIHandle::get_int() const {
  VPIHandleNode* h = get();
176
  VPISessionEntry* n = h->sess.get();
177 178 179 180 181 182 183 184 185 186
  CHECK(n->in_control);
  n->writer.Write(kGetInt32);
  n->writer.Write(h->handle);
  n->ReadExpect(kSuccess);
  int value;
  CHECK(n->reader.Read(&value));
  return value;
}

std::string VPIHandle::name() const {
187
  return VPIGetStrProp(get(), kVPIFullName);
188 189 190 191
}

void VPIHandle::put_vec(const std::vector<VPIVecVal>& vec) const {
  VPIHandleNode* h = get();
192
  VPISessionEntry* n = h->sess.get();
193 194 195 196 197 198 199 200 201
  CHECK(n->in_control);
  n->writer.Write(kPutVec);
  n->writer.Write(h->handle);
  n->writer.Write(vec);
  n->ReadExpect(kSuccess);
}

void VPIHandle::get_vec(std::vector<VPIVecVal>* vec) const {
  VPIHandleNode* h = get();
202
  VPISessionEntry* n = h->sess.get();
203
  CHECK(n->in_control);
204
  n->writer.Write(kGetVec);
205 206
  n->writer.Write(h->handle);
  n->ReadExpect(kSuccess);
207
  CHECK(n->reader.Read(vec));
208 209 210 211
}

VPIHandle VPIHandle::operator[](const std::string& name) const {
  VPIHandleNode* h = get();
212
  return GetHandleByName(h->sess, name, h->handle, false);
213 214 215
}

// API registration
216
TVM_REGISTER_API("_vpi_SessMake")
217 218 219 220
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = VPISession::make(args[0], args[1]);
  });

221
TVM_REGISTER_API("_vpi_SessGetHandleByName")
222 223 224 225
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = args[0].operator VPISession().operator[](args[1]);
  });

226
TVM_REGISTER_API("_vpi_SessYield")
227 228 229 230
.set_body([](TVMArgs args, TVMRetValue *ret) {
    args[0].operator VPISession().yield();
  });

231
TVM_REGISTER_API("_vpi_SessShutdown")
232 233 234 235
.set_body([](TVMArgs args, TVMRetValue *ret) {
    args[0].operator VPISession().shutdown();
  });

236
TVM_REGISTER_API("_vpi_HandlePutInt")
237 238 239 240
.set_body([](TVMArgs args, TVMRetValue *ret) {
    args[0].operator VPIHandle().put_int(args[1]);
  });

241
TVM_REGISTER_API("_vpi_HandleGetInt")
242 243 244 245
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = args[0].operator VPIHandle().get_int();
  });

246
TVM_REGISTER_API("_vpi_HandleGetName")
247 248 249 250
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = args[0].operator VPIHandle().name();
  });

251
TVM_REGISTER_API("_vpi_HandleGetSize")
252 253 254 255
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = args[0].operator VPIHandle().size();
  });

256
TVM_REGISTER_API("_vpi_HandleGetHandleByName")
257 258 259 260 261 262
.set_body([](TVMArgs args, TVMRetValue *ret) {
    *ret = args[0].operator VPIHandle().operator[](args[1]);
  });

}  // namespace codegen
}  // namespace tvm