2016-03-08 19:37:42 -05:00
|
|
|
//#############################################################################
|
|
|
|
//# Function: General Purpose Software Programmable IO #
|
|
|
|
//# (See README.md for complete documentation) #
|
|
|
|
//#############################################################################
|
|
|
|
//# Author: Andreas Olofsson #
|
|
|
|
//# License: MIT (see below) #
|
|
|
|
//#############################################################################
|
2016-03-05 07:28:28 -05:00
|
|
|
`include "gpio_regmap.vh"
|
2016-01-23 00:09:14 -05:00
|
|
|
module gpio(/*AUTOARG*/
|
|
|
|
// Outputs
|
2016-03-13 09:28:17 -04:00
|
|
|
wait_out, access_out, packet_out, gpio_out, gpio_oen, gpio_irq,
|
|
|
|
gpio_data,
|
2016-01-23 00:09:14 -05:00
|
|
|
// Inputs
|
2016-03-13 09:28:17 -04:00
|
|
|
nreset, clk, access_in, packet_in, wait_in, gpio_in
|
2016-01-23 00:09:14 -05:00
|
|
|
);
|
|
|
|
|
2016-03-08 19:37:42 -05:00
|
|
|
//##########################################
|
2016-01-23 00:09:14 -05:00
|
|
|
//# INTERFACE
|
2016-03-08 19:37:42 -05:00
|
|
|
//##########################################
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-13 09:28:17 -04:00
|
|
|
parameter N = 24; // number of gpio pins
|
|
|
|
parameter AW = 32; // address width
|
|
|
|
localparam PW = 2*AW+40; // packet width
|
2016-01-23 00:09:14 -05:00
|
|
|
|
|
|
|
//clk, reset
|
|
|
|
input nreset; // asynchronous active low reset
|
|
|
|
input clk; // clock
|
2016-03-13 09:28:17 -04:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//register access interface
|
2016-03-13 09:28:17 -04:00
|
|
|
input access_in; // register access
|
|
|
|
input [PW-1:0] packet_in; // data/address
|
|
|
|
output wait_out; // pushback from mesh
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-13 09:28:17 -04:00
|
|
|
output access_out; // register access
|
|
|
|
output [PW-1:0] packet_out; // data/address
|
|
|
|
input wait_in; // pushback from mesh
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//IO signals
|
2016-03-05 07:28:28 -05:00
|
|
|
output [N-1:0] gpio_out; // data to drive to IO pins
|
|
|
|
output [N-1:0] gpio_oen; // tristate enables for IO pins
|
|
|
|
input [N-1:0] gpio_in; // data from IO pins
|
2016-01-23 00:09:14 -05:00
|
|
|
|
|
|
|
//global interrupt
|
2016-03-05 07:28:28 -05:00
|
|
|
output gpio_irq; // toggle detect edge interrupt
|
2016-02-26 19:06:38 -05:00
|
|
|
output [N-1:0] gpio_data; // individual interrupt outputs
|
2016-01-23 00:09:14 -05:00
|
|
|
|
|
|
|
//##################################################################
|
|
|
|
//# BODY
|
|
|
|
//##################################################################
|
|
|
|
|
|
|
|
//registers
|
2016-03-05 07:28:28 -05:00
|
|
|
reg [63:0] oen_reg;
|
2016-03-05 16:16:22 -05:00
|
|
|
reg [63:0] out_reg;
|
2016-03-05 07:28:28 -05:00
|
|
|
reg [63:0] ien_reg;
|
2016-03-05 16:16:22 -05:00
|
|
|
reg [63:0] in_reg;
|
|
|
|
reg [63:0] imask_reg;
|
2016-03-13 09:28:17 -04:00
|
|
|
reg [63:0] read_data;
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//nets
|
|
|
|
wire [N-1:0] gpio_sync;
|
2016-03-05 07:28:28 -05:00
|
|
|
wire [N-1:0] gpio_edge;
|
2016-03-05 16:16:22 -05:00
|
|
|
wire [N-1:0] edge_data;
|
2016-03-05 07:28:28 -05:00
|
|
|
wire [63:0] reg_wdata;
|
2016-03-05 16:16:22 -05:00
|
|
|
wire [63:0] out_dmux;
|
2016-01-23 00:09:14 -05:00
|
|
|
integer i,j;
|
2016-03-05 07:28:28 -05:00
|
|
|
|
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
|
|
|
|
|
|
|
|
//################################
|
|
|
|
//# SYNCHRONIZE INPUT DATA
|
|
|
|
//################################
|
2016-03-05 16:16:22 -05:00
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
oh_dsync #(.DW(N))
|
|
|
|
dsync (.dout (gpio_sync[N-1:0]),
|
|
|
|
.clk (clk),
|
|
|
|
.din (gpio_in[N-1:0]));
|
|
|
|
|
|
|
|
//################################
|
|
|
|
//# REGISTER ACCESS DECODE
|
|
|
|
//################################
|
2016-02-26 19:06:38 -05:00
|
|
|
|
2016-03-13 09:28:17 -04:00
|
|
|
packet2emesh p2e(
|
2016-01-23 00:09:14 -05:00
|
|
|
/*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]),
|
2016-03-13 09:28:17 -04:00
|
|
|
.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;
|
|
|
|
assign reg_wdata[63:0] = {srcaddr_in[31:0],data_in[31:0]};
|
|
|
|
|
2016-03-13 09:28:17 -04:00
|
|
|
assign oen_write = reg_write & (dstaddr_in[6:3]==`GPIO_OEN);
|
|
|
|
assign out_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUT);
|
|
|
|
assign ien_write = reg_write & (dstaddr_in[6:3]==`GPIO_IEN);
|
|
|
|
assign in_write = reg_write & (dstaddr_in[6:3]==`GPIO_IN);
|
|
|
|
assign outand_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTAND);
|
|
|
|
assign outorr_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTORR);
|
|
|
|
assign outxor_write = reg_write & (dstaddr_in[6:3]==`GPIO_OUTXOR);
|
|
|
|
assign imask_write = reg_write & (dstaddr_in[6:3]==`GPIO_IMASK);
|
2016-03-05 16:16:22 -05:00
|
|
|
|
|
|
|
assign out_reg_write = out_write |
|
|
|
|
outand_write |
|
|
|
|
outorr_write |
|
|
|
|
outxor_write;
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-03-05 07:28:28 -05:00
|
|
|
//# OUTPUT
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
2016-03-05 07:28:28 -05:00
|
|
|
//oen (active low, tristate by default)
|
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
|
|
|
oen_reg[63:0] <= 'b0;
|
|
|
|
else if(oen_write & reg_double)
|
|
|
|
oen_reg[63:0] <= reg_wdata[63:0];
|
|
|
|
else if(oen_write)
|
|
|
|
oen_reg[31:0] <= reg_wdata[31:0];
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
assign gpio_oen[N-1:0] = oen_reg[N-1:0];
|
|
|
|
|
|
|
|
//odata
|
2016-03-05 16:16:22 -05:00
|
|
|
oh_mux4 #(.DW(64))
|
|
|
|
oh_mux4 (.out (out_dmux[63:0]),
|
|
|
|
// Inputs
|
|
|
|
.in0 (reg_wdata[63:0] ),.sel0 (out_write),
|
|
|
|
.in1 (out_reg[63:0] & reg_wdata[63:0]),.sel1 (outand_write),
|
|
|
|
.in2 (out_reg[63:0] | reg_wdata[63:0]),.sel2 (outorr_write),
|
|
|
|
.in3 (out_reg[63:0] ^ reg_wdata[63:0]),.sel3 (outxor_write));
|
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
always @ (posedge clk)
|
2016-03-05 16:16:22 -05:00
|
|
|
if(out_reg_write & reg_double)
|
|
|
|
out_reg[63:0] <= out_dmux[63:0];
|
|
|
|
else if(out_reg_write)
|
|
|
|
out_reg[31:0] <= out_dmux[31:0];
|
2016-03-05 07:28:28 -05:00
|
|
|
|
2016-03-05 16:16:22 -05:00
|
|
|
assign gpio_out[N-1:0] = out_reg[N-1:0];
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
//################################
|
|
|
|
//# INPUT
|
|
|
|
//################################
|
|
|
|
|
|
|
|
//ien
|
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
|
|
|
ien_reg[63:0] <= {(64){1'b1}};
|
|
|
|
else if(ien_write & reg_double)
|
|
|
|
ien_reg[63:0] <= reg_wdata[63:0];
|
|
|
|
else if(ien_write)
|
|
|
|
ien_reg[31:0] <= reg_wdata[31:0];
|
|
|
|
|
|
|
|
//idata
|
2016-01-23 00:09:14 -05:00
|
|
|
always @ (posedge clk)
|
2016-03-05 16:16:22 -05:00
|
|
|
in_reg[63:0] <= gpio_sync[N-1:0] & ien_reg[63:0];
|
2016-01-23 00:09:14 -05:00
|
|
|
|
2016-03-05 16:16:22 -05:00
|
|
|
assign gpio_data[N-1:0] = in_reg[63:0];
|
2016-01-23 00:09:14 -05:00
|
|
|
|
|
|
|
//################################
|
2016-03-05 16:16:22 -05:00
|
|
|
//# EDGE DETECTOR
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
|
|
|
|
2016-03-05 07:28:28 -05:00
|
|
|
always @ (posedge clk or negedge nreset)
|
|
|
|
if(!nreset)
|
2016-03-05 16:16:22 -05:00
|
|
|
imask_reg[63:0] <= 'b0;
|
|
|
|
else if(imask_write & reg_double)
|
|
|
|
imask_reg[63:0] <= reg_wdata[63:0];
|
|
|
|
else if(imask_write)
|
|
|
|
imask_reg[31:0] <= reg_wdata[31:0];
|
|
|
|
|
|
|
|
assign edge_data[N-1:0] = ~imask_reg[N-1:0] & in_reg[N-1:0];
|
2016-03-05 07:28:28 -05:00
|
|
|
|
|
|
|
//detect any edge on input data
|
|
|
|
oh_edgedetect #(.DW(N))
|
|
|
|
oh_edgedetect (.out (gpio_edge[N-1:0]),
|
|
|
|
.clk (clk),
|
|
|
|
.cfg (2'b11), //toggle detect
|
2016-03-05 16:16:22 -05:00
|
|
|
.in (edge_data[N-1:0])
|
|
|
|
);
|
2016-03-05 07:28:28 -05:00
|
|
|
|
|
|
|
assign gpio_irq = |gpio_edge[N-1:0];
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
//################################
|
|
|
|
//# READBACK
|
|
|
|
//################################
|
2016-03-05 07:28:28 -05:00
|
|
|
|
|
|
|
assign odd = (N>32) & dstaddr_in[2];
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
always @ (posedge clk)
|
2016-02-26 19:06:38 -05:00
|
|
|
if(reg_read)
|
2016-03-13 09:28:17 -04:00
|
|
|
case(dstaddr_in[6:3])
|
|
|
|
`GPIO_OEN :read_data[31:0]<= odd ? oen_reg[63:32] : oen_reg[31:0];
|
|
|
|
`GPIO_OUT :read_data[31:0]<= odd ? out_reg[63:32] : out_reg[31:0];
|
|
|
|
`GPIO_IEN :read_data[31:0]<= odd ? ien_reg[63:32] : ien_reg[31:0];
|
|
|
|
`GPIO_IN :read_data[31:0]<= odd ? in_reg[63:32] : in_reg[31:0];
|
|
|
|
`GPIO_IMASK:read_data[31:0]<= odd ? imask_reg[63:32]:imask_reg[31:0];
|
|
|
|
default :read_data[31:0]<='b0;
|
2016-03-05 07:28:28 -05:00
|
|
|
endcase // case (dstaddr_in[7:3])
|
2016-03-13 09:28:17 -04:00
|
|
|
|
|
|
|
emesh_readback #(.AW(AW))
|
|
|
|
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]),
|
|
|
|
.read_data (read_data[63:0]),
|
|
|
|
.wait_in (wait_in));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-23 00:09:14 -05:00
|
|
|
endmodule // gpio
|
|
|
|
// Local Variables:
|
|
|
|
// verilog-library-directories:("." "../../emesh/hdl" "../../common/hdl")
|
|
|
|
// End:
|
|
|
|
|
2016-03-08 19:37:42 -05:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The MIT License (MIT) //
|
|
|
|
// //
|
|
|
|
// Copyright (c) 2015-2016, Adapteva, Inc. //
|
|
|
|
// //
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a //
|
|
|
|
// copy of this software and associated documentation files (the "Software")//
|
|
|
|
// to deal in the Software without restriction, including without limitation//
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the //
|
|
|
|
// Software is furnished to do so, subject to the following conditions: //
|
|
|
|
// //
|
|
|
|
// The above copyright notice and this permission notice shall be included //
|
|
|
|
// in all copies or substantial portions of the Software. //
|
|
|
|
// //
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS //
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. //
|
|
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY //
|
|
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT//
|
|
|
|
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR //
|
|
|
|
// THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
|
|
|
|
// //
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|