10-【项目实战】基于串口校时的数字钟设计

【项目实战】基于串口校时的数字钟设计

项目要求

  • 编写可以通过串口修改时间的简易数字钟
  1. 使用数码管显示,能够显示时分秒
  2. 能够接收串口发送过来的设置时间的信息,并修改时间
  3. 能够将当前时间值通过串口以1秒一次的速率发送到电脑

tip:前几节已经有编写的模块代码,本次主要注重模块之间的调用和顶层的逻辑实现

设计思路

  • 在顶层模块中,通过计数器,分别对小时、分钟、秒进行计数,在分别计数到24、60、60后清零

  • 要求1可以利用数码管模块实现,在每次计满1秒时,将时分秒的三种数据输入到数码管模块中

  • 由于数码管的显示原理,数据变化时间不能过长,否则实际上将观察不到,因此上述数据输入数码管的过程,不能以每秒的变化为周期,而是要以时钟周期(50MHz)为基准

  • 数码管显示时,还需要注意,在代码中要将十六进制转换为十进制,数码管的表示限制在0~9.

  • 要求2对于时间进行修改,由实际钟表规则可知,在对时分秒任一单位进行修改时,另外的两个单位不变,例如:16:24:23,在对分钟修改为50后,应该从16:50:23开始记起(可能有些规则要求秒钟也清零,这里并未考虑进去)

  • 实现要求2,就需要使用接收标识符,每次接收成功后,都成功计数,不同计数对应着不同单位的修改(修改一般可以从时、分、秒或者秒、分、时的顺序展开,这里以前者为准)

  • 要求3将实时数据发送给PC机,由于前面的串口发送模块以8bit为一位发送,这里例化3个串口发送模块,实现分别实时发送时分秒数据

fpga框图

在这里插入图片描述

代码解析

顶层模块 Digital_clock

