Tại sao mẫu VHDL đơn giản này cho một thanh ghi thay đổi không hoạt động như mong đợi


8

Thoạt nhìn, bạn sẽ mong đợi mã nguồn VHDL bên dưới hoạt động như một thanh ghi thay đổi. Trong đó q, theo thời gian sẽ là

"UUUU0", "UUU00", "UU000", "U0000", "00000", ....

nhưng thay vào đó, nó luôn luôn Usau năm (hoặc nhiều hơn) chu kỳ đồng hồ liên tiếp.

Tại sao lại thế này?

Mã này thực sự là một phiên bản đơn giản hơn nhiều của một mô phỏng phức tạp hơn nhiều. Nhưng nó cho thấy các triệu chứng mà tôi thấy.

Nó thể hiện kết quả thú vị và bất ngờ này trong quá trình mô phỏng theo cả ModelSim và ActiveHDL, tôi đã không thử các trình giả lập khác và (thứ hai là giải thích nguyên nhân) muốn biết liệu những người khác có hành động tương tự không.

Để trả lời đúng câu hỏi này, bạn phải hiểu rằng:

  • Tôi biết đây không phải là cách tốt nhất để thực hiện đăng ký thay đổi
  • Tôi biết để tổng hợp RTL nên có một thiết lập lại.
  • Tôi biết một mảng của std_logic là một std_logic_vector.
  • Tôi biết các toán tử tổng hợp &,.

Những gì tôi cũng đã tìm thấy:

  • Nếu sự phân công temp(0)<='0';được di chuyển bên trong quá trình, nó hoạt động.
  • Nếu vòng lặp được mở ra (xem mã nhận xét), nó hoạt động.

Tôi sẽ nhắc lại rằng đây là phiên bản rất đơn giản với thiết kế phức tạp hơn nhiều (đối với CPU có đường ống), được cấu hình để hiển thị hoàn toàn các kết quả mô phỏng bất ngờ. Các loại tín hiệu thực tế chỉ là một sự đơn giản hóa. Vì lý do này, bạn phải xem xét câu trả lời của mình với mã theo mẫu.

Tôi đoán là trình tối ưu hóa của công cụ mô phỏng VHDL bị nhầm lẫn (hoặc có thể theo thông số kỹ thuật) không bận tâm để chạy các biểu thức bên trong vòng lặp vì không có tín hiệu bên ngoài thay đổi, mặc dù tôi có thể từ chối điều này bằng cách đặt vòng lặp không được bao bọc trong một vòng lặp.

Vì vậy, tôi hy vọng rằng câu trả lời cho câu hỏi này liên quan nhiều hơn đến các tiêu chuẩn cho mô phỏng VHDL của cú pháp VHDL không rõ ràng và cách các công cụ mô phỏng VHDL thực hiện tối ưu hóa của chúng, thay vì ví dụ mã được đưa ra có phải là cách tốt nhất để làm gì đó hay không.

Và bây giờ với mã tôi đang mô phỏng:

 library ieee;
 use ieee.std_logic_1164.all;   

 entity test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
 end entity;

 architecture example of test_simple is
    type   t_temp is array(4 downto 0) of std_logic;
    signal temp : t_temp;
 begin

    temp(0) <= '0';

    p : process (clk)
    begin               
        if rising_edge(clk) then
            for i in 1 to 4 loop
                    temp(i) <= temp(i - 1);
            end loop;

            --temp(1) <= temp(0);   
            --temp(2) <= temp(1);
            --temp(3) <= temp(2);
            --temp(4) <= temp(3);
        end if;
    end process p;
    q <= temp(4);
 end architecture;

Và băng ghế thử nghiệm:

library ieee;
use ieee.std_logic_1164.all;

entity Bench is
end entity;

architecture tb of bench is

component test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
end component;

signal clk:std_logic:='0';
signal q:std_logic;     
signal rst:std_logic;

constant freq:real:=100.0e3;

begin                       
    clk<=not clk after 0.5 sec / freq;

    TB:process
    begin
        rst<='1';
        wait for 10 us;
        rst<='0';
        wait for 100 us;
        wait;
    end process;

     --Note: rst is not connected
    UUT:test_simple  port map (clk=>clk,q=>q) ;
end architecture;

Lần đầu tiên thử khởi tạo temp trong khai báo tín hiệu, tôi đã thấy các trình giả lập vhdl rất kỳ quặc về nơi bạn khởi tạo mọi thứ
Matt

Có vẻ như trình giả lập đang bỏ qua việc gán đồng thời temp(0)vì không có "sự kiện" nào liên quan đến hằng số theo nghĩa đen. Đặt nhiệm vụ bên trong processtạo ra một liên kết với các sự kiện đồng hồ làm cho nó hoạt động. Tôi tự hỏi nếu thêm một aftermệnh đề vào bài tập sẽ là một cách giải quyết tiềm năng.
Dave Tweed

