tinyriscv/rtl/perips/rvic/rvic_core.sv

162 lines
5.4 KiB
Systemverilog
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
Copyright 2021 Blue Liang, liangkangnan@163.com
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.
*/
module rvic_core (
input logic clk_i,
input logic rst_ni,
input logic [31:0] src_i,
output logic [ 7:0] irq_id_o,
output logic irq_o,
input logic reg_we_i,
input logic reg_re_i,
input logic [31:0] reg_wdata_i,
input logic [ 3:0] reg_be_i,
input logic [31:0] reg_addr_i,
output logic [31:0] reg_rdata_o
);
import rvic_reg_pkg::*;
rvic_reg_pkg::rvic_reg2hw_t reg2hw;
rvic_reg_pkg::rvic_hw2reg_t hw2reg;
logic [31:0] priority_array[8];
logic [31:0] irq_enable;
logic [31:0] irq_pending;
assign priority_array[0] = reg2hw.priority0.q;
assign priority_array[1] = reg2hw.priority1.q;
assign priority_array[2] = reg2hw.priority2.q;
assign priority_array[3] = reg2hw.priority3.q;
assign priority_array[4] = reg2hw.priority4.q;
assign priority_array[5] = reg2hw.priority5.q;
assign priority_array[6] = reg2hw.priority6.q;
assign priority_array[7] = reg2hw.priority7.q;
assign irq_enable = reg2hw.enable.q;
assign irq_pending = reg2hw.pending.q;
// 找出优先级最高(优先级值最大)的中断源
// 二分法查找
logic [7:0] each_prio[32];
for (genvar i = 0; i < 8; i = i + 1) begin
for (genvar j = 0; j < 4; j = j + 1) begin
// 只有当中断使能并且有中断请求,优先级才有效
assign each_prio[i*4+j] = priority_array[i][8*j+7:8*j] & {8{irq_enable[i*4+j]}} & {8{src_i[i*4+j] | irq_pending[i*4+j]}};
end
end
typedef struct packed {
logic [7:0] id;
logic [7:0] prio;
} int_info_t;
int_info_t l1_max[16];
always_comb begin
for (int i = 0; i < 16; i = i + 1) begin
if (each_prio[2*i+1] > each_prio[2*i]) begin
l1_max[i].id = 2*i+1;
l1_max[i].prio = each_prio[2*i+1];
end else begin
l1_max[i].id = 2*i;
l1_max[i].prio = each_prio[2*i];
end
end
end
int_info_t l2_max[8];
always_comb begin
for (int i = 0; i < 8; i = i + 1) begin
if (l1_max[2*i+1].prio > l1_max[2*i].prio) begin
l2_max[i].id = l1_max[2*i+1].id;
l2_max[i].prio = l1_max[2*i+1].prio;
end else begin
l2_max[i].id = l1_max[2*i].id;
l2_max[i].prio = l1_max[2*i].prio;
end
end
end
int_info_t l3_max[4];
always_comb begin
for (int i = 0; i < 4; i = i + 1) begin
if (l2_max[2*i+1].prio > l2_max[2*i].prio) begin
l3_max[i].id = l2_max[2*i+1].id;
l3_max[i].prio = l2_max[2*i+1].prio;
end else begin
l3_max[i].id = l2_max[2*i].id;
l3_max[i].prio = l2_max[2*i].prio;
end
end
end
int_info_t l4_max[2];
always_comb begin
for (int i = 0; i < 2; i = i + 1) begin
if (l3_max[2*i+1].prio > l3_max[2*i].prio) begin
l4_max[i].id = l3_max[2*i+1].id;
l4_max[i].prio = l3_max[2*i+1].prio;
end else begin
l4_max[i].id = l3_max[2*i].id;
l4_max[i].prio = l3_max[2*i].prio;
end
end
end
logic [7:0] irq_id;
// 最终查找结果
assign irq_id = (l4_max[1].prio > l4_max[0].prio) ? l4_max[1].id : l4_max[0].id;
// 将irq_id打一拍后irq_id_o就与irq_o同步
always_ff @ (posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
irq_id_o <= 8'h0;
end else begin
irq_id_o <= irq_id;
end
end
// 只要有pending就向MCU发起中断请求
assign irq_o = |irq_pending;
// 最多32个中断源
logic [4:0] id = irq_id[4:0];
// 硬件置位pending
assign hw2reg.pending.de = src_i[id] & irq_enable[id];
assign hw2reg.pending.d = irq_pending | (1 << id);
rvic_reg_top u_rvic_reg_top (
.clk_i (clk_i),
.rst_ni (rst_ni),
.reg2hw (reg2hw),
.hw2reg (hw2reg),
.reg_we (reg_we_i),
.reg_re (reg_re_i),
.reg_wdata (reg_wdata_i),
.reg_be (reg_be_i),
.reg_addr (reg_addr_i),
.reg_rdata (reg_rdata_o)
);
endmodule