• 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

Hiển thị các bài đăng có nhãn Kiến Thức Cơ Bản. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Kiến Thức Cơ Bản. Hiển thị tất cả bài đăng

Thứ Bảy, 1 tháng 2, 2020

[Multi-clock Design] Bài 3 - Kỹ thuật đồng bộ tín hiệu nhiều bit

Bài viết này trình bày về các phương pháp và kỹ thuật phổ biến dùng để đồng bộ một tín hiệu nhiều bit, 2 bit trở lên, khi tín hiệu này được lan truyền giữa hai miền clock bất đồng bộ (asynchronous clock) trong các chip sử dụng nhiều nguồn clock khác nhau.
Một số từ khóa và từ viết tắt:
  • Trạng thái bất ổn định (metastability)
  • Mạch đồng bộ (synchronizer)
  • FF (Flip-Flop)
Các bài viết liên quan:

1) Vấn đề đồng bộ tín hiệu nhiều bit
Đối với tín hiệu 1 bit, việc đồng bộ có thể đơn giản là chỉ cần 2 hoặc nhiều Flip-Flop (FF) mắc nối tiếp. Nếu trạng thái bất ổn định (metastability) xảy ra và ổn định trước khi lan truyền đến FF cuối cùng trong mạch đồng bộ thì giá trị ngõ ra của mạch đồng bộ sẽ là giá trị trước đó hoặc giá trị mới được mong muốn. Điểm này rất quan trọng vì nó giúp miền nhận không xử lý sai khi dùng tín hiệu ngõ ra mạch đồng bộ làm tín hiệu điều khiển các logic khác.
Hình 1: Hiện tượng bất ổn định xảy ra trên tín hiệu 1 bit
Trong hình minh họa trên, khi hiện tượng bất ổn định xảy ra ở FF đầu tiên, pre_out sẽ ổn định về giá trị 0 (giá trị trước đó) hoặc 1 (giá trị mới). Điều này làm cho ngõ ra mạch đồng bộ sync_out chỉ có thể là 0 (giá trị trước đó) hoặc 1 (giá trị mới) ở chu kỳ tiếp theo.
  • Nếu sync_out=0 (giá trị cũ) thì nó sẽ không làm thay đổi trạng thái của logic mà nó sẽ điều khiển. Khi giá trị ngõ vào async_in vẫn duy trì mức tích cực thì sync_out=1 và lái logic mà nó điều khiển đến trạng thái mới như mong muốn
  • Nếu sync_out=1 (giá trị mới) thì nó lái logic đến trạng thái mới như mong muốn.
Do hiện tượng bất ổn định, một tín hiệu nhiều bit (2 bit trở lên) như bus dữ liệu, bus địa chỉ, giá trị trạng thái, … thường không thể chỉ được đồng bộ chỉ bằng 2 hoặc nhiều FF như đối với tín hiệu 1 bit. Chú ý, "thường không thể" nghĩa là một tín hiệu nhiều bit vẫn có thể chỉ cần đồng bộ bằng 2 hoặc nhiều FF nối tiếp trong một số trường hợp đặc biệt. Nguyên nhân, nếu hai hoặc nhiều bit thay đổi giá trị và cùng gây ra hiện tượng bất ổn định thì một giá trị không mong muốn có thể được sinh ra trên ngõ ra của mạch đồng bộ.
Hình 2: Ảnh hưởng của hiện tượng bất ổn định trên tín hiệu nhiều bit
Trong hình minh họa trên đây, khi xảy ra hiện tượng bất ổn định thì giá trị sync_out có thể là một trong các tổ hợp 00/01/10/11. Nếu tổ hợp xảy ra là 00 (giá trị cũ) hoặc 11 (giá trị mới) thì miền nhận có thể xử lý đúng như mong muốn. Nhưng, nếu một trong hai tổ hợp 01 10 xuất hiện thì miền nhận có thể xử lý sai vì đây là hai trạng thái không mong muốn. Vì vậy, đối với tín hiệu nhiều bit, một cơ chế hoặc phương pháp đồng bộ cần được áp dụng để tránh nhận các giá trị không mong muốn.
Để thực hiện cơ chế đồng bộ cho một tín hiệu nhiều bit, chúng ta cần tập trung vào 2 điểm sau đây:
  • Việc sinh ra các giá trị không mong muốn là do 2 hoặc nhiều bit của tín hiệu cùng thay đổi mức logic. Điều này làm cho hiện tượng bất ổn định có thể xảy ra cùng lúc trên các bit được thay đổi mức logic. Như vậy, một tín hiệu nhiều bit có thể chỉ cần đồng bộ bởi 2 hoặc nhiều FF mắc nối tiếp nếu chỉ 1 bit thay đổi tại một thời điểm trong suốt quá trình hoạt động. Nghĩa là, giá trị trên tín hiệu không bao giờ thay đổi giá trị nhiều bit cùng một lúc. Trong trường hợp này, nếu hiện tượng bất ổn định xảy ra thì giá trị của tín hiệu này sẽ chỉ có thể là giá trị trước đó hoặc giá trị mới như mong muốn chứ không xuất hiện tổ hợp giá trị không mong muốn.
  • Khi hiện tượng bất ổn định xảy ra, trong lần cập nhật giá trị mới đầu tiên, tại thời điểm T2 của hình 2, giá trị ngõ ra của mạch đồng bộ là một giá trị ngẫu nhiên. Để đảm bảo ngõ ra cập nhật được giá trị logic mới thì ngõ vào mạch đồng bộ phải duy trì ổn định giá trị mới trong một khoảng thời gian đảm bảo cho miền clock nhận bắt được giá trị đúng. Khoảng thời gian này phải lớn hơn (chu kỳ của clock nhận + thời gian setup của FF + thời gian hold của FF). Theo hình 2, async_in có thể được giữ 2 chu kỳ xung clock rclk để đảm bảo một giá trị đúng có thể được bắt bởi cạnh lên T2.
2) Ví dụ về đồng bộ sai tín hiệu nhiều bit
Một giá trị của máy trạng thái (FSM) cần được truyền từ xung clock tclk sang miền xung clock rclk. Giá trị này gồm 2 bit tên bus_state[1:0] quy định các trạng thái như sau:
IDLE = 2’b00;
ACTIVATE = 2b01;
RUN = 2’b10;
DEACTIVATE = 2’b11;
Hình 3: Ví dụ sai về việc đồng bộ một giá trị trạng thái nhiều bit
Trong hình vẽ trên, trạng thái được chuyển đổi lặp lại theo thứ tự IDLE->ACTIVATE->RUN->ACTIVATE. Giả sử bus_state[1:0] chỉ được đồng bộ bằng 2 FF tại miền xung clock rclk:
  • Nếu trạng thái chuyển từ IDLE (2’b00) -> ACTIVATE (2’b01) hoặc chuyển từ RUN (2’b10) -> DEACTIVATE (2’b11) thì miền clock nhận rclk sẽ phát hiện đúng trạng thái cho dù hiện tượng bất ổn định xảy ra vì chỉ một bit thay đổi giá trị.
  • Nếu trạng thái chuyển từ ACTIVATE (2’b01) -> RUN (2’b10) hoặc chuyển từ DEACTIVATE (2’b11) -> IDLE (2’b00) thì miền clock nhận rclk có thể nhận được một trạng thái sai nếu hiện tượng bất ổn định xảy ra. Ví dụ, ACTIVATE có thể chuyển sang trạng thái IDLE (2'b00) hoặc DEACTIVATE (2'b11) trước khi chuyển sang trạng thái RUN.
Một ví dụ khác, giá trị của một bộ đếm lên nhị phân truyền từ miền clock tclk sang miền clock rclk. Nếu giá trị bộ đếm này chỉ đồng bộ bằng các FF mắc nối tiếp, ví dụ như 2 FF, thì giá trị nhận được tại miền clock rclk có thể sẽ không tuần tự, tăng đều một đơn vị như bên miền clock tclk khi hiện tượng bất ổn định xảy ra.
Hình 4: Ví dụ sai về việc đồng bộ một bộ đếm nhị phân nhiều bit
Trong hình minh họa trên đây, một bộ đếm lên nhị phân 4 bit, bcounter[3:0],
  • Miền tclk: 0000 (0) -> 0001 (1) -> 0010 (2) -> 0011 (3) -> 0100 (4) -> …
  • Miền rclk: 0000 (0) -> 0001 (1) -> (0, 3) -> 0010 (2) -> 0011 (3) -> (0, 1, 2, 5, 6, 7) -> 0100 (4) -> …
Trong ví dụ trên đây khi bộ đếm tăng giá trị từ 1 lên 2, hai bit cuối thay đổi trạng thái logic. Tại miền clock rclk, nếu xảy ra hiện tượng bất ổn định trên 2 bit, giá trị bộ đếm nhận được có thể là 0 hoặc 3 trước khi đạt đến giá trị 2. Tương tự, tại thời điểm giá trị bộ đếm tang từ 3 lên 4, 3 bit cuối thay đổi mức logic. Nếu hiện tượng metastable xảy ra trên cả 3 bit, giá trị bộ đếm nhận được trên miền rclk có thể là 0, 1, 2, 5, 6 hoặc 7 trước khi đạt đến giá trị đúng là 4.
3) Các phương pháp đồng bộ tín hiệu nhiều bit
Việc đồng bộ tín hiệu nhiều bit cần giải quyết 2 vấn đề:
  • Hạn chế sự lan truyền trạng thái bất ổn định của tín hiệu đến các logic bên trong miền clock nhận
  • Lấy mẫu đúng giá trị mong muốn hoặc miền clock nhận không xử lý (hoạt động) sai khi hiện tượng bất ổn định xảy ra và triệt tiêu trên những tầng đầu tiên của mạch đồng bộ nhiều FF mắc nói tiếp.
Tùy vào trường hợp cụ thể, một trong các phương pháp đồng bộ sau đây có thể được áp dụng để đồng bộ tín hiệu nhiều bit:
  • Sử dụng logic kiểm tra giá trị tín hiệu nhận được để đảm bảo nhận được giá trị đúng
  • Sử dụng tín hiệu cho phép (enable) để xác định thời điểm giá trị hợp lệ
  • Sử dụng cơ chế chuyển đổi giá trị thay đổi nhiều bit thành giá trị chỉ thay đổi 1 bit
  • Sử dụng giao thức bắt tay giữa hai miền clock để nhận biết khi nào giá trị được truyền và khi nào giá trị đã được nhận. Có hai loại giao thức bắt tay phổ biến là:
    • Bắt tay 4 pha (4-phase handshake)
    • Bắt tay 2 pha (2-phase handshake)
  • Sử dụng bộ nhớ đệm giữa hai miền như FIFO, RAM, ...
Xin nhấn mạnh rằng, việc áp dụng phương pháp nào để đồng bộ phải căn cứ trên yêu cầu thực tế vì mỗi phương pháp sẽ có ưu điểm và nhược điểm riêng. Các mục tiếp theo sẽ mô tả tổng quát các phương pháp trên.
4) Phương pháp kiểm tra sự ổn định của giá trị nhận được
4.1) Mô tả nguyên lý
Như đã trình bày ở các mục trên, khi hiện tượng bất ổn định xảy ra ở các tầng FF trước tầng FF cuối cùng, giá trị nhận được có thể sai. Giá trị này chỉ tồn tại một chu kỳ xung clock miền nhận, rclk, nếu ngõ vào từ miền clock truyền, tclk, tiếp tục giữ ổn định giá trị trong nhiều chu kỳ xung clock rclk tiếp theo.
Hình 5: Mạch nguyên lý của phương pháp kiểm tra sự ổn định của giá trị nhận
Trong hình minh họa trên, một tầng FF được sử dụng ngay sau mạch đồng bộ để lưu lại giá trị ngõ ra của mạch đồng bộ, sync_out, theo từng chu kỳ xung clock rclk. Giá trị của tầng FF này, sync_tmp, sẽ được so sánh với ngõ ra của mạch đồng bộ, sync_out. Nếu hai giá trị này bằng nhau thì đây là giá trị ổn định được truyền từ miền clock tclk. Ngõ ra bộ so sánh, data_valid, sẽ tích cực để báo hiệu một giá trị hợp lệ cần được nhận. Trong ví dụ minh họa, khi data_valid tích cực, thanh ghi rec_data sẽ cập nhật giá trị mới. Giá trị mới có thể lấy từ sync_tmp hoặc sync_out vì lúc này, giá trị của hai tín hiệu này bằng nhau và bằng giá trị ổn định được truyền từ miền tclk.
4.2) Điều kiện sử dụng
Điều kiện sử dụng của mạch này là tín hiệu ngõ vào, async_in, phải duy trì ổn định giá trị mới đủ để rclk bắt đúng giá trị này từ 2 lần trở lên.
Chi tiết hơn, chúng ta hãy xem xét chi tiết sự tích cực của tín hiệu data_valid trong trường hợp xấu nhất để hiểu rõ hoạt động của cơ chế so sánh này.
Trường hợp xấu nhất là trường hợp xảy ra vi phạm timing khi ngõ thay đổi giá trị. 
Hình 6: Một waveform của ví dụ hình 5
Trong hình minh họa trên đây, async_in được duy trì trong 3 chu kỳ xung clock rclk. Điều này đảm bảo rclk chắc chắn bắt được giá trị đúng tại cạnh lên ở T2 và T3. Lưu ý, async_in được lái theo clock tclk nhưng tclk không được thể hiện ở đây.
Trường hợp xấu nhất, thời điểm T1 và T4 đều vi phạm timing, giá trị sync_out chỉ chắc chắn có giá trị mong muốn là 2'b11 trong 2 chu kỳ từ T3 đến T4 và từ T4 đến T5. Điều này ứng với việc data_valid chỉ đảm bảo chắc chắn tích cực trong chu kỳ từ T4 đến T5, lúc data_tmp=data_out=2'b11.
Nếu vi phạm timing tại T1 làm giá trị pre_out ổn định về 2'b11 thì data_valid sẽ tích cực trong chu kỳ từ T3 đến T4.
Nếu vi phạm timing tại T4 làm giá trị pre_out ổn định về 2'b11 thì data_valid sẽ tích cực trong chu kỳ từ T5 đến T6.
Như vậy độ rộng tối thiểu là data_valid là 1 chu kỳ rclk và độ rộng tối đa của data_valid là 3 chu kỳ rclk.
4.3) Ưu điểm và chú ý
Mục này nêu ra các ưu điểm và chú ý khi dùng phương pháp này. "chú ý" có thể là nhược điểm của phương pháp này hoặc không.
Ưu điểm:
  • Cơ chế đồng bộ đơn giản
  • Không cần tạo thêm tín hiệu giao tiếp mới giữa hai miền lock truyền và nhận
