Использование Float Math в VHDL, получение неверного ответа - PullRequest
0 голосов
/ 07 апреля 2020

У меня есть домашнее задание, в котором я использую предложенный ieee пакет с плавающей запятой. Я использую BRAM для перетасовки данных из PS в PL (c код для моего VHDL).

Я почти уверен, что мои номера правильно поступают в код VHDL, у меня есть 4 входа и 2 выхода, я по очереди назначил каждый вход на выход и увидел ожидаемое значение. Однако всякий раз, когда я выполняю математические операции с ними, я получаю неправильный ответ. Я никогда раньше не использовал пакет ieee, и, может быть, мне не хватает чего-то очевидного?

u1, u2, x и y назначаются через машину состояний из dataInB.

с u1 = 1, u2 = 2, x = 3, y = 4 вместо получения t1 = 1 (X "3F800000") и t2 = 1 (X "3F800000"), я вижу t1 = 0 (X "00000000") и t2 = -0,5 (X "BF000000").

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

 library ieee_proposed;
 use ieee_proposed.fixed_float_types.all;
 use ieee_proposed.float_pkg.all;
 use ieee_proposed.fixed_pkg.all;

 -- port inputs:
 port(
   signal dataInB : in std_logic_vector(31 downto 0);
   signal dataOutB : out std_logic_vector(31 downto 0);
 );


 arch a of a_1 is
   -- skipped some code, variable definitions:
   signal fDataIn : float32;
   signal u1 : float32 := X"00000000"; -- in
   signal u2 : float32 := X"00000000"; -- in
   signal x : float32 := X"00000000"; -- in
   signal y : float32 := X"00000000"; -- in
   signal t1 : float32 := X"00000000"; -- out
   signal t2 : float32 := X"00000000"; -- out

   begin

   fDataIn <= to_float(dataInB); -- combinational


  -- in state machine:
  case read_u1:
     u1 <= fDataIn; -- addr was changed in previous state to new address

  case read_u2:
     u2 <= fDataIn; -- addr was changed in previous state to new address

  -- etc. for x and y

  -- skip some code
  --  calculations - combinational
  t1 <= u2 - u1;
  t2 <= y - x;

  -- some time later in state machine:
  case write_T1:
     dataOutB <= std_logic_vector(t1);

  case write_T2:
     dataOutB <= std_logic_vector(t2);

 end a_1;

Как упоминалось ранее, если я изменю t1 <= x и t2 <= u2, я увижу ожидаемые значения вернемся к моему C коду, так что я думаю, что часть BRAM работает должным образом, только не расчет. </p>

Заранее спасибо.

Я использую плату Digilent ZyboZ7010 с Xilinx Vivado 2019.1 и связанный SDK. Это внутри пользовательского IP.