`timescale 1ns / 1ps

module Digital_clock(
    clk,
    reset_n,
    uart_rx,
    uart_tx1,
    uart_tx2,
    uart_tx3
    );
    
    input clk;
    input reset_n;
    input uart_rx;
    
    output uart_tx1;
    output uart_tx2;
    output uart_tx3;
    
    reg [32-1:0] disp_data;

    wire [8-1:0] SEL;
    wire [8-1:0] SEG;
    
	//仿真需要,计数值减小以便观察
    //TIME_==50_000_000-1
    parameter TIME_CNT = 5_000-1;//1us
    
	//数码管模块
    hex8 hex8(
        .clk(clk),
        .reset_n(reset_n),
        .disp_data(disp_data),
        .SEL(SEL),
        .SEG(SEG)
    );
    
    
    wire [8-1:0] Data_rx;
    wire Rx_Done;
    
    uart_byte_rx uart_byte_rx(
        .clk(clk),
        .reset_n(reset_n),
        .uart_rx(uart_rx),
        .baud_set('d4),
        .Data(Data_rx),
        .Rx_Done(Rx_Done)
    );
    
	//发送模块三次例化相关定义
    reg [8-1:0] Data_tx1;
    reg [8-1:0] Data_tx2;
    reg [8-1:0] Data_tx3;
    reg Send_go;
    wire Tx_Done;
    
    uart_byte_tx uart_byte_tx1(
        .clk(clk),
        .reset_n(reset_n),
        .Data(Data_tx1),
        .baud_set('d4),
        .Send_go(Send_go),
        .Tx_Done(Tx_Done),
        .uart_tx(uart_tx1)
    );
    
    uart_byte_tx uart_byte_tx2(
        .clk(clk),
        .reset_n(reset_n),
        .Data(Data_tx2),
        .baud_set('d4),
        .Send_go(Send_go),
        .Tx_Done(Tx_Done),
        .uart_tx(uart_tx2)
    );
    
    uart_byte_tx uart_byte_tx3(
        .clk(clk),
        .reset_n(reset_n),
        .Data(Data_tx3),
        .baud_set('d4),
        .Send_go(Send_go),
        .Tx_Done(Tx_Done),
        .uart_tx(uart_tx3)
    );
    
	//分频计数,计数周期由参数TIME_CNT确定
    reg [26-1:0] div_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            div_cnt<=0;
        else if(div_cnt>=TIME_CNT)
            div_cnt<=0;
        else
            div_cnt<=div_cnt+1;
    end
    
	//时、分、秒计数器
    reg [6-1:0] seconds_cnt;
    reg [6-1:0] minutes_cnt;
    reg [5-1:0] hours_cnt;
    
	//每当分频计数满,即为1秒
	//秒计数器
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            seconds_cnt<=0;
        else if(div_cnt==TIME_CNT) 
            if(seconds_cnt==60-1)
                seconds_cnt<=0;
            else
                seconds_cnt<=seconds_cnt+1;
        else
            seconds_cnt<=seconds_cnt;
    end
           
   //分钟计数器
   always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            minutes_cnt<=0;
        else if((seconds_cnt==60-1)&&(div_cnt==TIME_CNT))
            if(minutes_cnt==60-1)
                minutes_cnt<=0;
            else
                minutes_cnt<=minutes_cnt+1;
        else
            minutes_cnt<=minutes_cnt;
    end 
    
	//小时计数器
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            hours_cnt<=0;
        else if((seconds_cnt==60-1)&&(minutes_cnt==60-1)&&(div_cnt==TIME_CNT)) 
            if(hours_cnt==24-1)
                hours_cnt<=0;
            else
                hours_cnt<=hours_cnt+1;
        else
            hours_cnt<=hours_cnt;
    end
    
	//计数结果输出到数码管中
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            disp_data<=0;
        else if(div_cnt==TIME_CNT)begin
            disp_data[3:0]<=seconds_cnt%10;
            disp_data[7:4]<=seconds_cnt/10;
            disp_data[11:8]<=0;
            disp_data[15:12]<=minutes_cnt%10;
            disp_data[19:16]<=minutes_cnt/10;
            disp_data[23:20]<=0;
            disp_data[27:24]<=hours_cnt%10;
            disp_data[31:28]<=hours_cnt/10;
        end
        else 
            disp_data<=disp_data;
    end
            
	//接收计数,用于区分数据输出类别(时、分、秒)
    reg [2-1:0]rx_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            rx_cnt<=0;
        else if(rx_cnt>=3)
            rx_cnt<=0;
        else if(Rx_Done==1)
            rx_cnt<=rx_cnt+1;
        else
            rx_cnt<=rx_cnt;
    end
    
	
	//传输控制标识符
	//接收成功时置1,计满1秒时置0
    reg Trans_CTRL_Done;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Trans_CTRL_Done<=0;
        else if(Rx_Done==1)
            Trans_CTRL_Done<=1;
        else if(div_cnt==TIME_CNT)
            Trans_CTRL_Done<=0;
        else
            Trans_CTRL_Done<=Trans_CTRL_Done;
    end
    
	//当数据通过串口传输成功后,开始数据更新
    always@(posedge clk)begin
        if(Trans_CTRL_Done==1)
            case(rx_cnt)
                1: seconds_cnt<=Data_rx[3:0]+Data_rx[7:4]*10;            
                2: minutes_cnt<=Data_rx[3:0]+Data_rx[7:4]*10;
                0: hours_cnt<=Data_rx[3:0]+Data_rx[7:4]*10;                
                default:;
            endcase
     end   
    
	//发送控制脉冲,计满1秒置1
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Send_go<=0;
        else if(div_cnt==TIME_CNT) 
            Send_go<=1;
        else
            Send_go<=0;
    end
    
	//数据发送
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)begin
            Data_tx1<=0;
            Data_tx2<=0;
            Data_tx3<=0;
        end
        else begin
            Data_tx1<=seconds_cnt;
            Data_tx2<=minutes_cnt;
            Data_tx3<=hours_cnt;
        end
    end
    
endmodule

  • 顶层模块的输入输出并不多,只有来自PC机的时钟数据修改端口uart_rx,和实时发送时钟端口uart_tx1~3

  • 在仿真中,计数时间需要小一点以便观察仿真波形

  • 顶层模块和数码管模块的连接只有数据传输disp_data,在传输时要注意十进制的转换

  • 当接收到修改数据时,需要区分修改的单位,以秒、分、时的顺序进行修改

  • 通过传输控制标识符Trans_CTRL_Done,将数据更新,也就是更改时分秒计数器的值即可

  • 因为在数码管显示时,数据接收频率非常高,几乎可以在完成修改的同时就完成显示

  • 实时数据发送脉冲Send_go,用于控制串口发送模块的使能

  • 时分秒计数器将会实时更新到tx端的数据口上

数码管模块 hex8

`timescale 1ns / 1ps