Chú ý:
  • Phải tuân thủ ràng buộc về độ rộng xung của tín hiệu, một giá trị mới phải duy trì trong khoảng thời gian đủ để miền clock nhận chắc chắn bắt đúng từ 2 lần trở lên. Điều này làm cho miền clock truyền, tclk, có thể phải thêm logic để duy trì độ rộng xung của các tín hiệu như yêu cầu.
  • Số lượng FF của mạch đồng bộ càng lớn khi số lượng bit tín hiệu càng nhiều. Điểm này ảnh hưởng đến tài nguyên và công suất tiêu thụ.
  • Tài nguyên bộ so sánh giá trị lớn khi số lượng bit càng nhiều. Điểm này ảnh hưởng lớn đến độ trễ trên logic mạch tổ hợp.
  • Thời gian tối thiểu để miền nhận có thể nhận biết đúng giá trị mới là 4 chu kỳ rclk, từ lúc ngõ vào thay đổi giá trị ở T1 đến lúc nhận biết được data_valid tích cực ở T5.
  • Không sử dụng cho trường hợp một giá trị giống nhau được dùng nhiều lần liên tiếp. Nếu miền clock tclk truyền liên tiếp một giá trị nhiều lần, ví dụ như truyền 10 lần giá trị 2'b00, và các giá trị này là phân biệt nhau thì phương pháp này không thể nhận biết được số lần truyền nhận vì nó chỉ giữ tích cực tín hiệu data_valid liên tiếp nhiều chu kỳ trong trường hợp này.
5) Phương pháp dùng tín hiệu cho phép
5.1) Mô tả nguyên lý
Thay vì để miền nhận tự kiểm tra giá trị hợp lệ. Miền truyền tclk sẽ tạo thêm một tín hiệu 1 bit để báo hiệu thời điểm giá trị truyền hợp lệ. Trong cơ chế này, chỉ tín hiệu cho phép là cần được đồng bộ qua mạch nhiều FF mắc nối tiếp.
Hình 7: Mạch nguyên lý của phương pháp đồng bộ dùng tín hiệu cho phép
Trong mạch nguyên lý trên, data_valid được đồng bộ bằng 2 FF để tạo thành data_en. Sau đó, data_en được dùng để điều khiển thời điểm cập nhật giá trị mới từ async_in đến rec_data.
5.2) Điều kiện sử dụng
Điều kiện sử dụng của phương pháp này là:
  • Tín hiệu cho phép data_valid phải ổn định đủ để miền clock rclk chắc chắn bắt được đúng giá trị tích cực. Thời gian này phải lớn hơn "một chu kỳ rclk + thời gian setup của FF + thời gian hold của FF"
  • Tín hiệu ngõ vào async_in phải duy trì ổn định giá trị cần truyền trong mọi trường hợp data_en tích cực.
Xem xét waveform sau đây để xác định mối liên hệ giữa data_valid và thời gian duy trì giá trị cần truyền trên async_in.
Hình 8: Một waveform của ví dụ hình 7
Trong hình minh họa trên đây, data_valid được duy trì trong 2 chu kỳ xung clock rclk. Điều này đảm bảo rclk chắc chắn bắt được giá trị đúng tại cạnh lên ở T2. Lưu ý, data_valid async_in được lái theo clock tclk nhưng tclk không được thể hiện ở đây.
Thời điểm từ T3 đến T4, data_en chắc chắn tích cực.
Nếu vi phạm timing tại T1 làm giá trị pre_en ổn định về 1 thì data_en sẽ tích cực trong chu kỳ từ T2 đến T3.
Nếu vi phạm timing tại T3 làm giá trị pre_en ổn định về 1 thì data_en sẽ tích cực trong chu kỳ từ T4 đến T5.
Trường hợp này, độ rộng tối thiểu là data_en là 1 chu kỳ rclk và độ rộng tối đa của data_en là 3 chu kỳ rclk. Để đảm bảo miền clock luôn bắt đúng dữ liệu thì async_in phải duy trì ổn định giá trị trong trường hợp xấu nhất, khi data_en tích cực 3 chu kỳ. Trong ví dụ này, async_in được lái giá trị mới cùng thời điểm cạnh lên của data_valid theo clock tclk và duy trì ổn định trong 5 chu kỳ xung clock rclk
5.3) Ưu điểm và chú ý
Ưu điểm:
  • Cơ chế đồng bộ đơn giản
  • Chỉ dùng mạch đồng bộ nhiều FF nối tiếp trên tín hiệu cho phép nên logic đồng bộ tốn ít tài nguyên và công suất tiêu thụ so với cơ chế tự kiểm tra sự ổn định của giá trị
  • Số lượng FF của mạch đồng bộ không đổi khi số lượng bit tín hiệu tăng.
  • Có thể dùng trong trường hợp truyền nhiều giá trị giống nhau liên tục căn cứ trên số lần tích cực của tín hiệu cho phép.
Chú ý:
  • Phải tuân thủ ràng buộc về độ rộng xung của tín hiệu, một giá trị mới phải duy trì trong khoảng thời gian đủ để miền clock nhận chắc chắn bắt đúng giá trị trong trường hợp xấu nhất, trường hợp độ rộng xung tín hiệu cho phép ở ngõ ra mạch đồng bộ, data_en, dài nhất. Điều này làm cho miền clock truyền, tclk, có thể phải thêm logic để duy trì độ rộng xung của các tín hiệu như yêu cầu.
  • Thời gian tối thiểu để đảm bảo miền nhận lấy đúng giá trị mới là "4 chu kỳ rclk + thời gian setup của FF + thời gian hold của FF", tình từ thời điểm T1.
6) Phương pháp chuyển đổi giá trị
6.1) Mô tả nguyên lý
Như đã trình bày, vấn đề của việc đồng bộ một tín hiệu nhiều bit bằng nhiều FF mắc nối tiếp là sinh ra giá trị không mong muốn nếu hiện tượng bất ổn định xảy ra khi nhiều bit cùng thay đổi giá trị.
Để giải quyết vấn đề này, một phương pháp đồng bộ có thể được áp dụng là chuyển đổi giá trị làm thay đổi nhiều bit thành một giá trị chỉ làm thay đổi 1 bit so với giá trị trước đó ở miền clock truyền. Tại miền clock nhận, tín hiệu sẽ được đồng bộ bằng mạch đồng bộ nhiều FF. Sau đó, giá trị ngõ ra mạch đồng bộ được khôi phục lại giá trị ban đầu.

Hình 9: Mạch nguyên lý phương pháp chuyển đổi giá trị thay đổi nhiều bit thành giá trị thay đổi 1 bit trước khi đồng bộ
Trong hình minh họa trên, binary_data là một tín hiệu nhiều bit. Giá trị của binary_data có thể thay đổi nhiều bit cùng lúc. Nó được chuyển đổi thành data_in thông qua một logic chuyển đổi. data_in được đồng bộ bằng mạch đồng bộ 2 FF. Ngõ ra mạch đồng bộ 2 FF là sync_out sẽ đi qua logic khôi phục lại giá trị ban đầu, data_out.
Sau logic chuyển đổi ở miền tclk, một tầng FF có thể được thêm vào giúp loại bỏ độ trễ gây ra do mạch tổ hợp trên đường data_in. Đồng thời loại bỏ glitch có thể sinh ra trên từng bit của tín hiệu nếu có.
6.2) Điều kiện sử dụng
Điều kiện để sử dụng phương pháp này là dữ liệu cần truyền giữa hai miền clock phải thay đổi theo một quy luật cố định, không được thay đổi ngẫu nhiên hay tùy ỳ.
Dữ liệu thay đổi có quy luật có thể là giá trị bộ đếm lên hoặc đếm xuống, máy trạng thái, ... như ví dụ trong "mục 2".
Bộ chuyển đổi thường được dùng trong phương pháp này là bộ chuyển đổi giữa mã binary và Gray. Tuy nhiên, bạn có thể sử dụng bất kỳ loại mã nào miễn là nó phải đảm bảo chỉ thay đổi logic của 1 bit khi giá trị cần truyền thay đổi.
Nếu dữ liệu cần truyền là bộ đếm lên hoặc đếm xuống 1 đơn vị thì nó có thể được chuyển đổi thành mã Gray như trong link tham khảo sau. Việc chuyển đổi ngược từ mã Gray thành binary được thực hiện như mạch nguyên lý sau đây.
Hình 10: Mạch nguyên lý chuyển đổi từ mã nhị phân (binary) thành mã Gray
Tương tự đối với FSM, thay vì mã hóa trạng thái nhị phân, chúng ta có thể chuyển thành mã Gray. Quay lại ví dụ FSM ở mục 2, FSM này chuyển trạng thái theo thứ tự lặp lại IDLE->ACTIVATE->RUN->DEACTIVATE. Trong trường hợp này, chúng ta có thể chuyển giá trị mã hóa trạng thái theo thứ tự mã Gray như sau:
IDLE = 2’b00;
ACTIVATE = 2'b01;
RUN = 2’b11; //thay vì 2'b10
DEACTIVATE = 2’b10; //thay vì 2'b11
Như đã trình bày, tùy vào trường hợp cụ thể, chúng ta có thể dùng bất kỳ loại chuyển đổi nào miễn là tuân thủ quy tắc "hai giá trị liên tiếp chỉ thay đổi mức logic của 1 bit". Xét ví dụ sau đây:
Hình 11: Một FSM mà giá trị trạng thái cần được truyền từ miền clock tclk sang miền clock rclk
Hình trên là một FSM được tạo ra trên miền clock tclk và giá trị trạng thái cần được truyền sang miền clock rclk. FSM có 5 trạng thái nên chúng ta không thể dùng mã hóa Gray thông để mã hóa tuần tự cho từng trạng thái. Trường hợp này, một bộ giá trị sẽ được lựa chọn để đảm bảo khi chuyển trạng thái chỉ có 1 bit thay đổi, tạm gọi cách gán trạng thái này là "custom code".
IDLE                = 3’b000;
ACTIVATE      = 3'b100;
PRE_RUN       = 3’b101;
POST_RUN     = 3'b111;
DEACTIVATE = 3’b110;
Chú ý, trong trường hợp này, khi reset bằng cách tích cực tín hiệu rst_n, thì FSM sẽ về trạng thái IDLE. Nếu FSM đang ở trạng thái PRE_RUN, POST_RUN hoặc DEACTIVATE thì việc nhảy về RESET sẽ làm thay đổi giá trị của 2 bit. Vì vậy, việc gán trạng thái này chỉ được dùng ở một trong hai trường hợp sau:
  • Tín hiệu reset rst_n sẽ reset cả hai miền clock tclkrclk.
  • Tín hiệu reset rst_n chỉ reset miền tclk nhưng khi miền rclk phát hiện FSM là IDLE thì sẽ khởi tạo lại từ đầu (giống như được reset) hoặc không quan tâm đến các trạng thái hoạt động trước đó. Trường hợp này, cho dù giá trị FSM thay đổi nhiều bit và có thể sinh ra một trạng thái sai khi đồng bộ sang miền rclk nhưng nó không ảnh hưởng đến hoạt động của miền rclk vì miền này sẽ khởi tạo và hoạt động lại.
