mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-11-02 21:13:14 +00:00
184 lines
7.3 KiB
Verilog
184 lines
7.3 KiB
Verilog
|
|
// Heavily modified by M. Ettus, 2009, little original code remains
|
|
// Modified by M. Ettus, 2008 for 32 bit width
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// OpenCores Simple Programmable Interrupt Controller ////
|
|
//// ////
|
|
//// Author: Richard Herveille ////
|
|
//// richard@asics.ws ////
|
|
//// www.asics.ws ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
//// ////
|
|
//// Copyright (C) 2002 Richard Herveille ////
|
|
//// richard@asics.ws ////
|
|
//// ////
|
|
//// This source file may be used and distributed without ////
|
|
//// restriction provided that this copyright statement is not ////
|
|
//// removed from the file and that any derivative work contains ////
|
|
//// the original copyright notice and the associated disclaimer.////
|
|
//// ////
|
|
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
|
|
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
|
|
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
|
|
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
|
|
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
|
|
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
|
|
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
|
|
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
|
|
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
|
|
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
|
|
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
|
|
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
|
|
//// POSSIBILITY OF SUCH DAMAGE. ////
|
|
//// ////
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This is a simple Programmable Interrupt Controller.
|
|
// The number of interrupts is depending on the databus size.
|
|
// There's one interrupt input per databit (i.e. 16 interrupts for a 16
|
|
// bit databus).
|
|
// All attached devices share the same CPU priority level.
|
|
//
|
|
//
|
|
//
|
|
// Registers:
|
|
//
|
|
// 0x00: EdgeEnable Register
|
|
// bits 7:0 R/W Edge Enable '1' = edge triggered interrupt source
|
|
// '0' = level triggered interrupt source
|
|
// 0x01: PolarityRegister
|
|
// bits 7:0 R/W Polarity '1' = high level / rising edge
|
|
// '0' = low level / falling edge
|
|
// 0x02: MaskRegister
|
|
// bits 7:0 R/W Mask '1' = interrupt masked (disabled)
|
|
// '0' = interrupt not masked (enabled)
|
|
// 0x03: PendingRegister
|
|
// bits 7:0 R/W Pending '1' = interrupt pending
|
|
// '0' = no interrupt pending
|
|
//
|
|
// A CPU interrupt is generated when an interrupt is pending and its
|
|
// MASK bit is cleared.
|
|
//
|
|
//
|
|
//
|
|
// HOWTO:
|
|
//
|
|
// Clearing pending interrupts:
|
|
// Writing a '1' to a bit in the interrupt pending register clears the
|
|
// interrupt. Make sure to clear the interrupt at the source before
|
|
// writing to the interrupt pending register. Otherwise the interrupt
|
|
// will be set again.
|
|
//
|
|
// Priority based interrupts:
|
|
// Upon reception of an interrupt, check the interrupt register and
|
|
// determine the highest priority interrupt. Mask all interrupts from the
|
|
// current level to the lowest level. This negates the interrupt line, and
|
|
// makes sure only interrupts with a higher level are triggered. After
|
|
// completion of the interrupt service routine, clear the interrupt source,
|
|
// the interrupt bit in the pending register, and restore the MASK register
|
|
// to it's previous state.
|
|
//
|
|
// Addapt the core for fewer interrupt sources:
|
|
// If less than 8 interrupt sources are required, than the 'is' parameter
|
|
// can be set to the amount of required interrupts. Interrupts are mapped
|
|
// starting at the LSBs. So only the 'is' LSBs per register are valid. All
|
|
// other bits (i.e. the 8-'is' MSBs) are set to zero '0'.
|
|
// Codesize is approximately linear to the amount of interrupts. I.e. using
|
|
// 4 instead of 8 interrupt sources reduces the size by approx. half.
|
|
//
|
|
|
|
|
|
module pic
|
|
(input clk_i, input rst_i, input cyc_i, input stb_i,
|
|
input [2:0] adr_i,
|
|
input we_i,
|
|
input [31:0] dat_i,
|
|
output reg [31:0] dat_o,
|
|
output reg ack_o,
|
|
output reg int_o,
|
|
input [31:0] irq
|
|
);
|
|
|
|
reg [31:0] pol, edgen, pending, mask; // register bank
|
|
reg [31:0] lirq, dirq; // latched irqs, delayed latched irqs
|
|
|
|
// latch interrupt inputs
|
|
always @(posedge clk_i)
|
|
lirq <= irq;
|
|
|
|
// generate delayed latched irqs
|
|
always @(posedge clk_i)
|
|
dirq <= lirq;
|
|
|
|
// generate actual triggers
|
|
function trigger;
|
|
input edgen, pol, lirq, dirq;
|
|
reg edge_irq, level_irq;
|
|
begin
|
|
edge_irq = pol ? (lirq & ~dirq) : (dirq & ~lirq);
|
|
level_irq = pol ? lirq : ~lirq;
|
|
trigger = edgen ? edge_irq : level_irq;
|
|
end
|
|
endfunction
|
|
|
|
reg [31:0] irq_event;
|
|
integer n;
|
|
always @(posedge clk_i)
|
|
for(n = 0; n < 32; n = n+1)
|
|
irq_event[n] <= trigger(edgen[n], pol[n], lirq[n], dirq[n]);
|
|
|
|
// generate wishbone register bank writes
|
|
wire wb_acc = cyc_i & stb_i; // WISHBONE access
|
|
wire wb_wr = wb_acc & we_i; // WISHBONE write access
|
|
|
|
always @(posedge clk_i)
|
|
if (rst_i)
|
|
begin
|
|
pol <= 0; // clear polarity register
|
|
edgen <= 0; // clear edge enable register
|
|
mask <= 0; // mask all interrupts
|
|
end
|
|
else if(wb_wr) // wishbone write cycle??
|
|
case (adr_i) // synopsys full_case parallel_case
|
|
3'd0 : edgen <= dat_i; // EDGE-ENABLE register
|
|
3'd1 : pol <= dat_i; // POLARITY register
|
|
3'd2 : mask <= dat_i; // MASK register
|
|
3'd3 : ; // PENDING register is a special case (see below)
|
|
3'd4 : ; // Priority encoded live (pending & ~mask)
|
|
endcase
|
|
|
|
// pending register is a special case
|
|
always @(posedge clk_i)
|
|
if (rst_i)
|
|
pending <= 0; // clear all pending interrupts
|
|
else if ( wb_wr & (adr_i == 3'd3) )
|
|
pending <= (pending & ~dat_i) | irq_event;
|
|
else
|
|
pending <= pending | irq_event;
|
|
|
|
wire [31:0] live_enc;
|
|
priority_enc priority_enc ( .in(pending & ~mask), .out(live_enc) );
|
|
|
|
always @(posedge clk_i)
|
|
case (adr_i) // synopsys full_case parallel_case
|
|
3'd0 : dat_o <= edgen;
|
|
3'd1 : dat_o <= pol;
|
|
3'd2 : dat_o <= mask;
|
|
3'd3 : dat_o <= pending;
|
|
3'd4 : dat_o <= live_enc;
|
|
endcase
|
|
|
|
always @(posedge clk_i)
|
|
ack_o <= wb_acc & !ack_o;
|
|
|
|
always @(posedge clk_i)
|
|
if(rst_i)
|
|
int_o <= 0;
|
|
else
|
|
int_o <= |(pending & ~mask);
|
|
|
|
endmodule
|