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_completer #( 13 parameter int unsigned OutputLatency = 0, 14 int CosimToRenodeIndex = 0 15) ( 16 ref renode_runtime runtime, 17 renode_apb3_if bus 18); 19 20 typedef logic [bus.AddressWidth-1:0] address_t; 21 typedef logic [bus.DataWidth-1:0] data_t; 22 23 // Renaming the bus is a style preference 24 wire clk; 25 assign clk = bus.pclk; 26 logic rst_n; 27 assign bus.presetn = rst_n; 28 29 address_t paddr; 30 logic pselx; 31 logic penable; 32 logic pwrite; 33 data_t pwdata; 34 logic pready; 35 data_t prdata; 36 logic pslverr; 37 38 assign paddr = bus.paddr; 39 assign pselx = bus.pselx; 40 assign penable = bus.penable; 41 assign pwrite = bus.pwrite; 42 assign pwdata = bus.pwdata; 43 44 assign bus.pready = pready; 45 assign bus.prdata = prdata; 46 assign bus.pslverr = pslverr; 47 48 // Connection initiated reset 49 always @(runtime.peripherals[CosimToRenodeIndex].reset_assert_request) begin 50 rst_n = 0; 51 // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. 52 repeat (2) @(posedge clk); 53 runtime.peripherals[CosimToRenodeIndex].reset_assert_respond(); 54 end 55 56 always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin 57 rst_n = 1; 58 // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. 59 repeat (2) @(posedge clk); 60 runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond(); 61 end 62 63 renode_pkg::valid_bits_e valid_bits; 64 assign valid_bits = renode_pkg::valid_bits_e'((1 << bus.DataWidth) - 1); 65 66 // 67 // APB3 Completer 68 // 69 70 bit is_error; 71 renode_pkg::data_t prdata_int; 72 73 // Internal state 74 typedef enum { 75 STATE_IDLE, 76 STATE_ACCESS 77 } state_t; 78 state_t peripheral_state; 79 state_t peripheral_state_next; 80 81 // Next state logic 82 always_comb begin : proc_fsm_next_state 83 case (peripheral_state) 84 STATE_IDLE: begin 85 if (pselx && !penable) begin 86 peripheral_state_next = STATE_ACCESS; 87 end 88 end 89 STATE_ACCESS: begin 90 peripheral_state_next = STATE_IDLE; 91 end 92 default: begin 93 peripheral_state_next = STATE_IDLE; 94 end 95 endcase 96 end 97 98 // FSM logic 99 always_ff @(posedge clk or negedge rst_n) begin : proc_fsm 100 if (rst_n == 1'b0) begin 101 peripheral_state <= STATE_IDLE; 102 end else begin 103 peripheral_state <= peripheral_state_next; 104 105 // Write Enable logic: write data to memory in Renode 106 if (pselx && penable && pwrite) begin 107 // Workaround::Bug::Verilator::Task call inside of always block requires using fork...join 108 fork 109 begin 110 runtime.peripherals[CosimToRenodeIndex].write(renode_pkg::address_t'(paddr), valid_bits, renode_pkg::data_t'(pwdata), 111 is_error); 112 if (is_error) begin 113 runtime.connection.log(LogWarning, "Renode connection write transfer was unable to complete"); 114 end 115 end 116 join 117 end 118 119 // Read Enable logic: read data from memory in Renode 120 if (pselx && !penable && !pwrite) begin 121 // Workaround::Bug::Verilator::Task call inside of always block requires using fork...join 122 fork 123 begin 124 // The runtime.peripherals[CosimToRenodeIndex].read call may cause elapse of a simulation time. 125 runtime.peripherals[CosimToRenodeIndex].read(renode_pkg::address_t'(paddr), valid_bits, prdata_int, is_error); 126 if (is_error) begin 127 runtime.connection.log(LogWarning, "Renode connection read transfer was unable to complete"); 128 end 129 end 130 join 131 end else begin 132 prdata_int <= '0; 133 end 134 end 135 end 136 137 // 138 // Generate artificial delay to the {PRDATA,PREADY} signals 139 // Useful to validate wait states, by default is turned off. 140 // 141 genvar i; 142 generate 143 if (OutputLatency == 0) begin : gen_latency_0 144 assign prdata = data_t'(prdata_int); 145 assign pready = (peripheral_state == STATE_ACCESS); 146 end else begin : gen_latency_gt_0 147 data_t prdata_reg[OutputLatency]; 148 data_t pready_reg[OutputLatency]; 149 for (i = 0; i < OutputLatency; i++) begin : gen_output_registers 150 if (i == 0) begin : gen_i_eq_0 151 always_ff @(posedge clk or negedge rst_n) begin : proc_first_reg 152 prdata_reg[i] <= prdata_int; 153 pready_reg[i] <= (peripheral_state == STATE_ACCESS); 154 end 155 end else begin: gen_i_neq_0 156 always_ff @(posedge clk or negedge rst_n) begin : proc_latency_ith 157 prdata_reg[i] <= prdata_reg[i-1]; 158 pready_reg[i] <= pready_reg[i-1]; 159 end 160 end 161 end 162 assign prdata = prdata_reg[OutputLatency-1]; 163 assign pready = pready_reg[OutputLatency-1]; 164 end 165 endgenerate 166 167endmodule 168 169