controller.sv 6.68 KB
Newer Older
sakundu committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
// 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