Редактировать: Полный код ниже:

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

 library ieee_proposed;
 use ieee_proposed.fixed_float_types.all;
 use ieee_proposed.float_pkg.all;
 use ieee_proposed.fixed_pkg.all;


 entity myip_v1_0_S00_AXI is
 generic (
    -- Users to add parameters here

    -- User parameters ends
    -- Do not modify the parameters beyond this line
    -- Width of S_AXI data bus
    C_S_AXI_DATA_WIDTH  : integer   := 32;
    -- Width of S_AXI address bus
    C_S_AXI_ADDR_WIDTH  : integer   := 4
);
port (
    -- Users to add ports here
    signal addrB : out std_logic_vector(31 downto 0) := X"00000000";
    signal dataInB : in std_logic_vector(31 downto 0);
    signal dataOutB : out std_logic_vector(31 downto 0);
    signal enB : out std_logic := '1';
    signal writeB : out std_logic_vector(3 downto 0) := X"0";
    signal rstB : out std_logic := '0';
    -- User ports ends
    -- Do not modify the ports beyond this line

    -- Global Clock Signal
    S_AXI_ACLK  : in std_logic;
    -- Global Reset Signal. This Signal is Active LOW
    S_AXI_ARESETN   : in std_logic;
    -- Write address (issued by master, acceped by Slave)
    S_AXI_AWADDR    : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    -- Write channel Protection type. This signal indicates the
        -- privilege and security level of the transaction, and whether
        -- the transaction is a data access or an instruction access.
    S_AXI_AWPROT    : in std_logic_vector(2 downto 0);
    -- Write address valid. This signal indicates that the master signaling
        -- valid write address and control information.
    S_AXI_AWVALID   : in std_logic;
    -- Write address ready. This signal indicates that the slave is ready
        -- to accept an address and associated control signals.
    S_AXI_AWREADY   : out std_logic;
    -- Write data (issued by master, acceped by Slave) 
    S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    -- Write strobes. This signal indicates which byte lanes hold
        -- valid data. There is one write strobe bit for each eight
        -- bits of the write data bus.    
    S_AXI_WSTRB : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
    -- Write valid. This signal indicates that valid write
        -- data and strobes are available.
    S_AXI_WVALID    : in std_logic;
    -- Write ready. This signal indicates that the slave
        -- can accept the write data.
    S_AXI_WREADY    : out std_logic;
    -- Write response. This signal indicates the status
        -- of the write transaction.
    S_AXI_BRESP : out std_logic_vector(1 downto 0);
    -- Write response valid. This signal indicates that the channel
        -- is signaling a valid write response.
    S_AXI_BVALID    : out std_logic;
    -- Response ready. This signal indicates that the master
        -- can accept a write response.
    S_AXI_BREADY    : in std_logic;
    -- Read address (issued by master, acceped by Slave)
    S_AXI_ARADDR    : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    -- Protection type. This signal indicates the privilege
        -- and security level of the transaction, and whether the
        -- transaction is a data access or an instruction access.
    S_AXI_ARPROT    : in std_logic_vector(2 downto 0);
    -- Read address valid. This signal indicates that the channel
        -- is signaling valid read address and control information.
    S_AXI_ARVALID   : in std_logic;
    -- Read address ready. This signal indicates that the slave is
        -- ready to accept an address and associated control signals.
    S_AXI_ARREADY   : out std_logic;
    -- Read data (issued by slave)
    S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    -- Read response. This signal indicates the status of the
        -- read transfer.
    S_AXI_RRESP : out std_logic_vector(1 downto 0);
    -- Read valid. This signal indicates that the channel is
        -- signaling the required read data.
    S_AXI_RVALID    : out std_logic;
    -- Read ready. This signal indicates that the master can
        -- accept the read data and response information.
    S_AXI_RREADY    : in std_logic
);
 end myip_v1_0_S00_AXI;

 architecture arch_imp of myip_v1_0_S00_AXI is

-- AXI4LITE signals
signal axi_awaddr   : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_awready  : std_logic;
signal axi_wready   : std_logic;
signal axi_bresp    : std_logic_vector(1 downto 0);
signal axi_bvalid   : std_logic;
signal axi_araddr   : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_arready  : std_logic;
signal axi_rdata    : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal axi_rresp    : std_logic_vector(1 downto 0);
signal axi_rvalid   : std_logic;

-- Example-specific design signals
-- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
-- ADDR_LSB is used for addressing 32/64 bit registers/memories
-- ADDR_LSB = 2 for 32 bits (n downto 2)
-- ADDR_LSB = 3 for 64 bits (n downto 3)
constant ADDR_LSB  : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;
constant OPT_MEM_ADDR_BITS : integer := 1;
------------------------------------------------
---- Signals for user logic register space example
--------------------------------------------------
---- Number of Slave Registers 4
signal slv_reg0 :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg1 :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg2 :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg3 :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg_rden : std_logic;
signal slv_reg_wren : std_logic;
signal reg_data_out :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal byte_index   : integer;
signal aw_en    : std_logic;



