../src/lowrisc_ip_gpio_0.1/rtl/gpio.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // General Purpose Input/Output module
   6: 
   7: `include "prim_assert.sv"
   8: 
   9: module gpio (
  10:   input clk_i,
  11:   input rst_ni,
  12: 
  13:   // Below Regster interface can be changed
  14:   input  tlul_pkg::tl_h2d_t tl_i,
  15:   output tlul_pkg::tl_d2h_t tl_o,
  16: 
  17:   input        [31:0] cio_gpio_i,
  18:   output logic [31:0] cio_gpio_o,
  19:   output logic [31:0] cio_gpio_en_o,
  20: 
  21:   output logic [31:0] intr_gpio_o
  22: );
  23: 
  24:   import gpio_reg_pkg::* ;
  25: 
  26:   gpio_reg2hw_t reg2hw;
  27:   gpio_hw2reg_t hw2reg;
  28: 
  29:   logic [31:0] cio_gpio_q;
  30:   logic [31:0] cio_gpio_en_q;
  31: 
  32:   // possibly filter the input based upon register configuration
  33: 
  34:   logic [31:0] data_in_d;
  35: 
  36:   for (genvar i = 0 ; i < 32 ; i++) begin : gen_filter
  37:     prim_filter_ctr #(.Cycles(16)) filter (
  38:       .clk_i,
  39:       .rst_ni,
  40:       .enable_i(reg2hw.ctrl_en_input_filter.q[i]),
  41:       .filter_i(cio_gpio_i[i]),
  42:       .filter_o(data_in_d[i])
  43:     );
  44:   end
  45: 
  46:   // GPIO_IN
  47:   assign hw2reg.data_in.de = 1'b1;
  48:   assign hw2reg.data_in.d  = data_in_d;
  49: 
  50:   // GPIO_OUT
  51:   assign cio_gpio_o                     = cio_gpio_q;
  52:   assign cio_gpio_en_o                  = cio_gpio_en_q;
  53: 
  54:   assign hw2reg.direct_out.d            = cio_gpio_q;
  55:   assign hw2reg.masked_out_upper.data.d = cio_gpio_q[31:16];
  56:   assign hw2reg.masked_out_upper.mask.d = 16'h 0;
  57:   assign hw2reg.masked_out_lower.data.d = cio_gpio_q[15:0];
  58:   assign hw2reg.masked_out_lower.mask.d = 16'h 0;
  59: 
  60:   always_ff @(posedge clk_i or negedge rst_ni) begin
  61:     if (!rst_ni) begin
  62:       cio_gpio_q  <= '0;
  63:     end else if (reg2hw.direct_out.qe) begin
  64:       cio_gpio_q <= reg2hw.direct_out.q;
  65:     end else if (reg2hw.masked_out_upper.data.qe) begin
  66:       cio_gpio_q[31:16] <=
  67:         ( reg2hw.masked_out_upper.mask.q & reg2hw.masked_out_upper.data.q) |
  68:         (~reg2hw.masked_out_upper.mask.q & cio_gpio_q[31:16]);
  69:     end else if (reg2hw.masked_out_lower.data.qe) begin
  70:       cio_gpio_q[15:0] <=
  71:         ( reg2hw.masked_out_lower.mask.q & reg2hw.masked_out_lower.data.q) |
  72:         (~reg2hw.masked_out_lower.mask.q & cio_gpio_q[15:0]);
  73:     end
  74:   end
  75: 
  76:   // GPIO OE
  77:   assign hw2reg.direct_oe.d = cio_gpio_en_q;
  78:   assign hw2reg.masked_oe_upper.data.d = cio_gpio_en_q[31:16];
  79:   assign hw2reg.masked_oe_upper.mask.d = 16'h 0;
  80:   assign hw2reg.masked_oe_lower.data.d = cio_gpio_en_q[15:0];
  81:   assign hw2reg.masked_oe_lower.mask.d = 16'h 0;
  82: 
  83:   always_ff @(posedge clk_i or negedge rst_ni) begin
  84:     if (!rst_ni) begin
  85:       cio_gpio_en_q  <= '0;
  86:     end else if (reg2hw.direct_oe.qe) begin
  87:       cio_gpio_en_q <= reg2hw.direct_oe.q;
  88:     end else if (reg2hw.masked_oe_upper.data.qe) begin
  89:       cio_gpio_en_q[31:16] <=
  90:         ( reg2hw.masked_oe_upper.mask.q & reg2hw.masked_oe_upper.data.q) |
  91:         (~reg2hw.masked_oe_upper.mask.q & cio_gpio_en_q[31:16]);
  92:     end else if (reg2hw.masked_oe_lower.data.qe) begin
  93:       cio_gpio_en_q[15:0] <=
  94:         ( reg2hw.masked_oe_lower.mask.q & reg2hw.masked_oe_lower.data.q) |
  95:         (~reg2hw.masked_oe_lower.mask.q & cio_gpio_en_q[15:0]);
  96:     end
  97:   end
  98: 
  99:   logic [31:0] data_in_q;
 100:   always_ff @(posedge clk_i) begin
 101:     data_in_q <= data_in_d;
 102:   end
 103: 
 104:   logic [31:0] event_intr_rise, event_intr_fall, event_intr_actlow, event_intr_acthigh;
 105:   logic [31:0] event_intr_combined;
 106: 
 107:   // instantiate interrupt hardware primitive
 108:   prim_intr_hw #(.Width(32)) intr_hw (
 109:     .event_intr_i           (event_intr_combined),
 110:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.q),
 111:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.q),
 112:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.qe),
 113:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.q),
 114:     .hw2reg_intr_state_de_o (hw2reg.intr_state.de),
 115:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.d),
 116:     .intr_o                 (intr_gpio_o)
 117:   );
 118: 
 119:   // detect four possible individual interrupts
 120:   assign event_intr_rise    = (~data_in_q &  data_in_d) & reg2hw.intr_ctrl_en_rising.q;
 121:   assign event_intr_fall    = ( data_in_q & ~data_in_d) & reg2hw.intr_ctrl_en_falling.q;
 122:   assign event_intr_acthigh =                data_in_d  & reg2hw.intr_ctrl_en_lvlhigh.q;
 123:   assign event_intr_actlow  =               ~data_in_d  & reg2hw.intr_ctrl_en_lvllow.q;
 124: 
 125:   assign event_intr_combined = event_intr_rise   |
 126:                                event_intr_fall   |
 127:                                event_intr_actlow |
 128:                                event_intr_acthigh;
 129: 
 130: 
 131:   // Register module
 132:   gpio_reg_top u_reg (
 133:     .clk_i,
 134:     .rst_ni,
 135: 
 136:     .tl_i,
 137:     .tl_o,
 138: 
 139:     .reg2hw,
 140:     .hw2reg,
 141: 
 142:     .devmode_i  (1'b1)
 143:   );
 144: 
 145:   // Assert Known: Outputs
 146:   `ASSERT_KNOWN(IntrGpioKnown, intr_gpio_o)
 147:   `ASSERT_KNOWN(CioGpioEnOKnown, cio_gpio_en_o)
 148:   `ASSERT_KNOWN(CioGpioOKnown, cio_gpio_o)
 149: 
 150: endmodule
 151: