Skip to content

Latest commit

 

History

History
500 lines (390 loc) · 14.5 KB

File metadata and controls

500 lines (390 loc) · 14.5 KB

Unpacked Array - Лабораторна робота

Виконані завдання

1. ✅ Створення матриці 4×4

logic [7:0] image [0:3][0:3];

Структура:

  • logic [7:0] - кожен елемент 8 біт (піксель, 0-255)
  • [0:3] - перший вимір: 4 рядки (rows)
  • [0:3] - другий вимір: 4 стовпці (columns)
  • Unpacked dimensions - кожен елемент зберігається окремо в пам'яті

Звернення:

image[row][col]  // row = 0..3, col = 0..3

2. ✅ Заповнення матриці: row × col

for (row = 0; row < 4; row++) begin
  for (col = 0; col < 4; col++) begin
    image[row][col] = row * col;
  end
end

Результат:

image[0][0] = 0×0 = 0    image[0][1] = 0×1 = 0    ...
image[1][0] = 1×0 = 0    image[1][1] = 1×1 = 1    ...
image[2][0] = 2×0 = 0    image[2][1] = 2×1 = 2    ...
image[3][0] = 3×0 = 0    image[3][1] = 3×1 = 3    ...

Візуалізація:

       Col 0  Col 1  Col 2  Col 3
     +------+------+------+------+
Row 0 |    0 |    0 |    0 |    0 |
Row 1 |    0 |    1 |    2 |    3 |
Row 2 |    0 |    2 |    4 |    6 |
Row 3 |    0 |    3 |    6 |    9 |
     +------+------+------+------+

💡 Цікавий факт: Це таблиця множення! Стовпець 3 = рядок 3 = [0, 3, 6, 9]


3. ✅ Вивід рядків і стовпців

3.1. Усі рядки окремо

for (row = 0; row < 4; row++) begin
  $write("Рядок %0d: [", row);
  for (col = 0; col < 4; col++) begin
    $write("%3d", image[row][col]);
    if (col < 3) $write(", ");
  end
  $display("]");
end

Вивід:

Рядок 0: [  0,   0,   0,   0]
Рядок 1: [  0,   1,   2,   3]
Рядок 2: [  0,   2,   4,   6]
Рядок 3: [  0,   3,   6,   9]

3.2. Усі стовпці окремо

for (col = 0; col < 4; col++) begin
  $write("Стовпець %0d: [", col);
  for (row = 0; row < 4; row++) begin
    $write("%3d", image[row][col]);
    if (row < 3) $write(", ");
  end
  $display("]");
end

Вивід:

Стовпець 0: [  0,   0,   0,   0]
Стовпець 1: [  0,   1,   2,   3]
Стовпець 2: [  0,   2,   4,   6]
Стовпець 3: [  0,   3,   6,   9]

Відмінність:

  • Рядок: фіксуємо row, змінюємо colimage[row][0..3]
  • Стовпець: фіксуємо col, змінюємо rowimage[0..3][col]

4. ✅ Функція row_sum (закоментована)

function int row_sum(int row_index);
  int total;
  total = 0;
  for (int c = 0; c < 4; c++) begin
    total += image[row_index][c];
  end
  return total;
endfunction

Використання:

// Після розкоментування:
for (row = 0; row < 4; row++) begin
  $display("Сума рядка %0d = %0d", row, row_sum(row));
end

Очікувані результати:

row_sum(0) = 0 + 0 + 0 + 0 = 0
row_sum(1) = 0 + 1 + 2 + 3 = 6
row_sum(2) = 0 + 2 + 4 + 6 = 12
row_sum(3) = 0 + 3 + 6 + 9 = 18

Альтернатива (inline обчислення):

// Без функції, прямо в initial блоці:
for (row = 0; row < 4; row++) begin
  sum = 0;
  for (col = 0; col < 4; col++) begin
    sum += image[row][col];
  end
  $display("Сума рядка %0d = %0d", row, sum);
end

Особливості Unpacked Array

1. 📐 Оголошення

logic [7:0] image [0:3][0:3];
  ↑          ↑       ↑      ↑
  │          │       │      └─ стовпці (unpacked dimension)
  │          │       └──────── рядки (unpacked dimension)
  │          └────────────────── розмір елемента (packed part)
  └───────────────────────────── тип елемента

Packed vs Unpacked частини:

  • Packed: [7:0] - це один 8-бітний вектор на елемент
  • Unpacked: [0:3][0:3] - це розміри масиву (4×4 = 16 елементів)

2. 🔧 Ініціалізація

✅ Правильні способи:

Поелементно:

image[0][0] = 8'd100;
image[0][1] = 8'd200;
// ... і так далі

Через цикли:

for (int i = 0; i < 4; i++)
  for (int j = 0; j < 4; j++)
    image[i][j] = i * j;

Через агрегатну ініціалізацію (тільки в комерційних симуляторах):

// ✅ Працює в Questa, VCS, Xcelium:
image = '{
  '{8'd0, 8'd0, 8'd0, 8'd0},  // рядок 0
  '{8'd0, 8'd1, 8'd2, 8'd3},  // рядок 1
  '{8'd0, 8'd2, 8'd4, 8'd6},  // рядок 2
  '{8'd0, 8'd3, 8'd6, 8'd9}   // рядок 3
};

❌ НЕ працює:

// ❌ Compilation error!
image = 128'h0000_0123_0246_0369;

// ❌ НЕ підтримується в Icarus Verilog:
image = '{'{0,0,0,0}, '{0,1,2,3}, ...};

3. 🎯 Звернення до елементів

✅ Дозволено:

// До окремого елемента:
pixel = image[2][3];         // ✅ OK

// До цілого рядка (це теж масив):
logic [7:0] row_copy [0:3];
row_copy = image[2];         // ✅ OK (в деяких симуляторах)

// До біта в елементі:
bit_value = image[2][3][5];  // ✅ OK (біт 5 елемента [2][3])

// Part-select в елементі:
nibble = image[2][3][7:4];   // ✅ OK (старші 4 біти)

❌ НЕ дозволено:

// Part-select по масиву:
slice = image[3:2];          // ❌ ERROR

// Звернення як до плоского масиву:
element = image[10];         // ❌ ERROR (потрібно [row][col])

// Побітові операції на масиві:
inverted = ~image;           // ❌ ERROR

4. 📊 Використання

✅ Добре підходить для:

  • Тестбенчі: зберігання тестових даних
  • Матриці: обробка зображень, матриці трансформацій
  • Таблиці пошуку (LUT): ROM, конфігураційні таблиці
  • Буфери: FIFO, черги даних
  • Багатовимірні дані: RGB зображення [height][width][3]

❌ НЕ підходить для:

  • Синтез апаратури - unpacked arrays НЕ синтезуються!
  • Порти модулів - не можна передати як один порт
  • Побітові операції - немає операцій на рівні масиву

5. ⚙️ Операції

// ✅ Можна:
for (i = 0; i < 4; i++)
  for (j = 0; j < 4; j++)
    image[i][j] = image[i][j] + 1;  // Поелементна операція

// ✅ Можна передавати в функції:
function void print_matrix(logic [7:0] mat [0:3][0:3]);
  // ...
endfunction

// ❌ НЕ можна:
image = image + 1;           // ERROR! Немає операцій на масиві
image = ~image;              // ERROR!
result = image & mask;       // ERROR!

Packed vs Unpacked: Детальне порівняння

Візуальна схема

PACKED ARRAY:
logic [3:0][7:0] packed_data;

Пам'ять: [XXXXXXXX|XXXXXXXX|XXXXXXXX|XXXXXXXX]
          ↑----- 32 біти безперервно ------↑
         packed_data = 32'hFACE_CAFE;  ✅ OK


UNPACKED ARRAY:
logic [7:0] unpacked_data [0:3];

Пам'ять: [XXXXXXXX] ... [XXXXXXXX] ... [XXXXXXXX] ... [XXXXXXXX]
         ↑element 0      ↑element 1      ↑element 2      ↑element 3
         Окремі елементи, не обов'язково поруч!
         unpacked_data = 32'h...; ❌ ERROR

Таблиця порівняння

Характеристика Packed Array Unpacked Array
Оголошення logic [3:0][7:0] data logic [7:0] data [0:3]
Зберігання Безперервний вектор Окремі елементи
Пряме присвоєння data = 32'hXXXX ❌ Тільки поелементно
Побітові операції ~data, data & mask ❌ НЕ підтримується
Part-select data[3:2] ❌ НЕ підтримується
Flat indexing data[15:0] (в деяких) ❌ НЕ підтримується
Порт модуля ✅ Можна передати ❌ Не можна як один порт
Синтез Синтезується НЕ синтезується
Використання RTL код, апаратура Тестбенчі, моделі
Швидкість симуляції Швидше Повільніше
Гнучкість Обмежена Більша

Коли використовувати?