-- NE added 
 signal start : std_logic := '0';
 signal done : std_logic := '0';
 signal lAddr : std_logic_vector(31 downto 0) := X"00000000";
 type state_type is (s_setU1Addr, s_setU2Addr, s_setX_Addr, s_setY_Addr, s_readU1Addr, s_done, s_readU2Addr, s_readX_Addr, s_readY_Addr, s_calc, s_setT1Addr, s_setT2Addr, s_writeT1, s_writeT2, s_loop, s_wait, s_inc);
 signal present_state, next_state: state_type;
 signal fDataIn : float32;

 signal u1 : float32 := X"00000000";
 signal u2 : float32 := X"00000000";
 signal x : float32 := X"00000000";
 signal y : float32 := X"00000000";
 signal t1 : float32 := X"00000000";
 signal t2 : float32 := X"00000000";

begin
-- I/O Connections assignments

S_AXI_AWREADY   <= axi_awready;
S_AXI_WREADY    <= axi_wready;
S_AXI_BRESP <= axi_bresp;
S_AXI_BVALID    <= axi_bvalid;
S_AXI_ARREADY   <= axi_arready;
S_AXI_RDATA <= axi_rdata;
S_AXI_RRESP <= axi_rresp;
S_AXI_RVALID    <= axi_rvalid;
-- Implement axi_awready generation
-- axi_awready is asserted for one S_AXI_ACLK clock cycle when both
-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
-- de-asserted when reset is low.

process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      axi_awready <= '0';
      aw_en <= '1';
    else
      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
        -- slave is ready to accept write address when
        -- there is a valid write address and write data
        -- on the write address and data bus. This design 
        -- expects no outstanding transactions. 
           axi_awready <= '1';
           aw_en <= '0';
        elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then
           aw_en <= '1';
           axi_awready <= '0';
      else
        axi_awready <= '0';
      end if;
    end if;
  end if;
end process;

-- Implement axi_awaddr latching
-- This process is used to latch the address when both 
-- S_AXI_AWVALID and S_AXI_WVALID are valid. 

process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      axi_awaddr <= (others => '0');
    else
      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
        -- Write Address latching
        axi_awaddr <= S_AXI_AWADDR;
      end if;
    end if;
  end if;                   
end process; 

-- Implement axi_wready generation
-- axi_wready is asserted for one S_AXI_ACLK clock cycle when both
-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
-- de-asserted when reset is low. 

process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      axi_wready <= '0';
    else
      if (axi_wready = '0' and S_AXI_WVALID = '1' and S_AXI_AWVALID = '1' and aw_en = '1') then
          -- slave is ready to accept write data when 
          -- there is a valid write address and write data
          -- on the write address and data bus. This design 
          -- expects no outstanding transactions.           
          axi_wready <= '1';
      else
        axi_wready <= '0';
      end if;
    end if;
  end if;
end process; 

-- Implement memory mapped register select and write logic generation
-- The write data is accepted and written to memory mapped registers when
-- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
-- select byte enables of slave registers while writing.
-- These registers are cleared when reset (active low) is applied.
-- Slave register write enable is asserted when valid address and data are available
-- and the slave is ready to accept the write address and write data.
slv_reg_wren <= axi_wready and S_AXI_WVALID and axi_awready and S_AXI_AWVALID ;

