blob: 9278bd3900996fbe59ca74b45c4c61e054664cf1 [file] [log] [blame]
module apb_gpio
#(
parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
)
(
HCLK,
HRESETn,
PADDR,
PWDATA,
PWRITE,
PSEL,
PENABLE,
PRDATA,
PREADY,
PSLVERR,
gpio_in,
gpio_in_sync,
gpio_out,
gpio_dir,
gpio_padcfg,
power_event,
interrupt
);
//parameter APB_ADDR_WIDTH = 12;
input wire HCLK;
input wire HRESETn;
input wire [APB_ADDR_WIDTH - 1:0] PADDR;
input wire [31:0] PWDATA;
input wire PWRITE;
input wire PSEL;
input wire PENABLE;
output reg [31:0] PRDATA;
output wire PREADY;
output wire PSLVERR;
input wire [31:0] gpio_in;
output wire [31:0] gpio_in_sync;
output wire [31:0] gpio_out;
output wire [31:0] gpio_dir;
output reg [191:0] gpio_padcfg;
output reg power_event;
output reg interrupt;
reg [31:0] r_gpio_inten;
reg [31:0] r_gpio_inttype0;
reg [31:0] r_gpio_inttype1;
reg [31:0] r_gpio_out;
reg [31:0] r_gpio_dir;
reg [31:0] r_gpio_sync0;
reg [31:0] r_gpio_sync1;
reg [31:0] r_gpio_in;
reg [31:0] r_powerevent;
wire [31:0] s_gpio_rise;
wire [31:0] s_gpio_fall;
wire [31:0] s_is_int_rise;
wire [31:0] s_is_int_fall;
wire [31:0] s_is_int_lev0;
wire [31:0] s_is_int_lev1;
wire [31:0] s_is_int_all;
wire s_rise_int;
wire [3:0] s_apb_addr;
reg [31:0] r_status;
assign s_apb_addr = PADDR[5:2];
assign gpio_in_sync = r_gpio_sync1;
assign s_gpio_rise = r_gpio_sync1 & ~r_gpio_in;
assign s_gpio_fall = ~r_gpio_sync1 & r_gpio_in;
assign s_is_int_rise = (r_gpio_inttype1 & ~r_gpio_inttype0) & s_gpio_rise;
assign s_is_int_fall = (r_gpio_inttype1 & r_gpio_inttype0) & s_gpio_fall;
assign s_is_int_lev0 = (~r_gpio_inttype1 & r_gpio_inttype0) & ~r_gpio_in;
assign s_is_int_lev1 = (~r_gpio_inttype1 & ~r_gpio_inttype0) & r_gpio_in;
assign s_is_int_all = r_gpio_inten & (((s_is_int_rise | s_is_int_fall) | s_is_int_lev0) | s_is_int_lev1);
assign s_rise_int = |s_is_int_all;
always @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
interrupt <= 1'b0;
r_status <= 'h0;
end
else if (!interrupt && s_rise_int) begin
interrupt <= 1'b1;
r_status <= s_is_int_all;
end
else if ((((interrupt && PSEL) && PENABLE) && !PWRITE) && (s_apb_addr == 4'b0110)) begin
interrupt <= 1'b0;
r_status <= 'h0;
end
always @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
r_gpio_sync0 <= 'h0;
r_gpio_sync1 <= 'h0;
r_gpio_in <= 'h0;
end
else begin
r_gpio_sync0 <= gpio_in;
r_gpio_sync1 <= r_gpio_sync0;
r_gpio_in <= r_gpio_sync1;
end
always @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
r_gpio_inten <= 1'sb0;
r_gpio_inttype0 <= 1'sb0;
r_gpio_inttype1 <= 1'sb0;
r_gpio_out <= 1'sb0;
r_gpio_dir <= 1'sb0;
r_powerevent <= 1'sb0;
begin : sv2v_autoblock_1
reg signed [31:0] i;
for (i = 0; i < 32; i = i + 1)
gpio_padcfg[i * 6+:6] <= 6'b000010;
end
end
else if ((PSEL && PENABLE) && PWRITE)
case (s_apb_addr)
4'b0000: r_gpio_dir <= PWDATA;
4'b0010: r_gpio_out <= PWDATA;
4'b0011: r_gpio_inten <= PWDATA;
4'b0100: r_gpio_inttype0 <= PWDATA;
4'b0101: r_gpio_inttype1 <= PWDATA;
4'b0111: r_powerevent <= PWDATA;
4'b1000: begin
gpio_padcfg[0+:6] <= PWDATA[5:0];
gpio_padcfg[6+:6] <= PWDATA[13:8];
gpio_padcfg[12+:6] <= PWDATA[21:16];
gpio_padcfg[18+:6] <= PWDATA[29:24];
end
4'b1001: begin
gpio_padcfg[24+:6] <= PWDATA[5:0];
gpio_padcfg[30+:6] <= PWDATA[13:8];
gpio_padcfg[36+:6] <= PWDATA[21:16];
gpio_padcfg[42+:6] <= PWDATA[29:24];
end
4'b1010: begin
gpio_padcfg[48+:6] <= PWDATA[5:0];
gpio_padcfg[54+:6] <= PWDATA[13:8];
gpio_padcfg[60+:6] <= PWDATA[21:16];
gpio_padcfg[66+:6] <= PWDATA[29:24];
end
4'b1011: begin
gpio_padcfg[72+:6] <= PWDATA[5:0];
gpio_padcfg[78+:6] <= PWDATA[13:8];
gpio_padcfg[84+:6] <= PWDATA[21:16];
gpio_padcfg[90+:6] <= PWDATA[29:24];
end
4'b1100: begin
gpio_padcfg[96+:6] <= PWDATA[5:0];
gpio_padcfg[102+:6] <= PWDATA[13:8];
gpio_padcfg[108+:6] <= PWDATA[21:16];
gpio_padcfg[114+:6] <= PWDATA[29:24];
end
4'b1101: begin
gpio_padcfg[120+:6] <= PWDATA[5:0];
gpio_padcfg[126+:6] <= PWDATA[13:8];
gpio_padcfg[132+:6] <= PWDATA[21:16];
gpio_padcfg[138+:6] <= PWDATA[29:24];
end
4'b1110: begin
gpio_padcfg[144+:6] <= PWDATA[5:0];
gpio_padcfg[150+:6] <= PWDATA[13:8];
gpio_padcfg[156+:6] <= PWDATA[21:16];
gpio_padcfg[162+:6] <= PWDATA[29:24];
end
4'b1111: begin
gpio_padcfg[168+:6] <= PWDATA[5:0];
gpio_padcfg[174+:6] <= PWDATA[13:8];
gpio_padcfg[180+:6] <= PWDATA[21:16];
gpio_padcfg[186+:6] <= PWDATA[29:24];
end
endcase
always @(*)
case (s_apb_addr)
4'b0000: PRDATA = r_gpio_dir;
4'b0001: PRDATA = r_gpio_in;
4'b0010: PRDATA = r_gpio_out;
4'b0011: PRDATA = r_gpio_inten;
4'b0100: PRDATA = r_gpio_inttype0;
4'b0101: PRDATA = r_gpio_inttype1;
4'b0110: PRDATA = r_status;
4'b0111: PRDATA = r_powerevent;
4'b1000: PRDATA = {2'b00, gpio_padcfg[18+:6], 2'b00, gpio_padcfg[12+:6], 2'b00, gpio_padcfg[6+:6], 2'b00, gpio_padcfg[0+:6]};
4'b1001: PRDATA = {2'b00, gpio_padcfg[42+:6], 2'b00, gpio_padcfg[36+:6], 2'b00, gpio_padcfg[30+:6], 2'b00, gpio_padcfg[24+:6]};
4'b1010: PRDATA = {2'b00, gpio_padcfg[66+:6], 2'b00, gpio_padcfg[60+:6], 2'b00, gpio_padcfg[54+:6], 2'b00, gpio_padcfg[48+:6]};
4'b1011: PRDATA = {2'b00, gpio_padcfg[90+:6], 2'b00, gpio_padcfg[84+:6], 2'b00, gpio_padcfg[78+:6], 2'b00, gpio_padcfg[72+:6]};
4'b1100: PRDATA = {2'b00, gpio_padcfg[114+:6], 2'b00, gpio_padcfg[108+:6], 2'b00, gpio_padcfg[102+:6], 2'b00, gpio_padcfg[96+:6]};
4'b1101: PRDATA = {2'b00, gpio_padcfg[138+:6], 2'b00, gpio_padcfg[132+:6], 2'b00, gpio_padcfg[126+:6], 2'b00, gpio_padcfg[120+:6]};
4'b1110: PRDATA = {2'b00, gpio_padcfg[162+:6], 2'b00, gpio_padcfg[156+:6], 2'b00, gpio_padcfg[150+:6], 2'b00, gpio_padcfg[144+:6]};
4'b1111: PRDATA = {2'b00, gpio_padcfg[186+:6], 2'b00, gpio_padcfg[180+:6], 2'b00, gpio_padcfg[174+:6], 2'b00, gpio_padcfg[168+:6]};
default: PRDATA = 'h0;
endcase
always @(*) begin
power_event = 1'b0;
begin : sv2v_autoblock_2
reg signed [31:0] e;
for (e = 0; e < 32; e = e + 1)
if (r_powerevent[e] == 1'b1)
power_event = gpio_in[e];
end
end
assign gpio_out = r_gpio_out;
assign gpio_dir = r_gpio_dir;
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
endmodule