Thứ Năm, 31 tháng 8, 2017

[IP core] LIFO (STACK) đồng bộ có thể cấu hình được

Bài này giới thiệu về thiết kế LIFO (Last-In Fist-Out) đồng bộ có thể cấu hình được độ rộng dữ liệu và dung lượng lưu trữ trước khi tổng hợp. LIFO đồng bộ thường được sử dụng như bộ đệm lưu trữ dữ liệu tạm thời ví dụ như chức năng của STACK trong CPU.

1. Giới thiệu
Khác với FIFO, LIFO hoạt động theo nguyên tắc dữ liệu được lưu vào bộ nhớ sau cùng sẽ được lấy ra trước tiên và ngược lại. LIFO cũng có hai thông số quan trọng là số lượng ô nhớ và độ rộng dữ liệu để xác định dung lượng LIFO. Hai thông số đặc trưng của LIFO là:
  • Số lượng ô nhớ hay còn gọi là độ sâu của LIFO
  • Độ rộng ô nhớ tương ứng với độ rộng dữ liệu được ghi vào và đọc ra.
Hai thông số trên sẽ cho biết dung lượng của LIFO. Ví dụ, LIFO có 4 ô nhớ, mỗi ô nhớ lưu 8 bit dữ liệu thì dung lượng LIFO là 4*8 = 32 bit hoặc 4 byte. Để định địa chỉ các ô nhớ của LIFO, một phương pháp thường dùng là sử dụng con trỏ ghi và con trỏ đọc. Con trỏ ở đây thực chất là bộ đếm tuần tự.

Hình 1. Hoạt động của LIFO
LIFO thường có các tín hiệu báo trạng thái hoạt động của chúng như:
  • Trạng thái rỗng: không chưa bất cứ dữ liệu nào
  • Trạng thái đầy: toàn bộ dung lượng đã được lấp đầy dữ liệu
  • Trạng thái overflow: Đang đầy những vẫn tiếp tục được ghi vào. Vào trường hợp này, dữ liệu trong LIFO vẫn giữ nguyên chứ không bị ghi đè bởi dữ liệu mới
  • Trạng thái underflow: Đang rỗng những vẫn tiếp tục được đọc. Vào trường hợp này, ngõ ra dữ liệu sẽ giữ giá trị dữ liệu cũ gần nhất.
  • Trạng thái dưới hoặc trên một mức giá trị ngưỡng. Ví dụ, số dữ liệu trong LIFO nhỏ hơn hoặc bằng 4 thì tích cực báo ngưỡng dưới. Giá trị 4 ở đây là ngưỡng dưới.
2. Sơ đồ tín hiệu giao tiếp
Hình 1. Sơ đồ tín hiệu giao tiếp của LIFO
  1. Ngõ vào (input)
    1. clk:    xung clock
    2. rst_n: tín hiệu reset tích cực mức thấp
    3. wr:     tín hiệu ghi dữ liệu vào LIFO 
    4. rd:      tín hiệu đọc dữ liệu từ LIFO 
    5. data_in[DATA_WIDTH-1:0]: bus dữ liệu ghi có số bit là DATA_WIDTH
    6. low_th[POINTER_WIDTH-1:0]: tín hiệu cấu hình mức ngưỡng dưới có số bit là POINTER_WIDTH.
    7. high_th[POINTER_WIDTH-1:0]: tín hiệu cấu hình mức ngưỡng trên có số bit là POINTER_WIDTH.
  2. Ngõ ra (output)
    1. lifo_empty:   tín hiệu báo LIFO rỗng
    2. lifo_full:       tín hiệu báo LIFO đầy
    3. lifo_low_th:  tín hiệu báo LIFO thấp hơn mức ngưỡng dưới 
    4. lifo_high_th:  tín hiệu báo LIFO cao hơn hoặc bằng mức ngưỡng trên
    5. lifo_ov: tín hiệu báo LIFO bị overflow
    6. lifo_ud: tín hiệu báo LIFO bị underflow
    7. lifo_data_out[DATA_WIDTH-1:0]: bus dữ liệu đọc có số bit là DATA_WIDTH
3. Các thông số cấu hình
LIFO sẽ có các thông số cấu hình như sau:
Thông số định nghĩa chức năng:
  1. EMPTY_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo trạng thái rỗng của LIFO , lifo_empty
  2. FULL_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo trạng thái đầy của LIFO, lifo_full
  3. SET_LOW_EN: Thông số cho phép tạo tín hiệu ngõ vào dùng để thiết lập giá trị ngưỡng dưới. Chú ý, thông số này chỉ được định nghĩa khi LOW_TH_SIGNAL được sử dụng.
  4. SET_HIGH_EN: Thông số cho phép tạo tín hiệu ngõ vào dùng để thiết lập giá trị ngưỡng trên. Chú ý, thông số này chỉ được định nghĩa khi HIGH_TH_SIGNAL được sử dụng.
  5. LOW_TH_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo dưới một mức ngưỡng được thiết lập sẵn, lifo_low_th
  6. HIGH_TH_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo dưới mức ngưỡng được thiết lập của LIFO, lifo_high_th
  7. OV_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo overflow, lifo_ov
  8. UD_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo underflow, lifo_ud
  9. OUTPUT_REG: Chèn thanh ghi tại ngõ ra của bus dữ liệu LIFO
