HierarchyFilesModulesSignalsTasksFunctionsHelp
12

/******************************************************************************/ 
/*                                                                            */ 
/* Copyright (c) 1999 Sun Microsystems, Inc. All rights reserved.             */ 
/*                                                                            */ 
/* The contents of this file are subject to the current version of the Sun    */ 
/* Community Source License, microSPARCII ("the License"). You may not use    */ 
/* this file except in compliance with the License.  You may obtain a copy    */ 
/* of the License by searching for "Sun Community Source License" on the      */ 
/* World Wide Web at http://www.sun.com. See the License for the rights,      */ 
/* obligations, and limitations governing use of the contents of this file.   */ 
/*                                                                            */ 
/* Sun Microsystems, Inc. has intellectual property rights relating to the    */ 
/* technology embodied in these files. In particular, and without limitation, */ 
/* these intellectual property rights may include one or more U.S. patents,   */ 
/* foreign patents, or pending applications.                                  */ 
/*                                                                            */ 
/* Sun, Sun Microsystems, the Sun logo, all Sun-based trademarks and logos,   */ 
/* Solaris, Java and all Java-based trademarks and logos are trademarks or    */ 
/* registered trademarks of Sun Microsystems, Inc. in the United States and   */ 
/* other countries. microSPARC is a trademark or registered trademark of      */ 
/* SPARC International, Inc. All SPARC trademarks are used under license and  */ 
/* are trademarks or registered trademarks of SPARC International, Inc. in    */ 
/* the United States and other countries. Products bearing SPARC trademarks   */ 
/* are based upon an architecture developed by Sun Microsystems, Inc.         */ 
/*                                                                            */ 
/******************************************************************************/ 
// @(#)rl_dc_cntl.v	1.270 5/10/93
/******************************************************************************
//      Description:
//       This is the control block for dcache. This module contains
//      the dcache control state machine, store buffers,
//      logic for Dcache ASI read/writes, and the herbulator.
//
******************************************************************************/

[Up: rl_cc dc_cntl]
module rl_dc_cntl (
	little_endian,	// added to indicate current little endian it = 1
	ic_miss,
	ld_op_d,
	st_op_d,
	dp_perr,
	fp_dout_e,
    	iu_store_data,
    	select_IU_DOUT,
    	select_FP_DOUT,
    	sel_ldstb_1,
	dcc_miss_idle,
	dcc_nc_bypass,
	dt_cntx_in,
	cxr,
   	i_dva_req,
	sgnd_ld_e,
	standby_req,
	dc_standby_w,
	mm_dct_daten,
	dva_w_2,
	dt_val_w,
	dc_hld,
	invalid_wb_entry,
	dt_dout_w,
	flush_op_e,
	nforce_dva_f,   // G stage sel_dva signal
	flush_ic_e,
	dt_acc_in,
	dt_acc_out,
	dt_din,
	dwait_w,
	dwait_w_for_flush,
  	dc_dva_e,
        iu_dva_e,
    	iu_asi_e,
       	mm_dcdaten_in,  
       	mm_wbstb,  
       	mm_wbsel1,  
       	mm_dcache_enbl,  
       	mm_dstat_avail,  
       	enbl_dtag_match_w,  
       	dc_miss_or_part,  
       	dc_miss_and_part,  
       	dc_miss_sustain,  
	wb0_hold_lo,
       	wb1_hold_lo,
       	wb2_hold_lo, 
       	wb3_hold_lo, 
       	wb_1_sel,
       	wb_2_sel, 
       	wb_3_sel,
	wb_valid,
        it_index3_w,
        it_index2_w,
        it_index1_w,
        it_flush_w,
        it_flush_user_w,
        it_flush_user_cntx_w,
	dt_flush_w_l,
	dt_index3_w,
	dt_index2_w,
  	dt_index1_w,
    	dt_flush_user_w,
    	dt_flush_user_cntx_w,
	dt_cntx_out,
	dc_power_down,
	dt_at,
	dt_be,
	dt_be_vb,
        iu_bytemarks,           
        fast_hld_terms,                
        fast_iu_held_l,                
        iu_held,                
        iu_held_for_dc_be,                
        iu_held_l,                
        iu_in_trap,             
        mm_dabort,              
        mm_dcstben,             
        dc_shold,               
        wrtbuf,                
        dc_tagasi_bus,                
        misc_in,            
        cached,            
        dc_wle,                  
        dc_be,                  
        dc_dtv_din,             
	size_e,
	ld_op_e,
	st_op_e,
	dt_hit_w,
	dc_do,
	ld_iu,
	ld_fpu,
	fpu_mem_e,
	cache_fill,
	dc_di,
        ic_asi_load_cache_w,
        ic_asi_store_tag_e,
        ic_asi_store_cache_e,
	ss_scan_in,
	ss_scan_out,
	ss_scan_mode,
	ss_reset,
	ss_clock
	) ;
//	wire little_endian = 1'b1;          
	input little_endian; // add this bit to support little endian if = 1
	input [1:0] dp_perr;
    	input [31:0] iu_store_data;
    	input select_IU_DOUT;
    	input select_FP_DOUT;
	input [63:0] fp_dout_e;
    	input sel_ldstb_1;
	input [7:0] cxr;
	output [7:0] dt_cntx_in;
  	output i_dva_req;
      	input sgnd_ld_e;
      	input standby_req;
      	output dc_standby_w;
      	input mm_dct_daten;
      	input dt_val_w;
      	input nforce_dva_f;
      	input flush_op_e;
  	output flush_ic_e; 
  	output [31:`log2_dcachesize] dt_din;
  	output dwait_w;
  	output dwait_w_for_flush;
  	output [`dc_msb:3] dc_dva_e;
	input [63:0] cache_fill ;
	input [63:0] dc_do ;
	input fpu_mem_e ;
	input [1:0] size_e ;
	output [1:0] dc_hld ;
        input [3:0] iu_bytemarks ;
        input fast_hld_terms;                 
        input fast_iu_held_l;                 
        input iu_held;                 
        input iu_held_for_dc_be;                 
        input iu_held_l;                 
        input iu_in_trap ;
        input mm_dcstben ;
        input [3:1] misc_in ;
        input cached ;
        output [4:0] dt_acc_in ;
        input [4:0] dt_acc_out ;
        output [31:0] wrtbuf ;
        output [31:0] dc_tagasi_bus ;
        output dc_shold ;
        output dc_dtv_din ;
        input [7:0] dt_cntx_out;
        output [63:0] dc_di ;
        output [31:0] ld_iu ;
        output [63:0] ld_fpu ;
        output dt_be ;
        output dt_be_vb ;
	input [5:0] iu_asi_e ;
        input mm_dcdaten_in ;  // Strobe the writebuffer -> misc
        input mm_wbstb ;       // Strobe the writebuffer -> misc
        input mm_wbsel1 ;      // Strobe the writebuffer -> misc
        input mm_dabort ;      // MMU says, abort the last request
        input mm_dcache_enbl ; // MMU disable's dtag lookup in bootm/cache off
        input mm_dstat_avail ; // MMU says, Tag replacement here  
        output enbl_dtag_match_w ; // IU should look at dt_hit_w 
        output dc_miss_or_part ;       // output to MMU signalling miss request 
        output dc_miss_and_part ;      // output to MMU signalling miss request 
        output dc_miss_sustain ;       // output to MMU signalling miss request 
	// Controls for the address part of the WB
	output [1:0] wb_valid ;
    	output wb0_hold_lo ;
    	output wb1_hold_lo ;
    	output wb2_hold_lo ;
    	output wb3_hold_lo ;
    	output wb_1_sel ;
    	output wb_2_sel ;
    	output wb_3_sel ;
        // IU Store data (W-stage of HSt)
	output dc_power_down ;
	output [4:0] dt_at ;
        input [31:0] iu_dva_e;
    	wire  [31:0] iu_dva_w ;
	wire wb_empty ;
        wire dc_miss ;   
        input ic_miss ;
        input ld_op_e ;
        input st_op_e ; 
        input ld_op_d ;
        input st_op_d ; 
	input [`dt_msb:0] dt_dout_w;
        output it_index3_w ;
        output it_index2_w ;
        output it_index1_w ;
        output it_flush_w ;
        output it_flush_user_w ;
        output it_flush_user_cntx_w ;
    	output dt_index3_w ;
    	output dt_index2_w ;
    	output dt_index1_w ;
   	output dt_flush_w_l ;
    	output dt_flush_user_w ;
    	output dt_flush_user_cntx_w ;
        output [7:0] dc_be ;
        output dc_wle ;
	output ic_asi_load_cache_w;
	output ic_asi_store_tag_e;
	output ic_asi_store_cache_e;
    	output invalid_wb_entry ;
    	output dva_w_2 ;
        output ss_scan_out;
        output dcc_miss_idle;
        output dcc_nc_bypass;
        input ss_scan_in;
        input ss_scan_mode;
        input ss_clock ;
        input ss_reset ;
        input dt_hit_w ;

	wire ic_asi_load_tag_w;
    	wire ic_asi_store_tag_w;
    	wire ic_asi_store_cache_w;
    	wire dc_asi_store_tag_w;
 	wire asi_flush_e ;
    	wire dc_flush_op_w ;
        wire dc_flush_hold ;
    	wire wb_full ; 		   
    	wire atomic_op_e;
    	wire atomic_op_w;

//  State decodes declared
    	wire [11:0] dcc_state;
	wire dcc_st_miss ;
    	wire dcc_idle ;
    	wire dcc_ld_stat ;
    	wire dcc_st_stat ;
    	wire dcc_ld_stat_wait ;
    	wire dcc_st_stat_wait ;
    	wire dcc_stat_wait ;
    	wire dcc_stat ;
    	wire dcc_fill_wait ;
    	wire dcc_fill_write_f ;
    	wire dcc_dead_cyc ;
    	wire dcc_dead_cyc_1 ;
    	wire dcc_dead_cyc_2 ;
    	wire dcc_dead_cyc_3 ;
    	wire dcc_fill_write_l ;
    	wire dcc_ld_nc_wait ;
    	wire dcc_ld_nc_bypass ;
    	wire dcc_st_nc_bypass ;
    	wire dcc_nc_wait ;
    	wire dcc_nc_bypass ;
    	wire dcc_nc_retry ;
    	wire dcc_ld_nc_retry ;
	wire parity_error;
    	wire parity_error_d1;
//
    	wire flush1_out;
    	wire flush2_out;
    	wire flush123_out;
    	wire ic_flush_op_w;
    	wire [12:3] dmar ;
    	wire fill_dw ;
    	wire dt_be;
    	wire dt_be_vb ;
    	wire [5:0] iu_asi_w;
	wire [63:0] iu_dout; // Comes from the Store aligner
	wire [63:0] wb_dout; // Comes from the Store aligner
    	wire possible_bad_mem_op_dt_hit_w;
    	wire possible_bad_mem_op_w;
    	wire parity_error_in_fill; 

/*****************************************************************************/
//  Power management
//  Power down only if the sm is in :
//  dcc_idle & no flush instruction in progress  
//  or dcc_ld_nc_bypass (because of a potential deadlock condition, see below).

//  Deadlock condition, 
//  I$ can go -> standby before D$ and hence the D$ statemachine will
//  be stuck in dcc_ld_nc_bypass mode, and never assert dc_standby_w.

//  Three different signals available for powerdown:
//  1. standby_req
//  2. standby
//  3. dc_standby_w

//  Might need the dc_flush_hold term with dcc_idle.

    wire standby = 
     	standby_req & (~iu_in_trap | dc_standby_w) & wb_empty &
	   	( (dcc_idle & ~(dc_flush_op_w |dc_flush_hold) & ~dc_miss )
		| dcc_nc_retry 
		| (dcc_nc_bypass & dc_standby_w)
		);

//  Send an ack to the clock controller saying in powerdown mode now !

    Mflipflop_r standby_ff(dc_standby_w, standby, ~ss_reset, ss_clock) ;

//  Powerdown of the DT & D$
//  The only difference is dcc_ld_stat & dcc_st_stat in which
//  only the D$ RAMs can go into powerdown.

//  Remember the RAMs can go into powerdown on a cycle to cycle basis.

//## Fix Hold violation of @ 1.14ns for dc_power_down with 6 BUF's.
    wire dc_power_down_int1, dc_power_down_int2, dc_power_down_int;
    wire dc_power_down_int3, dc_power_down_int4, dc_power_down_int5;

    JBUFDA dc_power_down_gate1 (.O(dc_power_down_int1), 
     .A(standby_req & dcc_idle & ~(dc_flush_op_w | dc_flush_hold) & dc_standby_w));
    JBUFDA dc_power_down_gate2 (.O(dc_power_down_int2), .A(dc_power_down_int1));
    JBUFE dc_power_down_gate3 (.O(dc_power_down_int), .A(dc_power_down_int2));

    JBUFDA dc_power_down_gate4 (.O(dc_power_down_int3), 
					.A(dcc_fill_wait));
    JBUFDA dc_power_down_gate5 (.O(dc_power_down_int4), .A(dc_power_down_int3));
    JBUFE dc_power_down_gate6 (.O(dc_power_down_int5), .A(dc_power_down_int4));

//  Older logic, without hold fixes is below:
    assign dc_power_down = dc_power_down_int | (dc_power_down_int5 & ~mm_dcstben);

//    assign dc_power_down = 	  
//     ((standby_req & dcc_idle & ~(dc_flush_op_w | dc_flush_hold)) & dc_standby_w)
//			| ((dcc_ld_nc_wait | dcc_fill_wait) & ~mm_dcstben) 
//			   ;

/*****************************************************************************/
//  Register trap signal, and use it ONLY in the R stage.
//  NOTE:  the above, despite its emphatic tone, is a lie; iu_in_trap goes to
//         many places in dc_cntl besides this flipflop.
    wire iu_in_trap_d1;

    Mflipflop_r iu_in_trap_sr_ff (iu_in_trap_d1, iu_in_trap, ~ss_reset, ss_clock) ;
 
// ASI's 0x8, 0x9, 0xA, 0xB
    wire normal_asi_e = (iu_asi_e == 6'h08)
			| (iu_asi_e == 6'h09)
			| (iu_asi_e == 6'h0a)
			| (iu_asi_e == 6'h0b);

    wire normal_asi_w;
    MflipflopR normal_asi_w_ff (normal_asi_w, normal_asi_e, ss_clock, iu_held, ss_reset) ;


    // These ASIs never cause a dc_miss
    wire nomiss_asi_e = 
	  (iu_asi_e == 6'h0f)
	| (iu_asi_e == 6'h10)
	| (iu_asi_e == 6'h11)
	| (iu_asi_e == 6'h12) 
	| (iu_asi_e == 6'h13) 
	| (iu_asi_e == 6'h14)
	;

    MflipflopR nomiss_ff (nomiss_asi_w, nomiss_asi_e, ss_clock, iu_held, ss_reset) ;

//  Raw ld_op_e signal from IU

    wire ld_op_w ;
    MflipflopR ld_op_w_ff(ld_op_w, ld_op_e, ss_clock, iu_held, ss_reset) ;

//  Register D stage load decode for fast hold generation.
//  Only difference is that traps do not annul this signal
//  (see check below).
    wire ld_op_e_for_hold ;
    MflipflopR ld_op_e_for_hold_ff(ld_op_e_for_hold, ld_op_d, ss_clock, iu_held, ss_reset);

//  Raw st_op_e signal from IU

    wire st_op_w ;
    MflipflopR st_op_w_ff(st_op_w, st_op_e, ss_clock, iu_held, ss_reset) ;

//  Register D stage store decode for fast hold generation.
//  Only difference is that traps do not annul this signal.
//  (see check below).
    wire st_op_e_for_hold ;
    MflipflopR st_op_e_for_hold_ff(st_op_e_for_hold, st_op_d, ss_clock, iu_held, ss_reset);

// This F/F disables the D$sm from starting a new store miss routine in
// non-cached mode for ldst's

    wire atomic_op_r;
    MflipflopR atomic_op_r_ff(atomic_op_r, atomic_op_w, ss_clock, iu_held, ss_reset) ;

// This is a duplicate of the st_op_e, for mmu_asi accesses only.
// Might need to provide the mmu with an atomic ld miss signal from here ..
// 6'h0f is the cache data store ASI.
// Atomic ldst are seen as a ld followed by a st


//  st's have to be done in the R cycle of a ldst/swap

    wire dcache_write_asi_e =
	(normal_asi_e & mm_dcache_enbl) | (iu_asi_e == 6'h0f);
    wire dcache_write_asi_w =
	(normal_asi_w & mm_dcache_enbl) | (iu_asi_w == 6'h0f);
    wire stdi_w ; // (forward)
    wire nonatomic_st_e = st_op_e & ~ld_op_e;
    wire write_dcache_e = 
	(nonatomic_st_e & dcache_write_asi_e)
	| (stdi_w & dcache_write_asi_w)
	| (atomic_op_w & dcache_write_asi_w)
	;

    // Same as write_dcache_e, but without looking at ASIs.  Use this to speed
    //     up dwait a little.
    // Use fast _e stage decodes for fast hold generation.
    wire potential_write_dcache_e = 	 
		(st_op_e_for_hold & ~ld_op_e_for_hold) | stdi_w | atomic_op_w ;

    wire dt_flush_w_l ;
    MflipflopR dflush_w_ff(dt_flush_w_l,~asi_flush_e, ss_clock, iu_held, ss_reset) ;

//  Release hold of WB for 1 cycle to write the data into the WB during iu_held.
//  This prevents a deadlock on missing ldst's and imiss happening in parallel.
//  See bug #52
    wire atomic_wb_strobed ;
    wire atomic_dstat_avail =
	(atomic_op_w & ~nomiss_asi_w
	    & dcc_stat_wait & mm_dstat_avail & ~atomic_wb_strobed) ;

//  Store buffer gets further modified st_op_e. 
//  Don't write the writebuffer on sta (flushes) also.
//  I$ store ASI's (to TAG & DATA) are both sent to the WB
//  Final strobe to WB.
    wire st_op_wb_e;

//  Just in case we want to add new registers.
//wire st_op_wb_e= st_op_stbuf_e & ~(iu_asi_e==6'h39);

//  Special f/f to de-assert st_op_wb_e during the W->r cycle of a missing ldst
//      which was held throughout its miss sequence.  atomic_wb_strobed is
//      active IFF atomic_dstat_avail has been asserted for the instruction
//      which is now in W.
    wire atomic_wb_strobed_a1 =
	(atomic_dstat_avail | atomic_wb_strobed) & iu_held ;
    Mflipflop_r atomic_wb_ff(atomic_wb_strobed, atomic_wb_strobed_a1, ~ss_reset, ss_clock) ;

//  Stores with traps, iu_in_trap asserted in the 'w' stage
//  Use a free running register 
//  Case 1. Cancel last entry in WB with "cancel_last" pulse if > 1 entry.
//  Case 2. Cancel last entry and also signal MMU if == 1 entry in WB. 
//
// Note: when iu_in_trap is asserted, it is the responsibility of dc_cntl, not
//       IU, to cancel any stores in E or in W.  IU will cancel the D (by
//       de-asserting *_op_e when it gets to E).  We cancel everthing else by:
//
//           1) invalidating the DTag if we've written the DCache in error.
//
//           2) invalidating the corresponding writebuffer entry.
//
//       Note that we do not attempt to prevent the DCache write or the
//       creation of the writebuffer entry, since timing doesn't allow
//       that in all cases.
//
// Note: The MMU will trap any atomic op to any ASI other than {8,9,a,b,20},
// Note: ASI 20 is always noncached.
// Note: as implemented now, iu_in_trap does not cancel a flush in E or W.

    // On a store or atomic which writes the DCache, check in the W-cycle
    //     to see if it trapped; if so, go back and invalidate the DTag
    //     while holding the store/atomic in the R cycle.  To avoid conflicts
    //     for the DCache address bus with a subsequent store write in E
    //     (e.g. HStDI or LdSt, which would not have been cancelled in the IU
    //     by the trap) while we're in R, hold in R until the
    //     cycle after the write is done.  To avoid conflicts with fill
    //     writes and subsequent DCache/Tag StAs, hold in R, and delay the
    //     invalidation of the DTag, while dcc_state is not idle.
    //
    //         St:               D  E  W  R  R  R  R  R  R
    //         iu_in_trap:             == == == == == == ==
    //         bad_st_w:               ==
    //         dcc_idle:                           == == ==
    //         bad_st_inv_e:                       ==
    //         bad_st_inv_hold:           == == == == ==
    //
    // See Bugs 329, 372.

    wire bad_st_inv_e_d1, bad_st_inv_hold ;

    wire bad_st_w = st_op_w & normal_asi_w & mm_dcache_enbl & iu_in_trap ;

    wire bad_st_inv_e = bad_st_inv_hold & dcc_idle & ~bad_st_inv_e_d1 ;
    Mflipflop_r bsi_ff(bad_st_inv_e_d1, bad_st_inv_e, ~ss_reset, ss_clock) ;

    // Set when a bad store moves into R; clear after tag is invalidated
    wire bad_st_inv_hold_a1 =
	iu_held ? (bad_st_inv_hold & ~bad_st_inv_e_d1) : bad_st_w ;
    Mflipflop_r bsih_ff(bad_st_inv_hold, bad_st_inv_hold_a1, ~ss_reset, ss_clock) ;

    // Add writebuffer entry
    wire add_wb_entry = st_op_wb_e & (iu_held_l | atomic_dstat_avail) ;
    Mflipflop_r add_wb_ff(add_wb_entry_d1, add_wb_entry, ~ss_reset, ss_clock);

    // Cancel the last entry which we put into the writebuffer.
    wire cancel_last = iu_in_trap & add_wb_entry_d1 ;

    // Output to MMU - if the write buffer contains exactly one valid entry,
    //     this signal cancels it; otherwise this signal is a don't-care.
    wire invalid_wb_entry = cancel_last ;

    wire load_in_trap_w_d1 ;

    Mflipflop_r ld_op_in_trap_ff(load_in_trap_w_d1, (ld_op_w & iu_in_trap), ~ss_reset, ss_clock);

//  Hold the IU on flushes AND writebuffer full's
//    assign dc_shold       = wb_full & st_op_e & ~asi_flush_e;
//  The above term became a timing path, due to iu_asi_e.
//  So we use a more restrictive hold term, and the fast st_op_e. 
    assign dc_shold       = wb_full & st_op_e_for_hold;

//  The match in the tags is like this:
//  example 1:
//  Input pattern  (encoded acc)->   0 0 1 1 1		
//  Check pattern  (encoded at )->   1 1 0 0 0 
//        Match   		->     YES
//  example 2:
//  Input pattern  (encoded acc)->   0 0 1 0 0		
//  Check pattern  (encoded at )->   0 0 1 0 0 
//        Match   		->     NO
//
//  If 2  logic 1's clash at any bit position, this means there is
//  either a protection or privilege violation for that access.
//  ldst's are assumed to be st's, and thier protection is checked
//  1 cycle before the store is actally done.

//  First generating AT field, and then the encoded dt_at bits

    wire at_0_w = ld_op_w & ~st_op_w & (iu_asi_w==6'ha);
    wire at_1_w = ld_op_w & ~st_op_w & (iu_asi_w==6'hb);
    wire at_2_w = ld_op_w & ~st_op_w & (iu_asi_w==6'h8);
    wire at_3_w = ld_op_w & ~st_op_w & (iu_asi_w==6'h9);
//  ldst's masquerade as st's
    wire at_4_w = st_op_w & (iu_asi_w==6'ha);
    wire at_5_w = st_op_w & (iu_asi_w==6'hb);
    wire at_6_w = st_op_w & (iu_asi_w==6'h8);
    wire at_7_w = st_op_w & (iu_asi_w==6'h9);

    wire [2:0] real_at;
    assign real_at[2]	= at_4_w | at_5_w | at_6_w | at_7_w; 
    assign real_at[1]	= at_2_w | at_3_w | at_6_w | at_7_w; 
    assign real_at[0]	= at_1_w | at_3_w | at_5_w | at_7_w; 
    
//  Encoded AT  field generated here. 
    assign dt_at[4]	= (real_at[1] | (real_at[2] & ~real_at[0])); 
    assign dt_at[3]	= ~real_at[0];
    assign dt_at[2]	= real_at[2];
    assign dt_at[1]	= real_at[1];
    assign dt_at[0]	= (real_at[2] | ~real_at[1]);

//## Fix Hold violation of @ 0.9ns for dt_acc_in[], delay dc_asi_store_tag_w.
//## Used 2 JBUFDA gates in series.
    wire dc_asi_store_tag_w_hold, dc_asi_store_tag_w_hold1;
    JBUFDA dt_acc_in_gate1 
	(.O(dc_asi_store_tag_w_hold1), .A(dc_asi_store_tag_w));
    JBUFDA dt_acc_in_gate2 
	(.O(dc_asi_store_tag_w_hold), .A(dc_asi_store_tag_w_hold1));
//
//  Encoded ACC field generated here. 
    assign dt_acc_in[4] = 
	(dc_asi_store_tag_w_hold) ?
		iu_dout[3] & ~iu_dout[2] & iu_dout[1]:
		misc_in[3] & ~misc_in[2] & misc_in[1];
    assign dt_acc_in[3] = 
	(dc_asi_store_tag_w_hold) ?
		iu_dout[3] & iu_dout[2]:
		misc_in[3] & misc_in[2]; 
    assign dt_acc_in[2] = 
	(dc_asi_store_tag_w_hold) ?
		((iu_dout[2] & ~iu_dout[1])|(~iu_dout[3] & ~iu_dout[1])):
		((misc_in[2] & ~misc_in[1])|(~misc_in[3] & ~misc_in[1]));
    assign dt_acc_in[1] = 
	(dc_asi_store_tag_w_hold) ?
		~iu_dout[3] & ~iu_dout[2]:
		~misc_in[3] & ~misc_in[2]; 
    assign dt_acc_in[0] = 
	(dc_asi_store_tag_w_hold) ?
		iu_dout[3] & ~iu_dout[2] & ~iu_dout[1]:
		misc_in[3] & ~misc_in[2] & ~misc_in[1];

    wire iu_dva_e_2 = iu_dva_e[2] ;
    MflipflopR_6 iu_asi_w_ff(iu_asi_w[5:0], iu_asi_e[5:0], ss_clock, iu_held, ss_reset) ;
    assign atomic_op_e = st_op_e & ld_op_e ;
    MflipflopR atomic_ff(atomic_op_w, atomic_op_e, ss_clock, iu_held, ss_reset) ;

//  CACHE READ HIT LOGIC
//  For load alignment

     wire [1:0] size_e, size_w ;
     MflipflopR_2 size_w_ff(size_w, size_e, ss_clock, iu_held, ss_reset);

    wire double_e = (size_e==3) ;
    wire ldd_e = ld_op_e & double_e ;
    wire lddi_e = ldd_e & ~fpu_mem_e ;

//  Select signal for LSW of ld_fpu bus
    wire sel_ld_fpu_e = iu_dva_e_2 | ldd_e ;

    MflipflopR lddi_ff(lddi_w, lddi_e, ss_clock, iu_held, ss_reset) ;
    MflipflopR hlddi_ff(lddi_r, lddi_w, ss_clock, iu_held, ss_reset) ;
    MflipflopR sldf_ff(sel_ld_fpu_w, sel_ld_fpu_e, ss_clock, iu_held, ss_reset) ;
    MflipflopR dva2_ff(dva_w_2, iu_dva_e_2, ss_clock, iu_held, ss_reset) ;

//  Write enable generation logic
    wire stdi_e = st_op_e & double_e & ~fpu_mem_e ;
 
//  To handle stdi seperately 

    MflipflopR stdi_ff(stdi_w, stdi_e, ss_clock, iu_held, ss_reset) ;

//  Here we assume cached is valid in the same cycle as mm_dstat_avail.
    wire cached, cached_w;
    MflipflopR cached_w_ff (cached_w, (cached & mm_dstat_avail), ss_clock, ~mm_dstat_avail, ss_reset) ;
//  Atleast 1 non-held cycle ? For parity errors.
    wire nonheld_once;
    MflipflopR nonheld_once_ff (nonheld_once, iu_held_l, ss_clock, ~dcc_fill_write_f, ss_reset) ;

    wire fill_write_e;
//  Non-cached SWAP/LDST need a history of the fact that the store
//  should be disabled when the ld part of the ldst is being done.
//  (fix for Bug 293).
//  please explain why this is necessary.
    wire non_cached_ldst = 
	(atomic_op_w & (dcc_ld_nc_bypass|dcc_ld_nc_wait));

//  Disable D$ writes during any asi's except 0x8,0x9,0xA,0xB,0xF.
//  0xf's can write the D$ even if the D$ is disabled.
// No need to inhibit store writes on trap, or if the page turns out to be
//     noncached (but see Bug 293) - we patch things up later by invalidating
//     the DTag.  Note that StA,0f may write the DCache even if it traps.

//  Byte enable mask (in reverse byte order).  dc_be[7] is the enable for
//      byte 7 (the LSByte, on the right of the doubleword), and dc_be[0] is
//      the enable for byte 0 (the MSByte, on the left).

    // For LdD and HLdD, size==3, iu_bytemarks==1111, iu_dva_e_2==0

    // changed below for std integer so that the lsw is written first
    wire enbl_msw_we_e = ~iu_dva_e_2 & ~stdi_w & ~little_endian |
		little_endian & (stdi_w | ~iu_dva_e_2 & ~stdi_e);

    wire enbl_lsw_we_e =
	(~double_e & iu_dva_e_2) | (double_e & fpu_mem_e) 
	| ~little_endian & stdi_w | little_endian & ~iu_dva_e_2 & stdi_e;

	    // BUG #386
            // Added ~(iu_in_trap_d1 & (atomic_op_w| stdi_w) term for BUG 386.
            // During a trap sequence (3 non-held iu cycles),  
            // iu_dva_e is valid only for the 1st cycle, as a result
            // all stdi's and ldst/swaps will store to the wrong address. 
            // To prevent this the D$ write enables dc_be[7:0] are
            // turned off during this cycle. 
            // For timing reasons iu_in_trap_d1 is used, and it works in 
            // these cases because it is guaranteed that for atleast 1 
            // cycle after iu_in_trap goes away, there will be no mem 
            // instruction in the E/W stage of the pipeline, since the
            // first instruction of the trap target is in at the most the
            // D stage of the pipeline by the time iu_in_trap goes away.

//    assign dc_be[7:0] =
////  Normal stores
//    ( ({2{iu_bytemarks[3:0]}} & {{4{enbl_lsw_we_e}},{4{enbl_msw_we_e}}})
//   	& {8{
//	    // ASI & D$ enable are OK, and disable during traps(see above). 
//	    (write_dcache_e & ~(iu_in_trap_d1 & (atomic_op_w | stdi_w))) 
//	    & ~non_cached_ldst  // (Bug 293)
//	  }} 
//        & {8{~iu_held_for_dc_be}}   // Write only once
//    )
////  Cache fills
//    | {8{
//	fill_write_e
//	//  Non-cached bypass mode
//	| (dcc_ld_nc_wait & mm_dcstben)
//	| (dcc_ld_nc_retry & (~parity_error_in_fill | ~cached_w))
//    }}
//    ;
// ///////////////////////////////////////////////////////////////////////
// Handcoded dc_be[7:0]. See above for a better understanding.

   wire [7:0] dc_be_and = 
    ( ({2{iu_bytemarks[3:0]}} & {{4{enbl_lsw_we_e}},{4{enbl_msw_we_e}}})
        & {8{
            // ASI & D$ enable are OK, and disable during traps(see above).
            (write_dcache_e & ~(iu_in_trap_d1 & (atomic_op_w | stdi_w)))
            & ~non_cached_ldst  // (Bug 293)
          }}
    );   

   wire [7:0] dc_be_or = 	{8{
        			fill_write_e
        			//  Non-cached bypass mode
        			| (dcc_ld_nc_wait & mm_dcstben)
 	| (dcc_ld_nc_retry & (~parity_error_in_fill| ~cached_w))
    				}};  

//   wire [7:0] dc_be_and_hold = dc_be_and[7:0] & {8{~iu_held_for_dc_be}};
   wire [7:0] dc_be_and_hold;
   wire dc_be_held_l; 
   JINVD   iu_held_for_dc_be_inv  (.A(iu_held_for_dc_be), .O(dc_be_held_l));
   JNAND2B dc_be_0_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[0]), .O(dc_be_and_hold[0]));
   JNAND2B dc_be_1_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[1]), .O(dc_be_and_hold[1]));
   JNAND2B dc_be_2_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[2]), .O(dc_be_and_hold[2]));
   JNAND2B dc_be_3_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[3]), .O(dc_be_and_hold[3]));
   JNAND2B dc_be_4_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[4]), .O(dc_be_and_hold[4]));
   JNAND2B dc_be_5_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[5]), .O(dc_be_and_hold[5]));
   JNAND2B dc_be_6_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[6]), .O(dc_be_and_hold[6]));
   JNAND2B dc_be_7_nand_gate 
	     (.A1 (dc_be_held_l), .A2(dc_be_and[7]), .O(dc_be_and_hold[7]));

//   assign dc_be[7:0] = dc_be_or [7:0] | dc_be_and_hold [7:0];
   ANAND2D dc_be_0_fgate(.A1 (dc_be_and_hold[0]), .A2(~dc_be_or[0]), .O(dc_be[0]));
   ANAND2D dc_be_1_fgate(.A1 (dc_be_and_hold[1]), .A2(~dc_be_or[1]), .O(dc_be[1]));
   ANAND2D dc_be_2_fgate(.A1 (dc_be_and_hold[2]), .A2(~dc_be_or[2]), .O(dc_be[2]));
   ANAND2D dc_be_3_fgate(.A1 (dc_be_and_hold[3]), .A2(~dc_be_or[3]), .O(dc_be[3]));
   ANAND2D dc_be_4_fgate(.A1 (dc_be_and_hold[4]), .A2(~dc_be_or[4]), .O(dc_be[4]));
   ANAND2D dc_be_5_fgate(.A1 (dc_be_and_hold[5]), .A2(~dc_be_or[5]), .O(dc_be[5]));
   ANAND2D dc_be_6_fgate(.A1 (dc_be_and_hold[6]), .A2(~dc_be_or[6]), .O(dc_be[6]));
   ANAND2D dc_be_7_fgate(.A1 (dc_be_and_hold[7]), .A2(~dc_be_or[7]), .O(dc_be[7]));
// ///////////////////////////////////////////////////////////////////////

//## Fix Hold violation of @ 1.19ns for dc_wle with 3 BUF's.
    wire dc_wle_int, dc_wle_int1, dc_wle_int2;

    JBUFDA dc_wle_gate1 (.O(dc_wle_int1), 
     .A(~dcc_ld_nc_wait & ~(dcc_ld_nc_retry & (~parity_error_in_fill | ~cached_w))));
    JBUFDA dc_wle_gate2 (.O(dc_wle_int2), .A(dc_wle_int1));
    JBUFE  dc_wle_gate3 (.O(dc_wle_int), .A(dc_wle_int2));

//  See below for original equation for dc_wle.
    assign dc_wle = (dc_wle_int & ~dc_power_down) | mm_dct_daten;

//  Turn on dc_wle during reads and writes; turn off for NC cycles, during
//  which we only bypass. Turn off during powerdown cycles for full power saving.
//    assign dc_wle =  
//     (~dcc_ld_nc_wait & ~(dcc_ld_nc_retry & (~parity_error_in_fill | ~cached_w)) 
//	& ~dc_power_down) | mm_dct_daten;

//  Retain the DCache data-in-reg value on a held noncached bypass, until
//      IU/FPU can grab it.
//  Don't hold on nc_byp->idle transition - See Bug 361.
//  Hardcoded below. The equation is given below.
//    assign dc_hld [1:0] = {2{(dcc_ld_nc_bypass & iu_held) | dcc_ld_nc_retry}} ;
    wire [1:0] dc_hld_int;

    JGB12A dc_hld_gate0_0( .A2(fast_iu_held_l), .A1(~dcc_ld_nc_bypass), 
				.B(~dcc_ld_nc_retry), .O(dc_hld_int[0]));
    JINVE dc_hld_gate0_1 ( .O(dc_hld[0]), .A(dc_hld_int[0]));

    JGB12A dc_hld_gate1_0( .A2(fast_iu_held_l), .A1(~dcc_ld_nc_bypass), 
				.B(~dcc_ld_nc_retry), .O(dc_hld_int[1]));
    JINVE dc_hld_gate1_1 ( .O(dc_hld[1]), .A(dc_hld_int[1]));

//  For cache fills 

    assign fill_write_e = (dcc_fill_wait | dcc_dead_cyc_3 ) & mm_dcstben ;

//  Enable Tag hit to the IU.
   wire perr_in_atomic_wr;
    wire dt_be_vb_d1;

    assign enbl_dtag_match_w =  
			( (dcc_idle & ~iu_in_trap_d1) //For hits 
			    | dcc_fill_write_l 
			    | dcc_dead_cyc
			) & (ld_op_w|st_op_w)
//  Data surely available in these cycles or IU trapping.
			& ~dcc_fill_write_f
			& ~load_in_trap_w_d1   // patch for trapping ld's
			& ~dcc_nc_bypass
			& ~perr_in_atomic_wr
			& (normal_asi_w | (iu_asi_w==6'h20))
    			& ~dc_standby_w
    			& ~dt_be_vb_d1
			;

//  Datapath for a D$ asi tag load
//  Decode the output of the TAG RAM so that it fits into 32 bits.
  
  wire [2:0] dt_acc_tmp;
  assign dt_acc_tmp[2] = 
    (dt_acc_out[4:0] == 5'b00001) | (dt_acc_out[4:0] == 5'b10000) 
       | (dt_acc_out[4:0] == 5'b01100) | (dt_acc_out[4:0] == 5'b01000); 

  assign dt_acc_tmp[1] = 
    (dt_acc_out[4:0] == 5'b00100) | (dt_acc_out[4:0] == 5'b00000)
       | (dt_acc_out[4:0] == 5'b01100) | (dt_acc_out[4:0] == 5'b01000); 

  assign dt_acc_tmp[0] = 
    (dt_acc_out[4:0] == 5'b00010) | (dt_acc_out[4:0] == 5'b00000)
       | (dt_acc_out[4:0] == 5'b10000) | (dt_acc_out[4:0] == 5'b01000); 

  wire [31:0] dc_tag_tmp =
   {dt_dout_w[`dt_msb:0],1'b0,dt_cntx_out[7:0],dt_acc_tmp[2:0],dt_val_w};

//  The misc bus is driven by tag_out, during the dc_asi_load_tag_w duration. 
//  Drive the storebuffer bus (should rename it, confusing otherwise ..)

    tri_regen_32 dtag_tri32 ( dc_tagasi_bus[31:0], dc_tag_tmp [31:0], 
					   ss_clock, mm_dct_daten, ss_reset); 

//////////////////////////////////////////////////////////////////////////
//    Added for stores, qualified by iu_hold
// This is for timing fix iu_dva_e -> dwait (too long),
// Its better to hold for 1 cycle everytime a store is ready to
// stream, Then use the registered signal to check for st streaming
// Also hold the pipe for 1 cycle at the start of a st stream.

   // See if dva_e matches the doubleword to be filled in dcc_fill_write_l.
   // If the pipeline is not held, make it look like a match - we're using
   //     this signal next cycle, and the ld/st must have been held in E
   //     for this match to be valid then.
   wire fill_dw_match_e = iu_held_l | (iu_dva_e[12:3]=={dmar[12:4],~dmar[3]}) ;

   Mflipflop_r fill_dw_match_ff (fill_dw_match_e_d1, fill_dw_match_e, ~ss_reset, ss_clock);

    // Hold Store in E if it would write to the doubleword which will be
    //     filled in dcc_fill_write_l (or if we can't tell whether it
    //     matched because the pipe was not held last cycle).
    wire st_stream_hold = 
	(potential_write_dcache_e & fill_dw_match_e_d1)
	& (dcc_fill_write_f | dcc_dead_cyc) ;

// Address matches used for streaming analysis.
// Note: these are hard-coded for an 8KB cache, to facilitate synthesis. 
//       When running with a larger cache (i.e. cache mode), we can get
//       some needless streaming misses if we access a line whose
//       DVA differs from the line we're filling only in bits 15:13.

//  Hold the pipe for 1 cycle at the end of a stream, for cases where
//  The address hits, but it is an asi ld/st, these do not stream
//  The above condition (2nd D$ write) is also held by this signal.

    wire hold_after_last_stream;
    Mflipflop_r hold_after_last_stream_ff (hold_after_last_stream,
		((st_op_w|ld_op_w) & dcc_fill_write_l & (~normal_asi_w)), 
		 ~ss_reset, ss_clock);

//  Free running F/F to make a multicycle path of mm_dcache_enbl -> dwait_w.
    wire mm_dcache_enbl_to_dwait;
    Mflipflop_r mm_dcache_enbl_multi_cycle_ff (mm_dcache_enbl_d1,
         mm_dcache_enbl, ~ss_reset, ss_clock);

//  Changed dcc_stat from a state machine decode to (mm_dstat_avail & dcc_stat_wait)
    wire dcc_stat_new = mm_dstat_avail & dcc_stat_wait & normal_asi_w;
    wire parity_error_d2;

//  (dwait_w) Wait for certain, no data in these cycles (hold) ..

    dwait dwait(
	.possible_bad_ld_op_w	(possible_bad_mem_op_w),
	.parity_error_d1	(parity_error_d1 | parity_error_d2),
	.parity_error_in_fill	(parity_error_in_fill),
	.potential_write_dcache_e	(potential_write_dcache_e),
        .mm_dcache_enbl_d1	(mm_dcache_enbl_d1),
        .dcc_idle		(dcc_idle),
        .iu_in_trap_d1		(iu_in_trap_d1),
        .ld_op_w		(ld_op_w),
        .st_op_w		(st_op_w),
        .dcc_stat_wait		(dcc_stat_wait),
        .dcc_stat		(dcc_state[2]),
        .dcc_fill_wait		(dcc_fill_wait),
	.dcc_fill_write_l	(dcc_fill_write_l),
        .dcc_dead_cyc		(dcc_dead_cyc),
        .dcc_dead_cyc_3		(dcc_dead_cyc_3),
        .normal_asi_w		(normal_asi_w),
        .hold_after_last_stream	(hold_after_last_stream),
        .st_stream_hold		(st_stream_hold),
        .dcc_nc_wait		(dcc_nc_wait),
        .dcc_nc_retry		(dcc_nc_retry),
        .dcc_nc_bypass		(dcc_nc_bypass),
        .nomiss_asi_w		(nomiss_asi_w),
        .bad_st_inv_hold	(bad_st_inv_hold),
        .dc_flush_op_w		(dc_flush_op_w),
        .dc_flush_hold		(dc_flush_hold),
        .standby_req		(standby_req),
        .dc_standby_w		(dc_standby_w),
        .flush123_out		(flush123_out),
	.first_w_of_cache_ram_asi (first_w_of_cache_ram_asi),
        .dmar			(dmar[12:3]),
        .iu_dva_w		(iu_dva_w[12:3]),
 	.dwait_w		(dwait_w)
        );


// Special fast dwait_w subset for IU/I$ for flushes. (Timing fix)
//    assign dwait_w_for_flush = dwait_w;
  assign dwait_w_for_flush = dc_flush_op_w | dc_flush_hold ;

//  Write during fills and asi writes
    assign dt_be    = dcc_stat & (cached | dc_asi_store_tag_w) ;

//  Write during fills, asi writes, flushes and non-cached stores

    assign dt_be_vb =

	(dcc_stat & cached) 

//  Invalidate the D$ line on non-cached access only, when we have trashed
//      the cache line by writing the store data.
//  Only during normal asi's 0x8/0x9/0xA/0xB (Bug 140)
//  Only when DCache is enabled (Bug 160)
   	| (dcc_st_stat & ~cached & mm_dcache_enbl & normal_asi_w)

// Store to DTag RAM ASI
        | (dc_asi_store_tag_w & dcc_stat)  

//  Invalidate during mm_daborts also. (Protection error).
   	| (dcc_st_stat_wait & mm_dabort & mm_dcache_enbl)

//  Flush: write valid bit only if the entry in the D$ matched (even if the 
//       DCache is disabled - this feature is used by diagnostics).
//  Flush only during sta's, not during I$ flush
	| (dc_flush_op_w & dt_hit_w & ~ic_flush_op_w & ~parity_error_d1)

