Livt packages
Livt.Base
Version 1.2.1
Foundational bit, array, string, conversion, formatting, and timing helpers for Livt hardware designs.
Published files (32)
src/Bits.lvt
namespace Livt.Bits
/**
* Bit and logic-vector operations for non-negative integer values.
*
* All functions treat the value as a non-negative integer stored in an int.
* Bit indices are 0-based (0 = least significant bit, 30 = most significant
* bit of the usable range). Widths are 1..31; rotation amounts are nonnegative.
* Calls are scheduled and must be serialized. All functions are synthesizable.
*/
component Bits
{
/**
* Returns 2^n for n in 0..30.
*/
public fn Pow2(n: int) int
{
return 1 << n
}
/**
* Returns the bit at position index (0 = LSB) as 0 or 1.
*/
public fn GetBit(value: int, index: int) int
{
return (value >> index) & 1
}
/**
* Returns value with the bit at position index set to 1.
*/
public fn SetBit(value: int, index: int) int
{
var p: int = this.Pow2(index)
var bit: int = (value >> index) & 1
if (bit == 0) {
return value + p
}
return value
}
/**
* Returns value with the bit at position index cleared to 0.
*/
public fn ClearBit(value: int, index: int) int
{
var p: int = this.Pow2(index)
var bit: int = (value >> index) & 1
if (bit == 1) {
return value - p
}
return value
}
/**
* Returns value with the bit at position index inverted.
*/
public fn ToggleBit(value: int, index: int) int
{
var p: int = this.Pow2(index)
var bit: int = (value >> index) & 1
if (bit == 0) {
return value + p
}
return value - p
}
/**
* Returns value with the bit at position index set to bit.
* bit must be 0 or 1.
*/
public fn WithBit(value: int, index: int, bit: int) int
{
if (bit == 0) {
return this.ClearBit(value, index)
}
return this.SetBit(value, index)
}
/**
* Returns an integer with the lowest width bits set to 1.
* Example: Mask(4) returns 0b1111 = 15.
*/
public fn Mask(width: int) int
{
var p: int = this.Pow2(width)
return p - 1
}
/**
* Returns an integer with bits low through high (inclusive) set to 1.
* Example: MaskRange(5, 2) returns 0b111100 = 60.
*/
public fn MaskRange(high: int, low: int) int
{
var width: int = high - low + 1
var m: int = this.Mask(width)
return m << low
}
/**
* Returns bits low through high (inclusive) of value, shifted down to bit 0.
* Example: Extract(0b11010110, 5, 2) returns 0b0101 = 5.
*/
public fn Extract(value: int, high: int, low: int) int
{
var shifted: int = value >> low
var width: int = high - low + 1
var pw: int = this.Pow2(width)
return shifted & (pw - 1)
}
/**
* Returns value with bits low through high replaced by field.
* field is masked to the target width before insertion.
* Example: Insert(0b11000000, 5, 2, 0b0101) returns 0b11010100.
*/
public fn Insert(value: int, high: int, low: int, field: int) int
{
var width: int = high - low + 1
var pw: int = this.Pow2(width)
var fieldMasked: int = field & (pw - 1)
var extracted: int = this.Extract(value, high, low)
var cleared: int = value - (extracted << low)
return cleared + (fieldMasked << low)
}
/**
* Returns the number of 1-bits in the lower 31 bits of value.
* value must be non-negative.
*/
public fn CountOnes(value: int) int
{
var count: int = 0
var remaining: int = value
for (var i = 0; i < 31; i++) {
var bit: int = remaining & 1
count = count + bit
remaining = remaining >> 1
}
return count
}
/**
* Returns the number of 0-bits in the lower width bits of value.
* Use width = 8 for a byte field, width = 16 for a halfword, and so on.
*/
public fn CountZeros(value: int, width: int) int
{
var p: int = this.Pow2(width)
var masked: int = value & (p - 1)
var ones: int = this.CountOnes(masked)
return width - ones
}
/**
* Returns 1 if the number of 1-bits in value (lower 31 bits) is odd,
* otherwise returns 0.
*/
public fn Parity(value: int) int
{
var ones: int = this.CountOnes(value)
return ones & 1
}
/**
* Returns value with its lower width bits in reverse order.
* Use width = 8 for byte reversal, width = 16 for halfword reversal.
*/
public fn ReverseBits(value: int, width: int) int
{
var pw: int = this.Pow2(width)
var result: int = 0
var remaining: int = value & (pw - 1)
for (var i = 0; i < width; i++) {
var bit: int = remaining & 1
var shift: int = width - 1 - i
result = result + (bit << shift)
remaining = remaining >> 1
}
return result
}
/**
* Rotates value left by amount positions within a field of width bits.
* Example: RotateLeft(0b10110001, 2, 8) returns 0b11000110.
*/
public fn RotateLeft(value: int, amount: int, width: int) int
{
var pw: int = this.Pow2(width)
var masked: int = value & (pw - 1)
var normAmount: int = this.NormalizeRotation(amount, width)
var splitAt: int = width - normAmount
var pSplit: int = this.Pow2(splitAt)
var topBits: int = masked >> splitAt
var bottomBits: int = masked & (pSplit - 1)
return (bottomBits << normAmount) + topBits
}
/**
* Rotates value right by amount positions within a field of width bits.
* Example: RotateRight(0b10110001, 2, 8) returns 0b01101100.
*/
public fn RotateRight(value: int, amount: int, width: int) int
{
var pw: int = this.Pow2(width)
var masked: int = value & (pw - 1)
var normAmount: int = this.NormalizeRotation(amount, width)
var pNorm: int = this.Pow2(normAmount)
var lowBits: int = masked & (pNorm - 1)
var highBits: int = masked >> normAmount
return (lowBits << (width - normAmount)) + highBits
}
/**
* Returns value with its lower fromWidth bits zero-extended to toWidth bits.
* All bits above fromWidth are cleared.
*/
public fn ZeroExtend(value: int, fromWidth: int, toWidth: int) int
{
var pw: int = this.Pow2(fromWidth)
return value & (pw - 1)
}
/**
* Returns value with its lower fromWidth bits sign-extended to toWidth bits.
* If bit (fromWidth - 1) is 1, all bits from fromWidth to toWidth - 1 are
* set to 1.
*/
public fn SignExtend(value: int, fromWidth: int, toWidth: int) int
{
var pw: int = this.Pow2(fromWidth)
var masked: int = value & (pw - 1)
var signShift: int = fromWidth - 1
var signBit: int = masked >> signShift
if (signBit == 0) {
return masked
}
var extensionWidth: int = toWidth - fromWidth
var pExt: int = this.Pow2(extensionWidth)
var extensionMask: int = pExt - 1
return masked + (extensionMask << fromWidth)
}
/**
* Returns the minimum number of bits required to represent value.
* value must be non-negative.
* RequiredBits(0) returns 1.
* RequiredBits(1) returns 1.
* RequiredBits(255) returns 8.
* RequiredBits(256) returns 9.
*/
public fn RequiredBits(value: int) int
{
if (value <= 0) {
return 1
}
var bitCount: int = 0
var remaining: int = value
for (var i = 0; i < 31; i++) {
if (remaining > 0) {
bitCount = bitCount + 1
remaining = remaining >> 1
}
}
return bitCount
}
/**
* Reduces a nonnegative rotation amount for width 1..31 in 31 bit steps.
* Kept local to Base to avoid a dependency cycle through Livt.Math.
*/
fn NormalizeRotation(amount: int, width: int) int
{
var remainder = 0
for (var bit = 30; bit >= 0; bit--) {
state {
remainder = (remainder << 1) | ((amount >> bit) & 1)
if (remainder >= width) {
remainder = remainder - width
}
}
}
return remainder
}
}