tinyriscv/rtl/core/clint.v

243 lines
8.6 KiB
Coq
Raw Normal View History

/*
Copyright 2020 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 "defines.v"
// core local interruptor module
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٲ<EFBFBD>ģ<EFBFBD><EFBFBD>
module clint(
input wire clk,
input wire rst,
// from core
input wire[`INT_BUS] int_flag_i, // <EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
// from id
input wire[`InstBus] inst_i, // ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
input wire[`InstAddrBus] inst_addr_i, // ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
// from ex
input wire jump_flag_i,
input wire[`InstAddrBus] jump_addr_i,
input wire div_started_i,
// from ctrl
input wire[`Hold_Flag_Bus] hold_flag_i, // <EFBFBD><EFBFBD>ˮ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD>־
// from csr_reg
input wire[`RegBus] data_i, // CSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
input wire[`RegBus] csr_mtvec, // mtvec<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
input wire[`RegBus] csr_mepc, // mepc<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
input wire[`RegBus] csr_mstatus, // mstatus<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
input wire global_int_en_i, // ȫ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ʹ<EFBFBD>ܱ<EFBFBD>־
// to ctrl
output wire hold_flag_o, // <EFBFBD><EFBFBD>ˮ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD>־
// to csr_reg
output reg we_o, // дCSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
output reg[`MemAddrBus] waddr_o, // дCSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
output reg[`MemAddrBus] raddr_o, // <EFBFBD><EFBFBD>CSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
output reg[`RegBus] data_o, // дCSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// to ex
output reg[`InstAddrBus] int_addr_o, // <EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>ַ
output reg int_assert_o // <EFBFBD>жϱ<EFBFBD>־
);
// <EFBFBD>ж<EFBFBD>״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
localparam S_INT_IDLE = 4'b0001;
localparam S_INT_SYNC_ASSERT = 4'b0010;
localparam S_INT_ASYNC_ASSERT = 4'b0100;
localparam S_INT_MRET = 4'b1000;
// дCSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
localparam S_CSR_IDLE = 5'b00001;
localparam S_CSR_MSTATUS = 5'b00010;
localparam S_CSR_MEPC = 5'b00100;
localparam S_CSR_MSTATUS_MRET = 5'b01000;
localparam S_CSR_MCAUSE = 5'b10000;
reg[3:0] int_state;
reg[4:0] csr_state;
reg[`InstAddrBus] inst_addr;
reg[31:0] cause;
assign hold_flag_o = ((int_state != S_INT_IDLE) | (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;
// <EFBFBD>ж<EFBFBD><EFBFBD>ٲ<EFBFBD><EFBFBD>߼<EFBFBD>
always @ (*) begin
if (rst == `RstEnable) begin
int_state = S_INT_IDLE;
end else begin
if (inst_i == `INST_ECALL || inst_i == `INST_EBREAK) begin
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>н׶ε<EFBFBD>ָ<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><EFBFBD><EFBFBD>жϣ<EFBFBD><EFBFBD>ȳ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٴ<EFBFBD><EFBFBD><EFBFBD>
if (div_started_i == `DivStop) begin
int_state = S_INT_SYNC_ASSERT;
end else begin
int_state = S_INT_IDLE;
end
end else if (int_flag_i != `INT_NONE && global_int_en_i == `True) begin
int_state = S_INT_ASYNC_ASSERT;
end else if (inst_i == `INST_MRET) begin
int_state = S_INT_MRET;
end else begin
int_state = S_INT_IDLE;
end
end
end
// дCSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD>л<EFBFBD>
always @ (posedge clk) begin
if (rst == `RstEnable) begin
csr_state <= S_CSR_IDLE;
cause <= `ZeroWord;
inst_addr <= `ZeroWord;
end else begin
case (csr_state)
S_CSR_IDLE: begin
// ͬ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
if (int_state == S_INT_SYNC_ASSERT) begin
csr_state <= S_CSR_MEPC;
// <EFBFBD><EFBFBD><EFBFBD>жϴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϷ<EFBFBD><EFBFBD>ص<EFBFBD>ַ<EFBFBD><EFBFBD>4
if (jump_flag_i == `JumpEnable) begin
inst_addr <= jump_addr_i - 4'h4;
end else begin
inst_addr <= inst_addr_i;
end
case (inst_i)
`INST_ECALL: begin
cause <= 32'd11;
end
`INST_EBREAK: begin
cause <= 32'd3;
end
default: begin
cause <= 32'd10;
end
endcase
// <EFBFBD><EFBFBD>ж<EFBFBD>
end else if (int_state == S_INT_ASYNC_ASSERT) begin
// <EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
cause <= 32'h80000004;
csr_state <= S_CSR_MEPC;
if (jump_flag_i == `JumpEnable) begin
inst_addr <= jump_addr_i;
// <EFBFBD><EFBFBD>жϿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϳ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>У<EFBFBD><EFBFBD>жϴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>г<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
end else if (div_started_i == `DivStart) begin
inst_addr <= inst_addr_i - 4'h4;
end else begin
inst_addr <= inst_addr_i;
end
// <EFBFBD>жϷ<EFBFBD><EFBFBD><EFBFBD>
end else if (int_state == S_INT_MRET) begin
csr_state <= S_CSR_MSTATUS_MRET;
end
end
S_CSR_MEPC: begin
csr_state <= S_CSR_MSTATUS;
end
S_CSR_MSTATUS: begin
csr_state <= S_CSR_MCAUSE;
end
S_CSR_MCAUSE: begin
csr_state <= S_CSR_IDLE;
end
S_CSR_MSTATUS_MRET: begin
csr_state <= S_CSR_IDLE;
end
default: begin
csr_state <= S_CSR_IDLE;
end
endcase
end
end
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD>ź<EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>CSR<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
always @ (posedge clk) begin
if (rst == `RstEnable) begin
we_o <= `WriteDisable;
waddr_o <= `ZeroWord;
data_o <= `ZeroWord;
end else begin
case (csr_state)
// <EFBFBD><EFBFBD>mepc<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>ǰָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
S_CSR_MEPC: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MEPC};
data_o <= inst_addr;
end
// д<EFBFBD>жϲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD>
S_CSR_MCAUSE: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MCAUSE};
data_o <= cause;
end
// <EFBFBD>ر<EFBFBD>ȫ<EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>
S_CSR_MSTATUS: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MSTATUS};
data_o <= {csr_mstatus[31:4], 1'b0, csr_mstatus[2:0]};
end
// <EFBFBD>жϷ<EFBFBD><EFBFBD><EFBFBD>
S_CSR_MSTATUS_MRET: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MSTATUS};
data_o <= {csr_mstatus[31:4], csr_mstatus[7], csr_mstatus[2:0]};
end
default: begin
we_o <= `WriteDisable;
waddr_o <= `ZeroWord;
data_o <= `ZeroWord;
end
endcase
end
end
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><EFBFBD>źŸ<EFBFBD>exģ<EFBFBD><EFBFBD>
always @ (posedge clk) begin
if (rst == `RstEnable) begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end else begin
case (csr_state)
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>.д<EFBFBD><EFBFBD>mcause<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܷ<EFBFBD>
S_CSR_MCAUSE: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mtvec;
end
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
S_CSR_MSTATUS_MRET: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mepc;
end
default: begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end
endcase
end
end
endmodule