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