6.3) Ưu điểm và chú ý
Ưu điểm:
  • Cơ chế đồng bộ đơn giản
  • Hữu dụng cho việc đồng bộ giá trị bộ đếm và FSM đơn giản. FSM đơn giản được hiểu là FSM có số lượng chuyển trạng thái ít và không có nhiều nhánh chuyển trạng thái. Đây là một nhận xét mang tính tương đối.
Chú ý:
  • Chỉ dùng được trong trường hợp giá trị cần truyền giữa hai miền clock thay đổi có quy luật.
  • Tài nguyên dành cho mạch chuyển đổi giá trị lớn khi số bit cần truyền tăng. Khi tài nguyên mạch tổ hợp chuyển đổi giá trị ở miền tclk lớn đáng kể thì cần chèn thêm một tầng FF tại ngõ ra trước khi truyền sang miền rclk, điều này làm tăng công suất tiêu thụ
7) Phương pháp giao thức bắt tay
7.1) Mô tả nguyên lý
Phương pháp dùng giao thức bắt tay (handshake) là phương pháp thông tin hai chiều giữa miền truyền và miền nhận. Miền truyền dữ liệu sẽ gửi dữ liệu kèm một tín hiệu yêu cầu truyền (request), tín hiệu req, đến miền nhận. Miền nhận đồng bộ tín hiệu yêu cầu bằng mạch đồng bộ nhiều FF mắc nối tiếp theo clock rclk. Miền nhận sẽ phát hiện mức tích cực của tín hiệu yêu cầu để nhận dữ liệu. Sau khi nhận dữ liệu, miền nhận sẽ thông báo lại cho miền truyền bằng các tích cực một tín hiệu phản hồi, tín hiệu ack. Miền truyền sẽ đồng bộ lại tín hiệu ack theo clock tclk. Miền truyền sẽ tiếp tục truyền dữ liệu mới sau khi phát hiện ack tích cực.
Hình 12: Mạch nguyên lý của phương pháp đồng bộ bằng giao thức bắt tay
Trong hình minh họa trên đây:
  • Request logic là thành phần quyết định khi nào tích cực tín hiệu req và cập nhật dữ liệu truyền mới dựa trên thông tin từ tín hiệu sync_ack, tín hiệu ack sau khi đã đồng bộ, và trạng thái hoạt động của miền tclk.
  • Ack logic là thành phần quyết định khi nào tích cực tín hiệu ack dựa trên thông tin từ tín hiệu sync_req, tín hiệu req sau khi đã đồng bộ, và trạng thái hoạt động của miền rclk.
Có hai loại giao thức bắt tay là:
  • Bắt tay 2 bước
  • Bắt tay bốn bước
Hình 13: (a) Giao thức bắt tay 2 bước và (b) giao thức bắt tay 4 bước
Giao thức bắt tay 2 bước được thực hiện dựa trên việc lặp lại 2 bước sau đây:
  • (1) Miền tclk, tín hiệu req chuyển trạng thái, từ 0 lên 1 hoặc từ 1 xuống 0,  kèm với dữ liệu cần truyền
  • (2) Miền rclk, sau khi đã nhận được dữ liệu, tín hiệu ack chuyển trạng thái, từ 0 lên 1 hoặc từ 1 xuống 0.
Trong giao thức bắt tay 2 pha, tín hiệu req chỉ chuyển trạng thái khi có dữ liệu cần truyền. Miên tclk chỉ truyền dữ liệu khi đã phát hiện sự chuyển trạng thái trên ack, ứng với thời điểm.
Hình 14: Mạch nguyên lý cơ chế đồng bộ bằng giao thức bắt tay 2 pha
Trong hình vẽ trên:
  • Tại miền tclk: req đảo giá trị và async_in cập nhật giá trị mới cần truyền chỉ khi phát hiện được ack từ miền rclk, sync_ack=req. data_valid là một tín hiệu sinh ra từ logic của miền tclk, chỉ tích cực khi có dữ liệu mới cần truyền.
  • Tại miền rclk: ack đảo giá trị và rec_data cập nhật giá trị mới chỉ khi phát hiện được req từ miền tclk, mức logic của sync_req  khác mức logic của ackrec_ready là một tín hiệu sinh ra từ logic của miền rclk, chỉ tích cực khi có thể nhận dữ liệu.
Giao thức bắt tay 4 bước được thực hiện dựa trên việc lặp lại 4 bước sau đây:
  • (1) Miền tclk, tín hiệu req tích cực kèm với dữ liệu cần truyền
  • (2) Miền rclk, sau khi đã nhận được dữ liệu, tín hiệu ack tích cực.
  • (3) Miền tclk, tín hiệu req thôi tích cực sau khi đã phát hiện ack tích cực.
  • (4) Miền rclk, tín hiệu ack thôi tích cực sau khi đã phát hiện req thôi tích cực.
Trong giao thức bắt tay 4 pha, mỗi lần truyền dữ liệu req ack đều phải trải qua 2 trạng thái là tích cực và không tích cực. Một dữ liệu mới chỉ được phép truyền khi miền tclk nhìn thấy cả req ack đang trong trạng thái không tích cực.
Hình 15: Mạch nguyên lý của có chế đồng bộ bằng giao thức bắt tay 4 pha
Trong hình vẽ trên:
  • Tại miền tclk:
    • req chỉ được tích cực khi sync_ack=req=0 và data_valid=1. data_valid là tín hiệu sinh ra từ logic của miền tclk. Tín hiệu này chỉ tích cực khi miền tclk có dữ liệu muốn truyền. Thời điểm req tích cực cũng là lúc giá trị mới được nạp vào FF async_in.
    • req thôi tích cực khi sync_ack=1.
    • req giữ nguyên giá trị trong các trường hợp khác.
  • Tại miền rclk:
    • ack chỉ được tích cực khi ack=0, sync_req=1 và rec_ready=1rec_ready là tín hiệu sinh ra từ logic của miền rclk. Tín hiệu này chỉ tích cực khi miền rclk có thể nhận dữ liệu. Thời điểm ack tích cực cũng là lúc giá trị mới được nạp vào FF rec_data.
    • ack thôi tích cực khi sync_req=0.
    • ack giữ nguyên giá trị trong các trường hợp khác
7.2) Điều kiện sử dụng
Phương pháp đồng bộ bắt tay có thể được dùng mà không cần quan tâm đến tỉ lệ tần số hay độ rộng tín hiệu giữa miền truyền (tclk) và miền nhận (rclk) vì nó đảm bảo mỗi dữ liệu được truyền đi từ miền truyền sẽ chắc chắn được nhận bởi miền nhận.
7.3) Ưu điểm và chú ý
Ưu điểm:
  • Không cần quan tâm đến độ rộng tín hiệu khi truyền và nhận
  • Đảm bảo truyền và nhận đúng và đủ số lượng dữ liệu
  • Có thể truyền nhận các dữ liệu có giá trị ngẫu nhiên
  • Mạch logic đơn giản
Chú ý:
  • Nhược điểm của phương pháp này là tốc độ truyền nhận dữ liệu giữa hai miền thấp. Nếu dữ liệu hiện tại chưa hoàn thành thì dữ liệu mới không được phép truyền. Vì vậy, phương pháp này chỉ thích hợp cho các giao tiếp có số lượng dữ liệu truyền nhận ít, không cần xử lý nhanh hoặc dữ liệu truyền có khoảng thời gian giữa hai gói dài
8) Phương pháp bộ nhớ đệm
8.1) Mô tả nguyên lý
Phương pháp này sử dụng một bộ nhớ đệm nằm giữa hai miền truyền và nhận. Miền truyền sẽ ghi dữ liệu cần truyền vào bộ nhớ đệm này bằng clock của miền truyền, tclk. Miền nhận sẽ đọc dữ liệu từ bộ nhớ đệm này bằng clock của miền nhận, rclk.
Hình 16: Nguyên lý dùng bộ nhớ đệm bất đồng bộ
Một loại bộ nhớ đệm thường dùng trong thực tế là FIFO bất đồng bộ (asynchronous FIFO). Hiện có 2 cấu trúc FIFO bất đồng bộ được giới thiệu là:
  • Cấu trúc FIFO bất đồng bộ dùng bộ đếm ghi/đọc Gray.
  • Cấu trúc FIFO bất đồng bộ dùng bộ đếm ghi/đọc token ring.

Hình 17: Cấu trúc của FIFO bất đồng bộ dùng bộ đếm Gray (tài liệu tham khảo 1)
Trong hình minh họa trên, wclk là clock của miền truyền và rclk là clock của miền nhận.
Hình 18: Cấu trúc của FIFO bất đồng bộ dùng bộ đếm token ring (tài liệu tham khảo 2)
Trong hình minh họa trên, CLK_TX là clock miền truyền và CLK_RX là clock miền nhận.
Trong hai loại trên, FIFO bất đồng bộ dùng bộ đếm Gray đang được dùng phổ biến trong các thiết kế chip thực tế. Bài viết sẽ không trình bày chi tiết cấu trúc của hai loại FIFO này. Việc phân tích chi tiết và so sánh hai cấu trúc FIFO sẽ được thực hiện trong một bài viết khác.
8.2) Điều kiện sử dụng
Phương pháp đồng bộ này có thể được dùng mà không cần quan tâm đến tỉ lệ tần số hay độ rộng tín hiệu giữa miền truyền (tclk) và miền nhận (rclk) vì nó đảm bảo mỗi dữ liệu được truyền đi từ miền truyền sẽ chắc chắn được nhận bởi miền nhận.
8.3) Ưu điểm và chú ý
Ưu điểm:
  • Không cần quan tâm đến độ rộng tín hiệu khi truyền và nhận
  • Đảm bảo truyền và nhận đúng và đủ số lượng dữ liệu
  • Có thể truyền nhận các dữ liệu có giá trị ngẫu nhiên
  • Hỗ trợ các giao tiếp cần truyền nhận dữ liệu nhanh với số lượng lớn hoặc các giao tiếp yêu cầu truyền nhận dữ liệu liên tục
Chú ý:
  • Nhược điểm của phương pháp này là phức tạp hơn các phương pháp khác.
  • Tài nguyên và công suất tiêu thụ tăng đáng kể khi dung lượng bộ nhớ tăng
Lịch sử cập nhật:
1) 2020.02.02 - Tạo lần đầu

Tài liệu tham khảo:
1) Clifford E. Cummings, Sunburst Design, Inc; Simulation and Synthesis Techniques for Asynchronous FIFO Design; SNUG, San Jose, 2002
2) Clifford E. Cummings, Peter Alfke; Simulation and Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer Comparisons; SNUG, San Jose, 2002
3) Alessandro Stranoy, Daniele Ludovicix, Davide Bertozzi; A Library of Dual-Clock FIFOs for Cost-Effective and Flexible MPSoC Design; IEEE 2010

Chủ Nhật, 26 tháng 1, 2020

[SV for Syn] Bài 2- Giá trị không xác định kích thước (unsized literal)

Tiếp theo bài 1, bài viết này sẽ phân tích chi tiết về giá trị (số) không xác định kích thước (unsized literal value/number) trong System Verilog (SV). Đồng thời, chúng sẽ được so sánh với Verilog HDL để làm rõ các ưu nhược điểm khi dùng để mô tả RTL code.

Danh sách bài viết liên quan:
Bài 1: Những điểm mới của System Verilog khả tổng hợp

