|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
-
- 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<s_wtrans.b_len+1; i++) begin
- `uvm_info("DEBUG_S", "Inside read_data_loop", UVM_LOW)
- // addr_n = addr_align + i*no_bytes;
-
- // Lane selection for the first transfer. In case of unaligned transfer the bytes b/w the
- // start address and aligned address is not transferred. Thus for an unaligned burst, the
- // first transfer has less bytes and the actual burst size;
- // 'c' is a variable which stores which byte lane to select. In AXI, valid byte lane is used and
- // selected dynamically using lower_byte_lane and upper_byte_lane, but we for simplicity, we are
- // sending the data starting from WDATA[0:8*2**b_size], thus c converts the lower_byte_lane to
- // such that it always select the data lines within the valid byte lanes, i.e. [0:8*2**b_size]
- // This can be changed in future to match with proper AXI protocol
- if(i==0 || s_wtrans.b_type == FIXED) begin
- lower_byte_lane = addr_1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
- upper_byte_lane = addr_align+no_bytes-1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
- addr_n = addr_1;
- $display("entering");
- c = isAligned ? 0 : lower_byte_lane;
- while (c>=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<s_rtrans.b_len+1; i++) begin
- // `uvm_info("DEBUG_S", "Inside send_data_loop", UVM_LOW)
- // addr_n = addr_align + i*no_bytes;
-
- // Lane selection for the first transfer. In case of unaligned transfer the bytes b/w the
- // start address and aligned address is not transferred. Thus for an unaligned burst, the
- // first transfer has less bytes and the actual burst size;
- // 'c' is a variable which stores which byte lane to select. In AXI, valid byte lane is used and
- // selected dynamically using lower_byte_lane and upper_byte_lane, but we for simplicity, we are
- // sending the data starting from WDATA[0:8*2**b_size], thus c converts the lower_byte_lane to
- // such that it always select the data lines within the valid byte lanes, i.e. [0:8*2**b_size]
- // This can be changed in future to match with proper AXI protocol
- if(i==0 || s_rtrans.b_type == FIXED) begin
- lower_byte_lane = addr_1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
- upper_byte_lane = addr_align+no_bytes-1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
- addr_n = addr_1;
- c = isAligned ? 0 : lower_byte_lane;
- while (c>=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
|