| ////////////////////////////////////////////////////////////////////////////// |
| // SPDX-FileCopyrightText: Syntacore LLC © 2016-2021 |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileContributor: Syntacore LLC |
| // ////////////////////////////////////////////////////////////////////////// |
| /// @file <scr1_ipic.sv> |
| /// @brief Integrated Programmable Interrupt Controller (IPIC) |
| /// |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Functionality: |
| // - Synchronizes IRQ lines (optional) |
| // - Detects level and edge (with optional lines inversion) of IRQ lines |
| // - Setups interrupts handling (mode, inversion, enable) |
| // - Provides information about pending interrupts and interrupts currently in |
| // service |
| // - Generates interrupt request to CSR |
| // |
| // Structure: |
| // - IRQ lines handling (synchronization, level and edge detection) logic |
| // - IPIC registers: |
| // - CISV |
| // - CICSR |
| // - EOI |
| // - SOI |
| // - IDX |
| // - IPR |
| // - ISVR |
| // - IER |
| // - IMR |
| // - IINVR |
| // - ICSR |
| // - Priority interrupt generation logic |
| // |
| //------------------------------------------------------------------------------ |
| |
| `include "scr1_arch_description.svh" |
| |
| `ifdef SCR1_IPIC_EN |
| |
| `include "scr1_ipic.svh" |
| |
| module scr1_ipic |
| ( |
| // Common |
| input logic rst_n, // IPIC reset |
| input logic clk, // IPIC clock |
| |
| // External Interrupt lines |
| input logic [SCR1_IRQ_LINES_NUM-1:0] soc2ipic_irq_lines_i, // External IRQ lines |
| |
| // CSR <-> IPIC interface |
| input logic csr2ipic_r_req_i, // IPIC read request |
| input logic csr2ipic_w_req_i, // IPIC write request |
| input logic [2:0] csr2ipic_addr_i, // IPIC address |
| input logic [`SCR1_XLEN-1:0] csr2ipic_wdata_i, // IPIC write data |
| output logic [`SCR1_XLEN-1:0] ipic2csr_rdata_o, // IPIC read data |
| output logic ipic2csr_irq_m_req_o // IRQ request from IPIC |
| ); |
| |
| //------------------------------------------------------------------------------- |
| // Local types declaration |
| //------------------------------------------------------------------------------- |
| typedef struct packed { // cp.6 |
| logic vd; |
| logic idx; |
| } type_scr1_search_one_2_s; |
| |
| typedef struct packed { // cp.6 |
| logic vd; |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] idx; |
| } type_scr1_search_one_16_s; |
| |
| typedef struct packed { |
| logic ip; |
| logic ie; |
| logic im; |
| logic inv; |
| logic is; |
| logic [SCR1_IRQ_LINES_WIDTH-1:0] line; |
| } type_scr1_icsr_m_s; |
| |
| typedef struct packed { |
| logic ip; |
| logic ie; |
| } type_scr1_cicsr_s; |
| |
| //------------------------------------------------------------------------------- |
| // Local functions declaration |
| //------------------------------------------------------------------------------- |
| |
| function automatic type_scr1_search_one_2_s scr1_search_one_2( |
| input logic [1:0] din |
| ); |
| type_scr1_search_one_2_s tmp; |
| begin |
| tmp.vd = |din; |
| tmp.idx = ~din[0]; |
| scr1_search_one_2 = tmp; |
| end |
| endfunction |
| |
| function automatic type_scr1_search_one_16_s scr1_search_one_16( |
| input logic [15:0] din |
| ); |
| logic [7:0] stage1_vd; |
| logic [3:0] stage2_vd; |
| logic [1:0] stage3_vd; |
| |
| logic stage1_idx [7:0]; |
| logic [1:0] stage2_idx [3:0]; |
| logic [2:0] stage3_idx [1:0]; |
| type_scr1_search_one_16_s result; |
| type_scr1_search_one_2_s tmp; |
| integer i; // cp.17 |
| begin |
| // Stage 1 |
| for (i=0; i<8; i=i+1) begin |
| tmp = scr1_search_one_2(din[(i+1)*2-1-:2]); |
| stage1_vd[i] = tmp.vd; |
| stage1_idx[i] = tmp.idx; |
| end |
| |
| // Stage 2 |
| for (i=0; i<4; i=i+1) begin |
| tmp = scr1_search_one_2(stage1_vd[(i+1)*2-1-:2]); |
| stage2_vd[i] = tmp.vd; |
| stage2_idx[i] = (~tmp.idx) ? {tmp.idx, stage1_idx[2*i]} : {tmp.idx, stage1_idx[2*i+1]}; |
| end |
| |
| // Stage 3 |
| for (i=0; i<2; i=i+1) begin |
| tmp = scr1_search_one_2(stage2_vd[(i+1)*2-1-:2]); |
| stage3_vd[i] = tmp.vd; |
| stage3_idx[i] = (~tmp.idx) ? {tmp.idx, stage2_idx[2*i]} : {tmp.idx, stage2_idx[2*i+1]}; |
| end |
| |
| // Stage 4 |
| result.vd = |stage3_vd; |
| result.idx = (stage3_vd[0]) ? {1'b0, stage3_idx[0]} : {1'b1, stage3_idx[1]}; |
| |
| scr1_search_one_16 = result; |
| end |
| endfunction |
| |
| //------------------------------------------------------------------------------ |
| // Local signals declaration |
| //------------------------------------------------------------------------------ |
| |
| // IRQ lines handling signals |
| //------------------------------------------------------------------------------ |
| |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines; // Internal IRQ lines |
| `ifdef SCR1_IPIC_SYNC_EN |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_sync; |
| `endif // SCR1_IPIC_SYNC_EN |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_lines_dly; // Internal IRQ lines delayed for 1 cycle |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_edge_detected; // IRQ lines edge detected flags |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_lvl; // IRQ lines level |
| |
| // IPIC registers |
| //------------------------------------------------------------------------------ |
| |
| // CISV register |
| logic ipic_cisv_upd; // Current Interrupt Vecotr in Service register update |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_ff; // Current Interrupt Vector in Service register |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] ipic_cisv_next; // Current Interrupt Vector in Service register next value |
| |
| // CICS register (CICSR) |
| logic cicsr_wr_req; // Write request to Current Interrupt Control Status register |
| type_scr1_cicsr_s ipic_cicsr; // Current Interrupt Control Status register |
| |
| // EOI register |
| logic eoi_wr_req; // Write request to End of Interrupt register |
| logic ipic_eoi_req; // Request to end the interrupt that is currently in service |
| |
| // SOI register |
| logic soi_wr_req; // Write request to Start of Interrupt register |
| logic ipic_soi_req; // Request to start the interrupt |
| |
| // IDX register (IDXR) |
| logic idxr_wr_req; // Write request to Index register |
| logic [SCR1_IRQ_IDX_WIDTH-1:0] ipic_idxr_ff; // Index register |
| |
| // IP register (IPR) |
| logic ipic_ipr_upd; // Interrupt pending register update |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_ff; // Interrupt pending register |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_next; // Interrupt pending register next value |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_cond; // Interrupt pending clear condition |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr_req; // Interrupt pending clear request |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ipr_clr; // Interrupt pending clear operation |
| |
| // ISV register (ISVR) |
| logic ipic_isvr_upd; // Interrupt Serviced register update |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_ff; // Interrupt Serviced register |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_next; // Interrupt Serviced register next value |
| |
| // IE register (IER) |
| logic ipic_ier_upd; // Interrupt enable register update |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_ff; // Interrupt enable register |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_ier_next; // Interrupt enable register next value |
| |
| // IM register (IMR) |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_ff; // Interrupt mode register |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_imr_next; // Interrupt mode register next value |
| |
| // IINV register (IINVR) |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_ff; // Interrupt Inversion register |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_iinvr_next; // Interrupt Inversion register next value |
| |
| // ICS register (ICSR) |
| logic icsr_wr_req; // Write request to Interrupt Control Status register |
| type_scr1_icsr_m_s ipic_icsr; // Interrupt Control Status register |
| |
| // Priority interrupt generation signals |
| //------------------------------------------------------------------------------ |
| |
| // Serviced interrupt signals |
| logic irq_serv_vd; // There is an interrupt in service |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] irq_serv_idx; // Index of an interrupt that is currently in service |
| |
| // Requested interrupt signals |
| logic irq_req_vd; // There is a requested interrupt |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] irq_req_idx; // Index of a requested interrupt |
| |
| // Interrupt requested on "end of the previous interrupt" signals |
| logic irq_eoi_req_vd; // There is a requested interrupt when the previous one has ended |
| logic [SCR1_IRQ_VECT_WIDTH-1:0] irq_eoi_req_idx; // Index of an interrupt requested when the previous one has ended |
| |
| logic [SCR1_IRQ_VECT_NUM-1:0] irq_req_v; // Vector of interrupts that are pending and enabled |
| |
| logic irq_start_vd; // Request to start an interrupt is valid |
| logic irq_hi_prior_pnd; // There is a pending IRQ with a priority higher than of the interrupt that is currently in service |
| |
| type_scr1_search_one_16_s irr_priority; // Structure for vd and idx of the requested interrupt |
| type_scr1_search_one_16_s isvr_priority_eoi; // Structure for vd and idx of the interrupt requested when the previous interrupt has ended |
| logic [SCR1_IRQ_VECT_NUM-1:0] ipic_isvr_eoi; // Interrupt Serviced register when the previous interrupt has ended |
| |
| //------------------------------------------------------------------------------ |
| // IRQ lines handling |
| //------------------------------------------------------------------------------ |
| |
| `ifdef SCR1_IPIC_SYNC_EN |
| // IRQ lines synchronization |
| //------------------------------------------------------------------------------ |
| |
| always_ff @(posedge clk, negedge rst_n) begin |
| if (~rst_n) begin |
| irq_lines_sync <= '0; |
| irq_lines <= '0; |
| end else begin |
| irq_lines_sync <= soc2ipic_irq_lines_i; |
| irq_lines <= irq_lines_sync; |
| end |
| end |
| `else // SCR1_IPIC_SYNC_EN |
| assign irq_lines = soc2ipic_irq_lines_i; |
| `endif // SCR1_IPIC_SYNC_EN |
| |
| // IRQ lines level detection |
| //------------------------------------------------------------------------------ |
| |
| assign irq_lvl = irq_lines ^ ipic_iinvr_next; |
| |
| // IRQ lines edge detection |
| //------------------------------------------------------------------------------ |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| irq_lines_dly <= '0; |
| end else begin |
| irq_lines_dly <= irq_lines; |
| end |
| end |
| |
| assign irq_edge_detected = (irq_lines_dly ^ irq_lines) & irq_lvl; |
| |
| //------------------------------------------------------------------------------ |
| // IPIC registers read/write interface |
| //------------------------------------------------------------------------------ |
| |
| // Read Logic |
| //------------------------------------------------------------------------------ |
| |
| // Read data multiplexer |
| always_comb begin |
| ipic2csr_rdata_o = '0; |
| |
| if (csr2ipic_r_req_i) begin |
| case (csr2ipic_addr_i) |
| SCR1_IPIC_CISV : begin |
| ipic2csr_rdata_o[SCR1_IRQ_VECT_WIDTH-1:0] = irq_serv_vd |
| ? ipic_cisv_ff |
| : SCR1_IRQ_VOID_VECT_NUM; |
| end |
| SCR1_IPIC_CICSR : begin |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_cicsr.ip; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_cicsr.ie; |
| end |
| SCR1_IPIC_IPR : begin |
| ipic2csr_rdata_o = `SCR1_XLEN'(ipic_ipr_ff); |
| end |
| SCR1_IPIC_ISVR : begin |
| ipic2csr_rdata_o = `SCR1_XLEN'(ipic_isvr_ff); |
| end |
| SCR1_IPIC_EOI, |
| SCR1_IPIC_SOI : begin |
| ipic2csr_rdata_o = '0; |
| end |
| SCR1_IPIC_IDX : begin |
| ipic2csr_rdata_o = `SCR1_XLEN'(ipic_idxr_ff); |
| end |
| SCR1_IPIC_ICSR : begin |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IP] = ipic_icsr.ip; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IE] = ipic_icsr.ie; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IM] = ipic_icsr.im; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_INV] = ipic_icsr.inv; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_PRV_MSB: |
| SCR1_IPIC_ICSR_PRV_LSB] = SCR1_IPIC_PRV_M; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_IS] = ipic_icsr.is; |
| ipic2csr_rdata_o[SCR1_IPIC_ICSR_LN_MSB-1: |
| SCR1_IPIC_ICSR_LN_LSB] = ipic_icsr.line; |
| end |
| default : begin |
| ipic2csr_rdata_o = 'x; |
| end |
| endcase |
| end |
| end |
| |
| // Write logic |
| //------------------------------------------------------------------------------ |
| |
| // Register selection |
| always_comb begin |
| cicsr_wr_req = 1'b0; |
| eoi_wr_req = 1'b0; |
| soi_wr_req = 1'b0; |
| idxr_wr_req = 1'b0; |
| icsr_wr_req = 1'b0; |
| if (csr2ipic_w_req_i) begin |
| case (csr2ipic_addr_i) |
| SCR1_IPIC_CISV : begin end // Quiet Read-Only |
| SCR1_IPIC_CICSR: cicsr_wr_req = 1'b1; |
| SCR1_IPIC_IPR : begin end |
| SCR1_IPIC_ISVR : begin end // Quiet Read-Only |
| SCR1_IPIC_EOI : eoi_wr_req = 1'b1; |
| SCR1_IPIC_SOI : soi_wr_req = 1'b1; |
| SCR1_IPIC_IDX : idxr_wr_req = 1'b1; |
| SCR1_IPIC_ICSR : icsr_wr_req = 1'b1; |
| default : begin // Illegal IPIC register address |
| cicsr_wr_req = 'x; |
| eoi_wr_req = 'x; |
| soi_wr_req = 'x; |
| idxr_wr_req = 'x; |
| icsr_wr_req = 'x; |
| end |
| endcase |
| end |
| end |
| |
| //------------------------------------------------------------------------------ |
| // IPIC registers |
| //------------------------------------------------------------------------------ |
| // |
| // Registers: |
| // - Current Interrupt Vector in Service (CISV) register |
| // - Current Interrupt Control Status (CICSR) register |
| // - End of Interrupt (EOI) register |
| // - Start of Interrupt (SOI) register |
| // - Index (IDX) register |
| // - Interrupt Pending Register (IPR) |
| // - Interrupt Serviced Register (ISVR) |
| // - Interrupt Enable Register (IER) |
| // - Interrupt Mode Register (IMR) |
| // - Interrupt Inversion Register (IINVR) |
| // - Interrupt Control Status Register (ICSR) |
| // |
| |
| // CISV register |
| //------------------------------------------------------------------------------ |
| // Contains number of the interrupt vector currently in service. When no |
| // interrupts are in service, contains number of the void interrupt vector (0x10). |
| // The register cannot contain all 0's |
| |
| assign ipic_cisv_upd = irq_start_vd | ipic_eoi_req; |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_cisv_ff <= SCR1_IRQ_VOID_VECT_NUM; |
| end else if (ipic_cisv_upd) begin |
| ipic_cisv_ff <= ipic_cisv_next; |
| end |
| end |
| |
| assign ipic_cisv_next = irq_start_vd ? irq_req_idx |
| : ipic_eoi_req ? irq_eoi_req_vd ? irq_eoi_req_idx |
| : SCR1_IRQ_VOID_VECT_NUM |
| : 1'b0; |
| |
| assign irq_serv_idx = ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-2:0]; |
| assign irq_serv_vd = ~ipic_cisv_ff[SCR1_IRQ_VECT_WIDTH-1]; |
| |
| // CICSR register |
| //------------------------------------------------------------------------------ |
| // Shows whether the interrupt currently in service is pending and enabled |
| |
| assign ipic_cicsr.ip = ipic_ipr_ff[irq_serv_idx] & irq_serv_vd; |
| assign ipic_cicsr.ie = ipic_ier_ff[irq_serv_idx] & irq_serv_vd; |
| |
| // EOI register |
| //------------------------------------------------------------------------------ |
| // Writing any value to EOI register ends the interrupt which is currently in service |
| |
| assign ipic_eoi_req = eoi_wr_req & irq_serv_vd; |
| |
| // SOI register |
| //------------------------------------------------------------------------------ |
| // Writing any value to SOI activates start of interrupt if one of the following |
| // conditions is true: |
| // - There is at least one pending interrupt with IE and ISR is zero |
| // - There is at least one pending interrupt with IE and higher priority than the |
| // interrupts currently in service |
| |
| assign ipic_soi_req = soi_wr_req & irq_req_vd; |
| |
| // IDX register |
| //------------------------------------------------------------------------------ |
| // Defines the number of interrupt vector which is accessed through the IPIC_ICSR |
| // register |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_idxr_ff <= '0; |
| end else if (idxr_wr_req) begin |
| ipic_idxr_ff <= csr2ipic_wdata_i[SCR1_IRQ_IDX_WIDTH-1:0]; |
| end |
| end |
| |
| // IPR |
| //------------------------------------------------------------------------------ |
| // For every IRQ line shows whether there is a pending interrupt |
| |
| assign ipic_ipr_upd = (ipic_ipr_next != ipic_ipr_ff); |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_ipr_ff <= '0; |
| end else if (ipic_ipr_upd) begin |
| ipic_ipr_ff <= ipic_ipr_next; |
| end |
| end |
| |
| always_comb begin |
| ipic_ipr_clr_req = '0; |
| if (csr2ipic_w_req_i) begin |
| case (csr2ipic_addr_i) |
| SCR1_IPIC_CICSR: ipic_ipr_clr_req[irq_serv_idx] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP] |
| & irq_serv_vd; |
| SCR1_IPIC_IPR : ipic_ipr_clr_req = csr2ipic_wdata_i[SCR1_IRQ_VECT_NUM-1:0]; |
| SCR1_IPIC_SOI : ipic_ipr_clr_req[irq_req_idx] = irq_req_vd; |
| SCR1_IPIC_ICSR : ipic_ipr_clr_req[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IP]; |
| default : begin end |
| endcase |
| end |
| end |
| |
| assign ipic_ipr_clr_cond = ~irq_lvl | ipic_imr_next; |
| assign ipic_ipr_clr = ipic_ipr_clr_req & ipic_ipr_clr_cond; |
| integer i; |
| always_comb begin |
| ipic_ipr_next = '0; |
| for (i=0; i<SCR1_IRQ_VECT_NUM; i=i+1) begin |
| ipic_ipr_next[i] = ipic_ipr_clr[i] ? 1'b0 |
| : ~ipic_imr_ff[i] ? irq_lvl[i] |
| : ipic_ipr_ff[i] | irq_edge_detected[i]; |
| end |
| end |
| |
| // ISVR |
| //------------------------------------------------------------------------------ |
| // For every IRQ line shows whether the interrupt is in service or not |
| |
| assign ipic_isvr_upd = irq_start_vd | ipic_eoi_req; |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_isvr_ff <= '0; |
| end else if (ipic_isvr_upd) begin |
| ipic_isvr_ff <= ipic_isvr_next; |
| end |
| end |
| |
| always_comb begin |
| ipic_isvr_eoi = ipic_isvr_ff; |
| if (irq_serv_vd) begin |
| ipic_isvr_eoi[irq_serv_idx] = 1'b0; |
| end |
| end |
| |
| always_comb begin |
| ipic_isvr_next = ipic_isvr_ff; |
| if (irq_start_vd) begin |
| ipic_isvr_next[irq_req_idx] = 1'b1; |
| end else if (ipic_eoi_req) begin |
| ipic_isvr_next = ipic_isvr_eoi; |
| end |
| end |
| |
| // IER |
| //------------------------------------------------------------------------------ |
| // Enables/disables interrupt for every IRQ line |
| |
| assign ipic_ier_upd = cicsr_wr_req | icsr_wr_req; |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_ier_ff <= '0; |
| end else if (ipic_ier_upd) begin |
| ipic_ier_ff <= ipic_ier_next; |
| end |
| end |
| |
| always_comb begin |
| ipic_ier_next = ipic_ier_ff; |
| if (cicsr_wr_req) begin |
| ipic_ier_next[irq_serv_idx] = irq_serv_vd |
| ? csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE] |
| : ipic_ier_ff[irq_serv_idx]; |
| end else if (icsr_wr_req) begin |
| ipic_ier_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IE]; |
| end |
| end |
| |
| // IMR |
| //------------------------------------------------------------------------------ |
| // For every IRQ line sets either Level (0) or Edge (1) detection |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_imr_ff <= '0; |
| end else if (icsr_wr_req) begin |
| ipic_imr_ff <= ipic_imr_next; |
| end |
| end |
| |
| always_comb begin |
| ipic_imr_next = ipic_imr_ff; |
| if (icsr_wr_req) begin |
| ipic_imr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_IM]; |
| end |
| end |
| |
| // IINVR |
| //------------------------------------------------------------------------------ |
| // For every IRQ line defines whether it should be inverted or not |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| ipic_iinvr_ff <= '0; |
| end else if (icsr_wr_req) begin |
| ipic_iinvr_ff <= ipic_iinvr_next; |
| end |
| end |
| |
| always_comb begin |
| ipic_iinvr_next = ipic_iinvr_ff; |
| if (icsr_wr_req) begin |
| ipic_iinvr_next[ipic_idxr_ff] = csr2ipic_wdata_i[SCR1_IPIC_ICSR_INV]; |
| end |
| end |
| |
| // ICSR |
| //------------------------------------------------------------------------------ |
| // Holds control and status information about the interrupt defined by Index Register |
| |
| assign ipic_icsr.ip = ipic_ipr_ff [ipic_idxr_ff]; |
| assign ipic_icsr.ie = ipic_ier_ff [ipic_idxr_ff]; |
| assign ipic_icsr.im = ipic_imr_ff [ipic_idxr_ff]; |
| assign ipic_icsr.inv = ipic_iinvr_ff[ipic_idxr_ff]; |
| assign ipic_icsr.is = ipic_isvr_ff [ipic_idxr_ff]; |
| assign ipic_icsr.line = SCR1_IRQ_LINES_WIDTH'(ipic_idxr_ff); |
| |
| //------------------------------------------------------------------------------ |
| // Priority IRQ generation logic |
| //------------------------------------------------------------------------------ |
| |
| assign irq_req_v = ipic_ipr_ff & ipic_ier_ff; |
| |
| /*** Modified for Yosys handing typedef in function - dinesha |
| assign irr_priority = scr1_search_one_16(irq_req_v); |
| assign irq_req_vd = irr_priority.vd; |
| assign irq_req_idx = irr_priority.idx; |
| ****/ |
| |
| always_comb |
| begin |
| casex(irq_req_v) |
| 16'bxxxx_xxxx_xxxx_xxx1 : irq_req_idx = 0; |
| 16'bxxxx_xxxx_xxxx_xx10 : irq_req_idx = 1; |
| 16'bxxxx_xxxx_xxxx_x100 : irq_req_idx = 2; |
| 16'bxxxx_xxxx_xxxx_1000 : irq_req_idx = 3; |
| 16'bxxxx_xxxx_xxx1_0000 : irq_req_idx = 4; |
| 16'bxxxx_xxxx_xx10_0000 : irq_req_idx = 5; |
| 16'bxxxx_xxxx_x100_0000 : irq_req_idx = 6; |
| 16'bxxxx_xxxx_1000_0000 : irq_req_idx = 7; |
| 16'bxxxx_xxx1_0000_0000 : irq_req_idx = 8; |
| 16'bxxxx_xx10_0000_0000 : irq_req_idx = 9; |
| 16'bxxxx_x100_0000_0000 : irq_req_idx = 10; |
| 16'bxxxx_1000_0000_0000 : irq_req_idx = 11; |
| 16'bxxx1_0000_0000_0000 : irq_req_idx = 12; |
| 16'bxx10_0000_0000_0000 : irq_req_idx = 13; |
| 16'bx100_0000_0000_0000 : irq_req_idx = 14; |
| 16'b1000_0000_0000_0000 : irq_req_idx = 15; |
| 16'b0000_0000_0000_0000 : irq_req_idx = 16; |
| default : irq_req_idx = 16; |
| endcase |
| irq_req_vd = |irq_req_v; |
| end |
| |
| /*** Modified for Yosys handing typedef in function - dinesha |
| assign isvr_priority_eoi = scr1_search_one_16(ipic_isvr_eoi); |
| assign irq_eoi_req_vd = isvr_priority_eoi.vd; |
| assign irq_eoi_req_idx = isvr_priority_eoi.idx; |
| *************************************************/ |
| |
| always_comb |
| begin |
| casex(ipic_isvr_eoi) |
| 16'bxxxx_xxxx_xxxx_xxx1 : irq_eoi_req_idx = 0; |
| 16'bxxxx_xxxx_xxxx_xx10 : irq_eoi_req_idx = 1; |
| 16'bxxxx_xxxx_xxxx_x100 : irq_eoi_req_idx = 2; |
| 16'bxxxx_xxxx_xxxx_1000 : irq_eoi_req_idx = 3; |
| 16'bxxxx_xxxx_xxx1_0000 : irq_eoi_req_idx = 4; |
| 16'bxxxx_xxxx_xx10_0000 : irq_eoi_req_idx = 5; |
| 16'bxxxx_xxxx_x100_0000 : irq_eoi_req_idx = 6; |
| 16'bxxxx_xxxx_1000_0000 : irq_eoi_req_idx = 7; |
| 16'bxxxx_xxx1_0000_0000 : irq_eoi_req_idx = 8; |
| 16'bxxxx_xx10_0000_0000 : irq_eoi_req_idx = 9; |
| 16'bxxxx_x100_0000_0000 : irq_eoi_req_idx = 10; |
| 16'bxxxx_1000_0000_0000 : irq_eoi_req_idx = 11; |
| 16'bxxx1_0000_0000_0000 : irq_eoi_req_idx = 12; |
| 16'bxx10_0000_0000_0000 : irq_eoi_req_idx = 13; |
| 16'bx100_0000_0000_0000 : irq_eoi_req_idx = 14; |
| 16'b1000_0000_0000_0000 : irq_eoi_req_idx = 15; |
| 16'b0000_0000_0000_0000 : irq_eoi_req_idx = 16; |
| default : irq_eoi_req_idx = 16; |
| endcase |
| irq_eoi_req_vd = |ipic_isvr_eoi; |
| end |
| |
| assign irq_hi_prior_pnd = irq_req_idx < irq_serv_idx; |
| |
| assign ipic2csr_irq_m_req_o = irq_req_vd & (~irq_serv_vd | irq_hi_prior_pnd); |
| |
| assign irq_start_vd = ipic2csr_irq_m_req_o & ipic_soi_req; |
| |
| endmodule : scr1_ipic |
| |
| `endif // SCR1_IPIC_EN |