module rx_port_requester_mux (
	input RST,
	input CLK,
	
	input SG_RX_REQ,				// Scatter gather RX read request
	input [9:0] SG_RX_LEN,			// Scatter gather RX read request length
	input [63:0] SG_RX_ADDR,		// Scatter gather RX read request address
	output SG_RX_REQ_PROC,			// Scatter gather RX read request processing

	input SG_TX_REQ,				// Scatter gather TX read request
	input [9:0] SG_TX_LEN,			// Scatter gather TX read request length
	input [63:0] SG_TX_ADDR,		// Scatter gather TX read request address
	output SG_TX_REQ_PROC,			// Scatter gather TX read request processing
	
	input MAIN_REQ,					// Main read request
	input [9:0] MAIN_LEN,			// Main read request length
	input [63:0] MAIN_ADDR,			// Main read request address
	output MAIN_REQ_PROC,			// Main read request processing

	output RX_REQ,					// Read request
	input RX_REQ_ACK,				// Read request accepted
	output [1:0] RX_REQ_TAG,		// Read request data tag 
	output [63:0] RX_REQ_ADDR,		// Read request address
	output [9:0] RX_REQ_LEN,		// Read request length

	output REQ_ACK					// Request accepted
);

reg									rRxReqAck=0, _rRxReqAck=0;

(* syn_encoding = "user" *)
(* fsm_encoding = "user" *)
reg		[1:0]						rState=`S_RXPORTREQ_RX_TX, _rState=`S_RXPORTREQ_RX_TX;
reg		[9:0]						rLen=0, _rLen=0;
reg		[63:0]						rAddr=64'd0, _rAddr=64'd0;
reg									rSgRxAck=0, _rSgRxAck=0;
reg									rSgTxAck=0, _rSgTxAck=0;
reg									rMainAck=0, _rMainAck=0;
reg									rAck=0, _rAck=0;


assign SG_RX_REQ_PROC = rSgRxAck;
assign SG_TX_REQ_PROC = rSgTxAck;
assign MAIN_REQ_PROC = rMainAck;

assign RX_REQ = rState[1]; // S_RXPORTREQ_ISSUE
assign RX_REQ_TAG = {rSgTxAck, rSgRxAck};
assign RX_REQ_ADDR = rAddr;
assign RX_REQ_LEN = rLen;

assign REQ_ACK = rAck;


// Buffer signals that come from outside the rx_port.
always @ (posedge CLK) begin
	rRxReqAck <= #1 (RST ? 1'd0 : _rRxReqAck);
end

always @ (*) begin
	_rRxReqAck = RX_REQ_ACK;
end


// Handle issuing read requests. Scatter gather requests are processed
// with higher priority than the main channel.
always @ (posedge CLK) begin
	rState <= #1 (RST ? `S_RXPORTREQ_RX_TX : _rState);
	rLen <= #1 _rLen;
	rAddr <= #1 _rAddr;
	rSgRxAck <= #1 _rSgRxAck;
	rSgTxAck <= #1 _rSgTxAck;
	rMainAck <= #1 _rMainAck;
	rAck <= #1 _rAck;
end

always @ (*) begin
	_rState = rState;
	_rLen = rLen;
	_rAddr = rAddr;
	_rSgRxAck = rSgRxAck;
	_rSgTxAck = rSgTxAck;
	_rMainAck = rMainAck;
	_rAck = rAck;
	case (rState)

	`S_RXPORTREQ_RX_TX: begin // Wait for a new read request
		if (SG_RX_REQ) begin
			_rLen = SG_RX_LEN;
			_rAddr = SG_RX_ADDR;
			_rSgRxAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else if (SG_TX_REQ) begin
			_rLen = SG_TX_LEN;
			_rAddr = SG_TX_ADDR;
			_rSgTxAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else if (MAIN_REQ) begin
			_rLen = MAIN_LEN;
			_rAddr = MAIN_ADDR;
			_rMainAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else begin
			_rState = `S_RXPORTREQ_TX_RX;
		end
	end

	`S_RXPORTREQ_TX_RX: begin // Wait for a new read request
		if (SG_TX_REQ) begin
			_rLen = SG_TX_LEN;
			_rAddr = SG_TX_ADDR;
			_rSgTxAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else if (SG_RX_REQ) begin
			_rLen = SG_RX_LEN;
			_rAddr = SG_RX_ADDR;
			_rSgRxAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else if (MAIN_REQ) begin
			_rLen = MAIN_LEN;
			_rAddr = MAIN_ADDR;
			_rMainAck = 1;
			_rAck = 1;
			_rState = `S_RXPORTREQ_ISSUE;
		end
		else begin
			_rState = `S_RXPORTREQ_RX_TX;
		end
	end

	`S_RXPORTREQ_ISSUE: begin // Issue the request
		_rAck = 0;
		if (rRxReqAck) begin
			_rSgRxAck = 0;
			_rSgTxAck = 0;
			_rMainAck = 0;
			if (rSgRxAck)
				_rState = `S_RXPORTREQ_TX_RX;
			else
				_rState = `S_RXPORTREQ_RX_TX;
		end
	end

	default: begin
		_rState = `S_RXPORTREQ_RX_TX;
	end

	endcase
end

endmodule