I have not been able to understand how to dereference a pointer in VHDL.
What I have in mind is a C code like :
int a;
int* ptr_a;
a = 42;
ptr_a=&a;
*ptr_a=451;// how can I do this ?
I tried to mimick this code in VHDL :
ptr_test : process
type ptr_integer is access integer;
variable a : integer;
variable ptr_a : ptr_integer;
begin
a := 42;
ptr_a := new integer'(a);
report "ptr now points to a : ptr=" & str(ptr_a.all);
ptr_a.all := 451;
report "ptr modified : ptr=" & str(ptr_a.all);
report "a is NOT modified : a =" & str(a);
wait;
end process;
So how can I correctly modify a value through a pointer ?
You can't directly. Access types are not "just like pointers" - they are to at least some extent distinct types of data storage.
This line does not create a pointer to a:
ptr_a := new integer'(a);
It creates a data object with the same value as a and sets up ptr_a to reference it.
If you were to create another access type variable :
variable ptr_b : ptr_integer;
and set it to to point to ptr_a:
ptr_b := ptr_a;
then changes to ptr_b.all will reflect in ptr_a.all.
"new" is the equivalent of the (C++ rather than C) "new" operation; invoking a constructor allocating an integer on the heap and initialising it to "a". (Naturally, you can "deallocate" it when done)
What you are looking for is ptr_a := a'access; which is the Ada way of accessing a global or local (stack) variable via a pointer : this is only legal if said variable has been declared "aliased" alerting the compiler to the fact there may be more than one view of it (and thus, preventing some nice optimisations). In C, everything is "aliased" whether you want it or not.
This is one of the aspects of Ada that didn't make it through the simplification process into VHDL : and it's difficult to see a good use for it. So there isn't an exact equivalent in VHDL.
Martin's answer just popped up : as he says, you CAN have 2 or more pointers to the same heap object.
Alternatively, explain what you are trying to achieve this way; there may be a VHDL alternative way of doing it.
Related
I have a function block, inside of which I have a method. When the method is called, it takes it's input REAL variable and sets the function block's internal variable, also type REAL. Now, for some reason, when i put a breakpoint inside the method, the value for that variable is completely wrong, and is always assigned the same value. Here is the code
METHOD PUBLIC LowerTheObject : BOOL
VAR_INPUT
nSpeedSetpoint : INT; // 0-32767 (0-21mm/min)
fInsertionDistance : REAL; // Milimeters
END_VAR
IF bEnable AND eMotionStateInternal = E_FeedState.IDLE AND bInhibitMovementDown THEN
LowerTheObject := TRUE;
eMotionStateInternal := E_FeedState.AUTOMATIC_LOWERING;
THIS^.fLoweringStartPosition := THIS^.fPosition;
THIS^.nSpeedSetpoint := nSpeedSetpoint;
THIS^.fInsertionDepth := TO_REAL(fInsertionDistance);
ELSE
LowerTheObject := FALSE;
END_IF
When I call this method here is what happens:
Now comes the interesting part, which took me a while to even see it. The value of the variable is WRONG only, when I break the code inside the method. Breaking the code inside the function block, the variable gets assigned correct value:
To wrap it up, I am as confused as ever. Why does braking the code assign the wrong value? This is very wrong, the code can't be debugged properly. Is this a bug in this build of the TwinCAT?
I can guarantee that no other place in the code sets the value of the fInsertionDepth. I even added the TO_REAL(), in case the compiler did something weird I am not seeing. It seems like a memory allocation issue to me, I have tried restarting the PC, cleaning solution, re-activating the configuration, nothing helps.
Does anyone have a clue what might be happening, why is the variable fInsertionDepth get the 9.4 * 10^-38 when using a breakpoint, no matter what value is beeing assinged to it? I am running the solution on a local development machine, windows10, 64 bit as well as 64 bit CPU, never saw these issues before. Using TwinCAT 3, build 4024.25.
EDIT:
I have managed to make a project where this is very obviously replicated - I am not sure how/where to add attachments, so here is the code:
PROGRAM MAIN
VAR
END_VAR
ProgramExecution();
// Program that will containt FBs
PROGRAM ProgramExecution
VAR
fbTest : FB_Base;
END_VAR
fbTest();
// Base FB
FUNCTION_BLOCK FB_Base
VAR
fbTest : FB_Sub;
fValue : REAL := 10.0;
bStart : BOOL;
END_VAR
IF bStart THEN
bStart := FALSE;
fbTest.Method1(fValue := fValue);
END_IF
fbTest();
// Second FB, that is instantiated inside the base FB
FUNCTION_BLOCK FB_Sub
VAR
fValue : REAL;
bCall : BOOL;
END_VAR
// Method within the second FB
METHOD PUBLIC Method1 : BOOL
VAR_INPUT
fValue : REAL;
END_VAR
IF TRUE THEN
Method1 := TRUE;
THIS^.fValue := fValue;
ELSE
Method1 := FALSE;
END_IF
Here is the resulting error when breaking on the expression where the value is beeing assinged:
It is a glitch in displays, this value is assigned at some point, because you working in the stack memory (because the variable is declared in a method). In the PLC world you don't have any garbage collector, you just overwrite the address in every cycle. The number what you can see in when you break is some remaining data. Sometime the debug display not fast enough to collect everything when you break, especially if you change tab on the break. (This display issue is depend on your engineering PC not on the target PLC.)
It says
fatal: syntax error, OF expected but [ found" for the variable "lo"
But I really can't see whats wrong with it.
I tried to change variable name but seems not working.
procedure reg( index, gen : char;
fname, sname, loginname, passwords, pid : string;
var lo : array [1..26,1..1025] of bucket ;
var main : array[1..1025] of detail);
var
convertedindex, i, j : integer;
found, found2 : boolean;
It's supposed to be without error but it says syntax error.
You can't define an array while you are in the middle of declaring the parameters of a procedure (or function). You need to define the array type beforehand by doing something like this instead:
program arraydecl;
type
Bucket = integer;
Detail = integer;
type
BucketArray = array [1..26,1..1025] of Bucket;
DetailArray = array[1..1025] of Detail;
procedure reg(index, gen : char; fname, sname, loginname, passwords, pid : string ; var lo : BucketArray; var main : DetailArray);
begin
end;
The error message says that the compiler expected the keyword of, but instead it found an opening bracket [.
The reason is (I guess) that in procedure declarations, you cannot define the bounds of an array. For example, you cannot say main: array[1..2] of integer, you can only say main: array of integer.
You can try to define an array type and then use that type as the procedure parameter:
type TwoInts = array[1..2] of integer;
procedure PrintTwoInts(ti: TwoInts)
begin
WriteLn(ti[1], ti[2])
end;
I haven't programmed in Pascal for a long time, so the above may or may not work. I don't remember whether ti would be passed by value or by reference, and whether the array indices inside the procedure would always start at 0. That's some things you would need to find out.
Parameter lists
In some Pascal versions, like FreePascal or Delphi, parameter lists of functions or procedures cannot contain type declarations, only type specifications.
So, to specify such an array as parameter, you must declare its type first, before the function/procedure declaration:
type
// Type declarations
Bucket = ...
Detail = ...
TBuckets = array[1..26, 1..1025] of Bucket;
TDetails = array[1..1025] of Detail;
procedure Reg(Index, Gen: Char; FName, SName, LoginName, Passwords, PID: string;
var Lo: TBuckets; var Main: TDetails);
Note that other Pascals (including ISO Pascal, if I remember correctly) do allow these ad hoc (on the spot) declarations, even in parameter lists. But obviously your dialect of Pascal doesn't.
Open array parameters
Now if you see a parameter specifications like x: array of Integer or similar, then you are dealing with open array parameters. This is not a declaration and it doesn't specify one single type, it accepts all kinds of one-dimensional arrays of that base type. More on that in my article Open array parameters and array of const.
This explains the error message: only of can follow array in a parameter list, to specify an open array parameter.
For what it's worth: if you are using FreePascal or Delphi, then you should get in the habit of passing strings as const, if possible: const FName, SName, etc...: string.
The following code, taken from Gnu Pascal test code, will compile nicely in Free Pascal. And I can understand how it works.
var s1 : set of 0..255;
s2 : set of 64..128;
ok : boolean;
procedure p1;
begin
if s1 = s2 then begin
writeln('failed1');
ok := false;
end;
end;
However, I'm slightly curious what the rules are for set compatibility and what you can expect. For example:
program p;
var
a : set of 0..10;
b : set of 20..100;
s : integer;
begin
b := [20];
a := [];
if a = b then
writeln('a')
else
writeln('b');
end.
This prints 'b'. But if I have two empty sets (b := [];) then they are considered equal.
I'm just trying to get my head around how this actually gets implemented.
(What I'm kind of thinking is that the two sets are converted to the union of the ranges, so set of 0..100 are created, and two temporaries from a and b as set of 0..100, and then comparison is done those temporaries).
Sets with integers as base type (the type after the set of) are always compatible.
Your assumption is correct: in general both sets are converted to temporaries with common ranges and then the temporaries are compared. The conversion is done by calls to fpc_varset_load.
If you are interested in more details, the code which decides how to convert the sets, is located in nadd.pas (see 1) starting at line 1593.
I am having this issues in the Cadence tool chain simulation when I try to connect the multidimensional user defined type in VHDL to SystemVerilog in a UVM environment. This is the VHDL output type definition:
TYPE loop_reg_ty IS RECORD
loop_index_value : std_logic_vector(REG_BITWIDTH-1 DOWNTO 0);
loop_counter : std_logic_vector(REG_BITWIDTH-1 DOWNTO 0);
loop_end_flag : std_logic;
END RECORD;
TYPE loop_array_ty is array (MAX_NO_OF_LOOPS-1 downto 0) of loop_reg_ty;
One of the VHDL output ports in my DUT is of type loop_array_ty;
I am trying to define the SystemVerilog equivalent as:
typedef struct packed {
bit [REG_BITWIDTH-1:0] loop_index_value;
bit [REG_BITWIDTH-1:0] loop_counter;
bit loop_end_flag;
} raccu_loop_reg_ty;
typedef raccu_loop_reg_ty [MAX_NO_OF_RACCU_LOOPS-1:0] loop_array_ty;
When I use irun, I get the error:
VHDL port type is not compatible with Verilog.
Please suggest the possible work around solution.
First, your problem is that you're not defining the loop_array_ty correctly. It should be typedef raccu_loop_reg_ty loop_array_ty[MAX_NO_OF_RACCU_LOOPS-1:0].
I would suggest 2 things here:
First, try removing the packed qualifier from the struct definition. Connecting SV structs to VHDL records is something that is only available in newer Incisive versions. Make sure that the version you're using supports this.
If you're using an older version of Incisive (like I was a year back), your only choice is to map the individual record members using $nc_mirror (not tested code, but enough to get you started):
// struct definition...
// ...
module top;
// intermediate signal we'll mirror onto
loop_array_ty loop_s;
// no output connected
my_dut dut_inst();
// make the connection between SV and VHDL using nc_mirror
initial begin
for (int i = 0; i < MAX_NO_OF_RACCU_LOOPS; i++) begin
$nc_mirror($sformatf("loop_s[%0d].loop_index_value", i),
$sformatf("dut_inst.loop_o[%0d].loop_index_value", i);
// $nc_mirror for loop_counter
// $nc_mirror for loop_end_flag
end
end
endmodule
Also make sure that you're setting the REG_BITWIDTH constant appropriately in both languages, otherwise you'll also get a type mismatch.
In this piece of code I get this error for the line with +
function func (bv1 : in bit_vector; bv2 : in integer) return bit_vector is
variable temp : natural := 2**bv2;
variable result : bit_vector(1 to 32);
begin
report "asd" & natural'image(temp);
result <= bv1 + temp; // this line causes the error
return result;
end func;
The error is :
No function declarations for operator +
How can I solve this? I also get a similar error for "=" as well.
Don't use bit_vectors (or std_logic_vectors, really) for anything you want to do arithmetic on.
Use the ieee.numeric_std library and then declare your signals (or whatever) to be of type signed ot unsigned depending on what type of vector you want. (Or of course, you can just use integers and the subtypes of that)
It's because you try to add a natural to a bit_vector which does not work because they are of different types. So you'll have to use a converter, e.g. as shown here within one of the functions. The other method is to stick to all the same types, but that isn't always possible.
Some initial problems with the code are that VHDL comments markup is --, not
//, and assign to result variable must use :=, since <= is for assign
to signal.
Then, the reason for the error:
No function declarations for operator +
is that VHDL is a strong typed language, so it is not possible just to add a
natural type and a bit_vector type, as attempted in result <= bv1 + temp.
Instead you need to use the package numeric_bit_unsigned, and for example
convert temp to bit_vector using function to_bitvector before adding.
Resulting code can then be:
library ieee;
use ieee.numeric_bit_unsigned.all;
...
function func (bv1 : in bit_vector; bv2 : in integer) return bit_vector is
variable temp : natural := 2**bv2;
variable result : bit_vector(1 to 32);
begin
report "asd" & natural'image(temp);
result := bv1 + to_bitvector(temp, result'length); -- this line causes the error
return result;
end func;
You should check that the length is enough to handle the required values.
However, instead of using bit_vector type, you may consider the
std_logic_vector (depending on the design), since the std_logic_vector has
additional values that may reveal design problem in simulation.