📄 alu_rtl.vhd
字号:
-------------------------------------------------------------------------------
-- 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 + -