Use FPU for division instructions if we have an FPU

- Arrange for XER to be written for OE=1 forms
- Arrange for condition codes to be set for RC=1 forms
  (including correct handling for 32-bit mode)
- Don't instantiate the divider if we have an FPU.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/379/head
Paul Mackerras 3 years ago
parent 34330552e8
commit 73cc5167ec

@ -640,7 +640,10 @@ package common is
frc : std_ulogic_vector(63 downto 0); frc : std_ulogic_vector(63 downto 0);
frt : gspr_index_t; frt : gspr_index_t;
rc : std_ulogic; rc : std_ulogic;
m32b : std_ulogic;
out_cr : std_ulogic; out_cr : std_ulogic;
oe : std_ulogic;
xerc : xer_common_t;
stall : std_ulogic; stall : std_ulogic;
end record; end record;
constant Execute1ToFPUInit : Execute1ToFPUType := (valid => '0', op => OP_ILLEGAL, nia => (others => '0'), constant Execute1ToFPUInit : Execute1ToFPUType := (valid => '0', op => OP_ILLEGAL, nia => (others => '0'),
@ -649,6 +652,7 @@ package common is
fra => (others => '0'), frb => (others => '0'), fra => (others => '0'), frb => (others => '0'),
frc => (others => '0'), frt => (others => '0'), frc => (others => '0'), frt => (others => '0'),
single => '0', is_signed => '0', out_cr => '0', single => '0', is_signed => '0', out_cr => '0',
m32b => '0', oe => '0', xerc => xerc_init,
stall => '0'); stall => '0');


type FPUToExecute1Type is record type FPUToExecute1Type is record
@ -668,6 +672,8 @@ package common is
write_cr_enable : std_ulogic; write_cr_enable : std_ulogic;
write_cr_mask : std_ulogic_vector(7 downto 0); write_cr_mask : std_ulogic_vector(7 downto 0);
write_cr_data : std_ulogic_vector(31 downto 0); write_cr_data : std_ulogic_vector(31 downto 0);
write_xerc : std_ulogic;
xerc : xer_common_t;
intr_vec : intr_vector_t; intr_vec : intr_vector_t;
srr0 : std_ulogic_vector(63 downto 0); srr0 : std_ulogic_vector(63 downto 0);
srr1 : std_ulogic_vector(15 downto 0); srr1 : std_ulogic_vector(15 downto 0);
@ -677,6 +683,7 @@ package common is
write_enable => '0', write_reg => (others => '0'), write_enable => '0', write_reg => (others => '0'),
write_cr_enable => '0', write_cr_mask => (others => '0'), write_cr_enable => '0', write_cr_mask => (others => '0'),
write_cr_data => (others => '0'), write_cr_data => (others => '0'),
write_xerc => '0', xerc => xerc_init,
intr_vec => 0, srr1 => (others => '0'), intr_vec => 0, srr1 => (others => '0'),
others => (others => '0')); others => (others => '0'));



@ -35,6 +35,18 @@ architecture behaviour of decode1 is
constant illegal_inst : decode_rom_t := constant illegal_inst : decode_rom_t :=
(NONE, NONE, OP_ILLEGAL, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE); (NONE, NONE, OP_ILLEGAL, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE);


-- If we have an FPU, then it is used for integer divisions,
-- otherwise a dedicated divider in the ALU is used.
function divider_unit(hf : boolean) return unit_t is
begin
if hf then
return FPU;
else
return ALU;
end if;
end;
constant DVU : unit_t := divider_unit(HAS_FPU);

