blob: 21d8e5d9f2adab9e110f64a4f9e06645862cf599 [file] [log] [blame]
module sleep_unit
#(
parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
)
(
HCLK,
HRESETn,
PADDR,
PWDATA,
PWRITE,
PSEL,
PENABLE,
PRDATA,
PREADY,
PSLVERR,
irq_i,
event_i,
core_busy_i,
fetch_en_o,
clk_gate_core_o
);
//parameter APB_ADDR_WIDTH = 12;
input wire HCLK;
input wire HRESETn;
input wire [APB_ADDR_WIDTH - 1:0] PADDR;
input wire [31:0] PWDATA;
input wire PWRITE;
input wire PSEL;
input wire PENABLE;
output reg [31:0] PRDATA;
output wire PREADY;
output wire PSLVERR;
input wire irq_i;
input wire event_i;
input wire core_busy_i;
output reg fetch_en_o;
output reg clk_gate_core_o;
reg [1:0] SLEEP_STATE_N;
reg [1:0] SLEEP_STATE_Q;
reg [63:0] regs_q;
reg [63:0] regs_n;
reg core_sleeping_int;
always @(*) begin
SLEEP_STATE_N = SLEEP_STATE_Q;
case (SLEEP_STATE_Q)
2'd0:
if (regs_q[32])
if (~event_i)
SLEEP_STATE_N = 2'd1;
2'd1:
if (event_i)
SLEEP_STATE_N = 2'd0;
else if (~core_busy_i && ~irq_i)
SLEEP_STATE_N = 2'd2;
2'd2:
if (event_i)
SLEEP_STATE_N = 2'd0;
else if (irq_i)
SLEEP_STATE_N = 2'd1;
default: SLEEP_STATE_N = 2'd0;
endcase
end
always @(*) begin
fetch_en_o = 1'b1;
clk_gate_core_o = 1'b1;
core_sleeping_int = 1'b0;
case (SLEEP_STATE_Q)
2'd0:
if (regs_q[32] && ~event_i)
fetch_en_o = 1'b0;
else
fetch_en_o = 1'b1;
2'd1: fetch_en_o = 1'b0;
2'd2: begin
clk_gate_core_o = (event_i ? 1'b1 : 1'b0);
core_sleeping_int = 1'b1;
fetch_en_o = 1'b0;
end
default: begin
fetch_en_o = 1'b1;
clk_gate_core_o = 1'b1;
core_sleeping_int = 1'b0;
end
endcase
end
wire [0:0] register_adr;
assign register_adr = PADDR[3:2];
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
always @(*) begin
regs_n = regs_q;
regs_n[1'b0] = core_sleeping_int;
if (core_sleeping_int || event_i)
regs_n[32] = 1'b0;
if ((PSEL && PENABLE) && PWRITE)
case (register_adr)
2'b00: regs_n[32+:32] = PWDATA;
endcase
end
always @(*) begin
PRDATA = 'b0;
if ((PSEL && PENABLE) && !PWRITE)
case (register_adr)
2'b00: PRDATA = regs_q[32+:32];
2'b01: PRDATA = regs_q[0+:32];
default: PRDATA = 'b0;
endcase
end
always @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
SLEEP_STATE_Q <= 2'd0;
regs_q <= {2 {32'b00000000000000000000000000000000}};
end
else begin
SLEEP_STATE_Q <= SLEEP_STATE_N;
regs_q <= regs_n;
end
endmodule