Chủ Nhật, 30 tháng 7, 2017

[Verilog] Làm thế nào để mô tả mạch tuần tự đồng bộ dùng Flip-Flop bằng ngôn ngữ Verilog

1. Mạch tuần tự đồng bộ dùng Flip-Flop

Mô hình mạch tuần tự đồng bộ dùng FF được minh họa trong hình sau.
Hình 1. Mô hình mạch tuần tự dùng FF (trái) và ví dụ (phải)

Mạch tuần tự dùng FF là mạch đồng bộ theo xung clock gồm các thành phần chính như sau:
  • Mạch tổ hợp là phần mạch tạo giá trị ngõ vào cho FF, mạch này thực hiện tính toán dựa trên các giá trị ngõ vào và giá trị hồi tiếp từ ngõ ra của FF (nếu có)
  • Flip-Flop (FF) là thành phần sẽ cập nhật giá trị từ mạch tổ hợp theo cạnh tích cực của xung clock, cạnh lên hoặc cạnh xuống, và giữ giá trị này đến cạnh tích cực tiếp theo. FF có thể được reset hoặc không tùy vào yêu cầu cụ thể của từng mạch.
Mạch bên phải của hình 1 là một ví dụ về mạch tuần tự, trong đó:

  • Mạch tổ hợp gồm:
    • MUX của tín hiệu sel[2:0] thực hiện chuyển đổi giá trị binary của sel[2:0] thành giá trị mã Gray
    • MUX của tín hiệu en thực hiện đưa giá trị chuyển đổi đến count_i[2:0] nếu en = 1. Nếu en = 0, count_i[2:0] sẽ lấy giá trị từ ngõ ra thanh ghi FF
  • Thanh ghi gồm 3 FF để lưu giá trị từ mạch tổ hợp hoạt động theo cạnh lên xung clock

2. Mô tả mạch tuần tự bằng Verilog

Việc mô tả mạch tuần tự sẽ gồm 2 phần:
  • Mô tả mạch tổ hợp
  • Mô tả thanh ghi (FF)

RTL code của ví dụ trên đây như sau:


module gray_count (sel, en, reset, clock, count_o);
//Interface
input [2:0] sel;
input en;
input reset;
input clock;
output reg [2:0] count_o;
//Internal signal
wire [2:0] count_i;
reg [2:0] gray_code;
//Combinational circuit
//Binary-gray converter
always @ (sel[2:0]) begin
 case (sel[2:0])
   3'b000: gray_code[2:0] = 3'b000;
  3'b001: gray_code[2:0] = 3'b001;
  3'b010: gray_code[2:0] = 3'b011;
  3'b011: gray_code[2:0] = 3'b010;
  3'b100: gray_code[2:0] = 3'b110;
  3'b101: gray_code[2:0] = 3'b111;
  3'b110: gray_code[2:0] = 3'b101;
  3'b111: gray_code[2:0] = 3'b100;
 endcase
end
//MUX enable
assign count_i[2:0] = en? gray_code[2:0]: count_o[2:0];
//Register
always @ (posedge clock) begin
  if (reset) count_o[2:0] <= 3'b000;
 else       count_o[2:0] <= count_i[2:0];
end

endmodule

Mạch tổ hợp được mô tả bằng một khối always và một phát biểu assign. Việc mô tả một mạch tổ hợp các bạn hãy tham khảo ở bài khác trong trang này.

Việc mô tả một thanh ghi, thanh ghi là phần tử gồm một hoặc nhiều FF, cần quan tâm đến các vấn đề sau:

  • Mô tả cạnh tích cực của clock:
    • Cạnh lên (posedge)
    • Cạnh xuống (negedge)
  • Mô tả reset quan tâm đến 2 yếu tố:
    • Loại reset, đồng bộ hoặc bất đồng bộ. Reset đồng bộ là sự kiện reset phụ thuộc vào xung clock. Sự kiện reset chỉ xảy ra khi tín hiệu reset tích cực và có cạnh tích cực của xung clock. Reset bất đồng bộ là sự kiện reset xảy ra bất cứ khi nào tín hiệu reset tích cực, bất chấp xung clock.
    • Mức tích cực, mức cao hoặc mức thấp.