type reg_internal_t is record type reg_internal_t is record
override : std_ulogic; override : std_ulogic;
override_decode: decode_rom_t; override_decode: decode_rom_t;
@ -225,22 +237,22 @@ architecture behaviour of decode1 is
2#0100010110# => (ALU, NONE, OP_DCBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbt 2#0100010110# => (ALU, NONE, OP_DCBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbt
2#0011110110# => (ALU, NONE, OP_DCBTST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbtst 2#0011110110# => (ALU, NONE, OP_DCBTST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbtst
2#1111110110# => (LDST, NONE, OP_DCBZ, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbz 2#1111110110# => (LDST, NONE, OP_DCBZ, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dcbz
2#0110001001# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdeu 2#0110001001# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdeu
2#1110001001# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdeuo 2#1110001001# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdeuo
2#0110001011# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divweu 2#0110001011# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divweu
2#1110001011# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divweuo 2#1110001011# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divweuo
2#0110101001# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divde 2#0110101001# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divde
2#1110101001# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divdeo 2#1110101001# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divdeo
2#0110101011# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divwe 2#0110101011# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divwe
2#1110101011# => (ALU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divweo 2#1110101011# => (DVU, NONE, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divweo
2#0111001001# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdu 2#0111001001# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divdu
2#1111001001# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divduo 2#1111001001# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', NONE), -- divduo
2#0111001011# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divwu 2#0111001011# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divwu
2#1111001011# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divwuo 2#1111001011# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', NONE), -- divwuo
2#0111101001# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divd 2#0111101001# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divd
2#1111101001# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divdo 2#1111101001# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', NONE), -- divdo
2#0111101011# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divw 2#0111101011# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divw
2#1111101011# => (ALU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divwo 2#1111101011# => (DVU, NONE, OP_DIV, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', NONE), -- divwo
2#1100110110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dss 2#1100110110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dss
2#0101010110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dst 2#0101010110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dst
2#0101110110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dstst 2#0101110110# => (ALU, NONE, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- dstst
@ -318,10 +330,10 @@ architecture behaviour of decode1 is
2#0000010011# => (ALU, NONE, OP_MFCR, NONE, NONE, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfcr/mfocrf 2#0000010011# => (ALU, NONE, OP_MFCR, NONE, NONE, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfcr/mfocrf
2#0001010011# => (ALU, NONE, OP_MFMSR, NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE), -- mfmsr 2#0001010011# => (ALU, NONE, OP_MFMSR, NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1', NONE), -- mfmsr
2#0101010011# => (ALU, NONE, OP_MFSPR, SPR, NONE, RS, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfspr 2#0101010011# => (ALU, NONE, OP_MFSPR, SPR, NONE, RS, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mfspr
2#0100001001# => (ALU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- modud 2#0100001001# => (DVU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- modud
2#0100001011# => (ALU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- moduw 2#0100001011# => (DVU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- moduw
2#1100001001# => (ALU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE), -- modsd 2#1100001001# => (DVU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', NONE, '0', '0', NONE), -- modsd
2#1100001011# => (ALU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0', NONE), -- modsw 2#1100001011# => (DVU, NONE, OP_MOD, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', NONE, '0', '0', NONE), -- modsw
2#0010010000# => (ALU, NONE, OP_MTCRF, NONE, NONE, RS, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtcrf/mtocrf 2#0010010000# => (ALU, NONE, OP_MTCRF, NONE, NONE, RS, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtcrf/mtocrf
2#0010010010# => (ALU, NONE, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- mtmsr 2#0010010010# => (ALU, NONE, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', NONE, '0', '0', NONE), -- mtmsr
2#0010110010# => (ALU, NONE, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtmsrd # ignore top bits and d 2#0010110010# => (ALU, NONE, OP_MTMSRD, NONE, NONE, RS, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', NONE), -- mtmsrd # ignore top bits and d

@ -188,7 +188,7 @@ architecture behaviour of execute1 is


-- divider signals -- divider signals
signal x_to_divider: Execute1ToDividerType; signal x_to_divider: Execute1ToDividerType;
signal divider_to_x: DividerToExecute1Type; signal divider_to_x: DividerToExecute1Type := DividerToExecute1Init;


-- random number generator signals -- random number generator signals
signal random_raw : std_ulogic_vector(63 downto 0); signal random_raw : std_ulogic_vector(63 downto 0);
@ -367,13 +367,15 @@ begin
m_out => multiply_to_x m_out => multiply_to_x
); );


