From d4b670217a4e4f8ebcd3b8167154140e771d4b5b Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Sat, 14 Aug 2021 14:03:47 +0800 Subject: [PATCH] rtl:perips: rewrite rvic Signed-off-by: liangkangnan --- rtl.flist | 5 +- rtl/perips/rvic.sv | 240 ----------------- rtl/perips/rvic/rvic.hjson | 113 ++++++++ rtl/perips/rvic/rvic_core.sv | 161 +++++++++++ rtl/perips/rvic/rvic_reg_pkg.sv | 121 +++++++++ rtl/perips/rvic/rvic_reg_top.sv | 465 ++++++++++++++++++++++++++++++++ rtl/perips/rvic/rvic_top.sv | 64 +++++ rtl/top/tinyriscv_soc_top.sv | 7 +- 8 files changed, 932 insertions(+), 244 deletions(-) delete mode 100644 rtl/perips/rvic.sv create mode 100644 rtl/perips/rvic/rvic.hjson create mode 100644 rtl/perips/rvic/rvic_core.sv create mode 100644 rtl/perips/rvic/rvic_reg_pkg.sv create mode 100644 rtl/perips/rvic/rvic_reg_top.sv create mode 100644 rtl/perips/rvic/rvic_top.sv diff --git a/rtl.flist b/rtl.flist index fac319d..900065b 100644 --- a/rtl.flist +++ b/rtl.flist @@ -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 diff --git a/rtl/perips/rvic.sv b/rtl/perips/rvic.sv deleted file mode 100644 index f2fcb26..0000000 --- a/rtl/perips/rvic.sv +++ /dev/null @@ -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 diff --git a/rtl/perips/rvic/rvic.hjson b/rtl/perips/rvic/rvic.hjson new file mode 100644 index 0000000..a32f440 --- /dev/null +++ b/rtl/perips/rvic/rvic.hjson @@ -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", + } + ] + } + ] +} diff --git a/rtl/perips/rvic/rvic_core.sv b/rtl/perips/rvic/rvic_core.sv new file mode 100644 index 0000000..d362be7 --- /dev/null +++ b/rtl/perips/rvic/rvic_core.sv @@ -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 diff --git a/rtl/perips/rvic/rvic_reg_pkg.sv b/rtl/perips/rvic/rvic_reg_pkg.sv new file mode 100644 index 0000000..b20faa7 --- /dev/null +++ b/rtl/perips/rvic/rvic_reg_pkg.sv @@ -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 + diff --git a/rtl/perips/rvic/rvic_reg_top.sv b/rtl/perips/rvic/rvic_reg_top.sv new file mode 100644 index 0000000..310ac8a --- /dev/null +++ b/rtl/perips/rvic/rvic_reg_top.sv @@ -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: __{wd|we|qs} + // or _{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 diff --git a/rtl/perips/rvic/rvic_top.sv b/rtl/perips/rvic/rvic_top.sv new file mode 100644 index 0000000..c52aa1a --- /dev/null +++ b/rtl/perips/rvic/rvic_top.sv @@ -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 diff --git a/rtl/top/tinyriscv_soc_top.sv b/rtl/top/tinyriscv_soc_top.sv index 07c7216..c6c0e96 100644 --- a/rtl/top/tinyriscv_soc_top.sv +++ b/rtl/top/tinyriscv_soc_top.sv @@ -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]) );