rtl:perips: rewrite rvic

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-08-14 14:03:47 +08:00
parent 477d9efc34
commit d4b670217a
8 changed files with 932 additions and 244 deletions

View File

@ -35,7 +35,6 @@
../rtl/perips/ram.sv
../rtl/perips/rom.sv
../rtl/perips/rvic.sv
../rtl/perips/uart/uart_reg_pkg.sv
../rtl/perips/uart/uart_reg_top.sv
../rtl/perips/uart/uart_core.sv
@ -50,6 +49,10 @@
../rtl/perips/gpio/gpio_reg_top.sv
../rtl/perips/gpio/gpio_core.sv
../rtl/perips/gpio/gpio_top.sv
../rtl/perips/rvic/rvic_reg_pkg.sv
../rtl/perips/rvic/rvic_reg_top.sv
../rtl/perips/rvic/rvic_core.sv
../rtl/perips/rvic/rvic_top.sv
../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv

View File

@ -1,240 +0,0 @@
/*
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.
*/
`include "../core/defines.sv"
// RISC-V中断控制器
// 支持32个中断源每个中断源支持256级优先级
module rvic #(
)(
input logic clk_i,
input logic rst_ni,
input logic [31:0] src_i,
output logic irq_o, // 中断请求信号
output logic [7:0] irq_id_o, // 中断号
input logic [31:0] addr_i,
input logic [31:0] data_i,
input logic [3:0] be_i,
input logic we_i,
output logic [31:0] data_o
);
// 寄存器地址偏移
parameter logic [7:0] IE_OFFSET = 8'h0;
parameter logic [7:0] IP_OFFSET = 8'h4;
parameter logic [7:0] PRIO0_OFFSET = 8'h8;
parameter logic [7:0] PRIO1_OFFSET = 8'hc;
parameter logic [7:0] PRIO2_OFFSET = 8'h10;
parameter logic [7:0] PRIO3_OFFSET = 8'h14;
parameter logic [7:0] PRIO4_OFFSET = 8'h18;
parameter logic [7:0] PRIO5_OFFSET = 8'h1c;
parameter logic [7:0] PRIO6_OFFSET = 8'h20;
parameter logic [7:0] PRIO7_OFFSET = 8'h24;
parameter logic [7:0] ID_OFFSET = 8'h28;
logic ie_we;
logic ip_we;
logic [7:0] prio_we;
logic [31:0] prio_q[8];
logic [31:0] ie_q;
logic [31:0] ip_q;
logic [31:0] id_q;
logic [10:0] addr_hit;
logic [7:0] reg_addr = addr_i[7:0];
always_comb begin
addr_hit = 11'h0;
addr_hit[ 0] = (reg_addr == IE_OFFSET);
addr_hit[ 1] = (reg_addr == IP_OFFSET);
addr_hit[ 2] = (reg_addr == PRIO0_OFFSET);
addr_hit[ 3] = (reg_addr == PRIO1_OFFSET);
addr_hit[ 4] = (reg_addr == PRIO2_OFFSET);
addr_hit[ 5] = (reg_addr == PRIO3_OFFSET);
addr_hit[ 6] = (reg_addr == PRIO4_OFFSET);
addr_hit[ 7] = (reg_addr == PRIO5_OFFSET);
addr_hit[ 8] = (reg_addr == PRIO6_OFFSET);
addr_hit[ 9] = (reg_addr == PRIO7_OFFSET);
addr_hit[10] = (reg_addr == ID_OFFSET);
end
assign ie_we = we_i & addr_hit[0];
assign ip_we = we_i & addr_hit[1];
for (genvar p = 0; p < 8; p = p + 1) begin
assign prio_we[p] = we_i & addr_hit[p + 2];
end
// 写寄存器
logic [31:0] reg_wdata;
always_comb begin
reg_wdata = 32'h0;
// IP寄存器是写1清零的因此要区别对待
if (ip_we) begin
reg_wdata = ip_q;
if (be_i[0])
reg_wdata[7:0] = ip_q[7:0] & (~data_i[7:0]);
if (be_i[1])
reg_wdata[15:8] = ip_q[15:8] & (~data_i[15:8]);
if (be_i[2])
reg_wdata[23:16] = ip_q[23:16] & (~data_i[23:16]);
if (be_i[3])
reg_wdata[31:24] = ip_q[31:24] & (~data_i[31:24]);
end else begin
if (ie_we) begin
reg_wdata = ie_q;
end
for (int j = 0; j < 8; j = j + 1) begin
if (prio_we[j]) begin
reg_wdata = prio_q[j];
end
end
if (be_i[0])
reg_wdata[7:0] = data_i[7:0];
if (be_i[1])
reg_wdata[15:8] = data_i[15:8];
if (be_i[2])
reg_wdata[23:16] = data_i[23:16];
if (be_i[3])
reg_wdata[31:24] = data_i[31:24];
end
end
gen_en_dff #(32) ie_ff(clk_i, rst_ni, ie_we, reg_wdata, ie_q);
logic [31:0] ip_wdata;
assign ip_wdata = ip_we ? reg_wdata : (ip_q | src_i);
gen_en_dff #(32) ip_ff(clk_i, rst_ni, 1'b1, ip_wdata, ip_q);
for (genvar m = 0; m < 8; m = m + 1) begin
gen_en_dff #(32) prio_ff(clk_i, rst_ni, prio_we[m], reg_wdata, prio_q[m]);
end
// 读寄存器
always_ff @ (posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
data_o <= 32'h0;
end else begin
case (addr_i[7:0])
IE_OFFSET: data_o <= ie_q;
IP_OFFSET: data_o <= ip_q;
PRIO0_OFFSET: data_o <= prio_q[0];
PRIO1_OFFSET: data_o <= prio_q[1];
PRIO2_OFFSET: data_o <= prio_q[2];
PRIO3_OFFSET: data_o <= prio_q[3];
PRIO4_OFFSET: data_o <= prio_q[4];
PRIO5_OFFSET: data_o <= prio_q[5];
PRIO6_OFFSET: data_o <= prio_q[6];
PRIO7_OFFSET: data_o <= prio_q[7];
ID_OFFSET: data_o <= id_q;
default: data_o <= 32'h0;
endcase
end
end
// 找出优先级最高(优先级值最大)的中断源
// 二分法查找
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] = prio_q[i][8*j+7:8*j] & {8{ie_q[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;
always_ff @ (posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
irq_id_o <= 8'h0;
irq_o <= 1'b0;
end else begin
irq_id_o <= irq_id;
irq_o <= |((src_i | ip_q) & ie_q);
end
end
assign id_q = {24'h0, irq_id};
endmodule

113
rtl/perips/rvic/rvic.hjson Normal file
View File

@ -0,0 +1,113 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "rvic",
clocking: [{clock: "clk_i", reset: "rst_ni"}],
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
regwidth: "32",
registers: [
{ name: "ENABLE",
desc: "RVIC interrupt enable register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "one bit for one interrupt source",
}
]
}
{ name: "PENDING",
desc: "RVIC interrupt pending register",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "31:0",
swaccess: "rw1c",
desc: "one bit for one interrupt source",
}
]
}
{ name: "PRIORITY0",
desc: "RVIC interrupt priority0 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY1",
desc: "RVIC interrupt priority1 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY2",
desc: "RVIC interrupt priority2 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY3",
desc: "RVIC interrupt priority3 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY4",
desc: "RVIC interrupt priority4 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY5",
desc: "RVIC interrupt priority5 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY6",
desc: "RVIC interrupt priority6 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
{ name: "PRIORITY7",
desc: "RVIC interrupt priority7 register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31:0",
desc: "eight bits for one interrupt source",
}
]
}
]
}

View File

@ -0,0 +1,161 @@
/*
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]}};
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

View File

@ -0,0 +1,121 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Package auto-generated by `reggen` containing data structure
package rvic_reg_pkg;
// Address widths within the block
parameter int BlockAw = 6;
////////////////////////////
// Typedefs for registers //
////////////////////////////
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_enable_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_pending_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority0_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority1_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority2_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority3_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority4_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority5_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority6_reg_t;
typedef struct packed {
logic [31:0] q;
} rvic_reg2hw_priority7_reg_t;
typedef struct packed {
logic [31:0] d;
logic de;
} rvic_hw2reg_pending_reg_t;
// Register -> HW type
typedef struct packed {
rvic_reg2hw_enable_reg_t enable; // [319:288]
rvic_reg2hw_pending_reg_t pending; // [287:256]
rvic_reg2hw_priority0_reg_t priority0; // [255:224]
rvic_reg2hw_priority1_reg_t priority1; // [223:192]
rvic_reg2hw_priority2_reg_t priority2; // [191:160]
rvic_reg2hw_priority3_reg_t priority3; // [159:128]
rvic_reg2hw_priority4_reg_t priority4; // [127:96]
rvic_reg2hw_priority5_reg_t priority5; // [95:64]
rvic_reg2hw_priority6_reg_t priority6; // [63:32]
rvic_reg2hw_priority7_reg_t priority7; // [31:0]
} rvic_reg2hw_t;
// HW -> register type
typedef struct packed {
rvic_hw2reg_pending_reg_t pending; // [32:0]
} rvic_hw2reg_t;
// Register offsets
parameter logic [BlockAw-1:0] RVIC_ENABLE_OFFSET = 6'h0;
parameter logic [BlockAw-1:0] RVIC_PENDING_OFFSET = 6'h4;
parameter logic [BlockAw-1:0] RVIC_PRIORITY0_OFFSET = 6'h8;
parameter logic [BlockAw-1:0] RVIC_PRIORITY1_OFFSET = 6'hc;
parameter logic [BlockAw-1:0] RVIC_PRIORITY2_OFFSET = 6'h10;
parameter logic [BlockAw-1:0] RVIC_PRIORITY3_OFFSET = 6'h14;
parameter logic [BlockAw-1:0] RVIC_PRIORITY4_OFFSET = 6'h18;
parameter logic [BlockAw-1:0] RVIC_PRIORITY5_OFFSET = 6'h1c;
parameter logic [BlockAw-1:0] RVIC_PRIORITY6_OFFSET = 6'h20;
parameter logic [BlockAw-1:0] RVIC_PRIORITY7_OFFSET = 6'h24;
// Register index
typedef enum int {
RVIC_ENABLE,
RVIC_PENDING,
RVIC_PRIORITY0,
RVIC_PRIORITY1,
RVIC_PRIORITY2,
RVIC_PRIORITY3,
RVIC_PRIORITY4,
RVIC_PRIORITY5,
RVIC_PRIORITY6,
RVIC_PRIORITY7
} rvic_id_e;
// Register width information to check illegal writes
parameter logic [3:0] RVIC_PERMIT [10] = '{
4'b1111, // index[0] RVIC_ENABLE
4'b1111, // index[1] RVIC_PENDING
4'b1111, // index[2] RVIC_PRIORITY0
4'b1111, // index[3] RVIC_PRIORITY1
4'b1111, // index[4] RVIC_PRIORITY2
4'b1111, // index[5] RVIC_PRIORITY3
4'b1111, // index[6] RVIC_PRIORITY4
4'b1111, // index[7] RVIC_PRIORITY5
4'b1111, // index[8] RVIC_PRIORITY6
4'b1111 // index[9] RVIC_PRIORITY7
};
endpackage

View File

@ -0,0 +1,465 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Top module auto-generated by `reggen`
module rvic_reg_top (
input logic clk_i,
input logic rst_ni,
// To HW
output rvic_reg_pkg::rvic_reg2hw_t reg2hw, // Write
input rvic_reg_pkg::rvic_hw2reg_t hw2reg, // Read
input logic reg_we,
input logic reg_re,
input logic [31:0] reg_wdata,
input logic [ 3:0] reg_be,
input logic [31:0] reg_addr,
output logic [31:0] reg_rdata
);
import rvic_reg_pkg::* ;
localparam int AW = 6;
localparam int DW = 32;
localparam int DBW = DW/8; // Byte Width
logic reg_error;
logic addrmiss, wr_err;
logic [DW-1:0] reg_rdata_next;
assign reg_rdata = reg_rdata_next;
assign reg_error = wr_err;
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
// or <reg>_{wd|we|qs} if field == 1 or 0
logic enable_we;
logic [31:0] enable_qs;
logic [31:0] enable_wd;
logic pending_we;
logic [31:0] pending_qs;
logic [31:0] pending_wd;
logic priority0_we;
logic [31:0] priority0_qs;
logic [31:0] priority0_wd;
logic priority1_we;
logic [31:0] priority1_qs;
logic [31:0] priority1_wd;
logic priority2_we;
logic [31:0] priority2_qs;
logic [31:0] priority2_wd;
logic priority3_we;
logic [31:0] priority3_qs;
logic [31:0] priority3_wd;
logic priority4_we;
logic [31:0] priority4_qs;
logic [31:0] priority4_wd;
logic priority5_we;
logic [31:0] priority5_qs;
logic [31:0] priority5_wd;
logic priority6_we;
logic [31:0] priority6_qs;
logic [31:0] priority6_wd;
logic priority7_we;
logic [31:0] priority7_qs;
logic [31:0] priority7_wd;
// Register instances
// R[enable]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_enable (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (enable_we),
.wd (enable_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.enable.q),
// to register interface (read)
.qs (enable_qs)
);
// R[pending]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("W1C"),
.RESVAL (32'h0)
) u_pending (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (pending_we),
.wd (pending_wd),
// from internal hardware
.de (hw2reg.pending.de),
.d (hw2reg.pending.d),
// to internal hardware
.qe (),
.q (reg2hw.pending.q),
// to register interface (read)
.qs (pending_qs)
);
// R[priority0]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority0 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority0_we),
.wd (priority0_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority0.q),
// to register interface (read)
.qs (priority0_qs)
);
// R[priority1]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority1 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority1_we),
.wd (priority1_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority1.q),
// to register interface (read)
.qs (priority1_qs)
);
// R[priority2]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority2 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority2_we),
.wd (priority2_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority2.q),
// to register interface (read)
.qs (priority2_qs)
);
// R[priority3]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority3 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority3_we),
.wd (priority3_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority3.q),
// to register interface (read)
.qs (priority3_qs)
);
// R[priority4]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority4 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority4_we),
.wd (priority4_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority4.q),
// to register interface (read)
.qs (priority4_qs)
);
// R[priority5]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority5 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority5_we),
.wd (priority5_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority5.q),
// to register interface (read)
.qs (priority5_qs)
);
// R[priority6]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority6 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority6_we),
.wd (priority6_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority6.q),
// to register interface (read)
.qs (priority6_qs)
);
// R[priority7]: V(False)
prim_subreg #(
.DW (32),
.SWACCESS("RW"),
.RESVAL (32'h0)
) u_priority7 (
.clk_i (clk_i),
.rst_ni (rst_ni),
// from register interface
.we (priority7_we),
.wd (priority7_wd),
// from internal hardware
.de (1'b0),
.d ('0),
// to internal hardware
.qe (),
.q (reg2hw.priority7.q),
// to register interface (read)
.qs (priority7_qs)
);
logic [9:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == RVIC_ENABLE_OFFSET);
addr_hit[1] = (reg_addr == RVIC_PENDING_OFFSET);
addr_hit[2] = (reg_addr == RVIC_PRIORITY0_OFFSET);
addr_hit[3] = (reg_addr == RVIC_PRIORITY1_OFFSET);
addr_hit[4] = (reg_addr == RVIC_PRIORITY2_OFFSET);
addr_hit[5] = (reg_addr == RVIC_PRIORITY3_OFFSET);
addr_hit[6] = (reg_addr == RVIC_PRIORITY4_OFFSET);
addr_hit[7] = (reg_addr == RVIC_PRIORITY5_OFFSET);
addr_hit[8] = (reg_addr == RVIC_PRIORITY6_OFFSET);
addr_hit[9] = (reg_addr == RVIC_PRIORITY7_OFFSET);
end
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
// Check sub-word write is permitted
always_comb begin
wr_err = (reg_we &
((addr_hit[0] & (|(RVIC_PERMIT[0] & ~reg_be))) |
(addr_hit[1] & (|(RVIC_PERMIT[1] & ~reg_be))) |
(addr_hit[2] & (|(RVIC_PERMIT[2] & ~reg_be))) |
(addr_hit[3] & (|(RVIC_PERMIT[3] & ~reg_be))) |
(addr_hit[4] & (|(RVIC_PERMIT[4] & ~reg_be))) |
(addr_hit[5] & (|(RVIC_PERMIT[5] & ~reg_be))) |
(addr_hit[6] & (|(RVIC_PERMIT[6] & ~reg_be))) |
(addr_hit[7] & (|(RVIC_PERMIT[7] & ~reg_be))) |
(addr_hit[8] & (|(RVIC_PERMIT[8] & ~reg_be))) |
(addr_hit[9] & (|(RVIC_PERMIT[9] & ~reg_be)))));
end
assign enable_we = addr_hit[0] & reg_we & !reg_error;
assign enable_wd = reg_wdata[31:0];
assign pending_we = addr_hit[1] & reg_we & !reg_error;
assign pending_wd = reg_wdata[31:0];
assign priority0_we = addr_hit[2] & reg_we & !reg_error;
assign priority0_wd = reg_wdata[31:0];
assign priority1_we = addr_hit[3] & reg_we & !reg_error;
assign priority1_wd = reg_wdata[31:0];
assign priority2_we = addr_hit[4] & reg_we & !reg_error;
assign priority2_wd = reg_wdata[31:0];
assign priority3_we = addr_hit[5] & reg_we & !reg_error;
assign priority3_wd = reg_wdata[31:0];
assign priority4_we = addr_hit[6] & reg_we & !reg_error;
assign priority4_wd = reg_wdata[31:0];
assign priority5_we = addr_hit[7] & reg_we & !reg_error;
assign priority5_wd = reg_wdata[31:0];
assign priority6_we = addr_hit[8] & reg_we & !reg_error;
assign priority6_wd = reg_wdata[31:0];
assign priority7_we = addr_hit[9] & reg_we & !reg_error;
assign priority7_wd = reg_wdata[31:0];
// Read data return
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
addr_hit[0]: begin
reg_rdata_next[31:0] = enable_qs;
end
addr_hit[1]: begin
reg_rdata_next[31:0] = pending_qs;
end
addr_hit[2]: begin
reg_rdata_next[31:0] = priority0_qs;
end
addr_hit[3]: begin
reg_rdata_next[31:0] = priority1_qs;
end
addr_hit[4]: begin
reg_rdata_next[31:0] = priority2_qs;
end
addr_hit[5]: begin
reg_rdata_next[31:0] = priority3_qs;
end
addr_hit[6]: begin
reg_rdata_next[31:0] = priority4_qs;
end
addr_hit[7]: begin
reg_rdata_next[31:0] = priority5_qs;
end
addr_hit[8]: begin
reg_rdata_next[31:0] = priority6_qs;
end
addr_hit[9]: begin
reg_rdata_next[31:0] = priority7_qs;
end
default: begin
reg_rdata_next = '1;
end
endcase
end
// Unused signal tieoff
// wdata / byte enable are not always fully used
// add a blanket unused statement to handle lint waivers
logic unused_wdata;
logic unused_be;
assign unused_wdata = ^reg_wdata;
assign unused_be = ^reg_be;
endmodule

View File

@ -0,0 +1,64 @@
/*
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_top (
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,
// OBI总线接口信号
input logic req_i,
input logic we_i,
input logic [ 3:0] be_i,
input logic [31:0] addr_i,
input logic [31:0] data_i,
output logic [31:0] data_o
);
logic re;
logic we;
logic [31:0] addr;
logic [31:0] reg_rdata;
// 读信号
assign re = req_i & (!we_i);
// 写信号
assign we = req_i & we_i;
// 去掉基地址
assign addr = {16'h0, addr_i[15:0]};
rvic_core u_rvic_core (
.clk_i (clk_i),
.rst_ni (rst_ni),
.src_i (src_i),
.irq_id_o (irq_id_o),
.irq_o (irq_o),
.reg_we_i (we),
.reg_re_i (re),
.reg_wdata_i(data_i),
.reg_be_i (be_i),
.reg_addr_i (addr),
.reg_rdata_o(reg_rdata)
);
always_ff @(posedge clk_i) begin
data_o <= reg_rdata;
end
endmodule

View File

@ -255,16 +255,17 @@ module tinyriscv_soc_top #(
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
// 6.中断控制器模块
rvic u_rvic(
rvic_top u_rvic(
.clk_i (clk),
.rst_ni (ndmreset_n),
.src_i (irq_src),
.irq_o (int_req),
.irq_id_o (int_id),
.req_i (slave_req[Rvic]),
.we_i (slave_we[Rvic]),
.be_i (slave_be[Rvic]),
.addr_i (slave_addr[Rvic]),
.data_i (slave_wdata[Rvic]),
.be_i (slave_be[Rvic]),
.we_i (slave_we[Rvic]),
.data_o (slave_rdata[Rvic])
);