1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-21 18:04:59 +00:00
2019-07-22 23:42:05 +02:00

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;