support preemption

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/1/head
liangkangnan 2020-04-25 17:03:13 +08:00
parent 0ac39d9cdd
commit 09513f8f2c
1 changed files with 121 additions and 91 deletions

View File

@ -36,6 +36,14 @@ module clint(
// from csr_reg
input wire[`RegBus] data_i, // CSR
input wire[`RegBus] csr_mtvec, // mtvec
input wire[`RegBus] csr_mepc, // mepc
input wire[`RegBus] csr_mstatus, // mstatus
input wire global_int_en_i, // 使
// to ctrl
output wire hold_flag_o, // 线
// to csr_reg
output reg we_o, // CSR
@ -44,130 +52,152 @@ module clint(
output reg[`RegBus] data_o, // CSR
// to ex
output reg[`InstAddrBus] int_addr_o, //
output reg[`InstAddrBus] int_addr_o, //
output reg int_assert_o //
);
//
localparam STATE_IDLE = 4'b0001;
localparam STATE_ASSERT = 4'b0010;
localparam STATE_WAIT_MRET = 4'b0100;
localparam STATE_MRET = 4'b1000;
//
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;
reg[3:0] state;
reg[3:0] next_state;
// CSR
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;
//
always @ (posedge clk) begin
if (rst == `RstEnable) begin
state <= STATE_IDLE;
end else begin
state <= next_state;
end
end
assign hold_flag_o = ((int_state != S_INT_IDLE) || (csr_state != S_CSR_IDLE))? `HoldEnable: `HoldDisable;
//
//
always @ (*) begin
if (rst == `RstEnable) begin
next_state <= STATE_IDLE;
int_state <= S_INT_IDLE;
end else begin
case (state)
STATE_IDLE: begin
// .
// ()
if (int_flag_i != `INT_NONE) begin
next_state <= STATE_ASSERT;
end else begin
next_state <= STATE_IDLE;
end
end
STATE_ASSERT: begin
next_state <= STATE_WAIT_MRET;
end
STATE_WAIT_MRET: begin
if (inst_i == `INST_MRET) begin
next_state <= STATE_MRET;
end else begin
next_state <= STATE_WAIT_MRET;
end
end
STATE_MRET: begin
next_state <= STATE_IDLE;
end
default: begin
next_state <= STATE_IDLE;
end
endcase
if (inst_i == `INST_ECALL) begin
int_state <= S_INT_SYNC_ASSERT;
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
always @ (*) begin
if (rst == `RstEnable) begin
raddr_o <= `ZeroWord;
end else begin
case (state)
STATE_IDLE: begin
raddr_o <= {20'h0, `CSR_MTVEC};
end
STATE_ASSERT: begin
raddr_o <= {20'h0, `CSR_MTVEC};
end
STATE_WAIT_MRET: begin
raddr_o <= {20'h0, `CSR_MEPC};
end
STATE_MRET: begin
raddr_o <= {20'h0, `CSR_MEPC};
end
default: begin
raddr_o <= {20'h0, `CSR_MTVEC};
end
endcase
end
end
//
//
// CSR
always @ (posedge clk) begin
if (rst == `RstEnable) begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
csr_state <= S_CSR_IDLE;
cause <= `ZeroWord;
inst_addr <= `ZeroWord;
end else begin
case (state)
STATE_ASSERT: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= data_i;
case (csr_state)
S_CSR_IDLE: begin
if (int_state == S_INT_SYNC_ASSERT) begin
// ecall
cause <= 32'd11;
csr_state <= S_CSR_MEPC;
inst_addr <= inst_addr_i;
end else if (int_state == S_INT_ASYNC_ASSERT) begin
//
cause <= 32'h80000004;
csr_state <= S_CSR_MEPC;
inst_addr <= inst_addr_i;
//
end else if (int_state == S_INT_MRET) begin
csr_state <= S_CSR_MSTATUS_MRET;
end
end
STATE_MRET: begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= data_i;
S_CSR_MEPC: begin
csr_state <= S_CSR_MCAUSE;
end
S_CSR_MCAUSE: begin
csr_state <= S_CSR_MSTATUS;
end
S_CSR_MSTATUS: begin
csr_state <= S_CSR_IDLE;
end
S_CSR_MSTATUS_MRET: begin
csr_state <= S_CSR_IDLE;
end
default: begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
csr_state <= S_CSR_IDLE;
end
endcase
end
end
// CSR
// CSR
always @ (posedge clk) begin
if (rst == `RstEnable) begin
we_o <= `WriteDisable;
waddr_o <= `ZeroWord;
data_o <= `ZeroWord;
end else begin
if (state == STATE_ASSERT) begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MEPC};
data_o <= inst_addr_i;
case (csr_state)
// mepc
S_CSR_MEPC: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MEPC};
data_o <= inst_addr;
end
//
S_CSR_MCAUSE: begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MCAUSE};
data_o <= cause;
end
//
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
//
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
// ex
always @ (posedge clk) begin
if (rst == `RstEnable) begin
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end else begin
// .mstatus
if (csr_state == S_CSR_MSTATUS) begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mtvec;
//
end else if (csr_state == S_CSR_MSTATUS_MRET) begin
int_assert_o <= `INT_ASSERT;
int_addr_o <= csr_mepc;
end else begin
we_o <= `WriteEnable;
waddr_o <= {20'h0, `CSR_MCAUSE};
data_o <= {24'h0, int_flag_i};
int_assert_o <= `INT_DEASSERT;
int_addr_o <= `ZeroWord;
end
end
end