Hi,
I have been tasked to simulate a digital circuit with gates as tasks and wires as channels (rendezvous). I tried to make it as general as possible, with an arbitrary number of inputs and outputs. This works (as far the baby test is concerned):
pragma Ada_2022;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main2 is
package Circuits is
type BoolArray is array (Positive range <>) of Boolean with Pack;
function FnNot (Arr: BoolArray) return Boolean is (not Arr(1));
function FnOr (Arr: BoolArray) return Boolean is (Arr(1) or Arr(2));
function FnXOr (Arr: BoolArray) return Boolean is (Arr(1) xor Arr(2));
function FnAnd (Arr: BoolArray) return Boolean is (Arr(1) and Arr(2));
function FnNor (Arr: BoolArray) return Boolean is (not Arr(1) and not Arr(2));
type GateType is task interface;
procedure Enter (T: GateType; V: Boolean) is abstract;
type Circuit is array (Positive range <>) of access constant GateType'Class;
task type Gates
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit; Size: Positive) is new GateType with
entry Enter (V: Boolean);
end Gates;
task type EndGate (Size: Positive) is new GateType with
entry Enter (V: Boolean);
entry GiveResult (R: out BoolArray);
end EndGate;
function MakeGate
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit; Size: Positive) return Gates'Class;
function MakeEndgate (Size: Positive) return EndGate'Class;
end Circuits;
package body Circuits is
task body Gates is
InputArray: BoolArray (1..Nentries);
Index: Natural range 0..Nentries := 1;
begin
for S in 1..Size loop
for I in InputArray'Range loop
accept Enter (V: Boolean) do
InputArray (Index) := V;
end Enter;
end loop;
Index := 1;
for A of OutputCircuit.all loop
A.Enter(Func(InputArray));
end loop;
end loop;
end Gates;
task body EndGate is
Result: BoolArray (1..Size);
IndexR: Natural range 0..Size := 0;
begin
for S in 1..Size loop
accept Enter (V: Boolean) do
IndexR := @ + 1;
Result (IndexR) := V;
end Enter;
end loop;
accept GiveResult (R: out BoolArray) do
R := Result;
end GiveResult;
end EndGate;
function MakeGate
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit;
Size: Positive) return Gates'Class is
begin
return G: Gates (Nentries, Func,OutputCircuit,Size);
end MakeGate;
function MakeEndGate (Size: Positive) return EndGate'Class is
begin
return G: EndGate (Size);
end MakeEndGate;
end Circuits;
use Circuits;
theEnd: aliased EndGate(1);
OrGate: Gates (2, FnOr'Access, new Circuit'([theEnd'Access]), 1);
theTable : BoolArray (1..1);
begin
for I in 1..2 loop
OrGate.Enter(Boolean'Val(I-1));
end loop;
EndGate(theEnd).GiveResult (theTable);
Put_line(theTable'Image);
end Main2;
but if I make the tasks class-wide objects, they fail without starting (not reaching “begin”), and I get raised TASKING_ERROR : s-tasren.adb:377which I read usually denotes elaboration concerns, which I can’t understand since no task is created through an allocator.
pragma Ada_2022;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main2 is
package Circuits is
type BoolArray is array (Positive range <>) of Boolean with Pack;
function FnNot (Arr: BoolArray) return Boolean is (not Arr(1));
function FnOr (Arr: BoolArray) return Boolean is (Arr(1) or Arr(2));
function FnXOr (Arr: BoolArray) return Boolean is (Arr(1) xor Arr(2));
function FnAnd (Arr: BoolArray) return Boolean is (Arr(1) and Arr(2));
function FnNor (Arr: BoolArray) return Boolean is (not Arr(1) and not Arr(2));
type GateType is task interface;
procedure Enter (T: GateType; V: Boolean) is abstract;
type Circuit is array (Positive range <>) of access constant GateType'Class;
task type Gates
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit; Size: Positive) is new GateType with
entry Enter (V: Boolean);
end Gates;
task type EndGate (Size: Positive) is new GateType with
entry Enter (V: Boolean);
entry GiveResult (R: out BoolArray);
end EndGate;
function MakeGate
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit; Size: Positive) return Gates'Class;
function MakeEndgate (Size: Positive) return EndGate'Class;
end Circuits;
package body Circuits is
task body Gates is
InputArray: BoolArray (1..Nentries);
Index: Natural range 0..Nentries := 1;
begin
for S in 1..Size loop
for I in InputArray'Range loop
accept Enter (V: Boolean) do
InputArray (Index) := V;
end Enter;
end loop;
Index := 1;
for A of OutputCircuit.all loop
A.Enter(Func(InputArray));
end loop;
end loop;
end Gates;
task body EndGate is
Result: BoolArray (1..Size);
IndexR: Natural range 0..Size := 0;
begin
for S in 1..Size loop
accept Enter (V: Boolean) do
IndexR := @ + 1;
Result (IndexR) := V;
end Enter;
end loop;
accept GiveResult (R: out BoolArray) do
R := Result;
end GiveResult;
end EndGate;
function MakeGate
(Nentries: Positive;
Func: access function (A: BoolArray) return Boolean;
OutputCircuit: access constant Circuit;
Size: Positive) return Gates'Class is
begin
return G: Gates (Nentries, Func,OutputCircuit,Size);
end MakeGate;
function MakeEndGate (Size: Positive) return EndGate'Class is
begin
return G: EndGate (Size);
end MakeEndGate;
end Circuits;
use Circuits;
theEnd: aliased GateType'Class := MakeEndGate (1);
OrGate: GateType'Class := MakeGate (2, FnOr'Access, new Circuit'([theEnd'Access]), 1);
theTable : BoolArray (1..1);
begin
for I in 1..2 loop
OrGate.Enter(Boolean'Val(I-1));
end loop;
EndGate(theEnd).GiveResult (theTable);
Put_line(theTable'Image);
end Main2;