0% found this document useful (0 votes)
45 views14 pages

Memory RTL Code With Functional Coverage

The document contains a comprehensive design of a memory module in SystemVerilog, including RTL code, testbench, and various classes for transaction generation, driving, monitoring, and scoreboard functionalities. It defines a memory interface and includes assertions for protocol checks, along with a test program that orchestrates memory transactions. The design supports multiple read and write operations, ensuring data integrity through a scoreboard mechanism.

Uploaded by

1ds22ec170
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
45 views14 pages

Memory RTL Code With Functional Coverage

The document contains a comprehensive design of a memory module in SystemVerilog, including RTL code, testbench, and various classes for transaction generation, driving, monitoring, and scoreboard functionalities. It defines a memory interface and includes assertions for protocol checks, along with a test program that orchestrates memory transactions. The design supports multiple read and write operations, ensuring data integrity through a scoreboard mechanism.

Uploaded by

1ds22ec170
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

// Memory RTL Code

module memory (addr,cs,re,we,clk,reset,data_in,data_out);

parameter addr_width=8; parameter data_width=8;

input [addr_width-1:0] addr;

input cs; input re,we;

input clk,reset;

input [data_width-1:0] data_in;

output [data_width-1:0] data_out;

reg [data_width-1:0] data_out;

reg [data_width-1:0] mem [0:2**addr_width];

integer i;

always@(posedge clk)

begin: MEM

if(reset) begin

mem[addr]<=0;

end else begin

if(cs) begin

if(we) begin

mem[addr] <=data_in;

end

if(re) begin

data_out <=mem[addr];

end

end

end

end

endmodule
//Mem_gen.sv

/ /class generator

class mem_trans_gen #(addr_width=`awidth, data_width=`dwidth);

transaction mem_trans, mem_trans_mb;

mailbox gen2mbox;

function new(mailbox inbox);

this.gen2mbox=inbox;

endfunction

extern task run(string test_name);

endclass

// generator task

task mem_trans_gen :: run(string test_name);

begin

if (test_name == "single_wr_rd") begin

repeat (`no_of_trans) begin

mem_trans =new();

mem_trans_mb=new;

// Write transaction

assert(mem_trans.randomize() with {trans_type==WRITE;});

[Link](mem_trans);

$display("Generator addr=%h wr_data = %h, trans_type=%s \n", mem_trans.addr,


mem_trans.wr_data, mem_trans.trans_type.name());

// Read transaction

assert(mem_trans_mb.randomize() with {addr==mem_trans.addr; trans_type==READ;});

[Link](mem_trans_mb);

$display("Generator addr=%0h, rd_data=%0h, trans_type=%s \n", mem_trans_mb.addr,


mem_trans_mb.rd_data, mem_trans_mb.trans_type.name());
end

$display("Gen -mbox size=%0d", [Link]());

end

end

endtask

//Mem_drv.SV

// class mem_driver

class mem_trans_drv #(addr_width=`awidth, data_width=`dwidth);

transaction mem_trans, mem_trans_mb;

mailbox mbox2drv;

virtual mem_if mem_if_drv;

function new(mailbox inbox, virtual mem_if v_if);

this.mbox2drv=inbox;

this.mem_if_drv=v_if;

endfunction

extern task run();

extern task send_to_dut(transaction trans_drv);

endclass

// driver run task

task mem_trans_drv :: run;

begin

mem_trans =new();

mem_trans_mb=new;

@(negedge mem_if_drv.reset);

$display("driver-mbox size=%0d", [Link]());

repeat (`no_of_trans) begin

// Write transaction

[Link](mem_trans_mb);

send_to_dut(mem_trans_mb);
// read transaction

// $display("driver-mbox size=%0d", [Link]());

[Link](mem_trans_mb);

send_to_dut(mem_trans_mb);

end

end

endtask

// driver send_to_dut task

task mem_trans_drv :: send_to_dut(input transaction trans_drv);

begin

// write

@(posedge mem_if_drv.clk)

if (trans_drv.trans_type==WRITE) begin

