前言:刚开始接触sv时,由于有些参考的sv example中没有提供编译和仿真命令,为了更清晰地知道运行结果,故写了此博客
一、框架图如下所示
二、文档如下所示
2.1 memory.sv
module memory(
address,
data_in,
data_out,
read_write,
chip_en
);
input wire [7:0] address, data_in;
output reg [7:0] data_out;
input wire read_write, chip_en;
reg [7:0] mem [0:255];
always @ (address or data_in or read_write or chip_en)
if (read_write == 1 && chip_en == 1) begin
mem[address] = data_in;
end
always @ (read_write or chip_en or address)
if (read_write == 0 && chip_en)
data_out = mem[address];
else
data_out = 0;
endmodule
2.2、mem_ports.sv
interface mem_ports(
input wire clock,
output logic [7:0] address,
output logic chip_en,
output logic read_write,
output logic [7:0] data_in,
input logic [7:0] data_out
);
endinterface
2.3、mem_base_object.sv
class mem_base_object;
bit [7:0] addr;
bit [7:0] data;
// Read = 0, Write = 1
bit rd_wr;
endclass
2.4、mem_txgen.sv
class mem_txgen;
mem_base_object mem_object;
mem_driver mem_driver;
integer num_cmds;
function new(virtual mem_ports ports);
begin
num_cmds = 3;
mem_driver = new(ports);
end
endfunction
task gen_cmds();
begin
integer i = 0;
for (i=0; i < num_cmds; i ++ ) begin
mem_object = new();
mem_object.addr = $random();
mem_object.data = $random();
mem_object.rd_wr = 1;
mem_driver.drive_mem(mem_object);
mem_object.rd_wr = 0;
mem_driver.drive_mem(mem_object);
end
end
endtask
endclass
2.5、mem_driver.sv
class mem_driver;
virtual mem_ports ports;
function new(virtual mem_ports ports);
begin
this.ports = ports;
ports.address = 0;
ports.chip_en = 0;
ports.read_write = 0;
ports.data_in = 0;
end
endfunction
task drive_mem (mem_base_object object);
begin
@ (posedge ports.clock);
ports.address = object.addr;
ports.chip_en = 1;
ports.read_write = object.rd_wr;
ports.data_in = (object.rd_wr) ? object.data : 0;
if (object.rd_wr) begin
$display("Driver : Memory write access-> Address : %x Data : %x\n",
object.addr,object.data);
end else begin
$display("Driver : Memory read access-> Address : %x\n",
object.addr);
end
@ (posedge ports.clock);
ports.address = 0;
ports.chip_en = 0;
ports.read_write = 0;
ports.data_in = 0;
end
endtask
endclass
2.6、mem_ip_monitor.sv
class mem_ip_monitor;
mem_base_object mem_object;
mem_scoreboard sb;
virtual mem_ports ports;
function new (mem_scoreboard sb,virtual mem_ports ports);
begin
this.sb = sb;
this.ports = ports;
end
endfunction
task input_monitor();
begin
while (1) begin
@ (posedge ports.clock);
if ((ports.chip_en == 1) && (ports.read_write == 1)) begin
mem_object = new();
$display("input_monitor : Memory wr access-> Address : %x Data : %x",
ports.address,ports.data_in);
mem_object.addr = ports.address;
mem_object.data = ports.data_in;
sb.post_input(mem_object);
end
end
end
endtask
endclass
2.7、mem_op_monitor.sv
class mem_op_monitor;
mem_base_object mem_object;
mem_scoreboard sb;
virtual mem_ports ports;
function new (mem_scoreboard sb,virtual mem_ports ports);
begin
this.sb = sb;
this.ports = ports;
end
endfunction
task output_monitor();
begin
while (1) begin
@ (negedge ports.clock);
if ((ports.chip_en == 1) && (ports.read_write == 0)) begin
mem_object = new();
$display("Output_monitor : Memory rd access-> Address : %x Data : %x",
ports.address,ports.data_out);
mem_object.addr = ports.address;
mem_object.data = ports.data_out;
sb.post_output(mem_object);
end
end
end
endtask
endclass
2.8、mem_scoreboard.sv
class mem_scoreboard;
// Create a keyed list to store the written data
// Key to the list is address of write access
mem_base_object mem_object [*];
// post_input method is used for storing write data
// at write address
task post_input (mem_base_object input_object);
begin
mem_object[input_object.addr] = input_object;
end
endtask
// post_output method is used by the output monitor to
// compare the output of memory with expected data
task post_output (mem_base_object output_object);
begin
// Check if address exists in scoreboard
if (mem_object[output_object.addr] != null) begin
mem_base_object in_mem = mem_object[output_object.addr];
$display("scoreboard : Found Address %x in list",output_object.addr);
if (output_object.data != in_mem.data) begin
$display ("Scoreboard : Error : Exp data and Got data don't match");
$display(" Expected -> %x",
in_mem.data);
$display(" Got -> %x",
output_object.data);
end else begin
$display("Scoreboard : Exp data and Got data match");
end
end
end
endtask
endclass
2.9、test.sv
`include "mem_ports.sv"
program memory_top(mem_ports ports);
`include "mem_base_object.sv"
`include "mem_driver.sv"
`include "mem_txgen.sv"
`include "mem_scoreboard.sv"
`include "mem_ip_monitor.sv"
`include "mem_op_monitor.sv"
mem_txgen txgen;
mem_scoreboard sb;
mem_ip_monitor ipm;
mem_op_monitor opm;
initial begin
sb = new();
ipm = new (sb, ports);
opm = new (sb, ports);
txgen = new(ports);
fork
ipm.input_monitor();
opm.output_monitor();
join_none
txgen.gen_cmds();
repeat (20) @ (posedge ports.clock);
end
endprogram
2.10、top.sv
`include "memory.sv"
module memory_tb();
wire [7:0] address, data_in;
wire [7:0] data_out;
wire read_write, chip_en;
reg clk;
// Connect the interface
mem_ports ports(
.clock (clk),
.address (address),
.chip_en (chip_en),
.read_write (read_write),
.data_in (data_in),
.data_out (data_out)
);
// Connect the program
memory_top top (ports);
initial begin
clk = 0;
end
always #1 clk = ~clk;
memory U_memory(
.address (address),
.data_in (data_in),
.data_out (data_out),
.read_write (read_write),
.chip_en (chip_en)
);
endmodule
二、用vcs跑
首先输入
然后输入
可以看到运行结果
三、参考
Welcome To SystemVerilog Central
如有不正,欢迎指正