mirror of
				https://github.com/fairwaves/UHD-Fairwaves.git
				synced 2025-11-04 05:53:17 +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
 |