uart串口通信编程_verilog调用模块端口对应方式

uart串口通信编程_verilog调用模块端口对应方式1.发送模块moduleuart_tx(clk,rst,start,tx_data_in,tx,tx_active,done_tx);parameterclk_freq=50000000;//MHzparameterbaud_rate=19200;//bitspersecondinputclk,rst;inputstart;input[7:0]tx_…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1.发送模块

module uart_tx(clk,rst,start,tx_data_in,tx,tx_active,done_tx);

parameter clk_freq = 50000000; //MHz
parameter baud_rate = 19200; //bits per second
input clk,rst;
input start;
input [7:0] tx_data_in;
output tx;
output tx_active;
output logic done_tx;

localparam clock_divide = (clk_freq/baud_rate);//分频

enum bit [2:0]{ tx_IDLE = 3'b000,
                tx_START = 3'b001,
		        tx_DATA = 3'b010,
	            tx_STOP = 3'b011,
		        tx_DONE = 3'b100 } tx_STATE, tx_NEXT;//状态机的五个状态
					 
logic [11:0] clk_div_reg,clk_div_next;//分频计数
logic [7:0] tx_data_reg;//当前发送的数据
logic [7:0] tx_data_next;//下一个发送的数据
logic tx_out_reg;//当前发送的单bit数据
logic tx_out_next;//下一个发送的单bit数据
logic [2:0] index_bit_reg,index_bit_next;//发送bit的索引

assign tx_active = (tx_STATE == tx_DATA);//只有为发送状态时,tx_active==1
assign tx = tx_out_reg;

always_ff @(posedge clk) begin
if(rst) begin
tx_STATE <= tx_IDLE;
clk_div_reg <= 0;
tx_out_reg <= 0;
tx_data_reg <= 0;
index_bit_reg <= 0;
end
else begin
tx_STATE <= tx_NEXT;
clk_div_reg <= clk_div_next;
tx_out_reg <= tx_out_next;
tx_data_reg <= tx_data_next;
index_bit_reg <= index_bit_next;
end
end

always @(*) begin
tx_NEXT = tx_STATE;
clk_div_next = clk_div_reg;
tx_out_next = tx_out_reg;
tx_data_next = tx_data_reg;
index_bit_next = index_bit_reg;
done_tx = 0;

case(tx_STATE)

tx_IDLE: begin
tx_out_next = 1;
clk_div_next = 0;
index_bit_next = 0;
if(start == 1) begin//start=1,开始发送
tx_data_next = tx_data_in;
tx_NEXT = tx_START;
end
else begin
tx_NEXT = tx_IDLE;
end
end

tx_START: begin
tx_out_next = 0;//拉低一个电平,表示起始位
if(clk_div_reg < clock_divide-1) begin
clk_div_next = clk_div_reg + 1'b1;
tx_NEXT = tx_START;
end
else begin
clk_div_next = 0;
tx_NEXT = tx_DATA;
end
end

tx_DATA: begin
tx_out_next = tx_data_reg[index_bit_reg];//开始发送数据位
if(clk_div_reg < clock_divide-1) begin
clk_div_next = clk_div_reg + 1'b1;
tx_NEXT = tx_DATA;
end
else begin
clk_div_next = 0;
if(index_bit_reg < 7) begin
index_bit_next = index_bit_reg + 1'b1;
tx_NEXT = tx_DATA;
end
else begin
index_bit_next = 0;
tx_NEXT = tx_STOP; 
end
end
end

tx_STOP: begin
tx_out_next = 1;//停止位,拉高一个电平
if(clk_div_reg < clock_divide-1) begin
clk_div_next = clk_div_reg + 1'b1;
tx_NEXT = tx_STOP;
end
else begin
clk_div_next = 0;
tx_NEXT = tx_DONE;
end
end

tx_DONE: begin
done_tx = 1;
tx_NEXT = tx_IDLE;
end

default: tx_NEXT = tx_IDLE;
endcase
end

endmodule 

2.接收模块

 

module uart_rx(clk,rst,rx,rx_data_out);

parameter clk_freq = 50000000; //MHz
parameter baud_rate = 19200; //bits per second
input clk;
input rst;
input rx;
output [7:0] rx_data_out;

localparam clock_divide = (clk_freq/baud_rate);

enum bit [2:0] { rx_IDLE = 3'b000,
                 rx_START = 3'b001,
		 rx_DATA = 3'b010,
		 rx_STOP = 3'b011,
		 rx_DONE = 3'b100 } rx_STATE, rx_NEXT;
					 
logic [11:0] clk_div_reg,clk_div_next;//分频计数
logic [7:0] rx_data_reg,rx_data_next;
logic [2:0] index_bit_reg,index_bit_next;//bit索引


always_ff @(posedge clk) begin
if(rst) begin
rx_STATE <= rx_IDLE;
clk_div_reg <= 0;
rx_data_reg <= 0;
index_bit_reg <= 0;
end
else begin
rx_STATE <= rx_NEXT;
clk_div_reg <= clk_div_next;
rx_data_reg <= rx_data_next;
index_bit_reg <= index_bit_next;
end
end

always @(*) begin
rx_NEXT = rx_STATE;
clk_div_next = clk_div_reg;
rx_data_next = rx_data_reg;
index_bit_next = index_bit_reg;

case(rx_STATE)					 

rx_IDLE: begin
clk_div_next = 0;
index_bit_next = 0;
if(rx == 0) begin//接收到低电平,表示接收开始
rx_NEXT = rx_START;
end
else begin
rx_NEXT = rx_IDLE;
end
end

rx_START: begin
if(clk_div_reg == (clock_divide-1)/2) begin
if(rx == 0) begin
clk_div_next = 0;
rx_NEXT = rx_DATA;
end
else begin
rx_NEXT = rx_IDLE;
end
end
else begin
clk_div_next = clk_div_reg + 1'b1;
rx_NEXT = rx_START;
end
end

rx_DATA: begin
if(clk_div_reg < clock_divide-1) begin
clk_div_next = clk_div_reg + 1'b1;
rx_NEXT = rx_DATA;
end
else begin
clk_div_next = 0;
rx_data_next[index_bit_reg] = rx;//接收数据
if(index_bit_reg < 7) begin
index_bit_next = index_bit_reg + 1'b1;
rx_NEXT = rx_DATA;
end
else begin
index_bit_next = 0;
rx_NEXT = rx_STOP;
end
end
end

rx_STOP: begin
if(clk_div_reg < clock_divide - 1) begin
clk_div_next = clk_div_reg + 1'b1;
rx_NEXT = rx_STOP;
end
else begin
clk_div_next = 0;
rx_NEXT = rx_DONE;
end
end

rx_DONE: begin
rx_NEXT = rx_IDLE;
end

default: rx_NEXT = rx_IDLE;
endcase
end

assign rx_data_out = rx_data_reg;

endmodule

3.顶层模块

module uart(clk,rst,rx,tx_data_in,start,rx_data_out,tx,tx_active,done_tx);

parameter clk_freq = 50000000; //MHz
parameter baud_rate = 19200; //bits per second
parameter clock_divide = (clk_freq/baud_rate);

