forked from cores/microwatt
				
			core: Add framework for an FPU
This adds the skeleton of a floating-point unit and implements the mffs and mtfsf instructions. Execute1 sends FP instructions to the FPU and receives busy, exception, FP interrupt and illegal interrupt signals from it. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>jtag-port
							parent
							
								
									76ec1a2f0a
								
							
						
					
					
						commit
						856e9e955f
					
				@ -0,0 +1,185 @@
 | 
			
		||||
-- Floating-point unit for Microwatt
 | 
			
		||||
 | 
			
		||||
library ieee;
 | 
			
		||||
use ieee.std_logic_1164.all;
 | 
			
		||||
use ieee.numeric_std.all;
 | 
			
		||||
 | 
			
		||||
library work;
 | 
			
		||||
use work.insn_helpers.all;
 | 
			
		||||
use work.decode_types.all;
 | 
			
		||||
use work.crhelpers.all;
 | 
			
		||||
use work.helpers.all;
 | 
			
		||||
use work.common.all;
 | 
			
		||||
 | 
			
		||||
entity fpu is
 | 
			
		||||
    port (
 | 
			
		||||
        clk : in std_ulogic;
 | 
			
		||||
        rst : in std_ulogic;
 | 
			
		||||
 | 
			
		||||
        e_in  : in  Execute1toFPUType;
 | 
			
		||||
        e_out : out FPUToExecute1Type;
 | 
			
		||||
 | 
			
		||||
        w_out : out FPUToWritebackType
 | 
			
		||||
        );
 | 
			
		||||
end entity fpu;
 | 
			
		||||
 | 
			
		||||
