代码流程规范

git代码流程规范

git操作

在这里插入图片描述

1、安装教程

  • 配置:
git config --global user.name 'zhaotianyang'
  • 配置邮箱:
git config --global user.email '22140638@bjtu.edu.cn'
  • 使用git clone克隆远程仓库:
git clone 'https://gitee.com/zhaotianayng/zty.git'
  • git add 123.v
git add 123.v
  • 提交
git commit -m 'add 123.v'
  • push推送
git push

2、同步本地dev与远程dev

  • //切换到dev分支
git checkout dev	
  • //拉取最新代码到本地dev
git pull			
  • //切换到分支
git checkout <branch>
  • //合并dev到分支
git merge dev		

3、修改分支并同步到远程dev

  • //切换到dev分支
git add .\..路径..\<文件名>	
  • //拉取最新代码到本地dev
git commit -m '修改描述'		
  • //上传到远程
git push					
  • //切换到本地dev分支
git checkout dev			
  • //拉取最新代码到本地dev
git pull			
  • //合并到dev分支
git merge <branch>		
  • //上传到远程
git push					
  • //切换到分支
git checkout <branch>

iverilog操作

1、命令行控制方式

  • 注意testbench文件中有几行iverilog编译器专用的语句,如果不加的话后面不能生成vcd文件。
initial
begin            
    $dumpfile("wave.vcd");        //生成的vcd文件名称
    $dumpvars(0, led_demo_tb);    //tb模块名称
end
  • 对源文件和仿真文件,进行语法规则检查和编译
iverilog .\sim\tb\tb_spi.v .\soc\perips\spi.v
  • 2.生成波形文件
vvp a.out
  • 2.打开波形文件
gtkwave wave.vcd

2、.py自动执行方式

  • 需建立以下文件:

1、spi.v
2、tb_spi.v
3、filelist_spi.f
4、make.py

指令执行语句

  • 仿真
python ./sim/make.py -r -t tb_spi
  • 看波形
python ./sim/make.py -r -t tb_spi -w //运行、仿真、看波形
  • 如果生成的文件太多了,可以清理下
python ./sim/make.py -c

文件格式如下

1、spi.v

