Inside a process I have something like this:
CASE res IS
WHEN "00" => Y <= A;
WHEN "01" => Y <= A;
WHEN "10" => Y <= B;
WHEN "11" => Y <= C;
WHEN OTHERS => Y <= 'X';
END CASE;
Note that case "00" and "01" get the same value. Is there a correct syntax for something like
WHEN "00", "01" => ?
Extra note: There's far more to this than Y being changed, I just used that for simplicity. So the case/when is necessary.
You can separate multiple choices with the "pipe" or bar symbol. The proper syntax for your example is:
CASE res IS
WHEN "00" | "01" => Y <= A;
WHEN "10" => Y <= B;
WHEN "11" => Y <= C;
WHEN OTHERS => Y <= 'X';
END CASE;
You can also give a range of choices for a case:
USE IEEE.STD_LOGIC_ARITH.ALL;
CASE CONV_INTEGER(res) IS
WHEN 0 to 1 => Y <= A;
WHEN 2 => Y <= B;
WHEN 3 => Y <= C;
WHEN OTHERS => Y <= 'X';
END CASE;
Related
I am working on the following proof and the invariant result_val is proved with an induction strategy on i using begin as the base case.
The sup case is trying to prove true which holds trivially using Frama-C 24.0. But when I switch to 25.0, it tries to prove a seemingly more complicated condition, which looks closer to a correct inductive inference because it did the weakest precondition computation explicitly.
However, all SMT solvers I tried cannot prove the condition generated by Frama-C 25.0.
I am a bit worried about the correctness of version 24.0's result because using true as the inductive proof goal seems to be unlikely. Can anyone hint to me at what happened? Is that a bug in 24.0 or just some difference in the implementation?
#include <stdbool.h>
#define SIZE 1000
bool data[SIZE] ;
/*#
logic integer count(integer begin, integer end)=
begin >= end ? 0 : (data[begin]==true) ? count(begin+1, end)+1 : count(begin+1, end);
*/
/*#
requires SIZE > begin >= 0;
requires SIZE >= end >= 0;
requires begin <= end;
assigns \nothing;
ensures \result == count(begin, end);
*/
unsigned int occurrences_of(int begin, int end)
{
unsigned int result = 0;
/*#
loop invariant i_bound: begin <= i <= end;
loop invariant result_bound: 0 <= result <= i-begin;
loop invariant result_val: result == count(begin, i);
loop assigns i, result;
loop variant end-i;
*/
for (unsigned int i = begin; i < end; ++i){
result += (data[i] == true) ? 1 : 0;
}
return result;
}
Below is the result from Frama-c 24.0
Proof:
Goal Invariant 'result_val' (preserved) (Induction: proved)
+ Goal Induction (Base) (proved)
+ Goal Induction (Induction (sup)) (proved)
+ Goal Induction (Induction (inf)) (proved)
Qed.
--------------------------------------------------------------------------------
Goal Induction (Induction (sup)):
Prove: true.
Below is the result from Frama-c 25.0
--------------------------------------------------------------------------------
Proof:
Goal Invariant 'result_val' (preserved) (Induction: pending)
+ Goal Induction (Base) (proved)
+ Goal Induction (Induction (sup)) (pending)
+ Goal Induction (Induction (inf)) (proved)
End.
--------------------------------------------------------------------------------
Goal Induction (Induction (sup)):
Let x_0 = to_uint32(end#L1).
Let x_1 = to_uint32(tmp#L12).
Let x_2 = data#L1[i#L6].
Let x_3 = result#L6.
Let x_4 = result#L13.
Let x_5 = to_uint32(1 + i#L6).
Assume {
Have: begin#L1 < i#L6.
Have: i#L6 <= end#L1.
Have: i#L6 < x_0.
Have: 0 <= x_3.
Have: x_5 <= end#L1.
Have: begin#L1 <= x_5.
Have: (begin#L1 + x_3) <= i#L6.
Have: (begin#L1 + x_4) <= x_5.
Have: is_uint32(i#L6).
Have: is_bool(x_2).
Have: is_uint32(x_3).
Have: if (x_2 = 1) then (tmp#L12 = 1) else (tmp#L12 = 0).
Have: forall i_0 : Z. let x_6 = L_count(data#L1, begin#L1, i_0) in
let x_7 = to_uint32(1 + i_0) in let x_8 = to_uint32(x_1 + x_6) in
let x_9 = data#L1[i_0] in ((i_0 <= end#L1) -> ((begin#L1 <= i_0) ->
((i_0 < i#L6) -> ((i_0 < x_0) -> ((0 <= x_6) -> ((x_7 <= end#L1) ->
((begin#L1 <= x_7) -> (((begin#L1 + x_6) <= i_0) ->
(((begin#L1 + x_8) <= x_7) -> (is_uint32(i_0) -> (is_bool(x_9) ->
(is_uint32(x_6) ->
((if (x_9 = 1) then (tmp#L12 = 1) else (tmp#L12 = 0)) ->
(L_count(data#L1, begin#L1, x_7) = x_8)))))))))))))).
[...]
Stmt { L6: }
Stmt { tmp = tmp_0; }
Stmt { L12: result = x_4; }
Stmt { L13: }
}
Prove: L_count(data#L1, begin#L1, x_5) = x_4.
Goal id: typed_occurrences_of_loop_invariant_result_val_preserved
Short id: occurrences_of_loop_invariant_result_val_preserved
--------------------------------------------------------------------------------
Prover Alt-Ergo 2.4.2: Timeout (Qed:52ms) (10s).
A bug on the typing of the induction tactic was indeed fixed between Frama-C 24 and 25 (https://git.frama-c.com/pub/frama-c/-/commit/6058453cce2715f7dcf9027767559f95fb3b1679). And the symptom was indeed that the tactic could generate ill-typed formulas with true instead of a term.
Proving this example in not that easy. For two main reasons:
the function and the definition work in the opposite directions,
the definition does not have an optimal expression for reasoning.
However, one can write a lemma function to solve the problem:
#include <stdbool.h>
#define SIZE 1000
bool data[SIZE] ;
/*#
logic integer count(integer begin, integer end)=
begin >= end ? 0 : ((data[begin]==true) ? count(begin+1, end)+1 : count(begin+1, end));
*/
/*# ghost
/# requires begin < end ;
assigns \nothing ;
ensures count(begin, end) == ((data[end-1]==true) ? count(begin, end-1)+1 : count(begin, end-1));
#/
void lemma(bool* d, int begin, int end){
/# loop invariant begin <= i < end ;
loop invariant count(i, end) == ((data[end-1]==true) ? count(i, end-1)+1 : count(i, end-1));
loop assigns i ;
loop variant i - begin ;
#/
for(int i = end-1 ; i > begin ; i--);
}
*/
/*#
requires SIZE > begin >= 0;
requires SIZE >= end >= 0;
requires begin <= end;
assigns \nothing;
ensures \result == count(begin, end);
*/
unsigned int occurrences_of(int begin, int end)
{
unsigned int result = 0;
/*#
loop invariant i_bound: begin <= i <= end;
loop invariant result_bound: 0 <= result <= i-begin;
loop invariant result_val: result == count(begin, i);
loop assigns i, result;
loop variant end-i;
*/
for (unsigned int i = begin; i < end; ++i){
result += (data[i] == true) ? 1 : 0;
//# ghost lemma(data, begin, i+1);
}
return result;
}
I'd suggest to use the following definition:
/*#
logic integer count(integer begin, integer end)=
begin >= end ? 0 : ((data[end-1]==true) ? 1 : 0) + count(begin, end-1);
*/
It works in the same direction as the function and avoids the duplication of the term count(begin, end-1) which makes reasoning easier.
I am trying to add the 2 outputs together and show their result in a third/fourth display on the 7 segment display. Each output is shown in their own segment respectively. The fourth display being a double digit number (Max being 14, Min being 0). I am getting an error stating that I need to write all instances of the case "add". Not sure where to go from here. Any help is appreciated.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY Midterm2_Q2_4369 IS
PORT (
SW: IN STD_LOGIC_VECTOR(2 DOWNTO 0);
SW0: IN STD_LOGIC_VECTOR(2 DOWNTO 0);
ADD: IN STD_LOGIC_VECTOR(6 DOWNTO 0);
Y: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
Y0: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
Y1: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
Y2: OUT STD_LOGIC_VECTOR(6 DOWNTO 0));
END Midterm2_Q2_4369;
ARCHITECTURE MUX8 OF Midterm2_Q2_4369 IS
BEGIN
PROCESS (SW,SW0,ADD)
BEGIN
CASE SW IS
WHEN "000" => Y <= "0000001";
WHEN "001" => Y <= "1001111";
WHEN "010" => Y <= "0010010";
WHEN "011" => Y <= "0000110";
WHEN "100" => Y <= "1001100";
WHEN "101" => Y <= "0100100";
WHEN "110" => Y <= "0100000";
WHEN "111" => Y <= "0001111";
END CASE;
CASE SW0 IS
WHEN "000" => Y0 <= "0000001";
WHEN "001" => Y0 <= "1001111";
WHEN "010" => Y0 <= "0010010";
WHEN "011" => Y0 <= "0000110";
WHEN "100" => Y0 <= "1001100";
WHEN "101" => Y0 <= "0100100";
WHEN "110" => Y0 <= "0100000";
WHEN "111" => Y0 <= "0001111";
END CASE;
CASE ADD IS
WHEN "0000000" => Y1 <= "0000001"; --0
WHEN "0000001" => Y1 <= "1001111"; --1
WHEN "0000010" => Y1 <= "0010010"; --2
WHEN "0000011" => Y1 <= "0000110"; --3
WHEN "0000100" => Y1 <= "1001100"; --4
WHEN "0000101" => Y1 <= "0100100"; --5
WHEN "0000110" => Y1 <= "0100000"; --6
WHEN "0000111" => Y1 <= "0001111"; --7
WHEN "0001111" => Y1 <= "0000000"; --8
WHEN "0010111" => Y1 <= "0000100"; --9
--8421421
WHEN "0011111" => Y2 <= "1001111"; --(1)0
WHEN "0100111" => Y2 <= "1001111"; --(1)1
WHEN "0101111" => Y2 <= "1001111"; --(1)2
WHEN "0110111" => Y2 <= "1001111"; --(1)3
WHEN "0111111" => Y2 <= "1001111"; --(1)4--
WHEN "1000111" => Y2 <= "1001111"; --(1)5
WHEN "1001111" => Y2 <= "1001111"; --(1)6
WHEN "1010111" => Y2 <= "1001111"; --(1)7--
WHEN "1011111" => Y2 <= "1001111"; --(1)8
WHEN "1100111" => Y2 <= "1001111"; --(1)9
END CASE;
END PROCESS;
END MUX8;
When using a case in VHDL, all cases MUST be covered.
Becasue SW, SW0 and ADD are all std_logic_vector, you must also cover all of the meta cases like "UUUUUUUU", etc. The easiest way to do this is with others.
For example. SW0 has all "real" cases covered, but you must also cover values that can only occur in simulation, so provide a handy message:
CASE SW0 IS
WHEN "000" => Y0 <= "0000001";
WHEN "001" => Y0 <= "1001111";
WHEN "010" => Y0 <= "0010010";
WHEN "011" => Y0 <= "0000110";
WHEN "100" => Y0 <= "1001100";
WHEN "101" => Y0 <= "0100100";
WHEN "110" => Y0 <= "0100000";
WHEN "111" => Y0 <= "0001111";
when others => report "Meta value detected" severity warning;-- simulation only case
END CASE;
You must also ensure all cases are covered for SW and ADD too
I am trying to prove, that my algorithm for finding second largest value in array works as it should. This is my code:
function FindMax2 (V : Vector) return Integer is
Max : Natural := 0;
SecondMax : Natural := 0;
begin
for I in V'Range loop
pragma Assert
(Max >= 0 and
SecondMax >= 0 and
V(I) > 0);
if V(I) > Max then
SecondMax := Max;
Max := V(I);
elsif V(I) /= Max and V(I) > SecondMax then
SecondMax := V(I);
end if;
pragma Loop_Invariant
(Max > SecondMax and
V(I) > 0 and
(for all J in V'First .. I => V(J) <= Max));
end loop;
return SecondMax;
end FindMax2;
and this are my pre- and postconditions:
package Max2 with SPARK_Mode is
type Vector is array (Integer range <>) of Positive;
function FindMax2 (V : Vector) return Integer
with
Pre => V'First < Integer'Last and V'Length > 0,
Post => FindMax2'Result >= 0 and
(FindMax2'Result = 0 or (for some I in V'Range => FindMax2'Result = V(I))) and
(if FindMax2'Result /= 0 then (for some I in V'Range => V(I) > FindMax2'Result)) and
(if FindMax2'Result = 0 then (for all I in V'Range => (for all J in V'Range => V(I) = V(J)))
else
(for all I in V'Range => (if V(I) > FindMax2'Result then (for all J in V'Range => V(J) <= V(I)))));
end Max2;
I'm stuck now on this message from GNATprove:
max2.ads:8:17: medium: postcondition might fail (e.g. when FindMax2'Result = 1 and V = (others => 1) and V'First = 0 and V'Last = 0)
If I am not mistaken it is reffering to the first condition about the result being greater or equal to 0, then why does it put 1 as a counter-example? Is there any way I can prove this?
I managed to solve my problem. I was wrong about the error message, gnatprove was reffering to the whole post condition statement. If someone is interested in the solution, Iadded a few conditions in the loop invariant
pragma Loop_Invariant
(Max > SecondMax and
V(I) > 0 and
(for all J in V'First .. I => V(J) <= Max) and
(Max = 0 or (for some J in V'First .. I => Max = V(J))) and
(SecondMax = 0 or (for some J in V'First .. I => SecondMax = V(J))) and
(if SecondMax = 0 then (for all J in V'First .. I => (for all K in V'First .. I => V(J) = V(K)))
else (for all J in V'First .. I => (if V(J) > SecondMax then (for all K in V'First .. I => V(K) <= V(J))))));
Note that the actual answer was provided by the OP self here. Credits should go there. This is just an addition to my comment on that nice result.
max2.ads
package Max2 with SPARK_Mode is
type Vector is array (Integer range <>) of Positive;
function All_Same (V : Vector) return Boolean is
(for all I in V'Range => (for all J in V'Range => V(I) = V(J)))
with Ghost;
function Elem_Of (V : Vector; X : Integer) return Boolean is
(for some I in V'Range => V (I) = X)
with Ghost;
function Is_Largest (V : Vector; X : Integer) return Boolean is
(Elem_Of (V, X) and (for all I in V'Range => V (I) <= X))
with Ghost;
function Is_Second_Largest (V : Vector; X : Integer) return Boolean is
(Elem_Of (V, X) and not Is_Largest (V, X) and
(for all I in V'Range => V(I) <= X or else Is_Largest (V, V (I))))
with Ghost;
pragma Annotate (GNATprove, Inline_For_Proof, All_Same);
pragma Annotate (GNATprove, Inline_For_Proof, Elem_Of);
pragma Annotate (GNATprove, Inline_For_Proof, Is_Largest);
pragma Annotate (GNATprove, Inline_For_Proof, Is_Second_Largest);
procedure FindMax2 (V : Vector; Found : out Boolean; Value : out Natural)
with Post => (if Found then Is_Second_Largest (V, Value) else All_Same (V));
end Max2;
max2.adb
package body Max2 with SPARK_Mode is
--------------
-- FindMax2 --
--------------
procedure FindMax2
(V : in Vector;
Found : out Boolean;
Value : out Natural)
is
L1 : Natural := 0;
L2 : Natural := 0;
begin
if V'Length > 1 then
for I in V'Range loop
if L1 < V(I) then
L2 := L1;
L1 := V(I);
elsif L2 < V(I) and V(I) < L1 then
L2 := V(I);
end if;
pragma Loop_Invariant
(L2 < L1);
pragma Loop_Invariant
(L1 = 0 or Elem_Of (V (V'First .. I), L1));
pragma Loop_Invariant
(L2 = 0 or Elem_Of (V (V'First .. I), L2));
pragma Loop_Invariant
(Is_Largest (V (V'First .. I), L1));
pragma Loop_Invariant
(if L2 = 0
then All_Same (V (V'First .. I))
else Is_Second_Largest (V (V'First .. I), L2));
end loop;
end if;
Found := (L2 > 0);
Value := L2;
end FindMax2;
end Max2;
I am trying to implement the Grade-School Multiplication algorithm in Ada, and am currently getting an index out of bounds error. I'd appreciate any input on how to fix the error, and successfully implement the Algorithm. Thanks in advance!
I have a package BigNumPkg which defines type BigNum is array(0..Size - 1) of Integer;
The function I am trying to implement currently looks like this:
FUNCTION "*" (X, Y : BigNum) RETURN BigNum IS
Product : BigNum:= Zero;
Carry : Natural := 0;
Base : Constant Integer := 10;
BEGIN
FOR I IN REVERSE 0..Size-1 LOOP
Carry := 0;
FOR N IN REVERSE 0..Size-1 LOOP
Product(N + I - 1) := Product(N + I - 1) + Carry + X(N) * Y(I);
Carry := Product(N + I -1) / Base;
Product(N + I -1) := Product(N +I-1) mod Base;
END LOOP;
Product(I+Size-1) := Product(I+Size-1) + Carry;
END LOOP;
RETURN Product;
END "*";
Package specification:
package Big_Integer is
Base : constant := 10;
Size : constant := 3;
type Extended_Digit is range 0 .. Base * Base;
subtype Digit is Extended_Digit range 0 .. Base - 1;
type Instance is array (0 .. Size - 1) of Digit;
function "*" (Left, Right : in Instance) return Instance;
function Image (Item : in Instance) return String;
end Big_Integer;
You can of course adjust the parameters as needed, but these are nice for manual inspection of the results. Note that I haven't assured myself that the range of Extended_Digit is correct, but it seems to work in this case.
Package implementation:
with Ada.Strings.Unbounded;
package body Big_Integer is
function "*" (Left, Right : in Instance) return Instance is
Carry : Extended_Digit := 0;
Sum : Extended_Digit;
begin
return Product : Instance := (others => 0) do
for I in Left'Range loop
for J in Right'Range loop
if I + J in Product'Range then
Sum := Left (I) * Right (J) + Carry + Product (I + J);
Product (I + J) := Sum mod Base;
Carry := Sum / Base;
else
Sum := Left (I) * Right (J) + Carry;
if Sum = 0 then
Carry := 0;
else
raise Constraint_Error with "Big integer overflow.";
end if;
end if;
end loop;
if Carry /= 0 then
raise Constraint_Error with "Big integer overflow.";
end if;
end loop;
end return;
end "*";
function Image (Item : in Instance) return String is
Buffer : Ada.Strings.Unbounded.Unbounded_String;
begin
for E of reverse Item loop
Ada.Strings.Unbounded.Append (Buffer, Digit'Image (E));
end loop;
return Ada.Strings.Unbounded.To_String (Buffer);
end Image;
end Big_Integer;
Test driver:
with Ada.Text_IO;
with Big_Integer;
procedure Use_Big_Integers is
use all type Big_Integer.Instance;
procedure Multiply (A, B : in Big_Integer.Instance);
procedure Multiply (A, B : in Big_Integer.Instance) is
use Ada.Text_IO;
begin
Put (Image (A));
Put (" * ");
Put (Image (B));
Put (" = ");
Put (Image (A * B));
New_Line;
exception
when Constraint_Error =>
Put_Line ("Constraint_Error");
end Multiply;
begin
Multiply (A => (0 => 1, others => 0),
B => (others => Big_Integer.Digit'Last));
Multiply (A => (0 => Big_Integer.Digit'Last, others => 0),
B => (0 => Big_Integer.Digit'Last, others => 0));
Multiply (A => (0 => 2, others => 0),
B => (others => Big_Integer.Digit'Last));
Multiply (A => (2 => 0, 1 => 1, 0 => 2),
B => (2 => 0, 1 => 4, 0 => 5));
Multiply (A => (2 => 0, 1 => 2, 0 => 2),
B => (2 => 0, 1 => 4, 0 => 5));
Multiply (A => (2 => 0, 1 => 2, 0 => 3),
B => (2 => 0, 1 => 4, 0 => 5));
end Use_Big_Integers;
It is good style to provide a complete reproducer, but never mind...
When I is going to be used as an index into Y, it is good style to write the loop statement as for I in reverse Y'Range ... end loop;. Similarly for N.
Are you certain that N + I - 1 always is a valid index for Product? I'm pretty sure that you can get both too large and too small indices with your current implementation. I suspect that the too small indices is an off-by-one error in the implementation of the algorithm. The too large indices are because you haven't thought clearly about how to handle integer overflow (the traditional way in Ada is to raise Constraint_Error).
Shouldn't yo check the value of Carry at the end of the function?
I'm a beginner at VHDL and I have problems when to decide whether I should initialize my signal or not...
Here's an exemple :
entity tatoo is
port (
clk, reset : in std_logic;
opcode : in std_logic_vector(2 downto 0);
A, B : in std_logic_vector(3 downto 0);
F : out std_logic_vector(3 downto 0)
);
architecture toota of tatoo is
signal Q : std_logic_vector(3 downto 0);
begin
process (clk, reset) -- register for F
begin
if(reset = '1')
then F <= "0000";
elsif(Clk'event and Clk = '1')
then F <= Q;
end if;
end process;
process(opcode, A, B) -- ALU
begin
Should I initialize Q here ? => Q <= "0000"; ?
case opcode is
when "00" =>
Q <= "0000";
when "01" =>
Q <= A-B;
when "10" =>
Q <= B-A;
when "11" =>
Q <= A xor B;
end case;
end process;
Thanks a lot,
You need to initialise it somewhere, or you'll get a latch. Your suggestion is fine (though Q <= (others => '0') is more future-proof), of you could have a default/others branch in the case statement, where you give Q a default value. Basically, when you have a combinatorial process like this one, make sure that anything your drive always has a defined value whatever the value of the inputs may be. If not, you're inferring memory of some sort.