1) Khái niệm literal
Literal, còn gọi là literal constant, là giá trị thể hiện chính nó. Literal là một giá trị cố định, không thay đổi.
Ví dụ, số 8 là một literal đại diện cho chính nó và chỉ thể hiện một giá trị là 8, không thể là 9 hay bất kỳ ý nghĩa nào khác. 8 là một literal nguyên trong SV. Một ví dụ khác, chuỗi ký tự “good” là một literal chuỗi trong SV.
Literal còn được gọi là literal constant nhưng nó không phải là hằng số (constant). Nghĩa là literal constant hay literal là khác với constant. Constant là đối tượng dữ liệu được định danh theo tên (named data object). Trong SV, một hằng số có thể được khai báo bằng parameter, localparam, specparam hoặc const.
Ví dụ 1: Phân biệt literal và hằng số (constant)
parameter WIDTH = 32;
Trong ví dụ trên, WIDTH là một hằng số còn 32 là một literal. 32 luôn là 32 còn WIDTH có thể được gán giá trị lại bằng một literal khác.
2) Phân loại literal
SV chia literal thành các nhóm sau:
  • Số (number):
    • Literal nguyên (integer literal constant) có thể được biểu diễn dưới dạng thập phân (decimal), thập lục phân (hexadecimal), bát phân (octal) hoặc nhị phân (binary)
    • Literal thực (real literal constant) được biểu diễn theo chuẩn IEEE Std 754 về số dấu chấm động có độ chính xác kép.
  • Literal thời gian (time literal) là một giá trị realtime được tỷ lệ theo đơn vị thời gian (fs, ps, ns, us, ms, s) hiện tại và được làm tròn theo sai số thời gian hiện tại  
  • Literal chuỗi (string literal) là một chuỗi ký tự đặt trong cặp dấu ngoặc kép, “ ”, các ký tự không thể in được và ký tự đặc biệt sẽ đi kèm dấu “\” đằng trước 
  • Literal cấu trúc (structure literal) là các mẫu gán hoặc biểu thức cấu trúc với các thành phần là hằng số.
  • Literal mảng (arrayliteral) là các mẫu gán hoặc biểu thức mảng với các thành phần là hằng số.
Ví dụ 2: Minh họa các loại literal
8’h9a //literal nguyên
1.30e-2 //literal thực
2.1ps //literal thời gian
“Hello word\n” //literal chuỗi 
typedef struct {int a; shortreal b;} ab;
ab c; 
c = '{0, 0.0}; //literal cấu trúc
int n[1:2][1:3] = '{'{0,1,2},'{3{4}}}; //literal mảng
Trong ví dụ trên,
  • 2.1ps là một literal thời gian có giá trị là 2.1 và đơn vị là ps
  • “Hello world\n”, không bao gồm dấu ngoặc kép, là literal chuỗi. Trong đó, “\n” là ký tự xuống dòng
  • ‘{0, 0.0} là một literal cấu trúc được dùng để gán giá trị cho biến c được định nghĩa bởi kiểu dữ liệu struct ab.
  • '{'{0,1,2},'{3{4}}} là một literal mảng dùng để gán giá trị cho các phần tử có kiểu dữ liệu là int trong mảng n.
3) Giá trị không xác định kích thước
Một giá trị không xác định kích thước là một giá trị nguyên, thuộc integer literal, là một giá trị không được xác định rõ số bit biểu diễn giá trị. Một giá trị không xác định kích thước có thể là một trong hai dạng sau:
  • Một số thập thân đơn thuần (simple decimal number).
  • Một số nguyên được biểu diễn dưới dạng <size><base><value> nhưng thiếu trường <size>
Ví dụ 3: Giá trị không xác định kích thước
9 //số thập phân đơn thuần
‘h8 //số nguyên thiếu mô tả độ rộng bit
Trong ví dụ trên, 9 là một số thập phân đơn thuần, giá trị này không chỉ rõ số bit biểu diễn nó là bao nhiêu. Nó khác với cách biểu diễn 8’d9. Ở cách biểu diễn này, giá trị 9 được chỉ rõ được biểu diễn bằng 8 bit.
‘h8 là một giá trị thập lục phân nhưng khuyết trường <size> nên cũng không thể xác định cụ thể số bit biểu diễn giá trị này là bao nhiêu.
Cả Verilog HDL và SV đều hỗ trợ biểu diễn số không xác định kích thước. Nó được gọi là unsized number, hoặc unsized literal constant, hoặc unsized literal hoặc unsized literal value.
4) Số không xác định kích thước trong Verilog
Nội dung của mục này căn cứ trên phiên bản Verilog 2005.
Verilog HDL, không định nghĩa rõ ràng khái niệm literal. Khái niệm được sử dụng là số (number). Number được trình bày ở mục “3.5 Numbers” và được định nghĩa bằng syntax 3-1. Một số trong Verilog có thể là số thập phân, số bát phần, số thập lục phân, số nhị phân hoặc số thực.
number ::=decimal_number| octal_number| binary_number| hex_number| real_number  
Số không xác định kích thước thường dùng trong các trường hợp sau:
  • Gán đến một tín hiệu hoặc hằng số có kích thước (độ rộng bit) thay đổi
  • Gán cùng một giá trị (0, x hoặc z) đến tất cả các bit trong một tín hiệu hoặc hằng số
Ví dụ 4: Gán giá trị không xác định kích thước
reg [WIDTH-1:0] regData;
regData = 9; //Gán bằng 9
regData = ‘b0; //Gán tất cả các bit bằng 0
regData = ‘bx; //Gán tất cả các bit bằng x
regData = ‘hx9; //Gán 4 bit cuối là 1001, các bit khác là x
regData = ‘bz; //Gán tất cả các bit bằng z
regData = ‘hz8; //Gán 4 bit cuối là 1000, các bit khác là z
regData = ‘b1; //Gán bit 0 bằng 1 và các bit khác bằng 0
Trong ví dụ trên, regData là một tín hiệu có độ rộng bit thay đổi theo giá trị WIDTH. Độ rộng này được gán một lần trước khi biên dịch hoặc tổng hợp code. Giả sử động rộng bit là 16 bit. thì kết quả các phép gán theo thứ tự như sau:
# --- regData = 0000000000001001
# --- regData = 0000000000000000
# --- regData = xxxxxxxxxxxxxxxx
# --- regData =   xxxxxxxxxxxx1001
# --- regData =   zzzzzzzzzzzzzzzz
# --- regData =   zzzzzzzzzzzz1000
# --- regData = 0000000000000001
Trong đó:
  • Phép gán thứ 1, dù độ rộng bit là bao nhiêu thì regData cũng được gán bằng 9
  • Phép gán thứ 2,  dù độ rộng bit là bao nhiêu thì tất cả các bit của regData đều được gán bằng 0
  • Phép gán thứ 3,  dù độ rộng bit là bao nhiêu thì tất cả các bit của regData đều được gán bằng x
  • Phép gán thứ 4,  bốn bit cuối sẽ được gán bằng 9 vì biểu diễn kiểu hex còn tất cả các bit cao đều được gán bằng x
  • Phép gán thứ 5,  dù độ rộng bit là bao nhiêu thì tất cả các bit của regData đều được gán bằng z
  • Phép gán thứ 6,  bốn bit cuối sẽ được gán bằng 8 vì biểu diễn kiểu hex còn tất cả các bit cao đều được gán bằng z
  • Phép gán thứ 7,  chỉ 1 bit cuối sẽ được gán bằng 1 vì biểu diễn kiểu binary còn tất cả các bit cao đều được gán bằng 0
Việc gán giá trị được dựa trên nguyên tắc như sau:
  • Đối với số thập phân đơn thuần thì tất cả các bit được gán phải thể hiện đúng giá trị số thập phân
  • Đối với dạng biểu diễn <base><value>, ví dụ ‘b0, nguyên tắc mở rộng bit được áp dụng như sau:
    • x nếu bit ngoài cùng bên trái của value là x
    • z nếu bit ngoài cùng bên trái của value là z
    • 0 nếu ngoài 2 trường hợp trên
Verilog không hỗ trợ việc mô tả một số không xác định kích thước giúp gán tất cả các bit của một tín hiệu bằng 1. Để gán tất cả các bit của một tín hiệu, có độ rộng thay đổi, bằng 1 trong Verilog, hai cách sau có thể sử dụng:
  • Mô tả giá trị toàn bit 1 với độ rộng cụ thể đối với từng trường hợp
  • Dùng toán tử lặp (replication) “{{}}
  • Dùng toán tử bù bitwise (Bitwise negation) ~
Ví dụ 5: Các cách gán 1 đến tất cả các bit của một tín hiệu có giá trị thay đổi
parameter WIDTH = 16;
reg [WIDTH-1:0] regData;
regData = 16'hffff; //Mô tả đúng độ rộng bit
regData = {WIDTH{1'b1}}; //Dùng toán tử lặp
regData = ~0; //Dùng toán tử bù bitwise
Ví dụ trên là một số cách có thể áp dụng để gán giá trị toàn bit 1 đến một tín hiệu.
  • Cách thứ 1 phải chỉ rõ độ rộng bit của tín hiệu regData. Bất lợi lớn nhất của cách này là khi độ rộng bit tín hiệu thay đổi thì trường <size> của giá trị cũng phải thay đổi theo
  • Cách thứ 2 phải biết hằng số khai báo độ rộng WIDTH của tín hiệu regData.
  • Cách thứ 3 là một "mẹo" viết code
Tóm lại, việc gán cùng một giá trị 0, 1, x hoặc z đến tất cả các bit của một tín hiệu có thể thực hiện trên Verilog nhưng thông qua các cách “cần phải nhớ nguyên tắc và thủ thuật”. Trong các ví dụ đã trình bày, việc này đạt được thông qua cơ chế mở rộng bit hoặc dùng các toán tử khác kèm theo hoặc phải chỉ rõ độ rộng bit.
5) Số không xác định kích thước trong System Verilog
SV định nghĩa rõ ràng khái niệm literal. Trong SV 2017, khái niệm này định nghĩa trong mục “5.7 Numbers”. Tuy SV vẫn bắt đầu với khái niệm number nhưng căn cứ theo cú pháp "Syntax 5-2" thì number chỉ là một phần của literal.
primary_literal ::= number | time_literal | unbased_unsized_literal | string_literal
Trong đó, number bao gồm literal nguyên và literal thực, ứng với số nguyên (integer number) và số thực (real number) trong Verrilog.
Một điểm chú ý khác là, tuy tên của “syntax 5-2” là “Syntax for integer and real numbers” giống với “syntax 3-1” trong Verilog nhưng SV đã định nghĩa lại các điểm sau:
  • syntax 5-2 định nghĩa primary_literal đã bao gồm cả syntax 3-1 định nghĩa number
  • syntax 5-2 bổ sung thêm time_literal, unbased_unsized_literal string_literal
Như vậy, việc sử dụng tên cũ là “Syntax for integer and real numbers” trong SV dễ gây hiểm nhầm là literal chỉ gồm số nguyên và số thực. Bạn đọc cần chú ý điểm này khi đọc tài liệu SV.
Hình 1: Khái niệm số (number) trong Verilog (trái) và khái niệm literal trong SV (phải)
Ngoài các đặc điểm đã về số không xác định kích thước như Verilog. SV đã nâng cấp để hỗ trợ thêm loại giá trị không xác định kích thước (unsized) và không xác định cơ số (unbased), gọi là unbased unsized literal. Loại này là một giá trị đơn bit (single bit). Nó được dùng để thiết lập cùng một giá trị cho tất cả các bit của tín hiệu hoặc hằng số.
Ví dụ 6: Loại số không xác định kích thước và cơ số
‘0 //Gán 0 đến tất cả các bit được gán bên vế trái
‘1 //Gán 1 đến tất cả các bit được gán bên vế trái
‘x //Gán x (unknown) đến tất cả các bit được gán bên vế trái
‘X //Gán x (unknown) đến tất cả các bit được gán bên vế trái
‘z //Gán z (high-impedance) đến tất cả các bit được gán bên vế trái
‘Z //Gán z (high-impedance) đến tất cả các bit được gán bên vế trái
Chú ý, dấu nháy được sử dụng là dấu apostrophe, còn gọi là tick, nằm cạnh phím enter trên bàn phím chứ không phải dấu back tick, nằm cạnh số 1 trên bàn phím.
Ví dụ 7: Gán giá trị không xác định kích thước và cơ số
parameter WIDTH = 64;
reg [WIDTH-1:0] regData;
initial begin
  regData = '0;
  $display("--- regData = %b", regData);
  //
  regData = '1;
  $display("--- regData = %b", regData);
  //
  regData = 'x;
  $display("--- regData = %b", regData);
  //
  regData = 'z;
  $display("--- regData = %b", regData);
end
Kết quả của ví dụ trên đây:
# --- regData = 000000000000
# --- regData = 111111111111
# --- regData = xxxxxxxxxxxx
# --- regData = zzzzzzzzzzzz
Với nâng cấp mới này, khi cần gán một giá trị toàn bit 0, 1, x hoặc z đến một tín hiệu trong SV, chúng ta không cần “nhớ” xem tín hiệu này bao nhiêu bit, không cần mô tả kích thước và cơ số. Đặc biệt, trường hợp gán toàn bit 1 sẽ không cần dùng thêm toán tử như Verilog.
Hình 2: Số không xác định kích thước trong Verilog (trái) được mở rộng thêm trong SV (phải)

Lịch sử cập nhật:
1) 2019.1.10 - Tạo lần đầu

