I'm writing a sha-256 hash function in VHDL and it takes in a String. I need to convert this string to a std_logic_vector of bits. So, I must somehow extract the bits from the characters of the String, but I'm not sure of the best way. As far as I can tell there does not exist a built in function to do this in any of the libraries.
Is my only option to loop through each index of the string and use a case block to map the characters to their respective 8-bit ASCII counterparts? Or is there some way to convert a character to bits?
You can convert a string to bits with a function like this (untested):
function to_std_logic_vector(a : string) return std_logic_vector is
variable ret : std_logic_vector(a'length*8-1 downto 0);
begin
for i in a'range loop
ret(i*8+7 downto i*8) := std_logic_vector(to_unsigned(character'pos(a(i)), 8));
end loop;
return ret;
end function to_std_logic_vector;
I don't think type string is synthesisable, so this function is only useful for simulation or static initialization.
Related
I'm attempting to write a quick program to send AT commands to a serial-port modem. I have opened the port with the right settings (B115200, 8N1 etc) and the String'Write call in the below code sample does actually work correctly.
Now I'm adding the code to read the modem's response back as a string. However I cannot know the length of the response beforehand and hence I cannot create a String variable to pass in to the out String parameter unless I do know the length.
package GSC renames GNAT.Serial_Communications;
SP : aliased GSC.Serial_Port;
function Send (Port : in GSC.Serial_Port; S : in String) return String is
begin
String'Write (SP'Access, S);
delay 0.1;
declare
Retval : String; -- NOT VALID - needs to be initialised
begin
String'Read (SP'Access, Retval);
return Retval;
end;
end Send;
I have a chicken / egg situation here.
The answer is probably to read the input one character at a time until you reach the terminator.
You could allocate a buffer long enough to hold the longest possible response (e.g. 1024 bytes!) (or maybe use recursion - but that’d be more complicated and make it difficult to diagnose possible overrun errors).
If the string is terminated by a specific character, you could use Interfaces.C.Pointers:
function Receive (Port : in GSC.Serial_Port) return String is
package Character_Pointers is new Interfaces.C.Pointers (
Index => Positive, Element => Character, Element_Array => String,
Default_Terminator => Character'Val (13)); -- CR-Terminated
function Convert is new Ada.Unchecked_Conversion (
Source => access all Streams.Stream_Element,
Target => Character_Pointers.Pointer);
-- assuming no more than 1023 characters + terminator can be given.
Max_Elements : constant Streams.Stream_Element_Offset :=
1024 * Character'Size / Streams.Stream_Element'Size;
Buffer : Streams.Stream_Element_Array (1 .. Max_Elements);
Last : Stream_Element_Offset;
begin
Port.Read (Buffer, Last);
return Characters_Pointers.Value (Convert (Buffer (1)'Access));
end Receive;
This code makes several assumptions:
String is terminated with CR (can be modified by setting Default_Terminator appropriately).
The response contains nothing other than the string (additional content that may have been read after the string is silently discarded).
The whole content will never be longer than 1024 bytes.
The typical way to achieve this is to send the length first, then read the value. (This is what things like bencode do.) -- Something like:
-- A stream from Standard-Input; for passing to example parameters:
Some_Stream: not null access Ada.Streams.Root_Stream_Type'Class :=
Ada.Text_IO.Text_Streams.Stream( Ada.Text_IO.Standard_Input );
-- The simple way, use the 'Input attribute; this calls the appropriate
-- default deserializations to return an unconstrained type.
-- HOWEVER, if you're reading from an already extant data-stream, you may
-- need to customize the type's Input function.
Some_Value : Constant String := String'Input( Some_Stream );
-- If the stream places a length into the stream first, you can simply read
-- it and use that value, to prealocate the proper size and fill it with the
-- 'Read attribure.
Function Get_Value( Input : not null access Ada.Streams.Root_Stream_Type'Class ) return String is
Length : Constant Natural := Natural'Input( Input );
Begin
Return Result : String(1..Length) do
String'Read( Input, Result );
End Return;
End Get_Value;
-- The last method is to use when you're dealing with buffered information.
-- (Use this if you're dealing with idiocy like null-terminated strings.)
Function Get_Buffered_Value( Input : not null access Ada.Streams.Root_Stream_Type'Class;
Buffer_Size : Positive := 1024;
Full_Buffer : Boolean := True;
Terminator : Character:= ASCII.NUL
) return String is
Buffer : String(1..Buffer_Size);
Begin
-- Full_Buffer means we can read the entire buffer-size w/o
-- "overconsuming" -- IOW, the stream is padded to buffer-length.
if full_buffer then
String'Read(Input, Buffer);
declare
Index : Natural renames Ada.Strings.Fixed.Index(
Source => Buffer,
Pattern => (1..1 => Terminator),
From => Buffer'First
);
begin
Return Buffer(Buffer'First..Index);
end;
else
declare
Index : Positive := Buffer'First;
begin
-- Read characters.
loop
Character'Read( Input, Buffer(Index) );
exit when Buffer(Index) = Terminator;
Index:= Positive'Succ( Index );
exit when Index not in Buffer'Range;
end loop;
-- We're returning everything but the terminator.
Return Buffer(1..Positive'Pred(Index));
end;
end if;
End Get_Buffered_Value;
I am using the TComPort library, to send a request to the device I need to send the command in Hexadecimal data like the example below
procedure TForm1.Button3Click(Sender: TObject);
begin
ComPort1.WriteStr(#$D5#$D5);
end;
But that is a hardcoded example.
How can I convert S into a valid value for ComPort1.WriteStr
procedure TForm1.Button3Click(Sender: TObject);
var
S:String;
begin
Edit1.Text:='D5 D5';
ComPort1.WriteStr(Edit1.Text);
end;
You don't send actual hex strings over the port. That is just a way to encode binary data in source code at compile-time. #$D5#$D5 is encoding 2 string characters with numeric values of 213 (depending on {$HIGHCHARUNICODE}, which is OFF by default).
TComPort.WriteStr() expects actual bytes to send, not hex strings. If you want the user to enter hex strings that you then send as binary data, look at Delphi's HexToBin() functions for that conversion.
That being said, note that string in Delphi 2009+ is 16-bit Unicode, not 8-bit ANSI. You should use TComPort.Write() to send binary data instead of TComPort.WriteStr(), eg:
procedure TForm1.Button3Click(Sender: TObject);
var
buf: array[0..1] of Byte;
begin
buf[0] := $D5;
buf[1] := $D5;
ComPort1.Write(buf, 2);
end;
However, TComPort.WriteStr() will accept a 16-bit Unicode string and transmit it as an 8-bit binary string by simply stripping off the upper 8 bits of each Char. So, if you send a string containing two Char($D5) values in it, it will be sent as 2 bytes $D5 $D5.
I am trying to convert a string to the same value in hex. Eg
If string="abc123" it's hex value should also be 24'habc123.
The length of string is 64 and so I convert each char to hex,I'll get 64*4=256 bits of hex value
eg if text_o_cplus.getc(i)=a i.e 97,I should assign it a hex value a i'e 4'ha;
But I am not getting proper way to do that. That's what I tried
int j=255;
for(int i=text_o_cplus.len();i>0;i--)
begin
while(j>=0)
begin
case(text_o_cplus.getc(i))
48: begin
rev_result[j]=4'b0000;
j=j-4;
break;
end
and so on.
rev_result is defined as
bit [64][4] rev_result;
I tried to define it as
bit [255:0] rev_result
also but it didn't work.
Can someone please suggest how can I achieve it?
Use the built-in function:
bit [255:0] rev_result = text_o_cplus.atohex();
What I want to do
I want to have a script in python or matlab that creates files which can be read by VHDL / modelsim as a file of real values.
What I've done so far
I've written a small VHDL entity that creates a file of real values so I can find out what format it uses. It looks like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library std;
use std.textio.all;
entity read_arr is
end entity read_arr;
architecture reader of read_arr is
type t_real_arr is array (0 to 1023) of real;
signal real_arr : t_real_arr := (others => 0.0);
signal start : std_logic := '0';
signal filled : std_logic := '0';
type t_real_file is file of t_real_arr;
file real_file : t_real_file;
begin -- architecture reader
start <= '0', '1' after 10 ns;
fill_arr : process (start) is
variable real_fill : real := -10.0;
begin -- process fill_arr
if rising_edge(start) then
for i in real_arr'range loop
real_arr(i) <= real_fill;
real_fill := real_fill + 0.25;
end loop; -- i
filled <= '1';
end if;
end process fill_arr;
wr_arr : process (filled) is
variable filename : string (1 to 10) := "realvc.dat";
variable status : file_open_status := status_error;
begin -- process fill_arr
if rising_edge(filled) then
file_open(status, real_file, filename, write_mode);
write(real_file, real_arr);
file_close(real_file);
end if;
end process wr_arr;
end architecture reader;
What it does is it fills an array of 1024 elements with real values starting from -10.0 and incrementing in steps of 0.25. It then writes this data into the binary file realvc.dat. The content of the file (viewed with a hex editor) can be seen in this gist.
It's easy to see that modelsim uses 64 bit to store each real value, but I haven't figured out what kind of format that is. It isn't ieee double-precision.
The Question
Does anyone know what kind of data format that is and how I can recreate it in a script language such as python or matlab?
The standard VHDL package std.textio makes it possible to read/write real in
literal format to a text file, whereby scripting languages like Python can
easily access it. The binary format is thereby avoided, which improves portability.
An example similar to the question code, doing first write then read of an array of real with std.textio is:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
entity test_arr is
end entity test_arr;
architecture test of test_arr is
begin
process is
type real_arr_t is array (0 to 1023) of real;
variable real_arr_v : real_arr_t := (others => 0.0);
variable real_fill_v : real := -10.0;
procedure real_arr_write(variable real_arr : in real_arr_t) is
file txt_file : text;
variable real_v : real;
variable line_v : line;
begin
file_open(txt_file, "real.txt", write_mode);
for idx in real_arr'range loop
write(line_v, real_arr(idx));
writeline(txt_file, line_v);
end loop;
file_close(txt_file);
end procedure;
procedure real_arr_read(variable real_arr : out real_arr_t) is
file txt_file : text;
variable line_v : line;
variable good_v : boolean;
begin
file_open(txt_file, "real.txt", read_mode);
for idx in real_arr'range loop
readline(txt_file, line_v);
read(line_v, real_arr(idx), good_v);
assert good_v report "Failed convert to real of: " & line_v.all severity FAILURE;
end loop;
file_close(txt_file);
end procedure;
begin
-- Make and write real array to text file
for i in real_arr_v'range loop
real_arr_v(i) := real_fill_v;
real_fill_v := real_fill_v + 0.25;
end loop;
real_arr_write(real_arr_v);
-- Read real array from text file
real_arr_read(real_arr_v);
-- End
wait;
end process;
end architecture test;
The real values in the "real.txt" file are then:
-1.000000e+001
-9.750000e+000
-9.500000e+000
-9.250000e+000
Python 3 can create strings like this with '{:e}'.format(x), and convert from this format using float(s).
I have some problem regarding writing String variable to a file.
The problem is that I have to specify the exact length of that String. Or else the output file will just contain some scrap values. I wonder if this can be solved somehow without the need to tell the length of the String before hand?
I know that my Get() procedure stores the Length of that variable, and I just could return it to the main program. However I want to write my program so it will do all the read from the input file first before I begin writing to the out file.
with Ada.Text_Io, Ada.Integer_Text_Io;
use Ada.Text_Io,Ada.Integer_Text_Io;
procedure Uppgift is
type Bil_Register is
record
Namn : String(1..50);
Adress : String(1..50);
Post : String(1..50);
Reg : String(1..6);
end record;
Infil : File_Type;
Utfil : File_Type;
L, I : Integer;
Br : Bil_Register;
procedure Get(F : in out File_Type; Br : out Bil_Register) is
Length : Integer;
begin
Get_Line(F, Br.Namn, Length);
end;
begin
Open(Infil, In_File, "register.txt");
Create(Utfil, Out_File, "test.txt");
Get(Infil, Br);
Put_Line(Utfil, Br.Namn);
Close(Infil);
Close(Utfil);
end Uppgift;
-
EDIT (2011.08.20)
This seems to be an issue with Unix based OS only. When using Windows you don't have to be absolute with string size when you print it out to file or screen
Well, the length of the valid part of a string has to be tracked somewhere.
You could maintain the valid length of each of your record's string fields as a separate field:
Namn : String (1..50);
Namn_Length : Natural;
You could define your own variable string type package, or use a pre-existing one such as Variable_Length. E.g.
Namn : Variable_Length.Variable_String(50);
You could use Unbounded_String for the fields and variables:
Namn : Unbounded_String;
And Ada.Text_IO.Unbounded_IO for I/O:
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
with Ada.Text_IO.Unbounded_IO;
procedure UTIO_Demo is
use Ada.Text_IO;
F : Ada.Text_IO.File_Type;
Data : Unbounded_String := To_Unbounded_String("Output by Unbounded_IO");
begin
Create(F, Ada.Text_IO.Out_File, "utio.tst");
Unbounded_IO.Put_Line(F, Data);
Close(F);
end UTIO_Demo;
If you'd prefer not to use the Unbounded_IO package, use To_String and To_Unbounded_String to convert back and forth between Unbounded_String values and the strings being read and written via Text_IO.
I would personally just use Unbounded_String, as suggested by Marc C, but if you want to avoid that, you could do something like this:
with Ada.Text_IO;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
use Ada.Text_IO;
use Ada.Containers;
procedure Uppgift is
type Bil_Register (Namn_Length : Natural) is
record
Namn : String (1 .. Namn_Length);
-- Other components removed for brevity.
end record;
package BR_Container is new Indefinite_Doubly_Linked_Lists (Bil_Register);
use BR_Container;
BR_List : BR_Container.List;
BR_List_Cursor : BR_Container.Cursor;
Buffer : String (1 .. 100);
Length : Natural;
Register_File : File_Type;
Test_File : File_Type;
begin
-- First we read the contents of register.txt and add all the data to
-- our list of Bil_Register objects.
Open (File => Register_File,
Mode => In_File,
Name => "register.txt");
while not End_Of_File (File => Register_File) loop
Get_Line (File => Register_File,
Item => Buffer,
Last => Length);
declare
BR : Bil_Register
(Namn_Length => Length);
begin
BR.Namn := Buffer (1 .. Length);
BR_List.Append (New_Item => BR);
end;
end loop;
Close (File => Register_File);
-- Then we output the contents of our list of Bil_Register objects to
-- test.txt
Create (File => Test_File,
Mode => Out_File,
Name => "test.txt");
BR_List_Cursor := BR_List.First;
while Has_Element (Position => BR_List_Cursor) loop
Put_Line (File => Test_File,
Item => Element (Position => BR_List_Cursor).Namn);
Next (Position => BR_List_Cursor);
end loop;
Close (File => Test_File);
end Uppgift;
I've divided read and write into two blocks because you said:
...do all the read from the input file
first before I begin writing to the
out file
Obviously with this method, you're going to have to size the Buffer variable appropriately. But really, it's pretty clumsy, compared to just using Unbounded_String. I'd say, that unless you have some very specific concerns or requirements, Unbounded_String is probably the way to go. It will simplify things immensely.
Good luck! :o)
Generally you can get away without having to have a special "length" variable in Ada. Sadly, this one of the cases where that is very difficult to pull off.
There is however a trick that lets you do it in this case. If you don't mind a little recursion, and either don't expect your strings to be tremendously long, or don't care about execution speed too much (you are doing an I/O anyway, so it's going to be slow). If this sounds OK to you, try Carlisle's trick.
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;
Now you can change your code to:
begin
Open(Infil, In_File, "register.txt");
Create(Utfil, Out_File, "test.txt");
Put_Line(Utfil, Next_Line (Infil));
Close(Infil);
Close(Utfil);
end Uppgift;