2015-12-04 3 views
0

У меня есть два типа и два массива, что типы в file.adsИзменить тип массива: тип 8bit к типу 6bit

type Ebit is mod 2**8; 
type Sbit is mod 2**6; 
type Data_Type is array (Positive range <>) of Ebit; 
type Changed_Data_Type is array (Positive range <>) of Sbit; 

и функции:

function ChangeDataType (D : in Data_Type) return Changed_Data_Type 
with 
    Pre => D'Length rem 3 = 0 and D'Last < Positive'Last/4, 
Post => ChangeDataType'Result'Length = 4 * (D'Length/3) 

Ok я могу понять все это , Например, у нас есть следующие единицы:

65, 66, 65, 65, 66, 65 в 8-значных значениях функции должны давать нам 16, 20, 9, 1, 16, 20, 9, 1 в 6 бит значениях.

Я не знаю, как я могу построить 6-битную таблицу из 8-битной таблицы.

Моя идея sollutions является, например, принимая по кусочкам от типа:

fill all bites in 6bit type to 0 (propably default) 
if first bit (2**1) is 1 set bit (2**1) in 6bit type to 1; 
and do some iterations 

Но я не знаю, как это сделать, всегда есть проблема с типами. Является ли эта хорошая идея, или я могу сделать это проще? Я трачу последний нигт, чтобы попытаться написать это, но безуспешно.

Редактировать: Я написал код, его работа, но у меня проблема с инициализацией массива.

function ChangeDataType (D: in Data_Type) return Changed_Data_Type 
is 
    length: Natural := (4*(D'Length/3)); 
    ER: Changed_Data_type(length); 
    Temp: Ebit;  
    Temp1: Ebit; 
    Temp2: Ebit; 
    Actual: Ebit; 
    n: Natural; 
    k: Natural; 
begin 
    n := 0; 
    k := 0; 
    Temp := 2#00000000#; 
    Temp1 := 2#00000000#; 
    Temp2 := 2#00000000#; 

    Array_loop: 
    for k in D'Range loop 
    case n is 
     when 0 => 
      Actual := D(k); 
      Temp1 := Actual/2**2; 
      ER(k) := Sbit(Temp1); 
      Temp := Actual * (2**4); 
      n := 2; 
     when 2 => 
      Actual := D(k); 
      Temp1 := Actual/2**4; 
      Temp2 := Temp1 or Temp; 
      ER(k) := Sbit(Temp2); 
      Temp := Actual * (2**2); 
      n := 4; 
     when 4 => 
      Actual := D(k); 
      Temp1 := Actual/2**6; 
      Temp2 := Temp1 or Temp; 
      ER(k) := Sbit(Temp2); 
      n := 6; 
     when 6 => 
      Temp1 := Actual * (2**2); 
      Temp2 := Actual/2**2; 
      ER(k) := Sbit(Temp2); 
      n := 0; 
     when others => 
      n := 0; 
    end case; 
    end loop Array_Loop; 


    return ER; 
end; 
+0

'' '' и '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' Если вам нужна смена, вы можете умножить или разделить на мощность 2. – ajb

+0

Thx для ответа. Когда я пытаюсь установить значение 6 бит с 8 бит с помощью побитового оператора, я всегда получаю «ожидаемый тип 8 бит» от ADA. Можете ли вы дать мне один пример, как настроить 6-битное значение? – CryptoNewbie

+0

2 ошибки в опубликованном коде: 'length: Natural: = (4 * ((D'Length + 2)/3));' обязательно, чтобы избежать ошибки «вне игры», когда Length mod 3/= 0 .. и 'ER: Changed_Data_type (1 .. length);' ie подтип_марка точно, как указано в сообщении об ошибке. Кроме того, если вы получите упакованный массив ниже для работы, вы устраните весь цикл и регистр case ... –

ответ

1

ЕСЛИ Я понимаю, что вы просите ... это то, что вы хотите, чтобы повторно упаковать те же 8-битные данные в 6-битовых значений, так что «оставшиеся» биты первого EBit стали первые биты (самые высокие или самые низкие?) второго Sbit.