Tài liệu tham khảo:
1.  IEEE Computer Society and  IEEE Standards Association Corporate Advisory Group;  IEEE Standard for SystemVerilog—  Unified Hardware Design,  Specification, and Verification  Language; 06.Dec.2017
2. IEEE Computer Society  IEEE Standard for Verilog® Hardware Description Language,  Specification, and Verification  Language; 07.Apr.2006
3. Stuart Sutherland, Simon Davidmann, Peter Flake; A Guide to Using SystemVerilog for Hardware Design and Modeling; 2006.
5. Synopsys; HDL Compiler for SystemVerilog User Guider; March 2012.
6. Thiết kế vi mạch số với VHDL & Verilog-Tống Văn On.

Thứ Bảy, 28 tháng 12, 2019

[SystemC-UVM] Bài 1 - Hướng dẫn cài đặt thư viện UVM-SystemC và SCV

Bài viết này hướng dẫn cách cài đặt và sử dụng thư viện SystemC UVM (Universal Verification Methodology) và SCV phục vụ cho việc xây dựng môi trường mô phỏng UVM-SystemC.
Danh sách các bài viết liên quan:

1) Tổng quan
Để xây dựng một môi trường mô phỏng UVM với SystemC chúng ta cần các thành phần thư viện như sau:
  1. Thư viện SystemC (SystemC Library) - Thư viện xây dựng trên ngôn ngữ C/C++ chứa và định nghĩa các class, method, kiểu dữ liệu và nhân mô phỏng (simulation kernel) cơ sở dùng cho việc mô hình hóa hệ thống gồm cả phần cứng và phần mềm.
  2. Thư viện các thành phần UVM (UVM-SystemC Library) - Thư viện chứa các class, method, và kiểu dữ liệu dùng để tạo các thành phần cho môi trường mô phỏng theo phương pháp UVM
  3. Thư viện SCV (SystemC Verification Library) - Thư viện chứa một tập các API (Application Programming Interface) chung dùng cho các hoạt động kiểm tra trên SystemC như tạo các giá trị ràng buộc, ghi chép lại transaction, ...

Các thưc viện trên có thể tải miễn phí với mã nguồn mở tại website của Accellera ở các liên kết sau đây:
  1. Thư viện SystemC
  2. Thư viện UVM-SystemC
  3. Thư viện SCV
Các bước cơ bản để cài đặt và sử dụng các thư viện của SystemC như sau:
  1. Tìm hiểu các ràng buộc về cài đặt và đặc điểm hỗ trợ của thư viện, xem trong file INSTALL, README và RELEASENOTES của gói cài đặt, như:
    • Phiên bản hệ điều hành (OS), để biết thư viện hoạt động tốt (đã được kiểm tra) trên nền tảng nào
    • Phiên bản trình biên dịch (compiler C/C++), để biết thư viện có thể được tổng hợp tốt (đã được kiểm tra) với trình biên dịch nào
    • Thư viện liên kết, để biết thư viện này sẽ yêu cầu cần có thư viện nào khác hay không? hoặc thư viện này có thể hoạt động chung với thư viện nào khác hay không?
  2. Chuẩn bị môi trường cài đặt chứa các phần mềm (tool) đúng với yêu cầu của thư viện gồm
    • Hệ điều hành
    • Cài đặt các công vụ liên quan:
    • Lưu ý, các bạn có thể dùng các phần mềm và công cụ như hệ điều hành, trình biên dịch, ... khác với phiên bản mà thư viện yêu cầu nhưng điều này không được đảm bảo (non-offical) vì việc kiểm tra trên các nền tảng này chưa được thực hiện đầy đủ
  3. Cài đặt thư viện
    1. Tải gói cài đặt và giải nén
    2. Tạo thư mục sẽ chứa dữ liệu sau khi cài đặt
    3. Tiến hành cài đặt (Thư viện SystemC phải được cài đặt đầu tiên trước các gói thư viện khác)
2) Môi trường cài đặt
Môi trường cài đặt và sử dụng các thư viện SystemC dùng để minh họa trong bài viết này có thông số như sau:
  • Hệ điều hành Windows 7 Professional 64-bit
  • Cygwin terminal 3.1.2, phiên bản 32-bit, chúng ta không dùng phiên bản Cygwin 64-bit vì việc chạy mô phỏng file .exe sau khi biên dịch code SystemC không như mong muốn như đã trình bày trong bài viết
    • Công cụ giải nén: tar phiên bản 1.29
    • Công cụ tạo các file thực thi và cấu hình từ mã nguồn: make phiên bản 4.2.1
    • Trình biên dịch C/C++: gcc phiên bản 7.4.0
Các gói thư viện được sử dụng:
  1. Thư viện SystemC phiên bản 2.3.3 (systemc-2.3.3)
    • Đây không phải phiên bản mới nhất, phiên bản mới nhất là 2.3.3 tính đến ngày 28.12.2019 nhưng không được sử dụng vì phiên bản mới nhất của SCV không hỗ trợ
  2. Thư viện SystemC-UVM phiên bản 1.0-beta2 (uvm-systemc-1.0-beta2)
    • Mới nhất, tính đến ngày 28.12.2019
  3. Thư viện SCV phiên bản 2.0.1 (scv-2.0.1)
    • Mới nhất, tính đến ngày 28.12.2019
Mọi lệnh được trình bày sau đây đều thực hiện trên Cygwin terminal. Các bạn hãy tham khảo cách cài đặt và sử dụng chi tiết ở bài viết sau.

3) Cài đặt thư viện SystemC
Hướng dẫn này đã được trình bày trong bài viết sau đây nên sẽ không trình bày lại.
Hiện nay, phiên bản mới nhất là 2.3.3 tuy nhiên nó chưa được kiểm tra với thư viện SCV. Thư viện SCV mới nhất chỉ hỗ trợ tốt trên phiên bản 2.3.1, 2.3.0 và 2.2.0 tùy vào hệ điều hành.
Các nền tảng cài đặt được hỗ trợ gồm:
   o Linux
     * Architectures
       - x86 (32-bit)
       - x86_64 (64-bit)
       - x86 (32-bit) application running on x86_64 (64-bit) kernel
         (../configure --host=i686-linux-gnu)
   o Mac OS X
     * Architectures
       - x86 (32-bit)
       - x86_64 (64-bit)
       - powerpc (32-bit)   [deprecated]
       - powerpc64 (64-bit) [deprecated]
  o Solaris
     * Architectures
       - SPARC (32-bit)
   o BSD
     * Architectures
       - x86 (32-bit)
       - x86_64 (64-bit)
   o Windows
     * Compatibility layer
       - Cygwin
       - MinGW / MSYS
     * Architectures
       - x86 (32-bit)
       - x86_64 (64-bit)
Trình biện dịch được hỗ trợ gồm:
  • GNU C++ (gcc), phiên bản 3.4 trở lên
  • Clang C++ phiên bản 3.0 trở lên
Giả sử sau khi cài đặt đường dẫn thư mục cài đặt thư viện SystemC của bạn là:
/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/SystemC233_lib
Chú ý, đường dẫn này sẽ sử dụng cho các phần hướng dẫn tiếp theo.
4) Cài đặt thư viện SystemC-UVM
4.1) Tạo thư mục để cài đặt

Lệnh:
mkdir UvmSystemC_lib
Kết quả: ví dụ đường dẫn thư mục đã tạo là:
/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/UvmSystemC_lib
4.2) Giải nén gói thư viện ở một thư mục bất kỳ

Lệnh:
tar -xzf uvm-systemc-1.0-beta2.tar.gz
Kết quả: thư mục chứa source cài đặt được tạo
uvm-systemc-1.0-beta2
4.3) Chuyển đến thư mục đã giải nén
Lệnh:
cd uvm-systemc-1.0-beta2
Nội dung thư mục source:
Hình 1: Thư mục source của thư viện SystemC-UVM
4.4) Cấu hình cài đặt
Lệnh: khai báo đường dẫn thư mục cài đặt ở prefix và đường dẫn thư viện SystemC đã cài đặt trước đó ở --with-systemc
./configure --prefix=/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/UvmSystemC_lib --with-systemc=/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/SystemC233_lib
Kết quả: Nếu không có bất kỳ lỗi nào phát sinh trong quá trình cấu hình, bạn sẽ nhận được một bảng tóm tắt thông báo các thông tin cấu hình:
  • Phiên bản thư viện UVM-SystemC 1.0-beta2
  • Nền tảng cài đặt là i686-pc-cygwin
  • Các thư mục đã được thiết lập cho việc cài đặt (Directory setup)
  • Nền tảng cài đặt (Target architecture): cygwin
  • Các thiết lập cho việc xây dựng (build) thư viện (Build settings)
Lưu ý, thư mục cài đặt vẫn rỗng sau bước này nếu nó là một thư mục được tạo mới.
Hình 2: Hiển trị trên Cygwin sau khicấu hình cài đặt UVM-SystemC
4.5) Cài đặt thư viện
Nếu thư mục cài đặt đã được cài thư viện trước đó và đây là lần cài đặt lại thì cần thực thi lệnh sau để xóa bỏ dữ liệu cũ trước khi cài đặt:
make clean
Lệnh cài đặt:
make install
Kết quả: Thư mục cài đặt sẽ xuất hiện các thành phần của thư viện UVM-SystemC:
  • docs: chứa các file hướng dẫn về thư viện UVM-SystemC
  • examples: các source code để bạn có thể tham khảo
  • include: các header (.h) file
  • lib-cygwin: cấu hình sử dụng thư viện UVM-SystemC. Lưu ý, tên thư mục này sẽ khác nhau tùy nên tảng cài đặt. Ở đây, tác giả cài trên cygwin nên tên thư mục là lib-cygwin
Hình 3: Thư mục UvmSystemC_lib sau khi cài đặt

Hình 4: Thông tin trên terminal khi kết thúc quá trình cài đặt thư viện UVM-SystemC
5) Cài đặt thư viện SCV
5.1) Tạo thư mục để cài đặt (nếu muốn)
Lệnh:
mkdir scv201_lib
Kết quả: ví dụ đường dẫn thư mục đã tạo là:
/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/scv201_lib
Lưu ý, bạn có thể không cần tạo thư mục này mà có thể cài thư viện SCV vào cùng thư mục với thư viện SystemC.
5.2) Giải nén gói thư viện SCV ở một thư mục bất kỳ

Lệnh:
tar -xzf scv-2.0.1.tar.gz
Kết quả: thư mục chứa source cài đặt được tạo
scv-2.0.1
5.3) Chuyển đến thư mục đã giải nén
Lệnh:
cd scv-2.0.1
Nội dung thư mục source:
Hình 5: Thư mục source của thư viện scv-2.0.1
5.4) Cấu hình cài đặt
Thư viện SCV phiên bản 2.0.1 không hỗ trợ gcc 7.4 và nền tảng cygwin. Trong script cấu hình cài đặt SCV, phiên bản hệ điều hành và trình biên dịch sẽ được kiểm tra. Nếu script phát hiện nền tảng hoặc trình biên dịch đang dùng không nằm trong danh sách được hỗ trợ, nó sẽ báo lỗi và không thực hiện việc cấu hình cài đặt.
Hình 6: Báo lỗi "not supported" với trình biên dịch gcc và nền tảng cygwin
Để có thể sử dụng trên nền tảng Cygwin và trình biên dịch gcc 7.4, bạn cần chỉnh sửa lại script cấu hình trong thư mục mã nguồn, file scv-2.0.1/configure.
Đầu tiên, tìm đến dòng "checking for supported operating system" trong script, dòng 16109 16110. Bạn sẽ thấy đoạn code dưới đây:
case "$target_os" in solaris2.5*|solaris2.6|solaris2.7|solaris2.8|solaris2.9|solaris2.10|solaris2.11|hpux11*|linux-gnu|darwin*         |mingw32)
Đoạn code trên liệt kê một danh sách các hệ điều hành và nền tảng được hỗ trợ như mingw32, linux-gnu, solaris2.5, ... và không có cygwin. Bạn hãy thêm cygwin vào danh sách kiểm tra này.
case "$target_os" in solaris2.5*|solaris2.6|solaris2.7|solaris2.8|solaris2.9|solaris2.10|solaris2.11|hpux11*|linux-gnu|darwin*         |mingw32|cygwin)
Tiếp theo, tìm đến dòng 16084, bắt đầu với chuỗi ký tự  SUPPORTED_CXX_VERSIONS, nội dung dòng này liệt kê các phiên bản gcc được hỗ trợ. Bạn cần thêm 7.4 vào danh sách này.
SUPPORTED_CXX_VERSIONS="(3.2|3.4|4.1|4.2|4.3|4.4|4.5|4.6|4.7|4.8|4.9|5.4|6.1|6.3|7.4)"
Sau đó, chạy lệnh cấu hình cài đặt với đường dẫn thư mục thư viện SystemC đã cài trước đó:
./configure --with-systemc=/cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/SystemC233_lib
Lệnh trên không chứa tùy chọn "--prefix" nên thư viện SCV sẽ được cài vào thư mục SystemC233_lib, chung với thư viện SystemC. Trong quá trình, script configure thực thi, bạn sẽ thấy hiệu quả của việc chỉnh sửa trên qua hai thông báo sau trên cygwin terminal:
checking for supported C++ compiler... gcc 7.4 is supported
checking for supported operating system... cygwin is supported
Lưu ý, việc gcc 7.4 và cygwin không có trong danh sách được hỗ trợ là bởi vì thư viện chưa được kiểm tra đầy đủ và toàn diện trên các nền tảng này. Việc chỉnh sửa để có thể cài đặt và sử dụng có thể gây ra lỗi "nào đó". Nếu bạn không muốn gặp rủi ro thì hãy cài đặt và sử dụng trên các nền tảng đã được khuyến cáo.
HÌnh 7: Hiển thị trên cygwin khi quá trình cấu hình cài đặt scv-2.0.1 kết thúc
5.5) Cài đặt thư viện
Nếu thư mục cài đặt đã được cài thư viện trước đó và đây là lần cài đặt lại thì cần thực thi lệnh sau để xóa bỏ dữ liệu cũ trước khi cài đặt:
make clean
Tiếp theo, thực hiện một số chỉnh sửa ở file /scv-2.0.1/src/scv/scv_init_seed.cpp trước khi cài đặt như sau:
  • Thêm "#define _BSD_SOURCE" vào đầu file
  • Sửa dòng 52 từ " #include <time.h>" thành " #include <sys/time.h>"

