execute: Do comparisons using the main adder
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 13 Dec 2019 04:48:54 +0000 (15:48 +1100)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 14 Jan 2020 11:29:07 +0000 (22:29 +1100)
This handles OP_CMP like a subtraction; the main adder computes
~RA + RB + 1, and the condition codes are computed from the results.
A direct comparison of the two input operands is used to calculate the
EQ bit of the condition result.  The LT and GT bits are computed from
the MSB of the subtraction result, the carry out from the subtraction,
and the MSBs of the operands.  For a 32-bit comparison, the 32-bit
carry and bit 31 of the result and input operands are used; for a
64-bit comparison, the 64-bit carry and bit 63 of the operands and
result are used.

It turns out to be more convenient to use the 'signed' field of
the decode table to distinguish signed from unsigned comparisons,
rather than the insn_type.  Therefore this uses OP_CMP for both
cmp and cmpl, which also has the benefit of reducing the number
of values in insn_type_t.

Doing this saves over 200 slice LUTs on the Arty A7-100 and improves
timing slightly as well.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
decode1.vhdl
decode_types.vhdl
execute1.vhdl

index 6ac3f01af008914d0f1a713e2fd8d5579eed274a..0e42d1b672c36f86d462e5e4ced840eecc57215f 100644 (file)
@@ -44,8 +44,8 @@ architecture behaviour of decode1 is
                29 =>       (ALU,    OP_AND,       NONE,       CONST_UI_HI, RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', ONE,  '0', '0'), -- andis.
                18 =>       (ALU,    OP_B,         NONE,       CONST_LI,    NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0'), -- b
                16 =>       (ALU,    OP_BC,        SPR,        CONST_BD,    NONE, SPR , '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '1', '0'), -- bc
-               11 =>       (ALU,    OP_CMP,       RA,         CONST_SI,    NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpi
-               10 =>       (ALU,    OP_CMPL,      RA,         CONST_UI,    NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpli
+               11 =>       (ALU,    OP_CMP,       RA,         CONST_SI,    NONE, NONE, '0', '1', '1', '0', ONE,  '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0'), -- cmpi
+               10 =>       (ALU,    OP_CMP,       RA,         CONST_UI,    NONE, NONE, '0', '1', '1', '0', ONE,  '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpli
                34 =>       (LDST,   OP_LOAD,      RA_OR_ZERO, CONST_SI,    NONE, RT,   '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- lbz
                35 =>       (LDST,   OP_LOAD,      RA_OR_ZERO, CONST_SI,    NONE, RT,   '0', '0', '0', '0', ZERO, '0', is1B, '0', '0', '1', '0', '0', '0', NONE, '0', '1'), -- lbzu
                42 =>       (LDST,   OP_LOAD,      RA_OR_ZERO, CONST_SI,    NONE, RT,   '0', '0', '0', '0', ZERO, '0', is2B, '0', '1', '0', '0', '0', '0', NONE, '0', '1'), -- lha
@@ -145,10 +145,10 @@ architecture behaviour of decode1 is
                2#0000011100#  =>       (ALU,    OP_AND,       NONE,       RB,          RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- and
                2#0000111100#  =>       (ALU,    OP_AND,       NONE,       RB,          RS,   RA,   '0', '0', '1', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- andc
                -- 2#0011111100# bperm
-               2#0000000000#  =>       (ALU,    OP_CMP,       RA,         RB,          NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmp
+               2#0000000000#  =>       (ALU,    OP_CMP,       RA,         RB,          NONE, NONE, '0', '1', '1', '0', ONE,  '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0'), -- cmp
                2#0111111100#  =>       (ALU,    OP_CMPB,      NONE,       RB,          RS,   RA,   '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpb
                -- 2#0011100000# cmpeqb
-               2#0000100000#  =>       (ALU,    OP_CMPL,      RA,         RB,          NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpl
+               2#0000100000#  =>       (ALU,    OP_CMP,       RA,         RB,          NONE, NONE, '0', '1', '1', '0', ONE,  '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpl
                -- 2#0011000000# cmprb
                2#0000111010#  =>       (ALU,    OP_CNTZ,      NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- cntlzd
                2#0000011010#  =>       (ALU,    OP_CNTZ,      NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0'), -- cntlzw
index fdc1e6e01945352e1b550c91047cb552dc896845..82039bd0efe75a0e9b33524bf49f0aef0b5d6b2d 100644 (file)
@@ -4,7 +4,7 @@ use ieee.std_logic_1164.all;
 package decode_types is
     type insn_type_t is (OP_ILLEGAL, OP_NOP, OP_ADD,
                         OP_ADDPCIS, OP_AND, OP_ATTN, OP_B, OP_BC, OP_BCREG,
-                        OP_BPERM, OP_CMP, OP_CMPB, OP_CMPEQB, OP_CMPL, OP_CMPRB,
+                        OP_BPERM, OP_CMP, OP_CMPB, OP_CMPEQB, OP_CMPRB,
                         OP_CNTZ, OP_CRAND,
                         OP_CRANDC, OP_CREQV, OP_CRNAND, OP_CRNOR, OP_CROR, OP_CRORC,
                         OP_CRXOR, OP_DARN, OP_DCBF, OP_DCBST, OP_DCBT, OP_DCBTST,
index 19910091684f7ee43ee52e93f6910cad45c70be3..6889a6acd3d9936e6dd25af20140c51030a1dbfa 100644 (file)
@@ -193,6 +193,9 @@ begin
         variable abs1, abs2 : signed(63 downto 0);
        variable overflow : std_ulogic;
        variable negative : std_ulogic;
+        variable zerohi, zerolo : std_ulogic;
+        variable msb_a, msb_b : std_ulogic;
+        variable a_lt : std_ulogic;
     begin
        result := (others => '0');
        result_with_carry := (others => '0');
@@ -348,7 +351,7 @@ begin
                report "illegal";
            when OP_NOP =>
                -- Do nothing
-           when OP_ADD =>
+           when OP_ADD | OP_CMP =>
                if e_in.invert_a = '0' then
                    a_inv := e_in.read_data1;
                else
@@ -359,15 +362,57 @@ begin
                result := result_with_carry(63 downto 0);
                 carry_32 := result(32) xor a_inv(32) xor e_in.read_data2(32);
                 carry_64 := result_with_carry(64);
-               if e_in.output_carry = '1' then
-                   set_carry(v.e, carry_32, carry_64);
-               end if;
-               if e_in.oe = '1' then
-                   set_ov(v.e,
-                          calc_ov(a_inv(63), e_in.read_data2(63), carry_64, result_with_carry(63)),
-                          calc_ov(a_inv(31), e_in.read_data2(31), carry_32, result_with_carry(31)));
-               end if;
-               result_en := '1';
+                if e_in.insn_type = OP_ADD then
+                    if e_in.output_carry = '1' then
+                        set_carry(v.e, carry_32, carry_64);
+                    end if;
+                    if e_in.oe = '1' then
+                        set_ov(v.e,
+                               calc_ov(a_inv(63), e_in.read_data2(63), carry_64, result_with_carry(63)),
+                               calc_ov(a_inv(31), e_in.read_data2(31), carry_32, result_with_carry(31)));
+                    end if;
+                    result_en := '1';
+                else
+                    -- CMP and CMPL instructions
+                    -- Note, we have done RB - RA, not RA - RB
+                    bf := insn_bf(e_in.insn);
+                    l := insn_l(e_in.insn);
+                    v.e.write_cr_enable := '1';
+                    crnum := to_integer(unsigned(bf));
+                    v.e.write_cr_mask := num_to_fxm(crnum);
+                    zerolo := not (or (e_in.read_data1(31 downto 0) xor e_in.read_data2(31 downto 0)));
+                    zerohi := not (or (e_in.read_data1(63 downto 32) xor e_in.read_data2(63 downto 32)));
+                    if zerolo = '1' and (l = '0' or zerohi = '1') then
+                        -- values are equal
+                        newcrf := "001" & v.e.xerc.so;
+                    else
+                        if l = '1' then
+                            -- 64-bit comparison
+                            msb_a := e_in.read_data1(63);
+                            msb_b := e_in.read_data2(63);
+                        else
+                            -- 32-bit comparison
+                            msb_a := e_in.read_data1(31);
+                            msb_b := e_in.read_data2(31);
+                        end if;
+                        if msb_a /= msb_b then
+                            -- Subtraction might overflow, but
+                            -- comparison is clear from MSB difference.
+                            -- for signed, 0 is greater; for unsigned, 1 is greater
+                            a_lt := msb_a xnor e_in.is_signed;
+                        else
+                            -- Subtraction cannot overflow since MSBs are equal.
+                            -- carry = 1 indicates RA is smaller (signed or unsigned)
+                            a_lt := (not l and carry_32) or (l and carry_64);
+                        end if;
+                        newcrf := a_lt & not a_lt & '0' & v.e.xerc.so;
+                    end if;
+                    for i in 0 to 7 loop
+                        lo := i*4;
+                        hi := lo + 3;
+                        v.e.write_cr_data(hi downto lo) := newcrf;
+                    end loop;
+                end if;
            when OP_AND | OP_OR | OP_XOR =>
                result := logical_result;
                result_en := '1';
@@ -412,28 +457,6 @@ begin
            when OP_CMPB =>
                result := ppc_cmpb(e_in.read_data3, e_in.read_data2);
                result_en := '1';
-           when OP_CMP =>
-               bf := insn_bf(e_in.insn);
-               l := insn_l(e_in.insn);
-               v.e.write_cr_enable := '1';
-               crnum := to_integer(unsigned(bf));
-               v.e.write_cr_mask := num_to_fxm(crnum);
-               for i in 0 to 7 loop
-                   lo := i*4;
-                   hi := lo + 3;
-                   v.e.write_cr_data(hi downto lo) := ppc_cmp(l, e_in.read_data1, e_in.read_data2, v.e.xerc.so);
-               end loop;
-           when OP_CMPL =>
-               bf := insn_bf(e_in.insn);
-               l := insn_l(e_in.insn);
-               v.e.write_cr_enable := '1';
-               crnum := to_integer(unsigned(bf));
-               v.e.write_cr_mask := num_to_fxm(crnum);
-               for i in 0 to 7 loop
-                   lo := i*4;
-                   hi := lo + 3;
-                   v.e.write_cr_data(hi downto lo) := ppc_cmpl(l, e_in.read_data1, e_in.read_data2, v.e.xerc.so);
-               end loop;
            when OP_CNTZ =>
                result := countzero_result;
                result_en := '1';