OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /open8_urisc/trunk
    from Rev 317 to Rev 318
    Reverse comparison

Rev 317 → Rev 318

/VHDL/intdiv.vhd
0,0 → 1,134
-- Copyright (c)2023 Jeremy Seth Henry
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
-- * Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution,
-- where applicable (as part of a user interface, debugging port, etc.)
--
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-- VHDL units : intdiv
-- Description: Performs an integer division operation using a restoring
-- algorithm that produces both a quotient and a remainder.
-- Note that the Dividend and Divisor have the same bit width.
--
-- Algorithm:
-- 1: Initialize registers (Q = Dividend, M = Divisor, R = 0, N = number of bits in dividend)
-- 2: Shift R & Q (RQ) left by 1
-- 3: Calculate difference R = R - M
-- 4: Check the sign of the result.
-- If the MSB of RQ (R) is '0' (R >= M), then set the LSB of RQ (Q) to a '1'
-- If the MSB of RQ (R) is '1' (M > R) then restore R and set the LSB of Q to '0'
-- 5: Loop to step 2 while N < Div_Width (Dividend Width)
-- 6: Assign Q to Quotient and R to Remainder
--
-- Revision History
-- Author Date Change
------------------ -------- ---------------------------------------------------
-- Seth Henry 04/10/23 Initial Design
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
 
entity intdiv is
generic(
Div_Width : integer := 16;
Reset_Level : std_logic := '0'
);
port(
Clock : in std_logic;
Reset : in std_logic;
--
Enable : in std_logic;
Busy : out std_logic;
--
Dividend : in std_logic_vector(Div_Width - 1 downto 0);
Divisor : in std_logic_vector(Div_Width - 1 downto 0);
Quotient : out std_logic_vector(Div_Width - 1 downto 0);
Remainder : out std_logic_vector(Div_Width - 1 downto 0)
);
end entity;
 
architecture behave of intdiv is
 
-- RQ combines R & Q into a single register
signal RQ : std_logic_vector(Div_Width*2-1 downto 0) :=
(others => '0');
 
alias R is RQ(Div_Width*2-1 downto Div_Width);
alias Q is RQ(Div_Width-1 downto 0);
 
-- Dividend is assumed to be the same width as the Divisor
signal M : std_logic_vector(Div_Width - 1 downto 0) :=
(others => '0');
 
-- Difference result should be 1 bit larger than the Dividend to allow for
-- a sign bit
signal D : std_logic_vector(Div_Width downto 0) :=
(others => '0');
 
alias S is D(Div_Width);
 
constant LZ : std_logic_vector(Div_Width - 1 downto 0) :=
(others => '0');
 
signal N : integer range 0 to Div_Width := 0;
 
begin
 
Quotient <= Q;
Remainder <= R;
 
-- This statement combines the left shift logic with the subtraction.
-- Leading '0's are used to force both arguments to be positive.
D <= ('0' & RQ(Div_Width*2-2 downto Div_Width-1)) -
('0' & M);
 
Divide_proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
RQ <= (others => '0');
M <= (others => '0');
N <= 0;
Busy <= '0';
elsif( rising_edge(Clock) )then
Busy <= '0';
 
if( Enable = '1' )then
Busy <= '1';
N <= Div_Width;
RQ <= LZ & Dividend;
M <= Divisor;
end if;
 
if( N > 0 )then
Busy <= '1';
N <= N - 1;
-- Leave R set to R-M and set Q[0] to '1'
RQ <= D(Div_Width-1 downto 0) & -- New R
RQ(Div_Width-2 downto 0) & -- Q<<1
'1'; -- Q(0) = '1'
if( S = '1' )then
-- Restore R and set Q[0] to '0'
RQ <= RQ(Div_Width*2-2 downto 0) & '0';
end if;
end if;
end if;
end process;
 
