// 9-bit Serial port transmitter
// TX is high on idle.
// Baud rate is programmable via clk_divisor

`timescale 100 ps / 100 ps
module serial_tx (
		input  wire        clk,                	//      full-speed clock
		input  wire        rst,              	//      reset
		input  wire [8:0]  data,            	//      data to send
		input  wire [7:0]  clk_divisor,         //      defines baudrate
		input  wire 	   trigger,          	//      pulse to start transmission
		output wire 	   tx,         		//      tx serial connection
		output wire	   idle			//	1 if sender in idle state

	);

	reg	[2:0]	state;		//State of the state machine
	localparam STATE_IDLE		= 0;	//waiting for enable
	localparam STATE_STARTBIT	= 1;	//sending start bit
	localparam STATE_DATA		= 2;	//sending data
	localparam STATE_STOPBIT	= 3;	//sending stop bit
	localparam STATE_FINISH		= 4;	//finished

	reg	[4:0]	tx_ctr;			//counter of sent data words
	reg 	[7:0]	downctr;		//counter to generate baudrate
	reg	[8:0]	buffer;			//internal latch/shift register
	reg		reg_tx;

		//The state machine
	always @(posedge clk or posedge rst)
	begin 
		if (rst)
			state <= STATE_FINISH;
		else
			case(state)
				STATE_IDLE:
				begin
					if (trigger)
					begin
						state <= STATE_STARTBIT;
						tx_ctr <= 8;
						buffer <= data;
						downctr <= clk_divisor;
					end
				end
				STATE_STARTBIT:
				begin
					downctr = downctr - 1;
					if (downctr == 0)
					begin
						downctr <= clk_divisor;
						state <= STATE_DATA;
					end

				end
				STATE_DATA:
				begin
					downctr = downctr - 1;
					if (downctr == 0)
					begin
						downctr <= clk_divisor;
						tx_ctr <= tx_ctr - 1;
						buffer[7:0] <= buffer[8:1];
						buffer[8] <= 0;
						if (tx_ctr == 0)
							state <= STATE_STOPBIT;
					end
				end
				STATE_STOPBIT:
				begin
					downctr = downctr - 1;
					if (downctr == 0)
					begin
						downctr <= clk_divisor;
						state <= STATE_FINISH;
					end

				end
				STATE_FINISH:
				begin
					if (~trigger)
						state <= STATE_IDLE;
				end
				default:
					state <= STATE_FINISH;
			endcase
	end
	
		//tx assignment
	always @( * )
	begin
		if (rst)
			reg_tx = 1;
		else
			case(state)
				STATE_IDLE:
					reg_tx = 1;
				STATE_STARTBIT:
					reg_tx = 0;
				STATE_DATA:
					reg_tx = buffer[0];
				STATE_STOPBIT:
					reg_tx = 1;
				STATE_FINISH:
					reg_tx = 1;
				default:
					reg_tx = 1;
			endcase
	end
	assign tx = reg_tx;

		//idle assignment
	assign idle = (state == STATE_IDLE) ? 1 : 0;

endmodule
