thiết kế và tổng hợp hệ thống số-bài giảng
Post on 06-Aug-2015
402 Views
Preview:
TRANSCRIPT
1 Chương 1: Giới thiệu thiết kế mạch số
1.1 1.1 Các khái niệm cơ bản trong thiết kế mạch số
1.1.1 1.1.1 Định nghĩa: mạch điện tử là một hệ thống gồm các linh kiện điện tử biến đổi
tín hiệu (dòng điện, điện áp) đầu vào thành tín hiệu đầu ra
1.1.1.1 Để mô tả mạch điện tử: cần mô tả tín hiệu đầu vào, tín hiệu đầu ra, và hàm truyền
đạt của mạch
1.1.2 1.1.2 Phân loại
1.1.2.1 Mạch tương tự
1.1.2.2 Mạch số
Tín hiệu vào/ra chỉ có 2 mức thấp và mức cao
Mức 0,1
Mạch số tổ hợp
Hàm truyền đạt chỉ phụ thuộc vào đầu vào
Mạch số tuần tự (Mạch dãy)
Hàm truyền đạt phụ thuộc vào đầu vào và trạng thái hiện tại của mạch
Mạch đồng bộ
Trạng thái của mạch được lưu vào Flip Flop theo một tín hiệu nhịp (tín hiệu đồng hồ)
Mạch không đồng bộ
Trạng thái và hoạt động của mạch không theo đồng hồ
1.1.3 1.1.3. Đại số Bool và logic tổ hợp
1.1.3.1 Biến Bool
Biến đơn
a,b,x,y nhận các giá trị 0,1
Biến vector
a[3:0] nhận các giá trị {0,1}^4
1.1.3.2 Hàm Bool
Nhiều đầu vào, một đầu ra: MISO
Nhiều đầu vào, nhiều đầu ra: MIMO
Biểu diễn hàm Bool
Biểu thức Bool gồm
Các biến Bool
Các phép toán Bool
AND, OR, NOT, XOR
Bảng chân lý
Liệt kê tất cả các tổ hợp giá trị của các biến đầu vào
Liệt kê các giá trị hàm tương ứng
Là cách biểu diễn duy nhất
Kích thước rất lớn ~ hàm mũ của số biến
Bảng chân lý rút gọn
Kích thước nhỏ hơn
Không là duy nhất
Chỉ có thể dùng cho các mạch đơn giản, ít đầu vào
Tối ưu hàm Bool
Dùng cách tối giản bìa Karnaugh
http://en.wikipedia.org/wiki/Karnaugh_map
See document(s): Karnaugh_map
Dùng phương pháp Quine-McCluskey
http://en.wikipedia.org/wiki/Quine%E2%80%93McCluskey_algorithm
See document(s): Quine%E2%80%93McCluskey_algorithm
Triển khai hàm Bool bằng mạch logic tổ hợp
Gồm các cổng logic căn bản kết nối với nhau để tạo thành hàm truyền đạt
Kích thước ~ tuyến tính với số phép toán dùng trong hàm truyền đạt
1.1.3.3 Ví dụ:
Bộ giải mã 7 thanh
Bộ cộng
1.1.4 1.1.4. Máy trạng thái hữu hạn FSM
1.1.4.1 Hàm truyền đạt
Hàm trạng thái kế tiếp Delta
s' = delta(x,s)
s' trạng thái tiếp theo của mạch
s trạng thái hiện tại của mạch
x là đầu vào của mạch
Hàm đầu ra Lambda
Mealy: y = lambda(x,s)
More: y = lambda(s)
1.1.4.2 Biểu diễn FSM
Đồ thị chuyển trạng thái
Node: các trạng thái
Được dán nhãn là mã trạng thái tương ứng
Cạnh: chuyển trạng thái được dán nhãn là giá trị đầu vào tương ứng
Kích thước ~ số trạng thái ~ hàm mũ của số biến trạng thái
Bảng chuyển trạng thái và bảng đầu ra
1.1.4.3 Tối ưu FSM
Giảm số lượng trạng thái
Tìm các trạng thái tương đương
Mã hóa trạng thái
Mã one-hot, zero-hot, binary, gray
1.1.4.4 Triển khai FSM-Mạch dãy
Mã hóa các trạng thái, các ký hiệu vào và các ký hiệu ra bằng các biến Bool trạng thái, tín
hiệu vào và tín hiệu ra, tương ứng
Xác định hàm Bool cho trạng thái kế tiếp và cho đầu ra
Mạch tổ hợp trạng thái kế tiếp
Các Flip Flop
Mạch tổ hợp ra
1.1.4.5 Ví dụ
Bộ đếm
Bộ điều khiển đèn giao thông
Bộ điều khiển thang máy
Bộ điều khiển giao thức RS232, Bluetooth
1.1.5 1.1.5. Các phần tử phần cứng cơ bản
1.1.5.1 Transitor FET
1.1.5.2 Cổng logic cơ bản
1.1.5.3 Gate Netlist: mạng cổng
1.1.5.4 Standard Cell
Cell: Phần tử logic cơ bản, các khối chức năng cơ bản RAM, ROM...
Cấu trúc mô tả quy trình sản xuất
Chức năng logic
Mô hình tính thời gian
IC được chia làm các hàng và cột
Mỗi phần tử đặt một phần tử logic cơ bản: Cổng logic, RAM, ...
Các cell được kết nối thông qua dây kim loại
1.1.5.5 FPGA
Phần cứng có thể tái cấu hình: reconfigurable
Khối cơ bản LUT, LE: gồm bộ chọn MUX và SRAM
Bộ nhớ lưu bảng chân lý của hảm
Triển khai hàm logic
Giá trị bộ nhớ dùng điều khiển bộ MUX
Các khối được nối bằng đường dây có thể lập trình
1.2 1.2. Giới thiệu về HDL
1.2.1 1.2.1. Ngôn ngữ mô tả phần cứng (Hardware Description Language)
1.2.1.1 Mục đích
Mô hình và mô phỏng (có thời gian) thiết kế số
Có thể tổng hợp thành mạch bằng các công cụ tổng hợp
Synopsys Design Compiler
Altera Quatus
Xilinx ISE
Cadence
1.2.1.2 Phân loại
Verilog
Mềm dẻo
Sử dụng nhiều trong công nghiệp
VHDL
Sử dụng trong quốc phòng và thiết kế ô tô
Hướng kiểu mạnh
1.2.1.3 Ưu điểm của HDL
Cho phép thiết kế mạch rất lớn
Trừu tượng hơn sơ đồ mạch
Mô tả ở mức RTL-dịch chuyển thanh ghi
Sử dụng bit vector thay vì các bit đơn
Quá trình tổng hợp tự động sử dụng phần mềm EDA
Thiết kế có thể chuyển đổi
Thiết kế Verilog mô tả hành vi hoặc dòng dữ liệu có thể tổng hợp thành mạch dùng công nghệ
chế tạo mới với ít công sức (VD. Từ 0.13um sang 45nm)
Verilog ở dạng text, dễ dàng chuyển đổi giữa các chương trình khác nhau không như định
dạng nhị phân dùng riêng cho các chương trình vẽ mạch
Cho phép thử nghiệm, lựa chọn nhiều giải pháp thiết kế hơn
Các tùy chọn tổng hợp cho phép tối ưu và cân bằng các tham số về năng lượng, thời gian, kích
thước
Cho phép kiểm nghiệm thiết kế tốt hơn
Dùng Verilog để mô hình hóa môi trường hoạt động của mạch (testbench)
Phần mềm tổng hợp hoạt động tốt đảm bảo tính đúng đắn của hàm Bool được triển khai
1.2.1.4 Chú ý
Trông giống ngôn ngữ lập trình
Không phải ngôn ngữ lập trình
Luôn phải nhớ rằng đang mô tả phần cứng
Mã được dùng để tổng hợp ra phần cứng
Mã có thể được mô phỏng trên máy tính, chỉ là mục đích thứ 2
1.2.2 1.2.2. Ví dụ và các khái niệm ngôn ngữ cơ bản
1.2.2.1 module decoder_2_to_4 (A, D) ; input [1:0] A ; output [3:0] D ; assign D = (A ==
2'b00) ? 4'b0001 : (A == 2'b01) ? 4'b0010 : (A == 2'b10) ? 4'b0100 :
(A == 2'b11) ? 4'b1000 ; assign D[0] = (~A[1])*(~A[2]); endmodule
1.2.2.2 Một mạch điện là 1 module, được mô tả gồm các thành phần
Khai báo module
Tên
decoder_2_to_4
Đầu vào, đầu ra
Ports
A, D
Khai báo tín hiệu kết nối với đầu vào đầu ra
Kiểu port
Input
Output
Inout
Kích thước port
vô hương (đơn)
vector
[MSB:LSB]
Khai báo tín hiệu bên trong
Mô tả hoạt động của module
assign D = (A == 2'b00) ? 4'b0001 : (A == 2'b01) ? 4'b0010 : (A ==
2'b10) ? 4'b0100 : (A == 2'b11) ? 4'b1000 ;
1.2.3 1.2.3. Giới thiệu về phần mềm Quartus
1.2.3.1 http://www.youtube.com/watch?v=PDOTLuuKgqE
See document(s): watch
1.2.3.2 http://www.youtube.com/watch?v=PDOTLuuKgqE
See document(s): watch
1.2.4 1.2.4. Khái niệm mô phỏng và tổng hợp
1.2.4.1 Mô phỏng
Đưa tác động đầu vào (input stimuli) và quan sát so sánh đầu ra với đầu ra chuẩn (output
reference)
Hình vẽ
Kiểm tra mạch chiếm 90% công sức, giá thành làm ra mạch
1.2.4.2 Tổng hợp
Từ mô tả hoạt động mạch tạo ra phần cứng thực hiện hoạt động đó
Hình vẽ
Chú ý
Khác với chạy chương trình phần mềm tất cả các câu lệnh đều được tổng hợp thành phần
cứng
Học đề biết các câu lệnh Verilog HDL được chuyển thành phần cứng thế nào
Hình vẽ
1.3.1.1
1.3.2 Chia làm 2 công đoạn chính
1.3.2.1 Front-end
Thiết kế ở mức hoạt động, mức logic
B1. Xác định các tham số kỹ thuật của mạch
Hiệu năng
Tần số hoạt động
Thông lượng dữ liệu (Data throughput)
Chức năng logic của mạch
Ví dụ: Thực hiện phép cộng, thực hiện phép biến đổi FFT
B2. Phân tích chức năng và chia thành các khối chức năng nhỏ (thiết kế sơ đồ khối)
B3. Mô tả hoạt động các khối chức năng bằng ngôn ngữ HDL
Kiểm tra mô phỏng từng khối chức năng
Kiểm chứng toán học các khối chức năng
B4. Ghép nối các khối chức năng thành toàn bộ hệ thổng
Kiểm tra mô phỏng toàn bộ hệ thống
B5. Tổng hợp mạch từ mức HDL thành mức cổng
Kiểm tra các yêu cầu thời gian của mạch
Kiểm chứng sự tương đương của mạch ở mức cổng và mức HDL
1.3.2.2 Back-end
Thiết kế ở mức vật lý
1.4 1.4. Ứng dụng và ví dụ về thiết kế số
1.4.1 Thiết kế bộ xử lý MIPS pipelined
1.4.1.1 Chức năng
Thực hiện các chương trình assembly theo kiến trúc tập lệnh MIPS
add, sub, addi
beq, bne
j
lw, sw
Pipeline 5 trạng thái
Chương trình được lưu trong bộ nhớ chương trình (bộ nhớ lệnh)
Dữ liệu lưu trong bộ nhớ dữ liệu
1.4.2 Thiết kế bộ truyền nhận số QAM16
1.4.2.1 Chức năng
Điều chế
Đầu vào: Dòng số 1 bit
Đầu ra: Dòng tín hiệu I/Q điều chế theo phương pháp QAM
Giải điều chế
Đầu vào: Dòng tín hiệu I/Q điều chế theo phương pháp QAM
Đầu ra: Dòng số 1 bit
Tùy chọn
Dòng tín hiệu I/Q cần được nhân với tín hiệu sóng mang
Tín hiệu sóng mang có thể được biến đổi thành tương tự bằng bộ DAC
Tín hiệu thu được tương tự được biến đổi thành số dùng ADC
Tin hiệu số thu được cần được đồng bộ và nhân với sóng mang sau đó giải điều chế
2 Chương 2. Các khái niệm cơ bản trong thiết kế số (ôn lại). Tham khảo:
Digital Design and Computer Architecture
2.1 2.1 Mạch logic tổ hợp
2.1.1 2.1.1 Đại số Bool
2.1.1.1 Biểu thức và hàm Bool
Biểu thức tổng các tích
sum of product
DNF
sum of minterm
canonical form
Biểu thức tích các tổng
product of sum
CNF
product of maxterm
canonical form
Tham khảo
Mục 2.2
2.1.1.2 Phép toán và phép biến đổi Bool
And, or, not, xor
Tiên đề trong đại số Bool
Các quy tắc/định lý trong đại số bool
Quy tắc AND/OR với 1/0
Luật giao hoán, kết hợp, phân phối
Biến đổi Demorgan
Định lý với 1 biến
Định lý nhiều biến
Sử dụng phép biến đổi Bool để tối giản biểu thức Bool
2.1.2 2.1.2 Triển khai hàm Bool
2.1.2.1 Các cổng logic cơ bản
Tham khảo
Mục 1.5 sách đã nêu
Not
Buffer
2.1.2.2 Từ biểu thức Bool đến mạch logic
Tham khảo
Mục 2.4
Schematic, Gate-Net list
Gồm các cổng logic và các dây dẫn nối các cổng logic
Cổng logic: các node trong đồ thị
Dây dẫn: các cạnh có hướng trong đồ thị
Input: các node không có node phía trước
Output: các node không có node phía sau
Fanout: Các node nối vào cạnh đi ra khỏi một node
Fanin: Các node nối vào các cạnh đi vào node
Ví dụ
Mạch logic nhiểu mức
Tham khảo
Mục 2.5
2.1.3 2.1.3 Tối ưu hàm Bool bằng bìa Karnaugh
2.1.3.1 Tham khảo
Mục 2.6
Mục 2.7
2.1.3.2 Ví dụ
2.1.4 2.1.4 Một số hàm Bool và mạch đơn giản
2.1.4.1 Hàm lựa chọn và bộ MUX
Triển khai bộ MUX 4-1
2.1.4.2 Hàm giải mã và bộ giải mã
Bộ Decoder 2:4
2.1.4.3 Tham khảo
Mục 2.8
2.1.5 2.1.5 Hoạt động của mạch logic
2.1.5.1 Biểu đồ thời gian
Sườn lên: tín hiệu thay đổi từ mức logic thấp lên mức logic cao
Sườn xuống: tín hiệu thay đổi từ mức logic cao xuống mức logic thấp
Điểm 50%: thời điểm tín hiệu thay đổi giá trị được 50%
Hình vẽ
2.1.5.2 Thời gian
Thời gian đáp ứng của 1 cổng logic: Khoảng thời gian từ lúc đầu vào thay đổi đến khi đầu ra
thay đổi tương ứng
Đo từ điểm 50% của tín hiệu vào tới điểm 50% của tín hiệu ra
Độ trễ lan truyền (propagation delay) tpd
Thời gian từ lúc 1 đầu vào thay đổi đến khi đầu ra/các đầu ra đạt tới giá trị cuối cùng
trod = count t pdf ☹ of logic i train koreroing door what
Độ trễ ảnh hưởng (contamination delay) tcd
Thời gian từ khi 1 đầu vào thay đổi đến khi đầu ra bắt đầu thay đổi
tainted ong logic i train origin gain. what
Hình vẽ
Thời gian chuyển đổi (transition time)
Thời gian tín hiệu chuyển từ trạng thái 1->0 (falling time), và 0->1 (rising time): Đo bằng
khoảng cách giữa 2 điểm 10%-90% của tín hiệu
2.1.5.3 Đường tới hạn (đường dài nhất) - critical path và đường ngắn nhất
Đường dài nhất và chậm nhất trong mạch tổ hợp
Trễ lan truyền tpd là tổng trễ lan truyền của các cổng logic trên đường dài nhất
Trễ ảnh hưởng tcd là tổng các trễ ảnh hưởng của các cổng logic trên đường ngắn nhất
Ví dụ
Hình vẽ
2.1.5.4 Glitches/Hazards
1 sự thay đổi của đầu vào dẫn tới nhiều sự thay đổi ở đầu ra mà không phù hợp/tương ứng
với hàm logic
Hình vẽ
Loại trừ ành hưởng của hazards
Đợi đến khi đầu ra ổn định
Thêm cổng logic kết nối các prime implicants cách nhau
2.1.5.5 Tham khảo
Mục 2.9
2.2 2.2 Mạch dãy
2.2.1 2.2.1 Các phần tử nhớ cơ bản
2.2.1.1 Cấu trúc
Phần tử chốt SR
Phần tử chốt D
Thay đổi trạng thái khi CLK = 1 (level sensitive latch)
Phần từ D-Flip Flop
Thay đổi trạng thái khi có sườn lên của CLK
2.2.1.2 Mô tả hoạt động
Lưu trữ trạng thái
Chuyển đổi trạng thái
2.2.1.3 Mạch hoạt động theo đồng hồ
Tham khảo 3.3
Các phần từ nhớ trong mạch thay đổi trạng thái tại các sườn lên (xuống) của tín hiệu đồng
hồ
Hình vẽ
2.2.1.4 Tham khảo
Mục 3.2
2.2.1.5 Thực hành
Lab 3
ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Laboratory_Exercises/Digital_Logic/DE2/
verilog/lab3_Verilog.pdf
See document(s): lab3_Verilog.pdf
2.2.2 2.2.2 Máy trạng thái hữu hạn - FSM
2.2.2.1 Hàm Bool biểu diễn FSM
Hàm chuyển trạng thái
Hàm trạng thái kế tiếp Delta
s' = delta(x,s)
s' trạng thái tiếp theo của mạch
s trạng thái hiện tại của mạch
x là đầu vào của mạch
Hàm đầu ra
Hàm đầu ra Lambda
Mealy: y = lambda(x,s)
Moore: y = lambda(s)
2.2.2.2 Biểu diễn FSM bằng đồ thị chuyển trạng thái STG
Node: các trạng thái
Được dán nhãn là mã trạng thái tương ứng
Cạnh: chuyển trạng thái được dán nhãn là giá trị đầu vào tương ứng
Kích thước ~ số trạng thái ~ hàm mũ của số biến trạng thái
2.2.2.3 Mã hóa trạng thái bằng biến Bool
2.2.2.4 Biểu diễn hàm chuyển trạng thái bằng bảng chuyển trạng thái
2.2.2.5 Tham khảo
Mục 3.4
2.2.2.6 Thực hành
Lab 4. Phần 1
ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Laboratory_Exercises/Digital_Logic/DE2/
verilog/lab4_Verilog.pdf
See document(s): lab4_Verilog.pdf
2.2.2.7 Máy Moore/Mealy
2.2.3 2.2.3 Thời gian trong mạch dãy
2.2.3.1 Thời gian trong Flip-Flop
Setup time và hold time
Khoảng thời gian đầu vào D cần ổn định
Trễ lan truyền từ đồng hồ đến Q: Tpdq
Trễ ảnh hưởng từ đồng hồ đến Q: Tcdq
Hình vẽ
2.2.3.2 Thời gian hệ thống
Chu kỳ đồng hồ
Khoảng thời gian giữa 2 sườn lên (xuống) của tín hiệu đồng hồ Tc
2.2.3.3 Điều kiện thời gian setup
Đường trễ giữa 2 thanh ghi
Điều kiện về thời gian setup
Hình vẽ
Trong thực tế
Chu kỳ đồng hồ quyết định bởi khách hàng, thị trường, và giám đốc kỹ thuật để đảm bảo tính
cạnh tranh của sản phẩm
tsetup quyết định bởi nhà sản xuất
cần thiết kế phần mạch logic tổ hợp để thỏa mãn điều kiện thời gian setup
2.2.3.4 Điều kiện thời gian hold
Đầu vào D của FF không được thay đổi đến thold sau sườn lên (xuống) của clock
Hình vẽ
3 Chương 3. Cú pháp cơ bản của ngôn ngữ Verilog Tham khảo ví dụ:
http://www.asic-world.com
3.1 3.1. Chú thích
3.1.1 Giúp đọc code dễ dàng hơn cho người khác và về sau
3.1.2 Giúp gỡ lỗi dễ hơn
3.1.3 Không cần chú thích chức năng của đoạn code
3.1.3.1 Bản thân code chính là làm việc đó như thế nào nên không cần chú thích nữa
3.1.3.2 Ví dụ
always @(posedge clk) begin Sig_FF1 <= Sig // Capture value of Sig Line in FF Sig_FF2 <=
Sig_FF1; // Flop Sig_FF1 to form Sig_FF2 Sig_FF3 <= Sig_FF2; // Flow Sig_FF2 to form Sig_FF3 end
// start_bit is ~Sig_FF2 & Sig_FF3 assign start_bit = (~Sig_FF2 && Sig_FF3) ? 1’b1 : 1’b0;
signet-atop-Frito-Pa.-start. bit
3.1.4 Chú thích tại sao làm một việc
3.1.4.1 Ví dụ
always @(posedge clk) /******************************************** * Sig is ansynchronous
and has to be double flopped * * for meta-stability reasons prior to use
*********************************************/ begin Sig_FF1 <= Sig; Sig_FF2 <= Sig_FF1; //
double flopped meta-stability free Sig_FF3 <= Sig_FF2; // flop again for use in edge detection end
/********************************************** * Start bit in protocol initiated by falling edge of Sig
line * **********************************************/ assign start_bit = (~Sig_FF2 && Sig_FF3) ?
1’b1 : 1’b0;
3.1.5 Chú thích tương tự ngôn ngữ C
3.1.5.1 Nằm giữa /* */
3.1.5.2 Bắt đầu từ // đến cuối dòng
3.2 3.2. Khai báo module
3.2.1 Trong Verilog, để 1 mạch là 1 module
3.2.2 Hình vẽ
3.2.2.1
3.2.2.2
3.2.3 3.2.1. Khai báo module
3.2.3.1 Cú pháp
module module_name (list_of_port) port_declare; internal_signal_declare;
module_behavior_description endmodule
3.2.3.2 Tên module
Không được trùng với từ khóa
Nên chọn tên gợi nhớ chức năng module
3.2.3.3 Các cổng vào ra
3.2.3.4 Các tín hiệu bên trong module
3.2.3.5 Mô tả chức năng (hoạt động) của mạch
3.2.4 3.2.2.Khai báo cổng vào ra của module
3.2.4.1 Mỗi cổng vào ra tương ứng với 1 tín hiệu trong mạch
3.2.4.2 Khai báo kiểu của cổng port_type:
input
output
inout
bidirectional
3.2.4.3 Kích thước của cổng
vô hướng: một bit: input cin;
Vector: gồm nhiều bit - chỉ ra kích thước cụ thể trong 1 khoảng chỉ số [MSB:LSB]
Từ bit giá trị lớn nhất đến bit giá trị nhỏ nhất: từ trái sang phải
Chú ý: không cần bắt đầu từ chỉ số không
output [7:0] out; input [0:4] in;
3.2.4.4 Tóm lại, để khai báo 1 cổng: port_type [range] port_name;
3.2.4.5 Bài tập ví dụ: Khai báo module decoder 2:4 có tín hiệu enable
3.3 3.3. Khai báo các tín hiệu/biến/hằng bên trong mạch
3.3.1 3.3.1 Các giá trị dữ liệu trong Verilog
3.3.1.1 Kiểu logic
Có 4 giá trị
0: logic 0, điều kiện sai
1: logic 1, điều kiện đúng
x: không xác định: do chưa được khởi tạo hoặc xung đột
Hình vẽ
z: trở kháng cao: do không được nối với cổng logic, hoặc nối với cổng 3 trạng thái
Hình vẽ
Phép toán trên logic 4 giá trị
or
Hình vẽ
3.3.1.2 Kiểu số nguyên
Cú pháp chung
<size>'<base><number>
base nhận các giá trị> b, d, h, o
number có thể là
các chữ số (giá trị phụ thuộc cơ số)
x
z
size: chỉ ra kích thước (số bit) của số. Nếu không được chỉ rõ thì sẽ là giá trị mặc định của
phần mềm mô phỏng
Ví dụ
4'b1101
10'h2e7
12'h13x
số âm: -16'h3A
3.3.2 3.3.2 Khai báo biến/dây dẫn trong Verilog
3.3.2.1 Chú ý: Các biến trong Verilog thường được dùng để đại diện cho 1 phần tử vật lý
trong mạch. Ví dụ: dây dẫn, cổng logic, Flip-Flop
3.3.2.2 Cú pháp chung
type range identifier array_range
Tên biến: Identifier
Chọn tên có tính miêu tả, gợi nhớ
Chú ý: Dùng quy tắc nhất định để chỉ ra một tín hiệu là active-low
Ví dụ: rst_n
type
wire
biểu diễn dây dẫn trong mạch
Không lưu trữ giá trị
Cần được nối với cổng
Nhận giá trị của cổng điều khiển nó
Kết nối đầu ra và đầu vào khi thực thể hóa các module
Có thể khai báo tín hiệu input, output của module là wire
Không thể nằm bên trái phép gán = và <= trong khối always@
Là kiểu duy nhất có thể nằm bên trái phép gán dùng assign
Chỉ có thể dùng để mô tả logic tổ hợp
reg
biểu diễn cổng logic/flip flop trong mạch
lưu trữ giá trị cho đến khi được gán giá trị mới
chú ý không nhất thiết là flip flop
Có thể kết nối với 1 cổng vào của 1 module con
Không thể kết nối với 1 cổng ra của 1 module con
Có thể khai báo tín hiệu output là reg
Không thể khai báo tín hiệu input là reg
Là kiểu duy nhất nằm bên trái phép gán trong khối always và khối initial
Không thể nằm bên trái phép gán assign
Để mô tả thanh ghi nếu nằm bên trái phép gán trong khối always@(posedge clk)
Dùng để mô tả logic tổ hợp và logic tuần tự
wor, trior
wand, triand
tri
trireg
range
định nghĩa kích thước của biến
vector
tập hợp các bit
[msb:lsb]
array_range
dùng để định nghĩa một mảng (miêu tả bộ nhớ, tệp thanh ghi)
[index_1:index_2]
Ví dụ
wire [15:0] opA, opB, res;
reg [2:0] state, nxt_state;
reg [31:0] reg_files[0:15]
reg [31:0] mem[0:255]
3.3.3 3.3.3. Khai báo hằng số trong Verilog
3.3.3.1 Tăng tính biểu diễn, dễ hiểu
3.3.3.2 Tăng tính mềm dẻo, dễ thay đổi
3.3.3.3 define
định nghĩa hằng số toàn cục
ví dụ
`define idle = 2’b00; // idle state of state machine `define conv = 2’b01; // in this state while
A2D converting `define avg = 2’b10; // in this state while averaging samples
3.3.3.4 localparam
định nghĩa hằng số địa phương
ví dụ
localparam idle = 2’b00; // idle state of state machine localparam conv = 2’b01; // in this
state while A2D converting localparam accum = 2’b10; // in this state while averaging samples
3.3.3.5 parameter
có thể thay đổi khi tổng hợp mach
đề cập sau
3.4 3.4. Các mô hình mô tả mạch
3.4.1 3.4.1. Mô hình cấu trúc
3.4.1.1 Kết nối các phần tử cơ bản và các module con
3.4.1.2 Mô tả dạng text của mạng module gồm
Đường kết nối các phần tử trong mạch
Các phần tử trong mạch
Phần tử logic cơ bản
Flip-flop
Các module con
3.4.1.3 Các bước tạo mô hình cấu trúc
B1: Khai báo giao diện module
Tên module
Tên cổng, kiểu và kích thước cổng
B2: Khai báo các dây dẫn bên trong mạch
dùng kiểu biến wire
B3: Tạo module con hoặc primitive. Kết nối - đưa tên dây dẫn vào vị trí đầu vào, ra tương
ứng của cổng
Cú pháp
module_name instance_name [#(parameter values)] (port_connection_list)
port_connection_list
Phương pháp kết nối ẩn: dựa vào thứ tự khai báo cổng. Thứ tự tín hiệu khi tạo module
con quyết định cổng của module mà tín hiệu được nối vào.
Chỉ phù hợp với module ít cổng
Các cổng vào của module là giống nhau về vai trò (ví dụ primitive)
Khi số cổng lớn, dễ nhầm lẫn
Ví dụ
3.4.1.3..1.1.1.1 module dec_2_4_en (A, E_n, D); input [1:0] A; input E_n; output [3:0] D; . . .
3.4.1.3..1.1.1.2 wire [1:0] X; wire W_n; wire [3:0] word; // instantiate decoder dec_2_4_en DX (X, W_n,
word);
Phương pháp kết nối rõ ràng: chỉ rõ tên cổng mà tín hiệu sẽ được kết nối.
Cú pháp: .<port name>(<signal name>)
Ví dụ
3.4.1.3..1.1.1.3 wire [1:0] X; wire W_n; wire [3:0] word; // instantiate decoder dec_2_4_en DX (.A(X),
.E_n(W_n), .D(word));
3.4.1.4 Các cổng logic cơ bản (primitive)
Gate level
and, nand
or, nor
xor, xnor
buf , not
bufif0, bufif1, notif0, notif1 (three-state)
Switch level
*mos where * is n, p, c, rn, rp, rc; pullup, pulldown; *tran+ where * is (null), r and + (null), if0,
if1 with both * and + not (null)
Không cần khai báo, chỉ sử dụng (instantiate)
Khi sử dụng: đầu ra đứng đầu tiên, trước các đầu vào
Example: and N25 (Z, A, B, C); //instance name Example: and #10 (Z, A, B, X); // delay
(X, C, D, E); //delay /*Usually better to provide instance name for debugging.*/ Example: or N30
(SET, Q1, AB, N5), N41 (N25, ABC, R1); Example: and #10 N33(Z, A, B, X); // name + delay
3.4.1.5 Ví dụ
Ví dụ 3.4.1
module majority (major, V1, V2, V3) ; output major ; input V1, V2, V3 ; wire N1, N2, N3; and A0
(N1, V1, V2), A1 (N2, V2, V3), A2 (N3, V3, V1); or Or0 (major, N1, N2, N3); endmodule
Ví dụ 3.4.2
module half_add (X, Y, S, C); input X, Y ; output S, C ; xor SUM (S, X, Y); and CARRY (C, X, Y);
endmodule
module full_add (A, B, CI, S, CO) ; input A, B, CI ; output S, CO ; wire S1, C1, C2; // build full
adder from 2 half-adders half_add PARTSUM (A, B, S1, C1), SUM (S1, CI, S, C2); // … add an OR
gate for the carry or CARRY (CO, C2, C1); endmodule
Ví dụ 3.4.3
* module_keyword module_identifier (list of ports) */ module C_2_4_decoder_with_enable (A,
E_n, D) ; input [1:0] A ; // input_declaration input E_n ; // input_declaration output [3:0] D ; //
output_declaration assign D = {4{~E_n}} & ((A == 2'b00) ? 4'b0001 : (A == 2'b01) ? 4'b0010 :
(A == 2'b10) ? 4'b0100 : (A == 2'b11) ? 4'b1000 : 4'bxxxx) ; // continuous_assign endmodule
module C_4_16_decoder_with_enable (A, E_n, D) ; input [3:0] A ; input E_n ; output [15:0] D ;
wire [3:0] S; wire [3:0] S_n; C_2_4_decoder_with_enable DE (A[3:2], E_n, S); not N0 (S_n, S);
C_2_4_decoder_with_enable D0 (A[1:0], S_n[0], D[3:0]); C_2_4_decoder_with_enable D1 (A[1:0],
S_n[1], D[7:4]); C_2_4_decoder_with_enable D2 (A[1:0], S_n[2], D[11:8]); C_2_4_decoder_with_enable
D3 (A[1:0], S_n[3], D[15:12]); endmodule
3.4.1.6 Bài tập
Viết mô hình cấu trúc của mạch cộng 16bit CRA và CLA sử dụng bộ cộng full-adder
Tạo ra 20 giá trị đầu vào cho a, b
Mô phỏng timing cho 2 mạch
Đo độ trễ tpd cho từng giá tri đầu vào
Tính độ trễ trung bình cho 2 mạch CRA và CLA, so sánh
3.4.2 3.4.2. Mô hình dòng dữ liệu - RTL
3.4.2.1 Mô tả dòng xử lý dữ liệu
Dùng câu lệnh gán liên tục
assign
gán biểu thức bool cho biến wire
các phép gán assign hoạt động song song với nhau
phép gán sẽ được thực hiện khi giá trị biểu thức bên phải thay đổi
Mô hình chính xác, nhưng vẫn dễ đọc hiểu
Dùng mô tả các hàm Bool và đường dữ liệu
Nhược điểm: phải dựa vào phần mềm tổng hợp để tạo ra mạch
Với cách mạch yêu cầu tốc độ rất cao (GHz), vẫn cần mô hình cấu trúc
3.4.2.2 Ví dụ 3.4.3
module majority (major, V1, V2, V3) ; output major ; input V1, V2, V3 ; assign major = V1 &
V2 | V2 & V3 | V1 & V3; endmodule
3.4.2.3 Ví dụ 3.4.4
module fa_rtl (A, B, CI, S, CO) ; input A, B, CI ; output S, CO ; // use continuous assignments
assign S = A ^ B ^ CI; assign C0 = (A & B) | (A & CI) | (B & CI); endmodule
3.4.3 3.4.3. Mô hình hành vi
3.4.3.1 Mô tả các hành vi của mạch khi có các sự kiện (tín hiệu thay đổi giá trị) xảy ra
Dùng các khối always và initial
3.4.3.2 Ví dụ 3.4.5
module majority (major, V1, V2, V3) ; output reg major ; input V1, V2, V3 ; always @(V1, V2,
V3) begin if (V1 && V2 || V2 && V3 || V1 && V3) major = 1; else major = 0; end
endmodule
Trong mô phỏng: khi có sự thay đổi của V1, V2, hay V3 thì major sẽ được tính lại
Trong phần cứng: không có chờ đợi sự xuất hiện sự thay đổi=> các cổng logic tính toán ngay
lập tức
3.4.3.3 Ví dụ 3.4.6
module fa_bhv (A, B, CI, S, CO) ; input A, B, CI; output S, CO; reg S, CO; // assignment
made in an always block // must be made to registers // use procedural assignments
always@(A or B or CI) begin S = A ^ B ^ CI; CO = (A & B) | (A & CI) | (B & CI); end
endmodule
3.4.3.4 Chú ý
Khi mô phỏng khi tín hiệu đầu vào (bên phải phép gán) thay đổi, đầu ra (bên trái phép gán)
được tính toán lại
3.4.4 3.4.4. Phân cấp
3.4.4.1 Trong Verilog, mỗi khối (mạch) là một module.
3.4.4.2 Các module có thể được tái sử dụng bên trong một module khác (instantiate)
3.4.4.3 Thiết kế phân cấp xây dựng hệ thống từ các phần tử nhỏ hơn. Đây là phương pháp
thiết kế top-down
Primitives (cổng logic cơ bản)
Các module khác
3.4.4.4 Ví dụ
Thiết kế phân cấp của full-adder
Half-Adder
module Add_half(c_out, sum, a, b); output sum, c_out; input a, b; xor sum_bit(sum, a, b); and
carry_bit(c_out, a, b); endmodule
Full-Adder
module Add_full(c_out, sum, a, b, c_in) ; output sum, c_out; input a, b, c_in; wire w1, w2, w3;
Add_half AH1(.sum(w1), .c_out(w2), .a(a), .b(b)); Add_half AH2(.sum(sum), .c_out(w3), .a(c_in),
.b(w1)); or carry_bit(c_out, w2, w3); endmodule
3.4.4.5 Chú ý: Trong một module có thể sử dụng nhiều loại mô hình mô tả
Khi tổng hợp thành mạch, việc tính toán không cần chờ đợi được kích hoạt. Tính toán đồng
thời, cả 3 loại mô hình đều được tổng hợp thành phần cứng như nhau
3.4.4.6 Chú ý: Phạm vi của tín hiệu
Module cha không thể truy cập vào các tín hiệu trong module con => cần phải đưa ra thành
các cổng của module con
Ví dụ
module add8bit(cout, sum, a, b); output [7:0] sum; output cout; input [7:0] a, b;
wire cout0, cout1,… cout6; FA A0(cout0, sum[0], a[0], b[0], 1’b0); FA A1(cout1, sum[1], a[1],
b[1], cout0); … FA A7(cout, sum[7], a[7], b[7], cout6); endmodule
Để phát hiện tràn overflow = cout XOR cout6 Cần đưa ra tín hiệu cout6 hoặc overflow
3.4.4.7 Chú ý: Mỗi module nên đưa vào 1 file riêng biệt
Dễ tổ chức
Dễ tìm kiếm
Dễ tái sử dụng trong project khác
Tăng tốc độ tổng hợp khi tái sử dụng
Hình vẽ
Các module cùng trong 1 file
Mỗi module trong 1 file
3.5 3.5. Các cấu trúc mô tả dòng dữ liệu
3.5.1 3.5.1. Phép gán liên tục (continuous assignment)
3.5.1.1 Cú pháp
assign [drive_strength] [delay] list_of_net_assignments; Where: list_of_net_assignment ::=
net_assignment [{,net_assignment}] & Where: Net_assignment ::= net_lvalue = expression
assign <LHS> = <RHS expression>;
Khi các biến trong vế phải thay đổi giá trị, kết quả biểu thức RHS thay đổi, biến LHS được cập
nhật giá trị mới
Phép gán này hoạt động liên tục (hardware) và được tổng hợp thành mạch logic tổ hợp
Chú ý có một trường hợp ngoại lệ
Biểu thức RHS sử dụng các biến (dây dẫn, thanh ghi) và các phép toán: +,-,&,|,^,~,>>,…
LHS luôn là các biến kiểu dây dẫn (wire) hoặc phép toán nối vector
3.5.1.2 Ví dụ 3.5.1: Đơn giản
// out is a net, a & b are also nets assign out = a & b; // and gate functionality
3.5.1.3 Ví dụ 3.5.2: Gán vector
wire [15:0] result, src1, src2; // 3 16-bit wide vectors assign result = src1 ^ src2; // 16-bit
wide XOR
3.5.1.4 Ví dụ 3.5.3: Bộ cộng 32 bit
wire [31:0] sum, src1, src2; // 3 32-bit wide vectors assign {c_out,sum} = src1 + src2 + c_in;
// wow!
3.5.2 3.5.2. Các phép toán
3.5.2.1 Nối các vector
Tạo ra các vector từ các vector nhỏ hơn hoặc từ biến đơn
Operator {v1, v2}
Cú pháp: {list_of_subvector}
Các vector phía trái của danh sách các vector con sẽ có ý nghĩa cao hơn các vector phía phải
Ví dụ 3.5.4
module concatenate(out, a, b, c, d); input [2:0] a; input [1:0] b, c; input d; output
[9:0] out; assign out = {a[1:0],b,c,d,a[2]}; // assign out10 ={a[1:0],b,c,d,a[2]}[1:0]; endmodule
Ví dụ 3.5.5: Sử dụng khi kết nối cổng module
module add_concatenate(out, a, b, c, d); input [7:0] a; input [4:0] b; input [1:0] c;
input d; output [7:0] out; add8bit(.sum(out), .cout(), .a(a), .b({b,c,d}), .cin()); // đầu vào 8 bit b
của bộ cộng là 1 vector ghép từ 3 vector b, c, d endmodule
Thêm hằng số vào trước phép toán {}
Dùng để nhân bản bit
Ví dụ 3.5.6: Mở rộng dấu
input [7:0] offset; // 8-bit offset term from EEPROM wire [15:0] src1,src2; // 16-bit
source busses to ALU assign src1 = {8{offset[7]},offset}; // sign extend offset term // src1 =
offset[7], offset[7], ..., offset[7], offset[7], offset[6], ..., offset[0]
Chú ý phép toán tách vector là [msb_index:lst_index]
Ví dụ a[1:0] lấy 2 bit thấp của vector a
3.5.2.2 Phép toán số học
* multiply ** exponent / divide % modulus + add - subtract
Dễ mô tả hơn dùng mô hình cấu trúc
Không phải tất cả các phép toàn đều có thể tổng hợp
Ví dụ: các phép toàn *, **, /, % khó tổng hợp thành mạch logic, cho mạch kích thước lớn, tốc độ
chậm
Phần mềm tổng hợp thường sử dụng thư viện module có sẵn cho các phép toán
Cần chú ý đến kích thước kết quả
Ảnh hưởng đến dấu của phép toán
Kích thước (bitsize) quyết định bởi cả 2 phía của phép toán
Ví dụ 3.5.7: Các phép toán số học
1 module arithmetic_operators(); 2 3 initial begin 4 $display (" 5 + 10 = %d", 5 + 10); 5
$display (" 5 - 10 = %d", 5 - 10); 6 $display (" 10 - 5 = %d", 10 - 5); 7 $display (" 10 * 5 = %d", 10
* 5); 8 $display (" 10 / 5 = %d", 10 / 5); 9 $display (" 10 / -5 = %d", 10 / -5); 10 $display (" 10 %s
3 = %d","%", 10 % 3); 11 $display (" +5 = %d", +5); 12 $display (" -5 = %d", -5); 13 #10
$finish; 14 end 15 16 endmodule
3.5.2.3 Phép toán logic
Phép dịch
Dịch trái
Số học: <<<
Logic: <<
Dịch phải
Số học: >>>
Logic: >>
Ví dụ 3.5.8: Phép dịch
1 module shift_operators(); 2 3 initial begin 4 // Left Shift 5 $display (" 4'b1001
<< 1 = %b", (4'b1001 << 1)); 6 $display (" 4'b10x1 << 1 = %b", (4'b10x1 << 1)); 7 $display
(" 4'b10z1 << 1 = %b", (4'b10z1 << 1)); 8 // Right Shift 9 $display (" 4'b1001 >> 1 = %b",
(4'b1001 >> 1)); 10 $display (" 4'b10x1 >> 1 = %b", (4'b10x1 >> 1)); 11 $display (" 4'b10z1
>> 1 = %b", (4'b10z1 >> 1)); 12 #10 $finish; 13 end 14 15 endmodule
Phép so sánh
Lớn hơn, nhỏ hơn: <, >, <=, >=
Bằng: ==, !=
Có xét đến giá trị x và z
===, !==
chỉ dùng khi mô phỏng
Ví dụ 3.5.9: Phép so sánh
1 module relational_operators(); 2 3 initial begin 4 $display (" 5 <= 10 = %b", (5
<= 10)); 5 $display (" 5 >= 10 = %b", (5 >= 10)); 6 $display (" 1'bx <= 10 = %b", (1'bx
<= 10)); 7 $display (" 1'bz <= 10 = %b", (1'bz <= 10)); 8 #10 $finish; 9 end 10 11
endmodule
Ví dụ 3.5.10: Phép so sánh bằng
1 module equality_operators(); 2 3 initial begin 4 // Case Equality 5 $display ("
4'bx001 === 4'bx001 = %b", (4'bx001 === 4'bx001)); 6 $display (" 4'bx0x1 === 4'bx001 =
%b", (4'bx0x1 === 4'bx001)); 7 $display (" 4'bz0x1 === 4'bz0x1 = %b", (4'bz0x1 ===
4'bz0x1)); 8 $display (" 4'bz0x1 === 4'bz001 = %b", (4'bz0x1 === 4'bz001)); 9 // Case
Inequality 10 $display (" 4'bx0x1 !== 4'bx001 = %b", (4'bx0x1 ! == 4'bx001)); 11 $display ("
4'bz0x1 !== 4'bz001 = %b", (4'bz0x1 ! == 4'bz001)); 12 // Logical Equality 13 $display ("
5 == 10 = %b", (5 == 10)); 14 $display (" 5 == 5 = %b", (5 == 5)); 15 //
Logical Inequality 16 $display (" 5 != 5 = %b", (5 ! = 5)); 17 $display (" 5 != 6
= %b", (5 ! = 6)); 18 #10 $finish; 19 end 20 21 endmodule
Phép logic điều kiện
and: &&
or: ||
not: !
Dùng trong biểu thức điều kiện. Trả về kết quả là 1 bit
Ví dụ 3.5.11: Logic điều kiện
1 module logical_operators(); 2 3 initial begin 4 // Logical AND 5 $display ("1'b1
&& 1'b1 = %b", (1'b1 && 1'b1)); 6 $display ("1'b1 && 1'b0 = %b", (1'b1 && 1'b0)); 7
$display ("1'b1 && 1'bx = %b", (1'b1 && 1'bx)); 8 // Logical OR 9 $display ("1'b1 || 1'b0 =
%b", (1'b1 || 1'b0)); 10 $display ("1'b0 || 1'b0 = %b", (1'b0 || 1'b0)); 11 $display ("1'b0 ||
1'bx = %b", (1'b0 || 1'bx)); 12 // Logical Negation 13 $display ("! 1'b1 = %b", ( ! 1'b1));
14 $display ("! 1'b0 = %b", ( ! 1'b0)); 15 #10 $finish; 16 end 17 18 endmodule
Phép toán Bool
and: &
or: |
xor: ^
not: ~
Tính toán từng bit của vector. Kết quả là vector
Ví dụ 3.5.12: Phép toán Bool
1 module bitwise_operators(); 2 3 initial begin 4 // Bit Wise Negation 5 $display
(" ~4'b0001 = %b", (~4'b0001)); 6 $display (" ~4'bx001 = %b", (~4'bx001)); 7
$display (" ~4'bz001 = %b", (~4'bz001)); 8 // Bit Wise AND 9 $display (" 4'b0001 &
4'b1001 = %b", (4'b0001 & 4'b1001)); 10 $display (" 4'b1001 & 4'bx001 = %b", (4'b1001 &
4'bx001)); 11 $display (" 4'b1001 & 4'bz001 = %b", (4'b1001 & 4'bz001)); 12 // Bit Wise
OR 13 $display (" 4'b0001 | 4'b1001 = %b", (4'b0001 | 4'b1001)); 14 $display (" 4'b0001 |
4'bx001 = %b", (4'b0001 | 4'bx001)); 15 $display (" 4'b0001 | 4'bz001 = %b", (4'b0001 |
4'bz001)); 16 // Bit Wise XOR 17 $display (" 4'b0001 ^ 4'b1001 = %b", (4'b0001 ^
4'b1001)); 18 $display (" 4'b0001 ^ 4'bx001 = %b", (4'b0001 ^ 4'bx001)); 19 $display ("
4'b0001 ^ 4'bz001 = %b", (4'b0001 ^ 4'bz001)); 20 // Bit Wise XNOR 21 $display ("
4'b0001 ~^ 4'b1001 = %b", (4'b0001 ~^ 4'b1001)); 22 $display (" 4'b0001 ~^ 4'bx001 = %b",
(4'b0001 ~^ 4'bx001)); 23 $display (" 4'b0001 ~^ 4'bz001 = %b", (4'b0001 ~^ 4'bz001)); 24
#10 $finish; 25 end 26 27 endmodule
Phép rút gọn bit
Phép toán 1 số hạng. Thực hiện phép toán Bool với các toán hạng là các bit của vector, trả về
kết quả là 1 bit
and: &
nand: ~&
or: |
nor: ~|
xor: ^
Ví dụ 3.5.13: Phép toán rút gọn bit
1 module reduction_operators(); 2 3 initial begin 4 // Bit Wise AND reduction 5
$display (" & 4'b1001 = %b", (& 4'b1001)); 6 $display (" & 4'bx111 = %b", (& 4'bx111)); 7
$display (" & 4'bz111 = %b", (& 4'bz111)); 8 // Bit Wise NAND reduction 9 $display (" ~&
4'b1001 = %b", (~& 4'b1001)); 10 $display (" ~& 4'bx001 = %b", (~& 4'bx001)); 11 $display
(" ~& 4'bz001 = %b", (~& 4'bz001)); 12 // Bit Wise OR reduction 13 $display (" | 4'b1001 =
%b", (| 4'b1001)); 14 $display (" | 4'bx000 = %b", (| 4'bx000)); 15 $display (" | 4'bz000 =
%b", (| 4'bz000)); 16 // Bit Wise NOR reduction 17 $display (" ~| 4'b1001 = %b", (~|
4'b1001)); 18 $display (" ~| 4'bx001 = %b", (~| 4'bx001)); 19 $display (" ~| 4'bz001 = %b",
(~| 4'bz001)); 20 // Bit Wise XOR reduction 21 $display (" ^ 4'b1001 = %b", (^ 4'b1001));
22 $display (" ^ 4'bx001 = %b", (^ 4'bx001)); 23 $display (" ^ 4'bz001 = %b", (^ 4'bz001));
24 // Bit Wise XNOR 25 $display (" ~^ 4'b1001 = %b", (~^ 4'b1001)); 26 $display (" ~^
4'bx001 = %b", (~^ 4'bx001)); 27 $display (" ~^ 4'bz001 = %b", (~^ 4'bz001)); 28 #10
$finish; 29 end 30 31 endmodule
3.5.2.4 Phép toán điều kiện
Cú pháp
cond_expr ? true_expr : false_expr
Ví dụ 3.5.14: Phép toán có điều kiện
1 module conditional_operator(); 2 3 wire out; 4 reg enable,data; 5 // Tri state buffer 6
assign out = (enable) ? data : 1'bz; 7 8 initial begin 9 $display ("time\t enable data out"); 10
$monitor ("%g\t %b %b %b",$time,enable,data,out); 11 enable = 0; 12 data = 0; 13 #1 data =
1; 14 #1 data = 0; 15 #1 enable = 1; 16 #1 data = 1; 17 #1 data = 0; 18 #1 enable = 0; 19
#10 $finish; 20 end 21 22 endmodule
Chú ý khi mô tả latch?
assign q_out = enable ? data_in : q_out;
Kết quả tổng hợp
Chú ý: Luôn luôn cần biết mã Verilog được tổng hợp thành mạch cứng như thế nào?
3.5.2.5 Thứ tự ưu tiên của các phép toán
Unary, Multiply, Divide, Modulus !, ~, *, /, % Add, Subtract, Shift +, - , <<, >> Relation,
Equality <,>,<=,>=,==,!=,===,!== Reduction &, !&,^,^~,|,~| Logic &&, || Conditional ? :
3.5.2.6 Bài tập
3.5.1.Tổng hợp các phép toán bằng quartus
Xác định các phép toán hỗ trợ bởi quartus
So sánh kích thước (LE) khi tổng hợp các phép toán
So sánh kích thước với bộ cộng CRA, CLA mô tả bằng mô hình cấu trúc với phép cộng
So sánh độ trễ CRA, CLA với phép cộng
3.5.2. Xây dựng khối ALU 32 bit
Đầu vào
opA: 32 bit
opB: 32 bit
shamt: 5 bit
func
= 0: cộng
=1: trừ
=2: nhân
=3: so sánh bằng
=4: dịch trái số học opA số bit mã hóa trong shamt
=5: dịch phải số học opA số bit mã hóa trong số shamt
=others: đầu ra = 0000
Đầu ra
res: 32 bit
overflow
zero=1: nếu so sánh bằng nhau
a) Khi chưa có phép nhân xác định số LE và tốc độ
b) Thêm phép nhân xác định số LE và tốc độ
c) Mô phỏng để kiểm tra kết quả với ít nhất 5 cặp số opA, opB cho mỗi phép toán
3.6 3.6. Các cấu trúc mô tả hành vi
3.6.1 3.6.1. Một số khái niệm chung
3.6.1.1 Cấu trúc always/initial dùng để mô hình hoạt động dạng hành vi của mạch
3.6.1.2 Tất cả các cấu trúc hành vi khác đều nằm trong 2 khối always/initial
3.6.1.3 Nhiều cấu trúc hành vi có thể nằm trong always/initial bằng cách đặt giữa begin và
end
3.6.1.4 Tất cả các biến ở bên trái phép gán trong 2 khối always/initial đều phải là kiểu reg
3.6.2 3.6.2. Cấu trúc initial
3.6.2.1 Bắt đầu thực hiện ở thời điểm mô phỏng 0
3.6.2.2 Có thể có nhiều cấu trúc initial trong mã, chúng được thực hiện độc lập và đều bắt
đầu thực hiện ở thời điểm 0
3.6.2.3 Không được tổng hợp thành mạch
3.6.2.4 Các câu lệnh trong khối initial được thực hiện lần lượt và được thực hiện 1 lần
3.6.2.5 Chủ yếu được dùng trong testbench
3.6.2.6 Chú ý: Không dùng initial trong mô tả mạch
3.6.2.7 Ví dụ 3.6.1: Dùng cấu trúc initial trong testbench
`timescale 1 ns / 100 fs module full_adder_tb; reg [3:0] stim; wire s, c; full_adder(sum,
carry, stim[2], stim[1], stim[0]); // instantiate DUT // monitor statement is special - only needs to
be made once, initial $monitor(“%t: s=%b c=%b stim=%b”, $time, s, c, stim[2:0]); // tell our
simulation when to stop initial #50 $stop; initial begin // stimulus generation for (stim = 4’h0;
stim < 4’h8; stim = stim + 1) begin #5; end end endmodule
3.6.2.8 Cú pháp
initial [begin] behavior_statements; [end]
3.6.3 3.6.3. Cấu trúc always
3.6.3.1 Bắt đầu ở thực hiện ở thời điểm 0
3.6.3.2 Được thực hiện lặp đi lặp lại liên tục khi có sự kiện xảy ra trong danh sách kích hoạt
(trigger_list, danh sách nhậy - sensitive list)
3.6.3.3 Ví dụ 3.6.2: always 1
module clock_gen (output reg clock); initial clock = 1’b0; // must initialize in initial block
always // no trigger list for this always #10 clock = ~clock; // always will re-evaluate when //
last <LHS> assignment completes endmodule
3.6.3.4 Chú ý mô tả hoạt động của mạch
Tổ hợp
Không dùng kích hoạt bằng sườn (edge-triggered)
Tất cả các "đầu vào" (biến ở vế phải phép gán) cần được đưa vào trigger-list
Không phụ thuộc đồng hồ
Tuần tự (dãy)
Sự kiện đồng hồ và mô tả Flip-Flop
Sự kiện đồng hồ
posedge
3.6.3.4..1.1.1.1 Xảy ra khi tín hiệu chuyển từ 0 lên x,z, 1
3.6.3.4..1.1.1.2 Xảy ra khi tín hiệu chuyển tử x, z lên 1
negedge
3.6.3.4..1.1.1.3 Xảy ra khi tín hiệu chuyển từ 1 xuống x,z, 0
3.6.3.4..1.1.1.4 Xảy ra khi tín hiệu chuyển tử x, z xuống 0
Sử dụng sự kiện đồng hồ để mô tả Flip-Flop
always @ (posedge clk) register <= register_input;
Ví dụ 3.6.3: Mô tả D-FF không có tín hiệu reset
reg q; always @(posedge clk) q <= d;
Kết quả tổng hợp
3.6.3.4..1.1.1.5
Chú ý: Không nên dùng FF không có reset
Ví dụ 3.6.4: Mô tả D-FF có reset đồng bộ
reg q; always @(posedge clk) if (!rst_n) q <= 1’b0; //synch reset else q <= d;
Kết quả tổng hợp
3.6.3.4..1.1.1.6
Tín hiệu reset không nằm trong danh sách kích hoạt của khối always
Ví dụ 3.6.5: Mô tả flip-flop với reset không đồng bộ
Kết quả tổng hợp
3.6.3.4..1.1.1.7 Thư viện các cổng thường có flip-flop với đầu vào reset không đồng bộ
3.6.3.4..1.1.1.8 Kích thước lớn hơn flipflop thường không đáng kể
3.6.3.4..1.1.1.9
reg q; always @(posedge clk or negedge rst_n) if (!rst_n) q <= 1’b0; //synch reset
else q <= d;
Tín hiệu reset nằm trong trigger list của khối always
Ví dụ 3.6.6: Mô tả flip-flop với reset đồng bộ/không đồng bô và tín hiệu enable
Mã reset đồng bộ
3.6.3.4..1.1.1.10 1 module always_example(); 2 reg clk,reset,enable,q_in,data; 3 4 always @ (posedge clk)
5 if (reset) begin 6 data <= 0; 7 end else if (enable) begin 8 data <= q_in; 9 end 10 11 endmodule
3.6.3.4..1.1.1.11 Kết quả tổng hợp
3.6.3.4..1.1.1.12
Mã reset không đồng bộ
Chú ý: Cần biết rõ các cổng có trong thư viện
FF điều khiển bởi sườn dương hay sườn âm?
Đầu vào reset là active low hay active high, đồng bộ hay không đồng bộ?
FF có hỗ trợ test?
Khi viết code, viết code cho những cổng có trong thư viện
3.6.3.4..1.1.1.13 Phần mềm tổng hợp sẽ tạo ra mạch kích thước nhỏ nhất (cần ít cổng logic nhất)
3.6.3.4..1.1.1.14 Nếu thư viện không có FF với reset active high=>viết code thế nào?
Kích hoạt bằng sườn của tín hiệu đồng hồ
Chỉ đồng hồ và reset nằm trong trigger-list
Có thể bao gồm phần mô tả mạch tổ hợp nối vào FF. Tức là mô tả hàm trạng thái kế tiếp của
FF.
Ví dụ 3.6.7: Kết hợp logic tổ hợp trong khối always mạch dãy
module counter(up,down, cnt, rst_n, clk); output [7:0] cnt; input up,down; // =
10 count up, 01 count down, otherwise stop input clk, rst_n; reg [7:0] cnt; always @
(posedge clk or negedge rst_n) if (!rst_n) cnt <= 0; else if (up) cnt <= cnt+1;
else if (down) cnt <= cnt-1; else cnt <= cnt; endmodule
3.6.3.5 Cú pháp
always @(trigger list) begin behavior_statements; end
Trigger list (sensitive list)
always @(a, b, c) begin … end
Cú pháp
Before Verilog 2001
always @(signal_1 or signal_2 or signal 3 or...)
Verilog 2001
always @(signal_1, signal_2, signal_3, ...)
always @(*)
3.6.3.5..1.1.1.1 Dùng để mô tả mạch logic tổ hợp
3.6.3.5..1.1.1.2 Không khuyên dùng
Kích hoạt việc thực hiện các lệnh trong khối always khi có sự thay đổi giá trị của các tín hiệu
trong list
Nếu không có danh sách kích hoạt, được thực hiện lặp lại ngay sau khi phép gán cuối cùng kết
thúc
Chú ý: chỉ dùng trong testbench và mô phỏng
Các tín hiệu xuất hiện trong trigger list là đầu vào của khối mạch tổ hợp được mô tả bằng cấu
trúc always
Các tín hiệu cần xuất hiện trong trigger list là các biến/tín hiệu ở biểu thức bên phải phép gán
trong khối always
3.6.4 3.6.4. Phép gán blocking và non-blocking
3.6.4.1 Lệnh gán tuần tự (Blocking Assignment)
Cú pháp
LHS = RHS
LHS: các biến kiểu reg hoặc biểu thức nối vector của các biến kiểu reg
RHS: biểu thức
Trong mô phỏng được thực hiện tuần tự từng phép gán
B1: Tính toán RHS
B2: Gán RHS vào LHS
Trong tổng hợp: mô tả cổng logic trong mạch logic tổ hợp. Thể hiện sự kết nối tuần tự của
các cổng logic (đầu ra tới đầu vào)
Chú ý: Chỉ khi kết quả của phép gán phía trước được sử dụng trong phép gán phía sau
Ví dụ 3.6.8: Lệnh gán tuần tự
module addtree(output reg [9:0] out, input [7:0] in1, in2, in3, in4); reg [8:0] part1, part2;
always @(in1, in2, in3, in4) begin part1 = in1 + in2; part2 = in3 + in4; out = part1 + part2; end
endmodule
Kết quả tổng hợp
3.6.4.2 Lệnh gán song song (Nonblocking assignment)
Cú pháp
LHS <= RHS
LHS: các biến kiểu reg hoặc biểu thức nối vector
RHS: biểu thức
Trong mô phỏng được thực hiện đồng thời nếu không có thêm giá trị trễ
B1: Tính toán RHS cho tất cả các phép gán
B2: Gán RHS của từng biểu thức cho LHS tương ứng theo thứ tự không xác định
Trong tổng hợp: mô tả thanh ghi trong mạch tuần tự (dãy). Thể hiện các FF độc lập (giá trị
hiện tại của các FF không phụ thuôc vào nhau)
Ví dụ 3.6.9: Lệnh gán song song
module swap(output reg out0, out1, input rst, clk); always @(posedge clk) begin if (rst) begin
out0 <= 1’b0; out1 <= 1’b1; end else begin out0 <= out1; out1 <= out0; end end endmodule
Kết quả tổng hợp
3.6.4.3 So sánh gán tuần tự và gán song song
Ví dụ 3.6.10:Swap dùng lệnh gán tuần tự
module swap(output reg [15:0] out0, out1, input [15:0] in0, in1, input swap); reg [15:0] temp;
always @(*) begin out0 = in0; out1 = in1; if (swap) begin temp = out0; out0 = out1; out1 = temp; end
end endmodule
Kết quả tổng hợp
Ví dụ 3.6.11: Không dùng lệnh gán tuần tự để mô tả mạch tuần tự (trong always)
Chú ý: Việc tính toán biểu thức vế phải của các câu lệnh phía sau lệnh gán tuần tự sẽ bị dừng
cho đến khi việc gán kết thúc
Mục tiêu mô tả mạch
module pipe(input clk, d, output q1, q2, q3);
Mã mô tả dùng lệnh gán tuần tự
module blocking_pipe(clk, d, q1, q2, q3); input clk,d; output q1, q2, q3; reg q1, q2, q3;
always @(posedge clk) begin q1 = d; q2 = q1; q3 = q2; end endmodule
Kết quả tổng hợp
Mã mô tả dùng lệnh gán song song
module blocking_pipe(clk, d, q1, q2, q3); input clk,d; output q1, q2, q3; reg q1, q2, q3;
always @(posedge clk) begin q1 <= d; q2 <= q1; q3 <= q2; end endmodule
Kết quả tổng hợp
Ví dụ 3.6.12: Không dùng lệnh gán song song để mô tả mạch logic tổ hợp
Mã 1
module nonblocking_comb(z,a,b,c,d); input a,b,c,d; output z; reg z,tmp1,tmp2; always
@(a,b,c,d) begin tmp1 <= a & b; tmp2 <= c & d; z <= tmp1 | tmp2; end endmodule
Testbench
module test_nonblocking_comb; reg a, b, c, d; wire z; nonblocking_comb
nonblocking_comb_dut(z, a, b, c, d); initial $monitor ("%g z=%b, a=%b, b=%b, c=%b,
d=%b", $time, z, a, b, c, d); initial begin #0 a = 0; #0 b = 1; #0 c = 0; #0 d = 1; #5 a =
1; #5 c = 1; #5 b = 0; #5 d = 0; end endmodule;
Kết quả mô phỏng
# 0 z=x, a=0, b=1, c=0, d=1 # 5 z=0, a=1, b=1, c=0, d=1 (kết quả mô phỏng sai vì z
được tính bằng giá trị cũ của tmp1, tmp2) # 10 z=1, a=1, b=1, c=1, d=1 # 15 z=1, a=1, b=0,
c=1, d=1 # 20 z=1, a=1, b=0, c=1, d=0
Timing diagram
3.6.4.3..1.1.1.1
Phân tích:
1) a, b, c, d thay đổi => khối always được tính lại. Tức là tính lại các biểu thức bên
phải phép gán với các giá trị mới của a, b, c, d và giá trị cũ của tmp1, tmp2
2) phép gán cho tmp1, tmp2 được và phép gán cho z được định thời gian thực hiện
3) Thực hiện phép gán cho tmp1, tmp2, z làm các biến này thay đổi giá trị
4) Kết thúc thực hiện khối always đợi sự thay đổi itếp theo của a, b, c, d
Chú ý: tmp1, tmp2 thay đổi không làm always được thực hiện
Mã 2
module nonblocking_comb(z,a,b,c,d); input a,b,c,d; output z; reg z,tmp1,tmp2; always
@(a,b,c,d, tmp1, tmp2) begin tmp1 <= a & b; tmp2 <= c & d; z <= tmp1 | tmp2; end
endmodule
Kết quả mô phỏng
run # 0 z=0, a=0, b=1, c=0, d=1 # 5 z=1, a=1, b=1, c=0, d=1 # 10 z=1, a=1, b=1, c=1,
d=1 # 15 z=1, a=1, b=0, c=1, d=1 # 20 z=0, a=1, b=0, c=1, d=0
Phân tích:
1) a, b, c, d thay đổi => khối always được tính lại. Tức là tính lại các biểu thức bên
phải phép gán với các giá trị mới của a, b, c, d và giá trị cũ của tmp1, tmp2
2) phép gán cho tmp1, tmp2 được và phép gán cho z được định thời gian thực hiện
3) Thực hiện phép gán cho tmp1, tmp2, z làm các biến này thay đổi giá trị
4) Khối always được tính toán lần thứ 2 do sự thay đổi của tmp1, tmp2
Kết quả tổng hợp
Mã 2 đúng nhưng sẽ mất thời gian mô phỏng hơn khi dùng lệnh gán tuần tự
Bài tập: Viết lại đoạn mã trên dùng phép gán blocking. Các tín hiệu nào cần nằm trong
trigger_list để kết quả mô phỏng đúng? Kết quả tổng hợp mạch như thế nào?
Tham khảo thêm: Clifford E. Cummings, "Nonblocking Assignments in Verilog Synthesis,
Coding Styles That Kill!"
3.6.5 3.6.5. Cấu trúc if-else
3.6.5.1 Cú pháp
if đơn
if (condition) begin <statement1>; <statement2>; end
if và else
if (condition) begin <statement1>; <statement2>; end else begin <statement3>;
<statement4>; end
nested if
if (condition) begin <statement1>; <statement2>; end else if (condition2) begin
<statement3>; <statement4>; end else begin <statement5>; <statement6>; end
3.6.5.2 Tổng hợp
Phần cứng cho tất cả các nhánhthực hiện qua khối if/else đều được tạo ra
Không tạo ra phần cứng phụ thuộc vào kết quả điều kiện
Các nhánh được tính toán đồng thời
Tạo ra các khối mux để lựa chọn kết quả
Kết quả được lựa chọn phụ thuộc điều kiện
3.6.5.3 Ví dụ 3.6.13. Lệnh if/else
Mã
if (func_add) alu = a + b; else if (func_and) alu = a & b; else alu = 8’h00;
Kết quả tổng hợp
Ứng với mỗi nhánh if, một khối tính toán tương ứng được tạo ra (+, &, 8'h00)
Bộ mux thứ nhất để lựa chọn nhánh if và else dưới cùng
Bộ mux thứ 2 để lựa chọn nhánh if và else phía trên
3.6.5.4 Chú ý phần tử latches ẩn
Khi if không đi kèm else tương ứng
Ví dụ 3.6.14. Lệnh if thiếu nhánh else
Mã
module if_no_else(input [1:0] alu_func, input [4:0] src1, src2, output reg [4:0] res);
parameter alu_add = 2'b00; parameter alu_and = 2'b01; always @(alu_func, src1, src2) begin
// tránh latch khi không có nhánh else, // nhưng không khuyến khích. res = 0; if (alu_func
== alu_add) begin res = src1 + src2; end else if (alu_func == alu_and) begin res = src1 & src2;
end end endmodule
Kết quả tổng hợp
Lý do
res là kiểu reg, nó sẽ giữ nguyên giá trị khi không được gán giá trị mới (i.e. khi
alu_func != alu_add, alu_and) => latch
Chú ý: Luôn có viết if có else
3.6.5.5 Chú ý mức ưu tiên khi tổng hợp các nhánh if
Ví dụ 3.6.15: if lồng nhau
Mã
module nested_if(input clk, rst_n, up_en, down_en, output reg [3:0] counter); always
@ (posedge clk or negedge rst_n) // If reset is asserted if (!rst_n) begin counter <= 4'b0000;
// If counter is enable and up count is asserted end else if (up_en) begin counter <= counter +
1'b1; // If counter is enable and down count is asserted end else if (down_en) begin counter
<= counter - 1'b1; // If counting is disabled end else begin counter <= counter; // Redundant
code end endmodule
Kết quả tổng hợp
Khi các nhánh if được lồng với nhau, nhánh if đầu tiên sẽ có mức ưu tiên cao nhất
Khi điều kiện của các nhánh if lồng nhau không loại trừ nhau (overlapped conditions - có thể
cùng đúng) thì kết quả mạch có thể khác với specification
Ví dụ
Mạch đếm tăng/giảm có đầu vào: up,down = 10 => đếm tăng up,down = 01 => đếm
giảm others => dừng
Cần viết các điều kiện của nhánh if loại trừ nhau
Nếu điều kiện các nhánh if không loại trừ
Mã
3.6.5.5..1.1.1.1 module counter(input clk, input rst_n, input up, down, output reg [7:0] cnt); always
@(posedge clk or negedge rst_n) begin if (!rst_n) cnt <= 0; else if (up) cnt <= cnt+1; else if (down) cnt <=
cnt-1; else cnt <= cnt; end endmodule
Hoạt động
3.6.5.5..1.1.1.2 updown=11 vẫn đếm tăng
3.6.6 3.6.6. Cấu trúc case
3.6.6.1 Cú pháp
case (expression) alternative1 : statement1; // any of these statements could alternative2
: statement2; // be a compound statement using alternative3 : statement3; // begin/end default :
statement4 // always use default for synth stuff endcase
so sánh từng bit của expression với case item (alternative1, 2, 3, ...)
Nếu expression bằng nhánh case nào, thì sẽ thực hiện câu lệnh trong nhánh case tương ứng
3.6.6.2 Các loại case
case
Phân biệt các giá trị x, z, 0, 1
Các chuỗi bít 01, 0x, z1 là khác nhau
Ví dụ 3.6.16: Normal case
Mã
module alu(input [1:0] alu_op, input [31:0] src1, src2, output reg [31:0] res);
parameter AND = 2'b00; parameter OR = 2'b01; parameter XOR = 2'b10; parameter ADD =
2'b11; always @(alu_op, src1, src2) begin case (alu_op) AND : res = src1 & src2; OR : res
= src1 | src2; XOR : res = src1 ^ src2; default : res = src1 + src2; endcase end endmodule
Kết quả tổng hợp
casez
Các bit có giá trị z, ? được coi như nhau là don't care: có thể match với 0/1
Các chuỗi 01, 00, 0z, 0? được coi là giống nhau
Ví dụ 3.6.18: casez
casex
Các bit có giá trị x, z, ? được coi như nhau là don't care có thể match 0/1
Khi có nhiều lựa chọn case (alternative) cùng phù hợp với expression thì sử dụng lựa chọn đầu
tiên => alternative phía trên có mức độ ưu tiên cao hơn
Ví dụ 3.6.17: casex
Mã
module test_casex(); reg [1:0] code; reg [7:0] control; always @ (code) begin casex
(code) // case expression 2'b0?: control = 1; // case item1 2'b10: control = 2; // case item
2 2'b11: control = 3; // case item 3 endcase end initial $monitor("%t: code = %b, control =
%d", $time, code, control); initial begin #0 code = 2'b00; #5 code = 2'b01; #5 code = 2'b10;
#5 code = 2'b11; #5 code = 2'b1x; #5 code = 2'b0x; end endmodule
Kết quả mô phỏng
3.6.6.3 Chú ý:
Để tránh latch thì luôn phải có nhanh default
Luôn viết case cho trường hợp các điều kiện alternative là loại trừ nhau và có mức độ ưu
tiên như nhau
Nếu muốn viết điều kiện có ưu tiên và không loại trừ thì nên dùng if lồng
Hạn chế dùng casez và casex
Tham khảo:Clifford Cummings: "full_case parallel_case, the Evil Twins of Verilog Synthesis"
3.7 3.7 Thực hành
3.7.1 Làm quen với phần mềm Altera Quartus
3.7.1.1 Mô phỏng mạch số
ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Tutorials/Verilog/Quartus_II_Simulatio
n.pdf
See document(s): Quartus_II_Simulation.pdf
3.7.1.2 Giới thiệu Quartus
ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Tutorials/Verilog/Quartus_II_Introducti
on.pdf
3.7.2 Làm quen với kit DE1
3.7.2.1 ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Tutorials/Getting_Started_with_
DE-series_boards.pdf
3.7.3 Bài Lab 1
3.7.3.1 ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Laboratory_Exercises/Digital_Lo
gic/DE2/verilog/lab1_Verilog.pdf
3.7.3.2 Chú ý trong bài lab này ta cần làm các bước
B1. Xác định bảng sự thật cho các đầu ra
B2. Tối giản các hàm Bool cho đầu ra
B3. Triển khai mô ta các hàm Bool đầu ra bằng câu lệnh gán assign trong Verilog. Hoặc mô tả
mạch bằng Verilog
3.7.4 Bài Lab 2
3.7.4.1 ftp://ftp.altera.com/up/pub/Altera_Material/11.0/Laboratory_Exercises/Digital_Lo
gic/DE2/verilog/lab2_Verilog.pdf
3.7.4.2 Làm hết phần 2
3.7.5 Đỗ trễ
3.7.5.1 Cách mô tả độ trễ 1 cổng trong Verilog
3.7.5.2 Mô phỏng độ trễ của mạch trong lab1 và lab2
3.7.6 Tham khảo
3.7.6.1 altera.com, university program
3.8 Bài tập chương:
3.8.1 Thiết kế bộ đếm mã gray 4 bit, bộ dịch logic trái phải 1 bit, bộ quay trái phải 1 bit
gồm n bit
4 Chương 4. Mô phỏng và testbench
4.1 4.1. Nguyên tắc hoạt động của chương trình mô phỏng
4.1.1 4.1.1. Định nghĩa: Là quá trình phân tích mô hình mô tả mạch để tính toán giá trị
đầu ra từ đầu vào
4.1.1.1 Là một quá trình thực hiện trừu tượng bằng bộ não con người hoặc máy tính
4.1.2 4.1.2. Nguyên tắc mô phỏng mạch số
4.1.2.1 Khi đầu vào thay đổi tính toán lại toàn bộ các tín hiệu trong mạch
Hình vẽ
4.1.2.2 Khi dầu vào thay đổi tính lại các đường từ đầu vào
Hình vẽ
4.1.3 4.1.3. Mô phỏng dựa trên sự kiện
4.1.3.1 B1: Đưa các tín hiệu đầu vào thay đổi vào hàng đợi sự kiện tại thời gian mô phỏng 0
4.1.3.2 B2: Lặp lại đến khi nào hàng đợi rỗng
Lấy một tín hiệu ra khỏi hàng đợi
Với mỗi phần tử (cổng logic, câu lệnh Verilog, module, lệnh gán...) là fanout(sink) của tín
hiệu
Tính lại giá trị đầu ra tương ứng của phần tử
Nếu đầu ra thay đổi giá trị, đưa tín hiệu đầu ra vào hàng đợi tại thời điểm mô phỏng = thời
điểm hiện tại + trễ của phần từ
4.1.3.3 B3: Khi hàng đợi rỗng, giữ nguyên kết quả mô phỏng hoặc đi đến thời gian mô
phỏng tiếp theo
4.1.3.4 Hình vẽ
4.1.3.5 Ví dụ mô phỏng mạch số
4.1.3.6 Ưu điểm của mô phỏng sự kiện
Tốc độ nhanh
Mô phỏng được thời gian
Mô phỏng được mạch mô tả bằng các mô hình cấu trúc/RTL/hoạt động
4.1.4 4.1.4. Thời gian trong mô phỏng
4.1.4.1 Được dùng để mô hình hóa thời gian hoạt động của mạch (độ trễ tính toán)
Không trễ (zero-delay)
Cú pháp
and A0(OUT, A, B);
assign OUT = A&B;
always @(A, B) OUT = A&B;
Đầu ra được thay đổi cùng với đầu vào
Sự kiện tại OUT được đưa vào hàng đợi tại thời điểm mô phỏng hiện tai
Không thực tế
Có thể chấp nhận kết quả mô phỏng khi xét mạch hoạt động đồng bộ
Trễ đơn vị (unit-delay)
Các phần tử trong mạch được gán một thời gian trễ tính theo đơn vị trễ tưởng tượng
Không chính xác, nhưng là xấp xỉ gần đúng thực tế
Thể hiện được thực tế là số mức logic ảnh hưởng tới tốc độ của mạch
Dễ dàng quan sát sự thay đổi của tín hiệu lan truyền trong mạch
Cú pháp
and #1 A0(OUT, A, B);
assign OUT = #1 A & B; assign #1 OUT = A & B;
OUT được thay đổi 1 đơn vị mô phỏng sau khi A hoặc/và B thay đổi
Quy định đơn vị thời gian trong Verilog
`timescale 1ns /100 fs // time_unit/time_precision ' `
Tuy nhiên: Không nên viết độ trễ của cổng logic trong phần mô tả mạch
Vẫn không chính xác
Không có kết quả tổng hợp tương ứng
Chậm tốc độ mô phỏng
Có thể mô phỏng thời gian ngay sau khi tổng hợp
Chỉ nên dùng độ trễ trong testbench
4.1.4.2 Ví dụ về mô tả trễ trong Verilog
wire #5 net_1; // 5 unit trễ dây dẫn
and #4 (z_out, x_in, y_in); // 4 unit trễ cổng
wire #2 z_out; // 2 unit trễ dây dẫn
and #3 (z_out, x_in, y_in); // 3 for gate, 2 for wire
wire #3 c; // 3 unit transport delay
assign #5 c = a & b; // 5 for assign, 3 for wire
assign z_out = #3 a & b; // 3 unit trễ cổng
Thực hiện tính toán, chờ 3 đơn vị trễ và gán z_out = a & b
assign #3 z_out = a & b; // 3 unit trễ cổng
Thực hiện tính toán và gán z_out = a & b sau đó chờ 3 đơn vị trễ
Chỉ nên dùng kiểu trễ này
4.1.4.3 Trễ trong câu lệnh gán Verilog
Inter-Statement Delay
Trễ cả việc tính RHS và gán
#4 c = d; #8 e = f;
Intra-Statement Delay
Trễ việc gán nhưng không trễ việc tính RHS
c = #4 d; e = #8 f;
Ví dụ so sánh
# 0: a= 3, b= x # 3: a= 1, b= x # 6: a=
1, b= 2 # 8: a= 1, b= 3 # 10: a= 4, b= 3
# 0: a= 3, b= x # 3: a= 1, b= x # 6: a=
1, b= 6 # 8: a= 1, b= 3 # 10: a= 7, b= 3
Chú ý: Không gán giá trị cho một biến trong nhiều khối lệnh
4.2 4.2. Testbench
4.2.1 4.2.1. Định nghĩa
4.2.1.1 Mô hình hóa môi trường hoạt động của mạch cần được kiểm tra (DUT, DUV)
4.2.1.2 Là một module Verilog không có đầu vào và đầu ra
4.2.1.3 Hình vẽ
4.2.2 4.2.2. Chức năng
4.2.2.1 Tạo ra tín hiệu đầu vào (input vectors, input patterns, input stimuti) đưa tới mạch
cần kiểm tra
4.2.2.2 Theo dõi tín hiệu đầu ra (và) so sánh, kiểm tra với tín hiệu đầu ra chuẩn (đúng)
4.2.2.3 Ví dụ 4.2.1
Mạch cộng 4 bit
Testbench
`timescale 1ns /100 fs // time_unit/time_precision-định nghĩa đơn vị thời gian mô phỏng
module adder4bit_tb; // Khai báo các tín hiệu nối vào DUT reg[8:0] stim; // inputs to DUT are regs
wire[3:0] S; // outputs of DUT are wires wire C4; // instantiate DUT adder4bit adder4bit_DUT
(.sum(S), .c_out(C4), .a(stim[8:5]), .b(stim[4:1]), .c(stim[0])); // stimulus generation -- tạo tín hiệu đầu
vào initial begin stim = 9'b0000_0000_0; // at 0 ns #10 stim = 9'b1111_0000_1; // at 10 ns
#10 stim = 9'b0000_1111_1; // at 20 ns #10 stim = 9'b1111_0001_0; // at 30 ns #10 stim =
9'b0001_1111_0; // at 40 ns #10 $stop; // at 50 ns – stops simulation end // outputs observation
initial $monitor("%t, a = %d, b=%d, ci=%b, s = %d, co=%b", $time, stim[8:5], stim[4:1],stim[0],s, c4)
endmodule
4.2.2.4 Bài tập: Viết testbench cho bộ cộng 16 bit, CLA và CRA
4.2.3 4.2.3. Thành phần
4.2.3.1 1. Tạo module con là DUT và kết nối đầu vào của DUT với tín hiệu chứa input
patterns (mẫu đầu vào), kết nối đầu ra với tín hiệu được quan sát và kiểm tra
4.2.3.2 2. Tạo mẫu tín hiệu đầu vào cho DUT
Phương pháp 1: Tạo tất cả các tổ hợp tín hiệu đầu vào
Sử dụng vòng lặp
for (x = 0; x < 16; x = x + 1) #5;
Ví dụ 4.2.2
`timescale 1ns /100 fs // time_unit/time_precision module adder4bit_tb; reg [9:0]
stim; // inputs to DUT are regs - chú ý để vòng lặp for ở dưới kết thúc, stim có nhiều hơn 1
bit so với số bit đầu vào wire[3:0] S; // outputs of DUT are wires wire C4; // instantiate
DUT adder4bit(.sum(S), .c_out(C4), .a(stim[8:5]), .b(stim[4:1]), .c(stim[0])); // stimulus
generation initial begin for (stim = 0;stim <512; stim = stim+1) #10; #10 $stop; end
endmodule
exhaustive/complete simulation
Chậm
Không khả thi
Sử dụng cho các mạch nhỏ
Đảm bảo chắc chắn phát hiện được các lỗi của mạch
Phương pháp 2: Tạo tổ hợp tín hiệu đầu vào ngẫu nhiên
Sử dụng hàm random
Không phát hiện được tất cả các lỗi
Có thể bỏ sót các lỗi ở các trường hợp tới hạn/trường hợp góc (critical corner cases)
Bài tập: xây dựng lại testbench ở ví dụ trên dùng hàm random
Phương pháp 3: Tạo đầu vào từ các kịch bản hoạt động của mạch
Xem xét các trường hợp hoạt động tới hạn của mạch
Đầu vào và đầu ra tương ứng có thể được đọc ra từ file
Với mỗi mạch khác nhau sẽ cần liệt kê ra trường hợp tới hạn khác nhau
Được xác định trong bước lên kế hoạch kiểm tra (Verification Plan)
Được tiến hành đồng thời với bước Architecture Design
Phân tích các kịch bản hoạt động của mạch chính là tương ứng với phân tích/phân rã
chức năng của mạch
Tham số đánh giá chất lượng tổ hợp đầu vào
Coverage Metrics
Bao phủ mã
Bao phủ câu lệnh
Bao phủ điều kiện
Bao phủ nhánh lệnh
Bao phủ chức năng
Bao phủ FSM
Bao phủ trạng thái
Bao phủ chuyển trạng thái
4.2.3.3 3. Quan sát và kiểm tra tín hiệu đầu ra
Phương pháp 1: Quan sát và so sánh thủ công
Tín hiệu đầu vào/ đầu ra được hiển thị dưới dạng biểu đồ thời gian
In ra tín hiệu đầu ra dưới dạng text
$display, $strobe
$monitor
Dễ có sai sót do người thực hiện
Không tự động hóa được
Thường được thay thế bằng testbench tự kiểm tra (self-test)
Phương pháp 2: Quan sát và kiểm tra kết quả đầu ra tự động
Cần có khối tính toán kết quả đầu ra
Cách 1: Tính toán đầu ra "đúng" bằng mã Verilog trong testbench
Ví dụ:
4.2.3.3..1.1.1.1 `timescale 1ns /100 fs // time_unit/time_precision-định nghĩa đơn vị thời gian mô phỏng
module adder4bit_tb; // Khai báo các tín hiệu nối vào DUT reg[8:0] stim; // inputs to DUT are regs
wire[3:0] S; // outputs of DUT are wires wire C4; // instantiate DUT adder4bit adder4bit_DUT (.sum(S),
.c_out(C4), .a(stim[8:5]), .b(stim[4:1]), .c(stim[0])); // stimulus generation -- tạo tín hiệu đầu vào initial
begin stim = 9'b0000_0000_0; // at 0 ns #10 stim = 9'b1111_0000_1; // at 10 ns #10 stim =
9'b0000_1111_1; // at 20 ns #10 stim = 9'b1111_0001_0; // at 30 ns #10 stim = 9'b0001_1111_0; //
at 40 ns #10 $stop; // at 50 ns - stops simulation end // outputs observation initial $monitor("%t, a =
%d, b=%d, ci=%b, s = %d, co=%b", $time, stim[8:5], stim[4:1],stim[0],s, c4) // outputs self-test always
@(stim, s, c4) begin if ({c4, s} != stim[8:5]+stim[4:1]+stim[0]) $display ("FAIL: %t, a = %d, b=%d,
ci=%b, s = %d, co=%b", $time, stim[8:5], stim[4:1],stim[0],s, c4); end endmodule
Testbench thực hiện việc mô tả chức năng mạch một lần nữa (nguyên lý duplicate
trong kiểm tra)
4.2.3.3..1.1.1.2 Chú ý: mạch được mô tả trong testbench không cần phải tổng hợp => có thể mô tả bằng các
cấu trúc ngôn ngữ bậc cao (trừu tượng hơn) => đơn giản hơn mạch DUT
Cách 2: Tính toán đầu ra "đúng" bằng chương trình phần mềm (C/C++,
Matlab/Simulink)
Giao tiếp thông qua tệp tin
4.2.3.3..1.1.1.3 Phần mềm sẽ ghi mẫu đầu vào và đầu ra "đúng" tương ứng vào file
4.2.3.3..1.1.1.4 Testbench sẽ đọc file để lấy đầu vào và đầu ra "đúng"
Giao tiếp thông qua giao diện PLI, giao diện HIL,...
4.2.3.4 4. Tạo tín hiệu clk
Dùng always
initial clk = 0; always @(clk) clk = #5 ~clk;
Dùng forever
initial begin clk = 0; forever #5 clk = ~clk; end
4.3 4.3. Một số câu lệnh có thể dùng trong testbench
4.3.1 4.3.1. Các lệnh lặp
4.3.1.1 for
Cú pháp
for (starting_statement; condition_expression; ending_statement)
Ví dụ 4.3.1: for
reg [15:0] rf[0:15]; // memory structure for modeling register file reg [5:0] w_addr; // address
to write to for (w_addr=0; w_addr<16; w_addr=w_addr+1) rf[w_addr[3:0]] = 16’h0000; // initialize
register file memory
4.3.1.2 while
Cú pháp
while (condition_expression)
Ví dụ 4.3.2: while
reg [15:0] flag; reg [4:0] index; initial begin index=0; found=1’b0; while ((index<16) &&
(!found)) begin if (flag[index]) found = 1’b1; else index = index + 1; end if (!found)
$display(“non-zero flag bit not found!”); else $display(“non-zero flag bit found in position %d”,index);
end
4.3.1.3 repeat
Cú pháp
repeat (number_of_iteration)
Trong đó: number_of_iteration là 1 hằng số nguyên hoặc 1 biến
Lặp số lần cố định
Số lần lặp có thể là một biến, nhưng chỉ được tính một lần khi bắt đầu vòng lặp
Dùng khi muốn đợi một số xác định chu kỳ đồng hồ
Ví dụ 4.3.3: repeat
initial begin inc_DAC = 1’b1; repeat(4095) @(posedge clk); // bring DAC right up to point of
rollover inc_DAC = 1’b0; inc_smpl = 1’b1; repeat(7)@(posedge clk); // bring sample count up to 7
inc_smpl = 1’b0; end
4.3.1.4 forever
Cú pháp
forever statements;
Ví dụ 4.3.4: forever
initial begin clk = 0; forever #10 clk = ~ clk; end
4.3.2 4.3.2. Khối lệnh và điều khiển khối lệnh
4.3.2.1 Khối lệnh tuần tự - begin/end
bao khối lệnh thực hiện tuần tự
4.3.2.2 Khối lệnh song song - fork/join
bao khối lệnh thực hiện song song
các câu lệnh trong khối được thực hiện đồng thời
Thời gian trễ trong các câu lệnh nằm giữa fork/join được tính tương đối kể từ khi khối lệnh
được bắt đầu thực hiện
Thích hợp để chờ 2 sự kiện xuất hiện nhưng không biết sự kiện nào xuất hiện trước
begin fork @Aevent @Bevent join areg = breg; end
Chú ý: fork/join có thể gây ra đua tín hiệu (hazard)
Khi nhiều khối fork/join cùng gán giá trị cho một biến
4.3.2.3 Đặt tên khối lệnh
Có thể định nghĩa biến địa phương bên trong khối lệnh đã được đặt tên
Các biến địa phương có thể được truy cập bằng cách truy cập phân cấp
Có thể dừng (disable) một khối lệnh có tên
Hình vẽ
4.3.2.4 Tạm dừng thực hiện một khối lệnh
Cú pháp: disable block_name;
Tạm dừng thực hiện một khối lệnh
Ví dụ 4.3.5: disable
Mã
`timescale 1ns/1ns module test_diable(); integer a, b; integer i; reg clk; initial begin :
break for (i = 0; i < 20; i = i+1) begin : continue @(posedge clk) if (a == 0) //
"continue" loop disable continue; // Dừng không thực hiện lệnh bên trong khối continue
if (a == b) // "break" from loop disable break; // Dừng không thực hiện lệnh bên trong
khối break $display("%t:Inside continue block a=%d,b=%d,i=%d",$time,a,b,i); end
$display("%t:Inside break block a=%d,b=%d,i=%d",$time,a,b,i); end initial begin a = 2; b = 1;
#20 a = 0; #20 a = 3; #20 a = 1; end initial begin clk = 0; forever #5 clk = ~clk; end // initial
$monitor ("%t:a=%d,b=%d,i=%d",$time,a,b,i); endmodule;
Kết quả mô phỏng
run 100ns # 5:Inside continue block a= 2,b= 1,i= 0 #
15:Inside continue block a= 2,b= 1,i= 1 # 45:Inside continue block a=
3,b= 1,i= 4 # 55:Inside continue block a= 3,b= 1,i= 5
4.3.3 4.3.3 Vào ra file
4.3.3.1 Thực hiện kiểm chứng tự động
4.3.3.2 Đầu vào, đầu ra được đưa vào file và độc lập với testbench
Đầu vào và đầu ra chuẩn có thể được tạo ra bởi phần mềm ở ngôn ngữ bậc cao như C/C++,
Matlab/Simulink
Dùng file để kết nối 2 mức mô tả hệ thống
Mức phần mềm: mô tả thuật toán
Mức phần cứng (DUT): mô tả triển khai RTL/behavior
4.3.3.3 Các hàm thao tác trên file
Đóng mở
$fopen mở file, trả về 1 handle để sử dụng trong các lệnh khác
integer fd = $fopen(“filename”); integer fd = $fopen(“filename”, r);
Nếu không mở được file trả về 0
$fclose đóng file
$fclose(fd)
Ghi
$fdisplay, $fwrite ghi dữ liệu vào file khi được gọi. $fdisplay thêm 1 ký tự bắt đầu dòng mới
vào dữ liệu. $write không thêm.
$fstrobe ghi vào file, nhưng đợi đến khi tất cả các lệnh khác trong cùng thời gian mô phỏng
kết thúc trước khi ghi.
initial #1 a=1; b=0; $fstrobe(hand1, a,b); b=1;
Đoạn mã trên sẽ ghi giá trị 1 1 vào file cho a và b
$fmonitor ghi vào file bất cứ khi nào các tham số truyền cho nó thay đổi
$fdisplay(fd, “out=%b in=%b”, out, in);
Đọc
Đọc một ký tự
$fgetc
Ví dụ 3.3.6: fgetc
4.3.3.3..1.1.1.1 module file_read() parameter EOF = -1; integer file_handle,error,indx; reg signed [15:0]
wide_char; reg [7:0] mem[0:255]; reg [639:0] err_str; initial begin indx=0; file_handle =
$fopen(“text.txt”,”r”); error = $ferror(file_handle,err_str); if (error==0) begin wide_char = 16’h0000;
while (wide_char!=EOF) begin wide_char = $fgetc(file_handle); mem[indx] = wide_char[7:0];
$write(“%c”,mem[indx]); indx = indx + 1; end end else $display(“Can’t open file…”);
$fclose(file_handle); end endmodule
Đọc một dòng
$fgets
Ví dụ 3.3.7: fgets
4.3.3.3..1.1.1.2 module file_read2() integer file_handle,error,indx,num_bytes_in_line; reg [256*8:1]
mem[0:255],line_buffer; reg [639:0] err_str; initial begin indx=0; file_handle = $fopen(“text2.txt”,”r”);
error = $ferror(file_handle,err_str); if (error==0) begin num_bytes_in_line =
$fgets(line_buffer,file_handle); while (num_bytes_in_line>0) begin mem[indx] = line_buffer;
$write(“%s”,mem[indx]); indx = indx + 1; num_bytes_in_line = $fgets(line_buffer,file_handle); end
end else $display(“Could not open file text2.txt”);
Đọc theo biến
$fscanf
Ví dụ 3.3.8: fscanf
4.3.3.3..1.1.1.3 module file_read3() integer file_handle,error,indx,num_matches; reg [15:0] mem[0:255][1:0];
reg [639:0] err_str; initial begin indx=0; file_handle = $fopen(“text3.txt”,”r”); error =
$ferror(file_handle,err_str); if (error==0) begin num_matches = $fscanf(file_handle,”%h
%h”,mem[indx][0],mem[indx][1]); while (num_matches>0) begin $display(“data is: %h
%h”,mem[indx][0],mem[indx[1]); indx = indx + 1; num_matches = $fscanf(file_handle,”%h
%h”,mem[indx][0],mem[indx][1]); end end else $display(“Could not open file text3.txt”);
Đọc file theo khối bộ nhớ
$readmemb(“<file_name>”,<memory>);
$readmemb(“<file_name>”,<memory>,<start_addr>,<finish_addr>);
$readmemh(“<file_name>”,<memory>);
$readmemh(“<file_name>”,<memory>,<start_addr>,<finish_addr>);
Ví dụ cấu trúc file
Ví dụ 3.3.9: Đọc bộ nhớ
module rom(input clk; input [7:0] addr; output [15:0] dout); reg [15:0] mem[0:255];
// 16-bit wide 256 entry ROM reg [15:0] dout; initial $readmemh(“constants”,mem);
always @(negedge clk) begin
/////////////////////////////////////////////////////////// // ROM presents data
on clock low // ///////////////////////////////////////////////////////// dout <=
mem[addr]; end endmodule
Ví dụ 3.3.10: Testbench sử dụng file
module CLA16_selft_tb(); reg [32:0] stim; reg [55:0] inout_patterns [0:10]; wire [15:0] s; wire
co; reg [4:0] addr; CLA16 cla16_dut(.a(stim[15:0]), .b(stim[31:16]), .ci(stim[32]), .s(s), .co(co));
initial $monitor("%t: a=%h, b=%h, ci=%b, s=%h, co=%b, correct_s=%h, correct_co=%b", $time,
stim[15:0], stim[31:16], stim[32], s, co, inout_patterns[addr][51:36],inout_patterns[addr][52]); //
read input-output patterns from file and // drive to input // in file correct-outputs.txt the data is
arranged as follow: // each input patterns and corresponding correct output values are given as a
hexa number where // first four digits is a value [15:0] // next four is b value [31:16] // next one
digit is ci value [35:32] // next four digits is s value [51:36] // next one digit is co value [55:52] //
total are 14 digits initial begin: input_gen $readmemh("correct-outputs.txt", inout_patterns);
stim = 32'h0; for (addr = 0;addr < 11; addr=addr+1) begin stim = inout_patterns[addr][32:0];
#5; end end // output self-test always @(stim) begin: output_selftest if
((co!==inout_patterns[addr][52])|(s!==inout_patterns[addr][51:36])) $display ("WRONG!!!-%t:
a=%h, b=%h, ci=%b, s=%h, co=%b, correct_s=%h, correct_co=%b", $time, stim[15:0],
stim[31:16], stim[32], s, co,inout_patterns[addr][51:36],inout_patterns[addr][52]); end endmodule
4.3.4 4.3.4 Đặt giá trị tín hiệu trong mạch
4.3.4.1 Đưa mạch đến một trạng thái xác định và bắt đầu mô phỏng từ đó
4.3.4.2 Chỉ sử dụng trong testbench, không có trong thực tế
4.3.4.3 Giúp đi đến gần trạng thái có thể xảy ra lỗi của mạch
4.3.4.4 Dùng kiểm tra mạch dãy "sâu" (cần nhiều chu kỳ để đến được một trạng thái bất kỳ
của mạch)
Đưa mạch đến một trạng thái
Kiểm tra các bước chuyển trạng thái từ trạng thái đó
Kiểm tra đầu ra tương ứng
4.3.4.5 force signal_name = value; release signal_name = value;
Chú ý: có thể dùng cách truy cập phân cấp (dấu chấm) để chỉ tới tín hiệu sâu bên trong các
module con
4.3.4.6 Ví dụ 4.3.6: force/release
Testbench
module gray_counter_tsb(); reg clk, rst_n; wire [3:0] out; gray_counter GC(.cnt(out),
.clk(clk), .rst_n(rst_n)); // DUT initial $monitor("%t out: %b rst_n: %b state: %b", $time, out, rst_n,
GC.state); // no clock initial begin clk = 0; forever #5 clk = ~clk; // What is the clock period? end
initial begin rst_n = 1; #10 rst_n = 0; #90 rst_n = 1; force GC.state = 4'b0001; #10 release GC.state;
#10 force GC.state = 4'b0010; #10 release GC.state; #10 force GC.state = 4'b0011; #10 release
GC.state; #10 force GC.state = 4'b0100; #10 release GC.state; #10 force GC.state = 4'b0101; #10
release GC.state; #10 force GC.state = 4'b0110; #10 release GC.state; #10 force GC.state = 4'b0111;
#10 release GC.state; #10 force GC.state = 4'b1000; #10 release GC.state; #10 force GC.state =
4'b1001; #10 release GC.state; #10 force GC.state = 4'b1010; #10 release GC.state; #10 force
GC.state = 4'b1011; #10 release GC.state; #10 force GC.state = 4'b1100; #10 release GC.state; #10
force GC.state = 4'b1101; #10 release GC.state; #10 force GC.state = 4'b1110; #10 release GC.state;
#10 force GC.state = 4'b1111; #10 release GC.state; end // initial endmodule
gray_counter
module gray_counter (input clk, rst_n, output [3:0] cnt); reg [3:0] state; always @(posedge
clk) begin if (~rst_n) state <= 4'b0000; else state <= state+1; end assign cnt = state ^
{1'b0,state[3:1]}; endmodule
4.4 4.4. Một số hàm hệ thống trong Verilog
4.4.1 $stop
4.4.1.1 Dừng mô phỏng vào chế độ giao tiếp lệnh với người dùng, cho phép theo dõi các tín
hiệu và gỡ lỗi
4.4.2 $finish
4.4.2.1 Kết thúc chương trình mô phỏng quay về hệ điều hành
4.4.3 $reset
4.4.3.1 đặt lại thời gian mô phỏng về 0
4.4.4 $time, $stime, $realtime
4.4.4.1 Trả về thời gian mô phỏng hiện tại dạng 64 bit nguyên, 32 bit nguyên, số thực
4.4.5 $display, $strobe, $monitor
4.4.5.1 Cú pháp
$display ("format_string", par_1, par_2, ... ); $strobe ("format_string", par_1, par_2, ... );
$monitor ("format_string", par_1, par_2, ... ); $displayb (as above but defaults to binary..); $strobeh
(as above but defaults to hex..); $monitoro (as above but defaults to octal..);
format string tương tự printf của C
4.4.5.2 $display và $strobe được thực hiện 1 lần khi được gọi
4.4.5.3 $monitor được thực hiện bất cứ khi nào các tham số truyền vào thay đổi
4.4.5.4 Được sử dụng trong testbench khi mô phỏng mạch
4.4.5.5 $display(“At time %t count = %h”,$time,cnt);
4.4.6 $random
4.4.6.1 Tạo một số nguyên ngẫu nhiên khi được gọi
4.4.6.2 Ở lần gọi đầu tiên có thể truyền cho hàm một số seed (các lần gọi với cùng một số
seed sẽ tạo ra cũng một chuỗi ngẫu nhiên
4.4.6.3 Nếu không truyền số seed, số seed sẽ được lấy từ đồng hồ hệ thống
4.4.7 $dumpfile, $dumpvar, $dumpon, $dumpoff, $dumpall
4.4.7.1 $dumpfile("filename.vcd")
Đặt file chứa các giá trị biến được in ra
4.4.7.2 $dumpvar
In ra giá trị tất cả các biến trong thiết kế
4.4.7.3 $dumpvar(n, top)
In ra giá trị các biến trong module top và n-1 module con phía dưới
4.4.7.4 Subtopic
4.4.7.5 $dumpon
Bắt đầu thực hiện in
4.4.7.6 $dumpoff
Kết thúc việc in ra các biến
4.4.8 Chú ý: Các hàm này không dùng mô tả mạch mà chủ yếu dùng để gỡ lỗi mạch khi mô
phỏng, trong testbench
5 Chương 5. Tổng hợp. Tham khảo: http://asic-soc.blogspot.de
5.1 5.1. Giới thiệu chung
5.1.1 Quy trình thiết kế vi mạch
5.1.1.1
5.1.1.2 Thiết kế vật lý là quá trình đặt các layout các cổng lên phiến đế (Place) và kết nối
các cổng bằng các đường dây kim loại (Route)
5.1.2 Định nghĩa
5.1.2.1 Tổng hợp là quá trình chuyển từ mô tả RTL/behavior thành mạch ở lớp cổng
RTL/Behavior ở ngôn ngữ HDL (Verilog/VHDL) mô tả hoạt động của mạch bằng
RTL: mô tả quá trình xử lý dữ liệu của mạch (Dataflow)
Behavior: Mô tả các bước hoạt động của mạch-FSMD
Mạch ở lớp cổng: Các cổng logic kết nối với nhau
Mạch lớp cổng generic không phụ thuộc công nghệ chế tạo khi các cổng không đi kèm thông
tin về layout, kích thước transitor, bố trí transitor, điểm kết nối
Không dùng được để chế tạo vi mạch
Mạch lớp cổng phụ thuộc công nghệ chế tạo, nếu các cổng có thông tin về layout, kích thước
transitor, điểm kết nối
Cho phép xác định chính xác thời gian hoạt động/độ trễ/tốc độ của mạch
5.1.2.2 Hai bước tổng hợp
Dịch
Chuyển đổi mô tả Verilog thành mô tả lớp cổng generic
Tối ưu và ánh xạ cổng
Ánh xạ các cổng generic thành các cổng trong thư viện cell chuẩn phụ thuộc công nghệ.
Tối ưu mạch để đạt được các điều kiện kỹ thuật đặt ra
Hình vẽ
5.1.3 Nhiệm vụ của tổng hợp
5.1.3.1 Mức ưu tiên cao nhất: Đảm bảo chức năng của mạch
Mạch netlist tổng hợp được tương đương mạch mô tả ở Verilog
Tương đương về hàm logic Bool
Tương đương về sự thứ tự tuần tự trong mạch dãy
Không tạo ra các latch không mong muốn
5.1.3.2 Mức ưu tiêu 2: Thỏa mãn các giới hạn về luật thiết kế
Được cho trong thư viện công nghệ bởi các nhà sản xuất ASIC
Người thiết kế không thể thay đổi các giới hạn luật thiết kế
Người thiết kế có thể áp đặt giới hạn khắt khe hơn, nhưng không thể áp đặt giới hạn nhẹ
hơn
Ví dụ: Giới hạn về tốc độ chuyển giá trị tín hiệu, số fanout tối đa,...
5.1.3.3 Mức ưu tiên 3: Thỏa mãn các giới hạn tối ưu
Được đặt ra bởi người thiết kế, theo thứ tự ưu tiên như sau
1. Thời gian (Speed/Timing)
2. Kích thước (Area)
3. Năng lượng (Power)
Giới hạn này phải thực tế, nhưng không được quá nhẹ
Nếu không sẽ được thiết kế tồi
5.1.4 Đầu vào/ra của tổng hợp
5.1.4.1 Đầu vào
Mã HDL (.v, vhd)
Giới hạn về luật thiết kế
Giới hạn tối ưu
Tốc độ
Kích thước
Năng lượng
5.1.4.2 Đầu ra
Mô tả mạch ở mức cổng phụ thuộc công nghệ
5.2 5.2. Chuẩn bị tổng hợp
5.2.1 5.2.1 Thư viện đích
5.2.1.1 Cho biết công nghệ được sử dụng để sản xuất mạch
Cần thư viện các cổng logic phụ thuộc công nghệ
Thư viện target được dùng để tạo ra mạch cổng phụ thuộc công nghệ
Thư viện target được cung cấp bởi nhà sản xuất IC hoặc nhóm thiết kế standard cell .lib
Các thư viện standard cell là được lưu trong file .db ở trong các thư mục libs../../LM
5.2.1.2 Thư viện standard cells ở mức logic. Chứa các thông tin về các cổng logic cơ bản
Tên cell
Kích thước cell
Đầu vào/ra
Hàm logic
Tham số thời gian
5.2.1.3 Lệnh DC: set_app_var target_library
dc_shell-topo> set_app_var target_library libs/mw_lib/sc/LM/sc_max.db
libs/mw_lib/sc/LM/sc_max.db
5.2.1.4 Bắt buộc phải đặt target_library
5.2.2 5.2.2 Thư viện liên kết
5.2.2.1 Khi tổng hợp cần biết mô tả cấu trúc tất cả các module sử dụng trong mạch
Được chứa trong thư viện link
Ví dụ: Module DDR-RAM, module CPU được mua của hãng thứ 3
5.2.2.2 Nếu không có sẽ báo lỗi
Unable to resolve reference "..."
5.2.2.3 Lệnh DC set_app_var link_library
dc_shell-topo> set_app_var link_library * libs/mw_lib/sc/LM/sc_max.db
5.2.2.4 Thường link_library sẽ gồm * và target_library
* chỉ đến bộ nhớ, là phần dc lưu trữ tạm thời các thư viện nó đã tổng hợp hoặc đã nạp
Ví dụ: một file .v chứa module con
Các file ddc chứa module con đã được tổng hợp
Có thể dùng target_library để làm thư viện link nếu file .v bản đầu là RTL/behavior không
phụ thuộc công nghệ
Nếu file .v ban đầu là file đã tổng hợp phụ thuộc công nghệ thì link library phải là library
công nghệ cũ
5.2.3 5.2.3 Thư viện vật lý
5.2.3.1 Thư viện vật lý chứa các thông số giúp dc tính toán chính xác thời gian trễ của mạch
hơn trong chế độ hoạt động topological (tùy chọn -topo khi chạy dc_shell)
5.2.3.2 Gồm
Reference library
Standard Cells
Các cổng logic căn bản ở lớp transistor/layout
IP hoặc Macro cells
Ví dụ: RAM module, Multiplier IP
I/O Pad cells
Chứa thông tin ở các lớp/mức khác nhau
CEL
Thông tin đầy đủ về layout cell - đủ để chế tạo
FRAM
Thông tin về kích thước cell và vị trí các chân trong cell
DC cần dùng
LM
Thông tin về hàm logic và timing của cell
DC cần dùng
Chính là thư viện target
DC dùng định dạng Milkyway cho reference library
Được cung cấp bởi nhà chế tạo IC
Có thể được tạo ra từ file LEF, GDS bằng cách dùng tool Synopsys Milkyway
Tham khảo
Data preparation user guide
Dữ liệu công nghệ
Technology File
Định nghĩa về các lớp đi dây, các lỗ nối giữa các lớp, luật DRC
TLUPLUS file
Chứa các tham số về tụ điện và điện trở ký sinh
Layer Mapping file
Chứa các tên khác nhau cho cùng một lớp
5.2.3.3 Để tạo cần
Trỏ tới reference library
Nạp file technology
Nạp file tluplus
5.2.3.4 Lệnh
set_app_var mw_referecen_library
set_app_var mw_design_library
create_mw_lib
Chỉ cần tạo một lần
open_mw_lib
Sau đó chỉ cần mở
check_library
set_tluplus_files
check_tluplus_files
dc_shell-topo> set_app_var mw_reference_library libs/mw_lib/sc libs/mw_lib/sc dc_shell-
topo> set_app_var mw_design_library mylib mylib dc_shell-topo> create_mw_lib -technology
libs/tech/cb13_6m.tf -mw_reference_library $mw_reference_library $mw_design_library Start to
load technology file libs/tech/cb13_6m.tf. Technology file libs/tech/cb13_6m.tf has been loaded
successfully.
5.2.4 5.2.4 Quản lý các tệp
5.2.4.1 Tạo cấu trúc thư mục
Thư mục chính chứa toàn bộ dữ liệu về thiết kế: risc_design.
Là thư mục mà tại đó ta gọi dc_shell -topo
Thư mục con và files
mapped
Chứa các file .ddc mô tả mạch gồm các cổng phụ thuộc công nghệ (sau khi đã ánh xạ
từ cổng không phụ thuộc công nghệ) vào thư viện cổng theo công nghệ
libs
Chứa các file .db các thư viện khối, IPs được sử dụng trong thiết kế
cons
Chứa các file .cons là các câu lệnh tcl của dc_shell để thiết lập giới hạn thời gian, diện
tích năng lượng của mạch
rtl
Chứa các file thiết kế ở ngôn ngữ HDL
unmapped
Chứa các file .ddc mô tả mạch cổng không phụ thuộc công nghệ
.synopsys_dc.setup
File gồm các lệnh tcl sẽ được thực thi khi gọi dc_shell
Lệnh sử dụng: mkdir
minh@dolcetto-suse:/home/projects> mkdir dc-ex minh@dolcetto-suse:/home/projects>
mkdir dc-ex/rtl minh@dolcetto-suse:/home/projects> mkdir dc-ex/work minh@dolcetto-
suse:/home/projects> mkdir dc-ex/libs minh@dolcetto-suse:/home/projects> mkdir dc-ex/cons
minh@dolcetto-suse:/home/projects> mkdir dc-ex/mapped minh@dolcetto-suse:/home/projects>
mkdir dc-ex/unmapped minh@dolcetto-suse:/home/projects> ll dc-ex total 24 drwx--x--x 2 minh users
4096 2012-04-18 08:20 cons drwx--x--x 2 minh users 4096 2012-04-18 08:20 libs drwx--x--x 2 minh
users 4096 2012-04-18 08:20 mapped drwx--x--x 2 minh users 4096 2012-04-18 08:20 rtl drwx--x--x 2
minh users 4096 2012-04-18 08:20 unmapped drwx--x--x 2 minh users 4096 2012-04-18 08:20 work
Chạy dc_shell với option -topo
Chú ý: vào thư mục làm việc dc-ex
minh@dolcetto-suse:/home/projects> cd dc-ex minh@dolcetto-suse:/home/projects/dc-ex>
dc_shell -topo DC Professional (TM) DC Expert (TM) DC Ultra
(TM) FloorPlan Manager (TM) HDL Compiler (TM) VHDL
Compiler (TM) Library Compiler (TM) DesignWare Developer (TM)
DFT Compiler (TM) BSD Compiler Power Compiler (TM) Version D-
2010.03-SP5-2 for linux -- Jan 21, 2011 Copyright (c) 1988-2010 by Synopsys, Inc.
ALL RIGHTS RESERVED This software and the associated documentation are confidential and
proprietary to Synopsys, Inc. Your use or disclosure of this software is subject to the terms and
conditions of a written license agreement between you, or your company, and Synopsys, Inc. The above
trademark notice does not imply that you are licensed to use all of the listed products. You are licensed
to use only those products for which you have lawfully obtained a valid license key. Initializing...
Starting shell in Topographical mode... dc_shell-topo>
5.2.4.2 set_app_var search_path "$search_path rtl unmapped mapped"
Thêm các đường dẫn để dc tìm các file .v, .db, .ddc
5.2.4.3 define_design_lib WORK -path ./work
Các file tạm sinh ra trong quá trình tổng hợp được lưu trong work
Giữ thư mục chính dc-ex gọn gàng, trật tự
5.2.5 5.2.5 Tổng kết
5.2.5.1 các thiết lập đường dẫn cho thư viện có thể được viết vào file .tcl và được gọi ra
bằng file .synopsys_dc.setup
5.2.5.2 chỉ cần sửa các biến đường dẫn trong file common_setup.tcl cho các thiết kế khác
nhau
5.2.5.3 common_setup.tcl
đặt tên cho các biến đường dẫn
sử dụng lênh : set tên_biến đường dẫn
Ví dụ
##########################################################################################
# User-defined variables for logical library setup in dc_setup.tcl
##########################################################################################
set ADDITIONAL_SEARCH_PATH "../ref/libs/mw_lib/sc/LM ./rtl ./scripts" ;# Directories containing logical
libraries,
# logical design and script files.
set TARGET_LIBRARY_FILES sc_max.db ;# Logical technology library file
set SYMBOL_LIBRARY_FILES sc.sdb ;# Symbol library file
##########################################################################################
# User-defined variables for physical library setup in dc_setup.tcl
##########################################################################################
set MW_DESIGN_LIB TOP_LIB ;# User-defined Milkyway design library name
set MW_REFERENCE_LIB_DIRS ../ref/libs/mw_lib/sc ;# Milkyway reference libraries
set TECH_FILE ../ref/libs/tech/cb13_6m.tf ;# Milkyway technology file
set TLUPLUS_MAX_FILE ../ref/libs/tlup/cb13_6m_max.tluplus ;# Max TLUPlus file
set MAP_FILE ../ref/libs/tlup/cb13_6m.map ;# Mapping file for TLUplus
5.2.5.4 dc_setup.tcl
sử dụng các biến trong file common_setup/tcl để chỉ tới các thư viện link,target ...
ví dụ
######################################################################
# Logical Library Settings
######################################################################
set_app_var search_path "$search_path $ADDITIONAL_SEARCH_PATH"
set_app_var target_library $TARGET_LIBRARY_FILES
set_app_var link_library "* $target_library"
set_app_var symbol_library $SYMBOL_LIBRARY_FILES
######################################################################
# Physical Library Settings
######################################################################
set_app_var mw_reference_library $MW_REFERENCE_LIB_DIRS
set_app_var mw_design_library $MW_DESIGN_LIB
create_mw_lib -technology $TECH_FILE \
-mw_reference_library $mw_reference_library \
$mw_design_library
open_mw_lib $mw_design_library
set_tlu_plus_files -max_tluplus $TLUPLUS_MAX_FILE \
-tech2itf_map $MAP_FILE
5.2.5.5 .synopsys_dc.setup
dùng để gọi 2 file dc_setup và common_setup
tự động chạy khi gọi dc_shell tại đường dẫn chứa file này
ví dụ:
source common_setup.tcl
source dc_setup.tcl
ngoài ra có thế viết thêm các lệnh check lib để kiểm tra thư viện
5.3 5.3. Các điều kiện giới hạn tổng hợp
5.3.1 5.3.1. Giới hạn thời gian
5.3.1.1 Định nghĩa
Là thông tin thời điểm xuất hiện về tín hiệu đồng hồ, đầu vào, đầu ra của mạch. Thông tin
này cho phép bộ tổng hợp kiểm tra điều kiện setup và hold của các FF trong mạch
Thông tin đồng hồ: xác định thời điểm xuất hiện sườn đồng hồ điều khiển FF
Cho phép xác định/và tối ưu độ trễ của các đường tín hiệu từ đầu ra Q của FF đến đầu
vào D của FF (Đường tín hiệu REG-REG)
Thông tin đầu vào: xác định thời điểm đến của tín hiệu đầu vào so với sườn đồng hồ
Cho phép xác định/và tối ưu độ trễ của các đường tín hiệu từ đầu vào PI đến đầu vào
D của FF (Đường tín hiệu PI-REG)
Thông tin đầu ra: xác định thời điểm cần đưa tín hiệu đầu ra so với sườn đồng hồ
Cho phép xác định/và tối ưu độ trễ của các đường tín hiệu từ đầu ra Q của FF đến đầu
ra PO (Đường tín hiệu REG-PO)
Hình vẽ
5.3.1.2 Thông tin đồng hồ
Đặt giới hạn thời gian trễ tối đa cho đường logic tổ hợp giữa 2 FF: FF_start và FF_stop
Tmax(REG-REG)=min(t_clk_cap-t_clk_launch)-t_setup
Khoảng cách giữa 2 sườn xung đồng hồ liên tiếp dùng để điều khiển 2 FF_start, FF_stop
trong đường tín hiệu đang xét.
Hai loại sườn đồng hồ
Điều khiển 2 FF_start, FF_stop được dùng như mốc tham chiếu để tính toán thời gian
(thời điểm)
Sườn bắt dữ liệu (capture edge)
Là sườn được dùng để phát hiện và lưu trữ dữ liệu vào FF_stop
Xuất hiện tại thời điểm t_clk_cap
Sườn xuất dữ liệu (launch edge)
Là sườn được dùng để đưa dữ liệu ra khỏi FF_start
Xuất hiện tại thời điểm t_clk_lauch
Hình vẽ
Chú ý: loại sườn đồng hồ được xác định ứng với từng đường tín hiệu trong mạch
Thời điểm xuất hiện 2 sườn đồng hồ bắt dữ liệu và xuất dữ liệu được quyết định bởi các
khoảng thời gian
Chu kỳ và độ rộng xung đồng hồ
Hình vẽ
5.3.1.2..1.1.1.1
Lệnh tạo đồng hồ
5.3.1.2..1.1.1.2 create_clock -period chu_kỳ_clk [get_ports tên_clk]
5.3.1.2..1.1.1.3 create_clock -period 3.0 [get_ports clk]
# A 333Mhz clock is a 3.0ns period:
Lệnh đặt độ rộng xung đồng hồ
5.3.1.2..1.1.1.4 set_min_pulse_width -high 2.5 [all_clocks]
5.3.1.2..1.1.1.5 set_min_pulse_width -low 2.0 [all_clocks]
Độ trễ do đường tín hiệu đồng hồ (Clock latency)
Lệnh đặt latency
5.3.1.2..1.1.1.6 set_clock_latency -source
5.3.1.2..1.1.1.7 Độ trễ của các đường clk ngoài module đang xét
5.3.1.2..1.1.1.8 Có thể coi là độ trễ của đầu vào clk
5.3.1.2..1.1.1.9 set_clock_latency -max
5.3.1.2..1.1.1.10 Độ trễ đường clk bên trong module
5.3.1.2..1.1.1.11 sau khi post-layout thì dùng lệnh
5.3.1.2..1.1.1.12 set_propagated_clock
5.3.1.2..1.1.1.13 set_clock_latency -source -max 0.7 [get_clocks clk] set_clock_latency -max 0.3
[get_clocks clk]
Thời gian chuyển giá trị (0->1, 1->0)/Độ dốc sườn xung đồng hồ
Lệnh đặt transition
5.3.1.2..1.1.1.14 set_clock_transition
5.3.1.2..1.1.1.15 set_clock_transition 0.12 [get_clocks clk]
# The maximum clock transition is 120ps or 0.12ns
Sự thay đổi thời gian đến của các sườn đồng hồ (clock uncertainty)
Độ chênh thời gian lan truyền đồng hồ tới FF_start, FF_stop (Clock skew)
5.3.1.2..1.1.1.16 Độ chênh dương
5.3.1.2..1.1.1.17 Khi sườn bắt đến sau sườn xuất
5.3.1.2..1.1.1.18 Đồng hồ và dữ liệu đi theo cùng hướng
5.3.1.2..1.1.1.19 Độ chênh dương làm vi phạm điều kiện hold
5.3.1.2..1.1.1.20 Độ chênh dương hỗ trợ điều kiện setup
5.3.1.2..1.1.1.21 Độ chênh âm
5.3.1.2..1.1.1.22 Hình vẽ
5.3.1.2..1.1.1.23
Độ chênh xê dịch sườn xung đồng hồ (clock jitter) do nguồn tạo đồng hồ
Phần dự trữ (margin)
Lệnh đặt skew, jitter, margin
5.3.1.2..1.1.1.24 set_clock_uncertainty -setup 0.15 [get_clocks clk]
# The +/-30ps internal clock delay variation to register clock pins results in a 60ps worst case skew or
uncertainty, if you launch
# late (+30ps) and capture early (-30ps)r; Add 40ps due to jitter and 50ps for setup margin;
# This equals 150ps or 0.15 ns of total uncertainty.
Lệnh DC
Khoảng cách giữa 2 sườn bắt và xuất dữ liệu được tín bằng khoảng thời gian ngắn nhất giữa
thời điểm xuất hiện sườn bắt và xuất dữ liệu
=min(t_clk_cap-t_clk_launch)
Nếu 2 FF đều được điều khiển bằng sườn lên (xuống)
t_clk_launch_min = network_latency+source_latency-0.5*uncertainty
t_clk_launch_max = network_latency+source_latency+0.5*uncertainty
t_clk_capture_min = clk_period+network_latency+source_latency-0.5*uncertainty
t_clk_launch_max = clk_period+network_latency+source_latency+0.5*uncertainty
Đối với các thiết kế không dùng clk thì vẫn phải constraint như trên với 1 tín hiệu virtual_clk
5.3.1.3 Thông tin đầu vào/độ trễ đầu vào(input delay)
Là thời gian xuất hiện muộn nhất của tín hiệu tại đầu vào kể từ khi có sườn xuất tương ứng
với nó
Hình vẽ
Ví dụ 5.3.1
Nếu clock có chu kỳ là 2ns và uncertainty là 0.3ns, thời gian trễ tối đa của phần mạch logic tổ
hợp N là?
Tmax=Tclk-Tsetup-Tinput_delay-Tuncertainty=2-0.2-0.6-0.3=0.9ns
Ví dụ 5.3.2
Hình vẽ
Input delay cần đặt bằng bao nhiêu?
Tinput_delay=2.5-1.5-0.1-0.3=0.6ns
Input delay được phần mềm tổng hợp sử dụng để tính toán/tối ưu độ trễ của đường tín hiệu
(PI-REG)
Tmax(PI-REG)=min(t_clk_cap-t_clk_launch)-t_input_delay-t_setup
5.3.1.4 Thông tin đầu ra/độ trễ đầu ra(output delay)
Là thời gian xuất hiện muộn nhất của tín hiệu tại đầu ra trước khi có sườn bắt tương ứng
của nó
Hình vẽ
Ví dụ 5.3.3
Cho chu kỳ đồng hồ là 2ns, uncertainty là 0.3ns, thời gian trễ tối đa của phần tổ hợp S là bao
nhiêu?
Tmax=Tclk-Toutput_delay-Tuncertainty=2-(0.7+0.1)-0.3=0.9ns
Ví dụ 5.3.4
Xác định output delay cho đầu ra B?
Toutput_delay=Tclk-Tmax=2-0.7=1.3
Output delay được phần mềm tổng hợp sử dụng để tính toán/tối ưu độ trễ đường tín hiệu
(REG-PO)
Tmax(REG-PO)=min(Tclk_cap-Tclk_launch)-Toutput_delay
5.3.1.5 Chú ý 1: Để xác định input, output delay cần xác định rõ thời điểm của sườn xuất và
sườn bắt dữ liệu
5.3.1.6 Chú ý 2: Để giảm bớt thông tin đầu vào/đầu ra dùng output bằng FF
input delay = max FF delay
output delay = clock period - min FF delay
5.3.1.7 Chú ý 3: Giới hạn đường tín hiệu tổ hợp
Cho chu kỳ đồng hồ là 2ns, uncertainty là 0.3
Xác định input delay, output delay cho B và D
Tinput_delay(B)=Tmax(E)=0.4ns
Toutput_delay(D)=Tsetup+Tmax(G) =0.1+0.2=0.3
Xác định độ trễ tối đa của F
Tmax(F)=Tclk-Tinput_delay(B)-Toutput_delay(D)-Tuncertainty =2-0.4-0.3-0.3=1
5.3.1.8 Chú ý 4: Nếu mạch thiết kế là hoàn toàn logic tổ hợp
Để giới hạn thời gian cần tạo ra một đồng hồ ảo
Không gắn với tên một tín hiệu cụ thể trong mạch
Ví dụ
Hình vẽ
5.3.1.9 Lệnh của Design Compiler
5.3.2 5.3.2. Giới hạn luật thiết kế
5.3.2.1 Các tham số tính toán thời gian(Environmental attributes)
Các thông số ảnh hưởng tới độ trễ của cell
Thời gian chuyển giá trị của đầu vào Tinput_r, Tinput_f
Trở kháng kênh dẫn transitor của cổng (R)
Dung kháng tải Cload (đầu ra)
Độ biến thiên quy trình chế tạo: P
Điện áp cung cấp: V
Nhiệt độ hoạt động: T
Giới hạn thời gian chỉ xác định điều kiện cho độ trễ mà không xác định các điều kiện để tính
độ trễ
Chú ý: chỉ cần cung cấp các thông tin cho cổng ở biên của chip (các cổng nối với đầu vào, đầu
ra
5.3.2.2 Hình vẽ minh họa
5.3.2.3 a) Thời gian chuyển giá trị đầu vào/giá trị điện trở cổng đầu kích thích đầu vào
Thời gian chuyển giá trị tại đầu vào sẽ ảnh hưởng tới độ trễ của cổng tại đầu vào
Thời gian chuyển giá trị đầu vào lớn nhất là giới hạn luật thiết kế được quy định trong thư
viện đích (thư viện cell chuẩn)
cell (<cellname>) { cell_leakage_power : 3.748077e-03; threshold_voltage_group : "si38p" ;
area : "8.775" ; …. abc_cell () { … pin (Z) { direction : "output"; } pin (CP) {
direction : "input"; } pin (D) { direction : "input"; } …. } pin (CP) { clock : true;
direction : "input"; related_bias_pin : "VDDB VSSB"; rise_capacitance : 0.001733;
rise_capacitance_range(0.001268,0.002017); capacitance : 0.001706; fall_capacitance :
0.001680; fall_capacitance_range(0.001293,0.001938); max_transition : 0.550; ….. } pin (D)
{ direction : "input"; related_bias_pin : "VDDB VSSB"; rise_capacitance : 0.000752;
rise_capacitance_range(0.000648,0.000960); capacitance : 0.000741; fall_capacitance :
0.000730; fall_capacitance_range(0.000638,0.000875); max_transition : 0.800;
related_power_pin : "VDD"; related_ground_pin : "VSS"; ….. }
Hình vẽ
Nếu là đầu vào của vi mạch
Thường là 1 giá trị tuyệt đối, cho trong specification của chip
set_input_transition 0.12 [get_ports A]
Nếu là đầu vào của một module trong chip
Có thể xác định thông qua điện trở ra (kênh) của cổng kích thích đầu vào đang xét
Lệnh DC
set_driving_cell -lib_cell OR3B [get_ports A]
set_driving_cell -lib_cell FD1 -pin Qn [get_ports A]
set_driving_cell -lib_cell tên_cell -pin tên_pin -library tên_lib [get_ports tên_port]
5.3.2.4 b) Điện dung tải ở đầu ra
Điện dung tải đầu ra sẽ ảnh hưởng tới thời gian chuyển giá trị của tín hiệu ra=> ảnh hưởng
tới độ trễ của mạch
Tải đầu ra càng lớn thì mạch càng chậm
Hình vẽ
Nếu là đầu ra của chip
Được cho trong specification của chip và là giá trị tuyệt đối
Lệnh DC
set_load [expr 30.0/1000] [get_ports B]
Nếu là đầu ra của module
Được xác định bằng số lượng cổng tối đa mà đầu ra đó sẽ kích thích
Hình vẽ
Lệnh DC
set_load [expr [load_of my_lib/inv1a0/A]*3] [get_ports B]
my_lib/inv1a0/A= tên thư viện/tên_cell/tên_pin
5.3.2.5 Chú ý: Khi các cổng kích thích đầu vào và tải đầu ra chưa biêt
Dùng Load Budget,xác định dự phòng cho thiết kế
Giả sử các đầu vào được kích thích bằng cell yếu nhất
set_driving_cell -no_design_rule -lib_cell inv1a1 $all_in_ex_clk
set all_in_ex_clk [remove_from_collection [all_inputs] [get_ports clk]
mỗi thư viện sẽ qui định 1 rule thiết kế riêng -no_design_rule là để tạm thời dc sẽ
không check rule
Đặt điện dung đầu vào lớn nhất là 10 cell and2
set MAX_INPUT_LOAD [expr load_of my_lib/and2a1/A] * 10] set_max_capacitance
$MAX_INPUT_LOAD $all_in_ex_clk
Đặt điện dung đầu ra lớn nhất là 3 khối 10 cell
set_load [expr $MAX_INPUT_LOAD * 3] [all_outputs]
Hình vẽ
Khi đầu vào được kích thích bằng FF, và đầu ra sẽ kích thích FF
Cổng kích thích đầu vào sẽ là pin Q/Qn của FF
Cổng tải đầu ra sẽ là pin D của FF
5.3.2.6 c) Điều kiện nhiệt độ/điện áp/công nghệ chế tạo
Chỉ ra trong file target_library
list_libs
Xem các file db đã được nạp
Xác định tên của thư viện.VD : cb13fs120_tsmc_max
report_lib
Xem các thông số trong 1 thư viên
Sử dụng lệnh để xuất ra file report
redirect -file lib.rpt { report_lib tên_thưuviện}
sh gedit lib.rpt
set_operating_conditions
Đặt thông số PVT trong thư viên
Xem phần operating conditions trong file lib.rpt
set_operating_conditions -max cb13fs120_tsmc_max
Hình vẽ
5.3.2.7 d) RC ký sinh trên đường dây nối
phụ thuộc kích thước thiết kế(chiều dài dây nối)
5.3.2.8 Tổng kết lệnh
5.3.3.3 MY_DESIGN.con
###################################
# #
# UNITS #
# #
###################################
# The unit of time in this library is 1ns
# The unit of capacitance in this library is 1pF
#
###################################
# #
# CLEAN-UP #
# #
###################################
# Remove any existing constraints and attributes
#
reset_design
###################################
# #
# CLOCK DEFINITION #
# #
###################################
# A 333Mhz clock is a 3.0ns period:
#
create_clock -period 3.0 [get_ports clk]
# External clock source latency is 700ps or 0.7ns
#
set_clock_latency -source -max 0.7 [get_clocks clk]
# The maximum internal clock network insertion delay or latency is 300ps or 0.3 ns:
#
set_clock_latency -max 0.3 [get_clocks clk]
# The +/-30ps internal clock delay variation to register clock pins results in a 60ps worst case skew or
uncertainty, if you launch
# late (+30ps) and capture early (-30ps)r; Add 40ps due to jitter and 50ps for setup margin;
# This equals 150ps or 0.15 ns of total uncertainty.
#
set_clock_uncertainty -setup 0.15 [get_clocks clk]
# uncertainty = 190ps
# The maximum clock transition is 120ps or 0.12ns
#
set_clock_transition 0.12 [get_clocks clk]
###################################
# #
# INPUT TIMING #
# #
###################################
# The maximum "input delay" (external) on ports data1 and data2 is:
# clock period - clock uncertainty - delay of S - register setup time =
# Wrong: 3.0 - 0.15 - 2.2 - 0.2 = 0.45ns
# Right: 3.0 - 0.19 - 2.2 - 0.2 = 0.41ns
set_input_delay -max 0.45 -clock clk [get_ports data*]
# The latest arrival time at port sel is ds1.4ns (absolute time). The total clock insertion delay or latency to the
external
# registers is 700ps + 300ps or 1.0ns. Therefore, the relative input delay on the port is 1.4 -1.0 = 0.4ns
#
set_input_delay -max 0.4 -clock clk [get_ports sel]
###################################
# #
# OUTPUT TIMING #
# #
###################################
# The output delay at port out1 is 420ps + 80ps = 500ps or 0.5ns
#
set_output_delay -max 0.5 -clock clk [get_ports out1]
# The internal delay to out2 is 810ps. The external capturing clock edge happens 3ns after the launch edge,
# minus the uncertainty of 0.15ns, or 2.85ns after launch. To constrain the internal delay to 0.81ns the
# output delay must therefore be constrained to 2.85ns - 0.81ns = 2.04ns.
#
set_output_delay -max 2.04 -clock clk [get_ports out2]
# The setup time requirement on port out3 is 400ps or 0.4ns with respect to the capturing register's clock.
# This is, by definition, the "set_output_delay" value
#
set_output_delay -max 0.4 -clock clk [get_ports out3]
###################################
# #
# COMBINATIONAL LOGIC TIMING #
# #
###################################
# The maximum delay through the combinational logic is 2.45ns. This can be constrained by pretending that
there are
# launching registers on the input ports Cin1 and Cin2 and capturing registers on the output port Cout, and
applying
# corresponding input and output delays. The sum of the external input and output delay values must be equal
to the
# clock period minus the clock uncertainty minus the maximum combo delay = 3ns - 0.15ns - 2.45ns = 0.4ns.
# This means that the input and output delay values can be 0.4 and 0.0, or 0.2 and 0.2, or 0.1 and 0.3, etc.,
respectively.
#
set_input_delay -max 0.3 -clock clk [get_ports Cin*]
set_output_delay -max 0.1 -clock clk [get_ports Cout]
###################################
# #
# ENVIRONMENTAL ATTRIBUTES #
# #
###################################
# All input ports, except clk and Cin, are driven by bufbd1 buffers
#
set_driving_cell -lib_cell bufbd1 -library cb13fs120_tsmc_max \
[remove_from_collection [all_inputs] [get_ports "clk Cin*"]]
# Port Cin is a chip level input and has an input transition of 120ps or 0.12 ns
#
set_input_transition 0.12 [get_ports Cin*]
# All outputs, except Cout, drive 2x bufbd7 loads
#
set_load [expr 2 * {[load_of cb13fs120_tsmc_max/bufbd7/I]}] [get_ports out*]
# Cout drives 25fF, or .025 pF
#
set_load 0.025 [get_ports Cout*]
# operating condition use to scale cell and net delays.
#
set_operating_conditions -max cb13fs120_tsmc_max
5.4 5.4. Cơ sở quá trình tổng hợp
5.4.1 5.4.1 Quá trình tổng hợp
5.4.1.1 Hình vẽ
5.4.1.2 B1: Tổng hợp mức kiến trúc (mức cao)
5.4.1.3 B2: Tổng hợp mức logic không phụ thuộc công nghệ
5.4.1.4 B3: Tổng hợp mức cổng và ánh xạ công nghệ
5.4.1.5 Thuật toán tổng hợp tìm cách tối thiểu hóa diện tích trong khi thỏa mãn các điều
kiện giới hạn thời gian và các điều kiện khác
Tìm mạch có hiệu năng (tốc độ) vừa đủ và có diện tích nhỏ nhât
5.4.1.6 Để đạt được kết quả tổng hợp tốt
Code RTL được viết tốt, tối ưu cho phần mềm tổng hợp (Xem chương 6)
Code RTL tuân theo kiểu viết code của DC và phụ thuộc kinh nghiệm
Thuật toán được viết hiệu quả với phần cứng
Các điều kiện giới hạn được đặt đủ, và chính xác
Các điều kiện giới hạn và tính chất môi trường đặt thực tế, không quá chặt
Tất cả các đường tín hiệu được xác định
5.4.2 5.4.2. Một số kỹ thuật tổng hợp
5.4.2.1 Tối ưu phép toán số học
Tối giản hằng số và toán hạng
A+2*B-2+B-A+7 = 3*B + 5
Chia sẻ các biểu thức con
Z1 = A+B+C; Z2=C+D+B=> T=B+C; Z1=A+T;Z2=T+D;
Biến đổi SOP thành POS
A*C+B*C=(A+B)*C
Chia sẻ biểu thức so sánh
Z1=A>B;Z2=A<B;Z3=A<=B;
Dùng một bộ trừ
Tối ưu các phép nhân với hằng số
Temp =In1+In2; Out1=Temp*105 (64+32+8+1) Out2=Temp*621 (105+512+4) Out1 =
Temp<<6 + Temp<<5+Temp<<3+Temp Out2 = Out1+Temp<<9+Temp<<2
5.4.2.2 Chia sẻ tải và nhân bản cổng logic
Trước tối ưu
Sau tối ưu
Nhân bản các cổng logic điều khiển (kích thích) nhiều đầu ra và nằm trên đường tín hiệu
chậm nhất sẽ giúp giảm tải của cổng logic và tăng tốc độ đường tín hiệu chậm nhất
5.4.2.3 Tối ưu qua đường biên
Trước tối ưu
Sau tối ưu
Lan truyền hằng số, các cổng không kết nối, các bộ đảo để giảm trễ hoặc/và diện tích
5.4.2.4 Định thời thích nghi (Adaptive Retiming)
Trước
Sau
Retiming: thay đổi thời gian hoạt động của các tín hiệu bên trong mạch bằng cách di chuyển
các thanh ghi
Chú ý: Retiming không được làm thay đổi thời gian hoạt động của tín hiệu đầu vào/đầu ra
5.4.2.5 Định thời thanh ghi (Register Retiming)
always @(posedge clk) y <= a*b+c*d+e-f
Tổng hợp
Sử dụng thanh ghi pipeline
always @(posedge clk) begin prodAB <= a*b; prodCD <= c*d; diffEF <= e-f; p2_1 <=
prodAB+prodCD; p2_2 <= diffEF; y <= p2_1+p2_2;
Tổng hợp
Độ trễ là độ trễ của giai đoạn pipeline chậm nhất (bộ nhân)
5.5 5.5. Phân tích kết quả tổng hợp
5.5.1 Kiểm tra sự vi phạm điều kiện thời gian
5.5.1.1 Xem xét các đường tín hiệu có slack <0
5.5.2 Sử dụng các kỹ thuật Timing Analysis
5.5.2.1 Tham khảo thêm tài liệu của Synopsys
5.6 Bài tập ví dụ
5.6.1 Thiết kế và tổng hợp vi mạch tuân theo chỉ tiêu kỹ thuật của chip: Cd54hc192
6 Chương 6. Nâng cao
6.1 6.1. Các bộ đếm, dịch, quay
6.1.1 6.1.1 Bộ đếm
6.1.1.1 Hình vẽ
6.1.1.2 Mã
module cnt(clk,rst_n,en,cnt); input clk,rst_n; output [7:0] cnt; reg [7:0] cnt; always
@(posedge clk or negedge rst_n) if (!rst_n) cnt <= 8’h00; else if (en) cnt <= cnt + 1; //
combinational endmodule
6.1.1.3 Kết quả tổng hợp
6.1.2 6.1.2 Bộ đếm vòng
6.1.2.1 Mã
module ring_counter (count, enable, clock, reset_n); output reg [7: 0] count; input enable,
reset, clock; always @ (posedge clock or negedge reset_n) if (!reset_n) count <=
8'b0000_0001; else if (enable == 1'b1) count <= {count[6:0], count[7]}; endmodule
6.1.2.2 Kết quả tổng hợp
6.1.3 6.1.3 Bộ quay
6.1.3.1 Mã
module rotator (Data_out, Data_in, load, clk, rst_n); output reg [7: 0] Data_out; input [7: 0]
Data_in; input load, clk, rst_n; always @ (posedge clk or negedge rst_n) if (!rst_n) Data_out <=
8'b0; else if (load) Data_out <= Data_in; else if (en) Data_out <= {Data_out[6: 0], Data_out[7]};
else Data_out <= Data_out endmodule
6.1.3.2 Kết quả tổng hợp
6.1.4 6.1.4 Bộ dịch
6.1.4.1 Mã
always @ (posedge clk) begin if (rst) Data_Out <= 0; else case (select[1:0]) 2’b00:
Data_Out <= Data_Out; // Hold 2’b01: Data_Out <= {Data_Out[3], Data_Out[3:1]}; // ÷ by 2
2’b10: Data_Out <= {Data_Out[2:0], 1’b0}; // X by 2 2’b11: Data_Out <= Data_In; // Parallel
Load endcase end endmodule
6.1.4.2 Kết quả tổng hợp
6.1.5 6.1.5 Tham số hóa
6.1.5.1 parameter
Định nghĩa hằng số bên trong module
Có thể truyền như 1 tham số khi instantiate module
6.1.5.2 localparam
Định nghĩa hằng số trong module
Không truyền như tham số khi instantiate module
6.1.5.3 Ví dụ 6.1.5
Mã
module adder(a,b,cin,sum,cout); parameter WIDTH = 8; // default is 8 input [WIDTH-1:0] a,b;
input cin; output [WIDTH-1:0] sum; output cout; assign {cout,sum} = a + b + cin endmodule
module alu(src1,src2,dst,cin,cout); input [15:0] src1,src2; …
////////////////////////////////// // Instantiate 16-bit adder //
//////////////////////////////// adder #(16) add1(.a(src1),.b(src2),
.cin(cin),.cout(cout), .sum(dst)); … endmodule
6.1.5.4 Ví dụ 6.1.6
Mã
module register2001 #(parameter SIZE=8) (output reg [SIZE-1:0] q, input [SIZE-1:0] d, input
clk, rst_n); always @(posedge clk, negedge rst_n) if (!rst_n) q <= 0; else q <= d; endmodule
6.2 6.2. Mô tả máy trạng thái hữu hạn FSM
6.2.1 6.2.1. Khái niệm FSM
6.2.1.1 Hình vẽ
6.2.1.2 FSM được triển khai bằng mạch logic tuần tự gồm 2 khối cơ bản
Khối logic tổ hợp mô tả hàm trạng thái kế tiếp và hàm đầu ra
Khối FF lưu trữ trạng thái hiện tại của mạch
6.2.1.3 FSM được mô tả hoạt động bằng đồ thị chuyển trạng thái hoặc bảng chuyển trạng
thái
6.2.2 6.2.2. Mô tả FSM trong Verilog
6.2.2.1 Mô tả logic tổ hợp và FF riêng rẽ
6.2.2.2 Logic tổ hợp được mô tả bằng khối always và phép gán blocking
Thường sử dụng kèm lệnh case, trong đó mỗi case item là 1 trạng thái
6.2.2.3 FF được mô tả bằng khối always có clock và phép gán non-blocking
6.2.2.4 Chú ý: tránh latch
Khối case luôn cần nhánh default
Có thể gán giá trị mặc định cho đầu ra và thanh ghi trạng thái kế tiếp trước khối case, if/else
6.2.3 Ví dụ 6.2.1
6.2.3.1 Hình vẽ
6.2.3.2 Mã 1
module fsm(clk,rst,a,b,Y,Z); input clk,rst,a,b; output Y,Z; reg Y, Z; localparam S0 = 2'b00,
S1 = 2'b01, S2 = 2'b10; reg [1:0] state,nxt_state; always @(posedge clk, posedge rst) if
(rst) state <= S0; else state <= nxt_state; always @ (state,a,b) case (state) S0 : if (a) begin
nxt_state = S1; Z = 1; end else nxt_state = S0; S1 : begin Y=1;
if (b) begin nxt_state = S2; Z=1; end else nxt_state = S1; end
S2 : nxt_state = S0; endcase endmodule
6.2.3.3 Kết quả tổng hợp
6.2.3.4 Mã 2
6.2.4 6.2.3. Mô tả các máy trạng thái tương tác với nhau
6.2.4.1 Ví dụ khi cần đợi ở một trạng thái trong khoảng thời gian xác định
Máy trạng thái tương tác với bộ đếm
6.2.4.2 Đầu ra của một FSM được dùng để điều khiển một FSM khác và ngược lại.
Thường sử dụng kiểu liên lạc bắt tay
6.2.4.3 Ví dụ 6.2.2
Đồ thị chuyển trạng thái
Biểu đồ thời gian toàn mạch
Biểu đồ thời gian tương tác giữa FSM và bộ đếm
Sơ đồ khối mạch
Mã
module eeprom(clk,rst_n,wrt_eep, wrt_data,eep_r_w_n,eep_cs_n, eep_bus,chrg_pmp_en);
parameter IDLE=2'b00, BUS=2'b01, CHRG=2'b10; input clk,rst_n,wrt_eep; input [11:0] wrt_data; //
data to write output eep_r_w_n,eep_cs_n; output chrg_pmp_en; // hold for 3ms inout [11:0] eep_bus;
wire eep_r_w_n,eep_cs_n; reg chrg_pmp_en; // hold for 3ms reg [13:0] tm; // 3ms => 14-bit timer
reg clr_tm,inc_tm,bus_wrt; reg [1:0] state,nxtState; //// implement 3ms timer below //// always
@(posedge clk or posedge clr_tm) if (clr_tm) tm <= 14'h0000; else if (inc_tm) tm <= tm+1; ////
@4MHZ cnt of 2EE0 => 3ms //// assign tm_eq_3ms = (tm==14'h2EE0)?1'b1 : 1'b0; //// implement
state register below //// always @(posedge clk or negedge rst_n) if (!rst_n) state <= IDLE; else
state <= nxtState; //// state transition logic & //// //// output logic //// always
@(state,wrt_eep,tm_eq_3ms) begin nxtState = IDLE; // default all bus_wrt = 0; // to avoid
clr_tm = 0; // unintended inc_tm = 0; // latches chrg_pmp_en = 0; case (state)
IDLE : if (wrt_eep) nxtState = BUS; BUS : begin clr_tm = 1; bus_wrt = 1; nxtState =
CHRG; end default : begin // is CHRG inc_tm = 1; chrg_pmp_en=1; if (tm_eq_3ms)
begin nxtState = IDLE; end else nxtState = CHRG; end endcase end
assign eep_r_w_n = ~bus_wrt; assign eep_cs_n = ~bus_wrt; assign eep_bus = (bus_wrt) ? wrt_data :
12'bzzz; endmodule
Kết quả tổng hợp
Mạch
6.2.5 6.2.4. Thiết kế mạch điều khiển và đường dữ liệu: FSMD/ASMD
6.2.5.1 Các mạch xử lý tín hiệu (ví dụ trong thông tin/viễn thông) cần xử lý và dịch chuyển
một lượng lớn dữ liệu bằng các phép toán lặp đi lặp lại
6.2.5.2 Các mạch tuần tự xử lý dữ liệu thường được chia làm hai phần
Đường dữ liệu
Bao gồm các tài nguyên tính toán (như bộ cộng, nhân, dịch...) các thanh ghi lưu trữ dữ liệu,
các khối logic dùng để dịch chuyển dữ liệu giữa các khối tính toán, thanh ghi, và môi trường
Đường dữ liệu thực hiện các thao tác tính toán lặp lại trên các bộ dữ liệu khác nhau
Được mô tả bằng đồ thị dòng dữ liệu thể hiện các bước tính toán tuần tự dữ liệu
Khối điều khiển
Làm một FSM thực hiện việc điều phối các thao tác tính toán trong đường dữ liệu
Thực hiện việc điều phối, đồng bộ hoạt động của đường dữ liệu (hoạt động của các
khối chức năng trong đường dữ liệu)
Tạo ra các tín hiệu nạp, đọc, dịch chuyển nội dung các thanh ghi
Đọc lệnh/dữ liệu từ bộ nhớ
Ghi dữ liệu vào bộ nhớ
Điều hướng dữ liệu qua các bộ mux
Điều khiển các cổng 3 trạng thái
Điều khiển hoạt động của khối ALU hay các khối xử lý dữ liệu phức tạp
Được mô tả bằng đồ thị chuyển trạng thái, hoặc Algorithmic-State Machine
Hình vẽ
6.2.5.3 Phân chia mạch thành 2 phần giúp làm rõ kiến trúc và đơn giản hóa việc thiết kế
6.2.5.4 FSMD, ASMD được dùng để miêu tả hoạt động của thiết kế được chia thành 2 phần
đường dữ liệu và khối điều khiển
FSMD là sự kết hợp của đồ thị chuyển trạng thái STG và đồ thị dòng dữ liệu
Trong FSMD, các hoạt động của đường dữ liệu được thể hiện trên các đường chuyển trạng
thái
ASM là dạng đặc biệt của lưu đồ thuật toán
Gồm các khối kết nối với nhau. Mỗi khối gồm 3 node
Trạng thái: Thể hiện trạng thái của mạch
Quyết định: Thể hiện điều kiện chuyển trạng thái của mạch phụ thuộc đầu vào
Điều kiện: Thể hiện đầu ra của mạch
Hình vẽ
ASMD được tạo ra từ ASM bằng cách gắn các hoạt động của đường dữ liệu với các đường nối
giữa các trạng thái. Các hoạt động này xảy ra khi phần điều khiển chuyển từ trạng thái này sang
trạng thái khác tương ứng
6.2.5.5 Các bước để thiết kế mạch điều khiển và đường dữ liệu
Đầu vào: Lưu đồ thuật toán mô tả hoạt động của mạch
Đầu ra: Kiến trúc đường dữ liệu và ASMD mô tả hoạt động của đường dữ liệu và khối điều
khiển
B1: Thiết kế đường dữ liệu
B1a) Xác định các phép toán (hoạt động) của đường dữ liệu dựa trên các phép toán có trong
lưu đồ thuật toán
B1b) Xác định các khối chức năng phần cứng cần có để thực hiện các phép toán
B1c) Kết nối các khối chức năng phần cứng thành đường dữ liệu thể hiện dòng dịch chuyển
của dữ liệu cần được xử lý như lưu đồ thuật toán
B1d) Xác định đầu vào điều khiển và đầu ra trạng thái của đường dữ liệu
B2: Thiết kế khối điều khiển
B2a) Chuyển đổi lưu đồ thuật toán thành ASM
B2b) Gắn các hoạt động của đường dữ liệu với ASM
6.2.5.6 Ví dụ 6.2.2
Thiết kế bộ đếm up/down dùng FSMD
6.2.5.7 Ví dụ 6.2.3
Thiết kế bộ nhân nối tiếp
Mã
module serial_mult #(parameter n=8) (input clk, rst_n, input load, input [n-1:0] a, input [n-
1:0] b, output [2*n-1:0] c); wire b0, adder_control, load_control, compute_control; wire [n-1:0] i;
data_unit #(.n(n)) datapath (.clk(clk), .rst_n(rst_n), .a(a), .b(b), .c(c),
.load_control(load_control), .adder_control(adder_control), .compute_control(compute_control),
.i(i), .b0(b0) ); control_unit #(.n(n)) control (.clk(clk), .rst_n(rst_n), .load(load), .b0(b0),
.i(i), // status signal from datapath .load_control(load_control), // control signal to datapath
.adder_control(adder_control), .compute_control(compute_control) ); endmodule module
data_unit #(parameter n=8) (input clk, rst_n, input [n-1:0] a, b, output reg [2*n-1:0] c, input
load_control, adder_control, compute_control, output b0, output reg [n-1:0] i ); reg [n-1:0] Rb; reg
[n-1:0] Ra; reg [2*n:0] tmp; reg carry; assign b0 = Rb[0]; assign tmp = (adder_control==1)?(c[2*n-
1:n]+Ra):c; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin Ra <= 0; Rb <= 0; c <=
0; i <= 0; carry <= 0; end else begin if (load_control) begin Ra[n-1:0] <= a; Rb <= b; i <= 0;
c <= 0; carry <= 0; end else begin if (compute_control) begin Rb <= {1'b0, Rb[n-1:1]}; // dich
phai Rb c <= {tmp[2*n:1]}; // dich phai tmp i <= i+1; end end end end endmodule module
control_unit # (parameter n=8) ( input clk, rst_n, input load, input [n-1:0] i, input b0, output reg
load_control, adder_control, compute_control); localparam idle = 1'b0; localparam computing =
1'b1; reg current_state, next_state; always @(posedge clk or negedge rst_n) begin if (!rst_n)
current_state <= idle; else current_state <= next_state; end always @(current_state, load, i, b0)
begin next_state = idle; load_control = 0; adder_control = 0; compute_control = 0; case
(current_state) idle: if (load) begin next_state = computing; load_control = 1; end
computing: if (i==n) next_state = idle; else begin compute_control = 1; adder_control = b0;
next_state = computing; end endcase end endmodule
6.3 6.3. Các câu lệnh nâng cao
6.4 6.4. Hướng dẫn code của phần mềm tổng hợp Synopsys
6.4.1 Các kiểu viết code khác nhau sẽ cho kết quả tổng hợp khác nhau
6.4.2 Phần mềm tổng hợp không thể tự tối ưu mã nguồn RTL tồi
6.4.3 Hiểu cách phần mềm tổng hợp biên dịch mã RTL sẽ giúp có được kết quả tổng hợp
tốt
6.4.4 6.5.1. Dùng chung tài nguyên
6.4.4.1 Phần mềm tổng hợp có thể sử dụng 1 bộ tài nguyên số học cho các câu lệnh trong
if/case để đạt được thiết kế nhỏ nhất mà vẫn thỏa mãn điều kiện thời gian
6.4.4.2 Tối ưu tài nguyên dùng chung được thực hiện khi tối ưu mức kiến trúc.
6.4.4.3 Việc quyết định có chia sẻ hay không tài nguyên phụ thuộc
Cách viết code
Chỉ các phép toán trong cùng if/case có thể chia sẻ tài nguyên
Giới hạn
Chia sẻ tài nguyên chỉ xảy ra khi không vi phạm điều kiện giới hạn thời gian
6.4.4.4 Ví dụ:
Mã
Kết quả tổng hợp
6.4.4.5 Có thể viết mã để không cho phép hoặc luôn yêu cầu chia sẻ tài nguyên
6.4.5 6.5.2. Thay đổi thứ tự toán hạng
6.4.5.1 Phần mềm tổng hợp có thể thay đổi thứ tự thực hiện phép toán để thỏa mãn giới
hạn thời gian
Thứ tự sẽ không thay đổi nếu sử dụng dấu ngoặc đơn để bắt buộc thứ tự thực hiện
6.4.5.2 Ví dụ
Mã
Kết quả tổng hợp
6.4.6 6.5.3. For loop
7 Các kiến thức cần thiết
7.1 Lập trình Verilog
7.1.1 Mạch logic tổ hợp
7.1.1.1 always
7.1.1.2 If else
7.1.1.3 Assign
blocking, non-blocking assignment
7.1.1.4 Độ trễ trong mạch logic tổ hợp
7.1.2 Mạch tuần tự
7.1.2.1 always with clock
7.1.2.2 reset
7.1.2.3 case
7.1.2.4 Moore/Mealy
7.1.2.5 Setup/Hold time
7.1.2.6 Xác định tần số đồng hồ
7.1.2.7 Flip-Flop
7.1.3 Lập trình FSMD/ASM
7.2 Tổng hợp mạch (Synthesis)
7.2.1 Cấu trúc ASIC
7.2.1.1 Tổng hợp ra gate netlist dùng Synopsys
7.2.1.2 Phân tích timing
7.2.2 Cấu trúc FPGA
7.2.2.1 Tổng hợp mạch lên board Altera DE2
7.2.2.2 Kết nối mạch Altera DE2 với Simulink/Matlab
7.2.3 Các thuật toán tổng hợp mạch cơ bản
7.2.4 Khái niệm timing
7.2.5 Khái inệm Datapath optimization khi dùng HDL và khi synthesis
7.3 Layout mạch
7.3.1 Cấu trúc CMOS
7.3.2 Clock tree
7.3.3 Standard cell
7.3.4 Power supply
8 Mục đích môn học
8.1 Thiết kế mạch số dùng ngôn ngữ mô tả phần cứng Verilog HDL
8.2 Xây dựng testbench tự kiểm tra thiết kế phần cứng
8.2.1 Mô phỏng HDL
8.2.2 Kiểm chứng thiết kế số
8.3 Tông hợp dòng dữ liệu và thiết kế hành vi (behavior)
8.4 Khái niệm cơ bản về phân tích thời gian (Timing analysis)
8.5 Tối ưu thiết kế phần cứng (thời gian, diện tích, năng lượng)
8.6 Suy nghĩ kiểu phần cứng!!!
9 Yêu cầu kiến thức
9.1 Biểu diễn số
9.1.1 Nhị phân, hệ 16
9.1.2 Có dấu
9.1.2.1 Mã bù 2
9.1.3 Không dấu
9.2 Đại số Bool
9.3 Thiết kế mạch ở mức cổng logic
9.3.1 Tối ưu mạch bằng bìa Karnaugh
9.4 Máy trạng thái hữu hạn (FSM)
9.4.1 Máy More
9.4.2 Máy Mealy
9.4.3 Triển khai máy trạng thái hữu hạn bằng logic tổ hợp
9.4.3.1 Phương pháp tối ưu máy bằng cách tìm trạng thái tương đương
9.4.3.2 Phương pháp mã hóa trạng thái
10 Tài liệu tham khảo
10.1 Advanced Digital Design Verilog HDL, Michael D. Ciletti.
10.2 IEEE Standard Verilog Hardware Description Language, IEEE, Inc., 2001
10.3 IEEE Standard for Verilog Register Transfer Level Synthesis, IEEE, Inc.,
2002
10.4 Digital Design and Computer Architecture, David Money Harris
10.5 Bài giảng của Eric Hoffman
11 Công cụ phần mềm thực hành
11.1 Modelsim HDL Simulation Tools (Mentor)
11.1.1 http://model.com/content/modelsim-pe-student-edition-hdl-simulation
See document(s): modelsim-pe-student-edition-hdl-simulation
11.2 Công cụ tổng hợp IC: Synopsys - Design Compiler
11.3 Công cụ tổng hợp FPGA: Quartus II Web Edition Software
11.3.1 https://www.altera.com/download/software/quartus-ii-we
See document(s): quartus-ii-we
top related