blob: 10b90bddaf1c4823c2449ad57508bab419384c4d [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2021 , Dinesh Annayya
//
// 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.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org>
//
//////////////////////////////////////////////////////////////////////
//// ////
//// GPIO Register ////
//// ////
//// This file is part of the riscduino cores project ////
//// https://github.com/dineshannayya/riscduino.git ////
//// ////
//// Description ////
//// ////
//// To Do: ////
//// nothing ////
//// ////
//// Author(s): ////
//// - Dinesh Annayya, dinesha@opencores.org ////
//// ////
//// Revision : ////
//// 0.1 - 15th Aug 2022, Dinesh A ////
//// initial version ////
//////////////////////////////////////////////////////////////////////
//
module gpio_reg (
// System Signals
// Inputs
input logic mclk ,
input logic h_reset_n ,
// Reg Bus Interface Signal
input logic reg_cs ,
input logic reg_wr ,
input logic [3:0] reg_addr ,
input logic [31:0] reg_wdata ,
input logic [3:0] reg_be ,
// Outputs
output logic [31:0] reg_rdata ,
output logic reg_ack ,
input logic [31:0] gpio_in_data ,
output logic [31:0] gpio_prev_indata ,// previously captured GPIO I/P pins data
input logic [31:0] gpio_int_event ,
output logic [31:0] cfg_gpio_out_data ,// GPIO statuc O/P data from config reg
output logic [31:0] cfg_gpio_dir_sel ,// decides on GPIO pin is I/P or O/P at pad level, 0 -> Input, 1 -> Output
output logic [31:0] cfg_gpio_out_type ,// GPIO Type, 1 - WS_281X port
output logic [31:0] cfg_multi_func_sel ,// GPIO Multi function type
output logic [31:0] cfg_gpio_posedge_int_sel ,// select posedge interrupt
output logic [31:0] cfg_gpio_negedge_int_sel ,// select negedge interrupt
output logic [31:00] cfg_gpio_data_in ,
output logic [31:0] gpio_intr
);
//-----------------------------------------------------------------------
// Internal Wire Declarations
//-----------------------------------------------------------------------
logic sw_rd_en ;
logic sw_wr_en ;
logic [3:0] sw_addr ; // addressing 16 registers
logic [31:0] sw_reg_wdata ;
logic [3:0] sw_be ;
logic [31:0] reg_out ;
logic [31:0] reg_0 ; // GPIO Direction Select
logic [31:0] reg_1 ; // GPIO TYPE - Unused
logic [31:0] reg_2 ; // GPIO IN DATA
logic [31:0] reg_3 ; // GPIO OUT DATA
logic [31:0] reg_4 ; // GPIO INTERRUPT STATUS/CLEAR
logic [31:0] reg_5 ; // GPIO INTERRUPT SET
logic [31:0] reg_6 ; // GPIO INTERRUPT MASK
logic [31:0] reg_7 ; // GPIO POSEDGE INTERRUPT SEL
logic [31:0] reg_8 ; // GPIO NEGEDGE INTERRUPT SEL
assign sw_addr = reg_addr;
assign sw_rd_en = reg_cs & !reg_wr;
assign sw_wr_en = reg_cs & reg_wr;
assign sw_be = reg_be;
assign sw_reg_wdata = reg_wdata;
//-----------------------------------------------------------------------
// register read enable and write enable decoding logic
//-----------------------------------------------------------------------
wire sw_wr_en_0 = sw_wr_en & (sw_addr == 4'h0);
wire sw_wr_en_1 = sw_wr_en & (sw_addr == 4'h1);
wire sw_wr_en_2 = sw_wr_en & (sw_addr == 4'h2);
wire sw_wr_en_3 = sw_wr_en & (sw_addr == 4'h3);
wire sw_wr_en_4 = sw_wr_en & (sw_addr == 4'h4);
wire sw_wr_en_5 = sw_wr_en & (sw_addr == 4'h5);
wire sw_wr_en_6 = sw_wr_en & (sw_addr == 4'h6);
wire sw_wr_en_7 = sw_wr_en & (sw_addr == 4'h7);
wire sw_wr_en_8 = sw_wr_en & (sw_addr == 4'h8);
wire sw_rd_en_0 = sw_rd_en & (sw_addr == 4'h0);
wire sw_rd_en_1 = sw_rd_en & (sw_addr == 4'h1);
wire sw_rd_en_2 = sw_rd_en & (sw_addr == 4'h2);
wire sw_rd_en_3 = sw_rd_en & (sw_addr == 4'h3);
wire sw_rd_en_4 = sw_rd_en & (sw_addr == 4'h4);
wire sw_rd_en_5 = sw_rd_en & (sw_addr == 4'h5);
wire sw_rd_en_6 = sw_rd_en & (sw_addr == 4'h6);
wire sw_rd_en_7 = sw_rd_en & (sw_addr == 4'h7);
wire sw_rd_en_8 = sw_rd_en & (sw_addr == 4'h8);
always @ (posedge mclk or negedge h_reset_n)
begin : preg_out_Seq
if (h_reset_n == 1'b0) begin
reg_rdata <= 'h0;
reg_ack <= 1'b0;
end else if (reg_cs && !reg_ack) begin
reg_rdata <= reg_out;
reg_ack <= 1'b1;
end else begin
reg_ack <= 1'b0;
end
end
//-----------------------------------------------------------------------
// Logic for cfg_gpio_dir_sel
//-----------------------------------------------------------------------
assign cfg_gpio_dir_sel = reg_0[31:0]; // data to the GPIO O/P pins
gen_32b_reg #(32'h0) u_reg_0 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_0 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_0 )
);
//-----------------------------------------------------------------------
// Logic for cfg_gpio_out_type
//-----------------------------------------------------------------------
assign cfg_gpio_out_type = reg_1[31:0]; // Un-used
gen_32b_reg #(32'h0) u_reg_1 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_1 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_1 )
);
//-----------------------------------------------------------------------
// Logic for gpio_data_in
//-----------------------------------------------------------------------
logic [31:0] gpio_in_data_s;
logic [31:0] gpio_in_data_ss;
// Double Sync the gpio pin data for edge detection
always @ (posedge mclk or negedge h_reset_n)
begin
if (h_reset_n == 1'b0) begin
reg_2 <= 'h0 ;
gpio_in_data_s <= 32'd0;
gpio_in_data_ss <= 32'd0;
end
else begin
gpio_in_data_s <= gpio_in_data;
gpio_in_data_ss <= gpio_in_data_s;
reg_2 <= gpio_in_data_ss;
end
end
assign cfg_gpio_data_in = reg_2[31:0]; // to be used for edge interrupt detect
assign gpio_prev_indata = gpio_in_data_ss;
//-----------------------------------------------------------------------
// Logic for cfg_gpio_out_data
//-----------------------------------------------------------------------
assign cfg_gpio_out_data = reg_3[31:0]; // data to the GPIO control blk
gen_32b_reg #(32'h0) u_reg_3 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_3 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_3 )
);
//--------------------------------------------------------
// Interrupt Status Generation
// Note: Reg_4 --> Interrupt Status Register, Writting '1' will clear the
// corresponding interrupt status bit. Writting '0' has no
// effect
// Reg_5 --> Writting one to this register will set the interrupt in
// interrupt status register (reg_4), Writting '0' does not has any
// effect.
/// Always update int_status, even if no register write is occuring.
// Interrupt posting is higher priority than int clear by host
//--------------------------------------------------------
wire [31:0] gpio_int_status = reg_4;
generic_intr_stat_reg #(.WD(32),
.RESET_DEFAULT(0)) u_reg_4 (
//inputs
.clk (mclk ),
.reset_n (h_reset_n ),
.reg_we ({
{8{sw_wr_en_4 & reg_ack & sw_be[2]}},
{8{sw_wr_en_4 & reg_ack & sw_be[2]}},
{8{sw_wr_en_4 & reg_ack & sw_be[1]}},
{8{sw_wr_en_4 & reg_ack & sw_be[0]}}
} ),
.reg_din (sw_reg_wdata[31:0] ),
.hware_req (gpio_int_event | {
{8{sw_wr_en_5 & reg_ack}} & sw_reg_wdata[31:24],
{8{sw_wr_en_5 & reg_ack}} & sw_reg_wdata[23:16],
{8{sw_wr_en_5 & reg_ack}} & sw_reg_wdata[15:8] ,
{8{sw_wr_en_5 & reg_ack}} & sw_reg_wdata[7:0]
} ),
//outputs
.data_out (reg_4[31:0] )
);
//-------------------------------------------------
// Returns same value as interrupt status register
//------------------------------------------------
assign reg_5 = reg_4;
//-----------------------------------------------------------------------
// Logic for cfg_gpio_int_mask : GPIO interrupt mask
//-----------------------------------------------------------------------
wire [31:0] cfg_gpio_int_mask = reg_6[31:0]; // to be used for read
assign gpio_intr = reg_4 & reg_6; // interrupt pin to the RISC
// Register-11
gen_32b_reg #(32'h0) u_reg_6 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_6 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_6 )
);
//-----------------------------------------------------------------------
// Logic for cfg_gpio_posedge_int_sel : Enable posedge GPIO interrupt
//-----------------------------------------------------------------------
assign cfg_gpio_posedge_int_sel = reg_7[31:0]; // to be used for read
gen_32b_reg #(32'h0) u_reg_7 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_7 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_7 )
);
//-----------------------------------------------------------------------
// Logic for cfg_gpio_negedge_int_sel : Enable negedge GPIO interrupt
//-----------------------------------------------------------------------
assign cfg_gpio_negedge_int_sel = reg_8[31:0]; // to be used for read
gen_32b_reg #(32'h0) u_reg_8 (
//List of Inputs
.reset_n (h_reset_n ),
.clk (mclk ),
.cs (sw_wr_en_8 ),
.we (sw_be ),
.data_in (sw_reg_wdata ),
//List of Outs
.data_out (reg_8 )
);
//-----------------------------------------------------------------------
// Register Read Path Multiplexer instantiation
//-----------------------------------------------------------------------
always_comb
begin
reg_out [31:0] = 32'h0;
case (sw_addr [3:0])
4'b0000 : reg_out [31:0] = reg_0 [31:0];
4'b0001 : reg_out [31:0] = reg_1 [31:0];
4'b0010 : reg_out [31:0] = reg_2 [31:0];
4'b0011 : reg_out [31:0] = reg_3 [31:0];
4'b0100 : reg_out [31:0] = reg_4 [31:0];
4'b0101 : reg_out [31:0] = reg_5 [31:0];
4'b0110 : reg_out [31:0] = reg_6 [31:0];
4'b0111 : reg_out [31:0] = reg_7 [31:0];
4'b1000 : reg_out [31:0] = reg_8 [31:0];
default : reg_out [31:0] = 32'h0;
endcase
end
endmodule