Nếu các dòng trên không được chỉnh sửa, lỗi sau đây sẽ xuất hiện khi thực thi cài đặt:
Hình 8: Lỗi xuất hiện ở file scv_init_seed.cpp
Biên dịch lại mã nguồn:
make
Hình 9: Thông điệp hiển thị trên cygwin sau khi kết thúc lệnh make
Thực thi lệnh cài đặt:
make install
Kết quả: Trong thư mục /cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/SystemC233_lib/include sẽ có thư viện SCV gồm:
  • scv.h
  • scv/
Hình 10: Hiển thị trên cygwin sau khi kết thúc quá trình cài đặt SCV
6) Kiểm tra các thư viện đã cài đặt
  • Tải môi trường UVM-SystemC trên Github 
  • Vào thư mục apbUartUvmSystemC/sim, chỉnh sửa lại đường dẫn các thư viện và đường dẫn môi trườn trong file run.csh
setenv SYSTEMCLIB cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/SystemC233_lib
setenv UVMLIB cygdrive/d/20.Project/0.Library/001_SystemC/002_Lib/UvmSystemC_lib
setenv WDIR cygdrive/d/20.Project/3.Github/apbUartUvmSystemC
  • Thực thi lệnh ./run.csh trong thư mục sim
  • Kết quả: file testTop.exe được tạo ra và không có bất kỳ lỗi nào
Hình 11: Thư mục apbUartUvmSystemC/sim

Dữ liệu có thể tải:

Lịch sử cập nhật:
1. 2019.Apr.29 - Tạo lần đầu

Danh sách tác giả:
1. Trương Công Hoàng Việt
2. Lê Hoàng Vân
3. Nguyễn Hùng Quân

Thứ Ba, 26 tháng 11, 2019

[UVM] Bài 8 - Tạo báo cáo coverage và phân tích kết quả Coverage

Bài viết này trình bày về cách tạo báo cáo coverage (coverage report) và cách phân tích kết quả coverage trên một môi trường mô phỏng với phần mềm QuestaSim.


1) Coverage là gì?
Coverage, tạm dịch là mức độ bao phủ, là tỷ lệ phần trăm các mục tiêu kiểm tra đã được đáp ứng.
Ví dụ, mục tiêu kiểm tra của một thiết kế được xác định là 5 điểm. Mỗi mục tiêu kiểm tra sẽ ứng với một hoặc nhiều hoạt động, gọi là các chức năng (function), được thực hiện bởi một hoặc nhiều đoạn code. 5 mục tiêu được kỳ vọng sẽ giúp kiểm tra hết các chức năng và các đoạn code của thiết kế. Bạn sẽ cần tạo các testcase để kiểm tra 5 mục tiêu đã đặt ra. Để ước lượng kết quả kiểm tra, một số vấn đề sau cần được xác minh:
  • Làm thế nào để biết chắc rằng các chức năng và các đoạn code của thiết kế đã được kiểm tra toàn bộ hay chưa?
  • Làm thế nào để khẳng định số lượng testcase được tạo ra đã đáp ứng được 5 mục tiêu kiểm tra? Số lượng testcase đã đầy đủ hay chưa?
  • Làm thế nào để đánh giá tiến độ kiểm tra (verification progress) hiện tại?
*testcase là code dùng để thực thi kiểm tra thiết kế trên một môi trường mô phỏng. Mỗi testcase thường thực thi một trường hợp hoặc mục đích kiểm tra cụ thể.
Hình 1: Một thiết kế cần được kiểm tra (DUT) với 5 mục tiêu kiểm tra được xác định, mỗi mục tiêu sẽ kiểm tra một phần chức năng và code
Coverage là một thước đo hỗ trợ đánh giá các vấn đề trên. Ví dụ, coverage là 13/15, ứng với 86,667%, thể hiện:
  • Các chức năng và các đoạn code có thể chưa được kiểm tra toàn bộ. Các phần chưa được bao phủ cần được xem xét và đánh giá để xác định là cần được kiểm tra hay không.
  • Nếu các phần chưa được bao phủ cần phải kiểm tra, nghĩa là số lượng testcase đang bị thiếu và cần tạo thêm các testcase mới.
  • Việc lấy kết quả coverage theo từng giai đoạn có thể dùng làm thông số để ước lượng tiến độ kiểm tra.
Hình 2: Minh họa một kết quả coverage 13/15 = 86,667%
Việc dùng kết quả coverage để đánh giá tiến độ của quá trình kiểm tra thiết kế được thực hiện như sau:
  1. Xác định thời gian thực hiện kiểm tra, thời điểm bắt đầu và thời điểm kết thúc
  2. Xác định các mốc thời gian lấy kết quả coverage
  3. Thực thi các testcase trong từng giai đoạn và lấy kết quả coverage khi đến mốc thời gian đã xác định ở bước 2
Mốc thời gian
Tuần 1
Tuần 2
Tuần 3
Tuần 4
Tuần 5
Kết quả coverage
30%
40%
70%
95%
100%

Trong ví dụ trên, quá trình kiểm tra một thiết kế được xác định là 5 tuần, kết quả coverage sẽ được lấy vào cuối mỗi tuần. Thông qua kết quả coverage, tiến độ công việc kiểm tra thiết kế được thể hiện.
2) Phân loại coverage?
Covearge được chia làm hai nhóm chính là:
  • Code coverage là các thông tin coverage có thể được trích xuất tự động từ RTL code hoặc gate netlist, gọi chung là code, của thiết kế.
  • Function coverage là loại coverage được định nghĩa bởi người kiểm tra (user-defined) gắn liền với mục đích và chức năng thiết kế.
3) Code coverage
Code coverage là chức năng được hỗ trợ bởi hầu hết các phần mềm các phần mềm mô phỏng. Các phần mềm sẽ giúp trích xuất kết quả coverage từ RTL code hoặc gate netlist thông qua việc thực thi các testcase. Nguyên tắc cơ bản của code coverage là thống kê lại giá trị của các thành phần được mô tả trong code khi các testcase được thực thi.
Code coverage không được sử dụng để đánh giá:
  • Tính đầy đủ trong việc kiểm tra thiết kế. Một thiết kế có code coverage là 100% không có nghĩa là thiết kế này đã được kiểm tra toàn bộ các chức năng.
  • Tính đúng đắn của một thiết kế. Một thiết kế có code coverage 100% không có nghĩa là thiết kế này hoạt động chính xác 100%.
Code coverage không thể dùng để đánh giá 2 điểm trên vì việc thống kê được thực hiện độc lập trên các biến và các tín hiệu mà không xem xét đến chức năng và hoạt động của thiết kế. Nghĩa là không xem xét đến mối liên hệ của tất cả các thành phần trong thiết kế. Ví dụ, trong toggle coverage, ngõ vào của một khối trong thiết kế được báo là đạt 100%, điều này chỉ thể hiện là có sự chuyển trạng thái "từ 0 thành 1" và "từ 1 thành 0" trên tín hiệu, chứ không giúp khẳng định sự chuyển trạng thái này xảy ra đúng như chức năng mong muốn. 
Code coverage chỉ được dùng để đánh giá các điểm sau:
  • Hỗ trợ xác định các trường hợp test (testcase) bị thiếu. Khi coverage không đạt 100% thì phần code chưa được bao phủ có thể là phần code không được sử dụng (unused) hoặc phần code chưa được kiểm tra. Nếu là phần code chưa được kiểm tra, nghĩa là trường hợp test đang thiếu và cần tạo thêm testcase để kiểm tra phần code này.
  • Thống kê tác động của một testcase hoặc một nhóm testcase lên code cần kiểm tra. Ví dụ, sau khi chạy một testcase, thông qua báo cáo coverage, bạn có thể biết testcase này tác động lên những phần code nào của thiết kế.
Code coverage bao gồm các loại sau:
  • Statement coverage - mức độ bao phủ của các phát biểu, xác định xem một phát biểu (statement) trong code đã được thực thi hay chưa. Ví dụ về một phát biểu:
assign y = sel? a: b;
  • Branch coverage - mức độ bao phủ của các nhánh, dùng để đánh giá sự thực thi của cấu trúc rẽ nhánh if/elsecase. Một cấu trúc rẽ nhánh chỉ được bao phủ 100% khi tất cả các nhánh đều đã được thực thi. Ví dụ, cấu trúc if/else sau đây được bao phủ 100% nếu cả 3 nhánh if, else if else đều đã được thực thi.
if (a == 1)
  y = 0;
else if (b = 1)
  y = 2;
else
  y = 1;
  • Condition coverage - mức độ bao phủ của các điều kiện, dùng để đánh giá và phân tích các điều kiện mô tả trong các nhánh của phát biểu if và toán tử điều kiện ?. Tùy và phần mềm, nó có thể là một phần của branch coverage hoặc là một báo cáo riêng. Một điều kiện chỉ được bao phủ 100% khi tất cả các giá trị làm cho điều kiện đó đúng (TRUE) và sai (FALSE) đều xuất hiện. Ví dụ, điều kiện state == IDLE sau đây chỉ được bao phủ 100% nếu state bằng IDLE và state khác IDLE đã xảy ra.
if (state == IDLE)
  • Expression coverage - mức độ bao phủ của các biểu thức, dùng để đánh giá biểu thức bên vế phải của một phép gán. Một biểu thức được bao phủ 100% khi tất cả tổ hợp giá trị của các biến trong biểu thức đã xuất hiện. Ví dụ, biểu thức sau chỉ được xem là bao phủ 100% nếu tất cả các tổ hợp giá trị của {a, b}00, 01, 1011 đều đã xuất hiện.
assign y = a & b;
  • Toggle coverage - mức độ bao phủ của sự thay đổi trạng thái, dùng để đánh giá sự thay đổi trạng thái trên các tín hiệu. Một tín hiệu chỉ được bao phủ 100% khi nó đã xuất hiện sự chuyển mức logic từ 0 thành 1 và ngược lại. Đối với tín hiệu 3 trạng thái (tri-state) thì có thể cần phải thêm sự chuyển đổi từ 0 1 thành Z và từ Z thành 0 1.
Ngoài ra một số phần mềm còn hỗ trợ các loại coverage khác như:
  • FSM coverage - mức độ bao phủ của FSM, dùng để đánh giá riêng máy trạng thái
  • Class Coverage -  mức độ bao phủ của class, dùng để đánh giá riêng các class của System Verilog
Hình 3: Phân loại coverage
4) Function coverage
Fucntion coverage thuộc về người dùng định nghĩa chứ không thể được trích xuất tự động bằng phần mềm. Người kiểm tra sẽ phải mô tả cụ thể điểm cần được bao phủ bằng System Verilog. Dựa trên mô tả này, phần mềm sẽ giám sát và báo cáo kết quả coverage.  Các điểm quan trọng của function coverage là:
  • Người kiểm tra phải định nghĩa điểm cần bao phủ
  • Điểm cần bao phủ được định nghĩa dựa trên tài liệu mô tả kỹ thuật (specification) và đặc điểm mong muốn của thiết kế chứ không phụ thuộc vào cấu trúc hoặc code của thiết kế
  • Function coverage có thể hỗ trợ đánh giá tính đầy đủ và đúng đúng đắn của thiết kế. Điều mà code coverage không hỗ trợ được.
