diff --git a/primitives/bitnum/math.futil b/primitives/bitnum/math.futil index 8b36d4b14..64bc45054 100644 --- a/primitives/bitnum/math.futil +++ b/primitives/bitnum/math.futil @@ -1,3 +1,53 @@ extern "math.sv" { primitive std_sqrt(in: 32, go: 1, clk: 1) -> (out: 32, done: 1); -} \ No newline at end of file +} + +// Computes the unsigned value b^e, where +// b is the `base` and e is the `exp`. +component std_pow(base: 32, exp: 32) -> (out: 32) { + cells { + pow = std_reg(32); + count = std_reg(32); + mul = std_mult(32); + lt = std_lt(32); + incr = std_add(32); + } + wires { + group init { + pow.in = 32'd1; + pow.write_en = 1'd1; + count.in = 32'd0; + count.write_en = 1'd1; + init[done] = pow.done & count.done ? 1'd1; + } + group do_mul { + mul.left = base; + mul.right = pow.out; + pow.in = mul.out; + pow.write_en = 1'd1; + do_mul[done] = pow.done; + } + group incr_count { + incr.left = 32'd1; + incr.right = count.out; + count.in = incr.out; + count.write_en = 1'd1; + incr_count[done] = count.done; + } + group cond { + lt.right = exp; + lt.left = count.out; + cond[done] = 1'd1; + } + + out = pow.out; + } + control { + seq { + init; + while lt.out with cond { + par { do_mul; incr_count; } + } + } + } +} diff --git a/primitives/bitnum/unsigned.sv b/primitives/bitnum/unsigned.sv index 7027cfbf3..56b7fcea7 100644 --- a/primitives/bitnum/unsigned.sv +++ b/primitives/bitnum/unsigned.sv @@ -274,23 +274,3 @@ module std_mod #( ); assign out = left % right; endmodule - -module std_exp ( - input logic [31:0] exponent, - input logic go, - input logic clk, - output logic [31:0] out, - output logic done -); - always_ff @(posedge clk) begin - if (go) begin - // XXX: This is a hilariously bad approximation - /* verilator lint_off REALCVT */ - out <= /* 2.718281 */ 3 ** exponent; - done <= 1; - end else begin - out <= 0; - done <= 0; - end - end -endmodule diff --git a/tests/correctness/pow.expect b/tests/correctness/pow.expect new file mode 100644 index 000000000..7fd85cbc0 --- /dev/null +++ b/tests/correctness/pow.expect @@ -0,0 +1,11 @@ +{ + "base": [ + 2 + ], + "exp": [ + 10 + ], + "out": [ + 1024 + ] +} diff --git a/tests/correctness/pow.futil b/tests/correctness/pow.futil new file mode 100644 index 000000000..639345df1 --- /dev/null +++ b/tests/correctness/pow.futil @@ -0,0 +1,36 @@ +import "primitives/std.lib"; +import "primitives/bitnum/math.futil"; +component main() -> () { + cells { + out = std_mem_d1(32, 1, 1); + base = std_mem_d1(32, 1, 1); + exp = std_mem_d1(32, 1, 1); + base_reg = std_reg(32); + exp_reg = std_reg(32); + std_pow0 = std_pow(); + } + wires { + group init { + base.addr0 = 1'd0; + exp.addr0 = 1'd0; + base_reg.in = base.read_data; + exp_reg.in = exp.read_data; + base_reg.write_en = 1'd1; + exp_reg.write_en = 1'd1; + init[done] = base_reg.done & exp_reg.done ? 1'd1; + } + group fill_memory { + out.write_data = std_pow0.out; + out.addr0 = 1'd0; + out.write_en = 1'd1; + fill_memory[done] = out.done; + } + } + control { + seq { + init; + invoke std_pow0(base=base_reg.out, exp=exp_reg.out)(); + fill_memory; + } + } +} diff --git a/tests/correctness/pow.futil.data b/tests/correctness/pow.futil.data new file mode 100644 index 000000000..512e21361 --- /dev/null +++ b/tests/correctness/pow.futil.data @@ -0,0 +1,20 @@ +{ + "out": { + "data": [ + 0 + ], + "bitwidth": 32 + }, + "base": { + "data": [ + 2 + ], + "bitwidth": 32 + }, + "exp": { + "data": [ + 10 + ], + "bitwidth": 32 + } +}