parent
e9044a7efe
commit
3227fb1ffd
|
@ -39,6 +39,7 @@
|
||||||
../rtl/perips/timer.sv
|
../rtl/perips/timer.sv
|
||||||
../rtl/perips/uart.sv
|
../rtl/perips/uart.sv
|
||||||
../rtl/perips/machine_timer.sv
|
../rtl/perips/machine_timer.sv
|
||||||
|
../rtl/perips/rvic.sv
|
||||||
|
|
||||||
../rtl/sys_bus/obi_interconnect.sv
|
../rtl/sys_bus/obi_interconnect.sv
|
||||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
// Machine Timer
|
// Machine Timer
|
||||||
`define MTIMER_ADDR_MASK ~32'hffff
|
`define MTIMER_ADDR_MASK ~32'hffff
|
||||||
`define MTIMER_ADDR_BASE 32'hA0000000
|
`define MTIMER_ADDR_BASE 32'hA0000000
|
||||||
|
// Interrupt controller
|
||||||
|
`define RVIC_ADDR_MASK ~32'hffff
|
||||||
|
`define RVIC_ADDR_BASE 32'hD0000000
|
||||||
// SIM CTRL
|
// SIM CTRL
|
||||||
`define SIM_CTRL_ADDR_MASK ~32'hffff
|
`define SIM_CTRL_ADDR_MASK ~32'hffff
|
||||||
`define SIM_CTRL_ADDR_BASE 32'hE0000000
|
`define SIM_CTRL_ADDR_BASE 32'hE0000000
|
||||||
|
|
|
@ -16,18 +16,11 @@
|
||||||
|
|
||||||
`include "defines.sv"
|
`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_ECALL_M {1'b0, 31'd11}
|
||||||
`define CAUSE_EXCEP_EBREAK_M {1'b0, 31'd3}
|
`define CAUSE_EXCEP_EBREAK_M {1'b0, 31'd3}
|
||||||
`define CAUSE_EXCEP_ILLEGAL_INST_M {1'b0, 31'd2}
|
`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_NONE 3'h0
|
||||||
`define DCSR_CAUSE_STEP 3'h4
|
`define DCSR_CAUSE_STEP 3'h4
|
||||||
`define DCSR_CAUSE_DBGREQ 3'h3
|
`define DCSR_CAUSE_DBGREQ 3'h3
|
||||||
|
@ -49,7 +42,7 @@ module exception (
|
||||||
input wire inst_dret_i, // dret指令
|
input wire inst_dret_i, // dret指令
|
||||||
input wire[31:0] inst_addr_i, // 指令地址
|
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] mtvec_i, // mtvec寄存器
|
||||||
input wire[31:0] mepc_i, // mepc寄存器
|
input wire[31:0] mepc_i, // mepc寄存器
|
||||||
|
@ -58,10 +51,8 @@ module exception (
|
||||||
input wire[31:0] dpc_i, // dpc寄存器
|
input wire[31:0] dpc_i, // dpc寄存器
|
||||||
input wire[31:0] dcsr_i, // dcsr寄存器
|
input wire[31:0] dcsr_i, // dcsr寄存器
|
||||||
|
|
||||||
input wire irq_software_i,
|
input wire int_req_i,
|
||||||
input wire irq_timer_i,
|
input wire[7:0] int_id_i,
|
||||||
input wire irq_external_i,
|
|
||||||
input wire[14:0] irq_fast_i,
|
|
||||||
|
|
||||||
input wire trigger_match_i,
|
input wire trigger_match_i,
|
||||||
|
|
||||||
|
@ -78,6 +69,7 @@ module exception (
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 异常偏移
|
||||||
localparam ILLEGAL_INSTR_OFFSET = 0;
|
localparam ILLEGAL_INSTR_OFFSET = 0;
|
||||||
localparam INSTR_ADDR_MISA_OFFSET = 4;
|
localparam INSTR_ADDR_MISA_OFFSET = 4;
|
||||||
localparam ECALL_OFFSET = 8;
|
localparam ECALL_OFFSET = 8;
|
||||||
|
@ -86,12 +78,8 @@ module exception (
|
||||||
localparam STORE_MISA_OFFSET = 20;
|
localparam STORE_MISA_OFFSET = 20;
|
||||||
localparam RESERVED1_EXCEPTION_OFFSET = 24;
|
localparam RESERVED1_EXCEPTION_OFFSET = 24;
|
||||||
localparam RESERVED2_EXCEPTION_OFFSET = 28;
|
localparam RESERVED2_EXCEPTION_OFFSET = 28;
|
||||||
|
// 中断偏移
|
||||||
localparam EXTERNAL_INT_OFFSET = 32;
|
localparam INT_OFFSET = 32;
|
||||||
localparam SOFTWARE_INT_OFFSET = 36;
|
|
||||||
localparam TIMER_INT_OFFSET = 40;
|
|
||||||
localparam FAST_INT_OFFSET = 44;
|
|
||||||
|
|
||||||
|
|
||||||
localparam S_IDLE = 5'b00001;
|
localparam S_IDLE = 5'b00001;
|
||||||
localparam S_W_MEPC = 5'b00010;
|
localparam S_W_MEPC = 5'b00010;
|
||||||
|
@ -108,61 +96,16 @@ module exception (
|
||||||
reg[31:0] csr_waddr;
|
reg[31:0] csr_waddr;
|
||||||
reg[31:0] csr_wdata;
|
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 global_int_en;
|
||||||
|
wire interrupt_req_valid;
|
||||||
|
|
||||||
assign global_int_en = mstatus_i[3];
|
assign global_int_en = mstatus_i[3];
|
||||||
|
|
||||||
reg[3:0] fast_irq_id;
|
assign interrupt_req_valid = inst_valid_i &
|
||||||
wire fast_irq_req;
|
int_req_i &
|
||||||
|
((int_id_i != int_id_q) | (~in_irq_context_q));
|
||||||
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
|
|
||||||
|
|
||||||
reg exception_req;
|
reg exception_req;
|
||||||
reg[31:0] exception_cause;
|
reg[31:0] exception_cause;
|
||||||
|
@ -188,9 +131,9 @@ module exception (
|
||||||
wire[31:0] int_or_exception_cause;
|
wire[31:0] int_or_exception_cause;
|
||||||
wire[31:0] int_or_exception_offset;
|
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_req = (interrupt_req_valid & global_int_en & (~debug_mode_q)) | exception_req;
|
||||||
assign int_or_exception_cause = exception_req ? exception_cause : interrupt_cause;
|
assign int_or_exception_cause = exception_req ? exception_cause : int_id_i;
|
||||||
assign int_or_exception_offset = exception_req ? exception_offset : interrupt_offset;
|
assign int_or_exception_offset = exception_req ? exception_offset : INT_OFFSET;
|
||||||
|
|
||||||
wire trigger_matching;
|
wire trigger_matching;
|
||||||
|
|
||||||
|
@ -244,7 +187,7 @@ module exception (
|
||||||
enter_debug_cause_ebreak;
|
enter_debug_cause_ebreak;
|
||||||
|
|
||||||
assign stall_flag_o = ((state_q != S_IDLE) & (state_q != S_ASSERT)) |
|
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 |
|
debug_mode_req |
|
||||||
inst_mret_i |
|
inst_mret_i |
|
||||||
inst_dret_i;
|
inst_dret_i;
|
||||||
|
@ -258,6 +201,8 @@ module exception (
|
||||||
csr_waddr = 32'h0;
|
csr_waddr = 32'h0;
|
||||||
csr_wdata = 32'h0;
|
csr_wdata = 32'h0;
|
||||||
trigger_match_d = trigger_match_q;
|
trigger_match_d = trigger_match_q;
|
||||||
|
int_id_d = int_id_q;
|
||||||
|
in_irq_context_d = in_irq_context_q;
|
||||||
|
|
||||||
case (state_q)
|
case (state_q)
|
||||||
S_IDLE: begin
|
S_IDLE: begin
|
||||||
|
@ -268,6 +213,8 @@ module exception (
|
||||||
assert_addr_d = mtvec_i + int_or_exception_offset;
|
assert_addr_d = mtvec_i + int_or_exception_offset;
|
||||||
return_addr_d = inst_addr_i;
|
return_addr_d = inst_addr_i;
|
||||||
state_d = S_W_MSTATUS;
|
state_d = S_W_MSTATUS;
|
||||||
|
int_id_d = int_id_i;
|
||||||
|
in_irq_context_d = 1'b1;
|
||||||
end else if (debug_mode_req) begin
|
end else if (debug_mode_req) begin
|
||||||
debug_mode_d = 1'b1;
|
debug_mode_d = 1'b1;
|
||||||
if (enter_debug_cause_debugger_req |
|
if (enter_debug_cause_debugger_req |
|
||||||
|
@ -293,9 +240,11 @@ module exception (
|
||||||
state_d = S_W_DCSR;
|
state_d = S_W_DCSR;
|
||||||
end
|
end
|
||||||
end else if (inst_mret_i) begin
|
end else if (inst_mret_i) begin
|
||||||
|
in_irq_context_d = 1'b0;
|
||||||
assert_addr_d = mepc_i;
|
assert_addr_d = mepc_i;
|
||||||
csr_we = 1'b1;
|
csr_we = 1'b1;
|
||||||
csr_waddr = {20'h0, `CSR_MSTATUS};
|
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||||
|
// 开全局中断
|
||||||
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
|
csr_wdata = {mstatus_i[31:4], 1'b1, mstatus_i[2:0]};
|
||||||
state_d = S_ASSERT;
|
state_d = S_ASSERT;
|
||||||
end else if (inst_dret_i) begin
|
end else if (inst_dret_i) begin
|
||||||
|
@ -309,6 +258,7 @@ module exception (
|
||||||
S_W_MSTATUS: begin
|
S_W_MSTATUS: begin
|
||||||
csr_we = 1'b1;
|
csr_we = 1'b1;
|
||||||
csr_waddr = {20'h0, `CSR_MSTATUS};
|
csr_waddr = {20'h0, `CSR_MSTATUS};
|
||||||
|
// 关全局中断
|
||||||
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
|
csr_wdata = {mstatus_i[31:4], 1'b0, mstatus_i[2:0]};
|
||||||
state_d = S_W_MEPC;
|
state_d = S_W_MEPC;
|
||||||
end
|
end
|
||||||
|
@ -352,6 +302,8 @@ module exception (
|
||||||
return_addr_q <= 32'h0;
|
return_addr_q <= 32'h0;
|
||||||
dcsr_cause_q <= `DCSR_CAUSE_NONE;
|
dcsr_cause_q <= `DCSR_CAUSE_NONE;
|
||||||
trigger_match_q <= 1'b0;
|
trigger_match_q <= 1'b0;
|
||||||
|
int_id_q <= 8'h0;
|
||||||
|
in_irq_context_q <= 1'b0;
|
||||||
end else begin
|
end else begin
|
||||||
state_q <= state_d;
|
state_q <= state_d;
|
||||||
assert_addr_q <= assert_addr_d;
|
assert_addr_q <= assert_addr_d;
|
||||||
|
@ -359,6 +311,8 @@ module exception (
|
||||||
return_addr_q <= return_addr_d;
|
return_addr_q <= return_addr_d;
|
||||||
dcsr_cause_q <= dcsr_cause_d;
|
dcsr_cause_q <= dcsr_cause_d;
|
||||||
trigger_match_q <= trigger_match_d;
|
trigger_match_q <= trigger_match_d;
|
||||||
|
int_id_q <= int_id_d;
|
||||||
|
in_irq_context_q <= in_irq_context_d;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,8 @@ module tinyriscv_core #(
|
||||||
input wire data_err_i,
|
input wire data_err_i,
|
||||||
|
|
||||||
// interrupt input
|
// interrupt input
|
||||||
input wire irq_software_i,
|
input wire int_req_i,
|
||||||
input wire irq_timer_i,
|
input wire[7:0] int_id_i,
|
||||||
input wire irq_external_i,
|
|
||||||
input wire[14:0] irq_fast_i,
|
|
||||||
|
|
||||||
// debug request signal
|
// debug request signal
|
||||||
input wire debug_req_i
|
input wire debug_req_i
|
||||||
|
@ -343,10 +341,8 @@ module tinyriscv_core #(
|
||||||
.dpc_i(csr_dpc_o),
|
.dpc_i(csr_dpc_o),
|
||||||
.dcsr_i(csr_dcsr_o),
|
.dcsr_i(csr_dcsr_o),
|
||||||
.trigger_match_i(csr_trigger_match_o),
|
.trigger_match_i(csr_trigger_match_o),
|
||||||
.irq_software_i(irq_software_i),
|
.int_req_i(int_req_i),
|
||||||
.irq_timer_i(irq_timer_i),
|
.int_id_i(int_id_i),
|
||||||
.irq_external_i(irq_external_i),
|
|
||||||
.irq_fast_i(irq_fast_i),
|
|
||||||
.debug_halt_addr_i(DEBUG_HALT_ADDR),
|
.debug_halt_addr_i(DEBUG_HALT_ADDR),
|
||||||
.debug_req_i(debug_req_i),
|
.debug_req_i(debug_req_i),
|
||||||
.csr_we_o(excep_csr_we_o),
|
.csr_we_o(excep_csr_we_o),
|
||||||
|
|
|
@ -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
|
|
@ -41,9 +41,9 @@ module tinyriscv_soc_top #(
|
||||||
|
|
||||||
localparam int MASTERS = 3; // Number of master ports
|
localparam int MASTERS = 3; // Number of master ports
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
localparam int SLAVES = 7; // Number of slave ports
|
localparam int SLAVES = 8; // Number of slave ports
|
||||||
`else
|
`else
|
||||||
localparam int SLAVES = 6; // Number of slave ports
|
localparam int SLAVES = 7; // Number of slave ports
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
// masters
|
// masters
|
||||||
|
@ -58,8 +58,9 @@ module tinyriscv_soc_top #(
|
||||||
localparam int Mtimer = 3;
|
localparam int Mtimer = 3;
|
||||||
localparam int Gpio = 4;
|
localparam int Gpio = 4;
|
||||||
localparam int Uart = 5;
|
localparam int Uart = 5;
|
||||||
|
localparam int Rvic = 6;
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
localparam int SimCtrl = 6;
|
localparam int SimCtrl = 7;
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,12 +101,21 @@ module tinyriscv_soc_top #(
|
||||||
wire debug_req;
|
wire debug_req;
|
||||||
wire core_halted;
|
wire core_halted;
|
||||||
|
|
||||||
|
reg[31:0] irq_src;
|
||||||
|
wire int_req;
|
||||||
|
wire[7:0] int_id;
|
||||||
|
|
||||||
wire mtimer_irq;
|
wire mtimer_irq;
|
||||||
|
|
||||||
wire[1:0] io_in;
|
wire[1:0] io_in;
|
||||||
wire[31:0] gpio_ctrl;
|
wire[31:0] gpio_ctrl;
|
||||||
wire[31:0] gpio_data;
|
wire[31:0] gpio_data;
|
||||||
|
|
||||||
|
always @ (*) begin
|
||||||
|
irq_src = 32'h0;
|
||||||
|
irq_src[0] = mtimer_irq;
|
||||||
|
end
|
||||||
|
|
||||||
`ifdef VERILATOR
|
`ifdef VERILATOR
|
||||||
assign halted_ind_pin = core_halted;
|
assign halted_ind_pin = core_halted;
|
||||||
`else
|
`else
|
||||||
|
@ -139,10 +149,8 @@ module tinyriscv_soc_top #(
|
||||||
.data_rdata_i (master_rdata[CoreD]),
|
.data_rdata_i (master_rdata[CoreD]),
|
||||||
.data_err_i (1'b0),
|
.data_err_i (1'b0),
|
||||||
|
|
||||||
.irq_software_i (1'b0),
|
.int_req_i (int_req),
|
||||||
.irq_timer_i (mtimer_irq),
|
.int_id_i (int_id),
|
||||||
.irq_external_i (1'b0),
|
|
||||||
.irq_fast_i (15'b0),
|
|
||||||
|
|
||||||
.debug_req_i (debug_req)
|
.debug_req_i (debug_req)
|
||||||
);
|
);
|
||||||
|
@ -229,10 +237,26 @@ module tinyriscv_soc_top #(
|
||||||
.rx_pin (uart_rx_pin)
|
.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
|
`ifdef VERILATOR
|
||||||
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
assign slave_addr_mask[SimCtrl] = `SIM_CTRL_ADDR_MASK;
|
||||||
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
assign slave_addr_base[SimCtrl] = `SIM_CTRL_ADDR_BASE;
|
||||||
// 6.仿真控制模块
|
// 7.仿真控制模块
|
||||||
sim_ctrl u_sim_ctrl(
|
sim_ctrl u_sim_ctrl(
|
||||||
.clk_i (clk),
|
.clk_i (clk),
|
||||||
.rst_ni (ndmreset_n),
|
.rst_ni (ndmreset_n),
|
||||||
|
|
Loading…
Reference in New Issue