smolarith
Small arithmetic soft-cores for smol FPGAs. If your FPGA has hard IP implementing functions in this repository, you should use those instead.
Example
from amaranth import signed, Module, C
from amaranth.lib.wiring import Component, Out, In
from amaranth.lib.stream import Signature
from amaranth.back.verilog import convert
from amaranth.sim import Simulator
import sys
from smolarith import mul
from smolarith.mul import MulticycleMul
class Celsius2Fahrenheit(Component):
"""Module to convert Celsius temperatures to Fahrenheit (F = 1.8*C + 32)."""
def __init__(self, *, qc, qf, scale_const=5):
self.qc = qc
self.qf = qf
self.scale_const = scale_const
self.c_width = self.qc[0] + self.qc[1]
self.f_width = self.qf[0] + self.qf[1]
# 1.8 not representable. 1.78125 will have to be close enough.
# Q1.{self.scale_const}
self.mul_factor = C(9*2**self.scale_const // 5)
# Q6.{self.qc[1] + self.scale_const}
self.add_factor = C(32 << (self.qc[1] + self.scale_const))
# Mul result will have self.qc[1] + self.scale_const fractional bits.
# Adjust to desired Fahrenheit precision.
self.extra_bits = self.qc[1] + self.scale_const - self.qf[1]
# Output will be 2*max(len(self.mul_factor), self.c_width)...
# more bits than we need.
self.mul = MulticycleMul(width=max(len(self.mul_factor),
self.c_width))
super().__init__({
"c": In(Signature(signed(self.c_width))),
"f": Out(Signature(signed(self.f_width))),
})
def elaborate(self, plat):
m = Module()
m.submodules.mul = self.mul
m.d.comb += [
# res = 1.8*C
self.c.ready.eq(self.mul.inp.ready),
self.mul.inp.valid.eq(self.c.valid),
self.mul.inp.payload.a.eq(self.c.payload),
self.mul.inp.payload.b.eq(self.mul_factor),
self.mul.inp.payload.sign.eq(mul.Sign.SIGNED_UNSIGNED),
# F = res + 32, scaled to remove frac bits we don't need.
self.f.payload.eq((self.mul.outp.payload.o + self.add_factor) >>
self.extra_bits),
self.f.valid.eq(self.mul.outp.valid),
self.mul.outp.ready.eq(self.f.ready)
]
return m
def sim(*, c2f, start_c, end_c, gtkw=False):
sim = Simulator(c2f)
sim.add_clock(1e-6)
async def tb(ctx):
await ctx.tick()
ctx.set(c2f.f.ready, 1)
await ctx.tick()
for i in range(start_c, end_c):
ctx.set(c2f.c.payload, i)
ctx.set(c2f.c.valid, 1)
await ctx.tick()
ctx.set(c2f.c.valid, 0)
# Wait for module to calculate results.
await ctx.tick().until(c2f.f.valid == 1)
# This is a low-effort attempt to print fixed-point numbers
# by converting them into floating point.
print(ctx.get(c2f.c.payload) / 2**c2f.qc[1],
ctx.get(c2f.f.payload) / 2**c2f.qf[1])
sim.add_testbench(tb)
if gtkw:
with sim.write_vcd("c2f.vcd", "c2f.gtkw"):
sim.run()
else:
sim.run()
if __name__ == "__main__":
# See: https://en.wikipedia.org/wiki/Q_(number_format)
c2f = Celsius2Fahrenheit(qc=(8, 3), qf=(10, 3), scale_const=15)
if len(sys.argv) > 1 and sys.argv[1] == "sim":
if len(sys.argv) >= 2:
start_c = int(float(sys.argv[2]) * 2**c2f.qc[1])
else:
start_c = -2**(c2f.qc[0] + c2f.qc[1] - 1)
if len(sys.argv) >= 3:
end_c = int(float(sys.argv[3]) * 2**c2f.qc[1])
else:
end_c = 2**(c2f.qc[0] + c2f.qc[1] - 1)
sim(c2f=c2f, start_c=start_c, end_c=end_c, gtkw=False)
else:
print(convert(c2f))
Release files for smolarith 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| smolarith-0.2.1.tar.gz | 21.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| smolarith-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.9 kB
Release files / smolarith-0.2.1.tar.gz
| Download URL | smolarith-0.2.1.tar.gz |
|---|---|
| Size | 21.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5dcfbe6f6de0eb54c662b00512099bb9eb2c92df43826326453cd1ce8118fddd
|
|
BLAKE2b-256 checksum How to use checksums |
0a46a3a2677ba8a4e1e0030c273a516326d1cc4c65c3a9634794f6f0dca79968
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.29.2 CPython/3.14.7 Linux/7.1.8+deb13-amd64
|
Release files / smolarith-0.2.1-py3-none-any.whl
| Download URL | smolarith-0.2.1-py3-none-any.whl |
|---|---|
| Size | 18.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
66c5ff8d91ca8f47d7e7dc618f745e3d11441e96a3217f30844d109d432c61ca
|
|
BLAKE2b-256 checksum How to use checksums |
73ee6808a325e975893f92575cabab557918c53a3afd473cc7ad1618573f0683
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
pdm/2.29.2 CPython/3.14.7 Linux/7.1.8+deb13-amd64
|