1// 2// Copyright (c) 2010-2024 Antmicro 3// 4// This file is licensed under the MIT License. 5// Full license text is available in 'licenses/MIT.txt'. 6// 7 8`timescale 1ns / 1ps 9 10import renode_pkg::renode_runtime, renode_pkg::LogWarning; 11 12module renode_axi_manager #(int RenodeToCosimIndex = 0) ( 13 ref renode_runtime runtime, 14 renode_axi_if bus 15); 16 import renode_axi_pkg::*; 17 18 typedef logic [bus.AddressWidth-1:0] address_t; 19 typedef logic [bus.DataWidth-1:0] data_t; 20 typedef logic [bus.StrobeWidth-1:0] strobe_t; 21 typedef logic [bus.TransactionIdWidth-1:0] transaction_id_t; 22 23 wire clk = bus.aclk; 24 25 always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin 26 bus.arvalid = 0; 27 bus.awvalid = 0; 28 bus.wvalid = 0; 29 bus.areset_n = 0; 30 // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. 31 repeat (2) @(posedge clk); 32 runtime.controllers[RenodeToCosimIndex].reset_assert_respond(); 33 end 34 35 always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin 36 bus.areset_n = 1; 37 // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. 38 repeat (2) @(posedge clk); 39 runtime.controllers[RenodeToCosimIndex].reset_deassert_respond(); 40 end 41 42 always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) read_transaction(); 43 always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) write_transaction(); 44 45 task static read_transaction(); 46 bit is_error; 47 address_t address; 48 renode_pkg::valid_bits_e valid_bits; 49 burst_size_t burst_size; 50 data_t data; 51 52 address = address_t'(runtime.controllers[RenodeToCosimIndex].read_transaction_address); 53 valid_bits = runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits; 54 55 if(!is_access_valid(address, valid_bits)) begin 56 runtime.controllers[RenodeToCosimIndex].read_respond(0, 1); 57 end else begin 58 burst_size = bus.valid_bits_to_burst_size(valid_bits); 59 60 read(0, address, burst_size, data, is_error); 61 62 data = data >> ((address % bus.StrobeWidth) * 8); 63 runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(data) & valid_bits, is_error); 64 end 65 endtask 66 67 task static write_transaction(); 68 bit is_error; 69 address_t address; 70 renode_pkg::valid_bits_e valid_bits; 71 burst_size_t burst_size; 72 data_t data; 73 strobe_t strobe; 74 75 address = address_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_address); 76 valid_bits = runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits; 77 78 if(!is_access_valid(address, valid_bits)) begin 79 runtime.controllers[RenodeToCosimIndex].write_respond(1); 80 end else begin 81 burst_size = bus.valid_bits_to_burst_size(valid_bits); 82 data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data & valid_bits); 83 strobe = bus.burst_size_to_strobe(burst_size) << (address % bus.StrobeWidth); 84 data = data << ((address % bus.StrobeWidth) * 8); 85 86 write(0, address, burst_size, strobe, data, is_error); 87 88 runtime.controllers[RenodeToCosimIndex].write_respond(is_error); 89 end 90 endtask 91 92 function static is_access_valid(address_t address, renode_pkg::valid_bits_e valid_bits); 93 if(!renode_pkg::is_access_aligned(renode_pkg::address_t'(address), valid_bits)) begin 94 runtime.connection.log(LogWarning, $sformatf("Unaligned access to 0x%08X is unsupported by AXI Manager. Operation will have no effect.", address)); 95 return 0; 96 end 97 if(!bus.are_valid_bits_supported(valid_bits)) begin 98 runtime.connection.log(LogWarning, $sformatf("This instance of the AXI Manager doesn't support access using the 'b%b mask.", valid_bits)); 99 return 0; 100 end 101 return 1; 102 endfunction 103 104 task static read(transaction_id_t id, address_t address, burst_size_t burst_size, output data_t data, output bit is_error); 105 transaction_id_t response_id; 106 response_e response; 107 fork 108 set_read_address(id, address, burst_size); 109 get_read_response(data, response_id, response); 110 join 111 is_error = check_response(id, response_id, response); 112 endtask 113 114 task static write(transaction_id_t id, address_t address, burst_size_t burst_size, strobe_t strobe, data_t data, output bit is_error); 115 transaction_id_t response_id; 116 response_e response; 117 fork 118 set_write_address(id, address, burst_size); 119 set_write_data(data, strobe); 120 get_write_response(response_id, response); 121 join 122 is_error = check_response(id, response_id, response); 123 endtask 124 125 task static set_read_address(transaction_id_t transaction_id, address_t address, burst_size_t burst_size); 126 bus.arid = transaction_id; 127 bus.araddr = address; 128 bus.arsize = burst_size; 129 130 // Configure transaction with only one burst. 131 bus.arlen = 0; 132 bus.arburst = 0; 133 bus.arlock = 0; 134 bus.arprot = 0; 135 136 @(posedge clk); 137 bus.arvalid <= 1; 138 139 do @(posedge clk); while (!bus.arready); 140 bus.arvalid <= 0; 141 endtask 142 143 task static get_read_response(output data_t data, output transaction_id_t transaction_id, output response_e response); 144 @(posedge clk); 145 bus.rready <= 1; 146 147 do @(posedge clk); while (!bus.rvalid); 148 data = bus.rdata; 149 transaction_id = bus.bid; 150 response = response_e'(bus.bresp); 151 bus.rready <= 0; 152 endtask 153 154 task static set_write_address(transaction_id_t id, address_t address, burst_size_t burst_size); 155 bus.awid = id; 156 bus.awaddr = address; 157 bus.awsize = burst_size; 158 159 // Configure transaction with only one burst. 160 bus.awlen = 0; 161 bus.awburst = 0; 162 bus.awlock = 0; 163 bus.awprot = 0; 164 165 @(posedge clk); 166 bus.awvalid <= 1; 167 168 do @(posedge clk); while (!bus.awready); 169 bus.awvalid <= 0; 170 endtask 171 172 task static set_write_data(data_t data, strobe_t strobe); 173 bus.wdata = data; 174 bus.wstrb = strobe; 175 bus.wlast = 1; 176 177 @(posedge clk); 178 bus.wvalid <= 1; 179 180 do @(posedge clk); while (!bus.wready); 181 bus.wvalid <= 0; 182 endtask 183 184 task static get_write_response(output transaction_id_t transaction_id, output response_e response); 185 @(posedge clk); 186 bus.bready <= 1; 187 188 do @(posedge clk); while (!bus.bvalid); 189 transaction_id = bus.bid; 190 response = response_e'(bus.bresp); 191 bus.bready <= 0; 192 endtask 193 194 function automatic bit check_response(transaction_id_t request_id, transaction_id_t response_id, response_t response); 195 response_e response_enum = response_e'(response); 196 if (response_id != request_id) begin 197 runtime.connection.log(LogWarning, $sformatf("Unexpected transaction id in the response ('h%h), expected 'h%h", response_id, request_id)); 198 return 1; 199 end 200 if (response_enum != Okay && response_enum != ExclusiveAccessOkay) begin 201 runtime.connection.log(LogWarning, $sformatf("Response error 'h%h", response)); 202 return 1; 203 end 204 return 0; 205 endfunction 206endmodule 207 208