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

2022-10-05 10:11:48 浏览数 (2)

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

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. = 
",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 = , t tx_data_in = %0h,t done_tx = ",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 = , t tx_data_in = %0h,t done_tx = ",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

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

0 人点赞