Code Generation
Code Generation
生成代码或者小环境,我比较喜欢的方法,我总结如下。
- 用JSON格式文件控制输入变量
- 使用Template Toolkit,控制展示出来的代码样式
闲言少叙,我们举一个例子。 假设一个场景,我们需要根据很多简单的逻辑表达式,来生成一个verilog的module。
我们把这个任务划分成几部分考虑。
- 逻辑表达式需要怎么样的格式呢?
- 需要哪些变量控制我们最后生成的module的样式?
- 用怎么样的方式,把这个流程串起来,同时能便于以后的维护呢?逻辑表达式的变化,要可以重新生成代码,同时不需要手动去修改。
第一个问题,逻辑表达式需要怎么样的格式?因为我对Emacs比较情有独钟,恰好我觉得使用org-mode 来书写简单的组合逻辑特别合适。先看一下下面的贴图感受一下。
<img src="../../images/org.png" class="img-thumbnail" width="60%" >
上图是Emacs编辑器显示出来的,其实里面纯文本,是这样的:
<img src="../../images/org_text.png" class="img-thumbnail" width="60%" >
处理这个不是很复杂,可以看作对树形节点的处理。
第二个问题,需要哪些变量控制我们最后生成的module的样式?我想到的有这么几个变量,我用JSON格式写出来:
{
"prefix_name":"demo",
"org_file":"doc/demo.org",
"outputs":"ap_disp_light_sleep_req,ap_light_sleep_req"
}
可能你会说,其实可以通过命令行的option来把变量加进去一下,比如:
run.pl -prefix_name demo -org_file doc/demo.org -outputs ap_disp_light_sleep_req,ap_light_sleep_req
确实可以,但是这样我们的脚本对于option的处理不灵活,如果以后加的option更多,我们的命令也就越来越长。
第三个问题,用怎么样的方式,把这个流程串起来,同时能便于以后的维护呢?这就是核心了,Perl脚本来做这些工作。
use JSON;
use Template;
...
sub read_json {
...
}
sub template_proc {
...
}
我们的模板文件其实,比较简单:
module [% prefix_name %]_ref_model (
[%- FOREACH item IN inputs.sort %]
input [% item %],
[%- END %]
[%- cnt =0 -%]
[%- total_cnt = outputs.size %]
[%- FOREACH item IN outputs.sort %]
[%- cnt = cnt + 1 %]
[%- IF (cnt == total_cnt) %]
output wire [% item %]
[%- ELSE %]
output wire [% item %],
[%- END%]
[%- END %]
);
[%- FOREACH item IN wires.sort %]
wire [% item %];
[%- END %]
[%- FOREACH item IN lines_info_ref %]
[%- IF (item.leafs.size == 0) %]
[%- ELSE %]
assign [% item.name %] = [% item.contents.join(' ') %];
[%- END %]
[%- END %]
endmodule
perl的源代码可以来这里找 。Enjoy yourself!