1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-18 17:06:57 +00:00
2020-05-13 15:54:31 +02:00

2075 lines
65 KiB
VHDL

-------------------------------------------------------------------------------
--
-- The Decoder unit.
-- It decodes the instruction opcodes and executes them.
--
-- $Id: decoder.vhd,v 1.25 2006/06/20 00:46:03 arniml Exp $
--
-- Copyright (c) 2004, Arnim Laeuger (arniml@opencores.org)
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t48/
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.t48_pack.word_t;
use work.t48_pack.mstate_t;
use work.t48_alu_pack.alu_op_t;
use work.t48_cond_branch_pack.all;
use work.t48_dmem_ctrl_pack.all;
use work.t48_pmem_ctrl_pack.all;
entity t48_decoder is
generic (
-- store mnemonic in flip-flops (registered-out)
register_mnemonic_g : integer := 1
);
port (
-- Global Interface -------------------------------------------------------
clk_i : in std_logic;
res_i : in std_logic;
en_clk_i : in boolean;
xtal_i : in std_logic;
xtal_en_i : in boolean;
ea_i : in std_logic;
ale_i : in boolean;
int_n_i : in std_logic;
t0_dir_o : out std_logic;
-- T48 Bus Interface ------------------------------------------------------
data_i : in word_t;
data_o : out word_t;
alu_write_accu_o : out boolean;
alu_write_shadow_o : out boolean;
alu_write_temp_reg_o : out boolean;
alu_read_alu_o : out boolean;
bus_write_bus_o : out boolean;
bus_read_bus_o : out boolean;
dm_write_dmem_addr_o : out boolean;
dm_write_dmem_o : out boolean;
dm_read_dmem_o : out boolean;
p1_write_p1_o : out boolean;
p1_read_p1_o : out boolean;
p2_write_p2_o : out boolean;
p2_write_exp_o : out boolean;
p2_read_p2_o : out boolean;
p2_read_exp_o : out boolean;
pm_write_pcl_o : out boolean;
pm_read_pcl_o : out boolean;
pm_write_pch_o : out boolean;
pm_read_pch_o : out boolean;
pm_read_pmem_o : out boolean;
psw_read_psw_o : out boolean;
psw_read_sp_o : out boolean;
psw_write_psw_o : out boolean;
psw_write_sp_o : out boolean;
-- ALU Interface ----------------------------------------------------------
alu_carry_i : in std_logic;
alu_op_o : out alu_op_t;
alu_use_carry_o : out boolean;
alu_da_high_o : out boolean;
alu_accu_low_o : out boolean;
alu_p06_temp_reg_o : out boolean;
alu_p60_temp_reg_o : out boolean;
alu_da_overflow_i : in boolean;
-- BUS Interface ----------------------------------------------------------
bus_output_pcl_o : out boolean;
bus_bidir_bus_o : out boolean;
-- Clock Controller Interface ---------------------------------------------
clk_multi_cycle_o : out boolean;
clk_assert_psen_o : out boolean;
clk_assert_prog_o : out boolean;
clk_assert_rd_o : out boolean;
clk_assert_wr_o : out boolean;
clk_mstate_i : in mstate_t;
clk_second_cycle_i : in boolean;
-- Conditional Branch Logic Interface -------------------------------------
cnd_compute_take_o : out boolean;
cnd_branch_cond_o : out branch_conditions_t;
cnd_take_branch_i : in boolean;
cnd_comp_value_o : out comp_value_t;
cnd_f1_o : out std_logic;
cnd_tf_o : out std_logic;
-- Data Memory Controller Interface ---------------------------------------
dm_addr_type_o : out dmem_addr_ident_t;
-- Port 1 Interface -------------------------------------------------------
p1_read_reg_o : out boolean;
-- Port 2 Interface -------------------------------------------------------
p2_read_reg_o : out boolean;
p2_output_pch_o : out boolean;
-- Program Memory Controller Interface ------------------------------------
pm_inc_pc_o : out boolean;
pm_write_pmem_addr_o : out boolean;
pm_addr_type_o : out pmem_addr_ident_t;
-- Program Status Word Interface ------------------------------------------
psw_special_data_o : out std_logic;
psw_carry_i : in std_logic;
psw_aux_carry_i : in std_logic;
psw_f0_i : in std_logic;
psw_inc_stackp_o : out boolean;
psw_dec_stackp_o : out boolean;
psw_write_carry_o : out boolean;
psw_write_aux_carry_o : out boolean;
psw_write_f0_o : out boolean;
psw_write_bs_o : out boolean;
-- Timer Interface --------------------------------------------------------
tim_read_timer_o : out boolean;
tim_write_timer_o : out boolean;
tim_start_t_o : out boolean;
tim_start_cnt_o : out boolean;
tim_stop_tcnt_o : out boolean;
tim_overflow_i : in boolean
);
end t48_decoder;
use work.t48_pack.all;
use work.t48_alu_pack.all;
use work.t48_decoder_pack.all;
use work.t48_comp_pack.t48_opc_decoder;
use work.t48_comp_pack.t48_int;
-- pragma translate_off
use work.t48_tb_pack.tb_istrobe_s;
-- pragma translate_on
architecture rtl of t48_decoder is
-- Enable fixing a bug of Quartus II 4.0
constant enable_quartus_bugfix_c : boolean := true;
-- Opcode Decoder
signal opc_multi_cycle_s : boolean;
signal opc_read_bus_s : boolean;
signal opc_inj_int_s : boolean;
signal opc_opcode_s : word_t;
signal opc_mnemonic_s : mnemonic_t;
signal last_cycle_s : boolean;
-- state translators
signal assert_psen_s : boolean;
-- branch taken handshake
signal branch_taken_s,
branch_taken_q : boolean;
signal pm_inc_pc_s : boolean;
signal pm_write_pmem_addr_s : boolean;
-- additional signal to increment PC during CALL
signal add_inc_pc_s : boolean;
-- addtional signal to set PC during RET(R)
signal add_write_pmem_addr_s : boolean;
-- Flag 1
signal clear_f1_s,
cpl_f1_s : boolean;
signal f1_q : std_logic;
-- memory bank select
signal clear_mb_s,
set_mb_s : boolean;
signal mb_q : std_logic;
-- T0 direction selection
signal ent0_clk_s : boolean;
signal t0_dir_q : std_logic;
signal data_s : word_t;
signal read_dec_s : boolean;
signal tf_s : std_logic;
signal bus_read_bus_s : boolean;
signal add_read_bus_s : boolean;
signal dm_write_dmem_s : boolean;
signal p2_output_exp_s : boolean;
signal movx_first_cycle_s : boolean;
-- interrupt handling
signal jtf_executed_s : boolean;
signal en_tcnti_s : boolean;
signal dis_tcnti_s : boolean;
signal en_i_s : boolean;
signal dis_i_s : boolean;
signal tim_int_s : boolean;
signal retr_executed_s : boolean;
signal int_executed_s : boolean;
signal int_pending_s : boolean;
signal int_in_progress_s : boolean;
-- pragma translate_off
signal istrobe_res_q : std_logic;
signal istrobe_q : std_logic;
signal injected_int_q : std_logic;
-- pragma translate_on
begin
-----------------------------------------------------------------------------
-- Opcode Decoder
-----------------------------------------------------------------------------
opc_decoder_b : t48_opc_decoder
generic map (
register_mnemonic_g => register_mnemonic_g
)
port map (
clk_i => clk_i,
res_i => res_i,
en_clk_i => en_clk_i,
data_i => data_i,
read_bus_i => opc_read_bus_s,
inj_int_i => opc_inj_int_s,
opcode_o => opc_opcode_s,
mnemonic_o => opc_mnemonic_s,
multi_cycle_o => opc_multi_cycle_s
);
-----------------------------------------------------------------------------
-- Interrupt Controller.
-----------------------------------------------------------------------------
int_b : t48_int
port map (
clk_i => clk_i,
res_i => res_i,
en_clk_i => en_clk_i,
xtal_i => xtal_i,
xtal_en_i => xtal_en_i,
clk_mstate_i => clk_mstate_i,
jtf_executed_i => jtf_executed_s,
tim_overflow_i => tim_overflow_i,
tf_o => tf_s,
en_tcnti_i => en_tcnti_s,
dis_tcnti_i => dis_tcnti_s,
int_n_i => int_n_i,
ale_i => ale_i,
last_cycle_i => last_cycle_s,
en_i_i => en_i_s,
dis_i_i => dis_i_s,
ext_int_o => open,
tim_int_o => tim_int_s,
retr_executed_i => retr_executed_s,
int_executed_i => int_executed_s,
int_pending_o => int_pending_s,
int_in_progress_o => int_in_progress_s
);
last_cycle_s <= not opc_multi_cycle_s or
(opc_multi_cycle_s and clk_second_cycle_i);
-----------------------------------------------------------------------------
-- Process machine_cycle
--
-- Purpose:
-- Generates the control signals that are basically needed for the
-- handling of a machine cycle.
--
machine_cycle: process (clk_mstate_i,
clk_second_cycle_i,
last_cycle_s,
ea_i,
assert_psen_s,
branch_taken_q,
int_pending_s,
p2_output_exp_s,
movx_first_cycle_s)
variable need_address_v : boolean;
begin
-- default assignments
clk_assert_psen_o <= false;
pm_inc_pc_s <= false;
pm_write_pmem_addr_s <= false;
pm_read_pmem_o <= false;
bus_output_pcl_o <= false;
p2_output_pch_o <= false;
opc_read_bus_s <= false;
opc_inj_int_s <= false;
bus_read_bus_s <= false;
need_address_v := not clk_second_cycle_i or
(clk_second_cycle_i and assert_psen_s);
case clk_mstate_i is
when MSTATE1 =>
if need_address_v then
if ea_i = '0' then
if not int_pending_s then
pm_read_pmem_o <= true;
end if;
else
if not int_pending_s then
bus_read_bus_s <= true;
end if;
p2_output_pch_o <= true;
end if;
end if;
if not clk_second_cycle_i then
if not int_pending_s then
opc_read_bus_s <= true;
else
opc_inj_int_s <= true; -- inject interrupt call
end if;
end if;
when MSTATE2 =>
if need_address_v and not branch_taken_q and
not int_pending_s then
pm_inc_pc_s <= true;
end if;
when MSTATE3 =>
if need_address_v then
-- Theory of operation:
-- Program Memory address is updated at end of State 3 (or end of
-- State 2 in case of a RET). Address information is thus available
-- latest with State 4.
-- This is the time where we need information about access target
-- (internal or external = EA). EA information needs to be stable
-- until end of State 1.
pm_write_pmem_addr_s <= true;
end if;
when MSTATE4 =>
if ea_i = '1' and
((not clk_second_cycle_i and assert_psen_s)
or last_cycle_s) then
clk_assert_psen_o <= true;
p2_output_pch_o <= true;
bus_output_pcl_o <= true;
end if;
when MSTATE5 =>
if ea_i = '1' and
(need_address_v or last_cycle_s) and
-- Suppress output of PCH when either
-- a) expander port is driven on P2, has priority
not p2_output_exp_s and
-- b) first cycle of MOVX, don't disturb external access
not movx_first_cycle_s then
p2_output_pch_o <= true;
end if;
when others =>
-- pragma translate_off
assert false
report "Unkown machine state!"
severity error;
-- pragma translate_on
end case;
end process machine_cycle;
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Process decode
--
-- Purpose:
-- Indentifies each single instruction and steps through the related
-- execution sequence.
--
decode: process (alu_carry_i,
psw_aux_carry_i,
alu_da_overflow_i,
clk_mstate_i,
clk_second_cycle_i,
cnd_take_branch_i,
opc_opcode_s,
opc_mnemonic_s,
psw_carry_i,
psw_f0_i,
f1_q,
mb_q,
tim_int_s,
int_pending_s,
int_in_progress_s)
procedure address_indirect_3_f is
begin
-- apply dmem address from selected register for indirect mode
if opc_opcode_s(3) = '0' or enable_quartus_bugfix_c then
dm_read_dmem_o <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_PLAIN;
end if;
end;
procedure and_or_xor_add_4_f is
begin
-- write dmem contents to Temp Reg
dm_read_dmem_o <= true;
alu_write_temp_reg_o <= true;
end;
procedure and_or_xor_add_5_f (alu_op : alu_op_t) is
begin
-- perform ALU operation and store in Accumulator
alu_op_o <= alu_op;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
end;
procedure cond_jump_c2_m1_f is
begin
-- store address in Program Counter low byte if branch has to
-- be taken
-- if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
pm_write_pcl_o <= true;
branch_taken_s <= true;
-- end if;
end;
-- intermediate value of the Program Memory Bank Flag
variable mb_v : std_logic;
begin
-- default assignments
data_s <= (others => '-');
read_dec_s <= false;
branch_taken_s <= false;
clear_f1_s <= false;
cpl_f1_s <= false;
clear_mb_s <= false;
set_mb_s <= false;
add_inc_pc_s <= false;
assert_psen_s <= false;
alu_write_accu_o <= false;
alu_write_shadow_o <= false;
alu_write_temp_reg_o <= false;
alu_p06_temp_reg_o <= false;
alu_p60_temp_reg_o <= false;
alu_read_alu_o <= false;
bus_write_bus_o <= false;
bus_bidir_bus_o <= false;
dm_write_dmem_addr_o <= false;
dm_write_dmem_s <= false;
dm_read_dmem_o <= false;
pm_write_pcl_o <= false;
pm_read_pcl_o <= false;
pm_write_pch_o <= false;
pm_read_pch_o <= false;
pm_addr_type_o <= PM_PC;
psw_read_psw_o <= false;
psw_read_sp_o <= false;
psw_write_psw_o <= false;
psw_write_sp_o <= false;
alu_op_o <= ALU_NOP;
alu_use_carry_o <= false;
alu_da_high_o <= false;
alu_accu_low_o <= false;
clk_assert_prog_o <= false;
clk_assert_rd_o <= false;
clk_assert_wr_o <= false;
cnd_branch_cond_o <= COND_ON_BIT;
cnd_compute_take_o <= false;
cnd_comp_value_o <= opc_opcode_s(7 downto 5);
dm_addr_type_o <= DM_REG;
tim_read_timer_o <= false;
tim_write_timer_o <= false;
tim_start_t_o <= false;
tim_start_cnt_o <= false;
tim_stop_tcnt_o <= false;
p1_write_p1_o <= false;
p1_read_p1_o <= false;
p1_read_reg_o <= false;
p2_write_p2_o <= false;
p2_write_exp_o <= false;
p2_read_p2_o <= false;
p2_read_reg_o <= false;
p2_read_exp_o <= false;
p2_output_exp_s <= false;
psw_special_data_o <= '0';
psw_inc_stackp_o <= false;
psw_dec_stackp_o <= false;
psw_write_carry_o <= false;
psw_write_aux_carry_o <= false;
psw_write_f0_o <= false;
psw_write_bs_o <= false;
jtf_executed_s <= false;
en_tcnti_s <= false;
dis_tcnti_s <= false;
en_i_s <= false;
dis_i_s <= false;
retr_executed_s <= false;
int_executed_s <= false;
add_write_pmem_addr_s <= false;
ent0_clk_s <= false;
add_read_bus_s <= false;
movx_first_cycle_s <= false;
-- the Program Memory Bank Flag is held low when interrupts are in progress
-- according to the MCS-48 User's Manual
if int_in_progress_s then
mb_v := '0';
else
mb_v := mb_q;
end if;
-- prepare potential register indirect address mode
if not clk_second_cycle_i and clk_mstate_i = MSTATE2 then
data_s <= (others => '0');
if opc_opcode_s(3) = '1' then
data_s(2 downto 0) <= opc_opcode_s(2 downto 0);
else
data_s(2 downto 0) <= "00" & opc_opcode_s(0);
end if;
read_dec_s <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_REG;
end if;
case opc_mnemonic_s is
-- Mnemonic ADD ---------------------------------------------------------
when MN_ADD =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- store data from RAM to Temp Reg
when MSTATE4 =>
and_or_xor_add_4_f;
-- perform ADD and store in Accumulator
when MSTATE5 =>
and_or_xor_add_5_f(alu_op => ALU_ADD);
if opc_opcode_s(4) = '1' then
alu_use_carry_o <= true;
end if;
psw_special_data_o <= alu_carry_i;
psw_write_carry_o <= true;
psw_write_aux_carry_o <= true;
when others =>
null;
end case;
-- Mnemonic ADD_A_DATA --------------------------------------------------
when MN_ADD_A_DATA =>
assert_psen_s <= true;
if clk_second_cycle_i then
case clk_mstate_i is
-- write Temp Reg when contents of Program Memory is on bus
when MSTATE1 =>
alu_write_temp_reg_o <= true;
-- perform ADD and store in Accumulator
when MSTATE3 =>
and_or_xor_add_5_f(alu_op => ALU_ADD);
if opc_opcode_s(4) = '1' then
alu_use_carry_o <= true;
end if;
psw_special_data_o <= alu_carry_i;
psw_write_carry_o <= true;
psw_write_aux_carry_o <= true;
when others =>
null;
end case;
end if;
-- Mnemonic ANL ---------------------------------------------------------
when MN_ANL =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- store data from RAM to Temp Reg
when MSTATE4 =>
and_or_xor_add_4_f;
-- perform AND and store in Accumulator
when MSTATE5 =>
and_or_xor_add_5_f(alu_op => ALU_AND);
when others =>
null;
end case;
-- Mnemonic ANL_A_DATA --------------------------------------------------
when MN_ANL_A_DATA =>
assert_psen_s <= true;
if clk_second_cycle_i then
case clk_mstate_i is
-- write Temp Reg when contents of Program Memory is on bus
when MSTATE1 =>
alu_write_temp_reg_o <= true;
-- perform AND and store in Accumulator
when MSTATE3 =>
and_or_xor_add_5_f(alu_op => ALU_AND);
when others =>
null;
end case;
end if;
-- Mnemonic ANL_EXT -----------------------------------------------------
when MN_ANL_EXT =>
assert_psen_s <= true;
if not clk_second_cycle_i then
-- read port to Temp Reg
if clk_mstate_i = MSTATE5 then
if opc_opcode_s(1 downto 0) = "00" then
add_read_bus_s <= true;
elsif opc_opcode_s(1) = '0' then
p1_read_p1_o <= true;
p1_read_reg_o <= true;
else
p2_read_p2_o <= true;
p2_read_reg_o <= true;
end if;
alu_write_temp_reg_o <= true;
end if;
else
case clk_mstate_i is
-- write shadow Accumulator when contents of Program Memory is
-- on bus
when MSTATE1 =>
alu_write_shadow_o <= true;
-- loop shadow Accumulator through ALU to prevent update from
-- real Accumulator
when MSTATE2 =>
alu_read_alu_o <= true;
alu_write_shadow_o <= true;
-- write result of AND operation back to port
when MSTATE3 =>
alu_op_o <= ALU_AND;
alu_read_alu_o <= true;
if opc_opcode_s(1 downto 0) = "00" then
bus_write_bus_o <= true;
elsif opc_opcode_s(1) = '0' then
p1_write_p1_o <= true;
else
p2_write_p2_o <= true;
end if;
when others =>
null;
end case;
end if;
-- Mnemonic CALL --------------------------------------------------------
when MN_CALL =>
assert_psen_s <= true;
if not clk_second_cycle_i then
case clk_mstate_i is
-- read Stack Pointer and address Data Memory for low byte
-- also increment Program Counter to point to next instruction
when MSTATE3 =>
psw_read_sp_o <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_STACK;
-- only increment PC if this is not an injected CALL
-- injected CALLS are not located in Program Memory,
-- the PC points already to the instruction to be executed
-- after the interrupt
if not int_pending_s then
add_inc_pc_s <= true;
end if;
-- store Program Counter low byte on stack
when MSTATE4 =>
pm_read_pcl_o <= true;
dm_write_dmem_s <= true;
-- store Program Counter high byte and PSW on stack
-- increment Stack pointer
when MSTATE5 =>
psw_read_psw_o <= true;
pm_read_pch_o <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_STACK_HIGH;
dm_write_dmem_s <= true;
psw_inc_stackp_o <= true;
when others =>
null;
end case;
else
case clk_mstate_i is
-- store address in Program Counter low byte
when MSTATE1 =>
pm_write_pcl_o <= true;
branch_taken_s <= true;
if int_pending_s then
-- apply low part of vector address manually
data_s <= (others => '0');
data_s(1 downto 0) <= "11";
if tim_int_s then
data_s(2) <= '1';
end if;
read_dec_s <= true;
end if;
when MSTATE2 =>
pm_write_pch_o <= true;
read_dec_s <= true;
if not int_pending_s then
-- store high part of target address in Program Counter
data_s <= "0000" & mb_v & opc_opcode_s(7 downto 5);
else
-- apply high part of vector address manually
data_s <= (others => '0');
int_executed_s <= true;
end if;
when others =>
null;
end case;
end if;
-- Mnemonic CLR_A -------------------------------------------------------
when MN_CLR_A =>
-- write CLR output of ALU to Accumulator
if clk_mstate_i = MSTATE3 then
alu_op_o <= ALU_CLR;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
end if;
-- Mnemonic CLR_C -------------------------------------------------------
when MN_CLR_C =>
-- store 0 to Carry
if clk_mstate_i = MSTATE3 then
psw_special_data_o <= '0';
psw_write_carry_o <= true;
end if;
-- Mnemonic CLR_F -------------------------------------------------------
when MN_CLR_F =>
-- store 0 to selected flag
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(5) = '0' then
psw_special_data_o <= '0';
psw_write_f0_o <= true;
else
clear_f1_s <= true;
end if;
end if;
-- Mnemonic CPL_A -------------------------------------------------------
when MN_CPL_A =>
-- write CPL output of ALU to Accumulator
if clk_mstate_i = MSTATE3 then
alu_op_o <= ALU_CPL;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
end if;
-- Mnemnonic CPL_C ------------------------------------------------------
when MN_CPL_C =>
-- write inverse of Carry to PSW
if clk_mstate_i = MSTATE3 then
psw_special_data_o <= not psw_carry_i;
psw_write_carry_o <= true;
end if;
-- Mnemonic CPL_F -------------------------------------------------------
when MN_CPL_f =>
-- write inverse of selected flag back to flag
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(5) = '0' then
psw_special_data_o <= not psw_f0_i;
psw_write_f0_o <= true;
else
cpl_f1_s <= true;
end if;
end if;
-- Mnemonic DA ----------------------------------------------------------
when MN_DA =>
alu_op_o <= ALU_ADD;
case clk_mstate_i is
-- Step 1: Preload Temp Reg with 0x06
when MSTATE3 =>
alu_p06_temp_reg_o <= true;
-- Step 2: Check Auxiliary Carry and overflow on low nibble
-- Add 0x06 to shadow Accumulator if one is true
when MSTATE4 =>
if psw_aux_carry_i = '1' or alu_da_overflow_i then
alu_read_alu_o <= true;
alu_write_shadow_o <= true;
end if;
-- preload Temp Reg with 0x60
alu_p60_temp_reg_o <= true;
-- Step 3: Check overflow on high nibble
-- Add 0x60 to shadow Accumulator if true and store result
-- in Accumulator and PSW (only Carry)
when MSTATE5 =>
alu_da_high_o <= true;
if alu_da_overflow_i then
psw_special_data_o <= alu_carry_i;
else
alu_op_o <= ALU_NOP;
psw_special_data_o <= '0';
end if;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
psw_write_carry_o <= true;
when others =>
null;
end case;
-- Mnemonic DEC ---------------------------------------------------------
when MN_DEC =>
case clk_mstate_i is
when MSTATE4 =>
-- DEC Rr: store data from RAM to shadow Accumulator
if opc_opcode_s(6) = '1' then
dm_read_dmem_o <= true;
alu_write_shadow_o <= true;
end if;
when MSTATE5 =>
alu_op_o <= ALU_DEC;
alu_read_alu_o <= true;
if opc_opcode_s(6) = '0' then
-- write DEC of Accumulator to Accumulator
alu_write_accu_o <= true;
else
-- store DEC of shadow Accumulator back to dmem
dm_write_dmem_s <= true;
end if;
when others =>
null;
end case;
-- Mnemonic DIS_EN_I ----------------------------------------------------
when MN_DIS_EN_I =>
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(4) = '1' then
dis_i_s <= true;
else
en_i_s <= true;
end if;
end if;
-- Mnemonic DIS_EN_TCNTI ------------------------------------------------
when MN_DIS_EN_TCNTI =>
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(4) = '1' then
dis_tcnti_s <= true;
else
en_tcnti_s <= true;
end if;
end if;
-- Mnemonic DJNZ --------------------------------------------------------
when MN_DJNZ =>
assert_psen_s <= true;
if not clk_second_cycle_i then
case clk_mstate_i is
-- store data from RAM to shadow Accumulator
when MSTATE4 =>
dm_read_dmem_o <= true;
alu_write_shadow_o <= true;
-- write DEC result of shadow Accumulator back to dmem and
-- conditional branch logic
when MSTATE5 =>
alu_op_o <= ALU_DEC;
alu_read_alu_o <= true;
dm_write_dmem_s <= true;
cnd_compute_take_o <= true;
cnd_branch_cond_o <= COND_Z;
cnd_comp_value_o(0) <= '0';
when others =>
null;
end case;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic ENT0_CLK ----------------------------------------------------
when MN_ENT0_CLK =>
if clk_mstate_i = MSTATE3 then
ent0_clk_s <= true;
end if;
-- Mnemonic IN ----------------------------------------------------------
when MN_IN =>
-- read Port and store in Accumulator
if clk_second_cycle_i and clk_mstate_i = MSTATE2 then
alu_write_accu_o <= true;
if opc_opcode_s(1) = '0' then
p1_read_p1_o <= true;
else
p2_read_p2_o <= true;
end if;
end if;
-- Mnemonic INS ---------------------------------------------------------
when MN_INS =>
clk_assert_rd_o <= true;
-- read BUS and store in Accumulator
if clk_second_cycle_i and clk_mstate_i = MSTATE2 then
alu_write_accu_o <= true;
add_read_bus_s <= true;
end if;
-- Mnemonic INC ---------------------------------------------------------
when MN_INC =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
when MSTATE4 =>
-- INC Rr; INC @ Rr: store data from RAM to shadow Accumulator
if opc_opcode_s(3 downto 2) /= "01" then
dm_read_dmem_o <= true;
alu_write_shadow_o <= true;
end if;
when MSTATE5 =>
alu_op_o <= ALU_INC;
alu_read_alu_o <= true;
if opc_opcode_s(3 downto 2) = "01" then
-- write INC output of ALU to Accumulator
alu_write_accu_o <= true;
else
-- store INC of shadow Accumulator back to dmem
dm_write_dmem_s <= true;
end if;
when others =>
null;
end case;
-- Mnemonic JBB ---------------------------------------------------------
when MN_JBB =>
assert_psen_s <= true;
cnd_branch_cond_o <= COND_ON_BIT;
if not clk_second_cycle_i then
-- read Accumulator and start branch calculation
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
cnd_compute_take_o <= true;
-- cnd_comp_value_o is ok by default assignment
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JC ----------------------------------------------------------
when MN_JC =>
assert_psen_s <= true;
cnd_branch_cond_o <= COND_C;
if not clk_second_cycle_i then
-- start branch calculation
if clk_mstate_i = MSTATE3 then
cnd_compute_take_o <= true;
cnd_comp_value_o(0) <= opc_opcode_s(4);
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JF ----------------------------------------------------------
when MN_JF =>
assert_psen_s <= true;
if not clk_second_cycle_i then
-- start branch calculation
if clk_mstate_i = MSTATE3 then
cnd_compute_take_o <= true;
if opc_opcode_s(7) = '1' then
-- JF0
cnd_branch_cond_o <= COND_F0;
else
-- JF1
cnd_branch_cond_o <= COND_F1;
end if;
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JMP ---------------------------------------------------------
when MN_JMP =>
assert_psen_s <= true;
if clk_second_cycle_i then
case clk_mstate_i is
-- store address in Program Counter low byte
when MSTATE1 =>
pm_write_pcl_o <= true;
branch_taken_s <= true;
-- store high part of target address in Program Counter
when MSTATE2 =>
data_s <= "0000" & mb_v & opc_opcode_s(7 downto 5);
read_dec_s <= true;
pm_write_pch_o <= true;
when others =>
null;
end case;
end if;
-- Mnemonic JMPP --------------------------------------------------------
when MN_JMPP =>
assert_psen_s <= true;
if not clk_second_cycle_i then
-- write Accumulator to Program Memory address
-- (skip page offset update from Program Counter)
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
pm_addr_type_o <= PM_PAGE;
end if;
else
if clk_mstate_i = MSTATE1 then
-- store address in Program Counter low byte
pm_write_pcl_o <= true;
branch_taken_s <= true;
end if;
end if;
-- Mnemonic JNI ---------------------------------------------------------
when MN_JNI =>
assert_psen_s <= true;
cnd_branch_cond_o <= COND_INT;
if not clk_second_cycle_i then
-- start branch calculation
if clk_mstate_i = MSTATE3 then
cnd_compute_take_o <= true;
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JT ----------------------------------------------------------
when MN_JT =>
assert_psen_s <= true;
if opc_opcode_s(6) = '0' then
cnd_branch_cond_o <= COND_T0;
else
cnd_branch_cond_o <= COND_T1;
end if;
if not clk_second_cycle_i then
-- start branch calculation
if clk_mstate_i = MSTATE3 then
cnd_compute_take_o <= true;
cnd_comp_value_o(0) <= opc_opcode_s(4);
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JTF ---------------------------------------------------------
when MN_JTF =>
assert_psen_s <= true;
cnd_branch_cond_o <= COND_TF;
if not clk_second_cycle_i then
-- start branch calculation
if clk_mstate_i = MSTATE3 then
cnd_compute_take_o <= true;
jtf_executed_s <= true;
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic JZ ----------------------------------------------------------
when MN_JZ =>
assert_psen_s <= true;
cnd_branch_cond_o <= COND_Z;
if not clk_second_cycle_i then
-- read Accumulator and start branch calculation
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
cnd_compute_take_o <= true;
cnd_comp_value_o(0) <= opc_opcode_s(6);
end if;
else
-- store address in Program Counter low byte if branch has to
-- be taken
if clk_mstate_i = MSTATE1 and cnd_take_branch_i then
cond_jump_c2_m1_f;
end if;
end if;
-- Mnemonic MOV_A_DATA --------------------------------------------------
when MN_MOV_A_DATA =>
assert_psen_s <= true;
-- Write Accumulator when contents of Program Memory is on bus
-- during machine state 1 of second cycle.
if clk_second_cycle_i and clk_mstate_i = MSTATE1 then
alu_write_accu_o <= true;
end if;
-- Mnemonic MOV_A_RR ----------------------------------------------------
when MN_MOV_A_RR =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- read data from RAM and store in Accumulator
when MSTATE4 =>
and_or_xor_add_4_f;
alu_write_accu_o <= true;
when others =>
null;
end case;
-- Mnemonic MOV_A_PSW ---------------------------------------------------
when MN_MOV_A_PSW =>
if clk_mstate_i = MSTATE3 then
psw_read_psw_o <= true;
psw_read_sp_o <= true;
alu_write_accu_o <= true;
end if;
-- Mnemoniv MOV_PSW_A ---------------------------------------------------
when MN_MOV_PSW_A =>
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
psw_write_psw_o <= true;
psw_write_sp_o <= true;
end if;
-- Mnemonic MOV_RR ------------------------------------------------------
when MN_MOV_RR =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- write Accumulator to dmem
when MSTATE5 =>
alu_read_alu_o <= true;
dm_write_dmem_s <= true;
when others =>
null;
end case;
-- Mnemonic MOV_RR_DATA -------------------------------------------------
when MN_MOV_RR_DATA =>
assert_psen_s <= true;
-- read RAM once for indirect address mode
if not clk_second_cycle_i and clk_mstate_i = MSTATE3 then
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
end if;
-- Write Data Memory when contents of Program Memory is on bus
-- during machine state 1 of second cycle.
if clk_second_cycle_i and clk_mstate_i = MSTATE1 then
dm_write_dmem_s <= true;
end if;
-- Mnemonic MOV_T -------------------------------------------------------
when MN_MOV_T =>
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(5) = '1' then
alu_read_alu_o <= true; -- MOV T, A
tim_write_timer_o <= true;
else
tim_read_timer_o <= true; -- MOV A, T
alu_write_accu_o <= true;
end if;
end if;
-- Mnemonic OUTD_PP_A ---------------------------------------------------
when MN_OUTD_PP_A =>
clk_assert_prog_o <= true;
if not clk_second_cycle_i then
case clk_mstate_i is
-- propagate expander port number to Port 2
when MSTATE3 =>
data_s(7 downto 4) <= (others => '0');
data_s(1 downto 0) <= opc_opcode_s(1 downto 0);
-- decide which 8243 command to use
case opc_opcode_s(7 downto 4) is
when "1001" =>
data_s(3 downto 2) <= "11"; -- ANLD command
when "1000" =>
data_s(3 downto 2) <= "10"; -- ORLD command
when "0011" =>
data_s(3 downto 2) <= "01"; -- MOVD command
when others =>
null;
end case;
read_dec_s <= true;
p2_write_exp_o <= true;
-- output expander port number on Port 2 while active edge of PROG
-- write Accumulator to expander port
when MSTATE4 =>
p2_output_exp_s <= true;
alu_read_alu_o <= true;
p2_write_exp_o <= true;
when MSTATE5 =>
p2_output_exp_s <= true;
when others =>
null;
end case;
else
-- hold expander port until inactive edge of PROG
if clk_mstate_i = MSTATE1 or clk_mstate_i = MSTATE2 then
p2_output_exp_s <= true;
end if;
end if;
-- Mnemonic MOVD_A_PP ---------------------------------------------------
when MN_MOVD_A_PP =>
clk_assert_prog_o <= true;
if not clk_second_cycle_i then
case clk_mstate_i is
-- propagate expander port number to Port 2
when MSTATE3 =>
data_s <= "0000" &
"00" & -- 8243 command: read
opc_opcode_s(1 downto 0);
read_dec_s <= true;
p2_write_exp_o <= true;
-- output expander port number on Port 2 while active edge of PROG
-- write 1's to expander port to set lower nibble of Port 2 to input
when MSTATE4 =>
p2_output_exp_s <= true;
data_s(nibble_t'range) <= (others => '1');
read_dec_s <= true;
p2_write_exp_o <= true;
when MSTATE5 =>
p2_output_exp_s <= true;
when others =>
null;
end case;
else
case clk_mstate_i is
-- hold expander port until inactive edge of PROG
when MSTATE1 =>
p2_output_exp_s <= true;
-- hold expander port until inactive edge of PROG
-- write Accumulator with nibble of expander port
when MSTATE2 =>
p2_read_p2_o <= true;
p2_output_exp_s <= true;
p2_read_exp_o <= true;
alu_write_accu_o <= true;
when others =>
null;
end case;
end if;
-- Mnemonic MOVP --------------------------------------------------------
when MN_MOVP =>
assert_psen_s <= true;
if not clk_second_cycle_i then
-- write Accumulator to Program Memory address
-- (skip page offset update from Program Counter)
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
if opc_opcode_s(6) = '0' then
pm_addr_type_o <= PM_PAGE;
else
pm_addr_type_o <= PM_PAGE3;
end if;
end if;
else
if clk_mstate_i = MSTATE1 then
-- store data from Program Memory in Accumulator
alu_write_accu_o <= true;
-- trick & treat to prevent additional PC increment
-- our branch target is the previously incremented PC!
branch_taken_s <= true;
end if;
end if;
-- Mnemonic MOVX --------------------------------------------------------
when MN_MOVX =>
bus_bidir_bus_o <= true;
if opc_opcode_s(4) = '0' then
clk_assert_rd_o <= true;
else
clk_assert_wr_o <= true;
end if;
if not clk_second_cycle_i then
movx_first_cycle_s <= true;
case clk_mstate_i is
-- read dmem and put contents on BUS as external address
when MSTATE3 =>
dm_read_dmem_o <= true;
bus_write_bus_o <= true;
-- store contents of Accumulator to BUS
when MSTATE5 =>
if opc_opcode_s(4) = '1' then
alu_read_alu_o <= true;
bus_write_bus_o <= true;
end if;
when others =>
null;
end case;
else
if clk_mstate_i = MSTATE2 then
if opc_opcode_s(4) = '0' then
-- store contents of BUS in Accumulator
add_read_bus_s <= true;
alu_write_accu_o <= true;
else
-- store contents of Accumulator to BUS
-- to this to keep bus in output direction
alu_read_alu_o <= true;
bus_write_bus_o <= true;
end if;
end if;
end if;
-- Mnemonic NOP ---------------------------------------------------------
when MN_NOP =>
-- nothing to do
-- Mnemonic ORL ---------------------------------------------------------
when MN_ORL =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- store data from RAM to Temp Reg
when MSTATE4 =>
and_or_xor_add_4_f;
-- perform OR and store in Accumulator
when MSTATE5 =>
and_or_xor_add_5_f(alu_op => ALU_OR);
when others =>
null;
end case;
-- Mnemonic ORL_A_DATA --------------------------------------------------
when MN_ORL_A_DATA =>
assert_psen_s <= true;
if clk_second_cycle_i then
case clk_mstate_i is
-- write Temp Reg when contents of Program Memory is on bus
when MSTATE1 =>
alu_write_temp_reg_o <= true;
-- perform OR and store in Accumulator
when MSTATE3 =>
and_or_xor_add_5_f(alu_op => ALU_OR);
when others =>
null;
end case;
end if;
-- Mnemonic ORL_EXT -----------------------------------------------------
when MN_ORL_EXT =>
assert_psen_s <= true;
if not clk_second_cycle_i then
-- read port to Temp Reg
if clk_mstate_i = MSTATE5 then
if opc_opcode_s(1 downto 0) = "00" then
add_read_bus_s <= true;
elsif opc_opcode_s(1) = '0' then
p1_read_p1_o <= true;
p1_read_reg_o <= true;
else
p2_read_p2_o <= true;
p2_read_reg_o <= true;
end if;
alu_write_temp_reg_o <= true;
end if;
else
case clk_mstate_i is
-- write shadow Accumulator when contents of Program Memory is
-- on bus
when MSTATE1 =>
alu_write_shadow_o <= true;
-- loop shadow Accumulator through ALU to prevent update from
-- real Accumulator
when MSTATE2 =>
alu_read_alu_o <= true;
alu_write_shadow_o <= true;
-- write result of OR operation back to port
when MSTATE3 =>
alu_op_o <= ALU_OR;
alu_read_alu_o <= true;
if opc_opcode_s(1 downto 0) = "00" then
bus_write_bus_o <= true;
elsif opc_opcode_s(1) = '0' then
p1_write_p1_o <= true;
else
p2_write_p2_o <= true;
end if;
when others =>
null;
end case;
end if;
-- Mnemonic OUTL_EXT ----------------------------------------------------
when MN_OUTL_EXT =>
if opc_opcode_s(4) = '0' then
clk_assert_wr_o <= true;
end if;
-- read Accumulator and store in Port/BUS output register
if not clk_second_cycle_i and clk_mstate_i = MSTATE4 then
alu_read_alu_o <= true;
if opc_opcode_s(4) = '1' then
if opc_opcode_s(1) = '0' then
p1_write_p1_o <= true;
else
p2_write_p2_o <= true;
end if;
else
bus_write_bus_o <= true;
end if;
end if;
-- Mnemonic RET ---------------------------------------------------------
when MN_RET =>
if not clk_second_cycle_i then
case clk_mstate_i is
-- decrement Stack Pointer
when MSTATE3 =>
psw_dec_stackp_o <= true;
-- read Stack Pointer and address Data Memory for low byte
when MSTATE4 =>
psw_read_sp_o <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_STACK;
-- read Data Memory and store to Program Counter low
-- prepare address to Data memory for high byte
when MSTATE5 =>
dm_read_dmem_o <= true;
pm_write_pcl_o <= true;
dm_write_dmem_addr_o <= true;
dm_addr_type_o <= DM_STACK_HIGH;
when others =>
null;
end case;
else
case clk_mstate_i is
-- read Data Memory and store to Program Counter high and PSW
when MSTATE1 =>
dm_read_dmem_o <= true;
pm_write_pch_o <= true;
if opc_opcode_s(4) = '1' then
psw_write_psw_o <= true;
retr_executed_s <= true;
end if;
when MSTATE2 =>
add_write_pmem_addr_s <= true;
when others =>
null;
end case;
end if;
-- Mnemonic RL ----------------------------------------------------------
when MN_RL =>
if clk_mstate_i = MSTATE3 then
alu_op_o <= ALU_RL;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
if opc_opcode_s(4) = '1' then
psw_special_data_o <= alu_carry_i;
psw_write_carry_o <= true;
alu_use_carry_o <= true;
end if;
end if;
-- Mnemonic RR ----------------------------------------------------------
when MN_RR =>
if clk_mstate_i = MSTATE3 then
alu_op_o <= ALU_RR;
alu_read_alu_o <= true;
alu_write_accu_o <= true;
if opc_opcode_s(4) = '0' then
psw_special_data_o <= alu_carry_i;
psw_write_carry_o <= true;
alu_use_carry_o <= true;
end if;
end if;
-- Mnemonic SEL_MB ------------------------------------------------------
when MN_SEL_MB =>
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(4) = '1' then
set_mb_s <= true;
else
clear_mb_s <= true;
end if;
end if;
-- Mnemonic SEL_RB ------------------------------------------------------
when MN_SEL_RB =>
if clk_mstate_i = MSTATE3 then
psw_special_data_o <= opc_opcode_s(4);
psw_write_bs_o <= true;
end if;
-- Mnemonic STOP_TCNT ---------------------------------------------------
when MN_STOP_TCNT =>
if clk_mstate_i = MSTATE3 then
tim_stop_tcnt_o <= true;
end if;
-- Mnemonic STRT --------------------------------------------------------
when MN_STRT =>
if clk_mstate_i = MSTATE3 then
if opc_opcode_s(4) = '1' then
tim_start_t_o <= true;
else
tim_start_cnt_o <= true;
end if;
end if;
-- Mnemonic SWAP --------------------------------------------------------
when MN_SWAP =>
alu_op_o <= ALU_SWAP;
if clk_mstate_i = MSTATE3 then
alu_read_alu_o <= true;
alu_write_accu_o <= true;
end if;
-- Mnemonic XCH ---------------------------------------------------------
when MN_XCH =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- store data from RAM in Accumulator and Temp Reg
-- Accumulator is already shadowed!
when MSTATE4 =>
dm_read_dmem_o <= true;
alu_write_accu_o <= true;
alu_write_temp_reg_o <= true;
if opc_opcode_s(4) = '1' then
-- XCHD
-- only write lower nibble of Accumulator
alu_accu_low_o <= true;
end if;
-- store data from shadow (previous) Accumulator to dmem
when MSTATE5 =>
dm_write_dmem_s <= true;
alu_read_alu_o <= true;
if opc_opcode_s(4) = '1' then
-- XCHD
-- concatenate shadow Accumulator and Temp Reg
alu_op_o <= ALU_CONCAT;
end if;
when others =>
null;
end case;
-- Mnemonic XRL ---------------------------------------------------------
when MN_XRL =>
case clk_mstate_i is
-- read RAM once for indirect address mode
when MSTATE3 =>
if not enable_quartus_bugfix_c or
opc_opcode_s(3) = '0' then
address_indirect_3_f;
end if;
-- store data from RAM to Temp Reg
when MSTATE4 =>
and_or_xor_add_4_f;
-- perform XOR and store in Accumulator
when MSTATE5 =>
and_or_xor_add_5_f(alu_op => ALU_XOR);
when others =>
null;
end case;
-- Mnemonic XRL_A_DATA --------------------------------------------------
when MN_XRL_A_DATA =>
assert_psen_s <= true;
if clk_second_cycle_i then
case clk_mstate_i is
-- write Temp Reg when contents of Program Memory is on bus
when MSTATE1 =>
alu_write_temp_reg_o <= true;
-- perform XOR and store in Accumulator
when MSTATE3 =>
and_or_xor_add_5_f(alu_op => ALU_XOR);
when others =>
null;
end case;
end if;
-- Unimplemented mnemonic -----------------------------------------------
when others =>
-- this will behave like a NOP
-- pragma translate_off
assert false
report "Mnemonic not yet implemented."
severity warning;
-- pragma translate_on
end case;
end process decode;
--
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Process regs
--
-- Purpose:
-- Implements the various registes.
--
regs: process (res_i, clk_i)
begin
if res_i = res_active_c then
branch_taken_q <= false;
f1_q <= '0';
mb_q <= '0';
t0_dir_q <= '0';
-- pragma translate_off
istrobe_res_q <= '1';
istrobe_q <= '0';
injected_int_q <= '0';
-- pragma translate_on
elsif clk_i'event and clk_i = clk_active_c then
if en_clk_i then
-- branch taken flag
if branch_taken_s then
branch_taken_q <= true;
elsif clk_mstate_i = MSTATE5 then
-- release flag when new instruction starts
branch_taken_q <= false;
end if;
-- Flag 1
if clear_f1_s then
f1_q <= '0';
elsif cpl_f1_s then
f1_q <= not f1_q;
end if;
-- Memory Bank select
if clear_mb_s then
mb_q <= '0';
elsif set_mb_s then
mb_q <= '1';
end if;
-- T0 direction selection
if ent0_clk_s then
t0_dir_q <= '1';
end if;
-- pragma translate_off
-- Marker for injected instruction ------------------------------------
if opc_inj_int_s then
injected_int_q <= '1';
elsif clk_mstate_i = MSTATE5 and last_cycle_s then
injected_int_q <= '0';
end if;
-- Remove istrobe after reset suppression -----------------------------
if clk_mstate_i = MSTATE5 and last_cycle_s then
istrobe_res_q <= '0';
end if;
-- pragma translate_on
end if;
-- pragma translate_off
-- Instruction Strobe ---------------------------------------------------
if clk_mstate_i = MSTATE5 and last_cycle_s and
injected_int_q = '0' then
if istrobe_res_q = '0' then
istrobe_q <= '1';
end if;
else
istrobe_q <= '0';
end if;
-- pragma translate_on
end if;
end process regs;
--
-----------------------------------------------------------------------------
-- pragma translate_off
-- assign to global signal for testbench
tb_istrobe_s <= istrobe_q;
-- pragma translate_on
-----------------------------------------------------------------------------
-- Output Mapping.
-----------------------------------------------------------------------------
clk_multi_cycle_o <= opc_multi_cycle_s;
cnd_f1_o <= f1_q;
cnd_tf_o <= tf_s;
data_o <= data_s
when read_dec_s else
(others => bus_idle_level_c);
dm_write_dmem_o <= dm_write_dmem_s and en_clk_i;
pm_inc_pc_o <= pm_inc_pc_s or add_inc_pc_s;
pm_write_pmem_addr_o <= pm_write_pmem_addr_s or add_write_pmem_addr_s;
t0_dir_o <= t0_dir_q;
bus_read_bus_o <= bus_read_bus_s or add_read_bus_s;
end rtl;
-------------------------------------------------------------------------------
-- File History:
--
-- $Log: decoder.vhd,v $
-- Revision 1.25 2006/06/20 00:46:03 arniml
-- new input xtal_en_i
--
-- Revision 1.24 2005/11/14 21:12:29 arniml
-- suppress p2_output_pch_o when MOVX operation is accessing the
-- external memory
--
-- Revision 1.23 2005/11/07 19:25:01 arniml
-- fix sensitivity list
--
-- Revision 1.22 2005/11/01 21:25:37 arniml
-- * suppress p2_output_pch_o when p2_output_exp is active
-- * wire xtal_i to interrupt module
--
-- Revision 1.21 2005/10/31 10:08:33 arniml
-- Suppress assertion of bus_read_bus_s when interrupt is pending.
-- This should fix bug report
-- "PROBLEM WHEN INT AND JMP"
--
-- Revision 1.20 2005/09/13 21:08:34 arniml
-- move check for int_pending_s into ea_i_='0' branch
-- this fixes a glitch on PCH when an interrutp occurs
-- during external program memory fetch
--
-- Revision 1.19 2005/06/11 10:08:43 arniml
-- introduce prefix 't48_' for all packages, entities and configurations
--
-- Revision 1.18 2005/06/09 22:18:28 arniml
-- Move latching of BUS to MSTATE2
-- -> sample BUS at the end of RD'
--
-- Revision 1.17 2005/05/09 22:26:08 arniml
-- remove obsolete output stack_high_o
--
-- Revision 1.16 2004/10/25 19:39:24 arniml
-- Fix bug report:
-- "RD' and WR' not asserted for INS A, BUS and OUTL BUS, A"
-- rd is asserted for INS A, BUS
-- wr is asserted for OUTL BUS, A
-- P1, P2 and BUS are written in first instruction cycle
--
-- Revision 1.15 2004/09/12 00:35:44 arniml
-- Fix bug report:
-- "PSENn Timing"
-- PSEN is now only asserted for the second cycle if explicitely
-- requested by assert_psen_s.
-- The previous implementation asserted PSEN together with RD or WR.
--
-- Revision 1.14 2004/06/30 21:18:28 arniml
-- Fix bug report:
-- "Program Memory bank can be switched during interrupt"
-- int module emits int_in_progress signal that is used inside the decoder
-- to hold mb low for JMP and CALL during interrupts
--
-- Revision 1.13 2004/05/20 21:51:40 arniml
-- clean-up use of ea_i
--
-- Revision 1.12 2004/05/17 14:40:09 arniml
-- assert p2_read_p2_o when expander port is read
--
-- Revision 1.11 2004/05/16 15:33:39 arniml
-- work around bug in Quartus II 4.0
--
-- Revision 1.10 2004/04/25 16:22:03 arniml
-- adjust external timing of BUS
--
-- Revision 1.9 2004/04/24 11:22:55 arniml
-- removed superfluous signal from sensitivity list
--
-- Revision 1.8 2004/04/18 18:57:43 arniml
-- + enhance instruction strobe generation
-- + rework address output under EA=1 conditions
--
-- Revision 1.7 2004/04/15 22:06:05 arniml
-- + add marker for injected calls
-- + suppress intstruction strobes for injected calls
--
-- Revision 1.6 2004/04/14 20:53:33 arniml
-- make istrobe visible through testbench package
--
-- Revision 1.5 2004/04/07 22:09:03 arniml
-- remove unused signals
--
-- Revision 1.4 2004/04/04 14:18:53 arniml
-- add measures to implement XCHD
--
-- Revision 1.3 2004/03/28 21:15:48 arniml
-- implemented mnemonic DA
--
-- Revision 1.2 2004/03/28 13:06:32 arniml
-- implement mnemonics:
-- + MOVD_A_PP
-- + OUTD_PP_A -> ANLD PP, A; MOVD PP, A; ORLD PP, A
--
-- Revision 1.1 2004/03/23 21:31:52 arniml
-- initial check-in
--
-------------------------------------------------------------------------------