首页 > 其他分享 >如何在iEDA中添加自定义Tcl命令

如何在iEDA中添加自定义Tcl命令

时间:2023-10-25 12:45:10浏览次数:44  
标签:选项 option 自定义 cmd 命令 Tcl iEDA

注:ScriptEngine 和 UserShell 头文件和实现在 iEDA/src/utility/tcl/ScriptEngine.hh 路径下

1 使用 ScriptEngine 自定义 Tcl 命令

ScriptEngine 是 Tcl 命令解析器,包含命令、命令选项、解析器等一系列工具。用户可以使用 ScriptEngine 中的接口轻松实现自定义 Tcl 命令

  1. 文件结构:

    在你的点工具下添加独立的 Tcl 命令模块便于组织文件结构,参考 iEDA/src/iSTA/sdc-cmd的组织形式:

    ~$ tree iEDA/src/iSTA/sdc-cmd/
    iEDA/src/iSTA/sdc-cmd/
    ├── CMakeLists.txt
    ├── CmdCreateClock.cc
    ├── CmdCreateGenerateClock.cc
    ...
    └── Cmd.hh
    
    0 directories, 16 files
    

    其中

    CMakeLists.txt 用于生成静态库,示例见iEDA/src/iSTA/sdc-cmd/CMakeLists.txt

    Cmd.hh 用于用户自定义命令声明,解析见2;

    CmdCreateClock.cc 等cpp文件用于实现命令。

    Build 注意事项

    1. 安装 Tcl 8.6

    在你的工作系统环境中安装 Tcl 8.6

    1. 在点工具CMakeList.txt下加入链接库

    在点工具CMakeList.txt文件中添加tcl模块需要用到的头文件和链接库 include(${PROJECT_SOURCE_DIR}/cmake/tcl.cmake);

    并添加命令模块(或者直接添加cpp文件,取决于你的构建方式);

  2. 声明用户命令类:

    命令类需继承 TclCmd类。内容可参考 iEDA/src/iSTA/sdc-cmd/Cmd.hh 或如下实例,下列代码段 8~13 行建议直接复制。

    #include "tcl/ScriptEngine.hh"
    
    namespace pcl {
    /**
     * @brief your command.
     */
    class YourCommand : public TclCmd {
     public:
      explicit YourCommand(const char* cmd_name);
      ~YourCommand() override = default;
    
      unsigned check() override;
      unsigned exec() override;
    
     private:
      // private function
      // private data 
    };
    
    }
    
  3. 命令实现:

    命令类必须实现其 构造函数check()exec()

    • 1. 构造函数

      构造函数用于添加命令的 选项(Option)参数(Arg)(均为TclOption类)。目前命令的option选项及arg参数支持 String, String List, Int, Int List, Double, Double List, Switch(选项开关) 类(均为TclOption子类)

      • 选项(Option)是一条 Tcl 命令的可选项。option 无固定的顺序,用户需要输入提示符(如示例中-divide_by)来引导option的值(如divide_factor)。另外,Switch类型的option无值(使用TclOption::is_set_val()判断选项开关);
      • 参数(Arg)是一条 Tcl 命令的必选项。开发者需要按照顺序在构造函数中添加 arg,用户需要按照相同的顺序输入参数值,无需提示符引导;

      在构造函数中添加命令选项的过程包括:1 new Tcl{Int/Double/String/...}Option("选项/参数名",0(option选项)/1(arg参数),默认值); 2 使用 addOption 传入1中生成的选项指针,以注册命令。

      iEDA/src/iSTA/sdc-cmd/CmdGetClocks.cc 为例:

    /**
     * @brief add options and args for "create_generate_clock" command
     * @usage in Tcl-shell
     * % create_generated_clock
     *     [-name clock_name]
     *     [-source master_pin]
     *     [-divide_by divide_factor | -multiply_by multiply_factor | -edges edge_list ]
     *     ...
     *     source_objects
     */
    CmdCreateGenerateClock::CmdCreateGenerateClock(const char* cmd_name): TclCmd(cmd_name) {
      // creat an int option
      // option initialization list:
      // "-divide_by" -- option name
      //       0      -- option
      //       0      -- default value
      auto* period_option = new TclIntOption("-divide_by", 0, 0);
      addOption(period_option);
      
      // ...
    
      // creat a string list arg
      // option(arg) initialization list:
      // "source_objects" -- option name
      //       1          -- arg
      //       {}         -- default value
      auto* pin_port_arg = new TclStringListOption("source_objects", 1, {});
      addOption(pin_port_arg);
    }
    
    • 2. check()

      根据命令需要,设置选项/参数的合法性检查,

      一般可通过 getOptionOrArg("选项/参数名") 获得对应的 TclOption 指针。通过调用 TclOptionis_set_val() 方法来判断此选项/参数是否被赋值,若选项/参数有值可用 TclOptionget{String/Int/Double}Val(), get{String/Int/Double}List() 方法获得相应的值。

      例如 iEDA/src/iSTA/sdc-cmd/CmdCreateGenerateClock.cc :

    /**
     * @brief The create_generate_clock cmd legally check.
     * @return 1 if all options/args are legal, 0 if not
     */
    unsigned CmdCreateGenerateClock::check() {
      // rule: "-source" and "source_objects" are required
      TclOption* source_option = getOptionOrArg("-source");
      TclOption* source_obj_option = getOptionOrArg("source_objects");
      if (!(source_option->is_set_val() && source_obj_option->is_set_val())) {
        LOG_ERROR << "'-source' 'source_objects' are missing.";
        return 0;
      }
    
      // rule: "-edges", "-divide_by", "-multiply_by" are exclusive
      TclOption* edges_option = getOptionOrArg("-edges");
      TclOption* divide_by_option = getOptionOrArg("-divide_by");
      TclOption* multiply_by_option = getOptionOrArg("multiply_by");
      unsigned period_val_count = divide_by_option->is_set_val() +
                                  multiply_by_option->is_set_val() +
                                  edges_option->is_set_val();
      if (period_val_count > 1) {
        LOG_ERROR << "'-divide_by'  '-multiply_by'  '-edges' are exclusive.";
        return 0;
      }
    
      // ...
    }
    
    • 3. exec()

      根据命令需要,实现命令逻辑。在 exec() 中应当先进行 check() 检查。获得参数值的方法通 2 中的描述,通过 getOptionOrArg("选项/参数名") 获得对应的 TclOption 指针,在确定有值(is_set_val())的情况下调用 get{String/Int/Double}Val(), get{String/Int/Double}List() 方法取得相应类型的值。

      例如 iEDA/src/iSTA/sdc-cmd/CmdCreateGenerateClock.cc :

    /**
     * @brief The create_generate_clock execute body.
     * @return 1 if execution success, 0 if not
     */
    unsigned CmdCreateGenerateClock::exec() {
      if (!check()) {
        return 0;
      }
    
      // do something ...
    
      return 1;
    }
    

