前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >uart串口通信编程_verilog调用模块端口对应方式

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

作者头像
全栈程序员站长
发布2022-10-05 10:11:48
1.2K0
发布2022-10-05 10:11:48
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

1.发送模块

代码语言:javascript
复制
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.接收模块

代码语言:javascript
复制
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.顶层模块

代码语言:javascript
复制
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.定义接口

代码语言:javascript
复制
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

代码语言:javascript
复制
`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.覆盖率收集

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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.顶层模块

代码语言:javascript
复制
`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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月14日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档