`timescale 1ns / 1ps

`include "src/fifo.v"
`include "src/rmii/rmii_serializer.v"

module rmii_transmit_controller #(
	parameter FIFO_DEPTH = 16,
	parameter STORAGE_WIDTH = 8,
	
	// AUTOCALCULATED
	parameter STORAGE_MSB = STORAGE_WIDTH - 1,
	parameter SHIFT_COUNT = FIFO_DEPTH
)(
	input clk, rst, clear, // general signals
	input REF_pulse, // pulse that signals the coming rising edge on REF_CLK
	
	/* FIFO signals */
	input [STORAGE_MSB:0] data_in, // input data
	input wrt, // store the data
	output not_full, // the internal buffer is not full
	
	/* RMII signals */
	output reg TXEN, // transmit enable
	output [1:0] TXD, // transmit data
	
	output busy // there's an ongoing transmission
);

/* TX FIFO and its signals */
wire tx_fifo_empty;
wire tx_fifo_out_valid;
wire tx_fifo_full;
wire [STORAGE_WIDTH-1:0]tx_fifo_out;
wire tx_fifo_pop = oser_empty && REF_pulse;

fifo #(
	.DEPTH(FIFO_DEPTH),
	.WIDTH(STORAGE_WIDTH)
) tx_fifo (
	.clk(clk),
	.rst(rst),
	.clear(clear),
	
	.empty(tx_fifo_empty),
	.out_valid(tx_fifo_out_valid),
	.full(tx_fifo_full),
	
	.in(data_in),
	.push(wrt),
	
	.out(tx_fifo_out),
	.pop(tx_fifo_pop)
);

assign not_full = !tx_fifo_full;

/* output serializer */

wire oser_load = tx_fifo_out_valid;
wire oser_empty;

rmii_serializer #(
	.STORE_SIZE(STORAGE_WIDTH),
	.DIR(0) // LEFT
) out_serializer (
	.clk(clk),
	.rst(rst),
	.clear(clear),
	
	.par_in(tx_fifo_out),
	.ser_out(TXD),
	.load(oser_load),
	.shift(REF_pulse),
	.empty(oser_empty)
);

/* TXEN control */
always @(posedge clk)
begin
	if (rst | clear)
	begin
		TXEN <= 0;
	end
	else
	begin
		if (oser_load) // assert the same time the shift register loading occurs
		begin
			TXEN <= 1;
		end
		else if (REF_pulse && oser_empty && tx_fifo_empty) // deassert only when all buffers has depleted
		begin
			TXEN <= 0;
		end
	end
end

assign busy = TXEN;

endmodule