Один из способов сделать это - по крайней мере, для массивов с фиксированным размером, например. ваши 6 слов * 8 бит, 8 слов * 6 бит, например, путем указания точного макета в памяти для каждого типа массива с использованием упаковки и representation aspects (или прагмы, до Ada-2012), которые являются nicely described here.

Я не тестировал следующее, но это может служить отправной точкой.

type Ebit is mod 2**8; 
type Sbit is mod 2**6; 
for Ebit'Size use 8; 
for Sbit'Size use 6; 
type Data_Type is array (1 .. 6) of Ebit 
    with Alignment => 0; -- this should pack tightly 
type Changed_Data_Type is array (1 .. 8) of Sbit 
    with Alignment => 0; 

Затем вы можете создать экземпляр универсального Unchecked_Conversion функции с двумя типами массивов, и использовать эту функцию для преобразования из одного массива в другой.

with Ada.Unchecked_Conversion; 
function Change_Type is new Ada.Unchecked_Conversion(Data_Type, Changed_Data_Type); 

declare 
    Packed_Bytes : Changed_Data_Type := Change_Type(Original_Bytes); 
begin ... 

С точки зрения кода, сгенерированного, это не медленно, потому что Unchecked_Conversion не делает ничего, кроме сказать, типа во время компиляции проверки, чтобы искать другой путь.

Я рассматриваю Unchecked_Conversion как «Я хотел сделать это», смотри, мой кот дает мне после падения с окна. Опять же ...

В качестве альтернативы, если вы хотите избежать копирования, вы можете объявить Original_Bytes как aliased и использовать аналогичный трюк с типами доступа и Unchecked_Access, чтобы наложить оба массива на одну и ту же память (например, Union in C). Я думаю, что это то, что DarkestKhan называет «наложения массива» в комментарии ниже. См. Также раздел 3 из this rather dated page, который описывает эту технику далее. Он отмечает, что наложенная переменная должна быть объявлена ​​не только aliased, но также volatile, так что доступ к одному виду не оптимизирован в регистры, но отражают любые изменения, сделанные с помощью другого представления. Другой подход к оверлеям находится в Ada Wikibook here.

Теперь это может быть уязвимо к соображениям суждения, то есть может работать на некоторых платформах, но не в других. Вторая ссылка выше приведен пример записи с точным битовым выравнивания своих членов: мы можем по крайней мере взять на себя Bit_Order аспект, как в with Alignment => 0, Bit_Order => Low_Order_First; для указанных массивов ...

-- code stolen from "Rationale" ... see link above p.11 
type RR is record 
     Code: Opcode; 
     R1: Register; 
     R2: Register; 
end record 
with Alignment => 2, Bit_Order => High_Order_First; 

for RR use record 
     Code at 0 range 0 .. 7; 
     R1 at 1 range 0 .. 3; 
     R2 at 1 range 4 .. 7; 
end record; 

Одна вещь, которая не ясно для меня есть, если есть шаблонный способ указать точное расположение каждого элемента в массиве, как это делается в записи здесь - или даже если есть потенциальная необходимость. Если необходимо, одним из способов было бы заменить массивы выше с помощью записей. Но я бы хотел увидеть лучший ответ, если он есть.

+0

Спасибо за ответ Брайан. Я много читал об этом. Не спать, но я написал код;) Я использую или побитовую операцию сейчас, я отправлю свой код после 8 вечера. – CryptoNewbie

+0

У меня есть еще один вопрос: как я могу назначить массив Changed_Data_Type с выражением в аргументе диапазона? Мне нужно создать массив с 4 * (D'Length/3), Недопустимое ограничение индекса на ER: Encoded_Data_Type (4 * (D'Length/3)); и ожидание маски подтипа для ограничения индекса по длине: Natural: = (4 * (D'Length/3)); ER: Encoded_Data_Type (длина); – CryptoNewbie

+0

Я думаю, что если этот подход работает, это не так мало низкоуровневого кодирования. Crypto может быть другим, но во встроенном программировании вы видите, что C-кодировщики выполняют множество смен, масок и побитовых манипуляций вместо 'Ctrl_Reg.Enable_Bit: = True;' –

Смежные вопросы