// spi master模块
 module spi(

 input wire clk,
 input wire rstn,

 input wire[31:0] data_i,
 input wire[31:0] addr_i,
 input wire we_i,

 output reg[31:0] data_o,

 output reg spi_mosi,             // spi控制器输出、spi设备输入信号
 input wire spi_miso,             // spi控制器输入、spi设备输出信号
 output wire spi_ss,              // spi设备片选
 output reg spi_clk               // spi设备时钟,最大频率为输入clk的一半
 );

 localparam SPI_CTRL   = 4'h0;    // spi_ctrl寄存器地址偏移
 localparam SPI_DATA   = 4'h4;    // spi_data寄存器地址偏移
 localparam SPI_STATUS = 4'h8;    // spi_status寄存器地址偏移

 // spi控制寄存器
 // addr: 0x00
 // [0]: 1: enable, 0: disable
 // [1]: CPOL,时钟极性。CPOL=0,SCK空闲时为低电平
 // [2]: CPHA,CPHA=0,发送端数据在时钟后沿发生改变,接收端数据在时钟前沿发生改变
 // [3]: select slave, 1: select, 0: deselect
 // [15:8]: clk div
 reg[31:0] spi_ctrl;
 // spi数据寄存器
 // addr: 0x04
 // [7:0] cmd or inout data
 reg[31:0] spi_data;
 // spi状态寄存器
 // addr: 0x08
 // [0]: 1: busy, 0: idle
 reg[31:0] spi_status;

 reg[8:0] clk_cnt;               // 分频计数
 reg en;                         // 使能,开始传输信号,传输期间一直有效
 reg[4:0] spi_clk_edge_cnt;      // spi clk时钟沿的个数
 reg spi_clk_edge_level;         // spi clk沿电平
 reg[7:0] rdata;                 // 从spi设备读回来的数据
 reg done;                       // 传输完成信号
 reg[3:0] bit_index;             // 数据bit索引
 wire[8:0] div_cnt;

 assign spi_ss = ~spi_ctrl[3];   // SPI设备片选信号
 assign div_cnt = spi_ctrl[15:8];// 0: 2分频,14分频,28分频,316分频,432分频,以此类推

 // 产生使能信号
 // 传输期间一直有效
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         en <= 1'b0;
     end else begin
         if (spi_ctrl[0] == 1'b1) begin
             en <= 1'b1;
         end else if (done == 1'b1) begin
             en <= 1'b0;
         end else begin
             en <= en;
         end
     end
 end

 // 对输入时钟进行计数
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         clk_cnt <= 9'h0;
     end else if (en == 1'b1) begin
         if (clk_cnt == div_cnt) begin
             clk_cnt <= 9'h0;
         end else begin
             clk_cnt <= clk_cnt + 1'b1;
         end
     end else begin
         clk_cnt <= 9'h0;
     end
 end

 // 对spi clk沿进行计数
 // 每当计数到分频值时产生一个上升沿脉冲
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         spi_clk_edge_cnt <= 5'h0;
         spi_clk_edge_level <= 1'b0;
     end else if (en == 1'b1) begin
         // 计数达到分频值
         if (clk_cnt == div_cnt) begin
             if (spi_clk_edge_cnt == 5'd17) begin
                 spi_clk_edge_cnt <= 5'h0;
                 spi_clk_edge_level <= 1'b0;
             end else begin
                 spi_clk_edge_cnt <= spi_clk_edge_cnt + 1'b1;
                 spi_clk_edge_level <= 1'b1;
             end
         end else begin
             spi_clk_edge_level <= 1'b0;
         end
     end else begin
         spi_clk_edge_cnt <= 5'h0;
         spi_clk_edge_level <= 1'b0;
     end
 end

 // bit序列
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         spi_clk <= 1'b0;
         rdata <= 8'h0;
         spi_mosi <= 1'b0;
         bit_index <= 4'h0;
     end else begin
         if (en) begin
             if (spi_clk_edge_level == 1'b1) begin
                 case (spi_clk_edge_cnt)
                     // 第奇数个时钟沿
                     1, 3, 5, 7, 9, 11, 13, 15: begin
                         spi_clk <= ~spi_clk;
                         if (spi_ctrl[2] == 1'b1) begin//CPHA=1,发送端数据在时钟前沿发生改变,接收端数据在时钟后沿发生改变
                             spi_mosi <= spi_data[bit_index];   // 送出1bit数据
                             bit_index <= bit_index - 1'b1;
                         end else begin
                             rdata <= {rdata[6:0], spi_miso};   // 读1bit数据
                         end
                     end
                     // 第偶数个时钟沿
                     2, 4, 6, 8, 10, 12, 14, 16: begin
                         spi_clk <= ~spi_clk;
                         if (spi_ctrl[2] == 1'b1) begin
                             rdata <= {rdata[6:0], spi_miso};   // 读1bit数据
                         end else begin
                             spi_mosi <= spi_data[bit_index];   // 送出1bit数据
                             bit_index <= bit_index - 1'b1;
                         end
                     end
                     17: begin
                         spi_clk <= spi_ctrl[1];
                     end
                 endcase
             end
         end else begin
             // 初始状态
             spi_clk <= spi_ctrl[1];
             if (spi_ctrl[2] == 1'b0) begin
                 spi_mosi <= spi_data[7];           // 送出最高位数据
                 bit_index <= 4'h6;
             end else begin
                 bit_index <= 4'h7;
             end
         end
     end
 end

 // 产生结束(完成)信号
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         done <= 1'b0;
     end else begin
         if (en && spi_clk_edge_cnt == 5'd17) begin
             done <= 1'b1;
         end else begin
             done <= 1'b0;
         end
     end
 end

 // write reg
 always @ (posedge clk) begin
     if (rstn == 1'b0) begin
         spi_ctrl <= 32'h0;
         spi_data <= 32'h0;
         spi_status <= 32'h0;
     end else begin
         spi_status[0] <= en;
         if (we_i == 1'b1) begin
             case (addr_i[3:0])
                 SPI_CTRL: begin
                     spi_ctrl <= data_i;
                 end
                 SPI_DATA: begin
                     spi_data <= data_i;
                 end
                 default: begin

                 end
             endcase
         end else begin
             spi_ctrl[0] <= 1'b0;
             // 发送完成后更新数据寄存器
             if (done == 1'b1) begin
                 spi_data <= {24'h0, rdata};
             end
         end
     end
 end

 // read reg
 always @ (*) begin
     if (rstn == 1'b0) begin
         data_o = 32'h0;
     end else begin
         case (addr_i[3:0])
             SPI_CTRL: begin
                 data_o = spi_ctrl;
             end
             SPI_DATA: begin
                 data_o = spi_data;
             end
             SPI_STATUS: begin
                 data_o = spi_status;
             end
             default: begin
                 data_o = 32'h0;
             end
         endcase
     end
 end

endmodule

2、tb_spi.v

tb文件应额外增加代码见下图:
在这里插入图片描述

//spi testbench
//zhaoty
`timescale  1ns / 1ps
module tb_spi();

// spi Inputs
reg             clk      ;
reg             rstn     ;
reg   [31:0]    data_i   ;
reg   [31:0]    addr_i   ;
reg             we_i     ;
reg             spi_miso ;

// spi Outputs
wire  [31:0]    data_o   ;
wire            spi_mosi ;
wire            spi_ss   ;
wire            spi_clk  ;

initial
    begin
        clk = 1'b1           ;
        rstn   <=  1'b0      ;
        we_i   <=  1'b0      ;

        #30
        rstn   <=  1'b1      ;
        we_i   <=  1'b1      ;
        #20 // spi控制寄存器
        data_i <=32'h0000010D;          
        addr_i <=32'h00000000;                      
        #30// spi数据寄存器
        data_i <=32'h0000000A;          
        addr_i <=32'h00000004; 
        #30 // spi状态寄存器
        data_i <=32'h0000000A;          
        addr_i <=32'h00000008; 
        #1000 $finish;
    end
    
    initial
    begin            
        $dumpfile("tb_spi.vcd");        //生成的vcd文件名称
        $dumpvars(0, tb_spi);    //tb模块名称
    end
    
/*  */
always #10 clk = ~clk;

spi u_spi(
    .clk      ( clk      ),
    .rstn     ( rstn     ),
    .data_i   ( data_i   ),
    .addr_i   ( addr_i   ),
    .we_i     ( we_i     ),
    .data_o   ( data_o   ),
    .spi_miso ( spi_miso ),    
    
    .spi_mosi ( spi_mosi ), 
    .spi_ss   ( spi_ss   ),
    .spi_clk  ( spi_clk  )
);
endmodule

3、filelist_spi.f

.\soc\perips\spi.v
.\sim\tb\tb_spi.v 
//最后需要空一行,不然会报错!!!我也不知道为什么

4、make.py

.py文件应增加代码见下图
在这里插入图片描述

import os
import sys
import logging
import argparse

CUR_SYS = sys.platform  # get os type
# CUR_DIR = os.path.dirname(os.path.realpath(__file__))  
TOP_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))  # get top directory

logging.getLogger().setLevel(logging.INFO)

# 需要新增对某个模块的测试时,在此处添加tb文件名和对应的filelist文件名
tb_map = {
    'tb_soc'    :   'filelist_soc',
    'tb_core'   :   'filelist_core',
    'tb_ifu'    :   'filelist_ifu',
    'tb_id'     :   'filelist_id',
    'tb_id_ex'  :   'filelist_id_ex',
    'tb_ex'     :   'filelist_ex',
    'tb_spi'     :  'filelist_spi',
    'tb_regs'   :   'filelist_regs'
}

def sim_on_win(args: dict):
    
    if args["run"] and args["wave"]:
        cmd_run_with_wave = "iverilog -o {1}.out -c {0}/sim/filelist/{2}.f && \
                             vvp {0}/{1}.out && \
                             gtkwave {0}/{1}.vcd".format(TOP_DIR, args["tbfile"], tb_map[args["tbfile"]])
        os.system(cmd_run_with_wave)
    elif args["run"]:
        cmd_run = "iverilog -o {1}.out -c {0}/sim/filelist/{2}.f && vvp {0}/{1}.out".format(TOP_DIR, args["tbfile"], tb_map[args["tbfile"]])
        os.system(cmd_run)
    elif args["wave"]:
        if not os.path.exists("{0}/{1}.vcd".format(TOP_DIR, args["tbfile"])):
            logging.error("wave file does not exists!")
            exit(1)
        cmd_wave = "gtkwave {0}/{1}.vcd".format(TOP_DIR, args["tbfile"])
        os.system(cmd_wave)
    elif args['clean']:
        try:
            for root, dirs, files in os.walk(TOP_DIR):
                for name in files:
                    if name.endswith(".out"):
                        os.remove("{}/{}".format(TOP_DIR, name))
                    elif name.endswith(".vcd"):
                        os.remove("{}/{}".format(TOP_DIR, name))
        except FileNotFoundError:
            pass
        logging.info("clear done!")
    else:
        pass
    
    return

def sim_on_linux(args: dict):
    
    if args["run"] and args["wave"]:
        cmd_run_with_wave = "iverilog -o {1}.out -c {0}/sim/filelist/{2}.f && \
                             vvp {0}/{1}.out && \
                             gtkwave {0}/{1}.vcd".format(TOP_DIR, args["tbfile"], tb_map[args["tbfile"]])
        os.system(cmd_run_with_wave)
    elif args["run"]:
        cmd_run = "iverilog -o {1}.out -c {0}/sim/filelist/{2}.f && vvp {0}/{1}.out".format(TOP_DIR, args["tbfile"], tb_map[args["tbfile"]])
        os.system(cmd_run)
    elif args["wave"]:
        if not os.path.exists("{0}/{1}.vcd".format(TOP_DIR, args["tbfile"])):
            logging.error("wave file does not exists!")
            exit(1)
        cmd_wave = "gtkwave {0}/{1}.vcd".format(TOP_DIR, args["tbfile"])
        os.system(cmd_wave)
    elif args['clean']:
        try:
            for root, dirs, files in os.walk(TOP_DIR):
                for name in files:
                    if name.endswith(".out"):
                        os.remove("{}/{}".format(TOP_DIR, name))
                    elif name.endswith(".vcd"):
                        os.remove("{}/{}".format(TOP_DIR, name))
        except FileNotFoundError:
            pass
        logging.info("clear done!")
    else:
        pass

    return

def args_check(args: dict):
    
    if args['simtool'] not in ["iverilog"]:
        logging.warning("Unsupported simulator, aborting process!")
        exit(1)
    elif args['clean'] and (args['run'] or args['wave']):
        logging.warning("Parameter conflicts, 'clean' must be independent!")
        exit(1)
    else:
        pass
        
    return 

def parse() -> dict:
    parser = argparse.ArgumentParser()
    # group = parser.add_mutually_exclusive_group()
    # group.add_argument("-c", "--compile", action="store_true", help="Compile RTL only")
    parser.add_argument("-r", "--run", action="store_true", help="使用testbench进行编译和仿真")
    parser.add_argument("-w", "--wave", action="store_true", help="使用gtkwave打开vcd波形文件")
    parser.add_argument("-c", "--clean", action="store_true", help="删除.out/.vcd文件")
    parser.add_argument("-s", "--simtool", default="iverilog", help="指定仿真环境,默认为iverilog")
    parser.add_argument("-t", "--tbfile", default="tb_core", help="指定tb文件,默认为tb_core")
    args = vars(parser.parse_args())
    return args
    
def main():
    args = parse()
    args_check(args)
    if CUR_SYS == "win32":
        logging.info("Simulation starts on win...")
        sim_on_win(args)
    elif CUR_SYS == "linux":
        logging.info("Simulation starts on linux...")
        sim_on_linux(args)
    else:
        logging.warning("Unknown system, aborting process!")
        exit(1)

    return

if __name__ == "__main__":
    main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值