I have some problems with this unit and I don't know why it's not working. The platform ISE Project Navigator gives me this error: unit automat:the following signal(s) form a combinatorial loop.I would like to receive some advice and if you can tell me how to resolve this problem.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity automat is
port(CLK,EN,SEN,MONED:in STD_LOGIC;
COMP:STD_LOGIC_VECTOR(2 DOWNTO 0);
REN,MEN,ENR,IM_REST,REST,BILET,CLK_EN,RESET: out STD_LOGIC;
S1,S2,com:out STD_LOGIC_VECTOR(1 downto 0)
);
end automat;
architecture arh_automat of automat is
type STARE is(A,B,C,D,E,F,G,H,I,J);
signal ST,NXST:STARE;
begin
tranzitie:process(CLK,ST,EN,SEN,MONED,COMP)
begin
REN<='0';MEN<='0';clk_en<='0';RESET<='0';
ENR<='0';IM_REST<='0';REST<='0';BILET<='0';
S1<="00";S2<="00";com<="00";
case ST is
when A=>NXST<=B;
com<="00";
if(CLK'EVENT and CLK='1') then
if EN='1' then
ST<=B;
else
ST<=A;
end if;
END IF;
when B=>NXST<=C ;
RESET<='1';
com<="01";
if(CLK'EVENT and CLK='1') then
if EN='1' then
ST<=C;
else
ST<=B;
end if;
end if;
when C=>NXST<=D;
REN<='1';
CLK_EN<='1';
com<="10";
if(CLK'EVENT and CLK='1') then
if SEN ='1' then
ST<=D;
else
ST<=C;
end if;
end if;
when D=>NXST<=E ;
s1<="01";
s2<="10";
com<="10";
if(CLK'EVENT and CLK='1') then
if MONED='1' then
ST<=E;
else
ST<=F;
end if;
end if;
when E=>NXST<=F;
com<="00";
if(CLK'EVENT and CLK='1') then
ST<=F;
end if;
when F=>NXST<=G ;
MEN<='1';
com<="00";
if(CLK'EVENT and CLK='1') then
if COMP="010" or COMP="100" then
ST<=G;
else
ST<=C;
end if;
end if;
when G=>NXST<=H;
ENR<='1';
S1<="00";
S2<="11";
com<="00";
if(CLK'EVENT and CLK='1') then
if COMP="100" OR COMP="001" OR COMP="010" then
ST<=H;
else
ST<=I;
end if;
END IF;
when H=>NXST<=J;
REST<='1';
BILET<='1';
com<="00";
if(CLK'EVENT and CLK='1') then
ST<=J;
end if;
when I=>NXST<=J;
IM_REST<='1';
BILET<='1';
com<="00";
if(CLK'EVENT and CLK='1') then
ST<=J;
end if;
when J=>NXST<=A;
com<="00";
if(CLK'EVENT and CLK='1') then
ST<=A;
end if;
end case;
end process tranzitie;
end arh_automat;
You don't say which signals are forming the loop but your process & case construct are not written well.
Try splitting the combinatorial and synchronous signals into separate processes. Your clocking is messed up too. In the syncronous process, use just one "CLK'EVENT and CLK = '1'" statement with the case statement under it.
A combinatorial loop is when you have the output of some combinatorial logic fed back into itself. The most basic example I can think of is:
My_PROC : process(A)
begin
A <= not A;
end process;
Its obviously not possible to synthesize this.
Its pretty difficult to figure out what's going on in your code but you need to look for a case where the output of some combinatorial logic is fed back into itself. Like #lsf_design said, you should split up the combinatorial and clock synchronous logic. I would recommend using the format described here.
I would try to give your signals more descriptive names. Instead of using A, B, C, etc. for your state names, name them something that actually describes what that case does.
Related
I am working on a trigger function, and I only want to insert the data when it satisfies specific format. So I tried to use posix regulation expressions. But none of it seems working.
if(new.tin ~ '\d{10}') then
if not exists(
select *
from taxcodes
where code = substr(new.tin, 1, 4)
) then return null;
end if;
end if;
I'm trying to create a function designed to traverse a tree of organisational units filtering out some based on their level in the tree structure and weather they appear on our intranet page. The input to the function is the ORG_UNIT_ID of the starting unit, a flag to show if we should care about the intranet flag and a comma separated list of levels. For instance '2,3'. I'm trying to use REGEXP_LIKE in conjunction with an ELSEIF inside a loop to run up the tree until I hit the first eligible parent unit.
T_STOP is the control variable for the loop. R_ORG_UNIT_OVER is used to query meta-data on the above unit. During the loops first pass this will be the unit above the one passed as input to the function.
The cursor definition:
CURSOR C_ORG_UNIT_OVER(V_ORG_UNIT_ID ORG_UNIT.ORG_UNIT_ID%TYPE) IS
SELECT ORUI.ORG_UNIT_ID
, ORUI.ORG_LEVEL
, ORUI.SHOW_ON_INTRANET
FROM ORG_UNIT ORUI
JOIN ORG_UNIT_PARENT OUPA ON ORUI.ORG_UNIT_ID=OUPA.ORG_UNIT_ID_PARENT
WHERE OUPA.ORG_UNIT_ID = V_ORG_UNIT_ID;
The failing code segment in the loop:
IF R_ORG_UNIT_OVER.SHOW_ON_INTRANET = 'N' THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSEIF REGEXP_LIKE (P_SKIP_LEVEL, '(^|,)' || R_ORG_UNIT_OVER.ORG_LEVEL || '($|,)') THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSE
T_STOP := 'Y';
END IF;
However this code always throws a PLS-00103 error on the REGEXP_LIKE symbol. Is there some sort of limitation or alternate way in which REGEXP_LIKE works when used as a condition in a PL/SQL IF/ELSEIF block as opposed to in a regular query?
PL/SQL uses ELSIF, not ELSEIF. With your edit your code does get the error you described; with this it doesn't:
IF R_ORG_UNIT_OVER.SHOW_ON_INTRANET = 'N' THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSIF REGEXP_LIKE (P_SKIP_LEVEL, '(^|,)' || R_ORG_UNIT_OVER.ORG_LEVEL || '($|,)') THEN
T_ORG_UNIT_ID := R_ORG_UNIT_OVER.ORG_UNIT_ID;
ELSE
T_STOP := 'Y';
END IF;
Yes you can.
declare
testvar varchar2(20) := 'Kittens';
begin
if regexp_like(testvar, '^K') then
dbms_output.put_line(testvar || ' matches ''^K''');
end if;
end;
Kittens matches '^K'
PL/SQL procedure successfully completed.
Include some test data and I'll try to see what's not working as expected. For example,
declare
p_skip_level number := 2;
org_level number := 3;
begin
if regexp_like (p_skip_level, '(^|,)' || org_level || '($|,)')
then
dbms_output.put_line('Matched');
else
dbms_output.put_line('Not matched');
end if;
end;
I have six insert blocks (job, position, grade, etc.) in one package something like:
create or replace package body XX_package_cust
AS
PROCEDURE main_procedure( p_entity In VARCHAR2 default 'ALL')
is
begin
if p_entity='Job'
then
--execute job block
elsif p_entity='Position'
--execute postion block
elsif p_entity='Grade'
--execute grade block
end if;
end;
Now in the above if else i want to pass 'ALL' in p_entity such that if all is passed all these blocks should be executed and if 'job', grade position only the respective blocks should be executed.
In this for example in job section
begin
begin
insert into job_i
--------
end;
begin
insert into job_x
----
end;
end;
Now if I include if else in each... I will have to do something like :
begin
if p_entity ='JOB'
then
begin
insert into job_i
--------
end;
begin
insert into job_x
----
end;
end if;
end;
That is if else for each and every block. Is there any other way out
You could make each condition check for both the specific value or 'ALL'. Note that you'd have to replace the elsif statements with simple ifs:
if p_entity IN ('ALL', 'Job')
then
--execute job block
end if;
if p_entity IN ('ALL', 'Position')
--execute position block
end if;
if p_entity IN ('ALL', 'Grade')
--execute grade block
end if;
Try this
CREATE OR REPLACE PACKAGE body XX_package_cust
AS
PROCEDURE main_procedure(
p_entity IN VARCHAR2 DEFAULT 'ALL')
IS
BEGIN
IF p_entity ='Job' THEN
--execute job block
dbms_output.put_line('Job block executed');
elsif p_entity='Position' THEN
--execute postion block
dbms_output.put_line('Position block executed');
elsif p_entity='Grade' THEN
--execute grade block
dbms_output.put_line('Grade block executed');
elsif p_entity='All' THEN
--execute job block
dbms_output.put_line('Job block executed');
--execute postion block
dbms_output.put_line('Position block executed');
--execute grade block
dbms_output.put_line('Grade block executed');
END IF;
END;
END;
I am designing counter using vhdl using planahead software, anyway I am using if statment but it gave many errors . the purpose of the counter is to count Ascending/Descending from 1 to 10 and the opposite. In case of Ascending I reset the out when it get to 9 to count again from 0. And in case Descending reset the out when it gets 0 and give 9 as new value . and I am using switch button on the board to switch between Ascending/Descending counting. Below the if statment and the errors . I dont know if I use it on the write form . Plz if anyone have an idea would be perfect.
Line:27- if(inc_dec='1') then
Line:28 if (r_reg=M-1) then
r_next<=(others=>'0')
Line:30 else r_reg+1;
Line: 31 elsif (inc_dec='0')then
Line:32 if (r_reg=M-10) then
r_next<=(others=>'9')
Line:34 else
r_reg-1;
end if;
end if;
end if;
The errors :
Line:27 [HDLCompiler 806] Syntax error near "if".
Line:28[HDLCompiler 806] Syntax error near "then".
Line:30[HDLCompiler 806] Syntax error near "else".
Line:31[HDLCompiler 806] Syntax error near "then".
Line:32[HDLCompiler 806] Syntax error near "then".
Line:34[HDLCompiler 806] Syntax error near "else".
As pointed out by Morten Zilmer, you need to terminate the if/else with an end if. Also there have been some missing semicolons. The code below should work.
if (inc_dec='1') then
if (r_reg=(M-1)) then
r_next <= (others=>'0');
else
r_reg+1;
end if;
elsif (inc_dec='0') then
if (r_reg=(M-10)) then
r_next <= to_unsigned(9, r_next'length);
else
r_reg-1;
end if;
end if;
Update: Jonathan Drolet is right. Changed
r_next <= (others=>'9');
to
r_next <= to_unsigned(9, r_next'length)
in the code
Can anyone help me to make my code less? (If you can notice to both if-elsif statements I make the same Select.. so I wish there was a way to make this select once. and update with 1 or 0 depending on the pilot_action).
Below its my code.
create or replace
PROCEDURE F_16 (TRK_ID NUMBER, pilot_action NUMBER) IS
BEGIN
BEGIN
IF pilot_action=0 THEN
UPDATE "ControlTow"
SET "Intention"=0
WHERE "Id" IN (
SELECT "Id" FROM "ControlTow" WHERE "Id"=TRK_ID );
ELSIF pilot_action=1 THEN
UPDATE "ControlTow"
SET "Intention"=1
WHERE "Id" IN (
SELECT "Id" FROM "ControlTow" WHERE "Id"=TRK_ID );
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('False Alarm');
COMMIT;
END;
END F_16;
thank you , in advance.
Your code has several issues I have addressed in the comments below. Note that transaction management is not discussed as it's not clear based on the question when commit/rollback should take place.
-- #1 use of explicit parameter mode
create or replace procedure f_16(p_trk_id in number, p_pilot_action in number) is
begin
-- #2 use of in
if p_pilot_action in (0, 1)
then
-- #3 unnecessary subquery removed
update controltow
set intention = p_pilot_action
where id = p_trk_id;
-- #4 use pl/sql implicit cursor attribute to check the number of affected rows
if sql%rowcount = 0
then
dbms_output.put_line('false alarm');
end if;
end if;
end;
Since you seem to be assigning pilot_action to Intention, I would do following:
create or replace
PROCEDURE F_16 (TRK_ID NUMBER, pilot_action NUMBER) IS
BEGIN
BEGIN
IF pilot_action IN (0, 1) THEN
-- if the only condition in subselect is the ID then use it directly
UPDATE "ControlTow"
SET "Intention"= pilot_action
WHERE "Id"=TRK_ID;
-- if there are more conditions than just the ID then subselect may be the way to go
--(hard to say without more information)
-- WHERE "Id" IN (
-- SELECT "Id" FROM "ControlTow" WHERE "Id"=TRK_ID AND ... )
ELSE
Null; -- do whatever you need in this case. Raise exception?
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('False Alarm');
COMMIT;
END;
END F_16;
EDIT: As #user272735 said, there was room for more improvement on the code. Specifically rewriting the if condition to use in and simplifying the where clause (supposing Id is really the only condition to select rows to be updated).