codegen_verilog.h 6.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 106 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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/*!
 *  Copyright (c) 2017 by Contributors
 * \file codegen_verilog.h
 * \brief Generate verilog code.
 */
#ifndef TVM_CODEGEN_VERILOG_CODEGEN_VERILOG_H_
#define TVM_CODEGEN_VERILOG_CODEGEN_VERILOG_H_

#include <tvm/base.h>
#include <tvm/ir.h>
#include <tvm/ir_functor_ext.h>
#include <tvm/codegen.h>
#include <tvm/lowered_func.h>
#include <string>
#include <vector>
#include <unordered_map>
#include "./verilog_ir.h"
#include "../codegen_source_base.h"

namespace tvm {
namespace codegen {
namespace verilog {
using namespace ir;

/* \brief The variable type in register.*/
enum VerilogVarType {
  kWire,
  kInput,
  kOutput,
  kReg,
  kConst
};

/*! \brief The verilog value */
struct VerilogValue {
  /*! \brief The variable id */
  std::string vid;
  /*! \brief The variable type */
  VerilogVarType vtype{kReg};
  /*! \brief The data type it encodes */
  Type dtype;
  VerilogValue() {}
  VerilogValue(std::string vid, VerilogVarType vtype, Type dtype)
      : vid(vid), vtype(vtype), dtype(dtype) {}
};

/*! \brief Information of each procedure function generated */
struct VerilogFuncEntry {
  /*! \brief The original functions */
  std::vector<Type> arg_types;
  /*! \brief The real argument ids of the function */
  std::vector<std::string> arg_ids;
  /*! \brief The VPI Modules in the function */
  std::vector<std::string> vpi_modules;
};

/*!
 * \brief The code module of generated verilog code.
 */
class VerilogCodeGenModule {
 public:
  /*! \brief the code of each modoules */
  std::string code;
  /*! \brief map of functions */
  std::unordered_map<std::string, VerilogFuncEntry> fmap;
  /*!
   * \brief Generate a code that append simulator function to call func_name.
   * \param func_name The function to be called.
   * \return The generated code.
   */
  std::string AppendSimMain(const std::string& func_name) const;
};

/*!
 * \brief Verilog generator
 */
class CodeGenVerilog :
      public ExprFunctor<VerilogValue(const Expr&)>,
      public CodeGenSourceBase {
 public:
  /*!
   * \brief Initialize the code generator.
   * \param output_ssa Whether output SSA.
   */
  void Init();
  /*!
   * \brief Add the function to the generated module.
   * \param f The function to be compiled.
   */
  void AddFunction(LoweredFunc f);
  /*!
   * \brief Finalize the compilation and return the code.
   * \return The code.
   */
  VerilogCodeGenModule Finish();
  /*!
   * \brief Transform expression to verilog value.
   * \param n The expression to be printed.
   */
  VerilogValue MakeValue(const Expr& n) {
    return VisitExpr(n);
  }
  // The following parts are overloadable print operations.
  // expression
  VerilogValue VisitExpr_(const Variable* op) final;
  VerilogValue VisitExpr_(const Let* op) final;
  VerilogValue VisitExpr_(const Call* op) final;
  VerilogValue VisitExpr_(const Add* op) final;
  VerilogValue VisitExpr_(const Sub* op) final;
  VerilogValue VisitExpr_(const Mul* op) final;
  VerilogValue VisitExpr_(const Div* op) final;
  VerilogValue VisitExpr_(const Mod* op) final;
  VerilogValue VisitExpr_(const Min* op) final;
  VerilogValue VisitExpr_(const Max* op) final;
  VerilogValue VisitExpr_(const EQ* op) final;
  VerilogValue VisitExpr_(const NE* op) final;
  VerilogValue VisitExpr_(const LT* op) final;
  VerilogValue VisitExpr_(const LE* op) final;
  VerilogValue VisitExpr_(const GT* op) final;
  VerilogValue VisitExpr_(const GE* op) final;
  VerilogValue VisitExpr_(const And* op) final;
  VerilogValue VisitExpr_(const Or* op) final;
  VerilogValue VisitExpr_(const Cast* op) final;
  VerilogValue VisitExpr_(const Not* op) final;
  VerilogValue VisitExpr_(const Select* op) final;
  VerilogValue VisitExpr_(const Ramp* op) final;
  VerilogValue VisitExpr_(const Broadcast* op) final;
  VerilogValue VisitExpr_(const IntImm* op) final;
  VerilogValue VisitExpr_(const UIntImm* op) final;
  VerilogValue VisitExpr_(const FloatImm* op) final;
  VerilogValue VisitExpr_(const StringImm* op) final;

 protected:
  void InitFuncState(LoweredFunc f);
  void PrintDecl(const std::string& vid, VerilogVarType vtype, Type dtype,
                 const char* suffix = ";\n", bool indent = true);
  void PrintAssign(
      const std::string& target, const std::string& src);
  void PrintAssignAnd(
      const std::string& target, const std::vector<std::string>& conds);
  void PrintLine(const std::string& line);
  void PrintSSAAssign(
      const std::string& target, const std::string& src, Type t) final;
  // make binary op
  VerilogValue MakeBinary(Type t, VerilogValue a, VerilogValue b, const char* opstr);

 private:
  // Hand shake signal name.
  // These name can be empty.
  // Indicate that the signal is always true
  // or do not need to take these signals.
  struct SignalEntry {
    std::string valid;
    std::string ready;
  };
  // Information about port
  struct PortEntry {
    // The port value
    std::string value;
    // The data type
    Type dtype;
  };
  // Channel setup
  struct ChannelEntry {
    // The channel block
    ChannelBlock block;
    // The port map, on how port is assigned.
    std::unordered_map<std::string, PortEntry> ports;
    // Assign port to be valueo
    void AssignPort(std::string port, std::string value, Type dtype);
    // Assign port to be valueo
    const PortEntry& GetPort(const std::string& port) const;
    // Signal port name
    std::string SignalPortName(int index) const;
  };

  // Get wire ssa value from s
  VerilogValue GetSSAValue(std::string s, Type dtype) {
    VerilogValue ret;
    ret.vid = SSAGetID(s, dtype);
    ret.vtype = kWire;
    ret.dtype = dtype;
    return ret;
  }
  void CodeGen(const Pipeline& pipeine);
  // codegen the delays
  void MakeDelay(const std::string& dst,
                 const std::string& src,
                 Type dtype,
                 int delay,
                 const std::string& not_stall);
  // codegen the loop macros
  SignalEntry MakeLoop(const Array<Stmt>& loop);
  // codegen the loop macros
  void MakeStageInputs(const ComputeBlock& block,
                       const std::string& not_stall,
                       std::string* out_all_input_valid);
  // codegen compute block
  void MakeStore(const ComputeBlock& block, const Store* store);
  // Codegen of load statement into FIFO
  void MakeLoadToFIFO(const ComputeBlock& block,
                      const Store* store,
                      const Load* load);
  // Make channel unit.
  void MakeChannelUnit(const ChannelEntry& ch);
  void MakeChannelFIFO(const ChannelEntry& ch);
  void MakeChannelBuffer(const ChannelEntry& ch);
  void MakeChannelMemMap(const ChannelEntry& ch);
  // Get channel information
  ChannelEntry* GetChannelInfo(const Variable* var);
  // channel setup map.
  std::unordered_map<const Variable*, ChannelEntry> cmap_;
  // list of vpi modules to be hooked.
  std::vector<std::string> tvm_vpi_modules_;
  // The signals for done.
  std::vector<std::string> done_sigs_;
  // The verilog function.
  std::unordered_map<std::string, VerilogFuncEntry> functions_;
};
}  // namespace verilog
}  // namespace codegen
}  // namespace tvm
#endif  // TVM_CODEGEN_VERILOG_CODEGEN_VERILOG_H_