module hex8(
    clk,
    reset_n,
    disp_data,
    SEL,
    SEG
    );
    
    input clk;
    input reset_n;
    input [32-1:0] disp_data;
    
	//选择8位数码管
    output reg [8-1:0] SEL;
	//选择显示数字
    output reg [8-1:0] SEG;
    
	//用于选择数码管的计数
    reg [3-1:0] num_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            num_cnt<=0;
        else if(num_cnt>=5)
            num_cnt<=0;
        else
            num_cnt<=num_cnt+1;
    end
    
    always@(posedge clk)
        case(num_cnt)
            0: SEL<=8'b1000_0000;
            1: SEL<=8'b0100_0000;
            2: SEL<=8'b0001_0000;
            3: SEL<=8'b0000_1000;
            4: SEL<=8'b0000_0010;
            5: SEL<=8'b0000_0001;
        endcase
        
	//仿32位data中提取对应数码管位数上的显示数字data
	//直接将data和数码管相连掿
    reg [4-1:0] disp_temp;
    always@(posedge clk)begin
        case(num_cnt)
            5:disp_temp<=disp_data[3:0];
            4:disp_temp<=disp_data[7:4];
            3:disp_temp<=disp_data[15:12];
            2:disp_temp<=disp_data[19:16];
            1:disp_temp<=disp_data[27:24];
            0:disp_temp<=disp_data[31:28];
            default:;
        endcase
    end 
    
	//数码管显示数字和对应的编码的映射
    always@(posedge clk)
        case(disp_temp)
            0: SEG<=8'hc0;
            1: SEG<=8'hf9;
            2: SEG<=8'ha4;
            3: SEG<=8'hb0;
            4: SEG<=8'h99;
            5: SEG<=8'h92;
            6: SEG<=8'h82;
            7: SEG<=8'hf8;
            8: SEG<=8'h80;
            9: SEG<=8'h90;
           4'ha: SEG<=8'h88;
           4'hb: SEG<=8'h83;
           4'hc: SEG<=8'hc6;
           4'hd: SEG<=8'ha1;
           4'he: SEG<=8'h86;
           4'hf: SEG<=8'h8e;
           default:SEG<=8'h00;
        endcase
    
endmodule

串口接收模块 uart_byte_rx