  input clk,rst; 
  input rx;
  input [7:0] tx_data_in;
  input start;
  output tx; 
  output [7:0] rx_data_out;
  output tx_active;
  output done_tx;
	
	
uart_rx 
       #(.clk_freq(clk_freq),
	 .baud_rate(baud_rate)
	)
      receiver
             (
              .clk(clk),
	      .rst(rst),
	      .rx(rx),
	      .rx_data_out(rx_data_out)
             );


uart_tx 
       #(.clk_freq(clk_freq),
	 .baud_rate(baud_rate)
        )
      transmitter			 
               (               
                .clk(clk),
		.rst(rst),
		.start(start),
		.tx_data_in(tx_data_in),
		.tx(tx),
		.tx_active(tx_active),
		.done_tx(done_tx)
               );

endmodule

基于UVM的验证

1.定义接口

interface uart_intf;
  
  logic clk,rst;
  //接收端口
  logic rx;
  logic [7:0] rx_data_out;
  //发送端口
  logic [7:0] tx_data_in;
  logic start;
  logic tx;
  logic tx_active;
  logic done_tx; 

endinterface

2.transaction

`include "uvm_macros.svh"
import uvm_pkg::*;

  class uart_trans extends uvm_sequence_item;
   
  
    `uvm_object_utils(uart_trans)
         
     bit rx;
	 bit [7:0] rx_data_out;
	 bit start;
	 bit tx;
	   
	 rand bit [7:0] tx_data_in;
	 bit tx_active;
	 bit done_tx;
  
   
    function new (string name = "uart_trans");
      super.new(name);
    endfunction
 endclass: uart_trans

