From 83816cb9e331dcdffbb0e6faa801816b1d30350c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 7 Aug 2020 09:57:19 +1000 Subject: [PATCH] core: Implement BCD Assist instructions addg6s, cdtbcd, cbcdtod 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 --- decode1.vhdl | 3 ++ decode_types.vhdl | 1 + execute1.vhdl | 44 +++++++++++++++------- logical.vhdl | 77 +++++++++++++++++++++++++++++++++++++++ scripts/fmt_log/fmt_log.c | 2 +- 5 files changed, 112 insertions(+), 15 deletions(-) diff --git a/decode1.vhdl b/decode1.vhdl index 69b50a6..21fea4a 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -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 diff --git a/decode_types.vhdl b/decode_types.vhdl index 7a60eac..ef654c3 100644 --- a/decode_types.vhdl +++ b/decode_types.vhdl @@ -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); diff --git a/execute1.vhdl b/execute1.vhdl index 256cb5e..1b83997 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -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 => diff --git a/logical.vhdl b/logical.vhdl index 2df66dc..d008e47 100644 --- a/logical.vhdl +++ b/logical.vhdl @@ -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 diff --git a/scripts/fmt_log/fmt_log.c b/scripts/fmt_log/fmt_log.c index 9b6775b..146346d 100644 --- a/scripts/fmt_log/fmt_log.c +++ b/scripts/fmt_log/fmt_log.c @@ -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] =