head 1.1; access; symbols; locks; strict; comment @# @; 1.1 date 2008.05.20.10.57.53; author lekernel; state Exp; branches; next ; commitid 3ae64832aea64567; desc @@ 1.1 log @Floating point adder @ text @/* * Pipelined floating point adder/substracter * Copyright (C) 2008 Sebastien Bourdeauducq - http://lekernel.net * This file is part of Milkymist. * * Milkymist is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ module fadd( input clk, input sub, input [31:0] a, input [31:0] b, output [31:0] r ); wire sa; wire [7:0] ea; wire [22:0] fa; assign sa = a[31]; assign ea = a[30:23]; assign fa = a[22:0]; wire sb; wire [7:0] eb; wire [22:0] fb; assign sb = b[31]; assign eb = b[30:23]; assign fb = b[22:0]; /* Stage 1 * Sort the numbers according to the exponent. * A becomes the number with the biggest exponent. * Negate b in case of substraction. */ reg sa1; reg [7:0] ea1; reg [22:0] fa1; reg sb1; reg [7:0] eb1; reg [22:0] fb1; always @@(posedge clk) begin if(ea > eb) begin sa1 <= sa; ea1 <= ea; fa1 <= fa; sb1 <= sb ^ sub; eb1 <= eb; fb1 <= fb; end else begin sa1 <= sb ^ sub; ea1 <= eb; fa1 <= fb; sb1 <= sa; eb1 <= ea; fb1 <= fa; end end /* Stage 2 * Add leading (integer) bits on the mantissas. * Compute the difference between the exponents. */ reg [7:0] diff2; reg sa2; reg [7:0] ea2; reg [23:0] fa2; reg sb2; reg [23:0] fb2; always @@(posedge clk) begin diff2 <= ea1 - eb1; sa2 <= sa1; ea2 <= ea1; fa2 <= {~(ea1 == 8'h00), fa1}; sb2 <= sb1; fb2 <= {~(eb1 == 8'h00), fb1}; end /* Stage 3 * Shift B's mantissa. * We add trailing zeros to improve precision, * and a leading zero (at stage 4) for the possible carry. */ reg sa3; reg [7:0] ea3; reg [23:0] fa3; reg sb3; reg [30:0] fb3; always @@(posedge clk) begin sa3 <= sa2; ea3 <= ea2; fa3 <= fa2; sb3 <= sb2; fb3 <= {fb2, 7'b0000000} >> diff2; end /* Stage 4 * Compute fa+fb, fa-fb and fb-fa. * Determine which one we will choose at stage 5. */ reg sa4; reg [7:0] ea4; reg [31:0] fapfb4; reg [31:0] famfb4; reg [31:0] fbmfa4; reg sub4; reg fcompare4; always @@(posedge clk) begin sa4 <= sa3; ea4 <= ea3; fapfb4 <= {1'b0, fa3, 7'b0000000} + {1'b0, fb3}; famfb4 <= {1'b0, fa3, 7'b0000000} - {1'b0, fb3}; fbmfa4 <= {1'b0, fb3} - {1'b0, fa3, 7'b0000000}; sub4 <= sa3 ^ sb3; fcompare4 <= {fa3, 7'b0000000} > fb3; end /* Stage 5 * Choose the right operation. * Count leading zeros (clz32 module). * Compute the sign of the result. * Test for zero result. */ reg sr5; reg [7:0] er5; reg [31:0] fr5; reg [31:0] fr4; always @@(sub4 or fcompare4 or famfb4 or fbmfa4 or fapfb4) begin if(sub4) begin if(fcompare4) fr4 <= famfb4; else fr4 <= fbmfa4; end else fr4 <= fapfb4; end wire [4:0] lz4; reg [4:0] lz5; clz32 clz( .d(fr4), .clz(lz4) ); reg zero5; always @@(posedge clk) begin sr5 <= sa4 ^ (sub4 & ~fcompare4); er5 <= ea4; fr5 <= fr4; zero5 <= fr4 == 32'h00000000; lz5 <= lz4; end /* Stage 6 * Normalize. */ reg sr6; reg [7:0] er6; reg [22:0] fr6; wire [31:0] sfr5; assign sfr5 = fr5 << lz5; always @@(posedge clk) begin if(zero5) begin sr6 <= 1'b0; er6 <= 8'h00; fr6 <= 23'b00000000_00000000_0000000; end else begin sr6 <= sr5; er6 <= er5 + 1 - lz5; fr6 <= sfr5[30:8]; end end assign r[31] = sr6; assign r[30:23] = er6; assign r[22:0] = fr6; endmodule @