`timescale 1ns/1ps

module uart_byte_rx(
    clk,
    reset_n,
    uart_rx,
    baud_set,
    Data,
    Rx_Done
    );

    input clk;
    input reset_n;
    input uart_rx;
    input [3-1:0] baud_set;
    
    output reg [8-1:0] Data;
    output reg Rx_Done;
    
    // reg width name number          
    reg [3-1:0] r_data [8-1:0];
    reg [3-1:0] sta_bit;
    reg [3-1:0] sto_bit;
    
	
	//边沿检测(上升沿和下降沿)
	//通过两位宽的寄存器来实现
	//电路实现上面就是两级D触发器
    reg [1:0] uart_rx_r;
    always@(posedge clk) begin
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0];
    end
    
	//上升沿,两种写法
    wire pedge_uart_rx;
//    assign pedge_uart_rx = ((uart_rx_r[1]==0) && (uart_rx_r[0]==1));
    assign pedge_uart_rx = (uart_rx_r==2'b01);   
    
	//下降沿,两种写法
    wire nedge_uart_rx;
//    assign nedge_uart_rx = ((uart_rx_r[1]==1) && (uart_rx_r[0]==0));
    assign nedge_uart_rx = (uart_rx_r==2'b10);
    
	
	//波特率设置
	//波特率单位,每秒传输的bit数量,()bit/s
	//baud_DR计算为每一个bit所需要的时钟周期,这里的单位是ns
	//这里时钟周期以50MHz为例,也就是一个周期有20ns,因此是/20
	//同时在接收时,将1个bit的数据划分成为16位
    reg [8-1:0] Bps_DR;
    always@(*)
        case(baud_set)
            0: Bps_DR<=1_000_000_000/9600/20/16-1;
            1: Bps_DR<=1_000_000_000/19200/20/16-1;
            2: Bps_DR<=1_000_000_000/38400/20/16-1; 
            3: Bps_DR<=1_000_000_000/57600/20/16-1;
            4: Bps_DR<=1_000_000_000/115200/20/16-1;
            default: Bps_DR<=1_000_000_000/9600/20/16-1;
        endcase
    
	
	//接收使能
    reg Rx_EN;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Rx_EN<=0;
		//当接收当下降沿时,开始接收
        else if(nedge_uart_rx==1)
            Rx_EN<=1;
		//当接收成功时,将使能置0
		//为避免起始位误判,起始位若为高电平(也就是sta_bit>=4),也将使能置0
        else if((Rx_Done==1)||(sta_bit>=4))
            Rx_EN<=0;
    end
    
    //分频计数
    reg [8-1:0] div_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            div_cnt<=0;
		//在使能时,才开始计数
        else if(Rx_EN)begin
			//计数1bit所需周期数
            if(div_cnt==Bps_DR)
                div_cnt<=0;
            else
                div_cnt<=div_cnt+1;
        end
		//没有使能时,一直置0
        else 
            div_cnt<=0;
    end
    
    //数据传输标识符,只有在1bit数据计数到中间时
	//也就是div_cnt==Bps_DR/2时,标识符置1
	//相较于bps_clk,进一步16倍划分了
    wire bps_clk_16x;
    assign bps_clk_16x = (div_cnt==Bps_DR/2);
    
	//数据传输计数
	//bps_cnt标记着数据传输的数量
	//每次bps_clk出现时,bps_cnt才会加1或者清零
    reg [8-1:0] bps_cnt;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            bps_cnt<=0;
        else if(Rx_EN)begin 
            if(bps_clk_16x)begin
				//16倍细分后,总共就需要计数16*(10位bit)=160
                if(bps_cnt==160)
                    bps_cnt<=0;
                else 
                    bps_cnt<=bps_cnt+1;
            end
            else
                bps_cnt<=bps_cnt;
        end
        else
            bps_cnt<=0;    
    end
          
	//核心:数据传输
	//对于1bit数据,将其细分为16份,检测中间部分
	//通过对中间部分的电平计数,判断该位的电平高低
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)begin
             sta_bit<=0;
             sto_bit<=0;
             r_data[0]<=0;
             r_data[1]<=0;
             r_data[2]<=0;
             r_data[3]<=0;
             r_data[4]<=0;
             r_data[5]<=0;
             r_data[6]<=0;
             r_data[7]<=0;
       end
       else if(bps_clk_16x) begin
			//对bps_cnt计数,当技术到每16个区间中间部分时,进行数据判断
			//每次都自加上uart_rx数据线上传来的内容
            case(bps_cnt)
                0:begin
                     sta_bit<=0;
                     sto_bit<=0;
                     r_data[0]<=0;
                     r_data[1]<=0;
                     r_data[2]<=0;
                     r_data[3]<=0;
                     r_data[4]<=0;
                     r_data[5]<=0;
                     r_data[6]<=0;
                     r_data[7]<=0;
                end
                5,6,7,8,9,10,11:                sta_bit<=sta_bit+uart_rx;
                21,22,23,24,25,26,27:           r_data[0]<=r_data[0]+uart_rx;
                37,38,39,40,41,42,43:           r_data[1]<=r_data[1]+uart_rx;
                54,55,56,57,58,59,60:           r_data[2]<=r_data[2]+uart_rx;
                69,70,71,72,73,74,75:           r_data[3]<=r_data[3]+uart_rx;
                85,86,87,88,89,90,91:           r_data[4]<=r_data[4]+uart_rx;
                101,102,103,104,105,106,107:    r_data[5]<=r_data[5]+uart_rx;
                117,118,119,120,121,122,123:    r_data[6]<=r_data[6]+uart_rx;
                133,134,135,136,137,138,139:    r_data[7]<=r_data[7]+uart_rx;
                149,150,151,152,153,154,155:    sto_bit<=sto_bit+uart_rx;
                default:;
            endcase
       end 
    end

	//在统计完每一位的数据后,进行电平判断
	//对bps_cnt计数到每一位的中间部分(7位)累加
	//最终高电平有0,1,2,3次出现,判断为低电平
	//有4,5,6次出现,则判断为高电平
	//判决门限??
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Data<=0;
        else if(bps_clk_16x && (bps_cnt==160))begin
            Data[0]<=(r_data[0]>=4)? 1:0;
            Data[1]<=(r_data[1]>=4)? 1:0;
            Data[2]<=(r_data[2]>=4)? 1:0;
            Data[3]<=(r_data[3]>=4)? 1:0;
            Data[4]<=(r_data[4]>=4)? 1:0;
            Data[5]<=(r_data[5]>=4)? 1:0;
            Data[6]<=(r_data[6]>=4)? 1:0;
            Data[7]<=(r_data[7]>=4)? 1:0;
        end  
    end
    
	
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Rx_Done<=0;
		//当bps_cnt最终计数到第16个bit的最后一份(1/16)时(160)
		//再计满半个bit位所花费的周期(Bps_DR/2),则返回接收成功标识符
        else if((div_cnt==Bps_DR/2) && (bps_cnt==160))
            Rx_Done<=1;
        else 
            Rx_Done<=0; 
    end

endmodule

串口发送模块 uart_byte_tx

`timescale 1ns/1ps