$display($time, " Drive to dut WRITE addr=%0h, wr_data = %h, trans_type=%s \


n",trans_drv.addr, trans_drv.wr_data, trans_drv.trans_type.name());

mem_if_drv.mem_drv.cs=1;

mem_if_drv.mem_drv.we=1;

mem_if_drv.mem_drv.re=0;

mem_if_drv.mem_drv.addr=trans_drv.addr;

mem_if_drv.mem_drv.data_in=trans_drv.wr_data;

@(posedge mem_if_drv.clk)

mem_if_drv.mem_drv.we=0;

mem_if_drv.mem_drv.cs=0;

end

//read

if (trans_drv.trans_type==READ) begin

mem_if_drv.mem_drv.cs=1;

mem_if_drv.mem_drv.we=0;

mem_if_drv.mem_drv.re=1;

mem_if_drv.mem_drv.addr=trans_drv.addr;
repeat (2) @(posedge mem_if_drv.clk)

trans_drv.rd_data= mem_if_drv.mem_drv.data_out;

mem_if_drv.mem_drv.re=0;

mem_if_drv.mem_drv.cs=0;

$display($time, " Driver to dut READ addr=%0h, rd_data = %h, trans_type=%s \n",trans_drv.addr,
trans_drv.rd_data, trans_drv.trans_type.name());

end

end

endtask

//mem_if.SV

// interface for memory

interface mem_if #(awidth=`awidth, dwidth=`dwidth) (input bit clk, reset);

logic [awidth-1:0] addr;

logic [dwidth-1:0] data_in, data_out;

logic cs,re,we;

modport mem_drv (input data_out, output addr, data_in, cs, re, we);

modport mem_mon (input data_out, addr, data_in, cs, re, we);

// assertions for protocol check

property bus_check;

@(negedge clk) disable iff (reset| ~cs)

(cs & we & ~re) or (cs & ~we & re);

endproperty

property rd_check;

@(negedge clk) disable iff (reset|~cs)

(cs & ~we & re) |=> (cs & ~we & re) and $stable(addr);

endproperty

// asserting the property

assert property (bus_check);


assert property (rd_check);

endinterface: mem_if

//mem_tb.v

//memory_tb.sv : testbench

`timescale 1ns/1ps

// include RTL file

//`include "memory.v"

// include test bench files

`include "[Link]"

import globals::*;

`include "mem_gen.sv"

`include "mem_if.sv"

`include "mem_drv.sv"

`include "mem_mon.sv"

`include "mem_sb.sv"

`include "mem_test.sv"

// memory testbench module

module memory_tb;

reg clk, reset;

wire dut_clk;

// memory interface

mem_if mem_if_r(clk, reset); // physical interface

// Memory(DUT) instantiation

memory #(`awidth, `dwidth)


memory_inst(mem_if_r.addr,mem_if_r.cs,mem_if_r.re,mem_if_r.we,dut_clk,mem_if_r.reset,mem_if
_r.data_in,mem_if_r.data_out);

// test instantiation using program block


mem_test test(mem_if_r); // binding physical to virtual interface

// clock generation

initial begin

clk = 0;

forever

#5 clk = ~clk;

end

assign #1 dut_clk = clk;

//reset generation

initial begin

reset = 1;

mem_if_r.addr=0;

mem_if_r.cs=0;

mem_if_r.re=0;

mem_if_r.we=0;

#12

reset = 0;

end

//dump waves

initial begin

$dumpvars;

$dumpfile("[Link]");

//$recordfile("[Link]");

//$recordvars;

end

endmodule

//[Link]: global defines

package globals;
typedef enum {WRITE, READ} trans;

typedef enum {PATRN_AA, PATRN_55, WALK_1, WALK_0} vec_pattern;

`define awidth 16

`define dwidth 32

`define no_of_trans 100

`define timeout 1000000

// class transaction

class transaction #(addr_width=`awidth, data_width=`dwidth);

rand bit [addr_width-1:0] addr;

rand bit [data_width-1:0] wr_data;

bit [data_width-1:0] rd_data;

rand trans trans_type;

constraint addr_constr {addr[1:0] == 0;}

endclass

endpackage

//mem_test.sv : test

program mem_test (mem_if mem_if_t);

// mbox for gen 2 driver constrcution

mailbox gen2drv=new();

// mbox for monitor 2 scoreboard

mailbox mon2sb=new();

// memory gen construction

mem_trans_gen trans_gen=new(gen2drv);

// memory driver construction

mem_trans_drv trans_drv=new(gen2drv, mem_if_t);

// memory monitor construction

mem_trans_mon trans_mon=new(mon2sb, mem_if_t);

// memory scoreboard construction

mem_trans_sb trans_sb=new(mon2sb);
// tasks call for each test

initial begin

// Test 1 - single wr and read

trans_gen.run("single_wr_rd");

// Test 2 - multiple wr and read

// Test 3 - All locations wr and read

// Test 4 - All locations wr and read with pattern

// Test 5 - Walking 1's and walking 0s

fork

// run driver

trans_drv.run;

// run monitor

trans_mon.run;

//run scoreboard

trans_sb.run;

join

end

// timeout for tests

initial begin

#`timeout;

trans_sb.data_check;

$exit;

end

endprogram

// mem_mon.sv: class mem monitor


class mem_trans_mon #(addr_width=`awidth, data_width=`dwidth);

transaction mem_trans_mb;

mailbox mon2mbox;

virtual mem_if mem_if_m;

// functional coverage

covergroup mem_trans_cov;

//coverpoint mem_trans_mb;

option.per_instance=1;

option.at_least=1;

addr: coverpoint mem_trans_mb.addr {

bins addr_low={[0:'h00ff]};

bins addr_med={[16'h0100:16'h0fff]};

bins addr_high={[16'h1000:16'hffff]};

w_data:coverpoint mem_trans_mb.wr_data {

bins wr_data_low={[0:32'h00ff_ffff]};

bins wr_data_med={[32'h0100_0000:32'h0fff_ffff]};

bins wr_data_high={[32'h1000_0000:32'hffff_ffff]};

r_data:coverpoint mem_trans_mb.rd_data {

bins rd_data_low={[0:32'h00ff_ffff]};

bins rd_data_med={[32'h0100_0000:32'h0fff_ffff]};

bins rd_data_high={[32'h1000_0000:32'hffff_ffff]};

trans_type:coverpoint mem_trans_mb.trans_type {

bins write = {WRITE};

bins read ={READ};

addr_x_trans_type : cross addr, trans_type;

endgroup
function new(mailbox inbox, virtual mem_if v_if);

this.mon2mbox=inbox;

this.mem_if_m=v_if;

this.mem_trans_cov=new;

endfunction

extern task run();

endclass

// montor run task

task mem_trans_mon :: run;

integer count=0;

begin

forever begin

// write trans capture

@(posedge mem_if_m.clk)

if (mem_if_m.mem_mon.cs & mem_if_m.mem_mon.we & ~mem_if_m.mem_mon.re) begin

mem_trans_mb=new;

mem_trans_mb.addr=mem_if_m.mem_mon.addr;

mem_trans_mb.wr_data=mem_if_m.mem_mon.data_in;

mem_trans_mb.trans_type=WRITE;

[Link](mem_trans_mb); //put write trans to mailbox

$display($time, " Monitor WRITE addr=%0h wr_data = %0h, trans_type=%s \n",


mem_trans_mb.addr, mem_trans_mb.wr_data, mem_trans_mb.trans_type.name());

mem_trans_cov.sample();

end

// read trans capture

if (mem_if_m.mem_mon.cs & ~mem_if_m.mem_mon.we & mem_if_m.mem_mon.re) begin

count++;

if (count%2==0) begin
mem_trans_mb=new;

mem_trans_mb.addr=mem_if_m.mem_mon.addr;

mem_trans_mb.rd_data=mem_if_m.mem_mon.data_out;

mem_trans_mb.trans_type=READ;

[Link](mem_trans_mb); //put read trans to mailbox

$display($time, " Monitor READ addr=%0h rd_data = %0h, trans_type=%s count=%0d\n",


mem_trans_mb.addr, mem_trans_mb.rd_data, mem_trans_mb.trans_type.name(), count);

count=0;

mem_trans_cov.sample();

end

end

end

end

endtask

// mem_sb.sv: class mem scoreboard

class mem_trans_sb #(addr_width=`awidth, data_width=`dwidth);

transaction mem_trans_mb;

bit [data_width-1:0] wr_data[integer];

bit [data_width-1:0] rd_data[integer];

mailbox mbox2sb;

function new(mailbox inbox);

this.mbox2sb=inbox;

endfunction

extern task run();

extern task data_check();

endclass

// scoreaboard run task

task mem_trans_sb :: run;

integer count=0;
begin

mem_trans_mb=new;

forever begin

[Link](mem_trans_mb);

$display($time, " Score Board addr=%0h wr_data = %0h, rd_data=%0h, trans _type=%s \n",
mem_trans_mb.addr, mem_trans_mb.wr_data, mem_trans_mb.rd_data,
mem_trans_mb.trans_type.name());

if (mem_trans_mb.trans_type==WRITE)

wr_data[mem_trans_mb.addr]= mem_trans_mb.wr_data;

else

rd_data[mem_trans_mb.addr]= mem_trans_mb.rd_data;

end

end

endtask

// data check task

task mem_trans_sb :: data_check;

bit [addr_width-1:0] addr_t;

integer no_wr_entries, no_rd_entries;

begin

no_wr_entries=wr_data.num();

no_rd_entries=rd_data.num();

for (addr_t=0; addr_t< 2**addr_width; addr_t++) begin

if (wr_data.exists(addr_t)) begin

if (wr_data[addr_t] === rd_data[addr_t])

$display($time, " Addr=%0h, Write data=%0h MATCHED with READ data=%0h", addr_t,
wr_data[addr_t], rd_data[addr_t]);

else

$display($time, " ERROR-Addr=%0h, Write data=%0h NOT MATCHED with READ data=%0h",
addr_t, wr_data[addr_t], rd_data[addr_t]);

no_wr_entries--;

no_rd_entries--;
$display($time, " Write entries=%0d Read entries=%0d", no_wr_entries, no_rd_entries);

end //if

if (no_wr_entries == 0)

break;

end //for

end

endtask

You might also like