Parameter và generate: cấu hình phần cứng trước khi chạy
Tiên quyết
- Module A2: Logic tổ hợp: Đang tải
- Module A4: Tuần tự & timing: Đang tải
- Module và instance: nối hai bộ cộng mà không nhầm cổng: Đang tải
Sau bài này bạn sẽ
- Phân biệt parameter cấu hình với tín hiệu đầu vào thay đổi theo thời gian
- Dùng named parameter override và localparam dẫn xuất độ rộng
- Đọc for-generate, if-generate và đường dẫn block có tên
- Nhận diện defparam trong code cũ và kiểm tra cấu hình biên
Chọn cấu hình, rồi mới đưa dữ liệu vào
Bài trước dùng hai instance của cùng bộ cộng. Nhưng nếu mỗi sản phẩm cần số bit khác nhau, bạn không muốn duy trì nhiều bản module chỉ khác độ rộng. Parameter cho phép chọn cấu hình cho từng instance.
Trong bài này, lane_map xử lý một bus chia thành nhiều lane. W chọn số bit mỗi lane; LANES chọn số lane; INVERT chọn giữ nguyên hay đảo bit. Dữ liệu đi qua cổng data có thể thay đổi ở mỗi lần test. Ba parameter được chọn khi thiết kế được elaborate, không phải các nút điều khiển thay đổi theo từng lần đưa dữ liệu vào.
Hãy tưởng tượng đặt làm một bảng mạch: chọn số hàng và số cột khi thiết kế bảng, rồi mới thay đổi những tín hiệu đi trên bảng đó. Đây là trực giác cho ví dụ, không phải khẳng định parameter tương ứng một linh kiện vật lý cụ thể.
Ví dụ dùng SystemVerilog (.sv), trong đó có localparam ở parameter port list. Các quy tắc ngôn ngữ vẫn cần đối chiếu [1]; phần kiểm chứng của bài chỉ xác nhận các cấu hình cụ thể đã chạy.
Parameter, named override và localparam
Cấu hình mặc định của lane_map là W=4, LANES=3, INVERT=1. TOTAL là localparam dẫn xuất bằng W*LANES, dùng làm độ rộng cổng. Với mặc định, bus có 4*3=12 bit. Khi đổi một instance thành W=2, LANES=2, bus của instance đó có 4 bit.
lane_map #(.W(4), .LANES(3), .INVERT(0)) u_named
(.data(data), .mapped(pass_data));
Có hai danh sách khác nhau:
#(...)chọn giá trị parameter cho instance.(...)cuối dòng nối cổng với tín hiệu phía parent.
.W(4) cấu hình độ rộng; .data(data) nối một bus mang dữ liệu. Cả hai đều dùng cú pháp có tên, nhưng không cùng vai trò. Không đọc #(...) ở đây thành lệnh đợi thời gian như #1 trong testbench.
localparam TOTAL là giá trị nội bộ tính từ cấu hình, không phải một knob riêng cho bên ngoài override. Nếu công thức độ rộng là W*LANES, chỉ để người dùng chọn W/LANES giúp tránh ba giá trị bị cấu hình mâu thuẫn. Nó cũng không phải một thanh ghi lưu tích của hai số ở runtime.
Vòng generate tạo gì?
Trong lane_map, vòng for-generate tạo các block g_lane[0] đến g_lane[LANES-1]. Mỗi block có một value rộng W bit và xử lý một lát của bus.
for (lane = 0; lane < LANES; lane = lane + 1) begin : g_lane
Với LANES=3, có ba block lane. Nó không lấy một lane rồi đợi clock để xử lý lane tiếp theo. Thiết kế này thậm chí không có cổng clock. Số block được quyết định khi elaborate.
Bên trong mỗi lane, if-generate chọn một trong hai nhánh theo INVERT: g_invert gán giá trị đảo bit; g_pass nối nguyên lát dữ liệu. Đây là lựa chọn cấu hình, không phải một mux được điều khiển bằng tín hiệu input mode trong ví dụ.
Lát data[lane*W +: W] lấy W bit bắt đầu ở chỉ số lane*W theo hướng tăng chỉ số. Với W=4, ba lane là các lát bit 3:0, 7:4, 11:8. Nếu đổi W, phải tính lại ranh giới, không giữ các con số 4/8/12 ở những chỗ còn lại.
Bốn cấu hình được kiểm tra thật
Trước khi chạy, tính tay với data = 12'ha5c:
- Cấu hình mặc định đảo 12 bit:
~a5ctrong độ rộng 12 bit là5a3. - Named override
INVERT=0giữ nguyêna5c. - Instance legacy có
W=2,LANES=2; đầu vào là bốn bit thấpc, đảo thành3. - Cấu hình biên
W=1,LANES=1nhận bit thấp bằng 0, nên output đảo là 1. - Lane 2 của mặc định lấy nibble cao của
5a3, bằng5.
Số giá trị 12 bit cần thử là 2^12 = 4096. Testbench duyệt toàn bộ và so sánh tất cả output với phép toán độc lập ở TB; chỉ in số case hoàn tất sau khi không có mismatch nào.
Lệnh lint của example kiểm lane_map.sv; wrapper và TB được elaborate/mô phỏng cùng các instance. Mở tb_params.sv để thấy điều kiện $fatal: nếu một output không khớp, test dừng trước dòng tổng kết, không chỉ in số đẹp rồi coi là đạt.
Kết quả này không khẳng định mọi giá trị parameter đều hợp lệ hay mọi tool đều hỗ trợ mọi cấu trúc giống nhau. Cần kiểm tra riêng mỗi cấu hình sản phẩm thực sự dùng.
Hai nhánh generate, hai kết quả synthesis
Tính tay kỳ vọng trước khi synthesis:
lane_mapmặc định đảo 12 bit độc lập: cần 12 cổng NOT và không có flip-flop.map_passthroughnốilane_mapvớiINVERT=0: không cần cổng NOT và không có flip-flop.
Yosys thực sự cho kết quả khớp hai kỳ vọng này. [3]
Đừng đếm “ba lần lặp” thành “ba cổng NOT”: mỗi lane có 4 bit. Ngược lại, ba block generate ở nhánh passthrough không buộc synthesis giữ ba hộp phần cứng hoặc ba buffer riêng. Một block có tên giúp tổ chức mô hình; nó không bảo đảm số cell hay hình dạng hierarchy sau tối ưu.
Nếu muốn chọn đảo/giữ nguyên theo một tín hiệu thay đổi lúc chạy, giao diện và logic phải có tín hiệu điều khiển tương ứng; đổi parameter giữa chừng không phải cách làm của ví dụ này. Bài chưa đo timing, PPA hoặc kết quả mapping sang thư viện cell công nghệ cụ thể.
Đọc defparam và hierarchy trong code cũ
Testbench còn có một instance u_legacy rồi cấu hình bằng:
defparam u_legacy.W = 2;
defparam u_legacy.LANES = 2;
Hai dòng này đã được parser/elaborator và simulator của pipeline chấp nhận trong đúng chương trình của bài. Kết quả $bits(u_legacy.mapped)=4 cho thấy cấu hình đó đã có hiệu lực; nó không phải một thay đổi độ rộng tại mỗi vòng test.
TB đọc u_default.g_lane[2].value để quan sát lane cao. u_default là tên instance; g_lane[2] là block generate có chỉ số; value là dây trong block đó. Con số 2 là chỉ số cố định có trong cấu hình LANES=3 này; đừng mặc định đường dẫn đó tồn tại khi cấu hình chỉ có một lane.
Bài không khuyến nghị dùng đường dẫn sâu để thay thế giao diện cổng giữa các khối. Quy tắc đầy đủ về scope, defparam và generate cần tiếp tục đối chiếu [4].
Biên tham số và lỗi tư duy thường gặp
- Chỉ test cấu hình mặc định. Bug part-select hoặc độ rộng có thể chỉ xuất hiện khi
W=1,LANES=1, hoặc khi số lane khác mặc định. Ví dụ kiểm ba cặp kích thước, không chỉ4*3. - Dùng parameter như input.
datathay đổi qua 4096 giá trị;W,LANES,INVERTcủa từng instance giữ nguyên cấu hình trong lần mô phỏng này. - Nhầm số block với số bit/cell. Ba lane 4 bit là bus 12 bit. Synthesis còn có thể tối ưu các dây nối, nên số block không phải số cell.
- Cấu hình zero-width mà không thiết kế quy ước. Ví dụ yêu cầu
W>=1,LANES>=1. VớiTOTAL=0, biểu thức range thành[-1:0], không thể coi đó là cách khai báo một bus rỗng theo ý định. Bài không chạy cấu hình bằng 0 và không khẳng định mọi tool sẽ báo lỗi giống nhau. - Đếm
forbằng trực giác CPU. Vòng generate mô tả cấu trúc; vòngforcó#1trong TB tạo một chuỗi stimulus theo thời gian mô phỏng. Khi gặp vòngfortrong procedural RTL, phải xét riêng chức năng và khả năng synthesis.
Tự kiểm tra
Checklist cho RTL có cấu hình
- Xác định knob bên ngoài và giá trị dẫn xuất bằng localparam.
- Đọc riêng danh sách parameter
#(...)và kết nối cổng(...). - Tính số lane, độ rộng bus và ranh giới part-select bằng tay trước khi mô phỏng.
- Kiểm cấu hình mặc định, cấu hình ghi đè, cấu hình biên và từng nhánh generate được sử dụng.
- Khi debug hierarchy, kiểm block/index có thật trong cấu hình đã elaborate.
- Giữ đúng phạm vi bằng chứng: input 0/1, cấu hình đã chạy, cell count ở tool cụ thể; chưa xác minh đầy đủ LRM và chưa đo timing vật lý.
Nguồn và mức độ đối chiếu
- IEEE 1800-2023 SystemVerilog LRM, LRM: parameters và elaboration. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, Bằng chứng chạy thực. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, Bằng chứng synthesis. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, LRM: generate và defparam. Chưa đối chiếu với văn bản nguồn (chưa mở).
- IEEE 1800-2023 SystemVerilog LRM, Parameters, elaboration, generate constructs and defparam. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, verification.json: PARAMS RESULT. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Loop generate constructs. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, meta.yaml: synth map_passthrough; verification.json: achieved. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, verification.json: LANE RESULT. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm parameter/generate: content/code/ex.a6.params-generate/verification.json, content/code/ex.a6.params-generate/verification.json. Trích dẫn; nguồn đã đọc toàn văn.