tb_top.sv
module tb_top; logic clk, rstz; logic req,gnt,trans,write,ready; logic [31:0] addr,wdata,rdata; master_bfm master ( .clk, .rstz, .req, .gnt, .trans, .write, .addr, .wdata, .rdata, .ready ); slave_bfm slave ( .clk, .rstz, .trans, .write, .addr, .wdata, .rdata, .ready ); task gen_clk; forever begin #50 clk <= ~clk; end endtask task gen_gnt; forever begin while(req!==1'b1) @(posedge clk); repeat (2) @(posedge clk); gnt <= 1'b1; @(posedge clk); gnt <= 1'b0; @(posedge clk); end endtask initial begin bit [31:0] this_rdata; $display("run start"); clk <= 1'b1; rstz <= 1'b1; gnt <= 1'b0; #100 fork gen_clk; gen_gnt; join_none #20 rstz <= 1'b0; #100; -> master.go_e; endendmodulemaster_bfm.sv
module master_bfm ( input logic clk, rstz, output logic req, input logic gnt, output logic trans, output logic write, output logic [31:0] addr, output logic [31:0] wdata, input logic [31:0] rdata, input logic ready);/// clk ~~|_____|~~~~~|_____|~~~~~|_____|~~~~~|_____|~~~~~|_____|~~~~~/// req ________|~~~~~~~~~~~~~~~~~~~~~~~|_____________________________/// gnt ____________________|~~~~~~~~~~~|_____________________________/// trans ________________________________|~~~~~~~~~~~~~~~~~~~~~~~|_____/// write ________________________________|~~~~~~~~~~~~~~~~~~~~~~~|_____/// wdata XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_______________________XXXXXX/// ready XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX___________|~~~~~~~~~~~XXXXXX class transaction; bit cmd_type; /// 1:write, 0:read bit [31:0] addr; bit [31:0] data; endclass /// Define for DPI-C //////////////////////////// export "DPI-C" task write_issue; export "DPI-C" task read_issue; export "DPI-C" task wait_cycle; import "DPI-C" context task test(); ///////////////////////////////////////////////// typedef mailbox #(transaction) t_mbx; t_mbx mbx_trans_req; t_mbx mbx_trans_dat; t_mbx mbx_trans_end; event go_e; /// for export task (DPI-C) task write_issue(int unsigned this_addr, int unsigned this_data); transaction this_item; this_item = new; this_item.cmd_type = 1'b1; this_item.addr = this_addr; this_item.data = this_data; $display("[%0d] write cmd. addr=%08xh, data=%08xh",$time,this_addr,this_data); mbx_trans_req.put(this_item); mbx_trans_end.get(this_item); endtask task read_issue(int unsigned this_addr); transaction this_item; bit [31:0] this_data; this_item = new; this_item.cmd_type = 1'b0; this_item.addr = this_addr; $display("[%0d] read cmd. addr=%08xh",$time,this_addr); mbx_trans_req.put(this_item); mbx_trans_end.get(this_item); this_data = this_item.data; $display("[%0d] read data. data=%08xh",$time,this_data); endtask task wait_cycle(int val); repeat (val) @(posedge clk); endtask /// for internal task (Driver) task req_driver; transaction this_item; forever begin mbx_trans_req.get(this_item); @(posedge clk); req <= 1'b1; @(posedge clk); while(gnt!==1'b1) @(posedge clk); req <= 1'b0; mbx_trans_dat.put(this_item); end endtask task dat_driver; transaction this_item; forever begin mbx_trans_dat.get(this_item); trans <= 1'b1; write <= this_item.cmd_type; addr <= this_item.addr; if(this_item.cmd_type==1'b1)begin wdata <= this_item.data; //$display("[%0d]a write=%b", $time, write); end while(ready===1'b0) @(posedge clk); if(this_item.cmd_type==1'b0)begin this_item.data = rdata; end trans <= 1'b0; mbx_trans_end.put(this_item); end endtask task bus_reset; req <= 1'b0; trans <= 1'b0; write <= 1'b0; addr <= 32'h0000_0000; wdata <= 32'h0000_0000; endtask initial begin mbx_trans_req = new; mbx_trans_dat = new; mbx_trans_end = new; wait(rstz===1'b1); bus_reset; wait(rstz===1'b0); @(posedge clk); fork req_driver; dat_driver; join_none end initial begin @go_e; test(); $finish; endendmoduleslave_bfm.sv
module slave_bfm ( input logic clk,rstz, input logic trans, input logic write, input logic [31:0] addr, input logic [31:0] wdata, output logic [31:0] rdata, output logic ready); byte memory [int unsigned]; /// associative array
function byte get_mem_data(logic [31:0] this_addr); if(memory.exists(this_addr)) return(memory[this_addr]); else begin $display("[%0d] no written data. return random value...",$time); return($random); end endfunction task mem_access; byte wait_val; forever begin while(trans!==1'b1) @(posedge clk); wait_val = $urandom_range(0,3); repeat(wait_val) @(posedge clk); ready <= 1'b1; if(write===1'b1)begin memory[{addr[31:2],2'b00}] = wdata[7:0]; memory[{addr[31:2],2'b01}] = wdata[15:8]; memory[{addr[31:2],2'b10}] = wdata[23:16]; memory[{addr[31:2],2'b11}] = wdata[31:24]; end else begin rdata[7:0] = get_mem_data({addr[31:2],2'b00}); rdata[15:8] = get_mem_data({addr[31:2],2'b01}); rdata[23:16] = get_mem_data({addr[31:2],2'b10}); rdata[31:24] = get_mem_data({addr[31:2],2'b11}); end @(posedge clk); ready <= 1'b0; @(posedge clk); end endtask task reset_bus; rdata <= 32'h00000000; ready <= 1'b0; endtask initial begin reset_bus; wait(rstz===1'b1); mem_access; endendmodule