Làm cách nào tôi có thể chỉ định các lỗi không quan tâm đến các tín hiệu trong VHDL?


11

Trong các khóa học Thiết kế Logic, tất cả chúng ta đều học được rằng có thể giảm thiểu chức năng logic, ví dụ bằng cách sử dụng bản đồ Karnaugh hoặc thuật toán Quine siêu McCluskey . Chúng tôi cũng học được rằng các giá trị "Không quan tâm" làm tăng tiềm năng giảm thiểu.

Ví dụ lấy một tập tin đăng ký. Các tín hiệu write_addresswrite_datakhông thực sự quan trọng khi write_enabletín hiệu là '0'. Vì vậy, chúng nên được gán một giá trị "Không quan tâm" để cho phép tối ưu hóa nhiều hơn trong logic đang điều khiển các tín hiệu này (tức là không phải trong chính tệp đăng ký).

Cách chính xác để xác định các giá trị "Không quan tâm" như vậy trong VHDL là gì để cho phép công cụ tổng hợp có nhiều chỗ hơn cho các tối ưu hóa có thể?


Cho đến nay tôi đã tìm thấy những điều sau đây có thể phù hợp. Nhưng tôi không thực sự chắc chắn những ưu và nhược điểm của mỗi phương pháp là gì:

  • Đơn giản là không gán tín hiệu. Điều này có vẻ như nó có thể làm việc. Tuy nhiên tôi thấy rằng nó không hoạt động khi bạn muốn xác định một loại "không làm gì liên tục" của một số recordloại, vì các hằng số bản ghi cần phải được chỉ định đầy đủ (ít nhất là Modelim nói với tôi như vậy).
  • Các std_logic_1164gói xác định giá trị '-' -- Don't carecho std_ulogic. Có vẻ như đây là lựa chọn chính xác về mặt ngữ nghĩa cho một "không quan tâm" rõ ràng, nhưng tôi chưa bao giờ thấy nó được sử dụng ở bất cứ đâu (ngoại trừ trong các case?cấu trúc VHDL-2008 không liên quan ).
  • Modelim sử dụng giá trị 'X'để hiển thị các tín hiệu không xác định. Tuy nhiên tôi không chắc các công cụ tổng hợp có hiểu một sự phân bổ rõ ràng 'X'là "không quan tâm" hay không.

Đây là một đoạn mã đơn giản hóa để làm rõ, nơi tôi đã khởi tạo các tín hiệu không quan tâm '-'.

Như bạn có thể thấy, tín hiệu control.reg_write_addresscó thể có 3 giá trị khác nhau: "----", instruction(11 downto 8);instruction(3 downto 0);. Bây giờ tôi hy vọng điều này sẽ được tổng hợp thành một bộ ghép kênh 2 đầu vào nếu '-'được hiểu là "không quan tâm". Nếu tôi đã khởi tạo tín hiệu (others => '0')thay vì '-', công cụ sẽ phải tạo bộ ghép kênh 3 đầu vào thay thế.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package mytypes is
    type control_signals_t is record
        write_enable  : std_logic;
        write_address : std_ulogic_vector(3 downto 0);
        read_address  : std_ulogic_vector(3 downto 0);
    end record;

    -- All members of this constant must be fully specified.
    -- So it's not possible to simply not assign a value.
    constant CONTROL_NOP : control_signals_t := (
        write_enable  => '0',
        write_address => (others => '-'),
        read_address  => (others => '-')
    );
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library cfx;
use cfx.mytypes.all;

entity control_unit is
    port(
        instruction : in  std_ulogic_vector(15 downto 0);
        write_data  : out std_ulogic_vector(15 downto 0);
        ctrl        : out control_signals_t
    );
end entity;

