2016-03-08 19:37:42 -05:00
|
|
|
//#############################################################################
|
|
|
|
//# Function: General Purpose Software Programmable IO #
|
2016-04-10 23:24:26 -04:00
|
|
|
//# (See README.md for complete documentation) #
|
2016-03-08 19:37:42 -05:00
|
|
|
//#############################################################################
|
|
|
|
//# Author: Andreas Olofsson #
|
2016-04-10 23:24:26 -04:00
|
|
|
//# License: MIT (see LICENSE file in this repository) #
|
2016-03-08 19:37:42 -05:00
|
|
|
//#############################################################################
|
2016-04-10 23:24:26 -04:00
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
`include "gpio_regmap.vh"
|
2016-05-15 15:47:45 -04:00
|
|
|
module gpio #( parameter integer N = 24, // number of gpio pins
|
|
|
|
parameter integer AW = 32, // architecture address width
|
|
|
|
parameter integer PW = 104 // packet width
|
2016-04-10 23:24:26 -04:00
|
|
|
)
|
|
|
|
(
|
2016-06-19 17:12:24 -04:00
|
|
|
input nreset, // asynchronous active low reset
|
|
|
|
input clk, // clock
|
|
|
|
input access_in, // register access
|
|
|
|
input [PW-1:0] packet_in, // data/address
|
|
|
|
output wait_out, // pushback from mesh
|
|
|
|
output access_out, // register access
|
|
|
|
output [PW-1:0] packet_out, // data/address
|
|
|
|
input wait_in, // pushback from mesh
|
|
|
|
output reg [N-1:0] gpio_out, // data to drive to IO pins
|
|
|
|
output reg [N-1:0] gpio_dir, // gpio direction(0=input)
|
|
|
|
input [N-1:0] gpio_in, // data from IO pins
|
|
|
|
output gpio_irq // OR of GPIO_ILAT register
|
2016-04-10 23:24:26 -04:00
|
|
|
);
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
//################################
|
|
|
|
//# wires/regs/ params
|
|
|
|
//################################
|
2016-01-23 00:09:14 -05:00
|
|
|
|
|
|
|
//registers
|
2016-04-10 23:24:26 -04:00
|
|
|
reg [N-1:0] gpio_imask;
|
|
|
|
reg [N-1:0] gpio_itype;
|
|
|
|
reg [N-1:0] gpio_ipol;
|
|
|
|
reg [N-1:0] gpio_ilat;
|
2016-05-19 13:59:14 +02:00
|
|
|
reg [N-1:0] read_data;
|
2016-08-25 11:44:30 -04:00
|
|
|
wire [N-1:0] gpio_in_sync;
|
2016-04-10 23:24:26 -04:00
|
|
|
|
|
|
|
//wires
|
2016-08-25 11:44:30 -04:00
|
|
|
reg [N-1:0] data_old; //shadow
|
2016-04-10 23:24:26 -04:00
|
|
|
wire [N-1:0] ilat_clr;
|
|
|
|
wire [N-1:0] reg_wdata;
|
|
|
|
wire [N-1:0] out_dmux;
|
|
|
|
wire [N-1:0] rising_edge;
|
|
|
|
wire [N-1:0] falling_edge;
|
|
|
|
wire [N-1:0] irq_event;
|
2016-06-19 17:12:24 -04:00
|
|
|
wire reg_write;
|
|
|
|
wire reg_read;
|
|
|
|
wire reg_double;
|
|
|
|
wire dir_write;
|
|
|
|
wire imask_write;
|
|
|
|
wire itype_write;
|
|
|
|
wire ipol_write;
|
|
|
|
wire ilatclr_write;
|
|
|
|
wire out_write;
|
|
|
|
wire outset_write;
|
|
|
|
wire outclr_write;
|
|
|
|
wire outxor_write;
|
|
|
|
wire outreg_write;
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
/*AUTOWIRE*/
|
|
|
|
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
|
|
|
wire [4:0] ctrlmode_in; // From p2e of packet2emesh.v
|
|
|
|
wire [AW-1:0] data_in; // From p2e of packet2emesh.v
|
|
|
|
wire [1:0] datamode_in; // From p2e of packet2emesh.v
|
|
|
|
wire [AW-1:0] dstaddr_in; // From p2e of packet2emesh.v
|
|
|
|
wire [AW-1:0] srcaddr_in; // From p2e of packet2emesh.v
|
|
|
|
wire write_in; // From p2e of packet2emesh.v
|
|
|
|
// End of automatics
|
2016-04-10 23:24:26 -04:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-04-10 23:24:26 -04:00
|
|
|
//# DECODE LOGIC
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2021-07-29 11:20:44 -04:00
|
|
|
enoc_unpack #(.AW(AW),
|
|
|
|
.PW(PW))
|
2016-03-21 11:20:59 -04:00
|
|
|
p2e(
|
|
|
|
/*AUTOINST*/
|
|
|
|
// Outputs
|
|
|
|
.write_in (write_in),
|
|
|
|
.datamode_in (datamode_in[1:0]),
|
|
|
|
.ctrlmode_in (ctrlmode_in[4:0]),
|
|
|
|
.dstaddr_in (dstaddr_in[AW-1:0]),
|
|
|
|
.srcaddr_in (srcaddr_in[AW-1:0]),
|
|
|
|
.data_in (data_in[AW-1:0]),
|
|
|
|
// Inputs
|
|
|
|
.packet_in (packet_in[PW-1:0]));
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-13 09:28:17 -04:00
|
|
|
assign reg_write = access_in & write_in;
|
|
|
|
assign reg_read = access_in & ~write_in;
|
2016-03-05 07:28:28 -05:00
|
|
|
assign reg_double = datamode_in[1:0]==2'b11;
|
2016-04-10 23:24:26 -04:00
|
|
|
assign reg_wdata[N-1:0] = data_in[N-1:0];
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
assign dir_write = reg_write & (dstaddr_in[6:3]==`GPIO_DIR);
|
2016-06-19 17:12:24 -04:00
|
|
|
assign outreg_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUT);
|
2016-03-13 09:28:17 -04:00
|
|
|
assign imask_write = reg_write & (dstaddr_in[6:3]==`GPIO_IMASK);
|
2016-04-10 23:24:26 -04:00
|
|
|
assign itype_write = reg_write & (dstaddr_in[6:3]==`GPIO_ITYPE);
|
|
|
|
assign ipol_write = reg_write & (dstaddr_in[6:3]==`GPIO_IPOL);
|
|
|
|
assign ilatclr_write = reg_write & (dstaddr_in[6:3]==`GPIO_ILATCLR);
|
|
|
|
assign outclr_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTCLR);
|
|
|
|
assign outset_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTSET);
|
|
|
|
assign outxor_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTXOR);
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2016-06-19 17:12:24 -04:00
|
|
|
assign out_write = outreg_write |
|
|
|
|
outclr_write |
|
|
|
|
outset_write |
|
|
|
|
outxor_write;
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-04-10 23:24:26 -04:00
|
|
|
//# GPIO_DIR
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-08-25 11:44:30 -04:00
|
|
|
//0=input
|
|
|
|
//1=output
|
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
2016-04-10 23:24:26 -04:00
|
|
|
gpio_dir[N-1:0] <= 'b0;
|
|
|
|
else if(dir_write)
|
|
|
|
gpio_dir[N-1:0] <= reg_wdata[N-1:0];
|
|
|
|
|
|
|
|
//################################
|
|
|
|
//# GPIO_IN
|
|
|
|
//################################
|
|
|
|
|
2016-06-19 17:12:24 -04:00
|
|
|
oh_dsync oh_dsync[N-1:0] (.dout (gpio_in_sync[N-1:0]),
|
|
|
|
.clk (clk),
|
|
|
|
.nreset (nreset),
|
|
|
|
.din (gpio_in[N-1:0]));
|
2016-04-10 23:24:26 -04:00
|
|
|
|
|
|
|
always @ (posedge clk)
|
2016-08-25 11:44:30 -04:00
|
|
|
data_old[N-1:0] <= gpio_in_sync[N-1:0];
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
//################################
|
|
|
|
//# GPIO_OUT
|
|
|
|
//################################
|
|
|
|
|
|
|
|
oh_mux4 #(.DW(N))
|
|
|
|
oh_mux4 (.out (out_dmux[N-1:0]),
|
2016-03-05 16:16:22 -05:00
|
|
|
// Inputs
|
2016-06-19 17:12:24 -04:00
|
|
|
.in0 (reg_wdata[N-1:0]), .sel0 (outreg_write),
|
2016-04-10 23:24:26 -04:00
|
|
|
.in1 (gpio_out[N-1:0] & ~reg_wdata[N-1:0]),.sel1 (outclr_write),
|
|
|
|
.in2 (gpio_out[N-1:0] | reg_wdata[N-1:0]), .sel2 (outset_write),
|
|
|
|
.in3 (gpio_out[N-1:0] ^ reg_wdata[N-1:0]), .sel3 (outxor_write));
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
|
|
|
gpio_out[N-1:0] <= 'b0;
|
2016-06-19 17:12:24 -04:00
|
|
|
else if(out_write)
|
2016-04-10 23:24:26 -04:00
|
|
|
gpio_out[N-1:0] <= out_dmux[N-1:0];
|
2016-03-21 11:20:59 -04:00
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
//################################
|
2016-04-10 23:24:26 -04:00
|
|
|
//# GPIO_IMASK
|
2016-03-05 07:28:28 -05:00
|
|
|
//################################
|
|
|
|
|
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
2016-04-10 23:24:26 -04:00
|
|
|
gpio_imask[N-1:0] <= {(N){1'b1}};
|
|
|
|
else if(imask_write)
|
|
|
|
gpio_imask[N-1:0] <= reg_wdata[N-1:0];
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
//################################
|
|
|
|
//# GPIO_ITYPE
|
|
|
|
//################################
|
|
|
|
always @ (posedge clk)
|
|
|
|
if(itype_write)
|
|
|
|
gpio_itype[N-1:0] <= reg_wdata[N-1:0];
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
//################################
|
|
|
|
//# GPIO_IPOL
|
|
|
|
//################################
|
|
|
|
always @ (posedge clk)
|
|
|
|
if(ipol_write)
|
|
|
|
gpio_ipol[N-1:0] <= reg_wdata[N-1:0];
|
|
|
|
|
|
|
|
//################################
|
|
|
|
//# INTERRUPT LOGIC (DEFAULT EDGE)
|
|
|
|
//################################
|
2016-03-21 11:20:59 -04:00
|
|
|
|
2016-08-25 11:44:30 -04:00
|
|
|
assign rising_edge[N-1:0] = gpio_in_sync[N-1:0] & ~data_old[N-1:0];
|
2016-04-10 23:24:26 -04:00
|
|
|
|
2016-08-25 11:44:30 -04:00
|
|
|
assign falling_edge[N-1:0] = ~gpio_in_sync[N-1:0] & data_old[N-1:0];
|
2016-04-10 23:24:26 -04:00
|
|
|
|
|
|
|
assign irq_event[N-1:0] = (rising_edge[N-1:0] & ~gpio_itype[N-1:0] & gpio_ipol[N-1:0]) |
|
|
|
|
(falling_edge[N-1:0] & ~gpio_itype[N-1:0] & ~gpio_ipol[N-1:0]) |
|
|
|
|
(gpio_in_sync[N-1:0] & gpio_itype[N-1:0] & gpio_ipol[N-1:0]) |
|
|
|
|
(~gpio_in_sync[N-1:0] & gpio_itype[N-1:0] & ~gpio_ipol[N-1:0]);
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-04-10 23:24:26 -04:00
|
|
|
//# ILAT
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
assign ilat_clr[N-1:0] = ilatclr_write ? reg_wdata[N-1:0] : 'b0;
|
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
2016-04-10 23:24:26 -04:00
|
|
|
gpio_ilat[N-1:0] <= 'b0;
|
|
|
|
else
|
|
|
|
gpio_ilat[N-1:0] <= (gpio_ilat[N-1:0] & ~ilat_clr[N-1:0]) | //old values
|
|
|
|
(irq_event[N-1:0] & ~gpio_imask[N-1:0]); //new interrupts
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
//################################
|
|
|
|
//# ONE CYCLE IRQ PULSE
|
|
|
|
//################################
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-04-10 23:24:26 -04:00
|
|
|
assign gpio_irq = |gpio_ilat[N-1:0];
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
|
|
|
//# READBACK
|
|
|
|
//################################
|
2016-04-10 23:24:26 -04:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
always @ (posedge clk)
|
2016-02-26 19:06:38 -05:00
|
|
|
if(reg_read)
|
2016-05-19 13:59:14 +02:00
|
|
|
case(dstaddr_in[6:3])
|
|
|
|
`GPIO_IN : read_data[N-1:0] <= gpio_in_sync[N-1:0];
|
|
|
|
`GPIO_ILAT : read_data[N-1:0] <= gpio_ilat[N-1:0];
|
|
|
|
`GPIO_DIR : read_data[N-1:0] <= gpio_dir[N-1:0];
|
|
|
|
`GPIO_IMASK: read_data[N-1:0] <= gpio_imask[N-1:0];
|
|
|
|
`GPIO_IPOL : read_data[N-1:0] <= gpio_ipol[N-1:0];
|
|
|
|
`GPIO_ITYPE: read_data[N-1:0] <= gpio_itype[N-1:0];
|
|
|
|
default : read_data[N-1:0] <='b0;
|
2016-03-05 07:28:28 -05:00
|
|
|
endcase // case (dstaddr_in[7:3])
|
2016-05-19 13:59:14 +02:00
|
|
|
|
2016-05-15 15:47:45 -04:00
|
|
|
emesh_readback #(.AW(AW),
|
|
|
|
.PW(PW))
|
2016-03-13 09:28:17 -04:00
|
|
|
emesh_readback (/*AUTOINST*/
|
|
|
|
// Outputs
|
|
|
|
.wait_out (wait_out),
|
|
|
|
.access_out (access_out),
|
|
|
|
.packet_out (packet_out[PW-1:0]),
|
|
|
|
// Inputs
|
|
|
|
.nreset (nreset),
|
|
|
|
.clk (clk),
|
|
|
|
.access_in (access_in),
|
|
|
|
.packet_in (packet_in[PW-1:0]),
|
2016-06-19 17:12:24 -04:00
|
|
|
.read_data (read_data[63:0]),
|
2016-03-13 09:28:17 -04:00
|
|
|
.wait_in (wait_in));
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
endmodule // gpio
|
|
|
|
// Local Variables:
|
|
|
|
// verilog-library-directories:("." "../../emesh/hdl" "../../common/hdl")
|
|
|
|
// End:
|