mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-01-18 17:06:57 +00:00
477 lines
20 KiB
VHDL
477 lines
20 KiB
VHDL
-------------------------------------------------------------------------------
|
|
-- CPU86 - VHDL CPU8088 IP core --
|
|
-- Copyright (C) 2002-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 GNU GPL license. This means --
|
|
-- that designs based on CPU86 must be distributed in full source code --
|
|
-- under the same license. Contact HT-Lab for commercial applications where --
|
|
-- source-code distribution is not desirable. --
|
|
-- --
|
|
-------------------------------------------------------------------------------
|
|
-- --
|
|
-- This library is free software; you can redistribute it and/or --
|
|
-- modify it under the terms of the GNU Lesser General Public --
|
|
-- License as published by the Free Software Foundation; either --
|
|
-- version 2.1 of the License, or (at your option) any later version. --
|
|
-- --
|
|
-- This library is distributed in the hope that it will be useful, --
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
|
|
-- Lesser General Public License for more details. --
|
|
-- --
|
|
-- Full details of the license can be found in the file "copying.txt". --
|
|
-- --
|
|
-- You should have received a copy of the GNU Lesser General Public --
|
|
-- License along with this library; if not, write to the Free Software --
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --
|
|
-- --
|
|
-------------------------------------------------------------------------------
|
|
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.ALL;
|
|
USE ieee.std_logic_arith.ALL;
|
|
USE ieee.std_logic_unsigned.ALL;
|
|
|
|
USE work.cpu86pack.ALL;
|
|
|
|
ENTITY datapath IS
|
|
PORT(
|
|
clk : IN std_logic;
|
|
clrop : IN std_logic;
|
|
instr : IN instruction_type;
|
|
iomem : IN std_logic;
|
|
mdbus_in : IN std_logic_vector (15 DOWNTO 0);
|
|
path : IN path_in_type;
|
|
reset : IN std_logic;
|
|
wrpath : IN write_in_type;
|
|
dbusdp_out : OUT std_logic_vector (15 DOWNTO 0);
|
|
eabus : OUT std_logic_vector (15 DOWNTO 0);
|
|
segbus : OUT std_logic_vector (15 DOWNTO 0);
|
|
status : OUT status_out_type
|
|
);
|
|
END datapath ;
|
|
|
|
|
|
ARCHITECTURE struct OF datapath IS
|
|
|
|
-- Internal signal declarations
|
|
SIGNAL alu_inbusa : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL alu_inbusb : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL alubus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL aluopr : std_logic_vector(6 DOWNTO 0);
|
|
SIGNAL ax_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL bp_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL bx_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL ccbus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL cs_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL cx_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL data_in : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL di_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL dibus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL dimux : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL disp : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL dispmux : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL div_err : std_logic;
|
|
SIGNAL domux : std_logic_vector(1 DOWNTO 0);
|
|
SIGNAL ds_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL dx_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL ea : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL eamux : std_logic_vector(3 DOWNTO 0);
|
|
SIGNAL es_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL ipbus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL ipreg : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL nbreq : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL opmux : std_logic_vector(1 DOWNTO 0);
|
|
SIGNAL rm : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL sdbus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL segop : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL selalua : std_logic_vector(3 DOWNTO 0);
|
|
SIGNAL selalub : std_logic_vector(3 DOWNTO 0);
|
|
SIGNAL seldreg : std_logic_vector(2 DOWNTO 0);
|
|
SIGNAL selds : std_logic;
|
|
SIGNAL selsreg : std_logic_vector(1 DOWNTO 0);
|
|
SIGNAL si_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL sibus : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL simux : std_logic_vector(1 DOWNTO 0);
|
|
SIGNAL sp_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL ss_s : std_logic_vector(15 DOWNTO 0);
|
|
SIGNAL w : std_logic;
|
|
SIGNAL wralu : std_logic;
|
|
SIGNAL wrcc : std_logic;
|
|
SIGNAL wrd : std_logic;
|
|
SIGNAL wrip : std_logic;
|
|
SIGNAL wrop : std_logic;
|
|
SIGNAL wrs : std_logic;
|
|
SIGNAL wrtemp : std_logic;
|
|
SIGNAL xmod : std_logic_vector(1 DOWNTO 0);
|
|
|
|
-- Implicit buffer signal declarations
|
|
SIGNAL eabus_internal : std_logic_vector (15 DOWNTO 0);
|
|
|
|
|
|
signal domux_s : std_logic_vector(2 downto 0);
|
|
signal opreg_s : std_logic_vector(1 downto 0); -- Override Segment Register
|
|
signal opflag_s : std_logic; -- set if segment override in progress
|
|
signal eam_s : std_logic_vector(15 downto 0);
|
|
signal segsel_s : std_logic_vector(5 downto 0); -- segbus select
|
|
signal int0cs_s : std_logic;
|
|
|
|
-- Component Declarations
|
|
COMPONENT ALU
|
|
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 COMPONENT;
|
|
COMPONENT dataregfile
|
|
PORT (
|
|
dibus : IN std_logic_vector (15 DOWNTO 0);
|
|
selalua : IN std_logic_vector (3 DOWNTO 0);
|
|
selalub : IN std_logic_vector (3 DOWNTO 0);
|
|
seldreg : IN std_logic_vector (2 DOWNTO 0);
|
|
w : IN std_logic ;
|
|
wrd : IN std_logic ;
|
|
alu_inbusa : OUT std_logic_vector (15 DOWNTO 0);
|
|
alu_inbusb : OUT std_logic_vector (15 DOWNTO 0);
|
|
bp_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
bx_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
di_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
si_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
reset : IN std_logic ;
|
|
clk : IN std_logic ;
|
|
data_in : IN std_logic_vector (15 DOWNTO 0);
|
|
mdbus_in : IN std_logic_vector (15 DOWNTO 0);
|
|
sp_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
ax_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
cx_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
dx_s : OUT std_logic_vector (15 DOWNTO 0)
|
|
);
|
|
END COMPONENT;
|
|
COMPONENT ipregister
|
|
PORT (
|
|
clk : IN std_logic ;
|
|
ipbus : IN std_logic_vector (15 DOWNTO 0);
|
|
reset : IN std_logic ;
|
|
wrip : IN std_logic ;
|
|
ipreg : OUT std_logic_vector (15 DOWNTO 0)
|
|
);
|
|
END COMPONENT;
|
|
COMPONENT segregfile
|
|
PORT (
|
|
selsreg : IN std_logic_vector (1 DOWNTO 0);
|
|
sibus : IN std_logic_vector (15 DOWNTO 0);
|
|
wrs : IN std_logic ;
|
|
reset : IN std_logic ;
|
|
clk : IN std_logic ;
|
|
sdbus : OUT std_logic_vector (15 DOWNTO 0);
|
|
dimux : IN std_logic_vector (2 DOWNTO 0);
|
|
es_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
cs_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
ss_s : OUT std_logic_vector (15 DOWNTO 0);
|
|
ds_s : OUT std_logic_vector (15 DOWNTO 0)
|
|
);
|
|
END COMPONENT;
|
|
|
|
|
|
BEGIN
|
|
|
|
dimux <= path.datareg_input(6 downto 4); -- Data Register Input Path
|
|
w <= path.datareg_input(3);
|
|
seldreg <= path.datareg_input(2 downto 0);
|
|
|
|
selalua <= path.alu_operation(14 downto 11); -- ALU Path
|
|
selalub <= path.alu_operation(10 downto 7);
|
|
aluopr <= path.alu_operation(6 downto 0);
|
|
|
|
domux <= path.dbus_output; -- Data Output Path
|
|
|
|
simux <= path.segreg_input(3 downto 2); -- Segment Register Input Path
|
|
selsreg <= path.segreg_input(1 downto 0);
|
|
|
|
dispmux <= path.ea_output(9 downto 7); -- select ipreg addition
|
|
eamux <= path.ea_output(6 downto 3); -- 4 bits
|
|
segop <= path.ea_output(2 downto 0); -- segop(2)=override flag
|
|
|
|
wrd <= wrpath.wrd;
|
|
wralu <= wrpath.wralu;
|
|
wrcc <= wrpath.wrcc;
|
|
wrs <= wrpath.wrs;
|
|
wrip <= wrpath.wrip;
|
|
wrop <= wrpath.wrop;
|
|
wrtemp<= wrpath.wrtemp;
|
|
|
|
status.ax <= ax_s;
|
|
status.cx_one <= '1' when (cx_s=X"0001") else '0';
|
|
status.cx_zero <= '1' when (cx_s=X"0000") else '0';
|
|
status.cl <= cx_s(7 downto 0); -- used for shift/rotate
|
|
status.flag <= ccbus;
|
|
status.div_err <= div_err; -- Divider overflow
|
|
|
|
disp <= instr.disp;
|
|
data_in <= instr.data;
|
|
nbreq <= instr.nb;
|
|
rm <= instr.rm;
|
|
xmod <= instr.xmod;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Determine effective address
|
|
----------------------------------------------------------------------------
|
|
process (rm, ax_s,bx_s,cx_s,dx_s,bp_s,sp_s,si_s,di_s,disp,xmod)
|
|
begin
|
|
case rm is
|
|
when "000" => if xmod="11" then eam_s <= ax_s;
|
|
else eam_s <= bx_s + si_s + disp;
|
|
end if;
|
|
selds<='1';
|
|
when "001" => if xmod="11" then eam_s <= cx_s;
|
|
else eam_s <= bx_s + di_s + disp;
|
|
end if;
|
|
selds<='1';
|
|
when "010" => if xmod="11" then eam_s <= dx_s;
|
|
else eam_s <= bp_s + si_s + disp;
|
|
end if;
|
|
selds<='0';
|
|
when "011" => if xmod="11" then eam_s <= bx_s;
|
|
else eam_s <= bp_s + di_s + disp;
|
|
end if;
|
|
selds<='0';
|
|
when "100" => if xmod="11" then eam_s <= sp_s;
|
|
else eam_s <= si_s + disp;
|
|
end if;
|
|
selds<='1';
|
|
when "101" => if xmod="11" then eam_s <= bp_s;
|
|
else eam_s <= di_s + disp;
|
|
end if;
|
|
selds<='1';
|
|
when "110" => if xmod="00" then
|
|
eam_s <= disp;
|
|
selds <='1';
|
|
elsif xmod="11" then
|
|
eam_s <= si_s;
|
|
selds <='1';
|
|
else
|
|
eam_s <= bp_s + disp;
|
|
selds <='0'; -- Use SS
|
|
end if;
|
|
|
|
when others=> if xmod="11" then eam_s <= di_s;
|
|
else eam_s <= bx_s + disp;
|
|
end if;
|
|
selds<='1';
|
|
end case;
|
|
end process;
|
|
|
|
ea<=eam_s;
|
|
|
|
process(data_in,eabus_internal,alubus,mdbus_in,simux)
|
|
begin
|
|
case simux is
|
|
when "00" => sibus <= data_in;
|
|
when "01" => sibus <= eabus_internal;
|
|
when "10" => sibus <= alubus;
|
|
when others => sibus <= mdbus_in;
|
|
end case;
|
|
end process;
|
|
|
|
process(dispmux,nbreq,disp,mdbus_in,ipreg,eabus_internal)
|
|
begin
|
|
case dispmux is
|
|
when "000" => ipbus <= ("0000000000000"&nbreq) + ipreg;
|
|
when "001" => ipbus <= (("0000000000000"&nbreq)+disp) + ipreg;
|
|
when "011" => ipbus <= disp; -- disp contains new IP value
|
|
when "100" => ipbus <= eabus_internal; -- ipbus=effective address
|
|
when "101" => ipbus <= ipreg; -- bodge to get ipreg onto ipbus
|
|
when others => ipbus <= mdbus_in;
|
|
end case;
|
|
end process;
|
|
|
|
domux_s <= eabus_internal(0) & domux;
|
|
|
|
process(domux_s, alubus,ccbus, dibus, ipbus)
|
|
begin
|
|
case domux_s is
|
|
when "000" => dbusdp_out <= alubus; -- Even
|
|
when "001" => dbusdp_out <= ccbus;
|
|
when "010" => dbusdp_out <= dibus;
|
|
when "011" => dbusdp_out <= ipbus; -- CALL Instruction
|
|
when "100" => dbusdp_out <= alubus(7 downto 0)& alubus(15 downto 8); -- Odd
|
|
when "101" => dbusdp_out <= ccbus(7 downto 0) & ccbus(15 downto 8);
|
|
when "110" => dbusdp_out <= dibus(7 downto 0) & dibus(15 downto 8);
|
|
when others => dbusdp_out <= ipbus(7 downto 0) & ipbus(15 downto 8);
|
|
end case;
|
|
end process;
|
|
|
|
-- Write Prefix Register
|
|
process(clk,reset)
|
|
begin
|
|
if (reset = '1') then
|
|
opreg_s <= "01"; -- Default CS Register
|
|
opflag_s<= '0'; -- Clear Override Prefix Flag
|
|
elsif rising_edge(clk) then
|
|
if wrop='1' then
|
|
opreg_s <= segop(1 downto 0); -- Set override register
|
|
opflag_s<= '1'; -- segop(2); -- Set flag
|
|
elsif clrop='1' then
|
|
opreg_s <= "11"; -- Default Data Segment Register
|
|
opflag_s<= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
process (opflag_s,opreg_s,selds,eamux,segop)
|
|
begin
|
|
if opflag_s='1' and segop(2)='0' then -- Prefix register set and disable override not set?
|
|
opmux <= opreg_s(1 downto 0); -- Set mux to override prefix reg
|
|
elsif eamux(3)='1' then
|
|
opmux <= eamux(1 downto 0);
|
|
elsif eamux(0)='0' then
|
|
opmux <= "01"; -- Select CS for IP
|
|
else
|
|
opmux <= '1'&selds; -- DS if selds=1 else SS
|
|
end if;
|
|
end process;
|
|
|
|
process(dimux, data_in,alubus,mdbus_in,sdbus,eabus_internal)
|
|
begin
|
|
case dimux is
|
|
when "000" => dibus <= data_in; -- Operand
|
|
when "001" => dibus <= eabus_internal;-- Offset
|
|
when "010" => dibus <= alubus; -- Output ALU
|
|
when "011" => dibus <= mdbus_in; -- Memory Bus
|
|
when others => dibus <= sdbus; -- Segment registers
|
|
end case;
|
|
end process;
|
|
|
|
int0cs_s <= '1' when eamux(3 downto 1)="011" else '0';
|
|
segsel_s <= iomem & int0cs_s & eamux(2 downto 1) & opmux; -- 5 bits
|
|
|
|
process(segsel_s,es_s,cs_s,ss_s,ds_s) -- Segment Output Mux
|
|
begin
|
|
case segsel_s is
|
|
when "000000" => segbus <= es_s; -- 00**, opmux select register
|
|
when "000001" => segbus <= cs_s;
|
|
when "000010" => segbus <= ss_s;
|
|
when "000011" => segbus <= ds_s;
|
|
when "000100" => segbus <= es_s; -- 01**, opmux select register
|
|
when "000101" => segbus <= cs_s;
|
|
when "000110" => segbus <= ss_s;
|
|
when "000111" => segbus <= ds_s;
|
|
when "001000" => segbus <= ss_s; -- 10**=SS, used for PUSH& POP
|
|
when "001001" => segbus <= ss_s;
|
|
when "001010" => segbus <= ss_s;
|
|
when "001011" => segbus <= ss_s;
|
|
when "001100" => segbus <= es_s; -- 01**, opmux select register
|
|
when "001101" => segbus <= cs_s;
|
|
when "001110" => segbus <= ss_s;
|
|
when "001111" => segbus <= ds_s;
|
|
when others => segbus <= ZEROVECTOR_C(15 downto 0);-- IN/OUT instruction 0x0000:PORT/DX
|
|
end case;
|
|
end process;
|
|
|
|
-- Offset Mux
|
|
-- Note ea*4 required if non-32 bits memory access is used(?)
|
|
-- Currently CS &IP are read in one go (fits 32 bits)
|
|
process(ipreg,ea,sp_s,dx_s,eamux,si_s,di_s,bx_s,ax_s)
|
|
begin
|
|
case eamux is
|
|
when "0000" => eabus_internal <= ipreg;--ipbus;--ipreg;
|
|
when "0001" => eabus_internal <= ea;
|
|
when "0010" => eabus_internal <= dx_s;
|
|
when "0011" => eabus_internal <= ea + "10"; -- for call mem32/int
|
|
when "0100" => eabus_internal <= sp_s; -- 10* select SP_S
|
|
when "0101" => eabus_internal <= sp_s;
|
|
when "0110" => eabus_internal <= ea(13 downto 0)&"00";
|
|
when "0111" => eabus_internal <=(ea(13 downto 0)&"00") + "10"; -- for int
|
|
when "1000" => eabus_internal <= di_s; -- Select ES:DI
|
|
when "1011" => eabus_internal <= si_s; -- Select DS:SI
|
|
when "1001" => eabus_internal <= ea; -- added for JMP SI instruction
|
|
when "1111" => eabus_internal <= bx_s + (X"00"&ax_s(7 downto 0)); -- XLAT instruction
|
|
when others => eabus_internal <= DONTCARE(15 downto 0);
|
|
end case;
|
|
end process;
|
|
|
|
-- Instance port mappings.
|
|
I6 : ALU
|
|
PORT MAP (
|
|
alu_inbusa => alu_inbusa,
|
|
alu_inbusb => alu_inbusb,
|
|
aluopr => aluopr,
|
|
ax_s => ax_s,
|
|
clk => clk,
|
|
cx_s => cx_s,
|
|
dx_s => dx_s,
|
|
reset => reset,
|
|
w => w,
|
|
wralu => wralu,
|
|
wrcc => wrcc,
|
|
wrtemp => wrtemp,
|
|
alubus => alubus,
|
|
ccbus => ccbus,
|
|
div_err => div_err
|
|
);
|
|
I0 : dataregfile
|
|
PORT MAP (
|
|
dibus => dibus,
|
|
selalua => selalua,
|
|
selalub => selalub,
|
|
seldreg => seldreg,
|
|
w => w,
|
|
wrd => wrd,
|
|
alu_inbusa => alu_inbusa,
|
|
alu_inbusb => alu_inbusb,
|
|
bp_s => bp_s,
|
|
bx_s => bx_s,
|
|
di_s => di_s,
|
|
si_s => si_s,
|
|
reset => reset,
|
|
clk => clk,
|
|
data_in => data_in,
|
|
mdbus_in => mdbus_in,
|
|
sp_s => sp_s,
|
|
ax_s => ax_s,
|
|
cx_s => cx_s,
|
|
dx_s => dx_s
|
|
);
|
|
I9 : ipregister
|
|
PORT MAP (
|
|
clk => clk,
|
|
ipbus => ipbus,
|
|
reset => reset,
|
|
wrip => wrip,
|
|
ipreg => ipreg
|
|
);
|
|
I15 : segregfile
|
|
PORT MAP (
|
|
selsreg => selsreg,
|
|
sibus => sibus,
|
|
wrs => wrs,
|
|
reset => reset,
|
|
clk => clk,
|
|
sdbus => sdbus,
|
|
dimux => dimux,
|
|
es_s => es_s,
|
|
cs_s => cs_s,
|
|
ss_s => ss_s,
|
|
ds_s => ds_s
|
|
);
|
|
|
|
eabus <= eabus_internal;
|
|
|
|
END struct;
|