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

Subversion Repositories altor32

[/] [altor32/] [trunk/] [rtl/] [cpu/] [altor32_dcache.v] - Rev 36

Go to most recent revision | Compare with Previous | Blame | View Log

//-----------------------------------------------------------------
//                           AltOR32 
//                Alternative Lightweight OpenRisc 
//                            V2.1
//                     Ultra-Embedded.com
//                   Copyright 2011 - 2014
//
//               Email: admin@ultra-embedded.com
//
//                       License: LGPL
//-----------------------------------------------------------------
//
// Copyright (C) 2011 - 2013 Ultra-Embedded.com
//
// 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, write to the 
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
// Boston, MA  02111-1307  USA
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module - Data Cache (write back)
//-----------------------------------------------------------------
module altor32_dcache
( 
    input           clk_i /*verilator public*/,
    input           rst_i /*verilator public*/,
 
    input           flush_i /*verilator public*/,
 
    // Input (CPU)
    input [31:0]    address_i /*verilator public*/,
    output [31:0]   data_o /*verilator public*/,
    input [31:0]    data_i /*verilator public*/,
    input           we_i /*verilator public*/,
    input           stb_i /*verilator public*/,
    input [3:0]     sel_i /*verilator public*/,
    output          stall_o /*verilator public*/,
    output          ack_o /*verilator public*/,
 
    // Output (Memory)
    output [31:0]   mem_addr_o /*verilator public*/,
    input [31:0]    mem_data_i /*verilator public*/,
    output [31:0]   mem_data_o /*verilator public*/,
    output [2:0]    mem_cti_o /*verilator public*/,
    output          mem_cyc_o /*verilator public*/,
    output          mem_stb_o /*verilator public*/,
    output          mem_we_o /*verilator public*/,
    output [3:0]    mem_sel_o /*verilator public*/,
    input           mem_stall_i/*verilator public*/,
    input           mem_ack_i/*verilator public*/ 
);
 
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
parameter CACHE_LINE_SIZE_WIDTH     = 5; /* 5-bits -> 32 entries */
parameter CACHE_LINE_SIZE_BYTES     = 2 ** CACHE_LINE_SIZE_WIDTH; /* 32 bytes / 8 words per line */
parameter CACHE_LINE_ADDR_WIDTH     = 8; /* 256 lines */
parameter CACHE_LINE_WORDS_IDX_MAX  = CACHE_LINE_SIZE_WIDTH - 2; /* 3-bit = 8 words */
parameter CACHE_TAG_ENTRIES         = 2 ** CACHE_LINE_ADDR_WIDTH ; /* 256 tag entries */
parameter CACHE_DSIZE               = CACHE_LINE_ADDR_WIDTH * CACHE_LINE_SIZE_BYTES; /* 8KB data */
parameter CACHE_DWIDTH              = CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 2; /* 11-bits */
 
parameter CACHE_TAG_WIDTH           = 16; /* 16-bit tag entry size */
parameter CACHE_TAG_LINE_ADDR_WIDTH = CACHE_TAG_WIDTH - 2; /* 14 bits of data (tag entry size minus valid/dirty bit) */
 
parameter CACHE_TAG_ADDR_LOW        = CACHE_LINE_SIZE_WIDTH + CACHE_LINE_ADDR_WIDTH;
parameter CACHE_TAG_ADDR_HIGH       = CACHE_TAG_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH + CACHE_LINE_ADDR_WIDTH - 1;
 
// Tag fields
parameter CACHE_TAG_DIRTY_BIT       = 14;
parameter CACHE_TAG_VALID_BIT       = 15;
parameter ADDR_NO_CACHE_BIT         = 25;
parameter ADDR_CACHE_BYPASS_BIT     = 31;
 
parameter FLUSH_INITIAL             = 0;
 
//  31          16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
// |--------------|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
//  +--------------------+   +-------------------+   +-----------+      
//    Tag entry                     Line address         Address 
//       (15-bits)                    (8-bits)           within line 
//                                                       (5-bits)
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry;
wire [CACHE_TAG_WIDTH-1:0]       tag_data_out;
reg  [CACHE_TAG_WIDTH-1:0]       tag_data_in;
reg                              tag_wr;
 
