You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 rivejä
14 KiB

  1. class axi_s_driver extends uvm_driver;
  2. `uvm_component_utils(axi_s_driver)
  3. // Components
  4. virtual axi_intf#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)).SDRV vif;
  5. // Variables
  6. axi_transaction#(D_WIDTH, A_WIDTH) s_wtrans, s_rtrans;
  7. bit [7:0] mem [bit[A_WIDTH-1:0]];
  8. bit [A_WIDTH-1:0] w_addr, r_addr;
  9. bit w_done, r_done;
  10. // Methods
  11. extern task drive();
  12. extern task read_write_address();
  13. extern task read_read_address();
  14. extern task read_write_data();
  15. extern task send_read_data();
  16. function new(string name, uvm_component parent);
  17. super.new(name, parent);
  18. w_done = 1;
  19. r_done = 1;
  20. endfunction //new()
  21. // Function: build_phase
  22. extern function void build_phase(uvm_phase phase);
  23. // Function: run_phase
  24. extern task run_phase(uvm_phase phase);
  25. endclass //axi_s_driver extends uvm_driver
  26. function void axi_s_driver::build_phase(uvm_phase phase);
  27. s_wtrans = new("s_wtrans");
  28. s_rtrans = new("s_rtrans");
  29. endfunction: build_phase
  30. task axi_s_driver::run_phase(uvm_phase phase);
  31. vif.s_drv_cb.AWREADY <= 1;
  32. vif.s_drv_cb.ARREADY <= 1;
  33. vif.s_drv_cb.WREADY <= 1;
  34. // vif.s_drv_cb.BVALID <= 1;
  35. // vif.s_drv_cb.RLAST <= 1;
  36. vif.s_drv_cb.RVALID <= 1;
  37. vif.s_drv_cb.RDATA <= 'b0;
  38. forever begin
  39. @(vif.s_drv_cb);
  40. drive();
  41. end
  42. endtask: run_phase
  43. task axi_s_driver::drive();
  44. if(!vif.rstn) begin
  45. vif.s_drv_cb.RVALID <= 0;
  46. vif.s_drv_cb.BVALID <= 0;
  47. return;
  48. end
  49. // fork
  50. if(vif.s_drv_cb.WRITE)
  51. begin
  52. begin
  53. // `uvm_info("DEBUG_S", $sformatf("w_addr(), w_done = %0d", w_done), UVM_HIGH)
  54. //if(!s_wtrans.id[8])
  55. begin
  56. if(w_done) begin
  57. w_done = 0;
  58. read_write_address();
  59. #5
  60. read_write_data();
  61. w_done = 1;
  62. end
  63. end
  64. end
  65. end
  66. else if(!vif.s_drv_cb.WRITE)
  67. begin
  68. begin
  69. // `uvm_info("DEBUG_S", $sformatf("r_addr(), r_done = %0d", r_done), UVM_HIGH)
  70. // if(s_rtrans.id[8])
  71. begin
  72. if(r_done)
  73. begin
  74. r_done = 0;
  75. $display("t is %t,enter read//////////",$time);
  76. #10
  77. read_read_address();
  78. #20
  79. send_read_data();
  80. r_done = 1;
  81. $display("t is %t,exit read//////////",$time);
  82. end
  83. end
  84. end
  85. end
  86. // join_none
  87. endtask: drive
  88. task axi_s_driver::read_write_address();
  89. `uvm_info("DEBUG_S", "Inside read_write_address", UVM_LOW)
  90. wait(vif.s_drv_cb.AWVALID);
  91. s_wtrans.id = vif.s_drv_cb.AWID;
  92. s_wtrans.addr = vif.s_drv_cb.AWADDR;
  93. s_wtrans.b_size = vif.s_drv_cb.AWSIZE;
  94. s_wtrans.b_type = B_TYPE'(vif.s_drv_cb.AWBURST);
  95. s_wtrans.b_len = vif.s_drv_cb.AWLEN;
  96. s_wtrans.print();
  97. endtask: read_write_address
  98. task axi_s_driver::read_write_data();
  99. int addr_1, addr_n, addr_align;
  100. int lower_byte_lane, upper_byte_lane, upper_wrap_boundary, lower_wrap_boundary;
  101. int no_bytes, total_bytes;
  102. bit isAligned;
  103. int c;
  104. bit err, align_err;
  105. `uvm_info("DEBUG_S", "Inside read_write_data", UVM_LOW)
  106. vif.s_drv_cb.BVALID <= 0;
  107. // Initial values and calculations
  108. addr_1 = s_wtrans.addr;
  109. no_bytes = 2**s_wtrans.b_size;
  110. total_bytes = no_bytes * (s_wtrans.b_len+1);
  111. addr_align = int'(addr_1/no_bytes)*no_bytes;
  112. `uvm_info("DEBUG_S", $sformatf("Calculated aligned addr %0d,addr_1 %0d", addr_align,addr_1), UVM_LOW)
  113. isAligned = addr_1 == addr_align;
  114. // Calculate boundaries for WRAP Burst
  115. if(s_wtrans.b_type == WRAP) begin
  116. lower_wrap_boundary = int'(addr_1/total_bytes)*total_bytes;
  117. upper_wrap_boundary = lower_wrap_boundary + total_bytes;
  118. `uvm_info("DEBUG_S", $sformatf("Calculated Lower Wrap Boundary: %0d", lower_wrap_boundary), UVM_HIGH)
  119. `uvm_info("DEBUG_S", $sformatf("Calculated Upper Wrap Boundary: %0d", upper_wrap_boundary), UVM_HIGH)
  120. end
  121. // check whether the wrap burst is alligned or not
  122. if(s_wtrans.b_type == WRAP && !isAligned)
  123. align_err = 1;
  124. // Store data
  125. err = 0;
  126. for (int i=0; i<s_wtrans.b_len+1; i++) begin
  127. `uvm_info("DEBUG_S", "Inside read_data_loop", UVM_LOW)
  128. // addr_n = addr_align + i*no_bytes;
  129. // Lane selection for the first transfer. In case of unaligned transfer the bytes b/w the
  130. // start address and aligned address is not transferred. Thus for an unaligned burst, the
  131. // first transfer has less bytes and the actual burst size;
  132. // 'c' is a variable which stores which byte lane to select. In AXI, valid byte lane is used and
  133. // selected dynamically using lower_byte_lane and upper_byte_lane, but we for simplicity, we are
  134. // sending the data starting from WDATA[0:8*2**b_size], thus c converts the lower_byte_lane to
  135. // such that it always select the data lines within the valid byte lanes, i.e. [0:8*2**b_size]
  136. // This can be changed in future to match with proper AXI protocol
  137. if(i==0 || s_wtrans.b_type == FIXED) begin
  138. lower_byte_lane = addr_1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
  139. upper_byte_lane = addr_align+no_bytes-1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
  140. addr_n = addr_1;
  141. $display("entering");
  142. c = isAligned ? 0 : lower_byte_lane;
  143. while (c>=no_bytes) begin
  144. c -= no_bytes;
  145. end
  146. end
  147. // For 2nd and all other transfers the address is always alligned and thus can read the entire
  148. // valid byte lane, i.e, [0:8*2**b_size]; and thus c always start with 0
  149. else begin
  150. lower_byte_lane = addr_n-int'(addr_n/(D_WIDTH/8))*(D_WIDTH/8);
  151. upper_byte_lane = lower_byte_lane + no_bytes-1;
  152. c = 0;
  153. end
  154. `uvm_info("DEBUG_S", $sformatf("lower_byte_lane is %0d", lower_byte_lane), UVM_HIGH)
  155. `uvm_info("DEBUG_S", $sformatf("upper_byte_lane is %0d", upper_byte_lane), UVM_HIGH)
  156. `uvm_info("DEBUG_S", $sformatf("addr_n is %0d", addr_n), UVM_LOW)
  157. wait(vif.s_drv_cb.WVALID);
  158. `uvm_info("DEBUG_S", $sformatf("WVALID is %0d", vif.s_drv_cb.WVALID), UVM_LOW)
  159. // Follows little endian
  160. err = 0;
  161. for (int j=lower_byte_lane; j<=upper_byte_lane; j++) begin
  162. if(addr_n+j-lower_byte_lane >= 2**A_WIDTH)
  163. err = 1;
  164. if(err || align_err)
  165. continue;
  166. mem[addr_n+j-lower_byte_lane] = vif.s_drv_cb.WDATA[8*c+:8];
  167. `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)
  168. c++;
  169. c = c>=no_bytes ? 0:c;
  170. end
  171. // Update address
  172. if(s_wtrans.b_type != FIXED) begin
  173. if(isAligned) begin
  174. addr_n = addr_n+no_bytes;
  175. if(s_wtrans.b_type == WRAP) begin
  176. `uvm_info("DEBUG_S", $sformatf("Updated addrn before boundary check: %0d", addr_n), UVM_HIGH)
  177. addr_n = addr_n>=upper_wrap_boundary ? lower_wrap_boundary : addr_n;
  178. `uvm_info("DEBUG_S", $sformatf("Updated addrn after boundary check: %0d", addr_n), UVM_HIGH)
  179. end
  180. end
  181. else begin
  182. addr_n = addr_align + no_bytes;
  183. isAligned = 1;
  184. end
  185. end
  186. @(vif.s_drv_cb);
  187. end
  188. vif.s_drv_cb.BID <= s_wtrans.id;
  189. if(err || align_err)
  190. vif.s_drv_cb.BRESP <= 2'b01;
  191. else
  192. vif.s_drv_cb.BRESP <= 2'b00;
  193. @(vif.s_drv_cb);
  194. vif.s_drv_cb.BVALID <= 1;
  195. @(vif.s_drv_cb);
  196. wait(vif.s_drv_cb.BREADY)
  197. vif.s_drv_cb.BVALID <= 0;
  198. endtask: read_write_data
  199. task axi_s_driver::read_read_address();
  200. `uvm_info("DEBUG_S", "Inside read_write_address", UVM_LOW)
  201. // `uvm_info("DEBUG_S",$sformatf("ARVALID IS %b",vif.s_drv_cb.ARVALID) , UVM_LOW)
  202. wait(vif.s_drv_cb.ARVALID);
  203. // `uvm_info("DEBUG_S", $sformatf("ARVALID IS %b",vif.s_drv_cb.ARVALID), UVM_LOW)
  204. s_rtrans.id = vif.s_drv_cb.ARID;
  205. s_rtrans.addr = vif.s_drv_cb.ARADDR;
  206. s_rtrans.b_size = vif.s_drv_cb.ARSIZE;
  207. s_rtrans.b_type = B_TYPE'(vif.s_drv_cb.ARBURST);
  208. s_rtrans.b_len = vif.s_drv_cb.ARLEN;
  209. s_rtrans.print();
  210. endtask: read_read_address
  211. task axi_s_driver::send_read_data();
  212. int addr_1, addr_n, addr_align;
  213. int lower_byte_lane, upper_byte_lane, upper_wrap_boundary, lower_wrap_boundary;
  214. int no_bytes, total_bytes;
  215. bit isAligned;
  216. int c;
  217. bit err;
  218. `uvm_info("DEBUG_S", "Inside send_read_data", UVM_LOW)
  219. addr_1 = s_rtrans.addr;
  220. no_bytes = 2**s_rtrans.b_size;
  221. total_bytes = no_bytes * (s_rtrans.b_len+1);
  222. // Calculate align address
  223. addr_align = int'(addr_1/no_bytes)*no_bytes;
  224. `uvm_info("DEBUG_S", $sformatf("Calculated aligned addr %0d", addr_align), UVM_HIGH)
  225. isAligned = addr_1 == addr_align;
  226. // If WRAP Burst then calculate the wrap boundary
  227. if(s_rtrans.b_type == WRAP) begin
  228. lower_wrap_boundary = int'(addr_1/total_bytes)*total_bytes;
  229. upper_wrap_boundary = lower_wrap_boundary + total_bytes;
  230. `uvm_info("DEBUG_S", $sformatf("Calculated Lower Wrap Boundary: %0d", lower_wrap_boundary), UVM_HIGH)
  231. `uvm_info("DEBUG_S", $sformatf("Calculated Upper Wrap Boundary: %0d", upper_wrap_boundary), UVM_HIGH)
  232. end
  233. // Initial signals
  234. vif.s_drv_cb.RLAST <= 0;
  235. vif.s_drv_cb.RVALID <=0;
  236. vif.s_drv_cb.RID <= s_rtrans.id;
  237. // Store data
  238. for (int i=0; i<s_rtrans.b_len+1; i++) begin
  239. // `uvm_info("DEBUG_S", "Inside send_data_loop", UVM_LOW)
  240. // addr_n = addr_align + i*no_bytes;
  241. // Lane selection for the first transfer. In case of unaligned transfer the bytes b/w the
  242. // start address and aligned address is not transferred. Thus for an unaligned burst, the
  243. // first transfer has less bytes and the actual burst size;
  244. // 'c' is a variable which stores which byte lane to select. In AXI, valid byte lane is used and
  245. // selected dynamically using lower_byte_lane and upper_byte_lane, but we for simplicity, we are
  246. // sending the data starting from WDATA[0:8*2**b_size], thus c converts the lower_byte_lane to
  247. // such that it always select the data lines within the valid byte lanes, i.e. [0:8*2**b_size]
  248. // This can be changed in future to match with proper AXI protocol
  249. if(i==0 || s_rtrans.b_type == FIXED) begin
  250. lower_byte_lane = addr_1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
  251. upper_byte_lane = addr_align+no_bytes-1-int'(addr_1/(D_WIDTH/8))*(D_WIDTH/8);
  252. addr_n = addr_1;
  253. c = isAligned ? 0 : lower_byte_lane;
  254. while (c>=no_bytes) begin
  255. c -= no_bytes;
  256. end
  257. end
  258. // For 2nd and all other transfers the address is always alligned and thus can read the entire
  259. // valid byte lane, i.e, [0:8*2**b_size]; and thus c always start with 0
  260. else begin
  261. lower_byte_lane = addr_n-int'(addr_n/(D_WIDTH/8))*(D_WIDTH/8);
  262. upper_byte_lane = lower_byte_lane + no_bytes-1;
  263. c = 0;
  264. end
  265. // @(vif.s_drv_cb);
  266. `uvm_info("DEBUG_S", $sformatf("lower_byte_lane is %0d", lower_byte_lane), UVM_HIGH)
  267. `uvm_info("DEBUG_S", $sformatf("upper_byte_lane is %0d", upper_byte_lane), UVM_HIGH)
  268. `uvm_info("DEBUG_S", $sformatf("addr_n is %0d", addr_n), UVM_HIGH)
  269. // Follows little endian
  270. err = 0;
  271. for (int j=lower_byte_lane; j<=upper_byte_lane; j++) begin
  272. if(!mem.exists(addr_n+j-lower_byte_lane)) begin
  273. err = 1;
  274. vif.s_drv_cb.RDATA[8*c+:8] <= 'b0;
  275. `uvm_info("DEBUG_S", $sformatf("c is %0d, addr is %0d, No data in location", c, addr_n+j-lower_byte_lane), UVM_HIGH)
  276. end
  277. else begin
  278. vif.s_drv_cb.RDATA[8*c+:8] <= mem[addr_n+j-lower_byte_lane];
  279. `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)
  280. end
  281. c++;
  282. c = c>=no_bytes ? 0:c;
  283. end
  284. if(i == s_rtrans.b_len) begin
  285. vif.s_drv_cb.RLAST <= 1;
  286. end
  287. if(err)
  288. vif.s_drv_cb.RRESP <= 2'b01;
  289. else
  290. vif.s_drv_cb.RRESP <= 2'b00;
  291. @(vif.s_drv_cb);
  292. vif.s_drv_cb.RVALID <= 1;
  293. // Update address
  294. if(s_rtrans.b_type != FIXED) begin
  295. if(isAligned) begin
  296. addr_n = addr_n+no_bytes;
  297. if(s_rtrans.b_type == WRAP) begin
  298. `uvm_info("DEBUG_S", $sformatf("Updated addrn before boundary check: %0d", addr_n), UVM_HIGH)
  299. addr_n = addr_n>=upper_wrap_boundary ? lower_wrap_boundary : addr_n;
  300. `uvm_info("DEBUG_S", $sformatf("Updated addrn after boundary check: %0d", addr_n), UVM_HIGH)
  301. end
  302. end
  303. else begin
  304. addr_n = addr_align + no_bytes;
  305. isAligned = 1;
  306. end
  307. end
  308. @(vif.s_drv_cb);
  309. wait(vif.s_drv_cb.RREADY);
  310. vif.s_drv_cb.RVALID <= 0;
  311. end
  312. endtask: send_read_data