How would you write a SystemVerilog Function that adds an even parity bit to a 7-bit vector? - system-verilog

Would you take a 7-bit logic variable as an input and return an 8-bit logic output with the parity bit being the MSB (leftmost bit) of the output?
In a system that uses even parity you want the total number of 1 bits in the output vector to be even, right?
Can the the unary ^ operator can be used to calculate even parity?
Trying to figure out what that would look like?
I started something like this:
Code for parity
Sorry if this is more than one question.

I would do this like this:
input logic [N-1:0] data_in;
output logic [N:0] data_out;
assign data_out = {^data_in, data_in};
The ^ reduction operator does an XOR operation on all the bits in the operand. (So, it will return '1 if data_in has an odd number of ones.)

Related

Why doesn't 'd0 extend the full width of the signal (as '0 does)?

Using SystemVerilog and Modelsim SE 2020.1, I was surprised to see a behavior:
bus_address is a 64b signal input logic [63:0] bus_address
Using '0
.bus_address ('0),
Using 'd0
.bus_address ('d0),
Riviera-Pro 2020.04 (too buggy, we gave up using it and we are in a dispute with Aldec)
'd0:
'0:
Investigation/Answer:
11.3.3 Using integer literals in expressions: An unsized, based integer (e.g., 'd12 , 'sd12 )
5.7.1 Integer literal constants:
The number of bits that make up an unsized number (which is a simple
decimal number or a number with a base specifier but no size
specification) shall be at least 32. Unsized unsigned literal
constants where the high-order bit is unknown ( X or x ) or
three-state ( Z or z ) shall be extended to the size of the expression
containing the literal constant.
That was tricky and I thought it would set 0 all the other bits as '0 does.
I hope specs' authors will think more when defining such non-sense behaviors.
This problem has more with port connections with mismatched sizes than anything to do with numeric literals. It's just that the issue does not present itself when using the fill literals. This is because the fill literal automatically sizes itself eliminating port width mismatch.
The problem you see exists whether you use literals or other signals like in this example:
module top;
wire [31:0] a = 0;
dut d(a);
endmodule
module dut(input wire [63:0] p1);
initial $strobeb(p1);
endmodule
According to section 23.3.3.7 Port connections with dissimilar net types (net and port collapsing), the nets a and p1 might get merged into a single 64-bit net, but only the lower 32-bits remain driven, or 64'hzzzzzzzz00000000.
If you change the port connection to a sized literal, dut d(32'b0);, you see the same behavior 64'hzzzzzzzz00000000.
Now let's get back to the unsized numeric literal 'd0. Unsized is a misnomer—all numbers have a size. It's just that the size is implicit and never the size you want it to be. 😮 How many people write {'b1,'b0,'b1,'b0} thinking they've just wrote the same thing as 4'b1010? This is actually illegal in the LRM, but some tools silently interpret it as {32'b1,32'b0,32'b1,32'b0}.
Just never use an unsized literal.

8-bit unsigned fixed point implementation with multiplication and clamping

I'd like to represent numbers in the range [0.0, 1.0] ( optimally including both endpoints) using 8-bit words.
I'd like to be able to multiply them efficiently and addition/subtraction should optimally be clamped to [0,1], not overflow.
For example, if 0xFF would represent 1.0 and 0x00 would represent 0.0, then the multiplication should yield for example
0x3F (0.247) = 0x7F (0.499) * 0x7F (0.499)
I found https://courses.cs.washington.edu/courses/cse467/08au/labs/l5/fp.pdf and I think that what the paper would name U(0,8) corresponds to what I'm looking for, but I don't understand how multiplication for example would need to be implemented.
Is there a c++ library that efficiently implements such a data type or can someone point me to the necesseary math?
I don't need division, only multiplication, addition and subtraction
The fixed-point format you have chosen, U[0.8], does not include the exact endpoint value of 1. The maximum value in this format is actually 0.99609375. If that's close enough for you we can talk about doing the math.
Multiplying two U[0.8] values gives a 16-bit result in U[0.16] format. To convert back to U[0.8] you must shift right by 8 bit positions. So, multiplying 0x7F times 0x7F gives 0x3F01. Shifting right by 8 bits gives the U[0.8] result of 0x3F, as desired.
Two values in U[0.8] format can be added or subtracted using normal integer operations. However, you must either prevent overflow/underflow or detect overflow/underflow in the result. To detect overflow in addition you could zero-extend both values to 16 bits, perform the addition, and check to see if the result is greater than 0xFF. If so, you could saturate and return 0xFF.
For subtraction you could compare the values before doing the subtraction, and if the result would be negative just return zero.

Shifting through concatenation in SystemVerilog?

I have the following question
Implement a circuit which shifts a 32-bit vector by two to the left and fills empty spots with zeros. Use only concatenation operator.
I'm just learning SystemVerilog, and I can't understand how I can use a concatenation operator for this. I would have just done 'assign y = a << 2' without concatenation ( with a declared as 32bit vector and y a 32 bit output), but I don't understand how can concatenation have anything to do with it.
Concatenation allows you to concatenate multiple parts of a vector with constants. As such, the left shift operator for a << 2 can be implemented as the following:
logic [7:0] x, y;
always_comb
y[7:0] = {a[5:0], 2'b0};
Just a concatenation of the lower 6 bits of a with 2 bits of 0 on the right hand side. Same what the left shift would do, but without any overflow.

how to get reverse(not complement or inverse) of a binary number

I am implementing cooley-tuckey fft(raddix - 2 DIF / DIT) algorithm in matlab.In that for the bit reversing i want to have reverse of an binary number. so can anyone suggest how can I get the reverse of a binary number(like 100111 -> 111001). One who have worked on fft implementation can help me with the algorithm also.
Topic: How to do bit reversal in Matlab? .
If you're using double precision floating point ('double') numbers
which are integers, you can do this:
dr = bin2dec(fliplr(dec2bin(d,n))); % Bits in dr are in reverse order
where n is the number of bits to be reversed and where 0 <= d < 2^n.
You will experience no precision problems at all as long as the
integers are no more than 52 bits long.
And
Re: How to do bit reversal in Matlab?
How large will the numbers be that you need to reverse? May I ask what
is the purpose of it? Maybe there is a more efficient way to solve the
whole problem. If the numbers are large you can just store the bits as
a string. To reverse it just read the string backwards! Or use
fliplr().
(There may be better places to ask).
If it were VHDL I'd suggest an alias with 'REVERSE'RANGE.
Taken from the help section;
Y = swapbytes(X) reverses the byte ordering of each element in array X, converting little-endian values to big-endian (and vice versa). The input array must contain all full, noncomplex, numeric elements.

fortran90 reading array with real numbers

I have a list of real data in a file. The real data looks like this..
25.935
25.550
24.274
29.936
23.122
27.360
28.154
24.320
28.613
27.601
29.948
29.367
I write fortran90 code to read this data into an array as below:
PROGRAM autocorr
implicit none
INTEGER, PARAMETER :: TRUN=4000,TCOR=1800
real,dimension(TRUN) :: angle
real :: temp, temp2, average1, average2
integer :: i, j, p, q, k, count1, t, count2
REAL, DIMENSION(0:TCOR) :: ACF
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(100, file="fort.64",status="old")
do k = 1,TRUN
read(100,*) angle(k)
end do
Then, when I print again to see the values, I get
25.934999
25.549999
24.274000
29.936001
23.122000
27.360001
28.153999
24.320000
28.613001
27.601000
29.948000
29.367001
32.122002
33.818001
21.837000
29.283001
26.489000
24.010000
27.698000
30.799999
36.157001
29.034000
34.700001
26.058001
29.114000
24.177000
25.209000
25.820999
26.620001
29.761000
May I know why the values are now 6 decimal points?
How to avoid this effect so that it doesn't affect the calculation results?
Appreciate any help.
Thanks
You don't show the statement you use to write the values out again. I suspect, therefore, that you've used Fortran's list-directed output, something like this
write(output_unit,*) angle(k)
If you have done this you have surrendered the control of how many digits the program displays to the compiler. That's what the use of * in place of an explicit format means, the standard says that the compiler can use any reasonable representation of the number.
What you are seeing, therefore, is your numbers displayed with 8 sf which is about what single-precision floating-point numbers provide. If you wanted to display the numbers with only 3 digits after the decimal point you could write
write(output_unit,'(f8.3)') angle(k)
or some variation thereof.
You've declared angle to be of type real; unless you've overwritten the default with a compiler flag, this means that you are using single-precision IEEE754 floating-point numbers (on anything other than an exotic computer). Bear in mind too that most real (in the mathematical sense) numbers do not have an exact representation in floating-point and that the single-precision decimal approximation to the exact number 25.935 is likely to be 25.934999; the other numbers you print seem to be the floating-point approximations to the numbers your program reads.
If you really want to compute your results with a lower precision, then you are going to have to employ some clever programming techniques.