2020-01-23 06:22:50 +08:00
// SPDX-License-Identifier: Apache-2.0
2020-11-18 02:25:18 +08:00
// Copyright 2020 Western Digital Corporation or its affiliates.
2020-01-23 06:22:50 +08:00
//
// 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.
//********************************************************************************
// $Id$
//
// Owner:
// Function: AXI4 -> AHB Bridge
// Comments:
//
//********************************************************************************
module axi4_to_ahb
import el2_pkg::* ;
# (
`include " el2_param.vh "
, parameter TAG = 1 ) (
input clk ,
2020-11-18 02:25:18 +08:00
input free_clk ,
2020-01-23 06:22:50 +08:00
input rst_l ,
input scan_mode ,
input bus_clk_en ,
input clk_override ,
2020-11-18 02:25:18 +08:00
input dec_tlu_force_halt ,
2020-01-23 06:22:50 +08:00
// AXI signals
// AXI Write Channels
input logic axi_awvalid ,
output logic axi_awready ,
input logic [ TAG - 1 : 0 ] axi_awid ,
input logic [ 31 : 0 ] axi_awaddr ,
input logic [ 2 : 0 ] axi_awsize ,
input logic [ 2 : 0 ] axi_awprot ,
input logic axi_wvalid ,
output logic axi_wready ,
input logic [ 63 : 0 ] axi_wdata ,
input logic [ 7 : 0 ] axi_wstrb ,
input logic axi_wlast ,
output logic axi_bvalid ,
input logic axi_bready ,
output logic [ 1 : 0 ] axi_bresp ,
output logic [ TAG - 1 : 0 ] axi_bid ,
// AXI Read Channels
input logic axi_arvalid ,
output logic axi_arready ,
input logic [ TAG - 1 : 0 ] axi_arid ,
input logic [ 31 : 0 ] axi_araddr ,
input logic [ 2 : 0 ] axi_arsize ,
input logic [ 2 : 0 ] axi_arprot ,
output logic axi_rvalid ,
input logic axi_rready ,
output logic [ TAG - 1 : 0 ] axi_rid ,
output logic [ 63 : 0 ] axi_rdata ,
output logic [ 1 : 0 ] axi_rresp ,
output logic axi_rlast ,
// AHB-Lite signals
output logic [ 31 : 0 ] ahb_haddr , // ahb bus address
output logic [ 2 : 0 ] ahb_hburst , // tied to 0
output logic ahb_hmastlock , // tied to 0
output logic [ 3 : 0 ] ahb_hprot , // tied to 4'b0011
output logic [ 2 : 0 ] ahb_hsize , // size of bus transaction (possible values 0,1,2,3)
output logic [ 1 : 0 ] ahb_htrans , // Transaction type (possible values 0,2 only right now)
output logic ahb_hwrite , // ahb bus write
output logic [ 63 : 0 ] ahb_hwdata , // ahb bus write data
input logic [ 63 : 0 ] ahb_hrdata , // ahb bus read data
input logic ahb_hready , // slave ready to accept transaction
input logic ahb_hresp // slave response (high indicates erro)
) ;
localparam ID = 1 ;
localparam PRTY = 1 ;
typedef enum logic [ 2 : 0 ] { IDLE = 3 'b000 , CMD_RD = 3 'b001 , CMD_WR = 3 'b010 , DATA_RD = 3 'b011 , DATA_WR = 3 'b100 , DONE = 3 'b101 , STREAM_RD = 3 'b110 , STREAM_ERR_RD = 3 'b111 } state_t ;
state_t buf_state , buf_nxtstate ;
logic slave_valid ;
logic slave_ready ;
logic [ TAG - 1 : 0 ] slave_tag ;
logic [ 63 : 0 ] slave_rdata ;
logic [ 3 : 0 ] slave_opc ;
logic wrbuf_en , wrbuf_data_en ;
logic wrbuf_cmd_sent , wrbuf_rst ;
logic wrbuf_vld ;
logic wrbuf_data_vld ;
logic [ TAG - 1 : 0 ] wrbuf_tag ;
logic [ 2 : 0 ] wrbuf_size ;
logic [ 31 : 0 ] wrbuf_addr ;
logic [ 63 : 0 ] wrbuf_data ;
logic [ 7 : 0 ] wrbuf_byteen ;
logic master_valid ;
logic master_ready ;
logic [ TAG - 1 : 0 ] master_tag ;
logic [ 31 : 0 ] master_addr ;
logic [ 63 : 0 ] master_wdata ;
logic [ 2 : 0 ] master_size ;
logic [ 2 : 0 ] master_opc ;
logic [ 7 : 0 ] master_byteen ;
// Buffer signals (one entry buffer)
logic [ 31 : 0 ] buf_addr ;
logic [ 1 : 0 ] buf_size ;
logic buf_write ;
logic [ 7 : 0 ] buf_byteen ;
logic buf_aligned ;
logic [ 63 : 0 ] buf_data ;
logic [ TAG - 1 : 0 ] buf_tag ;
//Miscellaneous signals
logic buf_rst ;
logic [ TAG - 1 : 0 ] buf_tag_in ;
logic [ 31 : 0 ] buf_addr_in ;
logic [ 7 : 0 ] buf_byteen_in ;
logic [ 63 : 0 ] buf_data_in ;
logic buf_write_in ;
logic buf_aligned_in ;
logic [ 2 : 0 ] buf_size_in ;
logic buf_state_en ;
logic buf_wr_en ;
logic buf_data_wr_en ;
logic slvbuf_error_en ;
logic wr_cmd_vld ;
logic cmd_done_rst , cmd_done , cmd_doneQ ;
logic trxn_done ;
logic [ 2 : 0 ] buf_cmd_byte_ptr , buf_cmd_byte_ptrQ , buf_cmd_nxtbyte_ptr ;
logic buf_cmd_byte_ptr_en ;
logic found ;
logic slave_valid_pre ;
logic ahb_hready_q ;
logic ahb_hresp_q ;
logic [ 1 : 0 ] ahb_htrans_q ;
logic ahb_hwrite_q ;
logic [ 63 : 0 ] ahb_hrdata_q ;
logic slvbuf_write ;
logic slvbuf_error ;
logic [ TAG - 1 : 0 ] slvbuf_tag ;
logic slvbuf_error_in ;
logic slvbuf_wr_en ;
logic bypass_en ;
logic rd_bypass_idle ;
logic last_addr_en ;
logic [ 31 : 0 ] last_bus_addr ;
// Clocks
2020-11-18 02:25:18 +08:00
logic buf_clken ;
2020-01-23 06:22:50 +08:00
logic ahbm_data_clken ;
2020-11-18 02:25:18 +08:00
logic buf_clk ;
logic bus_clk ;
2020-01-23 06:22:50 +08:00
logic ahbm_data_clk ;
2020-11-18 02:25:18 +08:00
logic dec_tlu_force_halt_bus , dec_tlu_force_halt_bus_ns , dec_tlu_force_halt_bus_q ;
2020-01-23 06:22:50 +08:00
// Function to get the length from byte enable
function automatic logic [ 1 : 0 ] get_write_size ;
input logic [ 7 : 0 ] byteen ;
logic [ 1 : 0 ] size ;
size [ 1 : 0 ] = ( 2 'b11 & { 2 { ( byteen [ 7 : 0 ] = = 8 'hff ) } } ) |
( 2 'b10 & { 2 { ( ( byteen [ 7 : 0 ] = = 8 'hf0 ) | ( byteen [ 7 : 0 ] = = 8 'h0f ) ) } } ) |
( 2 'b01 & { 2 { ( ( byteen [ 7 : 0 ] = = 8 'hc0 ) | ( byteen [ 7 : 0 ] = = 8 'h30 ) | ( byteen [ 7 : 0 ] = = 8 'h0c ) | ( byteen [ 7 : 0 ] = = 8 'h03 ) ) } } ) ;
return size [ 1 : 0 ] ;
endfunction // get_write_size
// Function to get the length from byte enable
function automatic logic [ 2 : 0 ] get_write_addr ;
input logic [ 7 : 0 ] byteen ;
logic [ 2 : 0 ] addr ;
addr [ 2 : 0 ] = ( 3 'h0 & { 3 { ( ( byteen [ 7 : 0 ] = = 8 'hff ) | ( byteen [ 7 : 0 ] = = 8 'h0f ) | ( byteen [ 7 : 0 ] = = 8 'h03 ) ) } } ) |
( 3 'h2 & { 3 { ( byteen [ 7 : 0 ] = = 8 'h0c ) } } ) |
( 3 'h4 & { 3 { ( ( byteen [ 7 : 0 ] = = 8 'hf0 ) | ( byteen [ 7 : 0 ] = = 8 'h03 ) ) } } ) |
( 3 'h6 & { 3 { ( byteen [ 7 : 0 ] = = 8 'hc0 ) } } ) ;
return addr [ 2 : 0 ] ;
endfunction // get_write_addr
// Function to get the next byte pointer
function automatic logic [ 2 : 0 ] get_nxtbyte_ptr ( logic [ 2 : 0 ] current_byte_ptr , logic [ 7 : 0 ] byteen , logic get_next ) ;
logic [ 2 : 0 ] start_ptr ;
logic found ;
found = '0 ;
2020-11-18 02:25:18 +08:00
//get_nxtbyte_ptr[2:0] = current_byte_ptr[2:0];
2020-01-23 06:22:50 +08:00
start_ptr [ 2 : 0 ] = get_next ? ( current_byte_ptr [ 2 : 0 ] + 3 'b1 ) : current_byte_ptr [ 2 : 0 ] ;
for ( int j = 0 ; j < 8 ; j + + ) begin
if ( ~ found ) begin
get_nxtbyte_ptr [ 2 : 0 ] = 3 ' ( j ) ;
found | = ( byteen [ j ] & ( 3 ' ( j ) > = start_ptr [ 2 : 0 ] ) ) ;
end
end
endfunction // get_nextbyte_ptr
2020-11-18 02:25:18 +08:00
// Create bus synchronized version of force halt
assign dec_tlu_force_halt_bus = dec_tlu_force_halt | dec_tlu_force_halt_bus_q ;
assign dec_tlu_force_halt_bus_ns = ~ bus_clk_en & dec_tlu_force_halt_bus ;
rvdff # ( . WIDTH ( 1 ) ) force_halt_busff ( . din ( dec_tlu_force_halt_bus_ns ) , . dout ( dec_tlu_force_halt_bus_q ) , . clk ( free_clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
// Write buffer
assign wrbuf_en = axi_awvalid & axi_awready & master_ready ;
assign wrbuf_data_en = axi_wvalid & axi_wready & master_ready ;
assign wrbuf_cmd_sent = master_valid & master_ready & ( master_opc [ 2 : 1 ] = = 2 'b01 ) ;
2020-11-18 02:25:18 +08:00
assign wrbuf_rst = ( wrbuf_cmd_sent & ~ wrbuf_en ) | dec_tlu_force_halt_bus ;
2020-01-23 06:22:50 +08:00
assign axi_awready = ~ ( wrbuf_vld & ~ wrbuf_cmd_sent ) & master_ready ;
assign axi_wready = ~ ( wrbuf_data_vld & ~ wrbuf_cmd_sent ) & master_ready ;
assign axi_arready = ~ ( wrbuf_vld & wrbuf_data_vld ) & master_ready ;
assign axi_rlast = 1 'b1 ;
assign wr_cmd_vld = ( wrbuf_vld & wrbuf_data_vld ) ;
assign master_valid = wr_cmd_vld | axi_arvalid ;
assign master_tag [ TAG - 1 : 0 ] = wr_cmd_vld ? wrbuf_tag [ TAG - 1 : 0 ] : axi_arid [ TAG - 1 : 0 ] ;
assign master_opc [ 2 : 0 ] = wr_cmd_vld ? 3 'b011 : 3 'b0 ;
assign master_addr [ 31 : 0 ] = wr_cmd_vld ? wrbuf_addr [ 31 : 0 ] : axi_araddr [ 31 : 0 ] ;
assign master_size [ 2 : 0 ] = wr_cmd_vld ? wrbuf_size [ 2 : 0 ] : axi_arsize [ 2 : 0 ] ;
assign master_byteen [ 7 : 0 ] = wrbuf_byteen [ 7 : 0 ] ;
assign master_wdata [ 63 : 0 ] = wrbuf_data [ 63 : 0 ] ;
// AXI response channel signals
assign axi_bvalid = slave_valid & slave_ready & slave_opc [ 3 ] ;
assign axi_bresp [ 1 : 0 ] = slave_opc [ 0 ] ? 2 'b10 : ( slave_opc [ 1 ] ? 2 'b11 : 2 'b0 ) ;
assign axi_bid [ TAG - 1 : 0 ] = slave_tag [ TAG - 1 : 0 ] ;
assign axi_rvalid = slave_valid & slave_ready & ( slave_opc [ 3 : 2 ] = = 2 'b0 ) ;
assign axi_rresp [ 1 : 0 ] = slave_opc [ 0 ] ? 2 'b10 : ( slave_opc [ 1 ] ? 2 'b11 : 2 'b0 ) ;
assign axi_rid [ TAG - 1 : 0 ] = slave_tag [ TAG - 1 : 0 ] ;
assign axi_rdata [ 63 : 0 ] = slave_rdata [ 63 : 0 ] ;
assign slave_ready = axi_bready & axi_rready ;
// FIFO state machine
always_comb begin
buf_nxtstate = IDLE ;
buf_state_en = 1 'b0 ;
buf_wr_en = 1 'b0 ;
buf_data_wr_en = 1 'b0 ;
slvbuf_error_in = 1 'b0 ;
slvbuf_error_en = 1 'b0 ;
buf_write_in = 1 'b0 ;
cmd_done = 1 'b0 ;
trxn_done = 1 'b0 ;
buf_cmd_byte_ptr_en = 1 'b0 ;
buf_cmd_byte_ptr [ 2 : 0 ] = '0 ;
slave_valid_pre = 1 'b0 ;
master_ready = 1 'b0 ;
ahb_htrans [ 1 : 0 ] = 2 'b0 ;
slvbuf_wr_en = 1 'b0 ;
bypass_en = 1 'b0 ;
rd_bypass_idle = 1 'b0 ;
case ( buf_state )
IDLE: begin
master_ready = 1 'b1 ;
buf_write_in = ( master_opc [ 2 : 1 ] = = 2 'b01 ) ;
buf_nxtstate = buf_write_in ? CMD_WR : CMD_RD ;
buf_state_en = master_valid & master_ready ;
buf_wr_en = buf_state_en ;
buf_data_wr_en = buf_state_en & ( buf_nxtstate = = CMD_WR ) ;
buf_cmd_byte_ptr_en = buf_state_en ;
buf_cmd_byte_ptr [ 2 : 0 ] = buf_write_in ? get_nxtbyte_ptr ( 3 'b0 , buf_byteen_in [ 7 : 0 ] , 1 'b0 ) : master_addr [ 2 : 0 ] ;
bypass_en = buf_state_en ;
rd_bypass_idle = bypass_en & ( buf_nxtstate = = CMD_RD ) ;
ahb_htrans [ 1 : 0 ] = { 2 { bypass_en } } & 2 'b10 ;
end
CMD_RD: begin
buf_nxtstate = ( master_valid & ( master_opc [ 2 : 0 ] = = 3 'b000 ) ) ? STREAM_RD : DATA_RD ;
buf_state_en = ahb_hready_q & ( ahb_htrans_q [ 1 : 0 ] ! = 2 'b0 ) & ~ ahb_hwrite_q ;
cmd_done = buf_state_en & ~ master_valid ;
slvbuf_wr_en = buf_state_en ;
master_ready = buf_state_en & ( buf_nxtstate = = STREAM_RD ) ;
buf_wr_en = master_ready ;
bypass_en = master_ready & master_valid ;
buf_cmd_byte_ptr [ 2 : 0 ] = bypass_en ? master_addr [ 2 : 0 ] : buf_addr [ 2 : 0 ] ;
ahb_htrans [ 1 : 0 ] = 2 'b10 & { 2 { ~ buf_state_en | bypass_en } } ;
end
STREAM_RD: begin
master_ready = ( ahb_hready_q & ~ ahb_hresp_q ) & ~ ( master_valid & master_opc [ 2 : 1 ] = = 2 'b01 ) ;
buf_wr_en = ( master_valid & master_ready & ( master_opc [ 2 : 0 ] = = 3 'b000 ) ) ; // update the fifo if we are streaming the read commands
buf_nxtstate = ahb_hresp_q ? STREAM_ERR_RD : ( buf_wr_en ? STREAM_RD : DATA_RD ) ; // assuming that the master accpets the slave response right away.
buf_state_en = ( ahb_hready_q | ahb_hresp_q ) ;
buf_data_wr_en = buf_state_en ;
slvbuf_error_in = ahb_hresp_q ;
slvbuf_error_en = buf_state_en ;
slave_valid_pre = buf_state_en & ~ ahb_hresp_q ; // send a response right away if we are not going through an error response.
cmd_done = buf_state_en & ~ master_valid ; // last one of the stream should not send a htrans
bypass_en = master_ready & master_valid & ( buf_nxtstate = = STREAM_RD ) & buf_state_en ;
buf_cmd_byte_ptr [ 2 : 0 ] = bypass_en ? master_addr [ 2 : 0 ] : buf_addr [ 2 : 0 ] ;
ahb_htrans [ 1 : 0 ] = 2 'b10 & { 2 { ~ ( ( buf_nxtstate ! = STREAM_RD ) & buf_state_en ) } } ;
slvbuf_wr_en = buf_wr_en ; // shifting the contents from the buf to slv_buf for streaming cases
end // case: STREAM_RD
STREAM_ERR_RD: begin
buf_nxtstate = DATA_RD ;
buf_state_en = ahb_hready_q & ( ahb_htrans_q [ 1 : 0 ] ! = 2 'b0 ) & ~ ahb_hwrite_q ;
slave_valid_pre = buf_state_en ;
slvbuf_wr_en = buf_state_en ; // Overwrite slvbuf with buffer
buf_cmd_byte_ptr [ 2 : 0 ] = buf_addr [ 2 : 0 ] ;
ahb_htrans [ 1 : 0 ] = 2 'b10 & { 2 { ~ buf_state_en } } ;
end
DATA_RD: begin
buf_nxtstate = DONE ;
buf_state_en = ( ahb_hready_q | ahb_hresp_q ) ;
buf_data_wr_en = buf_state_en ;
slvbuf_error_in = ahb_hresp_q ;
slvbuf_error_en = buf_state_en ;
slvbuf_wr_en = buf_state_en ;
end
CMD_WR: begin
buf_nxtstate = DATA_WR ;
trxn_done = ahb_hready_q & ahb_hwrite_q & ( ahb_htrans_q [ 1 : 0 ] ! = 2 'b0 ) ;
buf_state_en = trxn_done ;
buf_cmd_byte_ptr_en = buf_state_en ;
slvbuf_wr_en = buf_state_en ;
buf_cmd_byte_ptr = trxn_done ? get_nxtbyte_ptr ( buf_cmd_byte_ptrQ [ 2 : 0 ] , buf_byteen [ 7 : 0 ] , 1 'b1 ) : buf_cmd_byte_ptrQ ;
cmd_done = trxn_done & ( buf_aligned | ( buf_cmd_byte_ptrQ = = 3 'b111 ) |
( buf_byteen [ get_nxtbyte_ptr ( buf_cmd_byte_ptrQ [ 2 : 0 ] , buf_byteen [ 7 : 0 ] , 1 'b1 ) ] = = 1 'b0 ) ) ;
ahb_htrans [ 1 : 0 ] = { 2 { ~ ( cmd_done | cmd_doneQ ) } } & 2 'b10 ;
end
DATA_WR: begin
buf_state_en = ( cmd_doneQ & ahb_hready_q ) | ahb_hresp_q ;
master_ready = buf_state_en & ~ ahb_hresp_q & slave_ready ; // Ready to accept new command if current command done and no error
buf_nxtstate = ( ahb_hresp_q | ~ slave_ready ) ? DONE :
( ( master_valid & master_ready ) ? ( ( master_opc [ 2 : 1 ] = = 2 'b01 ) ? CMD_WR : CMD_RD ) : IDLE ) ;
slvbuf_error_in = ahb_hresp_q ;
slvbuf_error_en = buf_state_en ;
buf_write_in = ( master_opc [ 2 : 1 ] = = 2 'b01 ) ;
buf_wr_en = buf_state_en & ( ( buf_nxtstate = = CMD_WR ) | ( buf_nxtstate = = CMD_RD ) ) ;
buf_data_wr_en = buf_wr_en ;
cmd_done = ( ahb_hresp_q | ( ahb_hready_q & ( ahb_htrans_q [ 1 : 0 ] ! = 2 'b0 ) &
( ( buf_cmd_byte_ptrQ = = 3 'b111 ) | ( buf_byteen [ get_nxtbyte_ptr ( buf_cmd_byte_ptrQ [ 2 : 0 ] , buf_byteen [ 7 : 0 ] , 1 'b1 ) ] = = 1 'b0 ) ) ) ) ;
bypass_en = buf_state_en & buf_write_in & ( buf_nxtstate = = CMD_WR ) ; // Only bypass for writes for the time being
ahb_htrans [ 1 : 0 ] = { 2 { ( ~ ( cmd_done | cmd_doneQ ) | bypass_en ) } } & 2 'b10 ;
slave_valid_pre = buf_state_en & ( buf_nxtstate ! = DONE ) ;
trxn_done = ahb_hready_q & ahb_hwrite_q & ( ahb_htrans_q [ 1 : 0 ] ! = 2 'b0 ) ;
buf_cmd_byte_ptr_en = trxn_done | bypass_en ;
buf_cmd_byte_ptr = bypass_en ? get_nxtbyte_ptr ( 3 'b0 , buf_byteen_in [ 7 : 0 ] , 1 'b0 ) :
trxn_done ? get_nxtbyte_ptr ( buf_cmd_byte_ptrQ [ 2 : 0 ] , buf_byteen [ 7 : 0 ] , 1 'b1 ) : buf_cmd_byte_ptrQ ;
end
DONE: begin
buf_nxtstate = IDLE ;
buf_state_en = slave_ready ;
slvbuf_error_en = 1 'b1 ;
slave_valid_pre = 1 'b1 ;
end
endcase
end
2020-11-18 02:25:18 +08:00
assign buf_rst = dec_tlu_force_halt_bus ;
2020-01-23 06:22:50 +08:00
assign cmd_done_rst = slave_valid_pre ;
assign buf_addr_in [ 31 : 3 ] = master_addr [ 31 : 3 ] ;
assign buf_addr_in [ 2 : 0 ] = ( buf_aligned_in & ( master_opc [ 2 : 1 ] = = 2 'b01 ) ) ? get_write_addr ( master_byteen [ 7 : 0 ] ) : master_addr [ 2 : 0 ] ;
assign buf_tag_in [ TAG - 1 : 0 ] = master_tag [ TAG - 1 : 0 ] ;
assign buf_byteen_in [ 7 : 0 ] = wrbuf_byteen [ 7 : 0 ] ;
assign buf_data_in [ 63 : 0 ] = ( buf_state = = DATA_RD ) ? ahb_hrdata_q [ 63 : 0 ] : master_wdata [ 63 : 0 ] ;
assign buf_size_in [ 1 : 0 ] = ( buf_aligned_in & ( master_size [ 1 : 0 ] = = 2 'b11 ) & ( master_opc [ 2 : 1 ] = = 2 'b01 ) ) ? get_write_size ( master_byteen [ 7 : 0 ] ) : master_size [ 1 : 0 ] ;
assign buf_aligned_in = ( master_opc [ 2 : 0 ] = = 3 'b0 ) | // reads are always aligned since they are either DW or sideeffects
( master_size [ 1 : 0 ] = = 2 'b0 ) | ( master_size [ 1 : 0 ] = = 2 'b01 ) | ( master_size [ 1 : 0 ] = = 2 'b10 ) | // Always aligned for Byte/HW/Word since they can be only for non-idempotent. IFU/SB are always aligned
( ( master_size [ 1 : 0 ] = = 2 'b11 ) &
( ( master_byteen [ 7 : 0 ] = = 8 'h3 ) | ( master_byteen [ 7 : 0 ] = = 8 'hc ) | ( master_byteen [ 7 : 0 ] = = 8 'h30 ) | ( master_byteen [ 7 : 0 ] = = 8 'hc0 ) |
( master_byteen [ 7 : 0 ] = = 8 'hf ) | ( master_byteen [ 7 : 0 ] = = 8 'hf0 ) | ( master_byteen [ 7 : 0 ] = = 8 'hff ) ) ) ;
// Generate the ahb signals
2020-11-18 02:25:18 +08:00
assign ahb_haddr [ 31 : 3 ] = bypass_en ? master_addr [ 31 : 3 ] : buf_addr [ 31 : 3 ] ;
assign ahb_haddr [ 2 : 0 ] = { 3 { ( ahb_htrans = = 2 'b10 ) } } & buf_cmd_byte_ptr [ 2 : 0 ] ; // Trxn should be aligned during IDLE
2020-01-23 06:22:50 +08:00
assign ahb_hsize [ 2 : 0 ] = bypass_en ? { 1 'b0 , ( { 2 { buf_aligned_in } } & buf_size_in [ 1 : 0 ] ) } :
{ 1 'b0 , ( { 2 { buf_aligned } } & buf_size [ 1 : 0 ] ) } ; // Send the full size for aligned trxn
assign ahb_hburst [ 2 : 0 ] = 3 'b0 ;
assign ahb_hmastlock = 1 'b0 ;
assign ahb_hprot [ 3 : 0 ] = { 3 'b001 , ~ axi_arprot [ 2 ] } ;
assign ahb_hwrite = bypass_en ? ( master_opc [ 2 : 1 ] = = 2 'b01 ) : buf_write ;
assign ahb_hwdata [ 63 : 0 ] = buf_data [ 63 : 0 ] ;
2020-11-18 02:25:18 +08:00
assign slave_valid = slave_valid_pre ; // & (~slvbuf_posted_write | slvbuf_error);
2020-01-23 06:22:50 +08:00
assign slave_opc [ 3 : 2 ] = slvbuf_write ? 2 'b11 : 2 'b00 ;
assign slave_opc [ 1 : 0 ] = { 2 { slvbuf_error } } & 2 'b10 ;
assign slave_rdata [ 63 : 0 ] = slvbuf_error ? { 2 { last_bus_addr [ 31 : 0 ] } } : ( ( buf_state = = DONE ) ? buf_data [ 63 : 0 ] : ahb_hrdata_q [ 63 : 0 ] ) ;
assign slave_tag [ TAG - 1 : 0 ] = slvbuf_tag [ TAG - 1 : 0 ] ;
assign last_addr_en = ( ahb_htrans [ 1 : 0 ] ! = 2 'b0 ) & ahb_hready & ahb_hwrite ;
2020-11-18 02:25:18 +08:00
rvdffsc_fpga # ( . WIDTH ( 1 ) ) wrbuf_vldff ( . din ( 1 'b1 ) , . dout ( wrbuf_vld ) , . en ( wrbuf_en ) , . clear ( wrbuf_rst ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffsc_fpga # ( . WIDTH ( 1 ) ) wrbuf_data_vldff ( . din ( 1 'b1 ) , . dout ( wrbuf_data_vld ) , . en ( wrbuf_data_en ) , . clear ( wrbuf_rst ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( TAG ) ) wrbuf_tagff ( . din ( axi_awid [ TAG - 1 : 0 ] ) , . dout ( wrbuf_tag [ TAG - 1 : 0 ] ) , . en ( wrbuf_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 3 ) ) wrbuf_sizeff ( . din ( axi_awsize [ 2 : 0 ] ) , . dout ( wrbuf_size [ 2 : 0 ] ) , . en ( wrbuf_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffe # ( . WIDTH ( 32 ) ) wrbuf_addrff ( . din ( axi_awaddr [ 31 : 0 ] ) , . dout ( wrbuf_addr [ 31 : 0 ] ) , . en ( wrbuf_en & bus_clk_en ) , . clk ( clk ) , . * ) ;
rvdffe # ( . WIDTH ( 64 ) ) wrbuf_dataff ( . din ( axi_wdata [ 63 : 0 ] ) , . dout ( wrbuf_data [ 63 : 0 ] ) , . en ( wrbuf_data_en & bus_clk_en ) , . clk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 8 ) ) wrbuf_byteenff ( . din ( axi_wstrb [ 7 : 0 ] ) , . dout ( wrbuf_byteen [ 7 : 0 ] ) , . en ( wrbuf_data_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
rvdffs_fpga # ( . WIDTH ( 32 ) ) last_bus_addrff ( . din ( ahb_haddr [ 31 : 0 ] ) , . dout ( last_bus_addr [ 31 : 0 ] ) , . en ( last_addr_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
rvdffsc_fpga # ( . WIDTH ( $bits ( state_t ) ) ) buf_state_ff ( . din ( buf_nxtstate ) , . dout ( { buf_state } ) , . en ( buf_state_en ) , . clear ( buf_rst ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 1 ) ) buf_writeff ( . din ( buf_write_in ) , . dout ( buf_write ) , . en ( buf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( TAG ) ) buf_tagff ( . din ( buf_tag_in [ TAG - 1 : 0 ] ) , . dout ( buf_tag [ TAG - 1 : 0 ] ) , . en ( buf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffe # ( . WIDTH ( 32 ) ) buf_addrff ( . din ( buf_addr_in [ 31 : 0 ] ) , . dout ( buf_addr [ 31 : 0 ] ) , . en ( buf_wr_en & bus_clk_en ) , . clk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 2 ) ) buf_sizeff ( . din ( buf_size_in [ 1 : 0 ] ) , . dout ( buf_size [ 1 : 0 ] ) , . en ( buf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 1 ) ) buf_alignedff ( . din ( buf_aligned_in ) , . dout ( buf_aligned ) , . en ( buf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 8 ) ) buf_byteenff ( . din ( buf_byteen_in [ 7 : 0 ] ) , . dout ( buf_byteen [ 7 : 0 ] ) , . en ( buf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffe # ( . WIDTH ( 64 ) ) buf_dataff ( . din ( buf_data_in [ 63 : 0 ] ) , . dout ( buf_data [ 63 : 0 ] ) , . en ( buf_data_wr_en & bus_clk_en ) , . clk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
rvdffs_fpga # ( . WIDTH ( 1 ) ) slvbuf_writeff ( . din ( buf_write ) , . dout ( slvbuf_write ) , . en ( slvbuf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( TAG ) ) slvbuf_tagff ( . din ( buf_tag [ TAG - 1 : 0 ] ) , . dout ( slvbuf_tag [ TAG - 1 : 0 ] ) , . en ( slvbuf_wr_en ) , . clk ( buf_clk ) , . clken ( buf_clken ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 1 ) ) slvbuf_errorff ( . din ( slvbuf_error_in ) , . dout ( slvbuf_error ) , . en ( slvbuf_error_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
rvdffsc_fpga # ( . WIDTH ( 1 ) ) buf_cmd_doneff ( . din ( 1 'b1 ) , . dout ( cmd_doneQ ) , . en ( cmd_done ) , . clear ( cmd_done_rst ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdffs_fpga # ( . WIDTH ( 3 ) ) buf_cmd_byte_ptrff ( . din ( buf_cmd_byte_ptr [ 2 : 0 ] ) , . dout ( buf_cmd_byte_ptrQ [ 2 : 0 ] ) , . en ( buf_cmd_byte_ptr_en ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
rvdff_fpga # ( . WIDTH ( 1 ) ) hready_ff ( . din ( ahb_hready ) , . dout ( ahb_hready_q ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdff_fpga # ( . WIDTH ( 2 ) ) htrans_ff ( . din ( ahb_htrans [ 1 : 0 ] ) , . dout ( ahb_htrans_q [ 1 : 0 ] ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdff_fpga # ( . WIDTH ( 1 ) ) hwrite_ff ( . din ( ahb_hwrite ) , . dout ( ahb_hwrite_q ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdff_fpga # ( . WIDTH ( 1 ) ) hresp_ff ( . din ( ahb_hresp ) , . dout ( ahb_hresp_q ) , . clk ( bus_clk ) , . clken ( bus_clk_en ) , . rawclk ( clk ) , . * ) ;
rvdff_fpga # ( . WIDTH ( 64 ) ) hrdata_ff ( . din ( ahb_hrdata [ 63 : 0 ] ) , . dout ( ahb_hrdata_q [ 63 : 0 ] ) , . clk ( ahbm_data_clk ) , . clken ( ahbm_data_clken ) , . rawclk ( clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
// Clock headers
// clock enables for ahbm addr/data
assign buf_clken = bus_clk_en & ( buf_wr_en | slvbuf_wr_en | clk_override ) ;
assign ahbm_data_clken = bus_clk_en & ( ( buf_state ! = IDLE ) | clk_override ) ;
2020-11-18 02:25:18 +08:00
`ifdef RV_FPGA_OPTIMIZE
assign bus_clk = 1 'b0 ;
assign buf_clk = 1 'b0 ;
assign ahbm_data_clk = 1 'b0 ;
`else
rvclkhdr bus_cgc ( . en ( bus_clk_en ) , . l1clk ( bus_clk ) , . * ) ;
rvclkhdr buf_cgc ( . en ( buf_clken ) , . l1clk ( buf_clk ) , . * ) ;
2020-01-23 06:22:50 +08:00
rvclkhdr ahbm_data_cgc ( . en ( ahbm_data_clken ) , . l1clk ( ahbm_data_clk ) , . * ) ;
2020-11-18 02:25:18 +08:00
`endif
2020-01-23 06:22:50 +08:00
2020-11-18 02:25:18 +08:00
`ifdef RV_ASSERT_ON
2020-01-23 06:22:50 +08:00
property ahb_trxn_aligned ;
2020-11-18 02:25:18 +08:00
@ ( posedge bus_clk ) ahb_htrans [ 1 ] | - > ( ( ahb_hsize [ 2 : 0 ] = = 3 'h0 ) |
2020-01-23 06:22:50 +08:00
( ( ahb_hsize [ 2 : 0 ] = = 3 'h1 ) & ( ahb_haddr [ 0 ] = = 1 'b0 ) ) |
( ( ahb_hsize [ 2 : 0 ] = = 3 'h2 ) & ( ahb_haddr [ 1 : 0 ] = = 2 'b0 ) ) |
( ( ahb_hsize [ 2 : 0 ] = = 3 'h3 ) & ( ahb_haddr [ 2 : 0 ] = = 3 'b0 ) ) ) ;
endproperty
assert_ahb_trxn_aligned: assert property ( ahb_trxn_aligned ) else
$display ( " Assertion ahb_trxn_aligned failed: ahb_htrans=2'h%h, ahb_hsize=3'h%h, ahb_haddr=32'h%h " , ahb_htrans [ 1 : 0 ] , ahb_hsize [ 2 : 0 ] , ahb_haddr [ 31 : 0 ] ) ;
property ahb_error_protocol ;
2020-11-18 02:25:18 +08:00
@ ( posedge bus_clk ) ( ahb_hready & ahb_hresp ) | - > ( ~ $past ( ahb_hready ) & $past ( ahb_hresp ) ) ;
2020-01-23 06:22:50 +08:00
endproperty
assert_ahb_error_protocol: assert property ( ahb_error_protocol ) else
$display ( " Bus Error with hReady isn't preceded with Bus Error without hready " ) ;
`endif
endmodule // axi4_to_ahb