URL
https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk
Subversion Repositories riscv_vhdl
[/] [riscv_vhdl/] [trunk/] [rtl/] [riverlib/] [core/] [arith/] [int_div.vhd] - Rev 5
Compare with Previous | Blame | View Log
----------------------------------------------------------------------------- --! @file --! @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved. --! @author Sergey Khabarov - sergeykhbr@gmail.com --! @brief Integer divider. --! @details Algorithm spends 33 clocks per instruction ------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; library commonlib; use commonlib.types_common.all; --! RIVER CPU specific library. library riverlib; --! RIVER CPU configuration constants. use riverlib.river_cfg.all; entity IntDiv is port ( i_clk : in std_logic; i_nrst : in std_logic; -- Reset Active LOW i_ena : in std_logic; -- Enable bit i_unsigned : in std_logic; -- Unsigned operands i_rv32 : in std_logic; -- 32-bits operands enable i_residual : in std_logic; -- Compute: 0 =division; 1=residual i_a1 : in std_logic_vector(RISCV_ARCH-1 downto 0); -- Operand 1 i_a2 : in std_logic_vector(RISCV_ARCH-1 downto 0); -- Operand 1 o_res : out std_logic_vector(RISCV_ARCH-1 downto 0); -- Result o_valid : out std_logic; -- Result is valid o_busy : out std_logic -- Multiclock instruction under processing ); end; architecture arch_IntDiv of IntDiv is type RegistersType is record rv32 : std_logic; resid : std_logic; -- Compute residual flag invert : std_logic; -- invert result value before output busy : std_logic; ena : std_logic_vector(33 downto 0); qr : std_logic_vector(127 downto 0); divider : std_logic_vector(64 downto 0); result : std_logic_vector(RISCV_ARCH-1 downto 0); end record; signal r, rin : RegistersType; begin comb : process(i_nrst, i_ena, i_unsigned, i_residual, i_rv32, i_a1, i_a2, r) variable v : RegistersType; variable wb_diff1 : std_logic_vector(64 downto 0); variable wb_diff2 : std_logic_vector(64 downto 0); variable wb_qr1 : std_logic_vector(127 downto 0); variable wb_qr2 : std_logic_vector(127 downto 0); variable wb_a1 : std_logic_vector(RISCV_ARCH-1 downto 0); variable wb_a2 : std_logic_vector(RISCV_ARCH-1 downto 0); variable wb_divident : std_logic_vector(64 downto 0); variable wb_divider : std_logic_vector(64 downto 0); variable w_invert64 : std_logic; variable w_invert32 : std_logic; begin v := r; w_invert64 := '0'; w_invert32 := '0'; wb_divident(64) := '0'; wb_divider(64) := '0'; if i_rv32 = '1' then wb_a1(63 downto 32) := (others => '0'); wb_a2(63 downto 32) := (others => '0'); if i_unsigned = '1' or i_a1(31) = '0' then wb_a1(31 downto 0) := i_a1(31 downto 0); else wb_a1(31 downto 0) := (not i_a1(31 downto 0)) + 1; end if; if i_unsigned = '1' or i_a2(31) = '0' then wb_a2(31 downto 0) := i_a2(31 downto 0); else wb_a2(31 downto 0) := (not i_a2(31 downto 0)) + 1; end if; else if i_unsigned = '1' or i_a1(63) = '0' then wb_a1 := i_a1; else wb_a1 := (not i_a1) + 1; end if; if i_unsigned = '1' or i_a2(63) = '0' then wb_a2 := i_a2; else wb_a2 := (not i_a2) + 1; end if; end if; wb_divident(63 downto 0) := wb_a1; wb_divider(63 downto 0) := wb_a2; v.ena := r.ena(32 downto 0) & (i_ena and not r.busy); -- Level 2*i of 64: wb_diff1 := r.qr(127 downto 63) - r.divider; if wb_diff1(64) = '1' then wb_qr1 := r.qr(126 downto 0) & '0'; else wb_qr1 := wb_diff1(63 downto 0) & r.qr(62 downto 0) & '1'; end if; -- Level 2*i + 1 of 64: wb_diff2 := wb_qr1(127 downto 63) - r.divider; if wb_diff2(64) = '1' then wb_qr2 := wb_qr1(126 downto 0) & '0'; else wb_qr2 := wb_diff2(63 downto 0) & wb_qr1(62 downto 0) & '1'; end if; if i_ena = '1' then v.qr(127 downto 65) := (others => '0'); v.qr(64 downto 0) := wb_divident; v.divider := wb_divider; v.busy := '1'; v.rv32 := i_rv32; v.resid := i_residual; w_invert32 := not i_unsigned and ((not i_residual and (i_a1(31) xor i_a2(31))) or (i_residual and i_a1(31))); w_invert64 := not i_unsigned and ((not i_residual and (i_a1(63) xor i_a2(63))) or (i_residual and i_a1(63))); v.invert := (not i_rv32 and w_invert64) or (i_rv32 and w_invert32); elsif r.ena(32) = '1' then v.busy := '0'; if r.resid = '1' then if r.invert = '1' then v.result := (not r.qr(127 downto 64)) + 1; else v.result := r.qr(127 downto 64); end if; else if r.invert = '1' then v.result := (not r.qr(63 downto 0)) + 1; else v.result := r.qr(63 downto 0); end if; end if; elsif r.busy = '1' then v.qr := wb_qr2; end if; if i_nrst = '0' then v.result := (others => '0'); v.ena := (others => '0'); v.busy := '0'; v.rv32 := '0'; v.invert := '0'; v.qr := (others => '0'); v.resid := '0'; end if; o_res <= r.result; o_valid <= r.ena(33); o_busy <= r.busy; rin <= v; end process; -- registers: regs : process(i_clk) begin if rising_edge(i_clk) then r <= rin; end if; end process; end;