blob: a572687c7dcd224b893f3acd0bfcd55ebd7874a4 [file]
//
// Copyright (c) 2023 Renesas Electronics Corporation
// Copyright (c) 2010-2024 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in 'LICENSE'.
//
`timescale 1ns / 1ps
import renode_pkg::renode_runtime, renode_pkg::LogWarning;
module renode_ahb_subordinate (
ref renode_runtime runtime,
renode_ahb_if bus
);
import renode_ahb_pkg::*;
typedef logic [bus.AddressWidth-1:0] address_t;
typedef logic [bus.DataWidth-1:0] data_t;
wire clk = bus.hclk;
always @(runtime.peripheral.reset_assert_request) begin
bus.hresetn = 0;
bus.hresp = Okay;
bus.hreadyout = 1;
repeat (2) @(posedge clk);
runtime.peripheral.reset_assert_respond();
end
always @(runtime.peripheral.reset_deassert_request) begin
bus.hresetn = 1;
repeat (2) @(posedge clk);
runtime.peripheral.reset_deassert_respond();
end
always @(posedge clk) transaction();
task static transaction();
renode_pkg::address_t address;
renode_pkg::valid_bits_e valid_bits;
renode_pkg::data_t data;
bit is_error;
bit is_invalid;
transfer_direction_e direction;
wait_for_transfer(address, valid_bits, direction, is_invalid);
// The runtime.peripheral.read call may consume an unknown number of clock cycles.
// To to make the logic simpler both read and write transactions contain at least one cycle with a deasserted ready.
// It also ensures that address and data phases don't overlap between transactions.
bus.hreadyout <= 0;
@(posedge clk);
if (!is_invalid) begin
if (direction == Read) begin
runtime.peripheral.read(address, valid_bits, data, is_error);
bus.hrdata = data_t'(data & valid_bits);
if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to read data from Renode at address 'h%h", address));
end else begin
runtime.peripheral.write(address, valid_bits, renode_pkg::data_t'(bus.hwdata) & valid_bits, is_error);
if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to write data to Renode at address 'h%h", address));
end
end
if (is_invalid || is_error) begin
bus.hresp = Error;
@(posedge clk); // An error response should last two cycles.
bus.hreadyout <= 1;
end
else begin
bus.hresp = Okay;
bus.hreadyout <= 1;
end
endtask
task static wait_for_transfer(output renode_pkg::address_t address, output renode_pkg::valid_bits_e valid_bits, output transfer_direction_e direction, output bit is_invalid);
is_invalid = 0;
bus.hreadyout <= 1;
while (!bus.hready || bus.htrans == Idle || bus.htrans == Busy) @(posedge clk);
address = bus.haddr;
valid_bits = bus.transfer_size_to_valid_bits(bus.hsize);
direction = transfer_direction_e'(bus.hwrite);
if (!bus.are_valid_bits_supported(valid_bits)) begin
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));
is_invalid = 1;
end
endtask
endmodule