it is probably because of me being newbe. Anyways, I want to define some variables to use in more than one function (like global variables in C). I decided to go with shared variables but it gives me the error Cannot reference shared variable "x" inside pure function "y". If I define the variable in a process, then it initializes(erases the value) every process activation.
Architecture SV_example of example is
shared variable temp:std_logic_vector(18 downto 0):= "0000000000000000000";
SIGNAL gct: STD_LOGIC_VECTOR(18 DOWNTO 0);
function register_adder( load_value:std_logic ) return std_logic_vector is
begin
for i in size downto 0 loop
temp(i) := load_value;
end loop;
return temp;
end register_adder;
p1 : process (CLK)
begin
if rising_edge(CLK) then
gct <= register_loader('1');
end if;
end process;
end SV_example;
In VHDL (at least with VHDL '93 and later), functions are pure by default. A pure function is one that has no side effects. It depends only on its inputs, with no dependency on (non-static) outside information.
So, your fix is to declare the function impure. I had to do some editing to your example to make it an MCVE. The fix:
library ieee;
use ieee.std_logic_1164.all;
entity example is
port
(
CLK : in std_logic
);
end entity example;
Architecture SV_example of example is
shared variable temp:std_logic_vector(18 downto 0):= "0000000000000000000";
SIGNAL gct: STD_LOGIC_VECTOR(18 DOWNTO 0);
impure function register_adder( load_value:std_logic ) return std_logic_vector is
begin
for i in temp'length-1 downto 0 loop
temp(i) := load_value;
end loop;
return temp;
end register_adder;
begin
p1 : process (CLK)
begin
if rising_edge(CLK) then
gct <= register_adder('1');
end if;
end process;
end SV_example;
Note this works only in VHDL '93. The use of a shared variable changes significantly in VHDL '02 and later.
One final note. Shared variables generally are not synthesizable (the only example I can think of is the inference model for a RAM). Shared variables are usually only for general purpose use in hardware or testbench modeling.
Shared variable often goes with protected types, which can handle encapsulation of data. An example using protected type is shown below:
architecture SV_example of example is
signal gct : std_logic_vector(18 downto 0);
type temp_t is protected
impure function register_adder(load_value : std_logic) return std_logic_vector;
end protected;
type temp_t is protected body
variable temp : std_logic_vector(18 downto 0) := (others => '0');
impure function register_adder(load_value : std_logic) return std_logic_vector is
begin
for i in temp'range loop
temp(i) := load_value;
end loop;
return temp;
end function;
end protected body;
shared variable temp_sv : temp_t;
begin
p1 : process (CLK)
begin
if rising_edge(CLK) then
gct <= temp_sv.register_adder('1');
end if;
end process;
end SV_example;
For access to the internal temp data, a function get_temp can be written, if needed.
Related
My code is under , i will be gratefull for any suggestion
(* //const
//pi=3.1415926;
//uses
//mathh.inc; *)
var
r,pole_kola,obwod_kola: real;
function Pi: valreal;
begin
Pi:=3.1415926;
end;
procedure dane();
begin
read(r);
end;
procedure obliczenia();
begin
pole_kola:= {pi}Pi*r*r;
obwod_kola:= 2*{pi}Pi*r;
end;
procedure wyniki();
begin
writeln('pole koła: ',pole_kola:4:8);
writeln('obwód koła: ',obwod_kola:4:8);
end;
begin
writeln('podaj promien r: ');
dane();
obliczenia();
wyniki();
end.
How i can use function Pi :
https://www.freepascal.org/docs-html/rtl/system/pi.html
to return automatic value of "PI" from function without assign in operation part of function body if i try modify function get back
Function result does not seem to be set
function Pi() :valreal;
begin
end;
begin
WriteLn('pi = ', Pi():1:20);
end.
Compiling main.pas
main.pas(1,10) Warning: Function result does not seem to be set
Linking a.out
8 lines compiled, 0.1 sec
1 warning(s) issued
pi = 0.00000000000000000000
in program
./main
podaj promien r:
6
pole koła: 0.00000000
obwód koła: 0.00000000
In the task, I wanted to automatically use a ready value for PI (3.14…) without using my function. My function didn’t returned a value because I didn’t assigned one. Like we see here:
function Pi() :valreal;
begin
//here is nothing but must be returned a value
end;
begin
WriteLn('pi = ', Pi():1:20);
end.
Going by #derpirscher’s comment, the function written by hand always needs to return something. So I commented part of my syntax, and used the built-in function named PI. (Pascal includes that function.)
(* function pi: valreal; // If I define my own function, it must return a value
begin
pi:=3.1415926; // So in the body of the function, we must assign value
end; *)
We see that here
procedure obliczenia();
begin
pole_kola:= {pi}Pi*r*r; // using build in function
obwod_kola:= 2*{pi}Pi*r; // as above
end;
If we need to use the value of PI in our task/homework, we can use predefinied built-in functions because it is easier; it is good practice to use less syntax in our code.
Must remember: If we define a function i.e., named Pi ourselves, it has to return a value.
Under the comment, the entire syntax of my code with corrections:
var
r,pole_kola,obwod_kola: real;
(* function pi: valreal; // If I define my own function, it must return a value
begin
pi:=3.1415926; // So in the body of the function, we must assign value
end; *)
procedure dane();
begin
read(r);
end;
procedure obliczenia();
begin
pole_kola:= {pi}Pi*r*r; // using build in function
obwod_kola:= 2*{pi}Pi*r; // as above
end;
procedure wyniki();
begin
writeln('pole koła: ',pole_kola:4:8);
writeln('obwód koła: ',obwod_kola:4:8);
end;
begin
writeln('podaj promien r: ');
dane();
obliczenia();
wyniki();
end.
Ok, so I have a problem with a ROM initialization function.
Before I get into the problem let me explain a bit the nature of my problem and my code.
What I want to do is generate N number of ROMs which I have to use as an input for a module that runs a matching algorithm.
My problem is that I have a file with my signatures (let's say 64 in total) which I want to load in my different ROMs depending on how many I've generated (powers of 2 in my case, e.g. 8 roms of 8 signatures each).
I figured the best way to do it is load the whole text file into an array (using a function outside of the architecture body) which I will then use (again in a function) to load the data into a smaller array which will then be my ROM.
It seemed to me that the synthesizer would then just ignore the big array since I don't actually use it in my architecture.
Problem now is that since the second array input arguments are signal dependent, the synthesizer just ignores them and ties my array to zero (line 57).
Does anyone know how else if there's a way to make this architecture synthesize-able?
library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_signed.all;
use std.textio.all;
entity signatures_rom_partial is
generic(
data_width : integer := 160;
cycle_int : integer :=32;
rom_size : integer := 4
);
port ( clk : in std_logic;
reset : in std_logic;
readlne: in integer range 0 to cycle_int-1; -- user input for array data initialization
address: in integer range 0 to rom_size-1; -- address for data read
data: out std_logic_vector(data_width-1 downto 0) -- data output
);
end signatures_rom_partial;
architecture rom_arch of signatures_rom_partial is
type rom_type is array (0 to cycle_int-1) of bit_vector (data_width-1 downto 0); -- big array for all signatures, not used in arch
type test_type is array (0 to rom_size-1) of std_logic_vector (data_width-1 downto 0); -- smaller ROMs used in arch
--Read from file function--
----------------------------------------------------------------------------------------------------------
impure function InitRomFromFile (RomFileName : in string) return rom_type is --
file RomFile : text is in RomFileName; --
variable RomFileLine : line; --
variable rom : rom_type; --
--
begin --
for i in rom_type'range loop --
readline (RomFile, RomFileLine); --
read (RomFileLine, rom(i)); --
end loop; --
return rom; --
end function; --
----------------------------------------------------------------------------------------------------------
--Function for smaller ROM initialization--
----------------------------------------------------------------------------------------------------------
impure function initPartRom (rom : rom_type; readlne : integer) return test_type is --
variable test_array : test_type; --
--
begin --
for j in test_type'range loop --
test_array(j) := to_stdlogicvector(rom(j+readlne)); --
end loop; --
return test_array; --
end function; --
----------------------------------------------------------------------------------------------------------
constant rom : rom_type := InitRomFromFile("signatures_input.txt");
signal test_array : test_type := initPartRom(rom , readlne); --(LINE 57) SYNTHESIZER IGNORES THESE INPUT ARGUMENTS
begin
process(clk,reset)
begin
if reset='1' then
data<=(others=>'0');
elsif (clk'event and clk='1') then
data <= (test_array(address));
end if;
end process;
end rom_arch;
Synthesis is done using Xilinx ISE, simulation is done with Modelsim in which, my creation works fine :)
Thanks for any help!
With Xilinx ISE (14.7) it is possible to synthesize ROMs and RAMs even if the initial data is read from an external file by function.
The only requirement is, that the reading function must be computable at synthesis time. This is not true for your code because readlne is not static at the point the function is called. You should change it to a generic instead of an input and assign a different value to this generic for every other ROM instance. Then it should work as intended.
A sample implementation of how to read initialization data from a text file in (Xilinx) .mem format can be found in VHDL Library PoC in the namespace PoC.mem.ocrom or PoC.mem.ocram
I wrote a function inside a package file, and I'm calling it inside the main vhd file. It seems to me everything is correctly in place. But the Sigasi editor says "No matching subprogram was found." at the line where I called the function.
This is the package file content:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.numeric_std.ALL;
PACKAGE pkg IS
TYPE t IS ARRAY (positive RANGE <>) OF std_logic_vector(7 DOWNTO 0);
FUNCTION char2byte (SIGNAL yazi_char: character) RETURN std_logic_vector;
END pkg;
PACKAGE BODY pkg IS
FUNCTION char2byte (SIGNAL yazi_char: character) RETURN std_logic_vector IS
VARIABLE yazi_byte: std_logic_vector;
BEGIN
case yazi_char is
when '0' => yazi_byte:=x"30";
when '1' => yazi_byte:=x"31";
when '2' => yazi_byte:=x"32";
....
when others =>
end case;
RETURN yazi_byte;
END char2byte;
END pkg;
And this is the main file content:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use WORK.pkg.ALL;
entity rs232 is
port(
clk:in std_logic;
tx_port:out std_logic
);
end rs232;
architecture Behavioral of rs232 is
signal yazi_byte: t;
begin
yazi_byte<=char2byte("y");
process(clk)
begin
....
end process;
end Behavioral;
Where is the fault? The funny thing is, ISE is giving another error, not a "No matching subprogram was found.".
It is:
ERROR:HDLParsers:522 - "D:/UME/FPGA/ise_projeleri/RS232_TEST/pkg.vhd" Line 16. Variable yazi_byte is not constrained.
ERROR:HDLParsers:3304 - "D:/UME/FPGA/ise_projeleri/RS232_TEST/pkg.vhd" Line 16. Can not determine the "others" values in aggregate. (LRM 7.3.2)
Thanks for helping.
You have lots of subtle errors. Some of them noted already, others not. Lets start with types. "y" is a single element string (string(1 to 1)). char2byte requires a character, such as 'y'. As #Brian pointed out, char2byte returns std_logic_vector and not type t (an array of std_logic_vector).
On char2byte you have declared the character input to be a signal. This would mean that you need to map a signal to it and not a literal, such as 'y'. You probably want to declare it as a constant instead (or just leave the class off). In the code below, note the fix to yazi_byte (also noted by #Andy).
FUNCTION char2byte (CONSTANT yazi_char: character) RETURN std_logic_vector IS
VARIABLE yazi_byte: std_logic_vector(7 downto 0) ;
BEGIN
case yazi_char is
when '0' => yazi_byte:=x"30";
when '1' => yazi_byte:=x"31";
when '2' => yazi_byte:=x"32";
....
when others =>
end case;
RETURN yazi_byte;
END char2byte;
Note a clever solution to Char2Byte may use an array of std_logic_vector(7 downto 0) that is indexed by type character (perhaps a project for another day). See #David's post here for an idea: Missing EOF at function. Indexing the array would work similar to a subprogram call.
If you only have char2byte, then your testbench needs to receive a std_logic_vector value (also see #Brian's fix):
architecture Behavioral of rs232 is
signal slv_byte: std_logic_vector(7 downoto 0) ;
begin
slv_byte<=char2byte('y');
If your testbench really needs to work with strings and type t, then a function that takes type string and returns type t, such as the following partially built function would be helpful:
FUNCTION string2slv (yazi_str : string) RETURN t is
variable result : t (yazi_str'range) ;
begin
. . .
end FUNCTION string2slv ;
The problem is that you are confusing a std_logic_vector with t, an array of std_logic_vector.
signal yazi_byte: t;
begin
yazi_byte<=char2byte("y");
...
Now t is an unconstrained array, which allows you to declare ts of different sizes when you use the package. There are two ways to do this :
declare a t and initialise it in the declaration : the initialiser (function call or array aggregate) defines its size. Works for signals but especially useful for constants
constrain it to the size you need in the declaration.
Thus the first example is constrained to be 4 bytes long:
constant deadbeef : t := (X"DE", X"AD", X"BE", X"EF");
And your second example is currently 1 byte long: however you still need to address that byte within it... This is actually why you get the obscure-looking error message.
signal yazi_byte: t(0 downto 0);
begin
yazi_byte(0) <= char2byte("y");
...
VHDL has operator and function overloading, so the compiler is looking for a "char2byte" function that returns an array of std_logic_vector because that's the type of the variable you are assigning to. It can't find one (hence "no matching subprogram") because the only "char2byte" you wrote returns a single std_logic_vector, not an array of them.
So addressing a single element of that array will let it find your char2byte - and now the error message makes perfect sense...
The variable yazi_byte needs to be constrained explicitly, as the error message says. It looks like it has a range of eight bit, so:
VARIABLE yazi_byte: std_logic_vector(7 downto 0);
would work.
I am doing this for my school work where I'm making my own rolling/shifting function.
Below is the code I wrote, but when i try to compile it i get syntax error on rownum<=rol(rowcount,1);
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture main of proj is
function "rol" (a: std_logic_vector; n : natural)
return std_logic_vector is
begin
return std_logic_vector(unsigned(a) rol n);
end function;
signal rownum : std_logic_vector(2 downto 0);
signal rowcount : std_logic_vector(2 downto 0);
begin
process begin
wait until rising_edge(i_clock);
**rownum<=rol(rowcount,1);**
end process;
end architecture main;
There are a couple of things that need to be addressed here.
Firstly, you need an entity statement:
entity proj is
port(
i_clock : in std_logic
);
end proj;
This declares what signals are inputs and outputs for your entity. In this case, it's just a clock. You can add rownum and rowcount inputs and outputs too as needed.
Your function name shouldn't be in inverted commas, and overloading an existing operator isn't a good idea either.
function rol_custom (a: std_logic_vector; n : natural)
return std_logic_vector is
begin
return std_logic_vector(unsigned(a) rol n);
end function;
Here's the synthesizable code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity proj is
port(
i_clock : in std_logic
);
end proj;
architecture main of proj is
function rol_custom (a: std_logic_vector; n : natural)
return std_logic_vector is
begin
return std_logic_vector(unsigned(a) rol n);
end function;
signal rownum : std_logic_vector(2 downto 0);
signal rowcount : std_logic_vector(2 downto 0);
begin
process begin
wait until rising_edge(i_clock);
rownum<=rol_custom(rowcount,1);
end process;
end architecture main;
However, even though this now should synthesize, the results won't make any sense, because rowcount has not been given a value. In order to define it, you might want to add a process which drives the signal based on certain criteria (a counter?) or add it as an input in the entity definition.
If your vectors represent numbers, you should use a numerical type for them. Use the ieee.numeric_std library and a unsigned or signed type as appropriate. rol will then just work. You won't have to create your own.
Can it be known in general whether or not placing a case within a for loop will result in bad assembly. I'm interested mainly in Delphi, but this is an interesting programming question, both in terms of style and performance.
Here are my codez!
case ResultList.CompareType of
TextCompareType:
begin
LastGoodIndex := -1;
for I := 1 to ResultList.Count -1 do
if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
LastGoodIndex := I
else if not ResultList[I].Indeterminate then
begin
if (StrComp(ResultList[LastGoodIndex].ResultAsText,
ResultList[I].ResultAsText) > 0)
and (Result FalseEval) then
Result := TrueEval
else
Result := FalseEval;
LastGoodIndex := I;
end;
end;
end;
NumericCompareType:
begin
//Same as above with a numeric comparison
end;
DateCompareType:
begin
//Same as above with a date comparison
end;
BooleanCompareType:
begin
//Same as above with a boolean comparison
end;
alternatively I could write
begin
LastGoodIndex := -1;
for I := 1 to ResultList.Count -1 do
if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
LastGoodIndex := I
else if not ResultList[I].Indeterminate then
begin
case ResultList.CompareType of
TextCompareType:
begin
if (StrComp(ResultList[LastGoodIndex].ResultAsText,
ResultList[I].ResultAsText) > 0)
and (Result FalseEval) then
Result := TrueEval
else
Result := FalseEval;
LastGoodIndex := I;
end;
NumericCompareType:
begin
//Same as above with a numeric comparison
end;
DateCompareType:
begin
//Same as above with a date comparison
end;
BooleanCompareType:
begin
//Same as above with a boolean comparison
end;
end;
end;
end;
I don't like the second way because I'm asking a question I know the answer to in a for loop and I don't like the first way because I'm repeating the code I use to figure out which of my objects contain valid information.
Perhaps there is a design pattern someone could suggest that would circumvent this all together.
In general, there is no way to know what assembly-language output will be generated for particular programming-language constructs. Every compiler is different. Even for a particular compiler, every application will be different, and the compiler will have different optimization strategies available to it.
If you are really worried about it, the easiest thing to do is compile the program and see what it generates. Play around with code and optimization settings until it looks how you want it to. (Or write assembly by hand.)
The common advice is to just write the clearest code you can, and don't worry about tweaking performance unless you really need to.
Why not using subclasses?
This saves the use of the case statement.
TComparer = class
protected
function Compare(const AItem1, AItem2: TItem): Boolean; virtual; abstract;
public
procedure DoCompare(ResultList: ...);
end;
TTextComparer = class (TComparer)
protected
function Compare(const AItem1, AItem2: TItem): Boolean; override;
end;
procedure TComparer.DoCompare(ResultList: ...);
var
LastGoodIndex, I : Integer;
begin
LastGoodIndex := -1;
for I := 1 to ResultList.Count -1 do
if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
LastGoodIndex := I
else if not ResultList[I].Indeterminate then begin
if Compare(ResultList[LastGoodIndex], ResultList[I]) then
Result := TrueEval
else
Result := FalseEval;
end;
end;
function TTextComparer.Compare(const AItem1, AItem2: TItem): Boolean;
begin
Result := StrComp(ResultList[LastGoodIndex].ResultAsText,
ResultList[I].ResultAsText) > 0)
end;
I suspect that it's more efficient to use a lambda or closure or even just a function reference. My Pascal's rusted right out, so my example is perl:
my %type = (
TextCompareType => sub { $_[0] lt $_[1] },
NumericCompareType => sub { $_[0] < $_[1] },
DateCompareType => sub { ... },
BooleanCompareType => sub { ... },
);
for (my $i = 1; $i <= $#list; ++$i)
{
if ( $type{$ResultList{CompareType}}->($list[$i-1], $list[$i]) )
{
$result = 1; # ?
}
}
I'm not really following most of your code, but I think I've captured the essence of the question without fully capturing the code.
Another solution is to create comparator objects as subclasses off a base comparator class, and then call the object's compare function, but you do mention trying to stay structured instead of OO.