rtl:perips: add rvic

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-07-22 09:36:04 +08:00
parent e9044a7efe
commit 3227fb1ffd
6 changed files with 313 additions and 95 deletions

View File

@ -39,6 +39,7 @@
../rtl/perips/timer.sv
../rtl/perips/uart.sv
../rtl/perips/machine_timer.sv
../rtl/perips/rvic.sv
../rtl/sys_bus/obi_interconnect.sv
../rtl/sys_bus/obi_interconnect_master_sel.sv

View File

@ -43,6 +43,9 @@
// Machine Timer
`define MTIMER_ADDR_MASK ~32'hffff
`define MTIMER_ADDR_BASE 32'hA0000000
// Interrupt controller
`define RVIC_ADDR_MASK ~32'hffff
`define RVIC_ADDR_BASE 32'hD0000000
// SIM CTRL
`define SIM_CTRL_ADDR_MASK ~32'hffff
`define SIM_CTRL_ADDR_BASE 32'hE0000000

View File

@ -16,18 +16,11 @@
`include "defines.sv"
`define CAUSE_IRQ_EXTERNAL_M {1'b1, 31'd11}
`define CAUSE_IRQ_SOFTWARE_M {1'b1, 31'd3}
`define CAUSE_IRQ_TIMER_M {1'b1, 31'd7}
`define CAUSE_EXCEP_ECALL_M {1'b0, 31'd11}
`define CAUSE_EXCEP_EBREAK_M {1'b0, 31'd3}
`define CAUSE_EXCEP_ILLEGAL_INST_M {1'b0, 31'd2}
`define MIE_MTIE_BIT 7
`define MIE_MEIE_BIT 11
`define MIE_MSIE_BIT 3
`define DCSR_CAUSE_NONE 3'h0
`define DCSR_CAUSE_STEP 3'h4
`define DCSR_CAUSE_DBGREQ 3'h3
@ -49,7 +42,7 @@ module exception (
input wire inst_dret_i, // dret指令
input wire[31:0] inst_addr_i, // 指令地址
input wire illegal_inst_i,
input wire illegal_inst_i, // 非法指令
input wire[31:0] mtvec_i, // mtvec寄存器
input wire[31:0] mepc_i, // mepc寄存器
@ -58,10 +51,8 @@ module exception (
input wire[31:0] dpc_i, // dpc寄存器
input wire[31:0] dcsr_i, // dcsr寄存器
input wire irq_software_i,
input wire irq_timer_i,
input wire irq_external_i,
input wire[14:0] irq_fast_i,
input wire int_req_i,
input wire[7:0] int_id_i,
input wire trigger_match_i,
@ -78,6 +69,7 @@ module exception (
);
// 异常偏移
localparam ILLEGAL_INSTR_OFFSET = 0;
localparam INSTR_ADDR_MISA_OFFSET = 4;
localparam ECALL_OFFSET = 8;
@ -86,12 +78,8 @@ module exception (
localparam STORE_MISA_OFFSET = 20;
localparam RESERVED1_EXCEPTION_OFFSET = 24;
localparam RESERVED2_EXCEPTION_OFFSET = 28;
localparam EXTERNAL_INT_OFFSET = 32;
localparam SOFTWARE_INT_OFFSET = 36;
localparam TIMER_INT_OFFSET = 40;
localparam FAST_INT_OFFSET = 44;
// 中断偏移
localparam INT_OFFSET = 32;
localparam S_IDLE = 5'b00001;
localparam S_W_MEPC = 5'b00010;
@ -108,61 +96,16 @@ module exception (
reg[31:0] csr_waddr;
reg[31:0] csr_wdata;
reg[7:0] int_id_d, int_id_q;
reg in_irq_context_d, in_irq_context_q;
wire global_int_en;
wire interrupt_req_valid;
assign global_int_en = mstatus_i[3];
reg[3:0] fast_irq_id;
wire fast_irq_req;
always @ (*) begin
if (irq_fast_i[ 0]) fast_irq_id = 4'd0;
else if (irq_fast_i[ 1]) fast_irq_id = 4'd1;
else if (irq_fast_i[ 2]) fast_irq_id = 4'd2;
else if (irq_fast_i[ 3]) fast_irq_id = 4'd3;
else if (irq_fast_i[ 4]) fast_irq_id = 4'd4;
else if (irq_fast_i[ 5]) fast_irq_id = 4'd5;
else if (irq_fast_i[ 6]) fast_irq_id = 4'd6;
else if (irq_fast_i[ 7]) fast_irq_id = 4'd7;
else if (irq_fast_i[ 8]) fast_irq_id = 4'd8;
else if (irq_fast_i[ 9]) fast_irq_id = 4'd9;
else if (irq_fast_i[10]) fast_irq_id = 4'd10;
else if (irq_fast_i[11]) fast_irq_id = 4'd11;
else if (irq_fast_i[12]) fast_irq_id = 4'd12;
else if (irq_fast_i[13]) fast_irq_id = 4'd13;
else fast_irq_id = 4'd14;
end
assign fast_irq_req = |irq_fast_i;
reg interrupt_req_tmp;
reg[31:0] interrupt_cause;
reg[31:0] interrupt_offset;
wire interrupt_req = inst_valid_i & interrupt_req_tmp;
always @ (*) begin
if (fast_irq_req) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = {1'b1, {26{1'b0}}, 1'b1, fast_irq_id};
interrupt_offset = {fast_irq_id, 2'b0} + FAST_INT_OFFSET;
end else if (irq_external_i & mie_i[`MIE_MEIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_EXTERNAL_M;
interrupt_offset = EXTERNAL_INT_OFFSET;
end else if (irq_software_i & mie_i[`MIE_MSIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_SOFTWARE_M;
interrupt_offset = SOFTWARE_INT_OFFSET;
end else if (irq_timer_i & mie_i[`MIE_MTIE_BIT]) begin
interrupt_req_tmp = 1'b1;
interrupt_cause = `CAUSE_IRQ_TIMER_M;
interrupt_offset = TIMER_INT_OFFSET;
end else begin
interrupt_req_tmp = 1'b0;
interrupt_cause = 32'h0;
interrupt_offset = 32'h0;
end
end
assign interrupt_req_valid = inst_valid_i &
int_req_i &
((int_id_i != int_id_q) | (~in_irq_context_q));
reg exception_req;
reg[31:0] exception_cause;
@ -188,9 +131,9 @@ module exception (
wire[31:0] int_or_exception_cause;
wire[31:0] int_or_exception_offset;
assign int_or_exception_req = (interrupt_req & global_int_en & (~debug_mode_q)) | exception_req;
assign int_or_exception_cause = exception_req ? exception_cause : interrupt_cause;
assign int_or_exception_offset = exception_req ? exception_offset : interrupt_offset;
assign int_or_exception_req = (interrupt_req_valid & global_int_en & (~debug_mode_q)) | exception_req;
assign int_or_exception_cause = exception_req ? exception_cause : int_id_i;
assign int_or_exception_offset = exception_req ? exception_offset : INT_OFFSET;
wire trigger_matching;
@ -244,7 +187,7 @@ module exception (
enter_debug_cause_ebreak;
assign stall_flag_o = ((state_q != S_IDLE) & (state_q != S_ASSERT)) |
(interrupt_req & global_int_en) | exception_req |
int_or_exception_req |
debug_mode_req |
inst_mret_i |
inst_dret_i;
@ -258,6 +201,8 @@ module exception (
csr_waddr = 32'h0;
csr_wdata = 32'h0;
trigger_match_d = trigger_match_q;
int_id_d = int_id_q;
in_irq_context_d = in_irq_context_q;
case (state_q)
S_IDLE: begin
@ -268,6 +213,8 @@ module exception (
assert_addr_d = mtvec_i + int_or_exception_offset;
return_addr_d = inst_addr_i;
state_d = S_W_MSTATUS;
int_id_d = int_id_i;
in_irq_context_d = 1'b1;
end else if (debug_mode_req) begin
debug_mode_d = 1'b1;
if (enter_debug_cause_debugger_req |
@ -293,9 +240,11 @@ module exception (
state_d = S_W_DCSR;
end
end else if (inst_mret_i) begin
in_irq_context_d = 1'b0;
assert_addr_d = mepc_i;
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MSTATUS};
// 开全局中断
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
state_d = S_ASSERT;
end else if (inst_dret_i) begin
@ -309,6 +258,7 @@ module exception (
S_W_MSTATUS: begin
csr_we = 1'b1;
csr_waddr = {20'h0, `CSR_MSTATUS};
// 关全局中断
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
state_d = S_W_MEPC;
end
@ -352,6 +302,8 @@ module exception (
return_addr_q <= 32'h0;
dcsr_cause_q <= `DCSR_CAUSE_NONE;
trigger_match_q <= 1'b0;
int_id_q <= 8'h0;
in_irq_context_q <= 1'b0;
end else begin
state_q <= state_d;
assert_addr_q <= assert_addr_d;
@ -359,6 +311,8 @@ module exception (
return_addr_q <= return_addr_d;
dcsr_cause_q <= dcsr_cause_d;
trigger_match_q <= trigger_match_d;
int_id_q <= int_id_d;
in_irq_context_q <= in_irq_context_d;
end
end

View File

@ -47,10 +47,8 @@ module tinyriscv_core #(
input wire data_err_i,
// interrupt input
input wire irq_software_i,
input wire irq_timer_i,
input wire irq_external_i,
input wire[14:0] irq_fast_i,
input wire int_req_i,
input wire[7:0] int_id_i,
// debug request signal
input wire debug_req_i
@ -343,10 +341,8 @@ module tinyriscv_core #(
.dpc_i(csr_dpc_o),
.dcsr_i(csr_dcsr_o),
.trigger_match_i(csr_trigger_match_o),
.irq_software_i(irq_software_i),
.irq_timer_i(irq_timer_i),
.irq_external_i(irq_external_i),
.irq_fast_i(irq_fast_i),
.int_req_i(int_req_i),
.int_id_i(int_id_i),
.debug_halt_addr_i(DEBUG_HALT_ADDR),
.debug_req_i(debug_req_i),
.csr_we_o(excep_csr_we_o),

240
rtl/perips/rvic.sv Normal file
View File

@ -0,0 +1,240 @@
/*
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

View File

@ -41,9 +41,9 @@ module tinyriscv_soc_top #(
localparam int MASTERS = 3; // Number of master ports
`ifdef VERILATOR
localparam int SLAVES = 7; // Number of slave ports
localparam int SLAVES = 8; // Number of slave ports
`else
localparam int SLAVES = 6; // Number of slave ports
localparam int SLAVES = 7; // Number of slave ports
`endif
// masters
@ -58,8 +58,9 @@ module tinyriscv_soc_top #(
localparam int Mtimer = 3;
localparam int Gpio = 4;
localparam int Uart = 5;
localparam int Rvic = 6;
`ifdef VERILATOR
localparam int SimCtrl = 6;
localparam int SimCtrl = 7;
`endif
@ -100,12 +101,21 @@ module tinyriscv_soc_top #(
wire debug_req;
wire core_halted;
reg[31:0] irq_src;
wire int_req;
wire[7:0] int_id;
wire mtimer_irq;
wire[1:0] io_in;
wire[31:0] gpio_ctrl;
wire[31:0] gpio_data;
always @ (*) begin
irq_src = 32'h0;
irq_src[0] = mtimer_irq;
end
`ifdef VERILATOR
assign halted_ind_pin = core_halted;
`else
@ -139,10 +149,8 @@ module tinyriscv_soc_top #(
.data_rdata_i (master_rdata[CoreD]),
.data_err_i (1'b0),
.irq_software_i (1'b0),
.irq_timer_i (mtimer_irq),
.irq_external_i (1'b0),
.irq_fast_i (15'b0),
.int_req_i (int_req),
.int_id_i (int_id),
.debug_req_i (debug_req)
);
@ -229,10 +237,26 @@ module tinyriscv_soc_top #(
.rx_pin (uart_rx_pin)
);
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
assign slave_addr_base[Rvic] = `RVIC_ADDR_BASE;
// 6.中断控制器模块
rvic u_rvic(
.clk_i (clk),
.rst_ni (ndmreset_n),
.src_i (irq_src),
.irq_o (int_req),
.irq_id_o (int_id),
.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])
);
`ifdef VERILATOR
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
// 6.仿真控制模块
// 7.仿真控制模块
sim_ctrl u_sim_ctrl(
.clk_i (clk),
.rst_ni (ndmreset_n),