⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alu_rtl.vhd

📁 Intel微处理器8088的VHDL实现
💻 VHD
📖 第 1 页 / 共 3 页
字号:
-------------------------------------------------------------------------------
--  CPU86 - VHDL CPU8088 IP core                                             --
--  Copyright (C) 2005-2008 HT-LAB                                           --
--                                                                           --
--  Contact/bugs : http://www.ht-lab.com/misc/feedback.html                  --
--  Web          : http://www.ht-lab.com                                     --
--                                                                           --
--  CPU86 is released as open-source under the Aladdin Free Public License.  --
--  Contact HT-Lab for commercial applications and/or support contracts.     --
--                                                                           --
--  Full details of the license can be found in the file "cpu86_license.txt" --
--  which is included in the distribution zip file.                          --
-------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
USE ieee.std_logic_arith.ALL;

USE work.cpu86pack.ALL;

ENTITY ALU IS
   PORT( 
      alu_inbusa : IN     std_logic_vector (15 DOWNTO 0);
      alu_inbusb : IN     std_logic_vector (15 DOWNTO 0);
      aluopr     : IN     std_logic_vector (6 DOWNTO 0);
      ax_s       : IN     std_logic_vector (15 DOWNTO 0);
      clk        : IN     std_logic;
      cx_s       : IN     std_logic_vector (15 DOWNTO 0);
      dx_s       : IN     std_logic_vector (15 DOWNTO 0);
      reset      : IN     std_logic;
      w          : IN     std_logic;
      wralu      : IN     std_logic;
      wrcc       : IN     std_logic;
      wrtemp     : IN     std_logic;
      alubus     : OUT    std_logic_vector (15 DOWNTO 0);
      ccbus      : OUT    std_logic_vector (15 DOWNTO 0);
      div_err    : OUT    std_logic
   );
END ALU ;

architecture rtl of alu is

component divider is                                    -- Generic Divider

generic( 
        WIDTH_DIVID : Integer := 32;                    --  Width Dividend
        WIDTH_DIVIS : Integer := 16;                    --  Width Divisor
        WIDTH_SHORT : Integer := 8);                    --  Check Overflow against short Byte/Word
port( 
        clk         : in   std_logic;                   -- System Clock, not used in this architecture   
        reset       : in   std_logic;                   -- Active high, not used in this architecture
        dividend    : in   std_logic_vector (WIDTH_DIVID-1 DOWNTO 0);
        divisor     : in   std_logic_vector (WIDTH_DIVIS-1 DOWNTO 0);
        quotient    : out  std_logic_vector (WIDTH_DIVIS-1 DOWNTO 0);  -- changed to 16 bits!! (S not D)
        remainder   : out  std_logic_vector (WIDTH_DIVIS-1 DOWNTO 0);
        twocomp     : in   std_logic;                   -- '1' = 2's Complement, '0' = Unsigned
        w           : in   std_logic;                   -- '0'=byte, '1'=word (cpu processor)
        overflow    : out  std_logic;                   -- '1' if div by 0 or overflow
        start       : in   std_logic;                   -- not used in this architecture
        done        : out  std_logic);                  -- not used in this architecture
end component divider;

component multiplier is                                 -- Generic Multiplier
 generic (WIDTH     : integer := 16);                   
port (multiplicant  : in   std_logic_vector (WIDTH-1 downto 0); 
      multiplier    : in   std_logic_vector (WIDTH-1 downto 0); 
      product       : out  std_logic_vector (WIDTH+WIDTH-1 downto 0);-- result
      twocomp       : in   std_logic);
end component multiplier;

signal  product_s   : std_logic_vector(31 downto 0);    -- result multiplier 

signal  dividend_s  : std_logic_vector(31 downto 0);    -- Input divider
signal  remainder_s : std_logic_vector(15 downto 0);    -- Divider result
signal  quotient_s  : std_logic_vector(15 downto 0);    -- Divider result
signal  divresult_s : std_logic_vector(31 DOWNTO 0);    -- Output divider to alubus
signal  div_err_s   : std_logic;                        -- Divide by 0 

signal  twocomp_s   : std_logic;                        -- Sign Extend for IMUL and IDIV
signal  wl_s        : std_logic;                        -- Latched w signal, used for muliplier/divider

signal  alubus_s    : std_logic_vector (15 DOWNTO 0);

signal  abus_s      : std_logic_vector(15 downto 0);        
signal  bbus_s      : std_logic_vector(15 downto 0);  
signal  dxbus_s     : std_logic_vector(15 downto 0);    -- DX register 

signal  addbbus_s   : std_logic_vector(15 downto 0);    -- bbus connected to full adder 
signal  cbus_s      : std_logic_vector(16 downto 0);    -- Carry Bus
signal  outbus_s    : std_logic_vector(15 downto 0);    -- outbus=abus+bbus

signal  sign16a_s   : std_logic_vector(15 downto 0);    -- sign extended alu_busa(7 downto 0)
signal  sign16b_s   : std_logic_vector(15 downto 0);    -- sign extended alu_busb(7 downto 0)
signal  sign32a_s   : std_logic_vector(15 downto 0);    -- 16 bits alu_busa(15) vector (CWD)

signal  aasbus_s    : std_logic_vector(15 downto 0);    -- used for AAS instruction
signal  aas1bus_s   : std_logic_vector(15 downto 0);    

signal  daabus_s    : std_logic_vector(7 downto 0);     -- used for DAA instruction
signal  dasbus_s    : std_logic_vector(7 downto 0);     -- used for DAS instruction

signal  aaabus_s    : std_logic_vector(15 downto 0);    -- used for AAA instruction
signal  aaa1bus_s   : std_logic_vector(15 downto 0);    

signal  aadbus_s    : std_logic_vector(15 downto 0);    -- used for AAD instruction
signal  aad1bus_s   : std_logic_vector(10 downto 0);    
signal  aad2bus_s   : std_logic_vector(10 downto 0);    

signal  setaas_s    : std_logic;                        -- '1' set CF & AF else both 0
signal  setaaa_s    : std_logic;                        -- '1' set CF & AF else both 0
signal  setdaa_s    : std_logic_vector(1 downto 0);     -- "11" set CF & AF 
signal  setdas_s    : std_logic_vector(1 downto 0);     -- "11" set CF & AF 

signal  bit4_s      : std_logic;                        -- used for AF flag
signal  cout_s      : std_logic;                    

signal  psrreg_s    : std_logic_vector(15 downto 0);    -- 16 bits flag register

signal  zflaglow_s  : std_logic;                        -- low byte zero flag (w=0)
signal  zflaghigh_s : std_logic;                        -- high byte zero flag (w=1)
signal  zeroflag_s  : std_logic;                        -- zero flag, asserted when zero

signal  c1flag_s    : std_logic;                        -- Asserted when CX=1(w=1) or CL=1(w=0)

signal  zflagdx_s   : std_logic;                        -- Result (DX) zero flag, asserted when not zero (used for mul/imul)

signal  zflagah_s   : std_logic;                        -- '1' if IMUL(15..8)/=0
signal  hflagah_s   : std_logic;                        -- Used for IMUL
signal  hflagdx_s   : std_logic;                        -- Used for IMUL

signal  overflow_s  : std_logic;
signal  parityflag_s: std_logic; 
signal  signflag_s  : std_logic;                        

alias   OFLAG       : std_logic is psrreg_s(11);
alias   DFLAG       : std_logic is psrreg_s(10);
alias   IFLAG       : std_logic is psrreg_s(9);
alias   TFLAG       : std_logic is psrreg_s(8);                           
alias   SFLAG       : std_logic is psrreg_s(7);
alias   ZFLAG       : std_logic is psrreg_s(6);
alias   AFLAG       : std_logic is psrreg_s(4);
alias   PFLAG       : std_logic is psrreg_s(2);
alias   CFLAG       : std_logic is psrreg_s(0);

