Thứ Bảy, 23 tháng 9, 2017

[Basic Knowledge][Bài 4] Hướng dẫn phân tích thiết kế lõi IP step-by-step - Mô tả và kiểm tra RTL code

Bạn đang muốn bắt tay vào thiết kế một lõi IP (IP core) nhưng không biết bắt đầu từ đâu? Bài viết này là một phần trong chuỗi bài viết hướng dẫn bạn đi từng bước để có thể thiết kế được một lõi IP hoàn chỉnh. Phương pháp được sử dụng ở đây là top-down, phân tích từ tổng quan đến chi tiết. Ví dụ được trình bày là một thiết kế CPU cơ bản (simple CPU).


Trong bài 1bài 2 và bài 3 chúng ta đã hiểu đến bước phân tích chi tiết từ khối trong một thiết kế vi mạch. Bài này chúng ta sẽ thực hiện mô tả RTL code cho toàn bộ một lõi IP trên ví dụ CPU 8 bit SCPU đã phân tích trong những bài trước.
1. Hướng dẫn mô tả RTL code sử dụng Verilog HDL
1.1 Xác định cấu trúc thứ bậc (hierachy)
Để mô tả RTL code cho một lõi IP hay một thiết kế nói chung, một số bước chính cần được thực hiện như sau:
  1. Xác định cấu trúc thứ bậc của các file
  2. Mô tả RTL code cho từng file, những file có cấp thấp nhất trong cấu trúc sẽ được mô tả trước, các file có cấp cao hơn sẽ được mô tả sau. Thứ tự mô tả RTL code là bottom-to-top. Vì các cấp cao hơn thường sẽ gọi (instance) các file cấp thấp hơn và file cấp cao nhất (top) thường chỉ mô tả các kết nối của các file cấp thấp hơn.
Hình 1. Xác định cấu trúc thứ bậc của các file RTL code sẽ mô tả
Trong ví dụ về CPU 8 bit, chúng ta có 3 khối FETCH, DECODER và EXECUTE. Tương ứng, chúng ta sẽ có 3 file RTL code để mô tả 3 khối này là scpu_fetch.v, scpu_decoder.v và scpu_execute.v. Bên cạch đó là một file để kết nối 3 khối trên là scpu_top.v. Ngoài ra, nếu trong thiết kế có các tham số và định nghĩa được sử dụng trong nhiều file khác nhau thì có thể có thêm các file header để chứa chúng, ví dụ như scpu_define.h, scpu_parameter.h.
Căn cứ theo cấu trúc thứ bậc trên thì các file scpu_fetch.v, scpu_decoder.v và scpu_execute.v sẽ được mô tả trước, file scpu_top sẽ được mô tả sau. Các file scpu_define.h, scpu_parameter.h có thể được mô tả song song với các file trước đó hoặc mô tả sau cùng để tập hợp các tham số và định nghĩa dùng chung.
Ở đây có một số quy định chung để tiện theo dõi như sau:
  1. Mỗi khối sẽ được mô tả bằng một cặp từ khóa module/endmodule nên một khối tương ứng với một module
  2. Mỗi module sẽ được mô tả trong một file riêng tuy nhiên các bạn hoàn toàn có thể mô tả chúng trong cùng một file ".v"
  3. Tên file và tên module sẽ trùng nhau để dễ quản lý. Ví dụ, file scpu_fetch.v sẽ chứa module có tên scpu_fetch.
  4. Tên file và tên module ở đây được đặt theo nguyên tắc <tên module top>_<tên module con>. Ví dụ, scpu_fetch thì scpu là ký hiệu chung chỉ module top, fetch là tên đại diện cho khối chức năng (module con)
  5. File header sẽ có đuôi ".h" chứa các tham số hoặc định nghĩa dùng chung 
1.2 Mô tả RTL code cho từng file
Như đã trình bày, một module ở đây được hiểu là một khối. Một module được mô tả trong một cặp từ khóa module/endmodule. Trước khi đi vào mô tả chi tiết từng file RTL code, chúng ta sẽ xem một file RTL code thường có những thành phần nào.
Một module thường chứa các thành phần cơ bản như sau:
1. Ghi chú ban đầu (file header)
2. Khai báo tiền tổng hợp (pre-synthesis define)
3. Khai báo module
4. Khai báo hằng số (parameter)
5. Khai báo tín hiệu giao tiếp (in/out interface)
6. Khai báo biến và tín hiệu nội (internal signal)
7. Mô tả thân module (module body) 
8. Khai báo endmodule

Trong các thành phần trên thì 3, 5, 7 và 8 là các thành phần bắt buộc phải có. Các thành phần khác có thể có hoặc không tùy vào trường hợp cụ thể. Để minh họa, sau đây, file scpu_fetch.v sẽ được mô tả.

