How to use for loop statement in case statement in Verilog - loops

I'm trying to compile a code similar to this:
`define CORES_NUM 4
reg [1:0] core = 'h0;
reg [`CORES_NUM-1:0] result = 'h0;
integer i;
always # (posedge clk) begin
case (core)
for (i = 0; i < `CORES_NUM; i = i + 1) begin
i: begin
result[i] <= 1;
end
end
endcase
end
Only one core is active at the moment. I expect that my code is equal to that:
case (core)
0: begin
result[0] <= 1;
end
1: begin
result[1] <= 1;
end
2: begin
result[2] <= 1;
end
3: begin
result[3] <= 1;
end
endcase
In other words, I need 'for loop' only for auto setting - if I change CORES_NUM, case states are automatically changed.
But my code builds with errors. How can I use for loop in case statement?

Why not:
always #(posedge clk) if (core < `CORES_NUM) result[core] = 1;

Related

Snowflake Nested Loop loop - Why is this code not starting a new iteration of the outer loop?

This query is successfully starting the first iteration of the outer loop, and then completing the first inner loop iteration (10), but is not moving on to the second outer loop iteration.
execute immediate $$
begin
CREATE OR REPLACE Temporary TABLE tmploop (ID INT IDENTITY, Counter INT, slotCounter INT);
let counter := 1;
let countermax := 5;
let slotcounter :=1;
let maxslots := 10;
let outercounter := 1;
loop
if (counter <= countermax) then
let slotcounter :=1;
//counter := counter + 1;
SET outercounter := outercounter +1;
end if;
loop
if (slotcounter <= maxslots) then
INSERT INTO tmploop (counter, slotcounter)
VALUES(:counter, :slotcounter);
slotcounter := slotcounter + 1;
continue outer;
else
//counter := counter + 1;
break inner;
end if;
end loop inner;
counter := counter + 1;
break;
end loop outer;
return array_construct(counter, slotcounter, outercounter);
end;
$$;
I've tried moving around the continue outer, break outer, removing the break, etc, but it seems everthing aside from the above code results in an infinite loop.
here is your code with spaces amount the actions:
execute immediate $$
begin
CREATE OR REPLACE Temporary TABLE tmploop (ID INT IDENTITY, Counter INT, slotCounter INT);
let counter := 1;
let countermax := 5;
let slotcounter :=1;
let maxslots := 10;
let outercounter := 1;
loop
if (counter <= countermax) then
let slotcounter :=1;
//counter := counter + 1;
SET outercounter := outercounter +1;
end if;
loop
if (slotcounter <= maxslots) then
INSERT INTO tmploop (counter, slotcounter)
VALUES(:counter, :slotcounter);
slotcounter := slotcounter + 1;
continue outer;
else
//counter := counter + 1;
break inner;
end if;
end loop inner;
counter := counter + 1;
break; -- THIS LINE IS THE PROBLEM
end loop outer;
return array_construct(counter, slotcounter, outercounter);
end;
$$;
that BREAK, it say, just before I do this loop again, stop looping.
So to answer the question, "why does it stop looping" because you told it too.
Like many problems loops should be avoided for inserting incremental data, and the problem should most likely be inverted, and ether a Recursive CTE or some other pattern used to generate the data you wish for.
The code as it stands loops forever, so that needs solving. If it was bonded at worked as expect offering methods to invert it could happen, but as it stands.. it is a little mysterious.
It needs the break, but needed to move the outer end if to the bottom. The below code works great.
execute immediate $$
begin
CREATE OR REPLACE Temporary TABLE tmploop (ID INT IDENTITY, Counter INT, slotCounter INT);
let counter := 1;
let countermax := 5;
let slotcounter :=1;
let maxslots := 10;
let outercounter := 1;
loop
if (counter <= countermax) then
let slotcounter :=1;
//counter := counter + 1;
SET outercounter := outercounter +1;
loop
if (slotcounter <= maxslots) then
INSERT INTO tmploop (counter, slotcounter)
VALUES(:counter, :slotcounter);
slotcounter := slotcounter + 1;
--we don't need the continue outer here.
else
//counter := counter + 1;
break inner;
end if;
end loop inner;
counter := counter + 1;
else
break; --definitely need to end the loop after all iterations of the outer loop are satisfied.
end if;
end loop outer;
return array_construct(counter, slotcounter, outercounter);
end;
$$;

