Rounding floating point numbers in Verilog? - verilog

So I am working with 64 bit floating point numbers on Verilog for synthesis, all are in the region of {-1,1}. Now, I am trying to create something like a Histogram which I guess I could do by creating a RAM to work like a 2D array. But I am facing issues with the rounding.
For Example,
I have a value 0.94394(FltPt). I would like to convert this into just,
0.82394 = 8 and 0.8862 =9 (All data are in 64 bit flt pt)
so that I can access that specific address on the RAM.
What would be the the most ideal way to round this, using another multiplier is too much overhead. Is there some trick I could do by truncating a part of the bits? Should I convert them to Fixed Point?

Two options I can think of:
The simplest is to change your bins so the boundaries are powers of 2. Then you can just use the some of bits of the input directly to address your histogram. I would have to go look at the floating point format to know which bits to use.
The other possibility is to just do a bunch of comparisons to see what bin to put it. L
You would have do this for both of the coordinates.
reg [4:0] ram_aadr;
always #* begin
if(data < -.95)
ram_addr = 5'd0;
else if(data < -.85)
ram_addr = 5'd1;
...
else if(data < .95)
ram_addr = 5'd19;
else
ram_addr = 5'd20;
end

Related

Expansion of logic array to 2D array

In my system, each pixel on an LCD screen is represented by 16-bits (RGBA):
typedef logic [15:0] pix;
In order to display characters on the screen, I have created a simple 8x8 typeface, whereby characters are stored such as:
typedef logic char_8x8 [7:0][7:0];
localparam char_8x8 txt_G = '{'h3C, 'h66, 'h03, 'h03, 'h73, 'h66, 'h7C, 'h00};
As they are currently stored (the hex numbers above), a 'b1 represents a turned-on pixel and 'b0 turned off.
Now, to display them, I need some method to convert each character to the following form:
typedef logic [15:0] char_8x8_colored [7:0][7:0];
Notice how now each pixel element also carries the 16 bits of color as a packed array. (Frankly I'm not 100% how the whole packed/unpacked affects code - even though I know the implementation difference).
The way this would work is, wherever there exists a 'b1 in the character array, this would be replaced with an element with value 'hFFFF (white) - and of course 'h0000 (black) for no pixel present.
I'm unsure of the best way to implement this in SystemVerilog.
Thanks.
As far as I know you the only type of indices you can use in systemverilog are slices (without stride). I know that numpy, pytorch, or octave for instance have much richer indexing options and could use something like colored[face] = foreground. To set the color of all the pixels turned on. But in systemverilog I would go with a function.
function char_8x8_colored color_out(
input char_8x8 face,
input pix background,
input pix foreground);
char_8x8_colored data;
begin
for(int i = 0; i < 8; i = i + 1) begin
for(int j = 0; j < 8; i = i + 1) begin
data[i][j] = face[i][j] ? foreground : background;
end
end
end
end
endfunction
This is a pure function this function can be synthesized using without any logic (only routing) if you pass a parameter such as txt_G as the face argument.

Verilog - masking using 1 bit input

I have a situation I'm not sure what's the right syntax that exists which can solve it.
In my code I have
reg [N-1:0] bit_list;
and another variable n which counts how many bits I inserted into bit_list.
Occasionally and according to the input - I need to, during a single posedge, shift bit_list by 1 then change bit_list[N-n] to my input. My idea was I can do the following
bit_list<=bit_list<<1 || X
Where X should be replaced some N-1 long vector that has zeros in all bits except for N-n. The problem is I don't know to describe such a vector - Hence my question.
I'm sure my problem is simple enough to be solved in a variety of simple ways, so any solution to my problem will work.
Sorry if my question is noobish as I'm still new, help will be appriciated of course.
You can use a mask. (BTW || is logical-or, you want | a bitwise-or)
reg [N-1:0] mask;
mask = ({ {N{1'b0}},1'b0}) << n) - 1; // the concat is needed in case N > 32
bit_list<=((bit_list<<1) & ~mask) | (X & mask);

How to implement an n-bit adder whose input vectors are represented in octal?

I'm somewhat stumped on this problem:
"Write a verilog module for full addition of n-bit integers. Let the parameter, the number of bits, equal 3. Call this module from a test bench, and in the test bench specify the numbers to be added in the arrays. Assign octal values to the X and Y arrays. The carryin is 0."
And yes, this is homework.
I was able to write the module for the n-bit adder:
module addern(carryin, X, Y, S, carryout, overflow);
parameter n = 3;
input carryin;
input [n-1:0] X, Y;
output reg [n-1:0] S;
output reg carryout, overflow;
always #(X,Y, carryin)
begin
{carryout, S} = X + Y + carryin;
overflow = (X[n-1] & Y[n-1] & ~S[n-1]) | (~X[n-1] & ~Y[n-1] & S[n-1]);
end
endmodule
I understand this component of the problem. However, I'm not sure how to implement the octal number addition. Is there a way in verilog to indicate that the arrays are holding octal values, rather than binary?
Is there anything like a typecast in verilog? For instance, input (octal) [n-1:0] X, Y, and do something likewise in the test bench.
Any constructive input is appreciated.
I'm pretty sure I'm in the same class as you. I think what you need to do is create a hierarchical Verilog module and then assign your values there. That would be your testbench. for example if you want to make X you write input [n-1:0] X = 3'o013, or maybe it's X = 9'o013 if Oli is correct. you don't change n, but it's kind of like BCD where they are in groups and you have a certain amount of bits you can represent before it overflows.
To help solve the problem thik about the question:
Q) How are numbers stored in digital hardware?
A) Binary, in digital logic we can only represent 2 values 1 and 0, but with this we can represent Integer, fixed point or floating point numbers.
Therefore digital numbers are base 2 (two possible values), while being able to represent any number. Other bases such as Octal (base 8) hex (base 16) and decimal (base 10) exist but these are just way of representing numbers, similar to the way binary just represents a number.
A decimal 1, is represented by 1 n all the bases, and when stored as binary they are all the same. An example of some values in verilog and there binary equivalents.
Octal Decimal Hex Binary
3'O7 => 3'd7 => 3'h7 => 3'b111
6'O10 => 6'd8 => 6'h8 => 6'b001000
Octal, Decimal and Hex in verilog are just representations of a binary format, a way of viewing the data. Since the low level electronics has no way of representing any thing other than 0 and 1.
The interesting thing about Octal and Hex is that they have a power of 2 values so they use an exact number of bits so an 9'O123 is the same as treating each Octal place separately and concatenating them together, 9'O123 == {3'O1, 3'O2, 3'O3}. This is also true for hexadecimal values but not decimal (base 10) values, as 10 is not a power of 2 and does not fully occupy the number space.
This does allow 'Octal' ports to be created, which are just 3 bit binary ports:
module octal_concat (
input [2:0] octal_2,
input [2:0] octal_1,
input [2:0] octal_0,
output [8:0] concat
);
assign concat = {octal_2, octal_1, octal_0};
endmodule
octal_concat octal_concat_0 (
.octal_2(3'O1),
.octal_1(3'O2),
.octal_0(3'O3),
.concat() //Drives 9'O123 which is also 9'b001_010_011
);

How does Audacity mix audio samples?

So let's say I want to mix these 2 audio tracks:
In Audacity, I can use the "Mix and Render" option to mix them together, and I'll get this:
However, when I try to write my own code to mix, I get this:
This is essentially how I mix the samples:
private function mixSamples(sample1:UInt, sample2:UInt):UInt
{
return (sample1 + sample2) & 0xFF;
}
(The syntax is Haxe but it should be easy to follow if you don't know it.)
These are 8-bit sample audio files, and I want the product to be 8-bit as well, hence the & 0xFF.
I do understand that by simply adding the samples, I should expect clipping. My issue is that mixing in Audacity doesn't cause clipping (at least not to the extent that my code does), and by looking at the "tail" of the second (longer) track, it doesn't seem to reduce the amplitude. It doesn't sound any softer either.
So basically, my question is this: what's Audacity doing that I'm not? I want to mix tracks to sound exactly as if they're being played on top of one another, but I (obviously) don't want this horrendous clipping.
EDIT:
Here is what I get if I sign the values before I add, then unsign the sum value, as suggested by Radiodef:
As you can see it's much better than before, but is still quite distorted and noisy compared to the result Audacity produces. So my problem still stands, Audacity must be doing something differently.
EDIT2:
I mixed the first track on itself, both with my code and Audacity, and compared the points where distortion occurs. This is Audacity's result:
And this is my result:
I think what is happening is you are summing them as unsigned. A typical sound wave is both positive and negative which is why they add together the way they do (some parts cancel). If you have some 8-bit sample that is -96 and another that is 96 and you sum them you will get 0. If what you have is unsigned audio you will instead have the samples 32 and 224 summed = 256 (offset and overflow).
What you need to do is sign them before summing. To sign 8-bit samples convert them to a signed int type and subtract 128 from all of them. I assume what you have are WAV files and you will need to unsign them again after the sum.
Audacity probably does floating point processing. I've heard some real dubious claims about floating point like that it has "infinite dynamic range" and garbage like that but it doesn't clip in the same determinate and obvious way as integers do. Floating point has a finite range of values same as integers but the largest and smallest values are much farther apart. (That's about the simplest way to put it.) Floating point can allow much greater amplitude changes in the audio but the catch is the overall signal to noise ratio is lower than integers.
With the weird distortion my best guess is it is from the mask you are doing with & 0xFF. If you want to actually clip instead of getting overflow you will need to do so yourself.
for (int i = 0; i < samplesLength; i++) {
if (samples[i] > 127) {
samples[i] = 127;
} else if (samples[i] < -128) {
samples[i] = -128;
}
}
Otherwise say you have two samples that are 125, summing gets you 250 (11111010). Then you unsign (add 128) and get 378 (101111010). An & will get you 1111010 which is 122. Other numbers might get you results that are effectively negative or close to 0.
If you want to clip at something other than 8-bit, full scale for a bit depth n will be positive (2 ^ (n - 1)) - 1 and negative 2 ^ (n - 1) so for example 32767 and -32768 for 16-bit.
Another thing you can do instead of clipping is to search for clipping and normalize. Something like:
double[] normalize(double[] samples, int length, int destBits) {
double fsNeg = -pow(2, destBits - 1);
double fsPos = -fsNeg - 1;
double peak = 0;
double norm = 1;
for (int i = 0; i < length; i++) {
// find highest clip if there is one
if (samples[i] < fsNeg || samples[i] > fsPos) {
norm = abs(samples[i]);
if (norm > peak) {
norm = peak;
}
}
}
if (peak != 0) {
// ratio to reduce to where there is not a clip
norm = -fsNeg / peak;
for (int i = 0; i < length; i++) {
samples[i] *= norm;
}
}
return samples;
}
It's a lot simpler than you think; although your original files are 8-bit, Audacity handles them internally as 32-bit floating point. You can see this in the screenshot, in the information panel to the left of each track. This means that adding 2 tracks together means adding two floating point samples at each point, and will simply yield sample values from -2.0 to +2.0, which are then clamped to the -1 to +1 range. By comparison, adding two 8-bit integers together will yield another 8-bit number where the value overflows and wraps around. (This can apply whether you use signed or unsigned values.)

Optimize this comparator for better synthesis

I have a module which is basically a LUT whose input is 64 bits. The LUT always block consists of a case statement which compares the input to over 200 different integers. The default case in the case statement checks if the input is > 100 or not before assigning the output a default value.
My problem is that when I synthesize, it leads to a 65 bit comparator, and I was wondering if there are better ways of doing it so that a large comparator isn't synthesized.
Here's my code snippet:
always #(in)
begin
case (in)
-100: out <= 495050;
-99: out <= 500000;
...
99: out <= 99500000;
100: out <= 99504950;
default:
begin
if (in > 100)
out <= 99504950;
else
out <= 495050;
end
endcase
end
Thanks,
Faisal
Assuming that in is a 64 bit number, what you can do is to chop it off such that you only have to 'compare' the lowest few bits, and then you can do quick checks to see if the number is outside of the range needed.
For example, let's just chop off in at 8 bits, and assign it to an 8 bit signed register. This should allow you to represent between -128 and 127.
You can test if the full number is larger than 127 by: !in[63] && (|in[62:8]) (check if any upper bit is 1, and the MSB is not set).
You can test if the full number is less than -128 by: in[63] && !(&in[62:8]) (check if any upper bit is 0, and the MSB is set).
Now you know three things:
if the number is larger than 127
if the number is between 127 and -128
and if the number is less than -128.
You should be able to use a small 8-bit LUT for the inbetween case, or use your default values if it's in either of the upper ranges.
Note I might expect a good synthesizer to do this automatically for you, but if you look at the generated netlist and it's too large you can try this to see if it gives you a better result.
It seems like You have calculated table with some function values of input x = [-100;100]. If so, it would be better to store them in memory one after another starting from some base address. So to read them, You can write base + X + 100 value on the address bus, and obtain value you need.
In case you need a gigantic multiplexer, you may want to try using a "parallel" case directive.
As for comparator in "default" - I have the same problem, so I am waiting for an answer.
I wanted to write this as a comment but I have no such privilege

Resources