ALU: chọn phép toán và giữ đúng hợp đồng cờ
Tiên quyết
Sau bài này bạn sẽ
- Định nghĩa opcode, độ rộng và cờ trước khi kiểm ALU
- Dùng chung đường cộng cho ADD/SUB và so signed
- Đối chiếu kết quả lẫn Z/N/C/V bằng mô hình số nguyên
Đúng kết quả mà sai cờ vẫn là sai ALU
Một ALU có thể trả đúng tổng nhưng báo sai carry, làm nhánh điều kiện của bên dùng ra quyết định sai. Cần mô tả cả dữ liệu lẫn cờ, không chỉ liệt kê các phép toán.
Bài này dùng A/B bốn bit, opcode ba bit và kết quả bốn bit. Đây là hợp đồng ví dụ để học cách suy luận/kiểm, không phải đặc tả của một ISA có sẵn.
Bảng opcode chốt mọi mã 0/1
| Opcode | Phép | Kết quả |
|---|---|---|
| 000 | ADD | Bốn bit thấp của A+B |
| 001 | SUB | Bốn bit thấp của A−B |
| 010 | AND | AND từng bit |
| 011 | OR | OR từng bit |
| 100 | XOR | XOR từng bit |
| 101 | LSL | Dịch trái logic A |
| 110 | LSR | Dịch phải logic A |
| 111 | SLT | 1 nếu A nhỏ hơn B theo signed, ngược lại 0 |
Số bước dịch lấy từ hai bit thấp của B, từ 0 tới 3. Ví dụ raw B bằng 1111 vẫn cho shift amount 3, không phải 15. LSL bỏ bit vượt độ rộng; LSR chèn 0 từ trái.
Cả tám mã binary xác định đều đã được gán ý nghĩa. X/Z ở opcode chưa thuộc miền kiểm trong ví dụ; một default trong source không tự chứng minh mọi tình huống unknown được xử lý đúng yêu cầu.
Một đường cộng, một đường logic và bộ chọn
ADD đưa B nguyên vẹn vào adder, carry-in 0. SUB đảo B rồi dùng carry-in 1. SLT cũng cần hiệu A−B nội bộ. Như vậy ba phép dùng chung một đường số học theo điều khiển opcode.
Các phép AND/OR/XOR và shift tạo các ứng viên khác. Bộ chọn đầu ra lấy đúng ứng viên; các cờ liên quan cũng phải được chọn hoặc đặt lại theo cùng hợp đồng.
Ví dụ 3 trừ 5 đi qua đường số học để tạo raw 1110. Chọn nhầm đường ADD sẽ trả 1000; chỉ kiểm “đã có adder và mux” chưa xác nhận control đúng.
Quy ước cờ của ví dụ
| Cờ | Định nghĩa ở bài |
|---|---|
| Z | 1 khi kết quả bốn bit bằng 0 |
| N | Bằng MSB của kết quả |
| C ở ADD | Carry-out của tổng unsigned |
| C ở SUB | 1 khi không borrow theo unsigned |
| V ở ADD/SUB | Tổng/hiệu signed không vừa bốn bit |
| C/V ở sáu opcode khác | Đặt 0, không giữ cờ của phép trước |
Z/N lấy từ kết quả cuối đã chọn, không lấy nhầm tổng nội bộ khi opcode đang chọn logic hay SLT. N chỉ là bit cao; với overflow, nó không biểu diễn dấu của kết quả toán học không giới hạn.
Shift của bài không xuất cờ “bit cuối bị đẩy ra”; C được đặt 0 theo bảng. Một ISA khác có thể quy định khác. Muốn kiểm đúng phải theo đặc tả đang dùng.
SLT cần hiệu chỉnh dấu của phép trừ
Dấu của hiệu hẹp có thể sai do overflow. Với signed bốn bit, +7 trừ −1 có hiệu thật +8 nhưng raw kết quả 1000 có MSB 1.
Gọi N_diff là bit dấu của hiệu nội bộ, V_diff là overflow của phép trừ. Điều kiện signed-less là N_diff XOR V_diff. Ca trên cho 1 XOR 1 bằng 0: +7 không nhỏ hơn −1.
Ngược lại −8 trừ +1 có hiệu thật −9, raw 0111 có bit dấu 0 nhưng overflow 1; 0 XOR 1 bằng 1, nên −8 nhỏ hơn +1.
Đây là cờ của đường trừ nội bộ, không phải lấy N/V của kết quả SLT đã đổi thành 0 hoặc 1. Cờ C/V xuất ra ngoài ở opcode SLT vẫn bằng 0 theo hợp đồng.
Tính cả dữ liệu và cờ
| Phép | A/B theo ý nghĩa đã nêu | Raw kết quả | Z | N | C | V |
|---|---|---|---|---|---|---|---|
| ADD | +7 và +1 | 1000 | 0 | 1 | 0 | 1 |
| SUB | Unsigned 3 và 5 | 1110 | 0 | 1 | 0 | 0 |
| SUB | 5 và 5 | 0000 | 1 | 0 | 1 | 0 |
| AND | 1010 và 0101 | 0000 | 1 | 0 | 0 | 0 |
| SLT | Signed −8 và +7 | 0001 | 0 | 0 | 0 | 0 |
Ở hàng SLT, A âm nhưng N bằng 0 vì N đọc kết quả 0001. Ở hàng AND, một cờ carry của phép trước không được rò sang kết quả mới.
ALU là tổ hợp trong ví dụ, không có clock hoặc cờ giữ trong thanh ghi. Nếu hệ thống cần lưu flags ở một stage, phải xác định thêm enable, reset và latency ở thiết kế chứa ALU.
Các lỗi control và cờ hay gặp
- Đảo bảng opcode giữa datapath và testbench.
- Dùng N_diff một mình cho SLT mà bỏ V_diff.
- Lấy Z/N từ adder dù đang chọn kết quả logic.
- Không gán mặc định cho C/V nên giữ cờ cũ hoặc suy latch.
- Dùng toàn bộ B làm số bước dịch trong khi hợp đồng chỉ dùng hai bit thấp.
- Mặc định mọi ISA có cùng quy tắc carry/borrow hoặc shift flag.
Khi debug, ghi opcode, cách đọc A/B, raw kết quả và từng cờ. Một nhãn “ADD pass” không thay việc đối chiếu các biên về độ rộng và signedness.
Tự viết mô hình trước khi nhìn RTL
- Tính ADD raw 1111 với 0001 và cả Z/N/C/V.
- Tính SLT signed A=0111, B=1111; vì sao không dùng riêng dấu hiệu?
- Với LSR, A=1000, B=1111, kết quả và N là gì?
- Nếu sau ADD có carry rồi thực hiện XOR, C cần bằng gì trong hợp đồng bài?
- Một ISA yêu cầu shift trả bit cuối bị đẩy ra ở C. Bạn phải sửa phần đặc tả và phép kiểm nào, thay vì chỉ đổi một hằng trong test?
Kiểm tra
Bằng chứng kiểm chứng
Expected tính trước chạy: ALU CHECK vectors=2048 opcodes=8 zero=386 negative=800 carry=256 overflow=128 signed_less=120 time_ns=2048.
Duyệt tám opcode × 256 cặp A/B, kiểm kết quả và mọi cờ ở từng vector. Mô hình bitwise dùng đếm bit số nguyên; shift dùng nhân/chia lũy thừa hai rồi modulo. Signed-less so trực tiếp hai số nguyên đã giải mã, tách khỏi cách hiệu chỉnh dấu của DUT.
Expected Z theo opcode là 16/16/81/1/16/60/60/136, tổng 386; N là 128/128/64/192/128/128/32/0, tổng 800. C chỉ đếm ADD/SUB, tổng 256; V tổng 128; SLT có 120 hàng đúng.
Parser/lint/simulation/synthesis đạt; không có FF/latch trong generic netlist. Không claim timing, cell sharing cụ thể sau mapping, ISA compliance hoặc X/Z. Bảng opcode/cờ là hợp đồng riêng; thay hợp đồng cần sửa mô hình và tính lại kỳ vọng trước chạy.
Nguồn và mức độ đối chiếu
- Comparators & ALUs — bản chụp resources.zip, Inside an ALU; A Worked 8-Bit ALU; What Hardware Each Part Needs. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thí nghiệm nguyên bản A3.alu, All eight four-bit opcodes, independent integer/bit-count result model and complete Z/N/C/V checks. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Combinational case selection, expression sizing, shifts, signed comparison correction and flag defaults — chưa đối chiếu LRM. Chưa đối chiếu với văn bản nguồn (chưa mở).