`include "defs.svh" module rs232_tx #( PARITY = 0 , STOP_BITS = 2 , RTS_BITS = 3 ) ( input bit clock , input bit reset , output bit clock_busy , output bit out_ready , input bit out_valid , input uart_byte_t out_data , output bit rxd , input bit rts ); bit hold_valid; uart_byte_t hold; bit parity; assign clock_busy = hold_valid; (* syn_encoding = "one-hot" *) enum int unsigned { START , DATA , PARITY_BIT , STOP } state; bit [$clog2($bits(uart_byte_t)):0] data_bits; bit [$clog2(STOP_BITS):0] stop_bits; bit [RTS_BITS-1:0] rts_samples; bit old_rts; always @(posedge clock, posedge reset) begin if (reset) begin out_ready = 0; rxd = 1; hold_valid = 0; parity = PARITY; state = state.first; data_bits = 0; stop_bits = 0; rts_samples = 0; old_rts = 0; end else begin if (out_ready && out_valid) begin hold_valid = 1; hold = out_data; parity = PARITY; state = state.first; data_bits = 0; stop_bits = 0; end rts_samples = rts_samples << 1; rts_samples[0] = old_rts; if (hold_valid) begin case (state) START: begin if (rts_samples == 0) begin rxd = 0; state = state.next; end end DATA: begin rxd = hold[0]; hold = hold >> 1; parity = parity ^ rxd; if (data_bits == `UART_BYTE_BITS-1) state = state.next; else ++data_bits; end PARITY_BIT: begin rxd = parity; state = state.next; end STOP: begin rxd = 1; if (stop_bits == STOP_BITS-1) begin hold_valid = 0; state = state.next; end else begin ++stop_bits; end end endcase end else begin rxd = 1; end out_ready = !hold_valid; old_rts = rts; end end endmodule module rs232_rx #( PARITY = 0 , OVERSAMPLE = 0 ) ( input bit clock , input bit reset , input bit clock_busy , output bit clock_out , input bit in_ready , output bit in_valid , output uart_byte_t in_data , input bit txd , output bit cts ); (* syn_encoding = "one-hot" *) enum int unsigned { START , ALIGN , DATA , PARITY_BIT , STOP , REALSTOP } state; uart_byte_t buffer; bit [$clog2(`UART_BYTE_BITS):0] data_bits; bit parity; bit [$clog2(OVERSAMPLE+1):0] sample; bit [$clog2(OVERSAMPLE+1):0] clock_counter; bit [$clog2(OVERSAMPLE+1):0] next_clock_counter; bit old_txd; always @(posedge clock, posedge reset) begin if (reset) begin clock_out = 0; in_valid = 0; cts = 1; state = state.first; buffer = 0; data_bits = 0; parity = PARITY; sample = 0; clock_counter = 0; next_clock_counter = 0; old_txd = 0; end else begin automatic bit ok = 0; if (in_ready && in_valid) in_valid = 0; if (state == state.first || state == state.last) begin sample = 0; ok = 1; end else begin ++sample; if (sample > OVERSAMPLE) begin sample = 0; ok = 1; end end ++clock_counter; if (clock_counter > OVERSAMPLE) begin clock_out = 1; clock_counter = 0; end else begin clock_out = 0; end ++next_clock_counter; if (next_clock_counter > OVERSAMPLE) begin next_clock_counter = 0; if (!clock_busy) begin clock_out = 1; clock_counter = 0; end end if (ok) begin case (state) START: begin if (old_txd == 0) begin state = state.next; if (OVERSAMPLE == 0) state = state.next; sample = (OVERSAMPLE+1) / 2; buffer = 0; data_bits = 0; parity = PARITY; end end ALIGN: state = state.next; DATA: begin buffer = buffer >> 1; buffer[`UART_BYTE_BITS-1] = old_txd; parity = parity ^ old_txd; if (data_bits == `UART_BYTE_BITS-1) state = state.next; else ++data_bits; end PARITY_BIT: begin parity = parity ^ old_txd; state = state.next; end STOP: begin if (!in_valid && old_txd == 1 && parity == 0) begin in_valid = 1; in_data = buffer; end if (old_txd == 1 && parity == 0) begin next_clock_counter = (OVERSAMPLE+1)/2; end if (old_txd == 1) state = state.first; else state = state.next; end REALSTOP: begin if (old_txd == 1) state = state.first; end endcase end cts = !(state == state.first && !in_valid); old_txd = txd; end end endmodule