// Copyright 2018 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law // or agreed to in writing, software, hardware and materials distributed under // this 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. // // Author: Florian Zaruba, ETH Zurich // Date: 08.05.2017 // Description: Flush controller import ariane_pkg::*; module controller ( input logic clk_i, input logic rst_ni, output logic set_pc_commit_o, // Set PC om PC Gen output logic flush_if_o, // Flush the IF stage output logic flush_unissued_instr_o, // Flush un-issued instructions of the scoreboard output logic flush_id_o, // Flush ID stage output logic flush_ex_o, // Flush EX stage output logic flush_icache_o, // Flush ICache output logic flush_dcache_o, // Flush DCache input logic flush_dcache_ack_i, // Acknowledge the whole DCache Flush output logic flush_tlb_o, // Flush TLBs input logic halt_csr_i, // Halt request from CSR (WFI instruction) output logic halt_o, // Halt signal to commit stage input logic eret_i, // Return from exception input logic ex_valid_i, // We got an exception, flush the pipeline input logic set_debug_pc_i, // set the debug pc from CSR input branchpredict_t resolved_branch_i, // We got a resolved branch, check if we need to flush the front-end input logic flush_csr_i, // We got an instruction which altered the CSR, flush the pipeline input logic fence_i_i, // fence.i in input logic fence_i, // fence in input logic sfence_vma_i, // We got an instruction to flush the TLBs and pipeline input logic flush_commit_i // Flush request from commit stage ); // active fence - high if we are currently flushing the dcache logic fence_active_d, fence_active_q; logic flush_dcache; // ------------ // Flush CTRL // ------------ always_comb begin : flush_ctrl fence_active_d = fence_active_q; set_pc_commit_o = 1'b0; flush_if_o = 1'b0; flush_unissued_instr_o = 1'b0; flush_id_o = 1'b0; flush_ex_o = 1'b0; flush_dcache = 1'b0; flush_icache_o = 1'b0; flush_tlb_o = 1'b0; // ------------ // Mis-predict // ------------ // flush on mispredict if (resolved_branch_i.is_mispredict) begin // flush only un-issued instructions flush_unissued_instr_o = 1'b1; // and if stage flush_if_o = 1'b1; end // --------------------------------- // FENCE // --------------------------------- if (fence_i) begin // this can be seen as a CSR instruction with side-effect set_pc_commit_o = 1'b1; flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; flush_ex_o = 1'b1; flush_dcache = 1'b1; fence_active_d = 1'b1; end // --------------------------------- // FENCE.I // --------------------------------- if (fence_i_i) begin set_pc_commit_o = 1'b1; flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; flush_ex_o = 1'b1; flush_icache_o = 1'b1; flush_dcache = 1'b1; fence_active_d = 1'b1; end // wait for the acknowledge here if (flush_dcache_ack_i && fence_active_q) begin fence_active_d = 1'b0; // keep the flush dcache signal high as long as we didn't get the acknowledge from the cache end else if (fence_active_q) begin flush_dcache = 1'b1; end // --------------------------------- // SFENCE.VMA // --------------------------------- if (sfence_vma_i) begin set_pc_commit_o = 1'b1; flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; flush_ex_o = 1'b1; flush_tlb_o = 1'b1; end // Set PC to commit stage and flush pipleine if (flush_csr_i || flush_commit_i) begin set_pc_commit_o = 1'b1; flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; flush_ex_o = 1'b1; end // --------------------------------- // 1. Exception // 2. Return from exception // --------------------------------- if (ex_valid_i || eret_i || set_debug_pc_i) begin // don't flush pcgen as we want to take the exception: Flush PCGen is not a flush signal // for the PC Gen stage but instead tells it to take the PC we gave it set_pc_commit_o = 1'b0; flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; flush_ex_o = 1'b1; end end // ---------------------- // Halt Logic // ---------------------- always_comb begin // halt the core if the fence is active halt_o = halt_csr_i || fence_active_q; end // ---------------------- // Registers // ---------------------- always_ff @(posedge clk_i or negedge rst_ni) begin if(~rst_ni) begin fence_active_q <= 1'b0; flush_dcache_o <= 1'b0; end else begin fence_active_q <= fence_active_d; // register on the flush signal, this signal might be critical flush_dcache_o <= flush_dcache; end end endmodule