学习目标:
实验2
SV绿皮书第六章:随机化
学习内容:
1.实验012代码整理
测试文件tb1
'timescale 1ns/1ps
module tb1;
reg clk;
reg rstn;
reg [31:0]ch0_data;
reg ch0_valid; //数据有效标志信号
wire ch0_ready; //为高可以写入
wire [4:0]ch0_margin; //
reg [31:0]ch1_data;
reg ch1_valid;
wire ch1_ready;
wire [4:0]ch1_margin;
reg [31:0]ch2_data;
reg ch2_valid;
wire ch2_ready;
wire [4:0]ch2_margin;
wire [31:0]mcdt_data;
wire mcdt_val; //
wire [1:0]mcdt_id;
mcdt dut(
.clk_i(clk)
,.rstn_i(rstn)
,.ch0_data_i(ch0_data)
,.ch0_valid_i(ch0_valid)
,.ch0_ready_o(ch0_ready)
,.ch0_margin_o(ch0_margin)
,.ch1_data_i(ch1_data)
,.ch1_valid_i(ch1_valid)
,.ch1_ready_o(ch1_ready)
,.ch1_margin_o(ch1_margin)
,.ch2_data_i(ch2_data)
,.ch2_valid_i(ch2_valid)
,.ch2_ready_o(ch2_ready)
,.ch2_margin_o(ch2_margin)
,.mcdt_data_o(mcdt_data)
,.mcdt_val_o(mcdt_val)
,.mcdt_id_o(mcdt_id)
);
//时钟生成
initial begin
clk<=0;
forever begin
#5 clk<=!clk;
end
end
//复位
initial begin
#10 rstn<=0;
repeat(10) @(posedge clk);
rstn<=1;
end
//通道012数据
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
//通道0 数据
chn1_write(0,'h00C0_0000); //chn_write为任务
chnl_write(0, 'h00C0_0001);
chnl_write(0, 'h00C0_0002);
chnl_write(0, 'h00C0_0003);
chnl_write(0, 'h00C0_0004);
chnl_write(0, 'h00C0_0005);
chnl_write(0, 'h00C0_0006);
chnl_write(0, 'h00C0_0007);
chnl_write(0, 'h00C0_0008);
chnl_write(0, 'h00C0_0009);
// channel 1 test
chnl_write(1, 'h00C1_0000);
chnl_write(1, 'h00C1_0001);
chnl_write(1, 'h00C1_0002);
chnl_write(1, 'h00C1_0003);
chnl_write(1, 'h00C1_0004);
chnl_write(1, 'h00C1_0005);
chnl_write(1, 'h00C1_0006);
chnl_write(1, 'h00C1_0007);
chnl_write(1, 'h00C1_0008);
chnl_write(1, 'h00C1_0009);
// channel 2 test
chnl_write(2, 'h00C2_0000);
chnl_write(2, 'h00C2_0001);
chnl_write(2, 'h00C2_0002);
chnl_write(2, 'h00C2_0003);
chnl_write(2, 'h00C2_0004);
chnl_write(2, 'h00C2_0005);
chnl_write(2, 'h00C2_0006);
chnl_write(2, 'h00C2_0007);
chnl_write(2, 'h00C2_0008);
chnl_write(2, 'h00C2_0009);
end
task chn1_write(input reg[1:0]id,input reg [31:0]data);
case(id)
0:begin
@(posedge clk);
ch0_valid<=1;
ch0_data<=data;
@(posedge clk);
ch0_valid<=0;
ch0_data<=0;
end
1:begin
@(posedge clk);
ch1_valid<=1;
ch1_data<=data;
@(posedge clk);
ch1_valid<=0;
ch1_data<=0;
end
2:begin
@(posedge clk);
ch2_valid<=1;
ch2_data<=data;
@(posedge clk);
ch2_valid<=0;
ch2_data<=0;
end
default:$error("channel id %0d is invalid",id);
endcase
endtask
endmodule
mcdt为顶层文件,连接三个fifo通道和arbiter
实验1TB2:任务与函数
`timescale 1ns/1ps
module tb2;
logic clk;
logic rstn;
logic [31:0] ch0_data;
logic ch0_valid;
logic ch0_ready;
logic [ 5:0] ch0_margin;
logic [31:0] ch1_data;
logic ch1_valid;
logic ch1_ready;
logic [ 5:0] ch1_margin;
logic [31:0] ch2_data;
logic ch2_valid;
logic ch2_ready;
logic [ 5:0] ch2_margin;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i(clk)
,.rstn_i(rstn)
,.ch0_data_i(ch0_data)
,.ch0_valid_i(ch0_valid)
,.ch0_ready_o(ch0_ready)
,.ch0_margin_o(ch0_margin)
,.ch1_data_i(ch1_data)
,.ch1_valid_i(ch1_valid)
,.ch1_ready_o(ch1_ready)
,.ch1_margin_o(ch1_margin)
,.ch2_data_i(ch2_data)
,.ch2_valid_i(ch2_valid)
,.ch2_ready_o(ch2_ready)
,.ch2_margin_o(ch2_margin)
,.mcdt_data_o(mcdt_data)
,.mcdt_val_o(mcdt_val)
,.mcdt_id_o(mcdt_id)
);
//创建时钟生成任务,然后调用
task clk_gen();
clk<=0;
forever begin
#5 clk<=!clk;
end
endtask
initial begin
clk_gen(); //调用
end
//同理的,复位任务创建并调用
task rstn_gen();
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
endtask
initial begin
rstn_gen();
end
//后面代码不变
实验1TB3:数组的使用
----data test代码修改
logic [31:0] chnl0_arr[];
logic [31:0] chnl1_arr[];
logic [31:0] chnl2_arr[]; //动态数组声明
initial begin
chnl0_arr=new[100];
chnl1_arr=new[100];
chnl2_arr=new[100]; //创建数组
//数组赋值
foreach(chnl0_arr[i]) begin
chnl0_arr[i]='h00C0_000+i;
chnl1_arr[i]='h00C1_000+i;
chnl2_arr[i]='h00C2_000+i;
end
end
//发送给三个通道
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
foreach(chnl0_arr[i]) chnl_write(0, chnl0_arr[i]);
foreach(chnl1_arr[i]) chnl_write(1, chnl1_arr[i]);
foreach(chnl2_arr[i]) chnl_write(2, chnl2_arr[i]);
end
实验1TB4:验证结构
//将channel write task封装成chnl_initiator,然后例化
module chnl_initiator(
input clk,
input rstn,
output logic [31:0]ch_data,
output logic ch_valid,
input ch_ready,
input [5:0]ch_margin
);
string name;
function void set_name(string s); //chnl0_init.set_name("chnl0_init") 调用
name=s;
endfunction
task chnl_write(input logic [31:0]data);
@(posedge clk);
ch_valid <= 1;
ch_data <= data;
@(negedge clk); //验证一下啊
wait(ch_ready === 'b1); //同一拍ready为低,要等待
$display("%t channel initial [%s] sent data %x", $time, name, data);
chnl_idle();
endtask
task chnl_idle();
@(posedge clk);
ch_valid <= 0;
ch_data <= 0;
endtask
//例化
chnl_initiator chnl0_init(
.clk (clk),
.rstn (rstn),
.ch_data (ch0_data),
.ch_valid (ch0_valid),
.ch_ready (ch0_ready),
.ch_margin(ch0_margin)
);
chnl_initiator chnl1_init(
.clk (clk),
.rstn (rstn),
.ch_data (ch1_data),
.ch_valid (ch1_valid),
.ch_ready (ch1_ready),
.ch_margin(ch1_margin)
);
chnl_initiator chnl2_init(
.clk (clk),
.rstn (rstn),
.ch_data (ch2_data),
.ch_valid (ch2_valid),
.ch_ready (ch2_ready),
.ch_margin(ch2_margin)
);
实验2—TB1:接口的使用
interface chnl_intf(input clk, input rstn); //接口
logic[31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [5:0]ch_margin;
clocking drv_ck@(posedge clk); //接口时钟块
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
module chnl_initiator(chnl_intf intf);
string name;
int idle_cycles=1;
function automatic void set_idle_cycles(int n); //控制空闲间隔
idle_cycles=n;
endfunction
function automatic void set_name(string s);
name = s;
endfunction
task automatic chnl_write(input logic [31:0]data); //write任务
@(posedge intf.clk);
intf.drv_ck.ch_valid<=1; //带接口时钟块
intf.drv_ck.ch_data<=data;
@(negedge intf.clk);
wait(intf.ch_ready==='b1);
$display(%t channel initiator [%s] sent data %x",$time,name,data);
repeat(idle_cycles) chnl_idle(); //调用方法控制空闲间隔
endtask
task automatic chnl_idle();
@(posedge intf.clk);
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endmodule
module chnl_generator; //id设置,名字设置
int chnl_arr[$];
int num;
int id;
function automatic void initialize(int n);
id=n;
num=0;
endfunction
function automatic int get_data();
int data;
data='h00C0_0000+(id<<16)+num;
num++;
chnl_arr.push_back(data);
return data;
endfunction
endmodule
module tb1;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_margin )
,.mcdt_data_o (mcdt_data )
,.mcdt_val_o (mcdt_val )
,.mcdt_id_o (mcdt_id )
);
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
initial begin
chnl0_gen.initialize(0);
chnl1_gen.initialize(1);
chnl2_gen.initialize(2);
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl0_init.chnl_write(chnl0_gen.get_data());
end
chnl0_init.chnl_idle();
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl1_init.chnl_write(chnl1_gen.get_data());
end
chnl1_init.chnl_idle();
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl2_init.chnl_write(chnl2_gen.get_data());
end
chnl2_init.chnl_idle();
end
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_initiator chnl0_init(chnl0_if);
chnl_initiator chnl1_init(chnl1_if);
chnl_initiator chnl2_init(chnl2_if);
chnl_generator chnl0_gen();
chnl_generator chnl1_gen();
chnl_generator chnl2_gen();
endmodule
问题:
学习时间:
早:9-11.30
中:15-17