• Integrated Circuit Design - Chia sẻ kiến thức về vi mạch

    Vi mạch và Ứng dụng

  • Integrated Circuit Design - Chia sẻ kiến thức về vi mạch

    Vi mạch và Ứng dụng

  • Integrated Circuit Design - Chia sẻ kiến thức về vi mạch

    Vi mạch và Ứng dụng

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.

Thứ Tư, 30 tháng 8, 2017

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

Bài này giới thiệu về thiết kế FIFO đồ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. FIFO đồng bộ thường được sử dụng như bộ đệm lưu trữ dữ liệu tạm thời giữa hai miền có tốc độ xử lý dữ liệu khác nhau.

1. Giới thiệu

Lưu ý, tốc độ xử lý dữ liệu khác nhau không có ý nghĩa là xung clock khác nhau hay bất đồng bộ với nhau. Trong trường hợp này, cả hai miền đều sử dụng các xung clock đồng bộ với nhau nhưng vì một miền xử lý nhanh, một miền xử lý chậm nên dữ liệu không thể truyền liên tục giữa hai miền. Giải pháp cho vấn đề này là sử dụng một bộ nhớ lưu dữ liệu tạm thời giữa hai miền để lưu những dữ liệu chưa được xử lý kịp.

FIFO hoạt động theo nguyên tắc dữ liệu được lưu vào trước sẽ là dữ liệu được lấy ra trước. Nghĩa là, thứ tự dữ liệu được đọc ra giống như thứ tự dữ liệu được ghi vào. Hai thông số đặc trưng của FIFO là:
  • Số lượng ô nhớ hay còn gọi là độ sâu của FIFO
  • Độ 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 FIFO. Ví dụ, FIFO có 4 ô nhớ, mỗi ô nhớ lưu 8 bit dữ liệu thì dung lượng FIFO là 4*8 = 32 bit hoặc 4 byte. Để định địa chỉ các ô nhớ của FIFO, 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. Minh họa hoạt động của FIFO
2. Sơ đồ tín hiệu giao tiếp FIFO
FIFO thiết kế sẽ có các tín hiệu giao tiếp như sau:
Hình 2. Sơ đồ tín hiệu giao tiếp của FIFO đồng bộ tên SFIFO
  1. Ngõ vào (input)
    1. clk_rd:    xung clock đọc dữ liệu
    2. clk_wr: xung clock ghi dữ liệu, đồng bộ với xung clock đọc clk_rd
    3. rst_n: tín hiệu reset tích cực mức thấp
    4. wr:     tín hiệu ghi dữ liệu vào FIFO
    5. rd:      tín hiệu đọc dữ liệu từ FIFO
    6. data_in[DATA_WIDTH-1:0]: bus dữ liệu ghi có số bit là DATA_WIDTH
    7. low_th[TH_WIDTH-1:0]: tín hiệu cấu hình mức ngưỡng dưới có số bit là TH_WIDTH.
    8. high_th[TH_WIDTH-1:0]: tín hiệu cấu hình mức ngưỡng trên có số bit là TH_WIDTH.
  2. Ngõ ra (output)
    1. sfifo_empty:   tín hiệu báo FIFO rỗng
    2. sfifo_full:       tín hiệu báo FIFO đầy
    3. sfifo_low_th:  tín hiệu báo FIFO thấp hơn mức ngưỡng dưới 
    4. sfifo_high_th:  tín hiệu báo FIFO cao hơn hoặc bằng mức ngưỡng trên
    5. sfifo_ov: tín hiệu báo FIFO bị overflow
    6. sfifo_ud: tín hiệu báo FIFO bị underflow
    7. sfifo_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
FIFO 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 FIFO, sfifo_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 FIFO, sfifo_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, sfifo_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 FIFO, sfifo_high_th
  7. OV_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo overflow, sfifo_ov
  8. UD_SIGNAL: Thông số cho phép tạo tín hiệu ngõ ra báo underflow, sfifo_ud
  9. OUTPUT_REG: Chèn thanh ghi tại ngõ ra của bus dữ liệu FIFO
  10. TWO_CLOCK: Tạo tín hiệu xung clock đọc và xung clock ghi khác nhau. Lưu ý, cấu hình này sẽ tạo ra hai tín hiệu xung clock ngõ vào sử dụng cho quá trình đọc và quá trình ghi nhưng hai xung clock cấp cho FIFO vẫn phải là 2 xung clock đồng bộ.
Thông số cấu hình giá trị:
  1. DATA_WIDTH: Thiết lập số bit của 1 ô dữ liệu FIFO, tương ứng là độ rộng của bus dữ liệu ghi/đọc
  2. POINTER_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 FIFO theo công thức "Số ô nhớ của FIFO=2^POINTER_WIDTH. Ví dụ, cấu hình POINTER_WIDTH= 3 thì số ô nhớ của FIFO là 2^3 = 8 ô.
  3. TH_WIDTH = POINTER_WIDTH
4. Phân tích cấu trúc FIFO
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 sfifo_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.
4.1 Mạch nguyên lý tổng quan

4.2 Con trỏ ghi và đọc

4.3 Mạch báo trạng thái full/empty/overflow/underflow

4.4 Mạch báo trạng thái ngưỡng trên và ngưỡng dưới

5. RTL code và testbench

Link: dowload RTL code của SFIFO

Pass (nếu có): nguyenquanicd

Source File:
  1.  sfifo.v  - RTL code
  2.  sfifo_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.  sfifo_parameter.h - chứa thông số cấu hình dung lượng FIFO
  4.  tb_sfifo - 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. Sử dụng 1 nguồn xung clock
  4. Dung lượng 8 bit * 8 ô nhớ
sfifo_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
//`define TWO_CLOCK

sfifo_parameter.h
parameter DATA_WIDTH    = 8;
parameter POINTER_WIDTH = 3;

Kết quả

6.2 Cấu hình 2

Yêu cầu:
  1. Sử dụng tín hiệu báo FIFO đầy và rỗng
  2. Ngõ ra chốt thanh ghi
  3. Sử dụng 2 nguồn xung clock đồng bộ
  4. Dung lượng 8 bit * 16 ô nhớ
sfifo_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
`define TWO_CLOCK

sfifo_parameter.h
parameter DATA_WIDTH    = 8;
parameter POINTER_WIDTH = 4;

Kết quả

6.3 Cấu hình 3

Yêu cầu: Thiết lập đầy đủ chức năng
  1. Sử dụng tất cả tín hiệu báo trạng thái trong đó hai trạng thái báo ngưỡng trên và dưới có thể lập trình được (có SET_LOW_EN và SET_HIGH_EN)
  2. Ngõ ra chốt thanh ghi
  3. Sử dụng 2 nguồn xung clock đồng bộ
  4. Dung lượng 32 bit * 16 ô nhớ
sfifo_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
`define TWO_CLOCK

sfifo_parameter.h
parameter DATA_WIDTH    = 8;
parameter POINTER_WIDTH = 4;

Kết quả


Note: Hãy trao đổi dưới bài viết nếu bạn gặp bất cứ vấn đề gì khi sử dụng.