Skip to content

Improve handling of signed numbers #450

@fdxmw

Description

@fdxmw

It is easy to make confusing mistakes with signed values in PyRTL. A broken example:

import pyrtl

a = -128
b = 127

# Compute a - b, which should be -255.
a_const = pyrtl.Const(name='a', val=a, signed=True, bitwidth=8)
b_const = pyrtl.Const(name='b', val=b, signed=True, bitwidth=8)

diff = a_const - b_const
diff.name = 'diff'

sim = pyrtl.Simulation()
sim.step()

print('expected diff is', a - b)

print('actual diff is',
      pyrtl.val_to_signed_integer(sim.inspect('diff'), bitwidth=diff.bitwidth),
      'bitwidth', diff.bitwidth)

When this example is run, it produces:

expected diff is -255
actual diff is 1 bitwidth 9

Note that the actual output has bitwidth 9, which is sufficient to represent -255.

This example is especially confusing because PyRTL has all the information to do the right thing, because we've marked the Consts as signed=True. To fix this example, the user currently has to call signed_sub instead of using the overloaded - operator.

The current approach is error prone because the user has to keep track of signed-ness as values propagate through their circuit, and make sure they call functions like signed_add and val_to_signed_integer at the right times.

It seems better to track signed-ness within WireVector, or within a WireVector subclass, but this raises questions about type promotion - what happens when we add a signed value and an unsigned value? My current intuition is to match Verilog's promotion behavior, but we should think about this more.

See also #417

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions