Thứ Sáu, 28 tháng 12, 2018

[System Verilog] Sự khác nhau của mô tả module trong System Verilog và Verilog

Vì mục đích sử dụng của hai ngôn ngữ khác nhau, Verilog chuyên hỗ trợ mô tả thiết kế phần cứng trong khi System Verilog được mở rộng hơn để hỗ trợ mạnh cho việc mô hình hóa phục vụ mô phỏng, nên nhiều quy định có sự khác biệt. Bài viết này phân tích sự khác nhau trong việc mô tả module của ngôn ngữ System Verilog và Verilog.

1) Mở đầu
Một module là thành phần được mô tả bằng một cặp từ khóa module-endmodule. Một module có thể xem như một khối (block) chức năng riêng và phân biệt với các khối chức năng khác. Định nghĩa module được sử dụng để phân chia cấu trúc và cấp bậc trong một thiết kế hoặc môi trường mô phỏng. Điều này giúp việc quản lý các chức năng của thiết kế dễ dàng hơn.
Hình 1. Một thiết kế có cấu trúc phân cấp (hierarchical structure)
Hình 1 minh họa một thiết kế có cấu trúc phân cấp. Chúng ta sẽ sử dụng định nghĩa module-endmodule để mô tả RTL code cho từng cấp trong thiết kế. Cụ thể, chúng ta sẽ có các module sau:
  1. Mức 1: module SOC
    1. Mức 2: module sys
      1. Mức 3: module clock_generator
      2. Mức 3: module reset_generator
      3. Mức 3: module power_management
    2. Mức 2: module core
      1. Mức 3: module CPU
      2. Mức 3: module sys_bus
        1. Mức 4: module bus_1
        2. Mức 4: module bus_2
        3. Mức 4: module bus_3
      3. Mức 3: module USB
      4. Mức 3: module video
      5. Mức 3: module UART
      6. Mức 3: module CAN
Mục đích sử dụng định nghĩa module của System Verilog và Verilog tuy giống nhau nhưng giới hạn về cách thức sử dụng thì có sự khác biệt.
2) Cấu trúc thứ bậc trong Verilog
Đối với Verilog, để tạo ra một thiết kế có cấu trúc có cấp bậc (hierarchy) như trên thì chúng ta cần thực hiện 2 bước sau:
1. Mô tả các module độc lập và không được lồng vào nhau. Chú ý, đối với Verilog không được phép định nghĩa module này lồng trong module kia, nghĩa là một cặp từ khóa module-endmodule không được phép chứa bất kỳ một cặp từ khóa module-endmodule nào khác. RTL code của các module được mô tả độc lập có thể chứa trong 1 file hoặc nằm trong các file khác nhau.

Hình 2: Verilog - Không được mô tả các module lồng vào nhau (trái) mà phải mô tả RTL của các module độc lập (phải)
Hình 3: RTL code của các module có thể đặt trong các file riêng biệt (trái) hoặc trong cùng một file (phải)
2. Gọi module khác bên trong nó bằng cách instantiating. Khi một module được gọi trong một module khác, nó sẽ tạo ra một instance. Một module có thể gọi nhiều module khác nhau hoặc gọi một module nhiều lần để tạo ra nhiều instance khác nhau. Các instance kết nối với nhau và với các thành phần khác trong module gọi nó thông qua các liên kết input, output hoặc port hay chiều (inout).

