如何批量化生成代码

RT, 写Verilog的时候要写类似于下面这种重复的代码段(其实就是生成一些重复的硬件)。是否有能够方便在Emacs内地生成这种格式化的代码的方法(也许类似于正则表达式)。现在的方案是使用Mathematica生成后复制过来,但是和Emacs契合度不够。

                   case(write_ptr)
                         5'd0 : memory[0] <= data_w;
                         5'd1 : memory[1] <= data_w;
                         5'd2 : memory[2] <= data_w;
                         5'd3 : memory[3] <= data_w;
                         5'd4 : memory[4] <= data_w;
                         5'd5 : memory[5] <= data_w;
                         5'd6 : memory[6] <= data_w;
                         5'd7 : memory[7] <= data_w;
                         5'd8 : memory[8] <= data_w;
                         5'd9 : memory[9] <= data_w;
                         5'd10 : memory[10] <= data_w;
                         5'd11 : memory[11] <= data_w;
                         5'd12 : memory[12] <= data_w;
                         5'd13 : memory[13] <= data_w;
                         5'd14 : memory[14] <= data_w;
                         5'd15 : memory[15] <= data_w;
                         5'd16 : memory[16] <= data_w;

好像道友中写Verilog的不是很多。这个的主要需求是用在case语句中给一片连续内存单元赋值,需要能够做到生成从0~n的格式化代码,n同时最好能有各种进制转换及用0补齐到k位(主要是2进制和16进制转换,同时保证位对齐)。例如希望的效果是

  5'b00000 : memory[0] <= data_w; //输入第一行

xxxxx操作后:

 5'b00000 : memory[0] <= data_w;
 5'b00001 : memory[1] <= data_w;
 5'b00010 : memory[2] <= data_w;
 5'b00011 : memory[3] <= data_w;
 5'b00100 : memory[4] <= data_w;
 5'b00101 : memory[5] <= data_w;
 5'b00110 : memory[6] <= data_w;
......
 5'b01000 : memory[16] <= data_w;

通过宏录制/verilog生成索引号/tiny可以很好地生成索引。假如能有类似于正则表达式这种更加完备且简约的生成方式就更赞了(其实是录制宏经常会误操作)。

I use tiny.

m0\n16|5'd%d : memory[%d] <= data_w;

5'd0 : memory[0] <= data_w;
5'd1 : memory[1] <= data_w;
5'd2 : memory[2] <= data_w;
5'd3 : memory[3] <= data_w;
5'd4 : memory[4] <= data_w;
5'd5 : memory[5] <= data_w;
5'd6 : memory[6] <= data_w;
5'd7 : memory[7] <= data_w;
5'd8 : memory[8] <= data_w;
5'd9 : memory[9] <= data_w;
5'd10 : memory[10] <= data_w;
5'd11 : memory[11] <= data_w;
5'd12 : memory[12] <= data_w;
5'd13 : memory[13] <= data_w;
5'd14 : memory[14] <= data_w;
5'd15 : memory[15] <= data_w;
5'd16 : memory[16] <= data_w;
2 个赞

其实 Emacs 自带的键盘宏就可以用计数器。

  • F3,输入 5'd
  • F3,会插入一个 0。把这个数字复制一下。
  • 继续输入到 memory[, 粘贴刚复制的数字。
  • 输入完整行,回车,按 F4
  • 一直按 F4
6 个赞

这个还有进制转换功能吗,好赞。

这个方法也很赞,看来要学习一下Emacs录制宏的各种技巧了。

FYI

用emacs macro貌似还可以这样玩:

  • F3, 输入 5'd [counter=0]
  • F3 插入 0 [counter=1]
  • 继续输入到 memory[, 按 C-u C-x C-k C-c [counter=0]
  • F3 插入 0 [counter=1]
  • 输入完整行,回车,按 F4
1 个赞

也可以用awk写个命令

1 个赞

还可以写一个复制替换上一行并粘贴的command

最好把需求的input output说一下,比如我猜测这里是“输入16,生成17行,每行上写0~16”。

回答:one-off的就用keyboard macro,思路是

  • 先写好第一行
  • 开始录制
  • 复制,移动到下一行,修改:得到第二行
  • 结束录制
  • 播放*n

如果隔两天就要输入这段,就用snippet,yasnippet支持动态执行elisp,想干啥都行。

1 个赞

verilog-mode 有个生成索引号的func啊 如图

3 个赞

我会直接选择M-: (eval-expression),然后输入

(dotimes (i 17)
  (insert (format "5'd%d : memory[%d] <= data_w;\n" i i)))

这种方式最灵活。

如果嫌minibuffer里输入比较麻烦,实际上也可以直接在对应的源文件里直接写elisp代码,然后C-x C-e (eval-last-sexp) 就行了,它会直接输入在当前的buffer里。

2 个赞

学到了,看来玩法很多啊,不过最简单的还是录制宏的方式解决当前的问题。

你是不是不知道 Verilog 有 generate block。