I am trying to retrieve data from an array of records constant. This is what i have in my current implementation:
CONSTANT Total_Feeds : INTEGER := 12;
TYPE Feed IS RECORD
s_Divisor : INTEGER RANGE 0 TO 255;
Display_Text : STRING(1 TO 8);
END RECORD Feed;
TYPE Feed_Array IS ARRAY (0 TO Total_Feeds -1) OF Feed;
CONSTANT FEED_INFO : Feed_Array := (
(225,"""0.02mm"""),
(112,"""0.04mm"""),
(75,"""0.06mm"""),
(56,"""0.08mm"""),
(45,"""0.10mm"""),
(38,"""0.12mm"""),
(32,"""0.14mm"""),
(28,"""0.16mm"""),
(25,"""0.18mm"""),
(23,"""0.20mm"""),
(20,"""0.22mm"""),
(19,"""0.24mm""")
);
------lower section of menu fsm----------
process(clk, reset)
begin
if (reset = '1') then
menu_pr <= start;
feed_index_pr <= 2;
ks_divisor_pr <= 0;
elsif (rising_edge(clk)) then
menu_pr <= menu_nx;
feed_index_pr <= feed_index_nx;
ks_divisor_pr <= ks_divisor_nx;
end if;
end process;
------upper section of menu fsm----------
process (menu_pr, menu_on_flag, delayed_select, delayed_up,
delayed_down, delayed_left, feed_index_pr, thread_index_pr,
delayed_right, menu_left_flag, menu_right_flag, menu_up_flag, menu_down_flag)
variable feedindex : integer range 0 to total_feeds;
begin
case menu_pr is
when start =>
feedindex := feed_index_pr;
feed_index_nx <= feedindex;
ks_divisor_nx <= FEED_INFO(feedindex).s_Divisor;
menu_nx <= feed_left;
when feed_left =>
feedindex := feed_index_pr;
feed_index_nx <= feedindex;
ks_divisor_nx <= FEED_INFO(feedindex).s_Divisor;
if (menu_on_flag = '1' and delayed_right = '1' and menu_right_flag = '1') then
menu_nx <= feed_left_right;
else
menu_nx <= feed_left;
end if;
when feed_left_right =>
feedindex := feed_index_pr + 1;
if (feedindex > (Total_Feeds - 1)) then
feedindex := 0;
feed_index_nx <= feedindex;
ks_divisor_nx <= FEED_INFO(feedindex).s_Divisor;
menu_nx <= feed_left;
else
feed_index_nx <= feedindex;
ks_divisor_nx <= FEED_INFO(feedindex).s_Divisor;
menu_nx <= feed_left;
end if;
end case;
end process;
rate_out <=ks_divisor_pr;
States are added after successful verification with simulation.
I'm trying to get the s_divisor for each record from a process using the following command:
ks_divisor_nx <= FEED_INFO(feedindex).s_Divisor;
Where feedindex changes from 0 to Total_Feeds -1, and ks_divisor is integer range 0 to 255.
Simulation results show correct output for all assignments except for the records with index 0, 1, and 2. Simulation output shows values: 11, 48, and 33 respectively.
simulation results
Any help is greatly appreciated.
Thanks.
Good time to everyone.
Resently I try to improve code in new project and found some interesting decoder.
It has 2 processes: in first all data formed and in second all bus triggered in out registers by control signal. But some wires need to be reset in some period of time (in second process).
So I deside to write this code for correct resettind some signals ([cm_regA/cm_regB] are records with different types of data):
----------------------------------------
LOAD_DATA_PROCESS: process(clk_i)
begin
if rising_edge(clk_i) then
if (reset_reg) then
cm_regB.reg_1 <= '0';
cm_regB.reg_2 <= '0';
cm_regB.reg_3 <= '0';
cm_regB.reg_4 <= '0';
else
if (load_reg) then
cm_regB <= cm_regA;
else null;
end if;
end if;
end if;
end process;
----------------------------------------
But this construction Synthesized with lot of multiplexers betwen reg_5...reg_10, so next code give me good synthesized construction and great speed:
----------------------------------------
LOAD_DATA_PROCESS: process(clk_i)
begin
if rising_edge(clk_i) then
if (reset_reg) then
cm_regB.reg_1 <= '0';
cm_regB.reg_2 <= '0';
cm_regB.reg_3 <= '0';
cm_regB.reg_4 <= '0';
else
if (load_reg) then
cm_regB.reg_1 <= cm_regA.reg_1;
cm_regB.reg_2 <= cm_regA.reg_2;
cm_regB.reg_3 <= cm_regA.reg_3;
cm_regB.reg_4 <= cm_regA.reg_4;
else null;
end if;
end if;
if (load_reg) then
cm_regB.reg_5 <= cm_regA.reg_5;
cm_regB.reg_6 <= cm_regA.reg_6;
cm_regB.reg_7 <= cm_regA.reg_7;
cm_regB.reg_8 <= cm_regA.reg_8;
cm_regB.reg_9 <= cm_regA.reg_9;
cm_regB.reg_10 <= cm_regA.reg_10;
else null;
end if;
end if;
end process;
----------------------------------------
So the questions next:
How make this construction more compact (like first example)?
Or how to make any changes in buses [cm_regA/cm_regB] visible for second example (in case changing first process and forgot add this changes to LOAD_DATA_PROCESS)?
P.S. Type of cm_regA and cm_regB are declarated in package. Here it is:
----------------------------------------
type cm_t is record
reg_1 : STD_LOGIC;
reg_2 : STD_LOGIC;
reg_3 : STD_LOGIC;
reg_4 : STD_LOGIC;
reg_5 : STD_LOGIC;
reg_6 : BOOLEAN;
reg_7 : STD_LOGIC;
reg_8 : STD_LOGIC;
reg_9 : STD_LOGIC_VECTOR(CONST_1-1 downto 0);
reg_10 : STD_LOGIC_VECTOR(CONST_2-1 downto 0);
end record cm_t;
----------------------------------------
In the case of your first code, you are indeed adding a dependency to reset for reg_5 to reg_10. This is because of the if-else statement. This is the effective code you write for these registers.
if not(reset_reg) and load_reg then
cm_regB.reg_5 <= cm_regA.reg_5;
[...]
cm_regB.reg_10 <= cm_regA.reg_10;
end if;
So, you should separate the reset block from the other assignment. You can achieve that by using the fact that for signals only the last assignment in a process will be applied the next delta cycle. So something like this:
LOAD_DATA_PROCESS: process(clk_i)
begin
if rising_edge(clk_i) then
if load_reg then
cm_regB <= cm_regA;
end if;
if reset_reg then
cm_regB.reg_1 <= '0';
cm_regB.reg_2 <= '0';
cm_regB.reg_3 <= '0';
cm_regB.reg_4 <= '0';
end if;
end if;
end process;
For a project, I need to read a name inside a TrueType font file (.ttf). I written a code to do that, inspirated from a c++ example. Here is the code:
TWByteArray = array of Byte;
TWAnsiCharArray = array of AnsiChar;
...
//---------------------------------------------------------------------------
class function TWStringHelper.ByteToStr(const bytes: TWByteArray): string;
begin
SetLength(Result, Length(bytes));
if Length(Result) > 0 then
Move(bytes[0], Result[1], Length(bytes));
end;
//---------------------------------------------------------------------------
class function TWStringHelper.UniStrToByte(const str: UnicodeString): TWByteArray;
begin
SetLength(Result, Length(str) * SizeOf(WideChar));
if (Length(Result) > 0) then
Move(str[1], Result[0], Length(Result));
end;
//---------------------------------------------------------------------------
class function TWStringHelper.BytesToUniStr(const bytes: TWByteArray): UnicodeString;
begin
SetLength(Result, Length(bytes) div SizeOf(WideChar));
if Length(Result) > 0 then
Move(bytes[0], Result[1], Length(bytes));
end;
//---------------------------------------------------------------------------
...
//---------------------------------------------------------------------------
class function TWControlFont.SwapWord(value: Word): Word;
begin
Result := MakeWord(HiByte(value), LoByte(value));
end;
//---------------------------------------------------------------------------
class function TWControlFont.SwapLong(value: LongInt): LongInt;
begin
Result := MakeLong(SwapWord(HiWord(value)), SwapWord(LoWord(value)));
end;
//---------------------------------------------------------------------------
class function TWControlFont.GetFontNameFromFile(const fileName: UnicodeString): UnicodeString;
var
pFile: TFileStream;
offsetTable: ITTFOffsetTable;
dirTable: ITTFDirectoryTable;
nameHeader: ITTFNameTableHeader;
nameRecord: ITTFNameRecord;
nameBuffer: TWByteArray;//TWAnsiCharArray;
i: USHORT;
found: Boolean;
test2: string;
test3: UnicodeString;
test: Integer;
const name: array [0..3] of Byte = (Ord('n'), Ord('a'), Ord('m'), Ord('e'));
begin
// open font file
pFile := TFileStream.Create(fileName, fmOpenRead);
// succeeded?
if (not Assigned(pFile)) then
Exit;
try
pFile.Seek(0, soFromBeginning);
// read TTF offset table
if (pFile.Read(offsetTable, SizeOf(ITTFOffsetTable)) <> SizeOf(ITTFOffsetTable)) then
Exit;
offsetTable.m_NumOfTables := SwapWord(offsetTable.m_NumOfTables);
offsetTable.m_MajorVersion := SwapWord(offsetTable.m_MajorVersion);
offsetTable.m_MinorVersion := SwapWord(offsetTable.m_MinorVersion);
// is truetype font and version is 1.0?
if ((offsetTable.m_MajorVersion <> 1) or (offsetTable.m_MinorVersion <> 0)) then
Exit;
found := False;
// iterate through file tables
if (offsetTable.m_NumOfTables > 0) then
for i := 0 to offsetTable.m_NumOfTables - 1 do
begin
// read table
if (pFile.Read(dirTable, SizeOf(ITTFDirectoryTable)) <> SizeOf(ITTFDirectoryTable)) then
Exit;
// found name table?
if (CompareMem(#dirTable.m_Tag, #name, 4) = True) then
begin
found := True;
dirTable.m_Length := SwapLong(dirTable.m_Length);
dirTable.m_Offset := SwapLong(dirTable.m_Offset);
break;
end;
end;
// found name table?
if (not found) then
Exit;
// seek to name location
pFile.Position := dirTable.m_Offset;
// read name table header
if (pFile.Read(nameHeader, SizeOf(ITTFNameTableHeader)) <> SizeOf(ITTFNameTableHeader)) then
Exit;
nameHeader.m_NRCount := SwapWord(nameHeader.m_NRCount);
nameHeader.m_StorageOffset := SwapWord(nameHeader.m_StorageOffset);
// iterate through name records
if (nameHeader.m_NRCount > 0) then
for i := 0 to nameHeader.m_NRCount - 1 do
begin
// read name record
if (pFile.Read(nameRecord, SizeOf(ITTFNameRecord)) <> SizeOf(ITTFNameRecord)) then
Exit;
nameRecord.m_NameID := SwapWord(nameRecord.m_NameID);
// found font name?
if (nameRecord.m_NameID = 1) then
begin
// get font name length and offset
nameRecord.m_StringLength := SwapWord(nameRecord.m_StringLength);
nameRecord.m_StringOffset := SwapWord(nameRecord.m_StringOffset);
if (nameRecord.m_StringLength = 0) then
continue;
// calculate and seek to font name offset
pFile.Position := dirTable.m_Offset + nameRecord.m_StringOffset + nameHeader.m_StorageOffset;
try
SetLength(nameBuffer, nameRecord.m_StringLength + 1);
//REM FillChar(nameBuffer[0], nameRecord.m_StringLength + 1, $0);
// read font name from file
if (pFile.Read(nameBuffer[0], nameRecord.m_StringLength)
<> nameRecord.m_StringLength)
then
Exit;
nameBuffer[nameRecord.m_StringLength] := $0;
//OutputDebugString(PChar(nameBuffer));
//TWMemoryHelper.SwapBytes(nameBuffer[0], nameRecord.m_StringLength);
//OutputDebugString(PChar(nameBuffer));
//test := StringElementSize(RawByteString(#nameBuffer[0]));
//Result := TWStringHelper.BytesToUniStr(nameBuffer);
//Result := UnicodeString(AnsiString(TWStringHelper.ByteToStr(nameBuffer)));
//REM Result := UnicodeString(nameBuffer);
test2 := TWStringHelper.ByteToStr(nameBuffer);
OutputDebugStringA(PAnsiChar(test2));
test3 := UnicodeString(PAnsiChar(test2));
OutputDebugStringW(PWideChar(test3));
Result := test3;
OutputDebugStringW(PWideChar(test3));
finally
SetLength(nameBuffer, 0);
end;
break;
end;
end;
finally
pFile.Free;
end;
end;
//---------------------------------------------------------------------------
This code works well until the final part of the GetFontNameFromFile() function. There, things start to get complicated. Indeed, I'm unable to convert the nameBuffer byte array to a string in a correct manner.
The first problem I met is that the nameBuffer may be a simple ASCII string, or an UTF16 string, depend on file (I tried with the emoji.ttf available in FireFox, that returns an ASCII string, and Tahoma.ttf from my Win installation, that returns a UTF16 string). I need a way to determine that, and I don't know if there is a function or class in the VCL to do that.
The second problem is the conversion itself. The above code works more or less, but I feel that is not a correct solution. When I try to convert to an UnicodeString directly from nameBuffer, I get some strange crashes. If I try to convert nameBuffer to an AnsiString, the conversion seems success, however a conversion like UnicodeString(AnsiString(nameBuffer)) fails.
And the code seems to be full of memory issues. As I'm new with Delphi, I'm not very comfortable with the memory usage. For example, I suspect several issues with the byte array when I activate the
FillChar(nameBuffer[0], nameRecord.m_StringLength + 1, $0);
line.
So anybody can analyse this code and points me what I doing wrong?
Thanks in advance,
Regards
I have a function in ada which has to check a large array of booleans to return a (sparse) value. It is difficult to explain in words, so here's an 'ideal' solution that doesn't work in ada (note that I have more than 3 challenger types and tougher logic):
type ChallengerType is (Rock,Paper,Scissors,Suicide,None);
type Challengers is array (ChallengerType) of Boolean;
pragma Pack(Challengers);
-- NOT legal, challengers is not an enumeration type
matchups : array (Challengers) of ChallengerType := (
-- Single challenger victories
(Rock => True, others => False) => Rock,
(Paper => True, others => False) => Paper,
(Scissors => True, others => False) => Scissors,
-- Double challenger victories
(Rock => True, Paper => True, others => False) => Paper,
(Rock => True, Scissors => True, others => False) => Rock,
(Paper => True, Scissors => True, others => False) => Scissors,
-- All the rest either are ambiguous (RPS) or suicided
others => None)
This is not legal in Ada, so I went with the more c-style version where my array was of Integer range 0..2#11111# and wrote a converter. However the code becomes much less clean (EG: (2#00101# => Scissors) is not as clear).
What would be the 'best' way to implement such a matchup array?
Summary: I want a mapping from the power set of an enumeration type to one of its values. IE: if my enumeration was {A,B,C} I would want a mapping from {{},{A},{B},{C},{A,B},{A,C},{B,C},{A,B,C}} to {A,B,C}. I also know in advance that most of the values in the mapping will be the same type, so the others keyword would be very nice to use. Currently I use binary indexing with '1' meaning that the specified enum element is present, but I wish I could be more explicit.
A somewhat simpler answer uses the Vector type from the Ada.Containers.Vectors package:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
use Type Ada.Containers.Count_Type;
procedure Mapping_Vector is
type ChallengerType is (Rock,Paper,Scissors,Suicide,None);
type Challengers is array (ChallengerType) of Boolean with Pack;
package Challenge_Vect is new Ada.Containers.Vectors(Positive, ChallengerType);
use Challenge_Vect;
function Map_Challengers(Item : in Challengers) return Vector is
Result : Vector := Empty_Vector;
begin
for I in Item'Range loop
if Item(I) then
Result.Append(I);
end if;
end loop;
return Result;
end Map_Challengers;
Foo : Challengers := (Rock..Scissors => True, Others => False);
Mapped_Challengers : Vector := Map_Challengers(Foo);
begin
If Mapped_Challengers.Length > 0 then
for C of Mapped_Challengers loop
Put_Line(ChallengerType'Image(C));
end loop;
else
Put_Line("No challengers were TRUE");
end if;
end Mapping_Vector;
This is not a purely static solution, but it makes it possible to configure the mapping elegantly in terms of enumeration values, even if the mapping array in reality is indexed by a modular type:
Specification:
with Ada.Text_IO;
with Ada.Unchecked_Conversion;
generic
type Element_Type is (<>);
type Numeric_Type is mod <>;
package Set_With_Modular_Representation is
type Instance is array (Element_Type) of Boolean with Pack;
Empty_Set : constant Numeric_Type := 0;
E : Numeric_Type renames Empty_Set; -- Got a request not to use Ø.
function "&" (Left : in Instance;
Right : in Instance) return Numeric_Type;
function "&" (Left : in Numeric_Type;
Right : in Instance) return Numeric_Type;
function "&" (Left : in Element_Type;
Right : in Element_Type) return Numeric_Type;
function "&" (Left : in Numeric_Type;
Right : in Element_Type) return Numeric_Type;
private
pragma Assert (Numeric_Type'Modulus = 2 ** Instance'Size);
pragma Assert (Numeric_Type'Size = Instance'Size);
function Numeric is
new Ada.Unchecked_Conversion (Source => Instance,
Target => Numeric_Type);
function Numeric (Item : in Element_Type) return Numeric_Type;
end Set_With_Modular_Representation;
Implementation:
package body Set_With_Modular_Representation is
function "&" (Left : in Instance;
Right : in Instance) return Numeric_Type is
begin
return Numeric (Left) or Numeric (Right);
end "&";
function "&" (Left : in Numeric_Type;
Right : in Instance) return Numeric_Type is
begin
return Left or Numeric (Right);
end "&";
function "&" (Left : in Element_Type;
Right : in Element_Type) return Numeric_Type is
begin
return Numeric (Left) or Numeric (Right);
end "&";
function "&" (Left : in Numeric_Type;
Right : in Element_Type) return Numeric_Type is
begin
return Left or Numeric (Right);
end "&";
function Numeric (Item : in Element_Type) return Numeric_Type is
Buffer : Instance := (others => False);
begin
Buffer (Item) := True;
return Numeric (Buffer);
end Numeric;
end Set_With_Modular_Representation;
Demonstration:
with Ada.Command_Line;
with Ada.Text_IO;
with Set_With_Modular_Representation;
procedure Set_With_Modular_Representation_Demo is
type Outcomes is (Paper, Rock, Scissors, Suicide, None);
subtype Choices is Outcomes range Paper .. Scissors;
type Numeric_Choices is mod 2 ** 3;
package Choice_Set is
new Set_With_Modular_Representation (Element_Type => Choices,
Numeric_Type => Numeric_Choices);
use Choice_Set;
Mapping : array (Numeric_Choices) of Outcomes := (others => None);
begin
Set_Up_Mapping :
begin
-- Single challenger victories
Mapping (E & Rock) := Rock;
Mapping (E & Paper) := Paper;
Mapping (E & Scissors) := Scissors;
-- Double challenger victories
Mapping (Rock & Paper) := Paper;
Mapping (Rock & Scissors) := Rock;
Mapping (Paper & Scissors) := Scissors;
end Set_Up_Mapping;
Test :
declare
package Outcome_Text_IO is
new Ada.Text_IO.Enumeration_IO (Outcomes);
use Ada.Command_Line, Ada.Text_IO, Outcome_Text_IO;
Chosen : Numeric_Choices := E;
begin
for Index in 1 .. Argument_Count loop
Chosen := Chosen & Choices'Value (Argument (Index)); -- '
end loop;
Put ("Outcome: ");
Put (Mapping (Chosen));
New_Line;
end Test;
end Set_With_Modular_Representation_Demo;
NOT an answer... posting in case it helps someone see a way forward.
This expands on my comment above : as far as generating a discrete type from an array goes, it appears to work...
with Ada.Unchecked_Conversion;
package RPS is
type ChallengerType is (Rock,Paper,Scissors,Suicide,None);
for ChallengerType use (Rock => 1, Paper => 2,Scissors => 4,Suicide => 8,None => 16);
type Challengers is array (ChallengerType) of Boolean with Pack;
type Challengers_int is range 0 .. 31;
function IDX is new Ada.Unchecked_Conversion(Challengers, Challengers_int);
Rock_Only : constant Challengers := (Rock => True, others => False);
Rock_IDX : constant Challengers_int := IDX(Rock_Only);
matchups : constant array (Challengers_int) of ChallengerType := (
-- Single challenger victories
-- Rock_IDX => Rock, -- fails
1 => Rock,
IDX((Paper => True, others => False)) => Paper, -- fails
IDX((Scissors => True, others => False)) => Scissors,
-- Double challenger victories
IDX((Rock => True, Paper => True, others => False)) => Paper,
IDX((Rock => True, Scissors => True, others => False)) => Rock,
IDX((Paper => True, Scissors => True, others => False)) => Scissors,
-- All the rest either are ambiguous (RPS) or suicided
others => None);
end RPS;
However, it fails to compile, dynamic or empty choice in aggregate must be the only choice at either of the commented lines in the array - even if the index is a constant rather than an expression.
A Case statement fails similarly :
case IDX(C) is
when Rock_IDX => return Rock;
when IDX((Paper => True, others => False)) => return Paper;
...
compiler reports:
rps.adb:11:10: choice given in case statement is not static
rps.adb:11:10: "Rock_IDX" is not a static constant (RM 4.9(5))
rps.adb:12:10: choice given in case statement is not static
rps.adb:12:10: non-static function call (RM 4.9(6,18)) rps.adb:12:14:
static expression must have scalar or string type (RM 4.9(2))
Here is one solution:
with Ada.Text_IO; use Ada.text_IO;
procedure Mapping_Question is
type ChallengerType is (Rock,Paper,Scissors,Suicide,None);
type Challengers is array (ChallengerType range <>) of Boolean with Pack;
Type Mapped_Challenges is array(Positive range <>) of ChallengerType;
function Map_Challengers(Item : Challengers) return Mapped_Challenges is
function Mapper(Item : Challengers) return Mapped_Challenges is
Single : Mapped_Challenges(1..1);
begin
for I in Item'Range loop
if Item(I) then
if I < Item'Last then
return I & Mapper(Item(ChallengerType'Succ(I)..Item'Last));
else
Single(Single'First) := I;
return Single;
end if;
end if;
end loop;
Single(Single'First) := None;
return Single;
end Mapper;
begin
return Mapper(Item);
end Map_Challengers;
procedure Print_Challenges(Item : Mapped_Challenges) is
begin
for I in Item'Range loop
Put_Line(ChallengerType'Image(Item(I)));
end loop;
end Print_Challenges;
Foo : Challengers(Rock..None) := (Rock..Scissors => True, Others => False);
begin
declare
Mapping : Mapped_Challenges := Map_Challengers(Foo);
begin
if Mapping'Length > 1 then
Print_Challenges(Mapping(Mapping'First..Mapping'Last - 1));
else
Print_challenges(Mapping);
end if;
end;
end Mapping_Question;
The following approach uses currying of sorts. To further simplify the example, I have shortened the enumeration type to three values. The solution is static, but the “elegance” of using the enumeration values directly is gone. If a static constant is not needed, then, as other approaches show, constant function tables F and T from ChallengerType into Boolean will be a possibility, the named components then appearing as T (Paper) => ... etc.
pragma Pure (Rps);
type ChallengerType is (Rock,Paper,None);
type Challengers1 is array (Boolean) of Challengertype;
type Challengers2 is array (Boolean) of Challengers1;
type Challengers3 is array (Boolean) of Challengers2;
Matchups : constant Challengers3 :=
-- Rock:
(True => --> Paper:
(True => --> None:
(False => Paper,
True => None),
False => --> None:
(others => Rock)),
-- Rock:
False => --> Paper:
(True => --> None:
(False => Paper,
True => None),
False =>
(others => None))
);
Solution using constants
This is not an elegant solution but it may help as a part of a better solution.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with System;
with System.Unsigned_Types;
procedure Main is
subtype S is System.Unsigned_Types.Unsigned range 0 .. 31;
use type S;
function Shift_Left (Value : S; Amount : Natural) return S renames System.Unsigned_Types.Shift_Left;
Rock : constant S := Shift_Left (1, 0);
Paper : constant S := Shift_Left (1, 1);
Scissors : constant S := Shift_Left (1, 2);
Suicide : constant S := Shift_Left (1, 3);
None : constant S := Shift_Left (1, 4);
P : array (S) of S := (others => None);
begin
P (Rock or Paper) := Paper;
P (Rock or Scissors) := Rock;
P (Paper or Scissors) := Scissors;
Put_Line ("P(Paper or Scissors) = Scissors");
Put ("P(");
Put (Integer (Paper), 0, 2);
Put (" or ");
Put (Integer (Scissors), 0, 2);
Put (") = P(");
Put (Integer (Paper or Scissors), 0, 2);
Put (") = ");
Put (Integer (P (Paper or Scissors)), 0, 2);
Put ("");
end;
Result
P(Paper or Scissors) = Scissors
P(2#10# or 2#100#) = P(2#110#) = 2#100#
Solution using enumeration
with Ada.Text_IO; use Ada.Text_IO;
with System;
with System.Unsigned_Types;
procedure Main is
type T is (Rock, Paper, Scissors, Suicide, None);
subtype S is System.Unsigned_Types.Unsigned range 0 .. 31;
use type S;
function B (Value : T) return S is (System.Unsigned_Types.Shift_Left (1, T'Pos (Value)));
function "&" (Left : T; Right : T) return S is (System.Unsigned_Types."or" (B (Left), B (Right)));
P : array (S) of T := (others => None);
begin
P (Rock & Paper) := Paper;
P (Rock & Scissors) := Rock;
P (Paper & Scissors) := Scissors;
Put_Line (T'Image (P (Rock & Paper)));
Put_Line (T'Image (P (Rock & Scissors)));
Put_Line (T'Image (P (Paper & Scissors)));
end;
Result
PAPER
ROCK
SCISSORS
I have this warnig in my code for a FSM:
WARNING:Xst:2170 - Unit P22_MustangSecuentialTailLight_Structural : the following signal(s) form a combinatorial loop: Lights<5>, U1/next_state_cmp_eq0000, next_state_int<0>, pres_state_int<0>.
WARNING:Xst:2170 - Unit P22_MustangSecuentialTailLight_Structural : the following signal(s) form a combinatorial loop: Lights<4>, next_state_int<1>, pres_state_int<1>.
WARNING:Xst:2170 - Unit P22_MustangSecuentialTailLight_Structural : the following signal(s) form a combinatorial loop: next_state_int<2>, U1/next_state_cmp_eq0003, Lights<3>, pres_state_int<2>.
WARNING:Xst:2170 - Unit P22_MustangSecuentialTailLight_Structural : the following signal(s) form a combinatorial loop: next_state_int<3>, pres_state_int<4>, U1/next_state_cmp_eq0013, pres_state_int<3>, Lights<2>, next_state_int<4>.
Its for a loop made in the code, the image of my diagram
But that enbedded signal(pres_state_int) is necessary for update the next state logic block. The code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.States.all;
entity P22_MustangSecuentialTailLight_Structural is
Port ( Lturn : in STD_LOGIC;
Rturn : in STD_LOGIC;
Hazard : in STD_LOGIC;
Rst : in STD_LOGIC;
Break : in STD_LOGIC;
Clk100MHz : in STD_LOGIC;
Lights : out STD_LOGIC_VECTOR (5 downto 0));
end P22_MustangSecuentialTailLight_Structural;
architecture Behavioral of P22_MustangSecuentialTailLight_Structural is
component NextStateLogic
port (
BLRH : in STD_LOGIC_VECTOR (3 downto 0);
pres_state : in STD_LOGIC_VECTOR (4 downto 0);
next_state : out STD_LOGIC_VECTOR (4 downto 0));
end component;
component CurrentStateRegister
port (
pres_state_b : out STD_LOGIC_VECTOR (4 downto 0);
next_state_b : in STD_LOGIC_VECTOR (4 downto 0);
Rst : in STD_LOGIC;
Clk : in STD_LOGIC );
end component;
component OutputLogic
port (
pres_state_c : in STD_LOGIC_VECTOR (4 downto 0);
Lights : out STD_LOGIC_VECTOR (5 downto 0));
end component;
component Clk1Hz
port (
Rst : in STD_LOGIC;
Clk_in : in STD_LOGIC;
Clk_out : out STD_LOGIC);
end component;
--Embedded signal declaration
signal LRH_int : STD_LOGIC_VECTOR (3 downto 0);
signal next_state_int : state_values := ST0;
signal pres_state_int : state_values := ST0;
signal Clk1Hz_int : STD_LOGIC;
begin
LRH_int <= Break & Lturn & Rturn & Hazard;
U1 : NextStateLogic
port map(
BLRH => LRH_int,
pres_state => pres_state_int,
next_state => next_state_int
);
U2 : CurrentStateRegister
port map(
pres_state_b => pres_state_int,
next_state_b => next_state_int,
Rst => Rst,
Clk => Clk1Hz_int
);
U3 : OutputLogic
port map(
pres_state_c => pres_state_int,
Lights => Lights
);
U4 : Clk1Hz
port map(
Rst => Rst,
Clk_in => Clk100MHz,
Clk_out => Clk1Hz_int
);
end Behavioral;
Next is the package use for encoding the code:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package States is
subtype state_values is std_logic_vector(4 downto 0);
constant ST0: state_values := "00000";
constant ST1: state_values := "00001";
constant ST2: state_values := "00010";
constant ST3: state_values := "00011";
constant ST4: state_values := "00100";
constant ST5: state_values := "00101";
constant ST6: state_values := "00110";
constant ST7: state_values := "00111";
constant ST8: state_values := "01000";
constant ST9: state_values := "01001";
constant ST10: state_values := "01010";
constant ST11: state_values := "01011";
constant ST12: state_values := "01100";
constant ST13: state_values := "01101";
constant ST14: state_values := "01110";
constant ST15: state_values := "01111";
constant ST16: state_values := "10000";
signal pres_state, next_state: state_values;
end States;
NextStateLogic component code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.States.all;
entity NextStateLogic is
Port( BLRH : in STD_LOGIC_VECTOR (3 downto 0);
pres_state : in STD_LOGIC_VECTOR (4 downto 0);
next_state : out STD_LOGIC_VECTOR (4 downto 0));
end NextStateLogic;
architecture NextStateLogicl of NextStateLogic is
begin
FSM: process (pres_state, BLRH)
begin
case pres_state is
when "00000" =>
case BLRH is
when "0000" => next_state <= "00000";--ST0; -- All off
when "0010" => next_state <= "00100";--ST4; -- Right Turn
when "0100" => next_state <= "00111";--ST7; -- Left Turn
when "0110" => next_state <= "00101";--ST5; -- All off
when others => next_state <= "00001";--ST1; -- Hazard
end case;
when "00001" => next_state <= "00010";--ST2;
when "00010" => next_state <= "00011";
when "00011" =>
case BLRH is
when "1000" => next_state <= "00011"; -- Break
when "1110" => next_state <= "00011"; --
when "1010" => next_state <= "01101"; -- Right Turn & Break
when "1100" => next_state <= "01010"; -- Left Turn & Break
when others => next_state <= "00000"; -- Hazard
end case;
when "00100" => next_state <= "00101";
when "00101" => next_state <= "00110";
when "00110" => next_state <= "00000";
when "00111" => next_state <= "01000";
when "01000" => next_state <= "01001";
when "01001" => next_state <= "01010";
when "01010" => next_state <= "01011";
when "01011" => next_state <= "01100";
when "01100" =>
case BLRH is
when "1100" => next_state <= "01111"; -- Right Turn & Break
when "1010" => next_state <= "10000"; -- Left Turn & Break
when others => next_state <= "00000";
end case;
when "01101" => next_state <= "01110";
when "01110" => next_state <= "01100";
when "01111" => next_state <= "01010";
when "10000" => next_state <= "01101";
-- Include when others to avoid latches
when others => next_state <= "00000";
end case;
end process FSM;
end NextStateLogicl;
CurrentStateRegister component code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity CurrentStateRegister is
Port(
pres_state_b : out STD_LOGIC_VECTOR (4 downto 0);
next_state_b : in STD_LOGIC_VECTOR (4 downto 0);
Rst : in STD_LOGIC;
Clk : in STD_LOGIC
);
end CurrentStateRegister;
architecture CurrentStateRegister of CurrentStateRegister is
begin
StateReg: process (Clk,Rst,next_state_b)
begin
if (Rst = '1') then
pres_state_b <= "00000";
elsif Clk = '1' then
pres_state_b <= next_state_b;
else
pres_state_b<= "00000";
end if;
end process StateReg;
end CurrentStateRegister;
OutputLogic component code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity OutputLogic is
Port(
pres_state_c : in STD_LOGIC_VECTOR (4 downto 0);
Lights : out STD_LOGIC_VECTOR (5 downto 0));
end OutputLogic;
architecture OutputLogic of OutputLogic is
begin
Outputs: process (pres_state_c)
begin
case pres_state_c is
when "00000" => Lights <= "000000";
----------------------------------------------- Hazard
when "00001" => Lights <= "001100";
when "00010" => Lights <= "011110";
when "00011" => Lights <= "111111";
----------------------------------------------- Right Turn
when "00100" => Lights <= "000100";
when "00101" => Lights <= "000110";
when "00110" => Lights <= "000111";
----------------------------------------------- Left Turn
when "00111" => Lights <= "001000";
when "01000" => Lights <= "011000";
when "01001" => Lights <= "111000";
----------------------------------------------- Right Turn & Break
when "01010" => Lights <= "001111";
when "01011" => Lights <= "011111";
-----------------------------------------------
when "01111" => Lights <= "000111";
when "01100" => Lights <= "111111"; -- Common Case
when "10000" => Lights <= "111000";
----------------------------------------------- Left Turn & Break
when "01101" => Lights <= "111100";
when "01110" => Lights <= "111110";
when others => Lights <= "000000";
end case;
end process Outputs;
end OutputLogic;
And finally the Clk1Hz component code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Clk1Hz is
port (
Rst : in STD_LOGIC;
Clk_in : in STD_LOGIC;
Clk_out : out STD_LOGIC);
end Clk1Hz;
architecture Clk1Hz of Clk1Hz is
-- Definition of embedded signals and constants
-- Constants used for frequency division
constant Fosc : integer := 100000000; --Frecuencia del oscilador de tabletas NEXYS 3
constant Fdiv : integer := 5; --Frecuencia deseada del divisor
constant CtaMax : integer := Fosc / Fdiv; --Cuenta maxima a la que hay que llegar
-- Signal used by the frequency division process
signal Cont : integer range 0 to CtaMax;
begin
-- Frequency divider to obtain a 2Hz signal from
-- the 100 MHz board oscillator
FreqDiv: process (Rst, Clk_in)
begin
if Rst = '1' then
Cont <= 0;
elsif (rising_edge(Clk_in)) then
if Cont = CtaMax - 1 then
Cont <= 0;
Clk_out <= '1';
else
Cont <= Cont + 1;
Clk_out <= '0';
end if;
end if;
end process FreqDiv;
end Clk1Hz;
Iam missing something?? Is there another way to instanciate the component NextStateLogic?
Thanks:D
In CurrentStateRegister, you need to test for rising_edge(clk) instead of clk = '1'. Your current code infers a latch instead of a register, causing a loop whenever clk = '1'. Also, lose the final else in the ControlStateRegister module:
StateReg: process (Clk,Rst,next_state_b)
begin
if (Rst = '1') then
pres_state_b <= "00000";
elsif (rising_edge(Clk)) then
pres_state_b <= next_state_b;
end if;
end process StateReg;