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 <paulus@ozlabs.org>
pull/235/head
Paul Mackerras 4 years ago
parent 7052ceef4a
commit 83816cb9e3

@ -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

@ -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);

@ -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 =>

@ -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

@ -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] =

Loading…
Cancel
Save