1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-18 17:06:57 +00:00
Gehstock.Mist_FPGA/common/CPU/cpu86/datapath_struct.vhd
2019-07-22 23:42:05 +02:00

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;