nvdla epython用于自动生成状态机编码的实例

英伟达深度学习加速器开源项目nvdla(NVIDIA Deep Learning Accelerator)中用到了一个python脚本epython。源代码地址:https://github.com/nvdla/hw/blob/master/tools/bin/epython 。epython全称embeded python utility,简单地说,就是用来预处理verilog文件中嵌入的python脚本。利用python语法的简洁性,来自动生成一些重复的、有规律的代码。

 

提出问题

我们在写Verilog代码时,状态机的编码一般是由parameter定义,如下:

​localparam IDLE  = 3'd0;
localparam START = 3'd1;
...
localparam START = 3'd7;

如果中间需要插入一个新状态,就可能要修改两部分。一是位宽可能加1,二是新插入的后面所有的状态都需要加1。

二进制、十进制、十六进制,可以利用Vim或Emacs列编辑、数据填充、格式化来重新编码。如果是格雷码或者独热码就会麻烦很多。

那么有没有一种比较简便的方法呢?

 

epython的一个应用

我们知道epython可以让verilog中嵌入python脚本,那么我们可以写一个脚本来做这个事情。

假设我们有若干个状态,用python的列表来描述就是:

st = ['IDLE', 'START', 'NEW', ‘DO_SOMETHING’, 'DONE']

那么我们是否可以仅跟据这个列表来自动产生localparam的定义呢?我们的目标是下面这个样子:

st = ['IDLE', 'START', 'NEW', 'DO_SOMETHING', 'DONE']
stat_gen()​

我的方法步骤如下:

1. 计算列表长度,也就是状态个数stat_num

2. 计算状态编码的位宽,log2(stat_num),再向上取整

3. 把0, ...,  stat_num-1进行编码转换,转成二、十、十六进制、gray、onehot等

4. 格式化输出

是不是很简单?

为了verilog中的嵌入python的简洁,我把主要的实现过程放在了python的module里,再import进来。最终手写verilog代码如下:

​//:| import vloglib
//:|  
//:| st = ['IDLE', 'FULL', 'WIN', 'PROT', 'WR_FULL', 'WR_WIN']
//:| vloglib.stat_gen(st, 'bin')
//:| 
//:) epython: generated_beg
//:) epython: generated_end
​

执行epython后,如下:

​//:| import vloglib
//:|  
//:| st = ['IDLE', 'START', 'NEW', 'DO_SOMETHING', 'DONE']
//:| vloglib.stat_gen(st, 'bin')
//:| 
//:) epython: generated_beg (DO NOT EDIT BELOW)
  localparam IDLE         = 3'b000;
  localparam START        = 3'b001;
  localparam NEW          = 3'b010;
  localparam DO_SOMETHING = 3'b011;
  localparam DONE         = 3'b100;
//:) epython: generated_end (DO NOT EDIT ABOVE)

格雷码效果如下:

//:| import vloglib
//:|  
//:| st = ['IDLE', 'START', 'NEW', 'DO_SOMETHING', 'DONE']
//:| vloglib.stat_gen(st, 'gray')
//:| 
//:) epython: generated_beg (DO NOT EDIT BELOW)
  localparam IDLE         = 3'b000;
  localparam START        = 3'b001;
  localparam NEW          = 3'b011;
  localparam DO_SOMETHING = 3'b010;
  localparam DONE         = 3'b110;
//:) epython: generated_end (DO NOT EDIT ABOVE)

独热码效果如下:

//:| import vloglib
//:|  
//:| st = ['IDLE', 'START', 'NEW', 'DO_SOMETHING', 'DONE']
//:| vloglib.stat_gen(st, 'onehot')
//:| 
//:) epython: generated_beg (DO NOT EDIT BELOW)
  localparam IDLE         = 5'b00001;
  localparam START        = 5'b00010;
  localparam NEW          = 5'b00100;
  localparam DO_SOMETHING = 5'b01000;
  localparam DONE         = 5'b10000;
//:) epython: generated_end (DO NOT EDIT ABOVE)

是不是效果还可以?

 

vloglib.py代码分析

代码如下:

import os
import sys
import re
import math
import bin2gray2bin

def stat_gen(l_stat, code='dec'):
    #calc bit width
    stat_num = len(l_stat)
    bit_width = math.ceil(math.log2(stat_num))

    #get the max lenght of strings in list
    l = [len(i) for i in l_stat]
    maxlenth = max(l)

    #print verilog code
    for i in range(len(l_stat)):
        n = '  localparam {}'.format(l_stat[i]).ljust(13 + maxlenth)
        c = ''

        if code == 'bin':
            t = '{:b}'.format(i)
            t = t.rjust(bit_width, '0')
            c = ' = {}\'b{};'.format(bit_width, t)

        elif code == 'dec':
            c = ' = {}\'d{};'.format(bit_width, i)

        elif code == 'hex':
            t = '{:x}'.format(i)
            t = t.rjust(math.ceil(bit_width/4), '0')
            c = ' = {}\'h{};'.format(bit_width, t)

        elif code == 'gray':
            t = '{:b}'.format(i)
            t = t.rjust(bit_width, '0')
            t = bin2gray2bin.bin2gray(t, bit_width)
            c = ' = {}\'b{};'.format(bit_width, t)

        elif code == 'onehot':
            if i == 0:
                t = '0' * (stat_num - 1) + '1'
            else:
                t = t[1:] + '0'
            c = ' = {}\'b{};'.format(stat_num, t)

        print(n + c)

要点:

  • math是数学库,使用了log2()和ceil()两个函数来计算位宽

  • string的ljust(len)是指定宽度len,左对齐,不足的用空格填充。len由状态字符串的最大长度决定。

  • 二、十、十六进制可以用sting.format()来格式化,再rjust(len)右对齐,填充‘0’

  • 格雷码调用了一个第三方库bin2gray2bin

  • 独热码采用字符串序列的拼接,来实现左移的效果

源码下载

下载地址:

https://github.com/chenfengrugao/vloglib

或者

git clone https://github.com/chenfengrugao/vloglib.git

 

上一篇:stat命令的实现-mysate


下一篇:字符串中的连续字符统,并将统计数字插入到原有字符串中 -- C语言