一、Openroad的函数入口

  • openroad中主要的功能模块都放在OpenROAD/src目录下,其内部模块都实现某一种功能,详细模块功能介绍可以去看这篇博文:https://www.cnblogs.com/shuaizhenmian/p/18849723
  • openroad这个项目github有个整合,可以从芯片的逻辑综合阶段一直到GDSII文件生成,其github地址:https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts
  • openroad其流程如下图所示:
  • 上述图中openroad所进行的阶段只有Floorplan -> Route阶段
  • openroad编译完成后,其执行文件地址在OpenRoad/build/src/openroad,编译后未执行安装的用户,可以在~/.bashrc中设置环境变量后,可以直接执行openroad即可。
  • 其所在的Main函数入口便在OpenROAD/src/Main.cc文件中的 int main(int argc, char* argv[])

二、openroad的初始化源码解析

  • 1.统一程序的本地化设置,确保数值解析、时间格式等行为在不同系统环境能够保持一致
      std::array locales = {"en_US.UTF-8", "C.UTF-8", "C"};
      for (auto locale : locales) {
        if (std::setlocale(LC_ALL, locale) != nullptr) {
          setenv("LC_ALL", locale, /* override */ 1);
          break;
        }
      }
  • 2.设置信号处理函数,其作用是为了记录程序发生错误是的信息
    signal(SIGABRT, handler); //触发场景:内存分配失败,断言以及不可恢复的内部错误
    signal(SIGBUS, handler);  //触发场景:访问未物理映射的内存区域以及内存对其错误,硬件设备访问异常
    signal(SIGFPE, handler);  //整数除零,浮点运算一产(无穷打),位操作溢出
    signal(SIGILL, handler);  //执行cpu不支持的命令,代码段损坏,跳转到非代码段
    signal(SIGSEGV, handler); //解引用空指针,数组访问越界,栈溢出(递归过深,或者是耗尽栈空间)

    static void handler(int sig)  //handle处理函数
    {
      if (fatal_error_in_progress) {
        raise(sig);
      }                                      //目的‌:通过静态变量fatal_error_in_progress标记“正在处理崩溃”,避免处理信号期间再次触发其他信号导致无限递归。‌逻辑‌:若标记已置位,直接重新发送信号(raise(sig))触发系统默认处理流程。
      fatal_error_in_progress = 1;

      std::cerr << "Signal " << sig << " received\n"; //打印触发崩溃的具体信号编号(如SIGSEGV对应11),明确错误类型。

      std::cerr << "Stack trace:\n";
      std::cerr << boost::stacktrace::stacktrace(); //使用Boost库的stacktrace模块输出当前线程的完整调用栈。

      signal(sig, SIG_DFL);     //signal(sig, SIG_DFL)将信号处理重置为系统默认行为(如SIGSEGV默认终止进程并生成core dump)。
      raise(sig);            //raise(sig)主动发送信号,此时系统按默认方式终止进程。
    }
    
  • 3.tclMian函数
    if (argc == 2 && stringEq(argv[1], "-help")) {
      showUsage(argv[0], init_filename);
      return 0;
    }  //hlep option终端打印可以使用的option信息
    if (argc == 2 && stringEq(argv[1], "-version")) {
      printf("%s %s\n",
             ord::OpenRoad::getVersion(),
             ord::OpenRoad::getGitDescribe());
      return 0;
    }  //获取openroad版本号以及git描述信息

    log_filename = findCmdLineKey(argc, argv, "-log");
    if (log_filename) {
      remove(log_filename);
    }  //log地址重置

    metrics_filename = findCmdLineKey(argc, argv, "-metrics");
    if (metrics_filename) {
      remove(metrics_filename);
    }  //未知

    no_settings = findCmdLineFlag(argc, argv, "-no_settings");
    minimize = findCmdLineFlag(argc, argv, "-minimize");

    cmd_argc = argc;  //参数个数
    cmd_argv = argv; //传递终端参数数组指针

    Tcl_Main(1, argv, ord::tclAppInit);  //tcl处理函数
    
  • 4.tclAppInit
      int ord::tclAppInit(Tcl_Interp* interp)
      {
        the_tech_and_design.tech = std::make_unique<ord::Tech>(interp);
        the_tech_and_design.design
            = std::make_unique<ord::Design>(the_tech_and_design.tech.get());
        ord::OpenRoad::setOpenRoad(the_tech_and_design.design->getOpenRoad()); //初始化构造tech这个单例类,tech类中构造openroad

        // This is to enable Design.i where a design arg can be
        // retrieved from the interpreter.  This is necessary for
        // cases with more than one interpreter (ie more than one Design).
        // This should replace the use of the singleton OpenRoad::openRoad().
        Tcl_SetAssocData(interp, "design", nullptr, the_tech_and_design.design.get());//将自定义c++数据结构在tcl解析器中与design字符串绑定,可以使得tcl获取简单的oop功能(如:$design get_core_area)

        return ord::tclInit(interp);
      }

      int ord::tclInit(Tcl_Interp* interp)
      {
        return tclAppInit(cmd_argc, cmd_argv, init_filename, interp); //上一个函数返回值的中转
      }
  
      static int tclAppInit(int& argc,
                      char* argv[],
                      const char* init_filename,
                      Tcl_Interp* interp)
      {
        bool exit_after_cmd_file = false;
        // first check if gui was requested and launch.
        // gui will call this function again as part of setup
        // ensuring the else {} will be utilized to initialize tcl and OR.
        if (findCmdLineFlag(argc, argv, "-gui")) {
          // gobble up remaining -gui flags if present, since this could result in
          // second invocation of the GUI
          while (findCmdLineFlag(argc, argv, "-gui")) {
            ;
          }

          gui::startGui(argc, argv, interp, "", true, !no_settings, minimize); //开启gui功能
        } else {  //不开启gui功能
          // init tcl
          if (Tcl_Init(interp) == TCL_ERROR) {
            return TCL_ERROR;
          }
          exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");

          ord::initOpenRoad(interp, log_filename, metrics_filename);

          bool no_splash = findCmdLineFlag(argc, argv, "-no_splash");
          if (!no_splash) {
            showSplash();  //显示openroad终端的tile说明
          }
          
          //线程数目设置
          const char* threads = findCmdLineKey(argc, argv, "-threads");
          if (threads) {
            ord::OpenRoad::openRoad()->setThreadCount(threads, !no_splash);
          } else {
            // set to default number of threads
            ord::OpenRoad::openRoad()->setThreadCount(
                ord::OpenRoad::openRoad()->getThreadCount(), false);
          }

          const bool gui_enabled = gui::Gui::enabled();

          if (argc > 2 || (argc > 1 && argv[1][0] == '-')) {
            showUsage(argv[0], init_filename);
            exit(1);
          } else {
            if (argc == 2) {
              char* cmd_file = argv[1];
              if (cmd_file) {
                if (!gui_enabled) {
                  int result = sourceTclFile(cmd_file, false, false, interp); //执行tcl文件,其底层是使用tcl来解析tcl文件,相当于source tclfile命令
                  if (exit_after_cmd_file) {
                    int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
                    exit(exit_code);
                  }
                } else {
                  // need to delay loading of file until after GUI is completed
                  // initialized
                  gui::Gui::get()->addRestoreStateCommand(
                      fmt::format("source {{{}}}", cmd_file));
                  if (exit_after_cmd_file) {
                    gui::Gui::get()->addRestoreStateCommand("exit");
                  }
                }
              }
            }
          }
        }
      #ifdef ENABLE_READLINE  //循环读入终端输入命令
        if (!gui::Gui::enabled() && !exit_after_cmd_file) {
          return tclReadlineInit(interp);
        }
      #endif
        return TCL_OK;
    
posted on 2025-04-28 17:43  shuaizhenmian  阅读(340)  评论(0)    收藏  举报