from amaranth import signed, Module, C, Cat from amaranth.lib.wiring import Component, Signature, Out, In from amaranth.back.verilog import convert from amaranth.sim import Simulator, Settle import sys class Celsius2Fahrenheit(Component): @property def signature(self): return Signature({ "c": Out(signed(self.qc[0] + self.qc[1])), "f": In(signed(self.qf[0] + self.qf[1])) }) def __init__(self, *, qc, qf, muln=5): self.qc = qc self.qf = qf self.muln = muln super().__init__() def elaborate(self, plat): m = Module() # 1.8 not representable. 1.78125 will have to be close enough. mul_factor = C(9*2**self.muln // 5) # Q1.{self.muln} add_factor = C(32 << (self.qc[1] + self.muln)) # Q6.{self.qn + self.muln} # Technically we get a Q{self.qm + 1}.{self.qn + self.muln} after mul, # so truncate the extra decimal. # Overflow prob won't happen. extra_bits = self.qc[1] + self.muln - self.qf[1] intermediate = (mul_factor * self.c) + add_factor m.d.comb += self.f.eq(intermediate >> extra_bits) return m if __name__ == "__main__": c2f = Celsius2Fahrenheit(qc=(8, 3), qf=(10, 3), muln=15) if len(sys.argv) > 1 and sys.argv[1] == "sim": sim = Simulator(c2f) def proc(): for i in range(-2**(c2f.qc[0] + c2f.qc[1] - 1), 2**(c2f.qc[0] + c2f.qc[1] - 1)): yield c2f.c.eq(i) yield Settle() print((yield c2f.c) / 2**c2f.qc[1], (yield c2f.f) / 2**c2f.qf[1]) sim.add_process(proc) sim.run() else: print(convert(c2f))