I have this code in VHDL. When I try to compile it - it says "Gated clock net clock_en is sourced by a combinatorial pin." Has anyone an idea how to get rid of this warning?
I have searched all over the internet and cant find the solution. It seems that gated clock is sometimes even useful, but when designing HW it is a warning.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
entity ledc8x8 is
port(
SMCLK: in std_logic;
RESET: in std_logic;
ROW: out std_logic_vector(0 to 7);
LED: out std_logic_vector(0 to 7)
);
end ledc8x8;
architecture behavioral of ledc8x8 is
signal count: std_logic_vector(7 downto 0) := (others => '0'); -- hlavni citac
signal row_count: std_logic_vector(7 downto 0) := "10000000"; -- prepinac radku
signal clock_en: std_logic; -- CE
signal output_logic: std_logic_vector(7 downto 0); -- "vystup"
begin
process(count, SMCLK, RESET, clock_en)
begin
if RESET = '1' then
count <= (others => '0');
elsif SMCLK = '1' and SMCLK'event then
count <= count + 1;
end if;
if count="11111110" then
clock_en <= '1'; else
clock_en <= '0';
end if ;
end process;
process(clock_en, RESET)
begin
if RESET = '1' then
row_count <= "10000000";
elsif clock_en = '1' and clock_en'event then
row_count <= row_count(0) & row_count(7 downto 1);
end if;
end process;
process(row_count)
begin
case row_count is
when "00000001" => output_logic <= "11110110";
-- more switch options
end case;
end process;
ROW <= row_count;
LED <= output_logic;
end behavioral;
Your code has several problems.
As you discovered in your answer, you were using a clock enable as a clock. I would recommend that you write it this way, though:
process(RESET, SMCLK)
begin
if RESET = '1' then
row_count <= "10000000";
elsif SMCLK = '1' and SMCLK'event then
if clock_en = '1' then
row_count <= row_count(0) & row_count(7 downto 1);
end if;
end if;
end process;
It may work the other way (maybe), but it's not conventional to put the enable check on the same line as the rising edge check. Note also that this means you don't need clock_en in your sensitivity list.
Your other clocked process should be rewritten as well. Assuming you want the assignment to clock_en to be combinational, you should really put it in a separate process:
process(RESET, SMCLK)
begin
if RESET = '1' then
count <= (others => '0');
elsif SMCLK = '1' and SMCLK'event then
count <= count + 1;
end if;
end process;
process (count)
begin
if count="11111110" then
clock_en <= '1';
else
clock_en <= '0';
end if ;
end process;
You could also write the second process here as a one-line concurrent statement:
clock_en <= '1' when count = "11111110" else '0';
Combining independent clocked and unclocked code in the same process is not a recommended coding style for various reasons.
The line with clock_en'event - asking for rising edge did the problem. Replaced to ask for rising edge of SMCLK signal.
process(RESET, SMCLK)
begin
if RESET = '1' then
row_count <= "10000000";
elsif clock_en = '1' and SMCLK = '1' and SMCLK'event then
row_count <= row_count(0) & row_count(7 downto 1);
end if;
end if;
end process;
Related
My task is to create a GCD calculator using a state machine in VHDL. Part of the task description says to use a while loop while(tempA /= tempB). When I used this loop I get following compilation error:
Error (10536): VHDL Loop Statement error at GCD_FSM.vhd(64): loop must terminate within 10,000 iterations
After doing some research online, I tried to fix this by implementing a count variable: loop_count, which increments on each iteration upto 10,000. Initially I still got the same error so tried reducing the max count value to only 1,000, which is the current set up in my code below.
For some reason that I cant understand I still get the same error, does anyone know why this is or have a solution? I am using Quartus II 13.1 as that is the latest edition with Cyclone III which is what we use at uni.
-- output function
process(current_state)
variable loop_count : integer range 0 to 10000 := 0;
begin
if current_state = STATE_load then
tempA <= unsigned(A);
tempB <= unsigned(B);
elsif current_state = STATE_calculate then
while (tempA /= tempB and loop_count < 1000) loop
if tempA < tempB then
tempB <= tempA - tempB;
else
tempA <= tempA - tempB;
end if;
loop_count := loop_count + 1;
end loop;
elsif current_state = STATE_done then
GCD <= std_logic_vector(tempA);
DONE <= '1';
end if;
end process;
Updating to add the full code for context below:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--use ieee.std_logic_unsigned.all;
entity GCD_FSM is
port(
A, B : in std_logic_vector(15 downto 0);
CLK, RESET, START : in std_logic;
GCD : out std_logic_vector(15 downto 0);
DONE : inout std_logic
);
end entity GCD_FSM;
architecture moore_machine of GCD_FSM is
type STATE is (
STATE_idle, STATE_load,
STATE_calculate, STATE_done
);
signal current_state, next_state : STATE;
signal tempA, tempB : unsigned(15 downto 0) := (others => '0');
begin
-- next state fuction
process(A, B, current_state)
begin
case current_state is
when STATE_idle =>
if START = '1' then
if (unsigned(A) /= 0) and (unsigned(B) /= 0) then
next_state <= STATE_load;
end if;
end if;
when STATE_load =>
next_state <= STATE_calculate;
when STATE_calculate =>
if tempA = tempB then
next_state <= STATE_done;
end if;
when STATE_done =>
next_state <= STATE_idle;
end case;
end process;
-- state register
process(CLK, RESET)
begin
if RESET = '0' then
current_state <= STATE_idle;
elsif rising_edge(CLK) then
current_state <= next_state;
end if;
end process;
-- output function
process(current_state)
variable loop_count : integer range 0 to 10000 := 0;
begin
if current_state = STATE_load then
tempA <= unsigned(A);
tempB <= unsigned(B);
elsif current_state = STATE_calculate then
while (tempA /= tempB and loop_count < 1000) loop
if tempA < tempB then
tempB <= tempA - tempB;
else
tempA <= tempA - tempB;
end if;
loop_count := loop_count + 1;
end loop;
elsif current_state = STATE_done then
GCD <= std_logic_vector(tempA);
DONE <= '1';
end if;
end process;
end architecture moore_machine;
create or replace FUNCTION "FNC_CALCULATE_MOD11" (P_VALOR IN NUMBER)
return number is
Result number;
begin
DECLARE
-- LOCAL VARIABLES HERE
V_PROCESSO VARCHAR2(30);
V_PESO NUMBER := 2;
V_SOMA NUMBER := 0;
V_RESTO NUMBER := 0;
BEGIN
V_PROCESSO := TO_CHAR(P_VALOR);
WHILE LENGTH(V_PROCESSO) < 6 --Popular com zeros no inicio até 6
LOOP
V_PROCESSO := '0'||V_PROCESSO;
END LOOP;
--accuses error on this line
FOR I IN REVERSE 1 .. LENGTH(V_PROCESSO)
LOOP
V_SOMA := TO_CHAR (V_SOMA) + TO_NUMBER(SUBSTR(V_PROCESSO,i,1))*V_PESO;
IF V_PESO = 9 THEN --repetir peso se for necessario
V_PESO := 2;
ELSE
V_PESO := V_PESO + 1;
END IF;
END LOOP;
V_RESTO := MOD(V_SOMA, 11);
Result := 11 - V_RESTO;
IF ((Result = 0) OR (Result = 1) OR (Result >= 10)) THEN
Result := 1;
END IF;
END;
return(Result);
end FNC_CALCULATE_MOD11;
Try to change V_PROCESSO to a bigger size, for example V_PROCESSO VARCHAR2(300);
I am interfacing with a FT600 16-bit chip for USB3.0 communication. The computer will communicate through the FT600 to the FPGA and vice versa. I have created an FSM to assert appropriate signals and write Data to memory.
Problem: I assume the problem is with the FPGA code and not the hardware but it looks like only every other byte is correctly recorded into memory.
The timing diagram I am referring to is on page 16: http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT600Q-FT601Q%20IC%20Datasheet.pdf
This is my FSM code:
parameter [4:0] S1 = 5'd0, //Neutral state
S2 = 5'd1, //Data transfer from FPGA to Computer
SA_1 = 5'd8,
SA_2 = 5'd9,
S3 = 5'd2, //Data transfer from Computer to FPGA
S4 = 5'd3,
S5 = 5'd4,
S6 = 5'd5,
S7 = 5'd6,
S8 = 5'd7;
reg [4:0] state=0;
reg [4:0] nstate=0;
//wire [15:0] wdata;
wire [15:0] rdata;
//Counter c1 (wdata, Cclock);
assign rdata = (state == S5) ? DATA_I : rdata; //Holds the recieved data on DATA
assign DATA_O = (state == S7) ? rdata : 16'bz; //rdata : 16'bz; //{8'h41,8'h41} : 16'bz; //Sends the transmitted data on DATA
reg OE_N_reg = 1;//Confirmation signal when Computer writes data to FPGA
reg RD_N_reg = 1;//Confirmation signal when Computer writes data to FPGA
reg WR_N_reg = 1;//Confirmation signal when FPGA writes data to Computer
assign OE_N = OE_N_reg;
assign RD_N = RD_N_reg;
assign WR_N = WR_N_reg;
//ByteEnable configuration based on state
assign BE[0] = (state == S3) ? 1'bz : 1;
assign BE[1] = (state == S3) ? 1'bz : 1;
//Debugging outputs
//assign GPIO_O[7:3] = 0;
//assign GPIO_O[2] = OE_N;
//assign GPIO_O[3] = RD_N;
//assign GPIO_O[4] = WR_N;
//assign GPIO_O[7:5] = DATA[2:0];
//State Logic
always#(*)
begin
case(state)
S1:if(TXE_N == 0)
begin
nstate <= S2;
end
else
begin
if(RXF_N == 0)
begin
nstate <= SA_1;
end
else
begin
nstate <= S1;
end
end
S2:if(TXE_N == 0)
begin
nstate <= SA_2;
end
else
begin
nstate <= S1;
end
SA_1: if(RXF_N == 0)
begin
nstate <= S3;
end
else
begin
nstate <= S1;
end
S3:if(RXF_N == 0)
begin
nstate <= S4;
end
else
begin
nstate <= S1;
end
S4:if(RXF_N == 0)
begin
nstate <= S5;
end
else
begin
nstate <= S1;
end
S5:if(RXF_N == 0)
begin
nstate <= S5;
end
else
begin
nstate <= S6;
end
S6: nstate <= S1;
SA_2: if(TXE_N == 0)
begin
nstate <= S7;
end
else
begin
nstate <= S1;
end
S7: if(TXE_N == 0)
begin
nstate <= S7;
end
else
begin
nstate <= S8;
end
S8: nstate <= S1;
default: nstate <= S1;
endcase
end
//Output Assignment
always#(negedge S_AXI_ACLK)
begin
case(state)
S1: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
S2: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
SA_1: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
S3: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
S4: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 0;
DATA_T <= 1;
end
S5: begin
RD_N_reg <= 0;
WR_N_reg <= 1;
OE_N_reg <= 0;
DATA_T <= 1;
end
S6: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
SA_2: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
S7: begin
RD_N_reg <= 1;
WR_N_reg <= 0;
OE_N_reg <= 1;
DATA_T <= 0;
end
S8: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
default: begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
end
endcase
end
//Update states
always#(negedge S_AXI_ACLK)
begin
state <= nstate;
end
//RECORD rdata INTO MEM:
always #(negedge Bus2IP_Clk)
begin
if((RD_N == 0)) begin
s <= s+(11'd15);
ram[0][0][s] <= rdata[15:0];
end
read_address <= mem_address; //AXI4 stuff
end
Any ideas/suggestions? If there already exists simple code for the FT600 as an example I would appreciate a link.
Here's a tip: replace the huge case statement with this. It does exactly the same thing, but takes up far less space and is easier to understand:
always#(negedge S_AXI_ACLK)
begin
RD_N_reg <= 1;
WR_N_reg <= 1;
OE_N_reg <= 1;
DATA_T <= 1;
case(state)
S4: OE_N_reg <= 0;
S5: begin
RD_N_reg <= 0;
OE_N_reg <= 0;
end
S7: begin
WR_N_reg <= 0;
DATA_T <= 0;
end
endcase
end
The four assignments at the top of the block are called default assignments and are often useful to make code more compact and easier to understand.
I am using the following stored procedure for returning an incremented key value for a specific keyword. It takes an optional parameter of Y or N to determine if the result should be prefixed by another value.
create or replace
PROCEDURE "ASGETPRIMARYKEY"
(
p_ObjectName IN LASTPRIMARYKEY.OBJECTNAME%type ,
p_PrimaryKey OUT LASTPRIMARYKEY.NEXTKEY%type,
useSitePrefix IN NVARCHAR2 Default 'Y'
)
AS
v_transcount NUMBER := 1;
v_sys_error NUMBER := 0;
v_SitePrefix NVARCHAR2(4000);
v_LastPrimaryKey NUMBER(10,0);
-- Error Handling Variables
v_LocalTran NUMBER(1,0);
v_Error NUMBER(10,0);
BEGIN
NULL/*TODO:SET XACT_ABORT ON*/;
NULL/*TODO:SET NOCOUNT ON*/;
-- STEP 0: Start the transaction
-- If procedure doesn't need to begin a transaction this can be set to 0
IF v_transcount > 0 THEN
v_LocalTran := 0;
ELSE
v_LocalTran := 1;
END IF;
IF v_LocalTran = 1 THEN
SET TRANSACTION READ WRITE;
v_transcount := v_transcount + 1;
END IF;
-- STEP 1: Get #SitePrefix
SELECT settingtext
INTO v_SitePrefix
FROM systemsetting
WHERE settingdescription = 'Site Id Prefix';
-- Check if there were any errors
v_Error := v_sys_error;
IF v_Error != 0 THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(1a)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
-- STEP 1b: Check SitePrefix exists
-- Rollback the transaction if SitePrefix doesn't exist in systemsetting
IF v_SitePrefix IS NULL THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(1b)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
BEGIN
-- STEP 2: Set NextKey for requested ObjectName
UPDATE LastPrimaryKey
SET NextKey = (NextKey + 1)
WHERE objectname = p_ObjectName;
EXCEPTION
WHEN OTHERS THEN
v_sys_error := SQLCODE;
END;
BEGIN
-- Check if there were any errors
v_Error := v_sys_error;
EXCEPTION
WHEN OTHERS THEN
v_sys_error := SQLCODE;
END;
IF v_Error != 0 THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(2)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
-- STEP 3: Set NextKey for for requested ObjectName
SELECT NextKey - 1
INTO v_LastPrimaryKey
FROM LastPrimaryKey
WHERE objectname = p_ObjectName;
BEGIN
-- Check if there were any errors
v_Error := v_sys_error;
EXCEPTION
WHEN OTHERS THEN
v_sys_error := SQLCODE;
END;
IF v_Error != 0 THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(3)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
-- STEP 4: Check SitePrefix exists
-- Rollback the transaction if SitePrefix doesn't exist in systemsetting
IF v_LastPrimaryKey IS NULL THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(4)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
-- STEP 5: Set #p_PrimaryKey by adding prefix
IF useSitePrefix = 'y' THEN
p_PrimaryKey := (CAST(v_SitePrefix || CAST(v_LastPrimaryKey AS NVARCHAR2) AS NUMBER));
ELSE
p_PrimaryKey := v_lastprimarykey;
END IF;
-- Check if there were any errors
v_Error := v_sys_error;
IF v_Error != 0 THEN
BEGIN
raise_application_error( -20002, 'Error whilst processing GetPrimaryKey.(5)' || cast(v_error as NVARCHAR2));
GOTO ErrExit;
END;
END IF;
-- STEP 6: If we reach this point, the commands completed successfully
-- Commit the transaction....
-- Normal exit
IF v_LocalTran = 1 THEN
COMMIT;
v_transcount := v_transcount - 1;
END IF;
-- Error Exit
<<ErrExit>>
IF v_LocalTran = 1 THEN
ROLLBACK;
v_transcount := v_transcount - 1;
END IF;
END;
The stored proc is called from a enterpriselibrary using the following vb code:
Dim sqlCommand As String = "asGetPrimaryKey"
Dim _db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)(ASDBMSS.clsDBMSS.ConnectionStringName)
Dim DbCommand As System.Data.Common.DbCommand = _db.GetStoredProcCommand(sqlCommand)
' Add primary keys to command wrapper.
_db.AddInParameter(DbCommand, "p_objectName", DbType.String, ObjectName)
If pbIgnoreSiteIndex Then
_db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "Y")
Else
_db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "N")
End If
_db.AddOutParameter(DbCommand, "p_PrimaryKey", DbType.Int32, 8)
_db.ExecuteNonQuery(DbCommand)
Dim _result As String = _db.GetParameterValue(DbCommand, "p_PrimaryKey").ToString
lcl_NextKey = CInt(_result)
result = 1
The problem arrises when I pass the optional parameter in.
If I skip the line with the optional parameter, it works fine.
If I use SQL server instead of Oracle, it works fine.
If I pass the parameter and use Oracle I get the following error message:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 1
Any suggestions?
Change v_LastPrimaryKey from number(10,0) to same as p_PrimaryKey OUT LASTPRIMARYKEY.NEXTKEY%type,
Secondly, you are passing Y or N but inside code comparing y. So flow is always going in "else", where you are not using cast.
Hope that helps.
Cheers
V
I have found the problem!
SQL server does not care in what order the parameters are passed as long as the names match. Oracle it seems, does.
I changed the order in which they are called to this:
_db.AddInParameter(DbCommand, "p_objectName", DbType.String, ObjectName)
_db.AddOutParameter(DbCommand, "p_PrimaryKey", DbType.Int32, 8)
If pbIgnoreSiteIndex Then
_db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "Y")
Else
_db.AddInParameter(DbCommand, "useSitePrefix", DbType.String, "N")
End If
_db.ExecuteNonQuery(DbCommand)
And it now works without error
Here is the script that i wrote and it has weird syntax error at EXCEPTION block. If i remove exception block the script compiles properly. but no sooner i write it back it gives me error
Error(58,11): PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following: ( begin case declare else elsif end exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Here is the script
LOOP
BEGIN
SAVEPOINT check_point;
EXIT WHEN DBMS_SQL.FETCH_ROWS (cursor_handle) = 0;
DBMS_SQL.COLUMN_VALUE (cursor_handle, 1, cc , col_err, actual_len);
DBMS_SQL.COLUMN_VALUE (cursor_handle, 2, di, col_err, actual_len);
IF INSTR (cc, '_') <> 0 THEN
cc := Trim (cc);
cc := Upper(cc);
cc := substr(cc,4,2);
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET cc = :v1 WHERE di = :v2'
USING cc, di;
if SQL%ROWCOUNT > 0 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF;
END IF;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dups := dups+1;
ROLLBACK TO check_point;
WHEN VALUE_ERROR THEN
valerr := valerr +1;
ROLLBACK TO check_point;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('errno: ' || TO_CHAR(SQLCODE) || ' Msg: ' || SQLERRM);
otherexc := otherexc +1;
IF otherexc > 50 THEN
EXIT;
END IF;
ROLLBACK TO check_point;
END IF;
END;
END LOOP;
I know its very annoying to ask such kind a question but i am unable to figure out what error is that. I am lehman at Pl/SQL.
The error appears to be that your EXCEPTION clause is inside the IF INSTR (cc, '_') <> 0 IF statements but you appear to want to match the EXCEPTION to the BEGIN statement at the top of your loop. I believe that you want to move the END IF; for the IF INSTR (cc, '_') <> 0 before the EXCEPTION as I do here
LOOP
BEGIN
SAVEPOINT check_point;
EXIT WHEN DBMS_SQL.FETCH_ROWS (cursor_handle) = 0;
DBMS_SQL.COLUMN_VALUE (cursor_handle, 1, cc , col_err, actual_len);
DBMS_SQL.COLUMN_VALUE (cursor_handle, 2, di, col_err, actual_len);
IF INSTR (cc, '_') <> 0 THEN
cc := Trim (cc);
cc := Upper(cc);
cc := substr(cc,4,2);
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET cc = :v1 WHERE di = :v2'
USING cc, di;
if SQL%ROWCOUNT > 0 THEN
inserts := inserts + 1;
counter := counter + 1;
IF counter > 500 THEN
counter := 0;
COMMIT;
END IF; -- IF counter > 500
END IF; -- IF SQL%ROWCOUNT > 0
END IF; -- INSTR (cc, '_') <> 0
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dups := dups+1;
ROLLBACK TO check_point;
WHEN VALUE_ERROR THEN
valerr := valerr +1;
ROLLBACK TO check_point;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('errno: ' || TO_CHAR(SQLCODE) || ' Msg: ' || SQLERRM);
otherexc := otherexc +1;
IF otherexc > 50 THEN
EXIT;
END IF;
ROLLBACK TO check_point;
END;
END LOOP;
That being said, however, I would probably rewrite the code a bit. Committing every 500 rows is almost certainly an error. I'm very dubious of your WHEN OTHERS exception handler-- I would really think that you'd want to at least write the error to a table or populate a collection of errors rather than writing to the DBMS_OUTPUT buffer that may or may not ever be displayed.
LOOP
SAVEPOINT check_point;
EXIT WHEN DBMS_SQL.FETCH_ROWS (cursor_handle) = 0;
DBMS_SQL.COLUMN_VALUE (cursor_handle, 1, cc , col_err, actual_len);
DBMS_SQL.COLUMN_VALUE (cursor_handle, 2, di, col_err, actual_len);
IF INSTR (cc, '_') <> 0 THEN
cc := Trim (cc);
cc := Upper(cc);
cc := substr(cc,4,2);
BEGIN
EXECUTE IMMEDIATE 'UPDATE ' || dest || ' SET cc = :v1 WHERE di = :v2'
USING cc, di;
if SQL%ROWCOUNT > 0 THEN
inserts := inserts + 1;
END IF;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
dups := dups+1;
ROLLBACK TO check_point;
WHEN VALUE_ERROR THEN
valerr := valerr +1;
ROLLBACK TO check_point;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('errno: ' || TO_CHAR(SQLCODE) || ' Msg: ' || SQLERRM);
otherexc := otherexc +1;
IF otherexc > 50 THEN
EXIT;
END IF;
ROLLBACK TO check_point;
END;
END IF; -- INSTR (cc, '_') <> 0
END LOOP;