Delphi create letters with for loop

As you know in Excel column names are letters. When it reaches Z it continues with AA-AB-AC. Is it possible to make a similar function in Delphi XE7 + for loop?
I've tried:
var
i:integer;
str:string;
begin
str:='a';
for i := 0 to 26-1 do
begin
inc (str,1);
memo1.Lines.Add(str);
end;
but it returned:
[dcc32 Error] FBarkodsuzIndesignVerisiOlustur.pas(249): E2064 Left side cannot be assigned to
I assume that's because str is not an integer.
I can convert numbers to letters with this function:
function numberToString(number: Integer): String;
begin
Result := '';
if (number < 1) or (number > 26) then
Exit;
Result := 'abcdefghijklmnopqrstuvwxyz'[number];
end;
But I have no idea how we can create letters like AA when it exceeds 26.
Also with below approach, it creates 26 letters just fine but when it exceeds 26 it starts to use characters like brackets:
for i := 0 to 27-1 do
begin
memo1.Lines.Add(Char(Ord('a') + i));
end;
Output of it:
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
when it reach to Z it'll continue as "AA" "BB" "CC" and so on like Excel creates column names.
This is the function that I use for the task.
function SpreadSheetColName(const Col: Integer): string;
var
c: Char;
begin
Assert(Col >= 0);
if Col<26 then begin
c := 'A';
Inc(c, Col);
Result := c;
end else begin
Result := SpreadSheetColName(Col div 26 - 1) + SpreadSheetColName(Col mod 26);
end;
end;
Note that it uses zero based indices. I would suggest that you also use zero based indices as a general rule throughout your programming.
If you can't bring yourself to do that, then a one based version would look like this:
function SpreadSheetColName(const Col: Integer): string;
function SpreadSheetColNameZeroBased(const Col: Integer): string;
var
c: Char;
begin
Assert(Col >= 0);
if Col<26 then begin
c := 'A';
Inc(c, Col);
Result := c;
end else begin
Result := SpreadSheetColNameZeroBased(Col div 26 - 1) + SpreadSheetColNameZeroBased(Col mod 26);
end;
end;
begin
Result := SpreadSheetColNameZeroBased(Col - 1);
end;

BCD Timer in VHDL

Just started out in VHDL not long ago,out of curiosity.
So I was trying to write BCD timer on spartan 3 board and
Somehow I couldn't find out why it keeps showing 'unexpected with' error.
So if I want to have such function as shown in the link of picture,
how can I modify the code?any help would be grateful.
(clickable)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity w3 is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
stp : in STD_LOGIC;
an : out STD_LOGIC_VECTOR (3 downto 0);
c : out STD_LOGIC_VECTOR (6 downto 0));
end w3;
architecture timer of w3 is
signal div1 : integer range 0 to 499999 :=0; -- 100Hz
signal ck100hz : std_logic; -- 100Hz output
signal div2 : integer range 0 to 249999 :=0; -- 200Hz
signal ck200hz : std_logic; -- 200Hz output
signal div3 : integer range 0 to 124999 :=0; -- 400Hz
signal ck400hz : std_logic; -- 400Hz output
signal index : integer range 0 to 9 :=0;
signal scan : std_logic_vector (3 downto 0);
signal S : std_logic;
signal disp : std_logic_vector (3 downto 0);
begin
process begin
wait until rising_edge(clk);
if div1 < 499999 then
ck100hz <= '0';
div1 <= div1+1;
else
ck100hz <= '1';
div1 <= 0;
end if;
if div2 < 249999 then
ck200hz <= '0';
div2 <= div2+1;
else
ck200hz <= '1';
div2 <= 0;
end if;
if div3 < 124999 then
ck400hz <= '0';
div3 <= div3+1;
else
ck400hz <= '1';
div3 <= 0;
end if;
end process;
process begin
wait until rising_edge(clk);
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
if index < 3 then index <= index+1;
else index <= 0;
if index < 4 and index > 7 then index <= index+1;
else index <= 0;
if index < 8 and index > 11 then index <= index+1;
else index <= 0;
if index < 12 and index > 15 then index <= index+1;
else index <= 0;
end if;
end if;
end if;
end if;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck400hz = '1' then
With scan select -- error unexpected With
an <= an(0) when "00",
an(1) when "01",
an(2) when "10",
an(3) when others;
end if;
end process;
process begin
wait until rising_edge(clk);
if ck200hz = '1' then
With S select -- error unexpected With
disp <= index integer range 0 to 3 when "00",
index integer range 4 to 7 when "01",
index integer range 8 to 11 when "10",
index integer range 12 to 15 when others;
end if;
end process;
with index select
C <= "1000000" when 0,
"1111001" when 1,
"0100100" when 2,
"0110000" when 3,
"0011001" when 4,
"0010010" when 5,
"0000010" when 6,
"1111000" when 7,
"0000000" when 8,
"0011000" when 9;
end timer;
For low-active:
You should assign 0111111 to C in case of index = 0. You have to enable almost all segments. Now your internal calculation would be high-active. The display itself is low-active, because of the PCB layout, thus you should invert the whole C vector before assigning it to a Cathode_n port: Cathode_n <= not C; Note, I used _n to designate the low-active behavior of this port.
Old code:
with index select
C <= "1000000" when 0,
"1111001" when 1,
-- ...
"0011000" when 9;
This should be the goal when writing purely high-active code:
with index select
C <= "0111111" when 0,
"0000110" when 1,
-- ...
"1100111" when 9;
Cathode_n <= not C;
High-active means: If a bit is high (1) then a thing is active. In your case an LED of a 7-segment display is activated. Based on the PCB design, you have to drive low (0) to activate a light. This is low-active, because a low value activates something.
The select statement needs to assign the position to 1 that should be enlightened, not the positions to turn off. More over low-active signals should be marked in to code to denote there different behavior. Only a top-level component should translate high-active signals to low-active signals and vice versa. This ensures, the inner parts of your design are purely high-active.
For no driver:
There is no assignment to S and scan. Both signals are 'U' or "UUUU", respectively.
Edit:
Each signal assignment creates a driver on a signal. Currently, your code never assigns any value to S nor scan. Thus the initial values of S and scan become the driving value of the signals. You should run a simulation und see a lot of Us in your waveform.
Synthesis tools might report: Signal S is read, but never assigned.
For using elsif:
I reformatted you horrible if-then-else construct:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
index <= 0;
if index < 4 and index > 7 then
index <= index+1;
else
index <= 0;
if index < 8 and index > 11 then
index <= index+1;
else
index <= 0;
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
Now we see, you code can not use elsif, because you have assignments in the else branch before the next if statement. On the otherhand, the index <= 0; assignment is redundant and can be removed:
if ck100hz = '1' then
if index < 3 then
index <= index+1;
else
if index < 4 and index > 7 then
index <= index+1;
else
if index < 8 and index > 11 then
index <= index+1;
else
if index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
end if;
end if;
end if;
Now we can transform it to use elsif branches:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
elsif index < 4 and index > 7 then
index <= index + 1;
elsif index < 8 and index > 11 then
index <= index + 1;
elsif index < 12 and index > 15 then
index <= index+1;
else
index <= 0;
end if;
end if;
Much more readable, right?
Next, lets check your expressions in that statement:
elsif index < 4 and index > 7 then
index cannot be less than 4 and greater than 7 at the same time. So lets play synthesis and optimized away unreachable branches:
if ck100hz = '1' then
if index < 3 then
index <= index + 1;
else
index <= 0;
end if;
end if;
Ok, other problems in the code:
if rst = '1' then
index <= 0;
end if;
if stp = '1' then
index <= index;
end if;
if ck100hz = '1' then
-- ...
end if;
Reset should always have highest priority. In your case, e.g. stp has higher priority. In a good case you're only wasting FPGA resources, in a bad case synthesis can not translate your code to primitives in the FPGA. E.g. flip-flops with matching reset behavior.
Correct implementation:
if rst = '1' then
index <= 0;
elsif stp = '1' then
index <= index;
elsif ck100hz = '1' then
-- ...
end if;
I think for now, you have enough input to fix your code.

