An example of nvdla ephon used to generate state machine code automatically

In NVIDIA Deep Learning Accelerator, a python script epython is used. Source code address: https://github.com/nvdla/hw/b...
Raise questions
An application of epython
vloglib.py code analysis
Source download

In NVIDIA Deep Learning Accelerator, a python script epython is used. Source code address: https://github.com/nvdla/hw/blob/master/tools/bin/epython  . The full name of ephon is embedded python utility, which is simply used to preprocess python scripts embedded in verilog files. Using the simplicity of python syntax, we can automatically generate some repetitive and regular code.

Raise questions

When we write Verilog code, the state machine code is generally defined by parameter, as follows:

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

If you need to insert a new state in the middle, you may need to modify both parts. One is that the bit width may be increased by 1, and the other is that all the States after the new insertion need to be increased by 1.

Binary, decimal and hexadecimal, which can be recoded by Vim or Emacs column editing, data filling and formatting. It would be a lot of trouble if it was gray code or single hot code.

So is there a simpler way?

An application of epython

We know that python can embed python script in verilog, so we can write a script to do this.

Suppose we have several States, which are described by python's list:

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

Can we automatically generate the definition of localparam based on this list? Our goal is to look like this:

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

My method steps are as follows:

1. Calculate the list length, that is, the number of States

2. Calculate the bit width of the state code, log2(stat_num), and then round it up

3. Convert 0,..., stat_num-1 to binary, decimal, hexadecimal, gray, onehot, etc

4. Format output

Isn't it simple?

For the simplicity of embedding python in verilog, I put the main implementation process in python module, and then import it. The final handwritten verilog code is as follows:

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

After executing ephon, it is as follows:

​//:| 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)

The effect of gray code is as follows:

//:| 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)

The effect of single hot code is as follows:

//:| 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)

Is the effect OK?

vloglib.py code analysis

The code is as follows:

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)

Main points:

  • Math is a math library, which uses two functions log2() and ceil() to calculate the bit width

  • ljust(len) of string is the specified width len, which is left aligned. If it is insufficient, it is filled with spaces. Len is determined by the maximum length of the status string.

  • 2, X. hexadecimal can be formatted with sting.format(), then right aligned with rjust(len), and filled with '0'

  • Gray code calls a third-party library bin2gray2bin

  • Single hot code uses string sequence splicing to achieve the effect of left shift

Source download

Download address:

https://github.com/chenfengrugao/vloglib

perhaps

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

ExASIC Published 6 original articles, won praise 11, visited 149 Private letter follow

5 March 2020, 00:26 | Views: 1538

Add new comment

For adding a comment, please log in
or create account

0 comments