module uart_byte_tx(
    clk,
    reset_n,
    Data,
    baud_set,
    Send_go,
    Tx_Done,
    uart_tx
);

    input clk;
    input reset_n;
    input Send_go;
    input [3-1:0] baud_set;
    input [8-1:0] Data;
    
    output reg Tx_Done;
    output reg uart_tx;
    
    reg [12-1:0] baud_DR;
    always@(*)begin
        if(reset_n == 0)
            baud_DR <= 1_000_000_000/9600/20;
        else  case (baud_set)
            0:  baud_DR <= 1_000_000_000/9600/20;
            1:  baud_DR <= 1_000_000_000/19200/20;
            2:  baud_DR <= 1_000_000_000/38400/20;
            3:  baud_DR <= 1_000_000_000/57600/20;
            4:  baud_DR <= 1_000_000_000/115200/20;
            default: baud_DR <= 1_000_000_000/9600/20;
            endcase
    end
    
    reg [20-1:0] div_cnt;
    reg [4-1:0] bps_cnt;
	
	wire bps_clk;
	//数据传输时钟,在分频计数丿1时拉髿
	//标志弿始新丿轮传辿
	assign bps_clk = (div_cnt == 1);
	
	reg Send_en;
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Send_en <= 1'b1;
        else if(Send_go==1)
            Send_en <= 1'b1; 
        else if(Tx_Done==1)
            Send_en <= 1'b0; 
    end
	
	//r_Data = register for data
	//用于数据保持,避免数据变更时出现意外
    reg [8-1:0] r_Data;
    always@(*)begin
        if(Send_go==1)
            r_Data <= Data;
        else         
            r_Data <= r_Data;
    end
    
    //分频计数
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            div_cnt <= 1'b0;
        else if(Send_en)begin //Send_en使能控制
			if (div_cnt == baud_DR - 1 )
				div_cnt <= 1'b0;
			else 
				 div_cnt <= div_cnt + 1'b1;       
		end
        else 
            div_cnt <= 1'b0;
    end
    
	//数据传输计数
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            bps_cnt <= 1'b0;
        else if(Send_en) begin	//Send_en使能控制
			if (bps_clk)begin
                if(bps_cnt == 11)//1位起姿+8位数捿+1位结板
                    bps_cnt <= 1'b0;
                else
                    bps_cnt <= bps_cnt + 1'b1;       
			end
		end
		else 
			bps_cnt <= 1'b0;
    end
    
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            uart_tx <= 1'b1;
        else if (Send_en) begin
            case(bps_cnt)//总计10位,仿1~10,第11位用于收尿
                1:  uart_tx <= 1'b0;
                2:  uart_tx <= r_Data[0];
                3:  uart_tx <= r_Data[1];            
                4:  uart_tx <= r_Data[2];           
                5:  uart_tx <= r_Data[3];            
                6:  uart_tx <= r_Data[4];
                7:  uart_tx <= r_Data[5];            
                8:  uart_tx <= r_Data[6];            
                9:  uart_tx <= r_Data[7];
                10:  uart_tx <= 1'b1;
                11:  uart_tx <= 1'b1;
                default: uart_tx <= 1'b1;    
                endcase
        end 
    end
    
	//发鿁成功标志符
    always@(posedge clk or negedge reset_n)begin
        if(reset_n==0)
            Tx_Done <= 1'b0; 
        else if(bps_clk==1 && bps_cnt==10)
            Tx_Done <= 1'b1; 
        else 
            Tx_Done <= 1'b0; 
    end
    

