|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | module uartdpi #( | 
|  | parameter BAUD = 'x, | 
|  | parameter FREQ = 'x, | 
|  | parameter string NAME = "uart0" | 
|  | )( | 
|  | input  logic clk_i, | 
|  | input  logic rst_ni, | 
|  |  | 
|  | output logic tx_o, | 
|  | input  logic rx_i | 
|  | ); | 
|  | // Path to a log file. Used if none is specified through the `UARTDPI_LOG_<name>` plusarg. | 
|  | localparam string DEFAULT_LOG_FILE = {NAME, ".log"}; | 
|  |  | 
|  | // Min cycles is 2 for fast test mode | 
|  | localparam int CYCLES_PER_SYMBOL = FREQ / BAUD; | 
|  |  | 
|  | import "DPI-C" function | 
|  | chandle uartdpi_create(input string name, input string log_file_path); | 
|  |  | 
|  | import "DPI-C" function | 
|  | void uartdpi_close(input chandle ctx); | 
|  |  | 
|  | import "DPI-C" function | 
|  | byte uartdpi_read(input chandle ctx); | 
|  |  | 
|  | import "DPI-C" function | 
|  | int uartdpi_can_read(input chandle ctx); | 
|  |  | 
|  | import "DPI-C" function | 
|  | void uartdpi_write(input chandle ctx, int data); | 
|  |  | 
|  | chandle ctx; | 
|  | string log_file_path = DEFAULT_LOG_FILE; | 
|  |  | 
|  | initial begin | 
|  | $value$plusargs({"UARTDPI_LOG_", NAME, "=%s"}, log_file_path); | 
|  | ctx = uartdpi_create(NAME, log_file_path); | 
|  | end | 
|  |  | 
|  | final begin | 
|  | uartdpi_close(ctx); | 
|  | ctx = null; | 
|  | end | 
|  |  | 
|  | // TX | 
|  | reg txactive; | 
|  | int  txcount; | 
|  | int  txcyccount; | 
|  | reg [9:0] txsymbol; | 
|  | reg seen_reset; | 
|  |  | 
|  | always_ff @(negedge clk_i or negedge rst_ni) begin | 
|  | if (!rst_ni) begin | 
|  | tx_o <= 1; | 
|  | txactive <= 0; | 
|  | end else begin | 
|  | if (!txactive) begin | 
|  | tx_o <= 1; | 
|  | if (uartdpi_can_read(ctx)) begin | 
|  | automatic int c = uartdpi_read(ctx); | 
|  | txsymbol <= {1'b1, c[7:0], 1'b0}; | 
|  | txactive <= 1; | 
|  | txcount <= 0; | 
|  | txcyccount <= 0; | 
|  | end | 
|  | end else begin | 
|  | txcyccount <= txcyccount + 1; | 
|  | tx_o <= txsymbol[txcount]; | 
|  | if (txcyccount == CYCLES_PER_SYMBOL - 1) begin | 
|  | txcyccount <= 0; | 
|  | if (txcount == 9) | 
|  | txactive <= 0; | 
|  | else | 
|  | txcount <= txcount + 1; | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  |  | 
|  | initial begin | 
|  | // Prevent falling edges of rx_i before reset causing spurious characters | 
|  | seen_reset = 0; | 
|  | end | 
|  |  | 
|  | // RX | 
|  | reg rxactive; | 
|  | int rxcount; | 
|  | int rxcyccount; | 
|  | reg [7:0] rxsymbol; | 
|  |  | 
|  | always_ff @(negedge clk_i or negedge rst_ni) begin | 
|  | rxcyccount <= rxcyccount + 1; | 
|  |  | 
|  | if (!rst_ni) begin | 
|  | rxactive <= 0; | 
|  | seen_reset <= 1; | 
|  | end else begin | 
|  | if (!rxactive) begin | 
|  | if (!rx_i && seen_reset) begin | 
|  | rxactive <= 1; | 
|  | rxcount <= 0; | 
|  | rxcyccount <= 0; | 
|  | end | 
|  | end else begin | 
|  | if (rxcount == 0) begin | 
|  | if (rxcyccount == CYCLES_PER_SYMBOL/2 - 1) begin | 
|  | if (rx_i) begin | 
|  | rxactive <= 0; | 
|  | end else begin | 
|  | rxcount <= rxcount + 1; | 
|  | rxcyccount <= 0; | 
|  | end | 
|  | end | 
|  | end else if (rxcount <= 8) begin | 
|  | if (rxcyccount == CYCLES_PER_SYMBOL - 1) begin | 
|  | rxsymbol[rxcount-1] <= rx_i; | 
|  | rxcount <= rxcount + 1; | 
|  | rxcyccount <= 0; | 
|  | end | 
|  | end else begin | 
|  | if (rxcyccount == CYCLES_PER_SYMBOL - 1) begin | 
|  | rxactive <= 0; | 
|  | if (rx_i) begin | 
|  | uartdpi_write(ctx, rxsymbol); | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  | end | 
|  |  | 
|  | endmodule |