brock ram = sram과 비슷하다.
FPGA에서 만드는 ram은 bram이라한다.
ram을 어떻게 컨트롤 할지가 더 어렵다.
clk, wr, address, wdata, radta
address 1에 a , 2에 b가 저장된다.
wr값에 따라 write, read 가 달라진다.
read : 조합회로.
wirte 할 때도 address 값이 막 나올 때가 있다.
write인지 read인지 모를 땐 두줄로 표시.
`timescale 1ns / 1ps
module ram(
input clk ,
input [9:0] address ,
input [7:0] data_in ,
input wr_en ,
output [7:0] data_out
);
reg [7:0] mem[0 : 2**10-1];
always @(posedge clk) begin
if (wr_en) begin
mem[address] <= data_in;
end
end
assign data_out = mem[address];
endmodule
Write, Read 각각 검증.
`timescale 1ns / 1ps
module ram (
input clk,
input [2:0] address,
input [7:0] wdata,
input wr_en,
output [7:0] rdata
);
reg [7:0] mem[0:2**3-1];
integer i;
initial begin
for (i = 0; i < 2 ** 3; i = i + 1) begin
mem[i] = 0;
end
end
always @(posedge clk) begin
if (!wr_en) begin
mem[address] <= wdata;
end
end
assign rdata = mem[address];
endmodule
제약사항.
`timescale 1ns / 1ps
interface ram_interface;
logic clk;
logic wr_en;
logic [9:0] addr;
logic [7:0] wdata;
logic [7:0] rdata;
endinterface //ram_interface
class transaction;
rand bit wr_en;
rand bit [9:0] addr;
rand bit [7:0] wdata;
bit [7:0] rdata;
task display(string name);
$display("[%s] wr_en: %x, address: %x, wdata: %x, rdata: %x", name, wr_en, addr, wdata, rdata);
endtask
// constraint c_adr {addr < 10;}
constraint c_addr {addr inside{[10:19]};}
constraint c_wdata1 {wdata<100;}
constraint c_wdata2 {wdata>10;}
// constraint c_wr_en {wr_en dist{0:=100, 1:=110};}
constraint c_wr_en {wr_en dist{0:/60, 1:/40};}
endclass //transaction
class generator;
transaction trans;
mailbox #(transaction) gen2drv_mbox;
event gen_next_event;
function new(mailbox #(transaction) gen2drv_mbox, event gen_next_event);
this.gen2drv_mbox = gen2drv_mbox;
this.gen_next_event = gen_next_event;
endfunction //new()
task run(int count);
repeat(count) begin
trans = new();
assert (trans.randomize())
else $error("[GEN] trans.randomize() error!");
gen2drv_mbox.put(trans);
trans.display("GEN");
@(gen_next_event);
end
endtask //
endclass //generator
class driver;
transaction trans;
mailbox #(transaction) gen2drv_mbox;
virtual ram_interface ram_intf;
function new(virtual ram_interface ram_intf, mailbox #(transaction) gen2drv_mbox);
this.ram_intf = ram_intf;
this.gen2drv_mbox = gen2drv_mbox;
endfunction //new()
task reset();
ram_intf.wr_en <= 1'b0;
ram_intf.addr <= 0;
ram_intf.wdata <= 0;
repeat(5) @(posedge ram_intf.clk);
endtask//
task run();
forever begin
gen2drv_mbox.get(trans);
ram_intf.wr_en <= trans.wr_en;
ram_intf.addr <= trans.addr;
ram_intf.wdata <= trans.wdata;
trans.display("DRV");
@(posedge ram_intf.clk);
end
endtask //
endclass //driver
class monitor;
virtual ram_interface ram_intf;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
function new(virtual ram_interface ram_intf, mailbox #(transaction) mon2scb_mbox);
this.ram_intf = ram_intf;
this.mon2scb_mbox = mon2scb_mbox;
endfunction //new()
task run();
forever begin
trans = new();
@(posedge ram_intf.clk);
trans.wr_en = ram_intf.wr_en;
trans.addr = ram_intf.addr;
trans.wdata = ram_intf.wdata;
trans.rdata = ram_intf.rdata;
mon2scb_mbox.put(trans);
trans.display("MON");
end
endtask //
endclass //monitor
class scoreboard;
mailbox #(transaction) mon2scb_mbox;
transaction trans;
event gen_next_event;
int total_cnt, pass_cnt, fail_cnt, write_cnt;
logic [7:0] mem[0:2**10-1];
function new(mailbox #(transaction) mon2scb_mbox, event gen_next_event);
this.mon2scb_mbox = mon2scb_mbox;
this.gen_next_event = gen_next_event;
total_cnt = 0;
pass_cnt = 0;
fail_cnt = 0;
write_cnt = 0;
for(int i = 0; i<2**10; i++) begin
mem[i] = 0;
end
endfunction //new()
task run();
forever begin
mon2scb_mbox.get(trans);
trans.display("SCB");
if(trans.wr_en) begin // read
if(mem[trans.addr]==trans.rdata) begin
$display("--> READ PASS! mem[%x] == %x", trans.addr, trans.rdata);
pass_cnt++;
end
else begin
$display("--> READ FAIL! mem[%x] == %x", trans.addr, trans.rdata);
fail_cnt++;
end
end
else begin //write
mem[trans.addr] = trans.wdata;
$display("--> WRITE! mem[%x] == %x", trans.addr, trans.wdata);
write_cnt++;
end
total_cnt++;
->gen_next_event;
end
endtask
endclass //scoreboard
class enviroment;
generator gen;
driver drv;
monitor mon;
scoreboard scb;
event gen_next_event;
mailbox #(transaction) gen2drv_mbox;
mailbox #(transaction) mon2scb_mbox;
function new(virtual ram_interface ram_intf);
gen2drv_mbox = new();
mon2scb_mbox = new();
gen = new(gen2drv_mbox, gen_next_event);
drv = new(ram_intf, gen2drv_mbox);
mon = new(ram_intf, mon2scb_mbox);
scb = new(mon2scb_mbox, gen_next_event);
endfunction //new()
task report();
$display("=============================");
$display("========Final Report=========");
$display("=============================");
$display("Total Test : %d", scb.total_cnt);
$display("Pass Count : %d", scb.pass_cnt);
$display("Fail Count : %d", scb.fail_cnt);
$display("Write Count : %d", scb.write_cnt);
$display("=============================");
$display("===test bench is finished!===");
endtask
task pre_run();
drv.reset();
endtask
task run();
fork
gen.run(50);
drv.run();
mon.run();
scb.run();
join_any
report();
#10 $finish;
endtask
task run_test();
pre_run();
run();
endtask
endclass //enviroment
module tb_ram();
enviroment env;
ram_interface ram_intf();
ram dut(
.clk(ram_intf.clk),
.address(ram_intf.addr),
.wdata(ram_intf.wdata),
.wr_en(ram_intf.wr_en),
.rdata(ram_intf.rdata)
);
always #5 ram_intf.clk = ~ram_intf.clk;
initial begin
ram_intf.clk = 0;
end
initial begin
env = new(ram_intf);
env.run_test();
end
endmodule
'공부방 > Verilog_노진호교수님_서울기술교육센터_필기' 카테고리의 다른 글
240524 FIFO+UART (0) | 2024.05.24 |
---|---|
240523 FIFO (0) | 2024.05.23 |
240522_32bit register (0) | 2024.05.22 |
240521_ TB_ADDER.SV (0) | 2024.05.21 |
240520 UART (0) | 2024.05.20 |