| // 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 |