module uartmm(input clk,
              input         rst,

              input         RX,
              output        TX,
              
              output [31:0] data_b,
              output reg    strobe_b,
              input [31:0]  addr_b,
              input [31:0]  data_b_in,
              input [31:0]  data_b_we);

   wire                 uart_RXD;
   inpin _rcxd(.clk(clk), .pin(RX), .rd(uart_RXD));


   reg                  qin_we, qin_re, qout_we, qout_re;
   wire                 qout_oready, qin_oready;
   
   wire [7:0]           qin_idata;
   reg [7:0]            qout_idata;
   wire [7:0]           qin_wdata;
   wire [7:0]           qout_wdata;
   wire                 uart_valid, uart_busy;

   // Insert the byte incoming from mm port 65539 into the uart output queue, if
   //  queue is not full.
   always @(posedge clk)
     if (!rst) begin
        qout_we <= 0;
        qout_idata <= 0;
     end else
     if (qout_we) begin
        qout_we <= 0;
     end else if ((addr_b == 65539) & data_b_we &
                  !qin_full) begin
        qout_idata <= data_b[7:0];
        qout_we <= 1;
     end

   // If uart is ready to transmit and the output queue is not empty, send one byte
   always @(posedge clk)
     if (!rst) qout_re <= 0;
     else if (qout_re) begin
        qout_re <= 0;
     end
     else if (qout_oready & !uart_busy) begin
        qout_re <= 1;
     end

   // If uart has a valid output, push it into the input queue
   always @(posedge clk)
     if (!rst) begin
        qin_we <= 0;
     end else if (qin_we) begin
        qin_we <= 0;
     end else if (uart_valid & !qin_full) begin
        qin_we <= 1;
     end

   reg cmd;
   wire addr_b_cmd =
        (addr_b == 65539);

   reg  out_tmp;
   assign data_b = cmd?{24'b0,qin_wdata}:{30'b0,out_tmp};
   
   // Manage the output
   always @(posedge clk)
     if (!rst) begin
        cmd <= 0;
        qin_re <= 0;
        out_tmp <= 0;
        strobe_b <= 0;
     end else begin
        cmd <= addr_b_cmd;
        if (qin_re) qin_re <= 0;
        else  if ((addr_b == 65539) & qin_oready) begin // UART DATA IN
           qin_re <= 1;
           strobe_b <= 1;
        end else if (addr_b == 65537) begin // UART IN READY
           out_tmp <= qin_oready;
           strobe_b <= 1;
        end else if (addr_b == 65538) begin // UART OUT READY
           out_tmp <= !qout_full;
           strobe_b <= 1;
        end else strobe_b <= 0;
     end

   // Modules
   delayqueue _qin (.clk(clk),
                    .rst(rst),

                    .we(qin_we),
                    .idata(qin_idata),

                    .re(qin_re),
                    .wdata(qin_wdata),
                    .oready(qin_oready),
                    .full(qin_full));

   delayqueue _qout (.clk(clk),
                    .rst(rst),

                    .we(qout_we),
                    .idata(qout_idata),

                    .re(qout_re),
                    .wdata(qout_wdata),
                    .oready(qout_oready),
                    .full(qout_full));
   
   buart _uart (
                .clk(clk),
                .resetq(rst),
                .rx(uart_RXD),
                .tx(TX),
                .rd(qin_we),
                .wr(qout_re),
                .valid(uart_valid),
                .busy(uart_busy),
                .tx_data(qout_wdata),
                .rx_data(qin_idata));

endmodule