Ghi chú ban đầu là các comment mô tả các thông tin liên quan đến file RTL code như tên công ty, tên dự án, chức năng của file RTL code, tên tác giả, ngày tạo file, các điểm chỉnh sửa trong file so với các phiên bản trước, thông tin quy định về việc phân phối và sử dụng file RTL code và các thông tin liên quan khác. Nội dung phần này sẽ khác nhau tùy quy định từng công ty. Nội dung phần ghi chú ban đầu được đặt sau dấu “//” hoặc trong cặp dấu “/*” và “*/ .
Hình 2. Ví dụ về ghi chú đầu file RTL code của khối FETCH
Khai báo tiền tổng hợp là các chỉ dẫn như `define, `timescale hoặc `include các tập tin chứa các khai báo `define`timescale được sử dụng trong tập tin RTL code. Ví dụ trong thiết kế SCPU, định nghĩa sau được sử dụng để tạo độ trễ khi mô tả mạch tuần tự:
`define DLY #1
Định nghĩa trên dùng để tạo độ trễ 1 đơn vị thời gian trước khi một tín hiệu cập nhật giá trị theo cạnh lên xung clock khi chạy mô phỏng RTL code.
Hình 3. Tạo độ trễ sau cạnh lên xung clock cho các tín hiệu hoạt động theo xung clock
Trong một số trường hợp mô phỏng RTL code, trình mô phỏng cho kết quả không chính xác khi ngõ vào và cạnh lênh xung clock cùng thay đổi tại một thời điểm. Vì vậy, mỗi tín hiệu hoạt động theo xung clock được delay để khi giá trị của nó truyền đến các mạch khác, cũng sử dụng xung clock, thì giá trị này không thay đổi cùng lúc với cạch lên xung clock.
Hình 4. Trình mô phỏng cho kết quả sai ở d_out khi d_in đổi giá trị cùng lúc với cạnh lên clk
Khai báo module là sẽ đi kèm với khai báo endmodule để định nghĩa một khối. ĐI cùng với khai báo module là tên module và danh sách các tín hiệu giao tiếp (input/output/inout) của một module. 
Khai báo hằng số sử dụng từ khóa parameter, localparam hoặc gọi các tập tin chứa khai báo hằng số sử dụng trong RTL code. Khai báo hằng số nằm bên trong khai báo module/endmodule.
Hình 4. Khai báo tiền tổng hợp, khai báo module và khai báo hằng số cho khối FETCH
Khai báo tín hiệu giao tiếp là khai báo các tín hiệu sẽ kết nối đến các module khác bằng các từ khóa input, output hoặc inout. Các tín hiệu giao tiếp này có được từ sơ đồ tín hiệu giao tiếp khi phân tích lõi IP. Một tín hiệu giao tiếp cần có các thông tin quan trọng sau:
  • Chiều tín hiệu (input/output/inout)
  • Loại tín hiệu (reg, wire, ...)
  • Độ rộng tín hiệu

Hình 5. Sơ đồ tín hiệu giao tiếp của các khối

Hình 6. Khai báo tín hiệu giao tiếp trong module scpu_fetch của khối FETCH
Khai báo tín hiệu giao tiếp nội là khai báo các biến nội chỉ được sử dụng trong module và không kết nối đến bất kỳ module nào khác. Phần thân module có thể được mô tả trước khi khai báo phần này vì khi mô tả các mạch nguyên lý cho phần thân module, các biến nội có thể sẽ phát sinh thêm để giúp việc mô tả RTL code dễ dàng hơn. Lưu ý, việc mô tả phần thân module trước không có nghĩ là đoạn code của thân module nằm trên đoạn code khai báo tín hiệu giao tiếp nội trong một module mà vẫn theo nguyên tắc chung là "một biến phải khai báo trước khi sử dụng". Tín hiệu giao tiếp nội cần 2 thông tin quan trọng là loại tín hiệu và độ rộng tín hiệu.
Hình 7. Khai báo tín hiệu giao tiếp nội của khối FETCH
Mô tả thân module là căn cứ trên các mạch nguyên lý và các phân tích chi tiết cấu trúc từng khối để viết code.
Hình 8. Mô tả RTL code cho thanh ghi IR, DR và một phần bộ nhớ memory
Hình 9. Sự tương ứng giữa RTL code và mạch nguyên lý của thanh ghi IR
Hình 10. Sự tương ứng giữa RTL code và mạch nguyên lý của MEMORY
Khai báo endmodule là từ khóa kết thúc việc mô tả RTL code cho một khối.
Hình 11. Khai báo endmodule của khối FETCH
Đối với module có gọi một module khác thì "việc gọi" được viết trong phần thân module và cách gọi đầy đủ như sau:
Hình 12. Gọi và kết nối một module trong một module khác
2. Kiểm tra cú pháp và luật thiết kế (design rules) RTL code
Bước cuối cùng trong công đoạn phân tích thiết kế là kiểm tra các tập tin RTL code trên các phần mềm chuyên dụng. Hai điểm chính mà RTL code phải được kiểm tra là cú pháp và luật thiết kế. Trong đó:
  • Cú pháp là những quy định của ngôn ngữ mô tả phần cứng mà RTL code phải tuân thủ.
  • Luật thiết kế là những quy định khác nhằm hạn chế các nguyên nhân gây ra hoạt động không mong muốn hoặc giúp bạn cải thiện code style (cách viết RTL code) tốt hơn.  

Hình 13. Kiểm tra RTL code với phần mềm LEDA của Synopsys
Thường sẽ có 2 cấp độ chính là:

  • Những cảnh báo phải sửa: nếu không sửa sẽ không thể tổng hợp hay mô phỏng được
  • Những cảnh báo không cần sửa: những lỗi này là không bắt buộc phải sửa nhưng người thiết kế phải kiểm tra từng cảnh báo của phần mềm để đảm bảo những "cảnh báo" đó không phải là một "lỗi"
3. RTL code (Phiên bản chưa mô phỏng cơ bản)
Link download RTL code của SCPU: CPU 8 bit SCPU
pass (nếu có): nguyenquanicd
Các file:
  • scpu_top.v
  • scpu_fetch.v
  • scpu_decoder.v
  • scpu_execute.v
  • scpu_define.h
  • scpu_parameter.h

Hình 14. Kết quả tổng hợp trên FPGA bằng Quartus
Đến đây, chúng ta đã có phiên bản RTL code ban đầu của một lõi IP. Bước cuối cùng là mô phỏng và sửa lỗi cơ bản sẽ được trình bày ở bài tiếp theo.

1 bình luận: