//   ==================================================================
//   >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
//   ------------------------------------------------------------------
//   Copyright (c) 2006-2011 by Lattice Semiconductor Corporation
//   ALL RIGHTS RESERVED 
//   ------------------------------------------------------------------
//
//   IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM.
//
//   Permission:
//
//      Lattice Semiconductor grants permission to use this code
//      pursuant to the terms of the Lattice Semiconductor Corporation
//      Open Source License Agreement.  
//
//   Disclaimer:
//
//      Lattice Semiconductor provides no warranty regarding the use or
//      functionality of this code. It is the user's responsibility to
//      verify the user’s design for consistency and functionality through
//      the use of formal verification methods.
//
//   --------------------------------------------------------------------
//
//                  Lattice Semiconductor Corporation
//                  5555 NE Moore Court
//                  Hillsboro, OR 97214
//                  U.S.A
//
//                  TEL: 1-800-Lattice (USA and Canada)
//                         503-286-8001 (other locations)
//
//                  web: http://www.latticesemi.com/
//                  email: techsupport@latticesemi.com
//
//   --------------------------------------------------------------------
//                         FILE DETAILS
// Project          : LatticeMico32
// File             : lm32_interrupt.v
// Title            : Interrupt logic
// Dependencies     : lm32_include.v
// Version          : 6.1.17
//                  : Initial Release
// Version          : 7.0SP2, 3.0
//                  : No Change
// Version          : 3.1
//                  : No Change
// =============================================================================

`include "lm32_include.v"

/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////

module lm32_interrupt (
    // ----- Inputs -------
    clk_i, 
    rst_i,
    // From external devices
    interrupt_n,
    // From pipeline
    stall_x,
`ifdef CFG_DEBUG_ENABLED
    non_debug_exception,
    debug_exception,
`else
    exception,
`endif
    eret_q_x,
`ifdef CFG_DEBUG_ENABLED
    bret_q_x,
`endif
    csr,
    csr_write_data,
    csr_write_enable,
    // ----- Outputs -------
    interrupt_exception,
    // To pipeline
    csr_read_data
    );

/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////

parameter interrupts = `CFG_INTERRUPTS;         // Number of interrupts

/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////

input clk_i;                                    // Clock
input rst_i;                                    // Reset

input [interrupts-1:0] interrupt_n;             // Interrupt pins, active-low
                           
input stall_x;                                  // Stall X pipeline stage

`ifdef CFG_DEBUG_ENABLED
input non_debug_exception;                      // Non-debug related exception has been raised
input debug_exception;                          // Debug-related exception has been raised
`else
input exception;                                // Exception has been raised
`endif
input eret_q_x;                                 // Return from exception 
`ifdef CFG_DEBUG_ENABLED
input bret_q_x;                                 // Return from breakpoint 
`endif

input [`LM32_CSR_RNG] csr;                      // CSR read/write index
input [`LM32_WORD_RNG] csr_write_data;          // Data to write to specified CSR
input csr_write_enable;                         // CSR write enable

/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////

output interrupt_exception;                     // Request to raide an interrupt exception
wire   interrupt_exception;

output [`LM32_WORD_RNG] csr_read_data;          // Data read from CSR
reg    [`LM32_WORD_RNG] csr_read_data;

/////////////////////////////////////////////////////
// Internal nets and registers 
/////////////////////////////////////////////////////

wire [interrupts-1:0] asserted;                 // Which interrupts are currently being asserted
//pragma attribute asserted preserve_signal true
wire [interrupts-1:0] interrupt_n_exception;

// Interrupt CSRs

reg ie;                                         // Interrupt enable
reg eie;                                        // Exception interrupt enable
`ifdef CFG_DEBUG_ENABLED
reg bie;                                        // Breakpoint interrupt enable
`endif
reg [interrupts-1:0] ip;                        // Interrupt pending
reg [interrupts-1:0] im;                        // Interrupt mask

/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////

// Determine which interrupts have occured and are unmasked
assign interrupt_n_exception = ip & im;

// Determine if any unmasked interrupts have occured
assign interrupt_exception = (|interrupt_n_exception) & ie;

// Determine which interrupts are currently being asserted (active-low) or are already pending
assign asserted = ip | ~interrupt_n;
       
assign ie_csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}}, 
`ifdef CFG_DEBUG_ENABLED
                           bie,
`else
                           1'b0,
`endif                             
                           eie, 
                           ie
                          };
assign ip_csr_read_data = ip;
assign im_csr_read_data = im;
generate
    if (interrupts > 1) 
    begin
// CSR read
always @(*)
begin
    case (csr)
    `LM32_CSR_IE:  csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}}, 
