Coverage for tsfpga/math_utils.py: 100%

42 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-07 20:51 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project, a project platform for modern FPGA development. 

5# https://tsfpga.com 

6# https://github.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9 

10def to_binary_string(value: int, result_width: int) -> str: 

11 """ 

12 Convert unsigned integer value to a zero-padded string of 1's and 0's. 

13 Most significant bit is the first (left-most) character in the string. 

14 

15 For example, value 37, width 6, returns ``100101``. 

16 For example, value 37, width 8, returns ``00100101``. 

17 

18 Arguments: 

19 value: The value to be converted. 

20 result_width_bits: The supplied ``value`` will be interpreted as an unsigned value with 

21 this many bits. 

22 The result string will contain this many bit characters. 

23 """ 

24 _check_unsigned_range(value=value, width=result_width) 

25 

26 # Cast to binary, pad with zeros on the left. 

27 formatting_string = f"{{:0{result_width}b}}" 

28 padded_binary_string = formatting_string.format(value) 

29 assert len(padded_binary_string) == result_width 

30 

31 return padded_binary_string 

32 

33 

34def to_binary_nibble_string(value: int, result_width_bits: int) -> str: 

35 """ 

36 Convert unsigned integer value to a zero-padded string of 1's and 0's, with each nibble (4 bits) 

37 separated by "_". 

38 Most significant bit is the first (left-most) character in the string. 

39 

40 For example, value 37, width 6, returns ``10_0101``. 

41 For example, value 37, width 8, returns ``0010_0101``. 

42 

43 Arguments: 

44 value: The value to be converted. 

45 result_width_bits: The supplied ``value`` will be interpreted as an unsigned value with 

46 this many bits. 

47 The result string will contain this many bit characters, plus separators. 

48 """ 

49 _check_unsigned_range(value=value, width=result_width_bits) 

50 

51 result_width_nibbles = (result_width_bits + 4 - 1) // 4 

52 num_separators = result_width_nibbles - 1 

53 result_width = result_width_bits + num_separators 

54 

55 # Cast to binary, pad with zeros on the left, separate every fourth character. 

56 formatting_string = f"{{:0{result_width}_b}}" 

57 result = formatting_string.format(value) 

58 assert len(result) == result_width 

59 

60 return result 

61 

62 

63def to_hex_string(value: int, result_width_bits: int) -> str: 

64 """ 

65 Convert unsigned integer value to a zero-padded string of 01ABCDEF. 

66 Most significant bit is the first (left-most) character in the string. 

67 

68 For example, value 60, width 6, returns ``3C``. 

69 For example, value 60, width 9, returns ``03C``. 

70 

71 Arguments: 

72 value: The value to be converted. 

73 result_width_bits: The supplied ``value`` will be interpreted as an unsigned value with 

74 this many bits. 

75 The result string will contain enough hex characters to represent this many 

76 bits (rounded up). 

77 """ 

78 _check_unsigned_range(value=value, width=result_width_bits) 

79 

80 result_width_nibbles = (result_width_bits + 4 - 1) // 4 

81 

82 # Cast to hex, pad with zeros on the left. 

83 formatting_string = f"{{:0{result_width_nibbles}X}}" 

84 result = formatting_string.format(value) 

85 assert len(result) == result_width_nibbles 

86 

87 return result 

88 

89 

90def to_hex_byte_string(value: int, result_width_bits: int) -> str: 

91 """ 

92 Convert unsigned integer value to a zero-padded string of 01ABCDEF, with each byte 

93 (8 bits, 2 result characters) separated by "_". 

94 Most significant bit is the first (left-most) character in the string. 

95 

96 For example, value 60, width 6, returns ``3C``. 

97 For example, value 60, width 9, returns ``0_3C``. 

98 

99 Arguments: 

100 value: The value to be converted. 

101 result_width_bits: The supplied ``value`` will be interpreted as an unsigned value with 

102 this many bits. 

103 The result string will contain enough hex characters to represent this many 

104 bits (rounded up), plus separators. 

105 """ 

106 hex_string = to_hex_string(value=value, result_width_bits=result_width_bits) 

107 

108 result_width_nibbles = (result_width_bits + 4 - 1) // 4 

109 assert len(hex_string) % result_width_nibbles == 0, hex_string 

110 

111 byte_strings = [] 

112 if result_width_nibbles % 2 == 1: 

113 byte_strings.append(hex_string[0]) 

114 for i in range(result_width_nibbles % 2, result_width_nibbles, 2): 

115 byte_strings.append(hex_string[i : i + 2]) 

116 

117 result = "_".join(byte_strings) 

118 

119 result_width_bytes = (result_width_bits + 8 - 1) // 8 

120 num_separators = result_width_bytes - 1 

121 result_width = result_width_nibbles + num_separators 

122 assert len(result) == result_width, result 

123 

124 return result 

125 

126 

127def _check_unsigned_range(value: int, width: int) -> None: 

128 if width < 1: 

129 raise ValueError(f'Invalid result width "{width}".') 

130 

131 if not 0 <= value < 2**width: 

132 raise ValueError(f'Value "{value}" out of {width}-bit range.')