wire [CACHE_DWIDTH-1:0]          cache_address;
wire [31:0]                      cache_data_r;
reg [31:0]                       cache_data_w;
reg [3:0]                        cache_wr;
 
wire [31:2]                      cache_update_addr;
wire [31:0]                      cache_update_data_w;
wire [31:0]                      cache_update_data_r;
wire                             cache_update_wr;
 
reg                              ack;
 
reg                              fill;
reg                              evict;
wire                             done;
 
wire [31:0]                      data_r;
reg                              rd_single;
reg [3:0]                        wr_single;
 
reg                              req_rd;
reg [3:0]                        req_wr;
reg                              req_ack;
reg [31:0]                       req_address;
reg [31:0]                       req_data;
 
reg                              req_flush;
reg                              req_init;
reg                              flush_single;
 
wire [31:0]                      line_address;
 
wire [31:0]                      muxed_address = (state == STATE_IDLE) ? address_i : req_address;
 
// Current state
parameter STATE_IDLE        = 0;
parameter STATE_SINGLE      = 1;
parameter STATE_CHECK       = 2;
parameter STATE_FETCH       = 3;
parameter STATE_WAIT        = 4;
parameter STATE_WAIT2       = 5;
parameter STATE_WRITE       = 6;
parameter STATE_SINGLE_READY= 7;
parameter STATE_EVICTING    = 8;
parameter STATE_UPDATE      = 9;
parameter STATE_FLUSH1      = 10;
parameter STATE_FLUSH2      = 11;
parameter STATE_FLUSH3      = 12;
parameter STATE_FLUSH4      = 13;
reg [3:0] state;
 
assign tag_entry               = muxed_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
assign cache_address           = {tag_entry, muxed_address[CACHE_LINE_SIZE_WIDTH-1:2]};
 
assign data_o                  = (state == STATE_SINGLE_READY) ? data_r : cache_data_r;
assign stall_o                 = (state != STATE_IDLE) | req_flush | flush_i;
 
wire valid                     = tag_data_out[CACHE_TAG_VALID_BIT];
wire dirty                     = tag_data_out[CACHE_TAG_DIRTY_BIT];
 
// Access is cacheable?
wire cacheable                 = ~muxed_address[ADDR_NO_CACHE_BIT] & ~muxed_address[ADDR_CACHE_BYPASS_BIT];
 
// Address matches cache tag
wire addr_hit                  = (req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] == tag_data_out[13:0]);
 
// Cache hit?
wire hit                       = cacheable & valid & addr_hit & (state == STATE_CHECK);
 
assign ack_o                   = ack | hit;
 