divider_0: entity work.divider divider_0: if not HAS_FPU generate
port map ( div_0: entity work.divider
clk => clk, port map (
rst => rst, clk => clk,
d_in => x_to_divider, rst => rst,
d_out => divider_to_x d_in => x_to_divider,
); d_out => divider_to_x
);
end generate;


random_0: entity work.random random_0: entity work.random
port map ( port map (
@ -1159,9 +1161,11 @@ begin
owait := '1'; owait := '1';


when OP_DIV | OP_DIVE | OP_MOD => when OP_DIV | OP_DIVE | OP_MOD =>
v.start_div := '1'; if not HAS_FPU then
slow_op := '1'; v.start_div := '1';
owait := '1'; slow_op := '1';
owait := '1';
end if;


when OP_FETCH_FAILED => when OP_FETCH_FAILED =>
-- Handling an ITLB miss doesn't count as having executed an instruction -- Handling an ITLB miss doesn't count as having executed an instruction
@ -1457,6 +1461,9 @@ begin
fv.frt := e_in.write_reg; fv.frt := e_in.write_reg;
fv.rc := e_in.rc; fv.rc := e_in.rc;
fv.out_cr := e_in.output_cr; fv.out_cr := e_in.output_cr;
fv.m32b := not ex1.msr(MSR_SF);
fv.oe := e_in.oe;
fv.xerc := xerc_in;
fv.stall := l_in.l2stall; fv.stall := l_in.l2stall;


-- Update registers -- Update registers

@ -125,6 +125,7 @@ architecture behaviour of fpu is
write_reg : gspr_index_t; write_reg : gspr_index_t;
complete_tag : instr_tag_t; complete_tag : instr_tag_t;
writing_cr : std_ulogic; writing_cr : std_ulogic;
writing_xer : std_ulogic;
int_result : std_ulogic; int_result : std_ulogic;
cr_result : std_ulogic_vector(3 downto 0); cr_result : std_ulogic_vector(3 downto 0);
cr_mask : std_ulogic_vector(7 downto 0); cr_mask : std_ulogic_vector(7 downto 0);
@ -151,6 +152,7 @@ architecture behaviour of fpu is
invalid : std_ulogic; invalid : std_ulogic;
negate : std_ulogic; negate : std_ulogic;
longmask : std_ulogic; longmask : std_ulogic;
integer_op : std_ulogic;
divext : std_ulogic; divext : std_ulogic;
divmod : std_ulogic; divmod : std_ulogic;
is_signed : std_ulogic; is_signed : std_ulogic;
@ -159,6 +161,10 @@ architecture behaviour of fpu is
inc_quot : std_ulogic; inc_quot : std_ulogic;
a_hi : std_ulogic_vector(7 downto 0); a_hi : std_ulogic_vector(7 downto 0);
a_lo : std_ulogic_vector(55 downto 0); a_lo : std_ulogic_vector(55 downto 0);
m32b : std_ulogic;
oe : std_ulogic;
xerc : xer_common_t;
xerc_result : xer_common_t;
end record; end record;


type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0); type lookup_table is array(0 to 1023) of std_ulogic_vector(17 downto 0);
@ -604,6 +610,7 @@ begin
r.do_intr <= '0'; r.do_intr <= '0';
r.writing_fpr <= '0'; r.writing_fpr <= '0';
r.writing_cr <= '0'; r.writing_cr <= '0';
r.writing_xer <= '0';
r.fpscr <= (others => '0'); r.fpscr <= (others => '0');
r.write_reg <= (others =>'0'); r.write_reg <= (others =>'0');
r.complete_tag.valid <= '0'; r.complete_tag.valid <= '0';
@ -658,6 +665,8 @@ begin
w_out.write_cr_mask <= r.cr_mask; w_out.write_cr_mask <= r.cr_mask;
w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result & w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
r.cr_result & r.cr_result & r.cr_result & r.cr_result; r.cr_result & r.cr_result & r.cr_result & r.cr_result;
w_out.write_xerc <= r.writing_xer and r.complete;
w_out.xerc <= r.xerc_result;
w_out.interrupt <= r.do_intr; w_out.interrupt <= r.do_intr;
w_out.intr_vec <= 16#700#; w_out.intr_vec <= 16#700#;
w_out.srr0 <= r.nia; w_out.srr0 <= r.nia;
@ -739,6 +748,7 @@ begin
v.instr_done := '0'; v.instr_done := '0';
v.writing_fpr := '0'; v.writing_fpr := '0';
v.writing_cr := '0'; v.writing_cr := '0';
v.writing_xer := '0';
v.comm_fpscr := r.fpscr; v.comm_fpscr := r.fpscr;
v.illegal := '0'; v.illegal := '0';
end if; end if;
@ -755,7 +765,11 @@ begin
v.is_signed := e_in.is_signed; v.is_signed := e_in.is_signed;
v.rc := e_in.rc; v.rc := e_in.rc;
v.is_cmp := e_in.out_cr; v.is_cmp := e_in.out_cr;
v.oe := e_in.oe;
v.m32b := e_in.m32b;
v.xerc := e_in.xerc;
v.longmask := '0'; v.longmask := '0';
v.integer_op := '0';
v.divext := '0'; v.divext := '0';
v.divmod := '0'; v.divmod := '0';
if e_in.op = OP_FPOP or e_in.op = OP_FPOP_I then if e_in.op = OP_FPOP or e_in.op = OP_FPOP_I then
@ -764,6 +778,7 @@ begin
int_input := '1'; int_input := '1';
end if; end if;
else -- OP_DIV, OP_DIVE, OP_MOD else -- OP_DIV, OP_DIVE, OP_MOD
v.integer_op := '1';
int_input := '1'; int_input := '1';
is_32bint := e_in.single; is_32bint := e_in.single;
if e_in.op = OP_DIVE then if e_in.op = OP_DIVE then
@ -2865,12 +2880,44 @@ begin
v.state := IDIV_DONE; v.state := IDIV_DONE;
end if; end if;
when IDIV_DONE => when IDIV_DONE =>
v.xerc_result := v.xerc;
if r.oe = '1' then
v.xerc_result.ov := '0';
v.xerc_result.ov32 := '0';
v.writing_xer := '1';
end if;
if r.m32b = '0' then
v.cr_result(3) := r.r(63);
v.cr_result(2 downto 1) := "00";
if r.r = 64x"0" then
v.cr_result(1) := '1';
else
v.cr_result(2) := not r.r(63);
end if;
else
v.cr_result(3) := r.r(31);
v.cr_result(2 downto 1) := "00";
if r.r(31 downto 0) = 32x"0" then
v.cr_result(1) := '1';
else
v.cr_result(2) := not r.r(31);
end if;
end if;
v.cr_result(0) := v.xerc.so;
int_result := '1'; int_result := '1';
v.writing_fpr := '1'; v.writing_fpr := '1';
v.instr_done := '1'; v.instr_done := '1';
when IDIV_ZERO => when IDIV_ZERO =>
opsel_r <= RES_MISC; opsel_r <= RES_MISC;
misc_sel <= "0101"; misc_sel <= "0101";
v.xerc_result := v.xerc;
if r.oe = '1' then
v.xerc_result.ov := r.int_ovf;
v.xerc_result.ov32 := r.int_ovf;
v.xerc_result.so := r.xerc.so or r.int_ovf;
v.writing_xer := '1';
end if;
v.cr_result := "001" & v.xerc_result.so;
int_result := '1'; int_result := '1';
v.writing_fpr := '1'; v.writing_fpr := '1';
v.instr_done := '1'; v.instr_done := '1';
@ -3169,14 +3216,16 @@ begin
v.state := IDLE; v.state := IDLE;
v.busy := '0'; v.busy := '0';
v.f2stall := '0'; v.f2stall := '0';
if r.rc = '1' then if r.rc = '1' and (r.op = OP_FPOP or r.op = OP_FPOP_I) then
v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX); v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
end if; end if;
v.sp_result := r.single_prec; v.sp_result := r.single_prec;
v.int_result := int_result; v.int_result := int_result;
v.illegal := illegal; v.illegal := illegal;
v.nsnan_result := v.quieten_nan; v.nsnan_result := v.quieten_nan;
if r.is_cmp = '0' then if r.integer_op = '1' then
v.cr_mask := num_to_fxm(0);
elsif r.is_cmp = '0' then
v.cr_mask := num_to_fxm(1); v.cr_mask := num_to_fxm(1);
else else
v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(r.insn)))); v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(r.insn))));

@ -1410,6 +1410,110 @@ int fpu_test_23(void)
return trapit(0, test23); return trapit(0, test23);
} }


struct idiv_tests {
unsigned long denom;
unsigned long divisor;
unsigned long divd;
unsigned long divdu;
unsigned long divde;
unsigned long divdeu;
unsigned long modsd;
unsigned long modud;
} idiv_tests[] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0x56789a, 0x1234, 0x4c0, 0x4c0, 0, 0, 0x19a, 0x19a },
{ 2, 3, 0, 0, 0, 0xaaaaaaaaaaaaaaaa, 2, 2 },
{ 31, 157, 0, 0, 0x328c3ab35cf15328, 0x328c3ab35cf15328, 31, 31 },
{ -4329874, 43879, -98, 0x17e5a119b9170, 0, 0, -29732, 39518 },
{ -4329874, -43879, 98, 0, 0, 0xffffffffffbe99d4, -29732, -4329874 },
{ 0x8000000000000000ul, -1, 0, 0, 0, 0x8000000000000000ul, 0, 0x8000000000000000ul },
};

int fpu_test_24(void)
{
long i;
unsigned long a, b, results[6];

for (i = 0; i < sizeof(idiv_tests) / sizeof(idiv_tests[0]); ++i) {
a = idiv_tests[i].denom;
b = idiv_tests[i].divisor;
asm("divd %0,%1,%2" : "=r" (results[0]) : "r" (a), "r" (b));
asm("divdu %0,%1,%2" : "=r" (results[1]) : "r" (a), "r" (b));
asm("divde %0,%1,%2" : "=r" (results[2]) : "r" (a), "r" (b));
asm("divdeu %0,%1,%2" : "=r" (results[3]) : "r" (a), "r" (b));
asm("modsd %0,%1,%2" : "=r" (results[4]) : "r" (a), "r" (b));
asm("modud %0,%1,%2" : "=r" (results[5]) : "r" (a), "r" (b));
if (results[0] != idiv_tests[i].divd ||
results[1] != idiv_tests[i].divdu ||
results[2] != idiv_tests[i].divde ||
results[3] != idiv_tests[i].divdeu ||
results[4] != idiv_tests[i].modsd ||
results[5] != idiv_tests[i].modud) {
print_hex(i, 2, " ");
print_hex(results[0], 16, " ");
print_hex(results[1], 16, " ");
print_hex(results[2], 16, " ");
print_hex(results[3], 16, " ");
print_hex(results[4], 16, " ");
print_hex(results[5], 16, "\r\n");
return i + 1;
}
}
return 0;
}

