/*Copyright 2020-2021 T-Head Semiconductor Co., Ltd. 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. */ // &Depend("environment.h"); @21 // &Depend("cpu_cfig.h"); @22 // &ModuleBeg; @24 module pmu( apb_pmu_paddr, apb_pmu_penable, apb_pmu_psel, apb_pmu_pwdata, apb_pmu_pwrite, biu_pad_lpmd_b, corec_pmu_sleep_out, cpu_clk, gate_en0, gate_en1, had_pad_wakeup_req_b, i_pad_cpu_jtg_rst_b, i_pad_jtg_tclk, intraw_vld, pad_cpu_rst_b, pad_had_jtg_tap_en, pad_had_jtg_tms_i, pad_had_jtg_trst_b, pad_had_jtg_trst_b_pre, pg_reset_b, pmu_apb_prdata, pmu_clk, pmu_corec_isolation, pmu_corec_sleep_in, sys_rst ); // &Ports; @25 input [11:0] apb_pmu_paddr; input apb_pmu_penable; input apb_pmu_psel; input [31:0] apb_pmu_pwdata; input apb_pmu_pwrite; input [1 :0] biu_pad_lpmd_b; input corec_pmu_sleep_out; input cpu_clk; input had_pad_wakeup_req_b; input i_pad_cpu_jtg_rst_b; input i_pad_jtg_tclk; input intraw_vld; input pad_cpu_rst_b; input pad_had_jtg_tap_en; input pad_had_jtg_tms_i; input pad_had_jtg_trst_b_pre; input pmu_clk; input sys_rst; output gate_en0; output gate_en1; output pad_had_jtg_trst_b; output pg_reset_b; output [31:0] pmu_apb_prdata; output pmu_corec_isolation; output pmu_corec_sleep_in; // &Regs; @26 reg [31:0] counter; reg counter_en_ff; reg [31:0] counter_load; reg [31:0] ctrl_reg; reg [2 :0] cur_state; reg debug_pending; reg event_ff; reg event_pending; reg [2 :0] next_state; reg [2 :0] pg_next_state; reg [2 :0] pg_state; reg [31:0] pmu_apb_prdata; // &Wires; @27 wire [11:0] apb_pmu_paddr; wire apb_pmu_penable; wire apb_pmu_psel; wire [31:0] apb_pmu_pwdata; wire apb_pmu_pwrite; wire [1 :0] biu_pad_lpmd_b; wire corec_pmu_sleep_out; wire counter_en; wire cpu_clk; wire debug_ctl_en; wire debug_vld; wire debug_vld_pre; wire debug_wake_vld; wire doze_mode; wire event_ctl_en; wire event_vld; wire gate_en0; wire gate_en1; wire had_pad_wakeup_req_b; wire i_pad_cpu_jtg_rst_b; wire i_pad_jtg_tclk; wire intraw_vld; wire load_cnt_en; wire low_power_dis; wire low_power_dis_pre; wire lpmd_en; wire lpmd_en_ff; wire pad_cpu_rst_b; wire pad_had_jtg_tap_en; wire pad_had_jtg_tms_i; wire pad_had_jtg_trst_b; wire pad_had_jtg_trst_b_pre; wire pad_vic_event_vld; wire pg_reset_b; wire pmu_clk; wire pmu_corec_isolation; wire pmu_corec_sleep_in; wire pmu_debug_wakeup; wire pmu_event_wakeup; wire pmu_wakeup; wire pmu_wic_wakeup; wire stop_mode; wire sys_rst; wire wait_mode; wire wic_ctl_en; parameter IDLE = 3'b000; parameter WAIT = 3'b001; parameter DOZE = 3'b010; parameter STOP = 3'b011; parameter WAIT_AWAKE = 3'b100; parameter PG_IDLE = 3'b000; parameter PG_RESET_ON = 3'b001; parameter PG_ISO_ON = 3'b010; parameter PG_POWER_OFF_REQ = 3'b011; parameter PG_POWER_OFF = 3'b100; parameter PG_POWER_ON = 3'b101; parameter PG_ISO_OFF = 3'b110; parameter PG_RESET_OFF = 3'b111; assign low_power_dis_pre = (biu_pad_lpmd_b[1:0] == 2'b11); assign lpmd_en = (biu_pad_lpmd_b[1:0] != 2'b11) ; ////////////sync ///////////////////// // &Instance("sync", "x_cpu2pmu_sync1"); @58 sync x_cpu2pmu_sync1 ( .fast_clk (cpu_clk ), .in (lpmd_en ), .out (lpmd_en_ff ), .pad_cpu_rst_b (pad_cpu_rst_b), .slow_clk (pmu_clk ) ); // &Connect( .in ( lpmd_en ), @59 // .out ( lpmd_en_ff ), @60 // .fast_clk ( cpu_clk ), @61 // .slow_clk ( pmu_clk ) @62 // ); @63 // &Instance("sync", "x_cpu2pmu_sync2"); @69 sync x_cpu2pmu_sync2 ( .fast_clk (cpu_clk ), .in (low_power_dis_pre), .out (low_power_dis ), .pad_cpu_rst_b (pad_cpu_rst_b ), .slow_clk (pmu_clk ) ); // &Connect( .in ( low_power_dis_pre ), @70 // .out ( low_power_dis ), @71 // .fast_clk ( cpu_clk ), @72 // .slow_clk ( pmu_clk ) @73 // ); @74 //------------------------------------------------ //WRITE CTRL REG //------------------------------------------------ always @ (posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) begin ctrl_reg[31:0] <= 32'b0; end else if (apb_pmu_psel && apb_pmu_pwrite && apb_pmu_penable) begin if (!apb_pmu_paddr[11:0] ) ctrl_reg[31:0] <= apb_pmu_pwdata[31:0]; else if (apb_pmu_paddr[11:0] == 12'h4 ) counter_load[31:0] <= apb_pmu_pwdata[31:0]; end end //------------------------------------------------ //READ CTRL REG //------------------------------------------------ // &CombBeg; @99 always @( apb_pmu_paddr[11:0] or ctrl_reg[3:0] or apb_pmu_psel or apb_pmu_pwrite or counter[31:0]) begin if (apb_pmu_psel && !apb_pmu_pwrite) begin if(!apb_pmu_paddr[11:0] ) pmu_apb_prdata[31:0] = {28'b0,ctrl_reg[3:0]}; else if (apb_pmu_paddr[11:0] == 12'h4 ) pmu_apb_prdata[31:0] = counter[31:0]; else pmu_apb_prdata[31:0] = 32'b0; end // &CombEnd; @109 end assign wic_ctl_en = ctrl_reg[0]; assign event_ctl_en = ctrl_reg[1]; assign debug_ctl_en = ctrl_reg[2]; assign counter_en = ctrl_reg[3]; //event counter always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if(!pad_cpu_rst_b) begin counter_en_ff <=0; end else begin counter_en_ff <=counter_en ; end end assign load_cnt_en= (counter_en && !counter_en_ff) || !(|counter[31:0]); always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if(!pad_cpu_rst_b) begin counter[31:0] <= 32'h0; end else if (load_cnt_en) begin counter[31:0] <= counter_load[31:0]; end else if (counter_en) counter[31:0] <= counter[31:0] -1'b1; else counter[31:0] <= counter[31:0]; end assign pad_vic_event_vld = (counter[31:0] == 32'b0) && counter_en; assign pmu_wic_wakeup = intraw_vld && wic_ctl_en && lpmd_en_ff ; // event_wakeup assign event_vld = pad_vic_event_vld && !event_ff && lpmd_en_ff ; always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) event_ff <= 1'b0; else event_ff <= pad_vic_event_vld; end always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) event_pending <= 1'b0; else if (event_vld) event_pending <= 1'b1; else if (low_power_dis) event_pending <= 1'b0; end assign pmu_event_wakeup = event_pending && event_ctl_en ; //debug wake up // &Instance("tap2_sm", "x_tap2_sm"); @180 tap2_sm x_tap2_sm ( .debug_wake_vld (debug_wake_vld ), .pad_had_jtg_tap_en (pad_had_jtg_tap_en ), .tclk (i_pad_jtg_tclk ), .tms_i (pad_had_jtg_tms_i ), .trst_b (i_pad_cpu_jtg_rst_b) ); // &Connect(.tclk (i_pad_jtg_tclk ), @181 // // .trst_b (i_pad_jtg_trst_b ), @182 // .trst_b (i_pad_cpu_jtg_rst_b ), @183 // .tms_i (pad_had_jtg_tms_i ) @184 // ); @185 assign debug_vld_pre = (debug_wake_vld || !had_pad_wakeup_req_b) && lpmd_en_ff; // &Instance("px_had_sync", "x_jtag2pmu_sync"); @193 px_had_sync x_jtag2pmu_sync ( .clk1 (i_pad_jtg_tclk ), .clk2 (pmu_clk ), .rst1_b (pad_had_jtg_trst_b_pre), .rst2_b (pad_cpu_rst_b ), .sync_in (debug_vld_pre ), .sync_out (debug_vld ) ); // &Connect(.clk1 (i_pad_jtg_tclk ), @194 // .clk2 (pmu_clk ), @195 // .rst1_b (pad_had_jtg_trst_b_pre ), @196 // .rst2_b (pad_cpu_rst_b ), @197 // .sync_in (debug_vld_pre ), @198 // .sync_out (debug_vld ) @199 // ); @200 always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) debug_pending <= 1'b0; else if (debug_vld) debug_pending <= 1'b1; else if (low_power_dis) debug_pending <= 1'b0; end //assign pad_had_jdb_req_b = !debug_pending; assign pmu_debug_wakeup = debug_pending && debug_ctl_en ; ///// assign pmu_wakeup = pmu_event_wakeup || pmu_wic_wakeup || pmu_debug_wakeup ; //----------------------------------------- // PMU FSM //----------------------------------------- always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) cur_state[2:0] <= IDLE; else cur_state[2:0] <= next_state[2:0]; end //assign doze_mode = ( biu_pad_lpmd_b[1:0] == 2'b10); //assign wait_mode = ( biu_pad_lpmd_b[1:0] == 2'b01); //assign stop_mode = ( biu_pad_lpmd_b[1:0] == 2'b00); assign doze_mode = 1'b0; assign wait_mode = 1'b0; assign stop_mode = 1'b0; // &CombBeg; @246 always @( cur_state or pmu_wakeup or pg_state[2:0] or biu_pad_lpmd_b[1:0] or doze_mode or stop_mode or wait_mode) begin case(cur_state) IDLE: begin if(doze_mode ) begin next_state = DOZE; end else if(wait_mode ) begin next_state = WAIT; end else if(stop_mode ) begin next_state = STOP; end else begin next_state = IDLE; end end DOZE: begin if(pmu_wakeup) begin next_state = WAIT_AWAKE; end else begin next_state = DOZE; end end WAIT: begin if(pmu_wakeup) begin next_state = WAIT_AWAKE; end else begin next_state = WAIT; end end STOP://////// more states more pg crtl signal begin if(pg_state[2:0]==3'b111) begin next_state = WAIT_AWAKE; end else begin next_state = STOP; end end WAIT_AWAKE: begin if(biu_pad_lpmd_b[1:0] == 2'b11) begin next_state = IDLE; end else begin next_state = WAIT_AWAKE; end end endcase // &CombEnd; @317 end assign gate_en0 = (cur_state[2:0] == IDLE) || (cur_state[2:0] == WAIT_AWAKE); assign gate_en1 = (cur_state[2:0] == WAIT) || (cur_state[2:0] == IDLE) || (cur_state[2:0] == WAIT_AWAKE); //---------------------------------------- // Power Gating FSM //----------------------------------------- always @(posedge pmu_clk or negedge pad_cpu_rst_b) begin if (!pad_cpu_rst_b) pg_state[2:0] <= PG_IDLE; else pg_state[2:0] <= pg_next_state[2:0]; end // &CombBeg; @337 always @( pmu_wakeup or pg_state[2:0] or corec_pmu_sleep_out or cur_state[2:0]) begin case(pg_state[2:0]) PG_IDLE: begin if(cur_state[2:0] == STOP) pg_next_state = PG_RESET_ON; else pg_next_state = PG_IDLE; end PG_RESET_ON: pg_next_state = PG_ISO_ON; PG_ISO_ON: pg_next_state = PG_POWER_OFF_REQ; PG_POWER_OFF_REQ: begin if(corec_pmu_sleep_out) pg_next_state = PG_POWER_OFF; else pg_next_state = PG_POWER_OFF_REQ; end PG_POWER_OFF: begin if(pmu_wakeup) pg_next_state = PG_POWER_ON; else pg_next_state = PG_POWER_OFF; end PG_POWER_ON: pg_next_state = PG_ISO_OFF; PG_ISO_OFF: pg_next_state = PG_RESET_OFF; PG_RESET_OFF: pg_next_state = IDLE; endcase // &CombEnd @371 end assign pmu_corec_sleep_in = pg_state[2:0] == PG_POWER_OFF_REQ || pg_state[2:0] == PG_POWER_OFF; assign pmu_corec_isolation = pg_state[2:0] == PG_ISO_ON || pg_state[2:0] == PG_POWER_OFF_REQ || pg_state[2:0] == PG_POWER_OFF || pg_state[2:0] == PG_POWER_ON || pg_state[2:0] == PG_ISO_OFF; assign pg_reset_b = pg_state[2:0] == PG_IDLE && pad_cpu_rst_b & sys_rst; assign pad_had_jtg_trst_b = pg_state[2:0] == PG_IDLE && pad_had_jtg_trst_b_pre; // &ModuleEnd; @392 endmodule