| `default_nettype none |
| |
| // ============================================================================ |
| |
| module message_formatter # |
| ( |
| parameter WIDTH = 24, // Word length in bits. MUST be a multiply of 4 |
| parameter COUNT = 2, // Word count |
| parameter TX_INTERVAL = 4 // Character transmission interval |
| ) |
| ( |
| // Clock and reset |
| input wire CLK, |
| input wire RST, |
| |
| // Data input |
| input wire I_STB, |
| input wire [(WIDTH*COUNT)-1:0] I_DAT, |
| |
| // ASCII output |
| output wire O_STB, |
| output wire [7:0] O_DAT |
| ); |
| |
| // ============================================================================ |
| |
| // Total input data word width |
| localparam TOTAL_WIDTH = WIDTH * COUNT; |
| |
| // ============================================================================ |
| // FSM states |
| integer fsm; |
| |
| localparam FSM_IDLE = 'h00; |
| localparam FSM_TX_HEX = 'h11; |
| localparam FSM_TX_CR = 'h21; |
| localparam FSM_TX_LF = 'h22; |
| localparam FSM_TX_SEP = 'h31; |
| |
| // ============================================================================ |
| // TX interval counter |
| reg [24:0] tx_dly_cnt; |
| reg tx_req; |
| wire tx_rdy; |
| |
| always @(posedge CLK) |
| if (RST) |
| tx_dly_cnt <= -1; |
| else if (!tx_rdy) |
| tx_dly_cnt <= tx_dly_cnt - 1; |
| else if ( tx_rdy && tx_req) |
| tx_dly_cnt <= TX_INTERVAL - 2; |
| |
| assign tx_rdy = tx_dly_cnt[24]; |
| |
| always @(posedge CLK) |
| if (RST) |
| tx_req <= 1'b0; |
| else case (fsm) |
| |
| FSM_TX_HEX: tx_req <= 1'b1; |
| FSM_TX_SEP: tx_req <= 1'b1; |
| FSM_TX_CR: tx_req <= 1'b1; |
| FSM_TX_LF: tx_req <= 1'b1; |
| |
| default: tx_req <= 1'b0; |
| |
| endcase |
| |
| // ============================================================================ |
| // Word and char counter |
| reg [7:0] char_cnt; |
| reg [7:0] word_cnt; |
| |
| always @(posedge CLK) |
| if (fsm == FSM_IDLE || fsm == FSM_TX_SEP) |
| char_cnt <= (WIDTH/4) - 1; |
| else if (tx_rdy && fsm == FSM_TX_HEX) |
| char_cnt <= char_cnt - 1; |
| |
| always @(posedge CLK) |
| if (fsm == FSM_IDLE) |
| word_cnt <= COUNT - 1; |
| else if (tx_rdy && fsm == FSM_TX_SEP) |
| word_cnt <= word_cnt - 1; |
| |
| // ============================================================================ |
| // Data shift register |
| reg [TOTAL_WIDTH-1:0] sr_reg; |
| wire [3:0] sr_dat; |
| |
| always @(posedge CLK) |
| if (fsm == FSM_IDLE && I_STB) |
| sr_reg <= I_DAT; |
| else if (fsm == FSM_TX_HEX && tx_rdy) |
| sr_reg <= sr_reg << 4; |
| |
| assign sr_dat = sr_reg[TOTAL_WIDTH-1:TOTAL_WIDTH-4]; |
| |
| // ============================================================================ |
| // Control FSM |
| always @(posedge CLK) |
| if (RST) |
| fsm <= FSM_IDLE; |
| else case (fsm) |
| |
| FSM_IDLE: if (I_STB) fsm <= FSM_TX_HEX; |
| |
| FSM_TX_HEX: |
| if (tx_rdy && (char_cnt == 0) && (word_cnt == 0)) |
| fsm <= FSM_TX_CR; |
| else if (tx_rdy && (char_cnt == 0)) fsm <= FSM_TX_SEP; |
| else if (tx_rdy && (char_cnt != 0)) fsm <= FSM_TX_HEX; |
| |
| FSM_TX_SEP: if (tx_rdy) fsm <= FSM_TX_HEX; |
| FSM_TX_CR: if (tx_rdy) fsm <= FSM_TX_LF; |
| FSM_TX_LF: if (tx_rdy) fsm <= FSM_IDLE; |
| |
| endcase |
| |
| // ============================================================================ |
| // Data to ASCII converter |
| reg o_stb; |
| reg [7:0] o_dat; |
| |
| always @(posedge CLK or posedge RST) |
| if (RST) |
| o_stb <= 1'd0; |
| else |
| o_stb <= tx_req & tx_rdy; |
| |
| always @(posedge CLK) |
| if (fsm == FSM_TX_CR) |
| o_dat <= 8'h0D; |
| else if (fsm == FSM_TX_LF) |
| o_dat <= 8'h0A; |
| else if (fsm == FSM_TX_SEP) |
| o_dat <= "_"; |
| else if (fsm == FSM_TX_HEX) case (sr_dat) |
| 4'h0: o_dat <= "0"; |
| 4'h1: o_dat <= "1"; |
| 4'h2: o_dat <= "2"; |
| 4'h3: o_dat <= "3"; |
| 4'h4: o_dat <= "4"; |
| 4'h5: o_dat <= "5"; |
| 4'h6: o_dat <= "6"; |
| 4'h7: o_dat <= "7"; |
| 4'h8: o_dat <= "8"; |
| 4'h9: o_dat <= "9"; |
| 4'hA: o_dat <= "A"; |
| 4'hB: o_dat <= "B"; |
| 4'hC: o_dat <= "C"; |
| 4'hD: o_dat <= "D"; |
| 4'hE: o_dat <= "E"; |
| 4'hF: o_dat <= "F"; |
| endcase |
| |
| assign O_STB = o_stb; |
| assign O_DAT = o_dat; |
| |
| endmodule |