`include "defs.svh" module rs232_tx #( PARITY = 0 , STOP_BITS = 2 , CTS_BITS = 3 ) ( input bit clock , input bit reset , output bit out_ready , input bit out_valid , input uart_byte_t out_data , output bit tx , input bit cts ); bit hold_valid; uart_byte_t hold; bit parity; (* 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 [CTS_BITS-1:0] cts_samples; always @(posedge clock, posedge reset) begin if (reset) begin out_ready = 0; tx = 1; hold_valid = 0; parity = PARITY; state = state.first; data_bits = 0; stop_bits = 0; cts_samples = 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 cts_samples = cts_samples << 1; cts_samples[0] = cts; if (hold_valid) begin case (state) START: begin if (cts_samples == 0) begin tx = 0; state = state.next; end end DATA: begin tx = hold[0]; hold = hold >> 1; parity = parity ^ tx; if (data_bits == `UART_BYTE_BITS-1) state = state.next; else ++data_bits; end PARITY_BIT: begin tx = parity; state = state.next; end STOP: begin tx = 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 tx = 1; end out_ready = !hold_valid; end end endmodule module rs232_rx #( PARITY = 0 , OVERSAMPLE = 0 ) ( input bit clock , input bit reset , output bit clock_out , input bit in_ready , output bit in_valid , output uart_byte_t in_data , input bit rx , output bit rts ); (* 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)+2:0] sample; bit [$clog2(OVERSAMPLE+1):0] clock_counter; always @(posedge clock, posedge reset) begin if (reset) begin clock_out = 0; in_valid = 0; rts = 1; state = state.first; buffer = 0; data_bits = 0; parity = PARITY; sample = 0; clock_counter = 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 if (ok) begin case (state) START: begin if (rx == 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] = rx; parity = parity ^ rx; if (data_bits == `UART_BYTE_BITS-1) state = state.next; else ++data_bits; end PARITY_BIT: begin parity = parity ^ rx; state = state.next; end STOP: begin if (!in_valid && rx == 1 && parity == 0) begin in_valid = 1; in_data = buffer; end if (rx == 1 && parity == 0) begin clock_counter = (OVERSAMPLE+1)/2; end if (rx == 1) state = state.first; else state = state.next; end REALSTOP: begin if (rx == 1) state = state.first; end endcase end rts = !(state == state.first && !in_valid); end end endmodule