Block RAM (BRAM)
: FPGA와 같은 프로그래머블 로직 장치 내부
- 내장형 메모리 : FPGA 내부에 위치하여 고속 접근이 가능하다.
- 크기 및 구성 : 18Kb 또는 36Kb 크기이며, 단일 포트 RAM, 듀얼 포트 RAM, FIFO 등으로 사용할 수 있다.
- 용도 : 임시 데이터 저장, 버퍼링, 캐시 메모리 등 다양한 용도로 사용되며, 고속 데이터 접근이 필요한 곳에 주로 사용된다.
- 동기화 : FPGA의 클럭과 동기화되어 동작하며, 안정적인 데이터 저장 및 접근을 보장한다.
- write : memory에 저장한다.
- read : memory 주소의 Data가 바로 출력된다.
SRAM
: Static Ramdom Access Memory, 전원이 공급되는 동안 데이터가 유지되는 비휘발성 메모리이다.
- 구조 : 플립플롭 회로를 사용하여 각 비트를 저장하며, DRAM과 달리 데이터 유지를 위해 주기적인 리프레시가 필요하지 않는다.
- 속도 : 매우 빠른 데이터 접근 시간을 가지며, 고속 캐시 메모리, 레지스터 파일 등에 사용된다.
- 용량과 비용 : 비트당 더 많은 트랜지스터를 사용하므로 용량당 비용이 높다. 대용량 메모리 구현에는 적합하지 않지만, 고속 접근이 필요한 소규모 메모리에 적합하다.
rand 난수 생성
- rand : 무작위 random 난수 생성한다.
- randc : 순환 random으로, 정수를 중복 없이 생성한다.
constraint, 제약 사항 설정
: constraint 이름 {제약조건;}
- constraint c_addr {addr inside[10:19];} : addr을 10~19 사이 값으로 생성한다.
- constraint c_wdata1 {wdata < 100;} : wdata를 100 미만으로 생성한다.
- constraint c_wdata1 {wdata > 10;} : 위의 조건과 같이 생성 시, 위의 조건을 만족하면서 wdata를 10 초과로 생성한다.
- constraint c_wr_en {wr_en dist {0:=100, 1:=110};} : 0을 100/210, 1을 110/210 비율로 생성한다.
- constraint c_wr_en {wr_en dist {0:/60, 1:/40};] : 0을 보낼 확률이 60%, 1을 보낼 확률이 40%이다.
Block RAM
ram.v
`timescale 1ns / 1ps
module ram (
input clk,
input [9:0] addr,
input [7:0] wdata,
input wr_en,
output [7:0] rdata
);
reg [7:0] mem[0 : 2**10-1];
integer i;
initial begin
for (i=0; i < 2 ** 10; i = i+1) begin
mem[i] = 0;
end
end
always @(posedge clk) begin
if (!wr_en) begin
mem[addr] <= wdata;
end
end
assign rdata = mem[addr];
endmodule
tb_ram.sv
`timescale 1ns / 1ps
interface ram_interface;
logic clk;
logic [9:0] addr;
logic [7:0] wdata;
logic wr_en;
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, addr: %x, wdata: %x, rdata: %x", name, wr_en,
addr, wdata, rdata);
endtask
//constraint c_addr {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};} // 0은 100만큼, 1은 110만큼 발생
constraint c_wr_en {wr_en dist {0:/60, 1:/40};} // 0은 60%, 1은 40%
endclass
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
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;
trans.display("MON");
mon2scb_mbox.put(trans);
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 environment;
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
task report();
$display("=======================================");
$display(" Final Report");
$display("=======================================");
$display("Total Test : %d", scb.total_cnt);
$display("Pass Counter : %d", scb.pass_cnt);
$display("Fail Counter : %d", scb.fail_cnt);
$display("WRITE CNT : %d", scb.write_cnt);
$display("=======================================");
$display(" test bench is finished!");
$display("=======================================");
#10 $finish;
endtask
task pre_run();
drv.reset();
endtask
task run();
fork
gen.run(100);
drv.run();
mon.run();
scb.run();
join_any
report();
#10 $finish;
endtask
task run_test();
pre_run();
run();
endtask
endclass
module tb_ram ();
environment env;
ram_interface ram_intf ();
ram dut (
.clk (ram_intf.clk),
.addr (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
simulation
'[하만]세미콘 아카데미 > verilog' 카테고리의 다른 글
0524 uart fifo (0) | 2024.07.09 |
---|---|
0523 FIFO Systemverilog verification (0) | 2024.07.09 |
0522 32bit register.sv (0) | 2024.07.09 |
0521 num.sv (0) | 2024.07.09 |
0521 system verilog, adder.sv (0) | 2024.07.09 |