//---------------------------------------------------------------------------
// Wishbone UART 
//
// Register Description:
//
//    0x00 UCR      [ 0 | 0 | 0 | tx_busy | 0 | 0 | rx_error | rx_avail ]
//    0x04 DATA
//
//---------------------------------------------------------------------------

module wb_uart #(
	parameter          clk_freq = 50000000,
	parameter          baud     = 115200
) (
	input              clk,
	input              reset,
	// Wishbone interface
	input              wb_stb_i,
	input              wb_cyc_i,
	output             wb_ack_o,
	input              wb_we_i,
	input       [31:0] wb_adr_i,
	input        [3:0] wb_sel_i,
	input       [31:0] wb_dat_i,
	output reg  [31:0] wb_dat_o,
	// Serial Wires
	input              uart_rxd,
	output             uart_txd
);

//---------------------------------------------------------------------------
// Actual UART engine
//---------------------------------------------------------------------------
wire [7:0] rx_data;
wire       rx_avail;
wire       rx_error;
reg        rx_ack;
wire [7:0] tx_data;
reg        tx_wr;
wire       tx_busy;

uart #(
	.freq_hz(   clk_freq ),
	.baud(      baud     )
) uart0 (
	.clk(       clk      ),
	.reset(     reset    ),
	//
	.uart_rxd(  uart_rxd ),
	.uart_txd(  uart_txd ),
	//
	.rx_data(   rx_data  ),
	.rx_avail(  rx_avail ),
	.rx_error(  rx_error ),
	.rx_ack(    rx_ack   ),
	.tx_data(   tx_data  ),
	.tx_wr(     tx_wr    ),
	.tx_busy(   tx_busy  )
);

//---------------------------------------------------------------------------
// 
//---------------------------------------------------------------------------
wire [7:0] ucr = { 3'b0, tx_busy, 2'b0, rx_error, rx_avail };

wire wb_rd = wb_stb_i & wb_cyc_i & ~wb_we_i;
wire wb_wr = wb_stb_i & wb_cyc_i &  wb_we_i & wb_sel_i[0];

reg  ack;

assign wb_ack_o       = wb_stb_i & wb_cyc_i & ack;

assign tx_data = wb_dat_i[7:0];

always @(posedge clk)
begin
	if (reset) begin
		wb_dat_o[31:8] <= 24'b0;
		tx_wr  <= 0;
		rx_ack <= 0;
		ack    <= 0;
	end else begin
		wb_dat_o[31:8] <= 24'b0;
		tx_wr  <= 0;
		rx_ack <= 0;
		ack    <= 0;

		if (wb_rd & ~ack) begin
			ack <= 1;

			case (wb_adr_i[3:2])
			2'b00: begin
				wb_dat_o[7:0] <= ucr;
			end
			2'b01: begin
				wb_dat_o[7:0] <= rx_data;
				rx_ack        <= 1;
			end
			default: begin
				wb_dat_o[7:0] <= 8'b0;
			end
			endcase
		end else if (wb_wr & ~ack ) begin
			ack <= 1;

			if ((wb_adr_i[3:2] == 2'b01) && ~tx_busy) begin
				tx_wr <= 1;
			end
		end
	end
end


endmodule