blob: 595cb682d1ae96b711ec1c11222e43be97fb399a [file]
//
// Copyright (c) 2010-2024 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
`timescale 1ns / 1ps
import renode_pkg::renode_runtime, renode_pkg::LogWarning;
module renode_apb3_completer #(
parameter int unsigned OutputLatency = 0,
int CosimToRenodeIndex = 0
) (
ref renode_runtime runtime,
renode_apb3_if bus
);
typedef logic [bus.AddressWidth-1:0] address_t;
typedef logic [bus.DataWidth-1:0] data_t;
// Renaming the bus is a style preference
wire clk;
assign clk = bus.pclk;
logic rst_n;
assign bus.presetn = rst_n;
address_t paddr;
logic pselx;
logic penable;
logic pwrite;
data_t pwdata;
logic pready;
data_t prdata;
logic pslverr;
assign paddr = bus.paddr;
assign pselx = bus.pselx;
assign penable = bus.penable;
assign pwrite = bus.pwrite;
assign pwdata = bus.pwdata;
assign bus.pready = pready;
assign bus.prdata = prdata;
assign bus.pslverr = pslverr;
// Connection initiated reset
always @(runtime.peripherals[CosimToRenodeIndex].reset_assert_request) begin
rst_n = 0;
// The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment.
repeat (2) @(posedge clk);
runtime.peripherals[CosimToRenodeIndex].reset_assert_respond();
end
always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin
rst_n = 1;
// There is one more wait for the clock edges to be sure that all modules aren't in a reset state.
repeat (2) @(posedge clk);
runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond();
end
renode_pkg::valid_bits_e valid_bits;
assign valid_bits = renode_pkg::valid_bits_e'((1 << bus.DataWidth) - 1);
//
// APB3 Completer
//
bit is_error;
renode_pkg::data_t prdata_int;
// Internal state
typedef enum {
STATE_IDLE,
STATE_ACCESS
} state_t;
state_t peripheral_state;
state_t peripheral_state_next;
// Next state logic
always_comb begin : proc_fsm_next_state
case (peripheral_state)
STATE_IDLE: begin
if (pselx && !penable) begin
peripheral_state_next = STATE_ACCESS;
end
end
STATE_ACCESS: begin
peripheral_state_next = STATE_IDLE;
end
default: begin
peripheral_state_next = STATE_IDLE;
end
endcase
end
// FSM logic
always_ff @(posedge clk or negedge rst_n) begin : proc_fsm
if (rst_n == 1'b0) begin
peripheral_state <= STATE_IDLE;
end else begin
peripheral_state <= peripheral_state_next;
// Write Enable logic: write data to memory in Renode
if (pselx && penable && pwrite) begin
// Workaround::Bug::Verilator::Task call inside of always block requires using fork...join
fork
begin
runtime.peripherals[CosimToRenodeIndex].write(renode_pkg::address_t'(paddr), valid_bits, renode_pkg::data_t'(pwdata),
is_error);
if (is_error) begin
runtime.connection.log(LogWarning, "Renode connection write transfer was unable to complete");
end
end
join
end
// Read Enable logic: read data from memory in Renode
if (pselx && !penable && !pwrite) begin
// Workaround::Bug::Verilator::Task call inside of always block requires using fork...join
fork
begin
// The runtime.peripherals[CosimToRenodeIndex].read call may cause elapse of a simulation time.
runtime.peripherals[CosimToRenodeIndex].read(renode_pkg::address_t'(paddr), valid_bits, prdata_int, is_error);
if (is_error) begin
runtime.connection.log(LogWarning, "Renode connection read transfer was unable to complete");
end
end
join
end else begin
prdata_int <= '0;
end
end
end
//
// Generate artificial delay to the {PRDATA,PREADY} signals
// Useful to validate wait states, by default is turned off.
//
genvar i;
generate
if (OutputLatency == 0) begin : gen_latency_0
assign prdata = data_t'(prdata_int);
assign pready = (peripheral_state == STATE_ACCESS);
end else begin : gen_latency_gt_0
data_t prdata_reg[OutputLatency];
data_t pready_reg[OutputLatency];
for (i = 0; i < OutputLatency; i++) begin : gen_output_registers
if (i == 0) begin : gen_i_eq_0
always_ff @(posedge clk or negedge rst_n) begin : proc_first_reg
prdata_reg[i] <= prdata_int;
pready_reg[i] <= (peripheral_state == STATE_ACCESS);
end
end else begin: gen_i_neq_0
always_ff @(posedge clk or negedge rst_n) begin : proc_latency_ith
prdata_reg[i] <= prdata_reg[i-1];
pready_reg[i] <= pready_reg[i-1];
end
end
end
assign prdata = prdata_reg[OutputLatency-1];
assign pready = pready_reg[OutputLatency-1];
end
endgenerate
endmodule