signal  alureg_s    : std_logic_vector(31 downto 0);    -- 31 bits temp register for alu_inbusa & alu_inbusb
signal  alucout_s   : std_logic;                        -- ALUREG Carry Out signal

signal  alu_temp_s  : std_logic_vector(15 downto 0);    -- Temp/scratchpad register, use ALU_TEMP to select

signal  done_s      : std_logic;                        -- Serial divider conversion done
signal  startdiv_s  : std_logic;                        -- Serial divider start pulse

begin

ALUU1 : divider
    generic map (WIDTH_DIVID =>  32,  WIDTH_DIVIS =>  16, WIDTH_SHORT => 8)
    port map   (clk         => clk,
                reset       => reset,
                dividend    => dividend_s,              -- DX:AX
                divisor     => alureg_s(15 downto 0),   -- 0&byte/word
                quotient    => quotient_s,              -- 16 bits
                remainder   => remainder_s,             -- 16 bits
                twocomp     => twocomp_s,
                w           => wl_s,                    -- Byte/Word
                overflow    => div_err_s,               -- Divider Overflow. generate int0
                start       => startdiv_s,              -- start conversion, generated by proc      
                done        => done_s);                 -- conversion done, latch results

ALUU2 : multiplier
    generic map (WIDTH      =>  16)                     -- Result is 2*WIDTH bits
    port map   (multiplicant=> alureg_s(31 downto 16),      
                multiplier  => alureg_s(15 downto 0),                   -- 0&byte/word              
                product     => product_s,               -- 32 bits!
                twocomp     => twocomp_s);

-- changed for serial divider
dividend_s  <= X"000000"&alureg_s(23 downto 16) when aluopr=ALU_AAM else dxbus_s & alureg_s(31 downto 16);-- DX is sign extended for byte IDIV

-- start serial divider 1 cycle after wralu pulse received. The reason is that the dividend is loaded into the
-- accumulator thus the data must be valid when this happens.
process (clk, reset)
    begin 
        if reset='1' then
            startdiv_s <= '0';
        elsif rising_edge(clk) then
            if  (wralu='1' and (aluopr=ALU_DIV or aluopr=ALU_IDIV OR aluopr=ALU_AAM)) then
                startdiv_s <= '1';  
            else 
                startdiv_s <= '0';
            end if;
        end if;
end process;

----------------------------------------------------------------------------
-- Create Full adder
----------------------------------------------------------------------------   
fulladd: for bit_nr in 0 to 15 generate       
    outbus_s(bit_nr) <= abus_s(bit_nr) xor addbbus_s(bit_nr) xor cbus_s(bit_nr);

    cbus_s(bit_nr+1) <= (abus_s(bit_nr) and addbbus_s(bit_nr)) or
                        (abus_s(bit_nr) and cbus_s(bit_nr)) or
                        (addbbus_s(bit_nr) and cbus_s(bit_nr));
end generate fulladd;
      
bit4_s    <= cbus_s(4);  

sign16a_s <= alu_inbusa(7) &alu_inbusa(7) &alu_inbusa(7) &alu_inbusa(7)&alu_inbusa(7)&
             alu_inbusa(7) &alu_inbusa(7) &alu_inbusa(7) &alu_inbusa(7 downto 0);   
sign16b_s <= alu_inbusb(7) &alu_inbusb(7) &alu_inbusb(7) &alu_inbusb(7)&alu_inbusb(7)&
             alu_inbusb(7) &alu_inbusb(7) &alu_inbusb(7) &alu_inbusb(7 downto 0);
sign32a_s <= alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&
             alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&
             alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&alu_inbusa(15)&
             alu_inbusa(15);

