Những hành trình đầy cảm hứng

Theo dõi những câu chuyện của các học giả và các chuyến thám hiểm nghiên cứu của họ

Verilog Cơ Bản Cho Thiết Kế Vi Mạch: Khởi Tạo Phần Tử Nguyên Thủy (Primitive Instantiation)

Thao Dinh

Mon, 16 Jun 2025

Verilog Cơ Bản Cho Thiết Kế Vi Mạch: Khởi Tạo Phần Tử Nguyên Thủy (Primitive Instantiation)

Verilog Cơ Bản Cho Thiết Kế Vi Mạch: Khởi Tạo Phần Tử Nguyên Thủy (Primitive Instantiation)


Mặc dù việc sử dụng hoàn toàn các phần tử nguyên thủy trong thiết kế mạch số bằng ngôn ngữ mô tả phần cứng (HDL) như Verilog hoặc SystemVerilog có thể đi ngược lại mục tiêu chính của việc sử dụng HDL – đó là trừu tượng hóa và dễ mở rộng thiết kế – nhưng ngôn ngữ Verilog vẫn cho phép người dùng thiết kế bất kỳ mạch số nào chỉ bằng các phép toán logic cơ bản.

Các loại cổng logic tiêu chuẩn như AND, OR, NAND, NOR, XOR, XNOR, và NOT đều được tích hợp sẵn trong Verilog. Ngoài ra, còn có các phần tử như buffer (bộ đệm)driver ba trạng thái (Tri-state driver). Có bốn loại driver ba trạng thái khác nhau (được liệt kê trong bảng 1.1 bên dưới).

Việc khởi tạo các phần tử nguyên thủy là một cách để xây dựng bất kỳ mạch logic nào, tuy nhiên đây là phương pháp dễ mắc lỗi và tốn thời gian. Dẫu vậy, ta vẫn bắt đầu với phương pháp này vì nó là cách tiếp cận tốt để giới thiệu cú pháp và cấu trúc của Verilog, đồng thời xây dựng trên nền tảng kiến thức logic số mà đa số người học đã quen thuộc.

 

Khái niệm Khởi Tạo (Instantiation)

Khởi tạo là một khái niệm cơ bản trong thiết kế bằng HDL – xuất hiện từ trước khi các ngôn ngữ HDL ra đời. Khởi tạo nghĩa là tạo ra một đối tượng thiết kế trừu tượng thuộc một kiểu xác định trong sơ đồ thiết kế, nơi nó có thể được kết nối với các đối tượng khác, các đầu vào và đầu ra.

Một instance (phiên bản) không phải là một linh kiện vật lý, mà chỉ là một thực thể logic trong mô hình. Khi làm việc với HDL, bạn có thể tạo ra bao nhiêu instance tùy ý, chỉ cần khai báo chúng trong cấu trúc thiết kế.

Thiết kế thông qua khởi tạo các phần tử nguyên thủy được gọi là thiết kế từ dưới lên (bottom-up design). Bạn bắt đầu từ những chức năng đơn giản nhất, tạo từng instance một, cho đến khi hoàn thiện thiết kế ở cấp độ cao hơn. Về mặt lý thuyết, mọi thiết kế đều có thể được xây dựng theo cách này, nhưng trên thực tế, đây là cách tiếp cận phi thực tế cho các hệ thống lớn, do mức độ phức tạp và thời gian phát triển.

 

Kích Thước và Định Nghĩa

Khi khởi tạo một phần tử nguyên thủy, kích thước của thành phần sẽ được xác định bởi số lượng dây tín hiệu (wires) được nối với nó. Không có mối liên hệ định sẵn giữa một instance của cổng logic Verilog và bất kỳ cổng logic vật lý nào thuộc công nghệ cụ thể. Nghĩa là, bạn có thể khởi tạo cổng logic với số lượng ngõ vào tùy ý (tối đa 1024), dù trong thực tế không tồn tại phần cứng tương ứng.

Không chỉ các phần tử logic cơ bản, bạn còn có thể khởi tạo toàn bộ module thiết kế này trong một thiết kế khác để tạo nên cấu trúc phân cấp lớn (hierarchy). Điều này cho phép thiết kế linh hoạt và mở rộng.

 

