How do you concatenate bits in VHDL? I'm trying to use the following code:
Case b0 & b1 & b2 & b3 is
...
and it throws an error
Thanks
The concatenation operator '&' is allowed on the right side of the signal assignment operator '<=', only
You are not allowed to use the concatenation operator with the case statement. One possible solution is to use a variable within the process:
process(b0,b1,b2,b3)
variable bcat : std_logic_vector(0 to 3);
begin
bcat := b0 & b1 & b2 & b3;
case bcat is
when "0000" => x <= 1;
when others => x <= 2;
end case;
end process;
Here is an example of concatenation operator:
architecture EXAMPLE of CONCATENATION is
signal Z_BUS : bit_vector (3 downto 0);
signal A_BIT, B_BIT, C_BIT, D_BIT : bit;
begin
Z_BUS <= A_BIT & B_BIT & C_BIT & D_BIT;
end EXAMPLE;
Related
I have a bit vector like this
subtype alarms_type : std_logic_vector(1 to 8)
signal alarms : alarms_type := (others => '0');
and the purpose of each bit is defined like this
constant sys1_temp_hi_al : integer := 1;
constant sys1_temp_lo_al : integer := 2;
constant sys1_crnt_hi_al : integer := 3;
constant sys1_cnrt_lo_al : integer := 4;
constant sys2_temp_hi_al : integer := 5;
constant sys2_temp_lo_al : integer := 6;
constant sys2_crnt_hi_al : integer := 7;
constant sys2_cnrt_lo_al : integer := 8;
I would like to be able to access subsets of the alarms_type with a short, readable notation. For example
alarms(SYS2_ALS) <= (others => '0'); -- set multiple values
temp_alarm <= or(alarms(TEMP_ALS)); -- or together multiple values to a std_logic
temp_alarms <= alarms(TEMP_ALS)); -- extract a subset to a suitably sized vector
alarms(TEMP_ALS) := (others => '1'); -- set (or clear) multiple disjoint values
I would like to know if the alias keyword will help me, like this:
alias HI_ALARMS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias LO_ALARMS is sys1_temp_lo_al|sys1_crnt_lo_al|sys2_temp_lo_al|sys2_crnt_lo_al;
alias TEMP_ALS is sys1_temp_hi_al|sys1_temp_lo_al|sys2_temp_hi_al|sys2_temp_lo_al;
alias CRNT_ALS is sys1_crnt_hi_al|sys1_crnt_lo_al|sys2_crnt_hi_al|sys2_crnt_lo_al;
alias SYS1_ALS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
alias SYS2_ALS is sys1_temp_hi_al|sys1_crnt_hi_al|sys2_temp_hi_al|sys2_crnt_hi_al;
It appears from the Alias chapter of the Ashenden book that this is not how an alias should be used, but hopefully I am missing something.
If there is a correct way to use alias to achieve my goal, please provide examples.
Alternatively, if there is a different or better way using constant or some other aspect of VHDL, please show me how.
Or just tell me that it can't be done, and if it is appropriate, please confirm that I could write functions to get and procedures to set the different subsets.
If I use functions and procedures, is there a cleaner notation than this? (I may need lots of this functions and procedures).
function get_temp_als(alarms : alarms_type)
return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);
function get_combined_temp_als(alarms : alarms_type)
return alarms(sys1_temp_hi_al) or alarms(sys1_temp_lo_al) or alarms(sys2_temp_hi_al) or alarms(sys2_temp_lo_al);
procedure set_temp_als(alarms: alarm_type, value:std_logic)
begin
alarms(sys1_temp_hi_al) <= value;
alarms(sys1_temp_lo_al) <= value;
alarms(sys2_temp_hi_al) <= value;
alarms(sys2_temp_lo_al) <= value;;
end;
I would like this to work with VHDL 2002 and it is intended for synthesis.
Aliases are new names for existing named entities not new entities.
Alternatively, if there is a different or better way using constant or some other aspect of VHDL, please show me how.
There's the basic issue where it isn't clear what you're going to do with information, lacking a minimal, complete, and verifiable example you're trying to make more 'elegant'.
It is possible to use constants to specify alarms_type indexes:
library ieee;
use ieee.std_logic_1164.all;
entity alarming is
end entity;
architecture fum of alarming is
-- subprograms, constants and type declarations could be in a package
subtype alarm_range is integer range 1 to 8;
subtype alarms_type is std_logic_vector(alarm_range);
signal alarms: alarms_type := (others => '0');
constant sys1_temp_hi_al : integer := 1;
constant sys1_temp_lo_al : integer := 2;
constant sys1_crnt_hi_al : integer := 3;
constant sys1_crnt_lo_al : integer := 4;
constant sys2_temp_hi_al : integer := 5;
constant sys2_temp_lo_al : integer := 6;
constant sys2_crnt_hi_al : integer := 7;
constant sys2_crnt_lo_al : integer := 8;
type index is array (natural range <>) of alarm_range;
constant HI_ALARMS: index := (sys1_temp_hi_al, sys1_crnt_hi_al,
sys2_temp_hi_al, sys2_crnt_hi_al);
constant LO_ALARMS: index := (sys1_temp_lo_al, sys1_crnt_lo_al,
sys2_temp_lo_al, sys2_crnt_lo_al);
constant TEMP_ALS: index := (sys1_temp_hi_al, sys1_temp_lo_al,
sys2_temp_hi_al, sys2_temp_lo_al);
constant CRNT_ALS: index := (sys1_crnt_hi_al, sys1_crnt_lo_al,
sys2_crnt_hi_al, sys2_crnt_lo_al);
constant SYS1_ALS: index := (sys1_temp_hi_al, sys1_temp_lo_al,
sys1_crnt_hi_al, sys1_crnt_lo_al);
constant SYS2_ALS: index := (sys2_temp_hi_al, sys2_temp_lo_al,
sys2_crnt_hi_al, sys2_crnt_lo_al);
function get_alarm (alarm: alarms_type; indx: alarm_range)
return std_logic is
begin
return alarm(indx);
end function;
function set_alarm (alarm: alarms_type; indx: alarm_range)
return alarms_type is
variable ret_val: alarms_type := alarm;
begin
ret_val(indx) := '1';
return ret_val;
end function;
function get_alarms (alarm: alarms_type; alarm_indx: index)
return std_logic_vector is -- doesn't look real useful.
variable ret_val: std_logic_vector(alarm_indx'range);
begin
for i in alarm_indx'range loop
ret_val(i) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
-- instead:
function select_alarms (alarm: alarms_type; alarm_indx: index)
return alarms_type is
variable ret_val: alarms_type := (others => '0');
begin
for i in alarm_indx'range loop
ret_val(alarm_indx(i)) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
-- which returns a mask selected alarms_type value that allows the use of a
-- single alarm service routine.
function set_alarms (alarm: alarms_type; alarm_indx: index)
return alarms_type is
variable ret_val: alarms_type := (others => '0');
begin
for i in alarm_indx'range loop
ret_val(i) := alarm(alarm_indx(i));
end loop;
return ret_val;
end function;
procedure report_alarms (alarm: in alarms_type) is
type name_array is array (alarm_range) of string (1 to 15);
constant alarm_name: name_array := (
"sys1_temp_hi_al", "sys1_temp_lo_al",
"sys1_crnt_hi_al", "sys1_crnt_lo_al",
"sys2_temp_hi_al", "sys2_temp_lo_al",
"sys2_crnt_hi_al", "sys2_crnt_lo_al"
);
begin
for i in alarm_range loop
if alarm(i) = '1' then
report "alarm " & alarm_name(i) & " is set";
end if;
end loop;
end procedure;
begin
alarms <= select_alarms("11111111", TEMP_ALS) after 5 ns;
LABELED:
process (alarms)
begin
report_alarms(alarms);
end process;
end architecture;
And
ghdl -r alarming
alarming.vhdl:102:17:#5ns:(report note): alarm sys1_temp_hi_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys1_temp_lo_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys2_temp_hi_al is set
alarming.vhdl:102:17:#5ns:(report note): alarm sys2_temp_lo_al is set
tells us I can set all the temperature alarms using alarms selected by the set of temperature alarm indexes.
By providing a second parameter for selecting a set of alarms by name the number of subprograms drops (the alternative is to declare a type for all the different sets of alarms and provide subprograms for them all).
You are correct in that aliases do not work like that. They are an alias to a single object (or slice thereof) and cannot be used to make new compounded objects like you might do with a pointer in another language.
A procedure is likely the only way you can achieve this. The alarms paramter should be a signal and mode out:
procedure set_temp_als(signal alarms: out alarm_type; value:std_logic)
begin
alarms(sys1_temp_hi_al) <= value;
alarms(sys1_temp_lo_al) <= value;
alarms(sys2_temp_hi_al) <= value;
alarms(sys2_temp_lo_al) <= value;
end;
so you can assign the alarms with:
set_temp_als(alarms, '1');
Your functions are the right idea, but syntactically wrong:
function get_temp_als(alarms : alarms_type) return std_logic_vector is
begin
return alarms(sys1_temp_hi_al) & alarms(sys1_temp_lo_al) & alarms(sys2_temp_hi_al) & alarms(sys2_temp_lo_al);
end function;
signal some_other_slv : std_logic_vector(3 downto 0);
some_other_slv <= get_temp_als(alarms);
Below is the piece of code from C, here they are assigning the hexadecimal value to a char variable sKaigyoCode
char sKaigyoCode[512];
sKaigyoCode[0] = 0x0d;
sKaigyoCode[1] = 0x0a;
I am trying to do the same thing in PLSQL
sKaigyoCode CHAR(512);
sKaigyoCode[0] = 0x0d;
sKaigyoCode[1] = 0x0a;
Which shows compile time error
Error(46,18): PLS-00103: Encountered the symbol "[" when expecting one of the following: := . ( # % ;
Error(46,23): PLS-00103: Encountered the symbol "X0D" when expecting one of the following: * & = - + ; < / > at in is mod remainder not rem <> or != or ~= >= <= <> and or like like2 like4 likec between || multiset member submultiset The symbol "*" was substituted for "X0D" to continue.
As already mentioned in comments, char, varchar, varchar2, nvarchar2, etc. are not arrays. Also, usually there is no need to use hex values in PL/SQL. But if you need to put special characters into a string variable you can do this:
declare
sKaigyoCode CHAR(512);
begin
sKaigyoCode := chr(10) || chr(13);
end;
And opposite operation - to return a symbol code:
declare
a number;
begin
a := ascii(substr('Hello, world!', 1, 1));
end;
Lets say we have a behavioural VHDL procedure for a testbench:
procedure jtag_load_data(data : in std_ulogic_vector) is
begin
jtag_clock(1, '1', '0');
jtag_clock(2, '0', '0');
for i in data'length-1 downto 1 loop
jtag_clock(1, '0', data(i));
end loop;
jtag_clock(2, '1', data(0));
jtag_clock(1, '0', data(0));
end procedure;
This procedure can either be called with a constant parameter like so
jtag_load_data("100")
or the parameter can be computed from others like this
jtag_load_data(tmasrc & tdosrc & tm)
Since VHDL arrays don't define the index order, I think the order the bits of data are processed within the for loop depends on the index of the data parameter when the procedure is called.
In case that wasn't clear, say a is of type std_logic_vector(3 downto 0) and b is of type std_logic_vector(0 to 3) and we do the following:
a <= "100";
b <= "100";
jtag_load_data(a);
jtag_load_data(b);
The bits processed for a will be 1, 0, 0 while for b they will be 0, 0, 1.
Back to my original two calling examples, this is a problem for the case where the parameter is a concatenation of std_logic_vectors: The expression tmasrc & tdosrc & tm (all three operands are of type std_logic_vector(n downto 0)) seems to evaluate to a std_logic_vector(0 to m), which reverses the order the bits are processed with respect to the case where I call the procedure with just one of the parameters (or a constant, which seems to default to the downto index ordering).
To fix this ambiguity, we can introduce a variable with known index order ordered_data like so:
procedure jtag_load_data(data : in std_ulogic_vector) is
variable ordered_data : std_ulogic_vector(data'length-1 downto 0);
begin
ordered_data := data;
jtag_clock(1, '1', '0');
jtag_clock(2, '0', '0');
for i in ordered_data'length-1 downto 1 loop
jtag_clock(1, '0', ordered_data(i));
end loop;
jtag_clock(2, '1', ordered_data(0));
jtag_clock(1, '0', ordered_data(0));
end procedure;
But I am wondering if there is a more elegant VHDL syntax to say either
"please interpret all data values passed into the procedure as having decreasing indexes" or
"please produce a std_logic_vector of decreasing indexes when concatenating them as in tmasrc & tdosrc & tm".
If you don't specify a range on a std_ulogic_vector (or std_logic_vector) input to a procedure (or function) then inside the procedure the left hand bit is always 0 and the bit numbers increase left to right. This is because a std_ulogic_vector is declared thus:
type std_ulogic_vector is array (natural range <>) of std_ulogic;
and since the index type is a natural whose left hand value is 0, the left hand element is always numbered 0 with an unconstrained parameter such as this.It is exactly the same for a std_logic_vector, which is declared the same way.
The numbering is not passed in from outside the procedure. Whatever is on the left outside the procedure (the actual) is numbered 0 inside the procedure (the formal).
So, in your example:
In case that wasn't clear, say a is of type std_logic_vector(3 downto
0) and b is of type std_logic_vector(0 to 3) and we do the following:
a <= "100"; b <= "100"; jtag_load_data(a); jtag_load_data(b);
a and b will be processed in exactly the same way; there is no difference; the fact that a is of type std_logic_vector(3 downto 0) and b is of type std_logic_vector(0 to 3) is irrelevant.
So, to answer your specific questions: it is up to you to ensure that the inputs are passed into the procedure in the correct order. If that is no good, then you need to pass in some other parameter to control the direction.
I have a vector A that's 64bits long and I want the output B to equal 3 while A is 30-35 and zero elsewhere. I can't figure out the testbench to loop through the vector A as a bit. I've tried several different ways but only got 1/5 of the array to give any output at all. This is as far as I could get without syntax/compile errors.
Main code
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
entity ent is
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end ent;
architecture arch_ent of ent is
begin
with A select
B <= "0011" when "011110",
"0011" when "011111",
"0011" when "100000",
"0011" when "100001",
"0011" when "100010",
"0011" when "100011",
"0000" when others;
end arch_ent;
Testbench
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb is
end tb;
architecture arch_tb of tb is
component ent
port(A:in std_logic_vector(5 downto 0);
B:out std_logic_vector(3 downto 0));
end component;
signal A_tb: std_logic_vector(5 downto 0);
signal B_tb: std_logic_vector(3 downto 0);
begin
uut: entity ent port map(A=>A_tb, B=>B_tb);
tb: process
constant period: time := 20ns;
begin
for i in A_tb'range loop
A_tb <= std_logic_vector(to_unsigned(i,6));
wait for period;
assert (B_tb = "0011")
report "test failed" severity error;
end loop;
wait;
end process;
end arch_tb;
In the end I'm trying to plot out the waveform like this:
http://i10.photobucket.com/albums/a142/blargonblop/wave.png
where A will go to 63 and each output is its correct value from 30-35 and 0 elsewhere
The loop parameter you use to specify the number of 'tests' is A_tb'range, which happens to be 5 downto 0, or six tests, i is assigned 5,4,3,2,1 and 0 successively.
You want to specify i in 0 to 2**A-tb'length-1 or i in 0 to 63 to get all 64 possible A_tb 'binary' values.
(A_tb'length = 6, 2**6-1 = 63, where ** is the exponentiation operator, 2 to the 6th power minus 1 equals 63)
I found two syntax errors in your test bench, 20ns where the standard requires a space between 20 and ns:
constant period: time := 20 ns;
And entity ent where that should either be just ent (you have a component declaration ent) or entity work.ent and no need for a component declaration:
uut: ent port map(A=>A_tb, B=>B_tb);
or
uut: entity work.ent port map(A=>A_tb, B=>B_tb);
And in keeping with Russell's answer there is no implied logic replication in a loop other than through synthesis which unravels loop iterations by paralleling logic (the replication). Not all loop statements are intended as synthesis targets.
Test benches are generally not synthesized and are used to write tests (as in your case) for a VHDL model that might be used as a synthesis target.
First, loops are just fine, and common, in testbenches. #Russell's comment applies to RTL code. You can adapt his approach for this problem and make it work. You would need to use 64 as a sentinel (ending) value and do your end of test checks then. Keep in mind though that the most important thing you do is code for readability. Test cases generally run from top to bottom of a process one time.
You loop has some issues in addition to the recommendations #DavidKoontz gave. Specifically,
Your assertion is should not be checked when you expect B to be 0.
Using numeric_std_unsigned (requires VHDL-2008 compile switch) will simplify your conversions.
Keep an error count so you can report pass or failed at the end.
Keep your constants in the architecture or a package
So the modified code is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
entity tb is
end tb;
architecture arch_tb of tb is
constant period: time := 20 ns;
...
begin
...
tb: process
variable ErrorCount :
begin
for i in i in 0 to 2**A-tb'length-1
A_tb <= to_slv(i,6);
wait for period;
if i >= 30 and i <= 35 then
if B_tb /= 3 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0011" severity ERROR ;
end if;
else
if B_tb /= 0 then
ErrorCount := Error Count + 1 ;
report "B_tb = " & to_string(B_tb) & " Expecting: 0000" severity ERROR ;
end if;
end loop;
if ErrorCount = 0 then
report "Test Passed" severity NOTE ;
else
report "Test FAILED. There were " & to_string(ErrorCount) & " Errors " severity NOTE;
end if;
std.env.stop(0) ; -- testbench stops here
end process;
Note that the rules about using (or forbidding usage of) numeric_std_unsigned do not apply to testbenches.
You really should not be using a for loop for this. For loops in VHDL are used to REPLICATE LOGIC, not to do something some number of times. Try something like this in your test bench:
signal r_CLOCK : std_logic := '0';
signal r_INDEX : unsigned(5 downto 0) := (others => '0');
begin
r_CLOCK <= not r_CLOCK after period/2;
process (r_CLOCK)
begin
if rising_edge(r_CLOCK) then
r_INDEX <= r_INDEX + 1;
end if;
end process;
Now simply cast r_INDEX as std_logic_vector and pass it to your ent component.
In PyDatalog I have defined the following assertions:
#stations
assert_fact('station', 'A' ,'yellow')
assert_fact('station', 'B' ,'yellow')
assert_fact('station', 'C' ,'yellow')
assert_fact('station', 'D' ,'yellow')
#sections
assert_fact('stretch', 'A' ,'B')
assert_fact('stretch', 'B' ,'C')
assert_fact('stretch', 'C', 'D')
And I would like to ask the database if there is a way to get to D from A.
The following code should work, because it answers set([()]) if there is a way, and None if there isn't. But it doesn't give me the result of the different evaluations of Z. I would like to know also the route, for example: A B C D
load("""
route(X,Y) <= stretch(X,Y)
route(X,Y) <= stretch(X,Z) & route(Z,Y)
""")
I have tried with unbound values, but it only gives me the result of the first iteration:
load("""
route(X,Y,P) <= stretch(X,Y) & (P==Y)
route(X,Y,P) <= stretch(X,P) & route(P,Y,Z)
""")
I think that the problem is that it only takes P in the first iteration. Or should I use aggregation functions? I don't understand very well how I could use concat...
Thanks in advance.
You need a predicate with a variable that contains the nodes between the 2 end points. You could use the following definition of route():
load("""
route(X,P, Y) <= stretch(X,Y) & (P==[])
route(X,P, Y) <= stretch(X,Z) & route(Z,P1,Y) & ~(Z in P1) & (P==[Z]+P1)
""")
print(pyDatalog.ask("route('A', P, 'D')"))
# prints set([(('B', 'C'),)])
Lists are supported since pyDatalog 0.13.