struct wdiv_tests {
unsigned int denom;
unsigned int divisor;
unsigned int divw;
unsigned int divwu;
unsigned int divwe;
unsigned int divweu;
unsigned int modsw;
unsigned int moduw;
} wdiv_tests[] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0x56789a, 0x1234, 0x4c0, 0x4c0, 0, 0, 0x19a, 0x19a },
{ 2, 3, 0, 0, 0, 0xaaaaaaaa, 2, 2 },
{ 31, 157, 0, 0, 0x328c3ab3, 0x328c3ab3, 31, 31 },
{ -4329874, 43879, -98, 0x17df7, 0, 0, -29732, 17165 },
{ -4329874, -43879, 98, 0, 0, 0xffbe99a9, -29732, -4329874 },
{ 0x80000000u, -1, 0, 0, 0, 0x80000000u, 0, 0x80000000u },
};

int fpu_test_25(void)
{
long i;
unsigned int a, b, results[6];

for (i = 0; i < sizeof(wdiv_tests) / sizeof(wdiv_tests[0]); ++i) {
a = wdiv_tests[i].denom;
b = wdiv_tests[i].divisor;
asm("divw %0,%1,%2" : "=r" (results[0]) : "r" (a), "r" (b));
asm("divwu %0,%1,%2" : "=r" (results[1]) : "r" (a), "r" (b));
asm("divwe %0,%1,%2" : "=r" (results[2]) : "r" (a), "r" (b));
asm("divweu %0,%1,%2" : "=r" (results[3]) : "r" (a), "r" (b));
asm("modsw %0,%1,%2" : "=r" (results[4]) : "r" (a), "r" (b));
asm("moduw %0,%1,%2" : "=r" (results[5]) : "r" (a), "r" (b));
if (results[0] != wdiv_tests[i].divw ||
results[1] != wdiv_tests[i].divwu ||
results[2] != wdiv_tests[i].divwe ||
results[3] != wdiv_tests[i].divweu ||
results[4] != wdiv_tests[i].modsw ||
results[5] != wdiv_tests[i].moduw) {
print_hex(i, 2, " ");
print_hex(results[0], 8, " ");
print_hex(results[1], 8, " ");
print_hex(results[2], 8, " ");
print_hex(results[3], 8, " ");
print_hex(results[4], 8, " ");
print_hex(results[5], 8, "\r\n");
return i + 1;
}
}
return 0;
}

int fail = 0; int fail = 0;


void do_test(int num, int (*test)(void)) void do_test(int num, int (*test)(void))
@ -1458,6 +1562,8 @@ int main(void)
do_test(21, fpu_test_21); do_test(21, fpu_test_21);
do_test(22, fpu_test_22); do_test(22, fpu_test_22);
do_test(23, fpu_test_23); do_test(23, fpu_test_23);
do_test(24, fpu_test_24);
do_test(25, fpu_test_25);


return fail; return fail;
} }

@ -73,6 +73,8 @@ begin
assert (to_integer(unsigned(w)) + to_integer(unsigned(x)) + assert (to_integer(unsigned(w)) + to_integer(unsigned(x)) +
to_integer(unsigned(y))) <= 1 severity failure; to_integer(unsigned(y))) <= 1 severity failure;


assert (e_in.write_xerc_enable and fp_in.write_xerc) /= '1' severity failure;

assert not (e_in.valid = '1' and e_in.instr_tag.valid = '0') severity failure; assert not (e_in.valid = '1' and e_in.instr_tag.valid = '0') severity failure;
assert not (l_in.valid = '1' and l_in.instr_tag.valid = '0') severity failure; assert not (l_in.valid = '1' and l_in.instr_tag.valid = '0') severity failure;
assert not (fp_in.valid = '1' and fp_in.instr_tag.valid = '0') severity failure; assert not (fp_in.valid = '1' and fp_in.instr_tag.valid = '0') severity failure;
@ -168,6 +170,11 @@ begin
c_out.write_cr_data <= fp_in.write_cr_data; c_out.write_cr_data <= fp_in.write_cr_data;
end if; end if;


if fp_in.write_xerc = '1' then
c_out.write_xerc_enable <= '1';
c_out.write_xerc_data <= fp_in.xerc;
end if;

if l_in.write_enable = '1' then if l_in.write_enable = '1' then
w_out.write_reg <= l_in.write_reg; w_out.write_reg <= l_in.write_reg;
w_out.write_data <= l_in.write_data; w_out.write_data <= l_in.write_data;

Loading…
Cancel
Save