-- Invert bus for subtract instructions
addbbus_s <= not bbus_s when ((aluopr=ALU_CMP) or (aluopr=ALU_CMP_SE) or (aluopr=ALU_CMPS) or (aluopr=ALU_DEC) 
                           or (aluopr=ALU_SBB) or (aluopr=ALU_SBB_SE) or (aluopr=ALU_PUSH) or (aluopr=ALU_SUB) 
                           or (aluopr=ALU_SUB_SE) or (aluopr=ALU_SCAS)) else bbus_s;


-- sign extend for IDIV and IMUL instructions           
twocomp_s <= '1' when  ((aluopr=ALU_IDIV) or (aluopr=ALU_IMUL) or
                        (aluopr=ALU_IDIV2)or (aluopr=ALU_IMUL2)) else '0';   

----------------------------------------------------------------------------
-- Sign Extend Logic abus & bbus & dxbus
----------------------------------------------------------------------------
process (w, alu_inbusa, alu_inbusb, sign16a_s, sign16b_s, aluopr, ax_s, alureg_s)
    begin 
        if (w='1') then                                 -- Word, no sign extend, unless signextend is specified
            case aluopr is  
                when ALU_CMPS =>
                    abus_s  <= alu_inbusa;              -- no sign extend
                    bbus_s  <= alureg_s(15 downto 0);   -- previous read ES:[DI]
                when ALU_NEG | ALU_NOT =>
                    abus_s  <= not(alu_inbusa);         -- NEG instruction, not(operand)+1
                    bbus_s  <= alu_inbusb;              -- 0001 (0000 for NOT)
                when ALU_ADD_SE | ALU_ADC_SE | ALU_SBB_SE | ALU_SUB_SE | ALU_CMP_SE |
                     ALU_OR_SE | ALU_AND_SE | ALU_XOR_SE=>
                    abus_s  <= alu_inbusa;              -- no sign extend
                    bbus_s  <= sign16b_s;               -- Sign extend on 8 bits immediate values (see O80I2RM)
                when others =>
                    abus_s  <= alu_inbusa;              -- no sign extend
                    bbus_s  <= alu_inbusb;
            end case;
        else                                                
            case aluopr is  
                when ALU_CMPS =>
                    abus_s  <= alu_inbusa;
                    bbus_s  <= alureg_s(15 downto 0);       
                when ALU_DIV | ALU_DIV2  =>
                    abus_s  <= ax_s;
                    bbus_s  <= alu_inbusb;
                when ALU_IDIV| ALU_IDIV2 =>
                    abus_s  <= ax_s;
                    bbus_s  <= sign16b_s;
                when ALU_MUL | ALU_MUL2 | ALU_SCAS  =>
                    abus_s  <= alu_inbusa;
                    bbus_s  <= alu_inbusb;
                when ALU_NEG | ALU_NOT =>
                    abus_s  <= not(alu_inbusa);         -- NEG instruction, not(operand)+1
                    bbus_s  <= alu_inbusb;              -- 0001 (0000 for NOT)
                when others =>
                    abus_s  <= sign16a_s;
                    bbus_s  <= sign16b_s;
            end case;                    
        end if;
end process; 

process (wl_s, aluopr, dx_s, alu_inbusa)                -- dxbus for DIV/IDIV only
    begin                   
        if (wl_s='1') then                              -- Word, no sign extend
            dxbus_s  <= dx_s;                   
        else                                            -- Byte  
            if (((aluopr=ALU_IDIV) or (aluopr=ALU_IDIV2)) and (alu_inbusa(15)='1')) then    -- signed DX<-SE(AX)/bbus<-SE(byte)
                dxbus_s <= X"FFFF";                     -- DX=FFFF (ignored for mul)
            else 
                dxbus_s <= X"0000";                     -- DX=0000 (ignored for mul)
            end if;
        end if;
end process;                         

----------------------------------------------------------------------------
-- Carry In logic
----------------------------------------------------------------------------
process (aluopr, psrreg_s)
    begin 
        case aluopr is
            when ALU_ADD | ALU_ADD_SE | ALU_INC | ALU_POP | ALU_NEG | ALU_NOT   

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -