346 lines
9.2 KiB
Verilog
346 lines
9.2 KiB
Verilog
/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
// &ModuleBeg; @21
|
|
module gpio_ctrl(
|
|
gpio_ext_porta,
|
|
gpio_ext_porta_rb,
|
|
gpio_int_polarity,
|
|
gpio_inten,
|
|
gpio_intmask,
|
|
gpio_intr,
|
|
gpio_intr_flag_int,
|
|
gpio_intr_int,
|
|
gpio_intrclk_en,
|
|
gpio_inttype_level,
|
|
gpio_ls_sync,
|
|
gpio_porta_ddr,
|
|
gpio_porta_dr,
|
|
gpio_porta_eoi,
|
|
gpio_raw_intstatus,
|
|
gpio_swporta_ctl,
|
|
gpio_swporta_ddr,
|
|
gpio_swporta_dr,
|
|
pclk,
|
|
pclk_intr,
|
|
presetn
|
|
);
|
|
|
|
// &Ports; @22
|
|
input [7:0] gpio_ext_porta;
|
|
input [7:0] gpio_int_polarity;
|
|
input [7:0] gpio_inten;
|
|
input [7:0] gpio_intmask;
|
|
input [7:0] gpio_inttype_level;
|
|
input gpio_ls_sync;
|
|
input [7:0] gpio_porta_eoi;
|
|
input [7:0] gpio_swporta_ctl;
|
|
input [7:0] gpio_swporta_ddr;
|
|
input [7:0] gpio_swporta_dr;
|
|
input pclk;
|
|
input pclk_intr;
|
|
input presetn;
|
|
output [7:0] gpio_ext_porta_rb;
|
|
output [7:0] gpio_intr;
|
|
output gpio_intr_flag_int;
|
|
output [7:0] gpio_intr_int;
|
|
output gpio_intrclk_en;
|
|
output [7:0] gpio_porta_ddr;
|
|
output [7:0] gpio_porta_dr;
|
|
output [7:0] gpio_raw_intstatus;
|
|
|
|
// &Regs; @23
|
|
reg [7:0] ed_int_d1;
|
|
reg [7:0] ed_out;
|
|
reg [7:0] gpio_ext_porta_int;
|
|
reg [7:0] gpio_ext_porta_rb;
|
|
reg [7:0] gpio_intr_ed_pm;
|
|
reg gpio_intrclk_en;
|
|
reg [7:0] gpio_porta_ddr;
|
|
reg [7:0] gpio_porta_dr;
|
|
reg [7:0] int_gpio_raw_intstatus;
|
|
reg [7:0] int_pre_in;
|
|
reg [7:0] int_s1;
|
|
reg [7:0] int_sy_in;
|
|
reg [7:0] intrclk_en;
|
|
reg [7:0] ls_int_in;
|
|
|
|
// &Wires; @24
|
|
wire [7:0] ed_rf;
|
|
wire [7:0] gpio_ext_porta;
|
|
wire [7:0] gpio_int_polarity;
|
|
wire [7:0] gpio_inten;
|
|
wire [7:0] gpio_intmask;
|
|
wire [7:0] gpio_intr;
|
|
wire gpio_intr_flag_int;
|
|
wire [7:0] gpio_intr_int;
|
|
wire gpio_intrclk_en_int;
|
|
wire [7:0] gpio_inttype_level;
|
|
wire gpio_ls_sync;
|
|
wire [7:0] gpio_porta_eoi;
|
|
wire [7:0] gpio_raw_intstatus;
|
|
wire [7:0] gpio_swporta_ctl;
|
|
wire [7:0] gpio_swporta_ctl_internal;
|
|
wire [7:0] gpio_swporta_ddr;
|
|
wire [7:0] gpio_swporta_dr;
|
|
wire [7:0] int_in;
|
|
wire pclk;
|
|
wire pclk_intr;
|
|
wire presetn;
|
|
|
|
|
|
// &Force("output", "gpio_intr"); @26
|
|
// &Force("output", "gpio_intr_int"); @27
|
|
// &Force("output", "gpio_raw_intstatus"); @28
|
|
// &Force("output", "gpio_porta_ddr"); @29
|
|
|
|
// gpio_intrclk_en output asserted if any bit of port
|
|
// a is enabled for edge sensitive interrupts or
|
|
// any bit of port a is enabled for level sensitive
|
|
// interrupts and level sensitive synchronisation
|
|
// is required.
|
|
integer type_i;
|
|
// &CombBeg; @37
|
|
always @( gpio_inttype_level[1:0]
|
|
or gpio_ls_sync
|
|
or gpio_inten[7:0]
|
|
or gpio_inttype_level[7:1])
|
|
begin
|
|
|
|
for(type_i = 0 ; type_i < 8 ; type_i=type_i+1)
|
|
begin
|
|
if(gpio_inten[type_i] == 1'b1)
|
|
if(gpio_inttype_level[type_i] == 1'b1)
|
|
intrclk_en[type_i] = 1'b1;
|
|
else
|
|
intrclk_en[type_i] = gpio_ls_sync;
|
|
else
|
|
intrclk_en[type_i] = 1'b0;
|
|
end
|
|
// &CombEnd; @49
|
|
end
|
|
|
|
assign gpio_intrclk_en_int = | intrclk_en;
|
|
|
|
always@(posedge pclk or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
gpio_intrclk_en <= 1'b0;
|
|
else
|
|
gpio_intrclk_en <= gpio_intrclk_en_int;
|
|
end
|
|
|
|
// Input is inverted for falling edge or active low
|
|
// sensitive interrupts.
|
|
integer polarity_i;
|
|
// &CombBeg; @64
|
|
always @( gpio_ext_porta[1:0]
|
|
or gpio_int_polarity[7:0]
|
|
or gpio_ext_porta[7:0]
|
|
or gpio_int_polarity[1:0])
|
|
begin
|
|
gpio_ext_porta_int[7:0] = {8{1'b0}};
|
|
for(polarity_i = 0 ; polarity_i < 8 ; polarity_i=polarity_i+1)
|
|
begin
|
|
if(gpio_int_polarity[polarity_i] == 1'b0)
|
|
gpio_ext_porta_int[polarity_i] = ~gpio_ext_porta[polarity_i];
|
|
else
|
|
gpio_ext_porta_int[polarity_i] = gpio_ext_porta[polarity_i];
|
|
end
|
|
// &CombEnd; @73
|
|
end
|
|
|
|
// &CombBeg; @75
|
|
always @( gpio_ext_porta_int[7:0])
|
|
begin
|
|
int_sy_in[7:0] = {8{1'b0}};
|
|
int_sy_in[7:0] = gpio_ext_porta_int[7:0];
|
|
// &CombEnd; @78
|
|
end
|
|
|
|
// Meta-stabilty registers. Synchronize to pclk_intr.
|
|
always @(posedge pclk_intr or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
int_s1[7:0] <= {8{1'b0}};
|
|
else
|
|
int_s1[7:0] <= int_sy_in[7:0];
|
|
end
|
|
|
|
always @(posedge pclk_intr or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
int_pre_in[7:0] <= {8{1'b0}};
|
|
else
|
|
int_pre_in[7:0] <= int_s1;
|
|
end
|
|
|
|
assign int_in[7:0] = int_pre_in[7:0];
|
|
|
|
// edge detect circuitry.
|
|
always @(posedge pclk_intr or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
ed_int_d1[7:0] <= {8{1'b0}};
|
|
else
|
|
ed_int_d1[7:0] <= int_in[7:0];
|
|
end
|
|
|
|
assign ed_rf[7:0] = int_in ^ ed_int_d1;
|
|
|
|
// Rising edge detect
|
|
integer ed_j;
|
|
// &CombBeg; @112
|
|
always @( ed_rf[7:0]
|
|
or int_in[7:0])
|
|
begin
|
|
|
|
ed_out[7:0] = {8{1'b0}};
|
|
for(ed_j = 0 ; ed_j < 8 ; ed_j=ed_j+1)
|
|
begin
|
|
ed_out[ed_j] = ed_rf[ed_j] & int_in[ed_j];
|
|
end
|
|
// &CombEnd; @119
|
|
end
|
|
|
|
// edge detect interrupt register pre-masking. If edge detection
|
|
// occurs at same time as write to interrupt clear register then
|
|
// write to interrupt clear register will not clear the interrupt.
|
|
// Interrupts can only be set when direction is input and in
|
|
// software mode.
|
|
assign gpio_swporta_ctl_internal[7:0] = gpio_swporta_ctl[7:0];
|
|
integer int_k;
|
|
always @(posedge pclk_intr or negedge presetn)
|
|
begin
|
|
if(!presetn)
|
|
gpio_intr_ed_pm[7:0] <= {8{1'b0}};
|
|
else
|
|
for(int_k = 0 ; int_k < 8 ; int_k=int_k+1)
|
|
begin
|
|
if(gpio_inten[int_k] == 1'b0)
|
|
gpio_intr_ed_pm[int_k] <= 1'b0;
|
|
else
|
|
if((ed_out[int_k] == 1'b1) &&
|
|
(gpio_inten[int_k] == 1'b1) &&
|
|
(gpio_swporta_ddr[int_k] == 1'b0) &&
|
|
(gpio_swporta_ctl_internal[int_k] == 1'b0))
|
|
gpio_intr_ed_pm[int_k] <= 1'b1;
|
|
else
|
|
if(gpio_porta_eoi[int_k] == 1'b1)
|
|
gpio_intr_ed_pm[int_k] <= 1'b0;
|
|
end
|
|
end
|
|
|
|
// Level senistive interrupts may pass through synchronization
|
|
// and debounce logic. Under S/W control.
|
|
// Interrupts can only be set when direction is input and in
|
|
// software mode.
|
|
integer lsa_k;
|
|
|
|
// &CombBeg; @155
|
|
always @( int_in[7:0]
|
|
or gpio_swporta_ddr[7:0]
|
|
or gpio_swporta_ctl_internal[2:0]
|
|
or gpio_ls_sync
|
|
or int_sy_in[7:0]
|
|
or gpio_swporta_ctl_internal[7:2])
|
|
begin
|
|
ls_int_in[7:0] = {8{1'b0}};
|
|
for(lsa_k = 0 ; lsa_k < 8 ; lsa_k=lsa_k+1)
|
|
begin
|
|
if(((gpio_swporta_ddr[lsa_k]) == 1'b1) ||
|
|
(gpio_swporta_ctl_internal[lsa_k] == 1'b1))
|
|
ls_int_in[lsa_k] = 0;
|
|
else
|
|
if(gpio_ls_sync == 1'b1)
|
|
ls_int_in[lsa_k] = int_in[lsa_k];
|
|
else
|
|
ls_int_in[lsa_k] = int_sy_in[lsa_k];
|
|
end
|
|
// &CombEnd; @168
|
|
end
|
|
|
|
// Level or edge sensitive interrupts
|
|
integer raw_l;
|
|
|
|
// &CombBeg; @173
|
|
always @( gpio_inten[7:3]
|
|
or gpio_intr_ed_pm[2:0]
|
|
or gpio_intr_ed_pm[7:1]
|
|
or gpio_inten[4:0]
|
|
or gpio_inttype_level[7:0]
|
|
or ls_int_in[7:0])
|
|
begin
|
|
int_gpio_raw_intstatus[7:0] = {8{1'b0}};
|
|
for(raw_l = 0 ; raw_l < 8 ; raw_l=raw_l+1)
|
|
begin
|
|
if(gpio_inten[raw_l] == 1'b0)
|
|
int_gpio_raw_intstatus[raw_l] = 0;
|
|
else
|
|
if(gpio_inttype_level[raw_l] == 1'b1)
|
|
int_gpio_raw_intstatus[raw_l] = gpio_intr_ed_pm[raw_l];
|
|
else
|
|
int_gpio_raw_intstatus[raw_l] = ls_int_in[raw_l];
|
|
end
|
|
// &CombEnd; @185
|
|
end
|
|
|
|
assign gpio_raw_intstatus[7:0] = int_gpio_raw_intstatus[7:0];
|
|
assign gpio_intr_int[7:0] = gpio_raw_intstatus[7:0] & ~gpio_intmask[7:0];
|
|
assign gpio_intr[7:0] = gpio_intr_int[7:0];
|
|
|
|
assign gpio_intr_flag_int = |gpio_intr_int[7:0];
|
|
// &CombBeg; @192
|
|
always @( gpio_swporta_dr[7:0])
|
|
begin
|
|
gpio_porta_dr[7:0] = {8{1'b0}};
|
|
gpio_porta_dr[7:0] = gpio_swporta_dr[7:0];
|
|
// &CombEnd; @195
|
|
end
|
|
|
|
// &CombBeg; @197
|
|
always @( gpio_swporta_ddr[7:0])
|
|
begin
|
|
gpio_porta_ddr[7:0] = {8{1'b0}};
|
|
gpio_porta_ddr[7:0] = gpio_swporta_ddr[7:0];
|
|
// &CombEnd; @200
|
|
end
|
|
|
|
integer rba_i;
|
|
|
|
// &CombBeg; @204
|
|
always @( gpio_swporta_dr[2:1]
|
|
or gpio_ext_porta[7:0]
|
|
or gpio_swporta_dr[7:0]
|
|
or gpio_porta_ddr[7:0])
|
|
begin
|
|
gpio_ext_porta_rb[7:0] = {8{1'b0}};
|
|
for(rba_i = 0 ; rba_i < 8 ; rba_i=rba_i+1)
|
|
begin
|
|
if(gpio_porta_ddr[rba_i] == 1'b1)
|
|
gpio_ext_porta_rb[rba_i] = gpio_swporta_dr[rba_i];
|
|
else
|
|
gpio_ext_porta_rb[rba_i] = gpio_ext_porta[rba_i];
|
|
end
|
|
// &CombEnd; @213
|
|
end
|
|
|
|
integer rbb_i;
|
|
|
|
// &ModuleEnd; @217
|
|
endmodule
|
|
|
|
|