core: Add framework for an FPU
[microwatt.git] / fpu.vhdl
1 -- Floating-point unit for Microwatt
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5 use ieee.numeric_std.all;
6
7 library work;
8 use work.insn_helpers.all;
9 use work.decode_types.all;
10 use work.crhelpers.all;
11 use work.helpers.all;
12 use work.common.all;
13
14 entity fpu is
15 port (
16 clk : in std_ulogic;
17 rst : in std_ulogic;
18
19 e_in : in Execute1toFPUType;
20 e_out : out FPUToExecute1Type;
21
22 w_out : out FPUToWritebackType
23 );
24 end entity fpu;
25
26 architecture behaviour of fpu is
27
28 type state_t is (IDLE,
29 DO_MFFS, DO_MTFSF);
30
31 type reg_type is record
32 state : state_t;
33 busy : std_ulogic;
34 instr_done : std_ulogic;
35 do_intr : std_ulogic;
36 op : insn_type_t;
37 insn : std_ulogic_vector(31 downto 0);
38 dest_fpr : gspr_index_t;
39 fe_mode : std_ulogic;
40 rc : std_ulogic;
41 is_cmp : std_ulogic;
42 single_prec : std_ulogic;
43 fpscr : std_ulogic_vector(31 downto 0);
44 b : std_ulogic_vector(63 downto 0);
45 writing_back : std_ulogic;
46 cr_result : std_ulogic_vector(3 downto 0);
47 cr_mask : std_ulogic_vector(7 downto 0);
48 end record;
49
50 signal r, rin : reg_type;
51
52 signal fp_result : std_ulogic_vector(63 downto 0);
53
54 begin
55 fpu_0: process(clk)
56 begin
57 if rising_edge(clk) then
58 if rst = '1' then
59 r.state <= IDLE;
60 r.busy <= '0';
61 r.instr_done <= '0';
62 r.do_intr <= '0';
63 r.fpscr <= (others => '0');
64 r.writing_back <= '0';
65 else
66 assert not (r.state /= IDLE and e_in.valid = '1') severity failure;
67 r <= rin;
68 end if;
69 end if;
70 end process;
71
72 e_out.busy <= r.busy;
73 e_out.exception <= r.fpscr(FPSCR_FEX);
74 e_out.interrupt <= r.do_intr;
75
76 w_out.valid <= r.instr_done and not r.do_intr;
77 w_out.write_enable <= r.writing_back;
78 w_out.write_reg <= r.dest_fpr;
79 w_out.write_data <= fp_result;
80 w_out.write_cr_enable <= r.instr_done and r.rc;
81 w_out.write_cr_mask <= r.cr_mask;
82 w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
83 r.cr_result & r.cr_result & r.cr_result & r.cr_result;
84
85 fpu_1: process(all)
86 variable v : reg_type;
87 variable illegal : std_ulogic;
88 variable j, k : integer;
89 variable flm : std_ulogic_vector(7 downto 0);
90 begin
91 v := r;
92 illegal := '0';
93 v.busy := '0';
94
95 -- capture incoming instruction
96 if e_in.valid = '1' then
97 v.insn := e_in.insn;
98 v.op := e_in.op;
99 v.fe_mode := or (e_in.fe_mode);
100 v.dest_fpr := e_in.frt;
101 v.single_prec := e_in.single;
102 v.rc := e_in.rc;
103 v.is_cmp := e_in.out_cr;
104 v.cr_mask := num_to_fxm(1);
105 v.b := e_in.frb;
106 end if;
107
108 v.writing_back := '0';
109 v.instr_done := '0';
110
111 case r.state is
112 when IDLE =>
113 if e_in.valid = '1' then
114 case e_in.insn(5 downto 1) is
115 when "00111" =>
116 if e_in.insn(8) = '0' then
117 v.state := DO_MFFS;
118 else
119 v.state := DO_MTFSF;
120 end if;
121 when others =>
122 illegal := '1';
123 end case;
124 end if;
125
126 when DO_MFFS =>
127 v.writing_back := '1';
128 case r.insn(20 downto 16) is
129 when "00000" =>
130 -- mffs
131 when others =>
132 illegal := '1';
133 end case;
134 v.instr_done := '1';
135 v.state := IDLE;
136
137 when DO_MTFSF =>
138 if r.insn(25) = '1' then
139 flm := x"FF";
140 elsif r.insn(16) = '1' then
141 flm := x"00";
142 else
143 flm := r.insn(24 downto 17);
144 end if;
145 for i in 0 to 7 loop
146 k := i * 4;
147 if flm(i) = '1' then
148 v.fpscr(k + 3 downto k) := r.b(k + 3 downto k);
149 end if;
150 end loop;
151 v.instr_done := '1';
152 v.state := IDLE;
153
154 end case;
155
156 -- Data path.
157 -- Just enough to read FPSCR for now.
158 fp_result <= x"00000000" & r.fpscr;
159
160 v.fpscr(FPSCR_VX) := (or (v.fpscr(FPSCR_VXSNAN downto FPSCR_VXVC))) or
161 (or (v.fpscr(FPSCR_VXSOFT downto FPSCR_VXCVI)));
162 v.fpscr(FPSCR_FEX) := or (v.fpscr(FPSCR_VX downto FPSCR_XX) and
163 v.fpscr(FPSCR_VE downto FPSCR_XE));
164 if r.rc = '1' then
165 v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
166 end if;
167
168 if illegal = '1' then
169 v.instr_done := '0';
170 v.do_intr := '0';
171 v.writing_back := '0';
172 v.busy := '0';
173 v.state := IDLE;
174 else
175 v.do_intr := v.instr_done and v.fpscr(FPSCR_FEX) and r.fe_mode;
176 if v.state /= IDLE or v.do_intr = '1' then
177 v.busy := '1';
178 end if;
179 end if;
180
181 rin <= v;
182 e_out.illegal <= illegal;
183 end process;
184
185 end architecture behaviour;