//---------------------------------------------------------------------------------------
// uart transmit module  
//
//---------------------------------------------------------------------------------------

module uart_tx  
(
	clock, reset,
	ce_16, tx_data, new_tx_data, 
	ser_out, tx_busy
);
//---------------------------------------------------------------------------------------
// modules inputs and outputs 
input 			clock;			// global clock input 
input 			reset;			// global reset input 
input			ce_16;			// baud rate multiplyed by 16 - generated by baud module 
input	[7:0]	tx_data;		// data byte to transmit 
input			new_tx_data;	// asserted to indicate that there is a new data byte for transmission 
output			ser_out;		// serial data output 
output 			tx_busy;		// signs that transmitter is busy 

// internal wires 
wire ce_1;		// clock enable at bit rate 

// internal registers 
reg ser_out;
reg tx_busy;
reg [3:0]	count16;
reg [3:0]	bit_count;
reg [8:0]	data_buf;
//---------------------------------------------------------------------------------------
// module implementation 
// a counter to count 16 pulses of ce_16 to generate the ce_1 pulse 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		count16 <= 4'b0;
	else if (tx_busy & ce_16)
		count16 <= count16 + 4'b1;
	else if (~tx_busy)
		count16 <= 4'b0;
end 

// ce_1 pulse indicating output data bit should be updated 
assign ce_1 = (count16 == 4'b1111) & ce_16;

// tx_busy flag 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		tx_busy <= 1'b0;
	else if (~tx_busy & new_tx_data)
		tx_busy <= 1'b1;
	else if (tx_busy & (bit_count == 4'h9) & ce_1)
		tx_busy <= 1'b0;
end 

// output bit counter 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		bit_count <= 4'h0;
	else if (tx_busy & ce_1)
		bit_count <= bit_count + 4'h1;
	else if (~tx_busy) 
		bit_count <= 4'h0;
end 

// data shift register 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		data_buf <= 9'b0;
	else if (~tx_busy)
		data_buf <= {tx_data, 1'b0};
	else if (tx_busy & ce_1)
		data_buf <= {1'b1, data_buf[8:1]};
end 

// output data bit 
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		ser_out <= 1'b1;
	else if (tx_busy)
		ser_out <= data_buf[0];
	else 
		ser_out <= 1'b1;
end 

endmodule
//---------------------------------------------------------------------------------------
//						Th.. Th.. Th.. Thats all folks !!!
//---------------------------------------------------------------------------------------
