1//
2// Copyright (c) 2023 Renesas Electronics Corporation
3// Copyright (c) 2010-2024 Antmicro
4//
5// This file is licensed under the MIT License.
6// Full license text is available in 'LICENSE'.
7//
8
9`timescale 1ns / 1ps
10
11import renode_pkg::renode_runtime, renode_pkg::bus_connection, renode_pkg::LogWarning;
12
13module renode_ahb_manager #(int RenodeToCosimIndex = 0) (
14    ref renode_runtime runtime,
15    renode_ahb_if bus
16);
17  import renode_ahb_pkg::*;
18
19  typedef logic [bus.AddressWidth-1:0] address_t;
20  typedef logic [bus.DataWidth-1:0] data_t;
21  wire clk = bus.hclk;
22
23  always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin
24    bus.hresetn = 0;
25    bus.haddr   = '0;
26    bus.htrans  = Idle;
27    repeat (2) @(posedge clk);
28    runtime.controllers[RenodeToCosimIndex].reset_assert_respond();
29  end
30
31  always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin
32    bus.hresetn = 1;
33    repeat (2) @(posedge clk);
34    runtime.controllers[RenodeToCosimIndex].reset_deassert_respond();
35  end
36
37  always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) read_transaction();
38  always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) write_transaction();
39
40  task static write_transaction();
41    renode_pkg::valid_bits_e valid_bits;
42    data_t data;
43    bit is_invalid;
44
45    valid_bits = runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits;
46    data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data & valid_bits);
47    configure_transfer(runtime.controllers[RenodeToCosimIndex].write_transaction_address, valid_bits, Write, is_invalid);
48    if (is_invalid) begin
49        runtime.controllers[RenodeToCosimIndex].write_respond(is_invalid);
50        return;
51    end
52
53    bus.hwstrb = bus.transfer_size_to_strobe(bus.valid_bits_to_transfer_size(valid_bits));
54    bus.hwdata = data;
55    bus.htrans <= Idle;
56
57    do @(posedge clk); while (!bus.hready);
58    runtime.controllers[RenodeToCosimIndex].write_respond(is_response_error(bus.hresp));
59  endtask
60
61  task static read_transaction();
62    renode_pkg::valid_bits_e valid_bits;
63    data_t data;
64    bit is_invalid;
65    bit is_error;
66
67    valid_bits = runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits;
68    configure_transfer(runtime.controllers[RenodeToCosimIndex].read_transaction_address, valid_bits, Read, is_invalid);
69    if (is_invalid) begin
70        runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(0), is_invalid);
71        return;
72    end
73
74    bus.htrans <= Idle;
75
76    do @(posedge clk); while (!bus.hready);
77    data = bus.hrdata;
78    is_error = is_response_error(bus.hresp);
79    runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(data) & valid_bits, is_error);
80  endtask
81
82  task static configure_transfer(renode_pkg::address_t address, renode_pkg::valid_bits_e valid_bits, transfer_direction_e direction, output logic is_invalid);
83    is_invalid = 0;
84    if (!bus.are_valid_bits_supported(valid_bits)) begin
85      is_invalid = 1;
86      runtime.connection.log(LogWarning, $sformatf("Unsupported transaction width of %d for AHB bus with width %d. No transaction will be performed.", renode_pkg::valid_bits_to_transaction_width(valid_bits), bus.DataWidth));
87      return;
88    end
89    bus.hwrite = direction;
90    bus.hsize  = bus.valid_bits_to_transfer_size(valid_bits);
91    bus.hburst = Single;
92    bus.haddr  = address_t'(address);
93    bus.htrans <= NonSequential;
94    do @(posedge clk); while (!bus.hready);
95  endtask
96
97  function static bit is_response_error(response_t response);
98    if (response == Okay) begin
99      return 0;
100    end
101    runtime.connection.log(LogWarning, $sformatf("Error response from a Subordinate: 'h%h", response));
102    return 1;
103  endfunction
104endmodule
105