I found a very strange behaviour when design my ALU, hope someone can have a look it and tell me what is going on.
Here is the code
module adder (
output logic signed[31:0] y,
output logic Cout,
input logic signed[31:0] a, b,
input logic Cin, sub
);
logic [31:0] adder_b;
assign adder_b = b ^ {32{sub}};
assign {Cout, y} = {a[31],a} + {adder_b[31],adder_b} +Cin;
endmodule
////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////
module andlogic (
output logic [31:0] y,
input logic [31:0] a, b
);
assign y = a & b;
endmodule
////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////
module orlogic (
output logic [31:0] y,
input logic [31:0] a, b
);
assign y = a | b;
endmodule
////////////////////////////////////////////////////
////////////////////////////////////////////////////
////////////////////////////////////////////////////
module xorlogic (
output logic [31:0] y,
input logic [31:0] a, b
);
assign y = a ^ b;
endmodule
///////////////////////////////////////////////////
///////////////////////////////////////////////////
///////////////////////////////////////////////////
module ALU(
output logic signed[31:0] Result,
output logic N,Z,C,V,
input logic signed[31:0] a, b,
input logic [2:0] ALU_control
);
wire [31:0] adder_rlt, and_rlt, or_rlt, xor_rlt;
logic Cin;
adder adder (
.y (adder_rlt),
.a (a),
.b (b),
.Cin (Cin),
.Cout (Cout),
.sub (sub)
);
andlogic andlogic (
.y (and_rlt),
.a (a),
.b (b)
);
orlogic orlogic (
.y (or_rlt),
.a (a),
.b (b)
);
xorlogic xorlogic (
.y (xor_rlt),
.a (a),
.b (b)
);
assign C = Cout;
assign sub = ALU_control[1];
assign Cin = ALU_control[1];
assign N = Result[31];
//assign Z = (Result ==0 )? 1:0;
assign V = {{~a[31]} & {~b[31]} & Result[31]}|{a[31] & b[31] & {~Result[31]}};
always_comb
begin
if (Result == 0) Z = 1;
else Z = 0;
case(ALU_control)
3'b001: Result = adder_rlt;
3'b010: Result = adder_rlt;
3'b011: Result = and_rlt;
3'b100: Result = or_rlt;
3'b101: Result = xor_rlt;
default: Result = 0;
endcase
end
endmodule
The first 4 modules are individual functions of my ALU, the adder contains both addition and subtraction. Then here is the odd thing:
My ALU has 4 flags, Z represent Zero, it sets when the value of output Result is 0. If I use these code to describe the behaviour of Z
always_comb
begin
if (Result == 0) Z = 1;
else Z = 0;
The simulation result is wrong, Z some time is 1, and some time is 0, and it looks like not depend on the value of Result at all.
What is more odd is the result of the synthesis result. Here the picture shows a part of my synplify synthesis result.
The gate level looks like correct, Z is a AND gate of all inverted Result signals, which when Result == 0, the output Z should be 1.
However, I spend all my afternoon yesterday try to figure out how to fix this bug, I fount that if I use assign statement instead of using if statement, then the simulation gives correct behaviour. assign Z = (Result ==0 )? 1:0;
I thought this two version of describing Z should be same! After I modified my code by using
assign Z = (Result ==0 )? 1:0;
The synthesis result still same as the picture I showed above...
Can someone tell me what is going on?
Thanks so much!!!
I believe the issue is with your order of operation. always_comb blocks execute procedurally, top to bottom. In simulation, Z is updated first with the existing value of Result (from the previous time the always block was executed). The Result is updated and Z is not re-evaluated. Result is not part of the sensitivity list because it is a left-hand value. Therefore, Z will not get updated until a signal that assigns Result changes.
Synthesis is different, it connects equivalent logic gates which may result in asynchronous feedback. Logical equivalent is not the same as functional equivalent. This is why synthesis is giving you what you logically intend and RTL simulation is giving what you functionally wrote. Explaining the reasons for the differences is outside the scope of this question.
When coding a RTL combinational block, just do a little self check and ask yourself:
Are the values at the end of a single pass of this always-block the intended final values? If no, rearrange your code.
Will any current values in this always-block be used assign any values in the next pass? If yes, rearrange your code or synchronize with a flip-flop.
In ALU case, tt is an easy fix. Change:
always_comb begin
if (Result==0) Z = 1; // <-- Z is evaluated using the previous value of Result
else Z = 0;
/*Logic to assign Result*/ // <-- change to Result does not re-trigger the always
end
To:
always_comb begin
/*Logic to assign Result*/ // <-- update Result first
if (Result==0) Z = 1; // <-- Z is evaluated using the final value of Result
else Z = 0;
end
An alternative solution (which I highly discourage) is to replace the always_comb with The IEEE1364-1995 style of combinational logic. Where the sensitivity list is manually defined. Here you can add Result to get the feed back update:
always #(ALU_control or adder_rlt or add_rlt or or_rtl or xor_rtl or Result)
I highly discourage because it easy to miss a necessary signal, unessary signals waste simulation time, creates a risk of zero time infinite loop, and you still don't get a guaranty functional equivalent between RTL and synthesis.
Related
I've been trying to plot a graph of function f(x) on interval 0,6. For some reason maple doesn't plot the graph when I use 'f(x)' as an argument. It works fine when I substitute assigned function as an argument. What can be the reason? How can I plot it using 'f(x)' as an argument?
My code is as follows and the error is on the pictures:
mystep:=proc(x,a,b,c)
if x<a
then
b;
else
c;
end if:
end proc:
f(x):=mystep(x,3,-2,7);
plot('f(x)', x=0..6);
enter image description here
Your syntax for creation of the operator (that you hope to assign to f) is incorrect for 1D plaintext input.
Here is the usual syntax for creation of such an operator, and assignment to name f.
restart;
mystep:=proc(x,a,b,c)
if x<a then b; else c; end if:
end proc:
f:=x->mystep(x,3,-2,7);
These should now all work as you expect.
plot('f(x)', x=0..6);
plot(f, 0..6);
plot(x->mystep(x,3,-2,7), 0..6);
In recent versions of Maple the syntax that you used can work in (only) 2D Input mode. But it is a poor syntax to use, since is easily confused with the 1D syntax for assigning into the remember table of an operator (and with even more confusion ensuing). You should avoid ambiguous syntax.
The type of function you have is piecewise-defined function (see this wikipedia page https://en.wikipedia.org/wiki/Piecewise). And in Maple there is already a command for defining this type of a function, piecewise, see its help page for a complete explanation of how to use it. Now for your mysetup, you have a condition x < a, and a value for when this happens, b, and a value for otherwise, c. So you want piecewise( x < a, b, c ). I think it is better to just use this command, but if it is really necessary to define a new procedure, then your mysetup becomes like the following.
mystep := proc(x, a, b, c)
return( piecewise( x < a, b, c ) ):
end proc:
Now for your plot you can use either
plot( piecewise( x < 3, -2, 7 ), x = 0..6 );
or
f(x) := mystep(x, 3, -2, 7);
plot( f(x), x = 0..6);
I have written a function called "tension.m" in which I have used if else condition as shown below.
function [T,T_earlyvalues,T_latervalues] = tension(u,sigma,G,N,K)
%the values of sigma,G,N,K can be taken arbitrary.
sigma=2; G=3;N=8;K=1; v=1;
w=2.2;
if u<w
T =v*sqrt(sigma+G^2/(N-K));
T_earlyvalues=T;
else
T=(2*v)*sqrt(sigma+G^2/(N+K));
T_latervalues=T;
end
Now in another script "myvalues.m" I need to call T_earlyvalues and T_latervalues separately.
%have some coding before this part
sigma0=2400; lambda=1.3; v=2; sigma=2; G=3;N=8;K=1;
u=0:0.01:5;
T=tension(u,sigma,G,N,K);
T_earlyvalues=tension(u,sigma,G,N,K);
T_latervalues=tension(u,sigma,G,N,K);
deltaA=T_earlyvalues*sigma0*pi;
deltaB=T_latervalue*lambda*pi/2;
%have some coding after this part
How could I call the said values which are under if-else statement from tension.m function to myvalues.m script?
You have defined the tension function such that it returns three outputs.
If you call that function by requiring only one output, the function returns the first value, in your case, T
This implies that
T=tension(u,sigma,G,N,K);
shoud work since T is the first output parameter
T_earlyvalues=tension(u,sigma,G,N,K);
T_latervalues=tension(u,sigma,G,N,K);
are not working, since, actually tension returns the first value (T, whjikle you are expecting the second and the third respectively.)
You can cahnge the two above calls this way:
[~,T_earlyvalues,~]=tension(u,sigma,G,N,K);
[~,~,T_latervalues]=tension(u,sigma,G,N,K);
The ~ allows to avoid the function return the output paraemter.
You can find additional information here
Notice that in your function T_earlyvalue is not set in the else block, same for T_latervalue in the if block.
This will generate an error such as
Output argument T_earlyvalue (and maybe others) not assigned during call to tension
or
Output argument T_latervalues (and maybe others) not assigned during call to tension
You can initialize the output values to default values, at the beginning of the function, for example:
T=NaN
T_earlyvalue=NaN
T_latervalues=NaN
You can then use these special values (or any other you want to use) to trace, for example, if the if block has been executed or the else.
There seem to be a number of issues here, not the least of which is some confusion about how output argument lists work when defining or calling functions. I suggest starting with this documentation to better understand how to create and call functions. However, this issue is somewhat moot because the larger problem is how you are using your conditional statement...
You are trying to pass a vector u to your function tension, and from what I can tell you want to return a vector T, where the values of T for u < w are computed with a different formula than the values of T for u >= w. Your conditional statement will not accomplish this for you. Instead, you will want to use logical indexing to write your function like so:
function [T, index] = tension(u, sigma, G, N, K)
T = zeros(size(u)); % Initialize T to a vector of zeroes
w = 2.2;
index = (u < w); % A logical vector, with true where u < w, false where u >= w
T(index) = u(index)*v*sqrt(sigma+G^2/(N-K)); % Formula for u < w
T(~index) = 2*(u(~index)-v)*sqrt(sigma+G^2/(N+K)); % Formula for u >= w
end
Now you can call this function, capturing the second output argument to use for identifying "early" versus "late" values:
sigma0 = 2400; lambda = 1.3; v = 2; sigma = 2; G = 3; N = 8; K = 1;
u = 0:0.01:5;
[T, earlyIndex] = tension(u, sigma, G, N, K); % Call function
T_earlyvalues = T(earlyIndex); % Use logical index to get early T values
T_latervalues = T(~earlyIndex); % Use negated logical index to get later T values
And you can then use the subvectors T_earlyvalues and T_latervalues however you like.
I am getting an error to compile code line 9, so I am not sure how to dynamically access arrays. I have to build logic [255:0] from the received bytes.
(Looks like I have to review data types of SystemVerilog :( ).
Thanks in advance.
module test;
task test_array (logic [7:0] B);
static logic [255:0] l_ar_B;
l_ar_B[7:0] = B;
for(int i=0; i<32; i++)
l_ar_B[(i*8+7) : (i*8)] = B; // Error-[IRIPS] Illegal range in part select
$stop();
endtask
initial begin
$display("Start");
test_array(8'h11);
end
endmodule
When using the range selection with [M : N] syntax, M and N must be be constants. You should use part-select addressing with the syntax [s +: W], where W is a constant for the width and s can be a variable indicating the starting bit position. The +: been around since IEEE Std 1364-2001 (Verilog 2001). See
Indexing vectors and arrays with +:
for(int i=0; i<32; i++)
l_ar_B[(i*8) +: 8] = B;
Since you are doing replication, you can use l_ar_B = {32{B}}; to get the same result in a singe step.
I try to compile the following code with Dymola:
class abc
import Modelica.SIunits;
parameter SIunits.Time delta_t=0.5;
constant Real a[:]={4,2,6,-1,3,5,7,4,-3,-6};
Real x;
Integer j(start=1);
Integer k=size(a, 1);
algorithm
when {(sample(0, delta_t) and j < k),j == 1} then
x := a[j];
j := j + 1;
end when;
end abc;
and for time = 0 the variable j starts with 2. But it should start with j = 1.
Does anybody have an idea for this problem?
Keep in mind that sample(x,y) means that sample is true at x+i*y where i starts at zero. Which is to say that sample(0, ...) becomes true at time=0.
Since j starts at 1 and k is presumably more than 1, it doesn't seem unexpected to me that sample(0, delta_t) and j<k should become true at the start of the simulation.
I suspect what you want is:
class abc
import Modelica.SIunits;
parameter SIunits.Time delta_t=0.5;
constant Real a[:]={4,2,6,-1,3,5,7,4,-3,-6};
Real x;
Integer j(start=1);
Integer k=size(a, 1);
algorithm
when {(sample(delta_t, delta_t) and j < k),j == 1} then
x := a[pre(j)];
j := pre(j) + 1;
end when;
end abc;
I don't really see the point of the j==1 condition. It is true at the outset which means it doesn't "become" true then. And since j is never decremented, I don't see why it should ever return to the value 1 once it increments for the first time.
Note that I added a pre around the right-hand side values for j. If this were in an
equation section, I'm pretty sure the pre would be required. Since it is an algorithm section, it is mainly to document the intent of the code. It also makes the code robust to switching from equation to algorithm section.
Of course, there is an event at time = 0 triggered by the expression sample(0, delta_t) and j<k which becomes true.
But in older versions of Dymola there is an bug with the initialization of discrete variables. For instance even if you remove sample(0.0, delta_t) and j<k in dymola74, j will become 2 at time=0. The issue was that the pre values of when clauses, where not initialized correct. As far as I know this is corrected at least in the version FD1 2013.
Say I have a function
a = b / c
and I ask the user to input two of these variables, either b and a or c and a and I want it to calculate the unknown variable without needing to write a function for every variable
In this case I would use:
pseudo-code
if input is a & b
then c = b / a
if input is a & c
then b = a * c
if input is b & c
then a = b / c
I know this is a function with only three variables so it is easy to put it in an if-statement and voilĂ BUT I want to apply it to a system containing lots of equations (a jet engine for example). I used TkSolver before and it was really great, you throw as many equations as you want at it (a jet engine was an example!), you only need to give a number of known quantities and in a few seconds, all the unknowns are calculated (even if I had a known quantity in one side of the equation and unknown on another side mixed with known ones, it will do the maths!)
So, is there a way to do this in MatLab or perhaps python which I'm learning?
Edit to the question, thanks for directing me to use the Symbolic toolbox, it's great, I have another problem:
I couldn't think of a way to let the program know which of the variables is entered. I can do this:
syms f a b c
f = a * c - b %(I want to write a = b / c)
c = 10; a = 5;
X = eval(solve(f,b))
What I want now is a way of letting the user enter two knowns (e.g c & a) and the code will recognise them and solve to the unknown variable (e.g b).
Edit 2: I managed to get what I want, it's a bit long and there might be another way of achieving the same thing.
clear, clc
syms a b c
var = [{'a'}, {'b'}, {'c'}];
var1n = 0;
var2n = 0;
while isvarname(var1n) == 0
var1n = input('Which variable is known: ','s');
while ( any( strcmpi(var1n,var) ) )== 0
fprintf('\nThe variable entered is wrong, please enter a, b, or c')
var1n = input('\nWhich variable is known: ', 's');
end
end
fprintf('\nPlease enter the value of %s', var1n)
var1v = input(': ');
eval([var1n '=' num2str(var1v)]);
while isvarname(var2n) == 0
var2n = input('What is the second known variable: ', 's');
while ( any( strcmpi(var2n,var) ) ) == 0
fprintf('\nThe variable entered is wrong, please enter a, b, or c')
var2n = input('\nWhat is the second known variable: ', 's');
end
end
fprintf('\nPlease enter the value of %s', var2n)
var2v = input(': ');
eval([var2n '=' num2str(var2v)]);
var3n = char ( var ( find( strcmpi(var1n, var) == strcmpi(var2n, var) ) ) );
var3v = solve(a - b / c);
eval([var3n '=' char(var3v)]);
You could use this: http://www.mathworks.de/help/toolbox/symbolic/solve.html but you have to have the symbolic math toolbox (:
EDIT: On the documentation page of solve there's a sentence:
If the right side of an equation is 0, specify the left side as a
symbolic expression or a string:
That means, if you want to solve a = b/c for the value which is NOT set, simply rewrite the equation so that there is a zero on the right hand side:, i.e. a - b/c = 0, than you can use:
syms a b c
% E.g. assign values to a and c and automatically let matlab chose the 'free' variable (in this case, it's b:
a = input('Input var a: ')
a = input('Input var c: ')
solve(a - b/c)
which than gives you b (e.g. entering a = 10 and c = 40 gives you b = a * c = 400). Input function is explained here: http://www.mathworks.de/help/techdoc/ref/input.html! Hope that helps!