/******************************************************************************/
/* */
/* Copyright (c) 1999 Sun Microsystems, Inc. All rights reserved. */
/* */
/* The contents of this file are subject to the current version of the Sun */
/* Community Source License, microSPARCII ("the License"). You may not use */
/* this file except in compliance with the License. You may obtain a copy */
/* of the License by searching for "Sun Community Source License" on the */
/* World Wide Web at http://www.sun.com. See the License for the rights, */
/* obligations, and limitations governing use of the contents of this file. */
/* */
/* Sun Microsystems, Inc. has intellectual property rights relating to the */
/* technology embodied in these files. In particular, and without limitation, */
/* these intellectual property rights may include one or more U.S. patents, */
/* foreign patents, or pending applications. */
/* */
/* Sun, Sun Microsystems, the Sun logo, all Sun-based trademarks and logos, */
/* Solaris, Java and all Java-based trademarks and logos are trademarks or */
/* registered trademarks of Sun Microsystems, Inc. in the United States and */
/* other countries. microSPARC is a trademark or registered trademark of */
/* SPARC International, Inc. All SPARC trademarks are used under license and */
/* are trademarks or registered trademarks of SPARC International, Inc. in */
/* the United States and other countries. Products bearing SPARC trademarks */
/* are based upon an architecture developed by Sun Microsystems, Inc. */
/* */
/******************************************************************************/
// @(#)qcore_ctl.v 1.31 12/7/93
//
// **************************************************************
// High-level verilog model of QCORE control
//
// This module contains 3 main sections that control and regulate
// the FP Queue:
// 1. FQ load control
// 2. FQ issue control and dependency checks
// 3. FQ writeback control
// **************************************************************
module qcore_ctl
(ss_clock, ss_reset, ext_flush, ext_hold, FpBusyPhi2,
fpm_unfin, fpop_e, rs1_dbl_e, rs1_used_e, rd_dbl_e,
unimpl_fpop_e, mul_fpop_d, notrap_writeback, exemode,
exemode_two, stdfq_r_noexc, opf5_q0,
ir_rs1_e, ir_rs2_e, fq_ir_0, fq_ir_1, fq_ir_2,
fq_rd_used, fq_rs1_used, fq_rs1_dbl,
fq_qne, fq_ld_nval, fq_rd_dbl, fq_src_sel,
fpm_start, fpp_fop, fpp_ld, fpp_reset,
qne, qne_r, qne_fhold, fq_empty_next, fq_full_next,
fq_full, fq_started_0, fq_type_0, fcmp_q1q2, fcmp_q0,
funimp_in_q, done_q0, writeback_q0, wbq0_fhold, fq_update,
unfin_fsmuld, fload_wait_w, res_select, ss_scan_mode);
input ss_clock
, // FPU clock
ss_reset
, // FPU reset
ext_flush
, // FPU flush (IU trap)
ext_hold
, // IU pipeline held (frozen)
FpBusyPhi2
, // Meiko FPP busy signal
fpm_unfin
, // mul unfinished signal
fpop_e
, // FPop in E-stage (includes fold_annul_e term)
rs1_dbl_e
, // FPop rs1 field size
rs1_used_e
, // FPop rs1 field used
rd_dbl_e
, // FPop rd field size
unimpl_fpop_e
, // unimplemented FPop in E-stage
mul_fpop_d
, // (FMULs, FMULd, or FsMULd) in decode
notrap_writeback
, // writeback q0 if no fpu exception
exemode
, // execute mode
exemode_two
, // exemode delayed 2 cycles
stdfq_r_noexc
, // stdfq in R-stage, no data access exception
opf5_q0
, // opf[5] of fq0, indicates fsmuld
ss_scan_mode
;
input [4:0] ir_rs1_e
, // E-stage instr. reg. field outputs
ir_rs2_e
;
input [15:0] fq_ir_0
, // output of FQ instruction registers
fq_ir_1
,
fq_ir_2
;
input [2:0] fq_rd_used
, // register field used
fq_rs1_used
,
fq_rs1_dbl
;
output [2:0] fq_qne
; // FQ not empty status bits
output [2:0] fq_ld_nval
, // FQ load controls, not validated
fq_rd_dbl
; // size of FQ rd field
output [1:0] fq_src_sel
; // FQ instr mux selects
output fpm_start
, // start signal for the multiplier
fpp_fop
, // FpOp for Meiko FPP (start instruction)
fpp_ld
, // FpLd for Meiko FPP (load operands)
fpp_reset
, // when an FPop needs to be flushed from
// the pipeline, the Meiko FPP core also needs
// to be reset
qne
, // FQ not empty status bit
qne_r
, // indicates FPop has reached R-stage
qne_fhold
, // qne signal for the fhold logic
fq_empty_next
, // only 1 entry used
fq_full_next
, // fq has only 1 entry available
fq_full
, // fq is full
fq_started_0
, // launch status of fq0
fq_type_0
, // type of fq0 (1=mul, 0=meiko)
fcmp_q1q2
, // fcmp in q1 or q2
fcmp_q0
, // fcmp in q0
funimp_in_q
, // unimplemented FPop in any fq
done_q0
, // FPop in q0 (if any) has finished
writeback_q0
, // result writeback signal
wbq0_fhold
, // writeback_q0 for fhold logic
fq_update
, // update fifo for writeback or stdfq
unfin_fsmuld
, // unfinished for fsmuld
fload_wait_w
; // FPop is currently executing, and may trap
output [1:0] res_select
; // result mux selects
assign fpp_reset = ss_reset ;
wire qne_e
= 1'b0 ;
wire qne_w
= 1'b0 ;
wire [2:0] fq_qne, fq_qne_val
;
wire [2:0] fq_started
, fq_type
, fq_unimp
;
wire issue_q0_nval
, issue_q1_nval
, issue_q2_nval
;
wire issue_q0_x
, issue_q1_x
, issue_q2_x
;
wire issue_q0_y
, issue_q1_y
, issue_q2_y
;
wire fpm_busy
, restart_mul
, fq_update, fast_fq_update
;
wire cancel_fpop
;
wire reset_l
= ~ss_reset ;
// wire resetflush = (~ext_hold & ext_flush) | ss_reset ;
// wire resetflush_l = (ext_hold | ~ext_flush) & ~ss_reset ;
ME_O2A1 iu_hold_gate_24 (.a(ext_hold), .b(~ext_flush), .c(reset_l),
.z(resetflush_l
) );
wire no_holds
= ~ext_hold ;
wire no_flush
= ~ext_flush ;
wire no_hold_no_flush
= ~ext_hold & ~ext_flush ;
// **********************************************************************
wire [4:0] fq_rd_q0
, fq_rs1_q0
, fq_rs2_q0
; // FQ instr. reg. fields
wire [4:0] fq_rd_q1
, fq_rs1_q1
, fq_rs2_q1
;
wire [4:0] fq_rd_q2
, fq_rs1_q2
, fq_rs2_q2
;
wire fq_op3_0_q0
, fq_op3_0_q1
, fq_op3_0_q2
;
assign {fq_rd_q0, fq_op3_0_q0, fq_rs1_q0, fq_rs2_q0} = fq_ir_0[15:0] ;
assign {fq_rd_q1, fq_op3_0_q1, fq_rs1_q1, fq_rs2_q1} = fq_ir_1[15:0] ;
assign {fq_rd_q2, fq_op3_0_q2, fq_rs1_q2, fq_rs2_q2} = fq_ir_2[15:0] ;
// **********************************************************************
// miscellaneous ctl signals
ME_FDS2LP fmul_e_ff(.q(mul_fpop_e
), .cp(ss_clock), .cr(resetflush_l),
.d(mul_fpop_d), .ld(~ext_hold) );
// Meiko busy
ME_FD1P fpp_busy_ff (.q(me_busy_1
), .cp(ss_clock), .d(FpBusyPhi2) );
wire fpp_busy
= me_busy_1 | fpp_ld ;
// **********************************************************************
// During normal operation, QI is loaded when the pipe moves from E-stage
// to W-stage; a trap that occurs while the FPop is in W-stage will flush
// that queue entry.
// **********************************************************************
wire decode_zero
= ~fq_qne[2] & ~fq_qne[1] & ~fq_qne[0] ; // 000
wire decode_one
= ~fq_qne[2] & ~fq_qne[1] & fq_qne[0] ; // 001
wire decode_two
= ~fq_qne[2] & fq_qne[1] & fq_qne[0] ; // 011
wire decode_three
= fq_qne[2] & fq_qne[1] & fq_qne[0] ; // 111
// FQ has 0 entries
wire zero_qne
= fq_update ? decode_one : decode_zero ;
wire fast_zero_qne
= fast_fq_update ? decode_one : decode_zero ;
assign qne_fhold = ~((fq_update | cancel_fpop) ? decode_one : decode_zero) ;
// FQ has 1 entry
wire one_qne
= fq_update ? decode_two : decode_one ;
wire fast_one_qne
= fast_fq_update ? decode_two : decode_one ;
// FQ has 2 entries
wire two_qne
= fq_update ? decode_three : decode_two ;
wire fast_two_qne
= fast_fq_update ? decode_three : decode_two ;
// FQ has 3 entries
wire three_qne
= ~fq_update & decode_three ;
assign fq_empty_next = decode_one ;
assign fq_full_next = two_qne & ~cancel_fpop ;
assign fq_full = three_qne & ~cancel_fpop ;
assign qne = ~zero_qne ;
assign qne_r = fq_qne_val[0] ;
// **********************************************************************
// FQ load controls
// FPop in E, FPU in exemode
wire fpop_nval_e
= fpop_e & exemode ;
wire [2:0] fq_ld_nh
, fq_ld_nval, fast_fq_ld_nval
, fq_ld
, fq_ld_ctl
;
wire [2:0] fq_ld_ctl_l
;
// fq_ld terms are duplicated
// in fp_qst for speed
assign fq_ld_nval[0] = fpop_nval_e & zero_qne ;
assign fq_ld_nval[1] = fpop_nval_e & one_qne ;
assign fq_ld_nval[2] = fpop_nval_e & two_qne ;
assign fast_fq_ld_nval[0] = fpop_nval_e & fast_zero_qne ;
assign fast_fq_ld_nval[1] = fpop_nval_e & fast_one_qne ;
assign fast_fq_ld_nval[2] = fpop_nval_e & fast_two_qne ;
assign fq_ld_nh[0] = fq_ld_nval[0] & no_flush ;
assign fq_ld_nh[1] = fq_ld_nval[1] & no_flush ;
assign fq_ld_nh[2] = fq_ld_nval[2] & no_flush ;
ME_NOR2_B iu_hold_gate_1 (.a(ext_hold), .b(~fq_ld_nh[0]), .z(fq_ld[0]) );
ME_NOR2_B iu_hold_gate_2 (.a(ext_hold), .b(~fq_ld_nh[1]), .z(fq_ld[1]) );
ME_NOR2_B iu_hold_gate_3 (.a(ext_hold), .b(~fq_ld_nh[2]), .z(fq_ld[2]) );
// fq_ld_ctl[x] = fq_ld[x] | fq_update ;
ME_O2A1 iu_hold_gate_4 (.a(ext_hold), .b(~fq_ld_nh[0]), .c(~fq_update),
.z(fq_ld_ctl_l[0]) );
ME_O2A1 iu_hold_gate_5 (.a(ext_hold), .b(~fq_ld_nh[1]), .c(~fq_update),
.z(fq_ld_ctl_l[1]) );
ME_O2A1 iu_hold_gate_6 (.a(ext_hold), .b(~fq_ld_nh[2]), .c(~fq_update),
.z(fq_ld_ctl_l[2]) );
assign fq_ld_ctl[2:0] = ~fq_ld_ctl_l[2:0];
// **********************************************************************
// Operations supported by the qne logic:
// 1. hold (do nothing)
// 2. load, no update (fq load)
// 3. update, no load (fq update==writeback==shift fifo)
// 4. load and update (simultaneous fq load and writeback)
wire [2:0] in_qne
;
// in_qne[0] = fq_ld[0] | fq_qne[1] ;
ME_AI2O1_C iu_hold_gate_7 (.a(fq_ld_nh[0]), .b(ext_hold), .c(fq_qne[1]),
.z(in_qne[0]) );
// in_qne[1] = fq_ld[1] | fq_qne[2] ;
ME_AI2O1_C iu_hold_gate_8 (.a(fq_ld_nh[1]), .b(ext_hold), .c(fq_qne[2]),
.z(in_qne[1]) );
assign in_qne[2] = fq_ld[2] ;
// qne may be cleared in
// W-stage by ext_flush
wire [2:0] clear_qne
, clear_qne_x
;
assign clear_qne_x[0] = reset_l & (no_flush | fq_qne_val[0]) ;
assign clear_qne_x[1] = reset_l & (no_flush | fq_qne_val[1]) ;
assign clear_qne_x[2] = reset_l & (no_flush | fq_qne_val[2]) ;
ME_A2O1_B iu_hold_gate_9 (.a( ext_hold ), .b( reset_l ), .c( clear_qne_x[0] ),
.z( clear_qne[0] ) );
ME_A2O1_B iu_hold_gate_10 (.a( ext_hold ), .b( reset_l ), .c( clear_qne_x[1] ),
.z( clear_qne[1] ) );
ME_A2O1_B iu_hold_gate_11 (.a( ext_hold ), .b( reset_l ), .c( clear_qne_x[2] ),
.z( clear_qne[2] ) );
wire [2:0] ld_qne
;
assign ld_qne[2:0] = fq_ld_ctl[2:0] ;
ME_FDS2LP qne_0_ff(.q(fq_qne[0]), .cp(ss_clock), .cr(clear_qne[0]),
.d(in_qne[0]), .ld(ld_qne[0]) );
ME_FDS2LP qne_1_ff(.q(fq_qne[1]), .cp(ss_clock), .cr(clear_qne[1]),
.d(in_qne[1]), .ld(ld_qne[1]) );
ME_FDS2LP qne_2_ff(.q(fq_qne[2]), .cp(ss_clock), .cr(clear_qne[2]),
.d(in_qne[2]), .ld(ld_qne[2]) );
// **********************************************************************
// qne valid until cleared.
// used to determine whether or not an FPop can trap
// (don't want an FPop to "shoot itself in the foot"
// by trapping itself.)
wire [2:0] in_qne_val
;
// in_qne_val[0] = no_hold_no_flush ?
// (fq_update ? fq_qne[1] : fq_qne[0]) : fq_qne_val[1] ;
//
// in_qne_val[0] = (fq_qne_val[1] & ext_hold) |
// (in_qne_val_0_y & ~ext_hold) | in_qne_val_0_z ;
wire in_qne_val_0_y
= ~ext_flush & (fq_update ? fq_qne[1] : fq_qne[0]) ;
wire in_qne_val_0_z
= ext_flush & fq_qne_val[1] ;
ME_AI22O1_C iu_hold_gate_25 (.a1( in_qne_val_0_y ), .a2( ext_hold ),
.b1( fq_qne_val[1] ), .b2( ext_hold ),
.c( in_qne_val_0_z ), .z( in_qne_val[0] ) );
// in_qne_val[1] = no_hold_no_flush ?
// (fq_update ? fq_qne[2] : fq_qne[1]) : fq_qne_val[2] ;
wire in_qne_val_1_y
= ~ext_flush & (fq_update ? fq_qne[2] : fq_qne[1]) ;
wire in_qne_val_1_z
= ext_flush & fq_qne_val[2] ;
ME_AI22O1_C iu_hold_gate_26 (.a1( in_qne_val_1_y ), .a2( ext_hold ),
.b1( fq_qne_val[2] ), .b2( ext_hold ),
.c( in_qne_val_1_z ), .z( in_qne_val[1] ) );
// in_qne_val[2] = no_hold_no_flush & ~fq_update & fq_qne[2] ;
ME_NOR4 iu_hold_gate_27 (.a( ext_hold ), .b( ext_flush ), .c( fq_update ),
.d( ~fq_qne[2] ), .z( in_qne_val[2] ) );
wire [2:0] ld_qne_val
;
wire ld_qne_val_l
;
// ld_qne_val[0] = no_hold_no_flush | fq_update ;
ME_O2A1 iu_hold_gate_28 (.a( ext_hold ), .b( ext_flush ), .c( ~fq_update ),
.z( ld_qne_val_l ) );
assign ld_qne_val[0] = ~ld_qne_val_l;
assign ld_qne_val[1] = ~ld_qne_val_l;
assign ld_qne_val[2] = ~ld_qne_val_l;
ME_FDS2LP qne_val_0_ff(.q(fq_qne_val[0]), .cp(ss_clock), .cr(clear_qne[0]),
.d(in_qne_val[0]), .ld(ld_qne_val[0]) );
ME_FDS2LP qne_val_1_ff(.q(fq_qne_val[1]), .cp(ss_clock), .cr(clear_qne[1]),
.d(in_qne_val[1]), .ld(ld_qne_val[1]) );
ME_FDS2LP qne_val_2_ff(.q(fq_qne_val[2]), .cp(ss_clock), .cr(clear_qne[2]),
.d(in_qne_val[2]), .ld(ld_qne_val[2]) );
// an FPop that traps in W-stage should be flushed out
// (may_cancel term added to fix bug #593)
// (would be prettier to use fq_update as a mux
// select, but the equation below works and makes
// the gate fix easier)
wire may_cancel
= ( fq_update & fq_qne[1] & ~fq_qne_val[1] ) |
( fq_qne[0] & ~fq_qne_val[0] );
wire cancel_fpop_in
= ext_flush & may_cancel & exemode ;
ME_FD1P cancel_ff (.q(cancel_fpop), .cp(ss_clock), .d(cancel_fpop_in) );
// **********************************************************************
// FPop type (1=mul, 0=meiko)
wire [2:0] in_fq_type
;
// in_fq_type[0] = fq_ld[0] ? (mul_fpop_e & ~restart_mul) :
// (fq_type[1] & ~restart_mul) ;
wire in_fq_type_0_x
= fq_type[1] & ~restart_mul;
wire in_fq_type_0_y
= fq_ld_nh[0] & (mul_fpop_e & ~restart_mul);
wire in_fq_type_0_z
= ~fq_ld_nh[0] & (fq_type[1] & ~restart_mul);
ME_AI22O1_C iu_hold_gate_29 (.a1( in_fq_type_0_y ), .a2( ext_hold ),
.b1( in_fq_type_0_x ), .b2( ext_hold ),
.c( in_fq_type_0_z ), .z( in_fq_type[0] ) );
// in_fq_type[1] = fq_ld[1] ? mul_fpop_e : fq_type[2] ;
wire in_fq_type_1_y
= fq_ld_nh[1] & mul_fpop_e ;
wire in_fq_type_1_z
= ~fq_ld_nh[1] & fq_type[2];
ME_AI22O1_C iu_hold_gate_30 (.a1( in_fq_type_1_y ), .a2( ext_hold ),
.b1( fq_type[2] ), .b2( ext_hold ),
.c( in_fq_type_1_z ), .z( in_fq_type[1] ) );
assign in_fq_type[2] = mul_fpop_e ;
wire [2:0] ld_fq_type
;
wire ld_fq_type_0_l
;
// ld_fq_type[0] = fq_ld[0] | fq_update | restart_mul ;
ME_O2A1 iu_hold_gate_21 (.a( ext_hold ), .b( ~fq_ld_nh[0] ),
.c( ~(fq_update | restart_mul) ),
.z( ld_fq_type_0_l ));
assign ld_fq_type[0] = ~ld_fq_type_0_l ;
assign ld_fq_type[2:1] = fq_ld_ctl[2:1] ;
ME_FDS2LP fq_type_0_ff(.q(fq_type[0]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_type[0]), .ld(ld_fq_type[0]) );
ME_FDS2LP fq_type_1_ff(.q(fq_type[1]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_type[1]), .ld(ld_fq_type[1]) );
ME_FDS2LP fq_type_2_ff(.q(fq_type[2]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_type[2]), .ld(ld_fq_type[2]) );
assign fq_type_0 = fq_type[0] ;
// **********************************************************************
// FPop unimplemented
wire [2:0] in_fq_unimp
;
// in_fq_unimp[0] = fq_ld[0] ? unimpl_fpop_e : fq_unimp[1] ;
wire in_fq_unimp_0_y
= fq_ld_nh[0] & unimpl_fpop_e ;
wire in_fq_unimp_0_z
= ~fq_ld_nh[0] & fq_unimp[1] ;
ME_AI22O1_C iu_hold_gate_31 (.a1( in_fq_unimp_0_y ), .a2( ext_hold ),
.b1( fq_unimp[1] ), .b2( ext_hold ),
.c( in_fq_unimp_0_z ), .z( in_fq_unimp[0] ) );
// in_fq_unimp[1] = fq_ld[1] ? unimpl_fpop_e : fq_unimp[2] ;
wire in_fq_unimp_1_y
= fq_ld_nh[1] & unimpl_fpop_e ;
wire in_fq_unimp_1_z
= ~fq_ld_nh[1] & fq_unimp[2] ;
ME_AI22O1_C iu_hold_gate_32 (.a1( in_fq_unimp_1_y ), .a2( ext_hold ),
.b1( fq_unimp[2] ), .b2( ext_hold ),
.c( in_fq_unimp_1_z ), .z( in_fq_unimp[1] ) );
// in_fq_unimp[2] = fq_ld[2] & unimpl_fpop_e ;
ME_NOR3 iu_hold_gate_33 (.a( ext_hold ), .b( ~fq_ld_nh[2] ),
.c( ~unimpl_fpop_e ), .z( in_fq_unimp[2] ) );
wire [2:0] ld_fq_unimp
;
assign ld_fq_unimp[2:0] = fq_ld_ctl[2:0] ;
ME_FDS2LP fq_unimp_0_ff(.q(fq_unimp[0]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_unimp[0]), .ld(ld_fq_unimp[0]) );
ME_FDS2LP fq_unimp_1_ff(.q(fq_unimp[1]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_unimp[1]), .ld(ld_fq_unimp[1]) );
ME_FDS2LP fq_unimp_2_ff(.q(fq_unimp[2]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_unimp[2]), .ld(ld_fq_unimp[2]) );
// add cancel_fpop term to fix bug #601
assign funimp_in_q = (fq_unimp[0] & fq_qne[0] & ~cancel_fpop) |
(fq_unimp[1] & fq_qne[1]) | (fq_unimp[2] & fq_qne[2]) ;
// **********************************************************************
// FPop rd size
wire [2:0] in_fq_rd_dbl
;
// in_fq_rd_dbl[0] = fq_ld[0] ? rd_dbl_e : fq_rd_dbl[1] ;
wire in_fq_rd_dbl_0_y
= fq_ld_nh[0] & rd_dbl_e ;
wire in_fq_rd_dbl_0_z
= ~fq_ld_nh[0] & fq_rd_dbl[1] ;
ME_AI22O1_C iu_hold_gate_34 (.a1( in_fq_rd_dbl_0_y ), .a2( ext_hold ),
.b1( fq_rd_dbl[1] ), .b2( ext_hold ),
.c( in_fq_rd_dbl_0_z ), .z( in_fq_rd_dbl[0] ) );
// in_fq_rd_dbl[1] = fq_ld[1] ? rd_dbl_e : fq_rd_dbl[2] ;
wire in_fq_rd_dbl_1_y
= fq_ld_nh[1] & rd_dbl_e ;
wire in_fq_rd_dbl_1_z
= ~fq_ld_nh[1] & fq_rd_dbl[2] ;
ME_AI22O1_C iu_hold_gate_35 (.a1( in_fq_rd_dbl_1_y ), .a2( ext_hold ),
.b1( fq_rd_dbl[2] ), .b2( ext_hold ),
.c( in_fq_rd_dbl_1_z ), .z( in_fq_rd_dbl[1] ) );
// in_fq_rd_dbl[2] = fq_ld[2] & rd_dbl_e ;
ME_NOR3 iu_hold_gate_36 (.a( ext_hold ), .b( ~fq_ld_nh[2] ),
.c( ~rd_dbl_e ), .z( in_fq_rd_dbl[2] ) );
wire [2:0] ld_fq_rd_dbl
;
assign ld_fq_rd_dbl[2:0] = fq_ld_ctl[2:0] ;
ME_FDS2LP fq_rd_dbl_0_ff(.q(fq_rd_dbl[0]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_rd_dbl[0]), .ld(ld_fq_rd_dbl[0]) );
ME_FDS2LP fq_rd_dbl_1_ff(.q(fq_rd_dbl[1]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_rd_dbl[1]), .ld(ld_fq_rd_dbl[1]) );
ME_FDS2LP fq_rd_dbl_2_ff(.q(fq_rd_dbl[2]), .cp(ss_clock), .cr(reset_l),
.d(in_fq_rd_dbl[2]), .ld(ld_fq_rd_dbl[2]) );
// **********************************************************************
// FPop started
wire [2:0] in_fq_started
, in_fq_started_x
, in_fq_started_y
;
// in_fq_started[0] = fq_update ? (issue_q1 | fq_started[1]) : issue_q0
assign in_fq_started_x[0] = fq_update ? issue_q1_x : issue_q0_x ;
assign in_fq_started_y[0] = fq_update ? (issue_q1_y | fq_started[1]) :
issue_q0_y ;
ME_AI2O1_C iu_hold_gate_15 (.a( in_fq_started_x[0] ), .b( ext_hold ),
.c( in_fq_started_y[0] ), .z( in_fq_started[0] ) );
// in_fq_started[1] = fq_update ? (issue_q2 | fq_started[2]) : issue_q1
assign in_fq_started_x[1] = fq_update ? issue_q2_x : issue_q1_x ;
assign in_fq_started_y[1] = fq_update ? (issue_q2_y | fq_started[2]) :
issue_q1_y ;
ME_AI2O1_C iu_hold_gate_16 (.a( in_fq_started_x[1] ), .b( ext_hold ),
.c( in_fq_started_y[1] ), .z( in_fq_started[1] ) );
// in_fq_started[2] = issue_q2 & ~fq_update ;
assign in_fq_started_x[2] = issue_q2_x & ~fq_update ;
assign in_fq_started_y[2] = issue_q2_y & ~fq_update ;
ME_AI2O1_C iu_hold_gate_17 (.a( in_fq_started_x[2] ), .b( ext_hold ),
.c( in_fq_started_y[2] ), .z( in_fq_started[2] ) );
wire [2:0] ld_fq_started
, ld_fq_started_l
;
// ld_fq_started[0] = issue_q0 | fq_update | restart_mul ;
ME_O2A1 iu_hold_gate_18 (.a( ext_hold ), .b( ~issue_q0_x ),
.c( ~(issue_q0_y | fq_update | restart_mul) ),
.z( ld_fq_started_l[0] ) );
// ld_fq_started[1] = issue_q1 | fq_update ;
ME_O2A1 iu_hold_gate_19 (.a( ext_hold ), .b( ~issue_q1_x ),
.c( ~(issue_q1_y | fq_update) ),
.z( ld_fq_started_l[1] ) );
// ld_fq_started[2] = issue_q2 | fq_update ;
ME_O2A1 iu_hold_gate_20 (.a( ext_hold ), .b( ~issue_q2_x ),
.c( ~(issue_q2_y | fq_update) ),
.z( ld_fq_started_l[2] ) );
assign ld_fq_started[2:0] = ~ld_fq_started_l[2:0];
wire [2:0] clr_started
;
assign clr_started[0] = clear_qne[0] ;
// clr_started[1] = clear_qne[1] & ~(restart_mul & ~fq_type[1]) ;
wire clr_started_1_b
= reset_l & ~(restart_mul & ~fq_type[1]) ;
wire clr_started_1_c
= clear_qne_x[1] & ~(restart_mul & ~fq_type[1]) ;
ME_A2O1_B iu_hold_gate_22 (.a( ext_hold ), .b( clr_started_1_b ),
.c( clr_started_1_c ), .z( clr_started[1] ) );
// clr_started[2] = clear_qne[2] & ~(restart_mul & ~fq_type[2]) ;
wire clr_started_2_b
= reset_l & ~(restart_mul & ~fq_type[2]) ;
wire clr_started_2_c
= clear_qne_x[2] & ~(restart_mul & ~fq_type[2]) ;
ME_A2O1_B iu_hold_gate_23 (.a( ext_hold ), .b( clr_started_2_b ),
.c( clr_started_2_c ), .z( clr_started[2] ) );
ME_FDS2LP fq_start_0_ff(.q(fq_started[0]), .cp(ss_clock), .cr(clr_started[0]),
.d(in_fq_started[0]), .ld(ld_fq_started[0]) );
ME_FDS2LP fq_start_1_ff(.q(fq_started[1]), .cp(ss_clock), .cr(clr_started[1]),
.d(in_fq_started[1]), .ld(ld_fq_started[1]) );
ME_FDS2LP fq_start_2_ff(.q(fq_started[2]), .cp(ss_clock), .cr(clr_started[2]),
.d(in_fq_started[2]), .ld(ld_fq_started[2]) );
assign fq_started_0 = fq_started[0] ;
// **********************************************************************
// For SPARC FPops, rs2 is always used, and is always the same size as rs1
// dependency checks between FQ entries,
// including the E-stage rd field:
// **********************
// q0(rd) -> q1(rs1,rs2)
chkdep_rd_src chk_q0_q1 (fq_rd_q0[4:1], fq_rs1_q1[4:1], fq_rs2_q1[4:1],
match4_0_1_rs1
, match4_0_1_rs2
) ;
wire match_0_1_rs1
= match4_0_1_rs1 & ((fq_rd_q0[0] ~^ fq_rs1_q1[0]) |
fq_rd_dbl[0] | fq_rs1_dbl[1] );
wire match_0_1_rs2
= match4_0_1_rs2 & ((fq_rd_q0[0] ~^ fq_rs2_q1[0]) |
fq_rd_dbl[0] | fq_rs1_dbl[1] );
wire dep_q0_q1
= fq_qne[0] & fq_rd_used[0] & fq_qne[1] &
((match_0_1_rs1 & fq_rs1_used[1]) | match_0_1_rs2) ;
// **********************
// q0(rd) -> q2(rs1,rs2)
chkdep_rd_src chk_q0_q2 (fq_rd_q0[4:1], fq_rs1_q2[4:1], fq_rs2_q2[4:1],
match4_0_2_rs1
, match4_0_2_rs2
) ;
wire match_0_2_rs1
= match4_0_2_rs1 & ((fq_rd_q0[0] ~^ fq_rs1_q2[0]) |
fq_rd_dbl[0] | fq_rs1_dbl[2] );
wire match_0_2_rs2
= match4_0_2_rs2 & ((fq_rd_q0[0] ~^ fq_rs2_q2[0]) |
fq_rd_dbl[0] | fq_rs1_dbl[2] );
wire dep_q0_q2
= fq_qne[0] & fq_rd_used[0] & fq_qne[2] &
((match_0_2_rs1 & fq_rs1_used[2]) | match_0_2_rs2) ;
// **********************
// q0(rd) -> E(rs1,rs2)
chkdep_rd_src chk_q0_ers (fq_rd_q0[4:1], ir_rs1_e[4:1], ir_rs2_e[4:1],
match4_0_e_rs1
, match4_0_e_rs2
) ;
wire match_0_e_rs1
= match4_0_e_rs1 & ((fq_rd_q0[0] ~^ ir_rs1_e[0]) |
fq_rd_dbl[0] | rs1_dbl_e );
wire match_0_e_rs2
= match4_0_e_rs2 & ((fq_rd_q0[0] ~^ ir_rs2_e[0]) |
fq_rd_dbl[0] | rs1_dbl_e );
wire dep_q0_ers
= fq_qne[0] & fq_rd_used[0] &
((match_0_e_rs1 & rs1_used_e) | match_0_e_rs2) ;
// **********************
// q1(rd) -> q2(rs1,rs2)
chkdep_rd_src chk_q1_q2 (fq_rd_q1[4:1], fq_rs1_q2[4:1], fq_rs2_q2[4:1],
match4_1_2_rs1
, match4_1_2_rs2
) ;
wire match_1_2_rs1
= match4_1_2_rs1 & ((fq_rd_q1[0] ~^ fq_rs1_q2[0]) |
fq_rd_dbl[1] | fq_rs1_dbl[2] );
wire match_1_2_rs2
= match4_1_2_rs2 & ((fq_rd_q1[0] ~^ fq_rs2_q2[0]) |
fq_rd_dbl[1] | fq_rs1_dbl[2] );
wire dep_q1_q2
= fq_qne[1] & fq_rd_used[1] & fq_qne[2] &
((match_1_2_rs1 & fq_rs1_used[2]) | match_1_2_rs2) ;
// **********************
// q1(rd) -> E(rs1,rs2)
chkdep_rd_src chk_q1_ers (fq_rd_q1[4:1], ir_rs1_e[4:1], ir_rs2_e[4:1],
match4_1_e_rs1
, match4_1_e_rs2
) ;
wire match_1_e_rs1
= match4_1_e_rs1 & ((fq_rd_q1[0] ~^ ir_rs1_e[0]) |
fq_rd_dbl[1] | rs1_dbl_e );
wire match_1_e_rs2
= match4_1_e_rs2 & ((fq_rd_q1[0] ~^ ir_rs2_e[0]) |
fq_rd_dbl[1] | rs1_dbl_e );
wire dep_q1_ers
= fq_qne[1] & fq_rd_used[1] &
((match_1_e_rs1 & rs1_used_e) | match_1_e_rs2) ;
// **********************
// q2(rd) -> E(rs1,rs2)
// Not needed because an fpop in E can be loaded into q2 during an update,
// but can't be issued as long as ~fq_started[2] term is in issue_q2 equation.
// Same reason that dep_q1_ers isn't checked in issue_q1.
//
// chkdep_rd_src chk_q2_ers (fq_rd_q2[4:1], ir_rs1_e[4:1], ir_rs2_e[4:1],
// match4_2_e_rs1, match4_2_e_rs2) ;
//
// wire match_2_e_rs1 = match4_2_e_rs1 & ((fq_rd_q2[0] ~^ ir_rs1_e[0]) |
// fq_rd_dbl[2] | rs1_dbl_e );
// wire match_2_e_rs2 = match4_2_e_rs2 & ((fq_rd_q2[0] ~^ ir_rs2_e[0]) |
// fq_rd_dbl[2] | rs1_dbl_e );
//
// wire dep_q2_ers = fq_qne[2] & fq_rd_used[2] &
// ((match_2_e_rs1 & rs1_used_e) | match_2_e_rs2) ;
// **********************************************************************
// FQ issue logic
// assign priority if 2 fpop's
// can be issued simultaneously
wire src_q0
= ~fq_qne[0] ;
wire type_q0
= ~restart_mul & ((src_q0) ? mul_fpop_e : fq_type[0] ) ;
wire chk_busy_q0
= (type_q0) ? fpm_busy : fpp_busy ;
wire could_issue_q0
= (fq_qne[0] | fq_ld_nval[0]) &
(~fq_started[0] | restart_mul) & ~chk_busy_q0 ;
wire src_q1
= ~fq_qne[1] ;
wire type_q1
= (src_q1) ? mul_fpop_e : fq_type[1] ;
wire chk_busy_q1
= (type_q1) ? fpm_busy : (fpp_busy | restart_mul) ;
wire could_issue_q1
= (fq_qne[1] | fq_ld_nval[1]) & ~fq_started[1]
& ~chk_busy_q1 ;
wire src_q2
= ~fq_qne[2] ;
wire type_q2
= (src_q2) ? mul_fpop_e : fq_type[2] ;
wire chk_busy_q2
= (type_q2) ? fpm_busy : (fpp_busy | restart_mul) ;
wire could_issue_q2
= (fq_qne[2] | fq_ld_nval[2]) & ~fq_started[2]
& ~chk_busy_q2 ;
wire priority_q1
= could_issue_q1 & ~could_issue_q0 ;
wire priority_q2
= could_issue_q2 & ~(could_issue_q0 | could_issue_q1) ;
// ************ checks for issuing from FQ0 *************
// highest priority
// issue FPop if (in FQ or being loaded) and (has not been
// started before) and (fpp is available) and no dependencies
assign issue_q0_nval = could_issue_q0 ;
// issue_q0 = (no_holds & issue_q0_x) | issue_q0_y;
assign issue_q0_x = fq_ld_nh[0] & issue_q0_nval ;
assign issue_q0_y = fq_qne[0] & issue_q0_nval ;
// fully qualified issue signal
//synopsys translate_off
wire issue_q0
= (fq_qne[0] | fq_ld[0]) & issue_q0_nval ;
//synopsys translate_on
// ************ checks for issuing from FQ1 *************
// 2nd priority
wire regdep_q0_q1
= (src_q1) ? dep_q0_ers : dep_q0_q1 ;
wire chk_2nd_q1
= fq_update | // q0 is going away
(~regdep_q0_q1 & // no reg depend
((fq_type[0] ^ type_q1) | // no resource depend
(type_q1 & ~fpm_busy))) ;
assign issue_q1_nval = priority_q1 & chk_2nd_q1 ;
// issue_q1 = (no_holds & issue_q1_x) | issue_q1_y;
assign issue_q1_x = fq_ld_nh[1] & issue_q1_nval ;
assign issue_q1_y = fq_qne[1] & issue_q1_nval ;
// fully qualified issue signal
//synopsys translate_off
wire issue_q1
= (fq_qne[1] | fq_ld[1]) & issue_q1_nval ;
//synopsys translate_on
// ************ checks for issuing from FQ2 *************
// 3rd priority
wire regdep_q0_q2
= (src_q2) ? dep_q0_ers : dep_q0_q2 ;
wire regdep_q1_q2
= (src_q2) ? dep_q1_ers : dep_q1_q2 ;
wire chk_3rd_q2
= (fq_update | (~regdep_q0_q2 & (fq_type[0] ^ type_q2))) &
~regdep_q1_q2 & // no reg depend
(fq_type[1] ^ type_q2) ; // no resource depend
assign issue_q2_nval = priority_q2 & chk_3rd_q2 ;
// issue_q2 = (no_holds & issue_q2_x) | issue_q2_y;
assign issue_q2_x = fq_ld_nh[2] & issue_q2_nval ;
assign issue_q2_y = fq_qne[2] & issue_q2_nval ;
// fully qualified issue signal
//synopsys translate_off
wire issue_q2
= (fq_qne[2] | fq_ld[2]) & issue_q2_nval ;
//synopsys translate_on
// **********************************************************************
// Partial FQ issue logic -- faster
// logic to use where full issue logic
// is not required.
// FQ2 will be selected by default
// if FQ0 and FQ1 aren't used.
// assign priority if 2 fpop's
// can be issued simultaneously
wire fast_could_issue_q0
= (fq_qne[0] | fast_fq_ld_nval[0]) &
(~fq_started[0] | restart_mul) & ~chk_busy_q0 ;
wire fast_could_issue_q1
= (fq_qne[1] | fast_fq_ld_nval[1]) & ~fq_started[1]
& ~chk_busy_q1 ;
wire fast_priority_q1
= fast_could_issue_q1 & ~fast_could_issue_q0 ;
wire fast_priority_q2
= ~(fast_could_issue_q0 | fast_could_issue_q1) ;
// ************ checks for issuing from FQ0 *************
// highest priority
wire fast_issue_q0_nval
= fast_could_issue_q0 ;
// ************ checks for issuing from FQ1 *************
// 2nd priority
wire fast_issue_q1_nval
= fast_priority_q1 ;
// ************ checks for issuing from FQ2 *************
// 3rd priority
wire fast_issue_q2_nval
= fast_priority_q2 ;
// **********************************************************************
// source mux selects
// 00 == qi_0
// 01 == qi_1
// 10 == qi_2
// 11 == ir_e
assign fq_src_sel[1] = (fast_issue_q1_nval & src_q1) |
(fast_issue_q0_nval & src_q0) |
fast_issue_q2_nval ;
assign fq_src_sel[0] = (fast_issue_q2_nval & src_q2) |
(fast_issue_q0_nval & src_q0) |
fast_issue_q1_nval ;
// **********************************************************************
// Meiko start signals
// fpp_fop = (issue_q0 & ~type_q0) | (issue_q1 & ~type_q1) |
// (issue_q2 & ~type_q2) ;
wire fpp_fop_x
= (issue_q0_x & ~type_q0) | (issue_q1_x & ~type_q1) |
(issue_q2_x & ~type_q2);
wire fpp_fop_y
= (issue_q0_y & ~type_q0) | (issue_q1_y & ~type_q1) |
(issue_q2_y & ~type_q2);
// fpp_fop = (fpp_fop_x & ~ext_hold) | fpp_fop_y;
ME_AI2O1_C iu_hold_gate_12 (.a( fpp_fop_x ), .b( ext_hold ), .c( fpp_fop_y ),
.z( fpp_fop ) );
ME_FD1P fpp_ld_ff (.q(fpp_ld), .cp(ss_clock), .d(fpp_fop) );
// Mult. start signals
// fpm_issue = (issue_q0 & type_q0) | (issue_q1 & type_q1) |
// (issue_q2 & type_q2) ;
wire fpm_issue_x
= (issue_q0_x & type_q0) | (issue_q1_x & type_q1) |
(issue_q2_x & type_q2);
wire fpm_issue_y
= (issue_q0_y & type_q0) | (issue_q1_y & type_q1) |
(issue_q2_y & type_q2);
ME_AI2O1_C iu_hold_gate_13 (.a( fpm_issue_x ), .b( ext_hold ), .c(fpm_issue_y),
.z( fpm_issue
) );
// mul aborted by trap
wire i_fpm_abort_x
= ext_flush &
((fq_qne[0] & ~fq_qne_val[0] & fq_started[0] & fq_type[0]) |
(fq_qne[1] & ~fq_qne_val[1] & fq_started[1] & fq_type[1]) |
(fq_qne[2] & ~fq_qne_val[2] & fq_started[2] & fq_type[2]) );
// i_fpm_abort = ~ext_hold & i_fpm_abort_x;
ME_NOR2 iu_hold_gate_14 (.a(ext_hold), .b(~i_fpm_abort_x), .z(i_fpm_abort
) );
ME_FD1P fpm_abort_ff (.q(fpm_abort
), .cp(ss_clock), .d(i_fpm_abort) );
// reset mul state for
// abort or exception
wire fpm_reset_l
= reset_l & ~fpm_abort & exemode ;
// mul state pipeline
ME_FD1R fpm_st_ff (.q(fpm_start), .cp(ss_clock), .cr(fpm_reset_l),
.d(fpm_issue) );
ME_FD1R fpm_x1_ff (.q(fpm_passx1
), .cp(ss_clock), .cr(fpm_reset_l),
.d(fpm_start) );
ME_FD1R fpm_x2_ff (.q(fpm_passx2
), .cp(ss_clock), .cr(fpm_reset_l),
.d(fpm_passx1) );
ME_FD1R fpm_x3_ff (.q(fpm_passx3
), .cp(ss_clock), .cr(fpm_reset_l),
.d(fpm_passx2) );
wire fpm_result_ld
= fpm_passx3 | // normal set
(writeback_q0 & fq_type[0]) | // normal clear
restart_mul ; // special clear
// reset result reg whenever fq is empty (fix
// for bug #590)
ME_FDS2LP fpm_res_ff(.q(fpm_result
), .cp(ss_clock),
.cr((fpm_reset_l & fq_qne[0])),
.d(fpm_passx3), .ld(fpm_result_ld) );
assign fpm_busy = (fpm_start | fpm_passx1) ;
wire unfin_mul
= fpm_unfin & fpm_result & fq_type[0] & fq_qne[0] ;
wire unfin_fsmuld = unfin_mul & opf5_q0 ;
// restart unfinished mul, but
// not fsmuld
assign restart_mul = unfin_mul & ~opf5_q0 ;
// **********************************************************************
// FP writeback signals
// prevents false early writeback
wire busy_q0
= (fq_type[0] ? (~fpm_result | restart_mul) : fpp_busy) |
cancel_fpop ;
// FPop in q0 (if any) has finished
assign done_q0 = ~busy_q0 ;
// writeback if q0 FPop has finished
// used to be fq_qne_val[0]
assign writeback_q0 = ~busy_q0 & fq_qne[0] & fq_started[0] & exemode &
exemode_two ;
// writeback_q0 used for fhold logic
// to prevent deadlock when an FPop
// is cancelled in W
assign wbq0_fhold = writeback_q0 | cancel_fpop ;
// fcmp in q0
assign fcmp_q0 = fq_op3_0_q0 & fq_qne[0] ;
// fcmp in fq1 or fq2
assign fcmp_q1q2 = (fq_op3_0_q1 & fq_qne[1]) | (fq_op3_0_q2 & fq_qne[2]) ;
// update fifo for writeback or stdfq
assign fq_update = notrap_writeback | stdfq_r_noexc ;
// version of fq_update without fptrap
assign fast_fq_update = writeback_q0 | stdfq_r_noexc ;
// result mux select controls
assign res_select[1] = ~fq_type[0] ;
assign res_select[0] = ~fq_rd_dbl[0] ;
// **********************************************************************
// fpu signal to fix bug in mmu--shows when an FPop is executing, and may
// cause an fp exception. Used to delay processing of fload to I/O space
// until FPop cannot cause a trap.
assign fload_wait_w = fq_qne[0] & exemode ;
endmodule
This page: |
Created: | Thu Aug 19 12:00:13 1999 |
| From: |
../../../sparc_v8/ssparc/fpu/fp_fpc/rtl/qcore_ctl.v
|