assign line_address[31:CACHE_TAG_ADDR_HIGH+1] = {(31-CACHE_TAG_ADDR_HIGH){1'b0}};
assign line_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] = tag_entry;
assign line_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] = tag_data_out[13:0];
assign line_address[CACHE_LINE_SIZE_WIDTH-1:0] = {CACHE_LINE_SIZE_WIDTH{1'b0}};
 
// Only allow cache write when same line present in the write state
wire cache_wr_enable           = (state == STATE_WRITE) ? valid & addr_hit : 1'b1;
 
//-----------------------------------------------------------------
// Next State Logic
//-----------------------------------------------------------------
reg [3:0] next_state_r;
always @ *
begin
    next_state_r = state;
 
    case (state)
    //-----------------------------------------
    // IDLE
    //-----------------------------------------
    STATE_IDLE :
    begin
        // Cache flush request
        if (flush_i | req_flush)
            next_state_r    = STATE_FLUSH2;
        // Read (uncacheable)
        else if (stb_i & ~we_i & ~cacheable)
            next_state_r    = STATE_SINGLE;
        // Read (cacheable)
        else if (stb_i & ~we_i)
            next_state_r    = STATE_CHECK;
        // Write (uncacheable)
        else if (stb_i & we_i & ~cacheable)
            next_state_r    = STATE_SINGLE;
        // Write (cacheable)
        else if (stb_i & we_i)
            next_state_r    = STATE_WRITE;
    end         
    //-----------------------------------------
    // WRITE
    //-----------------------------------------
    STATE_WRITE :
    begin            
        // Cache hit (line already dirty)
        if (valid & addr_hit & dirty)
            next_state_r    = STATE_IDLE;
        // Cache hit, make line dirty
        else if (valid & addr_hit & ~dirty)
            next_state_r    = STATE_WAIT2;            
        // Cache dirty
        else if (valid & dirty)
            next_state_r    = STATE_EVICTING;
        // Cache miss
        else
            next_state_r    = STATE_UPDATE;
    end
    //-----------------------------------------
    // EVICTING - Evicting cache line
    //-----------------------------------------
    STATE_EVICTING:
    begin
        // Data ready from memory?
        if (done)
        begin
            // Evict for read?
            if (req_rd)
                next_state_r   = STATE_FETCH;
            // Evict for write
            else
                next_state_r   = STATE_UPDATE;
        end
    end
    //-----------------------------------------
    // UPDATE - Update fetched cache line
    //-----------------------------------------
    STATE_UPDATE:
    begin
        // Data ready from memory?
        if (done)
            next_state_r    = STATE_WAIT2;
    end            
    //-----------------------------------------
    // CHECK - check cache for hit or miss
    //-----------------------------------------
    STATE_CHECK :
    begin         
        // Cache hit
        if (valid & addr_hit) 
            next_state_r    = STATE_IDLE;
        // Cache dirty
        else if (valid & dirty)
            next_state_r    = STATE_EVICTING;
        // Cache miss
        else
            next_state_r    = STATE_FETCH;
    end
    //-----------------------------------------
    // FETCH_SINGLE - Single access to memory
    //-----------------------------------------
    STATE_SINGLE:
    begin
        // Data ready from memory?
        if (done)
        begin
            // Single WRITE?
            if (~req_rd)
                next_state_r    = STATE_SINGLE_READY;
            // Dirty? Write back
            else if (valid & dirty & addr_hit)
                next_state_r    = STATE_FLUSH4;                           
            // Valid line, invalidate
            else if (valid & addr_hit)
                next_state_r    = STATE_SINGLE_READY;
            else
                next_state_r    = STATE_SINGLE_READY;
        end
    end            
    //-----------------------------------------
    // FETCH - Fetch row from memory
    //-----------------------------------------
    STATE_FETCH :
    begin
        // Cache line filled?
        if (done)
           next_state_r = STATE_WAIT;
    end
    //-----------------------------------------
    // WAIT - Wait cycle
    //-----------------------------------------
    STATE_WAIT :
    begin
        // Allow extra wait state to handle write & read collision               
        next_state_r    = STATE_WAIT2;
    end    
    //-----------------------------------------
    // WAIT2 - Wait cycle
    //-----------------------------------------
    STATE_WAIT2 :
    begin
        next_state_r    = STATE_IDLE;
    end            
    //-----------------------------------------
    // SINGLE_READY - Uncached access ready
    //-----------------------------------------
    STATE_SINGLE_READY :
    begin
        // Allow extra wait state to handle write & read collision               
        next_state_r    = STATE_IDLE;
    end
    //-----------------------------------------
    // FLUSHx - Flush dirty lines & invalidate
    //-----------------------------------------
    STATE_FLUSH1 :
    begin
        if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}})
            next_state_r    = STATE_WAIT;
        else
            next_state_r    = STATE_FLUSH2;
    end
    //-----------------------------------------
    // FLUSH2 - Wait state
    //-----------------------------------------
    STATE_FLUSH2 :
    begin
        // Allow a cycle to read line state
        next_state_r    = STATE_FLUSH3;
    end
    //-----------------------------------------
    // FLUSH3 - Check if line dirty & flush
    //-----------------------------------------            
    STATE_FLUSH3 :
    begin
        // Dirty line? Evict line first
        if (dirty && ~req_init)
            next_state_r    = STATE_FLUSH4;                
        // Not dirty? Just invalidate
        else
        begin
            if (flush_single)
                next_state_r    = STATE_WAIT;
            else
                next_state_r    = STATE_FLUSH1;
        end
    end
    //-----------------------------------------
    // FLUSH4 - Wait for line flush to complete
    //-----------------------------------------            
    STATE_FLUSH4 :
    begin
        // Cache line filled?
        if (done)
        begin
            if (flush_single)
                next_state_r    = STATE_SINGLE_READY;
            else                    
                next_state_r    = STATE_FLUSH1;
        end
    end      
 
    default:
        ;
   endcase
