Helper Functions#
Cutting and Extending WireVectors#
The functions below provide ways of combining, slicing, and extending
WireVectors
in ways that are often useful in hardware
design. The functions below extend those member functions of the
WireVector
class itself (which provides support for the Python
builtin len
, slicing e.g. wire[3:6]
,
zero_extended()
,
sign_extended()
, and many operators such as
addition and multiplication).
- pyrtl.corecircuits.concat(*args)[source]#
Concatenates multiple WireVectors into a single WireVector.
- Parameters:
args (WireVector) – inputs to be concatenated
- Returns:
WireVector with length equal to the sum of the args’ lengths
You can provide multiple arguments and they will be combined with the right-most argument being the least significant bits of the result. Note that if you have a list of arguments to concat together you will likely want index 0 to be the least significant bit and so if you unpack the list into the arguments here it will be backwards. The function
concat_list()
is provided for that case specifically.Example using
concat
to combine two bytes into a 16-bit quantity:concat(msb, lsb)
- pyrtl.corecircuits.concat_list(wire_list)[source]#
Concatenates a list of WireVectors into a single WireVector.
- Parameters:
wire_list (list[WireVector]) – list of WireVectors to concat
- Returns:
WireVector with length equal to the sum of the args’ lengths
This take a list of WireVectors and concats them all into a single WireVector with the element at index 0 serving as the least significant bits. This is useful when you have a variable number of WireVectors to concatenate, otherwise
concat()
is prefered.Example using
concat_list
to combine two bytes into a 16-bit quantity:mylist = [lsb, msb] concat_list(mylist)
- pyrtl.corecircuits.match_bitwidth(*args, **opt)[source]#
Matches the argument wires’ bitwidth via zero or sign extension, returning new WireVectors
- Parameters:
args (WireVector) – WireVectors of which to match bitwidths
opt – Optional keyword argument
signed=True
(defaults to False)
- Returns:
tuple of args in order with extended bits
Example of matching the bitwidths of two WireVectors
a
andb
with zero extension:a, b = match_bitwidth(a, b)
Example of matching the bitwidths of three WireVectors
a
,b
, andc
with with sign extension:a, b, c = match_bitwidth(a, b, c, signed=True)
- pyrtl.helperfuncs.truncate(wirevector_or_integer, bitwidth)[source]#
Returns a WireVector or integer truncated to the specified bitwidth
- Parameters:
wirevector_or_integer – Either a WireVector or an integer to be truncated.
bitwidth (int) – The length to which the first argument should be truncated.
- Returns:
A truncated WireVector or integer as appropriate.
This function truncates the most significant bits of the input, leaving a result that is only bitwidth bits wide. For integers this is performed with a simple bitmask of size bitwidth. For WireVectors the function calls
WireVector.truncate()
and returns a WireVector of the specified bitwidth.Examples:
truncate(9,3) # returns 1 (0b1001 truncates to 0b001) truncate(5,3) # returns 5 (0b101 truncates to 0b101) truncate(-1,3) # returns 7 (-0b1 truncates to 0b111) y = truncate(x+1, x.bitwidth) # y.bitwdith will equal x.bitwidth
- pyrtl.helperfuncs.chop(w, *segment_widths)[source]#
Returns a list of WireVectors, each a slice of the original w.
- Parameters:
w (WireVector) – The WireVector to be chopped up into segments
segment_widths (int) – Additional arguments are integers which are bitwidths
- Returns:
A list of WireVectors each with a proper segment width
- Return type:
List[WireVector]
This function chops a WireVector into a set of smaller WireVectors of different lengths. It is most useful when multiple “fields” are contained with a single WireVector, for example when breaking apart an instruction. For example, if you wish to break apart a 32-bit MIPS I-type (Immediate) instruction you know it has an 6-bit opcode, 2 5-bit operands, and 16-bit offset. You could take each of those slices in absolute terms:
offset=instr[0:16]
,rt=instr[16:21]
and so on, but then you have to do the arithmetic yourself. With this function you can do all the fields at once which can be seen in the examples below.As a check, chop will throw an error if the sum of the lengths of the fields given is not the same as the length of the WireVector to chop. Note also that chop assumes that the “rightmost” arguments are the least signficant bits (just like
concat()
) which is normal for hardware functions but makes the list order a little counter intuitive.Examples:
opcode, rs, rt, offset = chop(instr, 6, 5, 5, 16) # MIPS I-type instruction opcode, instr_index = chop(instr, 6, 26) # MIPS J-type instruction opcode, rs, rt, rd, sa, function = chop(instr, 6, 5, 5, 5, 5, 6) # MIPS R-type msb, middle, lsb = chop(data, 1, 30, 1) # break out the most and least significant bits
Coercion to WireVector#
In PyRTL there is only one function in charge of coercing values into
WireVectors
, and that is as_wires()
. This
function is called in almost all helper functions and classes to manage the
mixture of constants and WireVectors that naturally occur in hardware
development.
- pyrtl.corecircuits.as_wires(val, bitwidth=None, truncating=True, block=None)[source]#
Return wires from val which may be wires, integers (including IntEnums), strings, or bools.
- Parameters:
val – a WireVector-like object or something that can be converted into a Const
bitwidth (int) – The bitwidth the resulting wire should be
truncating (bool) – determines whether bits will be dropped to achieve the desired bitwidth if it is too long (if true, the most-significant bits will be dropped)
block (Block) – block to use for wire
This function is mainly used to coerce values into WireVectors (for example, operations such as
x + 1
where 1 needs to be converted to a Const WireVector). An example:def myhardware(input_a, input_b): a = as_wires(input_a) b = as_wires(input_b) myhardware(3, x)
as_wires()
will convert the 3 to Const but keepx
unchanged assuming it is a WireVector.
Control Flow Hardware#
- pyrtl.corecircuits.mux(index, *mux_ins, **kwargs)[source]#
Multiplexer returning the value of the wire from mux_ins according to index.
- Parameters:
index (WireVector) – used as the select input to the multiplexer
mux_ins (WireVector) – additional WireVector arguments selected when select>1
kwargs (WireVector) – additional WireVectors, keyword arg “default” If you are selecting between fewer items than your index can address, you can use the default keyword argument to auto-expand those terms. For example, if you have a 3-bit index but are selecting between 6 options, you need to specify a value for those other 2 possible values of index (0b110 and 0b111).
- Returns:
WireVector of length of the longest input (not including index)
To avoid confusion, if you are using the mux where the index is a “predicate” (meaning something that you are checking the truth value of rather than using it as a number) it is recommended that you use
select()
instead as named arguments because the ordering is different from the classic ternary operator of some languages.Example of multiplexing between
a0
anda1
:index = WireVector(1) mux(index, a0, a1)
Example of multiplexing between
a0
,a1
,a2
,a3
:index = WireVector(2) mux(index, a0, a1, a2, a3)
Example of default to specify additional arguments:
index = WireVector(3) mux(index, a0, a1, a2, a3, a4, a5, default=0)
- pyrtl.corecircuits.select(sel, truecase, falsecase)[source]#
Multiplexer returning falsecase when
sel == 0
, otherwise truecase.- Parameters:
sel (WireVector) – used as the select input to the multiplexer
truecase (WireVector) – the WireVector selected if
sel == 1
falsecase (WireVector) – the WireVector selected if
sel == 0
The hardware this generates is exactly the same as
mux()
but by putting the true case as the first argument it matches more of the C-style ternary operator semantics which can be helpful for readability.Example of taking the min of
a
and 5:select(a < 5, truecase=a, falsecase=5)
- pyrtl.corecircuits.enum_mux(cntrl, table, default=None, strict=True)[source]#
Build a mux for the control signals specified by an enum.
- Parameters:
cntrl – is a WireVector and control for the mux.
table – is a dictionary of the form mapping enum to WireVector.
default – is a WireVector to use when the key is not present. In addition it is possible to use the key otherwise to specify a default value, but it is an error if both are supplied.
strict (bool) – when True, check that the dictionary has an entry for every possible value in the enum. Note that if a default is set, then this check is not performed as the default will provide valid values for any underspecified keys.
- Returns:
a WireVector which is the result of the mux.
Examples:
from enum import IntEnum class Command(IntEnum): ADD = 1 SUB = 2 enum_mux(cntrl, {Command.ADD: a + b, Command.SUB: a - b}) enum_mux(cntrl, {Command.ADD: a + b}, strict=False) # SUB case undefined enum_mux(cntrl, {Command.ADD: a + b, otherwise: a - b}) enum_mux(cntrl, {Command.ADD: a + b}, default=a - b)
- pyrtl.corecircuits.bitfield_update(w, range_start, range_end, newvalue, truncating=False)[source]#
Return WireVector w but with some of the bits overwritten by newvalue.
- Parameters:
w (WireVector) – a WireVector to use as the starting point for the update
range_start (int) – the start of the range of bits to be updated
range_end (int) – the end of the range of bits to be updated
newvalue (int) – the value to be written in to the start:end range
truncating (bool) – if true, silently clip newvalue to the proper bitwidth rather than throw an error if the value provided is too large
Given a WireVector w, this function returns a new WireVector that is identical to w except in the range of bits specified. In that specified range, the value newvalue is swapped in. For example:
bitfield_update(w, 20, 23, 0x7)
will return a WireVector of the same length as w, and with the same values as w, but with bits 20, 21, and 22 all set to 1.
Note that range_start and range_end will be inputs to a slice and so standard Python slicing rules apply (e.g. negative values for end-relative indexing and support for None).
w = bitfield_update(w, 20, 23, 0x7) # sets bits 20, 21, 22 to 1 w = bitfield_update(w, 20, 23, 0x6) # sets bit 20 to 0, bits 21 and 22 to 1 w = bitfield_update(w, 20, None, 0x7) # assuming w is 32 bits, sets bits 31..20 = 0x7 w = bitfield_update(w, -1, None, 0x1) # set the MSB (bit) to 1 w = bitfield_update(w, None, -1, 0x9) # set the bits before the MSB (bit) to 9 w = bitfield_update(w, None, 1, 0x1) # set the LSB (bit) to 1 w = bitfield_update(w, 1, None, 0x9) # set the bits after the LSB (bit) to 9
- pyrtl.corecircuits.bitfield_update_set(w, update_set, truncating=False)[source]#
Return WireVector w but with some of the bits overwritten by values in update_set.
- Parameters:
w (WireVector) – a WireVector to use as the starting point for the update
update_set – a map from tuples of integers (bit ranges) to the new values
truncating (bool) – if true, silently clip new values to the proper bitwidth rather than throw an error if the value provided is too large
Given a WireVector w, this function returns a new WireVector that is identical to w except in the range of bits specified. When multiple non-overlapping fields need to be updated in a single cycle this provides a clearer way to describe that behavior than iterative calls to
bitfield_update()
(although that is, in fact, what it is doing).w = bitfield_update_set(w, { (20, 23): 0x6, # sets bit 20 to 0, bits 21 and 22 to 1 (26, None): 0x7, # assuming w is 32 bits, sets bits 31..26 to 0x7 (None, 1): 0x0, # set the LSB (bit) to 0 })
- pyrtl.helperfuncs.match_bitpattern(w, bitpattern, field_map=None)[source]#
Returns a single-bit WireVector that is 1 if and only if w matches the bitpattern, and a tuple containing the matched fields, if any. Compatible with the with statement.
- Parameters:
w (WireVector) – The WireVector to be compared to the bitpattern
bitpattern (str) – A string holding the pattern (of bits and wildcards) to match
field_map – (optional) A map from single-character field name in the bitpattern to the desired name of field in the returned namedtuple. If given, all non-“1”/”0”/”?” characters in the bitpattern must be present in the map.
- Returns:
A tuple of 1-bit WireVector carrying the result of the comparison, followed by a named tuple containing the matched fields, if any.
This function will compare a multi-bit WireVector to a specified pattern of bits, where some of the pattern can be “wildcard” bits. If any of the
1
or0
values specified in the bitpattern fail to match the WireVector during execution, a0
will be produced, otherwise the value carried on the wire will be1
. The wildcard characters can be any other alphanumeric character, with characters other than?
having special functionality (see below). The string must have length equal to the WireVector specified, although whitespace and underscore characters will be ignored and can be used for pattern readability.For all other characters besides
1
,0
, or?
, a tuple of WireVectors will be returned as the second return value. Each character will be treated as the name of a field, and non-consecutive fields with the same name will be concatenated together, left-to-right, into a single field in the resultant tuple. For example,01aa1?bbb11a
will match a string such as010010100111
, and the resultant matched fields are:(a, b) = (0b001, 0b100)
where the
a
field is the concenation of bits 9, 8, and 0, and theb
field is the concenation of bits 5, 4, and 3. Thus, arbitrary characters beside?
act as wildcard characters for the purposes of matching, with the additional benefit of returning the WireVectors corresponding to those fields.A prime example of this is for decoding instructions. Here we decode some RISC-V:
with pyrtl.conditional_assignment: with match_bitpattern(inst, "iiiiiiiiiiiirrrrr010ddddd0000011") as (imm, rs1, rd): regfile[rd] |= mem[(regfile[rs1] + imm.sign_extended(32)).truncate(32)] pc.next |= pc + 1 with match_bitpattern(inst, "iiiiiiirrrrrsssss010iiiii0100011") as (imm, rs2, rs1): mem[(regfile[rs1] + imm.sign_extended(32)).truncate(32)] |= regfile[rs2] pc.next |= pc + 1 with match_bitpattern(inst, "0000000rrrrrsssss111ddddd0110011") as (rs2, rs1, rd): regfile[rd] |= regfile[rs1] & regfile[rs2] pc.next |= pc + 1 with match_bitpattern(inst, "0000000rrrrrsssss000ddddd0110011") as (rs2, rs1, rd): regfile[rd] |= (regfile[rs1] + regfile[rs2]).truncate(32) pc.next |= pc + 1 # ...etc...
Some smaller examples:
m, _ = match_bitpattern(w, '0101') # basically the same as w == '0b0101' m, _ = match_bitpattern(w, '01?1') # m will be true when w is '0101' or '0111' m, _ = match_bitpattern(w, '??01') # m be true when last two bits of w are '01' m, _ = match_bitpattern(w, '??_0 1') # spaces/underscores are ignored, same as line above m, (a, b) = match_pattern(w, '01aa1?bbb11a') # all bits with same letter make up same field m, fs = match_pattern(w, '01aa1?bbb11a', {'a': 'foo', 'b': 'bar'}) # fields fs.foo, fs.bar
Creating Lists of WireVectors#
- pyrtl.helperfuncs.input_list(names, bitwidth=None)[source]#
Allocate and return a list of
Inputs
.- Parameters:
names – Names for the Inputs. Can be a list or single comma/space-separated string
bitwidth (int) – The desired bitwidth for the resulting Inputs.
- Returns:
List of Inputs.
- Return type:
List[Input]
Equivalent to:
wirevector_list(names, bitwidth, wvtype=pyrtl.wire.Input)
- pyrtl.helperfuncs.output_list(names, bitwidth=None)[source]#
Allocate and return a list of
Outputs
.- Parameters:
names – Names for the Outputs. Can be a list or single comma/space-separated string
bitwidth (int) – The desired bitwidth for the resulting Outputs.
- Returns:
List of Outputs.
- Return type:
List[Output]
Equivalent to:
wirevector_list(names, bitwidth, wvtype=pyrtl.wire.Output)
- pyrtl.helperfuncs.register_list(names, bitwidth=None)[source]#
Allocate and return a list of
Registers
.- Parameters:
names – Names for the Registers. Can be a list or single comma/space-separated string
bitwidth (int) – The desired bitwidth for the resulting Registers.
- Returns:
List of Registers.
- Return type:
List[Register]
Equivalent to:
wirevector_list(names, bitwidth, wvtype=pyrtl.wire.Register)
- pyrtl.helperfuncs.wirevector_list(names, bitwidth=None, wvtype=<class 'pyrtl.wire.WireVector'>)[source]#
Allocate and return a list of WireVectors.
- Parameters:
names – Names for the WireVectors. Can be a list or single comma/space-separated string
bitwidth (int) – The desired bitwidth for the resulting WireVectors.
wvtype (WireVector) – Which WireVector type to create.
- Returns:
List of WireVectors.
- Return type:
List[WireVector]
Additionally, the names string can also contain an additional bitwidth specification separated by a
/
in the name. This cannot be used in combination with a bitwidth value other than1
.Examples:
wirevector_list(['name1', 'name2', 'name3']) wirevector_list('name1, name2, name3') wirevector_list('input1 input2 input3', bitwidth=8, wvtype=pyrtl.wire.Input) wirevector_list('output1, output2 output3', bitwidth=3, wvtype=pyrtl.wire.Output) wirevector_list('two_bits/2, four_bits/4, eight_bits/8') wirevector_list(['name1', 'name2', 'name3'], bitwidth=[2, 4, 8])
Interpreting Vectors of Bits#
Under the hood, every single value a PyRTL design operates on is a bit vector (which is, in turn, simply an integer of bounded power-of-two size. Interpreting these bit vectors as humans, and turning human understandable values into their corresponding bit vectors, can both be a bit of a pain. The functions below do not create any hardware but rather help in the process of reasoning about bit vector representations of human understandable values.
- pyrtl.helperfuncs.val_to_signed_integer(value, bitwidth)[source]#
Return value as intrepreted as a signed integer under two’s complement.
- Parameters:
value (int) – a Python integer holding the value to convert
bitwidth (int) – the length of the integer in bits to assume for conversion
- Returns:
value as a signed integer
- Return type:
int
Given an unsigned integer (not a WireVector!) convert that to a signed integer. This is useful for printing and interpreting values which are negative numbers in two’s complement.
val_to_signed_integer(0xff, 8) == -1
- pyrtl.helperfuncs.val_to_formatted_str(val, format, enum_set=None)[source]#
Return a string representation of the value given format specified.
- Parameters:
val (int) – an unsigned integer to convert
format (str) – a string holding a format which will be used to convert the data string
enum_set – an iterable of enums which are used as part of the converstion process
- Returns:
a human-readable string representing val.
- Return type:
str
Given an unsigned integer (not a WireVector!) convert that to a human-readable string. This helps deal with signed/unsigned numbers (simulation operates on values that have been converted via two’s complement), but it also generates hex, binary, and enum types as outputs. It is easiest to see how it works with some examples.
val_to_formatted_str(2, 's3') == '2' val_to_formatted_str(7, 's3') == '-1' val_to_formatted_str(5, 'b3') == '101' val_to_formatted_str(5, 'u3') == '5' val_to_formatted_str(5, 's3') == '-3' val_to_formatted_str(10, 'x3') == 'a' class Ctl(Enum): ADD = 5 SUB = 12 val_to_formatted_str(5, 'e3/Ctl', [Ctl]) == 'ADD' val_to_formatted_str(12, 'e3/Ctl', [Ctl]) == 'SUB'
- pyrtl.helperfuncs.formatted_str_to_val(data, format, enum_set=None)[source]#
Return an unsigned integer representation of the data given format specified.
- Parameters:
data (str) – a string holding the value to convert
format (str) – a string holding a format which will be used to convert the data string
enum_set – an iterable of enums which are used as part of the conversion process
- Returns:
data as a signed integer
- Return type:
int
Given a string (not a WireVector!) convert that to an unsigned integer ready for input to the simulation enviornment. This helps deal with signed/unsigned numbers (simulation assumes the values have been converted via two’s complement already), but it also takes hex, binary, and enum types as inputs. It is easiest to see how it works with some examples.
formatted_str_to_val('2', 's3') == 2 # 0b010 formatted_str_to_val('-1', 's3') == 7 # 0b111 formatted_str_to_val('101', 'b3') == 5 formatted_str_to_val('5', 'u3') == 5 formatted_str_to_val('-3', 's3') == 5 formatted_str_to_val('a', 'x3') == 10 class Ctl(Enum): ADD = 5 SUB = 12 formatted_str_to_val('ADD', 'e3/Ctl', [Ctl]) == 5 formatted_str_to_val('SUB', 'e3/Ctl', [Ctl]) == 12
- pyrtl.helperfuncs.infer_val_and_bitwidth(rawinput, bitwidth=None, signed=False)[source]#
Return a tuple (value, bitwidth) infered from the specified input.
- Parameters:
rawinput – a bool, int, or verilog-style string constant
bitwidth (int) – an integer bitwidth or (by default) None
signed (bool) – a bool (by default set False) to include bits for proper two’s complement
- Returns:
tuple of integers (value, bitwidth)
- Return type:
(int, int)
Given a boolean, integer, or verilog-style string constant, this function returns a tuple of two integers (value, bitwidth) which are infered from the specified rawinput. The tuple returned is, in fact, a named tuple with names .value and .bitwidth for fields 0 and 1 respectively. If signed is True, bits will be included to ensure a proper two’s complement representation is possible, otherwise it is assume all bits can be used for standard unsigned representation. Error checks are performed that determine if the bitwidths specified are sufficient and appropriate for the values specified. Examples can be found below
infer_val_and_bitwidth(2, bitwidth=5) == (2, 5) infer_val_and_bitwidth(3) == (3, 2) # bitwidth infered from value infer_val_and_bitwidth(3, signed=True) == (3, 3) # need a bit for the leading zero infer_val_and_bitwidth(-3, signed=True) == (5, 3) # 5 = -3 & 0b111 = ..111101 & 0b111 infer_val_and_bitwidth(-4, signed=True) == (4, 3) # 4 = -4 & 0b111 = ..111100 & 0b111 infer_val_and_bitwidth(-3, bitwidth=5, signed=True) == (29, 5) infer_val_and_bitwidth(-3) ==> Error # negative numbers require bitwidth or signed=True infer_val_and_bitwidth(3, bitwidth=2) == (3, 2) infer_val_and_bitwidth(3, bitwidth=2, signed=True) ==> Error # need space for sign bit infer_val_and_bitwidth(True) == (1, 1) infer_val_and_bitwidth(False) == (0, 1) infer_val_and_bitwidth("5'd12") == (12, 5) infer_val_and_bitwidth("5'b10") == (2, 5) infer_val_and_bitwidth("5'b10").bitwidth == 5 infer_val_and_bitwidth("5'b10").value == 2 infer_val_and_bitwidth("8'B 0110_1100") == (108, 8)
- pyrtl.helperfuncs.log2(integer_val)[source]#
Return the log base 2 of the integer provided.
- Parameters:
integer_val (int) – The integer to take the log base 2 of.
- Returns:
The log base 2 of integer_val, or throw PyRTL error if not power of 2
- Return type:
int
This function is useful when checking that powers of 2 are provided on inputs to functions. It throws an error if a negative value is provided or if the value provided is not an even power of two.
Examples:
log2(2) # returns 1 log2(256) # returns 8 addrwidth = log2(size_of_memory) # will fail if size_of_memory is not a power of two
Debugging#
- pyrtl.core.set_debug_mode(debug=True)[source]#
Set the global debug mode.
- Parameters:
debug (bool) – Optional boolean paramter to which debug mode will be set
This function will set the debug mode to the specified value. Debug mode is, by default, set to off to keep the performance of the system. With debug mode set to true, all temporary WireVectors created will be given a name based on the line of code on which they were created and a snapshot of the call-stack for those WireVectors will be kept as well.
- pyrtl.helperfuncs.probe(w, name=None)[source]#
Print useful information about a WireVector when in debug mode.
- Parameters:
w (WireVector) – WireVector from which to get info
name (str) – optional name for probe (defaults to an autogenerated name)
- Returns:
original WireVector w
- Return type:
Probe can be inserted into a existing design easily as it returns the original wire unmodified. For example
y <<= x[0:3] + 4
could be turned intoy <<= probe(x)[0:3] + 4
to give visibility into both the origin ofx
(including the line that WireVector was originally created) and the run-time values ofx
(which will be named and thus show up by default in a trace). Likewisey <<= probe(x[0:3]) + 4
,y <<= probe(x[0:3] + 4)
, andprobe(y) <<= x[0:3] + 4
are all valid uses of probe.Note: probe does actually add an Output wire to the working block of w (which can confuse various post-processing transforms such as output to verilog).
- pyrtl.helperfuncs.rtl_assert(w, exp, block=None)[source]#
Add hardware assertions to be checked on the RTL design.
- Parameters:
w (WireVector) – should be a WireVector
exp (Exception) – Exception to throw when assertion fails
block (Block) – block to which the assertion should be added (default to working block)
- Returns:
the Output wire for the assertion (can be ignored in most cases)
- Return type:
If at any time during execution the wire w is not true (i.e. asserted low) then simulation will raise exp.
- pyrtl.helperfuncs.check_rtl_assertions(sim)[source]#
Checks the values in sim to see if any registers assertions fail.
- Parameters:
sim (Simulation) – Simulation in which to check the assertions
- Returns:
None
Reductions#
- pyrtl.corecircuits.and_all_bits(vector)[source]#
Returns WireVector, the result of “and”ing all items of the argument vector.
- Parameters:
vector (WireVector) – Takes a single arbitrary length WireVector
- Returns:
Returns a 1 bit result, the bitwise and of all of the bits in the vector to a single bit.
- pyrtl.corecircuits.or_all_bits(vector)[source]#
Returns WireVector, the result of “or”ing all items of the argument vector.
- Parameters:
vector (WireVector) – Takes a single arbitrary length WireVector
- Returns:
Returns a 1 bit result, the bitwise or of all of the bits in the vector to a single bit.
- pyrtl.corecircuits.xor_all_bits(vector)[source]#
Returns WireVector, the result of “xor”ing all items of the argument vector.
- Parameters:
vector (WireVector) – Takes a single arbitrary length WireVector
- Returns:
Returns a 1 bit result, the bitwise xor of all of the bits in the vector to a single bit.
- pyrtl.corecircuits.parity(vector)#
Returns WireVector, the result of “xor”ing all items of the argument vector.
- Parameters:
vector (WireVector) – Takes a single arbitrary length WireVector
- Returns:
Returns a 1 bit result, the bitwise xor of all of the bits in the vector to a single bit.
- pyrtl.corecircuits.rtl_any(*vectorlist)[source]#
Hardware equivalent of Python native
any
.- Parameters:
vectorlist (WireVector) – all arguments are WireVectors of length 1
- Returns:
WireVector of length 1
Returns a 1-bit WireVector which will hold a ‘1’ if any of the inputs are ‘1’ (i.e. it is a big ol’ OR gate). If no inputs are provided it will return a Const 0 (since there are no ‘1’s present) similar to Python’s
any
function called with an empty list.Examples:
rtl_any(thing1, thing2, thing3) # same as thing1 | thing2 | thing3 rtl_any(*[list_of_things]) # the unpack operator ("*") can be used for lists rtl_any() # returns Const(False) which comes up if the list above is empty
- pyrtl.corecircuits.rtl_all(*vectorlist)[source]#
Hardware equivalent of Python native
all
.- Parameters:
vectorlist (WireVector) – all arguments are WireVectors of length 1
- Returns:
WireVector of length 1
Returns a 1-bit WireVector which will hold a ‘1’ only if all of the inputs are ‘1’ (i.e. it is a big ol’ AND gate). If no inputs are provided it will return a Const 1 (since there are no ‘0’s present) similar to Python’s
all
function called with an empty list.Examples:
rtl_all(thing1, thing2, thing3) # same as thing1 & thing2 & thing3 rtl_all(*[list_of_things]) # the unpack operator ("*") can be used for lists rtl_all() # returns Const(True) which comes up if the list above is empty
Extended Logic and Arithmetic#
The functions below provide ways of comparing and arithmetically combining
WireVectors
in ways that are often useful in hardware
design. The functions below extend those member functions of the
WireVector
class itself (which provides support for addition,
unsigned multiplication, unsigned comparison, and many others).
- pyrtl.corecircuits.signed_add(a, b)[source]#
Return a WireVector for result of signed addition.
- Parameters:
a (WireVector) – a WireVector to serve as first input to addition
b (WireVector) – a WireVector to serve as second input to addition
Given WireVectors with length
n
andm
, the result of the signed addition has length:max(n, m) + 1
The inputs are two’s complement sign extended to the same length before adding. If an integer is passed to either a or b, it will be converted automatically to a two’s complement constant
- pyrtl.corecircuits.signed_mult(a, b)[source]#
Return
a * b
wherea
andb
are treated as signed values.- Parameters:
a (WireVector) – a wirevector to serve as first input to multiplication
b (WireVector) – a wirevector to serve as second input to multiplication
If an integer is passed to either
a
orb
, it will be converted automatically to a two’s complement constant
- pyrtl.corecircuits.signed_lt(a, b)[source]#
Return a single bit result of signed less than comparison.
- pyrtl.corecircuits.signed_le(a, b)[source]#
Return a single bit result of signed less than or equal comparison.
- pyrtl.corecircuits.signed_gt(a, b)[source]#
Return a single bit result of signed greater than comparison.
- pyrtl.corecircuits.signed_ge(a, b)[source]#
Return a single bit result of signed greater than or equal comparison.
- pyrtl.corecircuits.shift_left_arithmetic(bits_to_shift, shift_amount)[source]#
Shift left arithmetic operation.
- Parameters:
bits_to_shift (WireVector) – WireVector to shift left
shift_amount – WireVector or integer specifying amount to shift
- Returns:
WireVector of same length as bits_to_shift
This function returns a new WireVector of length equal to the length of the input bits_to_shift but where the bits have been shifted to the left. An arithemetic shift is one that treats the value as as signed number, although for left shift arithmetic and logic shift they are identical. Note that shift_amount is treated as unsigned.
- pyrtl.corecircuits.shift_right_arithmetic(bits_to_shift, shift_amount)[source]#
Shift right arithmetic operation.
- Parameters:
bits_to_shift (WireVector) – WireVector to shift right
shift_amount – WireVector or integer specifying amount to shift
- Returns:
WireVector of same length as bits_to_shift
This function returns a new WireVector of length equal to the length of the input bits_to_shift but where the bits have been shifted to the right. An arithemetic shift is one that treats the value as as signed number, meaning the sign bit (the most significant bit of bits_to_shift) is shifted in. Note that shift_amount is treated as unsigned.
- pyrtl.corecircuits.shift_left_logical(bits_to_shift, shift_amount)[source]#
Shift left logical operation.
- Parameters:
bits_to_shift (WireVector) – WireVector to shift left
shift_amount – WireVector or integer specifying amount to shift
- Returns:
WireVector of same length as bits_to_shift
This function returns a new WireVector of length equal to the length of the input bits_to_shift but where the bits have been shifted to the left. A logical shift is one that treats the value as as unsigned number, meaning the zeroes are shifted in. Note that shift_amount is treated as unsigned.
- pyrtl.corecircuits.shift_right_logical(bits_to_shift, shift_amount)[source]#
Shift right logical operation.
- Parameters:
bits_to_shift (WireVector) – WireVector to shift left
shift_amount – WireVector or integer specifying amount to shift
- Returns:
WireVector of same length as bits_to_shift
This function returns a new WireVector of length equal to the length of the input bits_to_shift but where the bits have been shifted to the right. A logical shift is one that treats the value as as unsigned number, meaning the zeros are shifted in regardless of the “sign bit”. Note that shift_amount is treated as unsigned.