core: Implement BCD Assist instructions addg6s, cdtbcd, cbcdtod
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 6 Aug 2020 23:57:19 +0000 (09:57 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 7 Aug 2020 00:36:23 +0000 (10:36 +1000)
To avoid adding too much logic, this moves the adder used by OP_ADD
out of the case statement in execute1.vhdl so that the result can
be used by OP_ADDG6S as well.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
decode1.vhdl
decode_types.vhdl
execute1.vhdl
logical.vhdl
scripts/fmt_log/fmt_log.c

index 69b50a674fad5886b11ca353cff5ecafca874d70..21fea4a6c7ed9d21b3b68740359f0c073bb4fa7a 100644 (file)
@@ -173,6 +173,7 @@ architecture behaviour of decode1 is
         2#0010001010#  =>       (ALU,    OP_ADD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', CA,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- adde
         2#1010001010#  =>       (ALU,    OP_ADD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', CA,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- addeo
         2#0010101010#  =>       (ALU,    OP_ADD,       RA,         RB,          NONE, RT,   '0', '0', '0', '0', OV,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- addex
+        2#0001001010#  =>       (ALU,    OP_ADDG6S,    RA,         RB,          NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- addg6s
         2#0011101010#  =>       (ALU,    OP_ADD,       RA,         CONST_M1,    NONE, RT,   '0', '0', '0', '0', CA,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- addme
         2#1011101010#  =>       (ALU,    OP_ADD,       RA,         CONST_M1,    NONE, RT,   '0', '0', '0', '0', CA,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- addmeo
         2#0011001010#  =>       (ALU,    OP_ADD,       RA,         NONE,        NONE, RT,   '0', '0', '0', '0', CA,   '1', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- addze
@@ -180,6 +181,8 @@ 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#  =>       (ALU,    OP_BPERM,     NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- bperm
+        2#0100111010#  =>       (ALU,    OP_BCD,       NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cbcdtd
+        2#0100011010#  =>       (ALU,    OP_BCD,       NONE,       NONE,        RS,   RA,   '0', '0', '1', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cdtbcd
         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#  =>       (ALU,    OP_CMPEQB,    RA,         RB,          NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- cmpeqb
index 7a60eac97fd19ea0b09e9f88fe6743fc3756210c..ef654c33c06d14b5e576ccd064496759b7a72cb0 100644 (file)
@@ -18,6 +18,7 @@ package decode_types is
                         OP_SHL, OP_SHR,
                         OP_SYNC, OP_TLBIE, OP_TRAP,
                         OP_XOR,
+                         OP_BCD, OP_ADDG6S,
                          OP_FETCH_FAILED
                         );
     type input_reg_a_t is (NONE, RA, RA_OR_ZERO, SPR, CIA);
index 256cb5e2451cb740f17f7e0cb919748802a8296e..1b839978439624150d78f7cc9eb0d747c9c4900e 100644 (file)
@@ -295,7 +295,7 @@ begin
        variable a_inv : std_ulogic_vector(63 downto 0);
        variable result : std_ulogic_vector(63 downto 0);
        variable newcrf : std_ulogic_vector(3 downto 0);
-       variable result_with_carry : std_ulogic_vector(64 downto 0);
+       variable sum_with_carry : std_ulogic_vector(64 downto 0);
        variable result_en : std_ulogic;
        variable crnum : crnum_t;
        variable crbit : integer range 0 to 31;
@@ -332,7 +332,7 @@ begin
         variable addend : std_ulogic_vector(127 downto 0);
     begin
        result := (others => '0');
-       result_with_carry := (others => '0');
+       sum_with_carry := (others => '0');
        result_en := '0';
        newcrf := (others => '0');
         is_branch := '0';
@@ -395,6 +395,15 @@ begin
         v.cntz_in_progress := '0';
         v.mul_finish := '0';
 
+        -- Main adder
+        if e_in.invert_a = '0' then
+            a_inv := a_in;
+        else
+            a_inv := not a_in;
+        end if;
+        sum_with_carry := ppc_adde(a_inv, b_in,
+                                   decode_input_carry(e_in.input_carry, v.e.xerc));
+
         -- signals to multiply and divide units
         sign1 := '0';
         sign2 := '0';
