blob: 02dca1d982f02dfaa3d7d79c59f3da7d23d5340a [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2021 , Dinesh Annayya
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Dinesh Annayya <dinesh.annayya@gmail.com>
//
//////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------
// This block translate the Reg Bus transaction from in_clk clock domain to out_clk clock domain.
// This block also generate and terminate the transfer if 512 cycle transaction is not completed
// Assumption
// 1. in_reg_cs will be asserted untill ack is received
// 2. reg_addr/reg_wdata/reg_be will be available during reg_cs
// 3. Ever after out_reg_ack de-asserted reg_rdata holds the old data
//----------------------------------------------------------------------------------------------
module async_reg_bus (
// Initiator declartion
in_clk ,
in_reset_n ,
// Reg Bus Master
// outputs
in_reg_rdata ,
in_reg_ack ,
in_reg_timeout ,
// Inputs
in_reg_cs ,
in_reg_addr ,
in_reg_wdata ,
in_reg_wr ,
in_reg_be ,
// Target Declaration
out_clk ,
out_reset_n ,
// Reg Bus Slave
// output
out_reg_cs ,
out_reg_addr ,
out_reg_wdata ,
out_reg_wr ,
out_reg_be ,
// Inputs
out_reg_rdata ,
out_reg_ack
);
parameter AW = 26 ; // Address width
parameter DW = 32 ; // DATA WIDTH
parameter BEW = 4 ; // Byte enable width
parameter TIMEOUT_ENB = 1 ; // TIMEOUT Generation enabled
//----------------------------------------
// Reg Bus reg inout declration
//----------------------------------------
input in_clk ; // Initiator domain clock
input in_reset_n ; // Initiator domain reset
input in_reg_cs ; // Initiator Chip Select
input [AW-1:0] in_reg_addr ; // Address bus
input [DW-1:0] in_reg_wdata ; // Write data
input in_reg_wr ; // Read/write indication, 1-> write
input [BEW-1:0] in_reg_be ; // Byte valid for write
output [DW-1:0] in_reg_rdata ; // Read Data
output in_reg_ack ; // Reg Access done
output in_reg_timeout ; // Access error indication pulse
// Genererated if no target ack
// received
// within 512 cycle
//---------------------------------------------
// Reg Bus target inout declration
//---------------------------------------------
input out_clk ; // Target domain clock
input out_reset_n ; // Traget domain reset
input [DW-1:0] out_reg_rdata ; // Read data
input out_reg_ack ; // target finish
output out_reg_cs ; // Target Start indication
output [AW-1:0] out_reg_addr ; // Target address
output [DW-1:0] out_reg_wdata ; // Target write data
output out_reg_wr ; // Target Read/write ind, 1-> Write
output [BEW-1:0] out_reg_be ; // Target Byte enable
//-----------------------------------
// Initiator Local Declaration
// ----------------------------------
parameter INI_IDLE = 2'b00;
parameter INI_WAIT_ACK = 2'b01;
parameter INI_WAIT_TAR_DONE = 2'b10;
reg [1:0] in_state ; // reg state
reg [8:0] in_timer ; // reg timout monitor timer
reg in_flag ; // reg handshake flag
reg in_reg_ack ; // reg reg access finish ind
reg [DW-1:0] in_reg_rdata ; // reg reg access read data
reg in_reg_timeout ; // reg time out error pulse
//-----------------------------------
// Target Local Declaration
// ----------------------------------
parameter TAR_IDLE = 2'b00;
parameter TAR_WAIT_ACK = 2'b01;
parameter TAR_WAIT_INI_DONE = 2'b10;
reg [1:0] out_state ; // target state machine
reg out_flag ; // target handshake flag
reg out_reg_cs ; // Target Start indication
reg [8:0] inititaor_timer ; // timeout counter
//-----------------------------------------------
// Double sync local declaration
// ----------------------------------------------
reg in_flag_s ; // Initiator handshake flag sync
// with target clk
reg in_flag_ss ; // Initiator handshake flag sync
// with target clk
reg out_flag_s ; // target handshake flag sync
// with initiator clk
reg out_flag_ss ; // target handshake flag sync
// with initiator clck
assign out_reg_addr = in_reg_addr;
assign out_reg_wdata = in_reg_wdata;
assign out_reg_wr = in_reg_wr;
assign out_reg_be = in_reg_be;
//------------------------------------------------------
// Initiator Domain logic
//------------------------------------------------------
always @(negedge in_reset_n or posedge in_clk)
begin
if(in_reset_n == 1'b0)
begin
in_state <= INI_IDLE;
in_timer <= 9'h0;
in_flag <= 1'b0;
in_reg_ack <= 1'b0;
in_reg_rdata <= {DW {1'b0}};
in_reg_timeout<= 1'b0;
end
else
begin
case(in_state)
INI_IDLE :
begin
in_reg_ack <= 1'b0;
in_reg_timeout <= 1'b0;
in_timer <= 'h0;
// Wait for Initiator Start Indication
// Once the reg start is detected
// Set the reg flag and move to WAIT
// for ack from Target
if(in_reg_cs) begin
in_flag <= 1'b1;
in_state <= INI_WAIT_ACK;
end
end
INI_WAIT_ACK :
begin
//--------------------------------------------
// 1. Wait for Out Flag == 1
// 2. If the Out Flag =1 is not
// detected witin 512 cycle, exit with error indication
// 3. If Target flag detected, then de-assert
// reg_flag = 0 and move the tar_wait_done state
// ---------------------------------------------
if(out_flag_ss == 1'b1) begin
in_flag <= 1'b0;
in_reg_rdata <= out_reg_rdata;
in_reg_ack <= 1'b1;
in_state <= INI_WAIT_TAR_DONE;
end
else begin if(TIMEOUT_ENB) begin
if(in_timer == 9'h1FF ) begin
in_flag <= 1'b0;
in_reg_ack <= 1'b1;
in_reg_rdata <= 32'h0;
in_reg_timeout <= 1'b1;
in_state <= INI_IDLE;
end
else begin
in_timer <= in_timer + 1;
end
end
end
end
INI_WAIT_TAR_DONE :
begin
in_reg_ack <= 1'b0;
//--------------------------------------------
// 1. Wait for Target Flag == 0
// 2. If Target flag = 0 detected, then remove
// move the idle state
// ---------------------------------------------
if(out_flag_ss == 1'b0) begin
in_state <= INI_IDLE;
end
end
default:
begin
in_state <= INI_IDLE;
in_timer <= 9'h0;
in_flag <= 1'b0;
in_reg_rdata <= {DW {1'b0}};
in_reg_timeout <= 1'b0;
end
endcase
end
end
//------------------------------------------------------
// target Domain logic
//------------------------------------------------------
always @(negedge out_reset_n or posedge out_clk)
begin
if(out_reset_n == 1'b0)
begin
out_state <= TAR_IDLE;
out_flag <= 1'b0;
out_reg_cs <= 1'b0;
end
else
begin
case(out_state)
TAR_IDLE :
begin
// 1. Wait for Initiator flag assertion
// 2. Once the reg flag = 1 is detected
// Set the target_flag and initiate the
// target reg bus access
out_flag <= 1'b0;
if(in_flag_ss) begin
out_reg_cs <= 1'b1;
out_state <= TAR_WAIT_ACK;
end
end
TAR_WAIT_ACK :
begin
//--------------------------------------------
// 1. Wait for reg Flag == 0
// 2. If reg flag = 0 detected, then
// move the idle state
// ---------------------------------------------
if(out_reg_ack == 1'b1)
begin
out_reg_cs <= 1'b0;
out_flag <= 1'b1;
out_state <= TAR_WAIT_INI_DONE;
end
end
TAR_WAIT_INI_DONE :
begin
if(in_flag_ss == 1'b0) begin
out_flag <= 1'b0;
out_state <= TAR_IDLE;
end
end
default:
begin
out_state <= TAR_IDLE;
out_reg_cs <= 1'b0;
out_flag <= 1'b0;
end
endcase
end
end
//-------------------------------------------------------
// Double Sync Logic
// ------------------------------------------------------
always @(negedge in_reset_n or posedge in_clk)
begin
if(in_reset_n == 1'b0)
begin
out_flag_s <= 1'b0;
out_flag_ss <= 1'b0;
end
else
begin
out_flag_s <= out_flag;
out_flag_ss <= out_flag_s;
end
end
always @(negedge out_reset_n or posedge out_clk)
begin
if(out_reset_n == 1'b0)
begin
in_flag_s <= 1'b0;
in_flag_ss <= 1'b0;
end
else
begin
in_flag_s <= in_flag;
in_flag_ss <= in_flag_s;
end
end
endmodule