Firmado vs. Sin firmar en VHDL
Todos los diseñadores digitales deben comprender cómo funcionan las matemáticas dentro de un FPGA o ASIC. El primer paso para eso es comprender cómo funcionan los tipos de señales firmadas y no firmadas. Los tipos firmados y sin firmar existen en numeric_std paquete, que forma parte de la biblioteca ieee. Cabe señalar que existe otro archivo de paquete que se utiliza con frecuencia para realizar operaciones matemáticas:std_logic_arith . Sin embargo, std_logic_arith no es un archivo de paquete compatible con ieee oficial y no se recomienda su uso en diseños digitales.
Una señal que se define como tipo firmado significa que las herramientas interpretan esta señal como positiva o negativa. Una señal que se define como tipo sin firmar significa que la señal será solo positiva. Internamente, la FPGA utilizará Complemento a dos representación. Por ejemplo, una señal de 3 bits se puede interpretar de acuerdo con la siguiente tabla:
¿Ya estás confundido? ¡Deberías serlo, esto no es intuitivo! Veamos un ejemplo que, con suerte, aclarará las cosas. El siguiente archivo prueba cómo funciona el firmado sin firmar. Lo que debe entenderse es que si las señales se definen o no como firmadas o no firmadas no afectan cómo se realizan las matemáticas binarias reales.
Por ejemplo:para dos vectores con signo 10001 + 00010, la respuesta sigue siendo 10011, PERO es la interpretación del resultado que es diferente.
Para el caso sin firmar, la respuesta (10011) representa 19.
Para el caso firmado, la respuesta (10011) representa -13.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity signed_unsigned is port ( i_rst_l : in std_logic; i_clk : in std_logic; i_a : in std_logic_vector(4 downto 0); i_b : in std_logic_vector(4 downto 0) ); end signed_unsigned; architecture behave of signed_unsigned is signal rs_SUM_RESULT : signed(4 downto 0) := (others => '0'); signal ru_SUM_RESULT : unsigned(4 downto 0) := (others => '0'); signal rs_SUB_RESULT : signed(4 downto 0) := (others => '0'); signal ru_SUB_RESULT : unsigned(4 downto 0) := (others => '0'); begin -- Purpose: Add two numbers. Does both the signed and unsigned -- addition for demonstration. This process is synthesizable. p_SUM : process (i_clk, i_rst_l) begin if i_rst_l = '0' then -- asynchronous reset (active low) rs_SUM_RESULT <= (others => '0'); ru_SUM_RESULT <= (others => '0'); elsif rising_edge(i_clk) then ru_SUM_RESULT <= unsigned(i_a) + unsigned(i_b); rs_SUM_RESULT <= signed(i_a) + signed(i_b); end if; end process p_SUM; -- Purpose: Subtract two numbers. Does both the signed and unsigned -- subtraction for demonstration. This process is synthesizable. p_SUB : process (i_clk, i_rst_l) begin if i_rst_l = '0' then -- asynchronous reset (active low) rs_SUB_RESULT <= (others => '0'); ru_SUB_RESULT <= (others => '0'); elsif rising_edge(i_clk) then ru_SUB_RESULT <= unsigned(i_a) - unsigned(i_b); rs_SUB_RESULT <= signed(i_a) - signed(i_b); end if; end process p_SUB; end behave;
Banco de prueba:
library ieee; use ieee.std_logic_1164.all; entity example_signed_unsigned_tb is end example_signed_unsigned_tb; architecture behave of example_signed_unsigned_tb is --Registers signal r_CLK : std_logic := '0'; signal r_RST_L : std_logic := '0'; signal r_A : natural := 0; signal r_B : natural := 0; signal r_A_SLV : std_logic_vector(4 downto 0) := (others => '0'); signal r_B_SLV : std_logic_vector(4 downto 0) := (others => '0'); constant c_CLK_PERIOD : time := 10 ns; component example_signed_unsigned is port ( i_rst_l : in std_logic; i_clk : in std_logic; i_a : in std_logic_vector(4 downto 0); i_b : in std_logic_vector(4 downto 0) ); end component example_signed_unsigned; begin i_DUT: example_signed_unsigned port map ( i_rst_l => r_RST_L, i_clk => r_CLK, i_a => r_A_SLV, i_b => r_B_SLV ); clk_gen : process is begin r_CLK <= '0' after c_CLK_PERIOD/2, '1' after c_CLK_PERIOD; wait for c_CLK_PERIOD; end process clk_gen; process begin r_RST_L <= '0'; wait for 20 ns; r_RST_L <= '1'; wait for 20 ns; r_A_SLV <= "01001"; r_B_SLV <= "00110"; wait for 20 ns; r_A_SLV <= "10001"; r_B_SLV <= "00110"; wait for 20 ns; r_A_SLV <= "10001"; r_B_SLV <= "00001"; wait for 20 ns; r_A_SLV <= "10001"; r_B_SLV <= "00010"; wait for 20 ns; r_A_SLV <= "11111"; r_B_SLV <= "00001"; wait for 20 ns; r_A_SLV <= "00000"; r_B_SLV <= "00001"; wait for 20 ns; wait; end process; end behave;
Valores de salida de onda de simulación de Modelsim mostrados en HEX
Valores de salida de onda de simulación de Modelsim mostrados en DECIMAL
Compare las dos capturas de pantalla de modelsim anteriores. En el primero puedes ver que los resultados de las funciones matemáticas son exactamente iguales cuando se representan en hexadecimal. Es la interpretación de los resultados que es diferente. Esto se puede ver mirando la captura de pantalla inferior. Cuando Modelsim muestra los resultados en decimal, interpreta algunos de ellos como números negativos. ¡Al usar tipos firmados y no firmados, debe tener mucho cuidado! Espero que entiendas un poco mejor este tema. Siento que esta es un área con la que luchan muchos diseñadores digitales, así que si hay algo que no entiende completamente, envíeme un correo electrónico a través del enlace de contacto en la barra lateral e intentaré aclararlo.
VHDL
- Tutorial - Introducción a VHDL
- Ejemplos de conversiones VHDL
- Declaración de procedimiento:ejemplo de VHDL
- Registros:ejemplo de VHDL
- Variables - Ejemplo de VHDL
- Sistemas de señales actuales
- Señal de tráfico
- Localización de LoRa
- Verificación formal en VHDL usando PSL
- Cómo crear una lista de cadenas en VHDL
- Integridad de señal y PCB