`ifdef CFG_DEBUG_ENABLED
                                    bie,
`else
                                    1'b0,                                     
`endif
                                    eie, 
                                    ie
                                   };
    `LM32_CSR_IP:  csr_read_data = ip;
    `LM32_CSR_IM:  csr_read_data = im;
    default:       csr_read_data = {`LM32_WORD_WIDTH{1'bx}};
    endcase
end
    end
    else
    begin
// CSR read
always @(*)
begin
    case (csr)
    `LM32_CSR_IE:  csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}}, 
`ifdef CFG_DEBUG_ENABLED
                                    bie, 
`else
                                    1'b0,                                    
`endif
                                    eie, 
                                    ie
                                   };
    `LM32_CSR_IP:  csr_read_data = ip;
    default:       csr_read_data = {`LM32_WORD_WIDTH{1'bx}};
    endcase
end
    end
endgenerate
    
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////

generate
    if (interrupts > 1)
    begin
// IE, IM, IP - Interrupt Enable, Interrupt Mask and Interrupt Pending CSRs
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
    begin
        ie <= #1 `FALSE;
        eie <= #1 `FALSE;
`ifdef CFG_DEBUG_ENABLED
        bie <= #1 `FALSE;
`endif
        im <= #1 {interrupts{1'b0}};
        ip <= #1 {interrupts{1'b0}};
    end
    else
    begin
        // Set IP bit when interrupt line is asserted
        ip <= #1 asserted;
`ifdef CFG_DEBUG_ENABLED
        if (non_debug_exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            eie <= #1 ie;
            ie <= #1 `FALSE;
        end
        else if (debug_exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            bie <= #1 ie;
            ie <= #1 `FALSE;
        end
`else
        if (exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            eie <= #1 ie;
            ie <= #1 `FALSE;
        end
`endif
        else if (stall_x == `FALSE)
        begin
            if (eret_q_x == `TRUE)
                // Restore interrupt enable
                ie <= #1 eie;          
`ifdef CFG_DEBUG_ENABLED
            else if (bret_q_x == `TRUE)
                // Restore interrupt enable
                ie <= #1 bie;
`endif
            else if (csr_write_enable == `TRUE)
            begin
                // Handle wcsr write
                if (csr == `LM32_CSR_IE)
                begin
                    ie <= #1 csr_write_data[0];
                    eie <= #1 csr_write_data[1];
`ifdef CFG_DEBUG_ENABLED
                    bie <= #1 csr_write_data[2];
`endif
                end
                if (csr == `LM32_CSR_IM)
                    im <= #1 csr_write_data[interrupts-1:0];
                if (csr == `LM32_CSR_IP)
                    ip <= #1 asserted & ~csr_write_data[interrupts-1:0];
            end
        end
    end
end
    end
else
    begin
// IE, IM, IP - Interrupt Enable, Interrupt Mask and Interrupt Pending CSRs
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
    if (rst_i == `TRUE)
    begin
        ie <= #1 `FALSE;
        eie <= #1 `FALSE;
`ifdef CFG_DEBUG_ENABLED
        bie <= #1 `FALSE;
`endif
        ip <= #1 {interrupts{1'b0}};
    end
    else
    begin
        // Set IP bit when interrupt line is asserted
        ip <= #1 asserted;
`ifdef CFG_DEBUG_ENABLED
        if (non_debug_exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            eie <= #1 ie;
            ie <= #1 `FALSE;
        end
        else if (debug_exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            bie <= #1 ie;
            ie <= #1 `FALSE;
        end
`else
        if (exception == `TRUE)
        begin
            // Save and then clear interrupt enable
            eie <= #1 ie;
            ie <= #1 `FALSE;
        end
`endif
        else if (stall_x == `FALSE)
        begin
            if (eret_q_x == `TRUE)
                // Restore interrupt enable
                ie <= #1 eie;          
`ifdef CFG_DEBUG_ENABLED
            else if (bret_q_x == `TRUE)
                // Restore interrupt enable
                ie <= #1 bie;
`endif
            else if (csr_write_enable == `TRUE)
            begin
                // Handle wcsr write
                if (csr == `LM32_CSR_IE)
                begin
                    ie <= #1 csr_write_data[0];
                    eie <= #1 csr_write_data[1];
`ifdef CFG_DEBUG_ENABLED
                    bie <= #1 csr_write_data[2];
`endif
                end
                if (csr == `LM32_CSR_IP)
                    ip <= #1 asserted & ~csr_write_data[interrupts-1:0];
            end
        end
    end
end
    end
endgenerate

endmodule

