Thiết kế và tổng hợp hệ thống số 2012 (C)
nguyenducminh@edabk.org
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 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
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
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
1.3 1.3. Lưu đồ thiết kế hệ thống số dùng ngôn ngữ mô tả phần cứng
1.3.1 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
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 pipelined1.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 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
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
And
Or
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
Hình vẽ bộ MUX 2-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
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ụ
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
Loại trừ ành hưởng của hazards Đợi đến khi đầu ra ổn định
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
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ẽ
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
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
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.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
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 Verilog3.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ẽ
and not 3 trạng thái
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úc3.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
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)
*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
* 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.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
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
* 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
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: |
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;
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
Đầ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 chung3.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ồ
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
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)
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
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
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;
Ứ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