class axi_s_driver extends uvm_driver; `uvm_component_utils(axi_s_driver) // Components virtual axi_intf#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)).SDRV vif; // Variables axi_transaction#(D_WIDTH, A_WIDTH) s_wtrans, s_rtrans; bit [7:0] mem [bit[A_WIDTH-1:0]]; bit [A_WIDTH-1:0] w_addr, r_addr; bit w_done, r_done; // Methods extern task drive(); extern task read_write_address(); extern task read_read_address(); extern task read_write_data(); extern task send_read_data(); function new(string name, uvm_component parent); super.new(name, parent); w_done = 1; r_done = 1; endfunction //new() // Function: build_phase extern function void build_phase(uvm_phase phase); // Function: run_phase extern task run_phase(uvm_phase phase); endclass //axi_s_driver extends uvm_driver function void axi_s_driver::build_phase(uvm_phase phase); s_wtrans = new("s_wtrans"); s_rtrans = new("s_rtrans"); endfunction: build_phase task axi_s_driver::run_phase(uvm_phase phase); vif.s_drv_cb.AWREADY <= 1; vif.s_drv_cb.ARREADY <= 1; vif.s_drv_cb.WREADY <= 1; // vif.s_drv_cb.BVALID <= 1; // vif.s_drv_cb.RLAST <= 1; vif.s_drv_cb.RVALID <= 1; vif.s_drv_cb.RDATA <= 'b0; forever begin @(vif.s_drv_cb); drive(); end endtask: run_phase task axi_s_driver::drive(); if(!vif.rstn) begin vif.s_drv_cb.RVALID <= 0; vif.s_drv_cb.BVALID <= 0; return; end // fork if(vif.s_drv_cb.WRITE) begin begin // `uvm_info("DEBUG_S", $sformatf("w_addr(), w_done = %0d", w_done), UVM_HIGH) //if(!s_wtrans.id[8]) begin if(w_done) begin w_done = 0; read_write_address(); #5 read_write_data(); w_done = 1; end end end end else if(!vif.s_drv_cb.WRITE) begin begin // `uvm_info("DEBUG_S", $sformatf("r_addr(), r_done = %0d", r_done), UVM_HIGH) // if(s_rtrans.id[8]) begin if(r_done) begin r_done = 0; $display("t is %t,enter read//////////",$time); #10 read_read_address(); #20 send_read_data(); r_done = 1; $display("t is %t,exit read//////////",$time); end end end end // join_none endtask: drive task axi_s_driver::read_write_address(); `uvm_info("DEBUG_S", "Inside read_write_address", UVM_LOW) wait(vif.s_drv_cb.AWVALID); s_wtrans.id = vif.s_drv_cb.AWID; s_wtrans.addr = vif.s_drv_cb.AWADDR; s_wtrans.b_size = vif.s_drv_cb.AWSIZE; s_wtrans.b_type = B_TYPE'(vif.s_drv_cb.AWBURST); s_wtrans.b_len = vif.s_drv_cb.AWLEN; s_wtrans.print(); endtask: read_write_address task axi_s_driver::read_write_data(); int addr_1, addr_n, addr_align; int lower_byte_lane, upper_byte_lane, upper_wrap_boundary, lower_wrap_boundary; int no_bytes, total_bytes; bit isAligned; int c; bit err, align_err; `uvm_info("DEBUG_S", "Inside read_write_data", UVM_LOW) vif.s_drv_cb.BVALID <= 0; // Initial values and calculations addr_1 = s_wtrans.addr; no_bytes = 2**s_wtrans.b_size; total_bytes = no_bytes * (s_wtrans.b_len+1); addr_align = int'(addr_1/no_bytes)*no_bytes; `uvm_info("DEBUG_S", $sformatf("Calculated aligned addr %0d,addr_1 %0d", addr_align,addr_1), UVM_LOW) isAligned = addr_1 == addr_align; // Calculate boundaries for WRAP Burst if(s_wtrans.b_type == WRAP) begin lower_wrap_boundary = int'(addr_1/total_bytes)*total_bytes; upper_wrap_boundary = lower_wrap_boundary + total_bytes; `uvm_info("DEBUG_S", $sformatf("Calculated Lower Wrap Boundary: %0d", lower_wrap_boundary), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("Calculated Upper Wrap Boundary: %0d", upper_wrap_boundary), UVM_HIGH) end // check whether the wrap burst is alligned or not if(s_wtrans.b_type == WRAP && !isAligned) align_err = 1; // Store data err = 0; for (int i=0; i=no_bytes) begin c -= no_bytes; end end // For 2nd and all other transfers the address is always alligned and thus can read the entire // valid byte lane, i.e, [0:8*2**b_size]; and thus c always start with 0 else begin lower_byte_lane = addr_n-int'(addr_n/(D_WIDTH/8))*(D_WIDTH/8); upper_byte_lane = lower_byte_lane + no_bytes-1; c = 0; end `uvm_info("DEBUG_S", $sformatf("lower_byte_lane is %0d", lower_byte_lane), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("upper_byte_lane is %0d", upper_byte_lane), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("addr_n is %0d", addr_n), UVM_LOW) wait(vif.s_drv_cb.WVALID); `uvm_info("DEBUG_S", $sformatf("WVALID is %0d", vif.s_drv_cb.WVALID), UVM_LOW) // Follows little endian err = 0; for (int j=lower_byte_lane; j<=upper_byte_lane; j++) begin if(addr_n+j-lower_byte_lane >= 2**A_WIDTH) err = 1; if(err || align_err) continue; mem[addr_n+j-lower_byte_lane] = vif.s_drv_cb.WDATA[8*c+:8]; `uvm_info("DEBUG_S", $sformatf("c is %0d, addr is %0d, stored value is %h", c, addr_n+j-lower_byte_lane, mem[addr_n+j-lower_byte_lane]), UVM_HIGH) c++; c = c>=no_bytes ? 0:c; end // Update address if(s_wtrans.b_type != FIXED) begin if(isAligned) begin addr_n = addr_n+no_bytes; if(s_wtrans.b_type == WRAP) begin `uvm_info("DEBUG_S", $sformatf("Updated addrn before boundary check: %0d", addr_n), UVM_HIGH) addr_n = addr_n>=upper_wrap_boundary ? lower_wrap_boundary : addr_n; `uvm_info("DEBUG_S", $sformatf("Updated addrn after boundary check: %0d", addr_n), UVM_HIGH) end end else begin addr_n = addr_align + no_bytes; isAligned = 1; end end @(vif.s_drv_cb); end vif.s_drv_cb.BID <= s_wtrans.id; if(err || align_err) vif.s_drv_cb.BRESP <= 2'b01; else vif.s_drv_cb.BRESP <= 2'b00; @(vif.s_drv_cb); vif.s_drv_cb.BVALID <= 1; @(vif.s_drv_cb); wait(vif.s_drv_cb.BREADY) vif.s_drv_cb.BVALID <= 0; endtask: read_write_data task axi_s_driver::read_read_address(); `uvm_info("DEBUG_S", "Inside read_write_address", UVM_LOW) // `uvm_info("DEBUG_S",$sformatf("ARVALID IS %b",vif.s_drv_cb.ARVALID) , UVM_LOW) wait(vif.s_drv_cb.ARVALID); // `uvm_info("DEBUG_S", $sformatf("ARVALID IS %b",vif.s_drv_cb.ARVALID), UVM_LOW) s_rtrans.id = vif.s_drv_cb.ARID; s_rtrans.addr = vif.s_drv_cb.ARADDR; s_rtrans.b_size = vif.s_drv_cb.ARSIZE; s_rtrans.b_type = B_TYPE'(vif.s_drv_cb.ARBURST); s_rtrans.b_len = vif.s_drv_cb.ARLEN; s_rtrans.print(); endtask: read_read_address task axi_s_driver::send_read_data(); int addr_1, addr_n, addr_align; int lower_byte_lane, upper_byte_lane, upper_wrap_boundary, lower_wrap_boundary; int no_bytes, total_bytes; bit isAligned; int c; bit err; `uvm_info("DEBUG_S", "Inside send_read_data", UVM_LOW) addr_1 = s_rtrans.addr; no_bytes = 2**s_rtrans.b_size; total_bytes = no_bytes * (s_rtrans.b_len+1); // Calculate align address addr_align = int'(addr_1/no_bytes)*no_bytes; `uvm_info("DEBUG_S", $sformatf("Calculated aligned addr %0d", addr_align), UVM_HIGH) isAligned = addr_1 == addr_align; // If WRAP Burst then calculate the wrap boundary if(s_rtrans.b_type == WRAP) begin lower_wrap_boundary = int'(addr_1/total_bytes)*total_bytes; upper_wrap_boundary = lower_wrap_boundary + total_bytes; `uvm_info("DEBUG_S", $sformatf("Calculated Lower Wrap Boundary: %0d", lower_wrap_boundary), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("Calculated Upper Wrap Boundary: %0d", upper_wrap_boundary), UVM_HIGH) end // Initial signals vif.s_drv_cb.RLAST <= 0; vif.s_drv_cb.RVALID <=0; vif.s_drv_cb.RID <= s_rtrans.id; // Store data for (int i=0; i=no_bytes) begin c -= no_bytes; end end // For 2nd and all other transfers the address is always alligned and thus can read the entire // valid byte lane, i.e, [0:8*2**b_size]; and thus c always start with 0 else begin lower_byte_lane = addr_n-int'(addr_n/(D_WIDTH/8))*(D_WIDTH/8); upper_byte_lane = lower_byte_lane + no_bytes-1; c = 0; end // @(vif.s_drv_cb); `uvm_info("DEBUG_S", $sformatf("lower_byte_lane is %0d", lower_byte_lane), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("upper_byte_lane is %0d", upper_byte_lane), UVM_HIGH) `uvm_info("DEBUG_S", $sformatf("addr_n is %0d", addr_n), UVM_HIGH) // Follows little endian err = 0; for (int j=lower_byte_lane; j<=upper_byte_lane; j++) begin if(!mem.exists(addr_n+j-lower_byte_lane)) begin err = 1; vif.s_drv_cb.RDATA[8*c+:8] <= 'b0; `uvm_info("DEBUG_S", $sformatf("c is %0d, addr is %0d, No data in location", c, addr_n+j-lower_byte_lane), UVM_HIGH) end else begin vif.s_drv_cb.RDATA[8*c+:8] <= mem[addr_n+j-lower_byte_lane]; `uvm_info("DEBUG_S", $sformatf("c is %0d, addr is %0d, stored value is %h", c, addr_n+j-lower_byte_lane, mem[addr_n+j-lower_byte_lane]), UVM_HIGH) end c++; c = c>=no_bytes ? 0:c; end if(i == s_rtrans.b_len) begin vif.s_drv_cb.RLAST <= 1; end if(err) vif.s_drv_cb.RRESP <= 2'b01; else vif.s_drv_cb.RRESP <= 2'b00; @(vif.s_drv_cb); vif.s_drv_cb.RVALID <= 1; // Update address if(s_rtrans.b_type != FIXED) begin if(isAligned) begin addr_n = addr_n+no_bytes; if(s_rtrans.b_type == WRAP) begin `uvm_info("DEBUG_S", $sformatf("Updated addrn before boundary check: %0d", addr_n), UVM_HIGH) addr_n = addr_n>=upper_wrap_boundary ? lower_wrap_boundary : addr_n; `uvm_info("DEBUG_S", $sformatf("Updated addrn after boundary check: %0d", addr_n), UVM_HIGH) end end else begin addr_n = addr_align + no_bytes; isAligned = 1; end end @(vif.s_drv_cb); wait(vif.s_drv_cb.RREADY); vif.s_drv_cb.RVALID <= 0; end endtask: send_read_data