├── agent ├── my_sqncr.sv ├── axi_s_agent.sv ├── axi_m_agent.sv ├── axi_s_drv.sv ├── axi_m_seq.sv ├── axi_m_mon.sv ├── my_seq_item.sv └── axi_m_drv.sv ├── env ├── axi_env.sv ├── axi_subscriber.sv └── axi_sb.sv ├── top ├── tb_top.sv ├── axi_test.sv └── axi_top.sv ├── interface └── my_interface.sv ├── README.md └── rtl └── axi_slave_dut.sv /agent/my_sqncr.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `ifndef SEQUENCER 4 | `define SEQUENCER 5 | 6 | import uvm_pkg::*; 7 | `include "uvm_macros.svh" 8 | 9 | class axi_m_sequencer #( 10 | int WIDTH = 32, 11 | int SIZE = 3 12 | ) extends uvm_sequencer#(axi_m_Sequence_Item#(WIDTH, SIZE)); 13 | `uvm_component_param_utils(axi_m_sequencer#(WIDTH, SIZE)) 14 | 15 | function new(string name = "axi_m_sequencer", uvm_component parent); 16 | super.new(name, parent); 17 | $display("inside axi m seqncr"); 18 | endfunction : new 19 | endclass 20 | 21 | `endif 22 | 23 | -------------------------------------------------------------------------------- /agent/axi_s_agent.sv: -------------------------------------------------------------------------------- 1 | `ifndef SLAVE_AGENT 2 | `define SLAVE_AGENT 3 | 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | 7 | class axi_s_Agent #( 8 | int WIDTH = 32, 9 | SIZE = 3 10 | ) extends uvm_agent; 11 | `uvm_component_param_utils(axi_s_Agent#(WIDTH, SIZE)) 12 | axi_s_driver #(WIDTH, SIZE) drv; 13 | 14 | 15 | function new(string name = "axi_s_Agent", uvm_component parent); 16 | super.new(name, parent); 17 | endfunction : new 18 | 19 | function void build_phase(uvm_phase phase); 20 | super.build_phase(phase); 21 | drv = axi_s_driver#(WIDTH, SIZE)::type_id::create("drv", this); 22 | endfunction : build_phase 23 | 24 | function void connect_phase(uvm_phase phase); 25 | endfunction : connect_phase 26 | 27 | endclass 28 | 29 | `endif 30 | -------------------------------------------------------------------------------- /agent/axi_m_agent.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `ifndef AGENT 4 | `define AGENT 5 | 6 | import uvm_pkg::*; 7 | `include "uvm_macros.svh" 8 | 9 | class axi_m_Agent #( 10 | int WIDTH = 32, 11 | int SIZE = 3 12 | ) extends uvm_agent; 13 | 14 | `uvm_component_param_utils(axi_m_Agent#(WIDTH, SIZE)) 15 | 16 | axi_m_sequencer#(WIDTH, SIZE) seq; 17 | axi_m_driver #(WIDTH, SIZE) drv; 18 | axi_m_monitor#(WIDTH,SIZE) mon; 19 | 20 | 21 | function new(string name = "axi_m_Agent", uvm_component parent); 22 | super.new(name, parent); 23 | endfunction : new 24 | 25 | function void build_phase(uvm_phase phase); 26 | super.build_phase(phase); 27 | 28 | seq = axi_m_sequencer#(WIDTH, SIZE)::type_id::create("seq", this); 29 | drv = axi_m_driver#(WIDTH, SIZE)::type_id::create("drv", this); 30 | mon = axi_m_monitor#(WIDTH,SIZE)::type_id::create("mon", this); 31 | 32 | endfunction : build_phase 33 | 34 | function void connect_phase(uvm_phase phase); 35 | drv.seq_item_port.connect(seq.seq_item_export); 36 | endfunction : connect_phase 37 | 38 | endclass 39 | 40 | `endif 41 | -------------------------------------------------------------------------------- /env/axi_env.sv: -------------------------------------------------------------------------------- 1 | `ifndef ENVIRONMENT 2 | `define ENVIRONMENT 3 | 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | 7 | class axi_Environment #( 8 | int WIDTH = 32, 9 | SIZE = 3 10 | ) extends uvm_env; 11 | `uvm_component_param_utils(axi_Environment#(WIDTH, SIZE)) 12 | 13 | axi_m_Agent #(WIDTH, SIZE) agent_m; 14 | axi_scoreboard #(WIDTH, SIZE) scoreboard; 15 | 16 | 17 | function new(string name = "axi_Environment", uvm_component parent); 18 | super.new(name, parent); 19 | endfunction : new 20 | 21 | function void build_phase(uvm_phase phase); 22 | super.build_phase(phase); 23 | agent_m = axi_m_Agent#(WIDTH, SIZE)::type_id::create("agent_m", this); 24 | scoreboard = axi_scoreboard#(WIDTH, SIZE)::type_id::create("scoreboard", this); 25 | endfunction : build_phase 26 | 27 | function void connect_phase(uvm_phase phase); 28 | $display("Inside env connect phaser"); 29 | 30 | agent_m.mon.mon2sb_port.connect(scoreboard.mon2sb_export_mon); 31 | agent_m.drv.drv2sb_port.connect(scoreboard.drv2sb_export_drv); 32 | 33 | endfunction : connect_phase 34 | endclass 35 | 36 | `endif 37 | 38 | -------------------------------------------------------------------------------- /top/tb_top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 11/05/2021 11:29:55 AM 7 | // Design Name: 8 | // Module Name: tb_top 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | import uvm_pkg::*; 23 | `include "uvm_macros.svh" 24 | 25 | `define WIDTH 32 26 | `define SIZE 3 27 | 28 | `include "../rtl/axi_slave_dut.sv" 29 | `include "../interface/my_interface.sv" 30 | `include "../agent/my_seq_item.sv" 31 | `include "../agent/my_sqncr.sv" 32 | `include "../agent/axi_m_seq.sv" 33 | `include "../agent/axi_m_drv.sv" 34 | //`include "axi_s_drv.sv" 35 | `include "../agent/axi_m_mon.sv" 36 | `include "../agent/axi_m_agent.sv" 37 | //`include "axi_s_agent.sv" 38 | `include "../env/axi_sb.sv" 39 | //`include "axi_subscriber.sv" 40 | `include "../env/axi_env.sv" 41 | `include "axi_test.sv" 42 | `include "axi_top.sv" 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /interface/my_interface.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `ifndef AXI_INTERFACE 3 | `define AXI_INTERFACE 4 | import uvm_pkg::*; 5 | `include "uvm_macros.svh" 6 | 7 | 8 | interface axi_intf #( 9 | int WIDTH = 32, 10 | SIZE = 3 11 | ) ( 12 | input bit clk, 13 | reset 14 | ); 15 | 16 | 17 | logic AWREADY; 18 | logic AWVALID; 19 | logic [SIZE-2:0] AWBURST; 20 | logic [SIZE-1:0] AWSIZE; 21 | logic [(WIDTH/8)-1:0] AWLEN; 22 | logic [WIDTH-1:0] AWADDR; 23 | logic [(WIDTH/8)-1:0] AWID; 24 | 25 | int que_WLEN[$]; 26 | 27 | // DATA WRITE CHANNEL 28 | logic WREADY; 29 | logic WVALID; 30 | logic WLAST; 31 | logic [(WIDTH/8)-1:0] WSTRB; 32 | logic [WIDTH-1:0] WDATA; 33 | //logic [(WIDTH/8)-1:0] WID; 34 | 35 | // WRITE RESPONSE CHANNEL 36 | logic [(WIDTH/8)-1:0] BID; 37 | logic [SIZE-2:0] BRESP; 38 | logic BVALID; 39 | logic BREADY; 40 | 41 | // READ ADDRESS CHANNEL 42 | logic ARVALID; 43 | logic ARREADY; 44 | logic [(WIDTH/8)-1:0] ARID; 45 | logic [WIDTH-1:0] ARADDR; 46 | logic [(WIDTH/8)-1:0] ARLEN; 47 | logic [SIZE-1:0] ARSIZE; 48 | logic [SIZE-2:0] ARBURST; 49 | 50 | // READ DATA CHANNEL 51 | logic [(WIDTH/8)-1:0] RID; 52 | logic [WIDTH-1:0] RDATA; 53 | logic [SIZE-2:0] RRESP; 54 | logic RLAST; 55 | logic RVALID; 56 | logic RREADY; 57 | 58 | endinterface 59 | 60 | `endif 61 | -------------------------------------------------------------------------------- /agent/axi_s_drv.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | 4 | `ifndef SLAVE_DRIVER 5 | `define SLAVE_DRIVER 6 | 7 | import uvm_pkg::*; 8 | `include "uvm_macros.svh" 9 | 10 | class axi_s_driver#(int WIDTH=32,SIZE=3) extends uvm_driver#(axi_m_Sequence_Item#(WIDTH,SIZE)); 11 | 12 | virtual interface axi_intf#(WIDTH,SIZE) intf; 13 | `uvm_component_param_utils(axi_s_driver#(WIDTH,SIZE)) 14 | 15 | 16 | byte unsigned m_mem[1024]; //4294967296 17 | 18 | axi_m_Sequence_Item#(WIDTH,SIZE) tx; 19 | 20 | 21 | function new(string name="axi_s_driver",uvm_component parent); 22 | super.new(name,parent); 23 | $display("Inside Driver Cons"); 24 | tx=new; 25 | endfunction : new 26 | 27 | function void build_phase(uvm_phase phase); 28 | super.build_phase(phase); 29 | endfunction : build_phase 30 | 31 | function void connect_phase(uvm_phase phase); 32 | super.connect_phase(phase); 33 | if (!uvm_config_db#(virtual interface axi_intf#(WIDTH,SIZE))::get(this, "", "intf", intf)) 34 | `uvm_error("NOVIF",{"virtual interface must be set for: ",get_full_name(),".intf"}) 35 | endfunction : connect_phase 36 | 37 | task run_phase(uvm_phase phase); 38 | phase.raise_objection (phase); 39 | //fork 40 | //reset_signals(); 41 | sent_addr_write_trx(); 42 | 43 | //join_any 44 | phase.drop_objection(phase); 45 | endtask : run_phase 46 | 47 | 48 | task sent_addr_write_trx(); 49 | @(posedge intf.clk); 50 | 51 | intf.AWREADY <= 1'b0; 52 | 53 | intf.AWREADY <= 1'b1; 54 | @(posedge intf.clk); 55 | 56 | intf.AWVALID <= 1'b1; 57 | 58 | endtask 59 | 60 | 61 | 62 | endclass 63 | 64 | `endif 65 | -------------------------------------------------------------------------------- /top/axi_test.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 11/05/2021 12:21:48 PM 7 | // Design Name: 8 | // Module Name: axi_test 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `ifndef TEST 23 | `define TEST 24 | 25 | import uvm_pkg::*; 26 | `include "uvm_macros.svh" 27 | 28 | class axi_Test extends uvm_test; 29 | 30 | `uvm_component_utils(axi_Test) 31 | 32 | axi_Environment #(`WIDTH, `SIZE) env; 33 | axi_m_wr_Sequence #(`WIDTH, `SIZE) seq_m_write; 34 | 35 | function new(string name = "axi_Test", uvm_component parent); 36 | super.new(name, parent); 37 | endfunction : new 38 | 39 | function void build_phase(uvm_phase phase); 40 | super.build_phase(phase); 41 | $display("HR:: AXI Test is Here"); 42 | 43 | env = axi_Environment#(`WIDTH, `SIZE)::type_id::create("env", this); 44 | seq_m_write = axi_m_wr_Sequence#(`WIDTH, `SIZE)::type_id::create("seq_m_write", this); 45 | endfunction : build_phase 46 | 47 | task run_phase(uvm_phase phase); 48 | phase.raise_objection(this); 49 | repeat (5) seq_m_write.start(env.agent_m.seq); 50 | // repeat(4) seq_m_read.start(env.agent_m.seq); 51 | repeat (4) seq_m_write.start(env.agent_m.seq); 52 | // repeat(4) seq_m_read.start(env.agent_m.seq); 53 | repeat (3) seq_m_write.start(env.agent_m.seq); 54 | // repeat(3) seq_m_read.start(env.agent_m.seq); 55 | phase.drop_objection(this); 56 | endtask 57 | 58 | endclass 59 | 60 | `endif 61 | -------------------------------------------------------------------------------- /top/axi_top.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module top; 4 | 5 | bit clk, reset; 6 | always #5 clk = ~clk; 7 | axi_intf #(32, 3) intf ( 8 | clk, 9 | reset 10 | ); 11 | 12 | axi_ram #( 13 | .DATA_WIDTH(32), 14 | .ADDR_WIDTH(10), 15 | .STRB_WIDTH(4), 16 | .ID_WIDTH(4), 17 | .PIPELINE_OUTPUT(0) 18 | ) dut_inst ( 19 | .s_axi_awready(intf.AWREADY), 20 | .s_axi_awvalid(intf.AWVALID), 21 | .s_axi_awburst(intf.AWBURST), 22 | .s_axi_awsize (intf.AWSIZE), 23 | .s_axi_awlen (intf.AWLEN), 24 | .s_axi_awaddr (intf.AWADDR), 25 | .s_axi_awid (intf.AWID), 26 | .rst (intf.reset), 27 | .clk (intf.clk), 28 | .s_axi_wdata (intf.WDATA), 29 | .s_axi_wstrb (intf.WSTRB), 30 | .s_axi_wvalid (intf.WVALID), 31 | .s_axi_wready (intf.WREADY), 32 | .s_axi_bid (intf.BID), 33 | .s_axi_bresp (intf.BRESP), 34 | .s_axi_bvalid (intf.BVALID), 35 | .s_axi_bready (intf.BREADY), 36 | .s_axi_arid (intf.ARID), 37 | .s_axi_araddr (intf.ARADDR), 38 | .s_axi_arlen (intf.ARLEN), 39 | .s_axi_arsize (intf.ARSIZE), 40 | .s_axi_arburst(intf.ARBURST), 41 | .s_axi_arvalid(intf.ARVALID), 42 | .s_axi_arready(intf.ARREADY), 43 | .s_axi_rid (intf.RID), 44 | .s_axi_rdata (intf.RDATA), 45 | .s_axi_rresp (intf.RRESP), 46 | .s_axi_rlast (intf.RLAST), 47 | .s_axi_rvalid (intf.RVALID), 48 | .s_axi_rready (intf.RREADY), 49 | .s_axi_wlast (intf.WLAST) 50 | ); 51 | 52 | initial begin 53 | clk = 0; 54 | reset = 1; 55 | #20 reset = 0; 56 | end 57 | 58 | 59 | initial begin 60 | $dumpfile("dump.vcd"); 61 | $dumpvars; 62 | $display("HR:: In Top Registering Interface"); 63 | uvm_config_db#(virtual axi_intf #(32, 3))::set(uvm_root::get(), "*", "intf", intf); 64 | $display("HR:: In top Running test"); 65 | run_test("axi_Test"); 66 | end 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /agent/axi_m_seq.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | 4 | `ifndef SEQUENCE 5 | `define SEQUENCE 6 | 7 | import uvm_pkg::*; 8 | `include "uvm_macros.svh" 9 | 10 | class axi_m_wr_Sequence #( 11 | int WIDTH = 32, 12 | SIZE = 3 13 | ) extends uvm_sequence#(axi_m_Sequence_Item#(WIDTH, SIZE)); 14 | 15 | `uvm_object_param_utils(axi_m_wr_Sequence#(WIDTH, SIZE)) 16 | 17 | function new(string name = "axi_m_wr_Sequence"); 18 | super.new(name); 19 | $display("m wr seq"); 20 | endfunction 21 | 22 | virtual task body(); 23 | 24 | `uvm_create(req) 25 | 26 | //req.AWVALID = 1'b1; 27 | req.AWBURST.rand_mode(1); // = 2'b11; 28 | req.AWSIZE.rand_mode(1); // = 3'b100; 29 | req.AWLEN.rand_mode(1); // = 4'b0101; 30 | req.AWADDR.rand_mode(1); 31 | req.AWID.rand_mode(1); // = 4'b1001; 32 | req.WSTRB.rand_mode(1); 33 | req.WDATA.rand_mode(1); 34 | 35 | 36 | $display("seq_item class defn"); 37 | req.print(); 38 | 39 | 40 | $display("m wr seq created with awvalid =%d, awaddr = %d", req.AWVALID, req.AWADDR); 41 | `uvm_rand_send_with(req, {req.RW==0; }) //Read sequence 42 | // previously it was RW=1 43 | $display("m wr seq sent"); 44 | 45 | endtask 46 | 47 | endclass 48 | 49 | class axi_m_rd_Sequence #( 50 | int WIDTH = 32, 51 | SIZE = 3 52 | ) extends uvm_sequence#(axi_m_Sequence_Item#(WIDTH, SIZE)); 53 | 54 | `uvm_object_param_utils(axi_m_rd_Sequence#(WIDTH, SIZE)) 55 | 56 | function new(string name = "axi_m_rd_Sequence"); 57 | super.new(name); 58 | endfunction 59 | 60 | virtual task body(); 61 | `uvm_create(req) 62 | req.ARADDR.rand_mode(1); 63 | req.ARID.rand_mode(1); 64 | req.ARLEN.rand_mode(1); 65 | req.ARBURST.rand_mode(1); 66 | req.ARSIZE.rand_mode(1); 67 | req.RID.rand_mode(1); 68 | req.RDATA.rand_mode(1); 69 | `uvm_rand_send_with(req, {req.RW==1; }) //Read sequence 70 | // previously it was RW=0 71 | endtask 72 | endclass 73 | 74 | `endif 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /agent/axi_m_mon.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `ifndef MASTER_MONITOR 4 | `define MASTER_MONITOR 5 | 6 | import uvm_pkg::*; 7 | `include "uvm_macros.svh" 8 | 9 | class axi_m_monitor#(int WIDTH=32,SIZE=3) extends uvm_monitor;//#(axi_m_Sequence_Item#(WIDTH,SIZE)); 10 | 11 | `uvm_component_param_utils(axi_m_monitor#(WIDTH,SIZE)) 12 | virtual axi_intf#(WIDTH,SIZE) intf; 13 | uvm_analysis_port#(axi_m_Sequence_Item#(WIDTH,SIZE)) mon2sb_port; 14 | axi_m_Sequence_Item#(WIDTH,SIZE) w_tx; 15 | 16 | function new(string name, uvm_component parent); 17 | super.new(name, parent); 18 | w_tx = new(); 19 | mon2sb_port = new("mon2sb_port",this); 20 | endfunction 21 | 22 | function void build_phase(uvm_phase phase); 23 | super.build_phase(phase); 24 | if(!uvm_config_db#(virtual axi_intf#(WIDTH,SIZE))::get(this, "", "intf", intf)) 25 | `uvm_fatal("NO_VIF","virtual interface not found"); 26 | endfunction 27 | 28 | 29 | virtual task run_phase(uvm_phase phase); 30 | forever begin 31 | collect_trans(); 32 | mon2sb_port.write(w_tx); 33 | end 34 | endtask 35 | 36 | task collect_trans(); 37 | @(!intf.reset); 38 | 39 | @(posedge intf.clk) 40 | //forever 41 | begin 42 | $display("In forever"); 43 | while (!intf.AWVALID || !intf.AWREADY || !intf.AWID) 44 | @(posedge intf.clk); 45 | w_tx.AWADDR = intf.AWADDR; 46 | w_tx.AWLEN = intf.AWLEN; 47 | w_tx.AWSIZE = intf. AWSIZE; 48 | w_tx.AWBURST = intf.AWBURST; 49 | 50 | while (!intf.WVALID || !intf.WREADY) 51 | @(posedge intf.clk); 52 | w_tx.WDATA = intf.WDATA; 53 | w_tx.WSTRB = intf.WSTRB; 54 | w_tx.WLAST = intf.WLAST; 55 | 56 | $display("w_tx.ARID =%d",w_tx.ARID); 57 | while (!intf.ARREADY || !intf.ARVALID || !intf.RREADY || !intf.RVALID) 58 | @(posedge intf.clk); 59 | $display("w_tx.ARID =%d",w_tx.ARID); 60 | w_tx.ARADDR = intf.ARADDR; 61 | $display("w_tx.ARADDR =%d",w_tx.ARADDR); 62 | w_tx.ARID = intf.ARID; 63 | w_tx.ARLEN = intf.ARLEN; 64 | w_tx.ARSIZE = intf.ARSIZE; 65 | w_tx.ARBURST = intf.ARBURST; 66 | 67 | @(posedge intf.clk) 68 | while (!intf.RREADY || !intf.RVALID) 69 | @(posedge intf.clk); 70 | w_tx.RID = intf.RID; 71 | w_tx.RDATA = intf.RDATA; 72 | w_tx.RRESP = intf.RRESP; 73 | w_tx.RLAST = intf.RLAST; 74 | 75 | 76 | end //forever begin 77 | $display("FLAG"); 78 | w_tx.print(); 79 | $display("mon2sb_port's package write complete"); 80 | 81 | endtask 82 | 83 | endclass 84 | 85 | 86 | `endif 87 | -------------------------------------------------------------------------------- /agent/my_seq_item.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `ifndef SEQUENCE_ITEM 4 | `define SEQUENCE_ITEM 5 | 6 | import uvm_pkg::*; 7 | `include "uvm_macros.svh" 8 | 9 | class axi_m_Sequence_Item #( 10 | int WIDTH = 32, 11 | int SIZE = 3 12 | ) extends uvm_sequence_item; 13 | 14 | bit RW = 1; 15 | logic AWREADY; 16 | logic AWVALID; 17 | rand logic [SIZE-2:0] AWBURST; 18 | rand logic [SIZE-1:0] AWSIZE; 19 | rand logic [(WIDTH/8)-1:0] AWLEN; 20 | rand logic [WIDTH-1:0] AWADDR; 21 | rand logic [(WIDTH/8)-1:0] AWID; 22 | 23 | // DATA WRITE CHANNEL 24 | logic WREADY; 25 | logic WVALID; 26 | logic WLAST; 27 | rand logic [(WIDTH/8)-1:0] WSTRB; 28 | rand logic [7:0] WDATA; 29 | //rand logic [(WIDTH/8)-1:0] WID; 30 | 31 | // WRITE RESPONSE CHANNEL 32 | logic [(WIDTH/8)-1:0] BID; 33 | logic [SIZE-2:0] BRESP; 34 | logic BVALID; 35 | logic BREADY; 36 | 37 | // READ ADDRESS CHANNEL 38 | logic ARREADY; 39 | logic ARVALID; 40 | rand logic [(WIDTH/8)-1:0] ARID; 41 | rand logic [WIDTH-1:0] ARADDR; 42 | rand logic [(WIDTH/8)-1:0] ARLEN; 43 | rand logic [SIZE-1:0] ARSIZE; 44 | rand logic [SIZE-2:0] ARBURST; 45 | 46 | // READ DATA CHANNEL 47 | rand logic [(WIDTH/8)-1:0] RID; 48 | rand logic [7:0] RDATA; 49 | logic [SIZE-2:0] RRESP; 50 | logic RLAST; 51 | logic RVALID; 52 | logic RREADY; 53 | 54 | `uvm_object_param_utils_begin(axi_m_Sequence_Item#(WIDTH, SIZE)) 55 | `uvm_field_int(AWREADY, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 56 | `uvm_field_int(AWVALID, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 57 | `uvm_field_int(AWBURST, UVM_ALL_ON) 58 | `uvm_field_int(AWSIZE, UVM_ALL_ON) 59 | `uvm_field_int(AWLEN, UVM_ALL_ON) 60 | `uvm_field_int(AWADDR, UVM_ALL_ON) 61 | `uvm_field_int(AWID, UVM_ALL_ON) 62 | `uvm_field_int(RW, UVM_ALL_ON | UVM_NOCOMPARE) 63 | `uvm_field_int(WREADY, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 64 | `uvm_field_int(WVALID, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 65 | `uvm_field_int(WLAST, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 66 | `uvm_field_int(WSTRB, UVM_ALL_ON | UVM_NOCOMPARE) 67 | `uvm_field_int(WDATA, UVM_ALL_ON | UVM_NOCOMPARE) 68 | `uvm_field_int(BID, UVM_ALL_ON) 69 | `uvm_field_int(BRESP, UVM_ALL_ON | UVM_NOCOMPARE) 70 | `uvm_field_int(BVALID, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 71 | `uvm_field_int(BREADY, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 72 | `uvm_field_int(ARREADY, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 73 | `uvm_field_int(ARVALID, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 74 | `uvm_field_int(ARBURST, UVM_ALL_ON | UVM_NOCOMPARE) 75 | `uvm_field_int(ARSIZE, UVM_ALL_ON) 76 | `uvm_field_int(ARLEN, UVM_ALL_ON) 77 | `uvm_field_int(ARADDR, UVM_ALL_ON) 78 | `uvm_field_int(ARID, UVM_ALL_ON) 79 | `uvm_field_int(RREADY, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 80 | `uvm_field_int(RVALID, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 81 | `uvm_field_int(RLAST, UVM_ALL_ON | UVM_NOPRINT | UVM_NOCOMPARE) 82 | `uvm_field_int(RRESP, UVM_ALL_ON | UVM_NOCOMPARE) 83 | `uvm_field_int(RDATA, UVM_ALL_ON | UVM_NOCOMPARE) 84 | `uvm_field_int(RID, UVM_ALL_ON) 85 | `uvm_object_utils_end 86 | 87 | function new(string name = "axi_m_Sequence_Item"); 88 | super.new(name); 89 | endfunction 90 | 91 | endclass 92 | 93 | `endif 94 | 95 | -------------------------------------------------------------------------------- /env/axi_subscriber.sv: -------------------------------------------------------------------------------- 1 | `ifndef SUBSCRIBER 2 | `define SUBSCRIBER 3 | import uvm_pkg::*; 4 | `include "uvm_macros.svh" 5 | 6 | class AXI_Subscriber#(int WIDTH=32,SIZE=3) extends uvm_subscriber#(axi_m_Sequence_Item#(WIDTH,SIZE)); 7 | 8 | `uvm_component_param_utils(AXI_Subscriber#(WIDTH,SIZE)) 9 | 10 | axi_m_Sequence_Item#(WIDTH,SIZE) tx; 11 | bit [(WIDTH/8)-1:0] wstrb; 12 | 13 | covergroup AXI_cg; 14 | 15 | rw_bit_transition : coverpoint tx.RW 16 | { 17 | bins trans_01 = (0 => 1); 18 | bins trans_10 = (1 => 0); 19 | } 20 | 21 | AWADDR_write : coverpoint tx.AWADDR 22 | { 23 | bins awaddr_1[10] = {[0:99]}; 24 | bins awaddr_2 = {[100:$]}; 25 | } 26 | ARADDR_read : coverpoint tx.ARADDR 27 | { 28 | bins araddr_1[10] = {[0:99]}; 29 | bins araddr_2 = {[100:$]}; 30 | } 31 | READ_WRITE : coverpoint tx.RW 32 | { 33 | bins wr = {0}; 34 | bins rd = {1}; 35 | } 36 | AWID_write : coverpoint tx.AWID 37 | { 38 | bins awid[3] = {[0:$]}; 39 | } 40 | WID_write : coverpoint tx.WID 41 | { 42 | bins wid[3] = {[0:$]}; 43 | } 44 | BID_write : coverpoint tx.BID 45 | { 46 | bins bid[3] = {[0:$]}; 47 | } 48 | ARID_read : coverpoint tx.ARID 49 | { 50 | bins arid[3] = {[0:$]}; 51 | } 52 | RID_read : coverpoint tx.RID 53 | { 54 | bins rid[3] = {[0:$]}; 55 | } 56 | AWSIZE_write : coverpoint tx.AWSIZE 57 | { 58 | bins awlen[3] = {[0:$]}; 59 | } 60 | ARSIZE_read : coverpoint tx.ARSIZE 61 | { 62 | bins arlen[3] = {[0:$]}; 63 | } 64 | 65 | AWLEN_write : coverpoint tx.AWLEN; 66 | ARLEN_read : coverpoint tx.ARLEN; 67 | 68 | AWBURST_write : coverpoint tx.AWBURST 69 | { 70 | bins awburst = {[0:2]}; 71 | illegal_bins awburst_illegal = {3}; 72 | } 73 | ARBURST_read : coverpoint tx.ARBURST 74 | { 75 | bins arburst = {[0:2]}; 76 | illegal_bins arburst_illegal = {3}; 77 | } 78 | 79 | endgroup 80 | 81 | covergroup AXI_WSTRB_cg; 82 | WSTRB_write : coverpoint wstrb 83 | { 84 | bins WSTRB_val[16] = {[0:$]}; 85 | } 86 | endgroup 87 | 88 | function new(string name="AXI_Subscriber",uvm_component parent); 89 | super.new(name,parent); 90 | AXI_cg = new(); 91 | AXI_WSTRB_cg=new(); 92 | endfunction : new 93 | 94 | virtual function void write(axi_m_Sequence_Item#(WIDTH,SIZE) t); 95 | tx = t; 96 | AXI_cg.sample(); 97 | foreach(tx.WSTRB[i]) 98 | begin 99 | wstrb=tx.WSTRB[i]; 100 | AXI_WSTRB_cg.sample(); 101 | end 102 | endfunction 103 | 104 | endclass 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | `endif 115 | -------------------------------------------------------------------------------- /env/axi_sb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 11/24/2021 05:09:47 PM 7 | // Design Name: 8 | // Module Name: axi_sb 9 | // Project Name: 10 | // Target Devices: 11 | // Tool Versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | `timescale 1ns / 1ps 24 | 25 | `ifndef SCOREBOARDS 26 | `define SCOREBOARDS 27 | 28 | import uvm_pkg::*; 29 | `include "uvm_macros.svh" 30 | 31 | class axi_scoreboard #( 32 | int WIDTH = 32, 33 | SIZE = 3 34 | ) extends uvm_scoreboard; 35 | 36 | `uvm_component_param_utils(axi_scoreboard#(WIDTH, SIZE)) 37 | 38 | uvm_analysis_export #(axi_m_Sequence_Item #(WIDTH, SIZE)) drv2sb_export_drv; //expected 39 | uvm_analysis_export #(axi_m_Sequence_Item #(WIDTH, SIZE)) mon2sb_export_mon; //actual 40 | 41 | uvm_tlm_analysis_fifo #(axi_m_Sequence_Item #(WIDTH, SIZE)) expfifo; 42 | uvm_tlm_analysis_fifo #(axi_m_Sequence_Item #(WIDTH, SIZE)) actualfifo; 43 | 44 | virtual axi_intf #(WIDTH, SIZE) intf; 45 | 46 | axi_m_Sequence_Item #(WIDTH, SIZE) mon_tx, drv_tx; 47 | 48 | 49 | function new(string name = "axi_scoreboard", uvm_component parent); 50 | super.new(name, parent); 51 | $display("In Scoreboard Constructor"); 52 | endfunction 53 | 54 | function void build_phase(uvm_phase phase); 55 | super.build_phase(phase); 56 | drv2sb_export_drv = new("drv2sb_export_drv", this); 57 | mon2sb_export_mon = new("mon2sb_export_mon", this); 58 | expfifo = new("expfifo", this); 59 | actualfifo = new("actualfifo", this); 60 | mon_tx = new("mon_tx"); 61 | drv_tx = new("drv_tx"); 62 | $display("In Scoreboard build phase"); 63 | endfunction 64 | 65 | function void connect_phase(uvm_phase phase); 66 | 67 | drv2sb_export_drv.connect(expfifo.analysis_export); 68 | mon2sb_export_mon.connect(actualfifo.analysis_export); 69 | $display("In Scoreboard Connect phase"); 70 | endfunction 71 | 72 | virtual task run_phase(uvm_phase phase); 73 | expfifo.get(drv_tx); 74 | actualfifo.get(mon_tx); 75 | compare(); 76 | $display("In Scoreboard Run phase"); 77 | endtask 78 | 79 | virtual function void compare(); 80 | $display("In Scoreboard: %d", mon_tx.RDATA); 81 | if (mon_tx.RDATA === drv_tx.WDATA) begin 82 | `uvm_info("compare", {"Test: OK!"}, UVM_LOW); 83 | $display("-------------------------------------------------"); 84 | $display("------ INFO : TEST CASE DATA PASSED ------------------"); 85 | $display("-------------------------------------------------"); 86 | end else begin 87 | `uvm_info("compare", {"Test: Fail!"}, UVM_LOW); 88 | $display("---------------------------------------------------"); 89 | $display("------ ERROR : TEST CASE DATA FAILED ------------------"); 90 | $display("---------------------------------------------------"); 91 | end 92 | $display("In Scoreboard Compare"); 93 | 94 | if (mon_tx.AWADDR === drv_tx.ARADDR) begin 95 | `uvm_info("compare", {"Test: OK!"}, UVM_LOW); 96 | $display("---------------------------------------------------------"); 97 | $display("------ INFO : TEST CASE ADDRESS PASSED ------------------"); 98 | $display("---------------------------------------------------------"); 99 | end else begin 100 | `uvm_info("compare", {"Test: Fail!"}, UVM_LOW); 101 | $display("----------------------------------------------------------"); 102 | $display("------ ERROR : TEST CASE ADDRESS FAILED ------------------"); 103 | $display("----------------------------------------------------------"); 104 | end 105 | $display("In Scoreboard: %d", mon_tx.ARADDR); 106 | endfunction 107 | 108 | endclass 109 | 110 | `endif 111 | -------------------------------------------------------------------------------- /agent/axi_m_drv.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `ifndef DRIVER 4 | `define DRIVER 5 | 6 | import uvm_pkg::*; 7 | `include "uvm_macros.svh" 8 | 9 | class axi_m_driver #( 10 | int WIDTH = 32, 11 | SIZE = 3 12 | ) extends uvm_driver#(axi_m_Sequence_Item#(WIDTH, SIZE)); 13 | 14 | `uvm_component_utils_begin(axi_m_driver#(WIDTH, SIZE)) 15 | `uvm_component_utils_end 16 | 17 | virtual interface axi_intf #(WIDTH, SIZE) intf; 18 | 19 | uvm_analysis_port #(axi_m_Sequence_Item #(WIDTH, SIZE)) drv2sb_port; 20 | 21 | // new 22 | int RW; 23 | // 24 | 25 | axi_m_Sequence_Item #(WIDTH, SIZE) tx; 26 | 27 | function new(string name = "axi_m_driver", uvm_component parent); 28 | super.new(name, parent); 29 | $display("inside m driver construct"); 30 | endfunction : new 31 | 32 | function void build_phase(uvm_phase phase); 33 | super.build_phase(phase); 34 | drv2sb_port = new("drv2sb_port", this); 35 | $display("inside m driver build phase"); 36 | endfunction : build_phase 37 | 38 | 39 | function void connect_phase(uvm_phase phase); 40 | super.connect_phase(phase); 41 | if (!uvm_config_db#(virtual interface axi_intf #(WIDTH, SIZE))::get(this, "", "intf", intf)) 42 | `uvm_error("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".intf"}) 43 | $display("inside master driver connect phase"); 44 | 45 | endfunction : connect_phase 46 | 47 | task run_phase(uvm_phase phase); 48 | super.run_phase(phase); 49 | 50 | `uvm_info(get_type_name(), "in run phase", UVM_DEBUG) 51 | $display("inside m driver run phase"); 52 | seq_item_port.get_next_item(req); 53 | $display("inside m driver run %d", req.AWADDR); 54 | 55 | @(posedge intf.clk) req.RDATA = req.WDATA; 56 | req.ARADDR = req.AWADDR; 57 | req.ARLEN = req.AWLEN; 58 | req.ARSIZE = req.AWSIZE; 59 | req.ARBURST = req.AWBURST; 60 | 61 | drv2sb_port.write(req); 62 | seq_item_port.item_done(); 63 | seq_item_port.put(req); 64 | 65 | 66 | $display("scoreboard package of driver start"); 67 | req.print(); 68 | $display("scoreboard package of driver print ended"); 69 | 70 | fork 71 | sent_trx_to_seq(); 72 | sent_addr_write_trx(); 73 | sent_data_write_trx(); 74 | received_resp_write(); 75 | sent_addr_read_trx(); 76 | join_any 77 | $display("inside master driver run end"); 78 | 79 | 80 | endtask : run_phase 81 | 82 | task sent_trx_to_seq(); 83 | begin 84 | case (RW) 85 | 0: drv2sb_port.write(req); 86 | 1: `uvm_error("NOTYPE", {"type not support in sent_trx_to_seq Loop"}) 87 | endcase 88 | end 89 | endtask 90 | 91 | task sent_addr_write_trx(); 92 | @(!intf.reset) intf.AWVALID <= 1'b0; 93 | @(posedge intf.clk) begin 94 | 95 | begin 96 | 97 | intf.AWVALID <= 1'b1; 98 | intf.AWADDR <= req.AWADDR; 99 | intf.AWBURST <= '0; 100 | intf.AWSIZE <= req.AWSIZE; 101 | intf.AWLEN <= 1'b0; 102 | intf.AWID <= req.AWID; 103 | while (!intf.AWREADY) @(posedge intf.clk); 104 | intf.AWVALID <= 1'b0; 105 | intf.AWBURST <= '0; 106 | intf.AWSIZE <= '0; 107 | intf.AWLEN <= '0; 108 | intf.AWID <= '0; 109 | 110 | sent_data_write_trx(); 111 | end 112 | end 113 | endtask 114 | 115 | task sent_data_write_trx(); 116 | @(!intf.reset) intf.WVALID <= 1'bz; 117 | @(posedge intf.clk) begin 118 | intf.WVALID <= 1'b1; 119 | intf.WSTRB <= req.WSTRB; 120 | intf.WDATA <= req.WDATA; 121 | intf.WLAST <= 1'b1; 122 | received_resp_write(); 123 | 124 | while (!intf.WREADY) @(posedge intf.clk); 125 | intf.WVALID <= 1'b0; 126 | intf.WSTRB <= 1'b0; 127 | intf.WDATA <= 1'b0; 128 | intf.WLAST <= 1'b0; 129 | end 130 | sent_addr_read_trx(); 131 | endtask 132 | 133 | task received_resp_write(); 134 | 135 | @(!intf.reset) begin 136 | intf.BREADY = 1'b0; 137 | 138 | @(posedge intf.clk) begin 139 | 140 | if (intf.WVALID && intf.WREADY && intf.WLAST) intf.BREADY = 1'b1; 141 | 142 | while (!intf.BVALID) 143 | @(posedge intf.clk) begin 144 | intf.BREADY <= 1'b1; 145 | end 146 | end 147 | end 148 | endtask 149 | 150 | task sent_addr_read_trx(); 151 | @(!intf.reset) intf.ARVALID <= 1'b0; 152 | //#55 153 | @(posedge intf.clk) begin 154 | while (!intf.BVALID) @(posedge intf.clk) intf.ARVALID <= 1'b1; 155 | intf.ARADDR <= req.AWADDR; 156 | intf.ARLEN <= 1'b0; 157 | intf.ARBURST <= 1'b0; 158 | intf.ARSIZE <= req.AWSIZE; 159 | intf.ARID <= req.AWID; 160 | intf.RREADY <= 1'b1; 161 | 162 | while (!intf.ARREADY) @(posedge intf.clk) intf.ARVALID <= 1'b0; 163 | intf.ARADDR <= 1'b0; 164 | intf.ARLEN <= 1'b0; 165 | intf.ARBURST <= 1'b0; 166 | intf.ARSIZE <= 1'b0; 167 | intf.ARID <= 1'b0; 168 | end 169 | endtask 170 | 171 | endclass 172 | 173 | `endif 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Title 2 | 3 | Verifying a simple ram module using AXI Master/Slave UVM method. 4 | 5 | ## Description 6 | 7 | Our project aims to test a ram module using UVM method. Ram module is used to perform simple write/read opeartion on a particular address. Here, our ram module acts like a slave dut & we run it by using AXI Master. We generate our inputs from a sequencer. Then we drive our ram module via driver module. Monitor block reads the information of each transactions from the interface and sends them to Scoreboard module. Scoreboard module compares the result and shows us the final result if a successful operation was performed or not. 8 | 9 | ## Folder Structure 10 | 11 | Our folder structure is given below, 12 | ```bash 13 | ├── top 14 | │ ├── axi_test.sv 15 | │ └── axi_top.sv 16 | │ └── tb_top.sv 17 | ├── rtl 18 | │ └── axi_slave_dut.sv 19 | ├── interface 20 | | └── my_interface.sv 21 | ├── env 22 | | ├── axi_env.sv 23 | │ └── axi_sb.sv 24 | │ └── axi_subscriber.sv 25 | ├── agent 26 | | ├── axi_m_agent.sv 27 | │ └── axi_m_drv.sv 28 | │ └── axi_m_mon.sv 29 | │ └── axi_m_seq.sv 30 | │ └── my_seq_item.sv 31 | │ └── my_sqncr.sv 32 | │ └── axi_s_agent.sv 33 | │ └── axi_s_mon.sv 34 | └── README.md 35 | ``` 36 | 37 | ### Details 38 | 39 | In this section we have provided details information of our modules. 40 | 41 | 1) axi_test: axi_test is the top level UVM component in the UVM testbench. This level instantiates the top level environment, configures the environment and 42 | applies stimulus by invoking UVM Sequences through the environment to the DUT. 43 | 44 | 2) axi_top: In axi_top we defined the clock, reset signals & their timeperiods. We also made connection with the DUT in this level. "axi_test" is initiated thorugh this module. 45 | 46 | 3) tb_top: In this module we have defined our modules access paths. One might need to change this if they want to run it in their machine. 47 | 48 | 4) my_interface: Interface module defines all the AXI protocol signals and their data types & sizes. 49 | 50 | 5) axi_env: axi_env module encapsulates the scoreboard & the agent modules. Environment module maintains the connections between various ports. 51 | 52 | 6) axi_sb: axi_sb module is like a checker board. This module checks the data & compares them. Scoreboard recieves data from the sequence item & the monitor. 53 | 54 | 7) my_seq_item: my_seq_item module initializes the input signals to drive the DUT. 55 | 56 | 8) axi_m_seq: axi_m_seq module generates various input sequences like write_sequence, read_sequence for the DUT using my_seq_item module 57 | 58 | 9) my_sqncr: This module is like a gateaway between driver module & sequence item. 59 | 60 | 10) axi_m_drv: This module drives the DUT through the interface. They receive the datas from the "my_sqncr" module. 61 | 62 | 11) axi_mon: This module just monitors all the datas from the interface. Then, it lists down all the informations & sends them to the scorboard. 63 | 64 | 12) axi_m_agent: Agent module encapsulates three modules (sequencer, driver & monitor) 65 | 66 | 67 | ### UVM Architecture 68 | 69 | Below, we have shown our UVM architecture. 70 | 71 | ![architecture](https://user-images.githubusercontent.com/89468502/145974227-5c536386-ab83-4d9e-9d69-5a1b459623fa.png) 72 | 73 | 74 | ## Getting Started 75 | 76 | 77 | ### Dependencies 78 | 79 | To simulate this project we need Xilinx Vivado as our EDA tool. We used the student version 2020.2 80 | 81 | 82 | ### Installing 83 | 84 | Below we have shown how one can install Xilinx Vivado Webpack. 85 | 86 | 1) First one must go to this site at https://www.xilinx.com/support/download.html 87 | 2) Now you can download any version (preferably the latest one) according to their own operating system. 88 | 3) One must create an account before downloading the EDA. 89 | 4) Then by following on screen instructions one can easily install the tool on their machine. 90 | 5) For first time run, one need to install gcc,gnn compilers. 91 | 92 | 93 | ## PREREQUISTE 94 | 95 | Before executing the program one must configure the settings of vivado. 96 | 97 | 1) We have to type "-L uvm" in the marked area. 98 | 99 | ![1](https://user-images.githubusercontent.com/89468502/145795314-a5dae749-bc8d-4f48-98cf-19876e283dda.png) 100 | 101 | 2) Just like the first one, we have to type "-L uvm" in the marked area. 102 | 103 | ![2](https://user-images.githubusercontent.com/89468502/145795342-c97461f6-3c38-4ae9-a423-ae2187d64d4f.png) 104 | 105 | 3) For the last modification we have to type "-testplusarg UVM_TESTNAME=axi_Test -testplusarg UVM_VERBOSITY=UVM_LOW" in the marked area. 106 | 107 | ![3](https://user-images.githubusercontent.com/89468502/145795363-a403a57e-791c-4ede-8497-cd0cb274bcf1.png) 108 | 109 | 110 | ## Authors 111 | 112 | 1) Nahid Rahman 113 | 2) Md. Shamiul Alam Hriday 114 | 115 | ## Version History 116 | 117 | * 0.1 118 | * Initial Release: This project only can simulate single fixed-burst operation mode. Currently we are working to simulate multiple incremental & wrapping burst mode. Will update them as soon as they are functional. 119 | 120 | ## Acknowledgments 121 | 122 | For our ram DUT we used, https://github.com/alexforencich/verilog-axi/blob/master/rtl/axi_ram.v 123 | 124 | 125 | -------------------------------------------------------------------------------- /rtl/axi_slave_dut.sv: -------------------------------------------------------------------------------- 1 | `resetall 2 | `timescale 1ns / 1ps 3 | `default_nettype none 4 | 5 | /* 6 | * AXI4 RAM 7 | */ 8 | module axi_ram # 9 | ( 10 | // Width of data bus in bits 11 | parameter DATA_WIDTH = 32, 12 | // Width of address bus in bits 13 | parameter ADDR_WIDTH = 16, 14 | // Width of wstrb (width of data bus in words) 15 | parameter STRB_WIDTH = (DATA_WIDTH/8), 16 | // Width of ID signal 17 | parameter ID_WIDTH = 8, 18 | // Extra pipeline register on output 19 | parameter PIPELINE_OUTPUT = 0 20 | ) 21 | ( 22 | input wire clk, 23 | input wire rst, 24 | 25 | input wire [ID_WIDTH-1:0] s_axi_awid, 26 | input wire [ADDR_WIDTH-1:0] s_axi_awaddr, 27 | input wire [7:0] s_axi_awlen, 28 | input wire [2:0] s_axi_awsize, 29 | input wire [1:0] s_axi_awburst, 30 | input wire s_axi_awlock, 31 | input wire [3:0] s_axi_awcache, 32 | input wire [2:0] s_axi_awprot, 33 | input wire s_axi_awvalid, 34 | output wire s_axi_awready, 35 | input wire [DATA_WIDTH-1:0] s_axi_wdata, 36 | input wire [STRB_WIDTH-1:0] s_axi_wstrb, 37 | input wire s_axi_wlast, 38 | input wire s_axi_wvalid, 39 | output wire s_axi_wready, 40 | output wire [ID_WIDTH-1:0] s_axi_bid, 41 | output wire [1:0] s_axi_bresp, 42 | output wire s_axi_bvalid, 43 | input wire s_axi_bready, 44 | input wire [ID_WIDTH-1:0] s_axi_arid, 45 | input wire [ADDR_WIDTH-1:0] s_axi_araddr, 46 | input wire [7:0] s_axi_arlen, 47 | input wire [2:0] s_axi_arsize, 48 | input wire [1:0] s_axi_arburst, 49 | input wire s_axi_arlock, 50 | input wire [3:0] s_axi_arcache, 51 | input wire [2:0] s_axi_arprot, 52 | input wire s_axi_arvalid, 53 | output wire s_axi_arready, 54 | output wire [ID_WIDTH-1:0] s_axi_rid, 55 | output wire [DATA_WIDTH-1:0] s_axi_rdata, 56 | output wire [1:0] s_axi_rresp, 57 | output wire s_axi_rlast, 58 | output wire s_axi_rvalid, 59 | input wire s_axi_rready 60 | ); 61 | 62 | parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); 63 | parameter WORD_WIDTH = STRB_WIDTH; 64 | parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; 65 | 66 | // bus width assertions 67 | initial begin 68 | if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin 69 | $error("Error: AXI data width not evenly divisble (instance %m)"); 70 | $finish; 71 | end 72 | 73 | if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin 74 | $error("Error: AXI word width must be even power of two (instance %m)"); 75 | $finish; 76 | end 77 | end 78 | 79 | localparam [0:0] 80 | READ_STATE_IDLE = 1'd0, 81 | READ_STATE_BURST = 1'd1; 82 | 83 | reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next; 84 | 85 | localparam [1:0] 86 | WRITE_STATE_IDLE = 2'd0, 87 | WRITE_STATE_BURST = 2'd1, 88 | WRITE_STATE_RESP = 2'd2; 89 | 90 | reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next; 91 | 92 | reg mem_wr_en; 93 | reg mem_rd_en; 94 | 95 | reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next; 96 | reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next; 97 | reg [7:0] read_count_reg = 8'd0, read_count_next; 98 | reg [2:0] read_size_reg = 3'd0, read_size_next; 99 | reg [1:0] read_burst_reg = 2'd0, read_burst_next; 100 | reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next; 101 | reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next; 102 | reg [7:0] write_count_reg = 8'd0, write_count_next; 103 | reg [2:0] write_size_reg = 3'd0, write_size_next; 104 | reg [1:0] write_burst_reg = 2'd0, write_burst_next; 105 | 106 | reg s_axi_awready_reg = 1'b0, s_axi_awready_next; 107 | reg s_axi_wready_reg = 1'b0, s_axi_wready_next; 108 | reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next; 109 | reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; 110 | reg s_axi_arready_reg = 1'b0, s_axi_arready_next; 111 | reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next; 112 | reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next; 113 | reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next; 114 | reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; 115 | reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}}; 116 | reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}}; 117 | reg s_axi_rlast_pipe_reg = 1'b0; 118 | reg s_axi_rvalid_pipe_reg = 1'b0; 119 | 120 | // (* RAM_STYLE="BLOCK" *) 121 | reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0]; 122 | 123 | wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 124 | wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 125 | wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 126 | wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 127 | 128 | assign s_axi_awready = s_axi_awready_reg; 129 | assign s_axi_wready = s_axi_wready_reg; 130 | assign s_axi_bid = s_axi_bid_reg; 131 | assign s_axi_bresp = 2'b00; 132 | assign s_axi_bvalid = s_axi_bvalid_reg; 133 | assign s_axi_arready = s_axi_arready_reg; 134 | assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg; 135 | assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg; 136 | assign s_axi_rresp = 2'b00; 137 | assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg; 138 | assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg; 139 | 140 | integer i, j; 141 | 142 | initial begin 143 | // two nested loops for smaller number of iterations per loop 144 | // workaround for synthesizer complaints about large loop counts 145 | for (i = 0; i < 2**VALID_ADDR_WIDTH; i = i + 2**(VALID_ADDR_WIDTH/2)) begin 146 | for (j = i; j < i + 2**(VALID_ADDR_WIDTH/2); j = j + 1) begin 147 | mem[j] = 0; 148 | end 149 | end 150 | end 151 | 152 | always @* begin 153 | write_state_next = WRITE_STATE_IDLE; 154 | 155 | mem_wr_en = 1'b0; 156 | 157 | write_id_next = write_id_reg; 158 | write_addr_next = write_addr_reg; 159 | write_count_next = write_count_reg; 160 | write_size_next = write_size_reg; 161 | write_burst_next = write_burst_reg; 162 | 163 | s_axi_awready_next = 1'b0; 164 | s_axi_wready_next = 1'b0; 165 | s_axi_bid_next = s_axi_bid_reg; 166 | s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready; 167 | 168 | case (write_state_reg) 169 | WRITE_STATE_IDLE: begin 170 | s_axi_awready_next = 1'b1; 171 | 172 | if (s_axi_awready && s_axi_awvalid) begin 173 | write_id_next = s_axi_awid; 174 | write_addr_next = s_axi_awaddr; 175 | write_count_next = s_axi_awlen; 176 | write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH); 177 | write_burst_next = s_axi_awburst; 178 | 179 | s_axi_awready_next = 1'b0; 180 | s_axi_wready_next = 1'b1; 181 | write_state_next = WRITE_STATE_BURST; 182 | end else begin 183 | write_state_next = WRITE_STATE_IDLE; 184 | end 185 | end 186 | WRITE_STATE_BURST: begin 187 | s_axi_wready_next = 1'b1; 188 | 189 | if (s_axi_wready && s_axi_wvalid) begin 190 | mem_wr_en = 1'b1; 191 | if (write_burst_reg != 2'b00) begin 192 | write_addr_next = write_addr_reg + (1 << write_size_reg); 193 | end 194 | write_count_next = write_count_reg - 1; 195 | if (write_count_reg > 0) begin 196 | write_state_next = WRITE_STATE_BURST; 197 | end else begin 198 | s_axi_wready_next = 1'b0; 199 | if (s_axi_bready || !s_axi_bvalid) begin 200 | s_axi_bid_next = write_id_reg; 201 | s_axi_bvalid_next = 1'b1; 202 | s_axi_awready_next = 1'b1; 203 | write_state_next = WRITE_STATE_IDLE; 204 | end else begin 205 | write_state_next = WRITE_STATE_RESP; 206 | end 207 | end 208 | end else begin 209 | write_state_next = WRITE_STATE_BURST; 210 | end 211 | end 212 | WRITE_STATE_RESP: begin 213 | if (s_axi_bready || !s_axi_bvalid) begin 214 | s_axi_bid_next = write_id_reg; 215 | s_axi_bvalid_next = 1'b1; 216 | s_axi_awready_next = 1'b1; 217 | write_state_next = WRITE_STATE_IDLE; 218 | end else begin 219 | write_state_next = WRITE_STATE_RESP; 220 | end 221 | end 222 | endcase 223 | end 224 | 225 | always @(posedge clk) begin 226 | write_state_reg <= write_state_next; 227 | 228 | write_id_reg <= write_id_next; 229 | write_addr_reg <= write_addr_next; 230 | write_count_reg <= write_count_next; 231 | write_size_reg <= write_size_next; 232 | write_burst_reg <= write_burst_next; 233 | 234 | s_axi_awready_reg <= s_axi_awready_next; 235 | s_axi_wready_reg <= s_axi_wready_next; 236 | s_axi_bid_reg <= s_axi_bid_next; 237 | s_axi_bvalid_reg <= s_axi_bvalid_next; 238 | 239 | for (i = 0; i < WORD_WIDTH; i = i + 1) begin 240 | if (mem_wr_en & s_axi_wstrb[i]) begin 241 | mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE]; 242 | end 243 | end 244 | 245 | if (rst) begin 246 | write_state_reg <= WRITE_STATE_IDLE; 247 | 248 | s_axi_awready_reg <= 1'b0; 249 | s_axi_wready_reg <= 1'b0; 250 | s_axi_bvalid_reg <= 1'b0; 251 | end 252 | end 253 | 254 | always @* begin 255 | read_state_next = READ_STATE_IDLE; 256 | 257 | mem_rd_en = 1'b0; 258 | 259 | s_axi_rid_next = s_axi_rid_reg; 260 | s_axi_rlast_next = s_axi_rlast_reg; 261 | s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg)); 262 | 263 | read_id_next = read_id_reg; 264 | read_addr_next = read_addr_reg; 265 | read_count_next = read_count_reg; 266 | read_size_next = read_size_reg; 267 | read_burst_next = read_burst_reg; 268 | 269 | s_axi_arready_next = 1'b0; 270 | 271 | case (read_state_reg) 272 | READ_STATE_IDLE: begin 273 | s_axi_arready_next = 1'b1; 274 | 275 | if (s_axi_arready && s_axi_arvalid) begin 276 | read_id_next = s_axi_arid; 277 | read_addr_next = s_axi_araddr; 278 | read_count_next = s_axi_arlen; 279 | read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH); 280 | read_burst_next = s_axi_arburst; 281 | 282 | s_axi_arready_next = 1'b0; 283 | read_state_next = READ_STATE_BURST; 284 | end else begin 285 | read_state_next = READ_STATE_IDLE; 286 | end 287 | end 288 | READ_STATE_BURST: begin 289 | if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin 290 | mem_rd_en = 1'b1; 291 | s_axi_rvalid_next = 1'b1; 292 | s_axi_rid_next = read_id_reg; 293 | s_axi_rlast_next = read_count_reg == 0; 294 | if (read_burst_reg != 2'b00) begin 295 | read_addr_next = read_addr_reg + (1 << read_size_reg); 296 | end 297 | read_count_next = read_count_reg - 1; 298 | if (read_count_reg > 0) begin 299 | read_state_next = READ_STATE_BURST; 300 | end else begin 301 | s_axi_arready_next = 1'b1; 302 | read_state_next = READ_STATE_IDLE; 303 | end 304 | end else begin 305 | read_state_next = READ_STATE_BURST; 306 | end 307 | end 308 | endcase 309 | end 310 | 311 | always @(posedge clk) begin 312 | read_state_reg <= read_state_next; 313 | 314 | read_id_reg <= read_id_next; 315 | read_addr_reg <= read_addr_next; 316 | read_count_reg <= read_count_next; 317 | read_size_reg <= read_size_next; 318 | read_burst_reg <= read_burst_next; 319 | 320 | s_axi_arready_reg <= s_axi_arready_next; 321 | s_axi_rid_reg <= s_axi_rid_next; 322 | s_axi_rlast_reg <= s_axi_rlast_next; 323 | s_axi_rvalid_reg <= s_axi_rvalid_next; 324 | 325 | if (mem_rd_en) begin 326 | s_axi_rdata_reg <= mem[read_addr_valid]; 327 | end 328 | 329 | if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin 330 | s_axi_rid_pipe_reg <= s_axi_rid_reg; 331 | s_axi_rdata_pipe_reg <= s_axi_rdata_reg; 332 | s_axi_rlast_pipe_reg <= s_axi_rlast_reg; 333 | s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg; 334 | end 335 | 336 | if (rst) begin 337 | read_state_reg <= READ_STATE_IDLE; 338 | 339 | s_axi_arready_reg <= 1'b0; 340 | s_axi_rvalid_reg <= 1'b0; 341 | s_axi_rvalid_pipe_reg <= 1'b0; 342 | end 343 | end 344 | 345 | endmodule 346 | 347 | --------------------------------------------------------------------------------