Nội dung giáo trình được bố cục bao gồm 7 bài với nội dung như sau:
Bài 1: Giới thiệu chung về PLD, CPLD và FPGA
Bài 2: Họ CPLD
Bài 3: Họ FPGA
Bài 4: Qui trình thiết kế cho CPLD và FPGA của hãng Xilinx
Bài 5: Phần mềm ISE và modelsim
Bài 6: Ngôn ngữ Verilog HDL
Bài 7: Mốt số chương trình ứng dụng
262 trang |
Chia sẻ: phuongt97 | Lượt xem: 470 | Lượt tải: 0
Bạn đang xem trước 20 trang nội dung tài liệu Giáo trình Vi mạch số lập trình - Lê Văn Hiền, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
phù hợp thì câu lệnh hay khối lệnh tương ứng sẽ được thực thi. Nếu không có alternative nào thích hợp thì lệnh default_statement được thực hiện, đó là tùy chọn không bắt buộc, không đặt nhiều lệnh mặc định này vào một câu lệnh case. Lệnh case có thể được lồng vào nhau.
Ví dụ:
reg [1:0] alu_control;
...
...
case (alu_control)
2'd0 : y = x + z;
2'd1 : y = x - z;
2'd2 : y = x * z;
default : $display("Invalid ALU control signal");
endcase
Lệnh case hoạt động như một bộ trộn, vì thế việc hiện thực bộ trộn với lệnh case rất dễ dàng.
Ví dụ:
module mux4_to_1 (out, i0, i1, i2, i3, s1, s0);
// Khai báo các IO
output out;
input i0, i1, i2, i3;
input s1, s0;
reg out;
always @ (s1 or s0 or i0 or i1 or i2 or i3)
case ({s1, s0}) //Lựa chọn tín hiệu dựa trên tập hợp s1, s0
2'd0 : out = i0;
2'd1 : out = i1;
2'd2 : out = i2;
2'd3 : out = i3;
default: $display("Invalid control signals");
endcase
endmodule
Lệnh case so sánh các giá trị 0, 1, x và z trong biểu thức với các alternative theo bit với bit. Nếu biểu thức và alternative có độ rộng không bằng nhau, những số 0 sẽ được thêm vào để đạt được độ rộng lớn nhất trong chúng. Ta xem xét ví dụ sau đây là một bộ demultiplexer với những ngõ ra hoàn toàn được xác định, sự lựa chọn đều được thực hiện, dù trong tín hiệu có giá trị x và z.
Ví dụ:
module demultiplexer1_to_4 (out0, out1, out2, out3, in, s1, s0);
// Khai báo các IO
output out0, out1, out2, out3;
reg out0, out1, out2, out3;
input in;
input s1, s0;
always @(s1 or s0 or in)
case ({s1, s0}) //chọn lựa dựa trên tín hiệu điều khiển
2'b00 : begin
out0 = in; out1 = 1'bz; out2 = 1'bz; out3 = 1'bz;
end
2'b01 : begin
out0 = 1'bz; out1 = in; out2 = 1'bz; out3 = 1'bz;
end
2'b10 : begin
out0 = 1'bz; out1 = 1'bz; out2 = in; out3 = 1'bz;
end
2'b11 : begin
out0 = 1'bz; out1 = 1'bz; out2 = 1'bz; out3 = in;
end
/* dù cho tín hiệu được chọn là không xác định, nếu chọn vào là x thì ra là x, vào là z thì ra là z. Nếu một là x, một là z thì lựa chọn x có mức ưu tiên cao hơn */
2'bx0, 2'bx1, 2'bxz, 2'bxx, 2'b0x, 2'b1x, 2'bzx :
begin
out0 = 1'bx; out1 = 1'bx; out2 = 1'bx; out3 = 1'bx;
end
2'bz0, 2'bz1, 2'bzz, 2'b0z, 2'b1z :
begin
out0 = 1'bz; out1 = 1'bz; out2 = 1'bz; out3 = 1'bz;
end
default: $display("Unspecified control signals");
endcase
endmodule
Từ khóa casex, casez:
Hai sự thay đổi trong lệnh case, chúng bao hàm nghĩa trong từ khóa casex và casez.
Casez xem như tất cả các giá trị z trong các alternative hoặc biểu thức như tùy định. Tất cả các bit z có thể được thể hiện bằng “?”.
Casez xem tất cả các giá trị x và z như tùy định.
Sử dụng casex hoặc casez chỉ cho phép so sánh ở những vị trí không phải x hoặc z.
Ví dụ:
casex (a)
2’b1x: msb = 1; // msb=1 nếu a=10 hoặc a=11
default:msb=0;
endcase
casez(d)
3’b1??: b = 2’b11; // b = 11 nếu d = 100 hoặc lớn hơn
3’b01?: b = 2’b10; // b = 10 nếu d = 010 hoặc 011
default: b = 2’b00;
endcase
Các vòng lặp (while, for, repeak, forever):
Có bốn loại cấu trúc vòng lặp trong verilog là: while, for, repeat và forever. Cú pháp của các vòng lặp rất giống với ngôn ngữ C. Tất cả các lệnh lặp chỉ xuất hiện trong khối initial và always, và chúng có thể chứa định thời trễ.
Vòng lặp While:
Từ khóa while được sử dụng để chỉ vòng lặp này, vòng lặp while được thực hiện cho đến khi biểu thức không còn đúng.
while (expression)
begin
... statements ...
end
Nếu biểu thức không đúng thì vòng lặp sẽ không bao giờ được thực hiện. Mỗi biểu thức có thể chứa các toán tử, nếu có nhiều câu lệnh trong một vòng lặp thì chúng phải được nhóm lại bằng từ khóa begin và end
Ví dụ:
//đếm tăng từ 0 đến 127, dừng ở 128
//Khai báo biến đếm
integer count;
initial
begin
count = 0;
while (count < 128)
//----------thực hiện vòng lặp đến khi count = 127, dừng ở 128----------
begin
$display("Count = %d", count);
count = count + 1;
end
end
Vòng lặp for:
Từ khóa for được dùng để chỉ vòng lặp này:
for (count = value1;count />= value2;count = count +/- step)
begin
... statements ...
end
Vòng lặp for chứa ba thành phần:
Một điều kiện ban đầu cho biến điều khiển: “count=value1”
Kiểm tra điều kiện sau vẫn còn đúng: “ count />= value2”
Một phép gán thủ tục để thay đổi giá trị của biến điều khiển: “count = count +/- step”
Vòng lặp for ngắn gọn hơn vòng lặp while, dù vậy, vòng lặp while được sử dụng nhiều hơn vòng lặp for. Vòng lặp for không thể thay thế cho vòng lặp while trong tất cả các trường hợp.
Ví dụ:
integer count;
initial
for ( count=0; count < 128; count = count + 1)
$display("Count = %d", count);
Vòng lặp for thường được dùng để muốn cố định điểm đầu và điểm cuối của vòng lặp, còn với những điều kiện chính xác thì vòng lặp while tốt hơn.
Vòng lặp repeat:
Từ khóa repeat dùng để chỉ vòng lặp này:
repeat (number_of_times)
begin
... statements ...
end
Cấu trúc repeat thực thi vòng lặp với số lần cố định. Một cấu trúc repeat không thể dùng với biểu thức logic thông thường, mà phải chứa một số, có thể là hằng số, biến hoặc tín hiệu. Dù thế, nếu số là một biến hoặc giá trị của tín hiệu, nó chỉ có giá trị với vòng khi bắt đầu thực hiện và không ảnh hưởng trong suốt quá trình thực thi vòng.
Ví dụ:
repeat (2)
begin // sau 50, a = 00
#50 a = 2’b00; // sau 100, a = 01,
#50 a = 2’b01; // sau 150, a = 00,
end // sau 200, a = 01
Vòng lặp forever:
Từ khóa forever dùng để diễn tả vòng lặp này:
forever
begin
... statements ...
end
Vòng lặp forever không chứa bất kì biểu thức nào, và sẽ thực hiện mãi cho đến khi gặp chỉ thị $finish. Vòng lặp forever tương đương với vòng lặp while trong trường hợp biểu thức trong vòng lặp luôn đúng. Có thể thoát khỏi vòng lặp forever bằng câu lệnh disable.
Ví dụ:
//tạo xung có chu kì là 20 đơn vị
reg clock;
initial
begin
clock = 1'b0;
forever #10 clock = ~clock;
end
Khối lệnh thực hiện tuần tự và song song:
Khối tuần tự:
Khối tuần tự sử dụng từ khóa begin và end có các đặc điểm sau:
Các lệnh được thực hiện theo vị trí của chúng trong khối, lệnh sau được thực hiện khi lệnh trước kết thúc (ngoại trừ nonblocking assignments với điều khiển thời gian), vị trí các lệnh là rất quan trọng.
Nếu có điều khiển trễ, nó cũng thể hiện mối quan hệ với thời gian hoàn tất lệnh trước đó.
Ví dụ:
//---------------khối tuần tự không có thời gian trễ--------------------
reg x, y;
reg [1:0] z, w;
initial
begin
x = 1'b0;
y = 1'b1;
z = {x, y};
w = {y, x};
end
//----------------khối tuần tự có thời gian trễ------------------------
reg x, y;
reg [1:0] z, w;
initial
begin
x = 1’b0; //kết thúc tại t =0;
#5 y = 1’b1; //kết thúc tại t = 5
#10 z ={x, y}; //kết thúc tại t = 15
#20 w = {y, x}; //kết thúc tại t = 35
end
Khối lệnh song song:
Khối lệnh song song sử dụng từ khóa fork và join, các tính chất của khối lệnh song song như sau:
Các lệnh trong khối song song thực thi đồng thời, vì vậy thứ tự các lệnh trong khối không quan trọng.
Thứ tự thực hiện các lệnh được điều khiển thông qua giá trị thời gian trễ hoặc sự kiện gán trên mỗi lệnh.
Ví dụ:
//-----------------khối lệnh song song với delay--------------
reg x, y;
reg [1:0] z, w;
initial
fork
x = 1’b0; //kết thúc tại t =0;
#5 y = 1’b1; //kết thúc tại t = 5
#10 z ={x, y}; //kết thúc tại t = 10
#20 w = {y, x}; //kết thúc tại t = 20
join
Từ khóa fork có thể được xem như việc chia một luồng xử lý đơn thành nhiều luồng xử lý độc lập. Từ khóa join được xem như việc kết hợp nhiều luồng độc lập thành một luồn đơn.
Các đặc tính của khối:
Kết hợp các khối: các khối có thể được lồng vào nhau, các khối tuần tự và song song có thể được trộn lại với nhau.
Ví dụ:
//------------------lồng khối------------------
initial
begin
x = 1'b0;
fork
#5 y = 1'b1;
#10 z = {x, y};
join
#20 w = {y, x};
end
Tên khối: khối có thể được đặt tên nhằm mục đích sau:
Các biến cục bộ được khai báo dựa trên tên khối
Đặt tên các khối là một phần của thiết kế phân cấp. Các biến trong một khối có thể được truy xuất bằng việc sử dụng tên theo kiểu phân cấp
Khối được đặt tên để có thể ngưng thực thi khi cần
Ví dụ:
module top;
initial;
begin: block1 //tên khối tuần tự block1
integer i; //biến cục bộ i kiểu integer thuộc block1, được //truy xuất bởi tên phân cấp top.block1.i
------
------
end
initial
fork: block2 //tên khối song song là block2
reg i; //biến cục bộ i kiểu integer thuộc block2, có //thể được truy xuất bởi tên phân cấp //top.block2.i
------
------
join
Ngưng hoạt động khối được đặt tên:từ khóa disable cung cấp một cách để ngưng thực thi một khối có tên. Disable có thể được dùng để thoát khỏi vòng lặp, kiểm soát điều kiện lỗi hoặc thực thi một phần của mã lệnh,
Ví dụ:
//-------------------tìm bit có giá trị 1 đầu tiên trong flag-------------------
reg [15:0] flag;
integer i;
initial
begin
flag = 16'b 0010_0000_0000_0000;
i = 0;
begin: block1
while (i<16)
begin
if (flag[i])
begin
$display ("da tim thay %d", i);
Disable block1; //ngưng thực hiện vì đã tìm thấy bit
end
i = i + 1;
end
end
end
Tast và Function:
Người thiết kế thường xuyên thực thi một chức năng giống nhau nhiều lần trong một thiết kế hành vi, những phần thường dùng đó nên được cho vào trong một tác vụ và tác vụ đó phải thay thế được cho các dòng lệnh lặp đi lặp lại này. Hầu hết các ngôn ngữ đều cung cấp thủ tục hoặc thủ tục con để thực hiện điều đó. Tasks (các tác vụ) và Functions (các hàm) cho phép người thiết kế loại bỏ đi tình trạng sử dụng các câu lệnh có cùng chức năng tại nhiều nơi.
Các tác vụ có tham số input, output và inout, các hàm có tham số input. Vì vậy, giá trị có thể thông qua đó mà vào và ra khỏi các tác vụ và hàm. Các tác vụ và hàm cũng bao gồm cả thiết kế thứ bậc. Giống như trên khối lệnh, các tác vụ và hàm có thể được địa chỉ hóa bằng các tên phân cấp.
Điểm khác nhau giữa task và function:
Các thủ tục và hàm được cung cấp với mục đích khác nhau trong verilog, điểm khác nhau được liệt kê ở bảng 6.13 và sẽ được trình bày chi tiết ở phần sau.
Bảng 6.13 – So sánh Task và Function
Hàm (Function)
Tác vụ (Task)
Một hàm có thể cho phép hàm khác hoạt động, nhưng không thể cho phép thủ tục
Một thủ tục có thể cho phép thủ tục khác hay hàm khác hoạt động
Hàm luôn thực thi tại thời điểm t = 0
Thủ tục có thể hoạt động tại thời điểm t ≠0
Hàm không chứa bất kỳ delay, event, hay lệnh điều khiển thời gian nào
Thủ tục có thể chứa delay, event hay lệnh điều khiển thời gian
Hàm phải có ít nhất một tham số input
Thủ tục có thể không có hoặc có nhiều tham số input, output, hoặc inout
Hàm luôn trả về một giá trị đơn, không có tham số output hay inout
Thủ tục không trả về một giá trị, nhưng thông qua nhiều giá trị tham số output và inout.
Cả tác vụ và hàm đều phải được định nghĩa trong một module và nội bộ của module đó. Các thủ tục được sử dụng trong các mã verilog có chứa delay, event hoặc nhiều tham số ngõ ra. Hàm thường được dùng trong các tổ hợp lệnh thực thi tại thời điểm t = 0, và chỉ có một output. Thêm vào đó, chúng có các biến cục bộ, thanh ghi, biến thời gian, integer, real hoặc event. Tác vụ hoặc hàm không có wire, chúng chỉ chứa các lệnh hành vi, không chứa phát biểu always hay initial, nhưng có thể gọi khối lệnh always, khối initial, cùng các tác vụ và hàm khác.
Task:
Tác vụ được khai báo bằng từ khóa task và endtask. Tác vụ phải được dùng nếu một trong các điều kiện sau là đúng trong thủ tục.
Có thời gian trễ, định thời hoặc cấu trúc điều khiển bên trong thủ tục.
Thủ tục không có hoặc có nhiều tham số ngõ ra
Thủ tục không có tham số ngõ ra
Khai báo trong task:
Tác vụ được khai báo các thông số theo cú pháp sau:
task
endtask
Các khai báo I/O sử dụng các từ khóa input, output hoặc inout dựa trên loại tham số được khai báo, tham số input và inout được đưa vào trong tác vụ. Tham số input được xử lý trong các câu lệnh tác vụ. Các giá trị tham số ouput và inout được truyền ra ngoài qua biến câu lệnh khi tác vụ hoàn thành. Tác vụ có thể gọi các tác vụ khác hoặc các hàm.
Ví dụ:
//------định nghĩa một module gọi là operation chứa tác vụ bitwise_oper----
module operation
parameter delay = 10;
reg [15:0] A, B;
reg [15:0] AB_AND, AB_OR, AB_XOR;
always @ (A or B) //bất kì khi nào A và B thay đổi giá trị
begin
/* dẫn ra tác vụ bitwise_oper, có hai tham số input là A và B, có ba tham số ouput là AB_AND, AB_OR, AB_XOR. Các thông số phải có cùng vị trí như khi tác vụ được khai báo*/
bitwise_oper(AB_AND, AB_OR, AB_XOR, A, B);
end
...
...
//--------khai báo tác vụ bitwise_oper----------
tast bitwise_oper;
ouput [15:0] ab_and, ab_or, ab_xor; //các ngõ ra từ task
input [15:0] a, b; //các ngõ vào từ task
begin
#delay ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask
...
endmodule
Trong tác vụ trên, các giá trị input được đưa vào A và B. Từ đó, tác vụ nạp vào a=A và b = B. Ba giá trị ouput được tính sau thời gian delay 10 đơn vị của thời gian. Khi tác vụ hoàn tất, giá trị ouput được trả về gọi là tham số ouput AB_AND = ab_and, AB_OR = ab_or và AB_XOR = ab_xor.
Tác vụ tự động:
Các tác vụ thường cố định, tất cả các thành phần được khai báo nằm ở vị trí cố định. Vì thế, khi một tác vụ được gọi đồng thời từ hai nơi khác nhau trong chương trình, các tác vụ sẽ thực hiện trên các biến của cùng một tác vụ, khả năng kết quả không đúng là rất cao.
Để tránh sự cố này, một từ khóa automatic được thêm vào trước từ khóa task. Các thành phần được khai báo trong một task tự động sẽ được định vị trí động cho mỗi lần gọi, mỗi tác vụ được thực hiện ở các vùng độc lập. Vì thế, tác vụ được thực thi độc lập trên các bản sao của biến. Kết quả thu được đúng, nên automatic task được khuyến cáo sử dụng trong các chương trình có xảy ra khả năng gọi hai tác vụ giống nhau cùng một thời điểm.
Ví dụ:
// module chứa một automatic task
// với xung clock là clk
module top;
reg [15:0] cd_xor, ef_xor; //các biến trong module
reg [15:0] c, d, e, f;
----
task automatic bitwise_xor;
output [15:0] ab_xor; //output từ task
input [15:0] a, b; //inputs của task
begin
ab_xor = a ^ b;
end
endtask
----
/*có hai khối lệnh always gọi tác vụ bitwise_xor đồng thời tại cùng một thời điểm là cạnh lênh của xung clk. Vì tác vụ là automatic task nên kết quả vẫn đúng*/
always @ (posedge clk)
bitwise_xor(ef_xor, e, f);
----
always @ (posedge clk)
bitwise_xor(cd_xor, c, d);
----
endmodule
Functions:
Các hàm được khai báo với từ khóa function và endfunction. Các hàm được sử dụng nếu tất cả các điều kiện sau là đúng trong thủ tục:
Không có định thời, trễ, hoặc các câu lệnh điều khiển (#, @, wait)
Trả về với 1 kết quả đơn
Có ít nhất một tham số vào
Không có tham số output hoặc inout
Không có phép gán nonblocking
Khai báo hàm:
Cú pháp:
function [] ;
endfunction
Khi một hàm được khai báo, một thanh ghi với tên là tên của hàm được khai báo ngầm trong verilog. Ouput của hàm được trả về thông qua việc thiết lập giá trị của thanh ghi tên hàm. Hàm được gọi bởi tên và kèm tham số ngõ vào. Tại thời điểm cuối của việc thực thi hàm, giá trị được trả về được đặt tại nơi hàm được gọi. Tùy chọn tầm giá trị và kiểu chỉ độ rộng của thanh ghi bên trong. Nếu không có độ rộng hoặc kiểu được chỉ định, giá trị mặc định là 1. Không có tham số ngõ ra cho hàm, bởi đã có thanh ghi ẩn chứa giá trị trả về. Ngoài ra, hàm không gọi được tác vụ khác, chúng chỉ gọi được hàm.
Ví dụ:
//-------định nghĩa module chứa hàm dịch (shift function)---------
//---------dịch trái/phải---------------
`define LEFT_SHIFT 1'b0
`define RIGHT_SHIFT 1'b1
reg [31:0] addr, left_addr, right_addr;
reg control;
//---------tính giá trị dịch trái và phải khi có địa chỉ mới-----------
always @ (addr)
begin
//----------gọi hàm được định nghĩa bên dưới để dịch trái/ phải-------------
left_addr = shift(addr, `LEFT_SHIFT);
right_addr = shift(addr, `RIGHT_SHIFT);
end
//--------định nghĩa hàm dịch, cho giá trị ra là 32 bit-------------
function [31:0] shift;
input [31:0] address;
input control;
begin
//-------thiết lập giá trị ra dựa trên tín hiệu điều khiển------------------
shift = (control == `LEFT_SHIFT) ?(address > 1);
end
endfunction
...
...
endmodule
Bài tập bài 6:
Mục tiêu: để người học làm quen với việc thiết kế, lập trình sử dụng vi mạch khả trình.
Bài tập 1: Thiết kế và mô phỏng IC 7408, IC 74138, IC 74192, IC 7490.
Bài tập 2: Thiết kế mạch giải mã led 7 đoạn loại anod và cathot chung.
Bài tập 3: Thiết kế mạch đếm lên từ 1 đến 9
Bài tập 4: Thiết kế mạch chuyển đổi số hex sang số BCD
YÊU CẦU VỀ ĐÁNH GIÁ KẾT QUẢ HỌC TẬP BÀI 6:
Nội dung:
Về kiến thức: Trình bày được các kiến thức cơ bản về ngôn ngữ Verilog HDL.
Về kỹ năng: Áp dụng những kiến thức về ngôn ngữ Verilog HDL để thiết kế cho một ứng dụng cụ thể.
Về thái độ: Đảm bảo an toàn về điện và vệ sinh công nghiệp.
Phương pháp:
Về kiến thức: Được đánh giá bằng hình thức kiểm tra viết, trắc nghiệm, vấn đáp.
Về kỹ năng: Đánh giá kỹ năng sử dụng ngôn ngữ Verilog HDL để thiết kế một ứng dụng cụ thể.
Về thái độ:Tỉ mỉ, cẩn thận, chính xác và ngăn nắp trong công việc.
BÀI 7
MỘT SỐ CHƯƠNG TRÌNH ỨNG DỤNG
Mã bài: MĐ30 - 07
Giới thiệu:
Để nắm rõ và hiểu sâu hơn về cách lập trình cho FPGA, CPLD của hãng Xilinx và ngôn ngữ Verilog HDL, thì người học phải viết chương trình thực hiện các yêu cầu đưa ra. Chương này cung cấp cho người học một số chương trình mẫu để người học tham khảo, trên cơ sở đó viết các chương trình theo yêu cầu cụ thể của từng bài tập.
Mục tiêu:
Viết được các chương trình ứng dụng theo nội dung đã học
Viết được các chương trình theo yêu cầu kỹ thuật.
Sử dụng được core có sẵn trong ISE vào chương trình.
Nội dung chính:
Điều khiển led đơn:
Chương trình chính:
Tên module là dieu_khien_led_don, điều khiển cho 1 led sáng, 1 led sáng chạy từ trái qua phải (chạy qua 8 led), 1 led sáng chạy từ phải qua trái, sáng dần từ phải qua trái, tắt dần từ phải qua trái, sáng dần từ trái qua phải, tắt dần từ trái qua phải, sau đó làm lại từ đầu.
Chú ý là trong module này, xung clock có tần số nhỏ để mắt ta có thể quan sát được, nếu tần số lớn thì ta phải chia xung để có được tần số cần thiết hoặc viết chương trình delay.
module dieu_khien_led_don (res,clk,out);
//---------------các ngõ vào--------------------------
input res; //---tín hiệu reset--------------
input clk; //---xung clock-----------------
//---------------các ngõ ra----------------------------
output [7:0] out; //---ngõ ra----------------------
reg [7:0] out;
//------------biến trung gian--------------------------
reg [2:0] k;
//-------------main program--------------------------
always @ (posedge clk)
begin
//-------xử lý reset-----------------------------
if (!res) begin
out = 0;
k=0;
end
//-------xử lý chương trình chính-----------
else begin
case (k)
//----------cho 1 led sang-------------
0: begin
k = 1;
out = 1;
end
//--------1 led sang chay tu phai qua trai----
1: begin
if(out == 128) k = 2;
else out = out<<1;
end
//--------1 led sang chay tu trai qua phai----
2: begin
if(out == 1) begin
out = 0;
k = 3;
end
else out = out>>1;
end
//--------sang dan tu trai qua phai---------
3: begin
if(out == 255) k = 4;
else out = (out<<1) + 1;
end
//--------tat dan tu trai qua phai---------
4: begin
if(out == 0) begin
k = 5;
end
else out = out<<1;
end
//--------sang dan tu phai qua trai---------
5: begin
if(out == 255) k = 6;
else out = (out>>1) + 128;
end
//--------tat dan tu phai qua trai---------
6: begin
if(out == 0) k = 0; //--quay lai lam lai tu dau--
else out = out>>1;
end
endcase
end
end
endmodule
Chương trình testbench:
module test_led_don; //-------ten module test là test_led_don------------
// ---------------Inputs----------------
reg res;
reg clk;
// --------------Outputs---------------
wire [7:0] out;
// -------------Instantiate the Unit Under Test (UUT)---------
dieu_khien_led_don uut (
.res(res),
.clk(clk),
.out(out)
);
initial begin
//------------- Initialize Inputs------------------------------------
res = 0;
clk = 0;
// Wait 100 ns for global reset to finish
#100;
res = 1; //-------cho reset len muc 1------
end
//----------------tao xung clock T = 20------------------
always
begin
#10 clk = !clk;
end
endmodule
kết quả mô phỏng:
Hình 7.1 – Kết quả mô phỏng chương trình led đơn
Thanh ghi dịch:
Chương trình chính:
Tên module là thanh_ghi_dich_8bit, bao gồm thanh ghi dịch vào song song ra nối tiếp và vào nối tiếp ra song song.
module thanh_ghi_dich_8bit (in_s, out_p, in_p, out_s, res, clk);
//-----------cac ngo vao------------
input in_s; //-------------- vao noi tiep ---------
input [7:0] in_p; //-------------- vao song song ------
input res; //-------------- tin hieu reset -------
input clk; //-------------- xung clock ----------
//-----------cac ngo ra--------------
output [7:0] out_p; //-------------- ra song song--------
output out_s; //-------------- ra noi tiep-----------
reg [7:0] out_p;
reg out_s;
//-----------bien trung giang--------
reg [2:0] i;
//-------------main program------------------
always @ (posedge clk)
begin
//---------------xu ly reset-----------------
if(!res) begin
out_s = 0; //---------xoa ngo ra noi tiep ve 0---------
out_p = 0; //---------xoa ngo ra song song ve 0------
i = 0;
end
//---------------chuong trinh chinh----------
else begin
//------------ thanh ghi vao noi tiep ra song song ---------
out_p = (out_p << 1) + in_s;
//------------ thanh ghi vao song song ra noi tiep ---------
out_s = in_p[i];
i = i + 1;
end
end
endmodule
Chương trình testbench:
module test_ghi_dich;
//------------------Inputs-------------------
reg in_s;
reg [7:0] in_p;
reg res;
reg clk;
//----------------- Outputs -----------------
wire [7:0] out_p;
wire out_s;
//------ Instantiate the Unit Under Test (UUT)---------
thanh_ghi_dich_8bit uut (
.in_s(in_s),
.out_p(out_p),
.in_p(in_p),
.out_s(out_s),
.res(res),
.clk(clk)
);
initial begin
//------------- Initialize Inputs-------------
in_s = 0;
in_p = 0;
res = 0;
clk = 0;
//------ Wait 100 ns for global reset to finish-----------
#100;
res = 1; //--------cho reset len 1------------------------------
//-------- Add stimulus here--------------
in_s=1; //---------nhap gia tri vao noi tiep la 1----------
in_p = 8'b01100111; //---------nhap gia tri vao song song-----
#500; //--------- delay 500----------------------
res = 0; //--------- cho reset ve 0 ----------------
in_s =0; //--------- nhap vao noi tiep la 0 -------
in_p =8'h10101010; //------ nhap gia tri vao song song ---
#100; //--------- delay 100 ---------------------
res = 1; //--------- cho reset len 1 ---------------
#100; //--------- delay 100 ---------------------
in_s=1; //--------- cho vao noi tiep len 1 -------
end
//------------tao xung clock có T = 20---------
always
begin
#10 clk = !clk;
end
endmodule
Kết quả mô phỏng:
Hình 7.2 – Kết quả mô phỏng thanh ghi dịch
Mạch đếm:
Chương trình chính:
Chương trình thực hiện đếm số BCD từ 0 đến 99, sau đó đưa qua hai IC giải mã BCD sang led 7 đoạn để hiển thị trên hai led 7 đoạn.
Hình 7.3 – Sơ đồ khối bộ đếm BCD từ 0 đến 99
Tên của module là: dem_tu_0_den_99.
Chương trình chính:
module dem_tu_0_den_99 (res, clk, dem1, dem2);
//----------cac ngo vao-----------------------
input res; //------tin hieu reset-------------
input clk; //------xung clock----------------
//----------cac ngo ra------------------------
output [3:0]dem1; //-----dem 4 bit thap-------------
output [3:0]dem2; //-----dem 4 bit cao-------------
reg [3:0] dem1;
reg [3:0] dem2;
//----------main program--------------
always @ (posedge clk)
begin
//------xu ly reset----------------
if(!res) begin
dem1 = 0; //-----xoa bo dem ve 0-------
dem2 = 0;
end
//------xu ly dem-----------------
else begin
if(dem1 == 9) begin
dem1 = 0;
if(dem2 == 9) dem2 =0;
else dem2 = dem2 + 1;
end
else dem1 = dem1 + 1;
end
end
endmodule
Chương trình testbench:
module test_dem_0_to_99;
//---------- Inputs--------
reg res;
reg clk;
//---------- Outputs-------
wire [3:0] dem1;
wire [3:0] dem2;
//---- Instantiate the Unit Under Test (UUT)-------
dem_tu_0_den_99 uut (
.res(res),
.clk(clk),
.dem1(dem1),
.dem2(dem2)
);
initial begin
//-------- Initialize Inputs------------
res = 0;
clk = 0;
//---- Wait 100 ns for global reset to finish---------
#100;
res = 1; //-------cho reset len 1 de bat dau dem -----
//---- Add stimulus here------------------
end
//----------tao xung clock co T = 20 -----------
always
begin
#10 clk = !clk;
end
endmodule
Kết quả mô phỏng:
Hình 7.4 – Kết quả mô phỏng đếm BCD từ 0 đến 99
Mạch đếm vòng xoắn Johson:
Chương trình chính:
Thực hiện chương trình đếm v
Các file đính kèm theo tài liệu này:
- giao_trinh_vi_mach_so_lap_trinh_le_van_hien.doc