电力电子转战数字IC20220701-02day37-38——路科实验3b

$sformatf()/$sformat()

system verilog中的$sformatf()/$sformat()_硅农阿轩的博客-CSDN博客转载自https://zhuanlan.zhihu.com/p/279618353字符串在验证平台中是经常被使用的,今天我们来说说在SystemVerilog中非常重要和常用的sformatf()/sformatf()/sformatf()/sformat()函数,他们是什么含义?如何用?如何妙用?01sformatf()/sformatf()/sformatf()/sformat()函数的含义首先Jerry和大家解释下这两个函数什么含义。看下这段代码:string jerry_string;https://blog.csdn.net/weixin_41155581/article/details/120068858

 packed压缩数组

Systemverilog 压缩数组 packed_小羊肖恩想的博客-CSDN博客_压缩数组文章目录压缩数组一、压缩数组的定义二、压缩数组的类型1.引入库2.读入数据总结压缩数组 这个文章的主要内容是以下三点: 1、压缩数组的定义 2、压缩数组的类型 3、压缩数组类型的测试实例一、压缩数组的定义二、压缩数组的类型1.引入库代码如下(示例):import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport warningswarni..https://blog.csdn.net/qq_42043804/article/details/122529744

 $display

Verilog系统函数(一) $display_李锐博恩的博客-CSDN博客_displayVerilog系统函数$display参考:FPGA篇(四)Verilog系统函数介绍($display,$fopen,$fscanf,$fwrite($fdisplay),$fclose,$random,$stop)下面代码截自仿真文件部分:regflag;//-----------------------------------------------------...https://blog.csdn.net/Reborn_Lee/article/details/89792937

中位向量系统函数

