VerilogA 数字序列波形发生器

基于ColsonZhang/VerilogA-Wave-Generator库进行改进:

在此感谢原作者,提供了生成波形的思路和代码。

 本版本具体改进点如下:

1.波形播放完后不再重复播放,而是停在最后一个码字

2.增加了可配置的上升时间和下降时间

 使用方法:

1.将以下三个文件保存到同一文件夹,并安装python 3.6.

2.编辑main.py,在 signal_args 数组中输入序列名字,序列宽度,序列长度,和序列数据,可以同时修改模块名(module_name)

3.在当前目录下运行python main.py 得到generate.va文件

4.将该va导入到virtuoso或其他仿真环境中使用 

 

CLK 代表时钟输入端,该veriloga模块每一个时钟周期输出一个码字,应接一个vpluse源

VDD代表电源输入 ,定义了输出波形的高电平,应接一个vdc源。

GND代表电源地,应接GND。

注意:使用时请保证CLK端的高电平标准和VDD端的高电平标准一致,均为同一电压值。

 

代码如下:

 template.va

// $TEMPLATE_HEAD_NOTES

`include "constants.vams"
`include "disciplines.vams"

module $TEMPLATE_MODULE_NAME(VDD, GND, CLK, $TEMPLATE_PORT_LIST);
    input VDD, GND, CLK ;
    electrical VDD, GND, CLK ;

$TEMPLATE_INPUT_DECLARATION

$TEMPLATE_OUTPUT_DECLARATION


$TEMPLATE_SIGNAL_DECLARATION
    
$TEMPLATE_COUNT_DECLARATION

$TEMPLATE_WAVELIST_DECLARATION


    integer count = 0;
    integer clock = 0;
    integer flag_clk ;
    
    genvar i ;

//       ___                   __                                         
//      /\_ \                 /\ \                                        
//   ___\//\ \     ___     ___\ \ \/'\               __      __    ___    
//  /'___\\ \ \   / __`\  /'___\ \ , <    _______  /'_ `\  /'__`\/' _ `\  
// /\ \__/ \_\ \_/\ \L\ \/\ \__/\ \ \\`\ /\______\/\ \L\ \/\  __//\ \/\ \ 
// \ \____\/\____\ \____/\ \____\\ \_\ \_\/______/\ \____ \ \____\ \_\ \_\
//  \/____/\/____/\/___/  \/____/ \/_/\/_/         \/___L\ \/____/\/_/\/_/
//                                                   /\____/        
//                                                   \_/__/ 
    
    // Clock-Generator
    analog begin
        @(initial_step)    begin

            count = 0 ;
            clock = 0 ;
            flag_clk = 0 ;

$TEMPLATE_SIGNAL_INITIAL
$TEMPLATE_COUNT_INITIAL

        end

        @( cross( V(CLK,GND)- V(VDD,GND), +1 ) ) begin    
            clock = 1 ;
            count = count + 1 ;
            if(count >= 100 ) count = 0 ;
        end

        @( cross( clock - 1 , +1) )  begin
            if(clock != 0) clock = 0 ;
            flag_clk = 1 ;    
        end

    end

//  __      __                                             ____                      
// /\ \  __/\ \                                           /\  _`\                    
// \ \ \/\ \ \ \     __     __  __     __    ____         \ \ \L\_\     __    ___    
//  \ \ \ \ \ \ \  /'__`\  /\ \/\ \  /'__`\ /',__\  _______\ \ \L_L   /'__`\/' _ `\  
//   \ \ \_/ \_\ \/\ \L\.\_\ \ \_/ |/\  __//\__, `\/\______\\ \ \/, \/\  __//\ \/\ \ 
//    \ `\___x___/\ \__/.\_\\ \___/ \ \____\/\____/\/______/ \ \____/\ \____\ \_\ \_\
//     '\/__//__/  \/__/\/_/ \/__/   \/____/\/___/            \/___/  \/____/\/_/\/_/


    // Waves-Generator
    analog begin

        @( cross( flag_clk - 1 , +1) )  begin
            flag_clk = 0 ;

$TEMPLATE_SIGNAL_GENERATE
$TEMPLATE_COUNT_GENERATE

        end


    end

//                __                     __      
//               /\ \__                 /\ \__   
//   ___   __  __\ \ ,_\  _____   __  __\ \ ,_\  
//  / __`\/\ \/\ \\ \ \/ /\ '__`\/\ \/\ \\ \ \/  
// /\ \L\ \ \ \_\ \\ \ \_\ \ \L\ \ \ \_\ \\ \ \_ 
// \ \____/\ \____/ \ \__\\ \ ,__/\ \____/ \ \__\
//  \/___/  \/___/   \/__/ \ \ \/  \/___/   \/__/
//                          \ \_\                
//                           \/_/                

    // Signal-Output
    analog begin