Function coverage có thể được dùng để giám sát và xác nhận các điểm sau:
  • Một đặc điểm hoặc chức năng nào đó của thiết kế hoạt động đúng. Ví dụ, một biến trong thiết kế phải thay đổi giá trị tuần tự 1 -> 3 -> 5 -> 8. Code coverage chỉ cho biết biến này đã xuất hiện những giá trị nào chứ không cho biết các giá trị đã xuất hiện có theo đúng thứ tự như yêu cầu thiết kế hay không. Function coverage sẽ giúp giám sát điều này.
  • Một điều kiện hoặc trường hợp kiểm tra đã xảy ra hay chưa. Trong một số trường hợp, điều kiện kiểm tra tạo ra từ testcase cần được xác nhận để đảm bảo rằng testcase thực thi đúng trường hợp như mong muốn.
SV có hỗ trợ các thành phần như covergroup, coverpoint, cross, các tùy chọn, task và function giúp người kiểm tra có thể mô tả function coverage.
5) Mô tả fucntion coverage với SV
Phần  này không nhằm mục đích trình bày chi tiết cách thức mô tả function coverage với SV mà chỉ thực hiện một ví dụ nhỏ về function coverage giúp bạn đọc hiểu rõ hơn function coverage là gì?
Trong môi trường mô phỏng đã xây dựng, một ví dụ về function coverage được thêm vào file ./checker/uart_protocol_checker.sv để kiểm tra trường hợp truyền back-to-back của giao thức UART. Back-to-back là truyền liên tiếp các gói dữ liệu UART mà không có khoảng thời gian rảnh giữa các gói. Nghĩa là bit START của gói sau nối tiếp ngay sau bit STOP của gói trước.
Hình 4: Truyền back-to-back của giao thức UART
Để đảm bảo chức năng này xảy ra, một điểm bao phủ sẽ được mô tả để kiểm tra frame_start và frame_end cùng tích cùng mức 1 trong khhi checker đang ở trạng thái CHK_UART_CHECK. Ở đây,
  • frame_end báo kết thúc một khung UART, ngay sau bit STOP
  • frame_start phát hiện một cạnh xuống của bit START
  • checker đang ở trạng thái CHK_UART_CHECK là để đảm bảo nó đang trong một trạng thái kiểm tra khung UART
Hình 5: Vị trí đặt điểm bao phủ (coverpoint) để đảm bảo có sự truyền nhận back-to-back trên giao thức UART
Ví dụ 1 - SV code mô tả một function coverage
 covergroup back_2_back @ (posedge pclk);
    coverpoint chk_uart_state {
      bins pass[] = {1} iff (frame_start && frame_end) ;
    }
    option.per_instance = 1;
  endgroup
  back_2_back b2b = new();
  initial begin
    b2b.sample();
  end
Trong đoạn code trên:
  • Tên covergroup back_2_back, việc lấy mẫu kiểm tra giá trị cần bao phủ được thực hiện tại cạnh lên pclk
  • Tín hiệu cần kiểm tra là chk_uart_state phải bằng 1, pass[] = {1}, trong khi frame_start=1 frame_end=1iff (frame_start && frame_end)
  • option.per_instance = 1 để cho phép thông tin của một instance tạo từ covergroup này được thống kê trong dữ liệu coverage và báo cáo coverage.
  • Tạo một instance covergroup bằng new()
  • sample() là một hàm hỗ trợ bở SV dùng để kích hoạt việc lấy mẫu covergae
6) Cách tạo báo cáo coverage với QuestaSim
Phần mềm được sử dụng là QuestaSim 10.2c. Việc tạo một báo cáo coverage trên phần mềm này được thực hiện như sau:
  • Lệnh vlog: Tổng hợp source code với tùy chọn "+cover". Tùy chọn này cho phép thu thập các kết quả coverage khác nhau trên tất cả các thành phần trong thiết kế. Tùy chọn này đi kèm với các giá trị sau:
    • b - cho phép branch coverage
    • c - cho phép condition coverage, chỉ thu thập loại ocverage FEC (Focused Expression Coverage)
    • e - cho phép expression coverage, chỉ thu thập loại ocverage FEC
    • s - cho phép statement coverage
    • t - cho phép toggle coverage, tùy chọn này có thể bị ghi đè bởi tùy chọn "x"
    • x - cho phép toggle coverage mở rộng, thêm việc giám sát chuyển trạng thái từ 0,1 thành Z và ngược lại.
    • f - cho phép FSM coverage
Ví dụ 2 - Lệnh tổng hợp source code cho phép coverage (chú ý dòng bôi đỏ, đây là đường dẫn thư viện UVM)
my $vlog = "$VLog -work work \\
+define+UVM_CMDLINE_NO_DPI \\
+define+UVM_REGEX_NO_DPI \\
+define+UVM_NO_DPI \\
+define+INTERRUPT_COM \\
+incdir+C:/questasim64_10.2c/uvm-1.2/src \\
-sv \\
../dut/uart_apb_if.v \\
../dut/uart_receiver.v \\
../dut/uart_transmitter.v \\
../dut/uart_top.v \\
../dut/dut_top.v \\
../checker/apb_protocol_checker.sv \\
../checker/apb_protocol_checker_top.sv \\
../checker/uart_protocol_checker.sv \\
../checker/uart_protocol_checker_top.sv \\
../uvm_comp/ifDut.sv \\
testTop.sv \\
-timescale 1ns/1ns \\
-l vlog.log \\
+cover=bcestf \\
    -coveropt 1
";
  • Lệnh vsim - Chạy mô phỏng và tạo cở sở dữ liệu coverage (coverage database). Cơ sở dữ liệu coverage được lưu trong file .ucdb. UCDB là viết tắt của Unified Coverage Database. với các tùy chọn
    • -coverage : cho phép thu thập các thống kê của code coverage trong quá trình chạy mô phỏng
    • -coveranalysis : lưu các điểm toggle vào file UCDB
    • -cvgperinstance :  thiết lập giá trị của  option.per_instance của tất cả các covergroup bằng 1.
    • -do : dùng tùy chọn này để thực thi một lệnh lưu cơ sở dữ liệu coverage.
  • Lệnh lưu cơ sở dữ liệu trong tùy chọn "-do" của vsim "coverage save -codeAll -cvg -onexit $ARGV[0].ucdb". Ý nghĩa của lệnh này như sau:
    • coverage save : lệnh lưu kết quả coverage với các loại coverage được mô tả trong một file .ucdb
    • -codeAll : Tất cả các loại coverage, tương được với tùy chọn " -code bcestf " 
    • -cvg : lưu lại dữ liệu của covergroup, cái dùng để đặc tả function coverage
    • -onexit : tự động lưu lại dữ liệu coverage khi thoát trình mô phỏng
    • $ARGV[0].ucdb : tên file cơ sở dữ liệu coverage. Trong script này, tên file là <tên testcase>.ucdb
Ví dụ 3 - Lệnh chạy mô phỏng và tạo cơ sở dữ liệu coverage
my $vsim = "$VSim -c -novopt work.testTop \\
+UVM_TESTNAME=cTest \\
+UVM_VERBOSITY=UVM_LOW \\
-do \"coverage save -codeAll -cvg -onexit $ARGV[0].ucdb; run -all;\" \\
-coverage \\
    -coveranalysis \\
-cvgperinstance \\

-l vsim.log";
  • Tạo báo cáo coverage cho một testcase
    • vcover report : Lệnh tạo báo cáo coverage
    • -html : tùy chọn tạo file báo cáo dạng HTML. File này được mở dễ dàng bằng các trình duyệt web như chrome, firefox, ...
    • -htmldir : chỉ định thư mục lưu báo cáo coverage
    • -code : chọn các loại code coverage sẽ có trong báo cáo
    • -cvg : hiển thị coverage group trong báo cáo
    • $ARGV[0].ucdb : tên file cơ sở dữ liệu coverage được tạo ra ở bước chạy mô phỏng phía trên
Ví dụ 4 - Lệnh tạo báo cáo coverage cho một testcase
my $vcover = "$VCov report -html -code bcestf -testhitdata -cvg $ARGV[0].ucdb";
  • Tạo báo cáo coverage cho toàn bộ kết quả chạy mô phỏng gồm nhiều testcase (merge coverage)
    • Lưu cơ sở dữ liệu coverage của mỗi testcase đến thư mục ./cov sau mỗi lần chạy mô phỏng bằng cách sao chép file cở dữ liệu sau khi chạy một testcase đến thư mục ./cov.
Ví dụ 5 - Lưu lại cơ sở dữ liệu coverage của mỗi testcase
system "cp -rf $ARGV[0].ucdb ../cov/";
    • Thực thi hợp nhất (merge) các cơ sở dữ liệu coverage. Lệnh sau đây sẽ hợp nhất tất cả các cơ sở dữ liệu của từng testcase lưu trong ./cov thành một file cơ sở dữ liệu tên mergedCov.ucdb
Ví dụ 6 - Lệnh hợp nhất các cơ sở dữ liệu
my $vmerge = "$VCov merge mergedCov.ucdb ../cov/*.ucdb";
  • Tạo file báo cáo coverage từ cơ sở dữ liệu đã được hợp nhất. Lệnh sau đây sẽ tạo file báo cáo tên index.html (tên mặc định) trong thư mục ./sim từ cơ sở dữ liệu đã hợp nhất trong file mergedCov.ucdcb.
Ví dụ 7 - Tạo file báo cáo
my $vcover = "$VCov report -html -htmldir ./ -code bcestf -cvg mergedCov.ucdb";
Chi tiết được thể hiện trong một script Perl tên ./sim/run_qsim.pl có thể tải cuối bài viết. Với môi trường này, các bạn chạy từng testcase bằng lệnh:
./run_qsim.pl <tên testcase>
Sau khi chạy toàn bộ hoặc một vài testcase, báo cáo coverage tổng hợp có thể được tạo bằng lệnh
./run_qsim.pl MERGE_COVERAGE
Mở file ./sim/index.html để kiểm tra kết quả coverage. Một số điểm quan trọng cần lưu ý:
  1. run_qsim.pl là Perl script sử dụng các biến đại diện cho các lệnh của QuestaSim như sau:
    • $VLog ứng với vlog
    • $VSim ứng với vsim
    • $VCov ứng với vcover
  2. Script chạy với Cygwin terminal trên hệ điều hành Windows
  3. Các tùy chọn của từng lệnh đã giới thiệu trên đây có thể khác nhau trên các phiên bản phần mềm khác nhau. Vì vậy, bạn cần kiểm tra lại các lệnh và các tùy chọn với tài liệu tên "Command Reference Manual" kèm theo phần mềm đang sử dụng.
  4. Báo cáo coverage với định dạng .html có thể chỉ được mở trên một số trình duyệt web và phiên bản trình duyệt nhất định
  5. Định dạng của báo cáo coverage có thể khác nhau trên các phiên bản phần mềm khác nhau.
  6. Phần mềm không có license thương mại sẽ bị hạn chế một số chức năng coverage, ví dụ như báo cáo coverage không được tạo ra chi tiết và đầy đủ.
7) Phân tích kết quả coverage
7.1) Báo cáo tổng quan
Tác giả chạy lệnh sau đây để lấy kết quả coverage cho testcase tên trialPat.
./run_qsim.pl trialPat
Sau khi chạy, dùng một trình duyệt web như Firefox, Chrome, ... để mở file ./sim/index.html, các bạn sẽ quan sát thấy như sau:
Hình 6: Báo cáo coverage
Kết quả coverage của từng thành phần trong môi trường được thể hiện bằng chỉ số % mức độ bao phủ. Mỗi loại coverage được sắp xếp thành từng cột, ứng với các tùy chọn đã trình bày ở mục trên.
  • Phần bên trái ngoài cùng liệt kê tất cả các thành phần được lấy coverage theo cấu trúc môi trường mô phỏng
  • Phần bên phải là báo cáo tổng hợp từng loại coverage
Bên dưới báo cáo tổng hợp này sẽ có báo cáo chi tiết. Báo cáo chi tiết này sẽ liên kết đến các báo cáo phân tích giúp người kiểm tra xác định các thành phần code hoặc chức năng (function) chưa được kiểm tra. Báo cáo chi tiết gồm các cột sau:

  • Coverage Type: Liệt kê loại coverage
  • Bins: Tổng số điểm kiểm tra được thống kế
  • Hits: Số điểm đã được bao phủ 100%
  • Misses: Số điểm chưa được bao phủ. Các điểm này có thể được bao phủ một phần hoặc hoàn toàn chưa được bao phủ.
  • Weight: Trọng số bao phủ, mặc định là 1
  • %Hit: là tỷ số của Hits/Bins
  • Coverage: là kết quả coverage

