大家好,又见面了,我是你们的朋友全栈君。
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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。