////////////////////////////////////////////////////////////////////////////////
//
// Filename:	rtl/axim2wbsp.v
// {{{
// Project:	WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose:	So ... this converter works in the other direction from
//		wbm2axisp.  This converter takes AXI commands, and organizes
//	them into pipelined wishbone commands.
//
//	This particular core treats AXI as two separate buses: one for writes,
//	and the other for reads.  This particular core combines the two channels
//	into one.  The designer should be aware that the two AXI buses turned
//	Wishbone buses can be kept separate as separate inputs to a WB crosssbar
//	for better performance in some circumstances.
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2016-2025, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License").  You may not use this project,
// or 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.
//
////////////////////////////////////////////////////////////////////////////////
//
`default_nettype	none
// }}}
module axim2wbsp #(
		// {{{
		parameter C_AXI_ID_WIDTH = 2, // The AXI id width used for R&W
                                             // This is an int between 1-16
		parameter  C_AXI_DATA_WIDTH  = 32,// Width of the AXI R&W data
		parameter  C_AXI_ADDR_WIDTH	= 28,	// AXI Address width
		localparam AXI_LSBS		= $clog2(C_AXI_DATA_WIDTH)-3,
		localparam DW			= C_AXI_DATA_WIDTH,
		localparam AW			= C_AXI_ADDR_WIDTH - AXI_LSBS,
		parameter  LGFIFO		= 5,
		parameter [0:0]	OPT_SWAP_ENDIANNESS = 1'b0,
		parameter [0:0]	OPT_READONLY	= 1'b0,
		parameter [0:0]	OPT_WRITEONLY	= 1'b0
		// }}}
	) (
		// {{{
		//
		input	wire			S_AXI_ACLK,	// System clock
		input	wire			S_AXI_ARESETN,

		// AXI write address channel signals
		// {{{
		input	wire			S_AXI_AWVALID,
		output	wire			S_AXI_AWREADY,
		input	wire	[C_AXI_ID_WIDTH-1:0]	S_AXI_AWID,
		input	wire	[C_AXI_ADDR_WIDTH-1:0]	S_AXI_AWADDR,
		input	wire	[7:0]		S_AXI_AWLEN,
		input	wire	[2:0]		S_AXI_AWSIZE,
		input	wire	[1:0]		S_AXI_AWBURST,
		input	wire	[0:0]		S_AXI_AWLOCK,
		input	wire	[3:0]		S_AXI_AWCACHE,
		input	wire	[2:0]		S_AXI_AWPROT,
		input	wire	[3:0]		S_AXI_AWQOS,
		// }}}
		// AXI write data channel signals
		// {{{
		input	wire			S_AXI_WVALID,
		output	wire			S_AXI_WREADY, 
		input	wire [C_AXI_DATA_WIDTH-1:0]   S_AXI_WDATA,
		input	wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
		input	wire			S_AXI_WLAST,
		// }}}
		// AXI write response channel signals
		// {{{
		output	wire 			S_AXI_BVALID, 
		input	wire			S_AXI_BREADY,
		output	wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,
		output	wire [1:0]		S_AXI_BRESP,
		// }}}
		// AXI read address channel signals
		// {{{
		input	wire			S_AXI_ARVALID,
		output	wire			S_AXI_ARREADY,
		input	wire [C_AXI_ID_WIDTH-1:0]   S_AXI_ARID,
		input	wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,
		input	wire	[7:0]		S_AXI_ARLEN,
		input	wire	[2:0]		S_AXI_ARSIZE,
		input	wire	[1:0]		S_AXI_ARBURST,
		input	wire	[0:0]		S_AXI_ARLOCK,
		input	wire	[3:0]		S_AXI_ARCACHE,
		input	wire	[2:0]		S_AXI_ARPROT,
		input	wire	[3:0]		S_AXI_ARQOS,
		// }}}
		// AXI read data channel signals
		// {{{
		output	wire			S_AXI_RVALID,  // Rd rslt valid
		input	wire			S_AXI_RREADY,  // Rd rslt ready
		output	wire [C_AXI_ID_WIDTH-1:0]   S_AXI_RID, // Response ID
		output	wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,// Read data
		output	wire			S_AXI_RLAST,   // Read last
		output	wire [1:0]		S_AXI_RRESP,   // Read response
		// }}}
		// We'll share the clock and the reset
		// {{{
		output	wire				o_reset,
		output	wire				o_wb_cyc,
		output	wire				o_wb_stb,
		output	wire				o_wb_we,
		output	wire [(AW-1):0]			o_wb_addr,
		output	wire [(C_AXI_DATA_WIDTH-1):0]	o_wb_data,
		output	wire [(C_AXI_DATA_WIDTH/8-1):0]	o_wb_sel,
		input	wire				i_wb_stall,
		input	wire				i_wb_ack,
		input	wire [(C_AXI_DATA_WIDTH-1):0]	i_wb_data,
		input	wire				i_wb_err
		// }}}
		// }}}
	);
	//
	//
	//


	wire	[(AW-1):0]			w_wb_addr, r_wb_addr;
	wire	[(C_AXI_DATA_WIDTH-1):0]	w_wb_data;
	wire	[(C_AXI_DATA_WIDTH/8-1):0]	w_wb_sel, r_wb_sel;
	wire	r_wb_err, r_wb_cyc, r_wb_stb, r_wb_stall, r_wb_ack;
	wire	w_wb_err, w_wb_cyc, w_wb_stb, w_wb_stall, w_wb_ack;
	wire	r_wb_we, w_wb_we;

	assign	r_wb_we = 1'b0;
	assign	w_wb_we = 1'b1;

	generate if (!OPT_READONLY)
	begin : AXI_WR
		// {{{
		aximwr2wbsp #(
			// {{{
			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
			.OPT_SWAP_ENDIANNESS(OPT_SWAP_ENDIANNESS),
			.LGFIFO(LGFIFO)
			// }}}
		) axi_write_decoder(
		// {{{
			.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
			//
			.S_AXI_AWVALID(S_AXI_AWVALID),
			.S_AXI_AWREADY(S_AXI_AWREADY),
			.S_AXI_AWID(   S_AXI_AWID),
			.S_AXI_AWADDR( S_AXI_AWADDR),
			.S_AXI_AWLEN(  S_AXI_AWLEN),
			.S_AXI_AWSIZE( S_AXI_AWSIZE),
			.S_AXI_AWBURST(S_AXI_AWBURST),
			.S_AXI_AWLOCK( S_AXI_AWLOCK),
			.S_AXI_AWCACHE(S_AXI_AWCACHE),
			.S_AXI_AWPROT( S_AXI_AWPROT),
			.S_AXI_AWQOS(  S_AXI_AWQOS),
			//
			.S_AXI_WVALID( S_AXI_WVALID),
			.S_AXI_WREADY( S_AXI_WREADY),
			.S_AXI_WDATA(  S_AXI_WDATA),
			.S_AXI_WSTRB(  S_AXI_WSTRB),
			.S_AXI_WLAST(  S_AXI_WLAST),
			//
			.S_AXI_BVALID(S_AXI_BVALID),
			.S_AXI_BREADY(S_AXI_BREADY),
			.S_AXI_BID(   S_AXI_BID),
			.S_AXI_BRESP( S_AXI_BRESP),
			//
			.o_wb_cyc(  w_wb_cyc),
			.o_wb_stb(  w_wb_stb),
			.o_wb_addr( w_wb_addr),
			.o_wb_data( w_wb_data),
			.o_wb_sel(  w_wb_sel),
			.i_wb_ack(  w_wb_ack),
			.i_wb_stall(w_wb_stall),
			.i_wb_err(  w_wb_err)
		// }}}
		);
		// }}}
	end else begin : NO_WRITE_CHANNEL
		// {{{
		assign	w_wb_cyc  = 0;
		assign	w_wb_stb  = 0;
		assign	w_wb_addr = 0;
		assign	w_wb_data = 0;
		assign	w_wb_sel  = 0;
		assign	S_AXI_AWREADY = 0;
		assign	S_AXI_WREADY  = 0;
		assign	S_AXI_BVALID  = 0;
		assign	S_AXI_BRESP   = 2'b11;
		assign	S_AXI_BID     = 0;
		// }}}
	end endgenerate

	generate if (!OPT_WRITEONLY)
	begin : AXI_RD
		// {{{
		aximrd2wbsp #(
			// {{{
			.C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
			.C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
			.C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
			.OPT_SWAP_ENDIANNESS(OPT_SWAP_ENDIANNESS),
			.LGFIFO(LGFIFO)
			// }}}
		) axi_read_decoder(
			// {{{
			.S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
			//
			.S_AXI_ARVALID(S_AXI_ARVALID),
			.S_AXI_ARREADY(S_AXI_ARREADY),
			.S_AXI_ARID(   S_AXI_ARID),
			.S_AXI_ARADDR( S_AXI_ARADDR),
			.S_AXI_ARLEN(  S_AXI_ARLEN),
			.S_AXI_ARSIZE( S_AXI_ARSIZE),
			.S_AXI_ARBURST(S_AXI_ARBURST),
			.S_AXI_ARLOCK( S_AXI_ARLOCK),
			.S_AXI_ARCACHE(S_AXI_ARCACHE),
			.S_AXI_ARPROT( S_AXI_ARPROT),
			.S_AXI_ARQOS(  S_AXI_ARQOS),
			//
			.S_AXI_RVALID(S_AXI_RVALID),
			.S_AXI_RREADY(S_AXI_RREADY),
			.S_AXI_RID(   S_AXI_RID),
			.S_AXI_RDATA( S_AXI_RDATA),
			.S_AXI_RLAST( S_AXI_RLAST),
			.S_AXI_RRESP( S_AXI_RRESP),
			//
			.o_wb_cyc(  r_wb_cyc),
			.o_wb_stb(  r_wb_stb),
			.o_wb_addr( r_wb_addr),
			.o_wb_sel(  r_wb_sel),
			.i_wb_ack(  r_wb_ack),
			.i_wb_stall(r_wb_stall),
			.i_wb_data( i_wb_data),
			.i_wb_err(  r_wb_err)
			// }}}
		);
		// }}}
	end else begin : NO_READ_CHANNEL
		// {{{
		assign	r_wb_cyc  = 0;
		assign	r_wb_stb  = 0;
		assign	r_wb_addr = 0;
		//
		assign S_AXI_ARREADY = 0;
		assign S_AXI_RVALID  = 0;
		assign S_AXI_RID     = 0;
		assign S_AXI_RDATA   = 0;
		assign S_AXI_RLAST   = 0;
		assign S_AXI_RRESP   = 0;
		// }}}
	end endgenerate

	generate if (OPT_READONLY)
	begin : ARB_RD
		// {{{
		assign	o_wb_cyc  = r_wb_cyc;
		assign	o_wb_stb  = r_wb_stb;
		assign	o_wb_we   = r_wb_we;
		assign	o_wb_addr = r_wb_addr;
		assign	o_wb_data = 0;
		assign	o_wb_sel  = r_wb_sel;
		assign	r_wb_ack  = i_wb_ack;
		assign	r_wb_stall= i_wb_stall;
		assign	r_wb_ack  = i_wb_ack;
		assign	r_wb_err  = i_wb_err;
		// }}}
	end else if (OPT_WRITEONLY)
	begin : ARB_WR
		// {{{
		assign	o_wb_cyc  = w_wb_cyc;
		assign	o_wb_stb  = w_wb_stb;
		assign	o_wb_we   = w_wb_we;
		assign	o_wb_addr = w_wb_addr;
		assign	o_wb_data = w_wb_data;
		assign	o_wb_sel  = w_wb_sel;
		assign	w_wb_ack  = i_wb_ack;
		assign	w_wb_stall= i_wb_stall;
		assign	w_wb_ack  = i_wb_ack;
		assign	w_wb_err  = i_wb_err;
		// }}}
	end else begin : ARB_WB
		// {{{
		wbarbiter	#(.DW(DW), .AW(AW))
		readorwrite(S_AXI_ACLK, o_reset,
			r_wb_cyc, r_wb_stb, r_wb_we, r_wb_addr, w_wb_data, r_wb_sel,
				r_wb_ack, r_wb_stall, r_wb_err,
			w_wb_cyc, w_wb_stb, w_wb_we, w_wb_addr, w_wb_data, w_wb_sel,
				w_wb_ack, w_wb_stall, w_wb_err,
			o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, o_wb_sel,
				i_wb_ack, i_wb_stall, i_wb_err
			);
		// }}}
	end endgenerate

	assign	o_reset = (S_AXI_ARESETN == 1'b0);

`ifdef	FORMAL
`endif
endmodule