Потрібен синтез в апаратуру?
├─ Так → PACKED ARRAY
│         • Регістри
│         • Порти модулів
│         • Шини даних
│         • FIFO, RAM
│
└─ Ні → UNPACKED ARRAY
          • Тестбенчі
          • Моделі пам'яті
          • Таблиці даних
          • Матриці для обробки

Практичні приклади

Приклад 1: RGB зображення 32×32

// Unpacked: зручно для обробки зображень у тестбенчах
logic [7:0] rgb_image [0:31][0:31][0:2];
//          ↑         ↑      ↑      ↑
//          8-біт     height width  RGB channels

// Заповнення червоним кольором:
for (int y = 0; y < 32; y++)
  for (int x = 0; x < 32; x++) begin
    rgb_image[y][x][0] = 8'd255;  // R = 255
    rgb_image[y][x][1] = 8'd0;    // G = 0
    rgb_image[y][x][2] = 8'd0;    // B = 0
  end

Приклад 2: Таблиця пошуку (LUT)

// Unpacked: таблиця sin(x) для тестування
logic [15:0] sin_lut [0:359];  // 360 значень (градуси)

initial begin
  // Заповнення таблиці
  for (int angle = 0; angle < 360; angle++) begin
    // Імітація sin(angle) * 32767
    sin_lut[angle] = $rtoi($sin(angle * 3.14159 / 180.0) * 32767);
  end
end

// Використання:
logic [15:0] sin_45 = sin_lut[45];

Приклад 3: Буфер FIFO

// Unpacked: FIFO буфер у тестбенчі
logic [31:0] fifo_buffer [0:15];  // 16 елементів по 32 біти
int write_ptr = 0;
int read_ptr = 0;

// Запис:
task fifo_write(logic [31:0] data);
  fifo_buffer[write_ptr] = data;
  write_ptr = (write_ptr + 1) % 16;
endtask

// Читання:
task fifo_read(output logic [31:0] data);
  data = fifo_buffer[read_ptr];
  read_ptr = (read_ptr + 1) % 16;
endtask

Поширені помилки та рішення

❌ Помилка 1: Спроба прямого присвоєння

logic [7:0] arr [0:3];
arr = 32'hFACECAFE;  // ❌ ERROR!

✅ Рішення:

arr[0] = 8'hFA;
arr[1] = 8'hCE;
arr[2] = 8'hCA;
arr[3] = 8'hFE;

❌ Помилка 2: Спроба побітових операцій

logic [7:0] arr [0:3];
arr = ~arr;  // ❌ ERROR!

✅ Рішення:

for (int i = 0; i < 4; i++)
  arr[i] = ~arr[i];  // Поелементна інверсія

❌ Помилка 3: Part-select на масиві

logic [7:0] arr [0:3];
logic [15:0] slice = arr[3:2];  // ❌ ERROR!

✅ Рішення:

logic [15:0] slice;
slice = {arr[3], arr[2]};  // Конкатенація

❌ Помилка 4: Передача як порт

logic [7:0] data [0:3];

module receiver(input logic [7:0] in [0:3]);  // ❌ НЕ синтезується!
  // ...
endmodule

✅ Рішення (використати packed):

logic [3:0][7:0] data;  // Packed array

module receiver(input logic [3:0][7:0] in);  // ✅ Синтезується
  // ...
endmodule

Ключові висновки

📌 Головні правила:

  1. Unpacked array = окремі елементи в пам'яті
  2. НЕ синтезується - тільки для тестбенчів!
  3. Немає побітових операцій на рівні масиву
  4. Ініціалізація: тільки поелементно або через цикли (в Icarus Verilog)
  5. Звернення: завжди через всі індекси arr[i][j]
  6. Використання: тестові дані, моделі, буфери

🎯 Коли використовувати:

✅ ВИКОРИСТОВУЙТЕ unpacked array для:
   • Тестбенчів (верифікація)
   • Зберігання тестових даних
   • Матриць і таблиць
   • Моделей пам'яті
   • Обробки даних у симуляції

❌ НЕ використовуйте unpacked array для:
   • RTL дизайну
   • Портів модулів
   • Синтезу в апаратуру
   • Побітових операцій
   • Передачі як одне ціле

🔄 Швидкий довідник:

Потрібно... Використовуйте
Синтез апаратури Packed
Тестбенч Unpacked
Порт модуля Packed
Матриця даних Unpacked
Побітові операції Packed
Багатовимірні дані Unpacked
Шина даних Packed
Таблиця пошуку Unpacked

Пам'ятайте: Unpacked arrays - це інструмент для верифікації та моделювання, не для апаратури! Для RTL коду завжди використовуйте packed arrays. 🧪