Hình 2. Sự khác nhau giữa reset đồng bộ và reset bất đồng bộ (mức tích cực của reset là mức thấp)
Đoạn RTL code ví dụ trên đây mô tả cạnh tích cực của clock là cạnh lên, loại reset sử dụng là đồng bộ với mức tích cực của tín hiệu reset là mức cao (mức 1).

Mô tả thanh ghi có reset đồng bộ tích cực mức thấp như sau:

always @ (posedge clock) begin
  if (~reset) count_o[2:0] <= 3'b000;
 else       count_o[2:0] <= count_i[2:0];
end

Mô tả thanh ghi có reset bất đồng bộ tích cực mức cao như sau:

always @ (posedge clock, posedge reset) begin
  if (reset) count_o[2:0] <= 3'b000;
 else       count_o[2:0] <= count_i[2:0];
end

Mô tả thanh ghi có reset bất đồng bộ tích cực mức thấp như sau:


always @ (posedge clock, negedge reset) begin
  if (~reset) count_o[2:0] <= 3'b000;
 else       count_o[2:0] <= count_i[2:0];

end

Mô tả thanh ghi không có reset như sau:


always @ (posedge clock) begin
  count_o[2:0] <= count_i[2:0];
end

Tất cả các mạch tuần tự khác đều có thể được mô tả bằng cách tách tiêng phần mạch tổ hợp và và phần thanh ghi như trên. Tuy nhiên, thông thường một phần hoặc toàn bộ phần mạch tổ hợp có thể được mô tả chung với thanh ghi như các đoạn RTL code minh họa sau đây.

Mô tả gộp chung MUX của tín hiệu en và bỏ qua tín hiệu trung gian count_i[2:0]:


module gray_count (sel, en, reset, clock, count_o);
//Interface
input [2:0] sel;
input en;
input reset;
input clock;
output reg [2:0] count_o;
//Internal signal
reg [2:0] gray_code;
//Combinational circuit
//Binary-gray converter
always @ (sel[2:0]) begin
 case (sel[2:0])
         3'b000: gray_code[2:0] = 3'b000;
  3'b001: gray_code[2:0] = 3'b001;
  3'b010: gray_code[2:0] = 3'b011;
  3'b011: gray_code[2:0] = 3'b010;
  3'b100: gray_code[2:0] = 3'b110;
  3'b101: gray_code[2:0] = 3'b111;
  3'b110: gray_code[2:0] = 3'b101;
  3'b111: gray_code[2:0] = 3'b100;
 endcase
end
//Register
always @ (posedge clock) begin
  if (reset) count_o[2:0] <= 3'b000;
  else if (en)
    count_o[2:0] <= gray_code[2:0];
  else count_o[2:0] <= count_o[2:0];
end
endmodule

Mô tả gộp chung tất cả phần mạch tổ hợp và thanh ghi, bỏ qua tín hiệu trung gian gray_code[2:0]:


module gray_count (sel, en, reset, clock, count_o);
//Interface
input [2:0] sel;
input en;
input reset;
input clock;
output reg [2:0] count_o;
//Register
always @ (posedge clock) begin
  if (reset) count_o[2:0] <= 3'b000;
 else if (en) begin
   case (sel[2:0])
            3'b000: count_o[2:0] <= 3'b000;
     3'b001: count_o[2:0] <= 3'b001;
     3'b010: count_o[2:0] <= 3'b011;
     3'b011: count_o[2:0] <= 3'b010;
     3'b100: count_o[2:0] <= 3'b110;
     3'b101: count_o[2:0] <= 3'b111;
     3'b110: count_o[2:0] <= 3'b101;
     3'b111: count_o[2:0] <= 3'b100;
    endcase
 end
 else count_o[2:0] <= count_o[2:0];
end

endmodule

0 bình luận:

Đăng nhận xét