Hình 4: Verilog - Gọi một module trong một module khác bằng cách tạo instance
Hình 5: Verilog - module bus được gọi 3 lần để tạo ra 3 instance trong module sys_bus
3) Cấu trúc thứ bậc trong System Verilog
Đối với System Verilog, ngoài khả năng cho phép gọi module như Verilog thì nó còn cho phép các khai báo module lồng nhau (nested module). Nghĩa là một cặp từ khóa module-endmodule có thể được khai báo bên trong một cặp từ khóa module-endmodule khác. Tuy nhiên, việc khai báo lồng nhau này chỉ sử dụng trong các thiết kế mô phỏng, mô mình mô phỏng và không sử dụng để mô tả RTL code của thiết kế khả tổng hợp. Để tạo cấu trúc thứ bậc cho một thiết kế khả tổng hợp, chúng ta chỉ sử dụng phương pháp instance như đã trình bày trên đây.
Việc khai báo các module lồng nhau giúp:
1. Phân chia các phần logic khác nhau trong một module mà không cần sử dụng port (không cần khai báo port).
2. Tạo thư viện module cục bộ chỉ sử dụng cho một phần nhất định trong một thiết kế.

Để minh họa việc cách sử dụng khai báo module lồng nhau trong System Verilog, chúng ta xét mô hình D-FlipFlop như sau:

  • ck: là tín hiệu clock của DFF
  • pr: là tín hiệu dùng để thiết lập ngõ ra q bằng 1. Tích cực mức 0.
  • clr: là tín hiệu dùng để thiết lập ngõ ra q bằng 0.Tích cực mức 0.
  • d: là chân dữ liệu đầu vào
  • q: là chân dữ liệu đầu ra
  • nq: là chân dữ liệu thể hiện giá trị bù của q
Hình 6: Mô hình D-FlipFlop
Để mô tả mô hình trên, chúng ta có thể tạo một module tên dff_model sử dụng mô hình cổng nand được System Verilog hỗ trợ sẵn như sau: 
module dff_model (input d, ck, pr, clr, output q, nq);
 wire q1, nq1, q2, nq2;
 nand n1a (nq1, d, clr, q1);
 nand n1b (q1, ck, nq2, nq1);
 nand n2a (nq2, ck, clr, q2);
 nand n2b (q2, nq1, pr, nq2);
 nand n3b (q, nq2, clr, nq);
 nand n3a (nq, q1, pr, q);
endmodule
Mô hình cổng nand được sử dụng trong đoạn code trên là NAND có 3 ngõ vào, 1 ngõ ra. Nếu muốn phân chia các thành phần logic nand thành từng cụm riêng, mỗi cụm có có cấu trúc như 1 RS latch, chúng ta sẽ sử dụng khai báo module như sau:
module dff_model (input d, ck, pr, clr, output q, nq);
  wire q1, nq1, nq2;
  module latch1;
    nand n1a (nq1, d, clr, q1);
    nand n1b (q1, ck, nq2, nq1);
  endmodule
  latch1 i1();
  module latch2;
    wire q2; // only be an internal signal of latch2
    nand n2a (nq2, ck, clr, q2);
    nand n2b (q2, nq1, pr, nq2);
  endmodule
  latch2 i2();

  module latch3;
    nand n3b (q, nq2, clr, nq);
    nand n3a (nq, q1, pr, q);
  endmodule
  latch3 i3();
endmodule
Hình 7: Mô hình DFF với 3 cấu trúc Latch
Với cách mô tả như trên, chúng ta tạo ra một module có cấu trúc cấp bậc với dff_model là top module và bên trong chưa 3 instance là i1, i2 và i3.
Hình 8: Cấu trúc cấp bậc của ví dụ hình 7
Những điểm cần lưu ý trong đoạn code cho ví dụ hình 7:
1. Không khai báo port cho các module con latch1, latch2 và latch3
2. Việc khai báo các biến (trong ví dụ này các biến được khai báo bằng từ khóa input, output wire) trong module dff_model và trùng tên với các tín hiệu dùng trong module latch1, latch2 và latch3 sẽ tạo ra các kết nối từ các module con latch1, latch2 và latch3 đến module dff_module. 
3. Một khai báo biến bên trong module con, ví dụ như q2 của module latch2, chỉ có tác dụng trong phạm vi của module con, và không tạo kết nối đến bên ngoài.
Trong ví dụ trên đây, sau khi latch1, latch2 và latch3 được khai báo, chúng được gọi để tạo ra 3 instance i1, i2 và i3. Trong trường hợp này, mỗi module con chỉ được gọi 1 lần để sử dụng trong module dff_model nên có thể bỏ các dòng code gọi module. Lúc này, các module con không khai báo port sẽ được ngầm hiểu là 1 instance.
module dff_model (input d, ck, pr, clr, output q, nq);
  wire q1, nq1, nq2;
  module latch1;
    nand n1a (nq1, d, clr, q1);
    nand n1b (q1, ck, nq2, nq1);
  endmodule
  module latch2;
    wire q2; // only be an internal signal of latch2    nand n2a (nq2, ck, clr, q2);
    nand n2b (q2, nq1, pr, nq2);
  endmodule

  module latch3;
    nand n3b (q, nq2, clr, nq);
    nand n3a (nq, q1, pr, q);
  endmodule
