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: