/******************************************************************************/
/* */
/* 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.
//
******************************************************************************/
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
;
This page: |
Created: | Thu Aug 19 11:59:20 1999 |
| From: |
../../../sparc_v8/ssparc/cc/rl_dc_cntl/rtl/rl_dc_cntl.v
|