File size: 1,427 Bytes
2166d7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// EXP_APPROX: exp(-delta/256) in Q0.16 (65536 == 1.0) for delta >= 0.
//   y = delta * log2(e);  n = integer part, f = fraction
//   2^-f  ~ 16-segment LUT with linear interpolation;  result = 2^-f >> n
// One cycle of latency.

module fa_exp_approx
    import fa_pkg::*;
(
    input  logic               clk,
    input  logic               rst_n,

    input  logic               in_valid,
    input  logic [31:0]        delta,       // non-negative, logit units (1/256)

    output logic               out_valid,
    output logic [16:0]        result
);

    logic [11:0] dcl;
    logic [23:0] y8;
    logic [4:0]  n;
    logic [7:0]  f;
    logic [16:0] t0, t1, diff, base;
    logic [20:0] interp;
    logic [16:0] res_c;

    always_comb begin
        dcl  = (delta > 32'd4095) ? 12'd4095 : delta[11:0];
        y8   = 24'(dcl) * 24'd369 >> 8;
        n    = y8[12:8];
        f    = y8[7:0];
        t0   = exp_lut({1'b0, f[7:4]});
        t1   = exp_lut({1'b0, f[7:4]} + 5'd1);
        diff   = t0 - t1;
        interp = diff * f[3:0];
        base   = t0 - 17'(interp >> 4);
        res_c = (y8[23:8] >= 16'd16) ? 17'd0 : (base >> n);
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            out_valid <= 1'b0;
            result    <= '0;
        end else begin
            out_valid <= in_valid;
            result    <= res_c;
        end
    end

endmodule : fa_exp_approx