architecture behaviour of fpu is
 | 
			
		||||
 | 
			
		||||
    type state_t is (IDLE,
 | 
			
		||||
                     DO_MFFS, DO_MTFSF);
 | 
			
		||||
 | 
			
		||||
    type reg_type is record
 | 
			
		||||
        state        : state_t;
 | 
			
		||||
        busy         : std_ulogic;
 | 
			
		||||
        instr_done   : std_ulogic;
 | 
			
		||||
        do_intr      : std_ulogic;
 | 
			
		||||
        op           : insn_type_t;
 | 
			
		||||
        insn         : std_ulogic_vector(31 downto 0);
 | 
			
		||||
        dest_fpr     : gspr_index_t;
 | 
			
		||||
        fe_mode      : std_ulogic;
 | 
			
		||||
        rc           : std_ulogic;
 | 
			
		||||
        is_cmp       : std_ulogic;
 | 
			
		||||
        single_prec  : std_ulogic;
 | 
			
		||||
        fpscr        : std_ulogic_vector(31 downto 0);
 | 
			
		||||
        b            : std_ulogic_vector(63 downto 0);
 | 
			
		||||
        writing_back : std_ulogic;
 | 
			
		||||
        cr_result    : std_ulogic_vector(3 downto 0);
 | 
			
		||||
        cr_mask      : std_ulogic_vector(7 downto 0);
 | 
			
		||||
    end record;
 | 
			
		||||
 | 
			
		||||
    signal r, rin : reg_type;
 | 
			
		||||
 | 
			
		||||
    signal fp_result     : std_ulogic_vector(63 downto 0);
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
    fpu_0: process(clk)
 | 
			
		||||
    begin
 | 
			
		||||
        if rising_edge(clk) then
 | 
			
		||||
            if rst = '1' then
 | 
			
		||||
                r.state <= IDLE;
 | 
			
		||||
                r.busy <= '0';
 | 
			
		||||
                r.instr_done <= '0';
 | 
			
		||||
                r.do_intr <= '0';
 | 
			
		||||
                r.fpscr <= (others => '0');
 | 
			
		||||
                r.writing_back <= '0';
 | 
			
		||||
            else
 | 
			
		||||
                assert not (r.state /= IDLE and e_in.valid = '1') severity failure;
 | 
			
		||||
                r <= rin;
 | 
			
		||||
            end if;
 | 
			
		||||
        end if;
 | 
			
		||||
    end process;
 | 
			
		||||
 | 
			
		||||
    e_out.busy <= r.busy;
 | 
			
		||||
    e_out.exception <= r.fpscr(FPSCR_FEX);
 | 
			
		||||
    e_out.interrupt <= r.do_intr;
 | 
			
		||||
 | 
			
		||||
    w_out.valid <= r.instr_done and not r.do_intr;
 | 
			
		||||
    w_out.write_enable <= r.writing_back;
 | 
			
		||||
    w_out.write_reg <= r.dest_fpr;
 | 
			
		||||
    w_out.write_data <= fp_result;
 | 
			
		||||
    w_out.write_cr_enable <= r.instr_done and r.rc;
 | 
			
		||||
    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 &
 | 
			
		||||
                           r.cr_result & r.cr_result & r.cr_result & r.cr_result;
 | 
			
		||||
 | 
			
		||||
    fpu_1: process(all)
 | 
			
		||||
        variable v           : reg_type;
 | 
			
		||||
        variable illegal     : std_ulogic;
 | 
			
		||||
        variable j, k        : integer;
 | 
			
		||||
        variable flm         : std_ulogic_vector(7 downto 0);
 | 
			
		||||
    begin
 | 
			
		||||
        v := r;
 | 
			
		||||
        illegal := '0';
 | 
			
		||||
        v.busy := '0';
 | 
			
		||||
 | 
			
		||||
        -- capture incoming instruction
 | 
			
		||||
        if e_in.valid = '1' then
 | 
			
		||||
            v.insn := e_in.insn;
 | 
			
		||||
            v.op := e_in.op;
 | 
			
		||||
            v.fe_mode := or (e_in.fe_mode);
 | 
			
		||||
            v.dest_fpr := e_in.frt;
 | 
			
		||||
            v.single_prec := e_in.single;
 | 
			
		||||
            v.rc := e_in.rc;
 | 
			
		||||
            v.is_cmp := e_in.out_cr;
 | 
			
		||||
            v.cr_mask := num_to_fxm(1);
 | 
			
		||||
            v.b := e_in.frb;
 | 
			
		||||
        end if;
 | 
			
		||||
 | 
			
		||||
        v.writing_back := '0';
 | 
			
		||||
        v.instr_done := '0';
 | 
			
		||||
 | 
			
		||||
        case r.state is
 | 
			
		||||
            when IDLE =>
 | 
			
		||||
                if e_in.valid = '1' then
 | 
			
		||||
                    case e_in.insn(5 downto 1) is
 | 
			
		||||
                        when "00111" =>
 | 
			
		||||
                            if e_in.insn(8) = '0' then
 | 
			
		||||
                                v.state := DO_MFFS;
 | 
			
		||||
                            else
 | 
			
		||||
                                v.state := DO_MTFSF;
 | 
			
		||||
                            end if;
 | 
			
		||||
                        when others =>
 | 
			
		||||
                            illegal := '1';
 | 
			
		||||
                    end case;
 | 
			
		||||
                end if;
 | 
			
		||||
 | 
			
		||||
            when DO_MFFS =>
 | 
			
		||||
                v.writing_back := '1';
 | 
			
		||||
                case r.insn(20 downto 16) is
 | 
			
		||||
                    when "00000" =>
 | 
			
		||||
                        -- mffs
 | 
			
		||||
                    when others =>
 | 
			
		||||
                        illegal := '1';
 | 
			
		||||
                end case;
 | 
			
		||||
                v.instr_done := '1';
 | 
			
		||||
                v.state := IDLE;
 | 
			
		||||
 | 
			
		||||
            when DO_MTFSF =>
 | 
			
		||||
                if r.insn(25) = '1' then
 | 
			
		||||
                    flm := x"FF";
 | 
			
		||||
                elsif r.insn(16) = '1' then
 | 
			
		||||
                    flm := x"00";
 | 
			
		||||
                else
 | 
			
		||||
                    flm := r.insn(24 downto 17);
 | 
			
		||||
                end if;
 | 
			
		||||
                for i in 0 to 7 loop
 | 
			
		||||
                    k := i * 4;
 | 
			
		||||
                    if flm(i) = '1' then
 | 
			
		||||
                        v.fpscr(k + 3 downto k) := r.b(k + 3 downto k);
 | 
			
		||||
                    end if;
 | 
			
		||||
                end loop;
 | 
			
		||||
                v.instr_done := '1';
 | 
			
		||||
                v.state := IDLE;
 | 
			
		||||
 | 
			
		||||
        end case;
 | 
			
		||||
 | 
			
		||||
        -- Data path.
 | 
			
		||||
        -- Just enough to read FPSCR for now.
 | 
			
		||||
        fp_result <= x"00000000" & r.fpscr;
 | 
			
		||||
 | 
			
		||||
        v.fpscr(FPSCR_VX) := (or (v.fpscr(FPSCR_VXSNAN downto FPSCR_VXVC))) or
 | 
			
		||||
                             (or (v.fpscr(FPSCR_VXSOFT downto FPSCR_VXCVI)));
 | 
			
		||||
        v.fpscr(FPSCR_FEX) := or (v.fpscr(FPSCR_VX downto FPSCR_XX) and
 | 
			
		||||
                                  v.fpscr(FPSCR_VE downto FPSCR_XE));
 | 
			
		||||
        if r.rc = '1' then
 | 
			
		||||
            v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
 | 
			
		||||
        end if;
 | 
			
		||||
 | 
			
		||||
        if illegal = '1' then
 | 
			
		||||
            v.instr_done := '0';
 | 
			
		||||
            v.do_intr := '0';
 | 
			
		||||
            v.writing_back := '0';
 | 
			
		||||
            v.busy := '0';
 | 
			
		||||
            v.state := IDLE;
 | 
			
		||||
        else
 | 
			
		||||
            v.do_intr := v.instr_done and v.fpscr(FPSCR_FEX) and r.fe_mode;
 | 
			
		||||
            if v.state /= IDLE or v.do_intr = '1' then
 | 
			
		||||
                v.busy := '1';
 | 
			
		||||
            end if;
 | 
			
		||||
        end if;
 | 
			
		||||
 | 
			
		||||
        rin <= v;
 | 
			
		||||
        e_out.illegal <= illegal;
 | 
			
		||||
    end process;
 | 
			
		||||
 | 
			
		||||
end architecture behaviour;
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue