Ada - accessibility check raised - ada

I have downloaded this program from Github: https://github.com/raph-amiard/ada-synth-lib
I have attemted the first example and I am presented with an exception. If anybody would be able to give me an insight into why this is, it would be massively appreciated. I've been stumped on this for a long time and I'm really keen to get this working.
The error I recieve is: raised PROGRAM_ERROR : waves.adb:110 accessibility check failed
Here is the main file:
with Waves; use Waves;
with Write_To_Stdout;
procedure Main is
Sine_Gen : constant access Sine_Generator := Create_Sine (Fixed (440.0));
begin
Write_To_Stdout (Sine_Gen);
end Main;
Here is the waves.adb file
with Effects; use Effects;
with Interfaces; use Interfaces;
package body Waves is
function Mod_To_Int (A : Unsigned_32) return Integer_32;
-------------------
-- Update_Period --
-------------------
procedure Update_Period
(Self : in out Wave_Generator'Class; Buffer : in out Period_Buffer)
is
begin
Self.Frequency_Provider.Next_Samples (Buffer);
for I in Buffer'Range loop
Buffer (I) :=
Utils.Period_In_Samples
(Frequency (Buffer (I)));
end loop;
end Update_Period;
------------
-- Create --
------------
function Create_Saw
(Freq_Provider : Generator_Access) return access Saw_Generator
is
begin
return new Saw_Generator'(Frequency_Provider => Freq_Provider,
Current => -1.0, others => <>);
end Create_Saw;
-----------------
-- Next_Sample --
-----------------
overriding procedure Next_Samples
(Self : in out Saw_Generator; Buffer : in out Generator_Buffer)
is
P_Buffer : Period_Buffer;
begin
Update_Period (Self, P_Buffer);
for I in Buffer'Range loop
Self.Step := 2.0 / Float (P_Buffer (I));
Self.Current := Self.Current + Sample (Self.Step);
if Self.Current > 1.0 then
Self.Current := Self.Current - 2.0;
end if;
Buffer (I) := Self.Current;
end loop;
end Next_Samples;
------------
-- Create --
------------
function Create_Square
(Freq_Provider : access Generator'Class) return access Square_Generator is
begin
return new Square_Generator'(Frequency_Provider =>
Generator_Access (Freq_Provider),
Is_High => True,
Current_Sample => 0,
others => <>);
end Create_Square;
-----------------
-- Next_Sample --
-----------------
overriding procedure Next_Samples
(Self : in out Square_Generator; Buffer : in out Generator_Buffer)
is
P_Buffer : Period_Buffer;
begin
Update_Period (Self, P_Buffer);
for I in Buffer'Range loop
Self.Current_Sample := Self.Current_Sample + 1;
declare
A : constant Period := Period (Self.Current_Sample)
/ P_Buffer (I);
begin
if A >= 1.0 then
Self.Current_Sample := 0;
Buffer (I) := 1.0;
end if;
Buffer (I) := (if A >= 0.5 then 1.0 else -1.0);
end;
end loop;
end Next_Samples;
------------
-- Create --
------------
function Create_Sine
(Freq_Provider : access Generator'Class) return access Sine_Generator
is
Ret : constant access Sine_Generator :=
new Sine_Generator'(Frequency_Provider =>
Generator_Access (Freq_Provider),
Current_Sample => 0,
Current_P => 0.0,
others => <>);
begin
Ret.Current_P := 0.0;
return Ret;
end Create_Sine;
-----------------
-- Next_Sample --
-----------------
overriding procedure Next_Samples
(Self : in out Sine_Generator; Buffer : in out Generator_Buffer)
is
P_Buffer : Period_Buffer;
begin
Update_Period (Self, P_Buffer);
for I in Buffer'Range loop
Self.Current_Sample := Self.Current_Sample + 1;
if Period (Self.Current_Sample) >= Self.Current_P then
Self.Current_P := P_Buffer (I) * 2.0;
Self.Current_Sample := 0;
end if;
Buffer (I) :=
Sample
(Sin
(Float (Self.Current_Sample)
/ Float (Self.Current_P) * Pi * 2.0));
end loop;
end Next_Samples;
------------
-- Create --
------------
function Create_Chain
(Gen : access Generator'Class;
Sig_Procs : Signal_Processors
:= No_Signal_Processors) return access Chain
is
Ret : constant access Chain :=
new Chain'(Gen => Generator_Access (Gen), others => <>);
begin
for P of Sig_Procs loop
Ret.Add_Processor (P);
end loop;
return Ret;
end Create_Chain;
-------------------
-- Add_Processor --
-------------------
procedure Add_Processor
(Self : in out Chain; P : Signal_Processor_Access) is
begin
Self.Processors (Self.Nb_Processors) := P;
Self.Nb_Processors := Self.Nb_Processors + 1;
end Add_Processor;
-----------------
-- Next_Sample --
-----------------
overriding procedure Next_Samples
(Self : in out Chain; Buffer : in out Generator_Buffer)
is
S : Sample;
begin
Self.Gen.Next_Samples (Buffer);
for J in Buffer'Range loop
S := Buffer (J);
for I in 0 .. Self.Nb_Processors - 1 loop
S := Self.Processors (I).Process (S);
end loop;
Buffer (J) := S;
end loop;
end Next_Samples;
---------
-- LFO --
---------
function LFO (Freq : Frequency; Amplitude : Float) return Generator_Access
is
Sin : constant Generator_Access := Create_Sine (Fixed (Freq));
begin
return new Attenuator'
(Level => Amplitude,
Source => new Transposer'(Source => Sin, others => <>), others => <>);
end LFO;
------------
-- Create --
------------
function Create_ADSR
(Attack, Decay, Release : Millisecond; Sustain : Scale;
Source : access Note_Generator'Class := null) return access ADSR
is
begin
return new ADSR'
(State => Off,
Source => Source,
Attack => Msec_To_Period (Attack),
Decay => Msec_To_Period (Decay),
Release => Msec_To_Period (Release),
Sustain => Sustain,
Current_P => 0, others => <>);
end Create_ADSR;
-----------------
-- Next_Sample --
-----------------
overriding procedure Next_Samples
(Self : in out ADSR; Buffer : in out Generator_Buffer)
is
Ret : Sample;
begin
for I in Buffer'Range loop
case Self.Source.Buffer (I).Kind is
when On =>
Self.Current_P := 0;
Self.State := Running;
when Off =>
Self.State := Release;
Self.Cur_Sustain := Scale (Self.Memo_Sample);
Self.Current_P := 0;
when No_Signal => null;
end case;
Self.Current_P := Self.Current_P + 1;
case Self.State is
when Running =>
if Self.Current_P in 0 .. Self.Attack then
Ret := Exp8_Transfer
(Sample (Self.Current_P) / Sample (Self.Attack));
elsif
Self.Current_P in Self.Attack + 1 .. Self.Attack + Self.Decay
then
Ret :=
Exp8_Transfer
(Float (Self.Decay + Self.Attack - Self.Current_P)
/ Float (Self.Decay));
Ret := Ret
* Sample (1.0 - Self.Sustain)
+ Sample (Self.Sustain);
else
Ret := Sample (Self.Sustain);
end if;
Self.Memo_Sample := Ret;
when Release =>
if Self.Current_P in 0 .. Self.Release then
Ret :=
Exp8_Transfer
(Sample (Self.Release - Self.Current_P)
/ Sample (Self.Release))
* Sample (Self.Cur_Sustain);
else
Self.State := Off;
Ret := 0.0;
end if;
when Off => Ret := 0.0;
end case;
Buffer (I) := Ret;
end loop;
end Next_Samples;
----------------------
-- Next_Sample --
----------------------
overriding procedure Next_Samples
(Self : in out Pitch_Gen; Buffer : in out Generator_Buffer)
is
Ret : Sample;
begin
if Self.Proc /= null then
Self.Proc.Next_Samples (Buffer);
end if;
for I in Buffer'Range loop
case Self.Source.Buffer (I).Kind is
when On =>
Self.Current_Note := Self.Source.Buffer (I).Note;
Self.Current_Freq :=
Note_To_Freq (Self.Current_Note, Self.Relative_Pitch);
when others => null;
end case;
Ret := Sample (Self.Current_Freq);
if Self.Proc /= null then
Ret := Ret + Buffer (I);
end if;
Buffer (I) := Ret;
end loop;
end Next_Samples;
------------------
-- Create_Noise --
------------------
function Create_Noise return access Noise_Generator
is
N : constant access Noise_Generator := new Noise_Generator;
begin
return N;
end Create_Noise;
F_Level : constant Sample := 2.0 / Sample (16#FFFFFFFF#);
G_X1 : Unsigned_32 := 16#67452301#;
G_X2 : Unsigned_32 := 16#EFCDAB89#;
Z : constant := 2 ** 31;
----------------
-- Mod_To_Int --
----------------
function Mod_To_Int (A : Unsigned_32) return Integer_32 is
Res : Integer_32;
begin
if A < Z then
return Integer_32 (A);
else
Res := Integer_32 (A - Z);
Res := Res - (Z - 1) - 1;
return Res;
end if;
end Mod_To_Int;
------------------
-- Next_Samples --
------------------
overriding procedure Next_Samples
(Self : in out Noise_Generator; Buffer : in out Generator_Buffer)
is
pragma Unreferenced (Self);
begin
for I in Buffer'Range loop
G_X1 := G_X1 xor G_X2;
Buffer (I) := Sample (Mod_To_Int (G_X2)) * F_Level;
G_X2 := G_X2 + G_X1;
end loop;
end Next_Samples;
------------------
-- Next_Samples --
------------------
overriding procedure Next_Samples
(Self : in out Fixed_Gen; Buffer : in out Generator_Buffer) is
begin
if Self.Proc /= null then
Self.Proc.Next_Samples (Buffer);
for I in Buffer'Range loop
Buffer (I) := Self.Val + Buffer (I);
end loop;
else
for I in Buffer'Range loop
Buffer (I) := Self.Val;
end loop;
end if;
end Next_Samples;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out ADSR) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Source);
Self.Memo_Sample := 0.0;
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Saw_Generator) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Frequency_Provider);
Self.Current := -1.0;
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Square_Generator) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Frequency_Provider);
Self.Current_Sample := 0;
Self.Is_High := True;
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Sine_Generator) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Frequency_Provider);
Self.Current_Sample := 0;
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Noise_Generator) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Frequency_Provider);
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Pitch_Gen) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Source);
Reset_Not_Null (Self.Proc);
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Fixed_Gen) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Proc);
end Reset;
-----------
-- Reset --
-----------
overriding procedure Reset (Self : in out Chain) is
begin
Base_Reset (Self);
Reset_Not_Null (Self.Gen);
end Reset;
-----------
-- Fixed --
-----------
function Fixed
(Freq : Frequency;
Modulator : Generator_Access := null;
Name : String := "";
Min : Float := 0.0;
Max : Float := 5_000.0;
Param_Scale : Param_Scale_T := Linear)
return access Fixed_Gen
is
begin
return new
Fixed_Gen'
(Val => Sample (Freq),
Proc => Modulator,
Name => To_Unbounded_String (Name),
Min => Min,
Max => Max,
Param_Scale => Param_Scale,
others => <>);
end Fixed;
---------------
-- Set_Value --
---------------
overriding procedure Set_Value
(Self : in out Fixed_Gen; I : Natural; Val : Float)
is
pragma Unreferenced (I);
begin
Self.Val := Sample (Val);
end Set_Value;
---------------
-- Set_Value --
---------------
overriding procedure Set_Value
(Self : in out ADSR; I : Natural; Val : Float)
is
begin
case I is
when 0 => Self.Attack := Sec_To_Period (Val);
when 1 => Self.Decay := Sec_To_Period (Val);
when 2 => Self.Sustain := Scale (Val);
when 3 => Self.Release := Sec_To_Period (Val);
when others => raise Constraint_Error;
end case;
end Set_Value;
end Waves;
And lastly, the write_to_stdout.adb file
with Utils; use Utils;
with GNAT.OS_Lib;
procedure Write_To_Stdout (G : access Generator'Class)
is
function Sample_To_Int16 is new Sample_To_Int (Short_Integer);
Int_Smp : Short_Integer := 0;
Ignore : Integer;
Buffer : Generator_Buffer;
begin
loop
Next_Steps;
G.Next_Samples (Buffer);
for I in Buffer'Range loop
Int_Smp := Sample_To_Int16 (Buffer (I));
Ignore := GNAT.OS_Lib.Write
(GNAT.OS_Lib.Standout, Int_Smp'Address, Int_Smp'Size / 8);
end loop;
exit when Sample_Nb > 10_000_000;
Sample_Nb := Sample_Nb + Generator_Buffer_Length;
end loop;
end Write_To_Stdout;
Thank you for reading, and any guidance into solving this would be most appreicated.
Cheers,
Lloyd

The function in question :
function Create_Sine
(Freq_Provider : access Generator'Class) return access Sine_Generator
is
Ret : constant access Sine_Generator :=
new Sine_Generator'(Frequency_Provider =>
Generator_Access (Freq_Provider),
Current_Sample => 0,
Current_P => 0.0,
others => <>);
begin
Ret.Current_P := 0.0;
return Ret;
end Create_Sine;
creates a new object, accessed by an access type in its local scope and returns a copy of the access. In this case it is probably OK but there is the possibility of similar cases where the object itself goes out of scope when the function returns, leaving a dangling access.
In this case it's probably overcautious since the only reference to the object is that returned, but the accessibility checks prohibit this whole class of potentially bug-ridden constructs. I say "probably" because the object could theoretically be allocated on the stack by some compilers, or in a locally owned storage pool rather than "the heap" for more reliable object lifetime management.
There is a solution : create the access in place in the returned object, rather than in an immediately discarded local object. Ada-2005 and later provide an "extended return" construct to allow this. It looks something like:
function Create_Sine
(Freq_Provider : access Generator'Class) return access Sine_Generator
is
begin
return Ret : constant access Sine_Generator :=
new Sine_Generator'( Frequency_Provider =>
Generator_Access (Freq_Provider),
Current_Sample => 0,
Current_P => 0.0,
others => <>)
do
-- initialisation actions here
Ret.Current_P := 0.0;
end return;
end Create_Sine;
not tested! but any of the usual sources should keep you straight now you know its name.
Here the caller owns the access type being initialised with the new object, so there is no danger of the access type out-living the accessed object.
There may be a better answer to this question overall. I have just addressed the immediate point, but the wider question is, do you need an access type here at all? In Ada the answer usually (but not always) is No. There are many cases where programmers coming from other languages just reach for the pointers, when there is a simpler or better way of doing things in Ada.

Related

Drawing Bowling Pins (pyramid) with Recursion in Ada

I know this is pushing the good will of the community by presenting my least elaborate work expecting someone to come and save me but I simply have no choice with nothing to lose. I've gone through packets, files, types, flags and boxes the last few weeks but I haven't covered much of recursion. Especially not drawing with recursion. My exam is in roughly one week and I hope this is ample time to repeat and learn simple recursion tricks like that of drawing bowling pins or other patterns:
I I I I I
I I I I
I I I
I I
I
n = 5
The problem I have with recursion is that I don't quite get it. How are you supposed to approach a problem like drawing pins like this using recursion?
The closest I've come is
I I I
I I
I
n = 3
and that's using
THIS CODE NOW WORKS
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure pyramidchaser is
subtype X_Type is Integer range 0..30;
X: X_Type;
Indent : Integer := 0;
procedure Numbergrabber (X : out Integer) is
begin
Put("Enter a number: ");
Get(X);
Skip_Line;
end Numbergrabber;
procedure PrintSpaces(I : in Integer) is
begin
if I in X_Type then
Put(" ");
else
return;
end if;
PrintSpaces(I - 1);
end Printspaces;
procedure PrintPins(i, n: in Integer) is
begin
if i >= n then
return;
end if;
Put('I');
Put(' ');
PrintPins(i + 1, n);
end Printpins;
function Pins (X, Indent: in Integer) return Integer is
Printed : Integer;
begin
Printed:= 0;
if X > 0 then
PrintSpaces(Indent);
PrintPins(0, X);
New_Line;
Printed := X + Pins(X - 1, Indent + 1);
end if;
return Printed;
end Pins;
Bowlingpins : Integer;
begin
Numbergrabber(X);
Bowlingpins:= Pins(X, Indent);
end pyramidchaser;
but with that I throw in a sum I dont really need just to kick off the recursive part which I dont really know why I do except it seems to be needed to be there. I experimented with code from a completely different assignment, thats why it looks the way it does. I know mod 2 will grant me too many new lines but at least it was an approach to finding heights to the pyramid. I understand the real approach is something similar to N+1 as with each step of the growing pyramid a new line is needed, but I dont know how to implement it.
I don't expect anyone to present a complete code but I hope somebody can clue me in on how to think on the way towards finding a solution.
I can still pass the exam without knowing recursion as its typically 2 assignments where one is and one isnt recursion and you need to pass one or the other, but given that I have some time I thought Id give it a chance.
As always, immensely thankful for anyone fighting the good fight!
Seeing this post gathered some attention Id like to expand the pyramid to one a little more complex:
THE PYRAMID PROBLEM 2
hope someone looks at it. I didnt expect so many good answers, I thought why not throw all I have out there.
Level 1
|=|
Level 2
|===|
||=||
|===|
Level 3
|=====|
||===||
|||=|||
||===||
|=====|
it needs to be figured out recursively. so some way it has to build both upwards and downwards from the center.
To clarify Im studying for an exam and surely so are many others whom would be thankful for code to sink their teeth in. Maybe theres an easy way to apply what Tama built in terms of bowling pin lines in pyramid walls?
Bowling pins:
Printing ----I---- is just: (I'm going to use dashes instead of spaces throughout for readability)
Put_Line (4 * "-" & "I" & 4 * "-");
And printing the whole bowling triangle could be:
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
procedure Print_Bowling_Line (Dashes : Natural; Pins : Positive) is
Middle : constant String := (if Pins = 1 then "I"
else (Pins - 1) * "I-" & "I");
begin
Put_Line (Dashes * "-" & Middle & Dashes * "-");
end Print_Bowling_Line;
begin
Print_Bowling_Line (0, 5);
Print_Bowling_Line (1, 4);
Print_Bowling_Line (2, 3);
Print_Bowling_Line (3, 2);
Print_Bowling_Line (4, 1);
end Main;
Writing the five repeated lines as a loop is quite obvious. For recursion, there are two ways.
Tail recursion
Tail recursion is the more natural 'ask questions, then shoot' approach; first check the parameter for an end-condition, if not, do some things and finally call self.
procedure Tail_Recurse (Pins : Natural) is
begin
if Pins = 0 then
return;
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
Tail_Recurse (Pins - 1);
end Tail_Recurse;
Head recursion
Head recursion is what mathematicians love; how do you construct a proof for N? Well, assuming you already have a proof for N-1, you just apply X and you're done. Again, we need to check the end condition before we go looking for a proof for N-1, otherwise we would endlessly recurse and get a stack overflow.
procedure Head_Recurse (Pins : Natural) is
begin
if Pins < Total_Pins then
Head_Recurse (Pins + 1); -- assuming N + 1 proof here
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
end Head_Recurse;
For the full code, expand the following snippet:
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Total_Pins : Natural := 5;
procedure Print_Bowling_Line (Dashes : Natural; Pins : Positive) is
Middle : constant String := (if Pins = 1 then "I"
else (Pins - 1) * "I-" & "I");
begin
Put_Line (Dashes * "-" & Middle & Dashes * "-");
end Print_Bowling_Line;
procedure Tail_Recurse (Pins : Natural) is
begin
if Pins = 0 then
return;
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
Tail_Recurse (Pins - 1);
end Tail_Recurse;
procedure Head_Recurse (Pins : Natural) is
begin
if Pins < Total_Pins then
Head_Recurse (Pins + 1); -- assuming N + 1 proof here
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
end Head_Recurse;
begin
Total_Pins := 8;
Head_Recurse (1);
end Main;
For simplicity, I don't pass around the second number, that indicates the stopping condition, but rather set it once before running the whole.
I always find it unfortunate to try to learn a technique by applying it where it makes the code more complicated, rather than less. So I want to show you a problem where recursion really does shine. Write a program that prints a maze with exactly one path between every two points in the maze, using the following depth-first-search pseudo code:
start by 'visiting' any field (2,2 in this example)
(recursion starts with this:)
while there are any neighbours that are unvisited,
pick one at random and
connect the current field to that field and
run this procedure for the new field
As you can see in the animation below, this should meander randomly until it gets 'stuck' in the bottom left, after which it backtracks to a node that still has an unvisited neighbour. Finally, when everything is filled, all the function calls that are still active will return because for each node there will be no neighbours left to connect to.
You can use the skeleton code in the snippet below. The answer should only modify the Depth_First_Make_Maze procedure. It need be no longer than 15 lines, calling Get_Unvisited_Neighbours, Is_Empty on the result, Get_Random_Neighbour and Connect (and itself, of course).
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Vectors;
with Ada.Numerics.Discrete_Random;
procedure Main is
N : Positive := 11; -- should be X*2 + 1 for some X >= 1
type Cell_Status is (Filled, Empty);
Maze : array (1 .. N, 1 .. N) of Cell_Status := (others => (others => Filled));
procedure Print_Maze is
begin
for Y in 1 .. N loop
for X in 1 .. N loop
declare
C : String := (case Maze (X, Y) is
--when Filled => "X", -- for legibility,
when Filled => "█", -- unicode block 0x2588 for fun
when Empty => " ");
begin
Put (C);
end;
end loop;
Put_Line ("");
end loop;
end Print_Maze;
type Cell_Address is record
X : Positive;
Y : Positive;
end record;
procedure Empty (Address : Cell_Address) is
begin
Maze (Address.X, Address.Y) := Empty;
end Empty;
procedure Connect (Address1 : Cell_Address; Address2 : Cell_Address) is
Middle_X : Positive := (Address1.X + Address2.X) / 2;
Middle_Y : Positive := (Address1.Y + Address2.Y) / 2;
begin
Empty (Address1);
Empty (Address2);
Empty ((Middle_X, Middle_Y));
end Connect;
function Cell_At (Address : Cell_Address) return Cell_Status is (Maze (Address.X, Address.Y));
function Left (Address : Cell_Address) return Cell_Address is (Address.X - 2, Address.Y);
function Right (Address : Cell_Address) return Cell_Address is (Address.X + 2, Address.Y);
function Up (Address : Cell_Address) return Cell_Address is (Address.X, Address.Y - 2);
function Down (Address : Cell_Address) return Cell_Address is (Address.X, Address.Y + 2);
type Neighbour_Count is new Integer range 0 .. 4;
package Neighbours_Package is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => Cell_Address);
use Neighbours_Package;
function Get_Unvisited_Neighbours (Address : Cell_Address) return Neighbours_Package.Vector is
NeighbourList : Neighbours_Package.Vector;
begin
NeighbourList.Reserve_Capacity (4);
if Address.X >= 4 then
declare
L : Cell_Address := Left (Address);
begin
if Cell_At (L) = Filled then
NeighbourList.Append (L);
end if;
end;
end if;
if Address.Y >= 4 then
declare
U : Cell_Address := Up (Address);
begin
if Cell_At (U) = Filled then
NeighbourList.Append (U);
end if;
end;
end if;
if Address.X <= (N - 3) then
declare
R : Cell_Address := Right (Address);
begin
if Cell_At (R) = Filled then
NeighbourList.Append (R);
end if;
end;
end if;
if Address.Y <= (N - 3) then
declare
D : Cell_Address := Down (Address);
begin
if Cell_At (D) = Filled then
NeighbourList.Append (D);
end if;
end;
end if;
return NeighbourList;
end Get_Unvisited_Neighbours;
package Rnd is new Ada.Numerics.Discrete_Random (Natural);
Gen : Rnd.Generator;
function Get_Random_Neighbour (List : Neighbours_Package.Vector) return Cell_Address is
Random : Natural := Rnd.Random (Gen);
begin
if Is_Empty (List) then
raise Program_Error with "Cannot select any item from an empty list";
end if;
declare
Index : Natural := Random mod Natural (List.Length);
begin
return List (Index);
end;
end Get_Random_Neighbour;
procedure Depth_First_Make_Maze (Address : Cell_Address) is
begin
null;
end Depth_First_Make_Maze;
begin
Rnd.Reset (Gen);
Maze (1, 2) := Empty; -- entrance
Maze (N, N - 1) := Empty; -- exit
Depth_First_Make_Maze ((2, 2));
Print_Maze;
end Main;
To see the answer, expand the following snippet.
procedure Depth_First_Make_Maze (Address : Cell_Address) is
begin
loop
declare
Neighbours : Neighbours_Package.Vector := Get_Unvisited_Neighbours (Address);
begin
exit when Is_Empty (Neighbours);
declare
Next_Node : Cell_Address := Get_Random_Neighbour (Neighbours);
begin
Connect (Address, Next_Node);
Depth_First_Make_Maze (Next_Node);
end;
end;
end loop;
end Depth_First_Make_Maze;
Converting recursion to loop
Consider how a function call works; we take the actual parameters and put them on the call stack along with the function's address. When the function completes, we take those values off the stack again and put back the return value.
We can convert a recursive function by replacing the implicit callstack containing the parameters with an explicit stack. I.e. instead of:
procedure Foo (I : Integer) is
begin
Foo (I + 1);
end Foo;
We would put I onto the stack, and as long as there are values on the stack, peek at the top value and do the body of the Foo procedure using that value. When there is a call to Foo within that body, push the value you would call the procedure with instead, and restart the loop so that we immediately start processing the new value. If there is no call to self in this case, we discard the top value on the stack.
Restructuring a recursive procedure in this way will give you an insight into how it works, especially since pushing on to the stack is now separated from 'calling' that function since you explicitly take an item from the stack and do something with it.
You will need a stack implementation, here is one that is suitable:
Bounded_Stack.ads
generic
max_stack_size : Natural;
type Element_Type is private;
package Bounded_Stack is
type Stack is private;
function Create return Stack;
procedure Push (Onto : in out Stack; Item : Element_Type);
function Pop (From : in out Stack) return Element_Type;
function Top (From : in out Stack) return Element_Type;
procedure Discard (From : in out Stack);
function Is_Empty (S : in Stack) return Boolean;
Stack_Empty_Error : exception;
Stack_Full_Error : exception;
private
type Element_List is array (1 .. max_stack_size) of Element_Type;
type Stack is
record
list : Element_List;
top_index : Natural := 0;
end record;
end Bounded_Stack;
Bounded_Stack.adb
package body Bounded_Stack is
function Create return Stack is
begin
return (top_index => 0, list => <>);
end Create;
procedure Push (Onto : in out Stack; Item : Element_Type) is
begin
if Onto.top_index = max_stack_size then
raise Stack_Full_Error;
end if;
Onto.top_index := Onto.top_index + 1;
Onto.list (Onto.top_index) := Item;
end Push;
function Pop (From : in out Stack) return Element_Type is
Top_Value : Element_Type := Top (From);
begin
From.top_index := From.top_index - 1;
return Top_Value;
end Pop;
function Top (From : in out Stack) return Element_Type is
begin
if From.top_index = 0 then
raise Stack_Empty_Error;
end if;
return From.list (From.top_index);
end Top;
procedure Discard (From : in out Stack) is
begin
if From.top_index = 0 then
raise Stack_Empty_Error;
end if;
From.top_index := From.top_index - 1;
end Discard;
function Is_Empty (S : in Stack) return Boolean is (S.top_index = 0);
end Bounded_Stack;
It can be instantiated with a maximum stack size of Width*Height, since the worst case scenario is when you happen to choose a non-forking path that visits each cell once:
N_As_Cell_Size : Natural := (N - 1) / 2;
package Cell_Stack is new Bounded_Stack(max_stack_size => N_As_Cell_Size * N_As_Cell_Size, Element_Type => Cell_Address);
Take your answer to the previous assignment, and rewrite it without recursion, using the stack above instead.
To see the answer, expand the following snippet.
procedure Depth_First_Make_Maze (Address : Cell_Address) is
Stack : Cell_Stack.Stack := Cell_Stack.Create;
use Cell_Stack;
begin
Push (Stack, Address);
loop
exit when Is_Empty (Stack);
declare
-- this shadows the parameter, which we shouldn't refer to directly anyway
Address : Cell_Address := Top (Stack);
Neighbours : Neighbours_Package.Vector := Get_Unvisited_Neighbours (Address);
begin
if Is_Empty (Neighbours) then
Discard (Stack); -- equivalent to returning from the function in the recursive version
else
declare
Next_Cell : Cell_Address := Get_Random_Neighbour (Neighbours);
begin
Connect (Address, Next_Cell);
Push (Stack, Next_Cell); -- equivalent to calling self in the recursive version
end;
end if;
end;
end loop;
end Depth_First_Make_Maze;
You’re going to print as many lines as there are pins. Each line has an indentation consisting of a number of spaces and a number of pins, each printed as "I " (OK,there's an extra space at the end of the line, but no one's going to see that).
Start off with no leading spaces and the number of pins you were asked to print.
The next line needs one more leading space and one fewer pin (unless, of course, that would mean printing no pins, in which case we're done).
I don't program in Ada (it looks like a strange Pascal to me), but there is an obvious algorithmic problem in your Pins function.
Basically, if you want to print a pyramid whose base is N down to the very bottom where base is 1, you would need to do something like this (sorry for crude pascalization of the code).
procedure PrintPins(i, n: Integer)
begin
if i >= n then return;
Ada.Text_IO.Put('I'); // Print pin
Ada.Text_IO.Put(' '); // Print space
PrintPins(i + 1, n); // Next iteration
end;
function Pins(x, indent: Integer): Integer
printed: Integer;
begin
printed := 0;
if x > 0 then
PrintSpaces(indent); // Print indentation pretty much using the same artificial approach as by printing pins
PrintPins(0, x);
(*Print new line here*)
(*Now go down the next level and print another
row*)
printed := x + Pins(x - 1, indent + 1);
end;
return printed;
end
P.S. You don't need a specific function to count the number of printed pins here. It's just a Gauss sequence sum of the range 1..N, which is given by N(N + 1)/2
A variation of this program is to use both head recursion and tail recursion in the same procedure.
The output of such a program is
Enter the number of rows in the pyramid: 5
I I I I I
I I I I
I I I
I I
I
I
I I
I I I
I I I I
I I I I I
N = 5
Tail recursion produces the upper triangle and head recursion produces the lower triangle.
The way you develop a recursive algorithm is to pretend that you already have a subprogram that does what you want, except for the first bit, and you know, or can figure out, how to do the first bit. Then your algorithm is
Do the first bit
Call the subprogram to do the rest on what remains,
taking into account the effect of the first bit, if necessary
The trick is that "Call the subprogram to do the rest" is a recursive call to the subprogram you're creating.
It's always possible that the subprogram may be called when there's nothing to do, so you have to take that into account:
if Ending Condition then
Do any final actions
return [expression];
end if;
Do the first bit
Call the subprogram to do the rest
And you're done. By repreatedly doing the first bit until the ending condition is True, you end up doing the whole thing.
As an example, the function Get_Line in Ada.Text_IO may be implemented (this is not how it is usually implemented) by thinking, "I know how to get the first Character of the line. If I have a function to return the rest of the line, then I can return the first Character concatenated with the function result." So:
function Get_Line return String is
C : Character;
begin
Get (Item => C);
return C & Get_Line;
end Get_Line;
But what if we're already at the end of a line, so there's no line to get?
function Get_Line return String is
C : Character;
begin
if End_Of_Line then
Skip_Line;
return "";
end if;
Get (Item => C);
return C & Get_Line;
end Get_Line;
For your problem the first bit is printing a row with an indent and a number of pins, and the ending condition is when there are no more rows to print.
For your pyramid problem, this tail recursion scheme doesn't work. You need to do "middle recursion":
if Level = 1 then
Print the line for Level
return
end if
Print the top line for Level
Recurse for Level - 1
Print the bottom line for Level

VHDL Unable to initialize array of unsigned vectors

The lines:
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
signal some_array : some_array_type := (others=>(others=>'0'));
cause vivado 2018.2 to throw the error:
[Synth 8-1807] character '0' is not in type unresolved_unsigned
for some reason in a VHDL 2008 file. What it the magical syntax to get Vivado to realize that I'm just trying to initialize the array to zeros? I shouldn't have to write a function to do this. I also tried unsigned((others=>(others=>'0')));
The code below can of course be ignored and isn't needed for anything at all. It is just there for the OCD people. "You have to always include a minimal working example!"
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity some_entity is
port (
clk, rst: in std_logic ;
);
end some_entity ;
architecture arch of some_entity is
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
-- throws error
signal some_array : some_array_type := (others=>(others=>'0'));
type some_other_array_type is array (natural range <>) of std_logic_vector(7 downto 0);
-- doesn't throw error
signal some_other_array : some_other_array_type(0 to 4) := (others=>(others=>'0'));
begin
-- some made up process
process(clk, rst)
begin
if(rising_edge(clk)) then
if rst = '1' then
some_array <= (others=>(others=>'0'));
else
some_array <= (others=>(others=>'1'));
end if;
end if;
end process;
end arch;

Record aggregate with dynamic choice

I need to write a value consisting of all 0 except for bit Bit in a hardware register, where the register is somewhat like
type Bit_Number is range 0 .. 31;
type Bits_1 is array (Bit_Number) of Boolean
with
Component_Size => 1,
Size => 32;
Register_1 : Bits_1
with
Volatile,
Address => System'To_Address (16#1234_5678#);
Register_1 (typical of registers in Atmel's ATSAM3X8E, as in the Arduino Due) is defined as write-only, and it's unspecified what you get back if you read it, and it's unspecified what access widths are legal; all we are told is that when we write to the register only the 1 bits have any effect. (Incidentally, this means that the GNAT-specific aspect Volatile_Full_Access or the changes proposed in AI12-0128 won't help).
Enabling a pin in a GPIO peripheral involves setting its Bit in several registers. For reasons which I can't change (AdaCore's SVD2Ada), each register has its own equivalent of the Bits_1 array type above.
I want to write
procedure Set_Bit (Bit : Bit_Number) is
begin
Register_1 := (Bit => True, others => False);
Register_2 := (Bit => True, others => False);
...
end Set_Bit;
but the compiler says
19. procedure Set_Bit (Bit : Bit_Number) is
20. begin
21. Register_1 := (Bit => True, others => False);
|
>>> dynamic or empty choice in aggregate must be the only choice
which is a reference to ARM 4.3.3(17),
The discrete_choice_list of an array_component_association is allowed to have a discrete_choice that is a nonstatic choice_expression or that is a subtype_indication or range that defines a nonstatic or null range, only if it is the single discrete_choice of its discrete_choice_list, and there is only one array_component_association in the array_aggregate.
I can work round this,
procedure Set_Bit (Bit : Bit_Number) is
begin
declare
B : Bits_1 := (others => False);
begin
B (Bit) := True;
Register_1 := B;
end;
... ad nauseam
end Set_Bit;
but this seems very clumsy! Any other suggestions?
Does it have to be an array?
An alternative could be:
with Interfaces;
procedure Set_Bit is
Register : Interfaces.Unsigned_32;
begin
for J in 0..31 loop
Register := 2**J;
end loop;
end Set_Bit;
I think that this can be a little cumbersome , but if you need an array you could initialize it as a whole using concatenated sliced aggregates:
for J in 0 .. 31 loop
Register := Bits'(others => False)(0..J-1) &
True & Bits'(others => False)(J+1..31);
end loop;
It looks like a candidate for a function:
function Single_Bit (Set : in Bit_Number) return Bits_1 is
begin
return Result : Bits_1 := (others => False) do
Result (Set) := True;
end return;
end Single_Bit;
And then:
Register_1 := Single_Bit (Set => Some_Bit);
Register_2 := Single_Bit (Set => Another_Bit);
Example 1
This uses the Shift_Left operation.
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces; use Interfaces;
procedure Main_Test is
function One_Bit (Index : Natural) return Unsigned_32 is (Shift_Left (1, Index));
type Bit_Array_32_Index is range 0 .. 31;
type Bit_Array_17_Index is range 0 .. 16;
type Bit_Array_32 is array (Bit_Array_32_Index) of Boolean with Component_Size => 1, Size => 32;
type Bit_Array_17 is array (Bit_Array_17_Index) of Boolean with Component_Size => 1, Size => 17;
-- For every new array type instantiate a convert function.
function Convert is new Ada.Unchecked_Conversion (Unsigned_32, Bit_Array_32);
function Convert is new Ada.Unchecked_Conversion (Unsigned_32, Bit_Array_17);
B32 : Bit_Array_32 with Volatile;
B17 : Bit_Array_17 with Volatile;
begin
B17 := Convert (One_Bit (2)) or Convert (One_Bit (5));
B32 := Convert (One_Bit (2) or One_Bit (5));
for E of B17 loop
Put (Boolean'Pos (E), 1);
end loop;
New_Line;
for E of B32 loop
Put (Boolean'Pos (E), 1);
end loop;
end;
Result
00100100000000000
00100100000000000000000000000000
Warnings
main.adb:21:04: warning: types for unchecked conversion have different sizes
main.adb:21:04: warning: size of "Unsigned_32" is 32, size of "Bit_Array_17" is 17
main.adb:21:04: warning: 15 high order bits of source will be ignored
Example generics
This uses the Shift_Left operation but with generics.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces; use Interfaces;
procedure Main is
package Unsigned_32_IO is new Ada.Text_IO.Modular_IO (Unsigned_32);
type Bit_Array_32_Index is range 0 .. 31;
type Bit_Array_17_Index is range 0 .. 16;
type Bit_Array_32 is array (Bit_Array_32_Index) of Boolean with Component_Size => 1, Size => 32;
type Bit_Array_17 is array (Bit_Array_17_Index) of Boolean with Component_Size => 1, Size => 32;
generic
type I is (<>);
type T is array (I) of Boolean;
procedure Generic_Put (Item : T; Width : Field; Base : Number_Base);
procedure Generic_Put (Item : T; Width : Field; Base : Number_Base) is
function Convert_To_Unsigned_32 is new Ada.Unchecked_Conversion (T, Unsigned_32);
begin
Unsigned_32_IO.Put (Convert_To_Unsigned_32 (Item), Width, Base);
end;
generic
type I is (<>);
type T is array (I) of Boolean;
function Generic_Shift_Left (Value : Unsigned_32; Amount : Natural) return T;
function Generic_Shift_Left (Value : Unsigned_32; Amount : Natural) return T is
function Convert_To_Bit_Array_32 is new Ada.Unchecked_Conversion (Unsigned_32, T);
begin
return Convert_To_Bit_Array_32 (Interfaces.Shift_Left (Value, Amount));
end;
function Shift_Left is new Generic_Shift_Left (Bit_Array_32_Index, Bit_Array_32);
function Shift_Left is new Generic_Shift_Left (Bit_Array_17_Index, Bit_Array_17);
procedure Put is new Generic_Put (Bit_Array_32_Index, Bit_Array_32);
procedure Put is new Generic_Put (Bit_Array_17_Index, Bit_Array_17);
B32 : Bit_Array_32 with Volatile;
B17 : Bit_Array_17 with Volatile;
begin
B32 := Shift_Left (1, 2) or Shift_Left (1, 5);
B17 := Shift_Left (1, 2) or Shift_Left (1, 5);
Put (B17, 0, 2);
New_Line;
Put (B32, 0, 2);
end;
Result
2#100100#
2#100100#
gprbuild -v
GPRBUILD GPL 2015 (20150428) (i686-pc-mingw32)
Questions
Does it work on big-endian machine?
I haven't tested. See does bit-shift depend on endianness?

VHDL RS-232 Receiver

I have been trying to design an RS-232 receiver taking an FSM approach. I will admit that I do not have a very well-rounded understanding of VHDL, so I have been working on the code on the fly and learning as I go. However, I believe I've hit a brick wall at this point.
My issue is that I have two processes in my code, one to trigger the next state and the other to perform the combinational logic. My code is as follows:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ASyncReceiverV4 is
Port ( DataIn : in STD_LOGIC;
Enable : in STD_LOGIC;
CLK : in STD_LOGIC;
BadData : out STD_LOGIC;
DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end ASyncReceiverV4;
architecture Behavioral of ASyncReceiverV4 is
type states is (StartBitCheck, ReadData, StopBitCheck);
signal currentState, nextState : states;
begin
process(CLK)
begin
if rising_edge(CLK) then
currentState <= nextState;
end if;
end process;
process(CLK)
variable counter : integer := 0;
variable dataIndex : integer := 0;
begin
case currentState is
when StartBitCheck =>
if Enable = '1' then
if (DataIn = '0' and counter < 8) then
counter := counter + 1;
elsif (DataIn = '0' and counter = 8) then
BadData <= '0';
nextState <= ReadData;
counter := 0;
else
nextState <= StartBitCheck;
end if;
end if;
when ReadData =>
if Enable = '1' then
if counter < 16 then
counter := counter + 1;
elsif (counter = 16 and dataIndex < 8) then
DataOut(dataIndex) <= DataIn;
counter := 0;
dataIndex := dataIndex + 1;
elsif dataIndex = 8 then
dataIndex := 0;
nextState <= StopBitCheck;
else
nextState <= ReadData;
end if;
end if;
when StopBitCheck =>
if Enable = '1' then
if DataIn = '1' then
if counter < 16 then
counter := counter + 1;
nextState <= StopBitCheck;
elsif counter = 16 then
counter := 0;
nextState <= StartBitCheck;
end if;
else
DataOut <= "11111111";
BadData <= '1';
nextState <= StartBitCheck;
end if;
end if;
end case;
end process;
end Behavioral;
For whatever reason, based on my simulations, it seems that my processes are out of sync. Although things are only supposed to occur at the rising edge of the clock, I have transitions occurring at the falling edge. Furthermore, it seems like things are not changing according to the value of counter.
The Enable input is high in all of my simulations. However, this is just to keep it simple for now, it will eventually be fed the output of a 153,600 Baud generator (the Baud generator will be connected to the Enable input). Hence, I only want things to change when my Baud generator is high. Otherwise, do nothing. Am I taking the right approach for that with my code?
I can supply a screenshot of my simulation if that would be helpful. I am also not sure if I am including the correct variables in my process sensitivity list. Also, am I taking the right approach with my counter and dataIndex variables? What if I made them signals as part of my architecture before any of my processes?
Any help on this would be very much so appreciated!
The easiest way to fix this, while also producing the easiest to read code, would be to move to a 1-process state machine like so (warning: not complied may contain syntax errors):
entity ASyncReceiverV4 is
Port ( DataIn : in STD_LOGIC;
Enable : in STD_LOGIC;
CLK : in STD_LOGIC;
BadData : out STD_LOGIC;
DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end ASyncReceiverV4;
architecture Behavioral of ASyncReceiverV4 is
type states is (StartBitCheck, ReadData, StopBitCheck);
signal state : states := StartBitCheck;
signal counter : integer := 0;
signal dataIndex : integer := 0;
begin
process(CLK)
begin
if rising_edge(CLK) then
case state is
when StartBitCheck =>
if Enable = '1' then
if (DataIn = '0' and counter < 8) then
counter <= counter + 1;
elsif (DataIn = '0' and counter = 8) then
BadData <= '0';
state <= ReadData;
counter <= 0;
end if;
end if;
when ReadData =>
if Enable = '1' then
if counter < 16 then
counter <= counter + 1;
elsif (counter = 16 and dataIndex < 8) then
DataOut(dataIndex) <= DataIn;
counter <= 0;
dataIndex <= dataIndex + 1;
elsif dataIndex = 8 then
dataIndex <= 0;
state <= StopBitCheck;
end if;
end if;
when StopBitCheck =>
if Enable = '1' then
if DataIn = '1' then
if counter < 16 then
counter <= counter + 1;
elsif counter = 16 then
counter <= 0;
state <= StartBitCheck;
end if;
else
DataOut <= "11111111";
BadData <= '1';
state <= StartBitCheck;
end if;
end if;
end case;
end if;
end process;
end Behavioral;
Note that while this no longer contains language issues, there are still odd things in the logic.
You cannot enter the state StopBitCheck until counter is 16 because the state transition is in an elsif of counter < 16. Therefore, the if counter < 16 in StopBitCheck is unreachable.
Also note that the state transition to StopBitCheck happens on the same cycle that you would normally sample data, so the sampling of DataIn within StopBitCheck will be a cycle late. Worse, were you ever to get bad data (DataIn/='1' in StopBitCheck), counter would still be at 16, StartBitCheck would always go to the else clause, and the state machine would lock up.
Some more explanation on what was wrong before:
Your simulation has things changing on the negative clock edge because your combinatorial process only has the clock on the sensitivity list. The correct sensitivity list for the combinatorial process would include only DataIn, Enable, currentState, and your two variables, counter and dataIndex. Variables can't be a part of your sensitivity list because they are out of scope for the sensitivity list (also you do not want to trigger your process off of itself, more on that in a moment).
The sensitivity list is, however, mostly just a crutch for simulators. When translated to real hardware, processes are implemented in LUTs and Flip Flops. Your current implementation will never synthesize because you incorporate feedback (signals or variables that get assigned a new value as a function of their old value) in unclocked logic, producing a combinatorial loop.
counter and dataIndex are part of your state data. The state machine is simpler to understand because they are split off from the explicit state, but they are still part of the state data. When you make a two process state machine (again, I recommend 1 process state machines, not 2) you must split all state data into Flip Flops used to store it (such as currentState) and the output of the LUT that generates the next value (such as nextState). This means that for your two process machine, the variables counter and dataIndex must instead become currentCounter, nextCounter, currentDataIndex, and nextDataIndex and treated like your state assignment. Note that if you choose to implement changes to keep a 2-process state machine, the logic errors mentioned above the line will still apply.
EDIT:
Yes, resetting the counter back to 0 before moving into StopBitCheck might be a good idea, but you also need to consider that you are waiting the full 16 counts after sampling the last data bit before you even transition into StopBitCheck. It is only because counter is not reset that the sample is only off by one clock instead of 16. You may want to modify your ReadData action to transition to StopBitCheck as you sample the last bit when dataIndex=7 (as well as reset counter to 0) like so:
elsif (counter = 16) then
DataOut(dataIndex) <= DataIn;
counter <= 0;
if (dataIndex < 7) then
dataIndex <= dataIndex + 1;
else
dataIndex <= 0;
state <= StopBitCheck;
end if;
end if;
A pure state machine only stores a state. It generates its output purely from the state, or from a combination of the state and the inputs. Because counter and dataIndex are stored, they are part of the state. If you wanted to enumerate every single state you would have something like:
type states is (StartBitCheck_Counter0, StartBitCheck_counter1...
and you would end up with 8*16*3 = 384 states (actually somewhat less because only ReadData uses dataIndex, so some of the 384 are wholly redundant states). As you can no doubt see, it is much simpler to just declare 3 separate signals since the different parts of the state data are used differently. In a two process state machine, people often forget that the signal actually named state isn't the only state data that needs to be stored in the clocked process.
In a 1-process machine, of course, this isn't an issue because everything that is assigned is by necessity stored in flip flops (the intermediary combinational logic isn't enumerated in signals). Also, do note that 1-process state machines and 2-process state machines will synthesize to the same thing (assuming they were both implemented correctly), although I'm of the opinion that is comparatively easier to read and more difficult to mess up a 1-process machine.
I also removed the else clauses that maintained the current state assignment in the 1-process example I provided; they are important when assigning a combinational nextState, but the clocked signal state will keep its old value whenever it isn't given a new assignment without inferring a latch.
First Process runs just on CLK rising edge, while the second one runs on both CLK edge (because runs on every CLK change).
You use 2 process, “memory-state” and “next-state builder”, the first must be synchronous (as you done) and the second, normally, is combinatorial to be able to produce next-state in time for next CLK active edge.
But in your case the second process needs also to run on every CLK pulse (because of variable counter and index), so the solution can be to run the first on rising-edge and the second on falling-edge (if your hardware support this).
Here is your code a little bit revisited, I hope can be useful.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ASyncReceiverV4 is
Port ( DataIn : in STD_LOGIC;
Enable : in STD_LOGIC;
CLK : in STD_LOGIC;
BadData : out STD_LOGIC := '0';
DataOut : out STD_LOGIC_VECTOR (7 downto 0) := "00000000");
end ASyncReceiverV4;
architecture Behavioral of ASyncReceiverV4 is
type states is (StartBitCheck, ReadData, StopBitCheck);
signal currentState : states := StartBitCheck;
signal nextState : states := StartBitCheck;
begin
process(CLK)
begin
if rising_edge(CLK) then
currentState <= nextState;
end if;
end process;
process(CLK)
variable counter : integer := 0;
variable dataIndex : integer := 0;
begin
if falling_edge(CLK) then
case currentState is
when StartBitCheck =>
if Enable = '1' then
if (DataIn = '0' and counter < 8) then
counter := counter + 1;
elsif (DataIn = '0' and counter = 8) then
BadData <= '0';
nextState <= ReadData;
counter := 0;
else
nextState <= StartBitCheck;
end if;
end if;
when ReadData =>
if Enable = '1' then
if counter < 15 then
counter := counter + 1;
elsif (counter = 15 and dataIndex < 8) then
DataOut(dataIndex) <= DataIn;
counter := 0;
dataIndex := dataIndex + 1;
elsif dataIndex = 8 then
dataIndex := 0;
nextState <= StopBitCheck;
else
nextState <= ReadData;
end if;
end if;
when StopBitCheck =>
if Enable = '1' then
if DataIn = '1' then
if counter < 15 then
counter := counter + 1;
nextState <= StopBitCheck;
elsif counter = 15 then
counter := 0;
nextState <= StartBitCheck;
end if;
else
DataOut <= "11111111";
BadData <= '1';
nextState <= StartBitCheck;
end if;
end if;
end case;
end if;
end process;
end Behavioral;
This is a 0x55 with wrong stop bit receive data simulation

How to resolve "Error 200: Division by zero"?

I've FreeDos OS installed on VirtualBox on a windows xp, dual core, host machine. I installed FreeDos because I wanted to run a Pascal code using Turbo Pascal. When I run the code, it throws error 'Error 200: Division by zero.'. How can I solve this?
-Turbo Pascal 7.0, Free DOS 1.1, Virtual Box 4.3.6, Windows XP Service Pack 3 Host machine
-This error is unfortunately caused by fast Pentium CPUs and I found a patch on the internet that will resolve the error. (www.filewatcher.com/m/bp7patch.zip.62550-0.html) Now the other problem is, when i was tracing the code, it hangs at 'RxWait procedure when trying to execute while not odd(port[RXTX + 5]) do;'
uses crt;
const
{ COM1: RS232 port address }
RXTX = $3F8; { $2F8 if COM2: is used }
ACK = 6;
NAK = 21;
ESC = 27;
var
dummy,
checkSum : integer;
key : char;
protocol : integer;
procedure InitComm;
{ Set baudrate to 9600, 8 bits, no parity, 1 stop bit }
var i : integer;
begin
i := 1843200 div 9600 div 16;
port[RXTX + 3] := $80;
port[RXTX + 1] := hi(i);
port[RXTX]:= lo(i);
port[RXTX + 3] := 3;
port[RXTX + 4] := $A;
while odd(port[RXTX + 5]) do
begin
dummy := port[RXTX];
delay(10);
end;
end; { InitComm }
procedure Tx(data : integer);
{ Transmit a character on serial channel }
begin
while port[RXTX + 5] and $20 = 0 do;
port[RXTX] := data and $FF;
end; { Tx }
function RxWait : integer;
{ Waits for a character from serial channel }
begin
while not odd(port[RXTX + 5]) do;
RxWait := port[RXTX];
end; { RxWait }
procedure Tx2(data : integer);
{ Transmit a char on serial channel + Calculate check sum }
begin
Tx(data);
checkSum := (checkSum + data) and $FF;
end; { Tx2 }
procedure TxCommand(c1, c2 : char;
sendCheckSum : boolean);
{ Transmit command (no data) on serial channel }
begin
Tx(ESC);
checkSum := 0;
Tx2(ord(c1));
Tx2(ord(c2));
if sendCheckSum then
begin
Tx2(checkSum);
dummy := RxWait;
end;
end; { TxCommand }
function ReadNumber(n : integer) : real;
{ Read n bytes from serial channel }
var
number: real;
i : integer;
begin
number := 0;
checkSum := 0;
for i := 1 to n do
number := number * 256 + RxWait;
dummy := RxWait;
ReadNumber := number;
end; { ReadNumber }
procedure Revisions;
var
tmp : integer;
sw,
prot : real;
begin
TxCommand('P', 'R', FALSE);
checkSum := 0;
tmp := RxWait;
sw := tmp + RxWait / 100.0;
protocol := RxWait;
prot := protocol + RxWait / 100.0;
dummy := RxWait;
tmp := RxWait;
writeln('Software revision: ', sw:4:2);
writeln('Protocol revision: ', prot:4:2);
end; { Revisions }
procedure ReadCountReg;
begin
TxCommand('R', 'C', FALSE);
writeln(ReadNumber(4):11:0, ' coins counted.');
dummy := RxWait;
end; { ReadCountReg }
procedure ReadAccReg;
begin
TxCommand('R', 'A', FALSE);
writeln(ReadNumber(4):11:0, ' coins in accumulator.');
dummy := RxWait;
end; { ReadAccReg }
procedure Setbatch(limit : longint);
begin
TxCommand('W', 'L', FALSE);
case protocol of
1 : begin
Tx2(limit div 256);
Tx2(limit mod 256);
end;
2 : begin
Tx2( limit div 16777216);
Tx2((limit div 65536) mod 256);
Tx2((limit div 256) mod 256);
Tx2( limit mod 256);
end;
end; { case protocol }
Tx2(checkSum);
dummy := RxWait;
end; { Setbatch }
As far as I remember (more than 12 years ago), CRT unit had problems about Pentium CPUs and giving that division by zero error. I was using Turbo Pascal 7 those days. What I mean is that it may not be your coding error, but just CRT unit itself.
Old question I know, but there is another way to write Turbo Pascal code without incurring the wrath of the infamous RTE 200 bug. FreePascal (www.freepascal.org) is fully TP7 compatible and runs under a number of OSes including DOS, Windows and Linux.
Hope this helps!
I solved it setting the Execution Cap to 20%. So the processor is probably as slower as expected in those days. You can play with percentages until the error disappear
Regards

Resources