systemverilog中位向量系统函数---$countbits/$countones/$onehot/$onehot0/$isunknown_Alfred.HOO的博客-CSDN博客_isunknown函数systemverilog中位向量系统函数有如下五个:1、$countbits ( expression , control_bit { , control_bit }此函数$countbits()的作用是计算位向量中指定的0 1 x z的数量;返回值位一个整数,这个整数就是指定的control_bit的数量。例如:$conutbits(expression, '1),返回表达式中1的数量;$countbits(expression, '0, '1),返回表达式中0和1的数量;$countbithttps://blog.csdn.net/michael177/article/details/120937977

命令行输入

verilog系统函数:$value$plusargs、$test$plusargs_lu-ming.xyz的博客-CSDN博客_$value$plusargs命令行输入读取文件以获取用于模拟的信息的另一种方法是使用调用仿真器的命令来指定信息。该信息以**可选参数(plusargs)**的形式提供给仿真器。这些参数形式上与其他仿真器参数不同,因为它们以加号(+)字符开头。作用:运行仿真时输入参数$test$plusargs (string)*用于只输入字符串时系统函数$test$plusarg搜索用户指定的plusarg_string的plusargs列表。字符串在系统函数的参数中指定为字符串或被解释为字符串的非实数变量。这个字符串不包含命令行参数的前导https://blog.csdn.net/lum250/article/details/120919673

画一半的结构图,跑完仿真还是得再完善。画图太慢,还不如上一篇那样文字描述,多次总结。

 

ch_pkg代码

package ch_pkg;

semaphore run_stop_flags=new();//创建这个运行停止的标志存放桶
//**************************************************//
class ch_trans;
//首先,对变量做随机化,加入间隔
//Packed arrays can be made of only the single bit data types (bit, logic, reg), enumerated types, and other packed arrays and packed structures. This also means you cannot have packed arrays of integer types with predefined widths (e.g. a packed array of byte).
	rand bit [31:0] data[];//数据变成动态数组(合并数组两边都有[]的只能用单比特的数据类型比如bit logic reg、枚举类型)
	rand int channel_id;
	rand int pkt_id;
	rand int data_idle;
	rand int pkt_idle;
	     bit rsp;
	local static int object_id=0;//静态变量,一开始就分配了空间且一直存在
	
	constraint cstr{
					data.size inside {[4:8]};
					foreach(data[i])//按一定规律给出数据(伪随机数)
						data[i]=='h00C0_0000+(this.channel_id<<24)+i;
					soft channel_id==0;
					soft pkt_id==0;
					data_idle inside{[0:2]};
					pkt_idle inside{[1:10]};//注意没有加soft,必须实现
	};
	//定义变量和约束后,每个类都需要做的是new函数,初始化/例化?
	function new();
		object_id++;
	endfunction
	//克隆函数,所有变量复制一次
	function ch_trans clone();
		ch_trans c;
		c=new();//这两可以写成一句 ch_trans c = new();
		c.data       =this.data;
		c.channel_id =this.channel_id;
		c.pkt_id     =this.pkt_id;
		c.data_idle  =this.data_idle;
		c.pkt_idle   =this.pkt_idle;
		c.rsp        =this.rsp;
		return c;
	endfunction
	
	function string sprint();
		string s;
		s={s, $sformatf("==============\n")};
		s={s, $sformatf("ch_trans object content\n")};
		s={s, $sformatf("object_id=%0d", this.object_id)};
		foreach(data[i])
			s={s, $sformatf("data[%0d]=%8x \n", i, this.data[i])};
		s={s, $sformatf("channel_id=%0d \n", this.channel_id)};
		s={s, $sformatf("pkt_id=%0d \n", this.pkt_id)};
		s={s, $sformatf("data_idle=%0d \n", this.data_idle)};
		s={s, $sformatf("pkt_idle=%0d \n", this.pkt_idle)};
		s={s, $sformatf("rsp=%0d \n", this.rsp)};
		s={s, $sformatf("==============\n")};
		return s;//这里要返回s
	endfunction
	
endclass

//**************************************************//
class initiator_chen;
virtual interface_chen intf;//virtual表示在子类中会被调用到,声明类的成员变量接口指针必须用virtual
mailbox #(ch_trans) req_mailbox;
mailbox #(ch_trans) rsp_mailbox;//不用例化,只取gen中的用,但要声明

local string name;

function new(string name="initiator_chen");
	this.name=name;
endfunction

function void set_interface(virtual interface_chen intf);
	if(intf==null)
		$error("null, need to be intantiated.");
	else this.intf=intf;
endfunction

task run();
	this.drive();//要加this表示这个class中的drive
endtask

task drive();//取出gen的mb,取完放在哪里?句柄,而且是ch_trans
	ch_trans req, rsp;
	@(posedge intf.rstn)//复位后开始一直执行
	forever begin
		this.req_mailbox.get(req);//先取
		this.chnl_write(req);//后用
		rsp=req.clone();//再复制和点亮
		rsp.rsp=1;
		this.rsp_mailbox.put(rsp);//最后放
		end
endtask

task chnl_write (input ch_trans t);//data变成动态数组,要做相应的改变
	foreach(t.data[i]) begin
	@(posedge intf.clk);
	intf.drv_clk.channel_valid<=1'b1;
	intf.drv_clk.channel_data<=t.data[i];//data要加t.引用
	@(negedge intf.clk);
	wait(intf.channel_ready==1'b1);
	$display("%t channel initial [%s] sent data %x", $time, name, t.data[i]);
	repeat (t.data_idle) channel_idle();//原来的idle由ch_trans中的data_idle替代
	end
	repeat (t.pkt_idle) channel_idle();
endtask

task channel_idle();
	@(posedge intf.clk);
	intf.drv_clk.channel_valid<=1'b0;
	intf.drv_clk.channel_data<=1'b0;
endtask

endclass 

//**************************************************//
class generator_chen;
    rand int pkt_id = -1;
    rand int channel_id = -1;
    rand int data_idle = -1;
    rand int pkt_idle = -1;
    rand int data_size = -1;
    rand int ntrans = 10;
    constraint cstr{
      soft channel_id == -1;
      soft pkt_id == -1;
      soft data_size == -1;
      soft data_idle == -1;
      soft pkt_idle == -1;
      soft ntrans == 10;
    }

mailbox #(ch_trans) req_mailbox;
mailbox #(ch_trans) rsp_mailbox;

function new();//例化两个信箱
	this.req_mailbox=new();
	this.rsp_mailbox=new();
endfunction

task run();
	repeat(ntrans) send_ntrans();
	run_stop_flags.put();
endtask

task send_ntrans();
	ch_trans req, rsp;
	req=new();//想随机化必须先例化?
	assert(req.randomize with { local::channel_id>=0  -> channel_id==local::channel_id;
                                local::pkt_id >= 0    -> pkt_id == local::pkt_id;
                                local::data_idle >= 0 -> data_idle == local::data_idle;
                                local::pkt_idle >= 0  -> pkt_idle == local::pkt_idle;
                                local::data_size >0   -> data.size() == local::data_size;}
			)
		else $fatal("randomization failure");
	this.pkt_id++;
	$display(req.sprint());
	this.req_mailbox.put(req);
	this.rsp_mailbox.get(rsp);
	$display(rsp.sprint());
	assert(rsp.rsp)
		else $error("%0t error response received", $time);
endtask

function string sprint();//同名函数,内容不一样
  string s;
  s = {s, $sformatf("=======================================\n")};
  s = {s, $sformatf("generator_chen object content is as below: \n")};
  s = {s, $sformatf("ntrans = %0d: \n", this.ntrans)};
  s = {s, $sformatf("ch_id = %0d: \n", this.channel_id)};
  s = {s, $sformatf("pkt_id = %0d: \n", this.pkt_id)};
  s = {s, $sformatf("data_nidles = %0d: \n", this.data_idle)};
  s = {s, $sformatf("pkt_nidles = %0d: \n", this.pkt_idle)};
  s = {s, $sformatf("data_size = %0d: \n", this.data_size)};
  s = {s, $sformatf("=======================================\n")};
  return s;
endfunction

function void post_randomize();//在上面randomize之后马上打印出来
	string s;
	s={"after randomization", this.sprint()};
	$display(s);
endfunction

endclass

//**************************************************//
typedef struct packed{
	bit[31:0] data;
	bit[1:0]  id;} monitor_data;
	
//**************************************************//
class channel_monitor;
	local string name;
	local virtual interface_chen intf;
	mailbox #(monitor_data) mon_mailbox;
	
	function new(string name="channel_monitor");
		this.name=name;
	endfunction
	
	function void set_interface(virtual interface_chen intf);
		if(intf==null)
			$error("null");
		else this.intf=intf;
	endfunction
	
	task run();
		this.mon_trans();
	endtask
	
	task mon_trans();
		monitor_data m;
		forever begin
			@(posedge intf.mon_clk iff(intf.mon_clk.channel_valid===1'b1 && intf.mon_clk.channel_ready===1'b1));
			m.data=intf.mon_clk.channel_data;
			mon_mailbox.put(m);
			$display("%0t %s monitored channel data %8x", $time, this.name, m.data);
		end
	endtask
	
endclass

//**************************************************//
class mcdt_monitor;
	local string name;
	local virtual mcdt_chen_interface intf;
	mailbox #(monitor_data) mon_mailbox;
	
	function new(string name="mcdt_monitor");
		this.name=name;
	endfunction
	
	function void set_interface(virtual mcdt_chen_interface intf);
		if(intf==null)
			$error("null");
		else this.intf=intf;
	endfunction
	
	task run();
		this.mon_trans();
	endtask

	task mon_trans();
		monitor_data m;
		forever begin
			@(posedge intf.mon_clk iff(intf.mon_clk.mcdt_valid===1'b1));
			m.data=intf.mon_clk.mcdt_data_output;
			m.id=intf.mon_clk.mcdt_id;
			mon_mailbox.put(m);
			$display("%0t %s monitored channel data %8x and id %0d", $time, this.name, m.data, m.id);
		end
	endtask
endclass

//**************************************************//	
class checker_chen;
mailbox #(monitor_data) mon_input[3];
mailbox #(monitor_data) mon_output;
local string name;
local int error_count;
local int comp_count;

function new(string name="checker_chen");
	this.name=name;
	foreach(mon_input[i])
		this.mon_input[i]=new();
	this.mon_output=new();
endfunction

task run();
	this.compare();
endtask

task compare();//typedef的monitor_data也有句柄?
	monitor_data in, out;
	forever begin
		mon_output.get(out);
		case(out.id)
			1: mon_input[0].get(in);
			2: mon_input[1].get(in);
			3: mon_input[2].get(in);
		default: $fatal("id %0d is not avalidable", out.id);
		endcase
	if(out.data != in.data) begin
		this.error_count++;
		$error("mcdt_data_output %8x, channel id %0d is not equal with channel in data %8x", out.data, out.id, in.data);
			end
		else begin
		$display("%8x, %0d,= %8x", out.data, out.id, in.data);
			end
		this.comp_count++;
	end
endtask

endclass
		
//**************************************************//				 
class ch_agent;
	channel_monitor ch_mon;
	initiator_chen init;
	local string name;
	virtual interface_chen aintf;
	
	function new(string name="ch_agent");
		this.name=name;
		this.ch_mon=new(name);
		this.init=new(name);
	endfunction
	
	function void set_interface(virtual interface_chen aintf);
		this.aintf=aintf;
		init.set_interface(aintf);
		ch_mon.set_interface(aintf);
	endfunction
	
	task run();
		fork
			init.run();
			ch_mon.run();
		join
	endtask
endclass 

//**************************************************//
class root_test;
	//声明所有句柄
	ch_agent agent[3];
	generator_chen gen[3];
	checker_chen chk;
	mcdt_monitor mcdt_mon;
	protected string name;
	event gen_stop_event;
	
	function new(string name="root_test");
		this.chk=new();
		this.name=name;
		foreach(agent[i]) begin
			this.agent[i]=new($sformatf("ch_agent%0d", i));//不仅要new,还要给id
			this.gen[i]=new();//可以直接和agent共用这个foreach
			this.agent[i].init.req_mailbox=this.gen[i].req_mailbox;
			this.agent[i].init.rsp_mailbox=this.gen[i].rsp_mailbox;
			this.agent[i].ch_mon.mon_mailbox=this.chk.mon_input[i];
			end
		this.mcdt_mon=new();
		this.mcdt_mon.mon_mailbox=this.chk.mon_output;
		$display("%s instantiated and connected objects", this.name );
	endfunction
	
	virtual task run();
		$display($sformatf("*****************%s started********************", this.name));
		this.do_config();
		fork
			agent[0].run();
			agent[1].run();
			agent[2].run();
			mcdt_mon.run();
			chk.run();
		join_none
		fork
			this.gen_stop_callback();
			@(this.gen_stop_event) disable gen_run;
		join_none
		fork: gen_run
			gen[0].run();
			gen[1].run();
			gen[2].run();
		join
		
		run_stop_callback();
	endtask
	
	virtual function void do_config();
	endfunction
	
	virtual task gen_stop_callback();
	endtask
	
	virtual task run_stop_callback();
		$display("run_stop_callback enterred");
		$display("%s: wait for all generators have generated and tranferred transcations", this.name);
		run_stop_flags.get(3);//一开始就例化了
        $display($sformatf("*****************%s finished********************", this.name));
        $finish();
    endtask
	
	virtual function void set_interface(virtual interface_chen intf1
									   ,virtual interface_chen intf2
									   ,virtual interface_chen intf3
									   ,virtual mcdt_chen_interface mcdt_intf);
		agent[0].set_interface(intf1);
		agent[1].set_interface(intf2);
		agent[2].set_interface(intf3);
	endfunction
endclass

//**************************************************//
class basic_test extends root_test;
function new(string name="basic_test");
	super.new(name);
endfunction

virtual function void do_config();//root里面给空,virtual多态在这里写具体的
	super.do_config();
	assert(gen[0].randomize() with {ntrans==100;
									data_idle==0;
									pkt_idle==1;
									data_size==8;})
	else $fatal("gen[0] randomization failure");
	
	assert(gen[1].randomize() with {ntrans==50;
									data_idle inside {[1:2]};
									pkt_idle inside {[3:5]};
									data_size==6;})
	else $fatal("gen[1] randomization failure");

	assert(gen[2].randomize() with {ntrans==80;
									data_idle inside {[0:1]};
									pkt_idle inside {[1:2]};
									data_size==32;})
	else $fatal("gen[2] randomization failure");
endfunction
endclass: basic_test
//**************************************************//
class burst_test extends root_test;
function new(string name="burst_test");
	super.new(name);
endfunction

virtual function void do_config();//root里面给空,virtual多态在这里写具体的
	super.do_config();
    assert(gen[0].randomize() with {ntrans inside {[80:100]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[0] randomization failure!");
		
    assert(gen[1].randomize() with {ntrans inside {[80:100]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[1] randomization failure!");
		
    assert(gen[2].randomize() with {ntrans inside {[80:100]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[2] randomization failure!");
endfunction
endclass: burst_test
//**************************************************//
class full_test extends root_test;
function new(string name="full_test");
	super.new(name);
endfunction

virtual function void do_config();
	super.do_config();
    assert(gen[0].randomize() with {ntrans inside {[1000:2000]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[0] randomization failure!");
		
    assert(gen[1].randomize() with {ntrans inside {[1000:2000]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[1] randomization failure!");
		
    assert(gen[2].randomize() with {ntrans inside {[1000:2000]}; 
									data_idle==0; 
									pkt_idle==1; 
									data_size inside {8, 16, 32};})
        else $fatal("[RNDFAIL] gen[2] randomization failure!");
endfunction
//这里报错(vlog-13169) Packed dimension must specify a range.
local function bit[0:2] get_channel_ready_flag();
	return{agent[2].aintf.mon_clk.channel_ready
		  ,agent[1].aintf.mon_clk.channel_ready
		  ,agent[0].aintf.mon_clk.channel_ready};//是agent中的接口,命名成了aintf
endfunction

virtual task gen_stop_callback();
	bit[0:2] channel_ready_flag;//表示赋值?
	$display("gen_stop_callback enterred");
	@(posedge agent[0].aintf.rstn);
	forever begin
		@(posedge agent[0].aintf.clk);
		channel_ready_flag=this.get_channel_ready_flag();
		if($countones(channel_ready_flag)<=1) break;//只剩一个以下的通道不给写入数据了,就break
		//这个还得再商榷一下
		end
	$display("%s: stop 3 generators running", this.name);
	-> this.gen_stop_event;//这个就是gen_stop的event
endtask

virtual task run_stop_callback();
	$display("run_stop_callback enterred");
	$display("%s: waiting DUT transfering all of data", this.name);
	fork
		wait(agent[0].aintf.slave_margin=='h0);
		wait(agent[1].aintf.slave_margin=='h0);
		wait(agent[2].aintf.slave_margin=='h0);
	join
	$display("%s: 3 channel fifos have transferred all data", this.name);
    $display($sformatf("*****************%s finished********************", this.name));
    $finish();
endtask

endclass: full_test
		
//**************************************************//
endpackage :ch_pkg
//**************************************************//

tb代码

`timescale 1ns/1ps
//*********************接口多了个mcdt的,monitor也需要时钟块**************************//
interface interface_chen (input clk, input rstn);

logic [31:0] channel_data;
logic        channel_valid;
logic        channel_ready;
logic [ 7:0] slave_margin;

clocking drv_clk @(posedge clk);
	default input #1ns output #1ns;
	input  channel_ready, slave_margin;//采样
	output channel_data, channel_valid;//驱动
endclocking 
//定义了monitor的时钟块
clocking mon_clk @(posedge clk);
	default input #1ns output #1ns;
	input channel_ready, slave_margin, channel_data, channel_valid;
endclocking

endinterface 

interface mcdt_chen_interface (input clk, input rstn);
//存放mcdt三个输出,monitor的时钟块
logic [31:0] mcdt_data_output;
logic        mcdt_valid;
logic [ 1:0] mcdt_id;

clocking mon_clk @(posedge clk);
	default input #1ns output #1ns;
	input mcdt_data_output, mcdt_valid, mcdt_id;//都是input
endclocking

endinterface 
//**************************************************//

module tb1_chen();//

logic          clk;
logic          rstn;
//原来的3个mcdt输出变成了接口


mcdt_chen dut(//括号里面的信号变成接口里面的
   .clk(clk)
  ,.rstn(rstn)
  
  ,.channel1_data(ch1_intf.channel_data)//信号改为接口中的名称
  ,.channel1_valid(ch1_intf.channel_valid)
  ,.slave1_margin(ch1_intf.slave_margin)
  ,.channell_ready(ch1_intf.channel_ready)

  
  ,.channel2_data(ch2_intf.channel_data)
  ,.channel2_valid(ch2_intf.channel_valid)
  ,.channel2_ready(ch2_intf.channel_ready)
  ,.slave2_margin(ch2_intf.slave_margin)

  
  ,.channel3_data(ch3_intf.channel_data)
  ,.channel3_valid(ch3_intf.channel_valid)
  ,.channel3_ready(ch3_intf.channel_ready)
  ,.slave3_margin(ch3_intf.slave_margin)

  
  ,.mcdt_data_output(mcdt_data_output)
  ,.mcdt_valid(mcdt_valid)
  ,.mcdt_id(mcdt_id)
);


//*****************clk和rstn******************************//
task clk_gen(input int T);
  clk <= 0;
  forever begin
    #(T/2) clk<= !clk;
  end
endtask

initial begin
  clk_gen(10);
end

task rstn_gen();
  #10 rstn <= 0;
  repeat(20) @(posedge clk);
  rstn <= 1;
endtask

initial begin
  rstn_gen();
end

import ch_pkg::*;//引入包中所有的类 

//**************************************************//
basic_test b1;
burst_test b2;
full_test  b3;
root_test test[string];
string name;


//**************接口************************//
interface_chen ch1_intf(.*);
interface_chen ch2_intf(.*);
interface_chen ch3_intf(.*);
mcdt_chen_interface mcdt_intf(.*);



initial begin
	b1=new();
	b2=new();
	b3=new();
	test["basic_test"]=b1;
	test["burst_test"]=b2;
	test["full_test"]=b3;
	if($value$plusargs("TESTNAME=%s", name)) begin
		if(test.exists(name)) begin//函数exists()来检查元素是否存在。
			test[name].set_interface(ch1_intf, ch2_intf, ch3_intf, mcdt_intf);
			test[name].run();
			end
		else begin
			$fatal($sformatf("[ERRTEST], test name %s is invalid, please specify a valid name!", name));
		end
	end
end

endmodule  

以上编译已经通过,可以打开仿真,结果如何等今晚再校验。

2022年7月2日18:21:55


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值