3.覆盖率收集

class uart_cov extends uvm_subscriber #(uart_trans);//继承uvm_subscriber,该类自带了一个uvm_analysis_imp analysis_export端口
  
  `uvm_component_utils(uart_cov)
  uart_trans trans;
	

  covergroup cov_inst;//定义覆盖组
  RX:coverpoint trans.rx {option.auto_bin_max = 1;}//定义bin的数量
  TX_DIN:coverpoint trans.tx_data_in {option.auto_bin_max = 8;}
  START:coverpoint trans.start {option.auto_bin_max = 1;}
  TX:coverpoint trans.tx {option.auto_bin_max = 1;}
  RX_DOUT:coverpoint trans.rx_data_out {option.auto_bin_max = 8;}
  TX_ACT:coverpoint trans.tx_active {option.auto_bin_max = 1;}
  DONE:coverpoint trans.done_tx {option.auto_bin_max = 1;}
  
  RXxRX_DOUT: cross RX,RX_DOUT;//交叉覆盖
  TXxTX_DINxTX_ACTxDONE: cross TX,TX_DIN,TX_ACT,DONE;
  STARTxTX_DIN: cross START,TX_DIN;
  endgroup 
  
  
  function new(string name="", uvm_component parent);
		super.new(name, parent);
		cov_inst = new();//创建覆盖组对象
	endfunction

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
	endfunction


  	virtual function void write(uart_trans t);//在分析imp端口定义write方法
  	$cast(trans, t);
	 cov_inst.sample();
	 endfunction

endclass

4.sequence

typedef uvm_sequencer #(uart_trans) uart_sequencer;//sequencer直接使用uvm_sequencer

class uart_sequence extends uvm_sequence #(uart_trans);
  
    `uvm_object_utils(uart_sequence)
    int count;
    
    function new (string name = ""); 
      super.new(name);
    endfunction

    task body;
      if (starting_phase != null)
        starting_phase.raise_objection(this);
        void'(uvm_config_db #(int)::get(null,"","no_of_transactions",count));
      repeat(count)
      begin
        req = uart_trans::type_id::create("req");//发送item
        start_item(req);
        if( !req.randomize() )
          `uvm_error("", "Randomize failed")
        finish_item(req);
      end
      
      if (starting_phase != null)
        starting_phase.drop_objection(this);
    endtask: body
   
  endclass: uart_sequence

5.driver

class uart_driver extends uvm_driver #(uart_trans);
  
    `uvm_component_utils(uart_driver)

    parameter clk_freq = 50000000; //MHz
    parameter baud_rate = 19200; //bits per second
    localparam clock_divide = (clk_freq/baud_rate);

    virtual uart_intf vif;
    reg [7:0] data;
    int no_transactions;
    
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
      // Get interface reference from config database
      if( !uvm_config_db #(virtual uart_intf)::get(this, "", "uart_intf", vif) )//获取虚接口
        `uvm_error("", "uvm_config_db::get failed")
    endfunction 
   
    virtual task void run_phase(uvm_phase phase);
	  super.run_phase(phase);
      forever
      begin
        seq_item_port.get_next_item(req);

        
      `uvm_info("","---------------------------------------------",UVM_MEDIUM) 
      `uvm_info("", $sformatf("\t Transaction No. = %0d",no_transactions),UVM_MEDIUM) 
      //Test tx 验证发送
      vif.start <= 1;
      vif.rx <= 1;
      @(posedge vif.clk);
      vif.tx_data_in <= req.tx_data_in;
      @(posedge vif.clk);
      wait(vif.done_tx == 1);
      vif.start <= 0;
      if(vif.done_tx == 1) begin
      `uvm_info("", $sformatf("\t start = %0b, \t tx_data_in = %0h,\t done_tx = %0b",vif.start,req.tx_data_in,vif.done_tx),UVM_MEDIUM)  
      `uvm_info("","[TRANSACTION]::TX PASS",UVM_MEDIUM)  
       end
      else begin
      `uvm_info("", $sformatf("\t start = %0b, \t tx_data_in = %0h,\t done_tx = %0b",vif.start,req.tx_data_in,vif.done_tx),UVM_MEDIUM)  
      `uvm_info("","[TRANSACTION]::TX PASS",UVM_MEDIUM)  
       end  
      repeat(100) @(posedge vif.clk);
      //Test rx 验证接收
	    @(posedge vif.clk);
	    data = $random;
	    vif.rx <= 1'b0;
	    repeat(clock_divide) @(posedge vif.clk);
	    for(int i=0;i<8;i++) 
		begin
	    vif.rx <= data[i];
	    repeat(clock_divide) @(posedge vif.clk);
	    end
	    vif.rx <= 1'b1;
	    repeat(clock_divide) @(posedge vif.clk);
	    repeat(100) @(posedge vif.clk); 
	   `uvm_info("", $sformatf("\t Expected data = %0h, \t Obtained data = %0h", data,vif.rx_data_out),UVM_MEDIUM)  
      begin
	    if(vif.rx_data_out == data) begin
	    `uvm_info("","[TRANSACTION]::RX PASS",UVM_MEDIUM)  
      `uvm_info("","---------------------------------------------",UVM_MEDIUM)  
       end
	    else begin 
	   `uvm_info("","[TRANSACTION]::RX FAIL",UVM_MEDIUM)  
     `uvm_info("","---------------------------------------------",UVM_MEDIUM)  
      end
  end
                
        seq_item_port.item_done();
        no_transactions++;
      end
    endtask

  endclass: uart_driver

6.monitor

class uart_mon extends uvm_monitor;
	
	virtual uart_intf intf;
	uart_trans trans;
	uvm_analysis_port #(uart_trans) ap_port;//分析端口
	`uvm_component_utils(uart_mon)
	
	function new(string name="", uvm_component parent);
		super.new(name, parent);
	endfunction


	function void build_phase(uvm_phase phase);
	  super.build_phase(phase);
	  ap_port = new("ap_port",this);
	  //trans = uart_trans::type_id::create("trans");
		if(!uvm_config_db #(virtual uart_intf)::get(this, "", "uart_intf", intf)) 
		   begin
		    `uvm_error("ERROR::", "UVM_CONFIG_DB FAILED in uart_mon")
		    end
		//ap_port = new("ap_port", this);
	endfunction

  
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    while(1) begin
      @(posedge intf.clk);
      trans = uart_trans::type_id::create("trans");
      trans.start = intf.start;
      trans.tx_active = intf.tx_active;
      trans.done_tx = intf.done_tx;
      trans.tx_data_in = intf.tx_data_in;
      trans.rx = intf.rx;
      trans.rx_data_out = intf.rx_data_out;
      trans.tx = intf.tx;
      ap_port.write(trans);
    end
  endtask
  
  
endclass

7.agent

class uart_agent extends uvm_agent;
	
 `uvm_component_utils(uart_agent)
	  
	  uart_sequencer seqr;
    uart_driver    driv;
    uart_mon mon;
    uart_cov cov;
    
    function new(string name = "", uvm_component parent);
      super.new(name, parent);
    endfunction
 
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      seqr = uart_sequencer::type_id::create("seqr", this);
      driv = uart_driver::type_id::create("driv", this);
      mon = uart_mon::type_id::create("mon", this);
      cov = uart_cov::type_id::create("cov", this);
    endfunction
    
    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      driv.seq_item_port.connect( seqr.seq_item_export);
      mon.ap_port.connect(cov.analysis_export);//连接monitor和subscriber
    endfunction
    

endclass

 8.environment

class uart_env extends uvm_env;

  `uvm_component_utils(uart_env)
    
   uart_agent agent;
    
    function new(string name = "", uvm_component parent);
      super.new(name, parent);
    endfunction
 
    function void build_phase(uvm_phase phase);
	super.build_phase(phase);
    agent = uart_agent::type_id::create("agent",this);  
    endfunction
    
    
  endclass: uart_env

9.test

class uart_test extends uvm_test;
  
    `uvm_component_utils(uart_test)
    
    uart_env env;
    
    function new(string name = "", uvm_component parent);
      super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
	   super.build_phase(phase);
      env = uart_env::type_id::create("env", this);
    endfunction
    
    	function void end_of_elaboration_phase(uvm_phase phase);
			//`uvm_info(uvm_get_fullname(), this.sprint(), UVM_NONE)
			`uvm_info("", this.sprint(), UVM_NONE)
		endfunction
    
    task run_phase(uvm_phase phase);
      uart_sequence seqr;
      seqr = uart_sequence::type_id::create("seqr");//创建对象并启动sequence
      //if( !seqr.randomize() ) 
        //`uvm_error("", "Randomize failed")
      seqr.starting_phase = phase;
      seqr.start( env.agent.seqr );
    endtask
     
  endclass: uart_test

10.顶层模块

`include "uart_trans.sv"
`include "uart_sequence.sv"
`include "uart_intf.sv"
`include "uart_driver.sv"
`include "uart_mon.sv"
`include "uart_cov.sv"
`include "uart_agent.sv"
`include "uart_env.sv"
`include "uart_test.sv"

module tb_uart_top;
  
  
  bit clk;
  bit rst;
  
  uart_intf intf();
  
  uart    dut(
              .clk(intf.clk),
              .rst(intf.rst),
              .rx(intf.rx),
              .tx_data_in(intf.tx_data_in),
              .start(intf.start),
              .rx_data_out(intf.rx_data_out),
              .tx(intf.tx),
              .tx_active(intf.tx_active),
              .done_tx(intf.done_tx)
              );

  // Clock generator
  initial
  begin
    intf.clk = 0;
    forever #5 intf.clk = ~intf.clk;
  end
  
  initial
  begin
    intf.rst = 1;
    #1000;
    intf.rst = 0;
  end



  initial
  begin
    uvm_config_db #(virtual uart_intf)::set(null, "*", "uart_intf", intf);
    void'(uvm_config_db #(int)::set(null,"*","no_of_transactions",10));
    
    uvm_top.finish_on_completion = 1;
    
    run_test("uart_test");
  end

endmodule: tb_uart_top

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/193990.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Django(14)模型中常用的属性(超详细)[通俗易懂]

    Django(14)模型中常用的属性(超详细)[通俗易懂]模型中常用字段字段说明AutoField一般不需要使用这个类型,自增长类型,数据表的字段类型为整数,长度为11位BigAutoField自增长类型,数据表的字段类型为bigint,长度为2

  • Struts2知识点小结(三)–值栈与ognl表达式

    Struts2知识点小结(三)–值栈与ognl表达式Struts2知识点小结(三)–值栈与ognl表达式

  • 跨链协议ChainBridge简明教程【EVM/Substrate】「建议收藏」

    跨链协议ChainBridge简明教程【EVM/Substrate】「建议收藏」ChainBridge是一个可扩展的跨链通信协议,目前兼容EMV和Substrate链,支持两个不同的EVM区块链、或者一个EVM链与一个Substrate链之间的跨链桥接与通证转移,支持ERC20、ERC721等多种类型的通证的跨链转移,以及普通数据的跨链转移。在这个教程中,我们将介绍ChainBridge的基本构成和安装方法,并利用ChainBridge实现Substrate原生资产和以太坊ERC20/ERC721通证之间的跨链转移。用自己熟悉的语言学习以太坊开发:Java|Php|

  • mp3格式音频文件结构解析图_mp3文件结构

    mp3格式音频文件结构解析图_mp3文件结构一、概述Layer-3音频文件,MPEG(MovingPictureExpertsGroup)在汉语中译为活动图像专家组,特指活动影音压缩标准,MPEG音频文件是MPEG1标准中的声音部分,也叫MPEG音频层,它根据压缩质量和编码复杂程度划分为三层,即Layer-1、Layer2、Layer3,且分别对应MP1、MP2、MP3这三种声音文件,并根据不同的用途,使用不同层次的编码

  • varchar2转number 详解 Oracle

    varchar2转number 详解 Oracle@varchar2转numbervarchar2转number详解Oracle1.使用转换方法:to_number(‘12.50’)2.方法1存在一个问题,如果转换一个可能为null的varchar2字段值,转换之后结果依然为null,而null与任何值相加结果都为null,这样可能导致查询结果错误:to_number(nvl(varchar2_column,0))3.注意使用v…

  • linux yum下载_虚拟机配置yum源

    linux yum下载_虚拟机配置yum源文章目录一.软件包管理1.RPM包管理2.源码包二.软件的安装工具1.YUM工具2.RPM工具一.软件包管理1.RPM包管理Red Hat Package Manager包的命名规则:软件名,版本号,发行版本,系统平台(32/64),后缀是.rpm**特点:**二进制包,无需编译,可以直接使用**缺点:**无法设定个人设置,开关功能2.源码包特点:需要经过gcc等编译环境编译才能运行,可以设定个人设置,开关功能缺点:配置复杂二.软件的安装工具1.YUM工具Yellow dog Upd

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号