好久没用博客园来,虽然以前也几乎没怎么用,但还是想慢慢用来,最近在学习uvm,一些心得体会,比较浅显的认识,但还是希望记录下来。
现有验证平台基本上都是基于VHDL完成的,验证工作通过的流程基本如下:
1.根据描述学习验证代码实现功能
2.制定Testing计划,根据功能要求提出关键性的feature,每条case针对一种或几种feature(相当于定向测试)
3.针对DUT完成验证平台的搭建,这一步通常是各自完成,但是由于很多case比较类似,因此相互之间很多可以借鉴共享,但是每条case的DUT都有一定的针对性。
4.验证功能,寻找Bug,对实现功能不清楚的地方和设计一起check,最后所有case测试完成以后进行review,看有没有需要进一步改进并测试的地方。
所以基本上现在的工作中没有用到方法学中的那套东西,这类测试平台搭建有其优点:
1.比较容易理解,因为从结构上而言,和设计级别的代码没有太多区别,抽象级别并不是很高,所以可以比较容易的从模块的互联互通上了解整个平台实现的功能。
2.针对性比较强,针对不同feature的平台搭建有复杂又简单,对于简单的测试内容,搭建测试平台较为容易。
3.测试更接近设计,平台的搭建自底向上,一般可以便搭建平台便查看DUT波形,通过最直接的波形来完成平台的搭建,保证所完成的case不会因为平台产生过多问题。
但是,这样的方式也是问题多多,首先,平台通用性比较差,尽管在实际工作中,已经将各类功能一定程度上抽象出来,代码可以实现重用,但是毕竟封装的层次有限,用户可以很容易对代码进行一定修改(可以比较容易实现特定功能,但是为后期维护带来麻烦)。同时,使用VHDL进行一些验证功能实现的时候,实现一些常用功能较为麻烦,很多时候需要像设计一个模块一样对待一个功能的设计,而且,会花费很多精力在模块的互联上,等等。
之前也查找过适用于VHDL的方法学,简单了解了一下,使用了其中很小一部分功能(生成随机数),但是在使用中还是发现很多不太方便的地方,最直接的问题是,在VHDL中package的申明和调用关系比较严格,编译时候必须严格按照包涵的次序,不然很容易报错。其次,查看源码后发现之前使用的那个随机功能其实也较弱,因此,并没有太深入的去了解下去。
最近工作比较闲,决定花点时间好好研究一下现在流行的方法学,看看能否给自己今后的工作带来一些启发。其实之前同事就推荐过UVM,不过并没有花精力去好好了解一下,毕竟,我本身没有systemverilog的基础,所以一直有些望而却步。下定决心后,花了几天时间泛读了一下《Systemverilog验证/测试平台编写指南》这本书,感受最深的是OOP以及为覆盖率的概念。个人的感受是,如果没有通过C++或是JAVA这类软件语言学习过OOP,而是从verilog到systemverilog,对于OOP的理解可能会费力一些,我的理解是,systemverilog毕竟是通过借鉴软件语言的方式来扩展verilog,而verilog本质上又不是编程语言(硬件描述语言),所以systemverilog总给我一种依葫芦画瓢的感觉,好用,但是有些变扭。我觉得sv得到业界大力支持的地方首先是他在硬件描述方面的能力,得益于verilog,其次是对软件工程上OOP概念的借鉴,可以完成复杂功能设计。
站在高一点的角度说,作为验证,特别是系统级别的验证,其实非常接近于软件层面,testbench要完成软件之于硬件的工作,又要能对硬件的功能信号进行分析,实现这样的方法有很多,就目前工作中使用的方式是VHDL加上C++进行系统级的仿真,其之间通过FLI接口进行交互。使用编程语言的好处是,仿真环境更接近真实,但是调试过程比较费劲,因为整个环境的运行需要modelsim以及GCC联合进行,中间通过动态链接库交换信息,如果想要对硬件环境进行干预的话比较麻烦,最终的debug方式往往只能通过C语言运行平台打印出来的信息进行判断,而且仿真的时间比较漫长,50ms的过程需要仿真数小时。其中,对硬件的干预能力弱是一个主要问题。作为systemverilog,其编写的方式更加软件化,又不失硬件语言的本质,因此成为业界主流的验证语言也就顺理成章了。
在学习UVM中,我觉得其实对于整个UVM验证平台的结构组成上,理解起来并不是太费劲,一般典型的结构就如下图所示那样(图片来源:UVM1.1应用指南及源码分析)
而简单的验证平台可能只包含driver、monitor甚至连reference model和scoreboard都没有,完全通过人力去比对,想想就感觉非常蛋疼。这也是为什么我非常想学习UVM的原因。UVM对于整个验证平台的分门别类,可以让我非常轻松的搭建起一个具有完整功能的平台,也避免了大家重复造轮子。
这样归类以后,验证平台的顶层就变成了下面这个样子,短短几十行内容,而具体的东西,例如,dut与平台间的互联互通、业务的生成、数据的比对工作等,就分散到了最顶上include进来的各个模块中,使用和修改起来都非常方便。
(代码来源:UVM实战)
`timescale 1ns/1ps `include "uvm_macros.svh" import uvm_pkg::*; `include "my_if.sv" `include "my_transaction.sv" `include "my_driver.sv" `include "my_monitor.sv" `include "my_agent.sv" `include "my_model.sv" `include "my_scoreboard.sv" `include "my_env.sv" module top_tb; reg clk; reg rst_n; reg[7:0] rxd; reg rx_dv; wire[7:0] txd; wire tx_en; my_if input_if(clk, rst_n); my_if output_if(clk, rst_n); dut my_dut(.clk(clk), .rst_n(rst_n), .rxd(input_if.data), .rx_dv(input_if.valid), .txd(output_if.data), .tx_en(output_if.valid)); initial begin clk = 0; forever begin #100 clk = ~clk; end end initial begin rst_n = 1'b0; #1000; rst_n = 1'b1; end initial begin run_test("my_env"); end initial begin uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.drv", "vif", input_if); uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.i_agt.mon", "vif", input_if); uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.o_agt.mon", "vif", output_if); end endmodule
下面一个是我使用vhdl编写的测试平台代码,某些部分由于利益关系已经隐去,看一下大致的实现就好。
可以看到整个测试平台的代码非常庞大,节凑层次并不是很清晰,看起来比较费劲。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_textio.all; use ieee.numeric_std.all; library std; use std.textio.all; use ieee.std_logic_misc.all; use ieee.math_real.all; library c; use c.stdio_h.all; use work.tb_***_pkg.all; library ??????????????; use ????????????.data_type_package.all; --------------------------------spec of testcase---------------------------------------------------------------------------------------- --basic structure for mutlti channel case: -- --gen indivual prbs block for each *** channel -- _________ __ --| |==>| \ ___________________ --|__prbs1__|<==| \ <-----------prbs_gen_sel---------------------------------------|__regular_pkt_send__| -- _________ | \ _______________________ || --| |==>| |<----------prbs_chk_sel----------------|__regular_pkt_receive__| || --|__prbs2__|<==| 12 | /\ || -- _________ | chan| ________||_________________ \/_____ --| |==>| sel | ___________ | | --|__prbs3__|<==| |===prbs_gen_dout_sel===>| | | | -- . | |<==prbs_chk_din_sel=====|????? rx&tx|<===>| DUT | -- . | | |___________| |___________________________________| -- . | | -- _________ | / --| |==>| / --|__prbs12_|<==|/ ------------------------------------------------------------------------------------------------------------------------ entity testcase1012xxx12345_&&& is generic ( channel_number :integer :=12 ); end testcase1012xxx12345_&&&; architecture sch of testcase1012xxx12345_&&& is component xxx12345_&&& generic ( ###_enable : integer := 1; --1: use ### interface ,0 use ????? interface in FE mode channel_number : integer := 12; max_channel_id : integer := 20; ethernet_head_length : integer := 23 --WDM *** over ethernet protocal ); port ( clkUnknow_reset_l : in std_logic; clkUnknow : in std_logic; ***_proc_rh_wl : in std_logic; ***_proc_exec : in std_logic; ***_proc_op_done : out std_logic; ***_proc_address : in std_logic_vector(13 downto 0); ***_proc_wr_data : in std_logic_vector(31 downto 0); ***_proc_rd_data : out std_logic_vector(31 downto 0); xxx12345_&&&_rh_wl : in std_logic; xxx12345_&&&_exec : in std_logic; xxx12345_&&&_op_done : out std_logic; xxx12345_&&&_address : in std_logic_vector(8 downto 0); xxx12345_&&&_wr_data : in std_logic_vector(31 downto 0); xxx12345_&&&_rd_data : out std_logic_vector(31 downto 0); clkunknow_reset_l : in std_logic_vector(channel_number-1 downto 0); clkunknow : in std_logic_vector(channel_number-1 downto 0); clkunknow_rxohfp : in std_logic_vector(channel_number-1 downto 0); clkunknow_rxohd : in std_logic_vector(channel_number-1 downto 0); clkunknow_txohfp : in std_logic_vector(channel_number-1 downto 0); clkunknow_txohd : out std_logic_vector(channel_number-1 downto 0); ###_inclk : out std_logic; ###_ind0 : in std_logic := '0'; ###_ind1 : in std_logic := '0'; ###_ind2 : in std_logic := '0'; ###_ind3 : in std_logic := '0'; ###_indv : in std_logic := '0'; ###_outclk : out std_logic; ###_outd0 : out std_logic; ###_outd1 : out std_logic; ###_outd2 : out std_logic; ###_outd3 : out std_logic; ###_outdv : out std_logic; ?????_rx_d : in std_logic_vector(7 downto 0) := (others => '0'); ?????_rx_dv : in std_logic := '0'; ?????_rx_er : in std_logic := '0'; ?????_rxclk_en : in std_logic := '0'; ?????_tx_d : out std_logic_vector(7 downto 0); ?????_tx_en : out std_logic; ?????_tx_er : out std_logic; ?????_txclk_en : out std_logic ); end component; component prbs31_8bit generic ( chk_mode : boolean; data_out_reg : integer); port ( reset_l : in std_logic; clk : in std_logic; inv_pattern : in std_logic; data_in : in std_logic_vector(8 - 1 downto 0); en_in : in std_logic; data_out : out std_logic_vector(8 - 1 downto 0); en_out : out std_logic); end component; component crc_gen port ( rst : in std_logic; tx_clk : in std_logic; tx_clken : in std_logic; tx_d : in std_logic_vector(7 downto 0); tx_den : in std_logic; crc_out : out std_logic_vector(31 downto 0)); end component; component crc_chk port ( rst : in std_logic; rx_clk : in std_logic; rx_clken : in std_logic; rx_d : in std_logic_vector(7 downto 0); rx_dv : in std_logic; rx_eop : in std_logic; crc_err : out std_logic); end component; signal reset_l : std_logic; signal clkUnknow : std_logic; signal clkunknow : std_logic_vector(channel_number-1 downto 0); signal clkunknow_reset_l : std_logic_vector(channel_number-1 downto 0); signal ***_rh_wl : std_logic; signal ***_exec : std_logic; signal ***_op_done : std_logic; signal ***_address : std_logic_vector(13 downto 0); signal ***_wr_data : std_logic_vector(31 downto 0); signal ***_rd_data : std_logic_vector(31 downto 0); signal &&&&_rh_wl : std_logic; signal &&&&_exec : std_logic; signal &&&&_op_done : std_logic; signal &&&&_address : std_logic_vector(8 downto 0); signal &&&&_wr_data : std_logic_vector(31 downto 0); signal &&&&_rd_data : std_logic_vector(31 downto 0); signal clkunknow_rxohfp : std_logic_vector(channel_number-1 downto 0); signal clkunknow_rxohd : std_logic_vector(channel_number-1 downto 0); signal clkunknow_txohfp : std_logic_vector(channel_number-1 downto 0); signal clkunknow_txohd : std_logic_vector(channel_number-1 downto 0); signal ?????_rx_d : std_logic_vector(7 downto 0); signal ?????_rx_dv : std_logic; signal ?????_rx_er : std_logic; signal ?????_rxclk_en : std_logic; signal ?????_tx_d : std_logic_vector(7 downto 0); signal ?????_tx_en : std_logic; signal ?????_tx_er : std_logic; signal ?????_txclk_en : std_logic; signal ?????_rx_crc_out : std_logic_vector(31 downto 0); signal ?????_tx_eop : std_logic; signal ?????_tx_crc_err : std_logic; signal prbs_gen_en_s : std_logic; signal prbs_gen_en : std_logic_vector(channel_number-1 downto 0); signal prbs_gen_dout : STD_BUS_W8(channel_number-1 downto 0); signal prbs_gen_dout_sel : std_logic_vector(7 downto 0); signal prbs_chk_din_sel : std_logic_vector(7 downto 0); signal prbs_chk_res_sel : std_logic_vector(7 downto 0); signal prbs_chk_din : STD_BUS_W8(channel_number-1 downto 0); signal prbs_chk_dv : std_logic_vector(channel_number-1 downto 0); signal prbs_chk_dv_s : std_logic; signal prbs_chk_res : STD_BUS_W8(channel_number-1 downto 0); signal prbs_gen_sel : std_logic_vector(7 downto 0) := X"01"; signal prbs_chk_sel : std_logic_vector(7 downto 0) := X"01"; signal reg_acc_no : integer := 0; signal strobe_pkt_no : integer := 0; signal send_pkt_no : integer := 0; signal ?????_rx_dv_crc : std_logic; signal ?????_tx_en_crc : std_logic; signal ?????_rxclk_en_crc : std_logic; signal bitcount : std_logic_vector(9 downto 0); signal bitcount_d2 : std_logic_vector(9 downto 0); signal bytecount : std_logic_vector(5 downto 0); signal multiframecount : std_logic_vector(7 downto 0); constant ETHERNET_MIN_GAP : natural := 12; constant PAYLOAD_LEN : natural := 64; -- include DA--SA--VLAN tag--TYPE--Physical Channel ID--ECC ID--CRC--total 27,1573 contents constant PACKET_NUMBER : natural := 5; -- packet number you wanna send on each channel type port_map_list_type is array (natural range<>) of natural; constant ?????_tx_port_map_list : port_map_list_type := (1,2,3,4,5,6,7,8,9,10,11,12); constant ?????_rx_port_map_list : port_map_list_type := (1,2,3,4,5,6,7,8,9,10,11,12); signal reg_config_done : std_logic; -- reg configuration complete flag singal begin process begin reset_l <= '0'; wait for 100 ns; reset_l <= '1'; wait; end process; process begin clkunknow_reset_l <= (others => '0'); wait for 100 ns; clkunknow_reset_l <= (others => '1'); wait; end process; process begin clkUnknow <= '0'; wait for 4 ns; clkUnknow <= '1'; wait for 4 ns; end process; process begin clkunknow <= (others => '0'); wait for 11.11 ns; clkunknow <= (others => '1'); wait for 11.11 ns; end process; --selector of prbs_gen_en signal process(prbs_gen_sel,prbs_gen_en,prbs_gen_en_s,?????_rxclk_en) begin case prbs_gen_sel is when X"01" => prbs_gen_en(0) <= prbs_gen_en_s and ?????_rxclk_en; when X"02" => prbs_gen_en(1) <= prbs_gen_en_s and ?????_rxclk_en; when X"03" => prbs_gen_en(2) <= prbs_gen_en_s and ?????_rxclk_en; when X"04" => prbs_gen_en(3) <= prbs_gen_en_s and ?????_rxclk_en; when X"05" => prbs_gen_en(4) <= prbs_gen_en_s and ?????_rxclk_en; when X"06" => prbs_gen_en(5) <= prbs_gen_en_s and ?????_rxclk_en; when X"07" => prbs_gen_en(6) <= prbs_gen_en_s and ?????_rxclk_en; when X"08" => prbs_gen_en(7) <= prbs_gen_en_s and ?????_rxclk_en; when X"09" => prbs_gen_en(8) <= prbs_gen_en_s and ?????_rxclk_en; when X"0a" => prbs_gen_en(9) <= prbs_gen_en_s and ?????_rxclk_en; when X"0b" => prbs_gen_en(10) <= prbs_gen_en_s and ?????_rxclk_en; when X"0c" => prbs_gen_en(11) <= prbs_gen_en_s and ?????_rxclk_en; when others => null; end case; end process; --selector of prbs_gen_dout_sel signal process(prbs_gen_sel,prbs_gen_dout_sel,prbs_gen_dout) begin case prbs_gen_sel is when X"01" => prbs_gen_dout_sel <= prbs_gen_dout(0); when X"02" => prbs_gen_dout_sel <= prbs_gen_dout(1); when X"03" => prbs_gen_dout_sel <= prbs_gen_dout(2); when X"04" => prbs_gen_dout_sel <= prbs_gen_dout(3); when X"05" => prbs_gen_dout_sel <= prbs_gen_dout(4); when X"06" => prbs_gen_dout_sel <= prbs_gen_dout(5); when X"07" => prbs_gen_dout_sel <= prbs_gen_dout(6); when X"08" => prbs_gen_dout_sel <= prbs_gen_dout(7); when X"09" => prbs_gen_dout_sel <= prbs_gen_dout(8); when X"0a" => prbs_gen_dout_sel <= prbs_gen_dout(9); when X"0b" => prbs_gen_dout_sel <= prbs_gen_dout(10); when X"0c" => prbs_gen_dout_sel <= prbs_gen_dout(11); when others => null; end case; end process; --selector of prbs_chk_res_sel signal process(prbs_chk_sel,prbs_chk_res_sel,prbs_chk_res) begin case prbs_chk_sel is when X"01" => prbs_chk_res_sel <= prbs_chk_res(0); when X"02" => prbs_chk_res_sel <= prbs_chk_res(1); when X"03" => prbs_chk_res_sel <= prbs_chk_res(2); when X"04" => prbs_chk_res_sel <= prbs_chk_res(3); when X"05" => prbs_chk_res_sel <= prbs_chk_res(4); when X"06" => prbs_chk_res_sel <= prbs_chk_res(5); when X"07" => prbs_chk_res_sel <= prbs_chk_res(6); when X"08" => prbs_chk_res_sel <= prbs_chk_res(7); when X"09" => prbs_chk_res_sel <= prbs_chk_res(8); when X"0a" => prbs_chk_res_sel <= prbs_chk_res(9); when X"0b" => prbs_chk_res_sel <= prbs_chk_res(10); when X"0c" => prbs_chk_res_sel <= prbs_chk_res(11); when others => null; end case; end process; --selector of prbs_chk_din signal process(prbs_chk_sel,prbs_chk_din,prbs_chk_din_sel) begin case prbs_chk_sel is when X"01" => prbs_chk_din(0) <= prbs_chk_din_sel; when X"02" => prbs_chk_din(1) <= prbs_chk_din_sel; when X"03" => prbs_chk_din(2) <= prbs_chk_din_sel; when X"04" => prbs_chk_din(3) <= prbs_chk_din_sel; when X"05" => prbs_chk_din(4) <= prbs_chk_din_sel; when X"06" => prbs_chk_din(5) <= prbs_chk_din_sel; when X"07" => prbs_chk_din(6) <= prbs_chk_din_sel; when X"08" => prbs_chk_din(7) <= prbs_chk_din_sel; when X"09" => prbs_chk_din(8) <= prbs_chk_din_sel; when X"0a" => prbs_chk_din(9) <= prbs_chk_din_sel; when X"0b" => prbs_chk_din(10) <= prbs_chk_din_sel; when X"0c" => prbs_chk_din(11) <= prbs_chk_din_sel; when others => null; end case; end process; --selector of prbs_chk_dv signal process(prbs_chk_sel,prbs_chk_dv,prbs_chk_dv_s,?????_txclk_en) begin case prbs_chk_sel is when X"01" => prbs_chk_dv(0) <= prbs_chk_dv_s and ?????_txclk_en; when X"02" => prbs_chk_dv(1) <= prbs_chk_dv_s and ?????_txclk_en; when X"03" => prbs_chk_dv(2) <= prbs_chk_dv_s and ?????_txclk_en; when X"04" => prbs_chk_dv(3) <= prbs_chk_dv_s and ?????_txclk_en; when X"05" => prbs_chk_dv(4) <= prbs_chk_dv_s and ?????_txclk_en; when X"06" => prbs_chk_dv(5) <= prbs_chk_dv_s and ?????_txclk_en; when X"07" => prbs_chk_dv(6) <= prbs_chk_dv_s and ?????_txclk_en; when X"08" => prbs_chk_dv(7) <= prbs_chk_dv_s and ?????_txclk_en; when X"09" => prbs_chk_dv(8) <= prbs_chk_dv_s and ?????_txclk_en; when X"0a" => prbs_chk_dv(9) <= prbs_chk_dv_s and ?????_txclk_en; when X"0b" => prbs_chk_dv(10) <= prbs_chk_dv_s and ?????_txclk_en; when X"0c" => prbs_chk_dv(11) <= prbs_chk_dv_s and ?????_txclk_en; when others => null; end case; end process; ---------------------------------------------------------------------------------------------------------------------- ---- packet send Configuration ---------------------------------------------------------------------------------------------------------------------- crc_gen_1: crc_gen port map ( rst => reset_l, tx_clk => clkUnknow, tx_clken => ?????_rxclk_en_crc, tx_d => ?????_rx_d, tx_den => ?????_rx_dv_crc, crc_out => ?????_rx_crc_out); crc_chk_1: crc_chk port map ( rst => reset_l, rx_clk => clkUnknow, rx_clken => ?????_txclk_en, rx_d => ?????_tx_d, rx_dv => ?????_tx_en_crc, rx_eop => ?????_tx_eop, crc_err => ?????_tx_crc_err); --generate individual prbs blocks for each channel prbs_gen: for i in 0 to channel_number-1 generate prbs31_8bit_gen:prbs31_8bit generic map ( chk_mode => false, data_out_reg => 0) port map ( reset_l => reset_l, clk => clkUnknow, inv_pattern => '0', data_in => (others=>'0'), en_in => prbs_gen_en(i), data_out => prbs_gen_dout(i), en_out => open); prbs31_8bit_chk: prbs31_8bit generic map ( chk_mode => true, data_out_reg => 0) port map ( reset_l => reset_l, clk => clkUnknow, inv_pattern => '0', data_in => prbs_chk_din(i), en_in => prbs_chk_dv(i), data_out => prbs_chk_res(i), en_out => open); end generate prbs_gen; process begin for i in 0 to 9 loop wait until rising_edge(clkUnknow); if i=6 then ?????_rxclk_en_crc<='1'; else ?????_rxclk_en_crc <='0'; end if; if i=8 then ?????_rxclk_en<='1'; else ?????_rxclk_en <='0'; end if; end loop; -- i in rang 0 to 9 loop end process; ?????_rx_er <= '0'; --modified by ys process (clkunknow(0), clkunknow_reset_l(0)) begin if (clkunknow_reset_l(0) = '0') then bitcount <= (others => '0'); bitcount_d2 <= (others => '0'); elsif (clkunknow(0)'event and clkunknow(0) = '1') then bitcount <= bitcount + 1; if bitcount = "0000000010" then bitcount_d2 <= (others => '0'); else bitcount_d2 <= bitcount_d2 + 1; end if; end if; end process; bytecount <= bitcount_d2(8 downto 3); process (clkunknow(0), clkunknow_reset_l(0)) begin if (clkunknow_reset_l(0) = '0') then clkunknow_txohfp <= (others => '0'); multiframecount <= (others => '0'); elsif (clkunknow(0)'event and clkunknow(0) = '1') then if bitcount = "0000000001" then clkunknow_txohfp <= (others => '1'); elsif bitcount = "0000000010" and multiframecount = "11111111" then clkunknow_txohfp <= (others => '1'); elsif bitcount = "1111111111" then multiframecount <= multiframecount + 1; clkunknow_txohfp <= (others => '0'); else clkunknow_txohfp <= (others => '0'); end if; end if; end process; --end of modification xxx12345_&&&_1: xxx12345_&&& generic map ( ###_enable =>0, channel_number =>12, max_channel_id =>20, ethernet_head_length =>23 ) port map ( clkUnknow_reset_l => reset_l, clkUnknow => clkUnknow, ***_proc_rh_wl => ***_rh_wl, ***_proc_exec => ***_exec, ***_proc_op_done => ***_op_done, ***_proc_address => ***_address, ***_proc_wr_data => ***_wr_data, ***_proc_rd_data => ***_rd_data, xxx12345_&&&_rh_wl => &&&&_rh_wl, xxx12345_&&&_exec => &&&&_exec, xxx12345_&&&_op_done => &&&&_op_done, xxx12345_&&&_address => &&&&_address, xxx12345_&&&_wr_data => &&&&_wr_data, xxx12345_&&&_rd_data => &&&&_rd_data, clkunknow_reset_l => clkunknow_reset_l, clkunknow => clkunknow, clkunknow_rxohfp => clkunknow_rxohfp, clkunknow_rxohd => clkunknow_rxohd, clkunknow_txohfp => clkunknow_txohfp, clkunknow_txohd => clkunknow_txohd, ###_inclk => open, ###_ind0 => open, ###_ind1 => open, ###_ind2 => open, ###_ind3 => open, ###_indv => open, ###_outclk => open, ###_outd0 => open, ###_outd1 => open, ###_outd2 => open, ###_outd3 => open, ###_outdv => open, ?????_rx_d => ?????_rx_d, ?????_rx_dv => ?????_rx_dv, ?????_rx_er => ?????_rx_er, ?????_rxclk_en => ?????_rxclk_en, ?????_tx_d => ?????_tx_d, ?????_tx_en => ?????_tx_en, ?????_tx_er => ?????_tx_er, ?????_txclk_en => ?????_txclk_en ); clkunknow_rxohfp <= clkunknow_txohfp; clkunknow_rxohd <= clkunknow_txohd; Packet_Send : process variable bit_rate : integer range 0 to 5000000 := 5000000; variable pkt_len : integer range 0 to 1700 := 1600; variable crc_value : std_logic_vector(31 downto 0); variable time_record : time; -- use to record packet send process time variable bit_rate_map_gap : real; procedure regular_pkt_send ( DA : in std_logic_vector(47 downto 0); SA : in std_logic_vector(47 downto 0); VLAN_TAG : in std_logic_vector(31 downto 0); ETH_TYPE : in std_logic_vector(15 downto 0); PHY_CHAN : in std_logic_vector(23 downto 0); ECC_ID : in std_logic_vector(15 downto 0); PAYLOAD : in std_logic_vector(7 downto 0); PAYLOAD_LEN : in integer range 0 to 1600; CRC_MASK : in std_logic_vector(31 downto 0)) is begin printf("*send_packet #%x--",send_pkt_no); send_pkt_no <= send_pkt_no+1; printf("DA : %012x SA: %012x VLAN_TAG: %08x ETH_TYPE: %04x PHY_CHAN: %06x ECC_ID: %04x\n",DA,SA,VLAN_TAG,ETH_TYPE,PHY_CHAN,ECC_ID); prbs_gen_sel <= PHY_CHAN(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; ?????_rx_dv <= '1'; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"55"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= X"d5"; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(47 downto 40); ?????_rx_dv_crc <= '1'; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(39 downto 32); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(31 downto 24); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= DA(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(47 downto 40); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(39 downto 32); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(31 downto 24); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= SA(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= VLAN_TAG(31 downto 24); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= VLAN_TAG(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= VLAN_TAG(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= VLAN_TAG(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= ETH_TYPE(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= ETH_TYPE(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= PHY_CHAN(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= PHY_CHAN(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= PHY_CHAN(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= ECC_ID(15 downto 8); --prbs_gen_en_s <= '1'; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= ECC_ID(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= conv_std_logic_vector(PAYLOAD_LEN,16)(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= conv_std_logic_vector(PAYLOAD_LEN,16)(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= conv_std_logic_vector(send_pkt_no,16)(15 downto 8); prbs_gen_en_s <= '1'; -- enable prbs submodule, -- enable signal need 2clk ahead -- before payload wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= conv_std_logic_vector(send_pkt_no,16)(7 downto 0); for i in 0 to PAYLOAD_LEN-1-4 loop -- include 4 bytes added(payload_len*2,packet_num*2) if i=PAYLOAD_LEN-1-4 then prbs_gen_en_s <= '0'; end if; wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= prbs_gen_dout_sel; --?????_rx_d <= x"55"; end loop; -- i in rang 0 to 8 loop wait until rising_clken(clkUnknow,?????_rxclk_en); crc_value := ?????_rx_crc_out XOR CRC_MASK; ?????_rx_d <= crc_value(31 downto 24); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= crc_value(23 downto 16); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= crc_value(15 downto 8); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= crc_value(7 downto 0); wait until rising_clken(clkUnknow,?????_rxclk_en); ?????_rx_d <= x"00"; ?????_rx_dv <= '0'; ?????_rx_dv_crc<='0'; for i in 0 to ETHERNET_MIN_GAP-1 loop wait until rising_clken(clkUnknow,?????_rxclk_en); end loop; -- i end regular_pkt_send; begin ?????_rx_d <= x"00"; ?????_rx_dv <= '0'; ?????_rx_dv_crc <= '0'; prbs_gen_en_s<= '0'; --wait for 10 us; bit_rate :=5000000; --5MHz --logic_1 wait until reg_config_done = '1'; -- pkt send begin after configuration process finished for k in 1 to PACKET_NUMBER loop time_record := now; for i in 1 to channel_number loop regular_pkt_send(X"DD1122334455",X"111111222222",X"81008200",X"88b7",conv_std_logic_vector(?????_rx_port_map_list(i-1),8)&x"02"&conv_std_logic_vector(?????_rx_port_map_list(i-1),8),X"0000",X"D5",PAYLOAD_LEN,X"00000000"); end loop; --i channel loop time_record := now - time_record; bit_rate_map_gap := real(payload_len*10e4)/((255.0/237.0 * 99532.8)*(2.0/(4080.0*4.0))); printf("%f\n",bit_rate_map_gap); wait for bit_rate_map_gap*1 ns - time_record; -- wait enough time to meet ODU bit rate end loop; --k : packet number loop wait; end process Packet_Send; Packet_Receive : process variable oh_match :std_logic; variable prbs_match :std_logic; variable crc_match :std_logic; variable is_match :std_logic; variable seq_num : std_logic_vector(15 downto 0); procedure regular_pkt_receive ( DA : in std_logic_vector(47 downto 0); SA : in std_logic_vector(47 downto 0); VLAN_TAG : in std_logic_vector(31 downto 0); ETH_TYPE : in std_logic_vector(15 downto 0); PHY_CHAN : in std_logic_vector(23 downto 0); ECC_ID : in std_logic_vector(15 downto 0); PAYLOAD : in std_logic_vector(7 downto 0); PAYLOAD_LEN : in integer range 0 to 1600; CRC_MASK : in std_logic_vector(31 downto 0)) is begin oh_match := '1'; prbs_match := '1'; crc_match := '1'; is_match := '1'; wait until (rising_clken(clkUnknow,?????_txclk_en) and ?????_tx_en='1'); printf("*strobe packet #%x: ",strobe_pkt_no); strobe_pkt_no <= strobe_pkt_no+1; printf("DA : %012x SA: %012x VLAN_TAG: %08x ETH_TYPE: %04x PHY_CHAN: %06x ECC_ID: %04x\n",DA,SA,VLAN_TAG,ETH_TYPE,PHY_CHAN,ECC_ID); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); wait until rising_clken(clkUnknow,?????_txclk_en); ?????_tx_en_crc <= '1'; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(47 downto 40) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(39 downto 32) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(31 downto 24) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(23 downto 16) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(15 downto 8) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if DA(7 downto 0) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(47 downto 40) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(39 downto 32) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(31 downto 24) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(23 downto 16) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(15 downto 8) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if SA(7 downto 0) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if VLAN_TAG(31 downto 24) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if VLAN_TAG(23 downto 16) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if VLAN_TAG(15 downto 8) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if VLAN_TAG(7 downto 0) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if ETH_TYPE(15 downto 8) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if ETH_TYPE(7 downto 0) /= ?????_tx_d then oh_match :='0'; end if; -- ignore phy_chan in oh match check process for receiving packets will arrive in random order wait until rising_clken(clkUnknow,?????_txclk_en); --if PHY_CHAN(23 downto 16) /= ?????_tx_d then oh_match :='1'; end if; --modified by ys prbs_chk_sel <= ?????_tx_d; --end of modification wait until rising_clken(clkUnknow,?????_txclk_en); if PHY_CHAN(15 downto 8) /= ?????_tx_d then oh_match :='1'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); --if PHY_CHAN(7 downto 0) /= ?????_tx_d then oh_match :='1'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if ECC_ID(15 downto 8) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); if ECC_ID(7 downto 0) /= ?????_tx_d then oh_match :='0'; end if; wait until rising_clken(clkUnknow,?????_txclk_en); -- PAYLOAD_LEN(15 downto 8) := ?????_tx_d; -- in this -- version the receive payload length is set by the module -- input, will change in other version wait until rising_clken(clkUnknow,?????_txclk_en); --PAYLOAD_LEN(7 downto 0) := ?????_tx_d; wait until rising_clken(clkUnknow,?????_txclk_en); seq_num(15 downto 8) := ?????_tx_d; wait until rising_clken(clkUnknow,?????_txclk_en); seq_num(7 downto 0) := ?????_tx_d; if oh_match='0' then printf("-- oh mismatch!\n"); end if; --modified by ys, reduce 4 clk for payload_len bytes and seq_num bytes for i in 0 to PAYLOAD_LEN-1-4 loop -- modify --add 4 bytes wait until rising_clken(clkUnknow,?????_txclk_en); prbs_chk_din_sel <= ?????_tx_d; if i=0 then wait until rising_edge(clkUnknow);prbs_chk_dv_s <= '1'; end if; if i/=0 and prbs_chk_res_sel /= "00000000" then prbs_match:='0'; printf("-- prbs_chk_res_sel: 0x%02x\n",prbs_chk_res_sel); end if; end loop; -- i in rang 0 to PAYLOAD_LEN loop if prbs_match='0' then printf("-- prbs mismatch!\n"); end if; for i in 0 to 3 loop wait until rising_clken(clkUnknow,?????_txclk_en); prbs_chk_din_sel <= ?????_tx_d; if i=0 then prbs_chk_dv_s <= '0'; end if; end loop; -- i in rang 0 to 3 loop ?????_tx_eop <= '1'; wait until rising_clken(clkUnknow,?????_txclk_en); ?????_tx_eop <= '0'; ?????_tx_en_crc <= '0'; if ?????_tx_crc_err = '1' then crc_match :='0'; end if; if crc_match='0' then printf("-- crc error!\n"); end if; if oh_match='0' or prbs_match='0' or crc_match='0' then is_match := '0'; printf("-- error! receive mismatch!\n"); else printf("-- ok! receive match!\n"); end if; end regular_pkt_receive; begin ?????_tx_eop <= '0'; ?????_tx_en_crc <= '0'; prbs_chk_din_sel <= (others=>'0'); prbs_chk_dv_s <= '0'; wait for 800 ns; for k in 1 to PACKET_NUMBER loop for i in 1 to channel_number loop regular_pkt_receive(X"112233445566",X"aaaaaa555555",X"81008200",X"88b7",conv_std_logic_vector(?????_rx_port_map_list(i-1),8)&x"02"&conv_std_logic_vector(?????_rx_port_map_list(i-1),8),X"0000",X"D5",PAYLOAD_LEN,X"00000000"); end loop; --i end loop; --k wait; end process Packet_Receive; -------------------------------------------------------------------------------------------------------------------- -- HOST initial Configuration -------------------------------------------------------------------------------------------------------------------- Host_Conf : process variable ***_read_value : std_logic_vector(31 downto 0); variable &&&&_read_value : std_logic_vector(31 downto 0); variable ***_chan_enable : bit_vector(31 downto 0); procedure ***_reg_write ( ***_addr : in std_logic_vector(31 downto 0); ***_value : in std_logic_vector(31 downto 0)) is begin printf("***_reg_write 0x%08x 0x%08x\n",***_addr,***_value); wait until rising_edge(clkUnknow); ***_exec <= '0'; ***_address <= ***_addr(13 downto 0); ***_wr_data <= ***_value; wait until rising_edge(clkUnknow); ***_exec <= '1'; ***_rh_wl <= '0'; wait until rising_edge(clkUnknow); ***_exec <= '0'; wait until ***_op_done = '1'; ***_rh_wl <= '1'; wait until rising_edge(clkUnknow); end ***_reg_write; procedure ***_reg_read ( ***_addr : in std_logic_vector(31 downto 0); variable ***_value : out std_logic_vector(31 downto 0)) is begin wait until rising_edge(clkUnknow); ***_exec <= '0'; ***_address <= ***_addr(13 downto 0); wait until rising_edge(clkUnknow); ***_exec <= '1'; ***_rh_wl <= '1'; wait until rising_edge(clkUnknow); ***_exec <= '0'; wait until rising_edge(clkUnknow) and ***_op_done = '1'; ***_value := ***_rd_data; printf("***_reg_read 0x%08x 0x%08x\n",***_addr,***_rd_data); wait until clkUnknow'event and clkUnknow = '1'; end ***_reg_read; procedure &&&&_reg_write ( &&&&_addr : in std_logic_vector(31 downto 0); &&&&_value : in std_logic_vector(31 downto 0)) is begin printf("&&&&_reg_write 0x%08x 0x%08x\n",&&&&_addr,&&&&_value); wait until rising_edge(clkUnknow); &&&&_exec <= '0'; &&&&_address <= &&&&_addr(8 downto 0); &&&&_wr_data <= &&&&_value; wait until rising_edge(clkUnknow); &&&&_exec <= '1'; &&&&_rh_wl <= '0'; wait until rising_edge(clkUnknow); &&&&_exec <= '0'; wait until &&&&_op_done = '1'; &&&&_rh_wl <= '1'; wait until rising_edge(clkUnknow); end &&&&_reg_write; procedure &&&&_reg_read ( &&&&_addr : in std_logic_vector(31 downto 0); variable &&&&_value : out std_logic_vector(31 downto 0)) is begin wait until rising_edge(clkUnknow); &&&&_exec <= '0'; &&&&_address <= &&&&_addr(8 downto 0); wait until rising_edge(clkUnknow); &&&&_exec <= '1'; &&&&_rh_wl <= '1'; wait until rising_edge(clkUnknow); &&&&_exec <= '0'; wait until rising_edge(clkUnknow) and &&&&_op_done = '1'; &&&&_value := &&&&_rd_data; printf("&&&&_reg_read 0x%08x 0x%08x\n",&&&&_addr,&&&&_rd_data); wait until clkUnknow'event and clkUnknow = '1'; end &&&&_reg_read; begin reg_config_done <= '0'; -- register configuration process signal: 0--not finish yet 1--finished ***_rh_wl <= '1'; ***_exec <= '0'; ***_address <= (others => '0'); ***_wr_data <= (others => '0'); &&&&_rh_wl <= '1'; &&&&_exec <= '0'; &&&&_address <= (others => '0'); &&&&_wr_data <= (others => '0'); wait for 1000 ns; ------------------------------------------------------------------------------------------------------------------------ -- testcase register config ------------------------------------------------------------------------------------------------------------------------ ***_reg_write(x"0000_0000",x"0000_ffff"); --FUNCTION_ENABLE_31_0 initial all channel ***_reg_write(x"0000_0001",x"0000_0000"); --FUNCTION_ENABLE_63_32 --*** to mac for i in 1 to channel_number loop ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"0", x"1122_3344"); --da & sa ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"1", x"5566_aaaa"); ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"2", x"aa55_5555"); ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"3", x"8100_8200"); -- vlan ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"4", x"88b7"&conv_std_logic_vector(i,8)&x"02"); -- phy_chan_id ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4,8)&x"5", conv_std_logic_vector(i,8)&x"00_00d5"); -- ecc_id end loop; -- i --mac to *** for i in 1 to channel_number loop ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"0", x"dd11_2233"); --da & sa ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"1", x"4455_1111"); ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"2", x"1122_2222"); ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"3", x"8100_8200"); -- vlan ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"4",x"88b7"&conv_std_logic_vector(i,8)&x"02"); -- phy_chan_id ***_reg_write(x"0000_1"&conv_std_logic_vector((i-1)*4+1,8)&x"5", conv_std_logic_vector(i,8)&x"00_00d5"); -- ecc_id end loop; -- i for i in 0 to channel_number-1 loop &&&&_reg_write(x"0000_000"&conv_std_logic_vector(i,4),x"0000_0000"); &&&&_reg_read(x"0000_000"&conv_std_logic_vector(i,4),&&&&_read_value); end loop; -- i --reg config done, pkt send send start reg_config_done <= '1'; wait; end process Host_Conf; end sch;
最近的目标是,在进一步了解UVM的功能特性之后,将UVM方法学移植到现有的测试平台上去,看是否能对现有的测试平台提供帮助,提升代码测试的效果。
*****