endmodule

测试平台 Digital_clock_tb

`timescale 1ns / 1ps
module Digital_clock_tb();

    reg clk;
    reg reset_n;
    reg uart_rx;   
    wire uart_tx1;
    wire uart_tx2;
    wire uart_tx3;

    Digital_clock Digital_clock(
        .clk(clk),
        .reset_n(reset_n),
        .uart_rx(uart_rx),
        .uart_tx1(uart_tx1),
        .uart_tx2(uart_tx2),
        .uart_tx3(uart_tx3)
        );
    
    initial begin
        clk=1;
        forever #10 clk=~clk;
    end
    
    initial begin
        reset_n=0;
        uart_rx=0;
        #201;
        reset_n=1;
        #200;
        #20_000_000
        uart_tx_byte(8'h30);
        #20_000_000
        uart_tx_byte(8'h11);
        #20_000_000
        uart_tx_byte(8'h5);
        #100_000_000;
        $stop;
    end
 
    task uart_tx_byte;
        input [8-1:0] tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
			//刚好是1s/115200
			//也就是1bit所需要的周期时间
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;
        end
    endtask
     
endmodule

个人理解

在最近阅读verilog数字系统设计教程(夏宇闻)一书的验证部分,对于`测试平台`有了进一步的理解体会。
对于数字系统设计过程中,可以大体分为`设计`和`验证`两个部分。
在初学阶段,一般是完成了逻辑设计后,需要自己编写测试平台(testbench)来验证逻辑是否正确,要通过仿真软件观察波形。
但在实际应用中,设计和验证是分开进行的,在设计完成后交由验证部门进行工作,
同样验证的语法也不仅是现在的简单代码,可以使用更加灵活的编写方式,
如果要加强验证部分的能力,还有System Verilog和UVM等内容需要学习?
加强对于设计和验证部分的理解,对于fpga实现流程也是有帮助的,特别是工程上的理解。

目前项目还存在着不足,还请多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值