//  Invalidate for stores which trap.
      	| bad_st_inv_e
//  Invalidate on parity errors
	| parity_error_d1
	;

//  On Parity Errors, invalidate the Data cache line.
//  Invalidate 1 cycle after data arrives on parity errors.
//  Also hold the IU for 1 cycle because the next instruction could
//  be a ld from the other half of the cache line, which is 
//  invalidated 1 cycle after the data in written into the D$ RAM.

    wire mm_dcstben_d1;
    MflipflopR parity_error_in_fill_srh( parity_error_in_fill,
     ( ((dp_perr[1]|dp_perr[0]) & cached_w & mm_dcstben_d1) | 
	 (parity_error_in_fill & ~dcc_idle)),
	    ss_clock, ~(mm_dcstben_d1 | dcc_idle), 
		 ss_reset);

    Mflipflop_r mm_dcstben_d1_ff(mm_dcstben_d1, mm_dcstben, ~ss_reset, ss_clock) ; 
    assign parity_error = 
	((mm_dcstben_d1 & dp_perr[1]) | (mm_dcstben_d1 & dp_perr[0])) & cached_w;

    Mflipflop_r parity_error_d1_ff (parity_error_d1,
	parity_error, ~ss_reset, ss_clock) ;
    Mflipflop_r parity_error_d2_ff (parity_error_d2,
	parity_error_d1, ~ss_reset, ss_clock) ;

   wire atomic_miss;
   MflipflopR atomic_miss_ff (atomic_miss, atomic_op_w, ss_clock, ~mm_dstat_avail, ss_reset);

// Disable store miss on parity errors for atomics. Assume they are hits.
   MflipflopR perr_in_atomic_ff (perr_in_atomic_wr, 
	(parity_error_in_fill & mm_dcstben_d1 & atomic_miss), ss_clock, 
		 (~mm_dcstben_d1 & iu_held), ss_reset);

//  Valid bit is 1'b1 unless its a flush or a non-cached store operation,
//  or a protection error on a store,
//  or a parity error.

//## Fixed hold violation of 0.65ns in dc_dtv_din, using 3 [JBUFE] in series.
    wire dc_dtv_din_int, dc_dtv_din_int1, dc_dtv_din_int2;
Next12
HierarchyFilesModulesSignalsTasksFunctionsHelp

This page: Created:Thu Aug 19 11:59:20 1999
From: ../../../sparc_v8/ssparc/cc/rl_dc_cntl/rtl/rl_dc_cntl.v

Verilog converted to html by v2html 5.0 (written by Costas Calamvokis).Help