Name | smolarith JSON |
Version |
0.1.1
JSON |
| download |
home_page | |
Summary | Soft-core arithmetic components written in Amaranth HDL |
upload_time | 2024-03-06 04:10:22 |
maintainer | |
docs_url | None |
author | |
requires_python | >=3.8 |
license | MIT |
keywords |
multiplication
division
hdl
cpu
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# smolarith
[![Documentation Status](https://readthedocs.org/projects/smolarith/badge/?version=latest)](https://smolarith.readthedocs.io/en/latest/?badge=latest)
Small arithmetic soft-cores for smol FPGAs. If your FPGA has hard IP
implementing functions in this repository, you should use those instead.
## Example
```python
from amaranth import signed, Module, C
from amaranth.lib.wiring import Component, Signature, Out, In
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(self.mul_factor.width, self.c_width)...
# more bits than we need.
self.mul = MulticycleMul(width=max(self.mul_factor.width,
self.c_width))
super().__init__({
"c": In(Signature({
"payload": Out(signed(self.c_width)),
"ready": In(1),
"valid": Out(1)
})),
"f": Out(Signature({
"payload": Out(signed(self.f_width)),
"ready": In(1),
"valid": Out(1)
}))
})
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)
def proc():
yield c2f.f.ready.eq(1)
yield
for i in range(start_c, end_c):
yield c2f.c.payload.eq(i)
yield c2f.c.valid.eq(1)
yield
yield c2f.c.valid.eq(0)
# Wait for module to calculate results.
while (yield c2f.f.valid) != 1:
yield
# This is a low-effort attempt to print fixed-point numbers
# by converting them into floating point.
print((yield c2f.c.payload) / 2**c2f.qc[1],
(yield c2f.f.payload) / 2**c2f.qf[1])
sim.add_sync_process(proc)
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=True)
else:
print(convert(c2f))
```
Raw data
{
"_id": null,
"home_page": "",
"name": "smolarith",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "",
"keywords": "multiplication division HDL cpu",
"author": "",
"author_email": "William D. Jones <thor0505@comcast.net>",
"download_url": "https://files.pythonhosted.org/packages/c9/b2/3677dc4a267a0992bb36ccf399552d53cf361f2efeb184166dbf598326ac/smolarith-0.1.1.tar.gz",
"platform": null,
"description": "# smolarith\n\n[![Documentation Status](https://readthedocs.org/projects/smolarith/badge/?version=latest)](https://smolarith.readthedocs.io/en/latest/?badge=latest)\n\nSmall arithmetic soft-cores for smol FPGAs. If your FPGA has hard IP\nimplementing functions in this repository, you should use those instead.\n\n## Example\n\n```python\nfrom amaranth import signed, Module, C\nfrom amaranth.lib.wiring import Component, Signature, Out, In\nfrom amaranth.back.verilog import convert\nfrom amaranth.sim import Simulator\n\nimport sys\nfrom smolarith import mul\nfrom smolarith.mul import MulticycleMul\n\n\nclass Celsius2Fahrenheit(Component):\n \"\"\"Module to convert Celsius temperatures to Fahrenheit (F = 1.8*C + 32).\"\"\"\n\n def __init__(self, *, qc, qf, scale_const=5):\n self.qc = qc\n self.qf = qf\n self.scale_const = scale_const\n\n self.c_width = self.qc[0] + self.qc[1]\n self.f_width = self.qf[0] + self.qf[1]\n # 1.8 not representable. 1.78125 will have to be close enough.\n # Q1.{self.scale_const}\n self.mul_factor = C(9*2**self.scale_const // 5)\n # Q6.{self.qc[1] + self.scale_const}\n self.add_factor = C(32 << (self.qc[1] + self.scale_const))\n # Mul result will have self.qc[1] + self.scale_const fractional bits.\n # Adjust to desired Fahrenheit precision.\n self.extra_bits = self.qc[1] + self.scale_const - self.qf[1]\n\n # Output will be 2*max(self.mul_factor.width, self.c_width)...\n # more bits than we need.\n self.mul = MulticycleMul(width=max(self.mul_factor.width,\n self.c_width))\n\n super().__init__({\n \"c\": In(Signature({\n \"payload\": Out(signed(self.c_width)),\n \"ready\": In(1),\n \"valid\": Out(1)\n })),\n \"f\": Out(Signature({\n \"payload\": Out(signed(self.f_width)),\n \"ready\": In(1),\n \"valid\": Out(1)\n }))\n })\n\n def elaborate(self, plat):\n m = Module()\n m.submodules.mul = self.mul\n\n m.d.comb += [\n # res = 1.8*C\n self.c.ready.eq(self.mul.inp.ready),\n self.mul.inp.valid.eq(self.c.valid),\n self.mul.inp.payload.a.eq(self.c.payload),\n self.mul.inp.payload.b.eq(self.mul_factor),\n self.mul.inp.payload.sign.eq(mul.Sign.SIGNED_UNSIGNED),\n\n # F = res + 32, scaled to remove frac bits we don't need.\n self.f.payload.eq((self.mul.outp.payload.o + self.add_factor) >>\n self.extra_bits),\n self.f.valid.eq(self.mul.outp.valid),\n self.mul.outp.ready.eq(self.f.ready)\n ]\n\n return m\n\n\ndef sim(*, c2f, start_c, end_c, gtkw=False):\n sim = Simulator(c2f)\n sim.add_clock(1e-6)\n\n def proc():\n yield c2f.f.ready.eq(1)\n yield\n\n for i in range(start_c, end_c):\n yield c2f.c.payload.eq(i)\n yield c2f.c.valid.eq(1)\n yield\n yield c2f.c.valid.eq(0)\n\n # Wait for module to calculate results.\n while (yield c2f.f.valid) != 1:\n yield\n\n # This is a low-effort attempt to print fixed-point numbers\n # by converting them into floating point.\n print((yield c2f.c.payload) / 2**c2f.qc[1],\n (yield c2f.f.payload) / 2**c2f.qf[1])\n\n sim.add_sync_process(proc)\n\n if gtkw:\n with sim.write_vcd(\"c2f.vcd\", \"c2f.gtkw\"):\n sim.run()\n else:\n sim.run()\n\n\nif __name__ == \"__main__\":\n # See: https://en.wikipedia.org/wiki/Q_(number_format)\n c2f = Celsius2Fahrenheit(qc=(8, 3), qf=(10, 3), scale_const=15)\n\n if len(sys.argv) > 1 and sys.argv[1] == \"sim\":\n if len(sys.argv) >= 2:\n start_c = int(float(sys.argv[2]) * 2**c2f.qc[1])\n else:\n start_c = -2**(c2f.qc[0] + c2f.qc[1] - 1)\n\n if len(sys.argv) >= 3:\n end_c = int(float(sys.argv[3]) * 2**c2f.qc[1])\n else:\n end_c = 2**(c2f.qc[0] + c2f.qc[1] - 1)\n\n sim(c2f=c2f, start_c=start_c, end_c=end_c, gtkw=True)\n else:\n print(convert(c2f))\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Soft-core arithmetic components written in Amaranth HDL",
"version": "0.1.1",
"project_urls": {
"Documentation": "https://smolarith.readthedocs.io",
"Repository": "https://github.com/cr1901/smolarith"
},
"split_keywords": [
"multiplication",
"division",
"hdl",
"cpu"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7f7490acb73720319372b951bce5292aeae7af8e7aac79f733af68fd0532c2ce",
"md5": "83eb828e8677602f9fa1be29441a1f48",
"sha256": "51b6087ab6f32cfc7b8e29ae57725901cd3e37bd997f3aa95106c61c7731f1a0"
},
"downloads": -1,
"filename": "smolarith-0.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "83eb828e8677602f9fa1be29441a1f48",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 16584,
"upload_time": "2024-03-06T04:10:20",
"upload_time_iso_8601": "2024-03-06T04:10:20.639957Z",
"url": "https://files.pythonhosted.org/packages/7f/74/90acb73720319372b951bce5292aeae7af8e7aac79f733af68fd0532c2ce/smolarith-0.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "c9b23677dc4a267a0992bb36ccf399552d53cf361f2efeb184166dbf598326ac",
"md5": "f9529b169fa354268e5fe8a2285692a8",
"sha256": "5fbe83144d96ad8ba913e368cbec54ecf09dbffe7de81fcd794a323a6961ba1c"
},
"downloads": -1,
"filename": "smolarith-0.1.1.tar.gz",
"has_sig": false,
"md5_digest": "f9529b169fa354268e5fe8a2285692a8",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 20047,
"upload_time": "2024-03-06T04:10:22",
"upload_time_iso_8601": "2024-03-06T04:10:22.649772Z",
"url": "https://files.pythonhosted.org/packages/c9/b2/3677dc4a267a0992bb36ccf399552d53cf361f2efeb184166dbf598326ac/smolarith-0.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-06 04:10:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "cr1901",
"github_project": "smolarith",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "smolarith"
}