$TEMPLATE_SIGNAL_OUTPUT

    end


endmodule

 

main.py

import va_gen as va

# input template file path
template_path ='./template.va'
# output file path
save_path = './generate.va'

# the comment in the veriloga file
comment = 'This file is generated by the VA_GEN .'
# the module name
module_name = 'SPI_SLAVE_DATA_V2'

# the expected output signals 
# signal-name | signal-width | waves-length | waves-value 
#signal_args = [
   # ['cmp_res', 1, 32, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]]
# ]
signal_args = [
   ['DATA', 1, 8, [0,0,0,1,0,0,0,0]]
]

rise_t='1n'
fall_t='1n'

#NOTICE:
#THIS GENERATOR WILL NOT REPEATER THE WAVE

if __name__ == '__main__':
    generator = va.VaGenerator(template_path)
    generator.generate_veriloga(module_name, comment, signal_args, save_path , rise_t, fall_t)

va_gen.py

# ***************************************************************
# File-Name: va_gen.py
# Author: Zhang Shen
# Email: zhangshen@shanghaitech.edu.cn
# Time: 2021/09/29
# Version: V-0.1
# Usage: Automatically generate the veriloga file used to
#        generating the wave according to your input.
# ***************************************************************



class Signal:
    def __init__(self, name = 'signal', width = 1, length = 1, waves = [0] ,rise_t = '1n' ,fall_t = '1n'):
        self.name   = name
        self.width  = width
        self.length = length
        self.waves  = waves
        self.rise_t = rise_t
        self.fall_t = fall_t
        self.signal_name    = 'signal_{}'.format(self.name)
        self.count_name     = 'count_{}'.format(self.name)
        self.wave_name      = "wave_{}".format(self.name)
        
        self.width_declaration      = self.get_width_declaration()
        self.length_declaration     = self.get_length_declaration()

        self.input_declaration      = ''
        self.output_declaration     = self.get_output_declaration()
        self.signal_declaration     = self.get_signal_declaration()
        self.count_declaration      = self.get_count_declaration()
        self.wavelist_declaration   = self.get_wavelist_declaration()
        self.signal_initial         = self.get_signal_initial()
        self.count_initial          = self.get_count_initial()
        self.signal_generate        = self.get_signal_generate()
        self.count_generate         = self.get_count_generate()
        self.signal_output          = self.get_signal_output()
        
        

    def get_width_declaration(self):
        arg_1 = ''
        if self.width > 1:
            arg_1 = '[{}:0]'.format(self.width - 1)
        return arg_1
    
    def get_length_declaration(self):
        template = '[0:{}]'
        return template.format(self.length-1)
    
    def get_output_declaration(self):
        template = '    output {} {} ;\n    electrical {} {} ;\n'
        arg_1 = self.width_declaration
        arg_2 = self.name
        
        return template.format(arg_1, arg_2, arg_1, arg_2)
    
    def get_signal_declaration(self):
        template = '    integer {} ;'

        return template.format(self.signal_name)

    def get_count_declaration(self):
        template = '    integer {} ;'

        return template.format(self.count_name)

    def get_wavelist_declaration(self):
        template = '    integer {} {} = {} ;'
        arg_1 = self.wave_name
        arg_2 = self.length_declaration
        arg_3 = ''

        if len(self.waves) > 0 :
            arg_3 = arg_3 + '{ '
            for i in self.waves:
                arg_3 = arg_3 + ' {},'.format(i)
            arg_3 = arg_3 + ' }'
        else:
            print('ERROR!!! The length of the wave list = 0 !!!')

        return template.format(arg_1, arg_2, arg_3)

    def get_signal_initial(self):
        template = '            {} = 0 ;'
        return template.format(self.signal_name)
    
    def get_count_initial(self):
        template = '            {} = 0 ;'
        return template.format(self.count_name)

    def get_signal_generate(self):
        template = '            {} = {}[ {} % {} ] ;'
        arg_1 = self.signal_name
        arg_2 = self.wave_name
        arg_3 = self.count_name
        arg_4 = self.length

        return template.format(arg_1, arg_2, arg_3, arg_4)


    def get_count_generate(self):
        template = '            if ({} < {})  {} = {} + 1 ;'
        arg_1 = self.count_name
        arg_2 = self.length - 1
        arg_3 = self.count_name
        arg_4 = self.count_name
        return template.format(arg_1, arg_2, arg_3, arg_4)

    def get_signal_output(self):
        template = '''
        for(i=0; i<{}; i=i+1) begin
            V( {} ) <+ transition( V(VDD,GND)*(({}&(1<<i))>>i), {}, {} ) ;
        end
        '''
        arg_1 = self.width
        if(self.width) > 1:
            arg_2 = "{}[i]".format(self.name)
        else:
            arg_2 = self.name 
            
        arg_3 = self.signal_name
        arg_4 = self.rise_t
        arg_5 = self.fall_t
        
        return template.format(arg_1, arg_2, arg_3 , arg_4, arg_5)


class MultiSignal:
    def __init__(self, args = []):

        self.signals = self.get_signals(args=args)

        self.port_list              = self.get_port_list()
        self.input_declaration      = ''
        self.output_declaration     = self.get_output_declaration()
        self.signal_declaration     = self.get_signal_declaration()
        self.count_declaration      = self.get_count_declaration()
        self.wavelist_declaration   = self.get_wavelist_declaration()
        self.signal_initial         = self.get_signal_initial()
        self.count_initial          = self.get_count_initial()
        self.signal_generate        = self.get_signal_generate()
        self.count_generate         = self.get_count_generate()
        self.signal_output          = self.get_signal_output()

    def get_signals(self, args):
        thelist = []
        for arg in args:
            the_signal =  Signal(   name = arg[0],
                                    width = arg[1],
                                    length = arg[2],
                                    waves = arg[3] )
            thelist.append(the_signal)
        return thelist


    def get_port_list(self):
        result = ''
        for i in self.signals[:-1]:
            result = result + ' {},'.format(i.name)
        result = result + ' {}'.format(self.signals[-1].name)
        return result

    def get_output_declaration(self):
        result = ''
        for i in self.signals:
            result = result + i.output_declaration +'\n'
        return result
    
    def get_signal_declaration(self):
        result = ''
        for i in self.signals:
            result = result + i.signal_declaration +'\n'
        return result

    def get_count_declaration(self):
        result = ''
        for i in self.signals:
            result = result + i.count_declaration +'\n'
        return result

    def get_wavelist_declaration(self):
        result = ''
        for i in self.signals:
            result = result + i.wavelist_declaration +'\n'
        return result

    def get_signal_initial(self):
        result = ''
        for i in self.signals:
            result = result + i.signal_initial +'\n'
        return result

    def get_count_initial(self):
        result = ''
        for i in self.signals:
            result = result + i.count_initial +'\n'
        return result

    def get_signal_generate(self):
        result = ''
        for i in self.signals:
            result = result + i.signal_generate +'\n'
        return result

    def get_count_generate(self):
        result = ''
        for i in self.signals:
            result = result + i.count_generate +'\n'
        return result  

    def get_signal_output(self):
        result = ''
        for i in self.signals:
            result = result + i.signal_output +'\n'
        return result  


class VaGenerator:
    def __init__(self, file_path):
        self.template = self.read_template(file_path=file_path)

        self.macro_list = [     '$TEMPLATE_HEAD_NOTES',
                                '$TEMPLATE_MODULE_NAME',
                                '$TEMPLATE_PORT_LIST',
                                '$TEMPLATE_INPUT_DECLARATION',
                                '$TEMPLATE_OUTPUT_DECLARATION',
                                '$TEMPLATE_SIGNAL_DECLARATION',
                                '$TEMPLATE_COUNT_DECLARATION',
                                '$TEMPLATE_WAVELIST_DECLARATION',
                                '$TEMPLATE_SIGNAL_INITIAL',
                                '$TEMPLATE_COUNT_INITIAL',
                                '$TEMPLATE_SIGNAL_GENERATE',
                                '$TEMPLATE_COUNT_GENERATE',
                                '$TEMPLATE_SIGNAL_OUTPUT'
                                ]
    def generate_veriloga(self, module_name, comment, args, save_path, rise_t, fall_t):
        self.module_name = module_name
        self.comment = comment
        self.generate_signals(args=args)
        self.fill_template()
        self.save_file(file_path=save_path)
        self.rise_time = rise_t
        self.fall_time = fall_t
        
    def read_template(self, file_path='./template.va'):
        with open(file_path,"r") as f: 
            str_template = f.read()
        return str_template 

    def generate_signals(self, args):
        thesignals = MultiSignal(args=args)
        self.signals = [    self.comment,
                            self.module_name,
                            thesignals.port_list,
                            thesignals.input_declaration ,
                            thesignals.output_declaration ,
                            thesignals.signal_declaration ,
                            thesignals.count_declaration ,
                            thesignals.wavelist_declaration ,
                            thesignals.signal_initial ,
                            thesignals.count_initial ,
                            thesignals.signal_generate ,
                            thesignals.count_generate ,
                            thesignals.signal_output ]

    def fill_template(self):
        content = self.template
        for i in range(len(self.macro_list)):
            content = content.replace( self.macro_list[i], self.signals[i] )
        self.veriloga = content

    def save_file(self,file_path='generated.va'):  
        with open(file_path,"w") as f:
            f.write(self.veriloga)

 

posted @ 2022-04-11 16:46  nevel  阅读(1620)  评论(0编辑  收藏  举报