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_subordinate #(int CosimToRenodeIndex = 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.peripherals[CosimToRenodeIndex].reset_assert_request) begin 26 bus.rvalid = 0; 27 bus.bvalid = 0; 28 bus.areset_n = 0; 29 // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. 30 repeat (2) @(posedge clk); 31 runtime.peripherals[CosimToRenodeIndex].reset_assert_respond(); 32 end 33 34 always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin 35 bus.areset_n = 1; 36 // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. 37 repeat (2) @(posedge clk); 38 runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond(); 39 end 40 41 always @(clk) read_transaction(); 42 always @(clk) write_transaction(); 43 44 task static read_transaction(); 45 transaction_id_t transaction_id; 46 address_t address; 47 renode_pkg::data_t data; 48 bit is_error; 49 burst_size_t burst_size; 50 burst_length_t burst_length; 51 burst_type_e burst_type; 52 address_t address_last; 53 renode_pkg::valid_bits_e valid_bits; 54 address_t transfer_bytes; 55 56 get_read_address(transaction_id, address, burst_size, burst_length, burst_type); 57 valid_bits = bus.burst_size_to_valid_bits(burst_size); 58 transfer_bytes = 2**burst_size; 59 address_last = address + transfer_bytes * burst_length; 60 for (; address <= address_last; address += transfer_bytes) begin 61 if(!is_access_valid(address, valid_bits, burst_type)) begin 62 set_read_response(transaction_id, 0, SlaveError, address == address_last); 63 end 64 else begin 65 // The conection.read call may cause simulation time to move forward 66 runtime.peripherals[CosimToRenodeIndex].read(renode_pkg::address_t'(address), valid_bits, data, is_error); 67 if (is_error) begin 68 runtime.connection.log(LogWarning, $sformatf("Unable to read data from Renode at address 'h%h, responding with 0.", address)); 69 data = 0; 70 end 71 data = data & valid_bits; 72 set_read_response(transaction_id, data_t'(data) << ((address % transfer_bytes) * 8), is_error ? SlaveError : Okay, address == address_last); 73 end 74 end 75 endtask 76 77 task static write_transaction(); 78 transaction_id_t transaction_id; 79 address_t address; 80 data_t data; 81 bit is_error; 82 bit last_transfer; 83 burst_size_t burst_size; 84 burst_length_t burst_length; 85 burst_type_e burst_type; 86 address_t address_last; 87 renode_pkg::valid_bits_e valid_bits; 88 address_t transfer_bytes; 89 90 get_write_address(transaction_id, address, burst_size, burst_length, burst_type); 91 valid_bits = bus.burst_size_to_valid_bits(burst_size); 92 if(!is_access_valid(address, valid_bits, burst_type)) begin 93 do @(posedge clk); while (!bus.wvalid); 94 bus.wready <= 1; 95 @(posedge clk); 96 bus.wready <= 0; 97 set_write_response(transaction_id, SlaveError); 98 end 99 else begin 100 transfer_bytes = 2**burst_size; 101 address_last = address + transfer_bytes * burst_length; 102 103 104 for (; address <= address_last; address += transfer_bytes) begin 105 do @(posedge clk); while (!bus.wvalid); 106 bus.wready <= 1; 107 data = bus.wdata >> ((address % transfer_bytes) * 8); 108 109 @(posedge clk); 110 bus.wready <= 0; 111 112 if (bus.wlast != (address == address_last)) runtime.connection.log(LogWarning, "Unexpected state of the wlast signal."); 113 // The conection.write call may cause simulation time to move forward 114 runtime.peripherals[CosimToRenodeIndex].write(renode_pkg::address_t'(address), valid_bits, renode_pkg::data_t'(data) & valid_bits, is_error); 115 if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to write data to Renode at address 'h%h", address)); 116 end 117 118 set_write_response(transaction_id, Okay); 119 end 120 endtask 121 122 function static is_access_valid(address_t address, renode_pkg::valid_bits_e valid_bits, burst_type_e burst_type); 123 if(!renode_pkg::is_access_aligned(renode_pkg::address_t'(address), valid_bits)) begin 124 runtime.connection.log(LogWarning, $sformatf("Unaligned access to 0x%08X unsupported by AXI Subordinate. This will result in bus error response.", address)); 125 return 0; 126 end 127 if(burst_type != Incrementing) begin 128 runtime.connection.fatal_error($sformatf("Unsupported burst type 'b%b", burst_type)); 129 return 0; 130 end 131 return 1; 132 endfunction 133 134 task static get_read_address(output transaction_id_t transaction_id, output address_t address, 135 output burst_size_t burst_size, output burst_length_t burst_length, output burst_type_e burst_type); 136 @(posedge clk); 137 bus.arready <= 1; 138 139 do @(posedge clk); while (!bus.arvalid); 140 transaction_id = bus.arid; 141 address = bus.araddr; 142 burst_size = bus.arsize; 143 burst_length = bus.arlen; 144 burst_type = burst_type_e'(bus.arburst); 145 bus.arready <= 0; 146 endtask 147 148 task static get_write_address(output transaction_id_t transaction_id, output address_t address, 149 output burst_size_t burst_size, output burst_length_t burst_length, output burst_type_e burst_type); 150 @(posedge clk); 151 bus.awready <= 1; 152 153 do @(posedge clk); while (!bus.awvalid); 154 transaction_id = bus.awid; 155 address = bus.awaddr; 156 burst_size = bus.awsize; 157 burst_length = bus.awlen; 158 burst_type = burst_type_e'(bus.awburst); 159 bus.awready <= 0; 160 endtask 161 162 task static set_read_response(transaction_id_t transaction_id, data_t data, response_e response, bit last); 163 @(posedge clk); 164 bus.rid <= transaction_id; 165 bus.rdata <= data; 166 bus.rresp <= response; 167 bus.rlast <= last; 168 bus.rvalid <= 1; 169 170 // It's required to assert the valid and ready signals only for one clock cycle. 171 do @(posedge clk); while (!bus.rready); 172 bus.rlast <= 0; 173 bus.rvalid <= 0; 174 endtask 175 176 task static set_write_response(transaction_id_t id, response_e response); 177 bus.bid = id; 178 bus.bresp = response; 179 180 @(posedge clk); 181 bus.bvalid <= 1; 182 183 do @(posedge clk); while (!bus.bready); 184 bus.bvalid <= 0; 185 endtask 186endmodule 187 188