diff options
Diffstat (limited to 'control_lib')
| -rw-r--r-- | control_lib/pic.v | 183 | ||||
| -rw-r--r-- | control_lib/priority_enc.v | 44 | 
2 files changed, 227 insertions, 0 deletions
diff --git a/control_lib/pic.v b/control_lib/pic.v new file mode 100644 index 000000000..9b9944d4a --- /dev/null +++ b/control_lib/pic.v @@ -0,0 +1,183 @@ + +// 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 diff --git a/control_lib/priority_enc.v b/control_lib/priority_enc.v new file mode 100644 index 000000000..916192445 --- /dev/null +++ b/control_lib/priority_enc.v @@ -0,0 +1,44 @@ + +module priority_enc +  (input [31:0] in, +   output reg [31:0] out); + +   always @* +     casex(in) +       32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 31; +       32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 30; +       32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 29; +       32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 28; +       32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 27; +       32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 26; +       32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 25; +       32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 24; +       32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 23; +       32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 22; +       32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 21; +       32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 20; +       32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx : out <= 19; +       32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx : out <= 18; +       32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx : out <= 17; +       32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx : out <= 16; +       32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx : out <= 15; +       32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx : out <= 14; +       32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx : out <= 13; +       32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx : out <= 12; +       32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx : out <= 11; +       32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx : out <= 10; +       32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx : out <=  9; +       32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx : out <=  8; +       32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx : out <=  7; +       32'b0000_0000_0000_0000_0000_0000_01xx_xxxx : out <=  6; +       32'b0000_0000_0000_0000_0000_0000_001x_xxxx : out <=  5; +       32'b0000_0000_0000_0000_0000_0000_0001_xxxx : out <=  4; +       32'b0000_0000_0000_0000_0000_0000_0000_1xxx : out <=  3; +       32'b0000_0000_0000_0000_0000_0000_0000_01xx : out <=  2; +       32'b0000_0000_0000_0000_0000_0000_0000_001x : out <=  1; +       32'b0000_0000_0000_0000_0000_0000_0000_0001 : out <=  0; +       32'b0000_0000_0000_0000_0000_0000_0000_0000 : out <= 32'hFFFF_FFFF; +       default : out <= 32'hFFFF_FFFF; +     endcase // casex (in) +    +endmodule // priority_enc  | 
