1 源码下载地址:
https://download.csdn.net/download/times_poem/10659354
书籍推荐:芯片验证漫游指南
2 整个实验文件划分为以下模块,以便分析。
3 代码分析
公用文件层
3.1 router_io.sv
default input #1ns output #1ns;
p175 采样偏移量,输出偏移量。
通过interface实现时钟同步。
interface router_io(input bit clock);
logic reset_n;
logic [15:0] din;
logic [15:0] frame_n;
logic [15:0] valid_n;
logic [15:0] dout;
logic [15:0] valido_n;
logic [15:0] busy_n;
logic [15:0] frameo_n;
clocking cb @(posedge clock);
default input #1ns output #1ns;
output reset_n;
output din;
output frame_n;
output valid_n;
input dout;
input valido_n;
input frameo_n;
input busy_n;
endclocking: cb
modport TB(clocking cb, output reset_n);
endinterface: router_io
3.2 Packet.sv
按照rtl数据传输类型,定义packet的数据。
compare 用于scoreboard.sv
display 用于打印当前packet的数据信息
copy 用于Receiver.sv
`ifndef INC_PACKET_SV
`define INC_PACKET_SV
class Packet;
rand bit[3:0] sa, da; // random port selection
rand logic[7:0] payload[$]; // random payload array
string name; // unique identifier
constraint Limit {
sa inside {[0:15]};
da inside {[0:15]};
payload.size() inside {[2:4]};
}
extern function new(string name = "Packet");
extern virtual function bit compare(Packet pkt2cmp, ref string message);
extern virtual function void display(string prefix = "NOTE");
extern virtual function Packet copy();
endclass
function Packet::new(string name);
this.name = name;
endfunction
function bit Packet::compare(Packet pkt2cmp, ref string message);
if (payload.size() != pkt2cmp.payload.size()) begin
message = "Payload Size Mismatch:\n";
message = { message, $sformatf("payload.size() = %0d, pkt2cmp.payload.size() = %0d\n", payload.size(), pkt2cmp.payload.size()) };
return(0);
end
if (payload == pkt2cmp.payload) ;
else begin
message = "Payload Content Mismatch:\n";
message = { message, $sformatf("Packet Sent: %p\nPkt Received: %p", payload, pkt2cmp.payload) };
return(0);
end
message = "Successfully Compared";
return(1);
endfunction
function void Packet::display(string prefix);
$display("[%s]%t %s sa = %0d, da = %0d", prefix, $realtime, name, sa, da);
foreach(payload[i])
$display("[%s]%t %s payload[%0d] = %0d", prefix, $realtime, name, i, payload[i]);
endfunction
function Packet Packet::copy();
Packet pkt_copy = new();
pkt_copy.sa = this.sa;
pkt_copy.da = this.da;
pkt_copy.payload = this.payload;
return(pkt_copy);
endfunction
`endif
顶层模块相关
3.3 router_test_top.sv
产生时钟
dump fsdb数据
实例化dut
`timescale 1ns/100ps
module router_test_top;
parameter simulation_cycle = 100;
bit SystemClock = 0;
router_io top_io(SystemClock);
test t(top_io);
router dut(
.reset_n (top_io.reset_n),
.clock (top_io.clock),
.din (top_io.din),
.frame_n (top_io.frame_n),
.valid_n (top_io.valid_n),
.dout (top_io.dout),
.valido_n (top_io.valido_n),
.busy_n (top_io.busy_n),
.frameo_n (top_io.frameo_n)
);
initial begin
$timeformat(-9, 1, "ns", 10);
//$fsdbDumpvars;
$fsdbDumpfile("novas.fsdb");
$fsdbDumpvars(0,"router_test_top");
end
always begin
#(simulation_cycle/2) SystemClock = ~SystemClock;
end
endmodule
3.4 test.sv
声明Environment
实例化
program automatic test(router_io.TB rtr_io);
import router_test_pkg::*;
Environment env;
initial begin
env = new("env", rtr_io);
env.configure();
run_for_n_packets = env.run_for_n_packets;
env.run();
end
endprogram: test
3.5 Environment.sv
semaphore的使用:各个组件间通信,访问公共变量,防止同时读写操作。
整个系统的核心组件。
class Environment;
string name;
rand int run_for_n_packets; // number of packets to test
virtual router_io.TB rtr_io;
semaphore sem[]; // prevent output port collision
Driver drvr[]; // driver objects
Receiver rcvr[]; // receiver objects
Generator gen[]; // generator objects
Scoreboard sb; // scoreboard object
constraint valid {
this.run_for_n_packets inside { [1500:2500] };
}
extern function new(string name = "Env", virtual router_io.TB rtr_io);
extern virtual task run();
extern virtual function void configure();
extern virtual function void build();
extern virtual task start();
extern virtual task wait_for_end();
extern virtual task reset();
endclass: Environment
function Environment::new(string name = "Env", virtual router_io.TB rtr_io);
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, name);
this.name = name;
this.rtr_io = rtr_io;
endfunction: new
task Environment::run();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
this.build();
this.reset();
this.start();
this.wait_for_end();
endtask: run
function void Environment::configure();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
this.randomize();
endfunction: configure
function void Environment::build();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
if(this.run_for_n_packets == 0) this.run_for_n_packets = 2000;
this.sem = new[16];
this.drvr = new[16];
this.rcvr = new[16];
this.gen = new[16];
this.sb = new();
foreach (this.sem[i])
this.sem[i] = new(1);
foreach (this.gen[i])
this.gen[i] = new($sformatf("gen[%0d]", i), i);
foreach (this.drvr[i])
this.drvr[i] = new($sformatf("drvr[%0d]", i), i, this.sem, this.gen[i].out_box, this.sb.driver_mbox, this.rtr_io);
foreach (this.rcvr[i])
this.rcvr[i] = new($sformatf("rcvr[%0d]", i), i, this.sb.receiver_mbox, this.rtr_io);
endfunction: build
task Environment::reset();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
this.rtr_io.reset_n <= 1'b0;
this.rtr_io.cb.frame_n <= '1;
this.rtr_io.cb.valid_n <= '1;
repeat(2) @this.rtr_io.cb;
this.rtr_io.cb.reset_n <= 1'b1;
repeat(15) @(this.rtr_io.cb);
endtask: reset
task Environment::start();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
this.sb.start();
foreach(this.gen[i])
this.gen[i].start();
foreach(this.drvr[i])
this.drvr[i].start();
foreach(this.rcvr[i])
this.rcvr[i].start();
endtask: start
task Environment::wait_for_end();
if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
wait(this.sb.DONE.triggered);
endtask: wait_for_end
Driver层
3.6 Generator.sv
3.7 Driver.sv
3.8 DriverBase.sv
Monitor层
3.9 Receiver.sv
3.10 ReceiverBase.sv
DUT层
router.v
————————————————
版权声明:本文为CSDN博主「Times_poem」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Times_poem/article/details/82626242