Mảng và bộ nhớ: chọn word, chọn bit, chọn thời điểm
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ẽ
- Đọc đúng vị trí kích thước packed/unpacked trong khai báo
- Phân biệt dung lượng 32 bit với một vector packed 32 bit
- Dự đoán đọc cùng địa chỉ ghi trước và sau cạnh clock của RTL cụ thể
- Thiết kế scoreboard bắt lỗi ghi nhầm ô, write enable và ưu tiên reset
- Phân biệt khai báo memory với kết quả mapping sang FF hoặc RAM macro
Một tủ bốn ngăn, mỗi ngăn tám bit
Hãy hình dung bốn ngăn có địa chỉ 0, 1, 2, 3; mỗi ngăn chứa một byte. Khi ghi địa chỉ 2, yêu cầu là thay đúng byte của ngăn 2, giữ nguyên ba ngăn còn lại. Khi đọc địa chỉ 1, phải lấy byte ở ngăn 1, không phải “bit số 1” của cả tủ.
Trong ví dụ, dung lượng dữ liệu là 4*8=32 bit. Địa chỉ 2 bit đủ chọn một trong bốn word. Word ở đây là đơn vị một lần đọc/ghi của thiết kế: 8 bit, không phải quy ước mọi máy đều có word 8 bit.
Ta sẽ kiểm một bộ nhớ nhỏ có ghi đồng bộ, đọc tổ hợp và reset đồng bộ. Đây là mô hình RTL cụ thể để học cách suy luận, không phải lời hứa về một SRAM/BRAM bất kỳ. Quy tắc ngôn ngữ tổng quát vẫn cần đối chiếu [1].
Kích thước nằm trước hay sau tên?
So sánh hai khai báo SystemVerilog trong testbench:
logic [3:0][7:0] packed_words;
logic [7:0] unpacked_words [0:3];
packed_wordscó hai kích thước packed trước tên. Trong khai báo này nó là một giá trị packed 32 bit, chia thành bốn nhóm 8 bit.unpacked_wordscó phần tử 8 bit và kích thước unpacked sau tên: một mảng bốn phần tử, chỉ số 0 đến 3.$bitscủa cả hai là 32 trong TB đã chạy. Cùng dung lượng không làm hai kiểu trở thành tương đương trong mọi phép gán, cổng module hoặc ép kiểu.
TB gán lần lượt word 0, 1, 2, 3 bằng hex 11, 22, 33, 44. Với đúng chiều chỉ số packed [3:0][7:0], word 3 chiếm byte cao nên toàn vector in ra 44332211. Không được lấy kết quả này làm quy tắc “index 0 luôn nằm bên phải” cho mọi chiều khai báo.
Mảng unpacked trong bài được ghi/đọc từng phần tử. Ta không ép cả mảng sang số nguyên rồi suy đoán thứ tự byte. Những phép chuyển kiểu và assignment pattern ngoài ví dụ vẫn cần đối chiếu LRM. [2]
Chọn word trước, chọn bit sau
Với unpacked_words[2][0], phép chọn đầu lấy phần tử số 2 (một byte), phép chọn sau lấy bit 0 của byte đó. Với dữ liệu 33 hex = 00110011, bit 0 là 1. TB cũng kiểm packed_words[2][0] bằng 1 và cả hai word 2 bằng 33.
Đọc khai báo RTL:
reg [7:0] mem [0:3];
assign rdata = mem[raddr];
raddr chọn một trong bốn byte. Output rdata rộng 8 bit. Không nhầm với reg [31:0] mem, nơi mem[raddr] chỉ chọn một bit của một vector một chiều.
Từ khóa reg trong khai báo này không tự quyết định phần tử sẽ thành flip-flop hay RAM macro. Cách đọc/ghi, clock/reset và công cụ mapping mới quyết định phần cứng suy ra. Bài dùng reg cho mảng RTL và logic cho biến TB; cả chương trình được biên dịch theo SystemVerilog.
Hợp đồng đọc và ghi của memory4
RTL của bài quy định:
- Chỉ cạnh lên
clkmới làm thay đổi dữ liệu lưu. - Khi cạnh lên thấy
rst=1, cả bốn word thành 0; reset ưu tiên ghi. - Nếu không reset và
we=1, chỉmem[waddr]nhậnwdatabằng non-blocking assignment. - Nếu cả
rstvàweđều 0, mọi word giữ nguyên. rdatađọc tổ hợp từmem[raddr]: đổi địa chỉ đọc có thể đổi output mà không cần cạnh clock mới.
Reset ở đây đồng bộ: đưa rst=1 giữa hai cạnh chưa lập tức xóa dữ liệu. Việc đặt lại nhiều word diễn ra bởi cùng một cạnh trong mô hình RTL; vòng for reset không phải bốn lệnh ghi nối tiếp qua bốn chu kỳ.
Ghi dữ liệu cũng không lập tức xảy ra khi thay waddr/wdata trong pha clock thấp. TB kiểm dữ liệu cũ trước cạnh, rồi kiểm dữ liệu mới sau khi NBA đã cập nhật. Cơ chế scheduling được học sâu hơn ở A7; ở đây chỉ cần giữ rõ thời điểm quan sát.
Chạy 2051 chu kỳ với scoreboard
Tính tay trước khi chạy:
- Reset ban đầu: 1 chu kỳ.
- Ghi mọi cặp địa chỉ/data:
4*256=1024chu kỳ. Cuối lượt ghi, mỗi word đều bằngff. - Thử mọi cặp địa chỉ/data với
we=0: 1024 chu kỳ; cả bốn word phải giữff. - Ghi riêng địa chỉ 2 bằng
a5: 1 chu kỳ. - Reset khi vẫn yêu cầu ghi
5avào địa chỉ 3: 1 chu kỳ; reset ưu tiên nên cả bốn word bằng 0.
Tổng 1+1024+1024+1+1=2051 chu kỳ: 1025 ghi có hiệu lực, 1024 giữ, 2 reset. Đây là mọi cặp địa chỉ/data trong chuỗi kiểm tra đã chọn, không phải vét cạn mọi trạng thái bộ nhớ 32 bit hoặc mọi chuỗi giao dịch.
Scoreboard lưu bốn số nguyên riêng, không đọc dut.mem để tự coi kết quả của DUT là chuẩn. Sau mỗi cạnh, TB quét cả bốn địa chỉ đọc và so với mô hình. Nhờ vậy, ghi nhầm một word khác cũng bị phát hiện dù word đích có vẻ đúng. TB còn kiểm đọc trước cạnh để bắt ghi sớm, và dùng $fatal khi dữ liệu hoặc số lượt sai.
Đọc cùng địa chỉ ghi: ff hay a5?
Trước chu kỳ ghi riêng, mem[2]=ff. Đặt raddr=waddr=2, wdata=a5, we=1, rst=0 trong pha clock thấp:
- Trước cạnh lên: bộ nhớ chưa được ghi, output là
ff. - Sau cạnh lên và sau cập nhật NBA:
mem[2]=a5, đường đọc tổ hợp phản ánha5.
Mô phỏng thực in COLLISION BEFORE old=ff rồi COLLISION AFTER new=a5. TB đợi một bước thời gian sau cạnh trước khi so giá trị mới, tránh testbench tranh thời điểm đọc với cập nhật NBA.
Không trả lời “read-during-write luôn ra dữ liệu mới” mà bỏ thời điểm quan sát và loại cổng đọc. Nếu đổi sang output đọc có thanh ghi, hoặc dùng macro có chế độ old-data/new-data/no-change, cần hợp đồng mới và TB mới. Bằng chứng trên chỉ áp dụng cho cách gán trong memory4, không xác minh các biến thể đó. [4]
Khai báo bộ nhớ không bảo đảm suy ra BRAM
Có 32 bit dữ liệu lưu, không có nghĩa tool bắt buộc tạo một khối RAM vật lý. Với lệnh synthesis generic của pipeline hiện tại, Yosys hạ thiết kế này thành 32 cell FF theo nhóm tên $_*DFF*, kèm logic chọn đọc/ghi và reset. Kỳ vọng 32 được tính từ bốn word × tám bit trước khi chạy, không lấy số tool in ra rồi sửa expected cho khớp.
Đây là kết quả cho top memory4 trong flow đang dùng. Chưa chạy target FPGA cụ thể, không có báo cáo BRAM utilization, không có thư viện SRAM ASIC và không đo timing/PPA. Reset đồng thời toàn bộ dữ liệu và kiểu cổng đọc có thể ảnh hưởng khả năng dùng memory primitive của target; cần xem tài liệu primitive và báo cáo mapping thực tế.
Debug theo địa chỉ, dữ liệu và thời điểm
- Đọc thành bit thay vì byte: kiểm tra chiều packed/unpacked và độ rộng output, đừng chỉ nhìn tên
mem. - Ghi phá word khác: scoreboard phải quét cả các word không được ghi.
- Bỏ qua write enable: thử nhiều data với
we=0; không chỉ thử ghi rồi đọc lại một lần. - Sai ưu tiên reset: kiểm
rst=1vàwe=1cùng cạnh, không chỉ reset riêng rẽ. - TB so quá sớm: xác định đang quan sát trước cạnh, tại vùng cập nhật nào hay sau NBA. Đổi expected thành dữ liệu cũ để che lỗi sampling sẽ làm sai hợp đồng.
- Tin giá trị khởi động bằng 0: bài không kiểm DUT trước reset; simulator 2-state không chứng minh giá trị khởi động của silicon hoặc hành vi X/Z.
- Gọi cả bộ nhớ là đã vét cạn: 1024 cặp ghi không phủ mọi chuỗi đọc/ghi và mọi trạng thái 32 bit.
Tự kiểm tra
Checklist khi review một bộ nhớ nhỏ
Ghi rõ số word, số bit mỗi word, miền địa chỉ, kiểu đọc, cạnh ghi, write enable, reset và ưu tiên. Tính một tình huống đọc cùng địa chỉ ghi ở hai thời điểm; sau đó dùng mô hình độc lập kiểm cả word đích lẫn word phải giữ.
Cuối cùng đọc báo cáo synthesis cho đúng target. Bài đã kiểm layout, chuỗi 2051 chu kỳ và mapping generic 32 FF; chưa kiểm X/Z, RAM macro, timing hay toàn bộ quy tắc array của LRM. Các nhãn draft/needs-spec-check vẫn giữ để người học thấy đúng phạm vi bằng chứng.
Nguồn và mức độ đối chiếu
- IEEE 1800-2023 SystemVerilog LRM, LRM về arrays và assignments. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, TB kiểm layout. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, Bằng chứng tool. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, Quan sát trước/sau cạnh. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Packed and unpacked arrays; memory indexing; nonblocking assignments. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, memory4.sv declaration; Yosys 32 FF check. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, verification.json: LAYOUT RESULT. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, tb_memory.sv layout assertions. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, verification.json: COLLISION BEFORE and AFTER. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, tb_memory.sv final reset cycle; RESET RESULT. Trích dẫn; nguồn đã đọc toàn văn.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, meta.yaml synth expectation and verification.json. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Packed and unpacked arrays; array indexing; nonblocking assignments. Chưa đối chiếu với văn bản nguồn (chưa mở). Chưa đối chiếu đầy đủ LRM; bài giữ draft, bằng chứng tool chỉ áp dụng cho chương trình đã chạy.
- Thử nghiệm arrays/memory: content/code/ex.a6.arrays-memories/verification.json, content/code/ex.a6.arrays-memories/verification.json và tb_memory.sv. Trích dẫn; nguồn đã đọc toàn văn.