Quy Tắc Cú Pháp trong Verilog

Tuy bạn có thể khởi tạo phần tử với bất kỳ kích thước nào, nhưng vẫn cần tuân theo một số quy tắc cú pháp bắt buộc. Vi phạm cú pháp sẽ khiến chương trình không thể biên dịch được. Các lỗi này phải được sửa thủ công trong trình soạn thảo văn bản.

Các quy tắc cơ bản như sau:

  • Mỗi instance phải có đúng một ngõ ra (output), trừ khi đó là NOT (inverter) hoặc BUF (buffer).
  • Với NOT và BUF, mỗi instance phải có đúng một ngõ vào (input) nhưng có thể có nhiều ngõ ra.
  • Trong khai báo instance, output luôn được viết đầu tiên, sau đó là các input.
  • Các tên primitive (như nand, and, or...) là từ khóa của Verilog và phải viết thường hoàn toàn. Những từ này không được dùng làm tên biến hoặc tên thiết kế.
  • Bạn cũng có thể định nghĩa primitive do người dùng tự viết (user-defined primitive). Các tên này không bị giới hạn viết thường, nhưng vẫn phải tuân thủ các quy tắc về khai báo instance.

 

Ví dụ Cụ Thể: Khởi tạo Cổng NAND Ba Ngõ Vào

Dưới đây là ví dụ khởi tạo một cổng NAND có ba đầu vào trong Verilog:

nand #3 G1 (Y, A, B, C);

  • nand: từ khóa chỉ loại primitive (viết thường)
  • #3: tham số độ trễ, tức là đầu ra chỉ thay đổi sau 3 đơn vị thời gian
  • G1: tên của instance (tùy chọn nhưng nên dùng)
  • (Y, A, B, C): Y là đầu ra, A/B/C là các đầu vào
  • Dấu ; kết thúc câu lệnh là bắt buộc

Trong ví dụ này, các tên biến (Y, A, B, C, G1) đều được viết hoa. Dù không bắt buộc, nhiều kỹ sư thiết kế có thói quen viết hoa các tên biến, để dễ phân biệt với từ khóa Verilog (luôn viết thường).

Việc khởi tạo các phần tử nguyên thủy trong Verilog là bước đầu quan trọng để:

  • Làm quen với cú pháp HDL
  • Rèn luyện khả năng tư duy thiết kế mạch số
  • Tạo nền tảng vững chắc cho các thiết kế mở rộng hơn, như module, hierarchy
  • Hiểu sâu bản chất hoạt động của từng loại cổng logic và cách thiết kế bottom-up

Dù không thực tế cho các thiết kế lớn, nhưng đây là phần không thể thiếu trong hành trình học Verilog và thiết kế hệ thống số.

Bảng 1.1: Bốn loại driver ba trạng thái khác nhau


Một mô phỏng đầy đủ (exhaustive simulation) cho instance cổng logic ở trên được trình bày trong Hình 1.1, kèm theo bảng chân trị (truth table).

Hình 1.1: Dạng sóng mô phỏng và bảng chân trị

của cổng NAND ba ngõ vào



Tất cả các toán tử Boolean cơ bản đều có thể được khởi tạo (instantiate) theo cách tương tự. Như một phần ôn lại các kiến thức nền tảng về đại số Boolean, bảng chân trị cho từng loại primitive (nguyên thủy) tích hợp sẵn được hiển thị bên dưới, cùng với một ví dụ về cách khởi tạo từng loại trong Verilog.

Như đã đề cập trước đó, mỗi primitive phải có đúng một đầu ra (output), ngoại trừ các primitive chỉ có một đầu vào như not và buf. Các primitive này phải có đúng một đầu vào, nhưng có thể có nhiều đầu ra. Vì vậy, đoạn mã khởi tạo sau đây sẽ tạo ra ba đầu ra song song giống hệt nhau, tất cả đều theo dõi (track) cùng một đầu vào duy nhất là dây A. Tính năng này hiếm khi thực sự hữu dụng trong thiết kế, nhưng vẫn hợp lệ theo cú pháp của Verilog.

0 Bình luận

Để lại bình luận