end
 
// Update state
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
        state   <= STATE_IDLE;
   else
        state   <= next_state_r;
end
 
//-----------------------------------------------------------------
// Tag Write
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
   begin
        tag_data_in     <= 16'b0;
        tag_wr          <= 1'b0;
   end
   else
   begin
        tag_wr          <= 1'b0;
 
        case (state)
        //-----------------------------------------
        // WRITE
        //-----------------------------------------
        STATE_WRITE :
        begin            
            // Cache hit
            if (valid & addr_hit) 
            begin
                // Mark line as dirty
                if (~dirty)
                begin
                    tag_data_in  <= tag_data_out;
                    tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1;
                    tag_wr       <= 1'b1;
                end
            end            
            // Cache miss / cache line doesn't require write back
            else if (~valid | ~dirty)
            begin
                // Update tag memory with this line's details   
                tag_data_in <= {1'b1, 1'b1, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
                tag_wr      <= 1'b1;
            end
        end
        //-----------------------------------------
        // EVICTING - Evicting cache line
        //-----------------------------------------
        STATE_EVICTING:
        begin
            // Data ready from memory?
            if (done)
            begin
                // Update tag memory with this new line's details   
                tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
                tag_wr      <= 1'b1;
            end
        end
        //-----------------------------------------
        // UPDATE - Update fetched cache line
        //-----------------------------------------
        STATE_UPDATE:
        begin
            // Data ready from memory?
            if (done)
            begin
                // Mark line as dirty
                tag_data_in  <= tag_data_out;
                tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b1;
                tag_wr       <= 1'b1;  
            end
        end            
        //-----------------------------------------
        // CHECK - check cache for hit or miss
        //-----------------------------------------
        STATE_CHECK :
        begin         
            // Cache hit
            if (valid & addr_hit)
            begin
 
            end                 
            // Cache miss / cache line doesn't require write back
            else if (~valid | ~dirty)
            begin
                // Update tag memory with this line's details   
                tag_data_in <= {1'b1, 1'b0, req_address[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
                tag_wr      <= 1'b1;
            end
        end
        //-----------------------------------------
        // FETCH_SINGLE - Single access to memory
        //-----------------------------------------
        STATE_SINGLE:
        begin
            // Data ready from memory?
            if (done)
            begin
                // Single WRITE?
                if (~req_rd)
                begin
                    // Invalidate cached version
                    if (valid & addr_hit)
                    begin
                        tag_data_in  <= tag_data_out;
                        tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
                        tag_wr       <= 1'b1;
                    end         
                end                
                // Valid line (not dirty), just invalidate
                else if (valid & ~dirty & addr_hit)
                begin
                    tag_data_in  <= tag_data_out;
                    tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
                    tag_wr       <= 1'b1;                  
                end
            end
        end            
 
        //-----------------------------------------
        // FLUSH3 - Check if line dirty & flush
        //-----------------------------------------            
        STATE_FLUSH3 :
        begin
            // Not dirty? Just invalidate
            if (~dirty | req_init)
            begin
                tag_data_in  <= 16'b0;
                tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
                tag_wr       <= 1'b1;
            end
        end
        //-----------------------------------------
        // FLUSH4 - Wait for line flush to complete
        //-----------------------------------------            
        STATE_FLUSH4 :
        begin
            // Cache line filled?
            if (done)
            begin
                // Invalidate line
                tag_data_in  <= 16'b0;
                tag_data_in[CACHE_TAG_VALID_BIT] <= 1'b0;
                tag_data_in[CACHE_TAG_DIRTY_BIT] <= 1'b0;
                tag_wr       <= 1'b1;
            end
        end          
        default:
            ;
       endcase
   end
end
 
//-----------------------------------------------------------------
// Register requests
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
   begin
        req_address     <= 32'h00000000;
        req_data        <= 32'h00000000;
        req_ack         <= 1'b0;
        req_wr          <= 4'h0;
        req_rd          <= 1'b0;
        req_flush       <= 1'b1;
        req_init        <= FLUSH_INITIAL;
   end
   else
   begin
        if (flush_i)
            req_flush       <= 1'b1;
 
        case (state)
        //-----------------------------------------
        // IDLE
        //-----------------------------------------
        STATE_IDLE :
        begin
            // Cache flush request
            if (flush_i | req_flush)
            begin
                // Set to first line address
                req_address <= 32'h00000000;
                req_flush   <= 1'b0;
                req_ack     <= 1'b0;
            end            
            // Read (uncacheable)
            else if (stb_i & ~we_i & ~cacheable)
            begin
                // Start read single from memory
                req_address <= address_i;
                req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0;
                req_rd      <= 1'b1;
                req_wr      <= 4'b0;
                req_ack     <= 1'b1;
            end
            // Read (cacheable)
            else if (stb_i & ~we_i)
            begin
                req_address <= address_i;
                req_rd      <= 1'b1;
                req_wr      <= 4'b0;
                req_ack     <= 1'b1;
            end                
            // Write (uncacheable)
            else if (stb_i & we_i & ~cacheable)
            begin
                // Perform write single
                req_address <= address_i;
                req_address[ADDR_CACHE_BYPASS_BIT] <= 1'b0;
                req_data    <= data_i;
                req_wr      <= sel_i;
                req_rd      <= 1'b0;                    
                req_ack     <= 1'b1;     
            end
            // Write (cacheable)
            else if (stb_i & we_i)
            begin
                req_address <= address_i;
                req_data    <= data_i;
                req_wr      <= sel_i;
                req_rd      <= 1'b0;
                req_ack     <= 1'b0;
            end              
        end
        //-----------------------------------------
        // FLUSHx - Flush dirty lines & invalidate
        //-----------------------------------------
        STATE_FLUSH1 :
        begin
            if (req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] == {CACHE_LINE_ADDR_WIDTH{1'b1}})
            begin
                req_ack <= 1'b0;
                req_init <= 1'b0;
            end
            else
            begin
                // Increment flush line address
                req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] <=
                req_address[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] + 1;
            end
        end      
        default:
            ;
       endcase
   end
end
 
//-----------------------------------------------------------------
// Cache Data Write
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
   begin
        cache_data_w    <= 32'h00000000;
        cache_wr        <= 4'b0;
   end
   else
   begin
        cache_wr        <= 4'b0;
 
        case (state)
        //-----------------------------------------
        // IDLE
        //-----------------------------------------
        STATE_IDLE:
        begin
            // Write (cacheable)
            if (stb_i & we_i & cacheable & ~(flush_i | req_flush))
            begin
                // Early write which is gated on line match
                cache_data_w <= data_i;
                cache_wr     <= sel_i;
            end    
        end
        //-----------------------------------------
        // UPDATE - Update fetched cache line
        //-----------------------------------------
        STATE_UPDATE:
        begin
            // Data ready from memory?
            if (done)
            begin
                // Update line already in cache
                cache_data_w <= req_data;
                cache_wr     <= req_wr;
            end
        end            
        default:
            ;
       endcase
   end
end
 
//-----------------------------------------------------------------
// Control
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
   begin
        wr_single       <= 4'h0;
        rd_single       <= 1'b0;
        flush_single    <= 1'b0;
        fill            <= 1'b0;
        evict           <= 1'b0;
   end
   else
   begin
        fill            <= 1'b0;
        evict           <= 1'b0;
        wr_single       <= 4'b0;
        rd_single       <= 1'b0;
 
        case (state)
 
            //-----------------------------------------
            // IDLE
            //-----------------------------------------
            STATE_IDLE :
            begin
                // Cache flush request
                if (flush_i | req_flush)
                begin
                    // Set to first line address
                    flush_single<= 1'b0;
                end            
                // Read (uncacheable)
                else if (stb_i & ~we_i & ~cacheable)
                begin
                    // Start read single from memory
                    rd_single     <= 1'b1;
                end             
                // Write (uncacheable)
                else if (stb_i & we_i & ~cacheable)
                begin
                    // Perform write single
                    wr_single     <= sel_i;
                end         
            end         
            //-----------------------------------------
            // WRITE
            //-----------------------------------------
            STATE_WRITE :
            begin            
                // Cache hit
                if (valid & addr_hit)
                begin
 
                end
                // Cache dirty
                else if (valid & dirty)
                begin
                    // Evict cache line
                    evict       <= 1'b1;
                end                
                // Cache miss
                else
                begin
                    // Fill cache line
                    fill        <= 1'b1;
                end
            end
            //-----------------------------------------
            // EVICTING - Evicting cache line
            //-----------------------------------------
            STATE_EVICTING:
            begin
                // Data ready from memory?
                if (done)
                begin
                    // Fill cache line
                    fill        <= 1'b1;
                end
            end        
            //-----------------------------------------
            // CHECK - check cache for hit or miss
            //-----------------------------------------
            STATE_CHECK :
            begin         
                // Cache hit
                if (valid & addr_hit)
                begin
 
                end
                // Cache dirty
                else if (valid & dirty)
                begin
                    // Evict cache line
                    evict       <= 1'b1;
                end                     
                // Cache miss
                else
                begin
                    // Fill cache line
                    fill        <= 1'b1;
                end
            end
            //-----------------------------------------
            // FETCH_SINGLE - Single access to memory
            //-----------------------------------------
            STATE_SINGLE:
            begin
                // Data ready from memory?
                if (done)
                begin
                    // Single WRITE?
                    if (~req_rd)
                    begin
 
                    end                
                    // Dirty? Write back
                    else if (valid & dirty & addr_hit)
                    begin
                        // Evict cache line
                        evict       <= 1'b1;
                        flush_single<= 1'b1;
                    end
                end
            end           
            //-----------------------------------------
            // FLUSH3 - Check if line dirty & flush
            //-----------------------------------------            
            STATE_FLUSH3 :
            begin
                // Dirty line? Evict line first
                if (dirty)
                begin
                    // Evict cache line
                    evict       <= 1'b1;
                end
            end      
            default:
                ;
           endcase
   end
end
 
//-----------------------------------------------------------------
// ACK
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
   if (rst_i == 1'b1)
        ack     <= 1'b0;
   else
   begin
        ack     <= 1'b0;
 
        case (state)
 
        //-----------------------------------------
        // IDLE
        //-----------------------------------------
        STATE_IDLE :
        begin
            // Write (cacheable), early acknowledge
            if (~(flush_i | req_flush) & stb_i & we_i & cacheable)
                ack <= 1'b1;
        end         
        //-----------------------------------------
        // FETCH_SINGLE - Single access to memory
        //-----------------------------------------
        STATE_SINGLE:
        begin
            // Data ready from memory?
            if (done)
            begin
                // Single WRITE?
                if (~req_rd)
                    ack         <= req_ack;                    
                // Dirty? Write back
                else if (valid & dirty & addr_hit)
                begin
 
                end
                // Valid line, invalidate
                else if (valid & addr_hit)
                    ack         <= req_ack;                        
                else
                    ack         <= req_ack;                    
            end
        end
        //-----------------------------------------
        // WAIT2 - Wait cycle
        //-----------------------------------------
        STATE_WAIT2 :
        begin
            ack     <= req_ack;
        end            
        //-----------------------------------------
        // FLUSH4 - Wait for line flush to complete
        //-----------------------------------------            
        STATE_FLUSH4 :
        begin
            if (done & flush_single)
                ack     <= req_ack;
        end          
        default:
            ;
       endcase
   end
end
 
//-----------------------------------------------------------------
// Instantiation
//-----------------------------------------------------------------
 
altor32_dcache_mem_if
#(
    .CACHE_LINE_SIZE_WIDTH(CACHE_LINE_SIZE_WIDTH),
    .CACHE_LINE_WORDS_IDX_MAX(CACHE_LINE_WORDS_IDX_MAX)
)
u_mem_if
( 
    .clk_i(clk_i),
    .rst_i(rst_i),
 
    // Cache interface
    .address_i(muxed_address),
    .data_i(req_data),
    .data_o(data_r),
    .fill_i(fill),
    .evict_i(evict),
    .evict_addr_i(line_address),
    .rd_single_i(rd_single),
    .wr_single_i(wr_single),
    .done_o(done),
 
    // Cache memory (fill/evict)
    .cache_addr_o(cache_update_addr),
    .cache_data_o(cache_update_data_w),
    .cache_data_i(cache_update_data_r),
    .cache_wr_o(cache_update_wr),    
 
    // Memory interface (slave)
    .mem_addr_o(mem_addr_o),
    .mem_data_i(mem_data_i),
    .mem_data_o(mem_data_o),
    .mem_cti_o(mem_cti_o),
    .mem_cyc_o(mem_cyc_o),
    .mem_stb_o(mem_stb_o),
    .mem_we_o(mem_we_o),
    .mem_sel_o(mem_sel_o),
    .mem_stall_i(mem_stall_i),
    .mem_ack_i(mem_ack_i)
);
 
// Tag memory    
altor32_ram_sp  
#(
    .WIDTH(CACHE_TAG_WIDTH),
    .SIZE(CACHE_LINE_ADDR_WIDTH)
) 
u1_tag_mem
(
    .clk_i(clk_i), 
    .dat_o(tag_data_out), 
    .dat_i(tag_data_in), 
    .adr_i(tag_entry), 
    .wr_i(tag_wr)
);
 
// Data memory   
altor32_ram_dp  
#(
    .WIDTH(8),
    .SIZE(CACHE_DWIDTH)
) 
u2_data_mem0
(
    .aclk_i(clk_i), 
    .aadr_i(cache_address), 
    .adat_o(cache_data_r[7:0]), 
    .adat_i(cache_data_w[7:0]),     
    .awr_i(cache_wr[0] & cache_wr_enable),
 
    .bclk_i(clk_i), 
    .badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]), 
    .bdat_o(cache_update_data_r[7:0]), 
    .bdat_i(cache_update_data_w[7:0]),     
    .bwr_i(cache_update_wr)
);
 
altor32_ram_dp  
#(
    .WIDTH(8),
    .SIZE(CACHE_DWIDTH)
) 
u2_data_mem1
(
    .aclk_i(clk_i), 
    .aadr_i(cache_address), 
    .adat_o(cache_data_r[15:8]), 
    .adat_i(cache_data_w[15:8]),     
    .awr_i(cache_wr[1] & cache_wr_enable),
 
    .bclk_i(clk_i), 
    .badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]), 
    .bdat_o(cache_update_data_r[15:8]), 
    .bdat_i(cache_update_data_w[15:8]),     
    .bwr_i(cache_update_wr)   
);
 
altor32_ram_dp  
#(
    .WIDTH(8),
    .SIZE(CACHE_DWIDTH)
) 
u2_data_mem2
(
    .aclk_i(clk_i), 
    .aadr_i(cache_address), 
    .adat_o(cache_data_r[23:16]), 
    .adat_i(cache_data_w[23:16]),     
    .awr_i(cache_wr[2] & cache_wr_enable),
 
    .bclk_i(clk_i), 
    .badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]), 
    .bdat_o(cache_update_data_r[23:16]), 
    .bdat_i(cache_update_data_w[23:16]),     
    .bwr_i(cache_update_wr)       
);
 
altor32_ram_dp  
#(
    .WIDTH(8),
    .SIZE(CACHE_DWIDTH)
) 
u2_data_mem3
(
    .aclk_i(clk_i), 
    .aadr_i(cache_address), 
    .adat_o(cache_data_r[31:24]), 
    .adat_i(cache_data_w[31:24]),     
    .awr_i(cache_wr[3] & cache_wr_enable),
 
    .bclk_i(clk_i), 
    .badr_i(cache_update_addr[CACHE_DWIDTH+2-1:2]), 
    .bdat_o(cache_update_data_r[31:24]), 
    .bdat_i(cache_update_data_w[31:24]),     
    .bwr_i(cache_update_wr)       
);
 
endmodule
 

Go to most recent revision | 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.