`timescale 1ns / 1ps
//-------------------------------------------------------
// File name    : uart_mm.v
// Title        : Memory-mapped UART (โครงร่างย่อ)
// Library      : RISC-V SoC, ตัวอย่างประกอบบทที่ 9
// Purpose      : Computer Architecture, Design and Verification
// Developers   : Krerk Piromsopa, Ph.D.
//              : Chulalongkorn University.
module uart_mm(
    // bus interface (memory-mapped)
    input         clk,
    input         nreset,
    input  [3:0]  addr,        // register offset
    input  [31:0] wdata,
    input         we,
    output reg [31:0] rdata,
    // serial interface
    output        tx,
    input         rx,
    // interrupt to PLIC
    output        irq
);
    // internal registers
    reg [7:0]  tx_data;
    reg [7:0]  rx_data;
    reg        tx_ready;       // 1 = สามารถรับตัวอักษรใหม่ได้
    reg        rx_ready;       // 1 = มีตัวอักษรใหม่รอใน rx_data
    reg        tx_int_en;
    reg        rx_int_en;

    // อ่าน register
    always @(*) begin
        case (addr)
            4'h0: rdata = {24'b0, tx_data};                  // TXDATA
            4'h4: rdata = {24'b0, rx_data};                  // RXDATA
            4'h8: rdata = {30'b0, rx_ready, tx_ready};       // STATUS
            4'hC: rdata = {30'b0, rx_int_en, tx_int_en};     // CTRL
            default: rdata = 32'b0;
        endcase
    end

    // เขียน register
    always @(posedge clk) begin
        if (nreset == 0) begin
            tx_data    <= 8'h00;
            tx_ready   <= 1'b1;
            rx_ready   <= 1'b0;
            tx_int_en  <= 1'b0;
            rx_int_en  <= 1'b0;
        end else if (we) begin
            case (addr)
                4'h0: begin
                    tx_data  <= wdata[7:0];
                    tx_ready <= 1'b0;       // ส่งกำลังดำเนินการ
                end
                4'hC: begin
                    tx_int_en <= wdata[0];
                    rx_int_en <= wdata[1];
                end
            endcase
        end
        // ในความเป็นจริง tx_ready จะถูกเซ็ตเมื่อ shift register ส่งจบ
        // และ rx_ready จะถูกเซ็ตเมื่อ shift register รับจบ
        // โค้ดของ baud rate generator และ shift register ตัดออกเพื่อความกระชับ
    end

    // interrupt: ส่งเมื่อบิตที่เกี่ยวข้องเปิดและสถานะตรงเงื่อนไข
    assign irq = (rx_int_en & rx_ready) | (tx_int_en & tx_ready);

    // tx (placeholder; ของจริงต้อง serialize)
    assign tx = 1'b1;
endmodule