architecture rtl of control_unit is
begin
    decode_instruction : process(instruction) is
    begin
        -- Set sensible default values that do nothing.
        -- Especially all "write_enable" signals should be '0'.
        -- Everything else is mostly irrelevant (don't care).
        ctrl       <= CONTROL_NOP;
        write_data <= (others => '-');

        if instruction(15 downto 12) = "1100" then
            -- Load 8 bit of data into the register file
            ctrl.write_enable  <= '1';
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
            ctrl.write_address <= instruction(11 downto 8);
        elsif instruction(15 downto 8) = "11111001" then
            -- Load 4 bit of data into the register file
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
            ctrl.write_address <= instruction(3 downto 0);
        elsif instruction(15 downto 8) = "10110101" then
            -- Read from the register file. Don't use the write signals at all.
            ctrl.read_address <= instruction(3 downto 0);
        end if;
    end process;
end architecture;

Bạn có thể giải thích những gì bạn đang cố gắng làm write_addresswrite_datakhông? Tối ưu hóa nào bạn mong đợi sẽ diễn ra?
fru1tbat

Tôi hy vọng ví dụ này làm cho nó rõ ràng hơn những gì tôi muốn đạt được.
Fritz

Câu trả lời:


9

Tôi sẽ để lại cho chuyên gia LRM để cung cấp câu trả lời chi tiết hơn, nhưng tóm lại, cách tiếp cận của bạn sẽ hợp lệ - Tôi đã chạy thử nghiệm nhanh với một phiên bản Quartus gần đây và nó xử lý '-'như được cho là - logic được tạo ra bị giảm như mong đợi khi đầu ra được mặc định '-'(nhân tiện 'X'cũng vậy). Thêm về các phương pháp bạn liệt kê:

  • Tất nhiên, việc không gán tín hiệu không thực sự là một lựa chọn cho ví dụ của bạn, nếu bạn không muốn chốt. Nếu đó là một quá trình đồng hồ, bạn sẽ khá hơn một chút, nhưng bạn vẫn sẽ được kích hoạt ở những nơi bạn có thể không cần đến chúng. Có lẽ tôi đang thiếu ý định của bạn ở đây.

  • '-', như đã lưu ý trước đây, có lẽ là lựa chọn tốt nhất, vì cả lý do ngữ nghĩa và thực tế.

  • Phụ thuộc vào những gì bạn có nghĩa là "không xác định". 'X'về mặt kỹ thuật là "chưa biết". 'U'dành cho các tín hiệu chưa được khởi tạo, ModelSim hiển thị như "X"đối với các biểu diễn hex. 'X'có vẻ như làm việc, mặc dù, như tôi đã lưu ý ở trên.

Một cách khác là tự tối ưu hóa và loại bỏ một trường hợp khỏi bị kiểm tra rõ ràng:

if instruction(15 downto 8) = "11111001" then
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
else
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
end if;

Tuy nhiên, điều này có những nhược điểm đáng kể (chủ yếu liên quan đến độ rõ của mã) và có lẽ tôi sẽ chọn giải pháp lý tưởng hơn.

Ngẫu nhiên, '-'cũng thường được sử dụng với std_match(), mà tôi sẽ xem xét sử dụng để giải mã của bạn, ví dụ:

if std_match(instruction(15 downto 8), "1100----") then

Mặc dù tại thời điểm đó, có lẽ bạn nên sử dụng case?.


6

Tóm lại: Đó là VHDL hợp pháp và nó thường được hỗ trợ bởi các công cụ tổng hợp.

Tuy nhiên, nó khá hiếm khi thấy nó được sử dụng. Tôi thực sự không biết tại sao. Mã của bạn dường như là một ví dụ tốt về việc sử dụng nó có ý nghĩa khi nào.

Tuy nhiên, có một nhược điểm mà người ta cần lưu ý: khi tổng hợp, các chức năng thúc đẩy đầu ra khi không quan tâm có thể khác nhau giữa các lần chạy tổng hợp. Điều này làm cho sự tổng hợp ít xác định. Nếu các đầu ra được xác định là không quan tâm được sử dụng (do nhầm lẫn), điều này có thể khiến lỗi khó tìm hơn.

Công cụ hỗ trợ

Ít nhất các công cụ sau đây sẽ chấp nhận không quan tâm và sử dụng các khả năng tối ưu hóa:

  • Xilinx (tham khảo: "Hướng dẫn sử dụng XST")
  • Altera (tham khảo: "Kiểu mã hóa HDL được đề xuất")
  • Synplify (ref.: "Hướng dẫn tham khảo đồng bộ hóa")

Xilinx và Altera sẽ đối xử '-''X'không quan tâm, Synplify sẽ đối xử với những người đó và hơn nữa 'U''W'(yếu) là không quan tâm.


1
Tôi đã có một ứng dụng khác của nhược điểm đó. Mã này hoạt động trong mô phỏng, nhưng không phải trên FPGA, bởi vì mã của tôi trông giống như : if signal = '1' then a; else b; end if;. Thật không may là signalkhông 1hay 0nhưng -. Vì vậy, trong mô phỏng, elsenhánh được thực thi, nhưng trong phần cứng -hóa ra là một 1, vì vậy nhánh thực sự đã được thực thi ...
Fritz

Vâng, tôi đã có lỗi tương tự vượt qua mô phỏng, nhưng thường nhất trong trường hợp của tôi có những lỗi 'U', phổ biến khi bắt đầu mô phỏng, đã được sử dụng dẫn đến một số elsekhối mã được thực thi. Thật tuyệt vời nếu bằng cách nào đó có thể được thực hiện để truyền bá 'U's, tương tự như hành vi của các biểu thức boolean đồng thời.
Carl

Sau khi tôi tìm thấy lỗi đó, tôi chắc chắn luôn viết một cái gì đó như thế if signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;. Và tôi đã thêm những điều sau đây vào tất cả các thanh ghi và ký ức: assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;. Cộng với tương tự cho write_data. Cùng nhau, điều đó sẽ nắm bắt gần như tất cả các lỗi này.
Fritz

Đó là một cách, nhưng đó là quá dài dòng đối với tôi. Tôi muốn có khả năng này trong ngôn ngữ VHDL.
Carl

1
Vâng, VHDL là một chút dài dòng, nhưng đó chỉ là cách VHDL. : D Mặt khác, nó cũng rất rõ ràng và không làm "ma thuật đen" sau lưng tôi, điều mà tôi thấy khá hay (x. Zen của Python "Rõ ràng là tốt hơn ngầm").
Fritz
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.