module UART(BCLK, BRESET, UART_RD, UART_WR, DIN, UA_RX, UA_TX, UART_Q, UA_INT);

	input			BCLK;
	input			BRESET;
	input			UART_RD;
	input	 [1:0]	UART_WR;
	input	[15:0]	DIN;
 
	output			UA_TX;
	input			UA_RX;
 
	output	[31:0]	UART_Q;
	output			UA_INT;
 
	reg		 [1:0]	iena;	// Interrupt enable
	
	parameter baudrate = 10'd867;	// 57600 Baud : 868 clocks of 20ns
	
	// +++++++++++++++++++++++++++++++ Transmitter +++++++++++++++++++++++++++++++++
 
	reg		 [8:0]	shifter_tx;
	reg		 [3:0]	txbits;
	reg		 [9:0]	txtimer;
	reg				tx_int;
	reg				trold;
	
	wire			tx_load,tx_run,tx_shift;
 
	assign tx_load = UART_WR[0] & ~tx_run; // no Write during transmisson
 
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) shifter_tx <= 9'h1FF;
			else
				if (tx_load) shifter_tx <= {DIN[7:0],1'b0};
					else
						if (tx_shift) shifter_tx <= {1'b1,shifter_tx[8:1]}; // LSB first to send
    
	assign UA_TX = shifter_tx[0];
 
	// ---1__2_one_3_two_4_three_5_four_6_five_7_six_8_seven_9_eight_10---11
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) txbits <= 4'd0;
			else
				if (tx_load) txbits <= 4'd1;
					else
						if (tx_shift) txbits <= (txbits == 4'd10) ? 4'd0 : txbits + 4'd1;
      
	assign tx_run = |txbits;
	always @(posedge BCLK) trold <= tx_run;
 
	always @(posedge BCLK) txtimer <= (~tx_run | tx_shift) ? 10'd0 : txtimer + 10'd1;
 
	assign tx_shift = (txtimer == baudrate);

	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) tx_int <= 1'b0;
			else	
				if (tx_load) tx_int <= 1'b0;
					else
						if (UART_WR[1]) tx_int <= DIN[13];
							else
								if (!tx_run && trold) tx_int <= 1'b1;

	// +++++++++++++++++++++++++++++++ Receiver +++++++++++++++++++++++++++++++++
 
	reg		 [2:0]	inshift;
	reg		 [3:0]	rxbits;
	reg		 [8:0]	shifter_rx;
	reg		 [9:0]	rxtimer;
	reg		 [7:0]	rxhold;
	reg				inbit,oldin;
	reg				rx_int;
	reg				rx_end;
 
	wire			rx_go,rx_shift,rx_run;
 
	always @(posedge BCLK) inshift <= {inshift[1:0],UA_RX};
	
	always @(posedge BCLK) inbit <= (inshift == 3'b111) ? 1'b1 : (inshift == 3'd0) ? 1'b0 : inbit;

	always @(posedge BCLK) oldin <= inbit;
 
	assign rx_go = ~inbit & oldin & (rxbits == 4'd0);

	// --1_2__3one_4two_5three_6four_7five_8six_9seven_10eight_-11--
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) rxbits <= 4'd0;
			else
				if (rx_go) rxbits <= 4'd1;
					else
						if (rx_shift) rxbits <= (((rxbits == 4'd1) & inbit) | (rxbits == 4'd10)) ? 4'd0 : rxbits + 4'd1;
      
	always @(posedge BCLK) if (rx_shift) shifter_rx <= {inbit,shifter_rx[8:1]};
  
	always @(posedge BCLK) rxtimer <= (~rx_run | rx_shift) ? 10'd0 : rxtimer + 10'd1;
 
	assign rx_shift = (rxtimer == ((rxbits == 4'd1) ? {1'b0,baudrate[9:1]} : baudrate));
	assign rx_run = |rxbits;
 
	always @(posedge BCLK) rx_end <= rx_shift & (rxbits == 4'd10) & inbit; // Stopbit must be "1"
 
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) rx_int <= 1'b0;
			else	
				if (UART_RD) rx_int <= 1'b0;
					else
						if (UART_WR[1]) rx_int <= DIN[10];
							else
								if (rx_end) rx_int <= 1'b1;
    
	always @(posedge BCLK) if (rx_end) rxhold <= shifter_rx[7:0]; // hold received data
      
	assign UART_Q = {18'd0,tx_int,iena[1],tx_run,rx_int,iena[0],rx_run,rxhold};
 
	// +++++++++++++++++++++++++++++++ Interrupt +++++++++++++++++++++++++++++++++
	
	always @(posedge BCLK or negedge BRESET)
		if (!BRESET) iena <= 2'd0;
			else
				if (UART_WR[1]) iena <= {DIN[12],DIN[9]};

	assign UA_INT = (tx_int & iena[1]) | (rx_int & iena[0]);
	
endmodule