Câu trả lời:


7

Nó phải làm với những gì có thể dễ dàng đánh giá tại thời điểm xây dựng, chính thức, cái được gọi là "biểu thức tĩnh cục bộ". Đây là một quy tắc tìm kiếm tối nghĩa, nhưng nó đáng được suy nghĩ - cuối cùng nó cũng có ý nghĩa và trình giả lập của bạn khá chính xác trong việc cảnh báo bạn bằng cách tạo ra kết quả không rõ ràng.

Bây giờ, temp(1)có thể được đánh giá tại thời gian biên dịch (thậm chí sớm hơn thời gian xây dựng) và nó có thể tạo trình điều khiển trên bit 1 của "temp".

Tuy nhiên, temp(i)liên quan đến một chút công việc hơn cho các công cụ. Do tính chất tầm thường của giới hạn vòng lặp ở đây (1 đến 4), rõ ràng con người chúng ta rằng temp (0) không thể được điều khiển và những gì bạn đang làm là an toàn. Nhưng hãy tưởng tượng các giới hạn là các hàm lower(foo) to upper(bar)trong một gói được khai báo ở một nơi khác ... bây giờ, điều bạn có thể nói chắc chắn nhất là tempđược điều khiển - vì vậy biểu thức "tĩnh cục bộ" là temp.

Và điều đó có nghĩa là quy trình bị ràng buộc bởi các quy tắc này để điều khiển tất cả temp, tại thời điểm đó bạn có nhiều trình điều khiển trên temp(0)- quá trình lái xe (không có giá trị ban đầu, tức là 'u') và bên ngoài temp(0) <= '0';. Vì vậy, tự nhiên hai trình điều khiển giải quyết 'U'.

Giải pháp thay thế sẽ là một "quy tắc nhỏ khó hiểu" (ý kiến) rằng nếu các giới hạn vòng lặp là hằng số, hãy làm một việc, nhưng nếu chúng được tuyên bố là một cái gì đó khác, hãy làm một cái gì đó khác, v.v ... có, ngôn ngữ càng phức tạp hơn ... theo tôi, không phải là một giải pháp tốt hơn.


Câu trả lời tốt (+1), nhưng tôi không đồng ý với đặc điểm của bạn về "quy tắc nhỏ khó hiểu". Toàn bộ điểm mô phỏng là đại diện cho hành vi của phần cứng thực. Tôi hiểu các ràng buộc được tạo ra bởi quá trình biên dịch độc lập của các mô-đun riêng lẻ, nhưng tôi nghĩ rằng quy tắc nên là bất cứ điều gì có thể được đánh giá tại thời điểm biên dịch nên được. Đây sẽ là một quy tắc chung hơn nhiều, và sẽ giúp hệ thống tuân thủ nguyên tắc "ít bất ngờ nhất". Cho phép các công cụ không thực hiện những đánh giá đó cảm thấy "hacky" hơn đối với tôi.
Dave Tweed

Nhận xét công bằng - Ví dụ, Ada đã (và chính thức thể hiện) sự phức tạp hơn nhiều về các quy tắc như thế này và quản lý để trình bày một cái nhìn đơn giản hơn nhiều cho người dùng chúng tôi (không có yếu tố WTF của C!). VHDL ban đầu được đơn giản hóa (IMO hơi xa) từ Ada. Nhưng có lẽ nó có thể áp dụng các quy tắc "đóng băng kiểu" của Ada, điều này sẽ cho phép loại tối ưu hóa này khi an toàn rõ ràng (như ở đây) và cấm nó theo cách khác ...
Brian Drumond

Cảm ơn Brian, những gì bạn nói chắc chắn có ý nghĩa. Ý tưởng về một quy tắc đơn giản thay vì nhiều quy tắc tối nghĩa dường như cũng có ý nghĩa. Bạn có nói hành vi này là đúng (và thực sự được chỉ định) cho tất cả các trình giả lập hay đó chỉ là hai hành vi tôi đã thử?
Jason Morgan

2
Nếu tôi tìm thấy một thứ đã làm một cái gì đó khác đi, tôi sẽ gửi một lỗi chống lại nó! Một điều mà những kẻ gièm pha lớn nhất của VHDL sẽ nói theo hướng có lợi là nó đảm bảo kết quả mô phỏng nhất quán trong trường hợp các ngôn ngữ khác (không chỉ Verilog) không có. (mặc dù đúng, đôi khi những thiếu sót của nó cũng làm tôi bực mình!)
Brian Drumond

1
Thử nghiệm khắc phục nhanh: nếu câu trả lời của tôi là đúng, bạn có thể lái "temp (0) <= 'Z';" do đó, trong quá trình này, do đó "ngắt kết nối" trình điều khiển ảo và trình điều khiển bên ngoài sẽ hoạt động ...
Brian Drumond
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.