Advertisement
AquaBlitz11

uart_tx.sv

Mar 5th, 2025
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. `default_nettype none
  2.  
  3. /*
  4. 8N1 UART transmitter.
  5. Takes in only one byte at a time.
  6. */
  7. module uart_tx #(
  8.     parameter CLOCK_FREQ_HZ = 0,
  9.     parameter BAUD_RATE = 0
  10. ) (
  11.     // axi inputs
  12.     input wire s_axis_aclk,
  13.     input wire s_axis_aresetn,
  14.     input wire s_axis_tvalid,
  15.     input wire [7:0] s_axis_tdata,
  16.     output logic s_axis_tready,
  17.     // uart outputs
  18.     output logic tx_bit
  19. );
  20.  
  21.   /// ---
  22.   /// cycle counter to generate baud rate
  23.   /// ---
  24.  
  25.   localparam UART_CYCLES = CLOCK_FREQ_HZ / BAUD_RATE;
  26.   localparam UART_CYCLES_BITS = $clog2(UART_CYCLES);
  27.  
  28.   logic [UART_CYCLES_BITS-1:0] uart_cycles;
  29.  
  30.   always_ff @(posedge s_axis_aclk) begin
  31.     if (end_of_cycle || do_latch_data) uart_cycles <= 0;
  32.     else uart_cycles <= uart_cycles + 1;
  33.   end
  34.  
  35.   logic end_of_cycle;
  36.   assign end_of_cycle = uart_cycles == UART_CYCLES - 1;
  37.  
  38.   /// ---
  39.   /// UART state machine
  40.   /// ---
  41.  
  42.   typedef enum {
  43.     IDLE,
  44.     START,
  45.     DATA,
  46.     STOP
  47.   } state_t;
  48.  
  49.   state_t state = IDLE;
  50.   always_ff @(posedge s_axis_aclk) begin
  51.     state <= next_state;
  52.     if (s_axis_aresetn == 0) state <= IDLE;
  53.   end
  54.  
  55.   state_t next_state;
  56.   always_comb begin
  57.     next_state = state;
  58.     case (state)
  59.       IDLE: begin
  60.         if (do_latch_data) next_state = START;
  61.       end
  62.       START: begin
  63.         if (end_of_cycle) next_state = DATA;
  64.       end
  65.       DATA: begin
  66.         if (end_of_cycle && data_counter == 7) next_state = STOP;
  67.       end
  68.       STOP: begin
  69.         if (end_of_cycle) next_state = IDLE;
  70.       end
  71.     endcase
  72.   end
  73.  
  74.   /// ---
  75.   /// DATA state counter
  76.   /// only used when state == DATA; otherwise the value is meaningless
  77.   /// resets to 0 upon entering DATA
  78.   /// increments by one at the end of each uart cycle
  79.   /// ---
  80.  
  81.   logic [3:0] data_counter;
  82.  
  83.   always_ff @(posedge s_axis_aclk) begin
  84.     if (state != next_state && next_state == DATA) begin
  85.       data_counter <= 0;
  86.     end
  87.  
  88.     if (state == DATA && end_of_cycle) begin
  89.       data_counter <= data_counter + 1;
  90.     end
  91.   end
  92.  
  93.   /// ---
  94.   /// AXI ready signal
  95.   /// ---
  96.  
  97.   assign s_axis_tready = state == IDLE;
  98.  
  99.   /// ---
  100.   /// AXI txn logic: whether to latch data or not
  101.   /// ---
  102.  
  103.   logic do_latch_data;
  104.   assign do_latch_data = s_axis_tvalid && s_axis_tready;
  105.  
  106.   /// ---
  107.   /// latches data when txn occurs or shifts right at the end of each data cycle
  108.   /// ---
  109.  
  110.   logic [7:0] data_latched;
  111.  
  112.   always_ff @(posedge s_axis_aclk) begin
  113.     if (do_latch_data) begin
  114.       data_latched <= s_axis_tdata;
  115.     end
  116.  
  117.     if (state == DATA && end_of_cycle) begin
  118.       data_latched <= data_latched >> 1;
  119.     end
  120.   end
  121.  
  122.   /// ---
  123.   /// output bit
  124.   /// ---
  125.  
  126.   localparam IDLE_BIT = 1'b1;
  127.   localparam START_BIT = 1'b0;
  128.   localparam STOP_BIT = 1'b1;
  129.  
  130.   always_comb begin
  131.     case (state)
  132.       IDLE:  tx_bit = IDLE_BIT;
  133.       START: tx_bit = START_BIT;
  134.       DATA:  tx_bit = data_latched[0];
  135.       STOP:  tx_bit = STOP_BIT;
  136.     endcase
  137.   end
  138.  
  139. endmodule
  140.  
  141. `default_nettype wire
  142.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement