Dynamically sized array elements in Ada - c

So I have the following Ada array declaration buried inside a package body, that eventually gets passed to a C function
declare
type t_buffer is array (0 .. ARR_SIZE) of Unsigned_32;
buffer : constant access t_buffer := new t_buffer;
begin
c_obj.buffer_p := buffer (1)'Address;
c_obj.buffer_length := Unsigned_64 (buffer'Last);
for idx in Integer range buffer'Range loop
buffer (idx) := Unsigned_32 (idx * 4);
end loop;
end
However, the elements of the array aren't actually always Unsigned_32/uint32_t - it varies between uint8_t, uint16_t, uint32_t & uint64_t, depending on a (runtime) parameter. This means that when it gets read as a (for example) uint16_t array in the C code, the numbers are coming out as a sequence of 0,0,4,0,8,0,... instead of the intended 0,4,8,... when the uint32_t is "split" into 2 different numbers.
Ada doesn't have something approximating dependent types so I can't dynamically create the array type. I'm not sure how I can solve this at all nicely, possibly something to do with making an array of Unsigned_8 and bitshifting as appropriate?

The way Ada works, you have to have four different array types.
But you can encapsulate the selection of the array types in a variant record:
package Variant_Records is
type Word_Sizes is range 8 .. 64
with Static_Predicate => Word_Sizes in 8 | 16 | 32 | 64;
type Data_8_Bit is mod 2 ** 8 with Size => 8;
type Data_16_Bit is mod 2 ** 16 with Size => 16;
type Data_32_Bit is mod 2 ** 32 with Size => 32;
type Data_64_Bit is mod 2 ** 64 with Size => 64;
type Array_8_Bit is array (Positive range <>) of Data_8_Bit;
type Array_16_Bit is array (Positive range <>) of Data_16_Bit;
type Array_32_Bit is array (Positive range <>) of Data_32_Bit;
type Array_64_Bit is array (Positive range <>) of Data_64_Bit;
type Data_Array (Word_Size : Word_Sizes;
Length : Natural) is
record
case Word_Size is
when 8 => Data_8 : Array_8_Bit (1 .. Length);
when 16 => Data_16 : Array_16_Bit (1 .. Length);
when 32 => Data_32 : Array_32_Bit (1 .. Length);
when 64 => Data_64 : Array_64_Bit (1 .. Length);
end case;
end record;
end Variant_Records;
And then an example of some usage:
with Variant_Records;
procedure Using_Variant_Records is
use Variant_Records;
A : Data_Array (Word_Size => 8, Length => 16);
B : Data_Array (Word_Size => 64, Length => 2);
begin
for I in A.Data_8'Range loop
A.Data_8 (I) := 2 * Data_8_Bit (I) + 4;
end loop;
for I in B.Data_64'Range loop
B.Data_64 (I) := Data_64_Bit (8 ** I) + 4;
end loop;
declare
D : Data_Array := B;
begin
for E of D.Data_64 loop
E := E * 8;
end loop;
end;
end Using_Variant_Records;

Related

How to convert a slice of a byte array to a uint32 value

I am unable to convert a slice of a byte array to a uint value. I have seen that passing in slices to functions is a more idiomatic way to go but I have the following problems:
Print only a single element from the slice (it prints [102] instead of 102) basically printing it as a byte array instead of a byte
Convert a slice of the byte array (1 element) to a uint32 (binary.BigEndian.Uint32 seems to work for the whole array but not just a single element in the array)
Convert a slice of the byte array (1 element) to a byte
Cast a slice of the byte array (1 element) to a uint32 variable
I have included the errors as comments below. The compiler gives the error as to why, but how do I cast/convert from these slices to a variable?
Below is the code:
package main
import (
"encoding/binary"
"fmt"
)
const FrameBitsIV = 0x10
func main() {
// str := "abĀ£"
data := []byte{102, 97, 108, 99, 111, 110}
uint_value := []uint8{1, 2, 3, 4, 5}
x := data[0:]
fmt.Println(x)
pass_slice(data[0:], uint_value[0:])
}
func pass_slice(buf []byte, uint_value []uint8) {
x := buf[0:1]
fmt.Println(x) //prints [102]
y := binary.BigEndian.Uint32(x)
fmt.Println(y) //prints error
var z byte = buf[0:1] //cannot use buf[0:1] (value of type []byte) as byte value in variable declaration
u := uint32(buf[0:]) //cannot convert buf[0:] (value of type []byte) to uint32
}
Thank you so much.
Print only a single element from the slice:
Convert a slice of the byte array (1 element) to a byte
Use an index expression to get an element of the byte slice as a byte:
x := buf[0] // x is type byte
fmt.Println(x) //prints 102
Convert a slice of the byte array (1 element) to a uint32.
Cast a slice of the byte array (1 element) to a uint32 variable
Use an index expression to get the byte and convert to uint32:
x := uint32(buf[0]) // x is type uint32
fmt.Println(x) //prints 102
Note the difference between the index expressions used in this answer and the slice expressions used in the question.

VHDL Operands Have Different Lengths Error During Synthesis

I have a code piece that concatenates two variable length vectors and XORs the result with another fixed-length vector. The variable lengths of related vectors does not affect the total length of concatenation result. Here is the respected code
-- Find the number of bits to be skipped.
-- This is done for better optimization of hardware.
bits2MSB := 15 - findHighestIndex(m_xorResult);
-- If there are sufficient number of remaining bits in the extended data
-- Then we can continue the XOR operation
if(bits2MSB < remainingXorCount) then
m_xorResult <= (m_xorResult((15 - bits2MSB - 1) downto 0) & m_dataExtended(remainingXorCount downto (remainingXorCount - bits2MSB))) xor STD_LOGIC_VECTOR(to_unsigned(polynom, 16));
remainingXorCount := remainingXorCount - bits2MSB - 1; -- Decrease remainingXorCount
-- If the remaining bit count of the extended data is equal to the number of bits to be skipped until the first HIGH bit
-- Then the last XOR operation for given data can be made.
elsif(bits2MSB = remainingXorCount) then
m_xorResult <= (m_xorResult((14 - remainingXorCount) downto 0) & m_dataExtended(remainingXorCount downto 0)) xor STD_LOGIC_VECTOR(to_unsigned(polynom, 16));
remainingXorCount := remainingXorCount - bits2MSB;
state <= FINISH;
-- If the remaining bits are not sufficient for a new XOR operation
-- Then the result is equal to the extended version of the last XOR result.
else
m_xorResult <= (m_xorResult((14 - remainingXorCount) downto 0) & m_dataExtended(remainingXorCount downto 0));
remainingXorCount := 0; -- Decrease remainingXorCount
state <= FINISH;
end if;
The error message points to the line below the if statement. It says that
[Synth 8-509] operands of logical operator '^' have different lengths (40 vs. 16)
The declaration of related vectors are as following
variable bits2MSB : integer range 0 to 8 := 0;
variable remainingXorCount : integer range 0 to 7 := 7;
signal m_xorResult : STD_LOGIC_VECTOR(15 downto 0);
signal m_dataExtended : STD_LOGIC_VECTOR(23 downto 0);
variable polynom : natural := 16#1021#;
In addition to these, the function findHighestIndex(...) can return an integer value in range 7 to 15.
The testbench for the given module works without any problem. I tested it for any given input to the module. Somehow, Vivado says that in some condition I can produce a length of 40 bits vector and try to XOR it with a length of 16 bit vector. What do you think the problem is?
Instead of concatenating variable width words to make a fixed width word, you can OR two fixed width words together, each with a variable number of bits masked out.
In outline, instead of
X"AAAA"(15 downto var) & X"5555"(var-1 downto 0) XOR X"1234";
compute
((X"AAAA" AND upper_mask(var)) OR (X"5555" AND not upper_mask(var))) XOR X"1234";
The masks can be generated by functions like this;
function upper_mask(var : natural) return std_logic_vector is
mask : std_logic_vector(15 downto 0) := (others => '1');
begin
mask(var - 1 downto 0) := (others => '0');
return mask;
end;
If Vivado still can't synthesise upper_mask, a loop over all bits in upper_mask should work:
for i in mask'range loop
if i < var then
mask(i) := '0';
end if;
end loop

Extract bits into a int slice from byte slice

I have following byte slice which from which i need to extract bits and place them in a []int as i intend to fetch individual bit values later. I am having a hard time figuring out how to do that.
below is my code
data := []byte{3 255}//binary representation is for 3 and 255 is 00000011 11111111
what i need is a slice of bits -- > [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
What i tried
I tried converting byte slice to Uint16 with BigEndian and then tried to use strconv.FormatUint but that fails with error panic: runtime error: index out of range
Saw many examples that simple output bit representation of number using fmt.Printf function but that is not useful for me as i need a int slice for further bit value access.
Do i need to use bit shift operators here ? Any help will be greatly appreciated.
One way is to loop over the bytes, and use a 2nd loop to shift the byte values bit-by-bit and test for the bits with a bitmask. And add the result to the output slice.
Here's an implementation of it:
func bits(bs []byte) []int {
r := make([]int, len(bs)*8)
for i, b := range bs {
for j := 0; j < 8; j++ {
r[i*8+j] = int(b >> uint(7-j) & 0x01)
}
}
return r
}
Testing it:
fmt.Println(bits([]byte{3, 255}))
Output (try it on the Go Playground):
[0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1]
Using the bits package provides a fairly straightforward solution.
func bitsToBits(data []byte) (st []int) {
st = make([]int, len(data)*8) // Performance x 2 as no append occurs.
for i, d := range data {
for j := 0; j < 8; j++ {
if bits.LeadingZeros8(d) == 0 {
// No leading 0 means that it is a 1
st[i*8+j] = 1
} else {
st[i*8+j] = 0
}
d = d << 1
}
}
return
}
Performance is comparable to similar solutions.

What does this Delphi PAnsiChar code mean?

We all use Delphi for one project and have for years.
But we have never seen the following syntax used with a PAnsiChar and do not know what it means:
buffer : PAnsiChar
recInstance : Byte
recX : smallint
num_info : integer
// buffer loaded from a file...
num_info := 0;
// next two lines are a mystery
recInstance := Byte(buffer[num_info*5]);
recX := Byte(buffer[num_info*5+1])+256*Byte(buffer[num_info*5+2]);
In the debugger it looks like recX is just loading 2 bytes, but the syntax does not seem to match.
PAnsiChar has always had the nice property that you can access the AnsiChar being pointed at, as well as the following AnsiChars using index notation like an array (of bytes or AnsiChars). That is why it is used here.
These days, in modern versions that have {$POINTERMATH}, you would rather use a PByte instead, which has the same indexing enabled.
recInstance is assigned the byte at offset numinfo*5, recX is assigned the following two bytes as one single 16 bit value.
In a current version, it could be written like:
buffer: PByte;
n: Integer;
...
n := num_info * 5;
recInstance := buffer[n];
recX := buffer[n+1] or (buffer[n+2] shl 8); // together a 16 bit value
As Remy hinted, you could read all three bytes at once using:
type
PRec = ^TRec;
TRec = packed record
Instance: Byte;
X: Smallint; // a 16 bit (i.e. 2 byte) signed integer.
end; // total size: 3 bytes.
var
MyRec: TRec;
...
MyRec := PRec(#buffer[num_info * 5])^;
The PRec cast re-interprets the address returned by #buffer[num_info * 5] as a pointer to a TRec, then dereferences that (using ^), and assigns the result to MyRec.
In other words, #buffer[...] is a pointer, PRec(...) turns that into a pointer of type PRec and PRec(...)^ gets the 3 bytes at that pointer, as if it were a TRec.
MyRec.X is now the same as recX and MyRec.Instance is now the same as recInstance in the original code.
Byte() is just type casting of one-byte size value (AnsiChar here) to Byte type
The last code line forms two-byte variable recX from two bytes (not accounting for possible overflow effects though)
int16var = byte1 + 256 * byte2
//almost equivalent of
(byte2 shl 8) or byte1

Delphi XE3 -> Integer to array of Bytes

I have a data structure:
data = array of integer;
I have filled it from an
source = array of byte;
with
data[x] := Source[offset] or (Source[offset + 1] shl 8) or
(Source[offset + 2] shl 16) or (Source[offset + 3] shl 24);
after processing these blocks i have to bring them back to "bytes"...
any idea?
You can do this in a one-liner using Move.
Move(source[0], dest[0], Length(source)*SizeOf(source[0]));
If you need to perform a network/host byte order transformation, then you can run across the integer array after the Move.
In the opposite direction you do it all in reverse.
If you haven't got byte order issues then you might not actually need to convert to a byte array at all. It's possible that you can use the integer array as is. Remember that, without byte order issues, the memory layout of the byte and integer arrays are the same (which is why you are able to blit with Move).
You mean like this?
var
i: integer;
b1, b2, b3, b4: byte;
begin
b1 := byte(i);
b2 := byte(i shr 8);
b3 := byte(i shr 16);
b4 := byte(i shr 24);
Try, for instance,
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
b1, b2, b3, b4: byte;
begin
i := $AABBCCDD;
b1 := byte(i);
b2 := byte(i shr 8);
b3 := byte(i shr 16);
b4 := byte(i shr 24);
ShowMessage(IntToHex(b1, 2));
ShowMessage(IntToHex(b2, 2));
ShowMessage(IntToHex(b3, 2));
ShowMessage(IntToHex(b4, 2));
end;
Hmmm... I see an answer using Move and one using shifts, but what about a simple cast?:
var
I: Integer;
B: array[0..3] of Byte;
begin
// from bytes to integer:
I := PInteger(#B)^;
// from integer to bytes:
PInteger(#B)^ := I;
Or with your arrays:
data[i] := PInteger(#source[offset])^;
and vice versa:
// get low byte
source[offset] := PByte(#data[i])^; // or := PByte(#data[i])[0];
// get second byte
secondByte := PByte(#data[i])[1]; // or := (PByte(#data[i]) + 1)^;
or
PInteger(#source[offset])^ := data[i];
As you see, you can get a long way by casting to pointers. This does not actually take the pointer, the compiler is clever enough to access the items directly.
As commented, you do not need to move the data to access it as both byte and integer.
Your original array of byte could be accessed as an array of integer by type casting.
type
TArrayInteger = array of Integer;
...
for i := 0 to Pred(Length(source)) div SizeOf(Integer) do
WriteLn(TArrayInteger(source)[i]);
Often I hide these type casts in a class. In XE3 there is possibility to declare class helpers for simple types, like string,byte,integers, etc. See TStringHelper for example.
The same goes for array of simple types.
Here is an example using a record helper:
type
TArrayByte = array of Byte;
TArrayInteger = array of Integer;
TArrayByteHelper = record helper for TArrayByte
private
function GetInteger(index : Integer) : Integer;
procedure SetInteger(index : Integer; value : Integer);
public
property AsInteger[index : Integer] : Integer read GetInteger write SetInteger;
end;
function TArrayByteHelper.GetInteger(index: Integer): Integer;
begin
Result := TArrayInteger(Self)[index];
end;
procedure TArrayByteHelper.SetInteger(index: Integer; value: Integer);
begin
TArrayInteger(Self)[index] := value;
end;
Use it like this:
Var
source : TArrayByte;
i : Integer;
begin
SetLength(source,8);
for i := 0 to 7 do
source[i] := i;
for i := 0 to 1 do
WriteLn(Format('%8.8X',[source.AsInteger[i]]));
ReadLn;
end.
To build this as a function:
Type TBytes = array of byte;
function InttoBytes(const int: Integer): TBytes;
begin
result[0]:= int and $FF;
result[1]:= (int shr 8) and $FF;
result[2]:= (int shr 16) and $FF;
end;

Resources