2 UserShell 接入 main 函数

  1. 在main函数中添加 用户命令类 的声明:例如 #include "sdc-cmd/Cmd.hh"

  2. 定义初始化函数:初始化函数可用于注册你的命令(也可执行别的初始化语句)。初始化函数形式:参数为空,返回值为int (返回0为执行成功,返回1则不会打开tcl解释器)。可使用registerTclCmd(命令类名,命令string)宏快速注册自定义命令。

  3. 向UserShell中添加步骤2中的初始化函数,此初始化函数将会在 Tcl 解释器运行前执行初始化,否则将无法运行用户自定义命令

  4. 使用userMain打开Tcl解释器,若参数为文件路径,则执行并退出;若参数为nullptr,将打开可交互的Tcl命令行,可用于Tcl命令输入执行

// 示例文件:iEDA/src/iSTA/main.cc
// 1.在main函数中添加用户命令类的声明
#include "sdc-cmd/Cmd.hh"
#include "shell-cmd/ShellCmd.hh"
#include "tcl/UserShell.hh"

using namespace pcl;

// 2.定义初始化函数:初始化函数可用于注册你的命令。初始化函数形式:参数为空,返回值为int (返回0为执行成功,返回1则不会打开tcl解释器)
int registerCommands() {
  // 可使用 registerTclCmd(命令类名,命令string) 宏快速注册自定义命令
  registerTclCmd(CmdReadVerilog, "read_verilog");
  // ...
  registerTclCmd(CmdGetPins, "get_pins");

  return EXIT_SUCCESS;
}

int main(int argc, char** argv) {
  auto shell = UserShell::getShell();
  // 3.向UserShell中添加步骤2中的初始化函数,此初始化函数将会在 Tcl 解释器运行前执行初始化,否则将无法运行用户自定义命令
  shell->set_init_func(registerCommands);

  // get Tcl file path from main args
  char* tcl_file_path = nullptr;
  if (argc == 2) {
    tcl_file_path = argv[1];
  } else {
    shell->displayHelp();
  }

  // 4.使用userMain打开Tcl解释器,若参数为文件路径,则执行并退出;若参数为nullptr,将打开可交互的Tcl命令行,可用于Tcl命令输入执行
  shell->userMain(tcl_file_path);
}

