OpenCores
URL https://opencores.org/ocsvn/oops/oops/trunk

Subversion Repositories oops

[/] [oops/] [trunk/] [rtl/] [icache_ctl.v] - Rev 2

Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////
//                                                              //
//  OoOPs Core Instruction Cache Control module                 //
//                                                              //
//  This file is part of the OoOPs project                      //
//  http://www.opencores.org/project,oops                       //
//                                                              //
//  Description:                                                //
//  Controller for Instruction Cache.  Block takes requests from//
//  the IF stage, handles the inputs to the cache RAMs, detects //
//  cache hits, and generates bus requests if the cache misses. //
//  The controller is only capable of handling one outstanding  //
//  miss and does no prefetching.                               //
//                                                              //
//  Author(s):                                                  //
//      - Joshua Smith, smjoshua@umich.edu                      //
//                                                              //
//////////////////////////////////////////////////////////////////
//                                                              //
// Copyright (C) 2012 Authors and OPENCORES.ORG                 //
//                                                              //
// This source file may be used and distributed without         //
// restriction provided that this copyright statement is not    //
// removed from the file and that any derivative work contains  //
// the original copyright notice and the associated disclaimer. //
//                                                              //
// This source file is free software; you can redistribute it   //
// and/or modify it under the terms of the GNU Lesser General   //
// Public License as published by the Free Software Foundation; //
// either version 2.1 of the License, or (at your option) any   //
// later version.                                               //
//                                                              //
// This source is distributed in the hope that it will be       //
// useful, but WITHOUT ANY WARRANTY; without even the implied   //
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
// PURPOSE.  See the GNU Lesser General Public License for more //
// details.                                                     //
//                                                              //
// You should have received a copy of the GNU Lesser General    //
// Public License along with this source; if not, download it   //
// from http://www.opencores.org/lgpl.shtml                     //
//                                                              //
//////////////////////////////////////////////////////////////////
`include "ooops_defs.v"
 
module icache_ctl (
  input wire                      clk,
  input wire                      rst,
  input wire                      rob_pipe_flush,
 
  // Coprocessor interface (for IC enable)
  input wire                      cp0_ic_enable,
 
  // IF interface
  input wire                      if_ic_req,
  input wire  [`ADDR_SZ-1:0]      if_ic_fpc,
  input wire  [`ADDR_SZ-1:0]      r_if_ic_fpc,
  output wire [`INSTR_SZ-1:0]     ic_if_data,
  output wire                     ic_if_data_valid,
  output wire                     ic_if_ready,
 
  // Interface to cache memories
  input wire  [`IC_TAGRAM_SZ-1:0] ic_tagram_data,
  input wire  [`IC_LINE_SZ-1:0]   ic_dataram_data,
  output wire [`IC_LINE_SZ-1:0]   ic_dataram_wr_data,
  output wire [`IC_SI_SZ-1:0]     ic_dataram_addr,
  output wire                     ic_dataram_wren,
  output wire [`IC_TAGRAM_SZ-1:0] ic_tagram_wr_data,
  output wire [`IC_SI_SZ-1:0]     ic_tagram_addr,
  output wire                     ic_tagram_wren,
 
  // Memory interface
  output wire                     ic2bus_req,
  output wire [`ADDR_SZ-1:0]      ic2bus_fpc,
  input wire                      bus2ic_valid,
  input wire  [`SYS_BUS_SZ-1:0]   bus2ic_data
  );
 
  parameter IC_STATE_IDLE   = 3'h0,
            IC_STATE_REQ    = 3'h1,
            IC_STATE_WAIT   = 3'h2,
            IC_STATE_WR_RAM = 3'h3,
            IC_STATE_INIT   = 3'h4;
 
  // Internal wires/regs
  wire                          ic_cache_hit;
  wire                          ic_tag_match;
  wire                          ic_tag_valid;
  wire [`IC_TAG_SZ-1:0]         ic_tag;
  wire                          r_if_ic_req;
 
  wire [2:0]                    ic_state;
  reg  [2:0]                    ic_nstate;
  wire [`IC_SI]                 ic_init_ctr;
  wire [`IC_SI]                 ic_init_nctr;
  wire                          ic_do_init;
  wire                          ic_init_done;
  wire                          ic_initialized;
  wire                          ic_initialized_ld;
 
  // Latch req signal so we can correctly assert "hit" and also request to memory
  // on a cache miss.
  MDFFR #(1) r_if_ic_req_ff (clk, rst, 1'b0, if_ic_req, r_if_ic_req);
 
  // If we get a cache miss and then a flush happens, need to make sure that instruction
  // coming back isn't sent down the pipe.
  wire rob_pipe_flush_seen, rob_pipe_flush_seen_in;
  assign rob_pipe_flush_seen_in = rob_pipe_flush_seen ? ~bus2ic_valid : rob_pipe_flush & (ic_state != IC_STATE_IDLE);
  MDFFR #(1) rob_pipe_flush_seen_ff (clk, rst, 1'b0, rob_pipe_flush_seen_in, rob_pipe_flush_seen);
 
  // Handle interface to Data and Tag SRAMs
  `ifdef USE_IC
  assign ic_do_init          = (ic_state == IC_STATE_INIT);
  assign ic_dataram_wren     = ic_do_init || (bus2ic_valid & !rob_pipe_flush_seen);
  assign ic_dataram_wr_data  = ic_do_init ? {`IC_LINE_SZ{1'b0}} : bus2ic_data;
  assign ic_dataram_addr     = (ic_state == IC_STATE_INIT) ? ic_init_ctr[`IC_SI] : 
                               (ic_state == IC_STATE_WAIT) ? ic2bus_fpc[`IC_SI] :
                                                             if_ic_fpc[`IC_SI];
 
  assign ic_tagram_wren      = ic_do_init || (bus2ic_valid & !rob_pipe_flush_seen);
  assign ic_tagram_wr_data   = ic_do_init ? {`IC_TAGRAM_SZ{1'b0}} : {1'b1, 1'b0, ic2bus_fpc[`IC_TAG]};
  assign ic_tagram_addr      = (ic_state == IC_STATE_INIT) ? ic_init_ctr[`IC_SI] : 
                               (ic_state == IC_STATE_WAIT) ? ic2bus_fpc[`IC_SI] :
                                                             if_ic_fpc[`IC_SI];
  `else
  // If not including Icache, then just zero cache inputs out
  assign ic_do_init          = 1'b0;
  assign ic_dataram_wren     = 1'b0;
  assign ic_dataram_wr_data  = {`IC_LINE_SZ{1'b0}};
  assign ic_dataram_addr     = {`IC_SI_SZ{1'b0}};
 
  assign ic_tagram_wren      = 1'b0;
  assign ic_tagram_wr_data   = {`IC_LINE_SZ{1'b0}};
  assign ic_tagram_addr      = {`IC_SI_SZ{1'b0}};
  `endif
 
  // Handle tag comparison and IF interface
  // Note: ic_if_ready just means we've initialized SRAMs.  This will block
  // IF requests and stall the pipeline on startup.
  `ifdef USE_IC
  assign ic_tag           = ic_tagram_data[`IC_TAGRAM_TAG];
  assign ic_tag_valid     = ic_tagram_data[`IC_TAGRAM_VLD];
  assign ic_tag_match     = (ic_tag == r_if_ic_fpc[`IC_TAG]);
  assign ic_cache_hit     = ic_tag_match & (r_if_ic_req & ic_tag_valid & cp0_ic_enable & ic_initialized & !rob_pipe_flush_seen);
  assign ic_if_ready      = ic_initialized & (ic_nstate == IC_STATE_IDLE);
  assign ic_if_data       = r_if_ic_fpc[2] ? ic_dataram_data[63:32] : ic_dataram_data[31:0];
  assign ic_if_data_valid = ic_cache_hit;
  `else
  // If not including Icache, then need to force everything as a cache miss and only return bus2ic_data
  assign ic_tag           = {`IC_TAG_SZ{1'b0}};
  assign ic_tag_valid     = 1'b0;
  assign ic_tag_match     = 1'b0;
  assign ic_cache_hit     = bus2ic_valid & !rob_pipe_flush_seen;
  assign ic_if_ready      = 1'b1; // No need to initialize cache
  assign ic_if_data       = r_if_ic_fpc[2] ? bus2ic_data[63:32] : bus2ic_data[31:0];
  assign ic_if_data_valid = ic_cache_hit;
 
  `endif
 
 
  // Icache state machine
  always @*
    case (ic_state)
      // From the IDLE state
      //  + move to req if we detect a miss
      IC_STATE_IDLE: begin
          if (r_if_ic_req & !ic_cache_hit)
            ic_nstate = IC_STATE_REQ;
          else
            ic_nstate = IC_STATE_IDLE;
        end
 
      // In the REQ state we send the request to memory for the needed data.
      // Then transition to WAIT state to wait for memory response
      // TODO: Need to stall here if arbiter doesn't accept our request
      IC_STATE_REQ: begin
        ic_nstate = IC_STATE_WAIT;
        end
 
      // In the WAIT state we wait for memory response, then transition to
      // WR_RAM state to write the data.
      IC_STATE_WAIT: begin
        if (bus2ic_valid) ic_nstate = IC_STATE_IDLE;
        else              ic_nstate = IC_STATE_WAIT;
        end
 
      // From the INIT state, we initialize each line of the cache to invalid
      // and transition to IDLE after writing each line.
      IC_STATE_INIT: begin
          if (ic_init_ctr == `IC_NUM_LINES-1)
            ic_nstate = IC_STATE_IDLE;
          else
            ic_nstate = IC_STATE_INIT;
        end
 
      default: ic_nstate = IC_STATE_IDLE;
    endcase
 
  // For the initialization, just loop through every set in cache and write it as invalid.  When done
  // set ic_initialized.
  `ifdef USE_IC
  assign ic_init_done      = (ic_state == IC_STATE_INIT) & (ic_init_ctr == `IC_NUM_LINES-1);
  assign ic_initialized_ld = ic_init_done;
  assign ic_init_nctr      = ic_init_ctr + `IC_SI_SZ'h1;
  `else
  assign ic_init_done      = 1'b1;
  assign ic_initialized_ld = 1'b0;
  assign ic_init_nctr      = {`IC_SI_SZ{1'b0}};
  `endif
 
  MDFFR  #(3)         ic_state_ff (clk, rst, IC_STATE_INIT, ic_nstate, ic_state);
  MDFFLR #(`IC_SI_SZ) ic_init_ctr_ff (clk, rst, (ic_state == IC_STATE_INIT), `IC_SI_SZ'h0, ic_init_nctr, ic_init_ctr);
  MDFFLR #(1)         ic_initialized_ff (clk, rst, ic_initialized_ld, 1'b0, 1'b1, ic_initialized);
 
  // Handle memory request outputs
  // Note that we request from the bus the cycle after detecting a hit, so if_ic_fpc should be corrected from miss already.
  assign ic2bus_fpc = if_ic_fpc;
  assign ic2bus_req = (ic_state == IC_STATE_REQ);
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.