Hình 7: Báo cáo chi tiết xuất hiện bên dưới báo cáo tổng hợp
Đây cũng là cấu trúc chung của một một báo cáo coverage trên QuestaSim, nó gồm:
  • Một báo cáo tổng hợp bên trên giúp đánh giá nhanh kết quả
  • Một báo cáo chi tiết bên dưới giúp liên kết đến các báo cáo phân tích kết quả
Người kiểm tra có thể truy xuất kết quả coverage của các thành phần nằm sâu hơn trong cấu trúc môi trường, các sub-instance, bằng các click vào các liên kết trên báo cáo coverage. Sau đây, tác giả sẽ phân tích cụ thể báo cáo của từng loại coverage.
Hình 8: Báo cáo coverage của intance uart0_chk trong testTop.uart_protocol_checker_top
7.2) Function coverage
Như đã trình bày ở trên function coverage là do người kiểm tra dịnh nghĩa bằng SV. Phần mềm sẽ thống kê lại các instance của covergroup mà người dùng định nghĩa.
Trong ví dụ này, chúng ta sẽ xem kết quả của của instance b2b, được tạo từ covergroup back_2_back, trong testTop.uart_protocol_checker_top.uart0_chk.
Hình 9: Báo cáo coverage của covergroup trong function coverage
Báo cáo trên có 3 bảng thể hiện 3 thông tin:
  • Bảng 1 thống kê số instance của các covergroup
  • Bảng 2 thống kê số coverpoint của các covergroup
  • Bảng 3 thống kê số bins của các coverpoint
7.3) Statements coverage
Báo cáo cho các loại code coverage sẽ được minh họa trên instance testTop.dut_top.uart_0.transmitter.
Hình 10: Báo cáo coverage của instance testTop.dut_top.uart_0.transmitter
Click vào các loại coverage tương ứng trong cột "Coverage Type" sẽ xem được báo cáo chi tiết của từng loại. Để xem báo cáo chi tiết của kết quả coverage, click vào Statements.
Hình 11: Báo cáo statement coverage
Trong báo cáo chi tiết của Statements coverage:
  • Các dòng code màu đen không thuộc phạm vi thống kê của statement coverage. Chúng sẽ được thống kê trong các loại báo cáo coverage khác.
  • Các dòng code được tô xanh là các phát biểu đã được thực thi, ứng với đã bao phủ.
  • Các dòng code được tô đỏ là các trường hợp code chưa được thực thi, ứng với chưa bao phủ. Các điểm chưa bao phủ cần được xem xét để thêm testcase kiểm tra hoặc bỏ qua dựa trên mô tả của thiết kế.
Hình 12: Báo cáo thể hiện chi tiết các dòng code đã được bao phủ và chưa được bao phủ
Trong báo cáo trên, ở phát biểu case(ctrl_txt[1:0]), code chỉ mới thực thi trường hợp đầu tiên, ứng với ctrl_txt=2'b00, ba trường hợp còn lại và nhánh default chưa được thực thi. Như vậy, người kiểm tra phải tạo thêm testcase để kiểm tra trường hợp 2'b01, 2'b102'b11. Nhánh default không cần phải bao phủ vì ctrl_txt[1:0] chỉ có 2 bit nên chỉ cần bao phủ đủ 4 trường hợp.
7.4) Branches coverage
Báo cáo thể hiện rõ nhánh điều kiện nào đã bao phủ, ứng với Status Covered và nhánh nào chưa bao phủ, ứng với Status là ZERO.
Nếu đã bao phủ, cột Hits sẽ cho biết số lần nhánh này được thực thi trong testcase hiện tại. Nếu chưa bao phủ, cột Hits sẽ là 0.
Hình 13: Báo cáo branch coverage
Cột Branch sẽ cho biết nhánh nào của điều kiện chưa được thực thi. Người kiểm tra có thể click vào tiêu đề của bảng báo cáo để xem RTL code tương ứng.
Hình 14: Dòng 68 là RTL code của bảng cáo cáo 3
7.5) Expressions coverage
Expressions coverage của QuestaSim dùng cơ chế FEC (Focused Expression Coverage) để đánh giá kết quả coverage.
FEC là một cơ chế đánh giá kết quả coverage trên các ngõ vào của một biểu thức. Biểu thức là vế phải của một phép gán hoặc một biểu thức điều kiện. Nguyên tắc của FEC là một biểu thức gọi là được bao phủ 100% nếu tất cả các ngõ vào của nó được bao phủ đầy đủ. Một ngõ vào được bao phủ đầy đủ bằng cách áp dụng phương pháp sau đây:
  • Tất cả các ngõ vào khác phải trong trạng thái cho phép ngõ vào này điều khiển giá trị ngõ ra
  • Ngõ ra phải đạt cả hai giá trị 0 1 khi ngõ vào này điều khiển
Giá trị coverage được tính bằng số ngõ vào được bao phủ đầy đủ chia tổng số ngõ vào.
Hình 15: Báo cáo expression coverage theo cơ chế FEC
Với mỗi biểu thức, kết quả sẽ gồm 2 bảng. Ví dụ trên đây là báo cáo cho biểu thức:
tx_shift_complete = ctrl_d9? (shift_tx_counter[3:0]==4'd10): (shift_tx_counter[3:0]==4'd9)
  • Bảng đầu tiên: báo cáo trên từng ngõ vào của biểu thức, trường hợp này là 3 ngõ vào là ctrl_d9, shift_tx_counter[3:0]==10shift_tx_counter[3:0]==9. Báo cáo gồm các cột sau:
    • Covered: Ngõ vào đã được bao phủ hay chưa
      • No: Chưa bao phủ
      • Yes: Đã bao phủ
    • Reason For No Coverage: Lý do của trường hợp chưa bao phủ (No). Trong ví dụ này, lý do gồm:
      • ctrl_d9 đã xảy ra trường hợp bằng 0 ('_0' hit) nhưng chưa xảy ra trường hợp bằng 1 (but '_1' not hit)
      • shift_tx_counter[3:0]==10 chưa xảy ra trường hợp nào (No hits) tác động đến kết quả ngõ ra  tx_shift_complete. Chú ý, "No hits" nghĩa là ngõ vào này chưa được tác động để điều khiển ngõ ra chứ không phải có ý nghĩa "chưa xảy ra trường hợp bộ đếm bằng 10". Bạn hãy xem lại giải thích về FEC. Ở đây, vì ctrl_d9 chưa bằng 1 nên nhánh này chưa được chọn, vì vậy, chưa được bao phủ.
    • Hint hướng dẫn làm thế nào để bao phủ trường hợp này. Trong ví dụ này, để bao phủ các trường hợp No, chúng ta cần thực hiện:
      • Đối với ngõ vào ctrl_d9: Lái ctrl_d9=1 (Hit '_1') và làm cho ngõ ra xuất hiện giá trị 0 hoặc 1 (for output ->0 or ->1)
      • Đối với shift_tx_counter[3:0]==10: Biểu thức này phải được lái giá trị ngõ ra bằng 0 và 1.

*Ghi chú: '_0 và '_1' ứng với phần hậu tố (suffix) được thêm vào các ngõ vào ở bảng chi tiết thứ 2.
  • Bảng thứ 2 sẽ chi tiết hóa từng trường hợp bao phủ của ngõ vào.
    • FEC Target là tên tín hiệu với hậu tố thể hiện giá trị cần được bao phủ. Ví dụ, ctrl_d9_0 là trường hợp ctrl_d9=0.
    • Hits (->0) là trường hợp bao phủ mà ngõ vào lái ngõ ra biểu thức bằng 0. Nếu giá trị cột này là 1 thì trường hợp này đã xảy ra, bằng 0 là chưa xảy ra. Ví dụ, cột này của ctrl_d9_0=1 chứng tỏ đã xảy ra trường hợp ctrl_d9=0 và làm ngõ ra tx_shift_complete=0
    • Hits (->1) là trường hợp bao phủ mà ngõ vào lái ngõ ra biểu thức bằng 1. Nếu giá trị cột này là 1 thì trường hợp này đã xảy ra, bằng 0 là chưa xảy ra. Ví dụ, cột này của ctrl_d9_0=1 chứng tỏ đã xảy ra trường hợp ctrl_d9=0 và làm ngõ ra tx_shift_complete=1
    • Matching Input Patterns (->0) thể hiện giá trị của 3 ngõ vào theo thứ tự đã làm cho ngõ ra bằng 0. Ví dụ, cột này của ctrl_d9_0 là {0-0} chứng tỏ trường hợp sau đã xuất hiện làm ngõ ra bằng 0:
      • ctrl_d9=0
      • shift_tx_counter[3:0]==10 không được thống kê giá trị trong trường hợp này, ứng với dấu "-"
      • shift_tx_counter[3:0]==9 bằng 0, ứng với shift_tx_counter khác 9
    • Matching Input Patterns (->1) thể hiện giá trị của 3 ngõ vào theo thứ tự đã làm cho ngõ ra bằng 1. Ví dụ, cột này của ctrl_d9_0 là {0-1} chứng tỏ trường hợp sau đã xuất hiện làm ngõ ra bằng 1:
      • ctrl_d9=0
      • shift_tx_counter[3:0]==10 không được thống kê giá trị trong trường hợp này, ứng với dấu "-"
      • shift_tx_counter[3:0]==9 bằng 1, ứng với shift_tx_counter đã bằng 9
Trong bảng trên, ký hiệu "E-Miss" và "Not Testable" thể hiện một trường hợp không thể kiểm tra. Ví dụ, trường hợp (shift_tx_counter[3:0]==9)_0, đây là trường hợp ngõ vào phải bằng 0, tức shift_tx_counter[3:0] khác 9. Trong biểu thức này, khi ctrl_d9=0 mà shift_tx_counter[3:0] khác 9 thì chỉ có thể làm ngõ ra bằng 0, không bao giờ "shift_tx_counter[3:0] khác 9" mà làm ngõ ra bằng 1. Vì vậy, cột Hits (->1) là "E-Miss" và cột Matching Input Patterns (->1) là "Not Testable".
Chú ý, bạn có thể click vào biểu thức ở đầu bảng báo cáo để xem file code chứa biểu thức này.
7.6) Conditions coverage
Báo cáo của condition coverage gần tương tự như expression coverage.Báo cáo này cũng theo cơ chế thống kế FEC. Bạn đọc có thể tự phân tích chi tiết. Mỗi điều kiện sẽ được thống kê kết quả bằng 2 bảng. Ở hình minh họa dưới đây, điều kiện sau đây được thể hiện:
else if ((state == IDLE) & load_data)
Điều kiện này không được bao phủ trường hợp (state==IDLE) bằng 0, ứng với state khác IDLE.
Hình 16: Báo cáo condition coverage
Trong báo cáo condition coverage và expression coverage, cột "Matching ..." thay bằng cột "Non-Masking Conditions(s)" trong các phiên bản mới hơn của QuestaSim. Cột này chỉ cung cấp tổ hợp giá trị của các ngõ vào còn lại trong biểu thức giúp ngõ vào cần bao phủ có thể lái được ngõ ra.
Hình 17: Báo cáo condition coverage của phiên bản QuestaSim mới hơn bản 10.2c
Xét lại điều kiện ((state == IDLE) & load_data), quan sát cột Non-Masking Condition(s) ứng với Row 1, giá trị cột này là load_data, điều này nghĩa là load_data phải bằng 1 thì biểu thức state == 0 (0 là IDLE) mới có thể ảnh hưởng (quyết định) đến giá trị ngõ ra.
7.7) Toggles coverage
Kết quả của báo cáo này được tính bằng công thức:
Mức độ bao phủ (Status) = số hit / tổng số trường hợp chuyển trạng thái được kiểm tra 
Trong ví dụ này, toggle coverage chỉ kiểm tra 2 trường hợp:
  • Chuyển từ 0 sang 1
  • Chuyển từ 1 sang 0
Không kiểm tra các trường hợp:
Chuyển từ 0 sang Z
Chuyển từ 1 sang Z
Chuyển từ Z sang 0
Chuyển từ Z sang 1
Muốn kiểm tra toàn bộ trường hợp, trong các lệnh tổng hợp và chạy mô phỏng. Bạn cần chọn "x" thay vì "t". Ví dụ, lệnh vlog sẽ dùng tùy chọn sau:
+cover=bcesfx
thay cho tùy chọn:
+cover=bcestf
Hình 18: Báo cáo condition coverage
Bài viết đã giới thiệu cơ bản về coverage và phân tích các báo cáo coverage với phần mềm QuestaSim 10.2c. Bạn có thể tải môi trường đầy đủ về để kiểm tra thử.

Dữ liệu có thể tải: 

Lịch sử cập nhật:
1/ 2019.11.26 - Tạo lần đầu

Danh sách tác giả:
1. Phạm Thanh Trâm
2. Đoàn Đức Hoàng
3. Trương Công Hoàng Việt
4. Nguyễn Sinh Tơn
5. Nguyễn Hùng Quân