常见 BUG

  1. 命令/选项明明已经注册了,但提示命令没找到/获取选项值出现core dump

    命令没找到:检查Tcl初始化函数中,命令名是否与输入的命令名相符

    选项出现core dump:检查在命令构造函数中注册选项时选项名是否正确,检查使用命令时getOptionOrArg 的选项名是否正确

  2. 有待提供...

标签:选项,option,自定义,cmd,命令,Tcl,iEDA
From: https://www.cnblogs.com/harrypotterisdead/p/17786896.html

相关文章

  • uniapp 预览pdf app端使用自定义导航时铺满全屏,需要留出导航栏
    1、安装pdf预览插件:hybrid插件(网上资料很多) 2、封装预览vue页面(重点在加粗部分,使用原生导航没有问题,但是使用自定义导航就把状态栏全部盖住了)<template><viewclass="page"><web-view:webview-styles="webviewStyles":src="src"></web-view>&l......
  • 微信小程序--5. 如下图将顶部导航栏的地方改成自定义样式
    5.如下图将顶部导航栏的地方改成自定义样式1)配置app.json{"window":{"navigationStyle":"custom"//增加这行}} 2)、封装顶部导航栏的样式创建组件文件夹及文件miniprogram\components\navigation-bar\index//components/navigation-bar/index.wxml<!......
  • 基于mutation的自定义指令以监听用户使用f12修改dom
    昨天写了功能后,就又封了一个指令,可以直接应用于ui框架的input组件上贴贴:preventChange/index.jsexportconstpreventChange={inserted(el,binding){constelTag=el.tagName.toLowerCase();//获取当前dom下类型为password的input标签constpasswordI......
  • LambdaUpdateWrapper 自定义修改
    当我们想要在原有的数据上添加新的数据的时候,我们需要一个更新操作,但是<Iservice>接口一般是根据ID进行修改当我们需要根据指定的条件设置值时,就需要自己写SQL但是这个办法会出现SQL错误并且很麻烦所以我们可以自定义一个wrapper来进行修改。 这是全部的代码 这是我们要......
  • 【ChatGPT系列】Python自定义打印各种颜色的日志
    如何在控制台和文件中同时输出日志?要将日志同时输出到文件和控制台,可以创建并配置一个额外的StreamHandler,然后将其添加到Logger中。下面是一个示例代码,演示如何将日志同时输出到文件和控制台:importlogging#创建Logger对象logger=logging.getLogger("example_logger")......
  • IEDA-Maven项目开发步骤
    1. 打开IDEA界面,选择“NewProject” 2. 输入项目名称和基本信息输入项目名称、选择存放路径、JDK版本、以及GroupId、ArtifactId。GroupID:是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构。GroupID定义了项目属于哪个组,举个例子,如果你的公......
  • Java:自定义实现SpringBoot Starter
    (目录)1、自定义Starter1.1、项目结构$tree.├──pom.xml└──src├──main│├──java││└──com││└──example││└──demo││├──ReadingConfiguration.java......
  • grafana 配置自定义dashboard
    本文为博主原创,转载请注明出处:1.配置数据源         配置完成后,点击SaveAndTest,如果配置正确,页面则显示如下:           2.配置dashboard          点击Addnewpanel后,界面如下:       ......
  • 记录EF 排序配上自定义的比较器
    记录EF排序配上自定义的比较器前言要求页面文件显示的时候能够按照序号去排序要求如下:数据库有一个列存放文件名,如:1.1文件1.2文件1.1.1文件1.1.11文件1.0.txt1.1.2(文件).pdf现在需要实现查询的时候按照这个列排序,并且是按照序号排序。查询的时候是按层级查询的,每次查......
  • IDEA工具第二篇:自定义Java方法注释模板
    网上搜索类似的文章有很多,但是一味的复制粘贴总会出现各种奇葩问题,最后然并卵!今天特意自己研究琢磨一下,将最终结果分享给大家,100%亲测可用。一、说明想必大家都用过Eclipse的方法注释生成,方法上输入/**,回车走你,巴拉巴拉如下的注释便生成了,今天就悄悄告诉大家如何自定义这样的模......