process (S_AXI_ACLK)
variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0); 
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      slv_reg0 <= (others => '0');
      slv_reg1 <= (others => '0');
      slv_reg2 <= (others => '0');
      slv_reg3 <= (others => '0');
    else
      loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
      if (slv_reg_wren = '1') then
        case loc_addr is
          when b"00" =>
            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
              if ( S_AXI_WSTRB(byte_index) = '1' ) then
                -- Respective byte enables are asserted as per write strobes                   
                -- slave registor 0
                slv_reg0(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when b"01" =>
            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
              if ( S_AXI_WSTRB(byte_index) = '1' ) then
                -- Respective byte enables are asserted as per write strobes                   
                -- slave registor 1
                slv_reg1(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when b"10" =>
            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
              if ( S_AXI_WSTRB(byte_index) = '1' ) then
                -- Respective byte enables are asserted as per write strobes                   
                -- slave registor 2
                slv_reg2(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when b"11" =>
            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
              if ( S_AXI_WSTRB(byte_index) = '1' ) then
                -- Respective byte enables are asserted as per write strobes                   
                -- slave registor 3
                slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
              end if;
            end loop;
          when others =>
            slv_reg0 <= slv_reg0;
            slv_reg1 <= slv_reg1;
            slv_reg2 <= slv_reg2;
            slv_reg3 <= slv_reg3;
        end case;
      end if;
    end if;
  end if;                   
end process; 

-- Implement write response logic generation
-- The write response and response valid signals are asserted by the slave 
-- when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
-- This marks the acceptance of address and indicates the status of 
-- write transaction.

process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      axi_bvalid  <= '0';
      axi_bresp   <= "00"; --need to work more on the responses
    else
      if (axi_awready = '1' and S_AXI_AWVALID = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0'  ) then
        axi_bvalid <= '1';
        axi_bresp  <= "00"; 
      elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then   --check if bready is asserted while bvalid is high)
        axi_bvalid <= '0';                                 -- (there is a possibility that bready is always asserted high)
      end if;
    end if;
  end if;                   
end process; 

-- Implement axi_arready generation
-- axi_arready is asserted for one S_AXI_ACLK clock cycle when
-- S_AXI_ARVALID is asserted. axi_awready is 
-- de-asserted when reset (active low) is asserted. 
-- The read address is also latched when S_AXI_ARVALID is 
-- asserted. axi_araddr is reset to zero on reset assertion.

process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then 
    if S_AXI_ARESETN = '0' then
      axi_arready <= '0';
      axi_araddr  <= (others => '1');
    else
      if (axi_arready = '0' and S_AXI_ARVALID = '1') then
        -- indicates that the slave has acceped the valid read address
        axi_arready <= '1';
        -- Read Address latching 
        axi_araddr  <= S_AXI_ARADDR;           
      else
        axi_arready <= '0';
      end if;
    end if;
  end if;                   
end process; 

-- Implement axi_arvalid generation
-- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
-- S_AXI_ARVALID and axi_arready are asserted. The slave registers 
-- data are available on the axi_rdata bus at this instance. The 
-- assertion of axi_rvalid marks the validity of read data on the 
-- bus and axi_rresp indicates the status of read transaction.axi_rvalid 
-- is deasserted on reset (active low). axi_rresp and axi_rdata are 
-- cleared to zero on reset (active low).  
process (S_AXI_ACLK)
begin
  if rising_edge(S_AXI_ACLK) then
    if S_AXI_ARESETN = '0' then
      axi_rvalid <= '0';
      axi_rresp  <= "00";
    else
      if (axi_arready = '1' and S_AXI_ARVALID = '1' and axi_rvalid = '0') then
        -- Valid read data is available at the read data bus
        axi_rvalid <= '1';
        axi_rresp  <= "00"; -- 'OKAY' response
      elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then
        -- Read data is accepted by the master
        axi_rvalid <= '0';
      end if;            
    end if;
  end if;
end process;

-- Implement memory mapped register select and read logic generation
-- Slave register read enable is asserted when valid address is available
-- and the slave is ready to accept the read address.
slv_reg_rden <= axi_arready and S_AXI_ARVALID and (not axi_rvalid) ;

process (slv_reg0, slv_reg1, slv_reg2, slv_reg3, axi_araddr, S_AXI_ARESETN, slv_reg_rden)
variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
begin
    -- Address decoding for reading registers
    loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
    case loc_addr is
      when b"00" =>
        reg_data_out <= slv_reg0;
      when b"01" =>
        reg_data_out <= "0000000000000000000000000000000" & done;
      when b"10" =>
        reg_data_out <= lAddr;
      when b"11" =>
        reg_data_out <= dataInB;
      when others =>
        reg_data_out  <= (others => '0');
    end case;
end process; 

-- Output register or memory read data
process( S_AXI_ACLK ) is
begin
  if (rising_edge (S_AXI_ACLK)) then
    if ( S_AXI_ARESETN = '0' ) then
      axi_rdata  <= (others => '0');
    else
      if (slv_reg_rden = '1') then
        -- When there is a valid read address (S_AXI_ARVALID) with 
        -- acceptance of read address by the slave (axi_arready), 
        -- output the read dada 
        -- Read address mux
          axi_rdata <= reg_data_out;     -- register read data
      end if;   
    end if;
  end if;
end process;


-- Add user logic here  
start <= slv_reg0(0);
fDataIn <= to_float(dataInB);
addrB <= lAddr;

t1 <= u2 - u1;--(u1 * x) - (u2 * y);
t2 <= y - x;--(u1 * y) + (u2 * x);

statemach: process(present_state, start)
begin
  case present_state is
    when s_wait =>
        writeB <= X"0";
        done <= '0';
        dataOutB <= X"00000000";
        if (start = '1') then
            next_state <= s_setU1Addr;
        else
            next_state <= s_wait;
        end if;
    when s_setU1Addr =>
        lAddr <= X"00000000";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_readU1Addr;
    when s_readU1Addr => 
        lAddr <= X"00000000";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        u1 <= fDataIn;
        next_state <= s_setU2Addr;
    when s_setU2Addr =>
        lAddr <= X"00000004";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_readU2Addr;
    when s_readU2Addr => 
        lAddr <= X"00000004";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        u2 <= fDataIn;
        next_state <= s_setX_Addr;
    when s_setX_Addr => 
        lAddr <= X"00000008";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_readX_Addr;
    when s_readX_Addr =>
        lAddr <= X"00000008";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        x <= fDataIn;
        next_state <= s_setY_Addr;
    when s_setY_Addr => 
        lAddr <= X"0000000C";
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_readY_Addr;
    when s_readY_Addr => 
        lAddr <= X"0000000C";
        y <= fDataIn;
        writeB <= X"0";
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_calc;       
    when s_calc =>
    --    t1 <= (u1 * x) - (u2 * y);
    --    t2 <= (u1 * y) + (u2 * x);
        writeB <= X"0"; -- f
        dataOutB <= X"00000000";
        done <= '0';
        next_state <= s_setT1Addr;
    when s_setT1Addr =>
   --     t1 <= (u1 * x) - (u2 * y);
   --     t2 <= (u1 * y) + (u2 * x);
        lAddr <= X"00000010";
        dataOutB <= std_logic_vector(t1);
        writeB <= X"0"; -- f
        done <= '0';
        next_state <= s_writeT1;
    when s_writeT1 =>
   --     t1 <= (u1 * x) - (u2 * y);
  --      t2 <= (u1 * y) + (u2 * x);
        lAddr <= X"00000010";
        dataOutB <= std_logic_vector(t1);
        writeB <= X"F";
        done <= '0';
        next_state <= s_setT2Addr;
    when s_setT2Addr =>
   --     t1 <= (u1 * x) - (u2 * y);
   --     t2 <= (u1 * y) + (u2 * x);
        lAddr <= X"00000014";
        dataOutB <= std_logic_vector(t2);
        writeB <= X"0"; -- f
        done <= '0';
        next_state <= s_writeT2;
    when s_writeT2 =>
   --     t1 <= u2 - u1;--(u1 * x) - (u2 * y);
    --    t2 <= y - x;--(u1 * y) + (u2 * x);
        lAddr <= X"00000014";
        dataOutB <= std_logic_vector(t2);
        writeB <= X"F";
        done <= '0';
        next_state <= s_done;
    when s_done =>
        writeB <= X"0";
        dataOutB <= X"00000000";
        if (start = '1') then -- hold until PS acks
            next_state <= s_done;
            done <= '1';
        else
            done <= '0';
            next_state <= s_wait;
        end if;
    when others =>
      null;
  end case;
end process;


updateState: process(S_AXI_ACLK, S_AXI_ARESETN)
begin
    if S_AXI_ARESETN = '0' then
        present_state <= s_wait;
    --  miniCounter <= 0;
    --  counter <= 0;
    elsif S_AXI_ACLK'event and S_AXI_ACLK = '1' then
        present_state <= next_state;
    --    miniCounter <= miniCounter + 1;
   --     counter <= counter + 1;
    end if;
end process;
-- User logic ends

end arch_imp;
...