end architecture;
/VHDL/o8_scale_conv.vhd
0,0 → 1,695
-- Copyright (c)2023 Jeremy Seth Henry
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
-- * Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution,
-- where applicable (as part of a user interface, debugging port, etc.)
--
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-- VHDL units : o8_scale_conv
-- Description: Performs the operation ACC = [(A*B)/C] + D, returning a 33-bit
-- value. Optionally converts this value into packed BCD format.
--
-- Note1: Operands A,B are 16-bit values. The output from this step is a 32-bit
-- value, which can be divided by Operand C, with the result added to
-- Operand D. Both operand C and D are 32-bit values.
-- Note2: If the operation type is '1', or SIGNED, then operand A,B, and D
-- will be treated as SIGNED values, while operand C remains UNSIGNED
-- If the operation type is '0', or UNSIGNED, all operands will be
-- treated as UNSIGNED values.
-- Note3: Setting Operand C to 0 or 1 will skip the division step. This
-- resolves the issue of divide by 0, as 0 will be treated as 1, as
-- well as saving time if the division isn't required.
--
-- Register Map:
-- Offset Bitfield Description Read/Write
-- 0x00 AAAAAAAA Operand A, Lower Byte RW
-- 0x01 AAAAAAAA Operand A, Upper Byte RW
-- 0x02 AAAAAAAA Operand B, Lower Byte RW
-- 0x03 AAAAAAAA Operand B, Upper Byte RW
-- 0x04 AAAAAAAA Operand C, Byte 0 RW
-- 0x05 AAAAAAAA Operand C, Byte 1 RW
-- 0x06 AAAAAAAA Operand C, Byte 2 RW
-- 0x07 AAAAAAAA Operand C, Byte 3 RW
-- 0x08 AAAAAAAA Operand D, Byte 0 RW
-- 0x09 AAAAAAAA Operand D, Byte 1 RW
-- 0x0A AAAAAAAA Operand D, Byte 2 RW
-- 0x0B AAAAAAAA Operand D, Byte 3 RW
 
-- 0x10 AAAAAAAA Accumulator, Byte 0 R0
-- 0x11 AAAAAAAA Accumulator, Byte 1 R0
-- 0x12 AAAAAAAA Accumulator, Byte 2 R0
-- 0x13 AAAAAAAA Accumulator, Byte 3 R0
-- 0x14 A------- Accumulator, Sign / Bit 32 R0
 
-- 0x18 AAAAAAAA BCD Data, Digits 1,0 RO
-- 0x19 AAAAAAAA BCD Data, Digits 3,2 RO
-- 0x1A AAAAAAAA BCD Data, Digits 5,4 RO
-- 0x1B AAAAAAAA BCD Data, Digits 7,6 RO
-- 0x1C AAAAAAAA BCD Data, Digits 9,8 RO
-- 0x1D A------- BCD Data, Sign [pos (0), neg (1)] R0
 
-- 0x1F C-----BA Control/Status RW
-- A = Operation Type:
-- Unsigned (0) / Signed (1)
-- B = BCD conversion (if set) (WR)*
-- BCD result valid if set (RD)
-- C = Conversion Status (1 = busy)
--
-- Note4: Setting bit 1 TRUE will enable the packed BCD conversion system
-- at the cost of ~3.5uS per conversion. If the most recent result
-- was converted, reading this bit will return a '1' to indicate
-- that the data is "fresh", or matches the raw result data.
-- Setting this bit FALSE will allow a new math operation to occur
-- WITHOUT altering the last BCD conversion, but will set this bit to
-- 0 on read to indicate that the BCD value is "stale", or no longer
-- matches the raw result data.
--
-- Revision History
-- Author Date Change
------------------ -------- ---------------------------------------------------
-- Seth Henry 04/10/23 Initial Design
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;
 
library work;
use work.open8_pkg.all;
use work.open8_cfg.all;
 
entity o8_scale_conv is
generic(
Address : ADDRESS_TYPE
);
port(
-- Bus IF Interface
Open8_Bus : in OPEN8_BUS_TYPE;
Write_Qual : in std_logic;
Rd_Data : out DATA_TYPE;
Interrupt : out std_logic
);
end entity;
 
architecture behave of o8_scale_conv is
 
-- Bus Interface Signals
 
alias Clock is Open8_Bus.Clock;
alias Reset is Open8_Bus.Reset;
alias uSec_Tick is Open8_Bus.uSec_Tick;
 
constant User_Addr : std_logic_vector(15 downto 5) :=
Address(15 downto 5);
 
alias Comp_Addr is Open8_Bus.Address(15 downto 5);
signal Addr_Match : std_logic := '0';
 
alias Reg_Sel_d is Open8_Bus.Address(4 downto 0);
signal Reg_Sel_q : std_logic_vector(4 downto 0) := (others => '0');
signal Wr_En_d : std_logic := '0';
signal Wr_En_q : std_logic := '0';
alias Wr_Data_d is Open8_Bus.Wr_Data;
signal Wr_Data_q : DATA_TYPE := x"00";
signal Rd_En_d : std_logic := '0';
signal Rd_En_q : std_logic := '0';
 
-- Operands A, B, and C are 16-bit with sign-extension, or 17-bit values
constant OPER_ABC_WIDTH : integer := 17;
 
signal OperandA : signed(OPER_ABC_WIDTH - 1 downto 0) :=
(others => '0');
alias OperandA_LB is OperandA(7 downto 0);
alias OperandA_UB is OperandA(15 downto 8);
alias OperandA_S is OperandA(15);
alias OperandA_SX is OperandA(OPER_ABC_WIDTH - 1 downto 16);
 
signal OperandB : signed(OPER_ABC_WIDTH - 1 downto 0) :=
(others => '0');
alias OperandB_LB is OperandB(7 downto 0);
alias OperandB_UB is OperandB(15 downto 8);
alias OperandB_S is OperandB(15);
alias OperandB_SX is OperandB(OPER_ABC_WIDTH - 1 downto 16);
 
-- The product will, by definition, be twice as wide as the input operands
 
constant MULT_WIDTH : integer := 2*OPER_ABC_WIDTH;
signal Product_AB : signed(MULT_WIDTH - 1 downto 0) :=
(others => '0');
 
-- The divider only needs a single bit for sign extension, so drop one
-- bit from the multiplier width
constant DIVIDER_WIDTH : integer := MULT_WIDTH - 1;
alias Operand_AB is Product_AB(DIVIDER_WIDTH - 1 downto 0);
 
signal OperandC : signed(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
alias OperandC_B0 is OperandC(7 downto 0);
alias OperandC_B1 is OperandC(15 downto 8);
alias OperandC_B2 is OperandC(23 downto 16);
alias OperandC_B3 is OperandC(31 downto 24);
alias OperandC_SX is OperandC(DIVIDER_WIDTH - 1 downto 32);
 
signal OperandABC : signed(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
signal OperandD : signed(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
alias OperandD_B0 is OperandD(7 downto 0);
alias OperandD_B1 is OperandD(15 downto 8);
alias OperandD_B2 is OperandD(23 downto 16);
alias OperandD_B3 is OperandD(31 downto 24);
alias OperandD_S is OperandD(31);
alias OperandD_SX is OperandD(DIVIDER_WIDTH - 1 downto 32);
 
signal Accumulator : signed(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
alias RAW_Data_B0 is Accumulator(7 downto 0);
alias RAW_Data_B1 is Accumulator(15 downto 8);
alias RAW_Data_B2 is Accumulator(23 downto 16);
alias RAW_Data_B3 is Accumulator(31 downto 24);
alias RAW_Sign_MSB is Accumulator(32);
 
-- Conversion control signals
 
type CONV_STATES is ( IDLE,
MULT_WAIT,
DIV_START, DIV_WAIT, DIV_SKIP,
ACCUM_WAIT,
DAA_INIT, DAA_NEGATE,
DAA_STEP1, DAA_WAIT1,
DAA_STEP2, DAA_WAIT2,
DAA_STEP3, DAA_WAIT3,
DAA_STEP4, DAA_WAIT4,
DAA_STEP5, DAA_WAIT5,
DAA_STEP6, DAA_WAIT6,
DAA_STEP7, DAA_WAIT7,
DAA_STEP8, DAA_WAIT8,
DAA_STEP9, DAA_WAIT9,
DAA_DONE );
 
signal Conv_State : CONV_STATES := IDLE;
 
signal CNV_En : std_logic := '0';
signal DAA_En : std_logic := '0';
signal CNV_Busy : std_logic := '0';
 
signal CNV_Mode : std_logic := '0';
 
constant CNV_SIGNED : std_logic := '1';
constant CNV_UNSIGNED : std_logic := '0';
 
signal CNV_Done : std_logic := '0';
 
-- Decimal adjust / BCD conversion signals
 
signal DAA_Valid : std_logic := '0';
 
constant DAA_ST1_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(1000000000,DIVIDER_WIDTH);
 
constant DAA_ST2_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(100000000,DIVIDER_WIDTH);
 
constant DAA_ST3_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(10000000,DIVIDER_WIDTH);
 
constant DAA_ST4_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(1000000,DIVIDER_WIDTH);
 
constant DAA_ST5_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(100000,DIVIDER_WIDTH);
 
constant DAA_ST6_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(10000,DIVIDER_WIDTH);
 
constant DAA_ST7_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(1000,DIVIDER_WIDTH);
 
constant DAA_ST8_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(100,DIVIDER_WIDTH);
 
constant DAA_ST9_DIV : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
conv_std_logic_vector(10,DIVIDER_WIDTH);
 
signal DAA_Next : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
signal DAA_Sign : std_logic := '0';
 
signal DAA_Buffer : std_logic_vector(39 downto 0) := (others => '0');
 
alias DAA_Data_B0 is DAA_Buffer(7 downto 0);
alias DAA_Data_B1 is DAA_Buffer(15 downto 8);
alias DAA_Data_B2 is DAA_Buffer(23 downto 16);
alias DAA_Data_B3 is DAA_Buffer(31 downto 24);
alias DAA_Data_B4 is DAA_Buffer(39 downto 32);
 
alias DAA_Digit_0 is DAA_Buffer( 3 downto 0);
alias DAA_Digit_1 is DAA_Buffer( 7 downto 4);
alias DAA_Digit_2 is DAA_Buffer(11 downto 8);
alias DAA_Digit_3 is DAA_Buffer(15 downto 12);
alias DAA_Digit_4 is DAA_Buffer(19 downto 16);
alias DAA_Digit_5 is DAA_Buffer(23 downto 20);
alias DAA_Digit_6 is DAA_Buffer(27 downto 24);
alias DAA_Digit_7 is DAA_Buffer(31 downto 28);
alias DAA_Digit_8 is DAA_Buffer(35 downto 32);
alias DAA_Digit_9 is DAA_Buffer(39 downto 36);
 
-- Integer divide unit signals
 
signal Div_Enable : std_logic := '0';
signal Div_Busy : std_logic := '0';
 
signal Dividend : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
signal Divisor : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
signal Quotient : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
signal Remainder : std_logic_vector(DIVIDER_WIDTH - 1 downto 0) :=
(others => '0');
 
begin
 
Addr_Match <= '1' when Comp_Addr = User_Addr else '0';
Wr_En_d <= Addr_Match and Open8_Bus.Wr_En and Write_Qual;
Rd_En_d <= Addr_Match and Open8_Bus.Rd_En;
 
reg_proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
Reg_Sel_q <= (others => '0');
Wr_En_q <= '0';
Wr_Data_q <= x"00";
Rd_En_q <= '0';
Rd_Data <= OPEN8_NULLBUS;
 
OperandA <= (others => '0');
OperandB <= (others => '0');
OperandC <= (others => '0');
OperandD <= (others => '0');
 
CNV_En <= '0';
DAA_En <= '0';
CNV_Mode <= '0';
CNV_Busy <= '0';
 
Interrupt <= '0';
 
elsif( rising_edge(Clock) )then
Reg_Sel_q <= Reg_Sel_d;
 
Wr_En_q <= Wr_En_d;
Wr_Data_q <= Wr_Data_d;
 
CNV_En <= '0';
 
if( Wr_En_q = '1' )then
case( Reg_Sel_q )is
when "00000" =>
OperandA_LB <= signed(Wr_Data_q);
when "00001" =>
OperandA_UB <= signed(Wr_Data_q);
when "00010" =>
OperandB_LB <= signed(Wr_Data_q);
when "00011" =>
OperandB_UB <= signed(Wr_Data_q);
when "00100" =>
OperandC_B0 <= signed(Wr_Data_q);
when "00101" =>
OperandC_B1 <= signed(Wr_Data_q);
when "00110" =>
OperandC_B2 <= signed(Wr_Data_q);
when "00111" =>
OperandC_B3 <= signed(Wr_Data_q);
when "01000" =>
OperandD_B0 <= signed(Wr_Data_q);
when "01001" =>
OperandD_B1 <= signed(Wr_Data_q);
when "01010" =>
OperandD_B2 <= signed(Wr_Data_q);
when "01011" =>
OperandD_B3 <= signed(Wr_Data_q);
 
when "11111" =>
CNV_Mode <= Wr_Data_q(0);
DAA_En <= Wr_Data_q(1);
CNV_En <= '1';
CNV_Busy <= '1';
when others => null;
end case;
end if;
 
Interrupt <= '0';
if( CNV_Done = '1' )then
CNV_Busy <= '0';
Interrupt <= '1';
end if;
 
OperandA_SX <= (others => '0');
OperandB_SX <= (others => '0');
OperandC_SX <= (others => '0');
OperandD_SX <= (others => '0');
 
if( CNV_Mode = CNV_SIGNED )then
OperandA_SX <= (others => OperandA_S);
OperandB_SX <= (others => OperandB_S);
OperandD_SX <= (others => OperandD_S);
end if;
 
Rd_En_q <= Rd_En_d;
Rd_Data <= OPEN8_NULLBUS;
if( Rd_En_q = '1' )then
case( Reg_Sel_q )is
-- Input operands
when "00000" =>
Rd_Data <= std_logic_vector(OperandA_LB);
when "00001" =>
Rd_Data <= std_logic_vector(OperandA_UB);
when "00010" =>
Rd_Data <= std_logic_vector(OperandB_LB);
when "00011" =>
Rd_Data <= std_logic_vector(OperandB_UB);
when "00100" =>
Rd_Data <= std_logic_vector(OperandC_B0);
when "00101" =>
Rd_Data <= std_logic_vector(OperandC_B1);
when "00110" =>
Rd_Data <= std_logic_vector(OperandC_B2);
when "00111" =>
Rd_Data <= std_logic_vector(OperandC_B3);
when "01000" =>
Rd_Data <= std_logic_vector(OperandD_B0);
when "01001" =>
Rd_Data <= std_logic_vector(OperandD_B1);
when "01010" =>
Rd_Data <= std_logic_vector(OperandD_B2);
when "01011" =>
Rd_Data <= std_logic_vector(OperandD_B3);
 
-- Raw results
when "10000" =>
Rd_Data <= std_logic_vector(RAW_Data_B0);
when "10001" =>
Rd_Data <= std_logic_vector(RAW_Data_B1);
when "10010" =>
Rd_Data <= std_logic_vector(RAW_Data_B2);
when "10011" =>
Rd_Data <= std_logic_vector(RAW_Data_B3);
when "10100" =>
Rd_Data(7) <= RAW_Sign_MSB;
 
-- BCD Conversion
when "11000" =>
Rd_Data <= DAA_Data_B0;
when "11001" =>
Rd_Data <= DAA_Data_B1;
when "11010" =>
Rd_Data <= DAA_Data_B2;
when "11011" =>
Rd_Data <= DAA_Data_B3;
when "11100" =>
Rd_Data <= DAA_Data_B4;
when "11101" =>
Rd_Data(7) <= DAA_Sign;
 
-- Control/Status
when "11111" =>
Rd_Data(0) <= CNV_Mode;
Rd_Data(1) <= DAA_Valid;
Rd_Data(7) <= CNV_Busy;
when others => null;
end case;
end if;
 
end if;
end process;
 
Conversion_FSM_proc: process( Clock, Reset )
begin
if( Reset = Reset_Level )then
Conv_State <= IDLE;
Div_Enable <= '0';
Dividend <= (others => '0');
Divisor <= (others => '0');
OperandABC <= (others => '0');
Accumulator <= (others => '0');
DAA_Sign <= '0';
DAA_Buffer <= (others => '0');
DAA_Next <= (others => '0');
CNV_Done <= '0';
elsif( rising_edge(Clock) )then
 
Div_Enable <= '0';
CNV_Done <= '0';
 
case Conv_State is
when IDLE =>
if( CNV_En = '1' )then
Conv_State <= MULT_WAIT;
end if;
 
when MULT_WAIT =>
-- Skip division if the operand is < 2
Conv_State <= DIV_SKIP;
if( OperandC > 1 )then
Conv_State <= DIV_START;
end if;
 
when DIV_START =>
Div_Enable <= '1';
Dividend <= std_logic_vector(Operand_AB);
Divisor <= std_logic_vector(OperandC);
if( Div_Busy = '1' )then
Conv_State <= DIV_WAIT;
end if;
 
when DIV_WAIT =>
if( Div_Busy = '0' )then
OperandABC <= signed(Quotient);
Conv_State <= ACCUM_WAIT;
end if;
 
when DIV_SKIP =>
OperandABC <= Operand_AB;
Conv_State <= ACCUM_WAIT;
 
when ACCUM_WAIT =>
Conv_State <= DAA_INIT;
if( DAA_En = '0' )then
DAA_Valid <= '0';
CNV_Done <= '1';
Conv_State <= IDLE;
end if;
 
when DAA_INIT =>
DAA_Sign <= '0';
DAA_Next <= std_logic_vector(Accumulator);
Conv_State <= DAA_STEP1;
if( RAW_Sign_MSB = '1' and CNV_Mode = CNV_SIGNED )then
Conv_State <= DAA_NEGATE;
end if;
 
when DAA_NEGATE =>
DAA_Sign <= '1';
DAA_Next <= (not DAA_Next) + 1;
Conv_State <= DAA_STEP1;
 
when DAA_STEP1 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST1_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT1;
end if;
 
when DAA_WAIT1 =>
if( DIV_Busy = '0' )then
DAA_Digit_9 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP2;
end if;
 
when DAA_STEP2 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST2_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT2;
end if;
 
when DAA_WAIT2 =>
if( DIV_Busy = '0' )then
DAA_Digit_8 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP3;
end if;
 
when DAA_STEP3 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST3_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT3;
end if;
 
when DAA_WAIT3 =>
if( DIV_Busy = '0' )then
DAA_Digit_7 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP4;
end if;
 
when DAA_STEP4 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST4_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT4;
end if;
 
when DAA_WAIT4 =>
if( DIV_Busy = '0' )then
DAA_Digit_6 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP5;
end if;
 
when DAA_STEP5 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST5_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT5;
end if;
 
when DAA_WAIT5 =>
if( DIV_Busy = '0' )then
DAA_Digit_5 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP6;
end if;
 
when DAA_STEP6 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST6_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT6;
end if;
 
when DAA_WAIT6 =>
if( DIV_Busy = '0' )then
DAA_Digit_4 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP7;
end if;
 
when DAA_STEP7 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST7_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT7;
end if;
 
when DAA_WAIT7 =>
if( DIV_Busy = '0' )then
DAA_Digit_3 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP8;
end if;
 
when DAA_STEP8 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST8_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT8;
end if;
 
when DAA_WAIT8 =>
if( DIV_Busy = '0' )then
DAA_Digit_2 <= Quotient(3 downto 0);
DAA_Next <= Remainder;
Conv_State <= DAA_STEP9;
end if;
 
when DAA_STEP9 =>
Dividend <= DAA_Next;
Divisor <= DAA_ST9_DIV;
Div_Enable <= '1';
if( DIV_Busy = '1' )then
Conv_State <= DAA_WAIT9;
end if;
 
when DAA_WAIT9 =>
if( DIV_Busy = '0' )then
DAA_Digit_1 <= Quotient(3 downto 0);
DAA_Digit_0 <= Remainder(3 downto 0);
Conv_State <= DAA_DONE;
end if;
 
when DAA_DONE =>
DAA_Valid <= '1';
CNV_Done <= '1';
Conv_State <= IDLE;
 
when others => null;
end case;
 
Product_AB <= OperandA * OperandB;
Accumulator <= OperandABC + OperandD;
 
end if;
end process;
 
-- Mult_proc: process( Clock)
-- begin
-- if( rising_edge(Clock) )then
-- Product_AB <= OperandA * OperandB;
-- end if;
-- end process;
 
U_DIV : entity work.intdiv
generic map(
Div_Width => DIVIDER_WIDTH,
Reset_Level => Reset_Level
)
port map(
Clock => Clock,
Reset => Reset,
--
Enable => Div_Enable,
Busy => Div_Busy,
--
Dividend => Dividend,
Divisor => Divisor,
Quotient => Quotient,
Remainder => Remainder
);
 
end architecture;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.