Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / verilog / ldst_sync / ldst_lsu.v
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: ldst_lsu.v
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
//
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
//
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// have any questions.
//
// ========== Copyright Header End ============================================
`ifdef CORE_0
module ldst_lsu_c0 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 0;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC0.lsu.dcc.ld_inst_vld_w &
~`PROBES0.asi_internal_w &
~`SPC0.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC0.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC0.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC0.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC0.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC0.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC0.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC0.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC0.lsu.tlb_pgnum[39:13],
`SPC0.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC0.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC0.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC0.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC0.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES0.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC0.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC0.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC0.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC0.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC0.lsu.dcc.pst_asi_b & `SPC0.lsu.dcc.tlb_tte_ie_b & `SPC0.lsu.dcc.tlb_tte_vld_b & `SPC0.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC0.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC0.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC0.lsu.tlb_pgnum[39:13],
`SPC0.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC0.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC0.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC0.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC0.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC0.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC0.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC0.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC0.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC0.lsu.sbs7.rmo_st_commit_p4,
`SPC0.lsu.sbs6.rmo_st_commit_p4,
`SPC0.lsu.sbs5.rmo_st_commit_p4,
`SPC0.lsu.sbs4.rmo_st_commit_p4,
`SPC0.lsu.sbs3.rmo_st_commit_p4,
`SPC0.lsu.sbs2.rmo_st_commit_p4,
`SPC0.lsu.sbs1.rmo_st_commit_p4,
`SPC0.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC0.lsu.cic.cic_st_atm_cmplt &
(`SPC0.lsu.lmc.dcl2u_err | `SPC0.lsu.lmc.dcl2nd_err))}} &
`SPC0.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC0.lsu.cic_invalidate_e &
(`SPC0.lsu.cic_inv_wen_e!=0)&
~`SPC0.lsu.cic.cpq_evict &
~`SPC0.lsu.cic.cid_set_inval &
~`SPC0.lsu.cic.cic_xinval_e &
~(`SPC0.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC0.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC0.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC0.lsu.cic_st_update_e;
assign stu_tid_e = `SPC0.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC0.lsu.cid.cpq_data_out[116],
`SPC0.lsu.cid.cpq_data_out[115],
`SPC0.lsu.cid.cpq_data_out[114],
`SPC0.lsu.cid.cpq_data_out[113],
`SPC0.lsu.cid.cpq_data_out[112],
`SPC0.lsu.cid.cpq_data_out[122],
`SPC0.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC0.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC0.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC0.lsu.cic_inv_wen_e!=0)&
`SPC0.lsu.cic.cpq_evict &
~`SPC0.lsu.cic.cid_set_inval &
~`SPC0.lsu.cic.cic_xinval_e}} &
{|(`SPC0.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC0.lsu.cic.evict_inv_wen[11:8]),
|(`SPC0.lsu.cic.evict_inv_wen[7:4]),
|(`SPC0.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC0.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC0.spc_pcx_req_pq;
assign pcx_data = `SPC0.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC0.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC0.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC0.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC0.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC0.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC0.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC0.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC0.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC0.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC0.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC0.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC0.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC0.tlu.fls1.pil_mask_15[3:0], `SPC0.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC0.lsu_dcl2u_err_g | `SPC0.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC0.lsu.sbs7.bst_kill,
`SPC0.lsu.sbs6.bst_kill,
`SPC0.lsu.sbs5.bst_kill,
`SPC0.lsu.sbs4.bst_kill,
`SPC0.lsu.sbs3.bst_kill,
`SPC0.lsu.sbs2.bst_kill,
`SPC0.lsu.sbs1.bst_kill,
`SPC0.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC0.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC0.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC0.lsu.cid.cpq_data_out[116],
`SPC0.lsu.cid.cpq_data_out[115],
`SPC0.lsu.cid.cpq_data_out[114],
`SPC0.lsu.cid.cpq_data_out[113],
`SPC0.lsu.cid.cpq_data_out[112],
`SPC0.lsu.cid.cpq_data_out[122],
`SPC0.lsu.cid.cpq_data_out[121],
`SPC0.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC0.l2clk) begin // {
if (`SPC0.lsu.dta.wr_way[0])
dta_way0[`SPC0.lsu.dta.index_y[6:0]] <= `SPC0.lsu.dta.wrtag_y[27:0];
if (`SPC0.lsu.dta.wr_way[1])
dta_way1[`SPC0.lsu.dta.index_y[6:0]] <= `SPC0.lsu.dta.wrtag_y[27:0];
if (`SPC0.lsu.dta.wr_way[2])
dta_way2[`SPC0.lsu.dta.index_y[6:0]] <= `SPC0.lsu.dta.wrtag_y[27:0];
if (`SPC0.lsu.dta.wr_way[3])
dta_way3[`SPC0.lsu.dta.index_y[6:0]] <= `SPC0.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_1
module ldst_lsu_c1 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 1;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC1.lsu.dcc.ld_inst_vld_w &
~`PROBES1.asi_internal_w &
~`SPC1.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC1.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC1.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC1.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC1.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC1.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC1.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC1.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC1.lsu.tlb_pgnum[39:13],
`SPC1.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC1.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC1.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC1.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC1.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES1.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC1.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC1.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC1.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC1.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC1.lsu.dcc.pst_asi_b & `SPC1.lsu.dcc.tlb_tte_ie_b & `SPC1.lsu.dcc.tlb_tte_vld_b & `SPC1.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC1.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC1.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC1.lsu.tlb_pgnum[39:13],
`SPC1.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC1.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC1.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC1.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC1.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC1.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC1.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC1.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC1.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC1.lsu.sbs7.rmo_st_commit_p4,
`SPC1.lsu.sbs6.rmo_st_commit_p4,
`SPC1.lsu.sbs5.rmo_st_commit_p4,
`SPC1.lsu.sbs4.rmo_st_commit_p4,
`SPC1.lsu.sbs3.rmo_st_commit_p4,
`SPC1.lsu.sbs2.rmo_st_commit_p4,
`SPC1.lsu.sbs1.rmo_st_commit_p4,
`SPC1.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC1.lsu.cic.cic_st_atm_cmplt &
(`SPC1.lsu.lmc.dcl2u_err | `SPC1.lsu.lmc.dcl2nd_err))}} &
`SPC1.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC1.lsu.cic_invalidate_e &
(`SPC1.lsu.cic_inv_wen_e!=0)&
~`SPC1.lsu.cic.cpq_evict &
~`SPC1.lsu.cic.cid_set_inval &
~`SPC1.lsu.cic.cic_xinval_e &
~(`SPC1.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC1.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC1.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC1.lsu.cic_st_update_e;
assign stu_tid_e = `SPC1.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC1.lsu.cid.cpq_data_out[116],
`SPC1.lsu.cid.cpq_data_out[115],
`SPC1.lsu.cid.cpq_data_out[114],
`SPC1.lsu.cid.cpq_data_out[113],
`SPC1.lsu.cid.cpq_data_out[112],
`SPC1.lsu.cid.cpq_data_out[122],
`SPC1.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC1.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC1.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC1.lsu.cic_inv_wen_e!=0)&
`SPC1.lsu.cic.cpq_evict &
~`SPC1.lsu.cic.cid_set_inval &
~`SPC1.lsu.cic.cic_xinval_e}} &
{|(`SPC1.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC1.lsu.cic.evict_inv_wen[11:8]),
|(`SPC1.lsu.cic.evict_inv_wen[7:4]),
|(`SPC1.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC1.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC1.spc_pcx_req_pq;
assign pcx_data = `SPC1.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC1.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC1.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC1.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC1.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC1.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC1.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC1.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC1.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC1.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC1.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC1.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC1.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC1.tlu.fls1.pil_mask_15[3:0], `SPC1.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC1.lsu_dcl2u_err_g | `SPC1.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC1.lsu.sbs7.bst_kill,
`SPC1.lsu.sbs6.bst_kill,
`SPC1.lsu.sbs5.bst_kill,
`SPC1.lsu.sbs4.bst_kill,
`SPC1.lsu.sbs3.bst_kill,
`SPC1.lsu.sbs2.bst_kill,
`SPC1.lsu.sbs1.bst_kill,
`SPC1.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC1.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC1.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC1.lsu.cid.cpq_data_out[116],
`SPC1.lsu.cid.cpq_data_out[115],
`SPC1.lsu.cid.cpq_data_out[114],
`SPC1.lsu.cid.cpq_data_out[113],
`SPC1.lsu.cid.cpq_data_out[112],
`SPC1.lsu.cid.cpq_data_out[122],
`SPC1.lsu.cid.cpq_data_out[121],
`SPC1.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC1.l2clk) begin // {
if (`SPC1.lsu.dta.wr_way[0])
dta_way0[`SPC1.lsu.dta.index_y[6:0]] <= `SPC1.lsu.dta.wrtag_y[27:0];
if (`SPC1.lsu.dta.wr_way[1])
dta_way1[`SPC1.lsu.dta.index_y[6:0]] <= `SPC1.lsu.dta.wrtag_y[27:0];
if (`SPC1.lsu.dta.wr_way[2])
dta_way2[`SPC1.lsu.dta.index_y[6:0]] <= `SPC1.lsu.dta.wrtag_y[27:0];
if (`SPC1.lsu.dta.wr_way[3])
dta_way3[`SPC1.lsu.dta.index_y[6:0]] <= `SPC1.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_2
module ldst_lsu_c2 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 2;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC2.lsu.dcc.ld_inst_vld_w &
~`PROBES2.asi_internal_w &
~`SPC2.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC2.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC2.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC2.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC2.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC2.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC2.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC2.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC2.lsu.tlb_pgnum[39:13],
`SPC2.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC2.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC2.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC2.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC2.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES2.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC2.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC2.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC2.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC2.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC2.lsu.dcc.pst_asi_b & `SPC2.lsu.dcc.tlb_tte_ie_b & `SPC2.lsu.dcc.tlb_tte_vld_b & `SPC2.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC2.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC2.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC2.lsu.tlb_pgnum[39:13],
`SPC2.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC2.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC2.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC2.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC2.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC2.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC2.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC2.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC2.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC2.lsu.sbs7.rmo_st_commit_p4,
`SPC2.lsu.sbs6.rmo_st_commit_p4,
`SPC2.lsu.sbs5.rmo_st_commit_p4,
`SPC2.lsu.sbs4.rmo_st_commit_p4,
`SPC2.lsu.sbs3.rmo_st_commit_p4,
`SPC2.lsu.sbs2.rmo_st_commit_p4,
`SPC2.lsu.sbs1.rmo_st_commit_p4,
`SPC2.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC2.lsu.cic.cic_st_atm_cmplt &
(`SPC2.lsu.lmc.dcl2u_err | `SPC2.lsu.lmc.dcl2nd_err))}} &
`SPC2.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC2.lsu.cic_invalidate_e &
(`SPC2.lsu.cic_inv_wen_e!=0)&
~`SPC2.lsu.cic.cpq_evict &
~`SPC2.lsu.cic.cid_set_inval &
~`SPC2.lsu.cic.cic_xinval_e &
~(`SPC2.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC2.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC2.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC2.lsu.cic_st_update_e;
assign stu_tid_e = `SPC2.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC2.lsu.cid.cpq_data_out[116],
`SPC2.lsu.cid.cpq_data_out[115],
`SPC2.lsu.cid.cpq_data_out[114],
`SPC2.lsu.cid.cpq_data_out[113],
`SPC2.lsu.cid.cpq_data_out[112],
`SPC2.lsu.cid.cpq_data_out[122],
`SPC2.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC2.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC2.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC2.lsu.cic_inv_wen_e!=0)&
`SPC2.lsu.cic.cpq_evict &
~`SPC2.lsu.cic.cid_set_inval &
~`SPC2.lsu.cic.cic_xinval_e}} &
{|(`SPC2.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC2.lsu.cic.evict_inv_wen[11:8]),
|(`SPC2.lsu.cic.evict_inv_wen[7:4]),
|(`SPC2.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC2.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC2.spc_pcx_req_pq;
assign pcx_data = `SPC2.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC2.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC2.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC2.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC2.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC2.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC2.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC2.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC2.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC2.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC2.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC2.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC2.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC2.tlu.fls1.pil_mask_15[3:0], `SPC2.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC2.lsu_dcl2u_err_g | `SPC2.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC2.lsu.sbs7.bst_kill,
`SPC2.lsu.sbs6.bst_kill,
`SPC2.lsu.sbs5.bst_kill,
`SPC2.lsu.sbs4.bst_kill,
`SPC2.lsu.sbs3.bst_kill,
`SPC2.lsu.sbs2.bst_kill,
`SPC2.lsu.sbs1.bst_kill,
`SPC2.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC2.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC2.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC2.lsu.cid.cpq_data_out[116],
`SPC2.lsu.cid.cpq_data_out[115],
`SPC2.lsu.cid.cpq_data_out[114],
`SPC2.lsu.cid.cpq_data_out[113],
`SPC2.lsu.cid.cpq_data_out[112],
`SPC2.lsu.cid.cpq_data_out[122],
`SPC2.lsu.cid.cpq_data_out[121],
`SPC2.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC2.l2clk) begin // {
if (`SPC2.lsu.dta.wr_way[0])
dta_way0[`SPC2.lsu.dta.index_y[6:0]] <= `SPC2.lsu.dta.wrtag_y[27:0];
if (`SPC2.lsu.dta.wr_way[1])
dta_way1[`SPC2.lsu.dta.index_y[6:0]] <= `SPC2.lsu.dta.wrtag_y[27:0];
if (`SPC2.lsu.dta.wr_way[2])
dta_way2[`SPC2.lsu.dta.index_y[6:0]] <= `SPC2.lsu.dta.wrtag_y[27:0];
if (`SPC2.lsu.dta.wr_way[3])
dta_way3[`SPC2.lsu.dta.index_y[6:0]] <= `SPC2.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_3
module ldst_lsu_c3 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 3;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC3.lsu.dcc.ld_inst_vld_w &
~`PROBES3.asi_internal_w &
~`SPC3.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC3.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC3.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC3.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC3.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC3.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC3.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC3.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC3.lsu.tlb_pgnum[39:13],
`SPC3.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC3.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC3.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC3.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC3.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES3.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC3.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC3.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC3.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC3.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC3.lsu.dcc.pst_asi_b & `SPC3.lsu.dcc.tlb_tte_ie_b & `SPC3.lsu.dcc.tlb_tte_vld_b & `SPC3.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC3.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC3.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC3.lsu.tlb_pgnum[39:13],
`SPC3.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC3.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC3.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC3.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC3.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC3.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC3.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC3.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC3.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC3.lsu.sbs7.rmo_st_commit_p4,
`SPC3.lsu.sbs6.rmo_st_commit_p4,
`SPC3.lsu.sbs5.rmo_st_commit_p4,
`SPC3.lsu.sbs4.rmo_st_commit_p4,
`SPC3.lsu.sbs3.rmo_st_commit_p4,
`SPC3.lsu.sbs2.rmo_st_commit_p4,
`SPC3.lsu.sbs1.rmo_st_commit_p4,
`SPC3.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC3.lsu.cic.cic_st_atm_cmplt &
(`SPC3.lsu.lmc.dcl2u_err | `SPC3.lsu.lmc.dcl2nd_err))}} &
`SPC3.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC3.lsu.cic_invalidate_e &
(`SPC3.lsu.cic_inv_wen_e!=0)&
~`SPC3.lsu.cic.cpq_evict &
~`SPC3.lsu.cic.cid_set_inval &
~`SPC3.lsu.cic.cic_xinval_e &
~(`SPC3.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC3.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC3.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC3.lsu.cic_st_update_e;
assign stu_tid_e = `SPC3.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC3.lsu.cid.cpq_data_out[116],
`SPC3.lsu.cid.cpq_data_out[115],
`SPC3.lsu.cid.cpq_data_out[114],
`SPC3.lsu.cid.cpq_data_out[113],
`SPC3.lsu.cid.cpq_data_out[112],
`SPC3.lsu.cid.cpq_data_out[122],
`SPC3.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC3.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC3.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC3.lsu.cic_inv_wen_e!=0)&
`SPC3.lsu.cic.cpq_evict &
~`SPC3.lsu.cic.cid_set_inval &
~`SPC3.lsu.cic.cic_xinval_e}} &
{|(`SPC3.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC3.lsu.cic.evict_inv_wen[11:8]),
|(`SPC3.lsu.cic.evict_inv_wen[7:4]),
|(`SPC3.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC3.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC3.spc_pcx_req_pq;
assign pcx_data = `SPC3.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC3.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC3.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC3.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC3.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC3.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC3.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC3.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC3.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC3.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC3.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC3.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC3.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC3.tlu.fls1.pil_mask_15[3:0], `SPC3.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC3.lsu_dcl2u_err_g | `SPC3.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC3.lsu.sbs7.bst_kill,
`SPC3.lsu.sbs6.bst_kill,
`SPC3.lsu.sbs5.bst_kill,
`SPC3.lsu.sbs4.bst_kill,
`SPC3.lsu.sbs3.bst_kill,
`SPC3.lsu.sbs2.bst_kill,
`SPC3.lsu.sbs1.bst_kill,
`SPC3.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC3.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC3.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC3.lsu.cid.cpq_data_out[116],
`SPC3.lsu.cid.cpq_data_out[115],
`SPC3.lsu.cid.cpq_data_out[114],
`SPC3.lsu.cid.cpq_data_out[113],
`SPC3.lsu.cid.cpq_data_out[112],
`SPC3.lsu.cid.cpq_data_out[122],
`SPC3.lsu.cid.cpq_data_out[121],
`SPC3.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC3.l2clk) begin // {
if (`SPC3.lsu.dta.wr_way[0])
dta_way0[`SPC3.lsu.dta.index_y[6:0]] <= `SPC3.lsu.dta.wrtag_y[27:0];
if (`SPC3.lsu.dta.wr_way[1])
dta_way1[`SPC3.lsu.dta.index_y[6:0]] <= `SPC3.lsu.dta.wrtag_y[27:0];
if (`SPC3.lsu.dta.wr_way[2])
dta_way2[`SPC3.lsu.dta.index_y[6:0]] <= `SPC3.lsu.dta.wrtag_y[27:0];
if (`SPC3.lsu.dta.wr_way[3])
dta_way3[`SPC3.lsu.dta.index_y[6:0]] <= `SPC3.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_4
module ldst_lsu_c4 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 4;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC4.lsu.dcc.ld_inst_vld_w &
~`PROBES4.asi_internal_w &
~`SPC4.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC4.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC4.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC4.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC4.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC4.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC4.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC4.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC4.lsu.tlb_pgnum[39:13],
`SPC4.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC4.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC4.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC4.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC4.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES4.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC4.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC4.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC4.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC4.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC4.lsu.dcc.pst_asi_b & `SPC4.lsu.dcc.tlb_tte_ie_b & `SPC4.lsu.dcc.tlb_tte_vld_b & `SPC4.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC4.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC4.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC4.lsu.tlb_pgnum[39:13],
`SPC4.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC4.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC4.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC4.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC4.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC4.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC4.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC4.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC4.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC4.lsu.sbs7.rmo_st_commit_p4,
`SPC4.lsu.sbs6.rmo_st_commit_p4,
`SPC4.lsu.sbs5.rmo_st_commit_p4,
`SPC4.lsu.sbs4.rmo_st_commit_p4,
`SPC4.lsu.sbs3.rmo_st_commit_p4,
`SPC4.lsu.sbs2.rmo_st_commit_p4,
`SPC4.lsu.sbs1.rmo_st_commit_p4,
`SPC4.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC4.lsu.cic.cic_st_atm_cmplt &
(`SPC4.lsu.lmc.dcl2u_err | `SPC4.lsu.lmc.dcl2nd_err))}} &
`SPC4.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC4.lsu.cic_invalidate_e &
(`SPC4.lsu.cic_inv_wen_e!=0)&
~`SPC4.lsu.cic.cpq_evict &
~`SPC4.lsu.cic.cid_set_inval &
~`SPC4.lsu.cic.cic_xinval_e &
~(`SPC4.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC4.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC4.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC4.lsu.cic_st_update_e;
assign stu_tid_e = `SPC4.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC4.lsu.cid.cpq_data_out[116],
`SPC4.lsu.cid.cpq_data_out[115],
`SPC4.lsu.cid.cpq_data_out[114],
`SPC4.lsu.cid.cpq_data_out[113],
`SPC4.lsu.cid.cpq_data_out[112],
`SPC4.lsu.cid.cpq_data_out[122],
`SPC4.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC4.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC4.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC4.lsu.cic_inv_wen_e!=0)&
`SPC4.lsu.cic.cpq_evict &
~`SPC4.lsu.cic.cid_set_inval &
~`SPC4.lsu.cic.cic_xinval_e}} &
{|(`SPC4.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC4.lsu.cic.evict_inv_wen[11:8]),
|(`SPC4.lsu.cic.evict_inv_wen[7:4]),
|(`SPC4.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC4.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC4.spc_pcx_req_pq;
assign pcx_data = `SPC4.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC4.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC4.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC4.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC4.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC4.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC4.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC4.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC4.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC4.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC4.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC4.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC4.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC4.tlu.fls1.pil_mask_15[3:0], `SPC4.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC4.lsu_dcl2u_err_g | `SPC4.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC4.lsu.sbs7.bst_kill,
`SPC4.lsu.sbs6.bst_kill,
`SPC4.lsu.sbs5.bst_kill,
`SPC4.lsu.sbs4.bst_kill,
`SPC4.lsu.sbs3.bst_kill,
`SPC4.lsu.sbs2.bst_kill,
`SPC4.lsu.sbs1.bst_kill,
`SPC4.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC4.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC4.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC4.lsu.cid.cpq_data_out[116],
`SPC4.lsu.cid.cpq_data_out[115],
`SPC4.lsu.cid.cpq_data_out[114],
`SPC4.lsu.cid.cpq_data_out[113],
`SPC4.lsu.cid.cpq_data_out[112],
`SPC4.lsu.cid.cpq_data_out[122],
`SPC4.lsu.cid.cpq_data_out[121],
`SPC4.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC4.l2clk) begin // {
if (`SPC4.lsu.dta.wr_way[0])
dta_way0[`SPC4.lsu.dta.index_y[6:0]] <= `SPC4.lsu.dta.wrtag_y[27:0];
if (`SPC4.lsu.dta.wr_way[1])
dta_way1[`SPC4.lsu.dta.index_y[6:0]] <= `SPC4.lsu.dta.wrtag_y[27:0];
if (`SPC4.lsu.dta.wr_way[2])
dta_way2[`SPC4.lsu.dta.index_y[6:0]] <= `SPC4.lsu.dta.wrtag_y[27:0];
if (`SPC4.lsu.dta.wr_way[3])
dta_way3[`SPC4.lsu.dta.index_y[6:0]] <= `SPC4.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_5
module ldst_lsu_c5 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 5;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC5.lsu.dcc.ld_inst_vld_w &
~`PROBES5.asi_internal_w &
~`SPC5.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC5.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC5.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC5.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC5.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC5.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC5.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC5.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC5.lsu.tlb_pgnum[39:13],
`SPC5.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC5.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC5.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC5.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC5.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES5.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC5.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC5.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC5.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC5.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC5.lsu.dcc.pst_asi_b & `SPC5.lsu.dcc.tlb_tte_ie_b & `SPC5.lsu.dcc.tlb_tte_vld_b & `SPC5.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC5.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC5.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC5.lsu.tlb_pgnum[39:13],
`SPC5.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC5.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC5.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC5.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC5.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC5.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC5.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC5.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC5.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC5.lsu.sbs7.rmo_st_commit_p4,
`SPC5.lsu.sbs6.rmo_st_commit_p4,
`SPC5.lsu.sbs5.rmo_st_commit_p4,
`SPC5.lsu.sbs4.rmo_st_commit_p4,
`SPC5.lsu.sbs3.rmo_st_commit_p4,
`SPC5.lsu.sbs2.rmo_st_commit_p4,
`SPC5.lsu.sbs1.rmo_st_commit_p4,
`SPC5.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC5.lsu.cic.cic_st_atm_cmplt &
(`SPC5.lsu.lmc.dcl2u_err | `SPC5.lsu.lmc.dcl2nd_err))}} &
`SPC5.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC5.lsu.cic_invalidate_e &
(`SPC5.lsu.cic_inv_wen_e!=0)&
~`SPC5.lsu.cic.cpq_evict &
~`SPC5.lsu.cic.cid_set_inval &
~`SPC5.lsu.cic.cic_xinval_e &
~(`SPC5.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC5.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC5.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC5.lsu.cic_st_update_e;
assign stu_tid_e = `SPC5.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC5.lsu.cid.cpq_data_out[116],
`SPC5.lsu.cid.cpq_data_out[115],
`SPC5.lsu.cid.cpq_data_out[114],
`SPC5.lsu.cid.cpq_data_out[113],
`SPC5.lsu.cid.cpq_data_out[112],
`SPC5.lsu.cid.cpq_data_out[122],
`SPC5.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC5.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC5.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC5.lsu.cic_inv_wen_e!=0)&
`SPC5.lsu.cic.cpq_evict &
~`SPC5.lsu.cic.cid_set_inval &
~`SPC5.lsu.cic.cic_xinval_e}} &
{|(`SPC5.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC5.lsu.cic.evict_inv_wen[11:8]),
|(`SPC5.lsu.cic.evict_inv_wen[7:4]),
|(`SPC5.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC5.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC5.spc_pcx_req_pq;
assign pcx_data = `SPC5.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC5.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC5.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC5.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC5.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC5.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC5.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC5.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC5.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC5.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC5.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC5.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC5.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC5.tlu.fls1.pil_mask_15[3:0], `SPC5.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC5.lsu_dcl2u_err_g | `SPC5.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC5.lsu.sbs7.bst_kill,
`SPC5.lsu.sbs6.bst_kill,
`SPC5.lsu.sbs5.bst_kill,
`SPC5.lsu.sbs4.bst_kill,
`SPC5.lsu.sbs3.bst_kill,
`SPC5.lsu.sbs2.bst_kill,
`SPC5.lsu.sbs1.bst_kill,
`SPC5.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC5.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC5.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC5.lsu.cid.cpq_data_out[116],
`SPC5.lsu.cid.cpq_data_out[115],
`SPC5.lsu.cid.cpq_data_out[114],
`SPC5.lsu.cid.cpq_data_out[113],
`SPC5.lsu.cid.cpq_data_out[112],
`SPC5.lsu.cid.cpq_data_out[122],
`SPC5.lsu.cid.cpq_data_out[121],
`SPC5.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC5.l2clk) begin // {
if (`SPC5.lsu.dta.wr_way[0])
dta_way0[`SPC5.lsu.dta.index_y[6:0]] <= `SPC5.lsu.dta.wrtag_y[27:0];
if (`SPC5.lsu.dta.wr_way[1])
dta_way1[`SPC5.lsu.dta.index_y[6:0]] <= `SPC5.lsu.dta.wrtag_y[27:0];
if (`SPC5.lsu.dta.wr_way[2])
dta_way2[`SPC5.lsu.dta.index_y[6:0]] <= `SPC5.lsu.dta.wrtag_y[27:0];
if (`SPC5.lsu.dta.wr_way[3])
dta_way3[`SPC5.lsu.dta.index_y[6:0]] <= `SPC5.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_6
module ldst_lsu_c6 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 6;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC6.lsu.dcc.ld_inst_vld_w &
~`PROBES6.asi_internal_w &
~`SPC6.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC6.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC6.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC6.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC6.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC6.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC6.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC6.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC6.lsu.tlb_pgnum[39:13],
`SPC6.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC6.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC6.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC6.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC6.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES6.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC6.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC6.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC6.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC6.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC6.lsu.dcc.pst_asi_b & `SPC6.lsu.dcc.tlb_tte_ie_b & `SPC6.lsu.dcc.tlb_tte_vld_b & `SPC6.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC6.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC6.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC6.lsu.tlb_pgnum[39:13],
`SPC6.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC6.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC6.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC6.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC6.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC6.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC6.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC6.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC6.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC6.lsu.sbs7.rmo_st_commit_p4,
`SPC6.lsu.sbs6.rmo_st_commit_p4,
`SPC6.lsu.sbs5.rmo_st_commit_p4,
`SPC6.lsu.sbs4.rmo_st_commit_p4,
`SPC6.lsu.sbs3.rmo_st_commit_p4,
`SPC6.lsu.sbs2.rmo_st_commit_p4,
`SPC6.lsu.sbs1.rmo_st_commit_p4,
`SPC6.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC6.lsu.cic.cic_st_atm_cmplt &
(`SPC6.lsu.lmc.dcl2u_err | `SPC6.lsu.lmc.dcl2nd_err))}} &
`SPC6.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC6.lsu.cic_invalidate_e &
(`SPC6.lsu.cic_inv_wen_e!=0)&
~`SPC6.lsu.cic.cpq_evict &
~`SPC6.lsu.cic.cid_set_inval &
~`SPC6.lsu.cic.cic_xinval_e &
~(`SPC6.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC6.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC6.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC6.lsu.cic_st_update_e;
assign stu_tid_e = `SPC6.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC6.lsu.cid.cpq_data_out[116],
`SPC6.lsu.cid.cpq_data_out[115],
`SPC6.lsu.cid.cpq_data_out[114],
`SPC6.lsu.cid.cpq_data_out[113],
`SPC6.lsu.cid.cpq_data_out[112],
`SPC6.lsu.cid.cpq_data_out[122],
`SPC6.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC6.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC6.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC6.lsu.cic_inv_wen_e!=0)&
`SPC6.lsu.cic.cpq_evict &
~`SPC6.lsu.cic.cid_set_inval &
~`SPC6.lsu.cic.cic_xinval_e}} &
{|(`SPC6.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC6.lsu.cic.evict_inv_wen[11:8]),
|(`SPC6.lsu.cic.evict_inv_wen[7:4]),
|(`SPC6.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC6.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC6.spc_pcx_req_pq;
assign pcx_data = `SPC6.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC6.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC6.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC6.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC6.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC6.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC6.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC6.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC6.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC6.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC6.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC6.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC6.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC6.tlu.fls1.pil_mask_15[3:0], `SPC6.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC6.lsu_dcl2u_err_g | `SPC6.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC6.lsu.sbs7.bst_kill,
`SPC6.lsu.sbs6.bst_kill,
`SPC6.lsu.sbs5.bst_kill,
`SPC6.lsu.sbs4.bst_kill,
`SPC6.lsu.sbs3.bst_kill,
`SPC6.lsu.sbs2.bst_kill,
`SPC6.lsu.sbs1.bst_kill,
`SPC6.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC6.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC6.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC6.lsu.cid.cpq_data_out[116],
`SPC6.lsu.cid.cpq_data_out[115],
`SPC6.lsu.cid.cpq_data_out[114],
`SPC6.lsu.cid.cpq_data_out[113],
`SPC6.lsu.cid.cpq_data_out[112],
`SPC6.lsu.cid.cpq_data_out[122],
`SPC6.lsu.cid.cpq_data_out[121],
`SPC6.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC6.l2clk) begin // {
if (`SPC6.lsu.dta.wr_way[0])
dta_way0[`SPC6.lsu.dta.index_y[6:0]] <= `SPC6.lsu.dta.wrtag_y[27:0];
if (`SPC6.lsu.dta.wr_way[1])
dta_way1[`SPC6.lsu.dta.index_y[6:0]] <= `SPC6.lsu.dta.wrtag_y[27:0];
if (`SPC6.lsu.dta.wr_way[2])
dta_way2[`SPC6.lsu.dta.index_y[6:0]] <= `SPC6.lsu.dta.wrtag_y[27:0];
if (`SPC6.lsu.dta.wr_way[3])
dta_way3[`SPC6.lsu.dta.index_y[6:0]] <= `SPC6.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
`ifdef CORE_7
module ldst_lsu_c7 ();
`ifndef GATESIM
// common defines
`include "defines.vh"
`include "nas.vh"
// PCX/CPX packet defines (see :/verif/env/common/vera/include)
`include "ccx.vri"
`include "cmp.vri"
//---------------------
// Load Signals
wire load_w;
wire ldi_suppress;
wire [2:0] ldi_tid_w;
wire [5:0] ldi_tnum_w;
wire [39:0] ldi_pa_b;
reg [39:0] ldi_pa_w;
wire [1:0] ldi_size_b;
reg [1:0] ldi_size_w;
wire ldi_bld_b;
wire ldi_qld_b;
wire ldi_ldbl_b;
wire ldi_ldd_b;
wire ldi_atomic_b;
wire ldi_pf_b;
reg ldi_pf_w;
reg [7:0] ldi_itype_w;
reg [7:0] dsrc;
wire ld_miss_b;
reg ld_miss_w;
reg stb_hit_w;
wire fraw_w;
wire hit_w;
wire miss_w;
wire load_data_hit;
wire load_fill_e;
reg load_fill_m;
reg load_fill_b;
reg load_fill_w;
wire [2:0] ldf_tid_e;
reg [2:0] ldf_tid_m;
reg [2:0] ldf_tid_b;
reg [2:0] ldf_tid_w;
reg [5:0] ldf_tnum_w;
wire [39:0] ldf_pa_e;
reg [39:0] ldf_pa_m;
reg [39:0] ldf_pa_b;
reg [39:0] ldf_pa_w;
//---------------------
// Store Signals
wire unflushed_store_w;
wire store_w;
wire sti_suppress;
wire [2:0] sti_tid_b;
reg [2:0] sti_tid_w;
wire [5:0] sti_tnum_w;
wire [39:0] sti_pa_b;
reg [39:0] sti_pa_w;
wire [63:0] sti_data_w;
wire [7:0] sti_size_m;
reg [7:0] sti_size_b;
reg [7:0] sti_size_w;
wire [7:0] sti_itype_w;
reg [7:0] itype_w;
wire [63:0] sbd_st_data_b;
reg [63:0] sbd_st_data_w;
wire flip_size_b;
wire atomic_b;
wire rmo_st_b;
wire blk_inst_b;
reg blk_inst_w;
wire bst_in_prog_b;
reg bst_in_prog_w;
wire [39:0] bst_pa_b;
reg [39:0] bst_pa_w;
wire [2:0] bst_tid_b;
reg [2:0] bst_tid_w;
wire [39:0] st_pa_b;
reg [39:0] st_pa_w;
wire [2:0] st_tid_b;
reg [2:0] st_tid_w;
wire store_inv_e;
reg store_inv_m;
reg store_inv_b;
reg store_inv_w;
wire [5:0] stinv_tnum_e;
reg [5:0] stinv_tnum_m;
reg [5:0] stinv_tnum_b;
reg [5:0] stinv_tnum_w;
wire store_update_e;
reg store_update_m;
reg store_update_b;
reg store_update_w;
wire [2:0] stu_tid_e;
reg [2:0] stu_tid_m;
reg [2:0] stu_tid_b;
reg [2:0] stu_tid_w;
wire [5:0] stu_tnum_e;
reg [5:0] stu_tnum_m;
reg [5:0] stu_tnum_b;
reg [5:0] stu_tnum_w;
wire [7:0] asi_st_dequeue;
wire [7:0] st_ack_no_asi_e;
reg [7:0] st_ack_no_asi_m;
reg [7:0] st_ack_no_asi_b;
wire [7:0] store_ack_b;
reg [7:0] store_ack_w;
wire [7:0] st_ack_rmo_b;
reg [7:0] st_ack_rmo_w;
reg sta_rmo;
reg [2:0] sta_tid;
reg [5:0] sta_tnum;
reg sta_suppress [0:7]; // 1 per thread
wire st_io_asi;
wire [2:0] st_io_tid;
wire [7:0] st_data_access_e;
reg [7:0] st_data_access_m;
reg [7:0] st_data_access_b;
reg [7:0] st_data_access_w;
reg [2:0] tmp_tid;
reg [5:0] tmp_tnum;
reg [39:0] store_pa_m;
reg [39:0] store_pa_b;
reg [39:0] store_pa_w;
wire [1:0] l1_way_select;
wire [6:0] l1_index;
wire [27:0] my_way;
wire [27:0] way0;
wire [27:0] way1;
wire [27:0] way2;
wire [27:0] way3;
wire [3:0] evict_inv_e;
reg [3:0] evict_inv_m;
reg [3:0] evict_inv_b;
reg [3:0] evict_inv_w;
wire [2:0] evict_srcid_e;
reg [2:0] evict_srcid_m;
reg [2:0] evict_srcid_b;
reg [2:0] evict_srcid_w;
wire [8:0] pcx_req;
reg [8:0] pcx_req_1;
wire [129:0] pcx_data;
wire perfmon;
wire perfmon_g;
reg perfmon_m;
reg perfmon_b;
reg perfmon_w;
wire [2:0] perfmon_tid;
wire [2:0] perfmon_tid_g;
reg [2:0] perfmon_tid_m;
reg [2:0] perfmon_tid_b;
reg [2:0] perfmon_tid_w;
wire [5:0] perfmon_tnum;
wire [7:0] perfmon_mask;
wire [7:0] perfmon_mask_g;
reg [7:0] perfmon_mask_m;
reg [7:0] perfmon_mask_b;
reg [7:0] perfmon_mask_w;
wire [7:0] bst_kill;
reg [2:0] bst_kill_tid;
reg [5:0] bst_kill_tnum;
wire [7:0] stb_state0_m;
wire [7:0] stb_state1_m;
wire [7:0] stb_state2_m;
wire [7:0] stb_state3_m;
wire [7:0] stb_state4_m;
wire [7:0] stb_state5_m;
wire [7:0] stb_state6_m;
wire [7:0] stb_state7_m;
reg [7:0] stb_state0_b;
reg [7:0] stb_state1_b;
reg [7:0] stb_state2_b;
reg [7:0] stb_state3_b;
reg [7:0] stb_state4_b;
reg [7:0] stb_state5_b;
reg [7:0] stb_state6_b;
reg [7:0] stb_state7_b;
reg [7:0] stb_state0_w;
reg [7:0] stb_state1_w;
reg [7:0] stb_state2_w;
reg [7:0] stb_state3_w;
reg [7:0] stb_state4_w;
reg [7:0] stb_state5_w;
reg [7:0] stb_state6_w;
reg [7:0] stb_state7_w;
reg [7:0] stb_state;
reg stb_last;
// Copy of dtag
reg [27:0] dta_way0 [127:0];
reg [27:0] dta_way1 [127:0];
reg [27:0] dta_way2 [127:0];
reg [27:0] dta_way3 [127:0];
//---------------------
// Misc Signals
wire [2:0] mycid;
integer tstamp;
integer junk;
integer i;
initial begin // {
ldf_tnum_w = 6'b0;
dsrc = 2'b0;
sta_tid = 3'b0;
sta_tnum = 6'b0;
for (i=0; i<=7; i=i+1) begin
sta_suppress[i] = 1'b0;
end
end // }
// for debug only - allows display in Debussy
wire sta_suppress0;
wire sta_suppress1;
wire sta_suppress2;
wire sta_suppress3;
wire sta_suppress4;
wire sta_suppress5;
wire sta_suppress6;
wire sta_suppress7;
assign sta_suppress0 = sta_suppress[0];
assign sta_suppress1 = sta_suppress[1];
assign sta_suppress2 = sta_suppress[2];
assign sta_suppress3 = sta_suppress[3];
assign sta_suppress4 = sta_suppress[4];
assign sta_suppress5 = sta_suppress[5];
assign sta_suppress6 = sta_suppress[6];
assign sta_suppress7 = sta_suppress[7];
//----------------------------------------------------------
//----------------------------------------------------------
// DUT probes
assign mycid = 7;
//---------------------
// Load Issue
// If Load to IO ASIs, load issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress load_w.
assign load_w = `SPC7.lsu.dcc.ld_inst_vld_w &
~`PROBES7.asi_internal_w &
~`SPC7.lsu.dcc.flush_w &
~ldi_pf_w;
// ldxa to IO ASI are already suppressed since load_w will not assert.
// ldi_suppress is required to also suppress normal ld to IO ASI address range.
assign ldi_suppress = (ldi_pa_w[39:32] == `IO_ASI_ADDR);
assign ldi_tid_w = `SPC7.lsu.dcc.tid_w;
assign ldi_tnum_w = {mycid,ldi_tid_w};
assign ldi_size_b = `SPC7.lsu.dcc.ldst_sz_b; // 2 bits
assign ldi_atomic_b = `SPC7.lsu.dcc.atomic_b;
assign ldi_qld_b = `SPC7.lsu.dcc.quad_ldd_b;
assign ldi_ldbl_b = `SPC7.lsu.dcc_ldbl_b;
assign ldi_ldd_b = ldi_ldbl_b & !ldi_qld_b;
assign ldi_bld_b = `SPC7.lsu.dcc.dcc_blk_inst_b;
assign ldi_pf_b = `SPC7.lsu.dcc.pref_inst_b;
// pa, tid are same for LoadIssue and StoreIssue
assign ldi_pa_b = {`SPC7.lsu.tlb_pgnum[39:13],
`SPC7.lsu.lmd.lsu_va_b[12:0]};
//---------------------
// Load Fill
assign load_fill_e = `SPC7.lsu.dcc.ld_fill_e;
assign ldf_tid_e = `SPC7.lsu.cid.cid_tid;
assign ldf_pa_e = {`SPC7.lsu.lmd.lmd_fill_addr_e[39:3],3'b0};
//---------------------
// Store Issue
// blk_inst_w will suppress store_w for 1st of 9 cycles on block store.
// If Store to IO ASIs, store issue should not be sent.
// In this case, asi_internal_w is asserted and will suppress store_w.
assign unflushed_store_w = `SPC7.lsu.sbc.unflushed_store_w;
assign store_w = unflushed_store_w &
(~(`PROBES7.asi_internal_w | blk_inst_w) |
bst_in_prog_w);
assign atomic_b = `SPC7.lsu.dcc.atomic_b;
assign rmo_st_b = `SPC7.lsu.sbc_rmo_st_b;
assign blk_inst_b = `SPC7.lsu.dcc.dcc_blk_inst_b;
assign sti_tnum_w = {mycid,sti_tid_w};
assign sti_size_m = `SPC7.lsu.dcc_ldst_bmask;
// flip_size will assert if endian swap for partial store is needed
assign flip_size_b = `SPC7.lsu.dcc.pst_asi_b & `SPC7.lsu.dcc.tlb_tte_ie_b & `SPC7.lsu.dcc.tlb_tte_vld_b & `SPC7.lsu.dcc.st_inst_vld_b;
// Change itype only when control signals are valid
assign sti_itype_w = unflushed_store_w ? itype_w : sti_itype_w;
// It is correct to mix W & B stage signals for this.
// STD is a 2 cycle instruction.
// inst valid in W, data in B (1 cycle behind)
assign sti_data_w = `SPC7.lsu.sbc.std_inst_w ?
sbd_st_data_b :
sbd_st_data_w;
assign sbd_st_data_b = `SPC7.lsu.sbd_st_data_b;
// Use different pa,tid if block store
assign sti_pa_b = bst_in_prog_b ? bst_pa_b : st_pa_b;
assign sti_tid_b = bst_in_prog_b ? bst_tid_b : st_tid_b;
// stxa to IO ASI are already suppressed since store_w will not assert.
// sti_suppress is required to also suppress normal st to IO ASI address range.
assign sti_suppress = (sti_pa_w[39:32] == `IO_ASI_ADDR);
// Normal Store
assign st_pa_b = {`SPC7.lsu.tlb_pgnum[39:13],
`SPC7.lsu.lmd.lsu_va_b[12:0]};
assign st_tid_b = `SPC7.lsu.dcc.tid_b;
// Block Store
assign bst_in_prog_b = `SPC7.lsu.sbc.bst_in_prog_b;
assign bst_pa_b = {`SPC7.lsu.sbd.st_addr_b[39:3],3'b0};
assign bst_tid_b = `SPC7.lsu.sbc.bst_tid;
//---------------------
// Store Ack
assign asi_st_dequeue[7:0] = `SPC7.lsu.dcc_asi_rtn_vld[7:0] &
{8{~`SPC7.lsu.dcc_asi_rtn_rd}};
assign st_ack_no_asi_e = `SPC7.lsu.cic.cic_st_dequeue[7:0] &
~asi_st_dequeue[7:0] &
~`SPC7.lsu.cic.sbc_bst_sel[7:0];
assign st_ack_rmo_b = {`SPC7.lsu.sbs7.rmo_st_commit_p4,
`SPC7.lsu.sbs6.rmo_st_commit_p4,
`SPC7.lsu.sbs5.rmo_st_commit_p4,
`SPC7.lsu.sbs4.rmo_st_commit_p4,
`SPC7.lsu.sbs3.rmo_st_commit_p4,
`SPC7.lsu.sbs2.rmo_st_commit_p4,
`SPC7.lsu.sbs1.rmo_st_commit_p4,
`SPC7.lsu.sbs0.rmo_st_commit_p4
};
// It is possible to see 2 threads store_ack in same cycle
// (1 st_ack_no_asi & 1 st_ack_rmo)
assign store_ack_b = st_ack_no_asi_b | st_ack_rmo_b;
// cic_st_atm_cmplt is atomic store completing (same time as store ack)
// (lsu.lmc.dcl2u_err | dcl2nd_err) indicate a data_access_error condition
assign st_data_access_e = {8{(`SPC7.lsu.cic.cic_st_atm_cmplt &
(`SPC7.lsu.lmc.dcl2u_err | `SPC7.lsu.lmc.dcl2nd_err))}} &
`SPC7.lsu.cic.cic_st_dequeue[7:0];
//---------------------
// Store Inv
// Same as evict_inv_e but with cpq_evict deasserted
assign store_inv_e = `SPC7.lsu.cic_invalidate_e &
(`SPC7.lsu.cic_inv_wen_e!=0)&
~`SPC7.lsu.cic.cpq_evict &
~`SPC7.lsu.cic.cid_set_inval &
~`SPC7.lsu.cic.cic_xinval_e &
~(`SPC7.lsu.cic.cid_pkt_type[4:0] == 5'b10110);
assign stinv_tnum_e =
{`SPC7.lsu.cid.cpq_data_out[`CPX_VACK_CID],
`SPC7.lsu.cid.cid_tid};
//---------------------
// Store Update
assign store_update_e = `SPC7.lsu.cic_st_update_e;
assign stu_tid_e = `SPC7.lsu.cid.cid_tid;
assign stu_tnum_e = {mycid,stu_tid_e};
assign l1_index = {`SPC7.lsu.cid.cpq_data_out[116],
`SPC7.lsu.cid.cpq_data_out[115],
`SPC7.lsu.cid.cpq_data_out[114],
`SPC7.lsu.cid.cpq_data_out[113],
`SPC7.lsu.cid.cpq_data_out[112],
`SPC7.lsu.cid.cpq_data_out[122],
`SPC7.lsu.cid.cpq_data_out[121]
};
assign l1_way_select = `SPC7.lsu.cid_inv_vec[17:16];
//---------------------
// EvictInv
// Same as store_inv_e but with cpq_evict asserted
// LSU can invalidate 1-4 Dcache lines
assign evict_inv_e[3:0] = {4{`SPC7.lsu.cic_invalidate_e & // enable for 4 bit wen below
(`SPC7.lsu.cic_inv_wen_e!=0)&
`SPC7.lsu.cic.cpq_evict &
~`SPC7.lsu.cic.cid_set_inval &
~`SPC7.lsu.cic.cic_xinval_e}} &
{|(`SPC7.lsu.cic.evict_inv_wen[15:12]), // 4 bit field - 1 hot. Send evinv when any one set.
|(`SPC7.lsu.cic.evict_inv_wen[11:8]),
|(`SPC7.lsu.cic.evict_inv_wen[7:4]),
|(`SPC7.lsu.cic.evict_inv_wen[3:0])
};
assign evict_srcid_e = `SPC7.lsu.cid.cpq_data_out[114:112];
//---------------------
// Detect Store to IO ASI in PCX crossbar packet.
// This causes next Store Ack to be suppressed.
// Normal Store only since atomics are always to cacheable space
// Trigger on Store to crossbar.
// If Store request is retried on crossbar (due to no grant),
// then, st_io_asi will fire multiple times for the same request.
// This is OK because it just causes sta_suppress to be set multiple times.
assign pcx_req = `SPC7.spc_pcx_req_pq;
assign pcx_data = `SPC7.spc_pcx_data_pa;
assign st_io_asi = (pcx_req_1 != 9'b0) &
(pcx_data [`PCX_VALID]==1'b1) &
(pcx_data [`PCX_RQTYP]==`CCX_REQ_ST) &
(pcx_data [103:96]==`IO_ASI_ADDR); // Upper byte of 40 bit addr
assign st_io_tid = pcx_data [`PCX_TID];
assign stb_state0_m = `SPC7.lsu.sbs0.stb_state_vld[7:0];
assign stb_state1_m = `SPC7.lsu.sbs1.stb_state_vld[7:0];
assign stb_state2_m = `SPC7.lsu.sbs2.stb_state_vld[7:0];
assign stb_state3_m = `SPC7.lsu.sbs3.stb_state_vld[7:0];
assign stb_state4_m = `SPC7.lsu.sbs4.stb_state_vld[7:0];
assign stb_state5_m = `SPC7.lsu.sbs5.stb_state_vld[7:0];
assign stb_state6_m = `SPC7.lsu.sbs6.stb_state_vld[7:0];
assign stb_state7_m = `SPC7.lsu.sbs7.stb_state_vld[7:0];
//---------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
assign load_data_hit = load_w && (hit_w | fraw_w);
assign ld_miss_b = `SPC7.lsu.dcc.dcc_ld_miss_b;
assign fraw_w = `SPC7.lsu.lmc.ld_raw_bypass_w;
assign hit_w = ~ld_miss_w & ~stb_hit_w;
assign miss_w = ~fraw_w & (ld_miss_w | stb_hit_w);
//---------------------
// Load Pop
assign perfmon_g = `SPC7.lsu.lsu_perfmon_trap_g;
assign perfmon_tid_g = `SPC7.lsu.lsu_dcerr_tid_g;
// perfmon_mask will not fire if trap is not enabled or higher priority trap is taken.
assign perfmon_mask_g = {`SPC7.tlu.fls1.pil_mask_15[3:0], `SPC7.tlu.fls0.pil_mask_15[3:0]} &
~{8 {`SPC7.lsu_dcl2u_err_g | `SPC7.lsu_dcl2nd_err_g}};
assign perfmon = perfmon_w;
assign perfmon_tid = perfmon_tid_w;
assign perfmon_tnum = {mycid,perfmon_tid_w};
assign perfmon_mask = perfmon_mask_w;
//---------------------
// Store Pop
assign bst_kill = {`SPC7.lsu.sbs7.bst_kill,
`SPC7.lsu.sbs6.bst_kill,
`SPC7.lsu.sbs5.bst_kill,
`SPC7.lsu.sbs4.bst_kill,
`SPC7.lsu.sbs3.bst_kill,
`SPC7.lsu.sbs2.bst_kill,
`SPC7.lsu.sbs1.bst_kill,
`SPC7.lsu.sbs0.bst_kill};
//----------------------------------------------------------
//----------------------------------------------------------
always @ (posedge `SPC7.l2clk) begin // {
tstamp = `TOP.core_cycle_cnt - 1;
//------------------------------
// Pipeline from B to W
ldi_pa_w <= ldi_pa_b;
ld_miss_w <= ld_miss_b;
stb_hit_w <= `SPC7.lsu.stb_cam_hit;
ldi_pf_w <= ldi_pf_b;
ldi_size_w <= ldi_size_b;
load_fill_m <= load_fill_e;
load_fill_b <= load_fill_m;
load_fill_w <= load_fill_b;
ldf_tid_m <= ldf_tid_e;
ldf_tid_b <= ldf_tid_m;
ldf_tid_w <= ldf_tid_b;
ldf_pa_m <= ldf_pa_e;
ldf_pa_b <= ldf_pa_m;
ldf_pa_w <= ldf_pa_b;
sti_size_b <= sti_size_m;
sti_size_w <= (flip_size_b) ? {sti_size_b[0],sti_size_b[1],sti_size_b[2],sti_size_b[3],
sti_size_b[4],sti_size_b[5],sti_size_b[6],sti_size_b[7]}
: sti_size_b;
sti_pa_w <= sti_pa_b;
sti_tid_w <= sti_tid_b;
st_ack_no_asi_m <= st_ack_no_asi_e;
st_ack_no_asi_b <= st_ack_no_asi_m;
st_data_access_m <= st_data_access_e;
st_data_access_b <= st_data_access_m;
st_data_access_w <= st_data_access_b;
store_ack_w <= store_ack_b;
store_update_m <= store_update_e;
store_update_b <= store_update_m;
store_update_w <= store_update_b;
store_inv_m <= store_inv_e;
store_inv_b <= store_inv_m;
store_inv_w <= store_inv_b;
stinv_tnum_m <= stinv_tnum_e;
stinv_tnum_b <= stinv_tnum_m;
stinv_tnum_w <= stinv_tnum_b;
st_ack_rmo_w <= st_ack_rmo_b;
stu_tid_m <= stu_tid_e;
stu_tid_b <= stu_tid_m;
stu_tid_w <= stu_tid_b;
stu_tnum_m <= stu_tnum_e;
stu_tnum_b <= stu_tnum_m;
stu_tnum_w <= stu_tnum_b;
store_pa_b <= store_pa_m;
store_pa_w <= store_pa_b;
bst_in_prog_w <= bst_in_prog_b;
blk_inst_w <= blk_inst_b;
sbd_st_data_w <= sbd_st_data_b;
evict_inv_m <= evict_inv_e;
evict_inv_b <= evict_inv_m;
evict_inv_w <= evict_inv_b;
evict_srcid_m <= evict_srcid_e;
evict_srcid_b <= evict_srcid_m;
evict_srcid_w <= evict_srcid_b;
pcx_req_1 <= pcx_req;
stb_state0_b <= stb_state0_m;
stb_state1_b <= stb_state1_m;
stb_state2_b <= stb_state2_m;
stb_state3_b <= stb_state3_m;
stb_state4_b <= stb_state4_m;
stb_state5_b <= stb_state5_m;
stb_state6_b <= stb_state6_m;
stb_state7_b <= stb_state7_m;
stb_state0_w <= stb_state0_b;
stb_state1_w <= stb_state1_b;
stb_state2_w <= stb_state2_b;
stb_state3_w <= stb_state3_b;
stb_state4_w <= stb_state4_b;
stb_state5_w <= stb_state5_b;
stb_state6_w <= stb_state6_b;
stb_state7_w <= stb_state7_b;
perfmon_m <= perfmon_g;
perfmon_b <= perfmon_m;
perfmon_w <= perfmon_b;
perfmon_tid_m <= perfmon_tid_g;
perfmon_tid_b <= perfmon_tid_m;
perfmon_tid_w <= perfmon_tid_b;
perfmon_mask_m <= perfmon_mask_g;
perfmon_mask_b <= perfmon_mask_m;
perfmon_mask_w <= perfmon_mask_b;
//----------------------------------------------------------
// Calculate pa for STUPDATE and STINV
// Moved this into the always block to avoid the constant
// probing of the dtag memory structure.
if (store_inv_e | store_update_e) begin // {
store_pa_m[2:0] <= 3'b000;
store_pa_m[10:3] <= {`SPC7.lsu.cid.cpq_data_out[116],
`SPC7.lsu.cid.cpq_data_out[115],
`SPC7.lsu.cid.cpq_data_out[114],
`SPC7.lsu.cid.cpq_data_out[113],
`SPC7.lsu.cid.cpq_data_out[112],
`SPC7.lsu.cid.cpq_data_out[122],
`SPC7.lsu.cid.cpq_data_out[121],
`SPC7.lsu.cid.cpq_data_out[104]
};
store_pa_m[38:11] <= (l1_way_select==2'h0) ? dta_way0[l1_index] :
(l1_way_select==2'h1) ? dta_way1[l1_index] :
(l1_way_select==2'h2) ? dta_way2[l1_index] : dta_way3[l1_index];
store_pa_m[39] <= 1'b0; // Only memory stores get inv/update
end // }
// After Store to IO ASI is detected at StI time, suppress the next Store Ack
// There is only 1 store to IO ASI active at one time per thread because
// that is all the LSU allows.
if (st_io_asi) begin
sta_suppress [st_io_tid] <= 1'b1;
end
case ({ldi_atomic_b,ldi_bld_b,ldi_ldd_b,ldi_qld_b,ldi_pf_b})
5'b00000: ldi_itype_w <= `ITYPE_LOAD;
5'b00001: ldi_itype_w <= `ITYPE_PREFETCH;
5'b00010: ldi_itype_w <= `ITYPE_QUAD_LOAD;
5'b00100: ldi_itype_w <= `ITYPE_DOUBLE_LOAD;
5'b01000: ldi_itype_w <= `ITYPE_BLOCK_LOAD;
5'b10000: ldi_itype_w <= `ITYPE_ATOMIC;
default: ldi_itype_w <= `ITYPE_NO; // Illegal
endcase
case ({atomic_b,rmo_st_b,bst_in_prog_b})
3'b000: itype_w <= `ITYPE_STORE;
3'b010: itype_w <= `ITYPE_BLK_INIT_ST;
3'b011: itype_w <= `ITYPE_BLOCK_STORE;
3'b100: itype_w <= `ITYPE_ATOMIC;
3'b001,
3'b101,
3'b110,
3'b111: itype_w <= `ITYPE_NO; // Illegal
endcase
//----------------------------------------------------------
//----------------------------------------------------------
// Load Issue
// Load Issue must be before Store Issue for atomic
if (load_w) begin // {
if (ldi_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h size=%h typ=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_ISSUE,ldi_tnum_w,ldi_pa_w,ldi_size_w,ldi_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDISSU tid=%d pa=%h Suppress for IO ASI",mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_LOAD tid=%d pa=%h ts=%0d (LSU - W stage)",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Data (hit only) (See ldst_l2.v for Load Data - miss)
if (load_data_hit) begin // {
dsrc = hit_w ? `DSRC_L1 : `DSRC_STB;
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldi_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDDATA tid=%d pa=%h dsrc=%0h ts=%0d",
mycid,ldi_tid_w,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
junk = $sim_send(`PLI_MEM_LD_DATA,ldi_tnum_w,ldi_pa_w,dsrc,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Ack
//
// Store Ack cmd must be sent before Store Inv, Store Update for NAS
// Store Ack & Store Update will be in the same timestamp
if (store_ack_w != 8'b0) begin // {
for (i=0; i<=7; i=i+1) begin // {
if (store_ack_w[i]) begin // {
sta_tid = i[2:0];
sta_tnum = {mycid,sta_tid};
sta_rmo = st_ack_rmo_w[i];
if (sta_suppress[sta_tid]==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
// It is possible for 2 Stores it be in flight because of the delay from CPQ push & pop.
// So, make sure Bench is suppressing the correct Store.
case (sta_tid)
3'h0: stb_state=stb_state0_w;
3'h1: stb_state=stb_state1_w;
3'h2: stb_state=stb_state2_w;
3'h3: stb_state=stb_state3_w;
3'h4: stb_state=stb_state4_w;
3'h5: stb_state=stb_state5_w;
3'h6: stb_state=stb_state6_w;
3'h7: stb_state=stb_state7_w;
default:
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. Should never execute case default",mycid,sta_tid);
endcase
// If stb_state has only 1 bit asserted, then suppress the STACK. Otherwise, send the STACK.
case (stb_state) // {
8'b0000_0000: begin
`PR_ERROR ("pli_ldst", `ERROR,
"C%0d T%0d PLI_MEM_XXX Bench Error. stb_state should not be 8'b0",
mycid,sta_tid);
end
8'b0000_0001,
8'b0000_0010,
8'b0000_0100,
8'b0000_1000,
8'b0001_0000,
8'b0010_0000,
8'b0100_0000,
8'b1000_0000: stb_last = 1'b1;
default: stb_last = 1'b0;
endcase // }
if (stb_last==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sta_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d rmo=%0h ts=%0d",
mycid,sta_tid,sta_tnum,sta_rmo,tstamp);
junk = $sim_send(`PLI_MEM_ST_ACK,sta_tnum,sta_rmo,tstamp);
end // }
end // }
else begin // {
sta_suppress[sta_tid] <= 1'b0;
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STACK tid=%d Suppress for IO ASI",mycid,sta_tid,sta_tnum);
end // }
end // }
end // if (store_ack_w[i]) }
end // for }
end // if (store_ack_w) }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Inv
if (store_inv_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stinv_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_STINV tid=%d pa=%h cid=%h ts=%0d",
mycid,stinv_tnum_w,store_pa_w,mycid,tstamp);
junk = $sim_send(`PLI_MEM_ST_INV,mycid,stinv_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Update
if (store_update_w) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[stu_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STUP tid=%d pa=%h ts=%0d",
mycid,stu_tid_w,stu_tnum_w,store_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_UPDATE,stu_tnum_w,store_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Fill
if (load_fill_w) begin // {
ldf_tnum_w = {mycid,ldf_tid_w};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[ldf_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDFILL tid=%d pa=%h ts=%0d",
mycid,ldf_tid_w,ldf_tnum_w,ldf_pa_w,tstamp);
junk = $sim_send(`PLI_MEM_LD_FILL,ldf_tnum_w,ldf_pa_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Issue
if (store_w) begin // {
if (sti_suppress==1'b0) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[sti_tnum_w]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h data=%h sz=%h typ=%0h ts=%0d",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
junk = $sim_send(`PLI_MEM_ST_ISSUE,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,sti_itype_w,tstamp);
end // }
end // }
else begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STISSU tid=%d pa=%h Suppress for IO ASI",mycid,sti_tid_w,sti_tnum_w,sti_pa_w);
end // }
if (`PARGS.show_memop_on) begin // {
`PR_NORMAL ("pli_ldst", `NORMAL,
"C%0d T%0d MEMOP_STORE tid=%d pa=%h data=%h sz=%h ts=%0d (LSU - W stage)",
mycid,sti_tid_w,sti_tnum_w,sti_pa_w,sti_data_w,sti_size_w,tstamp);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// EvictInv
// Send 1-4 EvictInv messages per cycle - based on how many Dcache lines were invalidated.
for (i=0; i<=3; i=i+1) begin // {
if (evict_inv_w[i]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d PLI_MEM_EVINV cid=%d srcid=%0d ts=%0d",
mycid,mycid,evict_srcid_w,tstamp);
junk = $sim_send(`PLI_MEM_EVICT_INV,mycid,evict_srcid_w,tstamp);
end // }
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Load Pop - special case
// This is required in case of a performance monitor trap due to L2 miss.
// In this case, the trap is not indicated until after the Load pkt returns to the LSU.
// ldst_sync has already sent LDISSUE and LDDATA to Riesling. But, the Load is not executed.
// Load Pop tells Riesling to pop the LDISSUE,LDDATA off of its queues.
if (perfmon & perfmon_mask[perfmon_tid]) begin // {
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[perfmon_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_LDPOP tid=%d ts=%0d",
mycid,perfmon_tid,perfmon_tnum,tstamp);
junk = $sim_send(`PLI_MEM_LD_POP,perfmon_tnum);
end // }
end // }
//----------------------------------------------------------
//----------------------------------------------------------
// Store Pop - special cases
// This is required in case of a FRF error trap (internal_proc_error) on a Block Store.
// In this case, the trap is not indicated until after the 8 STISSUE has been sent to Riesling.
// But, the Store is not executed.
// Store Pop tells Riesling to pop the 8 STISSUE off of its queues.
if (bst_kill!==8'b0) begin // {
for (i=0;i<=7;i=i+1) begin
if (bst_kill[i]==1'b1) begin
bst_kill_tid = i;
bst_kill_tnum = {mycid,bst_kill_tid};
if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[bst_kill_tnum]) begin // {
`PR_INFO ("pli_ldst", `INFO,
"C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
mycid,bst_kill_tid,bst_kill_tnum,tstamp);
junk = $sim_send(`PLI_MEM_ST_POP,bst_kill_tnum);
end // }
end
end
end // }
//--------------------
// This is required for data_access_error on atomic. In this case, Riesling only cleans up the Load,
// but doesn't know it is an atomic so Riesling doesn't clean up the store in its buffers.
// The STPOP tells Riesling to clear the newest Store from the buffers.
// It is possible to have older Stores in-flight but not newer Stores in-flight.
// if (st_data_access_w != 8'b0) begin // {
//
// for (i=0; i<=7; i=i+1) begin // {
// if (st_data_access_w[i]) begin // {
// tmp_tid = i[2:0];
// tmp_tnum = {mycid,tmp_tid};
//
// if (`PARGS.nas_check_on && `PARGS.ldst_sync_on && `PARGS.th_check_enable[tmp_tnum]) begin // {
// `PR_INFO ("pli_ldst", `INFO,
// "C%0d T%0d PLI_MEM_STPOP tid=%d ts=%0d",
// mycid,tmp_tid,tmp_tnum,tstamp);
// junk = $sim_send(`PLI_MEM_ST_POP,tmp_tnum);
// end // }
// end // } if st_data_access[i]
// end // } for
// end // } if st_data_access
end // always }
//----------------------------------------------------------
// Need to model the D arrays to get PA's for store updates and invalidates
always @ (negedge `SPC7.l2clk) begin // {
if (`SPC7.lsu.dta.wr_way[0])
dta_way0[`SPC7.lsu.dta.index_y[6:0]] <= `SPC7.lsu.dta.wrtag_y[27:0];
if (`SPC7.lsu.dta.wr_way[1])
dta_way1[`SPC7.lsu.dta.index_y[6:0]] <= `SPC7.lsu.dta.wrtag_y[27:0];
if (`SPC7.lsu.dta.wr_way[2])
dta_way2[`SPC7.lsu.dta.index_y[6:0]] <= `SPC7.lsu.dta.wrtag_y[27:0];
if (`SPC7.lsu.dta.wr_way[3])
dta_way3[`SPC7.lsu.dta.index_y[6:0]] <= `SPC7.lsu.dta.wrtag_y[27:0];
end // always }
//----------------------------------------------------------
`endif
endmodule
`endif
//----------------------------------------------------------
//----------------------------------------------------------