endmodule
Hình 9: Cấu trúc cấp bậc khi không có dòng code gọi instance đối với các module con không có khai báo port
Chú ý, một module con chỉ được ngầm hiểu là 1 instance khi đó là một module "KHÔNG CÓ KHAI BÁO PORT". Nếu các module latch1, latch2 và latch3 có mô tả đầy đủ các port input, output như một module thông thường thì phải có dòng code gọi module để tạo instance.
Việc khai báo một module con với đầy đủ các khai báo port input, output, inout được sử dụng khi module con này được gọi nhiều lần trong top module.
module part1(....);
  module and2 (input a, b, output z);
  ....
  endmodule
  module or2 (input a, b, output z);
  ....
  endmodule
  ....
  and2 u1(....), u2(....), u3(....);
  or2 y1(...);
  or2 y2(...);
  .....
endmodule
Trong ví dụ trên, hai module con là and2 và or2 được gọi nhiều lần để tạo ra nhiều instance khác nhau trong module part1. Mỗi instance này phải được mô tả các port kết nối như cách gọi module đã trình bày trong phần "2) Cấu trúc thứ bậc trong Verilog" của bài này. Việc khai báo module lồng nhau như trên giúp tạo thư viện module cục bộ chỉ sử dụng cho một phần nhất định trong một thiết kế.
Đến đây, bạn có thể thắc mắc "Tại sao cần phải khai báo module and2 và or2 trong module part1 mà không khai báo bên ngoài?". Việc khai báo hai module and2 và or2 ngoài module part1 và gọi chúng bằng cách instance là hoàn toàn không có vấn đề gì. Bạn vẫn tạo ra được module part1 như mong muốn. Tuy nhiên, việc khai báo bên trong giúp giới hạn phạm vi của module con. Trong trường hợp này, and2 và or2 thuộc phạm vi của module part1 có chức năng X1 và X2. Nhưng trong một module khác, ví dụ như module part2, chúng ta có thể tạo thêm module con cùng tên and2 và or2 có chức năng Y1 và Y2, trong đó chức năng Y1 và Y2 hoàn toàn khác chức năng X1 và X2. Nếu bạn khai báo and2 và or2 bên ngoài module part 1, để tạo thêm module có chức năng Y1 và Y2 thì bạn phải tạo module có tên khác với and2 và or2. 

Tóm lại:
1. Verilog: Không cho phép khai báo module lồng nhau
2. System Verilog: Cho phép khai báo module lồng nhau
3. Nếu mô tả RTL code khả tổng hợp (synthesis) thì phải theo quy định của Verilog
4. Nếu mô tả code để xây dựng các mô hình mô phỏng, thư viện mô phỏng thì có thể dùng quy định của Verilog hoặc System Verilog
5. Sử dụng khai báo module lồng nhau khi cần giới hạn phạm vi sử dụng của module hoặc phân chia các thành phần logic trong một module.

0 bình luận:

Đăng nhận xét