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_apb3_requester #(int RenodeToCosimIndex = 0) ( 13 ref renode_runtime runtime, 14 renode_apb3_if bus 15); 16 typedef logic [bus.AddressWidth-1:0] address_t; 17 typedef logic [bus.DataWidth-1:0] data_t; 18 19 // Renaming the bus is a style preference 20 wire clk; 21 assign clk = bus.pclk; 22 23 logic rst_n; 24 assign bus.presetn = rst_n; 25 26 address_t paddr; 27 logic pselx; 28 logic penable; 29 logic pwrite; 30 data_t pwdata; 31 logic pready; 32 data_t prdata; 33 logic pslverr; 34 35 assign bus.paddr = paddr; 36 assign bus.pselx = pselx; 37 assign bus.penable = penable; 38 assign bus.pwrite = pwrite; 39 assign bus.pwdata = pwdata; 40 41 assign pready = bus.pready; 42 assign prdata = bus.prdata; 43 assign pslverr = bus.pslverr; 44 45 int unsigned b2b_counter; 46 address_t write_address; 47 address_t read_address; 48 data_t write_data; 49 50 logic start_transaction; 51 logic write_mode; 52 53 // Only value of 1 is currently supported 54 localparam int unsigned Back2BackNum = 1; 55 56 57 always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin 58 write_address = '0; 59 read_address = '0; 60 write_data = '0; 61 start_transaction = '0; 62 write_mode = '0; 63 rst_n = 0; 64 // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. 65 repeat (2) @(posedge clk); 66 runtime.controllers[RenodeToCosimIndex].reset_assert_respond(); 67 end 68 69 always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin 70 rst_n = 1; 71 // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. 72 repeat (2) @(posedge clk); 73 runtime.controllers[RenodeToCosimIndex].reset_deassert_respond(); 74 end 75 76 // Internal state 77 typedef enum { 78 S_IDLE, 79 S_SETUP, 80 S_ACCESS 81 } state_t; 82 state_t state = S_IDLE; 83 84 // 85 // Waveform generation 86 // 87 88 always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) begin 89 integer transaction_width; 90 91 if(!renode_pkg::is_access_aligned(runtime.controllers[RenodeToCosimIndex].read_transaction_address, runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits)) begin 92 runtime.connection.log(LogWarning, "Unaligned access on APB bus results in unpredictable behavior"); 93 end 94 transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits); 95 if (bus.DataWidth > transaction_width) begin 96 runtime.connection.log(LogWarning, 97 $sformatf("Bus bus.bus.DataWidth is (%d) > transaction width (%d), MSB will be truncated.", bus.DataWidth, transaction_width)); 98 end else if (bus.DataWidth < transaction_width) begin 99 runtime.connection.log(LogWarning, 100 $sformatf("Bus bus.bus.DataWidth is (%d) < transaction width (%d), MSB will be zero-extended.", bus.DataWidth, transaction_width)); 101 end 102 103 read_address = address_t'(runtime.controllers[RenodeToCosimIndex].read_transaction_address); 104 write_mode = 1'b0; 105 start_transaction = 1'b1; 106 @(posedge clk) start_transaction <= 1'b0; 107 end 108 109 always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) begin 110 integer transaction_width; 111 112 if(!renode_pkg::is_access_aligned(runtime.controllers[RenodeToCosimIndex].write_transaction_address, runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits)) begin 113 runtime.connection.log(LogWarning, "Unaligned access on APB bus results in unpredictable behavior"); 114 end 115 transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits); 116 if (bus.DataWidth > transaction_width) begin 117 runtime.connection.log(LogWarning, 118 $sformatf("Bus bus.bus.DataWidth is (%d) > transaction width (%d), MSB will be truncated.", bus.DataWidth, transaction_width)); 119 end else if (bus.DataWidth < transaction_width) begin 120 runtime.connection.log(LogWarning, 121 $sformatf("Bus bus.bus.DataWidth is (%d) < transaction width (%d), MSB will be zero-extended.", bus.DataWidth, transaction_width)); 122 end 123 124 write_address = address_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_address); 125 write_data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data); 126 write_mode = 1'b1; 127 start_transaction = 1'b1; 128 @(posedge clk) start_transaction <= 1'b0; 129 end 130 131 state_t next_state; 132 always_comb begin : proc_next_state 133 case (state) 134 S_IDLE: begin 135 if (start_transaction) begin 136 next_state = S_SETUP; 137 end else begin 138 next_state = S_IDLE; 139 end 140 end 141 S_SETUP: begin 142 next_state = S_ACCESS; 143 end 144 S_ACCESS: begin 145 if (pready) begin 146 if (b2b_counter == 0) begin 147 next_state = S_IDLE; 148 end else begin 149 next_state = S_SETUP; 150 end 151 end else begin 152 next_state = S_ACCESS; 153 end 154 end 155 default: begin 156 next_state = S_IDLE; 157 end 158 endcase 159 end 160 161 always_ff @(posedge clk or negedge rst_n) begin 162 if (rst_n == '0) begin 163 state <= S_IDLE; 164 end else begin 165 state <= next_state; 166 167 case (state) 168 S_IDLE: begin 169 b2b_counter <= Back2BackNum; 170 end 171 S_SETUP: begin 172 b2b_counter <= b2b_counter - 1; 173 end 174 S_ACCESS: begin 175 if (pready) begin 176 if (write_mode) begin 177 runtime.controllers[RenodeToCosimIndex].write_respond(1'b0); // Notify Renode that write is done 178 end else begin 179 runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(prdata), 1'b0); 180 end 181 end 182 end 183 default: begin 184 b2b_counter <= Back2BackNum; 185 end 186 endcase 187 end 188 end 189 190 always_comb begin : proc_fsm_outputs 191 case (state) 192 S_IDLE: begin 193 paddr = '0; 194 pselx = '0; 195 penable = '0; 196 pwrite = '0; 197 pwdata = '0; 198 end 199 S_SETUP: begin 200 paddr = write_mode ? write_address : read_address; 201 pselx = 1'b1; 202 penable = 1'b0; 203 pwrite = write_mode; 204 pwdata = write_mode ? write_data : '0; 205 end 206 S_ACCESS: begin 207 paddr = write_mode ? write_address : read_address; 208 pselx = 1'b1; 209 penable = 1'b1; 210 pwrite = write_mode; 211 pwdata = write_mode ? write_data : '0; 212 end 213 default: begin 214 paddr = '0; 215 pselx = '0; 216 penable = '0; 217 pwrite = '0; 218 pwdata = '0; 219 end 220 endcase 221 end 222endmodule 223 224