Thông số cấu hình giá trị:
  1. DATA_WIDTH: Thiết lập số bit của 1 ô dữ liệu LIFO , tương ứng là độ rộng của bus dữ liệu ghi/đọc
  2. PTR_WIDTH: Thiết lập độ rộng của con trỏ ghi/đọc. Giá trị này sẽ quyết định số ô nhớ của LIFO theo công thức "Số ô nhớ của LIFO =2^POINTER_WIDTH. Ví dụ, cấu hình POINTER_WIDTH = 3 thì số ô nhớ của LIFO là 2^3 = 8 ô.
4. Phân tích cấu trúc LIFO
Lưu ý, các phần tô đỏ là các phần có thể được lựa chọn sẽ được tạo ra hoặc không tạo ra khi tổng hợp thông qua việc định nghĩa các thông số tương ứng. Ví dụ, nếu bạn muốn có tín hiệu slifo_ov thì hãy định nghĩa từ khóa OV_SIGNAL, ngược lại, nếu không định nghĩa OV_SIGNAL thì tín hiệu này sẽ không được tạo ra.
LIFO này không cho phép đọc và ghi đồng thời, nghĩa là một thời điểm chỉ đọc hoặc ghi.
4.1 Mạch nguyên lý tổng quan
Hình 2. Mạch nguyên lý của LIFO sử dụng 1 con trỏ quản lý đọc và ghi
4.2 Con trỏ đọc/ghi và cờ báo trạng thái

Con trỏ đọc và ghi đối với thiết kế LIFO này chỉ là 1 bộ đếm duy nhất hoạt động theo nguyên tắc:
  • Tăng 1 khi ghi
  • Giảm 1 khi đọc
Mạch con trỏ đọc ghi có thể thực hiện theo 2 cách:
  • Sử dụng 1 bộ cộng và 1 bộ trừ
  • Sử dụng 1 bộ cộng và 1 MUX. Cách này thực hiện dựa trên nguyên lý biến đổi bộ trừ thành mạch cộng bù 2. Sử dụng mạch này sẽ bớt được 1 bộ cộng và thay bằng bộ MUX và tận dụng cờ nhớ (carry flag) có sẵn của các bộ cộng thư viện tổng hợp ASIC nên tài nguyên sẽ giảm hơn.

Hình 3. Mạch con trỏ sử dụng 1 bộ cộng và 1 bộ trừ
Hình 4. Mạch nguyên lý sử dụng 1 bộ cộng và tạo các cờ báo trạng thái
4.3 Cờ báo trạng thái overflow và underflow
Hình 5. Cờ báo trạng thái overflow và underflow
5. RTL code và testbench


Pass (nếu có): nguyenquanicd

Source File:
  1. slifo.v - RTL code
  2. slifo_define.h - chứa các định nghĩa để cấu hình trước khi tổng hợp. Nếu bạn không muốn sử dụng phần tín hiệu hay mạch nào thì chỉ cần comment che định nghĩa đó đi.
  3. slifo_parameter.h - chứa thông số cấu hình dung lượng LIFO
  4. tb_slifo - một basic testbench
6. Kết quả
Một số hình ảnh tổng hợp trên Quartus II để các bạn có thể hình dung về cách cấu hình.
6.1 Cấu hình 1

Yêu cầu:
  1. Không sử dụng bất cứ tín hiệu báo trạng thái nào
  2. Ngõ ra không chốt thanh ghi
  3. Dung lượng 16 bit * 16 ô nhớ
slifo_define.h
//`define EMPTY_SIGNAL
//`define FULL_SIGNAL
//`define SET_LOW_EN
//`define SET_HIGH_EN
//`define LOW_TH_SIGNAL
//`define HIGH_TH_SIGNAL
//`define OV_SIGNAL
//`define UD_SIGNAL
//`define OUTPUT_REG

slifo_parameter.h
parameter DATA_WIDTH    = 16;
parameter POINTER_WIDTH = 4;

Kết quả

6.2 Cấu hình 2

Yêu cầu:
  1. Sử dụng tín hiệu báo LIFO đầy và rỗng
  2. Sử dụng tín hiệu báo ngưỡng trên, ngưỡng dưới và có tín hiệu đầu vào để cấu hình giá trị ngưỡng
  3. Ngõ ra chốt thanh ghi
  4. Dung lượng 4 bit * 16 ô nhớ
slifo_define.h
`define EMPTY_SIGNAL
`define FULL_SIGNAL
`define SET_LOW_EN
`define SET_HIGH_EN
`define LOW_TH_SIGNAL
`define HIGH_TH_SIGNAL
//`define OV_SIGNAL
//`define UD_SIGNAL
`define OUTPUT_REG

slifo_parameter.h
parameter DATA_WIDTH    = 4;
parameter POINTER_WIDTH = 4;

Kết quả

Mọi góp ý trao đổi, bạn đọc có thể comment dưới bài viết.

0 bình luận:

Đăng nhận xét