mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-01-21 18:04:59 +00:00
2759 lines
192 KiB
VHDL
2759 lines
192 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 --
|
|
-- --
|
|
-------------------------------------------------------------------------------
|
|
-- Version : 1.0a 02/08/2009 Fixed CALL [REG] Instruction --
|
|
-------------------------------------------------------------------------------
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.ALL;
|
|
USE ieee.std_logic_unsigned.ALL;
|
|
USE ieee.std_logic_arith.ALL;
|
|
|
|
USE work.cpu86pack.ALL;
|
|
USE work.cpu86instr.ALL;
|
|
|
|
ENTITY proc IS
|
|
PORT(
|
|
clk : IN std_logic;
|
|
flush_ack : IN std_logic;
|
|
instr : IN instruction_type;
|
|
inta1 : IN std_logic;
|
|
irq_req : IN std_logic;
|
|
latcho : IN std_logic;
|
|
reset : IN std_logic;
|
|
rw_ack : IN std_logic;
|
|
status : IN status_out_type;
|
|
clrop : OUT std_logic;
|
|
decode_state : OUT std_logic;
|
|
flush_coming : OUT std_logic;
|
|
flush_req : OUT std_logic;
|
|
intack : OUT std_logic;
|
|
iomem : OUT std_logic;
|
|
irq_blocked : OUT std_logic;
|
|
opc_req : OUT std_logic;
|
|
path : OUT path_in_type;
|
|
proc_error : OUT std_logic;
|
|
read_req : OUT std_logic;
|
|
word : OUT std_logic;
|
|
write_req : OUT std_logic;
|
|
wrpath : OUT write_in_type
|
|
);
|
|
END proc ;
|
|
|
|
architecture rtl of proc is
|
|
|
|
type state_type is (
|
|
Sopcode,Sdecode,
|
|
Sreadmem,Swritemem,
|
|
Sexecute,Sflush,Shalt);
|
|
|
|
-- Declare current and next state signals
|
|
signal current_state: state_type ;
|
|
signal next_state : state_type ;
|
|
signal second_pass : std_logic; -- if 1 go round the loop again
|
|
signal second_pass_s: std_logic; -- Comb version
|
|
|
|
signal rep_set_s : std_logic; -- Start of REP Instruction, check CX when set
|
|
signal rep_clear_s : std_logic; -- Signal end of REP Instruction
|
|
signal rep_flag : std_logic; -- REPEAT Flag
|
|
signal rep_z_s : std_logic; -- Z value of REP instruction
|
|
signal rep_zl_s : std_logic; -- Latched Z value of REP
|
|
|
|
signal flush_coming_s : std_logic; -- Signal that a flush is imminent (don't bother filling the queue)
|
|
signal irq_blocked_s: std_logic; -- Indicate that IRQ will be blocked during the next instruction
|
|
-- This is required for pop segment etc instructions.
|
|
|
|
signal intack_s : std_logic; -- Signal asserted during 8 bits vector read, this occurs during
|
|
-- the second INTA cycle
|
|
|
|
signal passcnt_s : std_logic_vector(7 downto 0); -- Copy of CL register
|
|
signal passcnt : std_logic_vector(7 downto 0);
|
|
|
|
signal wrpath_s : write_in_type; -- combinatorial
|
|
signal wrpathl_s : write_in_type; -- Latched version of wrpath_s
|
|
signal path_s : path_in_type; -- combinatorial
|
|
signal proc_error_s : std_logic; -- Processor decode error
|
|
signal proc_err_s : std_logic; -- Processor decode error latch signal
|
|
signal iomem_s : std_logic; -- IO/~M cycle
|
|
|
|
-- alias ZFLAG : std_logic is status.flag(6); -- doesn't work, why not??
|
|
signal flush_req_s : std_logic; -- Flush Prefetch queue request
|
|
signal flush_reql_s : std_logic; -- Latched version of Flush request
|
|
|
|
begin
|
|
|
|
proc_error <= proc_err_s; -- connect to outside world
|
|
flush_req <= flush_req_s;
|
|
|
|
----------------------------------------------------------------------------
|
|
clocked : process(clk,reset)
|
|
----------------------------------------------------------------------------
|
|
begin
|
|
if (reset = '1') then
|
|
current_state <= Sopcode;
|
|
path <= ((others =>'0'),(others =>'0'),(others =>'0'),(others =>'0'),
|
|
(others =>'0'));
|
|
wrpathl_s <= ('0','0','0','0','0','0','0');
|
|
word <= '0'; -- default to 8 bits
|
|
proc_err_s <= '0'; -- Processor decode error
|
|
iomem <= '0'; -- default to memory access
|
|
second_pass <= '0'; -- default 1 pass
|
|
flush_reql_s<= '0'; -- flush prefetch queue
|
|
passcnt <= X"01"; -- Copy of CL register used in rot/shft
|
|
rep_flag <= '0'; -- REP instruction running flag
|
|
rep_zl_s <= '0'; -- REP latched z bit
|
|
flush_coming<= '0'; -- flush approaching
|
|
irq_blocked <= '1'; -- IRQ blocking for next instruction
|
|
intack <= '0'; -- Second INTA cycle signal
|
|
|
|
elsif rising_edge(clk) then
|
|
current_state<= next_state;
|
|
proc_err_s <= proc_error_s or proc_err_s; -- Latch Processor error, cleared by reset only
|
|
flush_reql_s <= flush_req_s; -- Latch Flush_request signal
|
|
|
|
if current_state=Sdecode then -- Latch write pulse and path settings
|
|
second_pass <= second_pass_s; -- latch pass signal
|
|
word <= path_s.datareg_input(3); -- word <= w bit
|
|
path <= path_s;
|
|
wrpathl_s <= wrpath_s;
|
|
passcnt <= passcnt_s;
|
|
irq_blocked <=irq_blocked_s; -- Signal to block IRQ during next instruction
|
|
intack <= intack_s; -- Second INTA cycle signal
|
|
end if;
|
|
|
|
if ((current_state=Sdecode) or (current_state=Sexecute)) then--Latch IOMEM signal
|
|
iomem <= iomem_s; -- Latch IOM signal
|
|
flush_coming<=flush_coming_s; -- flush approaching
|
|
end if;
|
|
|
|
if rep_set_s='1' then -- Set/Reset REP flag
|
|
rep_flag <= '1';
|
|
elsif rep_clear_s='1' then
|
|
rep_flag <= '0';
|
|
end if;
|
|
|
|
if rep_set_s='1' then
|
|
rep_zl_s <= rep_z_s; -- Latch Z value of REP instruction
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end process clocked;
|
|
|
|
----------------------------------------------------------------------------
|
|
nextstate : process (current_state, latcho, rw_ack, flush_ack, instr, status,wrpathl_s, second_pass,irq_req,
|
|
passcnt, flush_reql_s, rep_flag, rep_zl_s, inta1)
|
|
----------------------------------------------------------------------------
|
|
begin
|
|
-- Default Assignment
|
|
opc_req <= '0';
|
|
read_req <= '0';
|
|
write_req <= '0';
|
|
|
|
wrpath_s <= ('0','0','0','0','0','0','0'); -- Default all writes disabled
|
|
wrpath <= ('0','0','0','0','0','0','0'); -- Combinatorial
|
|
path_s <= ((others =>'0'),(others =>'0'),(others =>'0'),(others =>'0'),
|
|
(others =>'0'));
|
|
proc_error_s<= '0';
|
|
iomem_s <= '0'; -- IO/~M default to memory access
|
|
flush_req_s <= '0'; -- Flush Prefetch queue request
|
|
passcnt_s <= X"01"; -- init to 1
|
|
rep_set_s <= '0'; -- default no repeat
|
|
rep_clear_s <= '0'; -- default no clear
|
|
rep_z_s <= '0'; -- REP instruction Z bit
|
|
flush_coming_s<='0'; -- don't fill the instruction queue
|
|
irq_blocked_s<='0'; -- default, no block IRQ
|
|
clrop <= '0'; -- Clear Segment override flag
|
|
second_pass_s<='0'; -- HT0912,
|
|
intack_s <= '0'; -- Signal asserted during INT second INTA cycle
|
|
decode_state<= '0'; -- Decode stage for signal spy only
|
|
|
|
case current_state is
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Get Opcode from BIU
|
|
----------------------------------------------------------------------------
|
|
when Sopcode =>
|
|
|
|
second_pass_s<='0';
|
|
opc_req <= '1';
|
|
|
|
if (latcho = '0') then
|
|
next_state <= Sopcode; -- Wait
|
|
else
|
|
next_state <= Sdecode; -- Decode instruction
|
|
end if;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Opcode received, decode instruction
|
|
-- Set Path (next state)
|
|
-- Set wrpath_s, lacthed as this stage, enabled only at Sexecute
|
|
----------------------------------------------------------------------------
|
|
when Sdecode =>
|
|
|
|
if second_pass='1' then
|
|
wrpath <= wrpathl_s; -- Assert write strobe(s) during first & second pass
|
|
else
|
|
decode_state <= '1'; -- Asserted during first decode stage
|
|
end if;
|
|
|
|
case instr.ireg is
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- IN Port Instruction 0xE4..E5, 0xEC..ED
|
|
-- Use fake xmod and rm setting for fixed port number
|
|
---------------------------------------------------------------------------------
|
|
when INFIXED0 | INFIXED1 | INDX0 | INDX1 =>
|
|
second_pass_s <= '0';
|
|
iomem_s <= '1'; -- Select IO cycle
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & "000"; -- dimux & w & seldreg AX/AL=000
|
|
|
|
if instr.ireg(3)='0' then -- 0=Fixed, 1=DX
|
|
path_s.ea_output <= PORT_00_EA & DONTCARE(2 downto 0);-- dispmux & eamux(4) & segop 11=00:EA
|
|
else -- 1=DX
|
|
path_s.ea_output <= PORT_00_DX & DONTCARE(2 downto 0);-- dispmux & eamux(4) & segop 10=00:DX
|
|
end if;
|
|
|
|
wrpath_s.wrd <= '1'; -- Write to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- XLAT Instruction
|
|
-- AL<= SEG:[BX+AL]
|
|
---------------------------------------------------------------------------------
|
|
when XLAT =>
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= MDBUS_IN & '0' & REG_AX(2 downto 0); -- dimux & w & seldreg AX/AL=000
|
|
|
|
path_s.ea_output<= "0001111011"; -- EA=BX+AL, dispmux(2) & eamux(4) & [flag]&segop(2)
|
|
|
|
wrpath_s.wrd <= '1'; -- Write to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- OUT Port Instruction 0xE6..E7, 0xEE..EF
|
|
-- Use fake xmod and rm setting for fixed port number
|
|
---------------------------------------------------------------------------------
|
|
when OUTFIXED0 | OUTFIXED1 | OUTDX0 | OUTDX1 =>
|
|
second_pass_s <= '0';
|
|
iomem_s <= '1'; -- Select IO cycle
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg Only need to set W
|
|
|
|
path_s.alu_operation<= "0000" & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr selalua=AX/AL
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
if instr.ireg(3)='0' then -- 0=Fixed, 1=DX
|
|
path_s.ea_output <= PORT_00_EA & DONTCARE(2 downto 0);-- dispmux & eamux(4) & segop 11=00:EA
|
|
else -- 1=DX
|
|
path_s.ea_output <= PORT_00_DX & DONTCARE(2 downto 0);-- dispmux & eamux(4) & segop 10=00:DX
|
|
end if;
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Increment/Decrement Register, word only!
|
|
---------------------------------------------------------------------------------
|
|
when INCREG0 |INCREG1 |INCREG2 |INCREG3 | INCREG4 |INCREG5 |INCREG6 |INCREG7 |
|
|
DECREG0 |DECREG1 |DECREG2 |DECREG3 | DECREG4 |DECREG5 |DECREG6 |DECREG7 =>
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & instr.reg; -- dimux & w & seldreg
|
|
|
|
-- instr.ireg(5..3) contains the required operation, ALU_INBUSB=X"0001"
|
|
-- Note ALU_INC is generic for INC/DEC
|
|
path_s.alu_operation<= '0'&instr.reg & REG_CONST1 & ALU_INC(6 downto 3)&instr.ireg(5 downto 3); -- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Update register
|
|
wrpath_s.wrcc <= '1'; -- Update Flag register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Shift/Rotate Instructions
|
|
-- Operation define in MODRM REG bits
|
|
-- Use MODRM reg bits
|
|
-- bit 0=b/w, bit1=0 then count=1 else count=cl
|
|
-- if cl=00 then don't write to CC register
|
|
-----------------------------------------------------------------------------
|
|
when SHFTROT0 | SHFTROT1 | SHFTROT2 | SHFTROT3 =>
|
|
|
|
if instr.reg="110" then -- Not supported/defined
|
|
proc_error_s<='1'; -- Assert Bus Error Signal
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** Illegal SHIFT/ROTATE instruction (proc) ***" severity warning;
|
|
-- pragma synthesis_on
|
|
end if;
|
|
|
|
if instr.xmod="11" then -- Immediate to Register r/m=reg field
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg Note RM=Destination!!
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if (second_pass='0') then -- first pass, load reg into alureg
|
|
|
|
if (instr.ireg(1)='1' and status.cl=X"00") then
|
|
second_pass_s <= '0'; -- No second pass if cl=0
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
else
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sdecode; -- round the loop again
|
|
end if;
|
|
|
|
-- Load instr.rm register into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & '0'&instr.rm & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
wrpath_s.wralu <= '1';
|
|
|
|
if (instr.ireg(1)='1') then
|
|
passcnt_s <= status.cl; -- Load CL loop counter
|
|
end if; -- else passcnt_s=1;
|
|
|
|
|
|
else -- second pass, terminate or go around the loop again
|
|
|
|
-- selalua & selalu are dontcare, instruction is V+001+instr.reg
|
|
-- ALU_ROL(6 downto 4) is generic for all shift/rotate
|
|
-- Instruction=Constant & V_Bit & modrm.reg(5 downto 3)
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & '0'&instr.rm & ALU_ROL(6 downto 4)& instr.ireg(1) & instr.reg; -- selalua(4) & selalub(4) & aluopr(7)
|
|
|
|
if (passcnt=X"00") then -- Check if end of shift/rotate
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register after last shift/rot
|
|
wrpath_s.wrd <= '1'; -- Write shift/rotate results to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
else
|
|
second_pass_s <= '1'; -- need another pass
|
|
wrpath_s.wralu <= '1';
|
|
wrpath_s.wrcc <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
next_state <= Sdecode; -- round the loop again
|
|
end if;
|
|
|
|
end if;
|
|
|
|
else -- Destination and source is memory, use ALUREG
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- ver 0.69, path& w! seldreg=don'tcare
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; -- {eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop
|
|
|
|
if (second_pass='0') then -- first pass, load memory operand into alureg
|
|
|
|
if (instr.ireg(1)='1' and status.cl=X"00") then
|
|
second_pass_s <= '0'; -- No second pass if cl=0
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
else
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
-- Load memory into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
wrpath_s.wralu <= '1'; -- ver 0.69, write MDBUS to ALUREG
|
|
|
|
if (instr.ireg(1)='1') then
|
|
passcnt_s <= status.cl; -- Load CL loop counter
|
|
end if; -- else passcnt_s=1;
|
|
|
|
else -- second pass, MDBUS contains memory byte
|
|
|
|
-- selalua & selalu are dontcare
|
|
-- ALU_ROL(6 downto 4) is generic for all shift/rotate
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & '0'&instr.rm & ALU_ROL(6 downto 4)& instr.ireg(1) & instr.reg; -- selalua(4) & selalub(4) & aluopr(7)
|
|
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register after each shift/rot
|
|
|
|
--if (passcnt=X"01") then -- Check if end of shift/rotate
|
|
if (passcnt=X"00") then -- ver 0.69, Check if end of shift/rotate
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- write result to memory & terminate
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
second_pass_s <= '1';
|
|
wrpath_s.wralu<= '1'; -- Update ALUREG
|
|
next_state <= Sdecode; -- round the loop again
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Immediate to Register
|
|
---------------------------------------------------------------------------------
|
|
when MOVI2R0 | MOVI2R1 |MOVI2R2 |MOVI2R3 |MOVI2R4 | MOVI2R5 | MOVI2R6 | MOVI2R7 |
|
|
MOVI2R8 | MOVI2R9 |MOVI2R10|MOVI2R11|MOVI2R12| MOVI2R13| MOVI2R14| MOVI2R15 =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= DATAIN_IN & instr.ireg(3) & instr.reg; -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Immediate to Register/Memory 0xC6, 0xC7
|
|
-- Data is routed from drmux->dibus->dbusdp_out
|
|
---------------------------------------------------------------------------------
|
|
when MOVI2RM0 | MOVI2RM1 =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= DATAIN_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only dimux, the rest is don't care)
|
|
-- change to instr.ireg(0) & instr.reg ???
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Memory to Accu and Accu to Memory AL, AX, not AH! 0xA0..0xA3
|
|
-- Use fake xmod and rm setting
|
|
-- Use instruction but (4..3)=000 as register selector
|
|
---------------------------------------------------------------------------------
|
|
when MOVM2A0 | MOVM2A1 | MOVA2M0 | MOVA2M1 =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg (don't care for write cycle)
|
|
|
|
path_s.alu_operation<= '0'&instr.reg & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr (don't care for read cycle)
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting (don't care for read cycle)
|
|
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if instr.ireg(1)='0' then -- 0= memory to Accu, Read Cycle
|
|
wrpath_s.wrd <= '1'; -- Write Memory to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else -- 1=Accu to Memory, Write cycle
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Move Register/Memory to/from Register 0x88..0x8B
|
|
---------------------------------------------------------------------------------
|
|
when MOVRM2R0 | MOVRM2R1 | MOVRM2R2 | MOVRM2R3 =>
|
|
|
|
second_pass_s <= '0';
|
|
if instr.xmod="11" then -- Register to Register rm=reg field
|
|
if instr.ireg(1)='0' then -- Check 'd' bit, 0-> SRC=Reg, DEST=rm
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg
|
|
path_s.alu_operation<= '0'&instr.reg & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr
|
|
else -- 'd'=1 SRC=rm, DEST=Reg
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg
|
|
path_s.alu_operation<= '0'&instr.rm & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr
|
|
end if;
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Source is memory
|
|
if instr.ireg(1)='0' then -- Check 'd' bit, 0-> SRC=Reg, DEST=rm, Write Cycle
|
|
path_s.alu_operation<= '0'&instr.reg & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- (only need w, the reset don't care)
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
|
|
else -- 'd'=1 SRC=rm, DEST=Reg, Read Cycle
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg
|
|
path_s.alu_operation<= '0'&instr.rm & DONTCARE(3 downto 0) & ALU_PASSA; -- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Memory to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Move Segment register to data register or memory
|
|
---------------------------------------------------------------------------------
|
|
when MOVS2RM =>
|
|
|
|
second_pass_s <= '0';
|
|
if instr.xmod="11" then -- Segment Register to Data Register , rm=reg field
|
|
|
|
path_s.datareg_input<= '1'& instr.reg(1 downto 0) & '1' & instr.rm; -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Seg to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
else -- Segment Register to memory indexed by rm
|
|
|
|
path_s.datareg_input<= '1'& instr.reg(1 downto 0) & '1' & DONTCARE(2 downto 0); -- dimux only -- [dimux(3) & w & seldreg(3)]
|
|
path_s.dbus_output <= DIBUS_OUT; --(Odd/Even) domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Register or Memory to Segment Register
|
|
-- In case of memory, stalls until operand is read from memory
|
|
---------------------------------------------------------------------------------
|
|
when MOVRM2S =>
|
|
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
|
|
second_pass_s <= '0';
|
|
if instr.reg(1 downto 0)="01" then
|
|
proc_error_s<='1'; -- if segment register = CS report error
|
|
-- pragma synthesis_off
|
|
report "MOVRM2S : MOV CS,REG/Memory not valid" severity warning;
|
|
-- pragma synthesis_on
|
|
end if;
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' & DONTCARE(2 downto 0); -- dimux & w=1 & seldreg
|
|
|
|
if instr.xmod="11" then -- Register to Segment Register , rm=reg field
|
|
|
|
path_s.alu_operation<= '0'&instr.rm & DONTCARE(3 downto 0) & ALU_PASSA; --selalua & selalub & aluopr
|
|
path_s.segreg_input <= SALUBUS_IN & instr.reg(1 downto 0); -- simux & selsreg
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrs <= '1'; -- Write Data Register to Segment Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Memory to Segment Register
|
|
|
|
path_s.segreg_input <= SMDBUS_IN & instr.reg(1 downto 0); -- simux & selsreg
|
|
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
wrpath_s.wrs <= '1'; -- Write Memory to Segment Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Load Effective Address in Data Register
|
|
-- mod=11 result in proc_error
|
|
---------------------------------------------------------------------------------
|
|
when LEA =>
|
|
second_pass_s <= '0';
|
|
|
|
if instr.xmod="11" then -- Register to Register rm=reg field
|
|
proc_error_s<='1'; -- Assert Bus Error Signal
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** Illegal LEA operand (mod=11) (proc) ***" severity warning;
|
|
-- pragma synthesis_on
|
|
end if; -- Transfer Effective addresss (EABUS) to data register
|
|
|
|
path_s.datareg_input<= EABUS_IN & '1' & instr.reg; -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop
|
|
|
|
wrpath_s.wrd <= '1'; -- Write EABUS to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Load Effective Address in ES/DS:DEST_REGISTER
|
|
-- mod=11 result in proc_error
|
|
-- TEMP <= readmem(ea) ; PASS1 (required for cases like LES SI,[SI] )
|
|
-- REG <= TEMP ; PASS2
|
|
-- ES/DS<= readmem(ea+2)
|
|
---------------------------------------------------------------------------------
|
|
when LES | LDS =>
|
|
|
|
if instr.xmod="11" then -- Register to Register rm=reg field
|
|
proc_error_s<='1'; -- Assert Bus Error Signal
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** Illegal LES/LDS operand (mod=11) (proc) ***" severity warning;
|
|
-- pragma synthesis_on
|
|
end if;
|
|
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_TEMP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
if (second_pass='0') then -- first pass reg<=mem(ea)
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
path_s.datareg_input<= MDBUS_IN & '1' & instr.reg;-- dimux & w & seldreg
|
|
|
|
path_s.ea_output<="0000001001"; -- dispmux(3) & eamux(4)=EA & dis_opflag & segop[1:0]
|
|
wrpath_s.wrtemp <= '1'; -- Write reg value to alu_temp first
|
|
next_state <= Sreadmem; -- start read to read temp<=EA
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & instr.reg;-- dimux & w & seldreg
|
|
path_s.ea_output<="0000011001"; -- dispmux(3) & eamux(4)=EA+2 & dis_opflag & segop[1:0]
|
|
-- Second Pass ES/DS<=mem(ea+2)
|
|
if instr.ireg(0)='0' then -- C4=LES
|
|
path_s.segreg_input <= SMDBUS_IN & ES_IN(1 downto 0); -- simux & selsreg=ES
|
|
else -- C5=LDS
|
|
path_s.segreg_input <= SMDBUS_IN & DS_IN(1 downto 0); -- simux & selsreg=DS
|
|
end if;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrd <= '1'; -- Update Reg<=temp
|
|
wrpath_s.wrs <= '1'; -- Update ES/DS Register
|
|
next_state <= Sreadmem;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Convert AL to AX, AX -> DX:AX
|
|
-- Flags are not affected
|
|
---------------------------------------------------------------------------------
|
|
when CBW | CWD =>
|
|
second_pass_s <= '0';
|
|
|
|
-- Note ALU_SEXT(6 downto 4) is generic for CBW and CWD
|
|
path_s.alu_operation<= REG_AX & DONTCARE(3 downto 0) & ALU_SEXT(6 downto 4) & instr.ireg(3 downto 0) ;-- selalua & selalub & aluopr
|
|
|
|
if (instr.ireg(0)='0') then -- if 0 then CBW else CWD
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_AX(2 downto 0);-- dimux & w & seldreg Note RM=Destination!!
|
|
else
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DX(2 downto 0);-- dimux & w & seldreg Note RM=Destination!!
|
|
end if;
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Convert AL
|
|
-- Use bit 4 of instruction to drive W bit
|
|
---------------------------------------------------------------------------------
|
|
when AAS | DAS | AAA | DAA | AAM | AAD =>
|
|
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(4) & REG_AX(2 downto 0);-- dimux & w & seldreg Note RM=Destination!!
|
|
path_s.alu_operation<= REG_AX & DONTCARE(3 downto 0) & ALU_DAA(6 downto 4)&instr.ireg(0)&instr.ireg(5 downto 3);-- selalua & selalub & aluopr
|
|
|
|
if (second_pass='0') then -- first pass
|
|
|
|
if (instr.ireg=AAM) then -- AAM instruction only
|
|
second_pass_s <= '1'; -- need another pass
|
|
wrpath_s.wralu <= '1'; -- Write Data to ALUREG, only used for AAM (uses divider)
|
|
passcnt_s <= "000"&DIV_MCD_C; -- Serial delay
|
|
next_state <= Sdecode; -- round the loop again
|
|
else
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
end if;
|
|
|
|
else
|
|
second_pass_s <= '1';
|
|
if (passcnt=X"00") then -- Divider Done?
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
else
|
|
next_state <= Sdecode; -- Version 0.78
|
|
end if;
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Segment Override Prefix
|
|
---------------------------------------------------------------------------------
|
|
when SEGOPES | SEGOPCS | SEGOPSS | SEGOPDS =>
|
|
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
|
|
path_s.ea_output <= "000"&DONTCARE(3 downto 0) & '0' & instr.ireg(4 downto 3); -- dispmux & eamux(4) & [flag]&segop[1:0]
|
|
|
|
wrpath_s.wrop <= '1'; -- Write to Override Prefix Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Halt Instruction, wait for NMI, INTR, Reset
|
|
---------------------------------------------------------------------------------
|
|
when HLT =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.ea_output<= NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- ADD/ADC/SUB/SBB/CMP/AND/OR/XOR Register/Memory <- Register/Memory
|
|
-- TEST same as AND without returning any result (wrpath_s.wrd is not asserted)
|
|
---------------------------------------------------------------------------------
|
|
when ADDRM2R0 | ADDRM2R1 | ADDRM2R2 | ADDRM2R3 | ADCRM2R0 | ADCRM2R1 | ADCRM2R2 | ADCRM2R3 |
|
|
SUBRM2R0 | SUBRM2R1 | SUBRM2R2 | SUBRM2R3 | SBBRM2R0 | SBBRM2R1 | SBBRM2R2 | SBBRM2R3 |
|
|
CMPRM2R0 | CMPRM2R1 | CMPRM2R2 | CMPRM2R3 | ANDRM2R0 | ANDRM2R1 | ANDRM2R2 | ANDRM2R3 |
|
|
ORRM2R0 | ORRM2R1 | ORRM2R2 | ORRM2R3 | XORRM2R0 | XORRM2R1 | XORRM2R2 | XORRM2R3 |
|
|
TESTRMR0 | TESTRMR1 =>
|
|
|
|
if instr.xmod="11" then -- Register to Register rm=reg field
|
|
second_pass_s <= '0';
|
|
|
|
if (instr.ireg(1)='1') then -- Check 'd' bit, if 1 dest=reg else r/m
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg Note REG=Destination!
|
|
-- Note aluopr = bit 5 to 3 of opcode
|
|
-- Note ALU_ADD(6 downto 4) is generic for all sub types
|
|
-- Note the selalua and selalub values are important for the SUB and CMP instructions!
|
|
-- It would have been nice if the position was fixed in the opcode!
|
|
path_s.alu_operation<= '0'&instr.reg & '0'&instr.rm & ALU_ADD(6 downto 4)&instr.ireg(7)&instr.ireg(5 downto 3);-- selalua & selalub & aluopr
|
|
else
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg Note RM=Destination!
|
|
path_s.alu_operation<= '0'&instr.rm & '0'&instr.reg & ALU_ADD(6 downto 4)&instr.ireg(7)&instr.ireg(5 downto 3);-- selalua & selalub & aluopr
|
|
end if;
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if ((instr.ireg(5 downto 3)/="111") and (instr.ireg(7)='0')) then -- Check if not CMP or TEST Instruction
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
end if;
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Source/dest is memory
|
|
if instr.ireg(1)='0' then -- Check 'd' bit ->0 SRC=Reg, DEST=rm, Read & Write Cycle (mem<- mem, reg, AND)
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only w)
|
|
|
|
path_s.alu_operation<= REG_MDBUS & '0'&instr.reg & ALU_ADD(6 downto 4)&instr.ireg(7)&instr.ireg(5 downto 3); -- selalua & selalub & aluopr Path for ALU
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
if ((instr.ireg(5 downto 3)/="111") and (instr.ireg(7)='0')) then-- Check if not CMP or TEST Instruction
|
|
next_state <= Swritemem; -- start write cycle
|
|
else
|
|
next_state <= Sexecute;
|
|
end if;
|
|
end if;
|
|
|
|
else -- 'd'=1 SRC=rm, DEST=Reg, Read Cycle (reg<- reg, mem, AND)
|
|
second_pass_s <= '0';
|
|
-- Select Data for result path
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg
|
|
-- Select Path for ALU
|
|
path_s.alu_operation<= '0'&instr.reg & REG_MDBUS & ALU_ADD(6 downto 4)&instr.ireg(7)&instr.ireg(5 downto 3);-- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if ((instr.ireg(5 downto 3)/="111") and (instr.ireg(7)='0')) then-- Check if not CMP or TEST Instruction
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
end if;
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- OPCODE 80,81,82,83, ADD/ADC/SUB/SBB/CMP/AND/OR/XOR Immediate to Reg/Mem
|
|
-- ALU operation is defined in reg field (3 bits) and not in bit 5-3 of opcode
|
|
-- Data is routed from drmux->dibus->dbusdp_out
|
|
-- If instr(1)=1 then signextend the data byte (SW=11)
|
|
---------------------------------------------------------------------------------
|
|
when O80I2RM | O81I2RM | O83I2RM =>
|
|
|
|
if instr.xmod="11" then -- Immediate to Register r/m=reg field
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg Note RM=Destination!!
|
|
|
|
-- instr.reg contains the required operation (Reg AND Constant)
|
|
-- If s-bit=0 then 000+REG else 110+REG, s-bit is bit 1 of instr.reg
|
|
path_s.alu_operation<= '0'&instr.rm & REG_DATAIN &instr.ireg(1)&instr.ireg(1)&"00"&instr.reg; -- selalua & selalub & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if (instr.reg/="111") then -- Check if not CMP Instruction
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
end if;
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Destination and source is memory (no wrpath_s.wrd)
|
|
-- This is nearly the same as AND with d=0, see above
|
|
-- only need W bit
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only dimux, the rest is don't care)
|
|
-- Memory AND Constant, need to read memory first
|
|
path_s.alu_operation<= REG_MDBUS & REG_DATAIN&instr.ireg(1)&instr.ireg(1)&"00"&instr.reg; -- selalua & selalub & aluopr
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
if (instr.reg/="111") then -- Check if not CMP Instruction
|
|
next_state <= Swritemem; -- start write cycle
|
|
else
|
|
next_state <= Sexecute; -- CMP, do not write results
|
|
end if;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- NOT/TEST F6/F7 Shared Instructions
|
|
-- TEST regfield=000
|
|
-- NOT regfield=010
|
|
-- NEG regfield=011
|
|
-- MUL regfield=100
|
|
-- IMUL regfield=101
|
|
-- DIV regfield=110
|
|
-- IDIV regfield=111
|
|
-- ALU operation is defined in bits 5-3 of modrm.reg
|
|
-- Same sequence as OPC80..83 instruction?
|
|
-- Note for NOT instruction DATAIN must be zero!!
|
|
-----------------------------------------------------------------------------
|
|
when F6INSTR | F7INSTR =>
|
|
|
|
-- case instr.reg(2 downto 0) is
|
|
case instr.reg is
|
|
|
|
when "000" => -- TEST instruction, Combine with NEG/NOT Instruction ?????????????
|
|
if instr.xmod="11" then -- Immediate to Register r/m=reg field
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg
|
|
-- instr.reg contains the required operation
|
|
-- Note ALU_TEST2 is generic for all sub types
|
|
path_s.alu_operation<= '0'&instr.rm & REG_DATAIN & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Destination and source is memory (no wrpath_s.wrd)
|
|
-- This is nearly the same as AND with d=0, see above
|
|
-- only need W bit
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only dimux, the rest is don't care)
|
|
-- Memory AND Constant, need to read memory first
|
|
path_s.alu_operation<= REG_MDBUS & REG_DATAIN & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
next_state <= Sexecute; -- TEST, do not write results
|
|
end if;
|
|
|
|
end if;
|
|
|
|
when "010" | "011" => -- Invert NOT and 2s complement NEG
|
|
-- Check with others to see if can be combined!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
if instr.xmod="11" then -- Negate Register r/m=reg field
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg
|
|
-- Note ALU_TEST2 is generic for all sub types
|
|
if (instr.reg(0)='1') then -- NEG instruction
|
|
path_s.alu_operation<= '0'&instr.rm & REG_CONST1 & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
else -- NOT instruction, note DATAIN must be zero!
|
|
path_s.alu_operation<= '0'&instr.rm & REG_DATAIN & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
end if;
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if (instr.reg(0)='1') then -- NEG instruction
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
end if;
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Destination and source is memory
|
|
-- only need W bit
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only dimux, the rest is don't care)
|
|
-- need to read memory first
|
|
if (instr.reg(0)='1') then -- NEG instruction
|
|
path_s.alu_operation<= REG_MDBUS & REG_CONST1 & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
else -- NOT instruction, note DATAIN must be zero!
|
|
path_s.alu_operation<= REG_MDBUS & REG_DATAIN & ALU_TEST2(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
end if;
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
if (instr.reg(0)='1') then -- NEG instruction
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
end if;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- write results
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
when "100" | "101" | "110" | "111" => -- DIV/IDIV/MUL/IMUL instruction
|
|
|
|
if (second_pass='0') then -- Set up multiply parameters
|
|
second_pass_s <= '1';
|
|
|
|
|
|
if (instr.reg(1)='1') then -- Only assert for DIV and IDIV, not for MUL/IMUL
|
|
passcnt_s <= "000"&DIV_MCD_C; -- Serial delay
|
|
else
|
|
passcnt_s <= "000"&MUL_MCD_C; -- Multiplier MCP
|
|
end if;
|
|
|
|
-- only need W bit
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- Note ALU_TEST is generic for all sub types
|
|
if instr.xmod="11" then -- Immediate to Register, result to AX or DX:AX
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
path_s.alu_operation<= REG_AX & '0'&instr.rm & ALU_TEST2(6 downto 4)&'0'&instr.reg; -- selalua & selalub & aluopr
|
|
next_state <= Sdecode; -- Next write remaining AX
|
|
else -- get byte/word from memory
|
|
path_s.ea_output <= NB_DS_EA;
|
|
path_s.alu_operation<= REG_AX & REG_MDBUS & ALU_TEST2(6 downto 4)&'0'&instr.reg; -- selalua & selalub & aluopr
|
|
next_state <= Sreadmem; -- Next write remaining AX
|
|
end if;
|
|
wrpath_s.wralu <= '1'; -- latch AX/AL and Byte/Word
|
|
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP (required???????????)
|
|
|
|
if (passcnt=X"01") then --
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_AX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & '0'&instr.rm & ALU_TEST2(6 downto 4)&'0'&instr.reg; -- selalua & selalub & aluopr
|
|
wrpath_s.wrd <= '1'; -- Write AX
|
|
if (instr.ireg(0)='1') then
|
|
second_pass_s <= '1'; -- HT0912
|
|
next_state <= Sdecode; -- Continue, next cycle to write DX
|
|
else
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
end if;
|
|
elsif (passcnt=X"00") then
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & '0'&instr.rm & ALU_TEST2(6 downto 4)&'1'&instr.reg; -- selalua & selalub & aluopr
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrd <= '1'; -- Write DX
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- terminate
|
|
else
|
|
second_pass_s <= '1'; -- HT0912
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & '0'&instr.rm & ALU_TEST2(6 downto 4)&'1'&instr.reg; -- selalua & selalub & aluopr
|
|
next_state <= Sdecode; -- round the loop again
|
|
end if;
|
|
end if;
|
|
|
|
|
|
when others =>
|
|
second_pass_s <= '0'; -- To avoid latch HT0912
|
|
proc_error_s <='1'; -- Assert Bus Error Signal
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** Illegal F7/F6 modrm field (proc) ***" severity warning;
|
|
-- pragma synthesis_on
|
|
next_state <= Sdecode; -- Reset State????
|
|
|
|
end case;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- ADD/ADC/SUB/SBB/CMP/AND/OR/XOR Immediate to ACCU
|
|
-- ALU operation is defined in bits 5-3 of opcode
|
|
---------------------------------------------------------------------------------
|
|
when ADDI2AX0 | ADDI2AX1 | ADCI2AX0 | ADCI2AX1 | SUBI2AX0 | SUBI2AX1 | SBBI2AX0 | SBBI2AX1 |
|
|
CMPI2AX0 | CMPI2AX1 | ANDI2AX0 | ANDI2AX1 | ORI2AX0 | ORI2AX1 | XORI2AX0 | XORI2AX1 |
|
|
TESTI2AX0| TESTI2AX1 =>
|
|
|
|
second_pass_s <= '0';
|
|
-- Note Destination reg is fixed to AX/AL/AH
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & REG_AX(2 downto 0); -- dimux & w & seldreg(3)
|
|
-- note aluopr = bit 5 to 3 of opcode
|
|
path_s.alu_operation<= REG_AX & REG_DATAIN & ALU_ADD(6 downto 4)&instr.ireg(7)&instr.ireg(5 downto 3);-- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if ((instr.ireg(5 downto 3)/="111") and (instr.ireg(7)='0')) then-- Check if not CMP or TEST Instruction
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
end if;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Exchange Register with Accu
|
|
---------------------------------------------------------------------------------
|
|
when XCHGAX | XCHGCX | XCHGDX | XCHGBX | XCHGSP | XCHGBP | XCHGSI | XCHGDI =>
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- First pass copy AX to reg and reg to ALUREG
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & instr.ireg(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & '0' & instr.ireg(2 downto 0) & ALU_PASSA; -- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrd <= '1'; -- Update AX & write reg to ALUREG
|
|
wrpath_s.wralu<= '1'; -- Write INBUSB to ALUREG
|
|
next_state <= Sdecode; -- second pass
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
-- Second Pass, write ALU register to AX
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_AX(2 downto 0); -- dimux & w & seldreg
|
|
-- selalua and selalub are don't care, use previous values to reduce synth
|
|
path_s.alu_operation<= REG_AX & '0' & instr.ireg(2 downto 0) & ALU_REGL;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrd <= '1'; -- Write ALUREG to AX
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Exchange Register with Register/Memory
|
|
---------------------------------------------------------------------------------
|
|
when XCHGW | XCHGB =>
|
|
|
|
if instr.xmod="11" then -- Register to Register rm=reg field
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- First pass copy rm to ireg and ireg to ALUREG
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg
|
|
path_s.alu_operation<= '0'&instr.rm & '0'&instr.reg & ALU_PASSA; -- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrd <= '1'; -- Update AX & write reg to ALUREG
|
|
wrpath_s.wralu<= '1'; -- Write INBUSB to ALUREG (instr.reg)
|
|
next_state <= Sdecode; -- second pass
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
-- Second Pass, write ALUREG(ireg) to rm
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg
|
|
|
|
-- selalua and selalub are don't care
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & '0'&instr.reg & ALU_REGL; -- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrd <= '1'; -- Write ALUREG to AX
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
else
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand from memory
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- First pass copy rm to ireg and ireg to ALUREG
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & instr.reg; -- dimux & w & seldreg
|
|
path_s.alu_operation<= '0'&instr.rm & '0'&instr.reg & ALU_PASSA; -- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrd <= '1'; -- Update AX & write reg to ALUREG
|
|
wrpath_s.wralu<= '1'; -- Write INBUSB to ALUREG (instr.reg)
|
|
next_state <= Sreadmem; -- get memory operand
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- selalua and selalub are don't care, use previous values to reduce synth?????
|
|
path_s.alu_operation<= '0'&instr.rm & '0'&instr.reg & ALU_REGL; -- selalua(4) & selalub(4) & aluopr
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem;
|
|
end if;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Processor Control Instructions
|
|
-- ALU operation is defined in bits 5-0 of opcode
|
|
---------------------------------------------------------------------------------
|
|
when CLC | CMC | STC | CLD | STDx | CLI | STI =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= DONTCARE(6 downto 0) ; -- dimux(3) & w & seldreg(3)
|
|
-- Note aluopr = bit 3 to 0 of opcode
|
|
-- Note ALU_CMC(6 downto 4) is generic for all sub types
|
|
path_s.alu_operation<= DONTCARE(7 downto 0) & ALU_CMC(6 downto 4)&instr.ireg(3 downto 0);-- selalua(4) & selalub(4) & aluopr(7)
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Load AH with flags (7 downto 0)
|
|
-- Note orginal instruction only loads bit 7,6,4,2,0 (easy change if required)
|
|
-- ALU operation is defined in bits 6-0 of opcode
|
|
---------------------------------------------------------------------------------
|
|
when LAHF =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= ALUBUS_IN & REG_AH; -- dimux & w & seldreg(3)
|
|
-- note aluopr = bit 6 to 0 of opcode
|
|
path_s.alu_operation<= DONTCARE(7 downto 0) & ALU_LAHF(6 downto 4)&instr.ireg(3 downto 0);-- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Result to AH
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Store AH into flags (7 downto 0)
|
|
-- Note orginal instruction only stores bit 7,6,4,2,0
|
|
-- ALU operation is defined in bits 6-0 of opcode
|
|
---------------------------------------------------------------------------------
|
|
when SAHF =>
|
|
|
|
second_pass_s <= '0';
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)&'0'& DONTCARE(2 downto 0); -- dimux(3) & w & seldreg(3)
|
|
-- note aluopr = bit 6 to 0 of opcode
|
|
path_s.alu_operation<= REG_AH & DONTCARE(3 downto 0) & ALU_SAHF(6 downto 4)&instr.ireg(3 downto 0);-- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register with contents AH
|
|
|
|
next_state <= Sexecute;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- PUSH Data Register
|
|
---------------------------------------------------------------------------------
|
|
when PUSHAX | PUSHCX | PUSHDX | PUSHBX | PUSHSP | PUSHBP | PUSHSI | PUSHDI =>
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
|
|
if (second_pass='0') then -- first pass SP-2
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
wrpath_s.wralu <= '1'; -- Save reg in alureg (required for PUSH SP)
|
|
next_state <= Sdecode; -- second pass
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
|
|
path_s.alu_operation<= '0'&instr.reg & REG_CONST2 & ALU_PASSA;-- selalua(4) & selalub(4) & aluopr
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- PUSH Flag Register
|
|
---------------------------------------------------------------------------------
|
|
when PUSHF => -- Push flag register
|
|
|
|
path_s.dbus_output <= CCBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
if (second_pass='0') then -- first pass SP-2
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
--next_state <= Sreadmem; -- start read cycle
|
|
next_state <= Sdecode; -- second pass
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
|
|
-- Second Pass, write memory operand to stack
|
|
path_s.datareg_input<= MDBUS_IN & '1' & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- dispmux(2) & eamux(4) & [flag]&segop(2)
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- POP Flag Register
|
|
---------------------------------------------------------------------------------
|
|
when POPF => -- POP Flags
|
|
-- Setup datapath for SP<=SP-2, ea=SS:SP
|
|
-- Note datareg_input is don't care during second pass
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_SS_SP &DONTCARE(2 downto 0); -- SS:SP+2
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- First pass, start read and update SP
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sreadmem; -- start read cycle to get [SS:SP]
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
-- Second Pass, write memory operand to CC register
|
|
path_s.alu_operation<= REG_MDBUS & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- POP Data Register
|
|
---------------------------------------------------------------------------------
|
|
when POPAX | POPCX | POPDX | POPBX | POPSP | POPBP | POPSI | POPDI =>
|
|
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- First pass, start read and update SP
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sreadmem; -- start read cycle to get [SS:SP]
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
-- Second Pass, write memory operand to data register
|
|
path_s.datareg_input<= MDBUS_IN & '1' & instr.ireg(2 downto 0); -- dimux & w & seldreg
|
|
|
|
wrpath_s.wrd <= '1'; -- Update DataReg
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- POP TOS to Memory or Register
|
|
--
|
|
---------------------------------------------------------------------------------
|
|
when POPRM =>
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
-- First pass, start read and update SP
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sreadmem; -- start read cycle to get [SS:SP]
|
|
|
|
else -- second pass, write to memory or register
|
|
second_pass_s <= '0'; -- no more passes
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
-- Next are only used when xmod/=11, for xmod=11 they are don't care
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux=000,eamux=0001, dis_opflag=0, segop=11
|
|
|
|
-- For xmod/=11 the last 3 bits are DONTCARE
|
|
path_s.datareg_input<= MDBUS_IN & '1' & instr.rm; -- dimux & w & seldreg ireg-> r=4, rm->r=1
|
|
|
|
if instr.xmod="11" then -- POP Register r/m=reg field
|
|
-- This is the same as POPAX, POPCX etc
|
|
wrpath_s.wrd <= '1'; -- Update DataReg
|
|
next_state <= Sexecute;
|
|
else
|
|
next_state <= Swritemem; -- Update memory location pointed to by EA
|
|
end if;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- POP Segment Register
|
|
-- Note POP CS is illegal, result unknown instruction, assert bus error
|
|
-- Interrupts are disabled until the next instruction
|
|
---------------------------------------------------------------------------------
|
|
when POPES | POPSS | POPDS =>
|
|
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
|
|
second_pass_s <= '0';
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
|
|
-- Path to update SP
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
-- Path to write operand to segment register
|
|
path_s.segreg_input <= SMDBUS_IN & instr.ireg(4 downto 3); -- simux(2) & selsreg(2)
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
wrpath_s.wrs <= '1'; -- Update Segment Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sreadmem; -- start read cycle to get [SS:SP]
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- PUSH Segment Register
|
|
-- PUSH CS is legal
|
|
---------------------------------------------------------------------------------
|
|
when PUSHES | PUSHCS | PUSHSS | PUSHDS =>
|
|
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
|
|
if (second_pass='0') then -- first pass SP-2
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode; -- second pass
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.datareg_input<= '1' & instr.ireg(4 downto 3) & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Unconditional Jump
|
|
-- Short Jump within segment, SignExt DISPL
|
|
-- Long Jump within segment, No SignExt DISPL
|
|
-- Direct within segment (JMPDIS, new CS,IP on data_in and disp)
|
|
---------------------------------------------------------------------------------
|
|
when JMPS| JMP | JMPDIS=>
|
|
|
|
second_pass_s <= '0';
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.segreg_input <= SDATAIN_IN & CS_IN(1 downto 0);-- simux & selsreg, only for JMPDIS
|
|
|
|
if (instr.ireg(1 downto 0)="10") then -- JMPDIS Instruction
|
|
path_s.ea_output <= LD_CS_IP; -- dispmux & eamux & segop Load new CS:IP from memory
|
|
wrpath_s.wrs <= '1'; -- Update CS register
|
|
else
|
|
path_s.ea_output <= DISP_CS_IP; -- CS:IPREG+DISPL
|
|
end if;
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- LOOP Instruction
|
|
-- No flags are affected
|
|
-- Note: JCXZ can be speeded up by 1 clk cycle since the first pass is not
|
|
-- required!!
|
|
---------------------------------------------------------------------------------
|
|
when LOOPCX | LOOPZ | LOOPNZ | JCXZ =>
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
|
|
if (second_pass='0') then -- first pass CX <= CX-1
|
|
second_pass_s <= '1'; -- need another pass
|
|
|
|
if (instr.ireg(1 downto 0)/="11") then
|
|
wrpath_s.wrd <= '1'; -- Update CX unless instr=JCXZ
|
|
end if;
|
|
next_state <= Sdecode; -- Next check CX value
|
|
|
|
else -- Next check CX and flag value
|
|
second_pass_s <= '0';
|
|
-- path ALU is don't care
|
|
-- ver 0.70 fixed loop!! status.cx_zero ro cx_one
|
|
if (((instr.ireg(1 downto 0)="00") and (status.flag(6)='0') and (status.cx_one='0')) or -- loopnz, jump if cx/=0 && zf=0
|
|
((instr.ireg(1 downto 0)="01") and (status.flag(6)='1') and (status.cx_one='0')) or-- loopz, jump if cx/=0 && zf=1
|
|
((instr.ireg(1 downto 0)="10") and (status.cx_one='0')) or -- loop, jump if cx/=0
|
|
((instr.ireg(1 downto 0)="11") and (status.cx_zero='1'))) then -- jcxz jump if cx=0
|
|
|
|
flush_req_s <= '1';
|
|
path_s.ea_output <= DISP_CS_IP; -- jump
|
|
else
|
|
path_s.ea_output <= NB_CS_IP; -- Do not jump
|
|
end if;
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
|
|
end if;
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- FF/FE Instructions. Use regfield to decode operation
|
|
-- INC reg=000 (FF/FE)
|
|
-- DEC reg=001 (FF/FE)
|
|
-- CALL reg=010 (FF) Indirect within segment
|
|
-- CALL reg=011 (FF) Indirect Intersegment
|
|
-- JMP reg=100 (FF) Indirect within segment
|
|
-- JMP reg=101 (FF) Indirect Intersegment
|
|
-- PUSH reg=110 (FF)
|
|
-----------------------------------------------------------------------------
|
|
when FEINSTR | FFINSTR =>
|
|
|
|
case instr.reg is
|
|
|
|
when "000" | "001" => -- INC or DEC instruction
|
|
if instr.xmod="11" then -- Immediate to Register r/m=reg field
|
|
second_pass_s <= '0';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & instr.ireg(0) & instr.rm; -- dimux & w & seldreg Note RM=Destination
|
|
-- instr.reg(5..3) contains the required operation, ALU_INBUSB=X"0001"
|
|
-- note ALU_INC(6 downto 3) is generic for both INC and DEC
|
|
path_s.alu_operation<= '0'&instr.rm & REG_CONST1 & ALU_INC(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
|
|
wrpath_s.wrd <= '1'; -- Write Data Register to Data Register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
|
|
next_state <= Sexecute;
|
|
|
|
else -- Destination and source is memory (no wrpath_s.wrd)
|
|
-- This is nearly the same as AND with d=0, see above
|
|
-- only need W bit
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg (only dimux, the rest is don't care)
|
|
-- INC/DEC Memory, need to read memory first
|
|
path_s.alu_operation<= REG_MDBUS & REG_CONST1 & ALU_INC(6 downto 3)&instr.reg; -- selalua & selalub & aluopr
|
|
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
wrpath_s.wrcc <= '1'; -- Update Status Register
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- CALL Indirect within Segment
|
|
-- SP<=SP-2
|
|
-- Mem(SP)<=IP
|
|
-- IP<=EA
|
|
---------------------------------------------------------------------------------
|
|
when "010" =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
if (second_pass='0') then -- first pass SP-2
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
passcnt_s <= X"02";
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode; -- second pass
|
|
else -- Second pass Mem
|
|
passcnt_s <= passcnt - '1';
|
|
if (passcnt=X"00") then
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<=NB_CS_IP; -- select CS:IP before Flush;
|
|
next_state <= Sexecute;
|
|
|
|
elsif (passcnt=X"01") then -- Third pass
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
if instr.xmod="11" then
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= "1001001001";-- fix version 1.0a 02/08/09 EA_CS_IP;
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- need another pass
|
|
-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
path_s.ea_output<= "0100001011"; -- Get indirect value
|
|
next_state <= Sreadmem;
|
|
end if;
|
|
else -- Second pass write MEM(SS:SP)<=IP
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=IP
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- CALL IntraSegment Indirect
|
|
-- SP<=SP-2
|
|
-- Mem(SP)<=CS
|
|
-- SP<=SP-2
|
|
-- Mem(SP)<=IP
|
|
-- CS<=DS:EA
|
|
-- IP<=DS:EA+2
|
|
-- Flush
|
|
---------------------------------------------------------------------------------
|
|
when "011" =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
if (second_pass='0') then -- first pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.dbus_output<=DONTCARE(1 downto 0);
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2 (DONTCARE)
|
|
passcnt_s <= X"05";
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (passcnt=X"05") then -- Second pass write CS to ss:sp
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(1 downto 0) & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= CS_IN & '1' & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"04") then -- Third pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.dbus_output<=DONTCARE(1 downto 0);
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"03") then -- fourth pass, write IP
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(3 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"02") then -- fifth pass, CS<=Mem(EA+2)
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
wrpath_s.wrs <= '1'; -- update cs
|
|
-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
path_s.ea_output<= MD_EA2_DS; --"010110011"; -- Get indirect value EA+2
|
|
next_state <= Sreadmem; -- Get CS value from memory
|
|
|
|
elsif (passcnt=X"01") then -- sixth pass, IP<=Mem(EA)
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
wrpath_s.wrip <= '1'; -- update ip
|
|
-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
path_s.ea_output<= "0100001011"; -- Get indirect value EA
|
|
next_state <= Sreadmem; -- Get CS value from memory
|
|
|
|
else -- Final pass, update IP & CS
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux & eamux & segop
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- JMP Indirect within Segment
|
|
-- IP<=EA
|
|
---------------------------------------------------------------------------------
|
|
when "100" =>
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
|
|
if instr.xmod="11" then -- Immediate to Register r/m=reg field
|
|
second_pass_s <= '0';
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= "1001001001"; -- Select eabus with eamux(0)=0 (dispmux(3) & eamux(4) & segop(2)
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else -- source is memory
|
|
|
|
if (second_pass='0') then -- first pass read operand
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.ea_output<= "0100001011"; -- Get indirect value
|
|
wrpath_s.wrip <= '1'; -- Update IP register
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= "0100000011"; -- select CS:IPreg before Flush
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- JMP Indirect Inter Segment
|
|
-- IP<=EA
|
|
-- CS<=EA+2
|
|
---------------------------------------------------------------------------------
|
|
when "101" =>
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
|
|
if (second_pass='0') then -- first pass read IP
|
|
second_pass_s <= '1'; -- need another pass
|
|
passcnt_s <= X"01"; -- need extra pass
|
|
path_s.ea_output<= "0100001011"; -- Get indirect value
|
|
wrpath_s.wrip <= '1'; -- Update IP register
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (passcnt=X"01") then
|
|
second_pass_s <= '1'; -- need another pass (HT0912)
|
|
-- path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
-- path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
path_s.ea_output<= MD_EA2_DS; -- Get indirect value EA+2
|
|
wrpath_s.wrs <= '1'; -- update cs
|
|
next_state <= Sreadmem; -- Get CS value from memory
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= "0100000011"; -- select CS:IPreg before Flush
|
|
next_state <= Sexecute;
|
|
end if;
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- PUSH reg/memory
|
|
---------------------------------------------------------------------------------
|
|
when "110" => -- PUSH MEM Instuction
|
|
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
-- change ALU_Push???
|
|
|
|
if (second_pass='0') then -- first pass read operand and execute SP-2
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_DS_EA; -- dispmux & eamux & segop (unless Segment OP flag is set)
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sreadmem; -- start read cycle
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
-- Second Pass, write memory operand to stack
|
|
path_s.datareg_input<= MDBUS_IN & '1' & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0); -- dispmux(2) & eamux(4) & [flag]&segop(2)
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
|
|
when others =>
|
|
next_state <= Sdecode; -- To avoid latches
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** FF/FE REGField=111 Illegal Instuction ***" severity warning;
|
|
-- pragma synthesis_on
|
|
|
|
end case;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- CALL Direct within Segment
|
|
-- SP<=SP-2
|
|
-- Mem(SP)<=IP
|
|
-- IP<=IP+/-Disp
|
|
---------------------------------------------------------------------------------
|
|
when CALL =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
|
|
if (second_pass='0') then -- first pass SP-2
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
passcnt_s <= X"01";
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode; -- second pass
|
|
else -- Second pass Mem
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (passcnt=X"00") then
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= DISP_CS_IP; -- CS: IPREG+DISPL
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
path_s.ea_output <= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=IP
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- CALL Direct InterSegment
|
|
-- SP<=SP-2,
|
|
-- Mem(SP)<=CS, CS<=SEGMh/l
|
|
-- SP<=SP-2
|
|
-- Mem(SP)<=IP, IP<=OFFSETh/l & Flush
|
|
---------------------------------------------------------------------------------
|
|
when CALLDIS =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
|
|
if (second_pass='0') then -- first pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.dbus_output<=DONTCARE(1 downto 0);
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2 (DONTCARE)
|
|
passcnt_s <= X"03";
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (passcnt=X"03") then -- Second pass write CS to ss:sp
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(1 downto 0) & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= CS_IN & '1' & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
elsif (passcnt=X"02") then -- Third pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.dbus_output<=DONTCARE(1 downto 0);
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
elsif (passcnt=X"01") then -- fourth pass, write IP
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(3 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= DONTCARE(6 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
else -- Final pass, update IP & CS
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.dbus_output<=DONTCARE(1 downto 0);
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.segreg_input <= SDATAIN_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.ea_output<=LD_CS_IP; -- dispmux & eamux & segop Load new IP from memory
|
|
wrpath_s.wrs <= '1'; -- Update CS register
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- RET Instructions
|
|
-- IP<=Mem(SS:SP),
|
|
-- SP<=SP+2 (RET)
|
|
-- CS<=Mem(SS:SP),
|
|
-- SP<=SP+2 (RETDIS)
|
|
---------------------------------------------------------------------------------
|
|
when RET | RETDIS | RETO | RETDISO =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
if (second_pass='1' and passcnt=X"00") then -- last stage, add data_in to SP
|
|
path_s.alu_operation<= REG_SP & REG_DATAIN & ALU_ADD;-- selalua(4) & selalub(4) & aluopr
|
|
else
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
end if;
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
-- required to write to abusreg!!
|
|
|
|
if (second_pass='0') then -- first pass IP<=MEM(SS:SP)
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<=LD_SS_SP&DONTCARE(2 downto 0);-- dispmux & eamux & segop, POP IP, SS:SP
|
|
passcnt_s <= X"03"; -- 4 cycles
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sreadmem; -- Read Stack
|
|
else
|
|
|
|
if (passcnt=X"03") then -- Second pass Mem SP=SP+2
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
if (instr.ireg(3 downto 0)="0011") then -- RET Instruction?
|
|
passcnt_s <= X"00"; -- Dontcare
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue
|
|
path_s.ea_output<=NB_CS_IP; -- select CS:IP before Flush;
|
|
next_state <= Sexecute;
|
|
elsif (instr.ireg(3 downto 0)="0010") then -- RETO Instruction?
|
|
passcnt_s <= X"00"; -- Jump to last stage
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= DONTCARE(9 downto 0);-- dispmux & eamux & segop, ADDR=SS:SP
|
|
next_state <= Sdecode;
|
|
else -- else RETDIS, RETDISO, update CS
|
|
passcnt_s <= passcnt - '1'; -- Jump to 010
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= DONTCARE(9 downto 0);-- dispmux & eamux & segop, ADDR=SS:SP
|
|
next_state <= Sdecode;
|
|
end if;
|
|
|
|
elsif (passcnt=X"02") then -- Third pass, get CS from SS:SP
|
|
|
|
passcnt_s <= passcnt - '1'; -- Jump to 01
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
wrpath_s.wrs <= '1'; -- update cs
|
|
next_state <= Sreadmem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"01") then -- SP=SP+2
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SPReg
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (instr.ireg(3 downto 0)="1010") then -- RETDISO Instruction?
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<= IPB_CS_IP; -- need ipbus
|
|
next_state <= Sdecode;
|
|
else
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<= IPB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
else -- Final pass, Add offset to SP
|
|
second_pass_s <= '0'; -- clear
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<=NB_CS_IP; -- select CS:IP for Flush;"100000000"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update SPReg
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Software/Hardware Interrupts
|
|
-- SP<=SP-2
|
|
-- MEM(SS:SP)<=FLAGS
|
|
-- SP<=SP-2
|
|
-- MEM(SS:SP)<=CS
|
|
-- SP<=SP-2
|
|
-- MEM(SS:SP)<=IP
|
|
-- CS<=MEM(type*4) IF=TF=0
|
|
-- IP<=MEM(type*4)+2
|
|
-- Note save 1 cycle by adding type*4+2 to dispmux, IP and CS can be updated at
|
|
-- the same time
|
|
---------------------------------------------------------------------------------
|
|
when INT | INT3 | INTO =>
|
|
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
|
|
if (second_pass='0') then -- first pass SP<=SP-2
|
|
|
|
if (instr.ireg(1 downto 0)="10" and status.flag(11)='0') then -- if int0 & no Overflow then do nothing
|
|
second_pass_s <='0';
|
|
path_s.ea_output<= NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute; -- no nothing
|
|
else
|
|
second_pass_s <= '1';
|
|
flush_coming_s <= '1'; -- Signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
end if;
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
passcnt_s <= X"07";
|
|
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
flush_coming_s<= '1'; -- Signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
if (passcnt=X"07") then -- Second pass write Flags to SS:SP
|
|
second_pass_s <= '1';
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= CCBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"06") then -- Third pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"05") then -- Fourth pass write CS to SS:SP
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(1 downto 0) & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.alu_operation<= DONTCARE(7 downto 0) & ALU_CLRTIF;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.datareg_input<= CS_IN & '1' & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= DIBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
wrpath_s.wrcc <= '1'; -- Clear IF and TF flag
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"04") then -- Fifth pass SP<=SP-2
|
|
second_pass_s <= '1';
|
|
path_s.dbus_output<=DONTCARE(1 downto 0); -- make same as previous??????????
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_PUSH;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"03") then -- Sixth pass, write IP
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= DONTCARE(3 downto 0); -- simux & selsreg
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting CS out
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
next_state <= Swritemem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"02") then -- Seventh pass, CS<=Mem(EA*4+2)
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg read mem
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
wrpath_s.wrs <= '1'; -- Update CS, NOTE THIS CHANGES SEGBUS THUS AFFECTING
|
|
-- THE NEXT READ ADDRESS, TO PREVEND THIS SEGBUS
|
|
-- IS FORCED TO ZERO.
|
|
path_s.ea_output<= "1100111001"; -- Get indirect value EA*4+2, ip<-mdbus_in
|
|
|
|
next_state <= Sreadmem; -- get CS value from MEM(type*4)
|
|
|
|
elsif (passcnt=X"01") then -- Eigth pass, IP<=MEM(EA*4+2)
|
|
second_pass_s <= '1'; -- need another pass
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
wrpath_s.wrip <= '1'; -- update ip
|
|
-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
path_s.ea_output<= "0100110001"; -- Get indirect value mem(EA*4)
|
|
next_state <= Sreadmem;
|
|
|
|
else -- Ninth pass, update IP & CS
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
path_s.datareg_input<= DONTCARE(2 downto 0)& '1' &DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux & eamux & segop
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- IRET, Interrupt Return
|
|
-- IP <=MEM(SS:SP)
|
|
-- SP<=SP+2
|
|
-- CS<=MEM(SS:SP)
|
|
-- SP<=SP+2
|
|
-- FLAGS<=MEM(SS:SP)
|
|
-- SP<=SP+2
|
|
-- Flush
|
|
---------------------------------------------------------------------------------
|
|
when IRET =>
|
|
|
|
flush_coming_s<= '1'; -- signal to the BIU that a flush is coming,
|
|
-- this will stop the BIU from filling the queue.
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SP(2 downto 0); -- dimux & w & seldreg
|
|
path_s.dbus_output <= IPBUS_OUT; --{eabus(0)&} domux setting
|
|
-- required to write to abusreg!!
|
|
|
|
if (second_pass='0') then -- first pass IP<=MEM(SS:SP)
|
|
second_pass_s <= '1';
|
|
path_s.ea_output<=LD_SS_SP&DONTCARE(2 downto 0);-- dispmux & eamux & segop, POP IP, SS:SP
|
|
passcnt_s <= X"04"; -- 4 cycles
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sreadmem; -- Read Stack
|
|
else
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
if (passcnt=X"04") then -- Second pass Mem SP=SP+2
|
|
second_pass_s <= '1';
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output<= DONTCARE(9 downto 0); -- dispmux & eamux & segop, ADDR=SS:SP
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"03") then -- Third pass, get CS from SS:SP
|
|
second_pass_s <= '1';
|
|
path_s.segreg_input <= SMDBUS_IN & CS_IN(1 downto 0); -- simux & selsreg
|
|
path_s.ea_output<= NB_SS_SP & DONTCARE(2 downto 0);-- ADDR=SS:SP
|
|
wrpath_s.wrs <= '1'; -- update cs
|
|
next_state <= Sreadmem; -- start write cycle, MEM(SP)<=CS
|
|
|
|
elsif (passcnt=X"02") then -- SP=SP+2
|
|
second_pass_s <= '1';
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
path_s.ea_output<= IPB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"01") then -- get FLAGS from memory
|
|
second_pass_s <= '1';
|
|
path_s.alu_operation<= REG_MDBUS & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_SS_SP &DONTCARE(2 downto 0); -- SS:SP+2
|
|
wrpath_s.wrcc <= '1'; -- Update FLAGS register
|
|
next_state <= Sreadmem;
|
|
|
|
else -- Final pass, SP<=SP+2
|
|
second_pass_s <= '0'; -- clear
|
|
path_s.alu_operation<= REG_SP & REG_CONST2 & ALU_POP;-- selalua(4) & selalub(4) & aluopr
|
|
wrpath_s.wrd <= '1'; -- Update SP
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output<=NB_CS_IP; -- select CS:IP for Flush;"100000000";-- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update SPReg
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Load String
|
|
-- AL/AX<=DS:[SI] SI++/--
|
|
-- if REP flag is set, then CX-1, check ZF,
|
|
-- for REP if zf=1 then exit
|
|
-- for REPZ if zf=0 then exit
|
|
-- NOTE: Debug does not seem to be able to handle this instruction on REPZ
|
|
-- To be compatable Z flag checking is removed, thus only depended on CX
|
|
---------------------------------------------------------------------------------
|
|
when LODSB | LODSW =>
|
|
|
|
if (second_pass='0') then -- First pass, load AL/AX<=DS:[SI]
|
|
passcnt_s <= X"01"; -- jump to extra pass 1 (skip 10 first round)
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & REG_AX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= DONTCARE(14 downto 0); -- selalua(4) & selalub(4) & aluopr(7)
|
|
-- DS:[SI]
|
|
if (rep_flag='1' and status.cx_zero='1') then -- if CX=0 then skip instruction
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
path_s.ea_output<=NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- Need another pass
|
|
path_s.ea_output<="0001011001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update AX
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
else
|
|
|
|
if (passcnt=X"02") then -- load al/ax<= DS:[SI]
|
|
second_pass_s <= '1'; -- Need another pass
|
|
passcnt_s <= passcnt - '1';
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & REG_AX(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= DONTCARE(14 downto 0);-- selalua(4) & selalub(4) & aluopr(7)
|
|
-- DS:[SI]
|
|
path_s.ea_output<="0001011001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- Update AX
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
elsif (passcnt=X"01") then -- Second PASS update SI
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_SI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SI
|
|
if rep_flag='1' then -- If repeat set, check CX-1
|
|
second_pass_s <= '1';
|
|
next_state <= Sdecode;
|
|
else -- no repeat end cycle
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
else -- third pass (only when rep_flag=1) CX-1
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC; -- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update CX
|
|
--if (status.cx_one='1' or rep_zl_s/=status.flag(6)) then -- quit on CX=1 or ZF=z_repeat_intr
|
|
if (status.cx_one='1') then -- quit on CX=1 IGNORE ZFLAG!!!!
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
passcnt_s <= passcnt - '1'; -- not required, change to DONTCARE???????????????????????????????
|
|
wrpath_s.wrip <= '1';
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
passcnt_s <= X"02"; -- Next another read mem pass
|
|
next_state <= Sdecode;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Store String
|
|
-- ES:[DI] <=AL/AX DI++/--
|
|
-- if REP/REPZ then repeat on CX value only!
|
|
---------------------------------------------------------------------------------
|
|
when STOSB | STOSW =>
|
|
|
|
if (second_pass='0') then -- First pass, load ES:[DI]<=AL/AX
|
|
passcnt_s <= X"01"; -- jump to extra pass 1 (skip 10 first round)
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX&DONTCARE(3 downto 0)&ALU_PASSA;-- selalua(4) & selalub(4) & aluopr(7)
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
if (rep_flag='1' and status.cx_zero='1') then -- if CX=0 then skip instruction
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
path_s.ea_output<=NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- Need another pass
|
|
path_s.ea_output<="0001000001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Swritemem; -- start write cycle
|
|
end if;
|
|
|
|
else
|
|
|
|
if (passcnt=X"02") then -- load ES:[DI]<=AL/AX
|
|
second_pass_s <= '1'; -- Need another pass
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX&DONTCARE(3 downto 0)&ALU_PASSA;-- selalua(4) & selalub(4) & aluopr(7)
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
|
|
path_s.ea_output<="0001000001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Swritemem; -- start write cycle
|
|
|
|
elsif (passcnt=X"01") then -- Second PASS update DI
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_DI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update DI
|
|
|
|
if rep_flag='1' then -- If repeat set, check CX-1
|
|
second_pass_s <= '1';
|
|
next_state <= Sdecode;
|
|
else -- no repeat end cycle
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
else -- third pass (only when rep_flag=1) CX-1
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC; -- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update CX
|
|
|
|
--if (status.cx_one='1' or rep_zl_s/=status.flag(6)) then -- quit on CX=1 or ZF=z_repeat_intr
|
|
if (status.cx_one='1') then -- quit on CX=1 IGNORE ZFLAG!!!!
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
passcnt_s <= passcnt - '1'; -- not required, change to DONTCARE???????????????????????????????
|
|
wrpath_s.wrip <= '1';
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
passcnt_s <= X"02"; -- Next another read mem pass
|
|
next_state <= Sdecode;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- MOV String
|
|
-- ES:[DI] <=SEG:[SI], SEG default to DS
|
|
-- DI++/-- ,SI++/--
|
|
---------------------------------------------------------------------------------
|
|
when MOVSB | MOVSW =>
|
|
|
|
if (second_pass='0') then -- First pass, load ALUREG<=SEG:[SI]
|
|
passcnt_s <= X"03"; -- Jump to state 3
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- Load memory into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
wrpath_s.wralu <= '1'; -- Don't care if instruction is not executed
|
|
|
|
if (rep_flag='1' and status.cx_zero='1') then -- if CX=0 then skip instruction
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
path_s.ea_output<=NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- Need another pass
|
|
path_s.ea_output<="0001011001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
else
|
|
|
|
if (passcnt=X"04") then -- Same operation as second_pass=0, load ALUREG<=SEG:[SI]
|
|
second_pass_s <= '1'; -- Need another pass
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- Load memory into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
wrpath_s.wralu <= '1'; -- Don't care if instruction is not executed
|
|
|
|
path_s.ea_output<="0001011001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
elsif (passcnt=X"03") then -- second pass write ALUREG to ES:DI
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= DONTCARE(7 downto 0)&ALU_REGL;-- selalua(4) & selalub(4) & aluopr(7) ALUREG=>output
|
|
path_s.dbus_output <= ALUBUS_OUT; --{eabus(0)&} domux setting
|
|
-- ES:[DI]
|
|
path_s.ea_output<="0001000101"; -- dispmux(3) & eamux(4) & dis_opflag=1 & segop[1:0]
|
|
|
|
next_state <= Swritemem; -- start write cycle
|
|
|
|
elsif (passcnt=X"02") then -- Next update DI
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_DI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=DONTCARE(9 downto 0); -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- Update DI
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"01") then -- Final pass if no repeat update SI
|
|
second_pass_s <= '0'; -- clear
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_SI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- Update SI
|
|
|
|
if rep_flag='1' then -- If repeat set, check CX-1
|
|
second_pass_s <= '1';
|
|
next_state <= Sdecode;
|
|
else -- no repeat end cycle
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
else -- third pass (only when rep_flag=1) CX-1
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC; -- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update CX
|
|
|
|
if (status.cx_one='1') then -- quit on CX=1 IGNORE ZFLAG!!!!
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
passcnt_s <= passcnt - '1'; -- not required, change to DONTCARE???????????????????????????????
|
|
wrpath_s.wrip <= '1';
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
passcnt_s <= X"04"; -- Next another R/W mem pass
|
|
next_state <= Sdecode;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- CMPS Destination, source
|
|
-- note source - destination
|
|
-- SEGM:[SI] - ES:[DI]
|
|
--
|
|
-- SEGM defaults to DS, can be overwritten
|
|
-- Destination is ALWAYS ES:[DI] (dis_opflag is asserted during the read cycle)
|
|
-- DI++/--, SI++/--
|
|
-- Note no signextend on operands (compared to the CMP instruction)
|
|
---------------------------------------------------------------------------------
|
|
when CMPSB | CMPSW =>
|
|
|
|
if (second_pass='0') then -- First pass, load ALUREG<=ES:[DI] (fixed!)
|
|
passcnt_s <= X"03"; -- Jump to state 3
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- Load memory into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
wrpath_s.wralu <= '1'; -- Don't care if instruction is not executed
|
|
|
|
if (rep_flag='1' and status.cx_zero='1') then -- if CX=0 then skip instruction
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
path_s.ea_output<=NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- Need another pass, note dis_opflag=1
|
|
path_s.ea_output<="0001000101"; -- dispmux(3) & eamux(4) & dis_opflag=1 & segop[1:0]
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
else
|
|
|
|
if (passcnt=X"04") then -- Same operation as second_pass=0, load ALUREG<=SEG:[SI]
|
|
second_pass_s <= '1'; -- Need another pass
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
-- for CMPS load memory into ALUREG
|
|
path_s.alu_operation<= DONTCARE(3 downto 0) & REG_MDBUS & ALU_REGL; -- selalua(4) & selalub(4) & aluopr(7)
|
|
path_s.ea_output<="0001000101"; -- dispmux(3) & eamux(4) & dis_opflag=1 & segop[1:0]
|
|
wrpath_s.wralu <= '1';
|
|
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
elsif (passcnt="0011") then -- second pass read SEG:[SI], ALUREG-SEG:[SI]
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= DONTCARE(2 downto 0) & instr.ireg(0) & DONTCARE(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_MDBUS & DONTCARE(3 downto 0)&ALU_CMPS;-- selalua(4) & selalub(4) & aluopr(7) ALUREG=>output
|
|
-- ES:[DI]
|
|
path_s.ea_output<="0001011001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrcc <= '1'; -- update flag register
|
|
next_state <= Sreadmem;
|
|
|
|
elsif (passcnt=X"02") then -- Next update DI
|
|
second_pass_s <= '1';
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_DI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=DONTCARE(9 downto 0); -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- Update DI
|
|
next_state <= Sdecode;
|
|
|
|
elsif (passcnt=X"01") then -- Final pass if no repeat update SI
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_SI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_SI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- yes, then update SI
|
|
|
|
if rep_flag='1' then -- If repeat set, check CX-1
|
|
second_pass_s <= '1';
|
|
next_state <= Sdecode;
|
|
else -- no repeat end cycle
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
else -- third pass (only when rep_flag=1) CX-1
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC; -- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update CX
|
|
|
|
if (status.cx_one='1' or rep_zl_s/=status.flag(6)) then -- quit on CX=1 or ZF=z_repeat_intr
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
passcnt_s <= passcnt - '1'; -- not required, change to DONTCARE?
|
|
wrpath_s.wrip <= '1';
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
passcnt_s <= X"04"; -- Next another R/W mem pass
|
|
next_state <= Sdecode;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- SCAS
|
|
-- SCAS -> AX/AL-ES[DI]
|
|
-- DI++/--
|
|
-- Note no signextend on operands (compared to the CMP instruction)
|
|
---------------------------------------------------------------------------------
|
|
when SCASB | SCASW =>
|
|
|
|
if (second_pass='0') then -- First pass, AX-ES:[DI]
|
|
passcnt_s <= X"01"; -- Jump to state 1
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & REG_MDBUS & ALU_SCAS; -- selalua(4) & selalub(4) & aluopr(7)
|
|
|
|
if (rep_flag='1' and status.cx_zero='1') then -- if CX=0 then skip instruction
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
path_s.ea_output<= NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1'; -- Need another pass
|
|
path_s.ea_output<= "0001000001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrcc <= '1'; -- update flag register
|
|
next_state <= Sreadmem; -- start read cycle
|
|
end if;
|
|
|
|
else
|
|
|
|
if (passcnt=X"02") then -- Same operation as second_pass=0, AX/AL-SEG:[SI]
|
|
second_pass_s <= '1'; -- Need another pass
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= MDBUS_IN & instr.ireg(0) & DONTCARE(2 downto 0); -- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_AX & REG_MDBUS & ALU_SCAS; -- selalua(4) & selalub(4) & aluopr(7)
|
|
|
|
path_s.ea_output<= "0001000001"; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrcc <= '1'; -- update flag register
|
|
next_state <= Sreadmem; -- start read cycle
|
|
|
|
elsif (passcnt=X"01") then -- Final pass if no repeat update DI
|
|
second_pass_s <= '0'; -- clear
|
|
passcnt_s <= passcnt - '1';
|
|
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_DI(2 downto 0);-- dimux & w & seldreg
|
|
|
|
path_s.alu_operation<= REG_DI & -- selalua(4) & selalub(4) & aluopr
|
|
REG_CONST1(3 downto 2)&instr.ireg(0)&(not instr.ireg(0))& -- w selects 1 or 2
|
|
ALU_INC(6 downto 1)&status.flag(10); -- df flag select inc/dec
|
|
|
|
path_s.ea_output<=NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
|
|
wrpath_s.wrd <= '1'; -- yes, then update DI
|
|
|
|
if rep_flag='1' then -- If repeat set, check CX-1
|
|
second_pass_s <= '1';
|
|
next_state <= Sdecode;
|
|
else -- no repeat end cycle
|
|
second_pass_s <= '0';
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
end if;
|
|
|
|
else -- third pass (only when rep_flag=1) CX-1
|
|
path_s.datareg_input<= ALUBUS_IN & '1' & REG_CX(2 downto 0);-- dimux & w & seldreg
|
|
path_s.alu_operation<= REG_CX & REG_CONST1 & ALU_DEC; -- selalua(4) & selalub(4) & aluopr
|
|
path_s.ea_output <= NB_CS_IP; -- dispmux(3) & eamux(4) & dis_opflag & segop[1:0]
|
|
wrpath_s.wrd <= '1'; -- Update CX
|
|
|
|
if (status.cx_one='1' or rep_zl_s/=status.flag(6)) then -- quit on CX=1 or ZF=z_repeat_intr
|
|
second_pass_s <= '0';
|
|
rep_clear_s <= '1'; -- Clear Repeat flag
|
|
passcnt_s <= passcnt - '1'; -- not required, change to DONTCARE???????????????????????????????
|
|
wrpath_s.wrip <= '1';
|
|
next_state <= Sexecute;
|
|
else
|
|
second_pass_s <= '1';
|
|
passcnt_s <= X"02"; -- Next another Read mem pass
|
|
next_state <= Sdecode;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- REP/REPz Instruction
|
|
-- Set REPEAT Flag
|
|
---------------------------------------------------------------------------------
|
|
when REPNE | REPE =>
|
|
|
|
irq_blocked_s <= '1'; -- Block IRQ if asserted during next instr.
|
|
second_pass_s <= '0';
|
|
rep_set_s <= '1';
|
|
rep_z_s <= instr.ireg(0); -- REPNE or REPE
|
|
path_s.ea_output<= NB_CS_IP;
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
|
|
---------------------------------------------------------------------------------
|
|
-- Conditional Jump
|
|
---------------------------------------------------------------------------------
|
|
when JZ | JL | JLE | JB | JBE| JP | JO | JS | JNE | JNL | JNLE | JNB| JNBE | JNP | JNO | JNS =>
|
|
|
|
second_pass_s <= '0';
|
|
|
|
if (((instr.ireg(3 downto 0)="0000") and (status.flag(11)='1')) or -- Jump on Overflow (OF=1)
|
|
((instr.ireg(3 downto 0)="0001") and (status.flag(11)='0')) or -- Jump on not overflow (OF=0)
|
|
((instr.ireg(3 downto 0)="0010") and (status.flag(0)='1')) or -- Jump on Below (CF=1)
|
|
((instr.ireg(3 downto 0)="0011") and (status.flag(0)='0')) or -- Jump on not below (CF=0)
|
|
((instr.ireg(3 downto 0)="0100") and (status.flag(6)='1')) or -- Jump on Zero ZF=1;
|
|
((instr.ireg(3 downto 0)="0101") and (status.flag(6)='0')) or -- Jump on not zero ZF=0
|
|
((instr.ireg(3 downto 0)="0110") and (status.flag(0)='1' or status.flag(6)='1')) or -- JBE, Jump on below or equal CF or ZF=1
|
|
((instr.ireg(3 downto 0)="0111") and (status.flag(0)='0' and status.flag(6)='0')) or -- JNBE, Jump on not below or equal CF&ZF=0
|
|
((instr.ireg(3 downto 0)="1000") and (status.flag(7)='1')) or -- JS, Jump on ZF=1
|
|
((instr.ireg(3 downto 0)="1001") and (status.flag(7)='0')) or -- JNS, Jump on ZF=0
|
|
((instr.ireg(3 downto 0)="1010") and (status.flag(2)='1')) or -- JP, Jump on Parity PF=1
|
|
((instr.ireg(3 downto 0)="1011") and (status.flag(2)='0')) or -- JNP, Jump on not parity PF=0
|
|
((instr.ireg(3 downto 0)="1100") and (status.flag(7)/=status.flag(11))) or -- JL, Jump on less or equal SF!=OF
|
|
((instr.ireg(3 downto 0)="1101") and (status.flag(7)=status.flag(11))) or -- JNL, Jump on not less, SF=OF
|
|
((instr.ireg(3 downto 0)="1110") and ((status.flag(7)/=status.flag(11)) or status.flag(6)='1')) or -- JLE, Jump on less or equal
|
|
((instr.ireg(3 downto 0)="1111") and ((status.flag(7)=status.flag(11)) and status.flag(6)='0'))) -- JNLE, Jump on not less or equal SF=OF & zf=0
|
|
then
|
|
flush_req_s <= '1'; -- Flush Prefetch queue, asserted during execute cycle
|
|
path_s.ea_output <= DISP_CS_IP; -- CS: IPREG+DISPL
|
|
else
|
|
path_s.ea_output <= NB_CS_IP; -- IPREG+NB ADDR=CS:IP
|
|
end if;
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
next_state <= Sexecute;
|
|
|
|
when others =>
|
|
proc_error_s<='1'; -- Assert Bus Error Signal
|
|
|
|
wrpath_s.wrip <= '1'; -- Update IP+nbreq register
|
|
path_s.ea_output<= NB_CS_IP; -- Go to next opcode
|
|
next_state <= Sexecute; -- Ignore opcode, fetch next one
|
|
|
|
-- pragma synthesis_off
|
|
assert not (now > 0 ns) report "**** Unknown Instruction to decode (proc) ***" severity warning;
|
|
-- pragma synthesis_on
|
|
|
|
end case;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Get Operand/Data from Memory
|
|
-- if second_pass=0 then execute else go for second pass
|
|
----------------------------------------------------------------------------
|
|
when Sreadmem =>
|
|
read_req <= '1'; -- Request Read Cycle
|
|
|
|
if rw_ack='1' then -- read cycle completed?
|
|
if second_pass='0' then
|
|
next_state <= Sexecute; -- execute instruction
|
|
else
|
|
next_state <= Sdecode; -- second pass
|
|
end if;
|
|
else
|
|
next_state <= Sreadmem; -- Wait ack from BIU
|
|
end if;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Write Data to Memory
|
|
-- if second_pass=0 then execute else go for second pass
|
|
----------------------------------------------------------------------------
|
|
when Swritemem =>
|
|
write_req <= '1'; -- Request Write Cycle
|
|
|
|
if rw_ack='1' then -- read cycle completed?
|
|
if second_pass='0' then
|
|
next_state <= Sexecute; -- execute instruction
|
|
else
|
|
next_state <= Sdecode; -- second pass
|
|
end if;
|
|
else
|
|
next_state <= Swritemem; -- Wait ack from BIU
|
|
end if;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Execute
|
|
-- wrpath get wrpathl_s signal
|
|
----------------------------------------------------------------------------
|
|
when Sexecute =>
|
|
|
|
wrpath <= wrpathl_s; -- Assert write strobe(s)
|
|
iomem_s <= '0'; -- Clear IOMEM cycle
|
|
|
|
-- Do not clear if REP or LOCK is used as a prefix
|
|
if ((instr.ireg/=SEGOPES) and (instr.ireg/=SEGOPCS) and (instr.ireg/=SEGOPSS) and
|
|
(instr.ireg/=SEGOPDS) and (instr.ireg/=REPNE) and
|
|
(instr.ireg/=REPE)) then
|
|
clrop <= '1'; -- clear Segment Override Flag
|
|
end if;
|
|
|
|
if instr.ireg=HLT then -- If instr=HLT then wait for interrupt
|
|
next_state <= Shalt;
|
|
elsif (flush_reql_s='1' AND flush_ack='1') then -- Flush Request & ACK
|
|
next_state <= Sopcode;
|
|
elsif (flush_reql_s='1' AND flush_ack='0') then -- Flush request and no ack yet
|
|
flush_req_s <= '1';
|
|
next_state <= Sflush; -- wait for ack flush
|
|
else
|
|
next_state <= Sopcode;
|
|
end if;
|
|
|
|
|
|
----------------------------------------------------------------------------
|
|
-- Flush State, wait until flush_ack is asserted
|
|
----------------------------------------------------------------------------
|
|
when Sflush =>
|
|
|
|
if flush_ack='0' then
|
|
flush_req_s <= '1'; -- Continue asserting flush req
|
|
next_state <= Sflush; -- Wait until req is removed
|
|
else
|
|
next_state <= Sopcode; -- Next Opcode
|
|
end if;
|
|
|
|
when Shalt =>
|
|
if irq_req='1' then
|
|
next_state <= Sopcode; -- Next Opcode
|
|
else
|
|
next_state <= Shalt; -- wait for interrupt
|
|
end if;
|
|
|
|
when others =>
|
|
next_state <= Sopcode;
|
|
|
|
end case;
|
|
end process nextstate;
|
|
|
|
end rtl;
|