@@ -584,16 +593,9 @@ begin
            when OP_NOP =>
                -- Do nothing
            when OP_ADD | OP_CMP | OP_TRAP =>
-               if e_in.invert_a = '0' then
-                   a_inv := a_in;
-               else
-                   a_inv := not a_in;
-               end if;
-               result_with_carry := ppc_adde(a_inv, b_in,
-                                             decode_input_carry(e_in.input_carry, v.e.xerc));
-               result := result_with_carry(63 downto 0);
+               result := sum_with_carry(63 downto 0);
                 carry_32 := result(32) xor a_inv(32) xor b_in(32);
-                carry_64 := result_with_carry(64);
+                carry_64 := sum_with_carry(64);
                 if e_in.insn_type = OP_ADD then
                     if e_in.output_carry = '1' then
                         if e_in.input_carry /= OV then
@@ -606,8 +608,8 @@ begin
                     end if;
                     if e_in.oe = '1' then
                         set_ov(v.e,
-                               calc_ov(a_inv(63), b_in(63), carry_64, result_with_carry(63)),
-                               calc_ov(a_inv(31), b_in(31), carry_32, result_with_carry(31)));
+                               calc_ov(a_inv(63), b_in(63), carry_64, sum_with_carry(63)),
+                               calc_ov(a_inv(31), b_in(31), carry_32, sum_with_carry(31)));
                     end if;
                     result_en := '1';
                 else
@@ -672,6 +674,19 @@ begin
                         end if;
                     end if;
                 end if;
+            when OP_ADDG6S =>
+                result := (others => '0');
+                for i in 0 to 14 loop
+                    lo := i * 4;
+                    hi := (i + 1) * 4;
+                    if (a_in(hi) xor b_in(hi) xor sum_with_carry(hi)) = '0' then
+                        result(lo + 3 downto lo) := "0110";
+                    end if;
+                end loop;
+                if sum_with_carry(64) = '0' then
+                    result(63 downto 60) := "0110";
+                end if;
+                result_en := '1';
             when OP_CMPRB =>
                 newcrf := ppc_cmprb(a_in, b_in, insn_l(e_in.insn));
                 bf := insn_bf(e_in.insn);
@@ -688,7 +703,8 @@ begin
                 v.e.write_cr_mask := num_to_fxm(crnum);
                 v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
                                      newcrf & newcrf & newcrf & newcrf;
-           when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS | OP_BPERM =>
+            when OP_AND | OP_OR | OP_XOR | OP_POPCNT | OP_PRTY | OP_CMPB | OP_EXTS |
+                    OP_BPERM | OP_BCD =>
                result := logical_result;
                result_en := '1';
            when OP_B =>
index 2df66dcea7034b510a7ef11ccbe5a4fd5abc4e8d..d008e4735660931f0a3398803244d039ae3fcc02 100644 (file)
@@ -37,6 +37,72 @@ architecture behaviour of logical is
     signal parity   : std_ulogic_vector(63 downto 0);
     signal permute  : std_ulogic_vector(7 downto 0);
 
+    function bcd_to_dpd(bcd: std_ulogic_vector(11 downto 0)) return std_ulogic_vector is
+        variable dpd: std_ulogic_vector(9 downto 0);
+        variable a, b, c, d, e, f, g, h, i, j, k, m: std_ulogic;
+    begin
+        -- The following equations are copied from PowerISA v3.0B Book 1 appendix B
+        a := bcd(11);
+        b := bcd(10);
+        c := bcd(9);
+        d := bcd(8);
+        e := bcd(7);
+        f := bcd(6);
+        g := bcd(5);
+        h := bcd(4);
+        i := bcd(3);
+        j := bcd(2);
+        k := bcd(1);
+        m := bcd(0);
+        dpd(9) := (f and a and i and not e) or (j and a and not i) or (b and not a);
+        dpd(8) := (g and a and i and not e) or (k and a and not i) or (c and not a);
+        dpd(7) := d;
+        dpd(6) := (j and not a and e and not i) or (f and not i and not e) or
+                  (f and not a and not e) or (e and i);
+        dpd(5) := (k and not a and e and not i) or (g and not i and not e) or
+                  (g and not a and not e) or (a and i);
+        dpd(4) := h;
+        dpd(3) := a or e or i;
+        dpd(2) := (not e and j and not i) or (e and i) or a;
+        dpd(1) := (not a and k and not i) or (a and i) or e;
+        dpd(0) := m;
+        return dpd;
+    end;
+
+    function dpd_to_bcd(dpd: std_ulogic_vector(9 downto 0)) return std_ulogic_vector is
+        variable bcd: std_ulogic_vector(11 downto 0);
+        variable p, q, r, s, t, u, v, w, x, y: std_ulogic;
+    begin
+        -- The following equations are copied from PowerISA v3.0B Book 1 appendix B
+        p := dpd(9);
+        q := dpd(8);
+        r := dpd(7);
+        s := dpd(6);
+        t := dpd(5);
+        u := dpd(4);
+        v := dpd(3);
+        w := dpd(2);
+        x := dpd(1);
+        y := dpd(0);
+        bcd(11) := (not s and v and w) or (t and v and w and s) or (v and w and not x);
+        bcd(10) := (p and s and x and not t) or (p and not w) or (p and not v);
+        bcd(9)  := (q and s and x and not t) or (q and not w) or (q and not v);
+        bcd(8)  := r;
+        bcd(7)  := (v and not w and x) or (s and v and w and x) or (not t and v and w and x);
+        bcd(6)  := (p and t and v and w and x and not s) or (s and not x and v) or
+                   (s and not v);
+        bcd(5)  := (q and t and w and v and x and not s) or (t and not x and v) or
+                   (t and not v);
+        bcd(4)  := u;
+        bcd(3)  := (t and v and w and x) or (s and v and w and x) or (v and not w and not x);
+        bcd(2)  := (p and not s and not t and w and v) or (s and v and not w and x) or
+                   (p and w and not x and v) or (w and not v);
+        bcd(1)  := (q and not s and not t and v and w) or (t and v and not w and x) or
+                   (q and v and w and not x) or (x and not v);
+        bcd(0)  := y;
+        return bcd;
+    end;
+
 begin
     logical_0: process(all)
         variable rb_adj, tmp : std_ulogic_vector(63 downto 0);
@@ -120,6 +186,17 @@ begin
                 tmp := ppc_cmpb(rs, rb);
             when OP_BPERM =>
                 tmp := std_ulogic_vector(resize(unsigned(permute), 64));
+            when OP_BCD =>
+                -- invert_in is abused to indicate direction of conversion
+                if invert_in = '0' then
+                    -- cbcdtd
+                    tmp := x"000" & bcd_to_dpd(rs(55 downto 44)) & bcd_to_dpd(rs(43 downto 32)) &
+                           x"000" & bcd_to_dpd(rs(23 downto 12)) & bcd_to_dpd(rs(11 downto 0));
+                else
+                    -- cdtbcd
+                    tmp := x"00" & dpd_to_bcd(rs(51 downto 42)) & dpd_to_bcd(rs(41 downto 32)) &
+                           x"00" & dpd_to_bcd(rs(19 downto 10)) & dpd_to_bcd(rs(9 downto 0));
+                end if;
             when others =>
                 -- EXTS
                 -- note datalen is a 1-hot encoding
index 9b6775b15c3e5bc02f196fbaa6e743cada27d8a1..146346d343b576c707fe8d13d2b6dd9dc34ada02 100644 (file)
@@ -94,7 +94,7 @@ const char *ops[64] =
        "mfcr   ", "mfmsr  ", "mfspr  ", "mod    ", "mtcrf  ", "mtmsr  ", "mtspr  ", "mull64 ",
        "mulh64 ", "mulh32 ", "or     ", "popcnt ", "prty   ", "rfid   ", "rlc    ", "rlcl   ",
        "rlcr   ", "sc     ", "setb   ", "shl    ", "shr    ", "sync   ", "tlbie  ", "trap   ",
-       "xor    ", "ffail  ", "?58    ", "?59    ", "?60    ", "?61    ", "?62    ", "?63    "
+       "xor    ", "bcd    ", "addg6s ", "ffail  ", "?60    ", "?61    ", "?62    ", "?63    "
 };
 
 const char *spr_names[13] =