Remove duplicate array elements

I need to remove all duplicate values from an array of integer, yet maintain the order of the elements:
Example:
10,20,20(duplicate),10(duplicate),50
Becomes:
10,20,50
Create a dictionary with Integer as the key. The value type is immaterial.
Iterate through the input array. For each value in the input array, check whether or not that value is in the dictionary.
If yes, this is a duplicate, discard.
If no, this is the first time the value has been encountered. Retain the value, and add it to the dictionary.
The point of the dictionary is that it can perform O(1) lookup.
In pseudocode:
var
arr: TArray<Integer>; // input and output
Dict: TDictionary<Integer, Integer>;
SrcIndex, DestIndex: Integer;
....
DestIndex := 0;
for SrcIndex := 0 to high(arr) do begin
Value := arr[SrcIndex];
if not Dict.ContainsKey(Value) then begin
arr[DestIndex] := arr[SrcIndex];
Dict.Add(Value, 0);
inc(DestIndex);
end;
end;
SetLength(arr, DestIndex);
Obviously you need to create, and destroy, the dictionary. I'm assuming you know how to do that. And I've opted to modify the array in place but you could equally create a new array if you prefer.
heres a version without dictionary.
procedure TForm1.RemoveDuplicates;
var
i,j,k,tot,mov:integer;
arr:array of integer;
begin
arr := [10,20,30,40,30,20,10,10,50,10,20,40];
tot := 0;
for i := 0 to length(arr)-1 do
begin
if i >= length(arr)-tot-1 then
break;
for j := i + 1 to length(arr)-1-tot do
begin
if j >= length(arr)-tot-1 then
break;
mov := 0;
while arr[i] = arr[j] do
begin
inc(mov);
arr[j] := arr[j+mov];
end;
tot := tot + mov;
if mov>0 then
for k := j+1 to length(arr)-1-tot do
arr[k] := arr[k+mov];
end;
end;
SetLength(arr,length(arr)-tot-1);
end;

Sum of Associate array values in PL/SQL

Is there any way to have sum of values of associate array in PL/SQL. normally the code is like this:
FOR i IN a.FIRST .. a.LAST
LOOP
IF a (i).weight > 0
THEN
flag := FALSE;
END IF;
END LOOP;
but it should be a way to do it without loop and using sum.
something like:
IF SUM(a.weight) > 0
THEN
flag := FALSE;
END IF;
Actually - normally the code above is wrong for looping through associative arrays. Try this.
declare
type t_array_rec is record(
weight number);
type t_array is table of t_array_rec index by pls_integer;
arr t_array;
li_idx int;
li_summ int := 0;
begin
arr(1).weight := 100;
arr(3).weight:= 200;
arr(5).weight := 150;
li_idx := arr.first;
while (li_idx is not null) loop
li_summ := li_summ + nvl(arr(li_idx).weight, 0);
li_idx := arr.next(li_idx);
end loop;
dbms_output.put_line(li_summ);
end;
This will count the min value. Also You can kindly have a look at the another answer on SO sorting the assotiative arrays .
In case of nested tables, You can use the table functions.
Assuming You have the TTI type on the database layer.
CREATE OR REPLACE TYPE TTI as table of int
You can aggragate it's values like shown bellow
declare
arr TTI := TTI(100, 200, 150);
li_summ number;
begin
select sum(column_value) into li_summ from table(arr);
dbms_output.put_line(li_summ);
end;

Resources