| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | module gpiodpi | 
 | #( | 
 |   parameter string NAME = "gpio0", | 
 |   parameter        N_GPIO = 32 | 
 | )( | 
 |   input  logic              clk_i, | 
 |   input  logic              rst_ni, | 
 |  | 
 |   output logic [N_GPIO-1:0] gpio_p2d, | 
 |   input  logic [N_GPIO-1:0] gpio_d2p, | 
 |   input  logic [N_GPIO-1:0] gpio_en_d2p | 
 | ); | 
 |    import "DPI-C" function | 
 |      chandle gpiodpi_create(input string name, input int n_bits); | 
 |  | 
 |    import "DPI-C" function | 
 |      void gpiodpi_device_to_host(input chandle ctx, input [N_GPIO-1:0] gpio_d2p, | 
 |                                  input [N_GPIO-1:0] gpio_en_d2p); | 
 |  | 
 |    import "DPI-C" function | 
 |      void gpiodpi_close(input chandle ctx); | 
 |  | 
 |    import "DPI-C" function | 
 |      int gpiodpi_host_to_device_tick(input chandle ctx, | 
 |                                      input [N_GPIO-1:0] gpio_en_d2p); | 
 |  | 
 |    chandle ctx; | 
 |  | 
 |    initial begin | 
 |      ctx = gpiodpi_create(NAME, N_GPIO); | 
 |    end | 
 |  | 
 |    final begin | 
 |      gpiodpi_close(ctx); | 
 |    end | 
 |  | 
 |    logic [N_GPIO-1:0] gpio_d2p_r; | 
 |    always_ff @(posedge clk_i) begin | 
 |      gpio_d2p_r <= gpio_d2p; | 
 |      if (gpio_d2p_r != gpio_d2p) begin | 
 |        gpiodpi_device_to_host(ctx, gpio_d2p, gpio_en_d2p); | 
 |      end | 
 |    end | 
 |  | 
 |    logic gpio_write_pulse; | 
 |  | 
 |    always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |      if (!rst_ni) begin | 
 |        gpio_p2d <= '0; // default value | 
 |      end else if (gpio_write_pulse) begin | 
 |        gpio_p2d <= gpiodpi_host_to_device_tick(ctx, gpio_en_d2p); | 
 |      end | 
 |    end | 
 |  | 
 |    // gpiodpio_host_to_device_tick() will be called every MAX_COUNT | 
 |    // clock posedges; this should be kept reasonably high, since each | 
 |    // tick call will perform at least one syscall. | 
 |    localparam MAX_COUNT = 2048; | 
 |    logic [$clog2(MAX_COUNT)-1:0] counter; | 
 |  | 
 |    assign gpio_write_pulse = counter == MAX_COUNT -1; | 
 |  | 
 |    always_ff @(posedge clk_i or negedge rst_ni) begin | 
 |      if (!rst_ni) begin | 
 |        counter <= '0; | 
 |      end else if (gpio_write_pulse) begin | 
 |        counter <= '0; | 
 |      end else begin | 
 |        counter <= counter + 1'b1; | 
 |      end | 
 |    end | 
 |  | 
 | endmodule |