You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

335 lines
12 KiB
Verilog

// © IBM Corp. 2020
// Licensed under the Apache License, Version 2.0 (the "License"), as modified by
// the terms below; you may not use the files in this repository except in
// compliance with the License as modified.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
// Modified Terms:
//
// 1) For the purpose of the patent license granted to you in Section 3 of the
// License, the "Work" hereby includes implementations of the work of authorship
// in physical form.
//
// 2) Notwithstanding any terms to the contrary in the License, any licenses
// necessary for implementation of the Work that are available from OpenPOWER
// via the Power ISA End User License Agreement (EULA) are explicitly excluded
// hereunder, and may be obtained from OpenPOWER under the terms and conditions
// of the EULA.
//
// Unless required by applicable law or agreed to in writing, the reference design
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
// for the specific language governing permissions and limitations under the License.
//
// Additional rights, including the ability to physically implement a softcore that
// is compliant with the required sections of the Power ISA Specification, are
// available at no cost under the terms of the OpenPOWER Power ISA EULA, which can be
// obtained (along with the Power ISA) here: https://openpowerfoundation.org.
`timescale 1 ns / 1 ns
// Description: XU ALU Compare
//
//*****************************************************************************
`include "tri_a2o.vh"
module xu_alu_cmp(
// Clocks
input [0:`NCLK_WIDTH-1] nclk,
// Power
inout vdd,
inout gnd,
// Pervasive
input d_mode_dc,
input delay_lclkr_dc,
input mpw1_dc_b,
input mpw2_dc_b,
input func_sl_force,
input func_sl_thold_0_b,
input sg_0,
input scan_in,
output scan_out,
input ex2_act,
input ex1_msb_64b_sel,
input [6:10] ex2_instr,
input ex2_sel_trap,
input ex2_sel_cmpl,
input ex2_sel_cmp,
input ex2_rs1_00,
input ex2_rs1_32,
input ex2_rs2_00,
input ex2_rs2_32,
input [64-`GPR_WIDTH:63] ex3_alu_rt,
input ex3_add_ca,
output [0:2] ex3_alu_cr,
output ex3_trap_val
);
localparam msb = 64 - `GPR_WIDTH;
// Latches
wire ex2_msb_64b_sel_q; // input=>ex1_msb_64b_sel ,act=>1'b1
wire ex3_msb_64b_sel_q; // input=>ex2_msb_64b_sel_q ,act=>ex2_act
wire ex3_diff_sign_q; // input=>ex2_diff_sign ,act=>ex2_act
wire ex2_diff_sign;
wire ex3_rs1_trm1_q; // input=>ex2_rs1_trm1 ,act=>ex2_act
wire ex2_rs1_trm1;
wire ex3_rs2_trm1_q; // input=>ex2_rs2_trm1 ,act=>ex2_act
wire ex2_rs2_trm1;
wire [6:10] ex3_instr_q; // input=>ex2_instr ,act=>ex2_act
wire ex3_sel_trap_q; // input=>ex2_sel_trap ,act=>ex2_act
wire ex3_sel_cmpl_q; // input=>ex2_sel_cmpl ,act=>ex2_act
wire ex3_sel_cmp_q; // input=>ex2_sel_cmp ,act=>ex2_act
// Scanchains
localparam ex2_msb_64b_sel_offset = 0;
localparam ex3_msb_64b_sel_offset = ex2_msb_64b_sel_offset + 1;
localparam ex3_diff_sign_offset = ex3_msb_64b_sel_offset + 1;
localparam ex3_rs1_trm1_offset = ex3_diff_sign_offset + 1;
localparam ex3_rs2_trm1_offset = ex3_rs1_trm1_offset + 1;
localparam ex3_instr_offset = ex3_rs2_trm1_offset + 1;
localparam ex3_sel_trap_offset = ex3_instr_offset + 5;
localparam ex3_sel_cmpl_offset = ex3_sel_trap_offset + 1;
localparam ex3_sel_cmp_offset = ex3_sel_cmpl_offset + 1;
localparam scan_right = ex3_sel_cmp_offset + 1;
wire [0:scan_right-1] siv;
wire [0:scan_right-1] sov;
// Signals
wire ex3_cmp0_hi;
wire ex3_cmp0_lo;
wire ex3_cmp0_eq;
wire ex2_rs1_msb;
wire ex2_rs2_msb;
wire ex3_rt_msb;
wire ex3_rslt_gt_s;
wire ex3_rslt_lt_s;
wire ex3_rslt_gt_u;
wire ex3_rslt_lt_u;
wire ex3_cmp_eq;
wire ex3_cmp_gt;
wire ex3_cmp_lt;
wire ex3_sign_cmp;
tri_st_or3232 or3232(
.d(ex3_alu_rt),
.or_hi_b(ex3_cmp0_hi),
.or_lo_b(ex3_cmp0_lo)
);
assign ex2_rs1_msb = (ex2_msb_64b_sel_q == 1'b1) ? ex2_rs1_00 : ex2_rs1_32;
assign ex2_rs2_msb = (ex2_msb_64b_sel_q == 1'b1) ? ex2_rs2_00 : ex2_rs2_32;
assign ex3_rt_msb = (ex3_msb_64b_sel_q == 1'b1) ? ex3_alu_rt[msb] : ex3_alu_rt[32];
// If the signs are different, then we immediately know if one is bigger than the other.
// but only look at this in case of compare instructions
assign ex3_cmp0_eq = (ex3_msb_64b_sel_q == 1'b1) ? (ex3_cmp0_lo & ex3_cmp0_hi) : ex3_cmp0_lo;
assign ex2_diff_sign = (ex2_rs1_msb ^ ex2_rs2_msb) & (ex2_sel_cmpl | ex2_sel_cmp | ex2_sel_trap);
// In case the sigs are not different, we need some more logic
// Look at adder carry out for compares (need to be able to check over flow case)
// Look at sign bit for record forms (overflow is ignored, ie two positives equal a negative.)
assign ex3_sign_cmp = ((ex3_sel_cmpl_q | ex3_sel_cmp_q | ex3_sel_trap_q) == 1'b1) ? ex3_add_ca : ex3_rt_msb;
assign ex2_rs1_trm1 = ex2_rs1_msb & ex2_diff_sign;
assign ex2_rs2_trm1 = ex2_rs2_msb & ex2_diff_sign;
// Signed compare
assign ex3_rslt_gt_s = (ex3_rs2_trm1_q | (~ex3_sign_cmp & ~ex3_diff_sign_q)); // RS2 < RS1
assign ex3_rslt_lt_s = (ex3_rs1_trm1_q | ( ex3_sign_cmp & ~ex3_diff_sign_q)); // RS2 > RS1
// Unsigned compare
assign ex3_rslt_gt_u = (ex3_rs1_trm1_q | (~ex3_sign_cmp & ~ex3_diff_sign_q)); // RS2 < RS1
assign ex3_rslt_lt_u = (ex3_rs2_trm1_q | ( ex3_sign_cmp & ~ex3_diff_sign_q)); // RS2 > RS1
assign ex3_cmp_eq = ex3_cmp0_eq;
assign ex3_cmp_gt = ((~ex3_sel_cmpl_q & ex3_rslt_gt_s) | (ex3_sel_cmpl_q & ex3_rslt_gt_u)) & (~ex3_cmp0_eq);
assign ex3_cmp_lt = ((~ex3_sel_cmpl_q & ex3_rslt_lt_s) | (ex3_sel_cmpl_q & ex3_rslt_lt_u)) & (~ex3_cmp0_eq);
// CR Field for Add, Logical, Rotate
assign ex3_alu_cr = {ex3_cmp_lt, ex3_cmp_gt, ex3_cmp_eq};
// Trap logic
assign ex3_trap_val = ex3_sel_trap_q &
((ex3_instr_q[6] & (~ex3_cmp_eq) & ex3_rslt_lt_s) |
(ex3_instr_q[7] & (~ex3_cmp_eq) & ex3_rslt_gt_s) |
(ex3_instr_q[8] & ex3_cmp_eq) |
(ex3_instr_q[9] & (~ex3_cmp_eq) & ex3_rslt_lt_u) |
(ex3_instr_q[10] & (~ex3_cmp_eq) & ex3_rslt_gt_u));
// Latch Instances
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex2_msb_64b_sel_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(1'b1),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex2_msb_64b_sel_offset]),
.scout(sov[ex2_msb_64b_sel_offset]),
.din(ex1_msb_64b_sel),
.dout(ex2_msb_64b_sel_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_msb_64b_sel_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_msb_64b_sel_offset]),
.scout(sov[ex3_msb_64b_sel_offset]),
.din(ex2_msb_64b_sel_q),
.dout(ex3_msb_64b_sel_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_diff_sign_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_diff_sign_offset]),
.scout(sov[ex3_diff_sign_offset]),
.din(ex2_diff_sign),
.dout(ex3_diff_sign_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_rs1_trm1_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_rs1_trm1_offset]),
.scout(sov[ex3_rs1_trm1_offset]),
.din(ex2_rs1_trm1),
.dout(ex3_rs1_trm1_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_rs2_trm1_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_rs2_trm1_offset]),
.scout(sov[ex3_rs2_trm1_offset]),
.din(ex2_rs2_trm1),
.dout(ex3_rs2_trm1_q)
);
tri_rlmreg_p #(.WIDTH(5), .INIT(0), .NEEDS_SRESET(1)) ex3_instr_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_instr_offset:ex3_instr_offset + 5 - 1]),
.scout(sov[ex3_instr_offset:ex3_instr_offset + 5 - 1]),
.din(ex2_instr),
.dout(ex3_instr_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_sel_trap_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_sel_trap_offset]),
.scout(sov[ex3_sel_trap_offset]),
.din(ex2_sel_trap),
.dout(ex3_sel_trap_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_sel_cmpl_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_sel_cmpl_offset]),
.scout(sov[ex3_sel_cmpl_offset]),
.din(ex2_sel_cmpl),
.dout(ex3_sel_cmpl_q)
);
tri_rlmlatch_p #(.INIT(0), .NEEDS_SRESET(1)) ex3_sel_cmp_latch(
.nclk(nclk),
.vd(vdd),
.gd(gnd),
.act(ex2_act),
.force_t(func_sl_force),
.d_mode(d_mode_dc),
.delay_lclkr(delay_lclkr_dc),
.mpw1_b(mpw1_dc_b),
.mpw2_b(mpw2_dc_b),
.thold_b(func_sl_thold_0_b),
.sg(sg_0),
.scin(siv[ex3_sel_cmp_offset]),
.scout(sov[ex3_sel_cmp_offset]),
.din(ex2_sel_cmp),
.dout(ex3_sel_cmp_q)
);
assign siv[0:scan_right-1] = {sov[1:scan_right-1], scan_in};
assign scan_out = sov[0];
endmodule